emacs-diffs
[Top][All Lists]
Advanced

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

feature/tree-sitter 77d5a0cf9f 5/5: Merge remote-tracking branch 'origin


From: Yuan Fu
Subject: feature/tree-sitter 77d5a0cf9f 5/5: Merge remote-tracking branch 'origin/master' into feature/tree-sitter
Date: Mon, 29 Aug 2022 14:43:27 -0400 (EDT)

branch: feature/tree-sitter
commit 77d5a0cf9fc4a6dc44f0c6ee5e3295e0eea08273
Merge: e98b4715bb df2f6fb7fc
Author: Yuan Fu <yuan@debian-BULLSEYE-live-builder-AMD64>
Commit: Yuan Fu <yuan@debian-BULLSEYE-live-builder-AMD64>

    Merge remote-tracking branch 'origin/master' into feature/tree-sitter
---
 .dir-locals.el                                     |    1 +
 .gitignore                                         |    6 +
 CONTRIBUTE                                         |   36 +-
 ChangeLog.2                                        |    6 +-
 ChangeLog.3                                        | 2342 +++++--
 Makefile.in                                        |   35 +-
 admin/MAINTAINERS                                  |    1 +
 admin/admin.el                                     |    9 +-
 admin/authors.el                                   |    3 +-
 admin/automerge                                    |    2 +-
 admin/check-doc-strings                            |    8 +-
 admin/coccinelle/window.cocci                      |    6 -
 admin/emake                                        |    5 +-
 admin/gitmerge.el                                  |    8 +-
 admin/make-tarball.txt                             |   57 +-
 admin/merge-gnulib                                 |    2 +-
 admin/notes/multi-tty                              |    2 +-
 admin/notes/spelling                               |    2 +-
 admin/nt/dist-build/README-scripts                 |    2 +-
 admin/nt/dist-build/build-zips.sh                  |    2 +-
 admin/quick-install-emacs                          |    4 +-
 admin/unidata/blocks.awk                           |   11 +-
 admin/unidata/unidata-gen.el                       |    4 +-
 admin/update_autogen                               |   14 +-
 autogen.sh                                         |    2 +-
 build-aux/config.guess                             |    9 +-
 build-aux/config.sub                               |    6 +-
 config.bat                                         |    1 +
 configure.ac                                       | 1545 ++---
 doc/emacs/ChangeLog.1                              |    2 +-
 doc/emacs/abbrevs.texi                             |    6 +-
 doc/emacs/buffers.texi                             |   13 +-
 doc/emacs/custom.texi                              |    8 +
 doc/emacs/dired.texi                               |  115 +-
 doc/emacs/display.texi                             |   97 +-
 doc/emacs/emacs.texi                               |    3 +-
 doc/emacs/files.texi                               |   61 +-
 doc/emacs/frames.texi                              |   11 +-
 doc/emacs/glossary.texi                            |    5 +-
 doc/emacs/help.texi                                |    5 +
 doc/emacs/killing.texi                             |   23 +-
 doc/emacs/maintaining.texi                         |    4 +-
 doc/emacs/mini.texi                                |   13 +-
 doc/emacs/misc.texi                                |  102 +-
 doc/emacs/msdos.texi                               |    6 +-
 doc/emacs/package.texi                             |   10 +
 doc/emacs/search.texi                              |   17 +-
 doc/emacs/trouble.texi                             |  150 +-
 doc/emacs/xresources.texi                          |   10 +-
 doc/lispintro/emacs-lisp-intro.texi                |   45 +-
 doc/lispref/buffers.texi                           |   14 +-
 doc/lispref/commands.texi                          |   37 +-
 doc/lispref/compile.texi                           |    6 +-
 doc/lispref/customize.texi                         |    4 +
 doc/lispref/debugging.texi                         |   44 +
 doc/lispref/display.texi                           |  258 +-
 doc/lispref/edebug.texi                            |   10 +-
 doc/lispref/files.texi                             |    9 +
 doc/lispref/frames.texi                            |   86 +-
 doc/lispref/functions.texi                         |   38 +
 doc/lispref/hash.texi                              |   28 +-
 doc/lispref/hooks.texi                             |    2 -
 doc/lispref/keymaps.texi                           |   35 +-
 doc/lispref/lists.texi                             |   67 +-
 doc/lispref/loading.texi                           |   36 +-
 doc/lispref/maps.texi                              |    4 +
 doc/lispref/modes.texi                             |   27 +-
 doc/lispref/objects.texi                           |    3 +
 doc/lispref/os.texi                                |   66 +-
 doc/lispref/positions.texi                         |   22 +
 doc/lispref/processes.texi                         |  152 +-
 doc/lispref/searching.texi                         |    4 +-
 doc/lispref/sequences.texi                         |   14 +
 doc/lispref/strings.texi                           |   27 +-
 doc/lispref/text.texi                              |   46 +-
 doc/lispref/tips.texi                              |   16 +-
 doc/lispref/variables.texi                         |   65 +-
 doc/lispref/windows.texi                           |   24 +-
 doc/misc/Makefile.in                               |    1 +
 doc/misc/auth.texi                                 |   16 +-
 doc/misc/autotype.texi                             |   40 +-
 doc/misc/calc.texi                                 |    2 +-
 doc/misc/cl.texi                                   |   94 +-
 doc/misc/dired-x.texi                              |  172 -
 doc/misc/ede.texi                                  |    4 +-
 doc/misc/ediff.texi                                |   11 +-
 doc/misc/efaq-w32.texi                             |  119 +-
 doc/misc/efaq.texi                                 |  264 +-
 doc/misc/emacs-mime.texi                           |    6 +-
 doc/misc/erc.texi                                  |  211 +-
 doc/misc/ert.texi                                  |    4 +-
 doc/misc/eshell.texi                               |  161 +-
 doc/misc/eudc.texi                                 |   21 +-
 doc/misc/eww.texi                                  |    4 +-
 doc/misc/gnus-faq.texi                             |  249 +-
 doc/misc/gnus.texi                                 |  273 +-
 doc/misc/htmlfontify.texi                          |   12 +-
 doc/misc/idlwave.texi                              |   49 +-
 doc/misc/message.texi                              |   18 +-
 doc/misc/mh-e.texi                                 |  103 +-
 doc/misc/modus-themes.org                          |  522 +-
 doc/misc/org.org                                   |   10 +-
 doc/misc/rcirc.texi                                |    6 +-
 doc/misc/reftex.texi                               |    8 +-
 doc/misc/texinfo.tex                               |  476 +-
 doc/misc/tramp.texi                                |  128 +-
 doc/misc/transient.texi                            |  802 +--
 doc/misc/url.texi                                  |    1 -
 doc/misc/viper.texi                                |    4 +-
 doc/misc/vtable.texi                               |    6 +-
 etc/AUTHORS                                        |  231 +-
 etc/DEBUG                                          |   44 +-
 etc/ERC-NEWS                                       |   90 +
 etc/NEWS                                           |  980 ++-
 etc/NEWS.1-17                                      |  860 +--
 etc/NEWS.18                                        |  512 +-
 etc/NEWS.19                                        | 1695 +++---
 etc/NEWS.20                                        | 1318 ++--
 etc/NEWS.21                                        | 1785 +++---
 etc/NEWS.22                                        | 2577 ++++----
 etc/NEWS.23                                        | 1212 ++--
 etc/NEWS.24                                        | 2264 +++----
 etc/NEWS.25                                        |    6 +-
 etc/NEWS.26                                        |   14 +-
 etc/NEWS.27                                        |   14 +-
 etc/NEWS.28                                        |   42 +-
 etc/ORG-NEWS                                       |   20 +-
 etc/PROBLEMS                                       |  205 +-
 etc/TODO                                           |   35 +-
 etc/compilation.txt                                |   13 +-
 etc/emacs_lldb.py                                  |  254 +
 etc/images/README                                  |    2 +-
 etc/publicsuffix.txt                               |   46 +-
 etc/srecode/ede-autoconf.srt                       |    4 +-
 etc/themes/leuven-dark-theme.el                    |    2 +-
 etc/themes/manoj-dark-theme.el                     |    2 +-
 etc/themes/modus-operandi-theme.el                 |    4 +-
 etc/themes/modus-themes.el                         |  432 +-
 etc/themes/modus-vivendi-theme.el                  |    4 +-
 etc/tutorials/TUTORIAL.nl                          |    2 +-
 lib-src/Makefile.in                                |    3 +
 lib-src/etags.c                                    |   19 +-
 lib-src/make-docfile.c                             |  360 +-
 lib/fchmodat.c                                     |   59 +-
 lib/filevercmp.c                                   |   18 +-
 lib/filevercmp.h                                   |    4 +-
 lib/gnulib.mk.in                                   |   37 +-
 lib/group-member.c                                 |    5 +-
 lib/intprops-internal.h                            |  392 ++
 lib/intprops.h                                     |  359 +-
 lib/lchmod.c                                       |   84 +-
 lib/mini-gmp.h                                     |    2 +-
 lib/stdckdint.in.h                                 |   37 +
 lib/str-two-way.h                                  |    4 +-
 lib/string.in.h                                    |   16 +-
 lib/sys_stat.in.h                                  |   28 +-
 lib/tempname.c                                     |  170 +-
 lib/tempname.h                                     |    2 +-
 lib/verify.h                                       |    7 +-
 lisp/ChangeLog.12                                  |    2 +-
 lisp/ChangeLog.17                                  |    2 +-
 lisp/ChangeLog.5                                   |    4 +-
 lisp/ChangeLog.9                                   |    2 +-
 lisp/Makefile.in                                   |   73 +-
 lisp/abbrev.el                                     |   30 +-
 lisp/align.el                                      |   18 +-
 lisp/allout.el                                     |   34 +-
 lisp/ansi-color.el                                 |    3 -
 lisp/apropos.el                                    |   99 +-
 lisp/arc-mode.el                                   |   28 +-
 lisp/array.el                                      |   87 +-
 lisp/auth-source.el                                |  160 +-
 lisp/autoinsert.el                                 |    5 +-
 lisp/autorevert.el                                 |    2 +-
 lisp/battery.el                                    |   22 +-
 lisp/bindings.el                                   |  240 +-
 lisp/bookmark.el                                   |  145 +-
 lisp/bs.el                                         |  119 +-
 lisp/buff-menu.el                                  |    4 +-
 lisp/button.el                                     |   14 +-
 lisp/calc/calc-embed.el                            |    3 +-
 lisp/calc/calc-keypd.el                            |    2 +-
 lisp/calc/calc-misc.el                             |   62 +-
 lisp/calc/calc-prog.el                             |    7 +-
 lisp/calc/calc-vec.el                              |    4 +-
 lisp/calc/calc-yank.el                             |   30 +-
 lisp/calc/calc.el                                  |   14 +-
 lisp/calendar/calendar.el                          |   18 +-
 lisp/calendar/diary-lib.el                         |   14 +-
 lisp/calendar/icalendar.el                         |    3 +-
 lisp/calendar/time-date.el                         |   20 +-
 lisp/calendar/timeclock.el                         |    4 +-
 lisp/cedet/cedet-global.el                         |    2 +-
 lisp/cedet/cedet.el                                |    6 +-
 lisp/cedet/data-debug.el                           |   22 +-
 lisp/cedet/ede.el                                  |    9 +-
 lisp/cedet/ede/auto.el                             |    1 +
 lisp/cedet/ede/autoconf-edit.el                    |    8 +-
 lisp/cedet/ede/base.el                             |    8 +-
 lisp/cedet/ede/config.el                           |    4 +-
 lisp/cedet/ede/custom.el                           |   10 +-
 lisp/cedet/ede/emacs.el                            |    3 +-
 lisp/cedet/ede/files.el                            |    5 +-
 lisp/cedet/ede/pmake.el                            |    2 +-
 lisp/cedet/ede/proj-elisp.el                       |    3 +-
 lisp/cedet/ede/project-am.el                       |    2 +-
 lisp/cedet/ede/speedbar.el                         |    6 +-
 lisp/cedet/ede/system.el                           |    2 +-
 lisp/cedet/pulse.el                                |    2 +-
 lisp/cedet/semantic.el                             |    6 +-
 lisp/cedet/semantic/bovine.el                      |    4 +-
 lisp/cedet/semantic/bovine/c.el                    |   10 +-
 lisp/cedet/semantic/complete.el                    |   94 +-
 lisp/cedet/semantic/db-file.el                     |    2 +-
 lisp/cedet/semantic/db-typecache.el                |    2 +-
 lisp/cedet/semantic/db.el                          |   11 +-
 lisp/cedet/semantic/edit.el                        |    2 +-
 lisp/cedet/semantic/grammar.el                     |    6 +-
 lisp/cedet/semantic/idle.el                        |    8 +-
 lisp/cedet/semantic/java.el                        |   37 +-
 lisp/cedet/semantic/lex-spp.el                     |    4 +-
 lisp/cedet/semantic/lex.el                         |   39 +-
 lisp/cedet/semantic/symref.el                      |    2 +-
 lisp/cedet/semantic/symref/list.el                 |    8 +-
 lisp/cedet/semantic/tag-file.el                    |  102 +-
 lisp/cedet/semantic/util-modes.el                  |    6 +-
 lisp/cedet/semantic/util.el                        |    3 -
 lisp/cedet/semantic/wisent/comp.el                 |   16 +-
 lisp/cedet/semantic/wisent/javascript.el           |    2 +-
 lisp/cedet/semantic/wisent/python.el               |    6 +-
 lisp/cedet/srecode.el                              |    4 +-
 lisp/cedet/srecode/compile.el                      |   10 +-
 lisp/cedet/srecode/document.el                     |    6 +-
 lisp/cedet/srecode/insert.el                       |    6 +-
 lisp/cedet/srecode/table.el                        |   10 +-
 lisp/chistory.el                                   |    6 +-
 lisp/comint.el                                     |   98 +-
 lisp/completion.el                                 |    4 -
 lisp/composite.el                                  |   19 +
 lisp/cus-dep.el                                    |    2 +-
 lisp/cus-edit.el                                   |  325 +-
 lisp/cus-face.el                                   |    4 +-
 lisp/cus-start.el                                  |    7 +
 lisp/custom.el                                     |   17 +-
 lisp/descr-text.el                                 |    5 +-
 lisp/desktop.el                                    |   16 +-
 lisp/dired-aux.el                                  |  466 +-
 lisp/dired-x.el                                    |  681 +--
 lisp/dired.el                                      |  232 +-
 lisp/dirtrack.el                                   |   21 +-
 lisp/dnd.el                                        |  140 +-
 lisp/doc-view.el                                   |  198 +-
 lisp/dos-fns.el                                    |   16 -
 lisp/ecomplete.el                                  |    2 +-
 lisp/edmacro.el                                    |   71 +-
 lisp/elec-pair.el                                  |   87 +-
 lisp/electric.el                                   |   28 +-
 lisp/emacs-lisp/advice.el                          |   27 +-
 lisp/emacs-lisp/autoload.el                        |  915 ---
 lisp/emacs-lisp/backtrace.el                       |  119 +-
 lisp/emacs-lisp/bindat.el                          |   45 +-
 lisp/emacs-lisp/byte-opt.el                        |  555 +-
 lisp/emacs-lisp/byte-run.el                        |  238 +-
 lisp/emacs-lisp/bytecomp.el                        |  230 +-
 lisp/emacs-lisp/cconv.el                           |    3 +-
 lisp/emacs-lisp/chart.el                           |    9 +-
 lisp/emacs-lisp/checkdoc.el                        |  107 +-
 lisp/emacs-lisp/cl-extra.el                        |    3 +-
 lisp/emacs-lisp/cl-generic.el                      |   46 +-
 lisp/emacs-lisp/cl-indent.el                       |    7 +-
 lisp/emacs-lisp/cl-lib.el                          |    4 +-
 lisp/emacs-lisp/cl-macs.el                         |   40 +-
 lisp/emacs-lisp/cl-preloaded.el                    |    2 +-
 lisp/emacs-lisp/cl-seq.el                          |    4 +
 lisp/emacs-lisp/comp-cstr.el                       |   14 +-
 lisp/emacs-lisp/comp.el                            |   86 +-
 lisp/emacs-lisp/crm.el                             |   51 +-
 lisp/emacs-lisp/debug-early.el                     |    8 +-
 lisp/emacs-lisp/debug.el                           |   93 +-
 lisp/emacs-lisp/derived.el                         |    5 +-
 lisp/emacs-lisp/easy-mmode.el                      |    4 +-
 lisp/emacs-lisp/easymenu.el                        |   18 +-
 lisp/emacs-lisp/edebug.el                          |  302 +-
 lisp/emacs-lisp/eieio-base.el                      |   46 +-
 lisp/emacs-lisp/eieio-core.el                      |    5 +-
 lisp/emacs-lisp/eieio-custom.el                    |   12 +-
 lisp/emacs-lisp/eieio-opt.el                       |    4 -
 lisp/emacs-lisp/eieio.el                           |    1 +
 lisp/emacs-lisp/eldoc.el                           |   17 +-
 lisp/emacs-lisp/elp.el                             |   14 +-
 lisp/emacs-lisp/ert-x.el                           |   11 +-
 lisp/emacs-lisp/ert.el                             |   29 +-
 lisp/emacs-lisp/find-func.el                       |    5 +-
 lisp/emacs-lisp/gv.el                              |  109 +-
 lisp/emacs-lisp/helper.el                          |   51 +-
 lisp/emacs-lisp/icons.el                           |  267 +
 lisp/emacs-lisp/lisp-mode.el                       |  222 +-
 lisp/emacs-lisp/lisp.el                            |   18 +-
 lisp/emacs-lisp/loaddefs-gen.el                    |  180 +-
 lisp/emacs-lisp/macroexp.el                        |   19 +-
 lisp/emacs-lisp/nadvice.el                         |   28 +-
 lisp/emacs-lisp/package.el                         |   96 +-
 lisp/emacs-lisp/pcase.el                           |   13 +-
 lisp/emacs-lisp/re-builder.el                      |   67 +-
 lisp/emacs-lisp/regi.el                            |    1 -
 lisp/emacs-lisp/ring.el                            |    4 +
 lisp/emacs-lisp/rmc.el                             |   25 +-
 lisp/emacs-lisp/rx.el                              |   15 +
 lisp/emacs-lisp/seq.el                             |   78 +-
 lisp/emacs-lisp/shadow.el                          |    7 +-
 lisp/emacs-lisp/shortdoc.el                        |   74 +-
 lisp/emacs-lisp/shorthands.el                      |    3 +-
 lisp/emacs-lisp/subr-x.el                          |  144 +-
 lisp/emacs-lisp/syntax.el                          |  115 +-
 lisp/emacs-lisp/tabulated-list.el                  |   65 +-
 lisp/emacs-lisp/testcover.el                       |    3 +-
 lisp/emacs-lisp/timer-list.el                      |   13 +-
 lisp/emacs-lisp/timer.el                           |   70 +-
 lisp/emacs-lisp/trace.el                           |   17 +-
 lisp/emacs-lisp/warnings.el                        |   55 +-
 lisp/emacs-lock.el                                 |   11 -
 lisp/emulation/cua-base.el                         |   18 +-
 lisp/emulation/edt.el                              |    2 +-
 lisp/emulation/viper-cmd.el                        |    8 +-
 lisp/emulation/viper-ex.el                         |    2 +-
 lisp/emulation/viper-init.el                       |    6 +-
 lisp/emulation/viper-keym.el                       |   86 +-
 lisp/emulation/viper-macs.el                       |    8 +-
 lisp/emulation/viper-util.el                       |   54 +-
 lisp/emulation/viper.el                            |   37 +-
 lisp/env.el                                        |    4 +-
 lisp/epa-ks.el                                     |    6 +-
 lisp/epa-mail.el                                   |   28 +-
 lisp/epa.el                                        |    2 +-
 lisp/epg-config.el                                 |    4 +-
 lisp/epg.el                                        |    4 +-
 lisp/erc/erc-backend.el                            |  289 +-
 lisp/erc/erc-button.el                             |    2 +-
 lisp/erc/erc-capab.el                              |    2 +-
 lisp/erc/erc-compat.el                             |    6 +
 lisp/erc/erc-dcc.el                                |   47 +-
 lisp/erc/erc-join.el                               |  121 +-
 lisp/erc/erc-networks.el                           |  699 ++-
 lisp/erc/erc-services.el                           |   53 +-
 lisp/erc/erc-speedbar.el                           |   29 +-
 lisp/erc/erc-stamp.el                              |    2 +-
 lisp/erc/erc-track.el                              |   16 +-
 lisp/erc/erc.el                                    | 1023 +++-
 lisp/eshell/em-alias.el                            |    2 +-
 lisp/eshell/em-cmpl.el                             |   11 -
 lisp/eshell/em-dirs.el                             |   41 +-
 lisp/eshell/em-extpipe.el                          |    4 +-
 lisp/eshell/em-glob.el                             |  221 +-
 lisp/eshell/em-hist.el                             |    1 -
 lisp/eshell/em-pred.el                             |   18 +-
 lisp/eshell/em-term.el                             |   10 +-
 lisp/eshell/em-unix.el                             |   19 +-
 lisp/eshell/esh-arg.el                             |    2 +-
 lisp/eshell/esh-cmd.el                             |   92 +-
 lisp/eshell/esh-io.el                              |   71 +-
 lisp/eshell/esh-mode.el                            |   13 +-
 lisp/eshell/esh-proc.el                            |  123 +-
 lisp/eshell/esh-util.el                            |   12 +-
 lisp/eshell/esh-var.el                             |  136 +-
 lisp/ezimage.el                                    |    5 -
 lisp/face-remap.el                                 |  116 +-
 lisp/faces.el                                      |   79 +-
 lisp/ffap.el                                       |  202 +-
 lisp/files-x.el                                    |   31 +-
 lisp/files.el                                      |  268 +-
 lisp/filesets.el                                   |   89 +-
 lisp/find-dired.el                                 |   99 +-
 lisp/find-file.el                                  |   15 +-
 lisp/find-lisp.el                                  |    2 +-
 lisp/finder.el                                     |   16 +-
 lisp/font-core.el                                  |    7 +-
 lisp/font-lock.el                                  |  210 +-
 lisp/format.el                                     |    1 +
 lisp/frame.el                                      |   16 +-
 lisp/fringe.el                                     |   12 +
 lisp/gnus/ChangeLog.3                              |    4 +-
 lisp/gnus/deuglify.el                              |    1 +
 lisp/gnus/gnus-agent.el                            |    6 +-
 lisp/gnus/gnus-art.el                              |   61 +-
 lisp/gnus/gnus-bookmark.el                         |    4 +-
 lisp/gnus/gnus-cache.el                            |    2 +-
 lisp/gnus/gnus-cite.el                             |    8 +-
 lisp/gnus/gnus-cus.el                              |    2 +-
 lisp/gnus/gnus-demon.el                            |    2 +-
 lisp/gnus/gnus-diary.el                            |    8 +-
 lisp/gnus/gnus-draft.el                            |    2 +-
 lisp/gnus/gnus-eform.el                            |    2 +-
 lisp/gnus/gnus-group.el                            |   30 +-
 lisp/gnus/gnus-int.el                              |    5 +-
 lisp/gnus/gnus-logic.el                            |    4 +-
 lisp/gnus/gnus-msg.el                              |   44 +-
 lisp/gnus/gnus-picon.el                            |    6 +-
 lisp/gnus/gnus-range.el                            |   12 +-
 lisp/gnus/gnus-registry.el                         |    3 -
 lisp/gnus/gnus-salt.el                             |    8 +-
 lisp/gnus/gnus-score.el                            |   14 +-
 lisp/gnus/gnus-search.el                           |   48 +-
 lisp/gnus/gnus-srvr.el                             |    7 +-
 lisp/gnus/gnus-start.el                            |   16 +-
 lisp/gnus/gnus-sum.el                              |   40 +-
 lisp/gnus/gnus-topic.el                            |   10 +-
 lisp/gnus/gnus-util.el                             |   46 +-
 lisp/gnus/gnus-uu.el                               |   11 +-
 lisp/gnus/gnus.el                                  |   45 +-
 lisp/gnus/message.el                               |   87 +-
 lisp/gnus/mm-decode.el                             |   16 +-
 lisp/gnus/mm-util.el                               |    1 -
 lisp/gnus/mm-view.el                               |    4 +-
 lisp/gnus/mml.el                                   |   12 +-
 lisp/gnus/mml2015.el                               |    2 +-
 lisp/gnus/nnagent.el                               |    1 +
 lisp/gnus/nnbabyl.el                               |    8 +-
 lisp/gnus/nndiary.el                               |    4 +-
 lisp/gnus/nndir.el                                 |    1 +
 lisp/gnus/nndoc.el                                 |    1 +
 lisp/gnus/nndraft.el                               |    1 +
 lisp/gnus/nneething.el                             |    4 +-
 lisp/gnus/nnfolder.el                              |   10 +-
 lisp/gnus/nnheader.el                              |   18 +-
 lisp/gnus/nnimap.el                                |   28 +-
 lisp/gnus/nnmail.el                                |    6 +-
 lisp/gnus/nnmaildir.el                             |   22 +-
 lisp/gnus/nnmairix.el                              |    2 +-
 lisp/gnus/nnmbox.el                                |    1 +
 lisp/gnus/nnmh.el                                  |   12 +-
 lisp/gnus/nnml.el                                  |    9 +-
 lisp/gnus/nnrss.el                                 |    7 +-
 lisp/gnus/nnspool.el                               |    1 +
 lisp/gnus/nntp.el                                  |   54 +-
 lisp/gnus/nnvirtual.el                             |    7 +-
 lisp/gnus/smime.el                                 |    2 +-
 lisp/gnus/spam-report.el                           |    2 +-
 lisp/gnus/spam-stat.el                             |    5 +-
 lisp/gnus/spam.el                                  |   10 +-
 lisp/help-fns.el                                   |  197 +-
 lisp/help-mode.el                                  |  108 +-
 lisp/help.el                                       |  146 +-
 lisp/hex-util.el                                   |    8 +-
 lisp/hi-lock.el                                    |   42 +-
 lisp/htmlfontify.el                                |   11 +-
 lisp/ibuf-ext.el                                   |   86 +-
 lisp/ibuf-macs.el                                  |   22 +-
 lisp/ibuffer.el                                    |  427 +-
 lisp/icomplete.el                                  |   14 +-
 lisp/ido.el                                        |   19 +-
 lisp/iimage.el                                     |    3 -
 lisp/image-dired.el                                |   20 +-
 lisp/image-mode.el                                 |  467 +-
 lisp/image.el                                      |  109 +-
 lisp/image/exif.el                                 |    4 +-
 lisp/image/gravatar.el                             |    2 +-
 lisp/image/image-converter.el                      |   81 +-
 lisp/imenu.el                                      |    8 +-
 lisp/indent.el                                     |   11 +-
 lisp/info-look.el                                  |    4 +-
 lisp/info.el                                       |   18 +-
 lisp/informat.el                                   |    2 +-
 lisp/international/characters.el                   |   23 +-
 lisp/international/emoji.el                        |   50 +-
 lisp/international/iso-transl.el                   |   30 +-
 lisp/international/ja-dic-utl.el                   |    8 +-
 lisp/international/latin1-disp.el                  |    2 +
 lisp/international/mule-cmds.el                    |   10 +-
 lisp/international/mule-diag.el                    |   62 +-
 lisp/international/quail.el                        |    8 +-
 lisp/international/titdic-cnv.el                   |    7 +-
 lisp/isearch.el                                    |  314 +-
 lisp/jit-lock.el                                   |   23 +-
 lisp/jsonrpc.el                                    |   12 +-
 lisp/keymap.el                                     |   37 +-
 lisp/kmacro.el                                     |  129 +-
 lisp/language/european.el                          |    2 +-
 lisp/language/ind-util.el                          |   16 +-
 lisp/language/indian.el                            |    2 +-
 lisp/language/misc-lang.el                         |    9 +-
 lisp/ldefs-boot.el                                 | 5982 +++++++++---------
 lisp/leim/quail/hangul.el                          |   33 +-
 lisp/leim/quail/indian.el                          |  310 +-
 lisp/leim/quail/persian.el                         |   90 +-
 lisp/linum.el                                      |   10 -
 lisp/loadhist.el                                   |    2 +-
 lisp/loadup.el                                     |   40 +-
 lisp/ls-lisp.el                                    |    8 -
 lisp/mail/binhex.el                                |    4 +
 lisp/mail/emacsbug.el                              |   64 +-
 lisp/mail/feedmail.el                              |    8 -
 lisp/mail/footnote.el                              |   30 +-
 lisp/mail/hashcash.el                              |   12 +-
 lisp/mail/ietf-drums.el                            |   13 +
 lisp/mail/mail-extr.el                             |  115 +-
 lisp/mail/mail-hist.el                             |    2 +-
 lisp/mail/mail-parse.el                            |    8 +-
 lisp/mail/mail-utils.el                            |   18 +-
 lisp/mail/mailabbrev.el                            |    4 +-
 lisp/mail/mailalias.el                             |   37 +-
 lisp/mail/mspools.el                               |   23 +-
 lisp/mail/rfc2047.el                               |   19 +-
 lisp/mail/rmail.el                                 |   22 +-
 lisp/mail/rmailedit.el                             |   11 +-
 lisp/mail/rmailmm.el                               |    5 +-
 lisp/mail/rmailsum.el                              |   14 +-
 lisp/mail/sendmail.el                              |   53 +-
 lisp/mail/smtpmail.el                              |   48 +-
 lisp/mail/supercite.el                             |  153 +-
 lisp/mail/uce.el                                   |  400 --
 lisp/mail/undigest.el                              |    4 -
 lisp/mail/unrmail.el                               |    2 +-
 lisp/makesum.el                                    |  109 -
 lisp/man.el                                        |   11 +-
 lisp/menu-bar.el                                   |   18 +-
 lisp/mh-e/mh-acros.el                              |   18 +-
 lisp/mh-e/mh-alias.el                              |    5 -
 lisp/mh-e/mh-buffers.el                            |    1 -
 lisp/mh-e/mh-comp.el                               |    1 -
 lisp/mh-e/mh-compat.el                             |  151 -
 lisp/mh-e/mh-e.el                                  |   34 +-
 lisp/mh-e/mh-folder.el                             |    5 +-
 lisp/mh-e/mh-funcs.el                              |    7 +-
 lisp/mh-e/mh-gnus.el                               |   12 +-
 lisp/mh-e/mh-identity.el                           |   13 +-
 lisp/mh-e/mh-inc.el                                |    1 -
 lisp/mh-e/mh-junk.el                               |    1 -
 lisp/mh-e/mh-letter.el                             |   22 +-
 lisp/mh-e/mh-limit.el                              |    1 -
 lisp/mh-e/mh-mime.el                               |   54 +-
 lisp/mh-e/mh-print.el                              |    1 -
 lisp/mh-e/mh-scan.el                               |    1 -
 lisp/mh-e/mh-search.el                             |    3 +-
 lisp/mh-e/mh-seq.el                                |    3 +-
 lisp/mh-e/mh-show.el                               |    1 -
 lisp/mh-e/mh-speed.el                              |    1 -
 lisp/mh-e/mh-thread.el                             |    1 -
 lisp/mh-e/mh-tool-bar.el                           |    1 -
 lisp/mh-e/mh-utils.el                              |   18 +-
 lisp/mh-e/mh-xface.el                              |    1 -
 lisp/midnight.el                                   |    4 +-
 lisp/minibuffer.el                                 |   98 +-
 lisp/misc.el                                       |   59 +-
 lisp/mouse.el                                      |   37 +-
 lisp/mpc.el                                        |   91 +-
 lisp/msb.el                                        |    9 +-
 lisp/mwheel.el                                     |   50 +-
 lisp/net/ange-ftp.el                               |   18 +-
 lisp/net/browse-url.el                             |  119 +-
 lisp/net/dbus.el                                   |    4 +-
 lisp/net/dictionary.el                             |   75 +-
 lisp/net/dig.el                                    |   72 +-
 lisp/net/eudc-capf.el                              |    2 +-
 lisp/net/eudc-export.el                            |    2 +-
 lisp/net/eudc-hotlist.el                           |   31 +-
 lisp/net/eudc-vars.el                              |   18 +-
 lisp/net/eudc.el                                   |   72 +-
 lisp/net/eudcb-ldap.el                             |   12 +-
 lisp/net/eudcb-macos-contacts.el                   |  201 +-
 lisp/net/eww.el                                    |   26 +-
 lisp/net/imap.el                                   |    9 +-
 lisp/net/ldap.el                                   |    4 +-
 lisp/net/mailcap.el                                |    7 +-
 lisp/net/mairix.el                                 |   29 +-
 lisp/net/net-utils.el                              |  125 +-
 lisp/net/netrc.el                                  |  238 -
 lisp/net/newst-backend.el                          |    9 +-
 lisp/net/newst-plainview.el                        |   17 +-
 lisp/net/newst-reader.el                           |   10 +-
 lisp/net/newst-treeview.el                         |  105 +-
 lisp/net/pop3.el                                   |    6 +-
 lisp/net/quickurl.el                               |  525 --
 lisp/net/rcirc.el                                  |  109 +-
 lisp/net/rlogin.el                                 |  313 -
 lisp/net/secrets.el                                |   15 +-
 lisp/net/shr.el                                    |  131 +-
 lisp/net/sieve-manage.el                           |    2 +-
 lisp/net/sieve-mode.el                             |   12 +-
 lisp/net/sieve.el                                  |   52 +-
 lisp/net/snmp-mode.el                              |   14 +-
 lisp/net/socks.el                                  |    9 +-
 lisp/net/telnet.el                                 |   31 +-
 lisp/net/tramp-adb.el                              |  675 +--
 lisp/net/tramp-archive.el                          |   67 +-
 lisp/net/tramp-cache.el                            |  183 +-
 lisp/net/tramp-cmds.el                             |   62 +-
 lisp/net/tramp-compat.el                           |   71 +-
 lisp/net/tramp-crypt.el                            |  244 +-
 lisp/net/tramp-ftp.el                              |   21 +-
 lisp/net/tramp-fuse.el                             |   61 +-
 lisp/net/tramp-gvfs.el                             |  455 +-
 lisp/net/tramp-integration.el                      |   15 +-
 lisp/net/tramp-rclone.el                           |   89 +-
 lisp/net/tramp-sh.el                               | 2048 +++----
 lisp/net/tramp-smb.el                              | 1077 ++--
 lisp/net/tramp-sshfs.el                            |   17 +-
 lisp/net/tramp-sudoedit.el                         |  219 +-
 lisp/net/tramp.el                                  | 1358 +++--
 lisp/net/trampver.el                               |   10 +-
 lisp/net/webjump.el                                |   46 +-
 lisp/nxml/nxml-mode.el                             |   48 +-
 lisp/nxml/nxml-outln.el                            |   54 +-
 lisp/nxml/nxml-parse.el                            |    2 +-
 lisp/nxml/rng-dt.el                                |    2 +-
 lisp/nxml/rng-loc.el                               |    8 +-
 lisp/nxml/rng-match.el                             |    2 +-
 lisp/nxml/rng-parse.el                             |    2 +-
 lisp/nxml/rng-util.el                              |   15 +-
 lisp/nxml/rng-valid.el                             |    8 +-
 lisp/obsolete/abbrevlist.el                        |   56 -
 lisp/obsolete/assoc.el                             |  140 -
 lisp/obsolete/autoload.el                          |  915 +++
 lisp/obsolete/complete.el                          | 1122 ----
 lisp/obsolete/cust-print.el                        |  674 ---
 lisp/obsolete/eieio-compat.el                      |   21 +-
 lisp/obsolete/erc-hecomplete.el                    |  218 -
 lisp/obsolete/fast-lock.el                         |  730 ---
 lisp/obsolete/gs.el                                |    2 +-
 lisp/obsolete/info-edit.el                         |   12 +-
 lisp/obsolete/lazy-lock.el                         | 1025 ----
 lisp/obsolete/longlines.el                         |  133 +-
 lisp/obsolete/mailpost.el                          |  101 -
 lisp/obsolete/makesum.el                           |  107 +
 lisp/obsolete/mh-compat.el                         |  136 +
 lisp/obsolete/mouse-sel.el                         |  731 ---
 lisp/obsolete/netrc.el                             |  245 +
 lisp/obsolete/old-emacs-lock.el                    |  102 -
 lisp/obsolete/patcomp.el                           |   24 -
 lisp/obsolete/pc-mode.el                           |   56 -
 lisp/obsolete/pc-select.el                         |  410 --
 lisp/obsolete/ps-def.el                            |   54 +
 lisp/obsolete/quickurl.el                          |  524 ++
 lisp/obsolete/rcompile.el                          |    2 +-
 lisp/obsolete/rlogin.el                            |  307 +
 lisp/obsolete/s-region.el                          |  123 -
 lisp/obsolete/sregex.el                            |  605 --
 lisp/obsolete/starttls.el                          |    3 -
 lisp/obsolete/tpu-extras.el                        |    2 +-
 lisp/obsolete/uce.el                               |  401 ++
 lisp/obsolete/url-about.el                         |  104 +
 lisp/obsolete/url-dired.el                         |   58 +
 lisp/org/ChangeLog.1                               |    4 +-
 lisp/org/ob-comint.el                              |    2 +-
 lisp/org/ob-core.el                                |   29 +-
 lisp/org/ob-julia.el                               |    7 +-
 lisp/org/ob-lilypond.el                            |    3 +-
 lisp/org/ob-octave.el                              |    2 +-
 lisp/org/ob-tangle.el                              |    5 +-
 lisp/org/oc-basic.el                               |   23 +-
 lisp/org/oc.el                                     |   25 +-
 lisp/org/ol-doi.el                                 |    2 +-
 lisp/org/ol-irc.el                                 |   12 +-
 lisp/org/ol.el                                     |   14 +-
 lisp/org/org-agenda.el                             |  101 +-
 lisp/org/org-capture.el                            |    2 +-
 lisp/org/org-clock.el                              |   14 +-
 lisp/org/org-compat.el                             |   25 +-
 lisp/org/org-element.el                            |   11 +-
 lisp/org/org-feed.el                               |    2 +-
 lisp/org/org-habit.el                              |    2 +-
 lisp/org/org-inlinetask.el                         |    6 +-
 lisp/org/org-lint.el                               |    6 +-
 lisp/org/org-list.el                               |   72 +-
 lisp/org/org-macs.el                               |    4 +-
 lisp/org/org-mobile.el                             |   12 +-
 lisp/org/org-mouse.el                              |    8 +-
 lisp/org/org-plot.el                               |   18 +-
 lisp/org/org-refile.el                             |    4 +-
 lisp/org/org-src.el                                |    4 +-
 lisp/org/org-table.el                              |   28 +-
 lisp/org/org-version.el                            |    2 +-
 lisp/org/org.el                                    |  101 +-
 lisp/org/ox-ascii.el                               |   18 +-
 lisp/org/ox-icalendar.el                           |   12 +-
 lisp/org/ox-md.el                                  |   10 +-
 lisp/org/ox.el                                     |  177 +-
 lisp/outline.el                                    |  140 +-
 lisp/paren.el                                      |    3 +-
 lisp/pcmpl-unix.el                                 |   14 +-
 lisp/pgtk-dnd.el                                   |  410 ++
 lisp/pixel-scroll.el                               |   98 +-
 lisp/play/5x5.el                                   |   12 +-
 lisp/play/bubbles.el                               |    9 +-
 lisp/play/cookie1.el                               |    3 +-
 lisp/play/decipher.el                              |    2 +-
 lisp/play/doctor.el                                |   24 +-
 lisp/play/dunnet.el                                |    2 +-
 lisp/play/fortune.el                               |   56 +-
 lisp/play/gamegrid.el                              |   36 +-
 lisp/play/gomoku.el                                |    5 +-
 lisp/play/hanoi.el                                 |   44 +-
 lisp/play/mpuz.el                                  |    2 +-
 lisp/play/spook.el                                 |    2 +-
 lisp/play/tetris.el                                |   35 +-
 lisp/plstore.el                                    |    1 +
 lisp/printing.el                                   |   78 +-
 lisp/profiler.el                                   |    2 +-
 lisp/progmodes/antlr-mode.el                       |    9 +-
 lisp/progmodes/autoconf.el                         |    2 +-
 lisp/progmodes/bug-reference.el                    |    2 +-
 lisp/progmodes/cc-awk.el                           |    2 +-
 lisp/progmodes/cc-cmds.el                          |   14 +-
 lisp/progmodes/cc-defs.el                          |   82 +-
 lisp/progmodes/cc-engine.el                        |  107 +-
 lisp/progmodes/cc-fonts.el                         |  103 +-
 lisp/progmodes/cc-langs.el                         |   14 +-
 lisp/progmodes/cc-mode.el                          |  183 +-
 lisp/progmodes/cfengine.el                         |   13 +-
 lisp/progmodes/compile.el                          |  243 +-
 lisp/progmodes/cperl-mode.el                       |  140 +-
 lisp/progmodes/cwarn.el                            |    3 -
 lisp/progmodes/ebnf2ps.el                          |   56 +-
 lisp/progmodes/ebrowse.el                          |    2 +-
 lisp/progmodes/elisp-mode.el                       |   86 +-
 lisp/progmodes/etags.el                            |    8 +-
 lisp/progmodes/f90.el                              |    7 +-
 lisp/progmodes/flymake-proc.el                     |    5 +-
 lisp/progmodes/flymake.el                          |    4 +-
 lisp/progmodes/fortran.el                          |   12 +-
 lisp/progmodes/gdb-mi.el                           |   47 +-
 lisp/progmodes/glasses.el                          |    6 +-
 lisp/progmodes/grep.el                             |   42 +-
 lisp/progmodes/gud.el                              |   36 +-
 lisp/progmodes/hideif.el                           |    5 +-
 lisp/progmodes/hideshow.el                         |   93 +-
 lisp/progmodes/icon.el                             |    2 -
 lisp/progmodes/idlw-shell.el                       |   18 +-
 lisp/progmodes/idlwave.el                          |   50 +-
 lisp/progmodes/js.el                               |   59 +-
 lisp/progmodes/make-mode.el                        |    5 +-
 lisp/progmodes/meta-mode.el                        |   76 +-
 lisp/progmodes/modula2.el                          |    5 +-
 lisp/progmodes/octave.el                           |    4 +-
 lisp/progmodes/opascal.el                          |    3 +-
 lisp/progmodes/pascal.el                           |   44 +-
 lisp/progmodes/perl-mode.el                        |    5 +-
 lisp/progmodes/project.el                          |   41 +-
 lisp/progmodes/prolog.el                           |  109 +-
 lisp/progmodes/ps-mode.el                          |    8 +-
 lisp/progmodes/python.el                           |  367 +-
 lisp/progmodes/ruby-mode.el                        |   11 +-
 lisp/progmodes/scheme.el                           |    6 +
 lisp/progmodes/sh-script.el                        |   33 +-
 lisp/progmodes/sql.el                              |   53 +-
 lisp/progmodes/tcl.el                              |    8 +-
 lisp/progmodes/verilog-mode.el                     |   26 +-
 lisp/progmodes/vhdl-mode.el                        |   22 +-
 lisp/progmodes/which-func.el                       |    6 +-
 lisp/progmodes/xref.el                             |   38 +-
 lisp/progmodes/xscheme.el                          |   23 +-
 lisp/ps-def.el                                     |  134 -
 lisp/ps-print.el                                   |  125 +-
 lisp/recentf.el                                    |  146 +-
 lisp/rect.el                                       |   58 +-
 lisp/repeat.el                                     |   44 +-
 lisp/replace.el                                    |  167 +-
 lisp/ruler-mode.el                                 |   45 +-
 lisp/savehist.el                                   |    3 +-
 lisp/saveplace.el                                  |   19 +-
 lisp/select.el                                     |  168 +-
 lisp/server.el                                     |    8 +-
 lisp/ses.el                                        |    2 +-
 lisp/shell.el                                      |   11 +-
 lisp/simple.el                                     |  386 +-
 lisp/so-long.el                                    |   62 +-
 lisp/speedbar.el                                   |   17 +-
 lisp/sqlite-mode.el                                |    1 +
 lisp/startup.el                                    |   23 +-
 lisp/strokes.el                                    |    4 +-
 lisp/subr.el                                       |  320 +-
 lisp/tab-bar.el                                    |  154 +-
 lisp/tab-line.el                                   |    2 +-
 lisp/tar-mode.el                                   |   78 +-
 lisp/term.el                                       |   28 +-
 lisp/term/common-win.el                            |   27 +-
 lisp/term/haiku-win.el                             |  243 +-
 lisp/term/ns-win.el                                |   13 +-
 lisp/term/pgtk-win.el                              |    7 +-
 lisp/term/w32-win.el                               |    1 -
 lisp/term/x-win.el                                 |   27 +-
 lisp/term/xterm.el                                 |    2 +-
 lisp/textmodes/artist.el                           |  171 +-
 lisp/textmodes/bib-mode.el                         |   79 +-
 lisp/textmodes/bibtex.el                           |   46 +-
 lisp/textmodes/conf-mode.el                        |   13 +-
 lisp/textmodes/css-mode.el                         |    2 +-
 lisp/textmodes/dns-mode.el                         |   26 +-
 lisp/textmodes/emacs-authors-mode.el               |  145 +
 lisp/textmodes/emacs-news-mode.el                  |   69 +-
 lisp/textmodes/etc-authors-mode.el                 |  133 -
 lisp/textmodes/fill.el                             |    4 +-
 lisp/textmodes/flyspell.el                         |   56 +-
 lisp/textmodes/ispell.el                           |   81 +-
 lisp/textmodes/nroff-mode.el                       |   23 +-
 lisp/textmodes/page-ext.el                         |   15 +-
 lisp/textmodes/paragraphs.el                       |   30 +-
 lisp/textmodes/picture.el                          |    1 -
 lisp/textmodes/refbib.el                           |   11 +-
 lisp/textmodes/reftex-cite.el                      |   52 +-
 lisp/textmodes/reftex-index.el                     |   19 +-
 lisp/textmodes/reftex-ref.el                       |    6 +-
 lisp/textmodes/reftex-sel.el                       |   16 +-
 lisp/textmodes/reftex-toc.el                       |   47 +-
 lisp/textmodes/reftex-vars.el                      |    2 +-
 lisp/textmodes/remember.el                         |    7 +-
 lisp/textmodes/rst.el                              |  199 +-
 lisp/textmodes/sgml-mode.el                        |   61 +-
 lisp/textmodes/tex-mode.el                         |   41 +-
 lisp/textmodes/texinfo.el                          |   11 +-
 lisp/textmodes/texnfo-upd.el                       |    2 +-
 lisp/textmodes/text-mode.el                        |   16 +-
 lisp/textmodes/tildify.el                          |    5 +-
 lisp/thingatpt.el                                  |   15 +-
 lisp/thumbs.el                                     |  104 +-
 lisp/time.el                                       |    4 +-
 lisp/tool-bar.el                                   |    4 +-
 lisp/tooltip.el                                    |   11 +-
 lisp/transient.el                                  | 1004 +--
 lisp/type-break.el                                 |   38 +-
 lisp/uniquify.el                                   |    5 +-
 lisp/url/url-about.el                              |  103 -
 lisp/url/url-cache.el                              |    2 +-
 lisp/url/url-cookie.el                             |    2 +-
 lisp/url/url-dired.el                              |   57 -
 lisp/url/url-file.el                               |   11 +-
 lisp/url/url-history.el                            |    2 +-
 lisp/url/url-http.el                               |   23 +-
 lisp/url/url-privacy.el                            |   11 +-
 lisp/url/url-queue.el                              |    4 +-
 lisp/url/url-tramp.el                              |   50 +-
 lisp/url/url-util.el                               |   41 +-
 lisp/url/url-vars.el                               |    7 +-
 lisp/url/url.el                                    |    2 +-
 lisp/vc/add-log.el                                 |   17 +-
 lisp/vc/compare-w.el                               |    5 +-
 lisp/vc/diff-mode.el                               |   34 +-
 lisp/vc/ediff-help.el                              |    6 +-
 lisp/vc/ediff-hook.el                              |   14 +-
 lisp/vc/ediff-init.el                              |  150 +-
 lisp/vc/ediff-mult.el                              |   42 +-
 lisp/vc/ediff-ptch.el                              |    4 +-
 lisp/vc/ediff-util.el                              |  100 +-
 lisp/vc/ediff-wind.el                              |   42 +-
 lisp/vc/ediff.el                                   |   16 +-
 lisp/vc/emerge.el                                  |    8 +-
 lisp/vc/pcvs-util.el                               |    8 +-
 lisp/vc/vc-annotate.el                             |   33 +-
 lisp/vc/vc-bzr.el                                  |   32 +-
 lisp/vc/vc-cvs.el                                  |    2 +-
 lisp/vc/vc-dir.el                                  |   16 +-
 lisp/vc/vc-dispatcher.el                           |   37 +-
 lisp/vc/vc-git.el                                  |   57 +-
 lisp/vc/vc-hg.el                                   |   17 +-
 lisp/vc/vc-hooks.el                                |   75 +-
 lisp/vc/vc-svn.el                                  |   10 +-
 lisp/vc/vc.el                                      |    6 +-
 lisp/vcursor.el                                    |    9 +-
 lisp/view.el                                       |   70 +-
 lisp/wdired.el                                     |   97 +-
 lisp/whitespace.el                                 |   87 +-
 lisp/wid-browse.el                                 |    9 +-
 lisp/wid-edit.el                                   |    9 +-
 lisp/widget.el                                     |    1 -
 lisp/windmove.el                                   |   20 +-
 lisp/window.el                                     |   50 +-
 lisp/winner.el                                     |    9 +-
 lisp/woman.el                                      |   28 +-
 lisp/x-dnd.el                                      | 1151 +++-
 lisp/xdg.el                                        |   17 +-
 lisp/xwidget.el                                    |   21 +-
 lwlib/lwlib-Xaw.c                                  |    2 +
 lwlib/xlwmenu.c                                    |  455 +-
 lwlib/xlwmenu.h                                    |    4 +
 lwlib/xlwmenuP.h                                   |   18 +-
 m4/fchmodat.m4                                     |    4 +-
 m4/gnulib-common.m4                                |    3 +-
 m4/gnulib-comp.m4                                  |   22 +
 m4/largefile.m4                                    |    7 +-
 m4/lchmod.m4                                       |    6 +-
 m4/sys_stat_h.m4                                   |    6 +-
 m4/year2038.m4                                     |   10 +-
 make-dist                                          |    4 +-
 msdos/sedlibmk.inp                                 |    5 +
 nextstep/Makefile.in                               |    7 +-
 src/.lldbinit                                      |   33 +
 src/Makefile.in                                    |   29 +-
 src/alloc.c                                        |   23 +-
 src/bidi.c                                         |   42 +-
 src/buffer.c                                       |  112 +-
 src/buffer.h                                       |   22 +-
 src/bytecode.c                                     |   16 +-
 src/callint.c                                      |  122 +-
 src/callproc.c                                     |   41 +-
 src/character.c                                    |   66 +-
 src/character.h                                    |    5 +-
 src/charset.c                                      |    5 +-
 src/coding.c                                       |   16 +-
 src/comp.c                                         |   27 +-
 src/composite.c                                    |  121 +-
 src/conf_post.h                                    |    2 +-
 src/data.c                                         |   36 +-
 src/dired.c                                        |   63 +-
 src/dispextern.h                                   |   67 +-
 src/dispnew.c                                      |   29 +-
 src/doc.c                                          |    6 +-
 src/editfns.c                                      |  223 +-
 src/emacs.c                                        |   40 +-
 src/eval.c                                         |   86 +-
 src/fileio.c                                       |   29 +-
 src/fns.c                                          |  583 +-
 src/font.c                                         |   10 +-
 src/frame.c                                        |  102 +-
 src/fringe.c                                       |   15 +
 src/ftcrfont.c                                     |    8 +-
 src/gnutls.c                                       |   32 +-
 src/gtkutil.c                                      |    2 +
 src/haiku_draw_support.cc                          |  202 +-
 src/haiku_font_support.cc                          |   23 +
 src/haiku_io.c                                     |    2 +
 src/haiku_select.cc                                |  141 +-
 src/haiku_support.cc                               |  451 +-
 src/haiku_support.h                                |   35 +-
 src/haikufns.c                                     |   57 +-
 src/haikufont.c                                    |  164 +-
 src/haikumenu.c                                    |    9 +-
 src/haikuselect.c                                  |  150 +-
 src/haikuselect.h                                  |   13 +-
 src/haikuterm.c                                    |  225 +-
 src/haikuterm.h                                    |    8 +-
 src/image.c                                        |  314 +-
 src/indent.c                                       |   91 +-
 src/inotify.c                                      |    2 +-
 src/insdel.c                                       |   19 +-
 src/intervals.c                                    |    4 +-
 src/json.c                                         |    6 +-
 src/keyboard.c                                     |  336 +-
 src/keyboard.h                                     |    6 +-
 src/keymap.c                                       |   24 +-
 src/kqueue.c                                       |    4 +-
 src/lisp.h                                         |   64 +-
 src/lread.c                                        |  193 +-
 src/macfont.m                                      |    7 +-
 src/marker.c                                       |    5 +-
 src/minibuf.c                                      |   65 +-
 src/nsfns.m                                        |   36 +-
 src/nsfont.m                                       |    5 +-
 src/nsimage.m                                      |    2 +-
 src/nsmenu.m                                       |    2 -
 src/nsselect.m                                     |    2 +-
 src/nsterm.h                                       |   10 +
 src/nsterm.m                                       |  240 +-
 src/pdumper.c                                      |   13 +-
 src/pgtkfns.c                                      |   40 +-
 src/pgtkmenu.c                                     |    2 -
 src/pgtkselect.c                                   | 1983 +++++-
 src/pgtkselect.h                                   |   31 -
 src/pgtkterm.c                                     |  436 +-
 src/pgtkterm.h                                     |  181 +-
 src/print.c                                        |  361 +-
 src/process.c                                      |  429 +-
 src/process.h                                      |    5 +-
 src/puresize.h                                     |    2 +-
 src/regex-emacs.c                                  |   30 +
 src/search.c                                       |   51 +-
 src/sheap.h                                        |    2 +-
 src/sound.c                                        |    8 +-
 src/sqlite.c                                       |    6 +-
 src/syntax.c                                       |    9 +
 src/sysdep.c                                       |   49 +-
 src/systime.h                                      |    3 +
 src/term.c                                         |   22 +-
 src/termhooks.h                                    |   31 +-
 src/terminal.c                                     |   12 +-
 src/textprop.c                                     |   14 +-
 src/timefns.c                                      |  180 +-
 src/undo.c                                         |    2 +-
 src/w32.c                                          |   79 +-
 src/w32fns.c                                       |   43 +-
 src/w32image.c                                     |    4 +-
 src/w32proc.c                                      |   17 +-
 src/w32select.c                                    |    2 +-
 src/w32term.c                                      |    2 +
 src/window.c                                       |   79 +-
 src/window.h                                       |   11 +-
 src/xdisp.c                                        |  970 ++-
 src/xfaces.c                                       |  238 +-
 src/xfns.c                                         |  437 +-
 src/xmenu.c                                        |  135 +-
 src/xml.c                                          |   16 +-
 src/xselect.c                                      |  337 +-
 src/xsettings.c                                    |    7 +-
 src/xsettings.h                                    |    2 +-
 src/xterm.c                                        | 6359 ++++++++++++++------
 src/xterm.h                                        |  242 +-
 test/ChangeLog.1                                   |    2 +-
 test/Makefile.in                                   |   21 +-
 .../authinfo                                       |    0
 .../netrc-folding                                  |    0
 test/lisp/auth-source-tests.el                     |   26 +-
 test/lisp/autorevert-tests.el                      |    2 +-
 test/lisp/bookmark-tests.el                        |    8 +-
 test/lisp/calc/calc-tests.el                       |    6 +-
 test/lisp/calendar/icalendar-tests.el              |   18 +-
 test/lisp/calendar/todo-mode-tests.el              |   10 +-
 test/lisp/cedet/cedet-files-tests.el               |   17 +-
 test/lisp/cedet/semantic-utest-c.el                |    8 +-
 .../semantic-utest-ia-resources/teststruct.cpp     |    2 +-
 test/lisp/cedet/semantic-utest-ia.el               |   12 +-
 test/lisp/cedet/semantic-utest.el                  |    6 +-
 test/lisp/cedet/srecode/document-tests.el          |    2 -
 test/lisp/comint-tests.el                          |    4 -
 test/lisp/custom-tests.el                          |    1 +
 test/lisp/dired-aux-tests.el                       |   13 +
 test/lisp/dired-tests.el                           |    4 +-
 test/lisp/dired-x-tests.el                         |   13 -
 test/lisp/dnd-tests.el                             |   72 +-
 test/lisp/emacs-lisp/backtrace-tests.el            |    6 +-
 test/lisp/emacs-lisp/bindat-tests.el               |   16 +-
 .../emacs-lisp/bytecomp-resources/fun-attr-warn.el |  266 +
 .../bytecomp-resources/no-byte-compile.el          |    1 +
 test/lisp/emacs-lisp/bytecomp-tests.el             |   78 +-
 test/lisp/emacs-lisp/cconv-tests.el                |    1 +
 test/lisp/emacs-lisp/edebug-tests.el               |    9 +
 test/lisp/emacs-lisp/find-func-tests.el            |    4 +-
 test/lisp/emacs-lisp/icons-tests.el                |   63 +
 test/lisp/emacs-lisp/lisp-mode-tests.el            |   25 +
 test/lisp/emacs-lisp/oclosure-tests.el             |    1 +
 test/lisp/emacs-lisp/package-tests.el              |   15 +
 test/lisp/emacs-lisp/seq-tests.el                  |   68 +-
 test/lisp/emacs-lisp/subr-x-tests.el               |   35 +-
 test/lisp/emacs-lisp/syntax-tests.el               |    4 -
 test/lisp/emacs-lisp/text-property-search-tests.el |   25 +-
 test/lisp/env-tests.el                             |   40 +
 test/lisp/erc/erc-join-tests.el                    |  361 ++
 test/lisp/erc/erc-networks-tests.el                | 1707 ++++++
 test/lisp/erc/erc-scenarios-auth-source.el         |  178 +
 .../erc/erc-scenarios-base-association-nick.el     |  163 +
 .../erc/erc-scenarios-base-association-samenet.el  |  144 +
 test/lisp/erc/erc-scenarios-base-association.el    |  192 +
 .../erc-scenarios-base-compat-rename-bouncer.el    |  171 +
 .../erc/erc-scenarios-base-misc-regressions.el     |  126 +
 .../erc/erc-scenarios-base-netid-bouncer-id.el     |   34 +
 .../erc-scenarios-base-netid-bouncer-recon-base.el |   30 +
 .../erc-scenarios-base-netid-bouncer-recon-both.el |   32 +
 .../erc-scenarios-base-netid-bouncer-recon-id.el   |   35 +
 test/lisp/erc/erc-scenarios-base-netid-bouncer.el  |   35 +
 test/lisp/erc/erc-scenarios-base-netid-samenet.el  |  147 +
 test/lisp/erc/erc-scenarios-base-reconnect.el      |  226 +
 test/lisp/erc/erc-scenarios-base-renick.el         |  305 +
 test/lisp/erc/erc-scenarios-base-reuse-buffers.el  |  238 +
 test/lisp/erc/erc-scenarios-base-unstable.el       |  134 +
 .../erc/erc-scenarios-base-upstream-recon-soju.el  |   43 +
 .../erc/erc-scenarios-base-upstream-recon-znc.el   |   43 +
 test/lisp/erc/erc-scenarios-internal.el            |   27 +
 test/lisp/erc/erc-scenarios-join-auth-source.el    |   67 +
 .../lisp/erc/erc-scenarios-join-netid-newcmd-id.el |   50 +
 test/lisp/erc/erc-scenarios-join-netid-newcmd.el   |   37 +
 test/lisp/erc/erc-scenarios-join-netid-recon-id.el |   46 +
 test/lisp/erc/erc-scenarios-join-netid-recon.el    |   36 +
 test/lisp/erc/erc-scenarios-misc.el                |  180 +
 test/lisp/erc/erc-scenarios-services-misc.el       |   86 +
 test/lisp/erc/erc-services-tests.el                |  574 ++
 test/lisp/erc/erc-tests.el                         |  655 +-
 .../base/assoc/bouncer-history/barnet.eld          |   44 +
 .../base/assoc/bouncer-history/foonet.eld          |   48 +
 .../lisp/erc/resources/base/assoc/bumped/again.eld |   30 +
 .../erc/resources/base/assoc/bumped/foisted.eld    |   30 +
 .../erc/resources/base/assoc/bumped/refoisted.eld  |   31 +
 .../erc/resources/base/assoc/bumped/renicked.eld   |   30 +
 .../erc/resources/base/assoc/multi-net/barnet.eld  |   42 +
 .../erc/resources/base/assoc/multi-net/foonet.eld  |   45 +
 .../erc/resources/base/assoc/reconplay/again.eld   |   42 +
 .../erc/resources/base/assoc/reconplay/foonet.eld  |   52 +
 .../erc/resources/base/assoc/samenet/chester.eld   |   40 +
 .../erc/resources/base/assoc/samenet/tester.eld    |   42 +
 .../erc/resources/base/assoc/samenet/tester2.eld   |   39 +
 .../lisp/erc/resources/base/auth-source/foonet.eld |   23 +
 .../lisp/erc/resources/base/auth-source/nopass.eld |   22 +
 .../base/channel-buffer-revival/foonet.eld         |   45 +
 test/lisp/erc/resources/base/flood/soju.eld        |   87 +
 .../erc/resources/base/gapless-connect/barnet.eld  |   40 +
 .../erc/resources/base/gapless-connect/foonet.eld  |   41 +
 .../resources/base/gapless-connect/pass-stub.eld   |    4 +
 .../resources/base/mask-target-routing/foonet.eld  |   45 +
 .../resources/base/netid/bouncer/barnet-again.eld  |   50 +
 .../resources/base/netid/bouncer/barnet-drop.eld   |   41 +
 .../erc/resources/base/netid/bouncer/barnet.eld    |   41 +
 .../resources/base/netid/bouncer/foonet-again.eld  |   50 +
 .../resources/base/netid/bouncer/foonet-drop.eld   |   46 +
 .../erc/resources/base/netid/bouncer/foonet.eld    |   46 +
 .../resources/base/netid/bouncer/stub-again.eld    |    4 +
 .../erc/resources/base/netid/samenet/chester.eld   |   48 +
 .../erc/resources/base/netid/samenet/tester.eld    |   52 +
 .../erc/resources/base/reconnect/aborted-dupe.eld  |   28 +
 test/lisp/erc/resources/base/reconnect/aborted.eld |   45 +
 .../erc/resources/base/reconnect/options-again.eld |   45 +
 test/lisp/erc/resources/base/reconnect/options.eld |   35 +
 .../erc/resources/base/reconnect/timer-last.eld    |    6 +
 test/lisp/erc/resources/base/reconnect/timer.eld   |    6 +
 .../base/renick/queries/bouncer-barnet.eld         |   54 +
 .../base/renick/queries/bouncer-foonet.eld         |   52 +
 .../erc/resources/base/renick/queries/solo.eld     |   55 +
 test/lisp/erc/resources/base/renick/self/auto.eld  |   46 +
 .../lisp/erc/resources/base/renick/self/manual.eld |   50 +
 .../resources/base/renick/self/qual-chester.eld    |   40 +
 .../erc/resources/base/renick/self/qual-tester.eld |   46 +
 .../base/reuse-buffers/channel/barnet.eld          |   68 +
 .../base/reuse-buffers/channel/foonet.eld          |   66 +
 .../resources/base/reuse-buffers/server/barnet.eld |   24 +
 .../resources/base/reuse-buffers/server/foonet.eld |   24 +
 .../base/upstream-reconnect/soju-barnet.eld        |   64 +
 .../base/upstream-reconnect/soju-foonet.eld        |   72 +
 .../base/upstream-reconnect/znc-barnet.eld         |   93 +
 .../base/upstream-reconnect/znc-foonet.eld         |   86 +
 test/lisp/erc/resources/dcc/chat/accept-dcc.eld    |    3 +
 test/lisp/erc/resources/dcc/chat/accept.eld        |   23 +
 test/lisp/erc/resources/erc-d/erc-d-i.el           |  124 +
 test/lisp/erc/resources/erc-d/erc-d-t.el           |  170 +
 test/lisp/erc/resources/erc-d/erc-d-tests.el       | 1373 +++++
 test/lisp/erc/resources/erc-d/erc-d-u.el           |  213 +
 test/lisp/erc/resources/erc-d/erc-d.el             | 1009 ++++
 test/lisp/erc/resources/erc-d/resources/basic.eld  |   32 +
 .../erc/resources/erc-d/resources/depleted.eld     |   12 +
 test/lisp/erc/resources/erc-d/resources/drop-a.eld |    4 +
 test/lisp/erc/resources/erc-d/resources/drop-b.eld |    4 +
 .../resources/erc-d/resources/dynamic-barnet.eld   |   33 +
 .../resources/erc-d/resources/dynamic-foonet.eld   |   32 +
 .../erc/resources/erc-d/resources/dynamic-stub.eld |    4 +
 .../lisp/erc/resources/erc-d/resources/dynamic.eld |   30 +
 test/lisp/erc/resources/erc-d/resources/eof.eld    |   33 +
 .../lisp/erc/resources/erc-d/resources/foreign.eld |    5 +
 test/lisp/erc/resources/erc-d/resources/fuzzy.eld  |   42 +
 .../erc/resources/erc-d/resources/incremental.eld  |   43 +
 .../resources/erc-d/resources/irc-parser-tests.eld |  380 ++
 .../resources/erc-d/resources/linger-multi-a.eld   |    3 +
 .../resources/erc-d/resources/linger-multi-b.eld   |    3 +
 test/lisp/erc/resources/erc-d/resources/linger.eld |   33 +
 .../erc/resources/erc-d/resources/no-block.eld     |   55 +
 .../erc/resources/erc-d/resources/no-match.eld     |   32 +
 .../lisp/erc/resources/erc-d/resources/no-pong.eld |   27 +
 .../erc/resources/erc-d/resources/nonstandard.eld  |    6 +
 .../erc/resources/erc-d/resources/proxy-barnet.eld |   24 +
 .../erc/resources/erc-d/resources/proxy-foonet.eld |   24 +
 .../erc/resources/erc-d/resources/proxy-solo.eld   |    9 +
 .../resources/erc-d/resources/proxy-subprocess.el  |   45 +
 .../lisp/erc/resources/erc-d/resources/timeout.eld |   27 +
 .../erc/resources/erc-d/resources/unexpected.eld   |   28 +
 test/lisp/erc/resources/erc-scenarios-common.el    |  516 ++
 .../lisp/erc/resources/join/auth-source/foonet.eld |   33 +
 test/lisp/erc/resources/join/legacy/foonet.eld     |   38 +
 test/lisp/erc/resources/join/network-id/barnet.eld |   43 +
 .../erc/resources/join/network-id/foonet-again.eld |   46 +
 test/lisp/erc/resources/join/network-id/foonet.eld |   39 +
 .../erc/resources/join/reconnect/foonet-again.eld  |   45 +
 test/lisp/erc/resources/join/reconnect/foonet.eld  |   45 +
 .../networks/announced-missing/foonet.eld          |    8 +
 .../erc/resources/services/auth-source/libera.eld  |   49 +
 .../erc/resources/services/password/libera.eld     |   49 +
 test/lisp/eshell/em-alias-tests.el                 |   87 +
 test/lisp/eshell/em-basic-tests.el                 |   18 +-
 test/lisp/eshell/em-dirs-tests.el                  |  102 +
 test/lisp/eshell/em-extpipe-tests.el               |   19 +-
 test/lisp/eshell/em-glob-tests.el                  |   30 +-
 test/lisp/eshell/em-pred-tests.el                  |   28 +-
 test/lisp/eshell/em-script-tests.el                |   62 +
 test/lisp/eshell/esh-cmd-tests.el                  |  275 +
 test/lisp/eshell/esh-proc-tests.el                 |   52 +-
 test/lisp/eshell/esh-var-tests.el                  |  513 +-
 test/lisp/eshell/eshell-tests-helpers.el           |   59 +-
 test/lisp/eshell/eshell-tests.el                   |  135 +-
 test/lisp/ffap-tests.el                            |   24 +
 test/lisp/filenotify-tests.el                      |    4 -
 test/lisp/files-tests.el                           |   10 +-
 test/lisp/gnus/message-tests.el                    |    8 +-
 test/lisp/help-fns-tests.el                        |    6 +-
 test/lisp/help-tests.el                            |   54 +-
 test/lisp/ibuffer-tests.el                         |    6 +-
 test/lisp/info-xref-tests.el                       |    3 +-
 test/lisp/international/ccl-tests.el               |   36 +-
 test/lisp/international/ucs-normalize-tests.el     |    2 +-
 test/lisp/isearch-tests.el                         |   80 +
 test/lisp/json-tests.el                            |    4 +-
 test/lisp/mail/footnote-tests.el                   |    2 +-
 test/lisp/mail/mail-extr-tests.el                  |   41 +
 test/lisp/mh-e/mh-utils-tests.el                   |    4 +-
 test/lisp/misc-tests.el                            |   54 +
 test/lisp/net/browse-url-tests.el                  |    2 +-
 test/lisp/net/netrc-resources/services             |    6 -
 test/lisp/net/netrc-tests.el                       |   60 -
 test/lisp/net/shr-tests.el                         |   15 +
 test/lisp/net/tramp-archive-tests.el               |   53 +-
 test/lisp/net/tramp-tests.el                       |  640 +-
 test/lisp/obsolete/inversion-tests.el              |    1 -
 test/lisp/{ => obsolete}/makesum-tests.el          |    0
 test/lisp/progmodes/autoconf-tests.el              |    8 +-
 test/lisp/progmodes/compile-tests.el               |    5 +-
 test/lisp/progmodes/cperl-mode-tests.el            |    3 +-
 test/lisp/progmodes/elisp-mode-tests.el            |   12 +-
 test/lisp/progmodes/f90-tests.el                   |    4 +-
 test/lisp/progmodes/hideshow-tests.el              |  268 +
 test/lisp/progmodes/python-tests.el                |  842 ++-
 test/lisp/replace-tests.el                         |    4 +-
 test/lisp/saveplace-tests.el                       |    2 +-
 test/lisp/shadowfile-tests.el                      |    4 -
 test/lisp/simple-tests.el                          |   20 +-
 test/lisp/so-long-tests/so-long-tests.el           |    4 +-
 test/lisp/so-long-tests/spelling-tests.el          |    2 +-
 test/lisp/subr-tests.el                            |   53 +-
 test/lisp/textmodes/conf-mode-tests.el             |    5 +-
 test/lisp/textmodes/css-mode-tests.el              |    8 +-
 .../emacs-news-mode-resources/toggle-tag.erts      |  131 +
 test/lisp/textmodes/emacs-news-mode-tests.el       |   32 +
 test/lisp/textmodes/fill-tests.el                  |    8 +-
 test/lisp/textmodes/reftex-tests.el                |  135 +-
 test/lisp/time-stamp-tests.el                      |   23 +-
 test/lisp/url/url-tramp-tests.el                   |   16 +-
 test/lisp/url/url-util-tests.el                    |   20 +
 test/lisp/whitespace-tests.el                      |    5 +-
 test/lisp/x-dnd-tests.el                           |  128 +-
 test/lisp/xml-tests.el                             |    4 -
 test/lisp/xt-mouse-tests.el                        |   50 +-
 test/manual/etags/ETAGS.good_1                     |  280 +-
 test/manual/etags/ETAGS.good_2                     |  376 +-
 test/manual/etags/ETAGS.good_3                     |  280 +-
 test/manual/etags/ETAGS.good_4                     |  280 +-
 test/manual/etags/ETAGS.good_5                     |  376 +-
 test/manual/etags/ETAGS.good_6                     |  376 +-
 test/manual/etags/cp-src/clheir.hpp                |    2 +-
 test/manual/etags/merc-src/accumulator.m           |    2 +-
 test/manual/etags/prol-src/natded.prolog           |    2 +-
 test/manual/image-circular-tests.el                |   17 +-
 test/manual/indent/perl.perl                       |    2 +-
 test/manual/process-callout-tests.el               |   64 +
 test/src/buffer-tests.el                           |   28 +-
 test/src/callint-tests.el                          |   13 +
 test/src/coding-tests.el                           |   25 +-
 test/src/comp-resources/comp-test-funcs.el         |    2 +
 test/src/comp-tests.el                             |   10 +-
 test/src/data-tests.el                             |   17 +-
 test/src/fileio-tests.el                           |   16 +
 test/src/fns-tests.el                              |  137 +-
 test/src/font-tests.el                             |    7 +-
 test/src/image-tests.el                            |    2 +-
 test/src/json-tests.el                             |    7 +-
 test/src/keymap-tests.el                           |   34 +-
 test/src/lread-resources/lazydoc.el                |  Bin 0 -> 171 bytes
 test/src/lread-tests.el                            |   19 +-
 test/src/print-tests.el                            |   14 +-
 test/src/process-tests.el                          |  211 +-
 test/src/timefns-tests.el                          |    6 -
 test/src/undo-tests.el                             |    5 +-
 1251 files changed, 73946 insertions(+), 46722 deletions(-)

diff --git a/.dir-locals.el b/.dir-locals.el
index b313945936..7812beb001 100644
--- a/.dir-locals.el
+++ b/.dir-locals.el
@@ -4,6 +4,7 @@
 ((nil . ((tab-width . 8)
          (sentence-end-double-space . t)
          (fill-column . 70)
+        (emacs-lisp-docstring-fill-column . 65)
          (bug-reference-url-format . "https://debbugs.gnu.org/%s";)))
  (c-mode . ((c-file-style . "GNU")
             (c-noise-macro-names . ("INLINE" "ATTRIBUTE_NO_SANITIZE_UNDEFINED" 
"UNINIT" "CALLBACK" "ALIGN_STACK"))
diff --git a/.gitignore b/.gitignore
index 16f449a446..0ecbcd061f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -324,3 +324,9 @@ lib-src/seccomp-filter-exec.pfc
 
 # Ignore directory made by admin/make-manuals.
 manual/
+
+# Ignore Finder files on MacOS.
+.DS_Store
+
+# Ignore a directory used by dap-mode.
+.vscode
diff --git a/CONTRIBUTE b/CONTRIBUTE
index 614afa27db..94d757daaf 100644
--- a/CONTRIBUTE
+++ b/CONTRIBUTE
@@ -314,11 +314,45 @@ them right the first time, so here are guidelines for 
formatting them:
   with Emacs commands like 'C-x 4 a', and commit the change using the
   shell command 'vc-dwim --commit'.  Type 'vc-dwim --help' for more.
 
+** Committing your changes.
+
+When you commit changes, Git invokes several scripts that test the
+commit for validity, and may abort the commit of some of the tests
+fail.  These scripts live in the '.git/hooks/' subdirectory of the
+top-level directory of the repository, and they perform the following
+tests:
+
+- commit log message must not be empty;
+- the first line of the commit log message doesn't start with
+  whitespace characters;
+- the second line of the commit log message must be empty;
+- commit log message should include only valid printable ASCII and
+  UTF-8 characters;
+- commit log message lines must be shorter than 79 characters, unless
+  a line consists of a single long word, in which case that word can
+  be up to 140 characters long;
+- there shouldn't be any "Signed-off-by:" tags in the commit log
+  message, and "git commit" should not be invoked with the '-s' option
+  (which automatically adds "Signed-off-by:");
+- if the commit adds new files, the file names must not begin with
+  '-' and must consist of ASCII letters, digits, and characters of the
+  set [-+./_];
+- the changes don't include unresolved merge conflict markers;
+- the changes don't introduce whitespace errors: trailing whitespace,
+  lines that include nothing but whitespace characters, and indented
+  lines where a SPC character is immediately followed by a TAB in the
+  line's initial indentation
+
 ** Committing changes by others
 
 If committing changes written by someone else, commit in their name,
 not yours.  You can use 'git commit --author="AUTHOR"' to specify a
-change's author.
+change's author.  When using Emacs VC to commit, the author can be
+specified in the log-edit buffer by adding an "Author: AUTHOR" header
+line (set 'log-edit-setup-add-author' non-nil to have this header line
+added automatically).  Note that the validity checks described in the
+previous section are still applied, so you will have to correct any
+problems they uncover in the changes submitted by others.
 
 ** Branches
 
diff --git a/ChangeLog.2 b/ChangeLog.2
index cf19abaa13..5a73d53b8b 100644
--- a/ChangeLog.2
+++ b/ChangeLog.2
@@ -4040,7 +4040,7 @@
 
        * lisp/progmodes/xref.el (xref--query-replace-1):
        Say 'All results processed' at the end if the user hadn't
-       cancelled the process (bug#23284).
+       canceled the process (bug#23284).
 
 2016-05-07  Eli Zaretskii  <eliz@gnu.org>
 
@@ -12542,7 +12542,7 @@
 
        * lisp/erc/erc-backend.el (erc-server-setup-periodical-ping): Checks
        for existing timers in the alist before adding new ones.  If a
-       timer already exists, it is cancelled and
+       timer already exists, it is canceled and
        overwritten. (bug#19292).
 
 2015-12-27  Jens Lechtenboerger  <jens.lechtenboerger@fsfe.org>
@@ -22108,7 +22108,7 @@
        * src/gfilenotify.c (dir_monitor_callback): Cancel the monitor if
        the file or directory to be watched is deleted.
        (Fgfile_add_watch): Make watch_object a triple.
-       (Fgfile_rm_watch): Check, whether watch is cancelled already.
+       (Fgfile_rm_watch): Check, whether watch is canceled already.
        (Fgfile_valid_p): New defun.
        (syms_of_gfilenotify): Declare Sgfile_valid_p.
 
diff --git a/ChangeLog.3 b/ChangeLog.3
index f0297fd1f0..700a210f35 100644
--- a/ChangeLog.3
+++ b/ChangeLog.3
@@ -1,4 +1,1634 @@
-2022-04-13  Tassilo Horn  <tsdh@gnu.org>
+2022-07-31  Eli Zaretskii  <eliz@gnu.org>
+
+       * src/lisp.h (CHECK_INTEGER): Fix the predicate.  (Bug#56856)
+
+2022-07-30  Eli Zaretskii  <eliz@gnu.org>
+
+       Improve documentation of column-related functions
+
+       * doc/lispref/text.texi (Primitive Indent, Columns):
+       * src/indent.c (Fcurrent_indentation, Fmove_to_column): Document
+       that column counting ignores invisible text.  (Bug#56837)
+
+2022-07-30  YAMAMOTO Mitsuharu  <mituharu@math.s.chiba-u.ac.jp>
+
+       * src/macfont.m (macfont_open): Initialize font->space_width.  
(Bug#56808)
+
+2022-07-30  Eli Zaretskii  <eliz@gnu.org>
+
+       Improve indexing of keymap variables
+
+       * doc/lispref/maps.texi (Standard Keymaps):
+       * doc/lispref/display.texi (Button Buffer Commands)
+       (Button Properties):
+       * doc/lispref/keymaps.texi (Translation Keymaps): Improve indexing
+       of keymaps.  (Bug#56816)
+
+2022-07-29  Alan Mackenzie  <acm@muc.de>
+
+       CC Mode: fontify variables/functions after line comments ending in 
spaces
+
+       * lisp/progmodes/cc-engine.el (c-forward-comment-minus-1): Take account 
of
+       spaces preceding a linefeed when scanning a putative line comment end.
+
+2022-07-28  Stefan Kangas  <stefan@marxist.se>
+
+       Bump Emacs version to 28.1.91
+
+       * README:
+       * configure.ac:
+       * msdos/sed2v2.inp:
+       * nt/README.W32: Bump Emacs version to 28.1.91.
+
+2022-07-28  Stefan Kangas  <stefan@marxist.se>
+
+       Update ChangeLog and AUTHORS for 28.1.91 pretest
+
+       * ChangeLog.3:
+       * etc/AUTHORS: Update.
+
+2022-07-28  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       Revert the `...' documentation back to actual usage
+
+       * doc/lispref/tips.texi (Documentation Tips): Document how `...'
+       is really used now (bug#55780).  ‘...’ is not really used in the
+       Emacs sources.
+
+       (cherry picked from commit 1ed9c1c7f9fe32ff5123091033350beb1ccae4ca)
+
+2022-07-28  Paul Pogonyshev  <pogonyshev@gmail.com>
+
+       Release the desktop lock in 'kill-emacs-hook'
+
+       * lisp/desktop.el: Run 'desktop--on-kill' in 'kill-emacs-hook'.
+       (desktop--on-kill): New function, refactored from 'desktop-kill'.
+       (desktop-kill): Call 'desktop--on-kill'.  (Bug#56800)
+
+2022-07-25  Eli Zaretskii  <eliz@gnu.org>
+
+       Avoid infloop in 'recenter'
+
+       * src/window.c (Frecenter): Avoid infinite loop in the minibuffer
+       under 'fido-vertical-mode'.  (Bug#56765)
+
+2022-07-25  Eli Zaretskii  <eliz@gnu.org>
+
+       Fix inaccuracies in "lax search" documentation
+
+       * doc/emacs/search.texi (Lax Search): Update the examples of
+       character folding in search.  (Bug#56747)
+
+2022-07-24  Kyle Meyer  <kyle@kyleam.com>
+
+       Update to Org 9.5.4-17-g6e991f
+
+2022-07-24  Eugene Ha  <eha@posteo.de>  (tiny change)
+
+       Find libgccjit.dylib on Homebrew Macos
+
+       * configure.ac: Also find libggcjit on Homebrew (bug#55173).
+
+       (cherry picked from commit faa29fa2c9e9d5a5d7544a1a39b2a89cf57a8439)
+
+2022-07-23  Michael Albinus  <michael.albinus@gmx.de>
+
+       Set `default-directory' of Tramp archive connection buffer
+
+       * lisp/net/tramp-archive.el (tramp-archive-file-name-handler):
+       Set `default-directory' of Tramp connection buffer.  (Bug#56628)
+
+2022-07-23  Eli Zaretskii  <eliz@gnu.org>
+
+       Update the documentation of 'declare' forms
+
+       * doc/lispref/compile.texi (Native-Compilation Variables): Mention
+       the 'declare' alternative for 'native-comp-speed'.
+       * doc/lispref/functions.texi (Declare Form): Document 'declare'
+       forms that were previously undocumented.
+
+2022-07-23  Eli Zaretskii  <eliz@gnu.org>
+
+       Fix bookmark support for Help functions in native-compilation builds
+
+       * lisp/help.el (describe-key--helper, describe-function--helper):
+       New helper functions.
+       (describe-key): Call 'describe-key--helper' instead of a
+       lambda-function.
+       * lisp/help-fns.el (describe-function): Call
+       'describe-function--helper' instead of a lambda-function.
+       (Bug#56643)
+
+2022-07-23  Miha Rihtarsic  <miha@kamnitnik.top>
+
+       Fix mode line mouse-1 binding when showing only column numbers
+
+       * lisp/bindings.el (mode-line-position): Fix the mouse-1 binding
+       when showing only column numbers (bug#56694).  Do not merge to
+       master.
+
+2022-07-23  Stefan Kangas  <stefan@marxist.se>
+
+       Adjust help-fns.el tests for recent change
+
+       * test/lisp/help-fns-tests.el (help-fns-test-lisp-defun)
+       (help-fns-test-lisp-defsubst): Adjust tests for recent change.
+
+2022-07-22  Robert Pluim  <rpluim@gmail.com>
+
+       * src/terminal.c (Fframe_terminal): Use active voice
+
+2022-07-22  Robert Pluim  <rpluim@gmail.com>
+
+       Improve 'terminal-live-p' docstring some more
+
+       * src/terminal.c (Fterminal_live_p): Improve description of
+       arguments and return value.
+
+2022-07-22  Robert Pluim  <rpluim@gmail.com>
+
+       Improve terminal-live-p docstring
+
+       * src/terminal.c (Fterminal_live_p): Explain what happens when the
+       argument is nil.
+
+2022-07-22  Robert Pluim  <rpluim@gmail.com>
+
+       * lisp/net/tramp-gvfs.el (tramp-gvfs-dbus-event-vector): Fix grammar
+
+2022-07-21  Stefan Kangas  <stefan@marxist.se>
+
+       * lisp/progmodes/cperl-mode.el: Don't mention obsolete archive.
+
+2022-07-21  Eli Zaretskii  <eliz@gnu.org>
+
+       Make 'describe-function' say "byte-compiled" when appropriate
+
+       * lisp/help-fns.el (help-fns-function-description-header): Say
+       "byte-compiled" when describing byte-compiled functions.
+
+2022-07-21  Eli Zaretskii  <eliz@gnu.org>
+
+       ;Improve documentation of locale-specific string comparison
+
+       * doc/lispref/strings.texi (Text Comparison): Mention the Unicode
+       collation rules and buffer-local case-tables.
+
+2022-07-19  Gerd Moellmann  <gerd.moellmann@gmail.com>
+
+       Prevent GC of window referenced from EmacsScroller
+
+       * src/nsterm.m (EmacsScroller.mark, mark_nsterm): New functions.
+       * src/nsterm.h (EmacsScroller.mark, mark_nsterm): Declare.
+       * src/alloc.c (garbage_collect) [MAVE_NS]: Call mark_nsterm.
+       (Bug#56095)
+
+       (cherry picked from commit 5f1bd872478927ad4bc635502e74628d39885286)
+
+2022-07-16  Stefan Kangas  <stefan@marxist.se>
+
+       Fix obsoletion of nntp-authinfo-file
+
+       * lisp/gnus/nntp.el (nntp-authinfo-file): Fix obsoletion.
+
+2022-07-15  Philipp Stephani  <phst@google.com>
+
+       Build Seccomp filter only if we have a 64-bit userspace (Bug#56549)
+
+       * configure.ac (SIZEOF_LONG): New variable.
+       * lib-src/Makefile.in (SIZEOF_LONG): New variable; added conditional.
+
+2022-07-14  Stefan Kangas  <stefan@marxist.se>
+
+       Update the Samaritan's contact details in M-x doctor
+
+       * lisp/play/doctor.el (doctor-death): Update the Samaritans's contact
+       details; anon.twwells.com is no longer valid.  Add link to Wikipedia.
+
+2022-07-14  Eli Zaretskii  <eliz@gnu.org>
+
+       * etc/PROBLEMS: Describe problems with remote files.  (Bug#56499)
+
+2022-07-13  Andrea Corallo  <akrl@sdf.org>
+
+       Remove uneffective test
+
+       * test/src/comp-tests.el (45603-1): Remove test.
+       * test/src/comp-resources/comp-test-45603.el: Delete.
+
+2022-07-13  Andrea Corallo  <akrl@sdf.org>
+
+       Mark async worker tmp file as utf-8-emacs-unix (bug#48029)
+
+       * lisp/emacs-lisp/comp.el (comp-final): Mark async worker tmp file
+       as utf-8.
+       * test/src/comp-tests.el (48029-1): New test.
+       * test/src/comp-resources/comp-test-funcs.el
+       (comp-test-48029-nonascii-žžž-f): New function.
+
+2022-07-13  Michael Albinus  <michael.albinus@gmx.de>
+
+       Adapt Tramp version (don't merge)
+
+       * doc/misc/trampver.texi:
+       * lisp/net/trampver.el: Change version to "2.5.3.28.2".
+       (customize-package-emacs-version-alist):
+       Add Tramp version integrated in Emacs 28.2.
+
+2022-07-13  Michael Albinus  <michael.albinus@gmx.de>
+
+       Adapt Tramp doc
+
+       * doc/misc/tramp.texi (Configuration): Mention enable-remote-dir-locals.
+       (Traces and Profiles): Fix tramp-verbose description.
+
+       * lisp/net/tramp.el (tramp-verbose): Fix docstring.
+
+2022-07-12  Stefan Kangas  <stefan@marxist.se>
+
+       Don't mention cl-cXXXr aliases in cl-lib manual
+
+       * doc/misc/cl.texi (Lists, List Functions, Efficiency Concerns): Don't
+       mention 'cl-cXXXr' compatibility aliases for built-in 'cXXXr'
+       functions.  They shouldn't be used in new code.
+
+2022-07-11  Ken Brown  <kbrown@cornell.edu>
+
+       etc/PROBLEMS: Describe issues with native compilation on Cygwin
+
+2022-07-11  Stefan Kangas  <stefan@marxist.se>
+
+       * lisp/find-dired.el (find-dired): Doc fix; add crossreference.
+
+2022-07-08  Stefan Kangas  <stefan@marxist.se>
+
+       Doc fix; don't mention obsolete variable
+
+       * src/window.c (Fset_window_hscroll): Doc fix; don't mention obsolete
+       variable.
+
+2022-07-05  Stefan Kangas  <stefan@marxist.se>
+
+       Add index entry for "ignore case"
+
+       * doc/emacs/glossary.texi (Glossary): Add index entry for "ignore
+       case" pointing to "Case Folding".
+
+2022-07-05  Stefan Kangas  <stefan@marxist.se>
+
+       Expand docstrings related to auto-saving
+
+       * lisp/files.el (auto-save-visited-mode):
+       * lisp/simple.el (auto-save-mode): Expand docstring.
+
+2022-07-04  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       Don't bug out in manual-html-fix-index-2 on newer makeinfo versions
+
+       Backport from master.
+
+       * admin/admin.el (manual-html-fix-index-2): Don't bug out if the
+       makeinfo version doesn't include <ul>.
+
+       (cherry picked from commit e0e3f2b672bc42da52ac9c7596c7560a88684651)
+
+2022-07-04  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       Preserve <title> in the Emacs manuals
+
+       Backport from master.
+
+       * admin/admin.el (manual-html-fix-headers): Preserve the <title>
+       element (bug#48334).
+
+       (cherry picked from commit b778e71af7ca8c59917334b4bb1b34cdb52faca9)
+
+2022-07-03  Eli Zaretskii  <eliz@gnu.org>
+
+       Document 'jit-lock-debug-mode'
+
+       * doc/lispref/modes.texi (Other Font Lock Variables): Document
+       'jit-lock-debug-mode'.
+
+2022-07-02  Alan Mackenzie  <acm@muc.de>
+
+       * lisp/progmodes/cc-mode.el (c-common-init): Bind case-fold-search to 
nil
+
+       Backport:  This fixes bug #53605.
+
+2022-07-02  Alan Mackenzie  <acm@muc.de>
+
+       CC Mode: Fix a c-backward-token-2 call wrongly jumping back over macros.
+
+       This fixes bug #56256.
+
+       * lisp/progmodes/cc-fonts.el (c-font-lock-c++-lambda-captures): Replace 
a
+       c-backward-token-2, which could jump back too far leading to an infinite
+       loop, with a save-excursion to remember the point we've got to go back 
to.
+
+2022-07-02  Stefan Kangas  <stefan@marxist.se>
+
+       Doc fixes; don't use obsolete names
+
+       * etc/compilation.txt:
+       * lisp/mh-e/mh-funcs.el (mh-kill-folder): Don't use obsolete
+       names.
+
+2022-07-02  Stefan Kangas  <stefan@marxist.se>
+
+       Don't refer to obsolete alias for insert-char
+
+       * lisp/leim/quail/persian.el: Don't refer to obsolete alias for
+       insert-char.
+
+2022-07-02  Stefan Kangas  <stefan@marxist.se>
+
+       Don't use obsolete face name in manoj-dark-theme
+
+       * etc/themes/manoj-dark-theme.el (change-log-acknowledgment): Don't
+       use obsolete/non-existent face name.
+
+2022-07-01  Eli Zaretskii  <eliz@gnu.org>
+
+       Fix "C-u C-x =" for SPC
+
+       * lisp/descr-text.el (describe-char): Don't report 'nobreak-space'
+       face for SPC.  (Bug#56337)
+
+2022-06-30  Stefan Kangas  <stefan@marxist.se>
+
+       Doc fixes: don't refer to some obsolete items
+
+       * admin/notes/multi-tty:
+       * lisp/chistory.el (command-history):
+       * lisp/emacs-lisp/nadvice.el:
+       * lisp/vc/diff-mode.el: Doc fix; don't refer to obsolete variables and
+       functions.
+
+2022-06-30  Stefan Kangas  <stefan@marxist.se>
+
+       Remove obsolete cust-print from elisp index
+
+       * doc/lispref/edebug.texi (Printing in Edebug): Remove obsolete
+       library "cust-print" from index.
+
+2022-06-30  Stefan Kangas  <stefan@marxist.se>
+
+       * admin/make-tarball.txt: Minor clarifications.
+
+2022-06-30  Eli Zaretskii  <eliz@gnu.org>
+
+       Fix external image conversion on MS-Windows
+
+       * lisp/image/image-converter.el (image-converter--convert-magick)
+       (image-converter--convert): Force encoding/decoding to avoid any
+       text or EOL conversions, since we are reading/writing binary
+       data.  (Bug#56317)
+
+2022-06-29  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * doc/emacs/buffers.texi (Indirect Buffers): Mention modification hook 
quirk
+
+2022-06-29  Stefan Kangas  <stefan@marxist.se>
+
+       Bump Emacs version to 28.1.90
+
+       * README:
+       * configure.ac:
+       * msdos/sed2v2.inp:
+       * nt/README.W32: Bump Emacs version to 28.1.90.
+
+2022-06-29  Stefan Kangas  <stefan@marxist.se>
+
+       Update ChangeLog and AUTHORS for 28.1.90 pretest
+
+       * ChangeLog.3:
+       * etc/AUTHORS: Update.
+
+2022-06-29  Michael Albinus  <michael.albinus@gmx.de>
+
+       Update Tramp version (don't merge with master)
+
+       * doc/misc/trampver.texi:
+       * lisp/net/trampver.el: Change version to "2.5.3".
+
+2022-06-28  Michael Albinus  <michael.albinus@gmx.de>
+
+       Tramp shall not trap unrelated D-Bus errors
+
+       * lisp/net/tramp-gvfs.el (tramp-gvfs-dbus-event-vector): Declare.
+       (tramp-gvfs-file-name-handler): Let-bind it.
+       (tramp-gvfs-dbus-event-vector): Fix docstring.
+       (tramp-gvfs-maybe-open-connection): Do not set it globally.  (Bug#56162)
+
+2022-06-28  Basil L. Contovounesios  <contovob@tcd.ie>
+
+       Fix hash table function return values in manual
+
+       * doc/lispref/hash.texi (Hash Access): Reconcile documented return
+       values of puthash and clrhash with their respective
+       docstrings (bug#55562).
+
+2022-06-27  Kyle Meyer  <kyle@kyleam.com>
+
+       Update to Org 9.5.4-3-g6dc785
+
+2022-06-27  Paul Eggert  <eggert@cs.ucla.edu>
+
+       Mention Solaris 10 'make clean' and 'make check'
+
+       Mention further crashes on Solaris 10
+
+2022-06-26  Paul Eggert  <eggert@cs.ucla.edu>
+
+       Port distribution tarball to Solaris 10
+
+       * make-dist (taropt): Use 'tar -H ustar' to generate a portable
+       tar file format instead of a GNU-specific format.  Needed now that
+       Emacs tarballs contain file names longer than 100 bytes, e.g.:
+       
emacs-28.1/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/C072AF82DCCCB9A7F1B85FFA10B802DC4ED16703.key
+       
emacs-28.1/test/lisp/emacs-lisp/bytecomp-resources/error-lexical-var-with-run-hook-with-args-until-success.el
+       Without this patch, extracting a tarball on Solaris 10 fails with
+       many diagnostics like “tar: ././@LongLink: typeflag 'L' not
+       recognized, converting to regular file”.
+
+       (cherry picked from commit 4410f5d86997b6b238ff05c2ece338b28e1163b1)
+
+2022-06-24  Stefan Kangas  <stefan@marxist.se>
+
+       Avoid treating number as an enum in the org manual
+
+       * doc/misc/org.org (The Agenda Dispatcher): Avoid treating number as
+       enum.
+
+2022-06-22  Eli Zaretskii  <eliz@gnu.org>
+
+       Improve last change in autotype.texi
+
+       * doc/misc/autotype.texi (Autoinserting): Fix wording.  Suggested
+       by Richard Stallman <rms@gnu.org>.
+
+2022-06-21  Stefan Kangas  <stefan@marxist.se>
+
+       * lisp/repeat.el (repeat-mode): Fix message format.
+
+2022-06-21  Earl Hyatt  <okamsn@protonmail.com>
+
+       Clarify autotype.texi text slightly
+
+       * doc/misc/autotype.texi (Autoinserting): Make text slightly
+       clearer (bug#56118).
+
+2022-06-20  Eli Zaretskii  <eliz@gnu.org>
+
+       Support builds configured with a separate --bindir
+
+       * src/emacs.c (load_pdump): Don't overwrite the leading
+       directories of the Emacs executable just because the pdumper file
+       was not found in the expected directory relative to the binary.
+       This is needed to support builds with a separate --bindir
+       configure-time option and native-compilation.  (Bug#55741)
+
+2022-06-20  Stefan Kangas  <stefan@marxist.se>
+
+       * doc/misc/eww.texi (Overview, Basics): Fix typos.
+
+2022-06-18  Richard Hansen  <rhansen@rhansen.org>
+
+       Fix invalid defcustom :group when :predicate is used
+
+       * lisp/emacs-lisp/easy-mmode.el (define-globalized-minor-mode): Fix
+       invalid `:group' argument for the `-modes' defcustom that is created
+       when `:predicate' is used (bug#56049).
+
+2022-06-17  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       Prune the Gnus FAQ of some outdated data
+
+       * doc/misc/gnus-faq.texi (FAQ 9-2): Remove some outdated advice
+       (bug#56042).
+
+2022-06-17  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       Fix efaq-w32.texi build warning
+
+       * doc/misc/efaq-w32.texi (Other useful ports): Fix ordering to
+       match nodes (or should the nodes be moved instead?).
+
+       Do not merge to master.
+
+2022-06-17  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       Update cl-struct-sequence-type doc string
+
+       * lisp/emacs-lisp/cl-macs.el (cl-struct-sequence-type): Fix doc
+       string to reflect what it does (bug#46523).
+
+2022-06-17  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       Fix a tagging problem in tramp.texi
+
+       * doc/misc/tramp.texi (Frequently Asked Questions): Restore an
+       @end lisp removed by accident.
+
+2022-06-17  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       Mention face quirks after the final line in the lispref manual
+
+       * doc/lispref/display.texi (Face Attributes): Mention the quirks
+       about point after the final line (bug#56011).
+
+2022-06-17  Stefan Kangas  <stefan@marxist.se>
+
+       Delete reference to obsolete library complete.el
+
+       * doc/misc/tramp.texi (Frequently Asked Questions): Delete reference
+       to obsolete library complete.el.
+
+2022-06-16  Stefan Kangas  <stefan@marxist.se>
+
+       * lisp/textmodes/artist.el: Minor doc fixes.
+
+2022-06-16  Michael Albinus  <michael.albinus@gmx.de>
+
+       * lisp/net/tramp.el (tramp-methods): Fix quoting in docstring.
+
+2022-06-16  Arash Esbati  <arash@gnu.org>
+
+       Update MS Windows FAQ for MinGW64-w64/MSYS2
+
+       * doc/misc/efaq-w32.texi (Compiling, Debugging): Mention
+       MinGW64-w64/MSYS2 as the preferred way for building Emacs on
+       capable systems.
+       (Attachments with Gnus): Catch up with emacs-mime.texi in the
+       example given.
+       (Spell check): Add the availability of GNU Aspell and Hunspell
+       in MSYS2 distribution.
+       (Other useful ports): Add an entry for MinGW64-w64/MSYS2.
+       Fix link for MinGW homepage.
+       Remove entry for defunct UWIN project.  (Bug#55930)
+
+2022-06-15  Robert Pluim  <rpluim@gmail.com>
+
+       Describe 'set-file-modes' argument prompting
+
+       * src/fileio.c (Fset_file_modes): Document that FILENAME is prompted
+       for.  (Bug#55984)
+
+2022-06-14  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       Revert "Clarify what a Calc registeri in in calc-insert-register"
+
+       This reverts commit 73400e4002ce8fca060093548e6791b3a784eeaa.
+
+       This has been fixed in Emacs 29 by making it possible to use regular 
registers in calc.
+
+2022-06-13  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       Clarify what a Calc registeri in in calc-insert-register
+
+       * lisp/calc/calc-yank.el (calc-insert-register): Note that these
+       aren't normal registers (bug#55943).
+
+2022-06-11  Eli Zaretskii  <eliz@gnu.org>
+
+       Fix doc strings in whitespace.el
+
+       * lisp/whitespace.el (whitespace-style, whitespace-action):
+       Untabify the doc strings.  (Bug#55904)
+
+2022-06-10  Eli Zaretskii  <eliz@gnu.org>
+
+       Improve documentation of "etags -I"
+
+       * doc/man/etags.1:
+       * doc/emacs/maintaining.texi (Create Tags Table): Elaborate on the
+       importance of the '-I' option to 'etags'.  (Bug#45246)
+
+2022-06-09  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       Mention the #f syntax from cl-prin1
+
+       * doc/lispref/objects.texi (Special Read Syntax): Mention #f,
+       which is in cl-prin1 output (bug#55853).
+
+2022-06-09  Michael Albinus  <michael.albinus@gmx.de>
+
+       Fix file name quoting in tramp-smb.el (do not merge)
+
+       * lisp/net/tramp-smb.el (tramp-smb-handle-write-region): Quote tmpfile.
+       (tramp-smb-get-localname): Remove superfluous test.  (Bug#55855)
+
+       * test/lisp/net/tramp-tests.el (tramp-test03-file-name-method-rules):
+       Remove superfluous checks.
+
+2022-06-09  Jeff Walsh  <fejfighter@gmail.com>
+
+       Update error message to reflect variable rename
+
+       * src/comp.c (Fcomp_el_to_eln_filename): Update error message.  
(Bug#55861)
+
+2022-06-08  Ken Brown  <kbrown@cornell.edu>
+
+       Fix error reporting in process-async-https-with-delay
+
+       * test/src/process-tests.el (process-async-https-with-delay): Use
+       'plist-get' instead of 'assq' in testing for a connection error.
+       The 'status' variable is a plist, not an alist.  (Bug#55849)
+
+2022-06-08  Stefan Kangas  <stefan@marxist.se>
+
+       * doc/misc/org.org: Remove spurious markup.
+
+2022-06-08  Michael Albinus  <michael.albinus@gmx.de>
+
+       Make Tramp version check more robust
+
+       * lisp/net/trampver.el (tramp-repository-branch)
+       (tramp-repository-version): Check for "git" executable.
+
+2022-06-07  Eli Zaretskii  <eliz@gnu.org>
+
+       Fix debugging with GDB when a breakpoint has multiple locations
+
+       * lisp/progmodes/gdb-mi.el (gdb-breakpoints--add-breakpoint-row):
+       New function, extracted from 'gdb-breakpoints-list-handler-custom'.
+       Don't print "in <unknown>" for header-rows of breakpoints with
+       multiple locations that don't have a function name attached.
+       (gdb-breakpoints-list-handler-custom): Add to the breakpoint table
+       also any locations in multiple-location breakpoints, which are
+       supported since GDB 6.8.
+
+2022-06-05  Eli Zaretskii  <eliz@gnu.org>
+
+       Update documentation of 'aset' and 'store-substring'
+
+       * doc/lispref/strings.texi (Modifying Strings): Adjust to
+       implementation changes: it is possible for the modified string to
+       have fewer or more bytes than the original.  Add recommendations
+       regarding unibyte vs multibyte strings and characters.  (Bug#55801)
+
+2022-06-04  Kyle Meyer  <kyle@kyleam.com>
+
+       Update to Org 9.5.4
+
+2022-06-04  Eli Zaretskii  <eliz@gnu.org>
+
+       Clarify documentation of 'string-to-unibyte'
+
+       * doc/lispref/nonascii.texi (Converting Representations): Clarify
+       what 'string-to-unibyte' does.  Reported by Richard Hansen
+       <rhansen@rhansen.org>.  (Bug#55777)
+
+2022-06-02  Ikumi Keita  <ikumi@ikumi.que.jp>  (tiny change)
+
+       Improve keystrokes in doc strings in some find-file functions
+
+       * lisp/files.el (find-file):
+       (find-file-other-window):
+       (find-file-other-frame): Include the correct keymap so that
+       keystrokes are displayed better (bug#55761).
+
+2022-06-02  Eli Zaretskii  <eliz@gnu.org>
+
+       Fix segfaults when starting on 80x26 TTY frames
+
+       * src/dispnew.c (adjust_frame_glyphs_for_frame_redisplay): Make
+       sure we have valid frame glyph matrices for the interactive
+       session.  (Bug#55760)
+       (adjust_frame_glyphs): Add assertions for when we fail to allocate
+       valid frame glyph matrices for a TTY frame.
+
+2022-06-01  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       Make it explicit that a couple of _s in lispref are underscores
+
+       * doc/lispref/strings.texi (Custom Format Strings):
+       * doc/lispref/control.texi (pcase Macro): Make it explicit that
+       it's an underscore (bug#55742).
+
+2022-05-31  Eli Zaretskii  <eliz@gnu.org>
+
+       Remove from FAQ the MS-Windows info about BDF fonts
+
+       * doc/misc/efaq.texi (How to add fonts): Remove the MS-Windows
+       specific steps, as BDF fonts are no longer supported on
+       MS-Windows.  (Bug#55740)
+
+2022-05-31  Ikumi Keita  <ikumi@ikumi.que.jp>  (tiny change)
+
+       Fix Display Property manual example
+
+       * doc/lispref/display.texi (Display Property): Fix syntax of
+       example (bug#55736).
+
+2022-05-29  Michael Albinus  <michael.albinus@gmx.de>
+
+       Some Tramp cleanup on MS Windows
+
+       * lisp/net/tramp.el (tramp-restricted-shell-hosts-alist): Do not add
+       localhost when `tramp-encoding-shell' is a POSIX shell.
+
+       * test/lisp/net/tramp-tests.el (tramp-test31-interrupt-process):
+       Skip on MS Windows.
+
+2022-05-28  Alan Mackenzie  <acm@muc.de>
+
+       do_switch_frame: before leaving mini-window, check other (mru) window 
is live
+
+       This fixes bug#55684.  There, with a minibuffer-only frame at start up,
+       Emacs tried to switch to this frame, whose selected window was the
+       mini-window.  There is no other active window in this frame, so the
+       attempt to switch to another window failed.
+
+       * src/frame.c (do_switch_frame): On switching to a frame whose selected
+       window is as above, before selecting the most recently used window, 
check
+       this ostensible window is an actual live window.  Otherwise leave the
+       mini-window selected.
+
+2022-05-28  Eli Zaretskii  <eliz@gnu.org>
+
+       Fix commands used to produce on-line HTML docs
+
+       * admin/admin.el (manual-meta-string): Only include the first
+       line, and move the rest...
+       (manual-links-string): ...to this new string.
+       (manual-html-fix-headers): Don't remove the '<meta name=' elements
+       produced by makeinfo, especially not the 'name="viewport"' one,
+       which is essential for viewing the docs on mobile devices.
+       Reported by "Facundo Lander via RT" <webmasters-comment@gnu.org>,
+       see gnu.org ticket #1840138.
+
+2022-05-28  Eli Zaretskii  <eliz@gnu.org>
+
+       Fix a bad cross-reference in elisp.pdf
+
+       * doc/lispref/control.texi (pcase Macro): Fix a conditional
+       cross-reference (bug#55689).
+
+2022-05-28  Eli Zaretskii  <eliz@gnu.org>
+
+       Fix documentation of 'string-pad'
+
+       * doc/lispref/strings.texi (Creating Strings): Fix description of
+       'string-pad'.  (Bug#55688)
+
+2022-05-27  Juri Linkov  <juri@linkov.net>
+
+       Fix more occurrences of renamed kmacro-keymap command
+
+       * doc/emacs/kmacro.texi (Basic Keyboard Macro): Fix documentation
+       after recent kmacro-redisplay command name change.
+
+2022-05-27  Eli Zaretskii  <eliz@gnu.org>
+
+       Mention "unspecified-fg" and "unspecified-bg" in some doc strings
+
+       * lisp/faces.el (face-foreground, face-background)
+       (foreground-color-at-point, background-color-at-point):
+       * lisp/color.el (color-name-to-rgb): Mention "unspecified-fg" and
+       "unspecified-bg" pseudo-colors on TTY frames.  (Bug#55623)
+
+2022-05-26  Hayden Shenk  <hayden.shenk@zetier.com>  (tiny change)
+
+       Fix format specifiers in tramp-adb.el
+
+       * lisp/net/tramp-adb.el (tramp-adb-get-device): Fix format
+       specifiers for port.  (Bug#55651)
+
+2022-05-22  Damien Cassou  <damien@cassou.me>
+
+       Improve documentation of mail-user-agent.
+
+       * doc/emacs/sending.texi (Mail Methods):
+       * lisp/simple.el (mail-user-agent): Mention additional options
+       of non-bundled MUA.  (Bug#5569)
+
+2022-05-21  Eli Zaretskii  <eliz@gnu.org>
+
+       More fixes in abbrev.el doc strings
+
+       * lisp/abbrev.el (inverse-add-global-abbrev, inverse-add-mode-abbrev):
+       Document the effect of negative ARG.  (Bug#55527)
+
+2022-05-21  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       Add note about Tramp completion to completion-styles doc string
+
+       * lisp/minibuffer.el (completion-styles): Add note about Tramp
+       completion (bug#37954).
+
+2022-05-21  Arash Esbati  <arash@gnu.org>
+
+       Remove mention of removed nnimap-nov-is-evil variable
+
+       * doc/misc/gnus.texi (Slow/Expensive Connection): Remove mention
+       of removed nnimap-nov-is-evil variable (bug#55556).
+
+2022-05-21  Eli Zaretskii  <eliz@gnu.org>
+
+       Improve documentation strings and prompts in abbrev.el
+
+       * lisp/abbrev.el (abbrev-file-name, only-global-abbrevs)
+       (copy-abbrev-table, insert-abbrevs, list-abbrevs)
+       (abbrev-table-name, edit-abbrevs, define-abbrevs)
+       (read-abbrev-file, quietly-read-abbrev-file, write-abbrev-file)
+       (abbrev-edit-save-to-file, abbrev-edit-save-buffer)
+       (add-mode-abbrev, add-global-abbrev, inverse-add-mode-abbrev)
+       (inverse-add-global-abbrev, abbrev-prefix-mark)
+       (expand-region-abbrevs, abbrev-table-get, abbrev-table-put)
+       (abbrev-get, abbrev-minor-mode-table-alist, abbrevs-changed)
+       (abbrev-all-caps, last-abbrev-text, last-abbrev-location)
+       (clear-abbrev-table, define-abbrev, define-global-abbrev)
+       (define-mode-abbrev, abbrev--active-tables, abbrev--symbol)
+       (abbrev-symbol, abbrev-expansion, abbrev-insert)
+       (abbrev-expand-function, abbrev--suggest-above-threshold)
+       (abbrev--suggest-saved-recommendations)
+       (abbrev--suggest-shortest-abbrev, abbrev--suggest-get-totals)
+       (insert-abbrev-table-description, define-abbrev-table)
+       (abbrev-table-menu): Fix doc strings: wording, punctuation,
+       clarity.
+       (add-abbrev, inverse-add-abbrev): Improve the prompt text.
+       (Bug#55527)
+
+2022-05-20  Alan Mackenzie  <acm@muc.de>
+
+       Restore the Fselect_window call in gui_consider_frame_title.
+
+       This fixes bug #55412.  The call to Fselect_window was removed on 
2021-03-21
+       in the commit "Prevent open minibuffers getting lost when their frame 
gets
+       deleted".  This call is actually needed to determine current elements 
of the
+       pertinent window and frame when these are used in the frame title.
+
+       * src/frame.c (do_switch_frame): When the selected window in the target 
frame
+       is the mini-window, switch away from this window unless there is a valid
+       minibuffer there.
+
+       * src/frame.h (struct frame): Add an incidental comment about the 
element
+       selected_window.
+
+       * src/minibuf.c (move_minibuffers_onto_frame): No longer set the 
selected
+       window of the source frame.  This action is now performed later, on 
returning
+       to that frame, in do_switch_frame when needed (see above).
+
+       * src/xdisp.c (gui_consider_frame_title): Replace the Fselect_window 
call and
+       associated ancillary settings.
+
+2022-05-20  Eli Zaretskii  <eliz@gnu.org>
+
+       Advise against settings in the MS-Windows system registry
+
+       * doc/emacs/cmdargs.texi (MS-Windows Registry): Advise against
+       setting environment variables in the system registry.  (Bug#16429)
+
+2022-05-17  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       Fix kmacro-keymap binding after previous change
+
+       * lisp/kmacro.el (kmacro-keymap): Fix binding after
+       kmacro-redisplay command name change.
+
+2022-05-17  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       Add glossary entries for "interactively"
+
+       * doc/emacs/glossary.texi (Glossary): Mention "interactively" and
+       how it relates to the "command" concept (bug#55461).
+
+2022-05-17  Eli Zaretskii  <eliz@gnu.org>
+
+       Fix the name of a kmacro command.
+
+       * lisp/kmacro.el (kmacro-redisplay): Rename from
+       'kdb-macro-redisplay' (which was wrong and included a typo).
+
+       * etc/NEWS: Announce the change.  (Bug#55471)
+
+2022-05-17  Michael Albinus  <michael.albinus@gmx.de>
+
+       Fix Tramp sshfs tests (don't merge)
+
+       * test/lisp/net/tramp-tests.el (tramp-fuse-remove-hidden-files): 
Declare.
+       (tramp-test16-directory-files)
+       (tramp-test16-file-expand-wildcards)
+       (tramp-test26-file-name-completion, tramp--test-check-files): Use it.
+       (tramp--test-check-files): Delete directory recursively.
+
+2022-05-17  Michael Albinus  <michael.albinus@gmx.de>
+
+       Some minor Tramp fixes
+
+       * lisp/net/tramp-cmds.el (tramp-list-tramp-buffers)
+       (tramp-list-remote-buffers): Add ;;;###tramp-autoload cookie.
+
+       * lisp/net/tramp-fuse.el (tramp-fuse-remove-hidden-files): New defvar.
+       (tramp-fuse-remove-hidden-files): Use it.
+
+       * lisp/net/tramp-gvfs.el (tramp-gvfs-handler-askquestion):
+       Keep regression tests running.
+
+2022-05-15  Kyle Meyer  <kyle@kyleam.com>
+
+       Update to Org 9.5.3-6-gef41f3
+
+2022-05-15  Michael Albinus  <michael.albinus@gmx.de>
+
+       Hide temporary FUSE files in Tramp
+
+       * lisp/net/tramp-fuse.el (tramp-fuse-remove-hidden-files): New defsubst.
+       (tramp-fuse-handle-directory-files)
+       (tramp-fuse-handle-file-name-all-completions): Use it.
+
+2022-05-15  Michael Albinus  <michael.albinus@gmx.de>
+
+       * test/lisp/net/tramp-tests.el (tramp-test27-load): Adapt test.  Don't 
merge
+
+2022-05-13  Po Lu  <luangruo@yahoo.com>
+
+       Fix tooltip face overwriting dragged text strings during mouse DND
+
+       * lisp/mouse.el (mouse-drag-and-drop-region): Copy
+       `text-tooltip' before showing it.  Do not merge to master.
+
+2022-05-13  Eli Zaretskii  <eliz@gnu.org>
+
+       Fix lexical-binding fallout in vhdl-mode.el
+
+       * lisp/progmodes/vhdl-mode.el (arch-alist, pack-alist)
+       (file-alist, unit-alist, rule-alist): Defvar them, since vhdl-aput
+       expects them to be dynamically bound.  (Bug#55389)
+       (vhdl-speedbar-insert-hierarchy): Rename the PACK-ALIST argument
+       to PACKAGE-ALIST, to avoid shadowing the global variable.
+
+2022-05-12  Michael Albinus  <michael.albinus@gmx.de>
+
+       Fix ControlPath quoting in Tramp
+
+       * lisp/net/tramp-sh.el (tramp-ssh-controlmaster-options):
+       Adapt docstring.  Do not quote ControlPath.  Reported by Daniel
+       Kessler <kesslerd@umich.edu>.
+
+2022-05-09  Eli Zaretskii  <eliz@gnu.org>
+
+       Remove the AUCTeX subsection from MS-Windows FAQ
+
+       * doc/misc/efaq-w32.texi (AUCTeX): Remove the subsection, it is no
+       longer useful.  (Bug#55330)
+
+2022-05-09  Arash Esbati  <arash@gnu.org>
+
+       Update AUCTeX FAQ entry
+
+       * doc/misc/efaq-w32.texi (AUCTeX): AUCTeX project isn't providing
+       pre-compiled versions for Windows anymore (bug#55330).
+
+2022-05-09  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       Update string-to-number documentation to bignum Emacs
+
+       * doc/lispref/strings.texi (String Conversion): string-to-number
+       no longer converts integers to floating point numbers (bug#55334).
+
+2022-05-09  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       Fix doc string references to tags-loop-continue
+
+       * lisp/vc/vc-dir.el (vc-dir-search, vc-dir-query-replace-regexp):
+       Fix reference to obsolete tags-loop-continue (bug#55311).
+
+2022-05-08  Visuwesh M  <visuweshm@gmail.com>
+
+       dired-do-query-replace-regexp doc string fix
+
+       * lisp/dired-aux.el (dired-do-query-replace-regexp): Refer
+       'fileloop-continue' instead of the obsolete command
+       'tags-loop-continue'.  (Bug#55311)
+
+       (cherry picked from commit 4c505203f9171886f47638779326e257a95a1d79)
+
+2022-05-08  Alan Mackenzie  <acm@muc.de>
+
+       Linux console: don't translate ESC TAB to `backtab' in input-decode-map.
+
+       This translation happened after the terminfo entry for <shift>TAB in 
the linux
+       section was changed to kcbt=\E^I in ncurses version 6.3.
+
+       * lisp/term/linux.el (terminal-init-linux): Add a define-key form to 
remove
+       the entry for "\e\t" from input-decode-map.
+
+       * etc/PROBLEMS: Add a new section under "character terminals" about 
S-TAB
+       wrongly doing the same thing as M-TAB, giving tips about amending the 
Linux
+       keyboard layout.
+
+2022-05-08  Michael Albinus  <michael.albinus@gmx.de>
+
+       Handle changed scp protocol in Tramp, don't merge
+
+       * lisp/net/tramp-sh.el (tramp-scp-force-scp-protocol): New defvar.
+       (tramp-scp-force-scp-protocol): New defun.
+       (tramp-do-copy-or-rename-file-out-of-band): Use it.
+       (tramp-methods) <scp, scpx>: Use "%y".
+
+       * lisp/net/tramp.el (tramp-methods): Adapt docstring.
+
+2022-05-06  Michael Albinus  <michael.albinus@gmx.de>
+
+       Fix bug#55274
+
+       * lisp/dired-aux.el (dired-do-compress-to): Use `file-local-name'
+       for shell out-file.  (Bug#55274)
+
+2022-05-06  Eli Zaretskii  <eliz@gnu.org>
+
+       Provide reference for OTF tags in the ELisp manual
+
+       * doc/lispref/display.texi (Low-Level Font): Provide the canonical
+       reference URL for OTF tags.
+
+2022-05-05  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       Be more resilient towards errors during error handling
+
+       * src/print.c (print_error_message): Avoid infinite recursion if
+       `substitute-command-keys' bugs out (bug#55269).
+
+       (cherry picked from commit 8364f058b821eba31f84dcded175cca403a965a5)
+
+2022-04-28  Eli Zaretskii  <eliz@gnu.org>
+
+       Improve documentation of font- and face-related attribute functions
+
+       * lisp/faces.el (face-attribute):
+       * src/xfaces.c (Fx_family_fonts):
+       * src/font.c (Ffont_get, Ffont_put): Improve and clarify the doc
+       strings.
+
+       * doc/lispref/display.texi (Low-Level Font): Document the :type
+       attribute of a font.  Improve documentation of 'font-get' and
+       'font-put'.
+       (Attribute Functions): Add cross-reference to the description of
+       face attributes.
+
+2022-04-25  Kyle Meyer  <kyle@kyleam.com>
+
+       Update to Org 9.5.3-3-gd54104
+
+2022-04-24  Eli Zaretskii  <eliz@gnu.org>
+
+       Improve indexing in "Programmed Completion"
+
+       * doc/lispref/minibuf.texi (Programmed Completion): Improve
+       indexing.  (Bug#55095)
+
+2022-04-24  Eli Zaretskii  <eliz@gnu.org>
+
+       Improve documentation of 'set-fontset-font'
+
+       * doc/lispref/display.texi (Fontsets):
+       * src/fontset.c (Fset_fontset_font): Improve and clarify the
+       documentation of 'set-fontset-font'.  Rename the arguments to be
+       more self-explanatory.  (Bug#55086)
+
+2022-04-23  Michael Albinus  <michael.albinus@gmx.de>
+
+       Fix problem with Solaris ls in Tramp
+
+       * lisp/net/tramp-sh.el (tramp-sunos-unames): Move up.
+       (tramp-sh--quoting-style-options): Handle erroneous Solaris ls.
+
+2022-04-22  Eli Zaretskii  <eliz@gnu.org>
+
+       Another fix for non-ASCII 'overlay-arrow-string'
+
+       * src/xdisp.c (get_overlay_arrow_glyph_row): Fix yet another place
+       that assumed each character is a single byte.
+
+2022-04-21  Eli Zaretskii  <eliz@gnu.org>
+
+       Avoid a redisplay loop when 'overlay-arrow-string' is non-ASCII
+
+       * src/xdisp.c (get_overlay_arrow_glyph_row): Don't assume every
+       character in 'overlay-arrow-string' is one byte long.  Reported by
+       Yuri D'Elia <wavexx@thregr.org>.
+
+2022-04-21  Eli Zaretskii  <eliz@gnu.org>
+
+       Add minimum instructions to 'query-replace' commands
+
+       * lisp/vc/vc-dir.el (vc-dir-query-replace-regexp):
+       * lisp/textmodes/reftex-global.el (reftex-query-replace-document):
+       * lisp/progmodes/project.el (project-query-replace-regexp):
+       * lisp/progmodes/etags.el (tags-query-replace):
+       * lisp/progmodes/ebrowse.el (ebrowse-tags-query-replace):
+       * lisp/isearch.el (isearch-query-replace, isearch-occur):
+       * lisp/emulation/viper-cmd.el (viper-query-replace):
+       * lisp/dired-aux.el (dired-do-query-replace-regexp)
+       (dired-do-find-regexp-and-replace):
+       * lisp/progmodes/xref.el (xref-query-replace-in-results):
+       * lisp/replace.el (query-replace, query-replace-regexp)
+       (query-replace-regexp-eval, map-query-replace-regexp): Add minimal
+       instructions for dealing with matches, with a link to the command
+       that shows the full instructions.  (Bug#55050)
+
+2022-04-21  Eli Zaretskii  <eliz@gnu.org>
+
+       Fix customization-group of 'python-forward-sexp-function'
+
+       * lisp/progmodes/python.el (python-forward-sexp-function): Make it
+       be part of both 'python' and 'python-flymake' groups.  (Bug#55027)
+       Do not merge to master.
+
+2022-04-20  Paul Eggert  <eggert@cs.ucla.edu>
+
+       Update from gnulib
+
+       (cherry picked from commit 992cf3cb675e074079341cc54c3b16d37a8b9ca8)
+
+       This is a partial backport from master: it only includes the changes 
below.
+
+       * lib/mini-gmp.c (gmp_assert_nocarry): Avoid many Clang
+       unused-variable warnings when building with optimization.
+       * lib/verify.h (_GL_HAVE__STATIC_ASSERT): Modify condition for using
+       _Static_assert to cope with older Apple builds of Clang exposing
+       misleading compiler version numbers.  See discussion starting at
+       https://lists.gnu.org/archive/html/emacs-devel/2022-04/msg00779.html
+
+2022-04-20  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       Revert prompting changes in viper-cmd
+
+       * lisp/emulation/viper-cmd.el (viper-quote-region)
+       (viper-read-string-with-history, viper-query-replace): Revert
+       prompting changes done in 50512e3 -- the way viper prompts in
+       command mode is special (bug#55007).
+
+       Do not merge to master.
+
+2022-04-19  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       Fix regression with multiple mode: entries in the prop line
+
+       * lisp/files.el (hack-local-variables): Fix regression with multiple
+       mode: entries in the prop line.
+
+       Do not merge to master.
+
+2022-04-18  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       Avoid hangs in python-mode with debug-on-error set
+
+       * lisp/progmodes/python.el (python-nav-end-of-statement): Avoid
+       using cl-assert here, because this is called from the font-lock
+       machinery, and if debug-on-error is set here, we'll hang Emacs
+       (bug#54996).
+
+       Do not merge to master.
+
+2022-04-18  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       Fix major-mode setting regression when there's a mode: cookie
+
+       * lisp/files.el (hack-local-variables): Fix regression in setting
+       the major mode when there are mode: cookies in the file (bug#54993).
+
+       Do not merge to master.
+
+2022-04-17  Kyle Meyer  <kyle@kyleam.com>
+
+       Update to Org 9.5.2-38-g682ccd
+
+2022-04-17  Eli Zaretskii  <eliz@gnu.org>
+
+       Revert "Don’t assume openat"
+
+       This reverts commit 3cccf0a9107d585173e527550bbc45253624ca2e.
+
+       This is a change with far-reaching effects on MS-Windows at the least,
+       where file-related APIs are shadowed to support transparent support
+       for UTF-8 encoded file names.  Making such changes on a stable branch
+       for the benefit of a proprietary platform with a 13-year old OS is a
+       tail wagging the dog.  Please don't do that without discussing first.
+
+2022-04-17  Paul Eggert  <eggert@cs.ucla.edu>
+
+       Don’t assume openat
+
+       Use openat only on platforms with O_PATH.
+       This ports to OS X 10.9 and earlier.
+       Problem reported by Keith David Bershatsky in:
+       https://lists.gnu.org/r/emacs-devel/2022-04/msg00805.html
+       * lib-src/emacsclient.c (local_sockname): Use open, not openat.
+       * src/sysdep.c (sys_openat): New static function,
+       which uses openat only if O_PATH is defined.
+       (emacs_openat): Use it instead of openat.
+       (emacs_openat_noquit): Remove.
+       (emacs_open_noquit): Reimplement as per the old emacs_openat_noquit,
+       but use plain 'open'.
+
+2022-04-17  Paul Eggert  <eggert@cs.ucla.edu>
+
+       Fix GC bug in filelock.c
+
+       Fix a bug where if GC occurred at the wrong moment when locking a
+       file, the lock file’s name was trashed so file locking did not work.
+       This bug was introduced in Emacs 28.1.  The bug sometimes caused
+       filelock-tests-detect-external-change test failures on Fedora 35
+       x86-64 in an en_US.utf8 locale.
+       * src/filelock.c (lock_file_1, current_lock_owner, lock_if_free)
+       (lock_file, unlock_file, Ffile_locked_p):
+       Use Lisp_Object, not char *, for string, so that GC doesn’t trash
+       string contents.
+       (make_lock_file_name): Return the encoded name, not the original.
+       All callers changed.
+
+2022-04-16  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       Clarify when mode tagging is used
+
+       * etc/NEWS: Clarify when mode tagging is used (bug#54964).
+
+2022-04-16  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       Further vcs-cvs/rcs-responsible-p updates from master
+
+       * lisp/vc/vc-bzr.el (vc-bzr-responsible-p):
+       * lisp/vc/vc-sccs.el (vc-sccs-responsible-p):
+       * lisp/vc/vc-dav.el (vc-dav-responsible-p): Update doc string.
+
+       * lisp/vc/vc-rcs.el (vc-rcs-responsible-p):
+       * lisp/vc/vc-cvs.el (vc-cvs-responsible-p): Further fixes from
+       master.
+
+       * lisp/vc/vc-src.el (vc-src-responsible-p): Return the directory.
+
+       * lisp/vc/vc.el: Update comments.
+
+2022-04-16  Mattias Engdegård  <mattiase@acm.org>
+
+       Fix builds on older versions of macOS
+
+       This adds back macOS-specific code replaced earlier (bug#48548),
+       specifically to fix build errors on macOS 10.7.5.  See discussion at
+       https://lists.gnu.org/archive/html/emacs-devel/2022-04/msg00779.html .
+
+       * src/sysdep.c (HAVE_RUSAGE_INFO_CURRENT, HAVE_PROC_PIDINFO): New.
+       (system_process_attributes): Use alternative code or exclude features
+       when building on older macOS versions.
+
+2022-04-16  Eli Zaretskii  <eliz@gnu.org>
+
+       Fix documentation of Outline minor mode options
+
+       * lisp/outline.el (outline-minor-mode-cycle-filter)
+       (outline-minor-mode-cycle, outline-minor-mode-highlight)
+       (outline-cycle, outline-cycle-buffer): Doc fixes.  (Bug#54967)
+
+2022-04-15  Eli Zaretskii  <eliz@gnu.org>
+
+       Improve discoverability of 'insert-directory-program'
+
+       * lisp/files.el (insert-directory-program): Mention 'dired' in the
+       doc string.
+       * lisp/dired.el (dired): Mention 'insert-directory-program' in the
+       doc string.  (Bug#54962)
+
+2022-04-15  Eli Zaretskii  <eliz@gnu.org>
+
+       Fix cursor motion under truncate-lines with Flymake fringe indicator
+
+       * src/indent.c (Fvertical_motion): Don't consider fringe bitmaps
+       as "images" for the purpose of vertical-motion logic dealing with
+       overshooting buffer positions.  (Bug#54946)
+
+2022-04-14  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       Make all vc-*-responsible-p functions return a string
+
+       * lisp/vc/vc-sccs.el (vc-sccs-responsible-p):
+       * lisp/vc/vc-rcs.el (vc-rcs-responsible-p):
+       * lisp/vc/vc-dav.el (vc-dav-responsible-p):
+       * lisp/vc/vc-cvs.el (vc-cvs-responsible-p): Return a file name
+       instead of t when we get a match (which is what
+       vc-backend-for-registration expects) (bug#51800).
+
+       This fixes the regression reported in bug#54935.
+
+       Do not merge to master.
+
+2022-04-14  Eli Zaretskii  <eliz@gnu.org>
+
+       Describe problems with invoking Python on MS-Windows
+
+       * etc/PROBLEMS: Describe problems with running an inferior Python
+       interpreter due to the MS-Windows "App Execution Aliases" feature.
+       (Bug#54860)
+
+2022-04-13  Eli Zaretskii  <eliz@gnu.org>
+
+       A better fix for bug#54800
+
+       * lisp/calc/calc.el (calc-align-stack-window): Improve scrolling
+       when windows have non-integral dimensions.
+
+2022-04-13  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       Add a comment about cl-concatenate
+
+       * lisp/emacs-lisp/cl-extra.el (cl-concatenate): Add a comment.
+
+2022-04-13  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       Revert "Make cl-concatenate an alias of seq-concatenate"
+
+       This reverts commit 78f76fe16e2737b40694f82af28d17a90a21ed7b.
+
+       The commit made calls to cl-concatenate bug out, since
+       autoloading defalises doesn't work very well (bug#54901).
+
+2022-04-12  Eli Zaretskii  <eliz@gnu.org>
+
+       Fix 'window-text-pixel-width' when starting from display property
+
+       * src/xdisp.c (Fwindow_text_pixel_size): Handle the case where
+       there's a display property at START, and move_it_to overshoots.
+       Do not merge to master.  (Bug#54862)
+
+2022-04-11  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * lisp/gnus/mm-encode.el (mm-default-file-encoding): Fix "when" arg
+
+2022-04-11  Eli Zaretskii  <eliz@gnu.org>
+
+       Fix default-directory of buffers visiting files in renamed directories
+
+       * lisp/dired-aux.el (dired-rename-file): Take note of whether FILE
+       is a directory before it is renamed, which makes it impossible to
+       determine if it was a directory.
+       (dired-rename-subdir, dired-rename-subdir-1): Revert to using
+       dired-in-this-tree-p instead of file-in-directory-p, for the
+       benefit of files that were renamed/removed, because
+       file-in-directory-p returns nil in those cases.  (Bug#54838)
+
+2022-04-11  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       Fix a kill-append regression
+
+       * lisp/simple.el (kill-append): Fix a regression when
+       kill-ring-max is zero (bug#54842).
+
+2022-04-10  Eli Zaretskii  <eliz@gnu.org>
+
+       * doc/misc/eww.texi (Advanced): Correct outdated info (bug#54839).
+
+2022-04-10  Eli Zaretskii  <eliz@gnu.org>
+
+       Clean up the MSDOS port
+
+       * src/msdos.h (tcdrain): Redirect to '_dos_commit'.
+       (openat, fchmodat, futimens, utimensat): Add prototypes.
+
+       * msdos/sed1v2.inp (MAKE_PDUMPER_FINGERPRINT): Fix indentation, so
+       that Make won't consider this line a command.
+       ($(etc)/DOC): Chdir back to ../src, since "make-docfile -d" leaves
+       us in a wrong directory.
+       * msdos/sedlibmk.inp (GL_GNULIB_GETRANDOM, GL_GNULIB_MEMMEM)
+       (GL_GNULIB_SIGDESCR_NP): Define to 1, to get the prototypes from
+       Gnulib headers.
+
+2022-04-10  Daniel Martín  <mardani29@yahoo.es>
+
+       Fix typo in next-error-find-buffer-function
+
+       * lisp/simple.el (next-error-find-buffer-function): Fix typo
+       (bug#54830).
+
+2022-04-10  Lars Ingebrigtsen  <larsi@gnus.org>
+
+       Revert "Make shell-resync-dirs handle whitespace in directory names"
+
+       This reverts commit 90e65c826fab2092ad2099d7763538194c93e021.
+
+       This change led to hangs (bug#54776).
+
+       Do not merge to master; it has been fixed in a more encompassing way 
there.
+
+2022-04-09  Eli Zaretskii  <eliz@gnu.org>
+
+       Fix scrolling of the stack window in Calc
+
+       * lisp/calc/calc.el (calc-align-stack-window): Fix off-by-one
+       error in computing the window-start point.  (Bug#54800)
+
+2022-04-08  Eli Zaretskii  <eliz@gnu.org>
+
+       Update and fix instructions and scripts for updating the Web pages
+
+       * admin/admin.el (manual-html-fix-index-2): Support Texinfo 6.8
+       and later by not converting TOC menus into tables.  (Bug#49719)
+       * admin/upload-manuals (New directory): Invoke "cvs add" in
+       $webdir, to pick up the correct CVSROOT.
+       * admin/make-tarball.txt: Update the section about the Emacs Web
+       pages.
+
+       * etc/refcards/Makefile (pl-refcard.dvi): If mex.fmt cannot be
+       found, invoke 'mex' instead of 'tex'.
+
+2022-04-08  Michael Albinus  <michael.albinus@gmx.de>
+
+       Extend tramp-archive-test45-auto-load
+
+       * test/lisp/net/tramp-archive-tests.el (tramp-archive-test45-auto-load):
+       Extend test.
+
+2022-04-08  Michael Albinus  <michael.albinus@gmx.de>
+
+       Ensure local `default-directory' in Tramp when needed
+
+       * lisp/net/tramp.el (tramp-process-running-p): Ensure local
+       `default-directory' when calling `list-system-processes' and
+       `process-attributes'.
+
+2022-04-08  Eli Zaretskii  <eliz@gnu.org>
+
+       Clarify "idleness" in the ELisp manual
+
+       * doc/lispref/os.texi (Idle Timers): Clarify that waiting for
+       input with timeout doesn't make Emacs idle.  Suggested by Ignacio
+       <ignaciocasso@hotmail.com>.  (Bug#54371)
+
+2022-04-07  Jürgen Hötzel  <juergen@archlinux.org>
+
+       Use correct signal oldset in posix_spawn implementation
+
+       posix_spawn was restoring the wrong signal set, which still had
+       SIGCHLD and SIGINT masked, causing problems with child processes that
+       spawned child processes.  (Bug#54667)
+
+       See the thread ending at
+       https://lists.gnu.org/archive/html/emacs-devel/2022-03/msg00067.html
+       for more details.
+
+       * src/callproc.c (emacs_spawn): Pass oldset parameter.
+       (emacs_posix_spawn_init_attributes): Use correct oldset.
+       (emacs_posix_spawn_init): Remove intermediate function.
+
+       (cherry picked from commit 8103b060d89ac63a12c439087bd46c30da72cd97)
+
+2022-04-07  Felix Dietrich  <felix.dietrich@sperrhaken.name>  (tiny change)
+
+       Fix error in tramp-archive-autoload-file-name-handler
+
+       * lisp/net/tramp-archive.el (tramp-archive-autoload-file-name-handler):
+       Always call `tramp-autoload-file-name'.  Otherwise, when
+       `tramp-archive-enabled’ is nil and
+       `tramp-archive-autoload-file-name-handler’ is in the
+       `file-name-handler-alist’ results in an error “Invalid handler in
+       `file-name-handler-alist” once Emacs calls
+       `tramp-archive-autoload-file-name-handler’ with a handler that
+       does not expect nil.  Always returning nil is also false in
+       general.
+
+2022-04-07  Michael Albinus  <michael.albinus@gmx.de>
+
+       Commit missing file from previous commit (Do not merge with master)
+
+       Commit missing file from previous commit
+
+2022-04-07  Michael Albinus  <michael.albinus@gmx.de>
+
+       Merge with Tramp 2.5.2.3 (Do not merge with master)
+
+       * doc/misc/tramp.texi (Archive file names): Explicitly say how to
+       open an archive with Tramp (Bug#25076).
+
+       * doc/misc/trampver.texi:
+       * lisp/net/trampver.el: Change version to "2.5.3-pre".
+
+       * lisp/net/tramp-adb.el (tramp-adb-handle-process-file)
+       * lisp/net/tramp-sh.el (tramp-sh-handle-process-file):
+       * lisp/net/tramp-smb.el (tramp-smb-handle-process-file):
+       * lisp/net/tramp-sshfs.el (tramp-sshfs-handle-process-file):
+       Improve implementation.  (Bug#53854)
+
+       * lisp/net/tramp-adb.el (tramp-adb-tolerate-tilde):
+       * lisp/net/tramp-sshfs.el (tramp-sshfs-tolerate-tilde):
+       New defuns.  Advice `shell-mode' with them.
+
+       * lisp/net/tramp.el (tramp-register-autoload-file-name-handlers):
+       * lisp/net/tramp-archive.el (tramp-register-archive-file-name-handler):
+       Check, whether the real file name handler is already registered.
+       rules.  (Bug#54542)
+
+       * lisp/net/tramp.el (tramp-autoload-file-name-handler)
+       (tramp-register-autoload-file-name-handlers)
+       (tramp-unload-file-name-handlers, tramp-unload-tramp):
+       * lisp/net/tramp-archive.el (tramp-archive-autoload-file-name-regexp)
+       (tramp-archive-autoload-file-name-handler)
+       (tramp-register-archive-file-name-handler):
+       Add `tramp-autoload' property.
+
+       * lisp/net/tramp-crypt.el (tramp-crypt-file-name-handler-alist):
+       * lisp/net/tramp-rclone.el (tramp-rclone-file-name-handler-alist):
+       * lisp/net/tramp-sudoedit.el (tramp-sudoedit-file-name-handler-alist):
+       * lisp/net/tramp-sshfs.el (tramp-sshfs-file-name-handler-alist):
+       Use `tramp-handle-file-notify-add-watch',
+       `tramp-handle-file-notify-rm-watch' and
+       `tramp-handle-file-notify-valid-p'.
+
+       * lisp/net/tramp-crypt.el (tramp-crypt-file-name-handler-alist):
+       Use `tramp-handle-insert-file-contents'.
+
+       * lisp/net/tramp-gvfs.el (tramp-gvfs-maybe-open-connection):
+       * lisp/net/tramp-rclone.el (tramp-rclone-maybe-open-connection):
+       * lisp/net/tramp-sshfs.el (tramp-sshfs-maybe-open-connection):
+       * lisp/net/tramp-sudoedit.el
+       (tramp-sudoedit-maybe-open-connection): Do not set "lock-pid"
+       connection-property.
+       (tramp-sudoedit-handle-delete-file): Use "rm -f".
+
+       * lisp/net/tramp-gvfs.el (tramp-gvfs-handle-file-executable-p):
+       * lisp/net/tramp-sh.el (tramp-sh-handle-file-executable-p):
+       Check also for setuid/setgid bit.
+       (tramp-gvfs-handle-expand-file-name):
+       Respect `tramp-tolerate-tilde'.
+
+       * lisp/net/tramp-sh.el (tramp-sh-handle-insert-directory):
+       * lisp/net/tramp-smb.el (tramp-smb-handle-insert-directory):
+       Do not modify disk space information when
+       `dired--insert-disk-space' is available.  (Bug#54512)
+
+       * lisp/net/tramp-sh.el (tramp-maybe-open-connection): Extend suppression
+       (tramp-get-remote-dev-tty): New defun.
+       (tramp-sh-handle-make-process): Use it.
+
+       * lisp/net/tramp-sshfs.el (tramp-methods) <sshfs>:
+       Add "-t -t" to `tramp-login-args'.
+       Add "-o dir_cache=no" to `tramp-mount-args'.  (Bug#54126)
+       Add "-o transform_symlinks" to `tramp-mount-args'.
+       (tramp-sshfs-file-name-handler-alist):
+       Use `tramp-sshfs-handle-file-writable-p'.
+       (tramp-sshfs-handle-file-writable-p): New defun.  (Bug#54130)
+       (tramp-sshfs-handle-write-region): Set file modification time.
+       (Bug#54016)
+       (tramp-sshfs-file-name-handler-alist):
+       Use `tramp-sshfs-handle-set-file-times'.
+       (tramp-sshfs-handle-set-file-times): New defun.
+
+       * test/lisp/net/tramp-tests.el (tramp--test-expensive-test-p):
+       Rename from `tramp--test-expensive-test'.  Make it a defun.  Adapt
+       all callees.
+       (tramp-test07-file-exists-p, tramp-test14-delete-directory)
+       (tramp-test18-file-attributes, tramp-test20-file-modes)
+       (tramp-test28-process-file, tramp-test29-start-file-process)
+       (tramp-test30-make-process, tramp-test32-shell-command)
+       (tramp-test33-environment-variables, tramp--test-check-files)
+       (tramp--test-special-characters, tramp-test46-unload): Adapt tests.
+       (tramp-test39-detect-external-change): New test.
+       (tramp-test29-start-file-process)
+       (tramp--test--deftest-direct-async-process)
+       (tramp-test30-make-process, tramp-test31-interrupt-process)
+       (tramp-test34-explicit-shell-file-name)
+       (tramp-test44-asynchronous-requests):
+       Add :tramp-asynchronous-processes tag.
+       (tramp--test-asynchronous-processes-p): New defun.
+       (tramp--test-hpux-p, tramp--test-macos-p): Protect against errors.
+
+2022-04-06  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       cl-generic.el: Fix bug#46722
+
+       Fix longstanding bug due to unexpected interference via side-effect.
+
+       * lisp/emacs-lisp/cl-generic.el (cl--generic-get-dispatcher):
+       Copy the `dispatch` arg before storing it into the hash-table.
+
+       Backport from `master` (cherrypick from commit 61f8f7f68f).
+
+2022-04-05  Eli Zaretskii  <eliz@gnu.org>
+
+       Fix fallout from lexical-binding in vhdl-mode.el
+
+       * lisp/progmodes/vhdl-mode.el (vhdl-update-sensitivity-list): Fix
+       production of a list with embedded function calls.  (Bug#54730)
+
+2022-04-03  Eli Zaretskii  <eliz@gnu.org>
+
+       Update logs and HISTORY for Emacs 28.1
+
+       * ChangeLog.3:
+       * etc/HISTORY:
+       * etc/AUTHORS: Update for Emacs 28.1 release.
+
+2022-04-03  Eli Zaretskii  <eliz@gnu.org>
+
+       Bump Emacs version to 28.1
+
+       * README:
+       * configure.ac:
+       * nt/README.W32:
+       * msdos/sed2v2.inp: Bump Emacs version to 28.1
+
+2022-03-30  Tassilo Horn  <tsdh@gnu.org>
 
        dired: implement feature from 7b50ed553f differently
 
@@ -7,29 +1637,29 @@
        (dired-clean-up-after-deletion): Use dired-buffers-for-dir-or-subdir
        instead dired-buffers-for-dir.
 
-2022-04-13  Eli Zaretskii  <eliz@gnu.org>
+2022-03-30  Eli Zaretskii  <eliz@gnu.org>
 
        Fix regression in 'dired-buffers-for-dir'
 
        * lisp/dired.el (dired-buffers-for-dir): Fix inadvertently swapped
        arguments.  (Bug#54636)
 
-2022-04-13  Eli Zaretskii  <eliz@gnu.org>
+2022-03-27  Eli Zaretskii  <eliz@gnu.org>
 
        * lisp/desktop.el (desktop-read): Clarify warning text.
 
-2022-04-13  Po Lu  <luangruo@yahoo.com>
+2022-03-26  Po Lu  <luangruo@yahoo.com>
 
        * doc/emacs/anti.texi (Antinews): Unannounce removal of Motif.
 
-2022-04-13  Lars Ingebrigtsen  <larsi@gnus.org>
+2022-03-25  Lars Ingebrigtsen  <larsi@gnus.org>
 
        Fix eshell-explicit-command-char doc string typo
 
        * lisp/eshell/esh-ext.el (eshell-explicit-command-char): Fix typo
        in doc string (bug#54567).
 
-2022-04-13  Eli Zaretskii  <eliz@gnu.org>
+2022-03-24  Eli Zaretskii  <eliz@gnu.org>
 
        Clarify the description of "selected tags table"
 
@@ -37,7 +1667,7 @@
        distinction between the "selected tags table" and the "current
        list of tags tables".  (Bug#54543)
 
-2022-04-13  Lars Ingebrigtsen  <larsi@gnus.org>
+2022-03-21  Lars Ingebrigtsen  <larsi@gnus.org>
 
        Add notes about command modes and nativecomp interaction
 
@@ -48,11 +1678,11 @@
 
        Do not merge to master.
 
-2022-04-13  Kyle Meyer  <kyle@kyleam.com>
+2022-03-20  Kyle Meyer  <kyle@kyleam.com>
 
        Update to Org 9.5.2-25-gaf6f12
 
-2022-04-13  Eli Zaretskii  <eliz@gnu.org>
+2022-03-20  Eli Zaretskii  <eliz@gnu.org>
 
        Improve doc strings of read-char-from-minibuffer-insert-* commands
 
@@ -60,7 +1690,7 @@
        (read-char-from-minibuffer-insert-other): Clarify the doc strings.
        (Bug#54479)
 
-2022-04-13  Eli Zaretskii  <eliz@gnu.org>
+2022-03-19  Eli Zaretskii  <eliz@gnu.org>
 
        Fix region highlight in non-selected windows
 
@@ -68,25 +1698,25 @@
        to pre-redisplay-functions windows whose point was moved from the
        last recorded position.  (Bug#54450)
 
-2022-04-13  Eli Zaretskii  <eliz@gnu.org>
+2022-03-18  Eli Zaretskii  <eliz@gnu.org>
 
        Fix a regression in 'decipher-digram-list'
 
        * lisp/play/decipher.el (decipher-stats-buffer): Don't assume the
        statistics buffer always exists.  (Bug#54443)
 
-2022-04-13  Karl Fogel  <kfogel@red-bean.com>
+2022-03-17  Karl Fogel  <kfogel@red-bean.com>
 
        Improve documentation of bookmark default sorting
 
        * lisp/bookmark.el (bookmark-alist, bookmark-store,
          bookmark-maybe-sort-alist): Update doc strings and comments.
 
-2022-04-13  Juri Linkov  <juri@linkov.net>
+2022-03-15  Juri Linkov  <juri@linkov.net>
 
        * doc/misc/transient.texi: Fix @dircategory to "Emacs misc features" 
for dir.
 
-2022-04-13  Jim Porter  <jporterbugs@gmail.com>
+2022-03-13  Jim Porter  <jporterbugs@gmail.com>
 
        Fix evaluation of negated argument predicates in Eshell
 
@@ -97,7 +1727,7 @@
 
        Do not merge to master.
 
-2022-04-13  Eli Zaretskii  <eliz@gnu.org>
+2022-03-12  Eli Zaretskii  <eliz@gnu.org>
 
        Emacs pretest 28.0.92
 
@@ -111,7 +1741,7 @@
 
        * ChangeLog.3: Regenerate.
 
-2022-04-13  Eli Zaretskii  <eliz@gnu.org>
+2022-03-10  Eli Zaretskii  <eliz@gnu.org>
 
        Fix regression in 'custom-prompt-customize-unsaved-options'
 
@@ -120,7 +1750,7 @@
        the doc string.  Patch by Sebastian Miele <iota@whxvd.name>.
        (Bug#54329)
 
-2022-04-13  Eli Zaretskii  <eliz@gnu.org>
+2022-03-10  Eli Zaretskii  <eliz@gnu.org>
 
        Improve documentation of 'map-charset-chars'
 
@@ -128,58 +1758,58 @@
        * src/charset.c (Fmap_charset_chars): Clarify the codepoint issue
        in using 'map-charset-chars'.
 
-2022-04-13  Eli Zaretskii  <eliz@gnu.org>
+2022-03-08  Eli Zaretskii  <eliz@gnu.org>
 
        Avoid assertion violations in 'bidi_resolve_brackets'
 
        * src/bidi.c (bidi_resolve_brackets): Move assertion to where it
        really matters.  (Bug#54295)
 
-2022-04-13  Lars Ingebrigtsen  <larsi@gnus.org>
+2022-03-07  Lars Ingebrigtsen  <larsi@gnus.org>
 
        Fix which-func-update doc string
 
        * lisp/progmodes/which-func.el (which-func-update): Make the doc
        string match the code (bug#54288).
 
-2022-04-13  Eli Zaretskii  <eliz@gnu.org>
+2022-03-07  Eli Zaretskii  <eliz@gnu.org>
 
        Improve wording of 'dired-jump's description
 
        * doc/emacs/dired.texi (Dired Enter): Clarify wording.  Reported
        by Natalie <batalie@riseup.net>.
 
-2022-04-13  Lars Ingebrigtsen  <larsi@gnus.org>
+2022-03-06  Lars Ingebrigtsen  <larsi@gnus.org>
 
        Add a comment for previous browse-url-of-dired-file change
 
        * lisp/net/browse-url.el (browse-url-of-dired-file): Add a comment
        for previous change.
 
-2022-04-13  Lars Ingebrigtsen  <larsi@gnus.org>
+2022-03-06  Lars Ingebrigtsen  <larsi@gnus.org>
 
-       Restore documented Emacs 27.2 behaviour of browse-url-of-dired-file
+       Restore documented Emacs 27.2 behavior of browse-url-of-dired-file
 
        * lisp/net/browse-url.el (browse-url-of-dired-file): Restore the
-       documented behaviour -- open a web browser instead of passing to
+       documented behavior -- open a web browser instead of passing to
        the various handlers.
 
-2022-04-13  Kyle Meyer  <kyle@kyleam.com>
+2022-03-06  Kyle Meyer  <kyle@kyleam.com>
 
        Update to Org 9.5.2-24-g668205
 
-2022-04-13  Andreas Schwab  <schwab@linux-m68k.org>
+2022-03-05  Andreas Schwab  <schwab@linux-m68k.org>
 
        * lib-src/seccomp-filter.c (main): Use faccessat2 only if defined.
 
-2022-04-13  Lars Ingebrigtsen  <larsi@gnus.org>
+2022-03-04  Lars Ingebrigtsen  <larsi@gnus.org>
 
        Fix regression in derived-mode-init-mode-variables
 
        * lisp/emacs-lisp/derived.el (derived-mode-init-mode-variables):
        Fix regression caused by lexical-binding derived.el (bug#54240).
 
-2022-04-13  Eli Zaretskii  <eliz@gnu.org>
+2022-03-03  Eli Zaretskii  <eliz@gnu.org>
 
        Avoid crashes when fringe bitmaps are defined in daemon mode
 
@@ -192,7 +1822,7 @@
        not available when a fringe bitmap is about to be drawn.  Don't
        try to draw a bitmap that is not known to fringe.c.  (Bug#54183)
 
-2022-04-13  Eli Zaretskii  <eliz@gnu.org>
+2022-03-03  Eli Zaretskii  <eliz@gnu.org>
 
        One more fix of the BPA implementation
 
@@ -200,7 +1830,7 @@
        when there are no strong directional characters inside the
        bracketed pair.  (Bug#54219)
 
-2022-04-13  Eli Zaretskii  <eliz@gnu.org>
+2022-03-03  Eli Zaretskii  <eliz@gnu.org>
 
        Fix handling of brackets in BPA
 
@@ -208,14 +1838,14 @@
        N0 rule when there are no strong directional characters inside the
        bracketed pair.  (Bug#54219)
 
-2022-04-13  Po Lu  <luangruo@yahoo.com>
+2022-03-02  Po Lu  <luangruo@yahoo.com>
 
        Correct etc/NEWS entry about bitmapped fonts
 
        * etc/NEWS: Don't say that bitmap font issues are due to Pango, that's
        not accurate.
 
-2022-04-13  Jim Porter  <jporterbugs@gmail.com>
+2022-03-01  Jim Porter  <jporterbugs@gmail.com>
 
        Improve/correct documentation about Eshell variable expansion
 
@@ -225,7 +1855,7 @@
        * doc/misc/eshell.texi (Dollars Expansion): Add documentation for
        $"var"/$'var' and $<command> syntaxes.
 
-2022-04-13  Jim Porter  <jporterbugs@gmail.com>
+2022-03-01  Jim Porter  <jporterbugs@gmail.com>
 
        Partially revert b03f74e0f2a578b1580e8b1c368665850ee7f808
 
@@ -238,7 +1868,7 @@
        * test/lisp/eshell/eshell-tests.el (eshell-test/interp-temp-cmd):
        New test.
 
-2022-04-13  Paul Eggert  <eggert@cs.ucla.edu>
+2022-03-01  Paul Eggert  <eggert@cs.ucla.edu>
 
        Backport: Port pre-commit hook to Git 2.35.0
 
@@ -247,32 +1877,32 @@
 
        (cherry picked from commit b8a96f055624f86fe965a0d1b7b2495b2db80e63)
 
-2022-04-13  Lars Ingebrigtsen  <larsi@gnus.org>
+2022-02-28  Lars Ingebrigtsen  <larsi@gnus.org>
 
        Fix :tag for eol in tab-first-completion
 
        * lisp/indent.el (tab-first-completion): Fix the :tag description
        (bug#54179).
 
-2022-04-13  Kyle Meyer  <kyle@kyleam.com>
+2022-02-28  Kyle Meyer  <kyle@kyleam.com>
 
        Update to Org 9.5.2-22-g33543d
 
-2022-04-13  Dmitry Gutov  <dgutov@yandex.ru>
+2022-02-27  Dmitry Gutov  <dgutov@yandex.ru>
 
        Add explicit '--no-heading' for ripgrep
 
        * lisp/progmodes/xref.el (xref-search-program-alist):
        Add explicit '--no-heading' for ripgrep (bug#54177).
 
-2022-04-13  Michael Albinus  <michael.albinus@gmx.de>
+2022-02-26  Michael Albinus  <michael.albinus@gmx.de>
 
        Follow OpenSSH changes in Tramp
 
        * lisp/net/tramp-sh.el (tramp-ssh-controlmaster-options):
        Reimplement.  OpenSSH has changed its diagnostics messages.
 
-2022-04-13  Eli Zaretskii  <eliz@gnu.org>
+2022-02-26  Eli Zaretskii  <eliz@gnu.org>
 
        Document better how to reset attributes of faces for new frames
 
@@ -280,25 +1910,25 @@
        * lisp/faces.el (set-face-attribute): Explain how to reset an
        attribute's value for future frames.  (Bug#54156)
 
-2022-04-13  Michael Albinus  <michael.albinus@gmx.de>
+2022-02-25  Michael Albinus  <michael.albinus@gmx.de>
 
        * lisp/net/tramp-sh.el (tramp-ssh-controlmaster-options): Adapt test.
 
-2022-04-13  Lars Ingebrigtsen  <larsi@gnus.org>
+2022-02-24  Lars Ingebrigtsen  <larsi@gnus.org>
 
        Mention flyspell-prog-mode in flyspell-mode doc string
 
        * lisp/textmodes/flyspell.el (flyspell-mode): Mention
        flyspell-prog-mode (bug#54131).
 
-2022-04-13  Lars Ingebrigtsen  <larsi@gnus.org>
+2022-02-23  Lars Ingebrigtsen  <larsi@gnus.org>
 
        Reword face-remap-add-relative manual entry
 
        * doc/lispref/display.texi (Face Remapping): Clarify the
        face-remap-add-relative (bug#54114).
 
-2022-04-13  Philipp Stephani  <phst@google.com>
+2022-02-22  Philipp Stephani  <phst@google.com>
 
        Fix indexing of module functions that return enumeration types.
 
@@ -309,25 +1939,25 @@
        * doc/lispref/internals.texi (Module Misc, Module Nonlocal): Enclose
        multi-word return types in braces.
 
-2022-04-13  Eli Zaretskii  <eliz@gnu.org>
+2022-02-22  Eli Zaretskii  <eliz@gnu.org>
 
        * doc/misc/transient.texi (Other Options): Fix a @ref.  (Bug#54108)
 
-2022-04-13  Glenn Morris  <rgm@gnu.org>
+2022-02-22  Glenn Morris  <rgm@gnu.org>
 
        tramp.texi texinfo 4.13 compatibility
 
        * doc/misc/tramp.texi (Frequently Asked Questions):
        Restore compatibility with Texinfo < 5.
 
-2022-04-13  Michael Albinus  <michael.albinus@gmx.de>
+2022-02-22  Michael Albinus  <michael.albinus@gmx.de>
 
        Explain "Tramp" spelling in its manual
 
        * doc/misc/tramp.texi (Frequently Asked Questions):
        Explain "Tramp" spelling.
 
-2022-04-13  Eli Zaretskii  <eliz@gnu.org>
+2022-02-21  Eli Zaretskii  <eliz@gnu.org>
 
        Fix 'display-line-numbers-mode' in hide-show buffers
 
@@ -336,25 +1966,25 @@
        'display-line-numbers-mode' is turned on in the buffer.
        (Bug#54091)
 
-2022-04-13  Martin Rudalics  <rudalics@gmx.at>
+2022-02-21  Martin Rudalics  <rudalics@gmx.at>
 
        Don't check whether a deleted window is deletable (Bug#54028)
 
        * lisp/window.el (window-state-put): Make sure window is live
        before calling 'window-deletable-p' on it (Bug#54028).
 
-2022-04-13  Eli Zaretskii  <eliz@gnu.org>
+2022-02-21  Eli Zaretskii  <eliz@gnu.org>
 
        A friendlier error message from image-mode in an empty buffer
 
        * lisp/image-mode.el (image-mode): Handle the case where the empty
        buffer doesn't visit a file  (Bug#54084)
 
-2022-04-13  Kyle Meyer  <kyle@kyleam.com>
+2022-02-20  Kyle Meyer  <kyle@kyleam.com>
 
        Update to Org 9.5.2-17-gea6b74
 
-2022-04-13  Eli Zaretskii  <eliz@gnu.org>
+2022-02-18  Eli Zaretskii  <eliz@gnu.org>
 
        Improve documentation of filling and justification commands
 
@@ -366,11 +1996,11 @@
        (set-justification-left, set-justification-right)
        (set-justification-full): Improve wording of doc strings.
 
-2022-04-13  Eli Zaretskii  <eliz@gnu.org>
+2022-02-18  Eli Zaretskii  <eliz@gnu.org>
 
        * lisp/progmodes/subword.el (superword-mode): Doc fix.  (Bug#54045)
 
-2022-04-13  Philipp Stephani  <phst@google.com>
+2022-02-17  Philipp Stephani  <phst@google.com>
 
        Fix indexing of module functions that return complex types.
 
@@ -381,7 +2011,7 @@
        * doc/lispref/internals.texi (Module Values): Enclose multi-word
        return types in braces.
 
-2022-04-13  Po Lu  <luangruo@yahoo.com>
+2022-02-17  Po Lu  <luangruo@yahoo.com>
 
        Prevent crashes caused by invalid locale coding systems
 
@@ -391,25 +2021,25 @@
 
        Do not merge to master.
 
-2022-04-13  Michael Albinus  <michael.albinus@gmx.de>
+2022-02-15  Michael Albinus  <michael.albinus@gmx.de>
 
        Fix problem with popd for in remote shell buffers
 
        * lisp/shell.el (shell-prefixed-directory-name):
        Use `file-local-name' for DIR.  (Bug#53927)
 
-2022-04-13  Jonas Bernoulli  <jonas@bernoul.li>
+2022-02-15  Jonas Bernoulli  <jonas@bernoul.li>
 
        Import texi source file for transient manual
 
        * doc/misc/Makefile.in: Add transient to INFO_COMMON.
        * doc/misc/transient.texi: New file.
 
-2022-04-13  Kyle Meyer  <kyle@kyleam.com>
+2022-02-13  Kyle Meyer  <kyle@kyleam.com>
 
        Update to Org 9.5.2-15-gc5ceb6
 
-2022-04-13  Eli Zaretskii  <eliz@gnu.org>
+2022-02-13  Eli Zaretskii  <eliz@gnu.org>
 
        Fix 'exchange-point-and-mark' in 'transient-mark-mode'
 
@@ -418,7 +2048,7 @@
 
        (cherry picked from commit 415ed4b42515ff2e6dd9b94e964b479e50c6392e)
 
-2022-04-13  Eli Zaretskii  <eliz@gnu.org>
+2022-02-13  Eli Zaretskii  <eliz@gnu.org>
 
        Fix "C-SPC C-SPC" after "C-x C-x"
 
@@ -427,31 +2057,31 @@
 
        (cherry picked from commit 19c6cad1821eb896b2ddd0f6eab030f0880ea254)
 
-2022-04-13  Eli Zaretskii  <eliz@gnu.org>
+2022-02-13  Eli Zaretskii  <eliz@gnu.org>
 
        Fix a typo in fontset.el
 
        * lisp/international/fontset.el (xlfd-regexp-spacing-subnum): Fix
        a typo.  Reported by Greg A. Woods <woods@robohack.ca>.
 
-2022-04-13  Eli Zaretskii  <eliz@gnu.org>
+2022-02-12  Eli Zaretskii  <eliz@gnu.org>
 
        Note in ELisp manual that too-wide images are truncated
 
        * doc/lispref/display.texi (Showing Images): Note that images are
        truncated at the window's edge.  (Bug#53952)
 
-2022-04-13  Andrea Corallo  <akrl@sdf.org>
+2022-02-11  Andrea Corallo  <akrl@sdf.org>
 
        * lisp/mail/emacsbug.el (report-emacs-bug): Report libgccjit status.
 
        * lisp/startup.el (normal-top-level): Small code move, improve 
202d3be873.
 
-2022-04-13  Andrea Corallo  <akrl@sdf.org>
+2022-02-10  Andrea Corallo  <akrl@sdf.org>
 
        * lisp/startup.el (normal-top-level): Disable native-comp if not 
available
 
-2022-04-13  Andrea Corallo  <akrl@sdf.org>
+2022-02-09  Andrea Corallo  <akrl@sdf.org>
 
        Fix integer arithmetic miss-compilation (bug#53451)
 
@@ -461,14 +2091,14 @@
        * test/src/comp-tests.el (comp-tests-type-spec-tests): Add test to
        verify this is effective.
 
-2022-04-13  Robert Pluim  <rpluim@gmail.com>
+2022-02-08  Robert Pluim  <rpluim@gmail.com>
 
        Mark flymake as compatible with emacs-26.1
 
        * lisp/progmodes/flymake.el: Bump package version and set
        emacs version in Package-Requires to 26.1 (Bug#53853).
 
-2022-04-13  Brian Leung  <leungbk@posteo.net>
+2022-02-08  Brian Leung  <leungbk@posteo.net>
 
        flymake: Ensure compatibility with older Emacsen
 
@@ -476,7 +2106,7 @@
        replace-regexp-in-string instead of Emacs 28's
        string-replace (bug#53853).
 
-2022-04-13  Eric Abrahamsen  <eric@ericabrahamsen.net>
+2022-02-07  Eric Abrahamsen  <eric@ericabrahamsen.net>
 
        Don't remove dummy.group from gnus-newsrc-alist on Gnus save
 
@@ -486,20 +2116,20 @@
        function was removing dummy.group from the global value of
        `gnus-newsrc-alist' on save; we only wanted to remove it temporarily.
 
-2022-04-13  Bob Rogers  <rogers@rgrjr.com>
+2022-02-05  Bob Rogers  <rogers@rgrjr.com>
 
        Fix ietf-drums-get-comment doc string
 
        * lisp/mail/ietf-drums.el (ietf-drums-get-comment):  We really return
        the last comment (bug#53810).
 
-2022-04-13  Daniel Martín  <mardani29@yahoo.es>
+2022-02-05  Daniel Martín  <mardani29@yahoo.es>
 
        Fix typo in display.texi
 
        * doc/lispref/display.texi (Making Buttons): Fix typo.  (Bug#53807)
 
-2022-04-13  Michael Albinus  <michael.albinus@gmx.de>
+2022-02-03  Michael Albinus  <michael.albinus@gmx.de>
 
        Revert an erroneous change in tramp-cache.el
 
@@ -507,7 +2137,7 @@
        Use `string-match-p' instead of `string-search'.  The latter one
        was introduced by accident.  Reported by Kai Tetzlaff <kai@tetzlaff.eu>.
 
-2022-04-13  Eli Zaretskii  <eliz@gnu.org>
+2022-02-02  Eli Zaretskii  <eliz@gnu.org>
 
        Improve documentation of 'emacs-version'
 
@@ -516,11 +2146,11 @@
 
        * lisp/version.el (emacs-version): Improve doc string.  (Bug#53720)
 
-2022-04-13  Michael Albinus  <michael.albinus@gmx.de>
+2022-02-01  Michael Albinus  <michael.albinus@gmx.de>
 
        * etc/NEWS: Apply final fixes after proofreading.
 
-2022-04-13  Eli Zaretskii  <eliz@gnu.org>
+2022-01-31  Eli Zaretskii  <eliz@gnu.org>
 
        Clarify documentation of a "face's font"
 
@@ -529,7 +2159,7 @@
        the font returned by 'face-font' are by default for ASCII
        characters.  (Bug#53664)
 
-2022-04-13  Alan Mackenzie  <acm@muc.de>
+2022-01-31  Alan Mackenzie  <acm@muc.de>
 
        Bind Qdebugger to Qdebug in signal_or_quit.
 
@@ -537,18 +2167,18 @@
        Vdebugger) to Qdebug in the section for errors in batch jobs.
        (syms_of_eval): New DEFSYM for Qdebugger.
 
-2022-04-13  Kyle Meyer  <kyle@kyleam.com>
+2022-01-30  Kyle Meyer  <kyle@kyleam.com>
 
        Update to Org 9.5.2-13-gdd6486
 
-2022-04-13  Eli Zaretskii  <eliz@gnu.org>
+2022-01-30  Eli Zaretskii  <eliz@gnu.org>
 
        Fix regression in Occur Edit mode
 
        * lisp/replace.el (occur-after-change-function): Fix the algorithm
        to find the smallest change in some corner cases.  (Bug#53598)
 
-2022-04-13  Eli Zaretskii  <eliz@gnu.org>
+2022-01-29  Eli Zaretskii  <eliz@gnu.org>
 
        Fix last change of Malayalam composition rules
 
@@ -557,7 +2187,7 @@
        Malayalam characters to the existing patterns, so as not
        to lose the patterns that use ZWJ and ZWNJ.  (Bug#53625)
 
-2022-04-13  Eli Zaretskii  <eliz@gnu.org>
+2022-01-29  Eli Zaretskii  <eliz@gnu.org>
 
        Fix rendering of Malayalam script
 
@@ -566,21 +2196,21 @@
        Instead, pass any sequence of Malayalam codepoints to the shaping
        engine.  (Bug#53625)
 
-2022-04-13  Eli Zaretskii  <eliz@gnu.org>
+2022-01-29  Eli Zaretskii  <eliz@gnu.org>
 
        Improve documentation of Occur mode
 
        * doc/emacs/search.texi (Other Repeating Search): Improve wording
        and document Occur Edit mode better.
 
-2022-04-13  Alan Third  <alan@idiocy.org>
+2022-01-29  Alan Third  <alan@idiocy.org>
 
        Remove debug logging
 
        * src/nsterm.m ([EmacsView copyRect:to:]): Remove logging as it's no
        longer required.
 
-2022-04-13  Michael Albinus  <michael.albinus@gmx.de>
+2022-01-29  Michael Albinus  <michael.albinus@gmx.de>
 
        Fix error in filelock.c
 
@@ -590,11 +2220,11 @@
        (Flock_file): Do not check for create_lockfiles.  Call file name
        handler if appropriate.  (Bug#53207)
 
-2022-04-13  Juri Linkov  <juri@linkov.net>
+2022-01-27  Juri Linkov  <juri@linkov.net>
 
        * lisp/frame.el (clone-frame): Filter out 'parent-id' (bug#51883).
 
-2022-04-13  Lars Ingebrigtsen  <larsi@gnus.org>
+2022-01-26  Lars Ingebrigtsen  <larsi@gnus.org>
 
        Partially revert a fill-region-as-paragraph regression
 
@@ -602,14 +2232,14 @@
        e186af261 (bug#53537), because it leads to regressions.  (But
        leave tests in place.)
 
-2022-04-13  Eli Zaretskii  <eliz@gnu.org>
+2022-01-26  Eli Zaretskii  <eliz@gnu.org>
 
        Fix 'make_lispy_position' when there's an image at EOB
 
        * src/xdisp.c (move_it_to): Don't compare IT_CHARPOS with an
        invalid TO_CHARPOS.  (Bug#53546)
 
-2022-04-13  Lars Ingebrigtsen  <larsi@gnus.org>
+2022-01-26  Lars Ingebrigtsen  <larsi@gnus.org>
 
        Fix copyright-find-copyright when searching from the end
 
@@ -618,7 +2248,7 @@
 
        Do not merge to master.
 
-2022-04-13  Lars Ingebrigtsen  <larsi@gnus.org>
+2022-01-26  Lars Ingebrigtsen  <larsi@gnus.org>
 
        Fix copyright.el comment and add a test
 
@@ -627,18 +2257,18 @@
 
        Do not merge to master.
 
-2022-04-13  Philipp Stephani  <phst@google.com>
+2022-01-24  Philipp Stephani  <phst@google.com>
 
        * configure.ac (LIBSECCOMP): Bump minimum version for faccessat2.
 
-2022-04-13  Lars Ingebrigtsen  <larsi@gnus.org>
+2022-01-24  Lars Ingebrigtsen  <larsi@gnus.org>
 
        Make the `f' command work in image-mode again
 
        * lisp/image.el (image-show-frame): Protect against not having
        computed the animation data yed (bug#53489).
 
-2022-04-13  Philipp Stephani  <phst@google.com>
+2022-01-22  Philipp Stephani  <phst@google.com>
 
        Seccomp: improve support for newer versions of glibc (Bug#51073)
 
@@ -647,14 +2277,14 @@
        with commits 95c1056962a3f2297c94ce47f0eaf0c5b6563231 and
        3d3ab573a5f3071992cbc4f57d50d1d29d55bde2, respectively).
 
-2022-04-13  Thomas Fitzsimmons  <fitzsim@fitzsim.org>
+2022-01-21  Thomas Fitzsimmons  <fitzsim@fitzsim.org>
 
        EUDC: Fix a quoting bug in the BBDB backend
 
        * lisp/net/eudcb-bbdb.el (eudc-bbdb-query-internal): Fix a quoting
        bug introduced during lexical-binding conversion.
 
-2022-04-13  Sergey Vinokurov  <serg.foo@gmail.com>
+2022-01-21  Sergey Vinokurov  <serg.foo@gmail.com>
 
        Fix memory-report-object-size to initialize memory-report--type-size
 
@@ -663,7 +2293,7 @@
 
        Do not merge to master.
 
-2022-04-13  Stefan Monnier  <monnier@iro.umontreal.ca>
+2022-01-20  Stefan Monnier  <monnier@iro.umontreal.ca>
 
        Fix menu-bar mouse clicks in "C-h c" and "C-h k" (bug#53322)
 
@@ -674,7 +2304,7 @@
 
        (cherry picked from commit 9ceb3070e34ad8a54184fd0deda477bf5ff77000)
 
-2022-04-13  Eli Zaretskii  <eliz@gnu.org>  (tiny change)
+2022-01-20  Eli Zaretskii  <eliz@gnu.org>  (tiny change)
 
        Fix UB in ebrowse
 
@@ -682,14 +2312,14 @@
        limits of 'matching_regexp_buffer'.  Patch by Jan Stranik
        <jan@stranik.org>.  (Bug#53333)
 
-2022-04-13  Lars Ingebrigtsen  <larsi@gnus.org>
+2022-01-20  Lars Ingebrigtsen  <larsi@gnus.org>
 
        Fix execute-extended-command-for-buffer in fundamental-mode
 
        * lisp/simple.el (execute-extended-command-for-buffer): Protect
        against the current local map being nil (bug#52907).
 
-2022-04-13  Martin Rudalics  <rudalics@gmx.at>
+2022-01-20  Martin Rudalics  <rudalics@gmx.at>
 
        Add workaround to handle a problem with Enlightenment WM (Bug#53298)
 
@@ -702,14 +2332,14 @@
        Enlightenment WM and 'x-set-frame-visibility-more-laxly'
        workaround.
 
-2022-04-13  Po Lu  <luangruo@yahoo.com>
+2022-01-17  Po Lu  <luangruo@yahoo.com>
 
        Fix regression leading to flickering tooltips when the mouse is moved
 
        * lisp/tooltip.el (tooltip-show-help): Compare string with
        previous tooltip string ignoring properties.
 
-2022-04-13  Andrea Corallo  <akrl@sdf.org>
+2022-01-17  Andrea Corallo  <akrl@sdf.org>
 
        * Fix native comp for non trivial function names (bug#52833)
 
@@ -721,15 +2351,15 @@
 
        Do not merge to master
 
-2022-04-13  Kyle Meyer  <kyle@kyleam.com>
+2022-01-15  Kyle Meyer  <kyle@kyleam.com>
 
        Update to Org 9.5.2-9-g7ba24c
 
-2022-04-13  Juri Linkov  <juri@linkov.net>
+2022-01-15  Juri Linkov  <juri@linkov.net>
 
        * lisp/net/dictionary.el (dictionary-context-menu): Use package prefix.
 
-2022-04-13  Philipp Stephani  <phst@google.com>
+2022-01-15  Philipp Stephani  <phst@google.com>
 
        Mark a few more map tests as unstable on Emacs 28 (Bug#46722).
 
@@ -741,24 +2371,24 @@
        (test-map-merge, test-map-merge-with, test-map-merge-empty): Mark as
        unstable.
 
-2022-04-13  Philipp Stephani  <phst@google.com>
+2022-01-15  Philipp Stephani  <phst@google.com>
 
        * lisp/indent.el (tab-first-completion): Fix incorrect choices.
 
-2022-04-13  Philipp Stephani  <phst@google.com>
+2022-01-14  Philipp Stephani  <phst@google.com>
 
        * lisp/simple.el (undo-no-redo): Fix customization group
 
        * lisp/progmodes/xref.el (xref-file-name-display): Fix docstring.
 
-2022-04-13  Eli Zaretskii  <eliz@gnu.org>
+2022-01-14  Eli Zaretskii  <eliz@gnu.org>
 
        Avoid another segfault in 'face_at_buffer_position'
 
        * src/xfaces.c (face_at_buffer_position): Make really sure the
        default face is usable.  (Bug#53254)
 
-2022-04-13  Lars Ingebrigtsen  <larsi@gnus.org>
+2022-01-14  Lars Ingebrigtsen  <larsi@gnus.org>
 
        Mark test-map-into as unstable
 
@@ -767,7 +2397,7 @@
 
        Do not merge to master.
 
-2022-04-13  Philipp Stephani  <phst@google.com>
+2022-01-13  Philipp Stephani  <phst@google.com>
 
        Fix Edebug specification for inline functions (Bug#53068).
 
@@ -776,7 +2406,7 @@
        * test/lisp/emacs-lisp/edebug-tests.el (edebug-tests-inline): New unit
        test.
 
-2022-04-13  N. Jackson  <nljlistbox2@gmail.com>
+2022-01-13  N. Jackson  <nljlistbox2@gmail.com>
 
        Remove mention of removed `gnus-treat-play-sounds' variable from manual
 
@@ -784,7 +2414,7 @@
        manual. According to lisp/gnus/ChangeLog.3 this variable was
        removed in 2010 (bug#53192).
 
-2022-04-13  Mattias Engdegård  <mattiase@acm.org>
+2022-01-12  Mattias Engdegård  <mattiase@acm.org>
 
        Revert "Fix closure-conversion of shadowed captured lambda-lifted vars"
 
@@ -793,18 +2423,18 @@
        It was committed to a stable branch without prior discussion;
        see bug#53071.
 
-2022-04-13  Juri Linkov  <juri@linkov.net>
+2022-01-12  Juri Linkov  <juri@linkov.net>
 
        * doc/lispref/windows.texi (Textual Scrolling): Remove obsolete text.
 
        Remove text about scrolling the minibuffer from the buffer,
        obsolete since Emacs 27 (bug#51210).
 
-2022-04-13  Glenn Morris  <rgm@gnu.org>
+2022-01-12  Glenn Morris  <rgm@gnu.org>
 
        * lisp/files.el (lock-file-name-transforms): Doc tweaks.
 
-2022-04-13  Mattias Engdegård  <mattiase@acm.org>
+2022-01-12  Mattias Engdegård  <mattiase@acm.org>
 
        Fix closure-conversion of shadowed captured lambda-lifted vars
 
@@ -823,7 +2453,7 @@
 
        (cherry picked from commit 45252ad8f932c98a373ef0ab7f3363a3e27ccbe4)
 
-2022-04-13  Philipp Stephani  <phst@google.com>
+2022-01-12  Philipp Stephani  <phst@google.com>
 
        Fix test lisp/cedet/semantic/bovine/gcc-tests on macOS (Bug#52431)
 
@@ -833,7 +2463,7 @@
 
        (cherry picked from commit 6e52becfbe2a33c025b8c4838b3c8f06ba5a6fb8)
 
-2022-04-13  Mattias Engdegård  <mattiase@acm.org>
+2022-01-12  Mattias Engdegård  <mattiase@acm.org>
 
        Don't fail flymake-tests if `gcc` actually is Clang
 
@@ -843,7 +2473,7 @@
 
        (cherry picked from commit b2167d98432a78442522b7564e22f47d75a98b6f)
 
-2022-04-13  Eli Zaretskii  <eliz@gnu.org>
+2022-01-10  Eli Zaretskii  <eliz@gnu.org>
 
        Revert "Remove the filename argument from the command line after an 
ELC+ELN build"
 
@@ -852,14 +2482,14 @@
        Please don't install anything non-trivial on the release branch
        without asking first.
 
-2022-04-13  Alan Mackenzie  <acm@muc.de>
+2022-01-10  Alan Mackenzie  <acm@muc.de>
 
        Remove the filename argument from the command line after an ELC+ELN 
build
 
        This fixes bug #53164.  Without this fix, bootstrap-emacs loads the 
source
        file uselessly into a buffer after completing the compilation.
 
-2022-04-13  Stefan Monnier  <monnier@iro.umontreal.ca>
+2022-01-09  Stefan Monnier  <monnier@iro.umontreal.ca>
 
        (save-some-buffers): Simplify the fix for bug#46374
 
@@ -872,14 +2502,14 @@
        with `pred` set to `save-some-buffers-root` since it's not an
        appropriate function for that any more.
 
-2022-04-13  Stefan Kangas  <stefan@marxist.se>
+2022-01-09  Stefan Kangas  <stefan@marxist.se>
 
        Improve docstring of edit-abbrevs
 
        * lisp/abbrev.el (edit-abbrevs): Doc fix; don't use obsolete name.
        Improve docstring formatting.
 
-2022-04-13  Eli Zaretskii  <eliz@gnu.org>
+2022-01-09  Eli Zaretskii  <eliz@gnu.org>
 
        Revert "Fix alignment on font size change in tabulated-list-mode"
 
@@ -888,21 +2518,21 @@
        That change caused a regression in a much more important use
        case, see bug#53133.
 
-2022-04-13  Stefan Kangas  <stefan@marxist.se>
+2022-01-08  Stefan Kangas  <stefan@marxist.se>
 
        Clarify docstring of package-native-compile
 
        * lisp/emacs-lisp/package.el (package-native-compile): Clarify
        docstring.
 
-2022-04-13  Eli Zaretskii  <eliz@gnu.org>
+2022-01-08  Eli Zaretskii  <eliz@gnu.org>
 
        Fix Subject "simplification" in Rmail
 
        * lisp/mail/rmail.el (rmail-simplified-subject): Match against
        "[external]" _after_ decoding the Subject by RFC-2047.
 
-2022-04-13  Stefan Kangas  <stefan@marxist.se>
+2022-01-08  Stefan Kangas  <stefan@marxist.se>
 
        Bump Emacs version to 28.0.91
 
@@ -1021,7 +2651,7 @@
        This fixes bug #52796.
 
        * lisp/progmodes/cc-engine.el (c-update-brace-stack): Handle a "*" like 
a
-       semicolon, cancelling the expectation of a brace.
+       semicolon, canceling the expectation of a brace.
 
        * lisp/progmodes/cc-langs.el (c-brace-stack-thing-key): Add a "*" into 
the
        sets of significant characters.
@@ -1053,7 +2683,7 @@
 
 2021-12-27  Eli Zaretskii  <eliz@gnu.org>
 
-       Fix typos in in 'reset-language-environment'
+       Fix typos in 'reset-language-environment'
 
        * lisp/international/mule-cmds.el (reset-language-environment):
        Fix a typo in 'windows-nt'.  (Bug#52816)
@@ -1595,7 +3225,7 @@
 
 2021-12-01  Alan Mackenzie  <acm@muc.de>
 
-       CC Mode: Recognise "struct foo {" as introducing a type declaration
+       CC Mode: Recognize "struct foo {" as introducing a type declaration
 
        This fixes bug #52157.
 
@@ -1681,7 +3311,7 @@
 
 2021-11-29  Andreas Schwab  <schwab@linux-m68k.org>
 
-       Avoid undefined behaviour when copying part of structure
+       Avoid undefined behavior when copying part of structure
 
        * src/dispnew.c (copy_row_except_pointers): Don't use address of
        subobject as starting point.
@@ -4838,14 +6468,14 @@
        Fix previous `newline' patch
 
        * lisp/simple.el (newline): Signal an error earlier to avoid
-       peculiar behaviour after getting a backtrace (bug#50900).
+       peculiar behavior after getting a backtrace (bug#50900).
 
 2021-09-30  Lars Ingebrigtsen  <larsi@gnus.org>
 
        Make `newline' check the argument earlier
 
        * lisp/simple.el (newline): Signal an error earlier to avoid
-       peculiar behaviour after getting a backtrace (bug#50900).
+       peculiar behavior after getting a backtrace (bug#50900).
 
 2021-09-30  akater  <nuclearspace@gmail.com>
 
@@ -5026,7 +6656,7 @@
          etc/themes/modus-vivendi-theme.el: Bump file version.
 
        * etc/themes/modus-themes.el (modus-themes-operandi-colors)
-       (modus-themes-vivendi-colors): Recalibrate some colour values and add
+       (modus-themes-vivendi-colors): Recalibrate some color values and add
        a few new ones.
        (modus-themes-slanted-constructs): Remove obsolete user option.
        Superseded by the alias 'modus-themes-italic-constructs'.
@@ -5882,11 +7512,11 @@
 
        Fix byte-compiler crash for legal dynamic-binding code
 
-       This should really be taken care of by a syntax normalisation step in
+       This should really be taken care of by a syntax normalization step in
        the frontend, but there is no such step for non-lexbind code yet.
 
        * lisp/emacs-lisp/byte-opt.el (byte-optimize-letX): Tolerate bindingsa
-       without initialising expressions.
+       without initializing expressions.
        * test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-tests--test-cases):
        Add test cases.
 
@@ -6945,7 +8575,7 @@
 
        This reverts commit 7e395a59b025c7f4be49294ad806addf5b1a25c9.
 
-       The behaviour change isn't good for the majority of tar files.
+       The behavior change isn't good for the majority of tar files.
 
 2021-09-21  Lars Ingebrigtsen  <larsi@gnus.org>
 
@@ -6957,10 +8587,10 @@
 
 2021-09-21  Lars Ingebrigtsen  <larsi@gnus.org>
 
-       Restore some of the previous behaviour in whitespace-display-window
+       Restore some of the previous behavior in whitespace-display-window
 
        * lisp/whitespace.el (whitespace-display-window): Emulate previous
-       behaviour (bug#50716).  Code from martin rudalics <rudalics@gmx.at>.
+       behavior (bug#50716).  Code from martin rudalics <rudalics@gmx.at>.
 
 2021-09-21  Lars Ingebrigtsen  <larsi@gnus.org>
 
@@ -7177,7 +8807,7 @@
 
        Add docstring for 'electric-pair-p-s-i-f' and minor refactor
 
-       Extract the "open newline between pairs behaviour" into its own
+       Extract the "open newline between pairs behavior" into its own
        function, electric-pair-open-newline-between-pairs-psif.
 
        * lisp/elec-pair.el (electric-pair-post-self-insert-function): Add
@@ -7417,7 +9047,7 @@
 
 2021-09-20  Philip Kaludercic  <philipk@posteo.net>
 
-       Fix dolist-with-progress-reporter behaviour
+       Fix dolist-with-progress-reporter behavior
 
        * lisp/subr.el (dolist-with-progress-reporter): Use the length of
        list argument as maximal value the reporter with reach.
@@ -7502,17 +9132,17 @@
 
 2021-09-19  Mattias Engdegård  <mattiase@acm.org>
 
-       Initialise unread buffer
+       Initialize unread buffer
 
        The reader has an extra 1-char unread buffer that was incorrectly
-       initialised to 0, which means that the first character read would
+       initialized to 0, which means that the first character read would
        always be NUL.  As this is often the code that looks for the
        lexical-binding cookie, the first loaded source module would be
        treated as dynamically bound.  During bootstrapping this is loadup.el
        and so its local variables got dumped into the global environment.
 
-       * src/lread.c (unread_char): Initialise to empty.
-       (Fload): Initialise here too just in case.
+       * src/lread.c (unread_char): Initialize to empty.
+       (Fload): Initialize here too just in case.
 
 2021-09-19  Stefan Kangas  <stefan@marxist.se>
 
@@ -9487,11 +11117,11 @@
 
        Replace uses of a variable aliasing another variable with that aliased
        variable, to allow for variable removal when possible.  This also
-       enables opportunities for other optimisations.  Example:
+       enables opportunities for other optimizations.  Example:
 
         (let ((y x)) (f y)) => (f x)
 
-       The optimisation is only performed if both aliased and aliasing
+       The optimization is only performed if both aliased and aliasing
        variables are lexically bound.  Shadowing bindings are α-renamed when
        necessary for correctness.  Example:
 
@@ -9501,7 +11131,7 @@
        * lisp/emacs-lisp/byte-opt.el (byte-optimize--aliased-vars): New.
        (byte-optimize-form-code-walker): Cancel aliasing upon mutation.
        (byte-optimize--rename-var-body, byte-optimize--rename-var): New.
-       (byte-optimize-let-form): Add the optimisation.
+       (byte-optimize-let-form): Add the optimization.
        * test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-tests--test-cases):
        Add relevant test cases.
 
@@ -10235,31 +11865,31 @@
 
 2021-09-06  Mattias Engdegård  <mattiase@acm.org>
 
-       Normalise nested `progn` forms in byte-code optimiser
+       Normalize nested `progn` forms in byte-code optimizer
 
        * lisp/emacs-lisp/byte-opt.el (byte-optimize-body): Flatten body.
        This simplifies the source tree and reduces the number of different
-       cases that other optimisations need to take into account.
+       cases that other optimizations need to take into account.
 
 2021-09-06  Mattias Engdegård  <mattiase@acm.org>
 
-       More robust optimisation of `ignore`
+       More robust optimization of `ignore`
 
-       Treat `ignore` as any other function during source-level optimisation,
-       to avoid having its warning-suppression effects cancelled by repeated
+       Treat `ignore` as any other function during source-level optimization,
+       to avoid having its warning-suppression effects canceled by repeated
        passes.  Instead, define a custom code generation function.
 
        * lisp/emacs-lisp/byte-opt.el (byte-optimize-form-code-walker):
        Don't treat `ignore' specially here.
        (side-effect-free-fns): Don't mark `ignore` as side-effect-free
-       or error-free (although it is), since that would allow the optimiser
+       or error-free (although it is), since that would allow the optimizer
        to elide calls.
        * lisp/emacs-lisp/bytecomp.el (ignore, byte-compile-ignore):
        Define and register a code-gen function.
 
 2021-09-06  Mattias Engdegård  <mattiase@acm.org>
 
-       Optimise `member` and `assoc` (etc) with constant empty list
+       Optimize `member` and `assoc` (etc) with constant empty list
 
        * lisp/emacs-lisp/byte-opt.el
        (byte-optimize-assq): New.
@@ -11497,7 +13127,7 @@
 
        This reverts commit c8e3347ec01a9ed6dc8d88c2dbbb3a08497e8eb2.
 
-       Jim Porter's paperwork isn't finalised yet.
+       Jim Porter's paperwork isn't finalized yet.
 
 2021-08-26  Lars Ingebrigtsen  <larsi@gnus.org>
 
@@ -14236,7 +15866,7 @@
        Fix automatic hscrolling when line numbers are displayed
 
        * src/xdisp.c (hscroll_window_tree): When line numbers are
-       displayed, account for the the line-number space when calculating
+       displayed, account for the line-number space when calculating
        the desired X coordinate on the left.  (Bug#49891)
 
 2021-08-06  Eli Zaretskii  <eliz@gnu.org>
@@ -14344,11 +15974,11 @@
 
        The current method of propagating constants through setq was unsound
        because it relied on each setq form only being traversed at most once
-       during optimisation, which isn't necessarily true in general; it could
+       during optimization, which isn't necessarily true in general; it could
        be made to miscompile code in rare cases.
 
        Since it was only used in limited circumstances, disabling this
-       optimisation doesn't cost us much.
+       optimization doesn't cost us much.
 
        * lisp/emacs-lisp/byte-opt.el (byte-optimize-form-code-walker):
        Don't update the known value when traversing `setq`.
@@ -14586,7 +16216,7 @@
 
 2021-08-03  Phil Sainty  <psainty@orcon.net.nz>
 
-       Make `global-so-long-mode' handle unrecognised file types
+       Make `global-so-long-mode' handle unrecognized file types
 
        * lisp/so-long.el (so-long-target-modes): Add `fundamental-mode'
 
@@ -15076,16 +16706,16 @@
 
        Ensure in cconv that let-bindings have the normal form (VAR EXPR)
        where VAR is a valid variable name, so that we don't need to keep
-       re-checking this all the time in the optimiser.
+       re-checking this all the time in the optimizer.
 
        * lisp/emacs-lisp/byte-opt.el
        (byte-optimize-enable-variable-constprop)
        (byte-optimize-warn-eliminated-variable): Remove; these were mainly
        used for debugging.
        * lisp/emacs-lisp/byte-opt.el (byte-optimize-let-form):
-       Assume normalised let-bindings (with lexical-binding).
+       Assume normalized let-bindings (with lexical-binding).
        Stop using the variables removed above.
-       * lisp/emacs-lisp/cconv.el (cconv-convert): Ensure normalised
+       * lisp/emacs-lisp/cconv.el (cconv-convert): Ensure normalized
        let-bindings.  Malformed bindings are dropped after warning.
 
        remove byte-optimize-warn-eliminated-variable
@@ -15177,7 +16807,7 @@
 
 2021-07-30  Mattias Engdegård  <mattiase@acm.org>
 
-       Optimise let and let* whose body is constant or the last variable
+       Optimize let and let* whose body is constant or the last variable
 
        Simplify  (let ((X1 E1) ... (Xn En)) Xn)
              =>  (progn E1 ... En)
@@ -15186,9 +16816,9 @@
              =>  (let* ((X1 E1) ... (Xn-1 En-1)) En)
 
        and similarly the case where the body is a constant, extending a
-       previous optimisation that only applied to the constant nil.
+       previous optimization that only applied to the constant nil.
        This reduces the number of bound variables, shortens the code, and
-       enables further optimisations.
+       enables further optimizations.
 
        * lisp/emacs-lisp/byte-opt.el (byte-optimize-letX): Rewrite using
        `pcase` and add the aforementioned transformations.
@@ -15197,7 +16827,7 @@
 
 2021-07-30  Mattias Engdegård  <mattiase@acm.org>
 
-       Move warnings about bad let-bindings from source optimiser to cconv
+       Move warnings about bad let-bindings from source optimizer to cconv
 
        * lisp/emacs-lisp/byte-opt.el (byte-optimize-let-form): Move warnings...
        * lisp/emacs-lisp/cconv.el (cconv-convert): ...here, which is an
@@ -15205,7 +16835,7 @@
 
 2021-07-30  Mattias Engdegård  <mattiase@acm.org>
 
-       Optimise prog1 better
+       Optimize prog1 better
 
        Rewrite (prog1 CONST FORMS...) => (progn FORMS... CONST)
        where CONST is a compile-time constant, because putting the value last
@@ -15217,23 +16847,23 @@
 
 2021-07-30  Mattias Engdegård  <mattiase@acm.org>
 
-       Elide lexical variables in for-effect context in source optimiser
+       Elide lexical variables in for-effect context in source optimizer
 
        * lisp/emacs-lisp/byte-opt.el (byte-optimize-form-code-walker):
        Remove for-effect uses of lexical variables.  We previously relied on
-       this being done by the lapcode peephole optimiser but at source level
-       it enables more optimisation opportunities.
+       this being done by the lapcode peephole optimizer but at source level
+       it enables more optimization opportunities.
        Keywords are elided for the same reason.
 
 2021-07-30  Mattias Engdegård  <mattiase@acm.org>
 
-       Single source optimiser entry point
+       Single source optimizer entry point
 
-       Make the optimiser aware of lexical arguments.  Otherwise we cannot
+       Make the optimizer aware of lexical arguments.  Otherwise we cannot
        know for sure whether a variable is lexical or dynamic during
        traversal.
 
-       * lisp/emacs-lisp/byte-opt.el (byte-optimize-one-form): New optimiser
+       * lisp/emacs-lisp/byte-opt.el (byte-optimize-one-form): New optimizer
        entry point, replacing the recursive byte-optimize-form.
        * lisp/emacs-lisp/bytecomp.el (byte-optimize-one-form): Autoload.
        (byte-compile-keep-pending, byte-compile-top-level):
@@ -16154,7 +17784,7 @@
 
        `term-char-mode' doc string clarification
 
-       * lisp/term.el (term-char-mode): Document behaviour (bug#49186).
+       * lisp/term.el (term-char-mode): Document behavior (bug#49186).
 
 2021-07-22  Dmitry Gutov  <dgutov@yandex.ru>
 
@@ -16391,14 +18021,14 @@
 
 2021-07-21  Mattias Engdegård  <mattiase@acm.org>
 
-       Fix mistake in `quote` optimiser
+       Fix mistake in `quote` optimizer
 
        Found by Pip Cet.
 
        * lisp/emacs-lisp/byte-opt.el (byte-optimize-quote): Fix mistake that
-       made this optimiser ineffective at removing quoting of nil, t, and
+       made this optimizer ineffective at removing quoting of nil, t, and
        keywords.  The only obvious consequence is that we no longer need...
-       (byte-optimize-form): ...a 'nil => nil normalising step here; remove.
+       (byte-optimize-form): ...a 'nil => nil normalizing step here; remove.
        (byte-optimize-form-code-walker): Make the compiler warn about (quote).
 
 2021-07-20  Juri Linkov  <juri@linkov.net>
@@ -16427,7 +18057,7 @@
 
        Strength-reduce (eq X nil) to (not X)
 
-       * lisp/emacs-lisp/byte-opt.el (byte-optimize-eq): New optimisation,
+       * lisp/emacs-lisp/byte-opt.el (byte-optimize-eq): New optimization,
        which results in better test and branch code generation where it
        applies.
 
@@ -17040,7 +18670,7 @@
 
        (Full support for packages or face groups): Include new items.
 
-       (Notes on individual packages): Add notes on Avy hints, the colour of
+       (Notes on individual packages): Add notes on Avy hints, the color of
        days in 'M-x calendar', and underlines in 'compilation-mode' buffers.
 
        (What is the best setup for legibility?): Remove single word.
@@ -18583,7 +20213,7 @@
        * etc/emacs-mail.desktop:
        * etc/emacsclient.desktop: Automatically try to
        reuse an existing frame, open a new frame, or start a new Emacs
-       daemon.  Add actions for specific behaviours (bug#49195).
+       daemon.  Add actions for specific behaviors (bug#49195).
 
 2021-06-30  Peter Oliver  <git@mavit.org.uk>
 
@@ -20650,7 +22280,7 @@
 
 2021-06-03  Mattias Engdegård  <mattiase@acm.org>
 
-       Optimise (cons X nil) to (list X)
+       Optimize (cons X nil) to (list X)
 
        * lisp/emacs-lisp/byte-opt.el (byte-optimize-cons): New function.
 
@@ -20913,7 +22543,7 @@
        When used with Fido, completions scroll like a typical dropdown
        widget.
 
-       If the dropdown behaviour is desired for Icomplete (instead of
+       If the dropdown behavior is desired for Icomplete (instead of
        rotation), icomplete-scroll can be adjusted separately by the user.
 
        * etc/NEWS (icomplete-vertical-mode): Reword.
@@ -21561,7 +23191,7 @@
 
        Don't propagate lexical variables into inlined functions
 
-       Functions compiled when inlined (thus from inside the optimiser)
+       Functions compiled when inlined (thus from inside the optimizer)
        mustn't retain the lexical environment of the caller or there will be
        tears.  See discussion at
        https://lists.gnu.org/archive/html/emacs-devel/2021-05/msg01227.html .
@@ -21805,7 +23435,7 @@
 
 2021-05-25  Miha Rihtaršič  <miha@kamnitnik.top>
 
-       Try to not prioritise reading from lower file descriptors
+       Try to not prioritize reading from lower file descriptors
 
        * src/process.c (wait_reading_process_output): When looping through
        fds, continue from where we left off.
@@ -24302,7 +25932,7 @@
 
 2021-05-04  Lars Ingebrigtsen  <larsi@gnus.org>
 
-       Fix inconsistent behaviour in find-file-noselect when using nowarn
+       Fix inconsistent behavior in find-file-noselect when using nowarn
 
        * lisp/files.el (after-find-file): Behave the same in when
        warning/not warning (bug#47850).  This fixes this test case:
@@ -24372,7 +26002,7 @@
 2021-05-03  Alan Third  <alan@idiocy.org>
            martin rudalics  <rudalics@gmx.at>
 
-       Fix incorrect resizing behaviour on macOS (bug#48157, bug#48162)
+       Fix incorrect resizing behavior on macOS (bug#48157, bug#48162)
 
        * src/nsterm.m ([EmacsView viewDidResize:]): The drawing buffer can be
        resized independently of Emacs's idea of the frame size.
@@ -25946,7 +27576,7 @@
        * lisp/minibuffer.el (minibuffer--sort-by-length-alpha): New function.
        (minibuffer--sort-by-position): New function extracted from
        `completion-all-sorted-completions`.
-       (completion-all-sorted-completions): Use use them.
+       (completion-all-sorted-completions): Use them.
 
 2021-04-19  Daniel Mendler  <mail@daniel-mendler.de>
 
@@ -27427,10 +29057,10 @@
 
 2021-04-09  Mattias Engdegård  <mattiase@acm.org>
 
-       Fix condition-case optimiser bug
+       Fix condition-case optimizer bug
 
        * lisp/emacs-lisp/byte-opt.el (byte-optimize-form-code-walker): Don't
-       perform incorrect optimisations when a condition-case variable shadows
+       perform incorrect optimizations when a condition-case variable shadows
        another lexical variable.
        * test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-tests--test-cases):
        New test case.
@@ -27539,7 +29169,7 @@
 
        Self-TCO in `condition-case` error handlers
 
-       * lisp/emacs-lisp/cl-macs.el (cl--self-tco): Recognise
+       * lisp/emacs-lisp/cl-macs.el (cl--self-tco): Recognize
        `condition-case` handlers as being in the tail position.
        * test/lisp/emacs-lisp/cl-macs-tests.el (cl-macs--labels):
        Extend test.
@@ -28025,7 +29655,7 @@
 
 2021-04-05  Stefan Kangas  <stefan@marxist.se>
 
-       Remove local uniquify functions in favour of seq-uniq
+       Remove local uniquify functions in favor of seq-uniq
 
        * lisp/emacs-lisp/seq.el (seq-uniq): Add autoload cookie.
        * lisp/pcomplete.el: (pcomplete-uniquify-list): Use seq-uniq.
@@ -28051,7 +29681,7 @@
 
        Obsolete local list functions in shadowfile.el
 
-       * lisp/shadowfile.el (shadow-union): Make obsolete in favour of
+       * lisp/shadowfile.el (shadow-union): Make obsolete in favor of
        cl-union.  Update callers.
        (shadow-find): Make into obsolete function alias for seq-find.
        Update callers.
@@ -30354,7 +31984,7 @@
 
 2021-03-18  Mattias Engdegård  <mattiase@acm.org>
 
-       Optimise tail calls in `and` and `or` forms in `cl-labels` functions
+       Optimize tail calls in `and` and `or` forms in `cl-labels` functions
 
        * lisp/emacs-lisp/cl-macs.el (cl--self-tco): Handle `and` and `or`.
        * test/lisp/emacs-lisp/cl-macs-tests.el (cl-macs--labels):
@@ -30472,7 +32102,7 @@
 
 2021-03-18  Lars Ingebrigtsen  <larsi@gnus.org>
 
-       Recognise "Verify password" as a password prompt
+       Recognize "Verify password" as a password prompt
 
        * lisp/comint.el (comint-password-prompt-regexp): Also react to
        "Verify password" (output by "zip -e") (bug#47209).
@@ -34432,7 +36062,7 @@
 
        * lisp/emacs-lisp/rx.el (rx): Add (pred stringp) to avoid type errors,
        and replace the `pred` clause for the actual match with something that
-       works with pcase-let(*) without being optimised away.
+       works with pcase-let(*) without being optimized away.
        * test/lisp/emacs-lisp/rx-tests.el (rx-pcase): Add test cases.
 
 2021-02-26  Stefan Kangas  <stefan@marxist.se>
@@ -36379,7 +38009,7 @@
        test/lisp/calendar/icalendar-resources/import-rrule-yearly.diary-iso:
        *
        test/lisp/calendar/icalendar-tests.el 
(icalendar-convert-anniversary-to-ical):
-       Match new diary-anniversary/yearly-rrule behaviour.
+       Match new diary-anniversary/yearly-rrule behavior.
 
        * lisp/calendar/icalendar.el (icalendar--datestring-to-isodate): Add
        year-shift option.  (icalendar--convert-anniversary-to-ical): Shift
@@ -36799,7 +38429,7 @@
        * lisp/emacs-lisp/easy-mmode.el (define-minor-mode): Keep
        `minor-modes' updated.
        * src/buffer.c (bset_minor_modes, Fmake_indirect_buffer)
-       (reset_buffer, init_buffer_once): Initialise `minor-modes'.
+       (reset_buffer, init_buffer_once): Initialize `minor-modes'.
        (syms_of_buffer): Add `minor-modes' as a new permanently-local
        variable.
 
@@ -37176,10 +38806,10 @@
 
 2021-02-12  Mattias Engdegård  <mattiase@acm.org>
 
-       Avoid traversing dead `if` branches in bytecode optimiser
+       Avoid traversing dead `if` branches in bytecode optimizer
 
        There is no point in traversing conditional branches that are
-       statically known never to be executed.  This saves some optimisation
+       statically known never to be executed.  This saves some optimization
        effort, but more importantly prevents variable assignments and
        references in those branches from blocking effective constant
        propagation.
@@ -37189,9 +38819,9 @@
        assignments.
 
        * lisp/emacs-lisp/byte-opt.el (byte-optimize-form):
-       Rewrite the (tail) recursion into an explicit loop.  Normalise a
+       Rewrite the (tail) recursion into an explicit loop.  Normalize a
        return value of (quote nil) to nil, for easier subsequent
-       optimisations.
+       optimizations.
        * lisp/emacs-lisp/byte-opt.el (byte-optimize-form-code-walker): Don't
        traverse dead `if` branches.  Use unconditional traversion context
        when possible.
@@ -37751,7 +39381,7 @@
        Make texinfmt-version variable obsolete
 
        * lisp/textmodes/texinfmt.el (texinfmt-version): Make variable and
-       command obsolete in favour of 'emacs-version'.
+       command obsolete in favor of 'emacs-version'.
        (texinfo-format-region, texinfo-format-buffer-1): Use
        'emacs-version' instead of above obsolete variable.
 
@@ -38422,7 +40052,7 @@
          (let ((x (+ 2 3))) (f x))  =>  (f 5)
 
        This reduces code size, eliminates stack operations, and enables
-       further optimisations.  The implementation is conservative, and is
+       further optimizations.  The implementation is conservative, and is
        strongly curtailed by the presence of variable mutation, conditions
        and loops.
 
@@ -39605,7 +41235,7 @@
 
 2021-01-31  Alan Mackenzie  <acm@muc.de>
 
-       Minimise the time Vminibuffer_list is in an inconsistent state 
(src/minibuf.c)
+       Minimize the time Vminibuffer_list is in an inconsistent state 
(src/minibuf.c)
 
        src/minibuf.c (get_minibuffer): Move the XSETCAR which writes the new
        minibuffer into Vminibuffer_list to immediately after the MB's 
creation, so
@@ -40995,7 +42625,7 @@
        string in the byte-code (so the two branches return `eq` strings).
 
        So, I think using `iso-2022-jp` is a bad idea here: it gives the
-       illusion that the the `charset` info exists, even it will be lost.
+       illusion that the `charset` info exists, even it will be lost.
        Eli discussed it with Handa-san a year ago, and they arrived at the
        conclusion that the charset information is indeed no longer important.
 
@@ -41980,7 +43610,7 @@
 
        * lisp/emacs-lisp/checkdoc.el (checkdoc-ispell-init): Always send
        the Lisp words to the process (bug#6221).  This allows an existing
-       ispell process to be correctly initialised.
+       ispell process to be correctly initialized.
 
 2021-01-20  Juri Linkov  <juri@linkov.net>
 
@@ -42277,7 +43907,7 @@
 
        Parse square root sign in embedded Calc mode
 
-       * lisp/calc/calc-lang.el (math-read-big-rec): Recognise √ since it may
+       * lisp/calc/calc-lang.el (math-read-big-rec): Recognize √ since it may
        be used in Big mode.
 
 2021-01-19  Mattias Engdegård  <mattiase@acm.org>
@@ -43847,7 +45477,7 @@
 
        * lisp/textmodes/paragraphs.el (mark-paragraph): Revert
        eb090f65ceb0ae8a90829e911694348583135ba5 (bug#45318).  This restores
-       the behaviour from Emacs 27 -- further work is needed on this patch.
+       the behavior from Emacs 27 -- further work is needed on this patch.
 
 2021-01-07  Michael Albinus  <michael.albinus@gmx.de>
 
@@ -46631,7 +48261,7 @@
        c-laomib-loop.  Insert code which calls c-laomib-loop minimally, with 
the help
        of the new cache.
 
-       * lisp/progmodes/cc-mode.el (c-basic-common-init): Initialise the new 
cach
+       * lisp/progmodes/cc-mode.el (c-basic-common-init): Initialize the new 
cach
        (at mode start).
        (c-before-change): Invalidate the new cache.
        (c-fl-decl-start): Add an extra check (> (point) bod-lim) to prevent 
looping.
@@ -48113,7 +49743,7 @@
 
 2020-12-14  Alan Mackenzie  <acm@muc.de>
 
-       Optimise c-font-lock-<>-arglists, particularly for buffers with few 
<..> pairs
+       Optimize c-font-lock-<>-arglists, particularly for buffers with few 
<..> pairs
 
        * lisp/progmodes/cc-fonts.el (c-font-lock-<>-arglists): In place of a 
regexp
        search for a complicated and slow regexp, search simply for "<" outside 
of
@@ -48134,7 +49764,7 @@
 
 2020-12-14  Alan Mackenzie  <acm@muc.de>
 
-       Optimise c-parse-state for large buffers with few (if any) braces.
+       Optimize c-parse-state for large buffers with few (if any) braces.
 
        * lisp/progmodes/cc-engine.el (c-get-fallback-scan-pos): Search a 
maximum of
        50,000 characters back for the two BODs.  Return nil if we dont' find 
them.
@@ -49332,7 +50962,7 @@
 
        * test/src/casefiddle-tests.el (casefiddle-tests-char-casing):
        (upcase ?ß) now returns ?ẞ (U+7838), partly for technical reasons but
-       the previous behaviour was arbitrary and arguably less useful.
+       the previous behavior was arbitrary and arguably less useful.
        Correct upcasing of ß is normally SS, which is what Fupcase returns if
        given a string, or (for special purposes) ẞ.
 
@@ -49421,7 +51051,7 @@
        exactly what the output looks like (see
        https://github.com/JetBrains/kotlin/commit/\
        ffe8ae3840d7b9bdc82170c8181031f05ced68bd) and there is no reason to
-       risk mismatches or expensive backtracking (bug#18109).  Recognise
+       risk mismatches or expensive backtracking (bug#18109).  Recognize
        'info' level messages.  Convert to rx.
 
 2020-12-09  Lars Ingebrigtsen  <larsi@gnus.org>
@@ -49501,7 +51131,7 @@
 
 2020-12-09  Mattias Engdegård  <mattiase@acm.org>
 
-       Recognise ß properly as a lower-case letter (bug#11309)
+       Recognize ß properly as a lower-case letter (bug#11309)
 
        ß was incorrectly treated as a caseless character and thus not matched
        by the regexp [[:lower:]] (or, in case-folding mode, [[:upper:]]).
@@ -51762,7 +53392,7 @@
        Remove keyboard anachronisms from tutorial
 
        * etc/tutorials/TUTORIAL: Don't keep referring to EDIT as if it were a
-       common name for the Meta key; since a few decades back it's labelled
+       common name for the Meta key; since a few decades back it's labeled
        Alt (or Option or ⌥ but those keys usually also have 'alt' engraved on
        them).  Similarly, CTL is practically extinct and not worth
        mentioning.
@@ -52863,7 +54493,7 @@
 
 2020-11-19  Mattias Engdegård  <mattiase@acm.org>
 
-       More string-search optimisations
+       More string-search optimizations
 
        All-ASCII strings cannot have substrings with non-ASCII characters in
        them; use this fact to avoid searching entirely.
@@ -54538,7 +56168,7 @@
 
 2020-11-09  Harald Jörg  <haj@posteo.de>
 
-       cperl-mode: Indentation of ')' follows customisation
+       cperl-mode: Indentation of ')' follows customization
 
        * lisp/progmodes/cperl-mode.el (cperl-style-alist): Add
        cperl-close-paren-offset to the settings for PBP style.
@@ -55612,7 +57242,7 @@
        * lisp/emacs-lisp/easy-mmode.el (easy-mmode--arg-docstring):
        Only document the values we want to support, not the ones we
        actually support.
-       (define-minor-mode): Partially revert to previous behaviour.
+       (define-minor-mode): Partially revert to previous behavior.
 
 2020-11-01  Stefan Kangas  <stefan@marxist.se>
 
@@ -55940,7 +57570,7 @@
 
        Since a supplied test function can do anything, assoc is not
        side-effect-free (bug#44018).  However, with only two arguments it is
-       pure and should be optimised accordingly.
+       pure and should be optimized accordingly.
 
        * lisp/emacs-lisp/byte-opt.el (side-effect-free-fns): Remove 'assoc'.
        (byte-optimize-assoc): Constant-propagate through 2-arg assoc calls.
@@ -56544,7 +58174,7 @@
        Remove unused function in gdb-mi.el
 
        * lisp/progmodes/gdb-mi.el (gdb-var-evaluate-expression-handler):
-       Remove.  (It was left behind in an old code reorganisation.)
+       Remove.  (It was left behind in an old code reorganization.)
 
 2020-10-27  Lars Ingebrigtsen  <larsi@gnus.org>
 
@@ -56877,7 +58507,7 @@
        (shortdoc-section): Remove colors.
        (shortdoc-separator): New face.
        (shortdoc-display-group, shortdoc--display-function): Don't use
-       background colours, because that makes things harder to read.
+       background colors, because that makes things harder to read.
        Separate with a horizontal line instead.
 
 2020-10-26  Andrea Corallo  <akrl@sdf.org>
@@ -57163,7 +58793,7 @@
        * lisp/emacs-lisp/eldoc.el:
        (eldoc-echo-area-prefer-doc-buffer): Rename from
        eldoc-echo-area-prefer-doc-buffer
-       (eldoc-display-in-echo-area): Rework to honour
+       (eldoc-display-in-echo-area): Rework to honor
        eldoc-echo-area-prefer-doc-buffer.
 
 2020-10-24  João Távora  <joaotavora@gmail.com>
@@ -58604,7 +60234,7 @@
 
        mixal-mode: add missed instructions
 
-       Synchronises with latest released GNU MDK 1.2.11
+       Synchronizes with latest released GNU MDK 1.2.11
 
        * lisp/progmodes/mixal-mode.el (mixal-operation-codes-alist):
        Add missed instructions: SLB,SRB,JAE,JAO,JXE,JXO.
@@ -58807,7 +60437,7 @@
        (No mixed fonts): Remove references to MELPA.
        (How do the themes look like)
        (Enable and load, Load automatically)
-       (Configure options prior to loading, Customisation Options)
+       (Configure options prior to loading, Customization Options)
        (No mixed fonts, Command prompts, Mode line, Completion UIs)
        (Fringes, Line highlighting, Matching parentheses, Diffs)
        (Org mode blocks, Heading styles, Tweak colors (DIY))
@@ -58989,7 +60619,7 @@
        Sanitize ical data in gnus-icalendar-event-from-ical
 
        * lisp/gnus/gnus-icalendar.el (gnus-icalendar-event-from-ical):
-       Sanitise the data before passing it on to the constructor.  This
+       Sanitize the data before passing it on to the constructor.  This
        avoids backtraces on icals with extra, unknown slots (bug#43057).
 
 2020-10-16  Basil L. Contovounesios  <contovob@tcd.ie>
@@ -59039,7 +60669,7 @@
 
 2020-10-16  Lars Ingebrigtsen  <larsi@gnus.org>
 
-       Restore vc-revision-other-window buffer-changing behaviour
+       Restore vc-revision-other-window buffer-changing behavior
 
        * lisp/vc/vc.el (vc-revision-other-window): This function used to
        change the current buffer, but this was changed in the previous
@@ -59727,14 +61357,14 @@
        Add more numeric shortdocs
 
        * lisp/emacs-lisp/shortdoc.el (shortdoc-section)
-       (shortdoc-example): Lighten up colours on light backgrounds.
+       (shortdoc-example): Lighten up colors on light backgrounds.
 
 2020-10-11  Lars Ingebrigtsen  <larsi@gnus.org>
 
-       Tweak shortdoc colours on light backgrounds
+       Tweak shortdoc colors on light backgrounds
 
        * lisp/emacs-lisp/shortdoc.el (shortdoc-section)
-       (shortdoc-example): Lighten up colours on light backgrounds.
+       (shortdoc-example): Lighten up colors on light backgrounds.
 
 2020-10-11  Lars Ingebrigtsen  <larsi@gnus.org>
 
@@ -61516,10 +63146,10 @@
 
 2020-09-30  Lars Ingebrigtsen  <larsi@gnus.org>
 
-       Fix isearch-group-* colours on low-colour displays
+       Fix isearch-group-* colors on low-colour displays
 
        * lisp/isearch.el (isearch-group-1): On low-colour displays, just
-       use the normal isearch colour (bug#43702).
+       use the normal isearch color (bug#43702).
        (isearch-group-2 etc): Ditto.
 
 2020-09-30  Lars Ingebrigtsen  <larsi@gnus.org>
@@ -61595,13 +63225,13 @@
 
 2020-09-29  Lars Ingebrigtsen  <larsi@gnus.org>
 
-       Fix emacsclient -c foo.txt behaviour with many frames
+       Fix emacsclient -c foo.txt behavior with many frames
 
        * lisp/server.el (server-execute): Pass in whether we opened a new
        frame or not (bug#43645).
        (server-switch-buffer): Use this to switch to the requested buffer
        in the new frame if we have "emacsclient -c foo.txt", and retain
-       the old behaviour if it's "emacsclient foo.txt".
+       the old behavior if it's "emacsclient foo.txt".
 
 2020-09-29  Lars Ingebrigtsen  <larsi@gnus.org>
 
@@ -61815,7 +63445,7 @@
 
 2020-09-27  Mattias Engdegård  <mattiase@acm.org>
 
-       Minor string-search optimisations (bug#43598)
+       Minor string-search optimizations (bug#43598)
 
        * src/fns.c (Fstring_search): Perform cheap all-ASCII checks before more
        expensive ones.  Use a faster loop when searching for non-ASCII
@@ -62673,7 +64303,7 @@
 
        Speed up shr-insert slightly
 
-       * lisp/net/shr.el (shr-insert): Speed up regularising spaces --
+       * lisp/net/shr.el (shr-insert): Speed up regularizing spaces --
        the vast majority of the spaces are already OK, so transforming
        " " to " " just takes time.
 
@@ -64644,7 +66274,7 @@
 
 2020-09-11  Mattias Engdegård  <mattiase@acm.org>
 
-       Calc: regularise test names
+       Calc: regularize test names
 
        * test/lisp/calc/calc-tests.el (calc-remove-units, calc-extract-units)
        (calc-convert-units, calc-bug-23889, calc-trig, calc-format-radix)
@@ -65193,7 +66823,7 @@
 
 2020-09-08  João Távora  <joaotavora@gmail.com>
 
-       Change icomplete-show-matches-on-no-input behaviour for Icomplete only
+       Change icomplete-show-matches-on-no-input behavior for Icomplete only
 
        (Bug#19032), bug#43120
 
@@ -65329,7 +66959,7 @@
 
 2020-09-07  João Távora  <joaotavora@gmail.com>
 
-       Better explain behaviour of icomplete--sorted-completions
+       Better explain behavior of icomplete--sorted-completions
 
        * lisp/icomplete.el (icomplete--sorted-completions): Overhaul comment
 
@@ -66135,7 +67765,7 @@
        wdired-do-renames: Speed up for long Emacs sessions
 
        `dired-rename-file' calls unconditionally `dired-rename-subdir'.
-       The second function performs performs a loop on all the Emacs
+       The second function performs a loop on all the Emacs
        buffers; this step is only needed if FILE is a directory (bug#32899).
 
        In a long lived Emacs session, this can make a difference
@@ -66700,9 +68330,9 @@
 
 2020-08-30  Lars Ingebrigtsen  <larsi@gnus.org>
 
-       Tweak background colours in shr when there's indentation
+       Tweak background colors in shr when there's indentation
 
-       * lisp/net/shr.el (shr-fill-line): Get the background colour right
+       * lisp/net/shr.el (shr-fill-line): Get the background color right
        for the indentation, too.
 
 2020-08-30  Mauro Aranda  <maurooaranda@gmail.com>
@@ -67615,7 +69245,7 @@
 
 2020-08-25  Lars Ingebrigtsen  <larsi@gnus.org>
 
-       Extend background colours in shr
+       Extend background colors in shr
 
        * lisp/net/shr.el (shr-colorize-region): Extend backgrounds to the
        end (bug#43031).  This avoid ragged edges to the right when, for
@@ -68577,7 +70207,7 @@
 
        * lisp/simple.el (read-extended-command): Allow doing interactive
        searches over the completions (bug#12490).  This restores the
-       behaviour from Emacs 23 that was lost in Emacs 24.
+       behavior from Emacs 23 that was lost in Emacs 24.
 
 2020-08-19  Grégoire Jadi  <gregoire.jadi@univ-nantes.fr>
 
@@ -68647,7 +70277,7 @@
 
 2020-08-19  Tino Calancha  <tino.calancha@gmail.com>
 
-       Make thingatpt recognise files names with @ in them
+       Make thingatpt recognize files names with @ in them
 
        * lisp/thingatpt.el (thing-at-point-file-name-chars): Add @
        (Bug#24606).
@@ -71552,7 +73182,7 @@
        Tweak how whitespace-mode marks the end of the buffer
 
        * lisp/whitespace.el (whitespace-missing-newline-at-eof): Change
-       the colours to not be as angry.
+       the colors to not be as angry.
        (whitespace-color-on): Don't mark the end of the buffer if point
        is there.
 
@@ -73083,7 +74713,7 @@
 
        (Bug#42563)
 
-       For some time, Eldoc has has some Elisp-specific code that shouldn't
+       For some time, Eldoc has some Elisp-specific code that shouldn't
        live there, but in elisp-mode.el.  This can be fixed in Emacs master,
        but since ElDoc is distributed in GNU Elpa and is meant to work with
        Emacs 26 and 27, this means that that elisp-specific code must still
@@ -73232,11 +74862,11 @@
 
 2020-07-25  Mattias Engdegård  <mattiase@acm.org>
 
-       Optimise 3-arg +, - and *
+       Optimize 3-arg +, - and *
 
        Turn (+ a b c) into (+ (+ a b) c), and do the same for - and *.
        The 2-arg operations have their own bytecode which results in a 1.5×
-       speed-up.  Furthermore, the transform enables other optimisations; for
+       speed-up.  Furthermore, the transform enables other optimizations; for
        example, (+ a 1 b) -> (+ (1+ a) b).
 
        * lisp/emacs-lisp/byte-opt.el (byte-optimize-plus, byte-optimize-minus)
@@ -73335,7 +74965,7 @@
 
        Do this conservatively for now: if the ElDoc helper buffer (as
        returned by eldoc--doc-buffer) is visible and showing documentation
-       for the very same "situation" (as computed by the the new
+       for the very same "situation" (as computed by the new
        eldoc--request-state helper), don't request that documentation from
        sources again.
 
@@ -73691,12 +75321,12 @@
 
 2020-07-17  Lars Ingebrigtsen  <larsi@gnus.org>
 
-       Fix NOT-CURRENT behaviour in text-property-search-backward
+       Fix NOT-CURRENT behavior in text-property-search-backward
 
        * lisp/emacs-lisp/text-property-search.el
-       (text-property-search-backward): Fix inconsistent behaviour of
+       (text-property-search-backward): Fix inconsistent behavior of
        S-TAB in eww (and other callers that use the NOT-CURRENT
-       behaviour) when there are adjacent elements
+       behavior) when there are adjacent elements
        (bug#39239).
 
 2020-07-17  Xu Chunyang  <xuchunyang56@gmail.com>
@@ -74619,7 +76249,7 @@
        (eldoc-documentation-compose, eldoc-documentation-default): Handle
        non-nil, non-string values of elements of
        eldoc-documentation-functions.  Use eldoc--handle-multiline.
-       (eldoc-print-current-symbol-info): Honour non-nil, non-string
+       (eldoc-print-current-symbol-info): Honor non-nil, non-string
        values returned by eldoc-documentation-callback.
        (eldoc--make-callback): Now also a function.
        (eldoc-documentation-default, eldoc-documentation-compose): Tweak 
docstring.
@@ -74671,7 +76301,7 @@
 
 2020-07-07  Mattias Engdegård  <mattiase@acm.org>
 
-       Optimise assoc and rassoc with symbol key to assq and rassq
+       Optimize assoc and rassoc with symbol key to assq and rassq
 
        This is the same transformation made for member to memq.
 
@@ -74703,9 +76333,9 @@
 
 2020-07-06  Mattias Engdegård  <mattiase@acm.org>
 
-       Simplify byte-code optimisation of pure functions
+       Simplify byte-code optimization of pure functions
 
-       Most pure functions need no explicit optimisation; we can do away with
+       Most pure functions need no explicit optimization; we can do away with
        almost all uses of byte-optimize-predicate (now renamed to
        byte-optimize-constant-args, since it is not just for predicates).
        Also remove some superfluous arity warnings.
@@ -74953,7 +76583,7 @@
 
        CC Mode: optimize for repeated simple operations.
 
-       Do this by recognising that unterminated strings in a buffer are 
typically
+       Do this by recognizing that unterminated strings in a buffer are 
typically
        going to be few and close together.  Also optimize code for C++ 
attributes.
 
        * lisp/progmodes/cc-defs.el (c-previous-single-property-change): New 
macro.
@@ -75269,7 +76899,7 @@
 
        * lisp/gnus/gnus-cloud.el (gnus-cloud-download-data): Return the
        result of calling `gnus-cloud-update-all' when UPDATE is t, as per the
-       documented behaviour. (Bug#40280)
+       documented behavior. (Bug#40280)
 
 2020-06-23  Andrea Corallo  <akrl@sdf.org>
 
@@ -75572,7 +77202,7 @@
        * lisp/progmodes/project.el (project-shell): Improve docstring to
        include information about an implementation detail.
 
-       * lisp/progmodes/project.el (project-eshell): Modelled after
+       * lisp/progmodes/project.el (project-eshell): Modeled after
        'project-shell', change default behavior such that we don't create too
        many eshell buffers by default.  Use universal argument to create
        subsequent buffers.
@@ -76135,7 +77765,7 @@
        still don't work).
        (tramp-crypt-handle-access-file): New defun.
        (tramp-crypt-do-copy-or-rename-file): Short track if both files
-       are on a crypted remote dir.
+       are on an encrypted remote dir.
 
        * lisp/net/tramp.el (file-notify-rm-watch): Declare.
        (tramp-inhibit-progress-reporter): New defvar.
@@ -76433,14 +78063,14 @@
 
 2020-06-10  Mattias Engdegård  <mattiase@acm.org>
 
-       Improved light/dark colour predicate (bug#41544)
+       Improved light/dark color predicate (bug#41544)
 
-       Add a predicate, color-dark-p, for deciding whether a colour is more
+       Add a predicate, color-dark-p, for deciding whether a color is more
        readable with black or white as contrast.  It has experimentally been
        shown to be more accurate and robust than the various methods
        currently employed.
 
-       The new predicate compares the relative luminance of the colour to an
+       The new predicate compares the relative luminance of the color to an
        empirically determined cut-off value, and it seems to get it right in
        almost all cases, with no value leading to outright bad results.
 
@@ -76602,14 +78232,14 @@
 
 2020-06-08  Mattias Engdegård  <mattiase@acm.org>
 
-       More robust NS hex colour string parsing
+       More robust NS hex color string parsing
 
        Invalid arguments to color-values, such as "#abcdefg" or "#1234", or
        valid ones like "#111222333", should not yield nonsense values.
 
        * src/nsterm.m (ns_get_color):
        Only accept "#RGB" strings with 1-4 digits per components, equal number
-       of digits each, and no trailing characters.  Parse 12-bit colours
+       of digits each, and no trailing characters.  Parse 12-bit colors
        correctly.
 
 2020-06-08  Michael Albinus  <michael.albinus@gmx.de>
@@ -76753,7 +78383,7 @@
 
        * lisp/emacs-lisp/comp.el (comp-symbol-values-optimizable): New
        defconst.
-       (comp-function-call-maybe-remove): New logic to to remove
+       (comp-function-call-maybe-remove): New logic to remove
        unnecessary `symbol-value' calls.
 
 2020-06-07  Juri Linkov  <juri@linkov.net>
@@ -77057,7 +78687,7 @@
        Make color-distance symmetric and more accurate
 
        * src/xfaces.c (color_distance): Don't throw away the low 8 bits of
-       the colours, and make the function symmetric (bug41544)
+       the colors, and make the function symmetric (bug41544)
        (Fcolor_distance): Add caution about this not being a true metric.
        * test/src/xfaces-tests.el: New file.
 
@@ -77585,7 +79215,7 @@
        * lisp/international/ucs-normalize.el
        (ucs-normalize-hfs-nfd-post-read-conversion)
        (ucs-normalize-hfs-nfd-pre-write-conversion):
-       Use save-match-data to avoid match data clobber in normalisation.
+       Use save-match-data to avoid match data clobber in normalization.
        * test/lisp/international/ucs-normalize-tests.el
        (ucs-normalize-save-match-data): New test.
 
@@ -79152,7 +80782,7 @@
 
 2020-05-14  Mattias Engdegård  <mattiase@acm.org>
 
-       Fix customisation of mouse-drag-and-drop-region (bug#41251)
+       Fix customization of mouse-drag-and-drop-region (bug#41251)
 
        Reported by David Ponce.
 
@@ -79588,12 +81218,12 @@
        cc-mode: extend regexp used by ‘c-or-c++-mode’
 
        * lisp/progmodes/cc-mode.el (c-or-c++-mode--regexp): Expand the regexp 
to
-       match some more C++-only constructs and recognise a few more standard
+       match some more C++-only constructs and recognize a few more standard
        C++ header files.  Also make sure identifiers start with non-digit.
        (c-or-c++-mode): Add ‘(interactive)’ declaration.
 
        * test/lisp/progmodes/cc-mode-tests.el (c-or-c++-mode): Add test case
-       for the newly recognised constructs.
+       for the newly recognized constructs.
 
 2020-05-09  Michal Nazarewicz  <mina86@mina86.com>
 
@@ -81362,7 +82992,7 @@
        * src/nsterm.m (ns_parent_window_rect): New function.
        (NS_PARENT_WINDOW_LEFT_POS):
        (NS_PARENT_WINDOW_TOP_POS): Move to nsterm.m and simplify.
-       (ns_set_offset): Fix strange behaviours when using negative values.
+       (ns_set_offset): Fix strange behaviors when using negative values.
        (ns_set_window_size):
        (ns_set_undecorated):
        ([EmacsView windowDidResize:]):
@@ -81478,7 +83108,7 @@
 
 2020-04-16  Mattias Engdegård  <mattiase@acm.org>
 
-       Regularise some file-matching regexps
+       Regularize some file-matching regexps
 
        * admin/authors.el (authors-obsolete-files-regexps)
        (authors-renamed-files-regexps): Replace ^ and $ with \` and \'.
@@ -82008,7 +83638,7 @@
 
        * lisp/progmodes/cl-font-lock.el: Fix header and make it a minor mode
 
-       Change copyright to FSF and licence to GPLv3+.
+       Change copyright to FSF and license to GPLv3+.
        Tweak Commentary (the code doesn't seem to provide the lambda
        prettification mentioned).
 
@@ -82401,7 +84031,7 @@
 
        Avoid expensive recoding for ASCII identity cases (bug#40407)
 
-       Optimise for the common case of encoding or decoding an ASCII-only
+       Optimize for the common case of encoding or decoding an ASCII-only
        string using an ASCII-compatible coding, for file names in particular.
 
        * src/coding.c (string_ascii_p): New function.
@@ -82733,7 +84363,7 @@
 
 2020-04-03  Ashish SHUKLA  <ashish.is@lostca.se>
 
-       configure.ac: switch to POSIX sh behaviour
+       configure.ac: switch to POSIX sh behavior
 
 2020-04-03  Federico Tedin  <federicotedin@gmail.com>
 
@@ -84145,7 +85775,7 @@
 
 2020-03-10  AndreaCorallo  <akrl@sdf.org>
 
-       * Fix store_function_docstring for for native functions
+       * Fix store_function_docstring for native functions
 
        Do not Nil native_doc fields.  This will be naturally dumped by
        pdumper.  This was affecting dumped functions.
@@ -84702,7 +86332,7 @@
        (ns_dumpglyphs_stretch): Remove unused variable.
        (ns_term_init):
        ([EmacsWindow setAppearance]): Only compile on macOS.
-       (ns_mouse_position): Make sure f is initialised on GNUstep.
+       (ns_mouse_position): Make sure f is initialized on GNUstep.
        * src/emacs.c (main): Move allocation of autorelease pool to before
        first use.
 
@@ -86421,7 +88051,7 @@
        2019-11-17 Prepend "unsigned" to MINI_GMP_LIMB_TYPE
        2019-11-17 Enable testing with different limb sizes (types)
        2019-11-20 Use already defined constants
-       2019-11-09 Avoid undefined behaviour with small limb sizes
+       2019-11-09 Avoid undefined behavior with small limb sizes
 
 2020-01-26  Paul Eggert  <eggert@cs.ucla.edu>
 
@@ -89792,7 +91422,7 @@
 
 2019-12-26  Mattias Engdegård  <mattiase@acm.org>
 
-       Optimise 'while' bodies for effect
+       Optimize 'while' bodies for effect
 
        * lisp/emacs-lisp/byte-opt.el (byte-optimize-form-code-walker):
        Treat all expressions in the body of 'while' as for-effect,
@@ -95751,7 +97381,7 @@
        * lisp/progmodes/compile.el (compilation-parse-errors):
        When 'omake' is enabled, allow error messages to be indented by 0 or 6
        spaces instead of any number of spaces, to avoid pathological
-       behaviour.
+       behavior.
        (compilation-error-regexp-alist-alist): Anchor the 'omake' pattern to
        bol for performance.  Repair the 'ruby-Test::Unit' pattern, which
        relied on the previously over-generous 'omake' hack.
@@ -95774,7 +97404,7 @@
 
        Speed up 'maven' compilation error message regexp
 
-       Anchor the regexp at line-start to prevent quadratic behaviour when
+       Anchor the regexp at line-start to prevent quadratic behavior when
        it doesn't match (bug#39595).  It's unclear whether the type tag, like
        [ERROR], is always present; we keep it optional just in case.
 
@@ -96898,7 +98528,7 @@
 
        Calc: fix interval entry (bug#39040)
 
-       * lisp/calc/calc.el (calcDigit-start): Initialise calc-prev-char to
+       * lisp/calc/calc.el (calcDigit-start): Initialize calc-prev-char to
        something more reasonable, so that non-algebraic entry of intervals
        whose start is a single digit, like (1..10), works properly.
        Reported by Michel Schinz.
@@ -96914,7 +98544,7 @@
 
        flymake: fix typo in variable binding (bug#38752)
 
-       This mistake was found by an experimental elisp optimiser.
+       This mistake was found by an experimental elisp optimizer.
 
        * lisp/progmodes/flymake-proc.el (flymake-proc-stop-all-syntax-checks):
        Add missing brackets.
@@ -98016,7 +99646,7 @@
 
        Improve sorting of flex completion style with non-nil minibuffer-default
 
-       This affects the behaviour of flex completion when there is a default
+       This affects the behavior of flex completion when there is a default
        completion and the user hasn't entered any input pattern to flex-match
        against.  It is most visible when icomplete-mode or fido-mode are
        being used in conjunctio.
@@ -98194,7 +99824,7 @@
        * lisp/emacs-lisp/regexp-opt.el (regexp-opt):
        * doc/lispref/searching.texi (Regexp Functions):
        Be more specific about how the KEEP-ORDER argument actually works.
-       If nil, the regexp guarantees a longest match; this is the behaviour
+       If nil, the regexp guarantees a longest match; this is the behavior
        that many callers implicitly rely on.
 
 2019-12-18  Michael Albinus  <michael.albinus@gmx.de>
@@ -100773,7 +102403,7 @@
        Handle FC_CHARCELL in xftfont_open
 
        * src/xftfont.c (xftfont_open): FC_CHARCELL is apparently an alias
-       for FC_DUAL used in some east Asian fonts (bug#35079).  Modelled
+       for FC_DUAL used in some east Asian fonts (bug#35079).  Modeled
        after a patch suggested by Kenichi Handa.
 
 2019-11-17  Eli Zaretskii  <eliz@gnu.org>
@@ -100924,7 +102554,7 @@
 
        When using this option and editing input, some transient situations
        may arise that lead to file-name shadowing, but that shouldn't
-       necessarily lead to auto-delete behaviour, which will be surprising.
+       necessarily lead to auto-delete behavior, which will be surprising.
 
        In '/foo/x/bar', if the user deletes the 'x', shadowing occurs, but
        probably shouldn't.  So, somewhat like ido-mode, only auto-tidy
@@ -101640,7 +103270,7 @@
        Add extra bindings to fido-mode.
 
        * lisp/icomplete.el (icomplete-fido-mode-map) : Add arrows and other
-       bindings to reproduce ido behaviour.
+       bindings to reproduce ido behavior.
 
 2019-11-09  Glenn Morris  <rgm@gnu.org>
 
@@ -104052,9 +105682,9 @@
 
 2019-10-23  Lars Ingebrigtsen  <larsi@gnus.org>
 
-       Make Gnus recognise "git am" diffs in all groups
+       Make Gnus recognize "git am" diffs in all groups
 
-       * lisp/gnus/mm-uu.el (mm-uu-diff-groups-regexp): Recognise diffs
+       * lisp/gnus/mm-uu.el (mm-uu-diff-groups-regexp): Recognize diffs
        in all groups (bug#32730).
 
 2019-10-22  Stefan Kangas  <stefankangas@gmail.com>
@@ -106752,7 +108382,7 @@
 
 2019-10-09  Lars Ingebrigtsen  <larsi@gnus.org>
 
-       Fix possible initialisation error in shell-mode-map
+       Fix possible initialization error in shell-mode-map
 
        * lisp/shell.el (shell-mode-map): Comint is the parent mode, so
        there's no need to explicitly make it a parent map here (bug#25187).
@@ -107100,10 +108730,10 @@
 
 2019-10-06  Lars Ingebrigtsen  <larsi@gnus.org>
 
-       Fix the colours on Motif horizontal scroll bars
+       Fix the colors on Motif horizontal scroll bars
 
        * src/xterm.c (x_create_horizontal_toolkit_scroll_bar): Use the
-       same foreground/background colours as the vertical scroll bar
+       same foreground/background colors as the vertical scroll bar
        (bug#37359).
 
 2019-10-06  Lars Ingebrigtsen  <larsi@gnus.org>
@@ -107954,7 +109584,7 @@
 
        C++ Mode: Fontify correctly declarators with identifier preceded by &
 
-       The problem was bar in the following being spuriously recognised as a
+       The problem was bar in the following being spuriously recognized as a
        function, and foo as a type, as though the & were a *: Foo foo (&bar);.
 
        * lisp/progmodes/cc-engine.el (c-forward-decl-or-cast-1): New variable
@@ -108421,9 +110051,9 @@
 
 2019-09-29  Lars Ingebrigtsen  <larsi@gnus.org>
 
-       Allow customising pdf-to-text parameters
+       Allow customizing pdf-to-text parameters
 
-       * lisp/doc-view.el (doc-view-pdf->txt): Allow customising the
+       * lisp/doc-view.el (doc-view-pdf->txt): Allow customizing the
        parameters (bug#8519).
        (doc-view-pdftotext-program-args): New variable.
 
@@ -110922,12 +112552,12 @@
 
 2019-09-14  Lars Ingebrigtsen  <larsi@gnus.org>
 
-       Add default foreground colours to SVG images
+       Add default foreground colors to SVG images
 
-       * lisp/net/shr.el (svg--wrap-svg): Add a default foreground colour
+       * lisp/net/shr.el (svg--wrap-svg): Add a default foreground color
        to SVG images (bug#37159).  This helps with images like the ones
        in https://en.wikipedia.org/wiki/Banach_fixed-point_theorem that
-       specify no foreground or background colours.
+       specify no foreground or background colors.
        (shr-parse-image-data): Use it.
 
 2019-09-14  Lars Ingebrigtsen  <larsi@gnus.org>
@@ -111732,7 +113362,7 @@
 
        * lisp/epa-file.el (epa-file--replace-text): Gingerly replace the
        text in the buffer to preserve as many markers as possible
-       (bug#34720).  This emulates the behaviour of Finsert_file_contents
+       (bug#34720).  This emulates the behavior of Finsert_file_contents
        more accurately.
        (epa-file-decode-and-insert): Remove compat code.
        (epa-file-insert-file-contents): Use the new function.
@@ -111744,7 +113374,7 @@
        Repair change to compilation-context-lines (bug#36832)
 
        * lisp/progmodes/compile.el (compilation-set-window):
-       Restore proper behaviour when compilation-context-lines is nil,
+       Restore proper behavior when compilation-context-lines is nil,
        which is the default.
 
 2019-09-04  Michael Albinus  <michael.albinus@gmx.de>
@@ -112424,7 +114054,7 @@
 
 2019-08-29  Lars Ingebrigtsen  <larsi@gnus.org>
 
-       Tweak shr background colour handling
+       Tweak shr background color handling
 
        * lisp/net/shr.el (shr-fill-line): Extend the background to the
        end of the line when folding lines.
@@ -113203,7 +114833,7 @@
 
 2019-08-21  Nicolas Petton  <nicolas@petton.fr>
 
-       * etc/HISTORY: Add Emacs 26.3 release release date.
+       * etc/HISTORY: Add Emacs 26.3 release date.
 
 2019-08-21  Nicolas Petton  <nicolas@petton.fr>
 
@@ -114532,7 +116162,7 @@
 
        * lisp/progmodes/cc-engine.el (c-beginning-of-statement-1): Check for
        operators which cannot start a statement, which may follow a closing 
brace.
-       Don't recognise an end of statement in such a case.
+       Don't recognize an end of statement in such a case.
 
        * lisp/progmodes/cc-langs.el (c-operator-re, c-bin-tern-operators)
        (c-unary-operators, c-non-after-{}-operators, c-non-after-{}-ops-re): 
New lang
@@ -115007,11 +116637,11 @@
 
 2019-08-04  Lars Ingebrigtsen  <larsi@gnus.org>
 
-       Capitalise a couple of node names
+       Capitalize a couple of node names
 
-       * doc/lispref/functions.texi (Advising Functions): Capitalise node
+       * doc/lispref/functions.texi (Advising Functions): Capitalize node
        names (bug#17717).
-       (Advice Combinators, Porting Old Advice): Capitalise.
+       (Advice Combinators, Porting Old Advice): Capitalize.
 
 2019-08-04  Michael Heerdegen  <michael_heerdegen@web.de>
 
@@ -115401,9 +117031,9 @@
 
 2019-08-02  Lars Ingebrigtsen  <larsi@gnus.org>
 
-       Make Info-find-file ensure that Info is initialised
+       Make Info-find-file ensure that Info is initialized
 
-       * lisp/info.el (Info-find-file): Ensure that Info is initialised,
+       * lisp/info.el (Info-find-file): Ensure that Info is initialized,
        because libraries call that function (bug#19880).
 
 2019-08-02  Lars Ingebrigtsen  <larsi@gnus.org>
@@ -115520,7 +117150,7 @@
        This fixes bug #36801.
 
        * lisp/progmodes/cc-langs.el (c-pre-lambda-tokens-re): Use 
c-make-keywords-re
-       rather than regexp-opt to make an optimised regexp out of a list of 
tokens.
+       rather than regexp-opt to make an optimized regexp out of a list of 
tokens.
 
 2019-08-02  Lars Ingebrigtsen  <larsi@gnus.org>
 
@@ -115620,7 +117250,7 @@
        Document batch-byte-compile directory behavior
 
        * lisp/emacs-lisp/bytecomp.el (batch-byte-compile): Document the
-       behaviour with directories (bug#20867).
+       behavior with directories (bug#20867).
 
 2019-08-01  Stefan Monnier  <monnier@iro.umontreal.ca>
 
@@ -116185,7 +117815,7 @@
 
 2019-07-30  Lars Ingebrigtsen  <larsi@gnus.org>
 
-       Use decoded time accessors in in em-ls
+       Use decoded time accessors in em-ls
 
        * lisp/eshell/em-ls.el (eshell-ls-file): Use decoded time
        accessors.
@@ -117112,7 +118742,7 @@
 
 2019-07-25  Lars Ingebrigtsen  <larsi@gnus.org>
 
-       Tweak the behaviour of thing-at-point--end-of-sexp
+       Tweak the behavior of thing-at-point--end-of-sexp
 
        * lisp/thingatpt.el (thing-at-point--end-of-sexp): Don't return
        nil when called with point between two parentheses (bug#29499).
@@ -117164,7 +118794,7 @@
 
        Make `C-u w' in the Gnus Summary buffer open externally
 
-       * doc/misc/gnus.texi (Article Commands): Document new behaviour.
+       * doc/misc/gnus.texi (Article Commands): Document new behavior.
 
        * lisp/gnus/gnus-sum.el (gnus-shorten-url): New function.
        (gnus-summary-browse-url): Change function to make `C-u' use the
@@ -117760,7 +119390,7 @@
        * doc/lispref/hash.texi (Creating Hash, Defining Hash):
        * src/fns.c (Fsxhash_eq, Fsxhash_eql, Fsxhash_equal):
        Say that hashes are fixnums.
-       (Fmake_hash_table): Say that that an integer rehash-size
+       (Fmake_hash_table): Say that an integer rehash-size
        should be a fixnum.
        * doc/lispref/hash.texi (Defining Hash): Say that hash and
        comparison functions should be consistent and pure, and should
@@ -118540,9 +120170,9 @@
 
 2019-07-14  Lars Ingebrigtsen  <larsi@gnus.org>
 
-       Tweak background colour handling in shr
+       Tweak background color handling in shr
 
-       * lisp/net/shr.el (shr-fill-line): Keep the background colour on
+       * lisp/net/shr.el (shr-fill-line): Keep the background color on
        the newline and the indentation.
 
 2019-07-14  Lars Ingebrigtsen  <larsi@gnus.org>
@@ -119009,7 +120639,7 @@
        * lisp/epg.el (epg-start-encrypt)
        * lisp/gnus/mml-sec.el (mml-secure-epg-encrypt): When
        'mml-secure-openpgp-sign-with-sender' is non-nil message sender's
-       email address (in addition to its old behaviour) will also be used
+       email address (in addition to its old behavior) will also be used
        to set gpg's "--sender email@domain" option.
 
 2019-07-12  Paul Eggert  <eggert@cs.ucla.edu>
@@ -119220,7 +120850,7 @@
        Support program switches in 'comint-run' command
 
        * etc/NEWS:
-       * doc/emacs/misc.texi: Describe new behaviour (bug#33037).
+       * doc/emacs/misc.texi: Describe new behavior (bug#33037).
        * lisp/comint.el (comint-run): Add optional SWITCHES argument.
        With prefix argument C-u, prompt for SWITCHES.
 
@@ -120365,11 +121995,11 @@
 
 2019-07-04  Mattias Engdegård  <mattiase@acm.org>
 
-       Optimise more inputs to `regexp-opt' (bug#36444)
+       Optimize more inputs to `regexp-opt' (bug#36444)
 
        Use a more precise test to determine whether the input to `regexp-opt'
-       is safe to optimise when KEEP-ORDER is non-nil, permitting more inputs
-       to be optimised than before.  For example, ("good" "goal" "go") is now
+       is safe to optimize when KEEP-ORDER is non-nil, permitting more inputs
+       to be optimized than before.  For example, ("good" "goal" "go") is now
        accepted.
 
        * lisp/emacs-lisp/regexp-opt.el (regexp-opt):
@@ -121167,7 +122797,7 @@
 
 2019-06-27  Lars Ingebrigtsen  <larsi@gnus.org>
 
-       Mention the new emacsclient -a/--eval behaviour
+       Mention the new emacsclient -a/--eval behavior
 
 2019-06-27  Lars Ingebrigtsen  <larsi@gnus.org>
 
@@ -121345,11 +122975,11 @@
 
        `replace-regexp-in-string' omits the first START characters of the
        input string in its return value.  This is a clear bug, but fixing it
-       probably causes more trouble; document the behaviour instead 
(bug#36372).
+       probably causes more trouble; document the behavior instead (bug#36372).
 
        * doc/lispref/searching.texi (Search and Replace)
        * lisp/subr.el (replace-regexp-in-string):
-       Document current behaviour.
+       Document current behavior.
 
 2019-06-26  Stefan Monnier  <monnier@iro.umontreal.ca>
 
@@ -121612,7 +123242,7 @@
 
        * lisp/view.el (view-search): Jump to the next/prev occurrence of
        the search, even if it's displayed in the buffer (bug#18131).
-       This seems more logical than the previous (undocumented) behaviour.
+       This seems more logical than the previous (undocumented) behavior.
 
 2019-06-25  Paul Eggert  <eggert@cs.ucla.edu>
 
@@ -121796,7 +123426,7 @@
        (goto-address-uri-schemes): Ditto.
        (goto-address-url-regexp): Use them to compose the final regexp.
 
-       * lisp/net/goto-addr.el: The URI schemes to be recognised by
+       * lisp/net/goto-addr.el: The URI schemes to be recognized by
        `goto-address-mode' were not regexp-quoted (Bug#23343).
 
 2019-06-25  Tino Calancha  <f92capac@gmail.com>
@@ -122384,7 +124014,7 @@
 
        Make ls-lisp--dired ape dired-noselect more closely
 
-       * lisp/ls-lisp.el (ls-lisp--dired): Emulate the behaviour of
+       * lisp/ls-lisp.el (ls-lisp--dired): Emulate the behavior of
        non-ls-lisp.el dired better by defaulting to default-directory as
        dired-noselect does (bug#35390).
 
@@ -125326,7 +126956,7 @@
        (global-auto-revert-mode): Don't use
        `after-set-visited-file-name-hook' here.
        (auto-revert-set-visited-file-name): Rename from
-       `auto-revert--global-set-visited-file-name' and generalise.
+       `auto-revert--global-set-visited-file-name' and generalize.
        * test/lisp/autorevert-tests.el (auto-revert-test06-write-file): New.
 
 2019-06-11  Michael Albinus  <michael.albinus@gmx.de>
@@ -127406,7 +129036,7 @@
 
        * lisp/emacs-lisp/package.el (package-install-from-archive): Fix last 
change
 
-       Don't place the unibyte content of of the downloaded file into
+       Don't place the unibyte content of the downloaded file into
        a multibyte buffer.
 
 2019-05-24  Michael Albinus  <michael.albinus@gmx.de>
@@ -129768,10 +131398,10 @@
 
 2019-05-05  Mattias Engdegård  <mattiase@acm.org>
 
-       Reorganise (auto-)revert nodes in the manual
+       Reorganize (auto-)revert nodes in the manual
 
        Put all information about auto-revert into a section of its own, and
-       organise the text in a more logical way.  Previously it was mainly
+       organize the text in a more logical way.  Previously it was mainly
        described in the section about reverting (bug#35418).
 
        * doc/emacs/files.texi (Files): Adjust menu.
@@ -132713,7 +134343,7 @@
        * lisp/progmodes/cc-engine.el (c-looking-at-or-maybe-in-bracelist): On
        detection of such a ref-qualifier, set braceassignp to nil.  When this
        variable has a nil value, return nil as the value of the function.  On
-       encountering a } when scanning backwards, recognise this as the end of a
+       encountering a } when scanning backwards, recognize this as the end of a
        previous construct and stop the scan.
 
 2019-04-12  Stefan Monnier  <monnier@iro.umontreal.ca>
@@ -136964,7 +138594,7 @@
 
        * doc/lispref/searching.texi (Regular Expression Functions):
        * etc/NEWS:
-       Document the new behaviour.
+       Document the new behavior.
        * lisp/emacs-lisp/regexp-opt.el (regexp-opt):
        Return a never-match regexp for empty inputs.
 
@@ -138681,7 +140311,7 @@
        xref-find-definitions or xref-find-definitions-other-window how to
        choose a window for the *xref* buffer or how to find windows for
        displaying the results after choosing a candidate.  This patch makes
-       that task easier, but keeps the current behaviour intact.
+       that task easier, but keeps the current behavior intact.
 
 
        * lisp/progmodes/xref.el (xref--show-pos-in-buf): Simplify.
@@ -139441,7 +141071,7 @@
        image-mode: Make parameters buffer-local
 
        Image parameters were treated as image specific, but because they
-       actually were global variables, their behaviour transferred to new
+       actually were global variables, their behavior transferred to new
        images.
        * lisp/image-mode.el (image-transform-resize, image-transform-scale)
        (image-transform-rotation): Declare with defvar-local.  (Bug#33990)
@@ -139581,7 +141211,7 @@
        To resolve this confusion, never cycle with C-M-i in icomplete:
        non-ambiguous cycling can be achieved with C-. and C-,
 
-       The former behaviour can still be restored with:
+       The former behavior can still be restored with:
 
        (define-key icomplete-minibuffer-map (kbd "C-M-i") 
'minibuffer-force-complete)
 
@@ -139706,7 +141336,7 @@
        really reindented.  Rewrite comment.
        (electric-layout-allow-duplicate-newlines): New variable.
        (electric-layout-post-self-insert-function-1): Rewrite comments.
-       Honours electric-layout-allow-duplicate-newlines.  Don't reindent
+       Honors electric-layout-allow-duplicate-newlines.  Don't reindent
        previous line because racecar.
 
        * test/lisp/electric-tests.el: New test.
@@ -139721,7 +141351,7 @@
 
        Remove tests of electric-pair-mode and CC-based modes
 
-       The behaviour previously observed in cc-mode-based-modes (and every
+       The behavior previously observed in cc-mode-based-modes (and every
        other major-mode) when electric-pair-mode or electric-layout-mode is
        turned on may no longer be observed: this because CC-mode goes around
        the generic implementation of electric-pair-mode.
@@ -140848,10 +142478,10 @@
 
 2019-01-10  Alan Third  <alan@idiocy.org>
 
-       Fix drag and drop behaviour on NS (bug#30929)
+       Fix drag and drop behavior on NS (bug#30929)
 
        * doc/emacs/macos.texi (Mac / GNUstep Events): Describe the new drag
-       and drop behaviour.
+       and drop behavior.
        * lisp/term/ns-win.el (ns-drag-n-drop): Handle the new event format.
        (ns-drag-n-drop-other-frame):
        (ns-drag-n-drop-as-text):
@@ -147548,7 +149178,7 @@
        2018-09-09 mktime: simplify in prep for glibc merge
        2018-09-07 intprops: minor clarification of code
        2018-09-06 stddef: Override max_align_t on NetBSD 8.0/x86
-       2018-09-06 fcntl: Fix F_DUPFD_CLOEXEC behaviour on Haiku
+       2018-09-06 fcntl: Fix F_DUPFD_CLOEXEC behavior on Haiku
        2018-09-06 strtoll, strtoull: Rely on limits-h module
        2018-09-06 limits-h: Provide numerical limits macros
        2018-09-06 fcntl: Don't access nonexistent optional argument
@@ -148448,7 +150078,7 @@
 
        * lisp/textmodes/bibtex.el (bibtex-next-entry)
        (bibtex-previous-entry): New commands.
-       (bibtex-mode-map): Bind to to forward-paragraph and
+       (bibtex-mode-map): Bind to forward-paragraph and
        backward-paragraph.  Add to menu under "Moving inside an Entry".
 
 2018-08-27  Noam Postavsky  <npostavs@gmail.com>
@@ -149801,7 +151431,7 @@
 
 2018-08-09  João Távora  <joaotavora@gmail.com>
 
-       Synchronous JSONRPC requests can be cancelled on user input
+       Synchronous JSONRPC requests can be canceled on user input
 
        This allows building more responsive interfaces, such as a snappier
        completion backend.
@@ -152799,7 +154429,7 @@
 
        Tweak previous gnutls change for efficiency
 
-       * src/gnutls.c (Fgnutls_peer_status): Minor optimisation to avoid
+       * src/gnutls.c (Fgnutls_peer_status): Minor optimization to avoid
        computing the topmost certificate twice.
 
 2018-06-24  Lars Ingebrigtsen  <larsi@gnus.org>
@@ -155894,7 +157524,7 @@
 
        * lisp/window.el (scroll-other-window-down):
        Move to src/window.c as Fscroll_other_window_down.
-       * src/window.c (scroll_command): Generalise for arbitrary windows.
+       * src/window.c (scroll_command): Generalize for arbitrary windows.
        (Fscroll_up, Fscroll_down): Use scroll_command with selected_window.
        (Fscroll_other_window, Fscroll_other_window_down):
        Rewrite in terms of scroll_command.
@@ -156618,7 +158248,7 @@
        326a296 ; * etc/NEWS: Mention 'display-buffer-in-major-side-window' c...
        3bdc9a1 Fix flyspell-auto-correct-previous-word broken by recent change
        a539eb5 * test/src/lread-tests.el (lread-test-bug-31186): New test.
-       3fa472b Fix undefined behaviour while looking for lexical-binding fil...
+       3fa472b Fix undefined behavior while looking for lexical-binding fil...
        4341aac Minor wording improvement in "Bookmarks"
 
        Conflicts:
@@ -157218,7 +158848,7 @@
        * lisp/gnus/gnus-group.el (gnus-update-group-mark-positions):
        Rewrite a call to string-to-multibyte that didn't even work.
        After the rewrite it gives the correct result and should allow
-       people to customise Gnus group process mark positions (but that's
+       people to customize Gnus group process mark positions (but that's
        a pretty obscure feature).
 
 2018-04-14  Lars Ingebrigtsen  <larsi@gnus.org>
@@ -157544,9 +159174,9 @@
 
        From the discussion on the ding mailing list, I said:
 
-       I think the colours should be reverted back to what they were before the
+       I think the colors should be reverted back to what they were before the
        change.  Normal text should be white on black (if you have a dark
-       background), and colours should be used to emphasise or de-emphasise
+       background), and colors should be used to emphasize or de-emphasize
        certain text.  Following that principle, normal Gnus groups should be
        white, not ... er...  what are they now?  Teal?
 
@@ -158975,8 +160605,8 @@
        and numeric conversion in function in order to parse -signal and
        -SIGNALNAME correctly.
        * doc/misc/eshell.texi (kill): Update docs to reflect new function
-       behaviour.
-       * etc/NEWS: Mention new eshell/kill behaviour.
+       behavior.
+       * etc/NEWS: Mention new eshell/kill behavior.
 
 2018-03-25  Noam Postavsky  <npostavs@gmail.com>
 
@@ -163526,7 +165156,7 @@
 
 2018-01-16  Alan Mackenzie  <acm@muc.de>
 
-       C++ Mode: Fontify correctly uniform initialisation with inner 
parentheses.
+       C++ Mode: Fontify correctly uniform initialization with inner 
parentheses.
 
        E.g.: someStruct x ( (nullptr != y) ? 3 : 4 )
        Also fontify declarations of function pointers correctly.
@@ -167575,7 +169205,7 @@
        413978727c Simplify Flymake user documentation
        6ff18c3995 * etc/NEWS: Mention the new version of Org.
        b78332c3c6 Don't use (format "%s" ...) for string copying (Bug#28774)
-       078fb7f6df Make frame-list-z-order on NS match Windows behaviour (bug...
+       078fb7f6df Make frame-list-z-order on NS match Windows behavior (bug...
 
        # Conflicts:
        #       etc/NEWS
@@ -185141,7 +186771,7 @@
 
        * lisp/progmodes/flymake-proc.el
        (flymake-proc--diagnostics-for-pattern): Rewrite (using cl-loop) to
-       honour more sophisticated flymake-proc-diagnostic-type-pred.
+       honor more sophisticated flymake-proc-diagnostic-type-pred.
        (flymake-warning-re): Is now an obsolete alias for
        flymake-proc-diagnostic-type-pred.
        (flymake-proc-diagnostic-type-pred): Rename and augment from
@@ -185306,7 +186936,7 @@
        Lay some groundwork for a more flexible approach that allows for
        different classes of diagnostics, not necessarily line-based.
        Importantly, one overlay per diagnostic is created, whereas the
-       original implementation had one per line, and on it it concatenated
+       original implementation had one per line, and on it concatenated
        the results of errors and warnings.
 
        This means that currently, an error and warning on the same line are
@@ -201597,7 +203227,7 @@
        titlecase_char_table member.  It’s set to the ‘titlecase’ Unicode
        property table if capitalization has been requested.
        (case_character): Make use of the titlecase_char_table to title-case
-       initial characters when capitalising.
+       initial characters when capitalizing.
 
        * test/src/casefiddle-tests.el (casefiddle-tests--characters,
        casefiddle-tests-casing): Update test cases which are now passing.
@@ -203852,7 +205482,7 @@
 
        * lisp/net/tramp.el (tramp-completion-mode): Fix docstring.
        (tramp-completion-mode-p): Optional parameter VEC.  Replace
-       check for `last-input-event' by analysing VEC argument.
+       check for `last-input-event' by analyzing VEC argument.
        (tramp-error-with-buffer, tramp-file-name-handler)
        (tramp-connectable-p, tramp-handle-file-name-as-directory):
        * lisp/net/tramp-sh.el (tramp-maybe-open-connection): Use it.
@@ -216457,8 +218087,7 @@
        Stick with debbugs-supported tags in triage
 
        * admin/notes/bug-triage: Stick to the tag "unreproducible", which
-       debbugs supports, rather than suggesting "doneunreproducible" or
-       "unreproducable".
+       debbugs supports.
 
 2016-09-26  Paul Eggert  <eggert@cs.ucla.edu>
 
@@ -234978,8 +236607,7 @@
 
 This file records repository revisions from
 commit 9d56a21e6a696ad19ac65c4b405aeca44785884a (exclusive) to
-2022-04-13e39829812098d8269eafbc0fcb98959ee5bb7 (inclusive).
-commit e7aa3ece52d26cc7e4d3f3990aff56127389779f (inclusive).
+commit 78759ddcb0fc7dd75a7a8edfb2c19dc2f1d86ee2 (inclusive).
 See ChangeLog.2 for earlier changes.
 
 ;; Local Variables:
diff --git a/Makefile.in b/Makefile.in
index 4b74963665..d288bacb9d 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -51,7 +51,15 @@
 #
 # make bootstrap
 #      Removes all the compiled files to force a new bootstrap from a
-#      clean slate, and then build in the normal way.
+#      clean slate, and then build in the normal way.  If the FAST Make
+#      variable is set, then the config.cache file isn't removed.  This
+#      allows you to say
+#
+#      ./configure -C
+#      make FAST=true bootstrap
+#
+#      and use the cached results from the configure run, which is much
+#      faster.
 #
 # make docs
 #      Make Emacs documentation files from their sources; requires makeinfo.
@@ -358,10 +366,17 @@ endif
 
 gsettings_SCHEMAS = etc/org.gnu.emacs.defaults.gschema.xml
 
-all: ${SUBDIR} info $(gsettings_SCHEMAS:.xml=.valid)
+all: ${SUBDIR} info $(gsettings_SCHEMAS:.xml=.valid) src-depending-on-lisp
 
 .PHONY: all ${SUBDIR} blessmail epaths-force epaths-force-w32 
epaths-force-ns-self-contained etc-emacsver
 
+# Changes in lisp may require us to reconsider the build in src.  For
+# example, if loaddefs.{el,elc} were built in lisp, we need a new
+# .pdmp containing the new autoloads.
+.PHONY: src-depending-on-lisp
+src-depending-on-lisp: lisp
+       ${MAKE} -C src BIN_DESTDIR='$(BIN_DESTDIR)' ELN_DESTDIR='$(ELN_DESTDIR)'
+
 # If configure were to just generate emacsver.tex from emacsver.tex.in
 # in the normal way, the timestamp of emacsver.tex would always be
 # newer than that of the pdf files, which are prebuilt in release tarfiles.
@@ -455,18 +470,11 @@ lisp: src
 lib lib-src lisp nt: Makefile
        $(MAKE) -C $@ all
 
-# Ideally, VCSWITNESS should be a file that is modified whenever the
-# repository registers a commit from either a local checkin or a
-# repository pull. In git there is no single file that guarantees
-# this, but the local log for the current head should be close enough.
-#
 # Pass an unexpanded $srcdir to src's Makefile, which then
 # expands it using its own value of srcdir (which points to the
 # source directory of src/).
-dirstate = .git/logs/HEAD
-VCSWITNESS = $(if $(wildcard $(srcdir)/$(dirstate)),$$(srcdir)/../$(dirstate))
 src: Makefile
-       $(MAKE) -C $@ VCSWITNESS='$(VCSWITNESS)' BIN_DESTDIR='$(BIN_DESTDIR)' \
+       $(MAKE) -C $@ BIN_DESTDIR='$(BIN_DESTDIR)' \
                 ELN_DESTDIR='$(ELN_DESTDIR)' all
 
 blessmail: Makefile src
@@ -936,7 +944,7 @@ clean: $(clean_dirs:=_clean) clean-gsettings-schemas
 ### 'bootclean'
 ###      Delete all files that need to be remade for a clean bootstrap.
 top_bootclean=\
-       rm -f config.cache config.log ${srcdir}/doc/man/emacs.1
+       rm -f config.log ${srcdir}/doc/man/emacs.1
 
 ### 'distclean'
 ###      Delete all files from the current directory that are created by
@@ -946,7 +954,7 @@ top_bootclean=\
 ###      distribution.
 top_distclean=\
        ${top_bootclean}; \
-       rm -f config.status config.log~ \
+       rm -f config.cache config.status config.log~ \
          Makefile makefile lib/gnulib.mk ${SUBDIR_MAKEFILES}
 
 distclean_dirs = $(clean_dirs) leim lisp admin/grammars
@@ -966,6 +974,9 @@ bootstrap-clean: $(distclean_dirs:=_bootstrap-clean)
        rm -rf ${srcdir}/info
        rm -f ${srcdir}/etc/refcards/emacsver.tex
        rm -rf native-lisp/ lisp/leim/ja-dic/
+ifndef FAST
+       rm -f config.cache
+endif
        ${top_bootclean}
 
 ### 'maintainer-clean'
diff --git a/admin/MAINTAINERS b/admin/MAINTAINERS
index f0239db008..6e080d1f5b 100644
--- a/admin/MAINTAINERS
+++ b/admin/MAINTAINERS
@@ -137,6 +137,7 @@ Andrea Corallo
 
 Stefan Kangas
         admin/automerge
+       admin/update_autogen
 
 Po Lu
        The Haiku port:
diff --git a/admin/admin.el b/admin/admin.el
index 6be378b924..c84287a702 100644
--- a/admin/admin.el
+++ b/admin/admin.el
@@ -488,10 +488,11 @@ the @import directive."
       (delete-region opoint (point))
       (search-forward "<meta http-equiv=\"Content-Style")
       (setq opoint (match-beginning 0)))
+    (search-forward "<title>")
+    (delete-region opoint (match-beginning 0))
     (search-forward "</title>\n")
-    (delete-region opoint (point))
-    (search-forward "<link href=")
-    (goto-char (match-beginning 0))
+    (when (search-forward "<link href=" nil t)
+      (goto-char (match-beginning 0)))
     (insert manual-links-string)
     (setq opoint (point))
     (search-forward "</head>")
@@ -617,7 +618,7 @@ style=\"text-align:left\">")
       ;; its original form.
       (when (or (search-forward "<ul class=\"menu\">" nil t)
                ;; FIXME?  The following search seems dangerously lax.
-               (search-forward "<ul>"))
+               (search-forward "<ul>" nil t))
         ;; Convert the list that Makeinfo made into a table.
         (replace-match "<table style=\"float:left\" width=\"100%\">")
         (forward-line 1)
diff --git a/admin/authors.el b/admin/authors.el
index 8a62520d6c..12fe25fa4e 100644
--- a/admin/authors.el
+++ b/admin/authors.el
@@ -163,6 +163,7 @@ files.")
     ("Michael R. Cook" "Michael Cook")
     ("Michael Sperber" "Mike Sperber" "Michael Sperber \\[Mr. Preprocessor\\]")
     ("Michalis V" "^mvar")
+    ("Miha Rihtaršič" "Miha Rihtarsic")
     ("Mikio Nakajima" "Nakajima Mikio")
     ("Nelson Jose dos Santos Ferreira" "Nelson Ferreira")
     ("Noorul Islam" "Noorul Islam K M")
@@ -1882,7 +1883,7 @@ list of their contributions.\n")
                (insert "\n "))
            (insert " " file))
          (insert "\n")))))
-    (insert "\nLocal" " Variables:\nmode: etc-authors\ncoding: "
+    (insert "\nLocal" " Variables:\nmode: emacs-authors\ncoding: "
            (symbol-name authors-coding-system) "\nEnd:\n")
     (message "Generating buffer %s... done" buffer-name)
     (unless noninteractive
diff --git a/admin/automerge b/admin/automerge
index 415d717a99..9919186736 100755
--- a/admin/automerge
+++ b/admin/automerge
@@ -4,7 +4,7 @@
 ## Copyright (C) 2018-2022 Free Software Foundation, Inc.
 
 ## Author: Glenn Morris <rgm@gnu.org>
-## Maintainer: Stefan Kangas <stefan@marxist.se>
+## Maintainer: Stefan Kangas <stefankangas@gmail.com>
 
 ## This file is part of GNU Emacs.
 
diff --git a/admin/check-doc-strings b/admin/check-doc-strings
index 135090b34c..b119b50885 100755
--- a/admin/check-doc-strings
+++ b/admin/check-doc-strings
@@ -290,13 +290,7 @@ while (my $file = <FIND>) {
   }
 }
 
-my @pkgs;
-if (-d "../xemacs-packages") {
-  @pkgs = qw (libs/edebug libs/xemacs-base comm/eudc oa/edit-utils);
-} else {
-  @pkgs = ();
-}
-for (@pkgs) { s@^@../xemacs-packages/@; }
+my @pkgs = ();
 open (FIND, "find lisp @pkgs -name '*.el' -print |") or die;
 while (my $file = <FIND>) {
   my $contents = FileContents $file;
diff --git a/admin/coccinelle/window.cocci b/admin/coccinelle/window.cocci
index 1448febfcc..4543fb2ce1 100644
--- a/admin/coccinelle/window.cocci
+++ b/admin/coccinelle/window.cocci
@@ -106,9 +106,6 @@ Lisp_Object O;
 - W->column_number_displayed
 + WVAR (W, column_number_displayed)
 |
-- W->redisplay_end_trigger
-+ WVAR (W, redisplay_end_trigger)
-|
 - W->combination_limit
 + WVAR (W, combination_limit)
 |
@@ -225,9 +222,6 @@ Lisp_Object O;
 - XWINDOW (O)->column_number_displayed
 + WVAR (XWINDOW (O), column_number_displayed)
 |
-- XWINDOW (O)->redisplay_end_trigger
-+ WVAR (XWINDOW (O), redisplay_end_trigger)
-|
 - XWINDOW (O)->combination_limit
 + WVAR (XWINDOW (O), combination_limit)
 |
diff --git a/admin/emake b/admin/emake
index 6c778c85d4..8b2114b3f8 100755
--- a/admin/emake
+++ b/admin/emake
@@ -20,7 +20,7 @@ if [ -f /proc/cpuinfo ]; then
        sed 's/^[0-9]*/+/')))
 fi
 
-make -j$cores "$@" 2>&1 | \
+make FAST=true -j$cores "$@" 2>&1 | \
 sed -u 's# \.\./\.\./# #
 s# \.\./# #
 s#^Configuring local git # Configuring local git #
@@ -29,6 +29,7 @@ s#^Running # Running #
 s#^Configured for # Configured for #
 s#^./temacs.*#  \\& #
 s#^make.*Error#  \\& #
+s#^Dumping under the name.*#  \\& #
 ' | \
 grep -E --line-buffered -v "^make|\
 ^Loading|\
@@ -36,13 +37,13 @@ SCRAPE|\
 INFO.*Scraping.*[.] ?\$|\
 INFO.*Scraping.*done\$|\
 GEN.*etc/DOC|\
+GEN.*autoloads|\
 ^Waiting for git|\
 ^Finding pointers|\
 ^Using load-path|\
 ^Adding name|\
 ^Dump mode|\
 ^Dumping finger|\
-^Dumping under the name|\
 ^Byte counts|\
 ^Reloc counts|\
 ^Pure-hashed|\
diff --git a/admin/gitmerge.el b/admin/gitmerge.el
index 5da70a4028..25bed949ad 100644
--- a/admin/gitmerge.el
+++ b/admin/gitmerge.el
@@ -124,7 +124,7 @@ If nil, the function `gitmerge-default-branch' guesses.")
       (let ((coding-system-for-read vc-git-log-output-coding-system))
        (call-process "git" nil t nil "show" (format "%s:configure.ac" branch)))
       (goto-char (point-min)))
-    (re-search-forward "^AC_INIT([^,]+, \\([0-9]+\\)\\.")
+    (re-search-forward "^AC_INIT([^,]+, \\[?\\([0-9]+\\)\\.")
     (string-to-number (match-string 1))))
 
 (defun gitmerge-default-branch ()
@@ -135,7 +135,7 @@ If nil, the function `gitmerge-default-branch' guesses.")
 (defun gitmerge-get-sha1 ()
   "Get SHA1 from commit at point."
   (save-excursion
-    (goto-char (point-at-bol))
+    (goto-char (line-beginning-position))
     (when (looking-at "^[A-Z ]\\s-*\\([a-f0-9]+\\)")
       (match-string 1))))
 
@@ -187,7 +187,7 @@ If nil, the function `gitmerge-default-branch' guesses.")
        skip)
     (when commit
       (save-excursion
-       (goto-char (point-at-bol))
+        (goto-char (line-beginning-position))
        (when (looking-at "^\\([A-Z ]\\)\\s-*\\([a-f0-9]+\\)")
          (setq skip (string= (match-string 1) " "))
          (goto-char (match-beginning 2))
@@ -195,7 +195,7 @@ If nil, the function `gitmerge-default-branch' guesses.")
          (dolist (ct gitmerge--commits)
            (when (string-match commit (car ct))
              (setcdr ct (when skip "M"))))
-         (goto-char (point-at-bol))
+          (goto-char (line-beginning-position))
          (setq buffer-read-only nil)
          (delete-char 1)
          (insert (if skip "M" " "))
diff --git a/admin/make-tarball.txt b/admin/make-tarball.txt
index 02b4f318e2..a60fead267 100644
--- a/admin/make-tarball.txt
+++ b/admin/make-tarball.txt
@@ -15,8 +15,8 @@ Steps to take before starting on the first pretest in any 
release sequence:
 2.  Consider increasing the value of the variable
     'customize-changed-options-previous-release' in cus-edit.el to
     refer to a newer version of Emacs.  (This is now done when cutting
-    the release branch, see admin/release-branch.txt.)
-    Commit cus-edit.el if changed.
+    the release branch, see admin/release-branch.txt, but it can't
+    hurt to double check its value.)  Commit cus-edit.el if changed.
 
 3.  Remove any old pretests from https://alpha.gnu.org/gnu/emacs/pretest.
     You can use 'gnupload --delete' (see below for more gnupload details).
@@ -24,8 +24,8 @@ Steps to take before starting on the first pretest in any 
release sequence:
 
 General steps (for each step, check for possible errors):
 
-1.   git pull     # fetch from the repository
-     git status   # check for locally modified files
+1.    git pull     # fetch from the repository
+      git status   # check for locally modified files
 
     Ensure that you have a clean, unmodified state.
     If you switched in-place from another branch to the release branch,
@@ -49,6 +49,9 @@ General steps (for each step, check for possible errors):
     files will end up in the tarball.  Otherwise, the *.eln files
     might not build correctly on the user's system.
 
+      ./autogen.sh
+      ./configure --with-native-compilation && make
+
     For a release (as opposed to pretest), delete any left-over "---"
     and "+++" markers from etc/NEWS, as well as the "Temporary note"
     section at the beginning of that file, and commit etc/NEWS if it
@@ -158,13 +161,15 @@ General steps (for each step, check for possible errors):
 
 5.  Copy lisp/loaddefs.el to lisp/ldefs-boot.el.
 
-    Commit ChangeLog.N, etc/AUTHORS, lisp/ldefs-boot.el, and the
-    files changed by M-x set-version.  The easiest way of doing that
-    is "C-x v d ROOT-DIR RET", then go to the first modified file,
-    press 'M' to mark all modified files, and finally 'v' to commit
-    them.  Make sure the commit log message mentions all the changes
-    in all modified files, as by default 'v' doesn't necessarily do
-    so.
+    Commit ChangeLog.N, etc/AUTHORS, lisp/ldefs-boot.el, and the files
+    changed by M-x set-version.  Note that the set-version changes
+    should be committed separately, as described in step 3 above.
+
+    The easiest way of doing that is "C-x v d ROOT-DIR RET", then go
+    to the first modified file, press 'M' to mark all modified files,
+    and finally 'v' to commit them.  Make sure the commit log message
+    mentions all the changes in all modified files, as by default 'v'
+    doesn't necessarily do so.
 
     If someone else made a commit between step 1 and now,
     you need to repeat from step 4 onwards.  (You can commit the files
@@ -178,9 +183,10 @@ General steps (for each step, check for possible errors):
     yourself, find it at <https://alpha.gnu.org/gnu/emacs/pretest>.
     Releases are of course at <https://ftp.gnu.org/pub/gnu/emacs/>.
 
-     ./admin/diff-tar-files emacs-OLD.tar.gz emacs-NEW.tar.gz
+     ./admin/diff-tar-files emacs-OLD.tar emacs-NEW.tar
 
-    Alternatively:
+    Alternatively, if you want to use the compressed tarballs (which
+    diff-tar-files doesn't understand):
 
      tar tJf emacs-OLD.tar.xz | sed -e 's,^[^/]*,,' | sort > old_tmp
      tar tJf emacs-NEW.tar.xz | sed -e 's,^[^/]*,,' | sort > new_tmp
@@ -198,7 +204,7 @@ General steps (for each step, check for possible errors):
     The output of this command might be easier to compare to the
     tarball than the one you get from find.
 
-7.   tar -xf emacs-NEW.tar; cd emacs-NEW
+7.   tar xf emacs-NEW.tar; cd emacs-NEW
      ./configure --prefix=/tmp/emacs && make check && make install
 
     Use 'script' or M-x compile to save the compilation log in
@@ -282,7 +288,8 @@ General steps (for each step, check for possible errors):
     https://alpha.gnu.org/gnu/emacs/pretest/ for a pretest, or
     https://ftp.gnu.org/gnu/emacs/ for a release.
 
-    Download them and check the signatures.  Check they build.
+    Download them and check the signatures and SHA1/SHA256 checksums.
+    Check they build (./configure --with-native-compilation).
 
 11. Send an announcement to: emacs-devel, and bcc: info-gnu-emacs@gnu.org.
     For a pretest, also bcc: platform-testers@gnu.org.
@@ -300,12 +307,20 @@ General steps (for each step, check for possible errors):
 
     To create the included SHA1 and SHA256 checksums, run:
 
-     sha1sum emacs-NEW.tar.xz
-     sha256sum emacs-NEW.tar.xz
+      sha1sum emacs-NEW.tar.xz
+      sha256sum emacs-NEW.tar.xz
+
+    You can optionally sign the announcement email, preferably using
+    the same PGP key that you used for signing the tarball.
+    (Use e.g. `M-x mml-secure-message-sign' in `message-mode' to sign
+    an email.)
 
 12. After a release, update the Emacs pages as described below.
 
-13. Bump the Emacs version on the release branch.
+13. After a release, bump the Emacs version on the release branch.
+    There is no need to bump the version after a pretest; the version
+    is bumped before the next pretest or release instead.
+
     If the released version was XX.Y, use 'set-version' from
     admin/admin.el to bump the version on the release branch to
     XX.Y.50.  Commit the changes.
@@ -313,8 +328,8 @@ General steps (for each step, check for possible errors):
 UPDATING THE EMACS WEB PAGES AFTER A RELEASE
 
 As soon as possible after a release, the Emacs web pages at
-https://www.gnu.org/software/emacs/ should be updated.  (See
-admin/notes/www for general information.)
+https://www.gnu.org/software/emacs/ should be updated.
+(See admin/notes/www for general information.)
 
 The pages to update are:
 
@@ -330,7 +345,7 @@ looks like this:
 
     <div class="release-banner">
        <div class="container">
-           <h2><em>Emacs 27.1 is out</em>, download it <a 
href="download.html">here</a>!</h2>
+           <h2><em>Emacs 28.1 is out</em>, download it <a 
href="download.html">here</a>!</h2>
        </div>
     </div>
 
diff --git a/admin/merge-gnulib b/admin/merge-gnulib
index ea3d23686f..4dd6a4d222 100755
--- a/admin/merge-gnulib
+++ b/admin/merge-gnulib
@@ -51,7 +51,7 @@ GNULIB_MODULES='
 '
 
 AVOIDED_MODULES='
-  btowc close crypto/af_alg dup fchdir fstat langinfo lock
+  btowc chmod close crypto/af_alg dup fchdir fstat langinfo lock
   mbrtowc mbsinit memchr mkdir msvc-inval msvc-nothrow nl_langinfo
   openat-die opendir pthread-h raise
   save-cwd select setenv sigprocmask stat stdarg stdbool
diff --git a/admin/notes/multi-tty b/admin/notes/multi-tty
index 9b3f1606a1..84bc1b77d4 100644
--- a/admin/notes/multi-tty
+++ b/admin/notes/multi-tty
@@ -474,7 +474,7 @@ THINGS TO DO
    definition.
 
    Exceptions found so far: x-select-text and
-   x-selection-value (old name: x-cut-buffer-or-selection-value).
+   x-selection-value.
 
 ** Have a look at fatal_error_hook.
 
diff --git a/admin/notes/spelling b/admin/notes/spelling
index b783227a37..b20f68bf62 100644
--- a/admin/notes/spelling
+++ b/admin/notes/spelling
@@ -6,6 +6,6 @@ Re "behavior" vs "behaviour", etc.
   for new text (code, docs), choose the US variant.
 
 - It's probably (IMHO --ttn, 2017-10-13) not a high priority to
-  change existing text; use your best judgement (ask if unsure).
+  change existing text; use your best judgment (ask if unsure).
 
 - https://lists.gnu.org/r/emacs-devel/2005-06/msg00489.html
diff --git a/admin/nt/dist-build/README-scripts 
b/admin/nt/dist-build/README-scripts
index 6b1adbe03e..e99fbe0706 100644
--- a/admin/nt/dist-build/README-scripts
+++ b/admin/nt/dist-build/README-scripts
@@ -131,7 +131,7 @@ The process is the same as for building from the master 
branch, except
 that the release branch should already exist as a worktree, and the
 version number must be added to the command line with `build-zips.sh
 -V 27 -s`.  The final zips will be named after the branch rather than
-the version (e.g emacs-27-2019-12-26.zip) rather than than the Emacs
+the version (e.g emacs-27-2019-12-26.zip) rather than the Emacs
 version (e.g emacs-27.0.50.zip).
 
 
diff --git a/admin/nt/dist-build/build-zips.sh 
b/admin/nt/dist-build/build-zips.sh
index 77d20a5a7b..39ac1fde60 100755
--- a/admin/nt/dist-build/build-zips.sh
+++ b/admin/nt/dist-build/build-zips.sh
@@ -148,7 +148,7 @@ done
 if [ -z $ACTUAL_VERSION ];
 then
     ACTUAL_VERSION=`
-  sed -n 's/^AC_INIT(GNU Emacs,[        ]*\([^  ,)]*\).*/\1/p' < 
../../../configure.ac
+  sed -n 's/^AC_INIT(\[*GNU Emacs]*,[   ]*\[*\([^]      ,)]*\).*/\1/p' < 
../../../configure.ac
 `
 fi
 
diff --git a/admin/quick-install-emacs b/admin/quick-install-emacs
index 9a73cf5a40..b0a1d34251 100755
--- a/admin/quick-install-emacs
+++ b/admin/quick-install-emacs
@@ -172,10 +172,10 @@ test x"$prefix" = x && { prefix="`get_config_var prefix`" 
|| exit 4 ; }
 test x"$ARCH" = x && { ARCH="`get_config_var host`" || exit 4 ; }
 
 VERSION=`
-  sed -n 's/^AC_INIT([  ]*emacs[        ]*,[    ]*\([^  ),]*\).*/\1/p' 
<$SRC/configure.ac
+  sed -n 's/^AC_INIT([  ]*\[*emacs]*[   ]*,[    ]*\[*\([^]      ),]*\).*/\1/p' 
<$SRC/configure.ac
 ` || exit 4
 test -n "$VERSION" || VERSION=`
-  sed -n 's/^AC_INIT([  ]*GNU Emacs[    ]*,[    ]*\([^  ),]*\).*/\1/p' 
<$SRC/configure.ac
+  sed -n 's/^AC_INIT([  ]*\[*GNU Emacs]*[       ]*,[    ]*\[*\([^]      
),]*\).*/\1/p' <$SRC/configure.ac
 ` || exit 4
 test -n "$VERSION" || { printf '%s\n' >&2 "$me: no version in configure.ac"; 
exit 4; }
 
diff --git a/admin/unidata/blocks.awk b/admin/unidata/blocks.awk
index 5f392b5ad3..1c571feff3 100755
--- a/admin/unidata/blocks.awk
+++ b/admin/unidata/blocks.awk
@@ -224,9 +224,14 @@ FILENAME ~ "emoji-data.txt" && /^[0-9A-F].*; 
Emoji_Presentation / {
 
 END {
     idx = 0
-    # ## These are here so that font_range can choose Emoji presentation
-    # ## for the preceding codepoint when it encounters a VS
-    override_start[idx] = "FE00"
+    ## This is here so that font_range can choose Emoji presentation
+    ## for the preceding codepoint when it encounters a VS-16
+    ## (U+FE0F).  See also font_range and the comments in composite.el
+    ## around the setup of `composition-function-table' for
+    ## U+FE00..U+FE0E.
+    ## It originally covered the whole FE00-FE0F range, but that
+    ## turned out to be a mistake.
+    override_start[idx] = "FE0F"
     override_end[idx] = "FE0F"
 
     for (k in override_start)
diff --git a/admin/unidata/unidata-gen.el b/admin/unidata/unidata-gen.el
index 0a9fd5108c..78dd1c3728 100644
--- a/admin/unidata/unidata-gen.el
+++ b/admin/unidata/unidata-gen.el
@@ -1083,8 +1083,8 @@ Property value is a symbol `o' (Open), `c' (Close), or 
`n' (None)."
 
 (defun unidata--ensure-compiled (&rest funcs)
   (dolist (fun funcs)
-    (or (byte-code-function-p (symbol-function fun))
-       (byte-compile fun))))
+    (unless (compiled-function-p (symbol-function fun))
+      (byte-compile fun))))
 
 (defun unidata-gen-table-name (prop index &rest _ignore)
   (let* ((table (unidata-gen-table-word-list prop index 'unidata-split-name))
diff --git a/admin/update_autogen b/admin/update_autogen
index bfbf9d15c2..2451367171 100755
--- a/admin/update_autogen
+++ b/admin/update_autogen
@@ -4,7 +4,7 @@
 ## Copyright (C) 2011-2022 Free Software Foundation, Inc.
 
 ## Author: Glenn Morris <rgm@gnu.org>
-## Maintainer: emacs-devel@gnu.org
+## Maintainer: Stefan Kangas <stefankangas@gmail.com>
 
 ## This file is part of GNU Emacs.
 
@@ -81,7 +81,6 @@ ldefs_flag=1
 lboot_flag=
 
 ## Parameters.
-ldefs_in=lisp/loaddefs.el
 ldefs_out=lisp/ldefs-boot.el
 sources="configure.ac lib/Makefile.am"
 ## Files to copy into autogendir.
@@ -177,8 +176,6 @@ modified=$(status ${autogendir:+$sources} 
${ldefs_flag:+lisp}) || die
     echo "Running 'make maintainer-clean'..."
 
     make maintainer-clean #|| die "Cleaning error"
-
-    rm -f $ldefs_in
 }
 
 
@@ -289,18 +286,13 @@ make -C src "$@" bootstrap-emacs || die "make src error"
 
 echo "Running lisp/ make..."
 
-make -C lisp "$@" autoloads EMACS=../src/bootstrap-emacs || die "make src 
error"
-
+make -C lisp "$@" ldefs-boot.el EMACS=../src/bootstrap-emacs || die "make src 
error"
 
-## Ignore comment differences.
-[ ! "$lboot_flag" ] ||                      \
-    diff -q -I '^;' $ldefs_in $ldefs_out || \
-    cp $ldefs_in $ldefs_out || die "cp ldefs_boot error"
 
 # Refresh the prebuilt grammar-wy.el
 grammar_in=lisp/cedet/semantic/grammar-wy.el
 grammar_out=lisp/cedet/semantic/grm-wy-boot.el
-make -C admin/grammars/ ../../$grammar_in
+make -C admin/grammars/ ../../$grammar_in EMACS=../../src/bootstrap-emacs
 cp $grammar_in $grammar_out || die "cp grm_wy_boot error"
 
 
diff --git a/autogen.sh b/autogen.sh
index 03f647e576..041468edcd 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -35,7 +35,7 @@
 progs="autoconf"
 
 ## Minimum versions we need:
-autoconf_min=`sed -n 's/^ *AC_PREREQ(\([0-9\.]*\)).*/\1/p' configure.ac`
+autoconf_min=`sed -n 's/^ *AC_PREREQ(\[\([0-9\.]*\)]).*/\1/p' configure.ac`
 
 
 ## $1 = program, eg "autoconf".
diff --git a/build-aux/config.guess b/build-aux/config.guess
index 160ecf0951..1817bdce90 100755
--- a/build-aux/config.guess
+++ b/build-aux/config.guess
@@ -4,7 +4,7 @@
 
 # shellcheck disable=SC2006,SC2268 # see below for rationale
 
-timestamp='2022-05-08'
+timestamp='2022-05-25'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -1378,8 +1378,11 @@ EOF
     BePC:Haiku:*:*)    # Haiku running on Intel PC compatible.
        GUESS=i586-pc-haiku
        ;;
-    x86_64:Haiku:*:*)
-       GUESS=x86_64-unknown-haiku
+    ppc:Haiku:*:*)     # Haiku running on Apple PowerPC
+       GUESS=powerpc-apple-haiku
+       ;;
+    *:Haiku:*:*)       # Haiku modern gcc (not bound by BeOS compat)
+       GUESS=$UNAME_MACHINE-unknown-haiku
        ;;
     SX-4:SUPER-UX:*:*)
        GUESS=sx4-nec-superux$UNAME_RELEASE
diff --git a/build-aux/config.sub b/build-aux/config.sub
index 9b62e37c43..dba16e84c7 100755
--- a/build-aux/config.sub
+++ b/build-aux/config.sub
@@ -1,10 +1,10 @@
 #! /bin/sh
 # Configuration validation subroutine script.
-#   Copyright 1992-2021 Free Software Foundation, Inc.
+#   Copyright 1992-2022 Free Software Foundation, Inc.
 
 # shellcheck disable=SC2006,SC2268 # see below for rationale
 
-timestamp='2021-12-25'
+timestamp='2022-01-03'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -76,7 +76,7 @@ Report bugs and patches to <config-patches@gnu.org>."
 version="\
 GNU config.sub ($timestamp)
 
-Copyright 1992-2021 Free Software Foundation, Inc.
+Copyright 1992-2022 Free Software Foundation, Inc.
 
 This is free software; see the source for copying conditions.  There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
diff --git a/config.bat b/config.bat
index e9a180c8ee..4adc477bc9 100644
--- a/config.bat
+++ b/config.bat
@@ -301,6 +301,7 @@ If Exist sys_time.in.h update sys_time.in.h sys_time.in-h
 If Exist sys_types.in.h update sys_types.in.h sys_types.in-h
 If Exist time.in.h update time.in.h time.in-h
 If Exist unistd.in.h update unistd.in.h unistd.in-h
+If Exist stdckdint.in.h update stdckdint.in.h stdckdint.in-h
 If Exist gnulib.mk.in update gnulib.mk.in gnulib.mk-in
 Rem Only repository has the msdos/autogen directory
 If Exist Makefile.in sed -f ../msdos/sedlibcf.inp < Makefile.in > makefile.tmp
diff --git a/configure.ac b/configure.ac
index a2b24e3961..43827e07a5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -21,9 +21,10 @@ dnl
 dnl  You should have received a copy of the GNU General Public License
 dnl  along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
-AC_PREREQ(2.65)
+AC_PREREQ([2.65])
 dnl Note this is parsed by (at least) make-dist and lisp/cedet/ede/emacs.el.
-AC_INIT(GNU Emacs, 29.0.50, bug-gnu-emacs@gnu.org, , 
https://www.gnu.org/software/emacs/)
+AC_INIT([GNU Emacs], [29.0.50], [bug-gnu-emacs@gnu.org], [],
+  [https://www.gnu.org/software/emacs/])
 
 dnl Set emacs_config_options to the options of 'configure', quoted for the 
shell,
 dnl and then quoted again for a C string.  Separate options with spaces.
@@ -64,13 +65,13 @@ for opt in "$@" CFLAGS CPPFLAGS LDFLAGS; do
   optsep=' '
 done
 
-AC_CONFIG_HEADERS(src/config.h:src/config.in)
-AC_CONFIG_SRCDIR(src/lisp.h)
-AC_CONFIG_AUX_DIR(build-aux)
-AC_CONFIG_MACRO_DIR(m4)
+AC_CONFIG_HEADERS([src/config.h:src/config.in])
+AC_CONFIG_SRCDIR([src/lisp.h])
+AC_CONFIG_AUX_DIR([build-aux])
+AC_CONFIG_MACRO_DIR([m4])
 
 xcsdkdir=
-AC_CHECK_PROGS(XCRUN, [xcrun])
+AC_CHECK_PROGS([XCRUN], [xcrun])
 if test -n "$XCRUN"; then
   if test -z "$MAKE"; then
     dnl Call the variable MAKE_PROG, not MAKE, to avoid confusion with
@@ -199,7 +200,7 @@ etcdocdir='${datadir}/emacs/${version}/etc'
 gamedir='${localstatedir}/games/emacs'
 
 dnl Special option to disable the most of other options.
-AC_ARG_WITH(all,
+AC_ARG_WITH([all],
 [AS_HELP_STRING([--without-all],
                [omit almost all features and build
                small executable with minimal dependencies])],
@@ -278,41 +279,45 @@ AC_ARG_WITH([pop],
      *) with_pop=no-by-default;;
    esac])
 if test "$with_pop" = yes; then
-   AC_DEFINE(MAIL_USE_POP)
+   AC_DEFINE([MAIL_USE_POP])
 fi
-AH_TEMPLATE(MAIL_USE_POP, [Define to support POP mail retrieval.])dnl
+AH_TEMPLATE([MAIL_USE_POP], [Define to support POP mail retrieval.])dnl
 
 OPTION_DEFAULT_OFF([kerberos],[support Kerberos-authenticated POP])
 if test "$with_kerberos" != no; then
-   AC_DEFINE(KERBEROS)
+   AC_DEFINE([KERBEROS])
 fi
-AH_TEMPLATE(KERBEROS,
+AH_TEMPLATE([KERBEROS],
            [Define to support Kerberos-authenticated POP mail retrieval.])dnl
 
 OPTION_DEFAULT_OFF([kerberos5],[support Kerberos version 5 authenticated POP])
 if test "${with_kerberos5}" != no; then
   if test "${with_kerberos}" = no; then
     with_kerberos=yes
-    AC_DEFINE(KERBEROS)
+    AC_DEFINE([KERBEROS])
   fi
-  AC_DEFINE(KERBEROS5, 1, [Define to use Kerberos 5 instead of Kerberos 4.])
+  AC_DEFINE([KERBEROS5], [1],
+    [Define to use Kerberos 5 instead of Kerberos 4.])
 fi
 
 OPTION_DEFAULT_OFF([hesiod],[support Hesiod to get the POP server host])
 dnl FIXME hesiod support may not be present, so it seems like an error
 dnl to define, or at least use, this unconditionally.
 if test "$with_hesiod" != no; then
-  AC_DEFINE(HESIOD, 1, [Define to support using a Hesiod database to find the 
POP server.])
+  AC_DEFINE([HESIOD], [1],
+    [Define to support using a Hesiod database to find the POP server.])
 fi
 
 OPTION_DEFAULT_OFF([mail-unlink],[unlink, rather than empty, mail spool after 
reading])
 if test "$with_mail_unlink" != no; then
-   AC_DEFINE(MAIL_UNLINK_SPOOL, 1, [Define to unlink, rather than empty, mail 
spool after reading.])
+   AC_DEFINE([MAIL_UNLINK_SPOOL], [1],
+     [Define to unlink, rather than empty, mail spool after reading.])
 fi
 
 AC_ARG_WITH([mailhost],[AS_HELP_STRING([--with-mailhost=HOSTNAME],
     [string giving default POP mail host])],
-    AC_DEFINE_UNQUOTED(MAILHOST, ["$withval"], [String giving fallback POP 
mail host.]))
+    AC_DEFINE_UNQUOTED([MAILHOST], ["$withval"],
+      [String giving fallback POP mail host.]))
 
 AC_ARG_WITH([sound],[AS_HELP_STRING([--with-sound=VALUE],
   [compile with sound support (VALUE one of: yes, alsa, oss, bsd-ossaudio, no;
@@ -395,7 +400,8 @@ if test "$with_dumping" = "unexec" && test "$with_unexec" = 
"no"; then
 fi
 
 if test "$with_pdumper" = "yes"; then
-  AC_DEFINE([HAVE_PDUMPER], 1, [Define to build with portable dumper support])
+  AC_DEFINE([HAVE_PDUMPER], [1],
+    [Define to build with portable dumper support])
   HAVE_PDUMPER=yes
 else
   HAVE_PDUMPER=no
@@ -403,7 +409,7 @@ fi
 AC_SUBST([HAVE_PDUMPER])
 
 DUMPING=$with_dumping
-AC_SUBST(DUMPING)
+AC_SUBST([DUMPING])
 
 dnl FIXME currently it is not the last.
 dnl This should be the last --with option, because --with-x is
@@ -436,7 +442,7 @@ OPTION_DEFAULT_OFF([wide-int],
    at the cost of 10% to 30% slowdown of Lisp interpreter
    and larger memory footprint])
 if test "$with_wide_int" = yes; then
-  AC_DEFINE([WIDE_EMACS_INT], 1, [Use long long for EMACS_INT if available.])
+  AC_DEFINE([WIDE_EMACS_INT], [1], [Use long long for EMACS_INT if available.])
 fi
 
 dnl _ON results in a '--without' option in the --help output, so
@@ -523,7 +529,7 @@ OPTION_DEFAULT_OFF([be-cairo],
   [enable use of cairo under Haiku's Application Kit])
 
 ## Makefile.in needs the cache file name.
-AC_SUBST(cache_file)
+AC_SUBST([cache_file])
 
 ## This is an option because I do not know if all info/man support
 ## compressed files, nor how to test if they do so.
@@ -531,7 +537,7 @@ OPTION_DEFAULT_ON([compress-install],
   [don't compress some files (.el, .info, etc.) when installing.  Equivalent 
to:
 make GZIP_PROG= install])
 
-AC_ARG_WITH(gameuser,dnl
+AC_ARG_WITH([gameuser],
 [AS_HELP_STRING([--with-gameuser=USER_OR_GROUP],
                [user for shared game score files.
                An argument prefixed by ':' specifies a group instead.])])
@@ -544,7 +550,7 @@ case ${with_gameuser} in
   *) gameuser=${with_gameuser} ;;
 esac
 
-AC_ARG_WITH([gnustep-conf],dnl
+AC_ARG_WITH([gnustep-conf],
 [AS_HELP_STRING([--with-gnustep-conf=FILENAME],
    [name of GNUstep configuration file to use on systems where the command
     'gnustep-config' does not work; default $GNUSTEP_CONFIG_FILE, or
@@ -554,24 +560,24 @@ test "X${with_gnustep_conf}" != X && test 
"${with_gnustep_conf}" != yes && \
 test "X$GNUSTEP_CONFIG_FILE" = "X" && \
      GNUSTEP_CONFIG_FILE=/etc/GNUstep/GNUstep.conf
 
-AC_ARG_ENABLE(ns-self-contained,
+AC_ARG_ENABLE([ns-self-contained],
 [AS_HELP_STRING([--disable-ns-self-contained],
                 [disable self contained build under NeXTstep])],
-   EN_NS_SELF_CONTAINED=$enableval,
-   EN_NS_SELF_CONTAINED=yes)
+   [EN_NS_SELF_CONTAINED=$enableval],
+   [EN_NS_SELF_CONTAINED=yes])
 
 locallisppathset=no
-AC_ARG_ENABLE(locallisppath,
+AC_ARG_ENABLE([locallisppath],
 [AS_HELP_STRING([--enable-locallisppath=PATH],
                 [directories Emacs should search for lisp files specific
                 to this site])],
-if test "${enableval}" = "no"; then
+[if test "${enableval}" = "no"; then
   locallisppath=
 elif test "${enableval}" != "yes"; then
   locallisppath=${enableval} locallisppathset=yes
-fi)
+fi])
 
-AC_ARG_ENABLE(checking,
+AC_ARG_ENABLE([checking],
 [AS_HELP_STRING([--enable-checking@<:@=LIST@:>@],
                [enable expensive checks.  With LIST,
                 enable only specific categories of checks.
@@ -604,17 +610,17 @@ do
        stringfreelist) ac_gc_check_string_free_list=1 ;;
        structs)        CHECK_STRUCTS=true ;;
        glyphs)         ac_glyphs_debug=1 ;;
-       *)      AC_MSG_ERROR(unknown check category $check) ;;
+       *)      AC_MSG_ERROR([unknown check category $check]) ;;
        esac
 done
 IFS="$ac_save_IFS"
 
 if test x$ac_enable_checking != x ; then
-  AC_DEFINE(ENABLE_CHECKING, 1,
+  AC_DEFINE([ENABLE_CHECKING], [1],
 [Define to 1 if expensive run-time data type and consistency checks are 
enabled.])
 fi
 if $CHECK_STRUCTS; then
-  AC_DEFINE([CHECK_STRUCTS], 1,
+  AC_DEFINE([CHECK_STRUCTS], [1],
     [Define this to check whether someone updated the portable dumper
      code after changing the layout of a structure that it uses.
      If you change one of these structures, check that the pdumper.c
@@ -623,21 +629,21 @@ if $CHECK_STRUCTS; then
 fi
 AC_SUBST([CHECK_STRUCTS])
 if test x$ac_gc_check_stringbytes != x ; then
-  AC_DEFINE(GC_CHECK_STRING_BYTES, 1,
+  AC_DEFINE([GC_CHECK_STRING_BYTES], [1],
 [Define this temporarily to hunt a bug.  If defined, the size of
    strings is redundantly recorded in sdata structures so that it can
    be compared to the sizes recorded in Lisp strings.])
 fi
 if test x$ac_gc_check_string_overrun != x ; then
-  AC_DEFINE(GC_CHECK_STRING_OVERRUN, 1,
+  AC_DEFINE([GC_CHECK_STRING_OVERRUN], [1],
 [Define this to check for short string overrun.])
 fi
 if test x$ac_gc_check_string_free_list != x ; then
-  AC_DEFINE(GC_CHECK_STRING_FREE_LIST, 1,
+  AC_DEFINE([GC_CHECK_STRING_FREE_LIST], [1],
 [Define this to check the string free list.])
 fi
 if test x$ac_glyphs_debug != x ; then
-  AC_DEFINE(GLYPH_DEBUG, 1,
+  AC_DEFINE([GLYPH_DEBUG], [1],
 [Define this to enable glyphs debugging code.])
 fi
 
@@ -645,7 +651,7 @@ dnl The name of this option is unfortunate.  It predates, 
and has no
 dnl relation to, the "sampling-based elisp profiler" added in 24.3.
 dnl Actually, it stops it working.
 dnl https://lists.gnu.org/r/emacs-devel/2012-11/msg00393.html
-AC_ARG_ENABLE(profiling,
+AC_ARG_ENABLE([profiling],
 [AS_HELP_STRING([--enable-profiling],
                [build emacs with low-level, gprof profiling support.
                 Mainly useful for debugging Emacs itself.  May not work on
@@ -656,15 +662,15 @@ if test x$ac_enable_profiling != x ; then
 else
    PROFILING_CFLAGS=
 fi
-AC_SUBST(PROFILING_CFLAGS)
+AC_SUBST([PROFILING_CFLAGS])
 
-AC_ARG_ENABLE(autodepend,
+AC_ARG_ENABLE([autodepend],
 [AS_HELP_STRING([--enable-autodepend],
                [automatically generate dependencies to .h-files.
                 Requires gcc, enabled if found.])],
 [ac_enable_autodepend="${enableval}"],[ac_enable_autodepend=yes])
 
-AC_ARG_ENABLE(gtk-deprecation-warnings,
+AC_ARG_ENABLE([gtk-deprecation-warnings],
 [AS_HELP_STRING([--enable-gtk-deprecation-warnings],
                [Show Gtk+/Gdk deprecation warnings for Gtk+ >= 3.0])],
 [ac_enable_gtk_deprecation_warnings="${enableval}"],[])
@@ -867,7 +873,7 @@ AC_DEFUN([_AC_PROG_CC_C89], [$2])
 dnl Sets GCC=yes if using gcc.
 AC_PROG_CC([gcc cc cl clang "$XCRUN gcc" "$XCRUN clang"])
 if test -n "$XCRUN"; then
-  AC_CHECK_PROGS(AR, [ar "$XCRUN ar"])
+  AC_CHECK_PROGS([AR], [ar "$XCRUN ar"])
   test -n "$AR" && export AR
 fi
 
@@ -1009,7 +1015,7 @@ AC_ARG_ENABLE([check-lisp-object-type],
      [Enable compile time checks for the Lisp_Object data type,
       which can catch some bugs during development.])])
 if test "$enable_check_lisp_object_type" = yes; then
-  AC_DEFINE([CHECK_LISP_OBJECT_TYPE], 1,
+  AC_DEFINE([CHECK_LISP_OBJECT_TYPE], [1],
     [Define to enable compile-time checks for the Lisp_Object data type.])
 fi
 
@@ -1158,7 +1164,7 @@ edit_cflags="
   s/^ //
 "
 
-AC_ARG_ENABLE(link-time-optimization,
+AC_ARG_ENABLE([link-time-optimization],
 [AS_HELP_STRING([--enable-link-time-optimization],
                 [build with link-time optimization
                 (experimental; see INSTALL)])],
@@ -1268,7 +1274,7 @@ fi
 rm -f conf$$ conf$$.file])
 LN_S_FILEONLY=$emacs_cv_ln_s_fileonly
 
-AC_SUBST(LN_S_FILEONLY)
+AC_SUBST([LN_S_FILEONLY])
 
 
 dnl AC_PROG_LN_S sets LN_S to 'cp -pR' for MinGW, on the premise that 'ln'
@@ -1287,13 +1293,13 @@ dnl if called via an absolute file name.
 dnl Use the entirely-identical-but-quieter ginstall-info instead if present.
 dnl Sadly some people may have an old ginstall-info installed on
 dnl non-Debian systems, so we can't use this.
-dnl AC_PATH_PROGS(INSTALL_INFO, [ginstall-info install-info], :,
-dnl   $PATH$PATH_SEPARATOR/usr/sbin$PATH_SEPARATOR/sbin)
+dnl AC_PATH_PROGS([INSTALL_INFO], [ginstall-info install-info], [:],
+dnl   [$PATH$PATH_SEPARATOR/usr/sbin$PATH_SEPARATOR/sbin])
 
-AC_PATH_PROG(INSTALL_INFO, install-info, :,
-  $PATH$PATH_SEPARATOR/usr/sbin$PATH_SEPARATOR/sbin)
+AC_PATH_PROG([INSTALL_INFO], [install-info], [:],
+  [$PATH$PATH_SEPARATOR/usr/sbin$PATH_SEPARATOR/sbin])
 dnl Don't use GZIP, which is used by gzip for additional parameters.
-AC_PATH_PROG(GZIP_PROG, gzip)
+AC_PATH_PROG([GZIP_PROG], [gzip])
 
 test $with_compress_install != yes && test -n "$GZIP_PROG" && \
    GZIP_PROG=" # $GZIP_PROG # (disabled by configure 
--without-compress-install)"
@@ -1362,7 +1368,7 @@ AC_SUBST([SETFATTR])
 
 # Makeinfo on macOS is ancient, check whether there is a more recent
 # version installed by Homebrew.
-AC_CHECK_PROGS(BREW, [brew])
+AC_CHECK_PROGS([BREW], [brew])
 if test -n "$BREW"; then
   AC_PATH_PROG([MAKEINFO], [makeinfo], [],
     [`$BREW --prefix texinfo 2>/dev/null`/bin$PATH_SEPARATOR$PATH])
@@ -1370,7 +1376,7 @@ fi
 
 # Check MacPorts on macOS.
 if test $opsys = darwin; then
-  AC_PATH_PROG(HAVE_MACPORTS, port)
+  AC_PATH_PROG([HAVE_MACPORTS], [port])
 fi
 
 ## Require makeinfo >= 4.13 (last of the 4.x series) to build the manuals.
@@ -1410,7 +1416,7 @@ if test $opsys = mingw32; then
 else
    DOCMISC_W32=
 fi
-AC_SUBST(DOCMISC_W32)
+AC_SUBST([DOCMISC_W32])
 
 dnl Add our options to ac_link now, after it is set up.
 
@@ -1469,7 +1475,7 @@ AC_CACHE_CHECK([whether addresses are sanitized],
      [emacs_cv_sanitize_address=no])])
 
 if test $with_unexec = yes; then
-  AC_DEFINE([HAVE_UNEXEC], 1, [Define if Emacs supports unexec.])
+  AC_DEFINE([HAVE_UNEXEC], [1], [Define if Emacs supports unexec.])
   if test "$emacs_cv_sanitize_address" = yes; then
     AC_MSG_WARN([[Addresses are sanitized; suggest --without-unexec]])
   fi
@@ -1506,7 +1512,7 @@ case "$opsys" in
    UNEXEC_OBJ=unexelf.o
    ;;
 esac
-AC_SUBST(UNEXEC_OBJ)
+AC_SUBST([UNEXEC_OBJ])
 
 LD_SWITCH_SYSTEM=
 test "$with_unexec" = no || case "$opsys" in
@@ -1536,7 +1542,7 @@ test "$with_unexec" = no || case "$opsys" in
    LD_SWITCH_SYSTEM="-Z"
    ;;
 esac
-AC_SUBST(LD_SWITCH_SYSTEM)
+AC_SUBST([LD_SWITCH_SYSTEM])
 
 ac_link="$ac_link $LD_SWITCH_SYSTEM"
 
@@ -1572,7 +1578,7 @@ case $canonical in
     fi
   ;;
 esac
-AC_SUBST(C_SWITCH_MACHINE)
+AC_SUBST([C_SWITCH_MACHINE])
 
 C_SWITCH_SYSTEM=
 ## Some programs in src produce warnings saying certain subprograms
@@ -1588,7 +1594,7 @@ if test "$opsys" = "mingw32"; then
 fi
 ## gnu-linux might need -D_BSD_SOURCE on old libc5 systems.
 ## It is redundant in glibc2, since we define _GNU_SOURCE.
-AC_SUBST(C_SWITCH_SYSTEM)
+AC_SUBST([C_SWITCH_SYSTEM])
 
 
 LIBS_SYSTEM=
@@ -1610,7 +1616,7 @@ case "$opsys" in
   haiku) LIBS_SYSTEM="-lnetwork" ;;
 esac
 
-AC_SUBST(LIBS_SYSTEM)
+AC_SUBST([LIBS_SYSTEM])
 
 ### Make sure subsequent tests use flags consistent with the build flags.
 
@@ -1718,8 +1724,8 @@ case $opsys in
 
 esac
 
-AC_SUBST(LIB_MATH)
-AC_DEFINE_UNQUOTED(SYSTEM_TYPE, "$SYSTEM_TYPE",
+AC_SUBST([LIB_MATH])
+AC_DEFINE_UNQUOTED([SYSTEM_TYPE], ["$SYSTEM_TYPE"],
   [The type of system you are compiling for; sets 'system-type'.])
 AC_SUBST([SYSTEM_TYPE])
 
@@ -1727,11 +1733,11 @@ AC_SUBST([SYSTEM_TYPE])
 pre_PKG_CONFIG_CFLAGS=$CFLAGS
 pre_PKG_CONFIG_LIBS=$LIBS
 
-PKG_PROG_PKG_CONFIG(0.9.0)
+PKG_PROG_PKG_CONFIG([0.9.0])
 
-dnl EMACS_CHECK_MODULES(GSTUFF, gtk+-2.0 >= 1.3 glib = 1.3.4)
-dnl acts like PKG_CHECK_MODULES(GSTUFF, gtk+-2.0 >= 1.3 glib = 1.3.4,
-dnl HAVE_GSTUFF=yes, HAVE_GSTUFF=no) -- see pkg-config man page --
+dnl EMACS_CHECK_MODULES([GSTUFF], [gtk+-2.0 >= 1.3 glib = 1.3.4])
+dnl acts like PKG_CHECK_MODULES([GSTUFF], [gtk+-2.0 >= 1.3 glib = 1.3.4],
+dnl [HAVE_GSTUFF=yes], [HAVE_GSTUFF=no]) -- see pkg-config man page --
 dnl except that it postprocesses CFLAGS as needed for --enable-gcc-warnings.
 dnl EMACS_CHECK_MODULES accepts optional 3rd and 4th arguments that
 dnl can take the place of the default HAVE_GSTUFF=yes and HAVE_GSTUFF=no
@@ -1746,7 +1752,7 @@ HAVE_SOUND=no
 if test "${with_sound}" != "no"; then
   # Sound support for GNU/Linux, the free BSDs, MinGW, and Cygwin.
   AC_CHECK_HEADERS([machine/soundcard.h sys/soundcard.h soundcard.h 
mmsystem.h],
-    have_sound_header=yes, [], [
+    [have_sound_header=yes], [], [
     #ifdef __MINGW32__
     #define WIN32_LEAN_AND_MEAN
     #include <windows.h>
@@ -1757,13 +1763,13 @@ if test "${with_sound}" != "no"; then
 
   if test "${with_sound}" = "bsd-ossaudio" || test "${with_sound}" = "yes"; 
then
     # Emulation library used on NetBSD.
-    AC_CHECK_LIB(ossaudio, _oss_ioctl, LIBSOUND=-lossaudio, LIBSOUND=)
+    AC_CHECK_LIB([ossaudio], [_oss_ioctl], [LIBSOUND=-lossaudio], [LIBSOUND=])
     test "${with_sound}" = "bsd-ossaudio" && test -z "$LIBSOUND" && \
       AC_MSG_ERROR([bsd-ossaudio sound support requested but not found.])
     dnl FIXME?  If we did find ossaudio, should we set with_sound=bsd-ossaudio?
     dnl Traditionally, we go on to check for alsa too.  Does that make sense?
   fi
-  AC_SUBST(LIBSOUND)
+  AC_SUBST([LIBSOUND])
 
   if test "${with_sound}" = "alsa" || test "${with_sound}" = "yes"; then
     ALSA_REQUIRED=1.0.0
@@ -1772,7 +1778,7 @@ if test "${with_sound}" != "no"; then
     if test $HAVE_ALSA = yes; then
       LIBSOUND="$LIBSOUND $ALSA_LIBS"
       CFLAGS_SOUND="$CFLAGS_SOUND $ALSA_CFLAGS"
-      AC_DEFINE(HAVE_ALSA, 1, [Define to 1 if ALSA is available.])
+      AC_DEFINE([HAVE_ALSA], [1], [Define to 1 if ALSA is available.])
     elif test "${with_sound}" = "alsa"; then
       AC_MSG_ERROR([ALSA sound support requested but not found.])
     fi
@@ -1788,25 +1794,25 @@ if test "${with_sound}" != "no"; then
        dnl defined __FreeBSD__ || defined __NetBSD__ || defined __linux__
        dnl Adjust the --with-sound help text if you change this.
        gnu-linux|freebsd|netbsd|mingw32|cygwin)
-         AC_DEFINE(HAVE_SOUND, 1, [Define to 1 if you have sound support.])
+        AC_DEFINE([HAVE_SOUND], [1], [Define to 1 if you have sound support.])
          HAVE_SOUND=yes
          ;;
      esac
   fi
 
-  AC_SUBST(CFLAGS_SOUND)
+  AC_SUBST([CFLAGS_SOUND])
 fi
 
 dnl checks for header files
 AC_CHECK_HEADERS_ONCE(
-  linux/fs.h
+ [linux/fs.h
   malloc.h
   sys/systeminfo.h
   sys/sysinfo.h
   coff.h pty.h
   sys/resource.h
   sys/utsname.h pwd.h utmp.h util.h
-  sanitizer/lsan_interface.h)
+  sanitizer/lsan_interface.h])
 
 AC_CACHE_CHECK([for ADDR_NO_RANDOMIZE],
   [emacs_cv_personality_addr_no_randomize],
@@ -1833,10 +1839,11 @@ if test "$ac_cv_header_sys_sysinfo_h" = yes; then
     emacs_cv_linux_sysinfo=yes, emacs_cv_linux_sysinfo=no)])
 
   if test $emacs_cv_linux_sysinfo = yes; then
-    AC_DEFINE([HAVE_LINUX_SYSINFO], 1, [Define to 1 if you have Linux sysinfo 
function.])
+    AC_DEFINE([HAVE_LINUX_SYSINFO], [1],
+      [Define to 1 if you have Linux sysinfo function.])
     AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/sysinfo.h>]],
                                        [[struct sysinfo si; return 
si.mem_unit]])],
-      AC_DEFINE(LINUX_SYSINFO_UNIT, 1,
+      AC_DEFINE([LINUX_SYSINFO_UNIT], [1],
                 [Define to 1 if Linux sysinfo sizes are in multiples of 
mem_unit bytes.]))
   fi
 fi
@@ -1844,19 +1851,20 @@ fi
 dnl On Solaris 8 there's a compilation warning for term.h because
 dnl it doesn't define 'bool'.
 AC_PREPROC_IFELSE([AC_LANG_PROGRAM([[#include <term.h>]],[[]])],
-  AC_DEFINE(HAVE_TERM_H, 1, [Define to 1 if you have the <term.h> header 
file.]))
+  [AC_DEFINE([HAVE_TERM_H], [1],
+     [Define to 1 if you have the <term.h> header file.])])
 AC_HEADER_SYS_WAIT
 
-AC_CHECK_HEADERS_ONCE(sys/socket.h)
-AC_CHECK_HEADERS(net/if.h, , , [AC_INCLUDES_DEFAULT
+AC_CHECK_HEADERS_ONCE([sys/socket.h])
+AC_CHECK_HEADERS([net/if.h], [], [], [AC_INCLUDES_DEFAULT
 #if HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
 #endif])
-AC_CHECK_HEADERS(ifaddrs.h, , , [AC_INCLUDES_DEFAULT
+AC_CHECK_HEADERS([ifaddrs.h], [], [], [AC_INCLUDES_DEFAULT
 #if HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
 #endif])
-AC_CHECK_HEADERS(net/if_dl.h, , , [AC_INCLUDES_DEFAULT
+AC_CHECK_HEADERS([net/if_dl.h], [], [], [AC_INCLUDES_DEFAULT
 #if HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
 #endif])
@@ -1865,7 +1873,7 @@ dnl checks for structure members
 AC_CHECK_MEMBERS([struct ifreq.ifr_flags, struct ifreq.ifr_hwaddr,
                  struct ifreq.ifr_netmask, struct ifreq.ifr_broadaddr,
                  struct ifreq.ifr_addr,
-                 struct ifreq.ifr_addr.sa_len], , ,
+                 struct ifreq.ifr_addr.sa_len], [], [],
                 [AC_INCLUDES_DEFAULT
 #if HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
@@ -1895,7 +1903,7 @@ if test "$GCC" = yes && test "$ac_enable_autodepend" = 
yes; then
       AUTO_DEPEND=yes
    fi
 fi
-AC_SUBST(AUTO_DEPEND)
+AC_SUBST([AUTO_DEPEND])
 
 #### Choose a window system.
 
@@ -1945,7 +1953,7 @@ ${x_library}/X11/%T/%N%S"
     fi
   done
 fi
-AC_SUBST(LD_SWITCH_X_SITE_RPATH)
+AC_SUBST([LD_SWITCH_X_SITE_RPATH])
 
 if test "${x_includes}" != NONE && test -n "${x_includes}"; then
   C_SWITCH_X_SITE=$isystem`AS_ECHO(["$x_includes"]) | sed -e "s/:/ $isystem/g"`
@@ -2029,17 +2037,20 @@ if test "${with_ns}" != no; then
      dnl GNUstep defines BASE_NATIVE_OBJC_EXCEPTIONS to 0 or 1.
      dnl If they had chosen to either define it or not, we could have
      dnl just used AC_CHECK_DECL here.
-     AC_CACHE_CHECK(if GNUstep defines BASE_NATIVE_OBJC_EXCEPTIONS,
-       emacs_cv_objc_exceptions,
-AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <GNUstepBase/GSConfig.h>]],
+     AC_CACHE_CHECK([if GNUstep defines BASE_NATIVE_OBJC_EXCEPTIONS],
+       [emacs_cv_objc_exceptions],
+       [AC_COMPILE_IFELSE(
+         [AC_LANG_PROGRAM([[#include <GNUstepBase/GSConfig.h>]],
 [[#if defined BASE_NATIVE_OBJC_EXCEPTIONS && BASE_NATIVE_OBJC_EXCEPTIONS > 0
 1;
 #else
 fail;
-#endif]])], emacs_cv_objc_exceptions=yes, emacs_cv_objc_exceptions=no ) )
+#endif]])],
+       [emacs_cv_objc_exceptions=yes],
+       [emacs_cv_objc_exceptions=no])])
      if test $emacs_cv_objc_exceptions = yes; then
        dnl _NATIVE_OBJC_EXCEPTIONS is used by the GNUstep headers.
-       AC_DEFINE(_NATIVE_OBJC_EXCEPTIONS, 1,
+       AC_DEFINE([_NATIVE_OBJC_EXCEPTIONS], [1],
          [Define if GNUstep uses ObjC exceptions.])
        GNU_OBJC_CFLAGS="$GNU_OBJC_CFLAGS -fobjc-exceptions"
      fi
@@ -2076,8 +2087,8 @@ Either fix this, or re-configure with the option 
'--without-ns'.])])
 #endif
 #endif
                    ])],
-                   ns_osx_have_106=yes,
-                   ns_osx_have_106=no)
+                   [ns_osx_have_106=yes],
+                   [ns_osx_have_106=no])
     AC_MSG_RESULT([$ns_osx_have_106])
 
     if test $ns_osx_have_106 = no; then
@@ -2096,12 +2107,13 @@ Mac OS X 12.x or later.
                  [emacs_cv_macosx_12_0=yes]))
 
   if test "${with_native_image_api}" = yes; then
-     AC_DEFINE(HAVE_NATIVE_IMAGE_API, 1, [Define to use native OS APIs for 
images.])
+     AC_DEFINE([HAVE_NATIVE_IMAGE_API], [1],
+       [Define to use native OS APIs for images.])
      NATIVE_IMAGE_API="yes (ns)"
   fi
 fi
 
-AC_SUBST(LIBS_GNUSTEP)
+AC_SUBST([LIBS_GNUSTEP])
 
 INSTALL_ARCH_INDEP_EXTRA=install-etc
 ns_self_contained=no
@@ -2115,7 +2127,7 @@ if test "${HAVE_NS}" = yes; then
   window_system=nextstep
   # set up packaging dirs
   if test "${EN_NS_SELF_CONTAINED}" = yes; then
-     AC_DEFINE(NS_SELF_CONTAINED, 1, [Build an NS bundled app])
+     AC_DEFINE([NS_SELF_CONTAINED], [1], [Build an NS bundled app])
      ns_self_contained=yes
      prefix=${ns_appresdir}
      exec_prefix=${ns_appbindir}
@@ -2138,42 +2150,40 @@ if test "${HAVE_NS}" = yes; then
 fi
 CFLAGS="$tmp_CFLAGS"
 CPPFLAGS="$tmp_CPPFLAGS"
-AC_SUBST(INSTALL_ARCH_INDEP_EXTRA)
-AC_SUBST(ns_self_contained)
-AC_SUBST(NS_OBJ)
-AC_SUBST(NS_OBJC_OBJ)
+AC_SUBST([INSTALL_ARCH_INDEP_EXTRA])
+AC_SUBST([ns_self_contained])
+AC_SUBST([NS_OBJ])
+AC_SUBST([NS_OBJC_OBJ])
 
 if test "${HAVE_NS}" = yes; then
+  AC_LANG_PUSH([Objective C])
   AC_CACHE_CHECK(
     [if the Objective C compiler supports instancetype],
     [emacs_cv_objc_instancetype],
-    [AC_LANG_PUSH([Objective C])
-     AC_COMPILE_IFELSE(
+    [AC_COMPILE_IFELSE(
        [AC_LANG_SOURCE([[@interface Test
                           + (instancetype)test;
                           @end]])],
-       emacs_cv_objc_instancetype=yes,
-       emacs_cv_objc_instancetype=no)
-     AC_LANG_POP([Objective C])])
+       [emacs_cv_objc_instancetype=yes],
+       [emacs_cv_objc_instancetype=no])])
 
   if test x$emacs_cv_objc_instancetype = xyes ; then
-    AC_DEFINE(NATIVE_OBJC_INSTANCETYPE, 1,
+    AC_DEFINE([NATIVE_OBJC_INSTANCETYPE], [1],
               [Define if ObjC compiler supports instancetype natively.])
   fi
 
   AC_CACHE_CHECK(
     [if the Objective C compiler defaults to C99],
     [emacs_cv_objc_c99],
-    [AC_LANG_PUSH([Objective C])
-     AC_COMPILE_IFELSE(
+    [AC_COMPILE_IFELSE(
        [AC_LANG_PROGRAM([], [[for (int i = 0;;);]])],
-       emacs_cv_objc_c99=yes,
-       emacs_cv_objc_c99=no)
-     AC_LANG_POP([Objective C])])
+       [emacs_cv_objc_c99=yes],
+       [emacs_cv_objc_c99=no])])
 
-   if test x$emacs_cv_objc_c99 = xno ; then
-     GNU_OBJC_CFLAGS="$GNU_OBJC_CFLAGS -std=c99"
-   fi
+  if test x$emacs_cv_objc_c99 = xno ; then
+    GNU_OBJC_CFLAGS="$GNU_OBJC_CFLAGS -std=c99"
+  fi
+  AC_LANG_POP([Objective C])
 fi
 
 HAVE_BE_APP=no
@@ -2190,7 +2200,7 @@ re-configure with the option '--without-be-app'.])])
    AC_LANG_POP([C++])
 fi
 
-AC_SUBST(HAVE_BE_APP)
+AC_SUBST([HAVE_BE_APP])
 
 HAVE_W32=no
 W32_OBJ=
@@ -2238,11 +2248,11 @@ NTLIB=
 CM_OBJ="cm.o"
 XARGS_LIMIT=
 if test "${HAVE_W32}" = "yes"; then
-  AC_DEFINE(HAVE_NTGUI, 1, [Define to use native MS Windows GUI.])
+  AC_DEFINE([HAVE_NTGUI], [1], [Define to use native MS Windows GUI.])
   if test "$with_toolkit_scroll_bars" = "no"; then
     AC_MSG_ERROR([Non-toolkit scroll bars are not implemented for w32 build.])
   fi
-  AC_CHECK_TOOL(WINDRES, [windres],
+  AC_CHECK_TOOL([WINDRES], [windres],
                 [AC_MSG_ERROR([No resource compiler found.])])
   W32_OBJ="w32fns.o w32menu.o w32reg.o w32font.o w32term.o"
   W32_OBJ="$W32_OBJ w32xfns.o w32select.o w32uniscribe.o w32cygwinx.o"
@@ -2255,8 +2265,8 @@ if test "${HAVE_W32}" = "yes"; then
   comma_version=`echo "${PACKAGE_VERSION}.0.0" | sed -e 's/\./,/g' -e 
's/^\([[^,]]*,[[^,]]*,[[^,]]*,[[^,]]*\).*/\1/'`
 
   comma_space_version=`echo "$comma_version" | sed 's/,/, /g'`
-  AC_SUBST(comma_version)
-  AC_SUBST(comma_space_version)
+  AC_SUBST([comma_version])
+  AC_SUBST([comma_space_version])
   AC_CONFIG_FILES([nt/emacs.rc nt/emacsclient.rc])
   if test "${opsys}" = "cygwin"; then
     W32_LIBS="$W32_LIBS -lkernel32 -luser32 -lusp10 -lgdi32"
@@ -2269,7 +2279,8 @@ if test "${HAVE_W32}" = "yes"; then
     dnl FIXME: This should probably be supported for Cygwin/w32 as
     dnl well, but the Cygwin build needs to link against -lgdiplus
     if test "${with_native_image_api}" = yes; then
-      AC_DEFINE(HAVE_NATIVE_IMAGE_API, 1, [Define to use native OS APIs for 
images.])
+      AC_DEFINE([HAVE_NATIVE_IMAGE_API], [1],
+       [Define to use native OS APIs for images.])
       NATIVE_IMAGE_API="yes (w32)"
       W32_OBJ="$W32_OBJ w32image.o"
     fi
@@ -2293,20 +2304,20 @@ if test "${HAVE_W32}" = "no" && test "${opsys}" = 
"cygwin"; then
   W32_OBJ="w32cygwinx.o"
 fi
 
-AC_SUBST(W32_OBJ)
-AC_SUBST(W32_LIBS)
-AC_SUBST(EMACSRES)
-AC_SUBST(EMACS_MANIFEST)
-AC_SUBST(CLIENTRES)
-AC_SUBST(CLIENTW)
-AC_SUBST(W32_RES_LINK)
-AC_SUBST(FIRSTFILE_OBJ)
-AC_SUBST(NTDIR)
-AC_SUBST(CM_OBJ)
-AC_SUBST(LIBS_ECLIENT)
-AC_SUBST(LIB_WSOCK32)
-AC_SUBST(NTLIB)
-AC_SUBST(XARGS_LIMIT)
+AC_SUBST([W32_OBJ])
+AC_SUBST([W32_LIBS])
+AC_SUBST([EMACSRES])
+AC_SUBST([EMACS_MANIFEST])
+AC_SUBST([CLIENTRES])
+AC_SUBST([CLIENTW])
+AC_SUBST([W32_RES_LINK])
+AC_SUBST([FIRSTFILE_OBJ])
+AC_SUBST([NTDIR])
+AC_SUBST([CM_OBJ])
+AC_SUBST([LIBS_ECLIENT])
+AC_SUBST([LIB_WSOCK32])
+AC_SUBST([NTLIB])
+AC_SUBST([XARGS_LIMIT])
 
 if test "${HAVE_W32}" = "yes"; then
   window_system=w32
@@ -2323,7 +2334,7 @@ if test "$opsys" = "haiku"; then
 fi
 
 if test "${HAVE_BE_APP}" = "yes"; then
-  AC_DEFINE([HAVE_HAIKU], 1,
+  AC_DEFINE([HAVE_HAIKU], [1],
       [Define if Emacs will be built with Haiku windowing support])
 fi
 
@@ -2335,16 +2346,17 @@ if test "${HAVE_BE_APP}" = "yes"; then
   HAIKU_LIBS="-lbe -lgame -ltranslation -ltracker" # -lgame is needed for 
set_mouse_position.
 
   if test "${with_native_image_api}" = yes; then
-     AC_DEFINE(HAVE_NATIVE_IMAGE_API, 1, [Define to use native OS APIs for 
images.])
+     AC_DEFINE([HAVE_NATIVE_IMAGE_API], [1],
+       [Define to use native OS APIs for images.])
      NATIVE_IMAGE_API="yes (haiku)"
      HAIKU_OBJ="$HAIKU_OBJ haikuimage.o"
   fi
 fi
 
-AC_SUBST(HAIKU_LIBS)
-AC_SUBST(HAIKU_OBJ)
-AC_SUBST(HAIKU_CXX_OBJ)
-AC_SUBST(HAIKU_CFLAGS)
+AC_SUBST([HAIKU_LIBS])
+AC_SUBST([HAIKU_OBJ])
+AC_SUBST([HAIKU_CXX_OBJ])
+AC_SUBST([HAIKU_CFLAGS])
 
 ## $window_system is now set to the window system we will
 ## ultimately use.
@@ -2391,16 +2403,16 @@ dnl use the toolkit if we have gtk, or X11R5 or newer.
     with_gtk3=yes
     USE_X_TOOLKIT=none
     HAVE_PGTK=yes
-    AC_DEFINE([HAVE_PGTK], 1, [Define to 1 if you have pure Gtk+-3.])
+    AC_DEFINE([HAVE_PGTK], [1], [Define to 1 if you have pure Gtk+-3.])
   ;;
   haiku )
     term_header=haikuterm.h
   ;;
 esac
-AC_SUBST(HAVE_PGTK)
+AC_SUBST([HAVE_PGTK])
 
 if test "$window_system" = none && test "X$with_x" != "Xno"; then
-   AC_CHECK_PROG(HAVE_XSERVER, X, true, false)
+   AC_CHECK_PROG([HAVE_XSERVER], [X], [true], [false])
    if test "$HAVE_XSERVER" = true ||
       test -n "$DISPLAY" ||
       {
@@ -2464,7 +2476,7 @@ fi
 GMALLOC_OBJ=
 HYBRID_MALLOC=
 if test "${system_malloc}" = "yes"; then
-  AC_DEFINE([SYSTEM_MALLOC], 1,
+  AC_DEFINE([SYSTEM_MALLOC], [1],
     [Define to 1 to use the system memory allocator, even if it is not
      Doug Lea style.])
   GNU_MALLOC=no
@@ -2472,7 +2484,7 @@ if test "${system_malloc}" = "yes"; then
     (The GNU allocators don't work with this system configuration.)"
   VMLIMIT_OBJ=
 elif test "$hybrid_malloc" = yes; then
-  AC_DEFINE(HYBRID_MALLOC, 1,
+  AC_DEFINE([HYBRID_MALLOC], [1],
     [Define to use gmalloc before dumping and the system malloc after.])
   HYBRID_MALLOC=1
   GNU_MALLOC=no
@@ -2492,21 +2504,21 @@ else
        [emacs_cv_data_start=yes],
        [emacs_cv_data_start=no])])
   if test $emacs_cv_data_start = yes; then
-    AC_DEFINE([HAVE_DATA_START], 1,
+    AC_DEFINE([HAVE_DATA_START], [1],
       [Define to 1 if data_start is the address of the start
        of the main data segment.])
   fi
 fi
 AC_SUBST([HYBRID_MALLOC])
-AC_SUBST(GMALLOC_OBJ)
-AC_SUBST(VMLIMIT_OBJ)
+AC_SUBST([GMALLOC_OBJ])
+AC_SUBST([VMLIMIT_OBJ])
 
 if test "$doug_lea_malloc" = "yes" && test "$hybrid_malloc" != yes; then
   if test "$GNU_MALLOC" = yes ; then
     GNU_MALLOC_reason="
       (Using Doug Lea's new malloc from the GNU C Library.)"
   fi
-  AC_DEFINE(DOUG_LEA_MALLOC, 1,
+  AC_DEFINE([DOUG_LEA_MALLOC], [1],
     [Define to 1 if the system memory allocator is Doug Lea style,
      with malloc hooks and malloc_set_state.])
 
@@ -2530,18 +2542,19 @@ esac
 
 AC_FUNC_MMAP
 if test $use_mmap_for_buffers = yes; then
-  AC_DEFINE(USE_MMAP_FOR_BUFFERS, 1, [Define to use mmap to allocate buffer 
text.])
+  AC_DEFINE([USE_MMAP_FOR_BUFFERS], [1],
+    [Define to use mmap to allocate buffer text.])
   REL_ALLOC=no
 fi
 
 LIBS="$LIBS_SYSTEM $LIBS"
 
 dnl FIXME replace main with a function we actually want from this library.
-AC_CHECK_LIB(Xbsd, main, LD_SWITCH_X_SITE="$LD_SWITCH_X_SITE -lXbsd")
+AC_CHECK_LIB([Xbsd], [main], [LD_SWITCH_X_SITE="$LD_SWITCH_X_SITE -lXbsd"])
 
 dnl Check for the POSIX thread library.
 LIB_PTHREAD=
-AC_CHECK_HEADERS_ONCE(pthread.h)
+AC_CHECK_HEADERS_ONCE([pthread.h])
 if test "$ac_cv_header_pthread_h" && test "$opsys" != "mingw32"; then
   AC_CACHE_CHECK([for pthread library],
     [emacs_cv_pthread_lib],
@@ -2576,7 +2589,7 @@ if test "$ac_cv_header_pthread_h" && test "$opsys" != 
"mingw32"; then
        fi
      done])
   if test "$emacs_cv_pthread_lib" != no; then
-    AC_DEFINE([HAVE_PTHREAD], 1, [Define to 1 if you have POSIX threads.])
+    AC_DEFINE([HAVE_PTHREAD], [1], [Define to 1 if you have POSIX threads.])
     case $emacs_cv_pthread_lib in
       -*) LIB_PTHREAD=$emacs_cv_pthread_lib;;
     esac
@@ -2586,10 +2599,10 @@ if test "$ac_cv_header_pthread_h" && test "$opsys" != 
"mingw32"; then
     # definition of 'errno' in <errno.h>.
     case $opsys in
       hpux* | solaris)
-       AC_DEFINE([_REENTRANT], 1,
+       AC_DEFINE([_REENTRANT], [1],
          [Define to 1 if your system requires this in multithreaded code.]);;
       aix4-2)
-       AC_DEFINE([_THREAD_SAFE], 1,
+       AC_DEFINE([_THREAD_SAFE], [1],
          [Define to 1 if your system requires this in multithreaded code.]);;
     esac
   fi
@@ -2600,12 +2613,12 @@ AC_MSG_CHECKING([for thread support])
 threads_enabled=no
 if test "$with_threads" = yes; then
    if test "$emacs_cv_pthread_lib" != no; then
-      AC_DEFINE(THREADS_ENABLED, 1,
+      AC_DEFINE([THREADS_ENABLED], [1],
                 [Define to 1 if you want elisp thread support.])
       threads_enabled=yes
    elif test "${opsys}" = "mingw32"; then
       dnl MinGW can do native Windows threads even without pthreads
-      AC_DEFINE(THREADS_ENABLED, 1,
+      AC_DEFINE([THREADS_ENABLED], [1],
                 [Define to 1 if you want elisp thread support.])
       threads_enabled=yes
    fi
@@ -2690,40 +2703,42 @@ if test "${HAVE_X11}" = "yes"; then
   [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <X11/Xlib.h>
 #include <X11/XKBlib.h>]],
        [[XkbDescPtr kb = XkbGetKeyboard (0, XkbAllComponentsMask, 
XkbUseCoreKbd);]])],
-       emacs_cv_xkb=yes, emacs_cv_xkb=no)])
+       [emacs_cv_xkb=yes],
+       [emacs_cv_xkb=no])])
   if test $emacs_cv_xkb = yes; then
-    AC_DEFINE(HAVE_XKB, 1, [Define to 1 if you have the Xkb extension.])
-    AC_CHECK_FUNCS(XkbRefreshKeyboardMapping XkbFreeNames)
+    AC_DEFINE([HAVE_XKB], [1], [Define to 1 if you have the Xkb extension.])
+    AC_CHECK_FUNCS([XkbRefreshKeyboardMapping XkbFreeNames])
   fi
 
-  AC_CHECK_FUNCS(XrmSetDatabase XScreenResourceString XScreenNumberOfScreen)
-  AC_CHECK_FUNCS(XDisplayCells XDestroySubwindows)
+  AC_CHECK_FUNCS([XrmSetDatabase XScreenResourceString XScreenNumberOfScreen])
+  AC_CHECK_FUNCS([XDisplayCells XDestroySubwindows])
 fi
 
 if test "${window_system}" = "x11"; then
-  AC_MSG_CHECKING(X11 version 6)
-  AC_CACHE_VAL(emacs_cv_x11_version_6,
+  AC_MSG_CHECKING([X11 version 6])
+  AC_CACHE_VAL([emacs_cv_x11_version_6],
   [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <X11/Xlib.h>]],
 [[#if XlibSpecificationRelease < 6
 fail;
 #endif
-]])], emacs_cv_x11_version_6=yes, emacs_cv_x11_version_6=no)])
+]])], [emacs_cv_x11_version_6=yes],
+      [emacs_cv_x11_version_6=no])])
   if test $emacs_cv_x11_version_6 = yes; then
-    AC_MSG_RESULT(6 or newer)
-    AC_DEFINE(HAVE_X11R6, 1,
+    AC_MSG_RESULT([6 or newer])
+    AC_DEFINE([HAVE_X11R6], [1],
              [Define to 1 if you have the X11R6 or newer version of Xlib.])
-    AC_DEFINE(HAVE_X_I18N, 1, [Define if you have usable i18n support.])
+    AC_DEFINE([HAVE_X_I18N], [1], [Define if you have usable i18n support.])
     AC_CHECK_MEMBERS([XICCallback.callback], [], [], [#include <X11/Xlib.h>])
     ## inoue@ainet.or.jp says Solaris has a bug related to X11R6-style
     ## XIM support.
     case "$opsys" in
       solaris) : ;;
-      *) AC_DEFINE(HAVE_X11R6_XIM, 1,
+      *) AC_DEFINE([HAVE_X11R6_XIM], [1],
            [Define if you have usable X11R6-style XIM support.])
          ;;
     esac
   else
-    AC_MSG_RESULT(before 6)
+    AC_MSG_RESULT([before 6])
   fi
 fi
 
@@ -2738,11 +2753,11 @@ if test "${HAVE_X11}" = "yes" || test "${HAVE_NS}" = 
"yes" \
     RSVG_MODULE="librsvg-2.0 >= $RSVG_REQUIRED"
 
     EMACS_CHECK_MODULES([RSVG], [$RSVG_MODULE])
-    AC_SUBST(RSVG_CFLAGS)
-    AC_SUBST(RSVG_LIBS)
+    AC_SUBST([RSVG_CFLAGS])
+    AC_SUBST([RSVG_LIBS])
 
     if test $HAVE_RSVG = yes; then
-      AC_DEFINE(HAVE_RSVG, 1, [Define to 1 if using librsvg.])
+      AC_DEFINE([HAVE_RSVG], [1], [Define to 1 if using librsvg.])
       CFLAGS="$CFLAGS $RSVG_CFLAGS"
       # Windows loads librsvg dynamically
       if test "${opsys}" = "mingw32"; then
@@ -2759,17 +2774,14 @@ if test "${with_webp}" != "no"; then
    || test "${HAVE_W32}" = "yes" || test "${HAVE_NS}" = "yes" \
    || test "${HAVE_BE_APP}" = "yes" || test "${HAVE_PGTK}" = "yes"; then
       WEBP_REQUIRED=0.6.0
-      WEBP_MODULE="libwebp >= $WEBP_REQUIRED"
+      WEBP_MODULE="libwebpdemux >= $WEBP_REQUIRED"
 
       EMACS_CHECK_MODULES([WEBP], [$WEBP_MODULE])
-      if test "$HAVE_WEBP" = "yes"; then
-        WEBP_LIBS="-lwebp -lwebpdemux"
-      fi
-      AC_SUBST(WEBP_CFLAGS)
-      AC_SUBST(WEBP_LIBS)
+      AC_SUBST([WEBP_CFLAGS])
+      AC_SUBST([WEBP_LIBS])
    fi
    if test $HAVE_WEBP = yes; then
-      AC_DEFINE(HAVE_WEBP, 1, [Define to 1 if using libwebp.])
+      AC_DEFINE([HAVE_WEBP], [1], [Define to 1 if using libwebp.])
       CFLAGS="$CFLAGS $WEBP_CFLAGS"
       # Windows loads libwebp dynamically
       if test "${opsys}" = "mingw32"; then
@@ -2781,20 +2793,25 @@ fi
 ### Use -lsqlite3 if available, unless '--with-sqlite3=no'
 HAVE_SQLITE3=no
 if test "${with_sqlite3}" != "no"; then
-   AC_CHECK_LIB(sqlite3, sqlite3_open_v2, HAVE_SQLITE3=yes, HAVE_SQLITE3=no)
+   AC_CHECK_LIB([sqlite3], [sqlite3_open_v2],
+     [HAVE_SQLITE3=yes],
+     [HAVE_SQLITE3=no])
    if test "$HAVE_SQLITE3" = "yes"; then
      SQLITE3_LIBS=-lsqlite3
-     AC_SUBST(SQLITE3_LIBS)
+     AC_SUBST([SQLITE3_LIBS])
      LIBS="$SQLITE3_LIBS $LIBS"
-     AC_DEFINE(HAVE_SQLITE3, 1, [Define to 1 if you have the libsqlite3 
library (-lsqlite).])
+     AC_DEFINE([HAVE_SQLITE3], [1],
+       [Define to 1 if you have the libsqlite3 library (-lsqlite).])
      # Windows loads libsqlite dynamically
      if test "${opsys}" = "mingw32"; then
         SQLITE3_LIBS=
      fi
-     AC_CHECK_LIB(sqlite3, sqlite3_load_extension,
-         HAVE_SQLITE3_LOAD_EXTENSION=yes, HAVE_SQLITE3_LOAD_EXTENSION=no)
+     AC_CHECK_LIB([sqlite3], [sqlite3_load_extension],
+       [HAVE_SQLITE3_LOAD_EXTENSION=yes],
+       [HAVE_SQLITE3_LOAD_EXTENSION=no])
      if test "$HAVE_SQLITE3_LOAD_EXTENSION" = "yes"; then
-       AC_DEFINE(HAVE_SQLITE3_LOAD_EXTENSION, 1, [Define to 1 if sqlite3 
supports loading extensions.])
+       AC_DEFINE([HAVE_SQLITE3_LOAD_EXTENSION], [1],
+        [Define to 1 if sqlite3 supports loading extensions.])
      fi
    fi
 fi
@@ -2811,7 +2828,8 @@ if test "${HAVE_X11}" = "yes" || test "${HAVE_NS}" = 
"yes" || test "${HAVE_W32}"
 
     EMACS_CHECK_MODULES([IMAGEMAGICK], [MagickWand >= 7])
     if test $HAVE_IMAGEMAGICK = yes; then
-       AC_DEFINE([HAVE_IMAGEMAGICK7], 1, [Define to 1 if using ImageMagick7.])
+       AC_DEFINE([HAVE_IMAGEMAGICK7], [1],
+        [Define to 1 if using ImageMagick7.])
     else
        ## 6.3.5 is the earliest version known to work; see Bug#17339.
        ## 6.8.2 makes Emacs crash; see Bug#13867.
@@ -2835,7 +2853,7 @@ if test "${HAVE_X11}" = "yes" || test "${HAVE_NS}" = 
"yes" || test "${HAVE_W32}"
       fi
     fi
     if test $HAVE_IMAGEMAGICK = yes; then
-      AC_DEFINE([HAVE_IMAGEMAGICK], 1, [Define to 1 if using ImageMagick.])
+      AC_DEFINE([HAVE_IMAGEMAGICK], [1], [Define to 1 if using ImageMagick.])
     else
       if test "${with_imagemagick}" != "no"; then
         AC_MSG_ERROR([ImageMagick wanted, but it does not compile.  Maybe some 
library files are missing?]);
@@ -2848,12 +2866,12 @@ if test "${HAVE_X11}" = "yes" || test "${HAVE_NS}" = 
"yes" || test "${HAVE_W32}"
   fi
 fi
 
-AC_CHECK_LIB(anl, getaddrinfo_a, HAVE_GETADDRINFO_A=yes)
+AC_CHECK_LIB([anl], [getaddrinfo_a], [HAVE_GETADDRINFO_A=yes])
 if test "${HAVE_GETADDRINFO_A}" = "yes"; then
-  AC_DEFINE(HAVE_GETADDRINFO_A, 1,
+  AC_DEFINE([HAVE_GETADDRINFO_A], [1],
 [Define to 1 if you have getaddrinfo_a for asynchronous DNS resolution.])
   GETADDRINFO_A_LIBS="-lanl"
-  AC_SUBST(GETADDRINFO_A_LIBS)
+  AC_SUBST([GETADDRINFO_A_LIBS])
 fi
 
 HAVE_GTK=no
@@ -2867,7 +2885,7 @@ if test "${opsys}" != "mingw32"; then
     if test "${window_system}" = "x11"; then
       GTK_REQUIRED=3.10
     else
-      GTK_REQUIRED=3.20
+      GTK_REQUIRED=3.22.23
     fi
     GTK_MODULES="gtk+-3.0 >= $GTK_REQUIRED glib-2.0 >= $GLIB_REQUIRED"
 
@@ -2875,10 +2893,10 @@ if test "${opsys}" != "mingw32"; then
     EMACS_CHECK_MODULES([GTK], [$GTK_MODULES],
       [pkg_check_gtk=yes], [pkg_check_gtk=no])
     if test "$pkg_check_gtk" = "no" && test "$with_gtk3" = "yes"; then
-       AC_MSG_ERROR($GTK_PKG_ERRORS)
+       AC_MSG_ERROR([$GTK_PKG_ERRORS])
     fi
     if test "$pkg_check_gtk" = "yes"; then
-       AC_DEFINE(HAVE_GTK3, 1, [Define to 1 if using GTK 3 or later.])
+       AC_DEFINE([HAVE_GTK3], [1], [Define to 1 if using GTK 3 or later.])
        GTK_OBJ=emacsgtkfixed.o
        gtk_term_header=gtkutil.h
        USE_GTK_TOOLKIT="GTK3"
@@ -2905,7 +2923,7 @@ if test "${opsys}" != "mingw32"; then
     if test "$pkg_check_gtk" = "no" &&
        { test "$with_gtk" = yes || test "$with_gtk2" = "yes"; }
     then
-      AC_MSG_ERROR($gtk3_pkg_errors$GTK_PKG_ERRORS)
+      AC_MSG_ERROR([$gtk3_pkg_errors$GTK_PKG_ERRORS])
     fi
     test "$pkg_check_gtk" = "yes" && USE_GTK_TOOLKIT="GTK2"
   fi
@@ -2916,7 +2934,7 @@ OLD_LIBS=$LIBS
 
 if test x"$pkg_check_gtk" = xyes; then
 
-  AC_SUBST(GTK_LIBS)
+  AC_SUBST([GTK_LIBS])
   CFLAGS="$CFLAGS $GTK_CFLAGS"
   LIBS="$GTK_LIBS $LIBS"
   dnl Try to compile a simple GTK program.
@@ -2948,7 +2966,7 @@ if test x"$pkg_check_gtk" = xyes; then
   else
     C_SWITCH_X_SITE="$C_SWITCH_X_SITE $GTK_CFLAGS"
     HAVE_GTK=yes
-    AC_DEFINE(USE_GTK, 1, [Define to 1 if using GTK.])
+    AC_DEFINE([USE_GTK], [1], [Define to 1 if using GTK.])
     GTK_OBJ="gtkutil.o $GTK_OBJ"
     term_header=$gtk_term_header
     USE_X_TOOLKIT=none
@@ -2960,7 +2978,7 @@ if test x"$pkg_check_gtk" = xyes; then
   fi
 
 fi
-AC_SUBST(GTK_OBJ)
+AC_SUBST([GTK_OBJ])
 
 
 if test "${HAVE_GTK}" = "yes"; then
@@ -2980,15 +2998,17 @@ if test "${HAVE_GTK}" = "yes"; then
     dnl  but not declared if deprecated featured has been selected out.
     dnl  AC_CHECK_DECL checks for a macro, so check for 
GTK_TYPE_FILE_SELECTION.
     HAVE_GTK_FILE_SELECTION=no
-    AC_CHECK_DECL(GTK_TYPE_FILE_SELECTION, HAVE_GTK_FILE_SELECTION=yes,
-                     HAVE_GTK_FILE_SELECTION=no, [AC_INCLUDES_DEFAULT
+    AC_CHECK_DECL([GTK_TYPE_FILE_SELECTION],
+                 [HAVE_GTK_FILE_SELECTION=yes],
+                 [HAVE_GTK_FILE_SELECTION=no],
+                 [AC_INCLUDES_DEFAULT
 #include <gtk/gtk.h>])
     if test "$HAVE_GTK_FILE_SELECTION" = yes; then
-      AC_CHECK_FUNCS(gtk_file_selection_new)
+      AC_CHECK_FUNCS([gtk_file_selection_new])
     fi
 
     dnl This procedure causes a bug on certain Ubuntu GTK+2 builds
-    AC_CHECK_FUNCS(gtk_window_set_has_resize_grip)
+    AC_CHECK_FUNCS([gtk_window_set_has_resize_grip])
   fi
 fi
 
@@ -3001,10 +3021,10 @@ if test "$window_system" = "pgtk"; then
   PGTK_OBJ="pgtkfns.o pgtkterm.o pgtkselect.o pgtkmenu.o pgtkim.o xsettings.o"
   PGTK_LIBS="$GTK_LIBS"
 fi
-AC_SUBST(PGTK_OBJ)
-AC_SUBST(PGTK_LIBS)
+AC_SUBST([PGTK_OBJ])
+AC_SUBST([PGTK_LIBS])
 
-AC_CHECK_FUNCS(malloc_trim)
+AC_CHECK_FUNCS([malloc_trim])
 
 dnl D-Bus has been tested under GNU/Linux only.  Must be adapted for
 dnl other platforms.
@@ -3013,25 +3033,25 @@ DBUS_OBJ=
 if test "${with_dbus}" = "yes"; then
    EMACS_CHECK_MODULES([DBUS], [dbus-1 >= 1.0])
    if test "$HAVE_DBUS" = yes; then
-     AC_DEFINE(HAVE_DBUS, 1, [Define to 1 if using D-Bus.])
+     AC_DEFINE([HAVE_DBUS], [1], [Define to 1 if using D-Bus.])
      dnl dbus_watch_get_unix_fd has been introduced in D-Bus 1.1.1.
      dnl dbus_type_is_valid and dbus_validate_* have been introduced in
      dnl D-Bus 1.5.12.
      OLD_LIBS=$LIBS
      LIBS="$LIBS $DBUS_LIBS"
-     AC_CHECK_FUNCS(dbus_watch_get_unix_fd \
+     AC_CHECK_FUNCS([dbus_watch_get_unix_fd \
                    dbus_type_is_valid \
                    dbus_validate_bus_name \
                     dbus_validate_path \
                    dbus_validate_interface \
-                   dbus_validate_member)
+                   dbus_validate_member])
      LIBS=$OLD_LIBS
      DBUS_OBJ=dbusbind.o
    fi
 fi
-AC_SUBST(DBUS_CFLAGS)
-AC_SUBST(DBUS_LIBS)
-AC_SUBST(DBUS_OBJ)
+AC_SUBST([DBUS_CFLAGS])
+AC_SUBST([DBUS_LIBS])
+AC_SUBST([DBUS_OBJ])
 
 dnl GSettings has been tested under GNU/Linux only.
 HAVE_GSETTINGS=no
@@ -3056,7 +3076,7 @@ if test "${HAVE_X11}" = "yes" -o "${window_system}" = 
"pgtk" && test "${with_gse
        [emacs_cv_gsettings_in_gio=yes], [emacs_cv_gsettings_in_gio=no])])
 
       if test "$emacs_cv_gsettings_in_gio" = "yes"; then
-        AC_DEFINE(HAVE_GSETTINGS, 1, [Define to 1 if using GSettings.])
+       AC_DEFINE([HAVE_GSETTINGS], [1], [Define to 1 if using GSettings.])
        SETTINGS_CFLAGS="$GSETTINGS_CFLAGS"
        SETTINGS_LIBS="$GSETTINGS_LIBS"
        test "$with_gconf" = "yes" || with_gconf=no
@@ -3065,7 +3085,7 @@ if test "${HAVE_X11}" = "yes" -o "${window_system}" = 
"pgtk" && test "${with_gse
       LIBS=$old_LIBS
    fi
 fi
-AC_SUBST(HAVE_GSETTINGS)
+AC_SUBST([HAVE_GSETTINGS])
 
 dnl GConf has been tested under GNU/Linux only.
 dnl The version is really arbitrary, it is about the same age as Gtk+ 2.6.
@@ -3073,7 +3093,7 @@ HAVE_GCONF=no
 if test "${HAVE_X11}" = "yes" -o "${window_system}" = "pgtk" && test 
"${with_gconf}" != "no"; then
    EMACS_CHECK_MODULES([GCONF], [gconf-2.0 >= 2.13])
    if test "$HAVE_GCONF" = yes; then
-      AC_DEFINE(HAVE_GCONF, 1, [Define to 1 if using GConf.])
+      AC_DEFINE([HAVE_GCONF], [1], [Define to 1 if using GConf.])
       dnl Newer GConf doesn't link with g_objects, so this is not defined.
       SETTINGS_CFLAGS="$SETTINGS_CFLAGS $GCONF_CFLAGS"
       SETTINGS_LIBS="$SETTINGS_LIBS $GCONF_LIBS"
@@ -3093,33 +3113,35 @@ if test "$HAVE_GSETTINGS" = "yes" || test "$HAVE_GCONF" 
= "yes"; then
     CFLAGS="$SAVE_CFLAGS"
     LIBS="$SAVE_LIBS"
 fi
-AC_SUBST(SETTINGS_CFLAGS)
-AC_SUBST(SETTINGS_LIBS)
+AC_SUBST([SETTINGS_CFLAGS])
+AC_SUBST([SETTINGS_LIBS])
 
 USE_STARTUP_NOTIFICATION=no
 if test "${HAVE_GTK}" = "yes"; then
     USE_STARTUP_NOTIFICATION=yes
 fi
-AC_SUBST(USE_STARTUP_NOTIFICATION)
+AC_SUBST([USE_STARTUP_NOTIFICATION])
 
 dnl SELinux is available for GNU/Linux only.
 HAVE_LIBSELINUX=no
 LIBSELINUX_LIBS=
 if test "${with_selinux}" = "yes"; then
-   AC_CHECK_LIB([selinux], [lgetfilecon], HAVE_LIBSELINUX=yes, 
HAVE_LIBSELINUX=no)
+   AC_CHECK_LIB([selinux], [lgetfilecon],
+     [HAVE_LIBSELINUX=yes],
+     [HAVE_LIBSELINUX=no])
    if test "$HAVE_LIBSELINUX" = yes; then
-      AC_DEFINE(HAVE_LIBSELINUX, 1, [Define to 1 if using SELinux.])
+      AC_DEFINE([HAVE_LIBSELINUX], [1], [Define to 1 if using SELinux.])
       LIBSELINUX_LIBS=-lselinux
    fi
 fi
-AC_SUBST(LIBSELINUX_LIBS)
+AC_SUBST([LIBSELINUX_LIBS])
 
 HAVE_GNUTLS=no
 if test "${with_gnutls}" != "no" ; then
   EMACS_CHECK_MODULES([LIBGNUTLS], [gnutls >= 2.12.2],
     [HAVE_GNUTLS=yes], [HAVE_GNUTLS=no])
   if test "${HAVE_GNUTLS}" = "yes"; then
-    AC_DEFINE(HAVE_GNUTLS, 1, [Define if using GnuTLS.])
+    AC_DEFINE([HAVE_GNUTLS], [1], [Define if using GnuTLS.])
   fi
 
   # Windows loads GnuTLS dynamically
@@ -3128,8 +3150,8 @@ if test "${with_gnutls}" != "no" ; then
   fi
 fi
 
-AC_SUBST(LIBGNUTLS_LIBS)
-AC_SUBST(LIBGNUTLS_CFLAGS)
+AC_SUBST([LIBGNUTLS_LIBS])
+AC_SUBST([LIBGNUTLS_CFLAGS])
 
 HAVE_LIBSYSTEMD=no
 if test "${with_libsystemd}" = "yes" ; then
@@ -3139,12 +3161,12 @@ if test "${with_libsystemd}" = "yes" ; then
   EMACS_CHECK_MODULES([LIBSYSTEMD], [libsystemd >= 222],
     [HAVE_LIBSYSTEMD=yes], [HAVE_LIBSYSTEMD=no])
   if test "${HAVE_LIBSYSTEMD}" = "yes"; then
-    AC_DEFINE(HAVE_LIBSYSTEMD, 1, [Define if using libsystemd.])
+    AC_DEFINE([HAVE_LIBSYSTEMD], [1], [Define if using libsystemd.])
   fi
 fi
 
-AC_SUBST(LIBSYSTEMD_LIBS)
-AC_SUBST(LIBSYSTEMD_CFLAGS)
+AC_SUBST([LIBSYSTEMD_LIBS])
+AC_SUBST([LIBSYSTEMD_CFLAGS])
 
 HAVE_JSON=no
 JSON_OBJ=
@@ -3153,7 +3175,7 @@ if test "${with_json}" != no; then
   EMACS_CHECK_MODULES([JSON], [jansson >= 2.7],
     [HAVE_JSON=yes], [HAVE_JSON=no])
   if test "${HAVE_JSON}" = yes; then
-    AC_DEFINE(HAVE_JSON, 1, [Define if using Jansson.])
+    AC_DEFINE([HAVE_JSON], [1], [Define if using Jansson.])
     JSON_OBJ=json.o
   fi
 
@@ -3163,9 +3185,9 @@ if test "${with_json}" != no; then
   fi
 fi
 
-AC_SUBST(JSON_LIBS)
-AC_SUBST(JSON_CFLAGS)
-AC_SUBST(JSON_OBJ)
+AC_SUBST([JSON_LIBS])
+AC_SUBST([JSON_CFLAGS])
+AC_SUBST([JSON_OBJ])
 
 HAVE_TREE_SITTER=no
 TREE_SITTER_OBJ=
@@ -3198,9 +3220,9 @@ case $with_file_notification,$opsys in
     Consider using gfile instead.])
     ;;
   w32,* | yes,mingw32)
-    AC_CHECK_HEADER(windows.h)
+    AC_CHECK_HEADER([windows.h])
     if test "$ac_cv_header_windows_h" = yes ; then
-       AC_DEFINE(HAVE_W32NOTIFY, 1, [Define to 1 to use w32notify.])
+       AC_DEFINE([HAVE_W32NOTIFY], [1], [Define to 1 to use w32notify.])
        NOTIFY_OBJ=w32notify.o
        NOTIFY_SUMMARY="yes (w32)"
     fi ;;
@@ -3209,11 +3231,11 @@ esac
 dnl inotify is available only on GNU/Linux.
 case $with_file_notification,$NOTIFY_OBJ in
   inotify, | yes,)
-    AC_CHECK_HEADER(sys/inotify.h)
+    AC_CHECK_HEADER([sys/inotify.h])
     if test "$ac_cv_header_sys_inotify_h" = yes ; then
-       AC_CHECK_FUNC(inotify_init1)
+       AC_CHECK_FUNC([inotify_init1])
        if test "$ac_cv_func_inotify_init1" = yes; then
-         AC_DEFINE(HAVE_INOTIFY, 1, [Define to 1 to use inotify.])
+         AC_DEFINE([HAVE_INOTIFY], [1], [Define to 1 to use inotify.])
          NOTIFY_OBJ=inotify.o
          NOTIFY_SUMMARY="yes -lglibc (inotify)"
        fi
@@ -3225,16 +3247,16 @@ case $with_file_notification,$NOTIFY_OBJ in
   kqueue,* | yes,)
     EMACS_CHECK_MODULES([KQUEUE], [libkqueue])
     if test "$HAVE_KQUEUE" = "yes"; then
-       AC_DEFINE(HAVE_KQUEUE, 1, [Define to 1 to use kqueue.])
+       AC_DEFINE([HAVE_KQUEUE], [1], [Define to 1 to use kqueue.])
        CPPFLAGS="$CPPFLAGS -I/usr/include/kqueue"
        NOTIFY_CFLAGS=$KQUEUE_CFLAGS
        NOTIFY_LIBS=$KQUEUE_LIBS
        NOTIFY_OBJ=kqueue.o
        NOTIFY_SUMMARY="yes -lkqueue"
     else
-       AC_SEARCH_LIBS(kqueue, [])
+       AC_SEARCH_LIBS([kqueue], [])
        if test "$ac_cv_search_kqueue" != no; then
-         AC_DEFINE(HAVE_KQUEUE, 1, [Define to 1 to use kqueue.])
+        AC_DEFINE([HAVE_KQUEUE], [1], [Define to 1 to use kqueue.])
         NOTIFY_OBJ=kqueue.o
         NOTIFY_SUMMARY="yes (kqueue)"
        fi
@@ -3252,7 +3274,7 @@ Consider kqueue instead.])
     else
        EMACS_CHECK_MODULES([GFILENOTIFY], [gio-2.0 >= 2.24])
        if test "$HAVE_GFILENOTIFY" = "yes"; then
-         AC_DEFINE(HAVE_GFILENOTIFY, 1, [Define to 1 if using GFile.])
+         AC_DEFINE([HAVE_GFILENOTIFY], [1], [Define to 1 if using GFile.])
          NOTIFY_CFLAGS=$GFILENOTIFY_CFLAGS
          NOTIFY_LIBS=$GFILENOTIFY_LIBS
          NOTIFY_OBJ=gfilenotify.o
@@ -3267,11 +3289,12 @@ case $with_file_notification,$NOTIFY_OBJ in
 esac
 
 if test -n "$NOTIFY_OBJ"; then
-   AC_DEFINE(USE_FILE_NOTIFY, 1, [Define to 1 if using file notifications.])
+   AC_DEFINE([USE_FILE_NOTIFY], [1],
+     [Define to 1 if using file notifications.])
 fi
-AC_SUBST(NOTIFY_CFLAGS)
-AC_SUBST(NOTIFY_LIBS)
-AC_SUBST(NOTIFY_OBJ)
+AC_SUBST([NOTIFY_CFLAGS])
+AC_SUBST([NOTIFY_LIBS])
+AC_SUBST([NOTIFY_OBJ])
 
 dnl Do not put whitespace before the #include statements below.
 dnl Older compilers (eg sunos4 cc) choke on it.
@@ -3279,36 +3302,37 @@ HAVE_XAW3D=no
 LUCID_LIBW=
 if test x"${USE_X_TOOLKIT}" = xmaybe || test x"${USE_X_TOOLKIT}" = xLUCID; then
   if test "$with_xaw3d" != no; then
-    AC_CACHE_VAL(emacs_cv_xaw3d,
+    AC_CACHE_VAL([emacs_cv_xaw3d],
     [AC_LINK_IFELSE([AC_LANG_PROGRAM([[
 #include <X11/Intrinsic.h>
 #include <X11/Xaw3d/Simple.h>]],
       [[]])],
-      [AC_CHECK_LIB(Xaw3d, XawScrollbarSetThumb,
-                    emacs_cv_xaw3d=yes, emacs_cv_xaw3d=no)],
-      emacs_cv_xaw3d=no)])
+      [AC_CHECK_LIB([Xaw3d], [XawScrollbarSetThumb],
+                   [emacs_cv_xaw3d=yes],
+                   [emacs_cv_xaw3d=no])],
+      [emacs_cv_xaw3d=no])])
   else
     emacs_cv_xaw3d=no
   fi
   if test $emacs_cv_xaw3d = yes; then
-    AC_MSG_CHECKING(for xaw3d)
+    AC_MSG_CHECKING([for xaw3d])
     AC_MSG_RESULT([yes; using Lucid toolkit])
     USE_X_TOOLKIT=LUCID
     HAVE_XAW3D=yes
     LUCID_LIBW=-lXaw3d
-    AC_DEFINE(HAVE_XAW3D, 1,
+    AC_DEFINE([HAVE_XAW3D], [1],
               [Define to 1 if you have the Xaw3d library (-lXaw3d).])
   else
-    AC_MSG_CHECKING(for xaw3d)
-    AC_MSG_RESULT(no)
-    AC_MSG_CHECKING(for libXaw)
-    AC_CACHE_VAL(emacs_cv_xaw,
+    AC_MSG_CHECKING([for xaw3d])
+    AC_MSG_RESULT([no])
+    AC_MSG_CHECKING([for libXaw])
+    AC_CACHE_VAL([emacs_cv_xaw],
     [AC_LINK_IFELSE([AC_LANG_PROGRAM([[
 #include <X11/Intrinsic.h>
 #include <X11/Xaw/Simple.h>]],
       [[]])],
-      emacs_cv_xaw=yes,
-      emacs_cv_xaw=no)])
+      [emacs_cv_xaw=yes],
+      [emacs_cv_xaw=no])])
     if test $emacs_cv_xaw = yes; then
       AC_MSG_RESULT([yes; using Lucid toolkit])
       USE_X_TOOLKIT=LUCID
@@ -3330,17 +3354,18 @@ X_TOOLKIT_TYPE=$USE_X_TOOLKIT
 LIBXTR6=
 LIBXMU=
 if test "${USE_X_TOOLKIT}" != "none"; then
-  AC_MSG_CHECKING(X11 toolkit version)
-  AC_CACHE_VAL(emacs_cv_x11_toolkit_version_6,
+  AC_MSG_CHECKING([X11 toolkit version])
+  AC_CACHE_VAL([emacs_cv_x11_toolkit_version_6],
   [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <X11/Intrinsic.h>]],
 [[#if XtSpecificationRelease < 6
 fail;
 #endif
-]])], emacs_cv_x11_toolkit_version_6=yes, emacs_cv_x11_toolkit_version_6=no)])
+]])], [emacs_cv_x11_toolkit_version_6=yes],
+      [emacs_cv_x11_toolkit_version_6=no])])
   HAVE_X11XTR6=$emacs_cv_x11_toolkit_version_6
   if test $emacs_cv_x11_toolkit_version_6 = yes; then
-    AC_MSG_RESULT(6 or newer)
-    AC_DEFINE(HAVE_X11XTR6, 1,
+    AC_MSG_RESULT([6 or newer])
+    AC_DEFINE([HAVE_X11XTR6], [1],
              [Define to 1 if you have the X11R6 or newer version of Xt.])
     LIBXTR6="-lSM -lICE"
     case "$opsys" in
@@ -3348,7 +3373,7 @@ fail;
       unixware) LIBXTR6="$LIBXTR6 -lw" ;;
     esac
   else
-    AC_MSG_RESULT(before 6)
+    AC_MSG_RESULT([before 6])
   fi
 
 dnl If using toolkit, check whether libXmu.a exists.
@@ -3366,8 +3391,8 @@ dnl tranle@intellicorp.com says libXmu.a can need 
XtMalloc in libXt.a to link.
   LIBS=$OLDLIBS
   dnl ac_cv_search_XmuConvertStandardSelection is also referenced below.
 fi
-AC_SUBST(LIBXTR6)
-AC_SUBST(LIBXMU)
+AC_SUBST([LIBXTR6])
+AC_SUBST([LIBXMU])
 
 LIBXP=
 if test "${USE_X_TOOLKIT}" = "MOTIF"; then
@@ -3385,21 +3410,21 @@ if test "${USE_X_TOOLKIT}" = "MOTIF"; then
   else
     emacs_cv_openmotif=no
   fi
-  AC_CACHE_CHECK(for (Open)Motif version 2.1, emacs_cv_motif_version_2_1,
+  AC_CACHE_CHECK([for (Open)Motif version 2.1], [emacs_cv_motif_version_2_1],
   [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <Xm/Xm.h>]],
     [[#if XmVERSION > 2 || (XmVERSION == 2 && XmREVISION >= 1)
 int x = 5;
 #else
 Motif version prior to 2.1.
 #endif]])],
-    emacs_cv_motif_version_2_1=yes, emacs_cv_motif_version_2_1=no)])
+     [emacs_cv_motif_version_2_1=yes],
+     [emacs_cv_motif_version_2_1=no])])
   if test $emacs_cv_motif_version_2_1 = yes; then
-    AC_CHECK_LIB(Xp, XpCreateContext, LIBXP=-lXp)
+    AC_CHECK_LIB([Xp], [XpCreateContext], [LIBXP=-lXp])
     if test x$emacs_cv_openmotif = xyes; then
       REAL_CPPFLAGS="-I/usr/include/openmotif $REAL_CPPFLAGS"
     fi
   else
-    AC_CACHE_CHECK(for LessTif where some systems put it, emacs_cv_lesstif,
     # We put this in CFLAGS temporarily to precede other -I options
     # that might be in CFLAGS temporarily.
     # We put this in CPPFLAGS where it precedes the other -I options.
@@ -3407,9 +3432,14 @@ Motif version prior to 2.1.
     OLD_CFLAGS=$CFLAGS
     CPPFLAGS="-I/usr/X11R6/LessTif/Motif1.2/include $CPPFLAGS"
     CFLAGS="-I/usr/X11R6/LessTif/Motif1.2/include $CFLAGS"
-    [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include 
</usr/X11R6/LessTif/Motif1.2/include/Xm/Xm.h>]],
-      [[int x = 5;]])],
-      emacs_cv_lesstif=yes, emacs_cv_lesstif=no)])
+    AC_CACHE_CHECK([for LessTif where some systems put it], [emacs_cv_lesstif],
+      [AC_COMPILE_IFELSE(
+        [AC_LANG_PROGRAM(
+           [[#include </usr/X11R6/LessTif/Motif1.2/include/Xm/Xm.h>
+           ]],
+           [[int x = 5;]])],
+        [emacs_cv_lesstif=yes],
+        [emacs_cv_lesstif=no])])
     if test $emacs_cv_lesstif = yes; then
       # Make sure this -I option remains in CPPFLAGS after it is set
       # back to REAL_CPPFLAGS.
@@ -3431,34 +3461,34 @@ dnl Use toolkit scroll bars if configured for GTK or X 
toolkit and either
 dnl using Motif or Xaw3d is available, and unless
 dnl --with-toolkit-scroll-bars=no was specified.
 
-AH_TEMPLATE(USE_TOOLKIT_SCROLL_BARS,
+AH_TEMPLATE([USE_TOOLKIT_SCROLL_BARS],
            [Define to 1 if we should use toolkit scroll bars.])dnl
 USE_TOOLKIT_SCROLL_BARS=no
 if test "${with_toolkit_scroll_bars}" != "no"; then
   if test "${USE_X_TOOLKIT}" != "none"; then
     if test "${USE_X_TOOLKIT}" = "MOTIF"; then
-      AC_DEFINE(USE_TOOLKIT_SCROLL_BARS)
+      AC_DEFINE([USE_TOOLKIT_SCROLL_BARS])
       HAVE_XAW3D=no
       USE_TOOLKIT_SCROLL_BARS=yes
     elif test "${HAVE_XAW3D}" = "yes" || test "${USE_X_TOOLKIT}" = "LUCID"; 
then
-      AC_DEFINE(USE_TOOLKIT_SCROLL_BARS)
+      AC_DEFINE([USE_TOOLKIT_SCROLL_BARS])
       USE_TOOLKIT_SCROLL_BARS=yes
     fi
   elif test "${HAVE_GTK}" = "yes"; then
-    AC_DEFINE(USE_TOOLKIT_SCROLL_BARS)
+    AC_DEFINE([USE_TOOLKIT_SCROLL_BARS])
     USE_TOOLKIT_SCROLL_BARS=yes
   elif test "${HAVE_NS}" = "yes"; then
-    AC_DEFINE(USE_TOOLKIT_SCROLL_BARS)
+    AC_DEFINE([USE_TOOLKIT_SCROLL_BARS])
     USE_TOOLKIT_SCROLL_BARS=yes
   elif test "${HAVE_W32}" = "yes"; then
-    AC_DEFINE(USE_TOOLKIT_SCROLL_BARS)
+    AC_DEFINE([USE_TOOLKIT_SCROLL_BARS])
     USE_TOOLKIT_SCROLL_BARS=yes
   elif test "${HAVE_BE_APP}" = "yes"; then
-    AC_DEFINE(USE_TOOLKIT_SCROLL_BARS)
+    AC_DEFINE([USE_TOOLKIT_SCROLL_BARS])
     USE_TOOLKIT_SCROLL_BARS=yes
   fi
-elif test "${window_system}" != "x11" && "${window_system}" != "none"; then
-  AC_MSG_ERROR(Non-toolkit scroll bars are not implemented for your system)
+elif test "${window_system}" != "x11" && test "${window_system}" != "none"; 
then
+  AC_MSG_ERROR([Non-toolkit scroll bars are not implemented for your system])
 fi
 
 dnl See if XIM is available.
@@ -3467,14 +3497,14 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
          #include <X11/Xresource.h>]],
         [[XIMProc  callback;]])],
         [HAVE_XIM=yes
-        AC_DEFINE(HAVE_XIM, 1, [Define to 1 if XIM is available])],
-        HAVE_XIM=no)
+        AC_DEFINE([HAVE_XIM], [1], [Define to 1 if XIM is available])],
+        [HAVE_XIM=no])
 
 dnl Note this is non-standard.  --with-xim does not control whether
 dnl XIM support is compiled in, it only affects the runtime default of
 dnl use_xim in xterm.c.
 if test "${with_xim}" != "no"; then
-  AC_DEFINE(USE_XIM, 1,
+  AC_DEFINE([USE_XIM], [1],
            [Define to 1 to default runtime use of XIM to on.])
 fi
 
@@ -3490,8 +3520,8 @@ if test "${HAVE_X11}" = "yes"; then
     [AC_CHECK_LIB([Xrender], [XRenderQueryExtension], [HAVE_XRENDER=yes])])
   if test $HAVE_XRENDER = yes; then
     XRENDER_LIBS="-lXrender"
-    AC_SUBST(XRENDER_LIBS)
-    AC_DEFINE([HAVE_XRENDER], 1, [Define to 1 if XRender is available.])
+    AC_SUBST([XRENDER_LIBS])
+    AC_DEFINE([HAVE_XRENDER], [1], [Define to 1 if XRender is available.])
   fi
 fi
 
@@ -3500,20 +3530,21 @@ if test "${HAVE_X11}" = "yes"; then
   if test "${with_cairo}" != "no"; then
     CAIRO_REQUIRED=1.8.0
     CAIRO_MODULE="cairo >= $CAIRO_REQUIRED"
-    EMACS_CHECK_MODULES(CAIRO, $CAIRO_MODULE)
+    EMACS_CHECK_MODULES([CAIRO], [$CAIRO_MODULE])
     if test $HAVE_CAIRO = yes; then
       CAIRO_XCB_MODULE="cairo-xcb >= $CAIRO_REQUIRED"
-      EMACS_CHECK_MODULES(CAIRO_XCB, $CAIRO_XCB_MODULE)
+      EMACS_CHECK_MODULES([CAIRO_XCB], [$CAIRO_XCB_MODULE])
       if test $HAVE_CAIRO_XCB = yes; then
        CAIRO_CFLAGS="$CAIRO_CFLAGS $CAIRO_XCB_CFLAGS"
        CAIRO_LIBS="$CAIRO_LIBS $CAIRO_XCB_LIBS"
-       AC_DEFINE(USE_CAIRO_XCB, 1, [Define to 1 if cairo XCB surfaces are 
available.])
+       AC_DEFINE([USE_CAIRO_XCB], [1],
+         [Define to 1 if cairo XCB surfaces are available.])
       fi
-      AC_DEFINE(USE_CAIRO, 1, [Define to 1 if using cairo.])
+      AC_DEFINE([USE_CAIRO], [1], [Define to 1 if using cairo.])
       CFLAGS="$CFLAGS $CAIRO_CFLAGS"
       LIBS="$LIBS $CAIRO_LIBS"
-      AC_SUBST(CAIRO_CFLAGS)
-      AC_SUBST(CAIRO_LIBS)
+      AC_SUBST([CAIRO_CFLAGS])
+      AC_SUBST([CAIRO_LIBS])
     else
       AC_MSG_WARN([cairo requested but not found.])
     fi
@@ -3533,12 +3564,12 @@ if test "$with_xwidgets" != "no"; then
     XWIDGETS_OBJ="xwidget.o"
     if test "$HAVE_X_WINDOWS" = "yes" && test "${with_cairo}" = "no"; then
       CAIRO_XLIB_MODULES="cairo >= 1.8.0 cairo-xlib >= 1.8.0"
-      EMACS_CHECK_MODULES(CAIRO_XLIB, $CAIRO_XLIB_MODULES)
+      EMACS_CHECK_MODULES([CAIRO_XLIB], [$CAIRO_XLIB_MODULES])
       if test $HAVE_CAIRO_XLIB = "yes"; then
         CAIRO_CFLAGS="$CAIRO_XLIB_CFLAGS"
        CAIRO_LIBS="$CAIRO_XLIB_LIBS"
-       AC_SUBST(CAIRO_CFLAGS)
-       AC_SUBST(CAIRO_LIBS)
+       AC_SUBST([CAIRO_CFLAGS])
+       AC_SUBST([CAIRO_LIBS])
       else
         AC_MSG_ERROR([xwidgets requested, but a suitable cairo installation 
wasn't found])
       fi
@@ -3553,7 +3584,7 @@ if test "$with_xwidgets" != "no"; then
     XWIDGETS_OBJ="xwidget.o"
     NS_OBJC_OBJ="$NS_OBJC_OBJ nsxwidget.o"
     dnl Update NS_OBJC_OBJ with added nsxwidget.o
-    AC_SUBST(NS_OBJC_OBJ)
+    AC_SUBST([NS_OBJC_OBJ])
   else
     AC_MSG_ERROR([xwidgets requested, it requires GTK3 as X window toolkit or 
macOS Cocoa as window system.])
   fi
@@ -3561,37 +3592,37 @@ if test "$with_xwidgets" != "no"; then
   test $HAVE_XWIDGETS = yes ||
     AC_MSG_ERROR([xwidgets requested but WebKitGTK+ or WebKit framework not 
found.])
 
-  AC_DEFINE([HAVE_XWIDGETS], 1, [Define to 1 if you have xwidgets support.])
+  AC_DEFINE([HAVE_XWIDGETS], [1], [Define to 1 if you have xwidgets support.])
 fi
-AC_SUBST(XWIDGETS_OBJ)
+AC_SUBST([XWIDGETS_OBJ])
 
 if test "$window_system" = "pgtk"; then
   CAIRO_REQUIRED=1.12.0
   CAIRO_MODULE="cairo >= $CAIRO_REQUIRED"
-  EMACS_CHECK_MODULES(CAIRO, $CAIRO_MODULE)
+  EMACS_CHECK_MODULES([CAIRO], [$CAIRO_MODULE])
   if test $HAVE_CAIRO = yes; then
-    AC_DEFINE(USE_CAIRO, 1, [Define to 1 if using cairo.])
+    AC_DEFINE([USE_CAIRO], [1], [Define to 1 if using cairo.])
   else
     AC_MSG_ERROR([cairo required but not found.])
   fi
 
   CFLAGS="$CFLAGS $CAIRO_CFLAGS"
   LIBS="$LIBS $CAIRO_LIBS"
-  AC_SUBST(CAIRO_CFLAGS)
-  AC_SUBST(CAIRO_LIBS)
+  AC_SUBST([CAIRO_CFLAGS])
+  AC_SUBST([CAIRO_LIBS])
 fi
 
 if test "${HAVE_BE_APP}" = "yes"; then
   if test "${with_be_cairo}" != "no"; then
     CAIRO_REQUIRED=1.8.0
     CAIRO_MODULE="cairo >= $CAIRO_REQUIRED"
-    EMACS_CHECK_MODULES(CAIRO, $CAIRO_MODULE)
+    EMACS_CHECK_MODULES([CAIRO], [$CAIRO_MODULE])
     if test $HAVE_CAIRO = yes; then
-      AC_DEFINE(USE_BE_CAIRO, 1, [Define to 1 if using cairo on Haiku.])
+      AC_DEFINE([USE_BE_CAIRO], [1], [Define to 1 if using cairo on Haiku.])
       CFLAGS="$CFLAGS $CAIRO_CFLAGS"
       LIBS="$LIBS $CAIRO_LIBS"
-      AC_SUBST(CAIRO_CFLAGS)
-      AC_SUBST(CAIRO_LIBS)
+      AC_SUBST([CAIRO_CFLAGS])
+      AC_SUBST([CAIRO_LIBS])
     else
       AC_MSG_WARN([cairo requested but not found.])
     fi
@@ -3611,11 +3642,12 @@ if test "${HAVE_X11}" = "yes"; then
     dnl The following is needed to set FREETYPE_LIBS.
     EMACS_CHECK_MODULES([FREETYPE], [freetype2])
 
-    test "$HAVE_FREETYPE" = "no" && AC_MSG_ERROR(cairo requires libfreetype)
+    test "$HAVE_FREETYPE" = "no" && AC_MSG_ERROR([cairo requires libfreetype])
 
     EMACS_CHECK_MODULES([FONTCONFIG], [fontconfig >= 2.2.0])
 
-    test "$HAVE_FONTCONFIG" = "no" && AC_MSG_ERROR(cairo requires 
libfontconfig)
+    test "$HAVE_FONTCONFIG" = "no" &&
+      AC_MSG_ERROR([cairo requires libfontconfig])
     dnl For the "Does Emacs use" message at the end.
     HAVE_XFT=no
   else
@@ -3642,13 +3674,15 @@ if test "${HAVE_X11}" = "yes"; then
        CPPFLAGS="$CPPFLAGS $XFT_CFLAGS"
        CFLAGS="$CFLAGS $XFT_CFLAGS"
        LIBS="$XFT_LIBS $LIBS"
-       AC_CHECK_HEADER(X11/Xft/Xft.h,
-         AC_CHECK_LIB(Xft, XftFontOpen, HAVE_XFT=yes, , $XFT_LIBS) , ,
+       AC_CHECK_HEADER([X11/Xft/Xft.h],
+         [AC_CHECK_LIB([Xft], [XftFontOpen], [HAVE_XFT=yes],
+            [], [$XFT_LIBS])],
+         [],
           [[#include <X11/X.h>]])
 
        if test "${HAVE_XFT}" = "yes"; then
-         AC_DEFINE(HAVE_XFT, 1, [Define to 1 if you have the Xft library.])
-           AC_SUBST(XFT_LIBS)
+         AC_DEFINE([HAVE_XFT], [1], [Define to 1 if you have the Xft library.])
+           AC_SUBST([XFT_LIBS])
          C_SWITCH_X_SITE="$C_SWITCH_X_SITE $XFT_CFLAGS"
        fi                        # "${HAVE_XFT}" = "yes"
        CPPFLAGS=$OLD_CPPFLAGS
@@ -3671,34 +3705,35 @@ if test "${HAVE_X11}" = "yes"; then
        dnl The following is needed to set FREETYPE_LIBS.
        EMACS_CHECK_MODULES([FREETYPE], [freetype2])
 
-       test "$HAVE_FREETYPE" = "no" && AC_MSG_ERROR(libxft requires 
libfreetype)
+       test "$HAVE_FREETYPE" = "no" &&
+        AC_MSG_ERROR([libxft requires libfreetype])
     fi
   fi                             # $HAVE_CAIRO != yes
 
   HAVE_LIBOTF=no
   if test "${HAVE_FREETYPE}" = "yes"; then
-    AC_DEFINE(HAVE_FREETYPE, 1,
+    AC_DEFINE([HAVE_FREETYPE], [1],
              [Define to 1 if using the freetype and fontconfig libraries.])
     OLD_CFLAGS=$CFLAGS
     OLD_LIBS=$LIBS
     CFLAGS="$CFLAGS $FREETYPE_CFLAGS"
     LIBS="$FREETYPE_LIBS $LIBS"
-    AC_CHECK_FUNCS(FT_Face_GetCharVariantIndex)
+    AC_CHECK_FUNCS([FT_Face_GetCharVariantIndex])
     CFLAGS=$OLD_CFLAGS
     LIBS=$OLD_LIBS
     if test "${with_libotf}" != "no"; then
       EMACS_CHECK_MODULES([LIBOTF], [libotf])
       if test "$HAVE_LIBOTF" = "yes"; then
-       AC_DEFINE(HAVE_LIBOTF, 1, [Define to 1 if using libotf.])
-       AC_CHECK_LIB(otf, OTF_get_variation_glyphs,
-                    HAVE_OTF_GET_VARIATION_GLYPHS=yes,
-                    HAVE_OTF_GET_VARIATION_GLYPHS=no)
+       AC_DEFINE([HAVE_LIBOTF], [1], [Define to 1 if using libotf.])
+       AC_CHECK_LIB([otf], [OTF_get_variation_glyphs],
+                    [HAVE_OTF_GET_VARIATION_GLYPHS=yes],
+                    [HAVE_OTF_GET_VARIATION_GLYPHS=no])
        if test "${HAVE_OTF_GET_VARIATION_GLYPHS}" = "yes"; then
-         AC_DEFINE(HAVE_OTF_GET_VARIATION_GLYPHS, 1,
+         AC_DEFINE([HAVE_OTF_GET_VARIATION_GLYPHS], [1],
                    [Define to 1 if libotf has OTF_get_variation_glyphs.])
        fi
        if ! $PKG_CONFIG --atleast-version=0.9.16 libotf; then
-         AC_DEFINE(HAVE_OTF_KANNADA_BUG, 1,
+         AC_DEFINE([HAVE_OTF_KANNADA_BUG], [1],
 [Define to 1 if libotf is affected by https://debbugs.gnu.org/28110.])
        fi
       fi
@@ -3712,7 +3747,7 @@ if test "${HAVE_X11}" = "yes"; then
     if test "${with_m17n_flt}" != "no"; then
       EMACS_CHECK_MODULES([M17N_FLT], [m17n-flt])
       if test "$HAVE_M17N_FLT" = "yes"; then
-       AC_DEFINE(HAVE_M17N_FLT, 1, [Define to 1 if using libm17n-flt.])
+       AC_DEFINE([HAVE_M17N_FLT], [1], [Define to 1 if using libm17n-flt.])
       fi
     fi
   fi
@@ -3721,20 +3756,20 @@ else # "${HAVE_X11}" != "yes"
     EMACS_CHECK_MODULES([FONTCONFIG], [fontconfig >= 2.2.0])
     EMACS_CHECK_MODULES([FREETYPE], [freetype2])
     if test "$HAVE_FONTCONFIG" != yes -o "$HAVE_FREETYPE" != yes; then
-      AC_MSG_ERROR(fontconfig and freetype is required.)
+      AC_MSG_ERROR([fontconfig and freetype is required.])
     fi
     HAVE_LIBOTF=no
-    AC_DEFINE(HAVE_FREETYPE, 1,
+    AC_DEFINE([HAVE_FREETYPE], [1],
              [Define to 1 if using the freetype and fontconfig libraries.])
     if test "${with_libotf}" != "no"; then
       EMACS_CHECK_MODULES([LIBOTF], [libotf])
       if test "$HAVE_LIBOTF" = "yes"; then
-       AC_DEFINE(HAVE_LIBOTF, 1, [Define to 1 if using libotf.])
-       AC_CHECK_LIB(otf, OTF_get_variation_glyphs,
-                    HAVE_OTF_GET_VARIATION_GLYPHS=yes,
-                    HAVE_OTF_GET_VARIATION_GLYPHS=no)
+       AC_DEFINE([HAVE_LIBOTF], [1], [Define to 1 if using libotf.])
+       AC_CHECK_LIB([otf], [OTF_get_variation_glyphs],
+                    [HAVE_OTF_GET_VARIATION_GLYPHS=yes],
+                    [HAVE_OTF_GET_VARIATION_GLYPHS=no])
        if test "${HAVE_OTF_GET_VARIATION_GLYPHS}" = "yes"; then
-         AC_DEFINE(HAVE_OTF_GET_VARIATION_GLYPHS, 1,
+         AC_DEFINE([HAVE_OTF_GET_VARIATION_GLYPHS], [1],
                    [Define to 1 if libotf has OTF_get_variation_glyphs.])
        fi
       fi
@@ -3761,7 +3796,7 @@ if test "${HAVE_X11}" = "yes" && test "${HAVE_FREETYPE}" 
= "yes" \
   if test "${with_harfbuzz}" != "no"; then
     EMACS_CHECK_MODULES([HARFBUZZ], [harfbuzz >= $harfbuzz_required_ver])
     if test "$HAVE_HARFBUZZ" = "yes"; then
-      AC_DEFINE(HAVE_HARFBUZZ, 1, [Define to 1 if using HarfBuzz.])
+      AC_DEFINE([HAVE_HARFBUZZ], [1], [Define to 1 if using HarfBuzz.])
       ### mingw32 and Cygwin-w32 don't use -lharfbuzz, since they load
       ### the library dynamically.
       if test "${HAVE_W32}" = "yes"; then
@@ -3775,36 +3810,38 @@ fi
 if test "${HAVE_BE_APP}" = "yes"; then
   if test $HAVE_CAIRO = "yes"; then
       EMACS_CHECK_MODULES([FREETYPE], [freetype2 >= 2.5.0])
-      test "$HAVE_FREETYPE" = "no" && AC_MSG_ERROR(cairo on Haiku requires 
libfreetype)
+      test "$HAVE_FREETYPE" = "no" &&
+       AC_MSG_ERROR([cairo on Haiku requires libfreetype])
       EMACS_CHECK_MODULES([FONTCONFIG], [fontconfig >= 2.2.0])
-      test "$HAVE_FONTCONFIG" = "no" && AC_MSG_ERROR(cairo on Haiku requires 
libfontconfig)
+      test "$HAVE_FONTCONFIG" = "no" &&
+       AC_MSG_ERROR([cairo on Haiku requires libfontconfig])
   fi
 
   HAVE_LIBOTF=no
 
   if test "${HAVE_FREETYPE}" = "yes"; then
-    AC_DEFINE(HAVE_FREETYPE, 1,
+    AC_DEFINE([HAVE_FREETYPE], [1],
              [Define to 1 if using the freetype and fontconfig libraries.])
     OLD_CFLAGS=$CFLAGS
     OLD_LIBS=$LIBS
     CFLAGS="$CFLAGS $FREETYPE_CFLAGS"
     LIBS="$FREETYPE_LIBS $LIBS"
-    AC_CHECK_FUNCS(FT_Face_GetCharVariantIndex)
+    AC_CHECK_FUNCS([FT_Face_GetCharVariantIndex])
     CFLAGS=$OLD_CFLAGS
     LIBS=$OLD_LIBS
     if test "${with_libotf}" != "no"; then
       EMACS_CHECK_MODULES([LIBOTF], [libotf])
       if test "$HAVE_LIBOTF" = "yes"; then
-       AC_DEFINE(HAVE_LIBOTF, 1, [Define to 1 if using libotf.])
-       AC_CHECK_LIB(otf, OTF_get_variation_glyphs,
-                    HAVE_OTF_GET_VARIATION_GLYPHS=yes,
-                    HAVE_OTF_GET_VARIATION_GLYPHS=no)
+       AC_DEFINE([HAVE_LIBOTF], [1], [Define to 1 if using libotf.])
+       AC_CHECK_LIB([otf], [OTF_get_variation_glyphs],
+                    [HAVE_OTF_GET_VARIATION_GLYPHS=yes],
+                    [HAVE_OTF_GET_VARIATION_GLYPHS=no])
        if test "${HAVE_OTF_GET_VARIATION_GLYPHS}" = "yes"; then
-         AC_DEFINE(HAVE_OTF_GET_VARIATION_GLYPHS, 1,
+         AC_DEFINE([HAVE_OTF_GET_VARIATION_GLYPHS], [1],
                    [Define to 1 if libotf has OTF_get_variation_glyphs.])
        fi
        if ! $PKG_CONFIG --atleast-version=0.9.16 libotf; then
-         AC_DEFINE(HAVE_OTF_KANNADA_BUG, 1,
+         AC_DEFINE([HAVE_OTF_KANNADA_BUG], [1],
 [Define to 1 if libotf is affected by https://debbugs.gnu.org/28110.])
        fi
       fi
@@ -3818,41 +3855,41 @@ if test "${HAVE_BE_APP}" = "yes" && test 
"${HAVE_FREETYPE}" = "yes"; then
   if test "${with_harfbuzz}" != "no"; then
     EMACS_CHECK_MODULES([HARFBUZZ], [harfbuzz >= $harfbuzz_required_ver])
     if test "$HAVE_HARFBUZZ" = "yes"; then
-      AC_DEFINE(HAVE_HARFBUZZ, 1, [Define to 1 if using HarfBuzz.])
+      AC_DEFINE([HAVE_HARFBUZZ], [1], [Define to 1 if using HarfBuzz.])
     fi
   fi
 fi
 
 ### End of font-backend section.
 
-AC_SUBST(FREETYPE_CFLAGS)
-AC_SUBST(FREETYPE_LIBS)
-AC_SUBST(FONTCONFIG_CFLAGS)
-AC_SUBST(FONTCONFIG_LIBS)
-AC_SUBST(HARFBUZZ_CFLAGS)
-AC_SUBST(HARFBUZZ_LIBS)
-AC_SUBST(LIBOTF_CFLAGS)
-AC_SUBST(LIBOTF_LIBS)
-AC_SUBST(M17N_FLT_CFLAGS)
-AC_SUBST(M17N_FLT_LIBS)
+AC_SUBST([FREETYPE_CFLAGS])
+AC_SUBST([FREETYPE_LIBS])
+AC_SUBST([FONTCONFIG_CFLAGS])
+AC_SUBST([FONTCONFIG_LIBS])
+AC_SUBST([HARFBUZZ_CFLAGS])
+AC_SUBST([HARFBUZZ_LIBS])
+AC_SUBST([LIBOTF_CFLAGS])
+AC_SUBST([LIBOTF_LIBS])
+AC_SUBST([M17N_FLT_CFLAGS])
+AC_SUBST([M17N_FLT_LIBS])
 
 XCB_LIBS=
 if test "${HAVE_X11}" = "yes"; then
-  AC_CHECK_HEADER(X11/Xlib-xcb.h,
-    AC_CHECK_LIB(xcb, xcb_translate_coordinates, HAVE_XCB=yes))
+  AC_CHECK_HEADER([X11/Xlib-xcb.h],
+    [AC_CHECK_LIB([xcb], [xcb_translate_coordinates], [HAVE_XCB=yes])])
   if test "${HAVE_XCB}" = "yes"; then
-    AC_CHECK_LIB(X11-xcb, XGetXCBConnection, HAVE_X11_XCB=yes)
+    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)
+      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)
+       AC_CHECK_LIB([xcb-aux], [xcb_aux_sync], [HAVE_XCB_AUX=yes])
         if test "${HAVE_XCB_AUX}" = "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-aux"
@@ -3861,7 +3898,7 @@ if test "${HAVE_X11}" = "yes"; then
     fi
   fi
 fi
-AC_SUBST(XCB_LIBS)
+AC_SUBST([XCB_LIBS])
 
 ### Use -lXpm if available, unless '--with-xpm=no'.
 ### mingw32 doesn't use -lXpm, since it loads the library dynamically.
@@ -3873,18 +3910,18 @@ if test "${HAVE_W32}" = "yes" && test "${opsys}" = 
"cygwin"; then
   if test "${with_xpm}" != "no"; then
     SAVE_LDFLAGS="$LDFLAGS"
     LDFLAGS="$LDFLAGS -L/usr/lib/noX"
-    AC_CHECK_HEADER(noX/xpm.h,
-      [AC_CHECK_LIB(Xpm, XpmReadFileToImage, HAVE_XPM=yes)])
+    AC_CHECK_HEADER([noX/xpm.h],
+      [AC_CHECK_LIB([Xpm], [XpmReadFileToImage], [HAVE_XPM=yes])])
     if test "${HAVE_XPM}" = "yes"; then
       AC_CACHE_CHECK([for XpmReturnAllocPixels preprocessor define],
       [emacs_cv_cpp_xpm_return_alloc_pixels],
-      [AC_EGREP_CPP(no_return_alloc_pixels,
+      [AC_EGREP_CPP([no_return_alloc_pixels],
       [#include "noX/xpm.h"
 #ifndef XpmReturnAllocPixels
 no_return_alloc_pixels
 #endif
-      ], emacs_cv_cpp_xpm_return_alloc_pixels=no,
-      emacs_cv_cpp_xpm_return_alloc_pixels=yes)])
+      ], [emacs_cv_cpp_xpm_return_alloc_pixels=no],
+        [emacs_cv_cpp_xpm_return_alloc_pixels=yes])])
 
       if test "$emacs_cv_cpp_xpm_return_alloc_pixels" = "no"; then
         HAVE_XPM=no
@@ -3894,7 +3931,8 @@ no_return_alloc_pixels
   fi
 
   if test "${HAVE_XPM}" = "yes"; then
-    AC_DEFINE(HAVE_XPM, 1, [Define to 1 if you have the Xpm library (-lXpm).])
+    AC_DEFINE([HAVE_XPM], [1],
+      [Define to 1 if you have the Xpm library (-lXpm).])
     LIBXPM=-lXpm
   fi
 fi
@@ -3907,18 +3945,19 @@ if test "${HAVE_X11}" = "yes"; then
   esac
 
   if test "${with_xpm}" != "no"; then
-    AC_CHECK_HEADER(X11/xpm.h,
-      [AC_CHECK_LIB(Xpm, XpmReadFileToPixmap, HAVE_XPM=yes, , -lX11)])
+    AC_CHECK_HEADER([X11/xpm.h],
+      [AC_CHECK_LIB([Xpm], [XpmReadFileToPixmap],
+        [HAVE_XPM=yes], [], [-lX11])])
     if test "${HAVE_XPM}" = "yes"; then
       AC_CACHE_CHECK([for XpmReturnAllocPixels preprocessor define],
       [emacs_cv_cpp_xpm_return_alloc_pixels],
-      [AC_EGREP_CPP(no_return_alloc_pixels,
+      [AC_EGREP_CPP([no_return_alloc_pixels],
       [#include "X11/xpm.h"
 #ifndef XpmReturnAllocPixels
 no_return_alloc_pixels
 #endif
-      ], emacs_cv_cpp_xpm_return_alloc_pixels=no,
-      emacs_cv_cpp_xpm_return_alloc_pixels=yes)])
+      ], [emacs_cv_cpp_xpm_return_alloc_pixels=no],
+        [emacs_cv_cpp_xpm_return_alloc_pixels=yes])])
 
       if test "$emacs_cv_cpp_xpm_return_alloc_pixels" = "no"; then
        HAVE_XPM=no
@@ -3927,7 +3966,8 @@ no_return_alloc_pixels
   fi
 
   if test "${HAVE_XPM}" = "yes"; then
-    AC_DEFINE(HAVE_XPM, 1, [Define to 1 if you have the Xpm library (-lXpm).])
+    AC_DEFINE([HAVE_XPM], [1],
+      [Define to 1 if you have the Xpm library (-lXpm).])
     LIBXPM=-lXpm
   elif test "$opsys,$LUCID_LIBW" = aix4-2,-lXaw; then
     dnl AIX -lXaw needs -lXpm linked too; see Bug#17598 Message#152.
@@ -3941,16 +3981,17 @@ fi
 ### run time).
 if test "${opsys}" = "mingw32"; then
   if test "${with_xpm}" != "no"; then
-    AC_CHECK_HEADER(X11/xpm.h, HAVE_XPM=yes, HAVE_XPM=no, [
+    AC_CHECK_HEADER([X11/xpm.h], [HAVE_XPM=yes], [HAVE_XPM=no], [
 #define FOR_MSW 1])
   fi
 
   if test "${HAVE_XPM}" = "yes"; then
-    AC_DEFINE(HAVE_XPM, 1, [Define to 1 if you have the Xpm library (-lXpm).])
+    AC_DEFINE([HAVE_XPM], [1],
+      [Define to 1 if you have the Xpm library (-lXpm).])
   fi
 fi
 
-AC_SUBST(LIBXPM)
+AC_SUBST([LIBXPM])
 
 ### Use -ljpeg if available, unless '--with-jpeg=no'.
 HAVE_JPEG=no
@@ -3989,7 +4030,7 @@ if test "${HAVE_X11}" = "yes" || test "${HAVE_W32}" = 
"yes" \
        done])
     if test "$emacs_cv_jpeglib" != no; then
       HAVE_JPEG=yes
-      AC_DEFINE([HAVE_JPEG], 1,
+      AC_DEFINE([HAVE_JPEG], [1],
        [Define to 1 if you have the jpeg library (typically -ljpeg).])
       ### mingw32 doesn't use -ljpeg, since it loads the library
       ### dynamically when needed, and doesn't want a run-time
@@ -3999,7 +4040,7 @@ if test "${HAVE_X11}" = "yes" || test "${HAVE_W32}" = 
"yes" \
     fi
   fi
 fi
-AC_SUBST(LIBJPEG)
+AC_SUBST([LIBJPEG])
 
 HAVE_LCMS2=no
 LCMS2_CFLAGS=
@@ -4008,14 +4049,15 @@ if test "${with_lcms2}" != "no"; then
   EMACS_CHECK_MODULES([LCMS2], [lcms2])
 fi
 if test "${HAVE_LCMS2}" = "yes"; then
-  AC_DEFINE([HAVE_LCMS2], 1, [Define to 1 if you have the lcms2 library 
(-llcms2).])
+  AC_DEFINE([HAVE_LCMS2], [1],
+    [Define to 1 if you have the lcms2 library (-llcms2).])
   ### mingw32 doesn't use -llcms2, since it loads the library dynamically.
   if test "${opsys}" = "mingw32"; then
      LCMS2_LIBS=
   fi
 fi
-AC_SUBST(LCMS2_CFLAGS)
-AC_SUBST(LCMS2_LIBS)
+AC_SUBST([LCMS2_CFLAGS])
+AC_SUBST([LCMS2_LIBS])
 
 HAVE_ZLIB=no
 LIBZ=
@@ -4028,13 +4070,14 @@ if test "${with_zlib}" != "no"; then
   esac
 fi
 if test "${HAVE_ZLIB}" = "yes"; then
-  AC_DEFINE([HAVE_ZLIB], 1, [Define to 1 if you have the zlib library (-lz).])
+  AC_DEFINE([HAVE_ZLIB], [1],
+    [Define to 1 if you have the zlib library (-lz).])
   ### mingw32 doesn't use -lz, since it loads the library dynamically.
   if test "${opsys}" = "mingw32"; then
      LIBZ=
   fi
 fi
-AC_SUBST(LIBZ)
+AC_SUBST([LIBZ])
 
 ### Dynamic library support
 case $opsys in
@@ -4099,19 +4142,20 @@ fi
 if test "${HAVE_MODULES}" = yes; then
    MODULES_OBJ="emacs-module.o"
    NEED_DYNLIB=yes
-   AC_DEFINE(HAVE_MODULES, 1, [Define to 1 if dynamic modules are enabled])
-   AC_DEFINE_UNQUOTED(MODULES_SUFFIX, "$MODULES_SUFFIX",
-     [System extension for dynamic modules])
+   AC_DEFINE([HAVE_MODULES], [1], [Define to 1 if dynamic modules are enabled])
+   AC_DEFINE_UNQUOTED([MODULES_SUFFIX], ["$MODULES_SUFFIX"],
+     [System extension for dynamic libraries])
    if test -n "${MODULES_SECONDARY_SUFFIX}"; then
-     AC_DEFINE_UNQUOTED(MODULES_SECONDARY_SUFFIX, "$MODULES_SECONDARY_SUFFIX",
-       [Alternative system extension for dynamic modules.])
+     AC_DEFINE_UNQUOTED([MODULES_SECONDARY_SUFFIX],
+       ["$MODULES_SECONDARY_SUFFIX"],
+       [Alternative system extension for dynamic libraries.])
    fi
 fi
-AC_SUBST(MODULES_OBJ)
-AC_SUBST(LIBMODULES)
-AC_SUBST(HAVE_MODULES)
-AC_SUBST(MODULES_SUFFIX)
-AC_SUBST(MODULES_SECONDARY_SUFFIX)
+AC_SUBST([MODULES_OBJ])
+AC_SUBST([LIBMODULES])
+AC_SUBST([HAVE_MODULES])
+AC_SUBST([MODULES_SUFFIX])
+AC_SUBST([MODULES_SECONDARY_SUFFIX])
 
 AC_CONFIG_FILES([src/emacs-module.h])
 AC_SUBST_FILE([module_env_snippet_25])
@@ -4125,7 +4169,7 @@ module_env_snippet_27="$srcdir/src/module-env-27.h"
 module_env_snippet_28="$srcdir/src/module-env-28.h"
 module_env_snippet_29="$srcdir/src/module-env-29.h"
 emacs_major_version="${PACKAGE_VERSION%%.*}"
-AC_SUBST(emacs_major_version)
+AC_SUBST([emacs_major_version])
 
 ### Emacs Lisp native compiler support
 
@@ -4223,8 +4267,8 @@ if test "${with_native_compilation}" != "no"; then
         if test -n "`$BREW --prefix --installed libgccjit 2>/dev/null`"; then
           MAC_CFLAGS="-I$(dirname $($BREW ls -v libgccjit | \
                                                 grep libgccjit.h))"
-          MAC_LIBS="-L$(dirname $($BREW ls -v libgccjit| \
-                                            grep -E 'libgccjit\.(so|dylib)$'))"
+          MAC_LIBS="-L$(dirname $($BREW ls -v libgccjit \
+                                  | grep -m1 -E 'libgccjit\.(so|dylib)$'))"
         fi
       fi
 
@@ -4252,8 +4296,9 @@ if test "${with_native_compilation}" != "no"; then
     fi
 
     # Check if libgccjit is available.
-    AC_CHECK_LIB(gccjit, gcc_jit_context_acquire, [], [libgccjit_not_found])
-    AC_CHECK_HEADERS(libgccjit.h, [], [libgccjit_dev_not_found])
+    AC_CHECK_LIB([gccjit], [gcc_jit_context_acquire],
+      [], [libgccjit_not_found])
+    AC_CHECK_HEADERS([libgccjit.h], [], [libgccjit_dev_not_found])
     # Check if libgccjit really works.
     AC_RUN_IFELSE([libgccjit_smoke_test], [], [libgccjit_broken])
     HAVE_NATIVE_COMP=yes
@@ -4270,22 +4315,23 @@ if test "${with_native_compilation}" != "no"; then
         LIBGCCJIT_LIBS="-lgccjit -ldl" ;;
     esac
     NEED_DYNLIB=yes
-    AC_DEFINE(HAVE_NATIVE_COMP, 1, [Define to 1 if native compiler is 
available.])
+    AC_DEFINE([HAVE_NATIVE_COMP], [1],
+      [Define to 1 if native compiler is available.])
 
     CFLAGS=$SAVE_CFLAGS
     LIBS=$SAVE_LIBS
 fi
-AC_DEFINE_UNQUOTED(NATIVE_ELISP_SUFFIX, ".eln",
+AC_DEFINE_UNQUOTED([NATIVE_ELISP_SUFFIX], [".eln"],
   [System extension for native compiled elisp])
-AC_SUBST(HAVE_NATIVE_COMP)
-AC_SUBST(LIBGCCJIT_CFLAGS)
-AC_SUBST(LIBGCCJIT_LIBS)
+AC_SUBST([HAVE_NATIVE_COMP])
+AC_SUBST([LIBGCCJIT_CFLAGS])
+AC_SUBST([LIBGCCJIT_LIBS])
 
 DYNLIB_OBJ=
 if test "${NEED_DYNLIB}" = yes; then
   DYNLIB_OBJ="dynlib.o"
 fi
-AC_SUBST(DYNLIB_OBJ)
+AC_SUBST([DYNLIB_OBJ])
 
 ### Use -lpng if available, unless '--with-png=no'.
 HAVE_PNG=no
@@ -4357,8 +4403,8 @@ if test $HAVE_PNG = yes; then
     ]])
   CFLAGS=$SAVE_CFLAGS
 fi
-AC_SUBST(LIBPNG)
-AC_SUBST(PNG_CFLAGS)
+AC_SUBST([LIBPNG])
+AC_SUBST([PNG_CFLAGS])
 
 ### Use -ltiff if available, unless '--with-tiff=no'.
 ### mingw32 doesn't use -ltiff, since it loads the library dynamically.
@@ -4366,29 +4412,32 @@ HAVE_TIFF=no
 LIBTIFF=
 if test "${opsys}" = "mingw32"; then
   if test "${with_tiff}" != "no"; then
-    AC_CHECK_HEADER(tiffio.h, HAVE_TIFF=yes, HAVE_TIFF=no)
+    AC_CHECK_HEADER([tiffio.h], [HAVE_TIFF=yes], [HAVE_TIFF=no])
   fi
   if test "${HAVE_TIFF}" = "yes"; then
-    AC_DEFINE(HAVE_TIFF, 1, [Define to 1 if you have the tiff library 
(-ltiff).])
+    AC_DEFINE([HAVE_TIFF], [1],
+      [Define to 1 if you have the tiff library (-ltiff).])
   fi
 elif test "${HAVE_X11}" = "yes" || test "${HAVE_W32}" = "yes" \
      || test "${HAVE_NS}" = "yes" || test "${HAVE_BE_APP}" = "yes" \
      || test "$window_system" = "pgtk"; then
   if test "${with_tiff}" != "no"; then
-    AC_CHECK_HEADER(tiffio.h,
+    AC_CHECK_HEADER([tiffio.h],
       [tifflibs="-lz -lm"
       # At least one tiff package requires the jpeg library.
       if test "${HAVE_JPEG}" = yes; then tifflibs="-ljpeg $tifflibs"; fi
-      AC_CHECK_LIB(tiff, TIFFGetVersion, HAVE_TIFF=yes, , $tifflibs)])
+      AC_CHECK_LIB([tiff], [TIFFGetVersion], [HAVE_TIFF=yes], [],
+       [$tifflibs])])
   fi
 
   if test "${HAVE_TIFF}" = "yes"; then
-    AC_DEFINE(HAVE_TIFF, 1, [Define to 1 if you have the tiff library 
(-ltiff).])
+    AC_DEFINE([HAVE_TIFF], [1],
+      [Define to 1 if you have the tiff library (-ltiff).])
     dnl FIXME -lz -lm, as per libpng?
     LIBTIFF=-ltiff
   fi
 fi
-AC_SUBST(LIBTIFF)
+AC_SUBST([LIBTIFF])
 
 ### Use -lgif or -lungif if available, unless '--with-gif=no'.
 ### mingw32 doesn't use -lgif/-lungif, since it loads the library dynamically.
@@ -4396,34 +4445,40 @@ HAVE_GIF=no
 LIBGIF=
 if test "${opsys}" = "mingw32"; then
   if test "${with_gif}" != "no"; then
-    AC_CHECK_HEADER(gif_lib.h, HAVE_GIF=yes, HAVE_GIF=no)
+    AC_CHECK_HEADER([gif_lib.h], [HAVE_GIF=yes], [HAVE_GIF=no])
   fi
   if test "${HAVE_GIF}" = "yes"; then
-    AC_DEFINE(HAVE_GIF, 1, [Define to 1 if you have a gif (or ungif) library.])
+    AC_DEFINE([HAVE_GIF], [1],
+      [Define to 1 if you have a gif (or ungif) library.])
   fi
 elif test "${HAVE_X11}" = "yes" && test "${with_gif}" != "no" \
         || test "${HAVE_W32}" = "yes" || test "${HAVE_NS}" = "yes" \
        || test "${HAVE_BE_APP}" = "yes" || test "$window_system" = "pgtk" \
        && test "${with_gif}" != "no"; then
-  AC_CHECK_HEADER(gif_lib.h,
+  AC_CHECK_HEADER([gif_lib.h],
 # EGifPutExtensionLast only exists from version libungif-4.1.0b1.
 # Earlier versions can crash Emacs, but version 5.0 removes 
EGifPutExtensionLast.
-    [AC_CHECK_LIB(gif, GifMakeMapObject, HAVE_GIF=yes,
-        [AC_CHECK_LIB(gif, EGifPutExtensionLast, HAVE_GIF=yes, 
HAVE_GIF=maybe)])])
+    [AC_CHECK_LIB([gif], [GifMakeMapObject], [HAVE_GIF=yes],
+       [AC_CHECK_LIB([gif], [EGifPutExtensionLast],
+          [HAVE_GIF=yes],
+          [HAVE_GIF=maybe])])])
 
   if test "$HAVE_GIF" = yes; then
     LIBGIF=-lgif
   elif test "$HAVE_GIF" = maybe; then
 # If gif_lib.h but no libgif, try libungif.
-    AC_CHECK_LIB(ungif, EGifPutExtensionLast, HAVE_GIF=yes, HAVE_GIF=no)
+    AC_CHECK_LIB([ungif], [EGifPutExtensionLast],
+      [HAVE_GIF=yes],
+      [HAVE_GIF=no])
     test "$HAVE_GIF" = yes && LIBGIF=-lungif
   fi
 
   if test "${HAVE_GIF}" = "yes"; then
-    AC_DEFINE(HAVE_GIF, 1, [Define to 1 if you have a gif (or ungif) library.])
+    AC_DEFINE([HAVE_GIF], [1],
+      [Define to 1 if you have a gif (or ungif) library.])
   fi
 fi
-AC_SUBST(LIBGIF)
+AC_SUBST([LIBGIF])
 
 dnl Check for required libraries.
 MISSING=
@@ -4489,28 +4544,33 @@ fi
 HAVE_GPM=no
 LIBGPM=
 if test "${with_gpm}" != "no"; then
-  AC_CHECK_HEADER(gpm.h,
-    [AC_CHECK_LIB(gpm, Gpm_Open, HAVE_GPM=yes)])
+  AC_CHECK_HEADER([gpm.h],
+    [AC_CHECK_LIB([gpm], [Gpm_Open], [HAVE_GPM=yes])])
 
   if test "${HAVE_GPM}" = "yes"; then
-    AC_DEFINE(HAVE_GPM, 1, [Define to 1 if you have the gpm library (-lgpm).])
+    AC_DEFINE([HAVE_GPM], [1],
+      [Define to 1 if you have the gpm library (-lgpm).])
     LIBGPM=-lgpm
   fi
 fi
-AC_SUBST(LIBGPM)
+AC_SUBST([LIBGPM])
 
 dnl Check for malloc/malloc.h on darwin
-AC_CHECK_HEADERS_ONCE(malloc/malloc.h)
+AC_CHECK_HEADERS_ONCE([malloc/malloc.h])
 
 GNUSTEP_CFLAGS=
 ### Use NeXTstep API to implement GUI.
 if test "${HAVE_NS}" = "yes"; then
-  AC_DEFINE(HAVE_NS, 1, [Define to 1 if you are using the NeXTstep API, either 
GNUstep or Cocoa on macOS.])
+  AC_DEFINE([HAVE_NS], [1],
+    [Define to 1 if you are using the NeXTstep API,
+     either GNUstep or Cocoa on macOS.])
   if test "${NS_IMPL_COCOA}" = "yes"; then
-    AC_DEFINE(NS_IMPL_COCOA, 1, [Define to 1 if you are using NS windowing 
under macOS.])
+    AC_DEFINE([NS_IMPL_COCOA], [1],
+      [Define to 1 if you are using NS windowing under macOS.])
   fi
   if test "${NS_IMPL_GNUSTEP}" = "yes"; then
-    AC_DEFINE(NS_IMPL_GNUSTEP, 1, [Define to 1 if you are using NS windowing 
under GNUstep.])
+    AC_DEFINE([NS_IMPL_GNUSTEP], [1],
+      [Define to 1 if you are using NS windowing under GNUstep.])
     if test $NS_GNUSTEP_CONFIG != yes; then
       # See also .m.o rule in src/Makefile.in.  */
       # FIXME: are all these flags really needed?  Document here why.  */
@@ -4526,15 +4586,16 @@ fi
 HAVE_X_SM=no
 LIBXSM=
 if test "${HAVE_X11}" = "yes"; then
-  AC_CHECK_HEADER(X11/SM/SMlib.h,
-    [AC_CHECK_LIB(SM, SmcOpenConnection, HAVE_X_SM=yes, , -lICE)])
+  AC_CHECK_HEADER([X11/SM/SMlib.h],
+    [AC_CHECK_LIB([SM], [SmcOpenConnection], [HAVE_X_SM=yes], [], [-lICE])])
 
   if test "${HAVE_X_SM}" = "yes"; then
-    AC_DEFINE(HAVE_X_SM, 1, [Define to 1 if you have the SM library (-lSM).])
+    AC_DEFINE([HAVE_X_SM], [1],
+      [Define to 1 if you have the SM library (-lSM).])
     LIBXSM="-lSM -lICE"
   fi
 fi
-AC_SUBST(LIBXSM)
+AC_SUBST([LIBXSM])
 
 ### Use XRandr (-lXrandr) if available
 HAVE_XRANDR=no
@@ -4546,8 +4607,8 @@ if test "${HAVE_X11}" = "yes"; then
     # Test old way in case pkg-config doesn't have it (older machines).
     # Include Xrender.h by hand to work around bug in older Xrandr.h
     # (e.g. RHEL5) and silence (harmless) configure warning (bug#18465).
-    AC_CHECK_HEADER(X11/extensions/Xrandr.h,
-      [AC_CHECK_LIB(Xrandr, XRRGetScreenResources, HAVE_XRANDR=yes)],
+    AC_CHECK_HEADER([X11/extensions/Xrandr.h],
+      [AC_CHECK_LIB([Xrandr], [XRRGetScreenResources], [HAVE_XRANDR=yes])],
       [], [AC_INCLUDES_DEFAULT
 #include <X11/extensions/Xrender.h>])
     if test $HAVE_XRANDR = yes; then
@@ -4555,11 +4616,12 @@ if test "${HAVE_X11}" = "yes"; then
     fi
   fi
   if test $HAVE_XRANDR = yes; then
-    AC_DEFINE(HAVE_XRANDR, 1, [Define to 1 if you have the XRandr extension.])
+    AC_DEFINE([HAVE_XRANDR], [1],
+      [Define to 1 if you have the XRandr extension.])
   fi
 fi
-AC_SUBST(XRANDR_CFLAGS)
-AC_SUBST(XRANDR_LIBS)
+AC_SUBST([XRANDR_CFLAGS])
+AC_SUBST([XRANDR_LIBS])
 
 ### Use Xinerama (-lXinerama) if available
 HAVE_XINERAMA=no
@@ -4569,18 +4631,20 @@ if test "${HAVE_X11}" = "yes"; then
   EMACS_CHECK_MODULES([XINERAMA], [$XINERAMA_MODULES])
   if test $HAVE_XINERAMA = no; then
     # Test old way in case pkg-config doesn't have it (older machines).
-    AC_CHECK_HEADER(X11/extensions/Xinerama.h,
-      [AC_CHECK_LIB(Xinerama, XineramaQueryExtension, HAVE_XINERAMA=yes)])
+    AC_CHECK_HEADER([X11/extensions/Xinerama.h],
+      [AC_CHECK_LIB([Xinerama], [XineramaQueryExtension],
+        [HAVE_XINERAMA=yes])])
     if test $HAVE_XINERAMA = yes; then
       XINERAMA_LIBS=-lXinerama
     fi
   fi
   if test $HAVE_XINERAMA = yes; then
-    AC_DEFINE(HAVE_XINERAMA, 1, [Define to 1 if you have the Xinerama 
extension.])
+    AC_DEFINE([HAVE_XINERAMA], [1],
+      [Define to 1 if you have the Xinerama extension.])
   fi
 fi
-AC_SUBST(XINERAMA_CFLAGS)
-AC_SUBST(XINERAMA_LIBS)
+AC_SUBST([XINERAMA_CFLAGS])
+AC_SUBST([XINERAMA_LIBS])
 
 ### Use Xfixes (-lXfixes) if available
 HAVE_XFIXES=no
@@ -4590,18 +4654,19 @@ if test "${HAVE_X11}" = "yes"; then
   EMACS_CHECK_MODULES([XFIXES], [$XFIXES_MODULES])
   if test $HAVE_XFIXES = no; then
     # Test old way in case pkg-config doesn't have it (older machines).
-    AC_CHECK_HEADER(X11/extensions/Xfixes.h,
-      [AC_CHECK_LIB(Xfixes, XFixesHideCursor, HAVE_XFIXES=yes)])
+    AC_CHECK_HEADER([X11/extensions/Xfixes.h],
+      [AC_CHECK_LIB([Xfixes], [XFixesHideCursor], [HAVE_XFIXES=yes])])
     if test $HAVE_XFIXES = yes; then
       XFIXES_LIBS=-lXfixes
     fi
   fi
   if test $HAVE_XFIXES = yes; then
-    AC_DEFINE(HAVE_XFIXES, 1, [Define to 1 if you have the Xfixes extension.])
+    AC_DEFINE([HAVE_XFIXES], [1],
+      [Define to 1 if you have the Xfixes extension.])
   fi
 fi
-AC_SUBST(XFIXES_CFLAGS)
-AC_SUBST(XFIXES_LIBS)
+AC_SUBST([XFIXES_CFLAGS])
+AC_SUBST([XFIXES_LIBS])
 
 ## Use XInput 2.0 if available
 HAVE_XINPUT2=no
@@ -4609,11 +4674,12 @@ if test "${HAVE_X11}" = "yes" && test "${with_xinput2}" 
!= "no"; then
    EMACS_CHECK_MODULES([XINPUT], [xi])
    if test $HAVE_XINPUT = yes; then
      # Now check for XInput2.h
-     AC_CHECK_HEADER(X11/extensions/XInput2.h,
-       [AC_CHECK_LIB(Xi, XIGrabButton, HAVE_XINPUT2=yes)])
+     AC_CHECK_HEADER([X11/extensions/XInput2.h],
+       [AC_CHECK_LIB([Xi], [XIGrabButton], [HAVE_XINPUT2=yes])])
    fi
    if test $HAVE_XINPUT2 = yes; then
-     AC_DEFINE(HAVE_XINPUT2, 1, [Define to 1 if the X Input Extension version 
2.0 or later is present.])
+     AC_DEFINE([HAVE_XINPUT2], [1],
+       [Define to 1 if the X Input Extension version 2.0 or later is present.])
      if test "$USE_GTK_TOOLKIT" = "GTK2"; then
        AC_MSG_WARN([You are building Emacs with GTK+ 2 and the X Input 
Extension version 2.
 This might lead to problems if your version of GTK+ is not built with support 
for XInput 2.])
@@ -4627,31 +4693,36 @@ This might lead to problems if your version of GTK+ is 
not built with support fo
        [], [], [#include <X11/extensions/XInput2.h>])
    fi
 fi
-AC_SUBST(XINPUT_CFLAGS)
-AC_SUBST(XINPUT_LIBS)
+AC_SUBST([XINPUT_CFLAGS])
+AC_SUBST([XINPUT_LIBS])
 
 XSYNC_LIBS=
 XSYNC_CFLAGS=
 HAVE_XSYNC=no
 if test "${HAVE_X11}" = "yes"; then
-   AC_CHECK_HEADER(X11/extensions/sync.h,
-     AC_CHECK_LIB(Xext, XSyncQueryExtension, HAVE_XSYNC=yes),
+   AC_CHECK_HEADER([X11/extensions/sync.h],
+     [AC_CHECK_LIB([Xext], [XSyncQueryExtension], [HAVE_XSYNC=yes])],
      [], [#include <X11/Xlib.h>])
 
   if test "${HAVE_XSYNC}" = "yes"; then
-    AC_DEFINE(HAVE_XSYNC, 1, [Define to 1 if the X Synchronization Extension 
is available.])
+    AC_DEFINE([HAVE_XSYNC], [1],
+      [Define to 1 if the X Synchronization Extension is available.])
     XSYNC_LIBS="-lXext"
+    OLDLIBS="$LIBS"
+    LIBS="-lXext $LIBS" # Set this temporarily for AC_CHECK_FUNC
+    AC_CHECK_FUNCS([XSyncTriggerFence]) # Check for version 3.1
+    LIBS="$OLDLIBS"
   fi
 fi
-AC_SUBST(XSYNC_LIBS)
-AC_SUBST(XSYNC_CFLAGS)
+AC_SUBST([XSYNC_LIBS])
+AC_SUBST([XSYNC_CFLAGS])
 
 ### Use Xdbe (-lXdbe) if available
 HAVE_XDBE=no
 if test "${HAVE_X11}" = "yes"; then
   if test "${with_xdbe}" != "no"; then
-    AC_CHECK_HEADER(X11/extensions/Xdbe.h,
-      [AC_CHECK_LIB(Xext, XdbeAllocateBackBufferName, HAVE_XDBE=yes)],
+    AC_CHECK_HEADER([X11/extensions/Xdbe.h],
+      [AC_CHECK_LIB([Xext], [XdbeAllocateBackBufferName], [HAVE_XDBE=yes])],
       [],
       [#include <X11/Xlib.h>
       ])
@@ -4660,44 +4731,49 @@ if test "${HAVE_X11}" = "yes"; then
     XDBE_LIBS=-lXext
   fi
   if test $HAVE_XDBE = yes; then
-    AC_DEFINE(HAVE_XDBE, 1, [Define to 1 if you have the Xdbe extension.])
+    AC_DEFINE([HAVE_XDBE], [1], [Define to 1 if you have the Xdbe extension.])
   fi
 fi
-AC_SUBST(XDBE_CFLAGS)
-AC_SUBST(XDBE_LIBS)
+AC_SUBST([XDBE_CFLAGS])
+AC_SUBST([XDBE_LIBS])
 
 ### Use the Nonrectangular Window Shape extension if available.
 HAVE_XSHAPE=no
 HAVE_XCB_SHAPE=no
 if test "${HAVE_X11}" = "yes"; then
-  AC_CHECK_HEADER(X11/extensions/shape.h,
-    [AC_CHECK_LIB(Xext, XShapeQueryVersion, HAVE_XSHAPE=yes)],
+  AC_CHECK_HEADER([X11/extensions/shape.h],
+    [AC_CHECK_LIB([Xext], [XShapeQueryVersion], [HAVE_XSHAPE=yes])],
     [],
     [#include <X11/extensions/shape.h>
     ])
   if test $HAVE_XSHAPE = yes; then
     XSHAPE_LIBS=-lXext
-    AC_CHECK_HEADER(xcb/shape.h,
-      [AC_CHECK_LIB(xcb-shape, xcb_shape_combine, HAVE_XCB_SHAPE=yes)], [],
+    AC_CHECK_HEADER([xcb/shape.h],
+      [AC_CHECK_LIB([xcb-shape], [xcb_shape_combine], [HAVE_XCB_SHAPE=yes])],
+      [],
       [#include <xcb/shape.h>])
 
     if test $HAVE_XCB_SHAPE = yes && test "$XCB_LIBS" != ""; then
       XSHAPE_LIBS="$XSHAPE_LIBS -lxcb-shape"
-      AC_DEFINE(HAVE_XCB_SHAPE, 1, [Define to 1 if XCB supports the 
Nonrectangular Window Shape extension.])
+      AC_DEFINE([HAVE_XCB_SHAPE], [1],
+       [Define to 1 if XCB supports the
+        Nonrectangular Window Shape extension.])
     fi
   fi
   if test $HAVE_XSHAPE = yes; then
-    AC_DEFINE(HAVE_XSHAPE, 1, [Define to 1 if you have the Nonrectangular 
Window Shape extension.])
+    AC_DEFINE([HAVE_XSHAPE], [1],
+      [Define to 1 if you have the Nonrectangular Window Shape extension.])
   fi
 fi
-AC_SUBST(XSHAPE_CFLAGS)
-AC_SUBST(XSHAPE_LIBS)
+AC_SUBST([XSHAPE_CFLAGS])
+AC_SUBST([XSHAPE_LIBS])
 
 ### Use Xcomposite (-lXcomposite) if available
 HAVE_XCOMPOSITE=no
 if test "${HAVE_X11}" = "yes"; then
-  AC_CHECK_HEADER(X11/extensions/Xcomposite.h,
-    [AC_CHECK_LIB(Xcomposite, XCompositeRedirectWindow, HAVE_XCOMPOSITE=yes)],
+  AC_CHECK_HEADER([X11/extensions/Xcomposite.h],
+    [AC_CHECK_LIB([Xcomposite], [XCompositeRedirectWindow],
+       [HAVE_XCOMPOSITE=yes])],
     [],
     [#include <X11/extensions/Xcomposite.h>
     ])
@@ -4705,11 +4781,12 @@ if test "${HAVE_X11}" = "yes"; then
     XCOMPOSITE_LIBS=-lXcomposite
   fi
   if test $HAVE_XCOMPOSITE = yes; then
-    AC_DEFINE(HAVE_XCOMPOSITE, 1, [Define to 1 if you have the XCOMPOSITE 
extension.])
+    AC_DEFINE([HAVE_XCOMPOSITE], [1],
+      [Define to 1 if you have the XCOMPOSITE extension.])
   fi
 fi
-AC_SUBST(XCOMPOSITE_CFLAGS)
-AC_SUBST(XCOMPOSITE_LIBS)
+AC_SUBST([XCOMPOSITE_CFLAGS])
+AC_SUBST([XCOMPOSITE_LIBS])
 
 ### Use libxml (-lxml2) if available
 ### mingw32 doesn't use -lxml2, since it loads the library dynamically.
@@ -4729,8 +4806,8 @@ if test "${with_xml2}" != "no"; then
       esac
     fi
     CPPFLAGS="$CPPFLAGS -isystem${xcsdkdir}/usr/include/libxml2"
-    AC_CHECK_HEADER(libxml/HTMLparser.h,
-      [AC_CHECK_DECL(HTML_PARSE_RECOVER, HAVE_LIBXML2=yes, ,
+    AC_CHECK_HEADER([libxml/HTMLparser.h],
+      [AC_CHECK_DECL([HTML_PARSE_RECOVER], [HAVE_LIBXML2=yes], [],
                     [#include <libxml/HTMLparser.h>])])
     CPPFLAGS="$SAVE_CPPFLAGS"
     if test "${HAVE_LIBXML2}" = "yes"; then
@@ -4740,21 +4817,24 @@ if test "${with_xml2}" != "no"; then
   fi
   if test "${HAVE_LIBXML2}" = "yes"; then
     if test "${opsys}" != "mingw32"; then
-      AC_CHECK_LIB(xml2, htmlReadMemory, HAVE_LIBXML2=yes, HAVE_LIBXML2=no,
+      AC_CHECK_LIB([xml2], [htmlReadMemory],
+       [HAVE_LIBXML2=yes],
+       [HAVE_LIBXML2=no],
         [$LIBXML2_LIBS])
     else
       LIBXML2_LIBS=""
     fi
     if test "${HAVE_LIBXML2}" = "yes"; then
-      AC_DEFINE(HAVE_LIBXML2, 1, [Define to 1 if you have the libxml library 
(-lxml2).])
+      AC_DEFINE([HAVE_LIBXML2], [1],
+       [Define to 1 if you have the libxml library (-lxml2).])
     else
       LIBXML2_LIBS=""
       LIBXML2_CFLAGS=""
     fi
   fi
 fi
-AC_SUBST(LIBXML2_LIBS)
-AC_SUBST(LIBXML2_CFLAGS)
+AC_SUBST([LIBXML2_LIBS])
+AC_SUBST([LIBXML2_CFLAGS])
 
 BLESSMAIL_TARGET=
 LIBS_MAIL=
@@ -4858,9 +4938,13 @@ AC_SUBST([HAVE_LIBSECCOMP])
 AC_SUBST([LIBSECCOMP_LIBS])
 AC_SUBST([LIBSECCOMP_CFLAGS])
 
+AC_CHECK_SIZEOF([long])
+SIZEOF_LONG="$ac_cv_sizeof_long"
+AC_SUBST([SIZEOF_LONG])
+
 OLD_LIBS=$LIBS
 LIBS="$LIB_PTHREAD $LIB_MATH $LIBS"
-AC_CHECK_FUNCS(accept4 fchdir gethostname \
+AC_CHECK_FUNCS([accept4 fchdir gethostname \
 getrusage get_current_dir_name \
 lrand48 random rint trunc \
 select getpagesize setlocale newlocale \
@@ -4870,7 +4954,7 @@ sendto recvfrom getsockname getifaddrs freeifaddrs \
 gai_strerror sync \
 getpwent endpwent getgrent endgrent \
 cfmakeraw cfsetspeed __executable_start log2 pthread_setname_np \
-pthread_set_name_np)
+pthread_set_name_np])
 LIBS=$OLD_LIBS
 
 if test "$ac_cv_func_pthread_setname_np" = "yes"; then
@@ -4885,7 +4969,7 @@ if test "$ac_cv_func_pthread_setname_np" = "yes"; then
      [emacs_cv_pthread_setname_np_1arg=no])])
   if test "$emacs_cv_pthread_setname_np_1arg" = "yes"; then
     AC_DEFINE(
-      HAVE_PTHREAD_SETNAME_NP_1ARG, 1,
+      [HAVE_PTHREAD_SETNAME_NP_1ARG], [1],
       [Define to 1 if pthread_setname_np takes a single argument.])
   else
     AC_CACHE_CHECK(
@@ -4899,7 +4983,7 @@ if test "$ac_cv_func_pthread_setname_np" = "yes"; then
        [emacs_cv_pthread_setname_np_3arg=no])])
      if test "$emacs_cv_pthread_setname_np_3arg" = "yes"; then
        AC_DEFINE(
-         HAVE_PTHREAD_SETNAME_NP_3ARG, 1,
+        [HAVE_PTHREAD_SETNAME_NP_3ARG], [1],
          [Define to 1 if pthread_setname_np takes three arguments.])
      fi
   fi
@@ -4932,28 +5016,28 @@ AC_CACHE_CHECK([for __builtin_frame_address],
      [emacs_cv_func___builtin_frame_address=yes],
      [emacs_cv_func___builtin_frame_address=no])])
 if test $emacs_cv_func___builtin_frame_address = yes; then
-  AC_DEFINE([HAVE___BUILTIN_FRAME_ADDRESS], 1,
+  AC_DEFINE([HAVE___BUILTIN_FRAME_ADDRESS], [1],
            [Define to 1 if you have the '__builtin_frame_address' function.])
 fi
 AC_CACHE_CHECK([for __builtin_unwind_init],
-              emacs_cv_func___builtin_unwind_init,
+              [emacs_cv_func___builtin_unwind_init],
 [AC_LINK_IFELSE([AC_LANG_PROGRAM([], [__builtin_unwind_init ();])],
-               emacs_cv_func___builtin_unwind_init=yes,
-               emacs_cv_func___builtin_unwind_init=no)])
+               [emacs_cv_func___builtin_unwind_init=yes],
+               [emacs_cv_func___builtin_unwind_init=no])])
 if test $emacs_cv_func___builtin_unwind_init = yes; then
-  AC_DEFINE(HAVE___BUILTIN_UNWIND_INIT, 1,
+  AC_DEFINE([HAVE___BUILTIN_UNWIND_INIT], [1],
            [Define to 1 if you have the '__builtin_unwind_init' function.])
 fi
 
-AC_CHECK_HEADERS_ONCE(sys/un.h)
+AC_CHECK_HEADERS_ONCE([sys/un.h])
 
 AC_FUNC_FSEEKO
 
 # UNIX98 PTYs.
-AC_CHECK_FUNCS(grantpt)
+AC_CHECK_FUNCS([grantpt])
 
 # PTY-related GNU extensions.
-AC_CHECK_FUNCS(getpt posix_openpt)
+AC_CHECK_FUNCS([getpt posix_openpt])
 
 dnl Run a test program that contains a call to tputs, a call that is
 dnl never executed.  This tests whether a pre-'main' dynamic linker
@@ -5025,14 +5109,15 @@ case "$opsys" in
 
   freebsd)
     AC_MSG_CHECKING([whether FreeBSD is new enough to use terminfo])
-    AC_CACHE_VAL(emacs_cv_freebsd_terminfo,
+    AC_CACHE_VAL([emacs_cv_freebsd_terminfo],
     [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <osreldate.h>]],
 [[#if __FreeBSD_version < 400000
 fail;
 #endif
-]])], emacs_cv_freebsd_terminfo=yes, emacs_cv_freebsd_terminfo=no)])
+]])], [emacs_cv_freebsd_terminfo=yes],
+      [emacs_cv_freebsd_terminfo=no])])
 
-    AC_MSG_RESULT($emacs_cv_freebsd_terminfo)
+    AC_MSG_RESULT([$emacs_cv_freebsd_terminfo])
 
     if test $emacs_cv_freebsd_terminfo = yes; then
       LIBS_TERMCAP="-lncurses"
@@ -5067,7 +5152,8 @@ esac
 
 TERMCAP_OBJ=tparam.o
 if test $TERMINFO = yes; then
-  AC_DEFINE(TERMINFO, 1, [Define to 1 if you use terminfo instead of termcap.])
+  AC_DEFINE([TERMINFO], [1],
+    [Define to 1 if you use terminfo instead of termcap.])
   TERMCAP_OBJ=terminfo.o
   AC_CACHE_CHECK([whether $LIBS_TERMCAP library defines BC],
     [emacs_cv_terminfo_defines_BC],
@@ -5078,15 +5164,15 @@ if test $TERMINFO = yes; then
        [emacs_cv_terminfo_defines_BC=no])
      LIBS=$OLD_LIBS])
   if test "$emacs_cv_terminfo_defines_BC" = yes; then
-    AC_DEFINE([TERMINFO_DEFINES_BC], 1, [Define to 1 if the
+    AC_DEFINE([TERMINFO_DEFINES_BC], [1], [Define to 1 if the
       terminfo library defines the variables BC, PC, and UP.])
   fi
 fi
 if test "X$LIBS_TERMCAP" = "X-lncurses"; then
-  AC_DEFINE(USE_NCURSES, 1, [Define to 1 if you use ncurses.])
+  AC_DEFINE([USE_NCURSES], [1], [Define to 1 if you use ncurses.])
 fi
-AC_SUBST(LIBS_TERMCAP)
-AC_SUBST(TERMCAP_OBJ)
+AC_SUBST([LIBS_TERMCAP])
+AC_SUBST([TERMCAP_OBJ])
 
 # GNU/Linux-specific timer functions.
 AC_CACHE_CHECK([for timerfd interface], [emacs_cv_have_timerfd],
@@ -5099,7 +5185,7 @@ AC_CACHE_CHECK([for timerfd interface], 
[emacs_cv_have_timerfd],
      [emacs_cv_have_timerfd=yes],
      [emacs_cv_have_timerfd=no])])
 if test "$emacs_cv_have_timerfd" = yes; then
-  AC_DEFINE([HAVE_TIMERFD], 1,
+  AC_DEFINE([HAVE_TIMERFD], [1],
     [Define to 1 if timerfd functions are supported as in GNU/Linux.])
 fi
 
@@ -5126,25 +5212,26 @@ LIBRESOLV=
 if test "$with_hesiod" != no ; then
   # Don't set $LIBS here -- see comments above.  FIXME which comments?
   resolv=no
-  AC_CHECK_FUNC(res_send, , [AC_CHECK_FUNC(__res_send, ,
-     [AC_CHECK_LIB(resolv, res_send, resolv=yes,
-                 [AC_CHECK_LIB(resolv, __res_send, resolv=yes)])])])
+  AC_CHECK_FUNC([res_send], [], [AC_CHECK_FUNC([__res_send], [],
+     [AC_CHECK_LIB([resolv], [res_send], [resolv=yes],
+                 [AC_CHECK_LIB([resolv], [__res_send], [resolv=yes])])])])
   if test "$resolv" = yes ; then
     RESOLVLIB=-lresolv
   else
     RESOLVLIB=
   fi
   hesiod=no
-  AC_CHECK_FUNC(hes_getmailhost, , [AC_CHECK_LIB(hesiod, hes_getmailhost,
-       hesiod=yes, :, $RESOLVLIB)])
+  AC_CHECK_FUNC([hes_getmailhost], [],
+    [AC_CHECK_LIB([hesiod], [hes_getmailhost],
+       [hesiod=yes], [:], [$RESOLVLIB])])
 
   if test x"$hesiod" = xyes; then
     LIBHESIOD=-lhesiod
     LIBRESOLV=$RESOLVLIB
   fi
 fi
-AC_SUBST(LIBHESIOD)
-AC_SUBST(LIBRESOLV)
+AC_SUBST([LIBHESIOD])
+AC_SUBST([LIBRESOLV])
 
 # These tell us which Kerberos-related libraries to use.
 COM_ERRLIB=
@@ -5155,45 +5242,51 @@ KRB4LIB=
 
 if test "${with_kerberos}" != no; then
   OLD_LIBS=$LIBS
-  AC_CHECK_LIB(com_err, com_err, have_com_err=yes, have_com_err=no)
+  AC_CHECK_LIB([com_err], [com_err], [have_com_err=yes], [have_com_err=no])
   if test $have_com_err = yes; then
     COM_ERRLIB=-lcom_err
     LIBS="$COM_ERRLIB $LIBS"
   fi
-  AC_CHECK_LIB(crypto, mit_des_cbc_encrypt, have_crypto=yes, have_crypto=no)
+  AC_CHECK_LIB([crypto], [mit_des_cbc_encrypt],
+    [have_crypto=yes],
+    [have_crypto=no])
   if test $have_crypto = yes; then
     CRYPTOLIB=-lcrypto
     LIBS="$CRYPTOLIB $LIBS"
   fi
-  AC_CHECK_LIB(k5crypto, mit_des_cbc_encrypt, have_k5crypto=yes, 
have_k5crypto=no)
+  AC_CHECK_LIB([k5crypto], [mit_des_cbc_encrypt],
+    [have_k5crypto=yes],
+    [have_k5crypto=no])
   if test $have_k5crypto = yes; then
     CRYPTOLIB=-lk5crypto
     LIBS="$CRYPTOLIB $LIBS"
   fi
-  AC_CHECK_LIB(krb5, krb5_init_context, have_krb5=yes, have_krb5=no)
+  AC_CHECK_LIB([krb5], [krb5_init_context], [have_krb5=yes], [have_krb5=no])
   if test $have_krb5=yes; then
     KRB5LIB=-lkrb5
     LIBS="$KRB5LIB $LIBS"
   fi
   dnl FIXME Simplify.  Does not match 22 logic, thanks to default_off?
   if test "${with_kerberos5}" = no; then
-    AC_CHECK_LIB(des425, des_cbc_encrypt, have_des425=yes, have_des425=no )
+    AC_CHECK_LIB([des425], [des_cbc_encrypt],
+      [have_des425=yes],
+      [have_des425=no])
     if test $have_des425 = yes; then
       DESLIB=-ldes425
       LIBS="$DESLIB $LIBS"
     else
-      AC_CHECK_LIB(des, des_cbc_encrypt, have_des=yes, have_des=no)
+      AC_CHECK_LIB([des], [des_cbc_encrypt], [have_des=yes], [have_des=no])
       if test $have_des = yes; then
         DESLIB=-ldes
         LIBS="$DESLIB $LIBS"
       fi
     fi
-    AC_CHECK_LIB(krb4, krb_get_cred, have_krb4=yes, have_krb4=no)
+    AC_CHECK_LIB([krb4], [krb_get_cred], [have_krb4=yes], [have_krb4=no])
     if test $have_krb4 = yes; then
       KRB4LIB=-lkrb4
       LIBS="$KRB4LIB $LIBS"
     else
-      AC_CHECK_LIB(krb, krb_get_cred, have_krb=yes, have_krb=no)
+      AC_CHECK_LIB([krb], [krb_get_cred], [have_krb=yes], [have_krb=no])
       if test $have_krb = yes; then
         KRB4LIB=-lkrb
         LIBS="$KRB4LIB $LIBS"
@@ -5202,25 +5295,25 @@ if test "${with_kerberos}" != no; then
   fi
 
   if test "${with_kerberos5}" != no; then
-    AC_CHECK_HEADERS(krb5.h,
-      [AC_CHECK_MEMBERS([krb5_error.text, krb5_error.e_text],,,
+    AC_CHECK_HEADERS([krb5.h],
+      [AC_CHECK_MEMBERS([krb5_error.text, krb5_error.e_text], [], [],
                        [#include <krb5.h>])])
   else
-    AC_CHECK_HEADERS(krb.h,,
-                    [AC_CHECK_HEADERS(kerberosIV/krb.h,,
-                                      [AC_CHECK_HEADERS(kerberos/krb.h)])])
+    AC_CHECK_HEADERS([krb.h], [],
+                    [AC_CHECK_HEADERS([kerberosIV/krb.h], [],
+                                      [AC_CHECK_HEADERS([kerberos/krb.h])])])
   fi
-  AC_CHECK_HEADERS(com_err.h)
+  AC_CHECK_HEADERS([com_err.h])
   LIBS=$OLD_LIBS
 fi
 
-AC_SUBST(COM_ERRLIB)
-AC_SUBST(CRYPTOLIB)
-AC_SUBST(KRB5LIB)
-AC_SUBST(DESLIB)
-AC_SUBST(KRB4LIB)
+AC_SUBST([COM_ERRLIB])
+AC_SUBST([CRYPTOLIB])
+AC_SUBST([KRB5LIB])
+AC_SUBST([DESLIB])
+AC_SUBST([KRB4LIB])
 
-AC_CHECK_HEADERS(valgrind/valgrind.h)
+AC_CHECK_HEADERS([valgrind/valgrind.h])
 
 AC_CHECK_MEMBERS([struct unipair.unicode], [], [], [[#include <linux/kd.h>]])
 
@@ -5230,7 +5323,7 @@ AC_FUNC_FORK
 
 dnl AC_CHECK_FUNCS_ONCE wouldn’t be right for snprintf, which needs
 dnl the current CFLAGS etc.
-AC_CHECK_FUNCS(snprintf)
+AC_CHECK_FUNCS([snprintf])
 
 dnl posix_spawn.  The chdir and setsid functionality is relatively
 dnl recent, so we check for it specifically.
@@ -5274,12 +5367,12 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM(
 CFLAGS="$OLDCFLAGS"
 LIBS="$OLDLIBS"])
 if test "${emacs_cv_links_glib}" = "yes"; then
-  AC_DEFINE(HAVE_GLIB, 1, [Define to 1 if GLib is linked in.])
+  AC_DEFINE([HAVE_GLIB], [1], [Define to 1 if GLib is linked in.])
   if test "$HAVE_NS" = no ; then
     XGSELOBJ=xgselect.o
   fi
 fi
-AC_SUBST(XGSELOBJ)
+AC_SUBST([XGSELOBJ])
 
 dnl Adapted from Haible's version.
 AC_CACHE_CHECK([for nl_langinfo and CODESET], [emacs_cv_langinfo_codeset],
@@ -5289,7 +5382,7 @@ AC_CACHE_CHECK([for nl_langinfo and CODESET], 
[emacs_cv_langinfo_codeset],
     [emacs_cv_langinfo_codeset=no])
   ])
 if test "$emacs_cv_langinfo_codeset" = yes; then
-  AC_DEFINE([HAVE_LANGINFO_CODESET], 1,
+  AC_DEFINE([HAVE_LANGINFO_CODESET], [1],
     [Define if you have <langinfo.h> and nl_langinfo (CODESET).])
 
   AC_CACHE_CHECK([for nl_langinfo and _NL_PAPER_WIDTH],
@@ -5300,7 +5393,7 @@ if test "$emacs_cv_langinfo_codeset" = yes; then
       [emacs_cv_langinfo__nl_paper_width=no])
     ])
   if test "$emacs_cv_langinfo__nl_paper_width" = yes; then
-    AC_DEFINE([HAVE_LANGINFO__NL_PAPER_WIDTH], 1,
+    AC_DEFINE([HAVE_LANGINFO__NL_PAPER_WIDTH], [1],
       [Define if you have <langinfo.h> and nl_langinfo (_NL_PAPER_WIDTH).])
   fi
 fi
@@ -5313,15 +5406,17 @@ dnl The following looks like a useful start.
 dnl
 dnl AC_SYS_POSIX_TERMIOS
 dnl if test $ac_cv_sys_posix_termios = yes; then
-dnl    AC_DEFINE(HAVE_TERMIOS, 1, [Define to 1 if you have POSIX-style 
functions
-dnl                                and macros for terminal control.])
-dnl    AC_DEFINE(HAVE_TCATTR, 1, [Define to 1 if you have tcgetattr and 
tcsetattr.])
+dnl    AC_DEFINE([HAVE_TERMIOS], [1],
+dnl      [Define to 1 if you have POSIX-style
+dnl       functions and macros for terminal control.])
+dnl    AC_DEFINE([HAVE_TCATTR], [1],
+dnl      [Define to 1 if you have tcgetattr and tcsetattr.])
 dnl fi
 
 dnl Turned on June 1996 supposing nobody will mind it.
 dnl MinGW emulates passwd database, so this feature doesn't make sense there.
 if test "${opsys}" != "mingw32"; then
-   AC_DEFINE(AMPERSAND_FULL_NAME, 1, [Define to use the convention that &
+   AC_DEFINE([AMPERSAND_FULL_NAME], [1], [Define to use the convention that &
      in the full name stands for the login id.])
 fi
 
@@ -5329,22 +5424,23 @@ dnl Everybody supports this, except MS.
 dnl Seems like the kind of thing we should be testing for, though.
 ## Note: PTYs are broken on darwin <6.  Use at your own risk.
 if test "${opsys}" != "mingw32"; then
-  AC_DEFINE(HAVE_PTYS, 1, [Define if the system supports pty devices.])
+  AC_DEFINE([HAVE_PTYS], [1], [Define if the system supports pty devices.])
 fi
 
 dnl Everybody supports this, except MS-DOS.
 dnl Seems like the kind of thing we should be testing for, though.
-AC_DEFINE(HAVE_SOCKETS, 1, [Define if the system supports
+AC_DEFINE([HAVE_SOCKETS], [1], [Define if the system supports
   4.2-compatible sockets.])
 
-AH_TEMPLATE(INTERNAL_TERMINAL, [This is substituted when $TERM is "internal".])
+AH_TEMPLATE([INTERNAL_TERMINAL],
+  [This is substituted when $TERM is "internal".])
 
-AH_TEMPLATE(NULL_DEVICE, [Name of the file to open to get
+AH_TEMPLATE([NULL_DEVICE], [Name of the file to open to get
   a null file, or a data sink.])
 if test "${opsys}" = "mingw32"; then
-  AC_DEFINE(NULL_DEVICE, ["NUL:"])
+  AC_DEFINE([NULL_DEVICE], ["NUL:"])
 else
-  AC_DEFINE(NULL_DEVICE, ["/dev/null"])
+  AC_DEFINE([NULL_DEVICE], ["/dev/null"])
 fi
 
 if test "${opsys}" = "mingw32"; then
@@ -5352,7 +5448,8 @@ if test "${opsys}" = "mingw32"; then
 else
   SEPCHAR=':'
 fi
-AC_DEFINE_UNQUOTED(SEPCHAR, ['$SEPCHAR'], [Character that separates PATH 
elements.])
+AC_DEFINE_UNQUOTED([SEPCHAR], ['$SEPCHAR'],
+  [Character that separates PATH elements.])
 dnl This is for MinGW, and is used in test/Makefile.in.
 dnl The MSYS Bash has heuristics for replacing ':' with ';' when it
 dnl decides that a command-line argument to be passed to a MinGW program
@@ -5362,34 +5459,35 @@ dnl sees a colon-separated list of file names; e.g. 
":." is left alone,
 dnl which breaks in-tree builds.  So we do this manually instead.
 dnl Note that we cannot rely on PATH_SEPARATOR, as that one will always
 dnl be computed as ':' in MSYS Bash.
-AC_SUBST(SEPCHAR)
+AC_SUBST([SEPCHAR])
 
 dnl Everybody supports this, except MS-DOS.
-AC_DEFINE(subprocesses, 1, [Define to enable asynchronous subprocesses.])
+AC_DEFINE([subprocesses], [1], [Define to enable asynchronous subprocesses.])
 
-AC_DEFINE(USER_FULL_NAME, [pw->pw_gecos], [How to get a user's full name.])
+AC_DEFINE([USER_FULL_NAME], [pw->pw_gecos], [How to get a user's full name.])
 
 
-AC_DEFINE(DIRECTORY_SEP, ['/'],
+AC_DEFINE([DIRECTORY_SEP], ['/'],
   [Character that separates directories in a file name.])
 
 if test "${opsys}" = "mingw32"; then
-  AC_DEFINE(IS_DEVICE_SEP(_c_), [((_c_) == ':')],
+  AC_DEFINE([IS_DEVICE_SEP(_c_)], [((_c_) == ':')],
     [Returns true if character is a device separator.])
 
-  AC_DEFINE(IS_DIRECTORY_SEP(_c_), [((_c_) == '/' || (_c_) == '\\')],
+  AC_DEFINE([IS_DIRECTORY_SEP(_c_)], [((_c_) == '/' || (_c_) == '\\')],
     [Returns true if character is a directory separator.])
 
-  AC_DEFINE(IS_ANY_SEP(_c_), [(IS_DIRECTORY_SEP (_c_) || IS_DEVICE_SEP(_c_))],
+  AC_DEFINE([IS_ANY_SEP(_c_)],
+    [(IS_DIRECTORY_SEP (_c_) || IS_DEVICE_SEP (_c_))],
     [Returns true if character is any form of separator.])
 else
-  AC_DEFINE(IS_DEVICE_SEP(_c_), 0,
+  AC_DEFINE([IS_DEVICE_SEP(_c_)], 0,
     [Returns true if character is a device separator.])
 
-  AC_DEFINE(IS_DIRECTORY_SEP(_c_), [((_c_) == DIRECTORY_SEP)],
+  AC_DEFINE([IS_DIRECTORY_SEP(_c_)], [((_c_) == DIRECTORY_SEP)],
     [Returns true if character is a directory separator.])
 
-  AC_DEFINE(IS_ANY_SEP(_c_), [(IS_DIRECTORY_SEP (_c_))],
+  AC_DEFINE([IS_ANY_SEP(_c_)], [(IS_DIRECTORY_SEP (_c_))],
     [Returns true if character is any form of separator.])
 fi
 
@@ -5414,7 +5512,7 @@ if test "$USE_X_TOOLKIT" != "none"; then
       [[#include <X11/Intrinsic.h>
        #include <X11/Xmu/Editres.h>]],
       [[_XEditResCheckMessages (0, 0, 0, 0);]])],
-      [AC_DEFINE([X_TOOLKIT_EDITRES], 1,
+      [AC_DEFINE([X_TOOLKIT_EDITRES], [1],
         [Define to 1 if we should use XEditRes.])])
     LIBS=$OLDLIBS
   fi
@@ -5426,7 +5524,7 @@ case $opsys in
     dnl instead, there's a system variable _sys_nsig.  Unfortunately, we
     dnl need the constant to dimension an array.  So wire in the appropriate
     dnl value here.
-    AC_DEFINE(NSIG_MINIMUM, 32, [Minimum value of NSIG.])
+    AC_DEFINE([NSIG_MINIMUM], [32], [Minimum value of NSIG.])
     ;;
 esac
 
@@ -5459,7 +5557,7 @@ case $opsys in
     dnl of this file, so that we do not check for get_current_dir_name
     dnl on AIX.  But that might be fragile if something else ends
     dnl up testing for get_current_dir_name as a dependency.
-    AC_DEFINE(BROKEN_GET_CURRENT_DIR_NAME, 1, [Define if
+    AC_DEFINE([BROKEN_GET_CURRENT_DIR_NAME], [1], [Define if
       get_current_dir_name should not be used.])
     ;;
 
@@ -5477,7 +5575,7 @@ case $opsys in
     dnl successfully after processing (for example with CRs added if the
     dnl terminal is set up that way which it is here).  The same bytes will
     dnl be seen again in a later read(2), without the CRs.
-    AC_DEFINE(BROKEN_PTY_READ_AFTER_EAGAIN, 1, [Define on FreeBSD to
+    AC_DEFINE([BROKEN_PTY_READ_AFTER_EAGAIN], [1], [Define on FreeBSD to
       work around an issue when reading from a PTY.])
     ;;
 esac
@@ -5485,13 +5583,13 @@ esac
 case $opsys in
   gnu-* | solaris )
     dnl FIXME Can't we test if this exists (eg /proc/$$)?
-    AC_DEFINE(HAVE_PROCFS, 1, [Define if you have the /proc filesystem.])
+    AC_DEFINE([HAVE_PROCFS], [1], [Define if you have the /proc filesystem.])
   ;;
 esac
 
 case $opsys in
   darwin | dragonfly | freebsd | netbsd | openbsd )
-    AC_DEFINE(DONT_REOPEN_PTY, 1, [Define if process.c does not need to
+    AC_DEFINE([DONT_REOPEN_PTY], [1], [Define if process.c does not need to
       close a pty to make it a controlling terminal (it is already a
       controlling terminal of the subprocess, because we did ioctl 
TIOCSCTTY).])
   ;;
@@ -5504,7 +5602,7 @@ case $opsys in
 esac
 
 dnl Used in sound.c
-AC_DEFINE_UNQUOTED(DEFAULT_SOUND_DEVICE, "$sound_device",
+AC_DEFINE_UNQUOTED([DEFAULT_SOUND_DEVICE], ["$sound_device"],
   [Name of the default sound device.])
 
 
@@ -5531,7 +5629,7 @@ dnl to read the input and send it to the true Emacs 
process
 dnl through a pipe.
 case $opsys in
   darwin | gnu-linux | gnu-kfreebsd)
-    AC_DEFINE(INTERRUPT_INPUT, 1, [Define to read input using SIGIO.])
+    AC_DEFINE([INTERRUPT_INPUT], [1], [Define to read input using SIGIO.])
   ;;
 esac
 
@@ -5543,73 +5641,78 @@ dnl NARROWPROTO, we will see the wrong function 
prototypes for X functions
 dnl taking float or double parameters.
 case $opsys in
   cygwin|gnu|gnu-linux|gnu-kfreebsd|freebsd|netbsd|openbsd)
-    AC_DEFINE(NARROWPROTO, 1, [Define if system's imake configuration
+    AC_DEFINE([NARROWPROTO], [1], [Define if system's imake configuration
       file defines 'NeedWidePrototypes' as 'NO'.])
   ;;
 esac
 
 
 dnl Used in process.c, this must be a loop, even if it only runs once.
-AH_TEMPLATE(PTY_ITERATION, [How to iterate over PTYs.])
+AH_TEMPLATE([PTY_ITERATION], [How to iterate over PTYs.])
 dnl Only used if !PTY_ITERATION.  Iterate from FIRST_PTY_LETTER to z,
 dnl trying suffixes 0-16.
-AH_TEMPLATE(FIRST_PTY_LETTER, [Letter to use in finding device name of
+AH_TEMPLATE([FIRST_PTY_LETTER], [Letter to use in finding device name of
   first PTY, if PTYs are supported.])
-AH_TEMPLATE(PTY_OPEN, [How to open a PTY, if non-standard.])
-AH_TEMPLATE(PTY_NAME_SPRINTF, [How to get the device name of the control
+AH_TEMPLATE([PTY_OPEN], [How to open a PTY, if non-standard.])
+AH_TEMPLATE([PTY_NAME_SPRINTF], [How to get the device name of the control
   end of a PTY, if non-standard.])
-AH_TEMPLATE(PTY_TTY_NAME_SPRINTF, [How to get device name of the tty
+AH_TEMPLATE([PTY_TTY_NAME_SPRINTF], [How to get device name of the tty
   end of a PTY, if non-standard.])
 
 case $opsys in
   aix4-2 )
-    AC_DEFINE(PTY_ITERATION, [int c; for (c = 0; !c ; c++)])
+    AC_DEFINE([PTY_ITERATION], [int c; for (c = 0; !c ; c++)])
     dnl You allocate a pty by opening /dev/ptc to get the master side.
     dnl To get the name of the slave side, you just ttyname() the master side.
-    AC_DEFINE(PTY_NAME_SPRINTF, [strcpy (pty_name, "/dev/ptc");])
-    AC_DEFINE(PTY_TTY_NAME_SPRINTF, [strcpy (pty_name, ttyname (fd));])
+    AC_DEFINE([PTY_NAME_SPRINTF], [strcpy (pty_name, "/dev/ptc");])
+    AC_DEFINE([PTY_TTY_NAME_SPRINTF], [strcpy (pty_name, ttyname (fd));])
     ;;
 
   cygwin )
-    AC_DEFINE(PTY_ITERATION, [int i; for (i = 0; i < 1; i++)])
+    AC_DEFINE([PTY_ITERATION], [int i; for (i = 0; i < 1; i++)])
     dnl multi-line AC_DEFINEs are hard. :(
-    AC_DEFINE(PTY_OPEN, [ do { int dummy; sigset_t blocked, procmask; 
sigemptyset (&blocked); sigaddset (&blocked, SIGCHLD); pthread_sigmask 
(SIG_BLOCK, &blocked, &procmask); if (-1 == openpty (&fd, &dummy, pty_name, 0, 
0)) fd = -1; pthread_sigmask (SIG_SETMASK, &procmask, 0); if (fd >= 0) 
emacs_close (dummy); } while (false)])
-    AC_DEFINE(PTY_NAME_SPRINTF, [])
-    AC_DEFINE(PTY_TTY_NAME_SPRINTF, [])
+    AC_DEFINE([PTY_OPEN],
+      [ do { int dummy; sigset_t blocked, procmask; sigemptyset (&blocked); 
sigaddset (&blocked, SIGCHLD); pthread_sigmask (SIG_BLOCK, &blocked, 
&procmask); if (-1 == openpty (&fd, &dummy, pty_name, 0, 0)) fd = -1; 
pthread_sigmask (SIG_SETMASK, &procmask, 0); if (fd >= 0) emacs_close (dummy); 
} while (false)])
+    AC_DEFINE([PTY_NAME_SPRINTF], [])
+    AC_DEFINE([PTY_TTY_NAME_SPRINTF], [])
     ;;
 
   gnu | qnxnto )
-    AC_DEFINE(FIRST_PTY_LETTER, ['p'])
+    AC_DEFINE([FIRST_PTY_LETTER], ['p'])
     ;;
 
   gnu-linux | gnu-kfreebsd | dragonfly | freebsd | openbsd | netbsd | darwin | 
nacl )
     dnl if HAVE_GRANTPT
     if test "x$ac_cv_func_grantpt" = xyes; then
-      AC_DEFINE(UNIX98_PTYS, 1, [Define if the system has Unix98 PTYs.])
-      AC_DEFINE(PTY_ITERATION, [int i; for (i = 0; i < 1; i++)])
+      AC_DEFINE([UNIX98_PTYS], [1], [Define if the system has Unix98 PTYs.])
+      AC_DEFINE([PTY_ITERATION], [int i; for (i = 0; i < 1; i++)])
       dnl Note that grantpt and unlockpt may fork.  We must block SIGCHLD
       dnl to prevent sigchld_handler from intercepting the child's death.
-      AC_DEFINE(PTY_TTY_NAME_SPRINTF, [{ char *ptyname = 0; sigset_t blocked; 
sigemptyset (&blocked); sigaddset (&blocked, SIGCHLD); pthread_sigmask 
(SIG_BLOCK, &blocked, 0); if (grantpt (fd) != -1 && unlockpt (fd) != -1) 
ptyname = ptsname(fd); pthread_sigmask (SIG_UNBLOCK, &blocked, 0); if 
(!ptyname) { emacs_close (fd); return -1; } snprintf (pty_name, PTY_NAME_SIZE, 
"%s", ptyname); }])
+      AC_DEFINE([PTY_TTY_NAME_SPRINTF],
+       [{ char *ptyname = 0; sigset_t blocked; sigemptyset (&blocked); 
sigaddset (&blocked, SIGCHLD); pthread_sigmask (SIG_BLOCK, &blocked, 0); if 
(grantpt (fd) != -1 && unlockpt (fd) != -1) ptyname = ptsname(fd); 
pthread_sigmask (SIG_UNBLOCK, &blocked, 0); if (!ptyname) { emacs_close (fd); 
return -1; } snprintf (pty_name, PTY_NAME_SIZE, "%s", ptyname); }])
       dnl if HAVE_POSIX_OPENPT
       if test "x$ac_cv_func_posix_openpt" = xyes; then
-        AC_DEFINE(PTY_OPEN, [do { fd = posix_openpt (O_RDWR | O_CLOEXEC | 
O_NOCTTY); if (fd < 0 && errno == EINVAL) fd = posix_openpt (O_RDWR | 
O_NOCTTY); } while (false)])
-        AC_DEFINE(PTY_NAME_SPRINTF, [])
+       AC_DEFINE([PTY_OPEN],
+         [do { fd = posix_openpt (O_RDWR | O_CLOEXEC | O_NOCTTY); if (fd < 0 
&& errno == EINVAL) fd = posix_openpt (O_RDWR | O_NOCTTY); } while (false)])
+       AC_DEFINE([PTY_NAME_SPRINTF], [])
       dnl if HAVE_GETPT
       elif test "x$ac_cv_func_getpt" = xyes; then
-        AC_DEFINE(PTY_OPEN, [fd = getpt ()])
-        AC_DEFINE(PTY_NAME_SPRINTF, [])
+       AC_DEFINE([PTY_OPEN], [fd = getpt ()])
+       AC_DEFINE([PTY_NAME_SPRINTF], [])
       else
-        AC_DEFINE(PTY_NAME_SPRINTF, [strcpy (pty_name, "/dev/ptmx");])
+       AC_DEFINE([PTY_NAME_SPRINTF], [strcpy (pty_name, "/dev/ptmx");])
       fi
     else
-      AC_DEFINE(FIRST_PTY_LETTER, ['p'])
+      AC_DEFINE([FIRST_PTY_LETTER], ['p'])
     fi
     ;;
 
   hpux*)
-    AC_DEFINE(FIRST_PTY_LETTER, ['p'])
-    AC_DEFINE(PTY_NAME_SPRINTF, [sprintf (pty_name, "/dev/ptym/pty%c%x", c, 
i);])
-    AC_DEFINE(PTY_TTY_NAME_SPRINTF, [sprintf (pty_name, "/dev/pty/tty%c%x", c, 
i);])
+    AC_DEFINE([FIRST_PTY_LETTER], ['p'])
+    AC_DEFINE([PTY_NAME_SPRINTF],
+      [sprintf (pty_name, "/dev/ptym/pty%c%x", c, i);])
+    AC_DEFINE([PTY_TTY_NAME_SPRINTF],
+      [sprintf (pty_name, "/dev/pty/tty%c%x", c, i);])
     ;;
 
   solaris )
@@ -5617,22 +5720,25 @@ case $opsys in
     dnl O_CLOEXEC when opening the pty, and keep the SIGCHLD handler
     dnl from intercepting that death.  If any child but grantpt's should die
     dnl within, it should be caught after sigrelse(2).
-    AC_DEFINE(PTY_OPEN, [fd = open (pty_name, O_RDWR | O_NONBLOCK)])
-    AC_DEFINE(PTY_TTY_NAME_SPRINTF, [{ char *ptsname (int), *ptyname; int 
grantpt_result; sigset_t blocked; sigemptyset (&blocked); sigaddset (&blocked, 
SIGCHLD); pthread_sigmask (SIG_BLOCK, &blocked, 0); grantpt_result = grantpt 
(fd); pthread_sigmask (SIG_UNBLOCK, &blocked, 0); if (grantpt_result == -1 || 
unlockpt (fd) == -1 || !(ptyname = ptsname (fd))) { emacs_close (fd); return 
-1; } snprintf (pty_name, PTY_NAME_SIZE, "%s", ptyname); }])
+    AC_DEFINE([PTY_OPEN], [fd = open (pty_name, O_RDWR | O_NONBLOCK)])
+    AC_DEFINE([PTY_TTY_NAME_SPRINTF],
+      [{ char *ptsname (int), *ptyname; int grantpt_result; sigset_t blocked; 
sigemptyset (&blocked); sigaddset (&blocked, SIGCHLD); pthread_sigmask 
(SIG_BLOCK, &blocked, 0); grantpt_result = grantpt (fd); pthread_sigmask 
(SIG_UNBLOCK, &blocked, 0); if (grantpt_result == -1 || unlockpt (fd) == -1 || 
!(ptyname = ptsname (fd))) { emacs_close (fd); return -1; } snprintf (pty_name, 
PTY_NAME_SIZE, "%s", ptyname); }])
     ;;
 
   unixware )
     dnl Comments are as per solaris.
-    AC_DEFINE(PTY_OPEN, [fd = open (pty_name, O_RDWR | O_NONBLOCK)])
-    AC_DEFINE(PTY_TTY_NAME_SPRINTF, [{ char *ptsname (int), *ptyname; int 
grantpt_result; sigset_t blocked; sigemptyset (&blocked); sigaddset (&blocked, 
SIGCHLD); pthread_sigmask (SIG_BLOCK, &blocked, 0); grantpt_result = grantpt 
(fd); pthread_sigmask (SIG_UNBLOCK, &blocked, 0); if (grantpt_result == -1) 
fatal("could not grant slave pty"); if (unlockpt(fd) == -1) fatal("could not 
unlock slave pty"); if (!(ptyname = ptsname(fd))) fatal ("could not enable 
slave pty"); snprintf (pty_name, P [...]
+    AC_DEFINE([PTY_OPEN], [fd = open (pty_name, O_RDWR | O_NONBLOCK)])
+    AC_DEFINE([PTY_TTY_NAME_SPRINTF],
+      [{ char *ptsname (int), *ptyname; int grantpt_result; sigset_t blocked; 
sigemptyset (&blocked); sigaddset (&blocked, SIGCHLD); pthread_sigmask 
(SIG_BLOCK, &blocked, 0); grantpt_result = grantpt (fd); pthread_sigmask 
(SIG_UNBLOCK, &blocked, 0); if (grantpt_result == -1) fatal("could not grant 
slave pty"); if (unlockpt(fd) == -1) fatal("could not unlock slave pty"); if 
(!(ptyname = ptsname(fd))) fatal ("could not enable slave pty"); snprintf 
(pty_name, PTY_NAME_SIZE, "%s", ptyname); }])
     ;;
 
   haiku*)
-    AC_DEFINE(FIRST_PTY_LETTER, ['s'])
-    AC_DEFINE(PTY_NAME_SPRINTF, [])
+    AC_DEFINE([FIRST_PTY_LETTER], ['s'])
+    AC_DEFINE([PTY_NAME_SPRINTF], [])
     dnl on Haiku pty names aren't distinctive, thus the use of posix_openpt
-    AC_DEFINE(PTY_OPEN, [fd = posix_openpt (O_RDWR | O_NONBLOCK)])
-    AC_DEFINE(PTY_TTY_NAME_SPRINTF, [{ char *ptyname; int grantpt_result; 
sigset_t blocked; sigemptyset (&blocked); sigaddset (&blocked, SIGCHLD); 
pthread_sigmask (SIG_BLOCK, &blocked, 0); grantpt_result = grantpt (fd); 
pthread_sigmask (SIG_UNBLOCK, &blocked, 0); if (grantpt_result == -1) 
fatal("could not grant slave pty"); if (unlockpt(fd) == -1) fatal("could not 
unlock slave pty"); if (!(ptyname = ptsname(fd))) fatal ("could not enable 
slave pty"); snprintf (pty_name, PTY_NAME_SIZE, "% [...]
+    AC_DEFINE([PTY_OPEN], [fd = posix_openpt (O_RDWR | O_NONBLOCK)])
+    AC_DEFINE([PTY_TTY_NAME_SPRINTF],
+      [{ char *ptyname; int grantpt_result; sigset_t blocked; sigemptyset 
(&blocked); sigaddset (&blocked, SIGCHLD); pthread_sigmask (SIG_BLOCK, 
&blocked, 0); grantpt_result = grantpt (fd); pthread_sigmask (SIG_UNBLOCK, 
&blocked, 0); if (grantpt_result == -1) fatal("could not grant slave pty"); if 
(unlockpt(fd) == -1) fatal("could not unlock slave pty"); if (!(ptyname = 
ptsname(fd))) fatal ("could not enable slave pty"); snprintf (pty_name, 
PTY_NAME_SIZE, "%s", ptyname); }])
     ;;
 esac
 
@@ -5641,21 +5747,22 @@ case $opsys in
   solaris | unixware )
     dnl This change means that we don't loop through allocate_pty too
     dnl many times in the (rare) event of a failure.
-    AC_DEFINE(FIRST_PTY_LETTER, ['z'])
-    AC_DEFINE(PTY_NAME_SPRINTF, [strcpy (pty_name, "/dev/ptmx");])
+    AC_DEFINE([FIRST_PTY_LETTER], ['z'])
+    AC_DEFINE([PTY_NAME_SPRINTF], [strcpy (pty_name, "/dev/ptmx");])
     dnl Push various streams modules onto a PTY channel.  Used in process.c.
-    AC_DEFINE(SETUP_SLAVE_PTY, [if (ioctl (std_in, I_PUSH, "ptem") == -1) 
fatal ("ioctl I_PUSH ptem"); if (ioctl (std_in, I_PUSH, "ldterm") == -1) fatal 
("ioctl I_PUSH ldterm"); if (ioctl (std_in, I_PUSH, "ttcompat") == -1) fatal 
("ioctl I_PUSH ttcompat");], [How to set up a slave PTY, if needed.])
+    AC_DEFINE([SETUP_SLAVE_PTY],
+      [if (ioctl (std_in, I_PUSH, "ptem") == -1) fatal ("ioctl I_PUSH ptem"); 
if (ioctl (std_in, I_PUSH, "ldterm") == -1) fatal ("ioctl I_PUSH ldterm"); if 
(ioctl (std_in, I_PUSH, "ttcompat") == -1) fatal ("ioctl I_PUSH ttcompat");], 
[How to set up a slave PTY, if needed.])
     ;;
 esac
 
 
-AH_TEMPLATE(SIGNALS_VIA_CHARACTERS, [Make process_send_signal work by
+AH_TEMPLATE([SIGNALS_VIA_CHARACTERS], [Make process_send_signal work by
 "typing" a signal character on the pty.])
 
 case $opsys in
   dnl Perry Smith <pedz@ddivt1.austin.ibm.com> says this is correct for AIX.
   aix4-2 | cygwin | gnu | dragonfly | freebsd | netbsd | openbsd | darwin )
-    AC_DEFINE(SIGNALS_VIA_CHARACTERS, 1)
+    AC_DEFINE([SIGNALS_VIA_CHARACTERS], [1])
     ;;
 
   dnl 21 Jun 06: Eric Hanchrow <offby1@blarg.net> says this works.
@@ -5668,35 +5775,41 @@ case $opsys in
 #if LINUX_VERSION_CODE < 0x20400
 # error "Linux version too old"
 #endif
-      ]], [[]])], emacs_cv_signals_via_chars=yes, 
emacs_cv_signals_via_chars=no)])
+      ]], [[]])],
+       [emacs_cv_signals_via_chars=yes],
+       [emacs_cv_signals_via_chars=no])])
 
-    test "$emacs_cv_signals_via_chars" = yes && 
AC_DEFINE(SIGNALS_VIA_CHARACTERS, 1)
+    test "$emacs_cv_signals_via_chars" = yes &&
+      AC_DEFINE([SIGNALS_VIA_CHARACTERS], [1])
     ;;
 esac
 
 
-AH_TEMPLATE(TAB3, [Undocumented.])
+AH_TEMPLATE([TAB3], [Undocumented.])
 
 case $opsys in
-  darwin) AC_DEFINE(TAB3, OXTABS) ;;
+  darwin) AC_DEFINE([TAB3], [OXTABS]) ;;
 
   gnu | dragonfly | freebsd | netbsd | openbsd )
-    AC_DEFINE(TABDLY, OXTABS, [Undocumented.])
-    AC_DEFINE(TAB3, OXTABS)
+    AC_DEFINE([TABDLY], [OXTABS], [Undocumented.])
+    AC_DEFINE([TAB3], [OXTABS])
     ;;
 
   gnu-linux | gnu-kfreebsd )
-    AC_PREPROC_IFELSE([AC_LANG_PROGRAM([[
+    AC_PREPROC_IFELSE(
+      [AC_LANG_PROGRAM(
+        [[
 #ifndef __ia64__
 # error "not ia64"
 #endif
-      ]], [[]])], AC_DEFINE(GC_MARK_SECONDARY_STACK(),
+        ]], [[]])],
+      [AC_DEFINE([GC_MARK_SECONDARY_STACK()],
         [do { extern void *__libc_ia64_register_backing_store_base; 
__builtin_ia64_flushrs (); mark_memory 
(__libc_ia64_register_backing_store_base, __builtin_ia64_bsp ());} while 
(false)],
-        [Mark a secondary stack, like the register stack on the ia64.]), [])
+       [Mark a secondary stack, like the register stack on the ia64.])], [])
     ;;
 
   hpux*)
-    AC_DEFINE(RUN_TIME_REMAP, 1, [Define if emacs.c needs to call
+    AC_DEFINE([RUN_TIME_REMAP], [1], [Define if emacs.c needs to call
       run_time_remap; for HPUX.])
     ;;
 esac
@@ -5704,7 +5817,7 @@ esac
 
 dnl This won't be used automatically yet.  We also need to know, at least,
 dnl that the stack is continuous.
-AH_TEMPLATE(GC_SETJMP_WORKS, [Define if setjmp is known to save all
+AH_TEMPLATE([GC_SETJMP_WORKS], [Define if setjmp is known to save all
   registers relevant for conservative garbage collection in the jmp_buf.])
 
 
@@ -5724,18 +5837,18 @@ case $opsys in
 #else
 # error "setjmp not known to work on this arch"
 #endif
-    ]], [[]])], AC_DEFINE(GC_SETJMP_WORKS, 1))
+    ]], [[]])], [AC_DEFINE([GC_SETJMP_WORKS], [1])])
     ;;
 esac
 
 
 if test x$GCC = xyes; then
    dnl GC_SETJMP_WORKS is nearly always appropriate for GCC.
-   AC_DEFINE(GC_SETJMP_WORKS, 1)
+   AC_DEFINE([GC_SETJMP_WORKS], [1])
 else
   case $opsys in
     aix* | dragonfly | freebsd | netbsd | openbsd | solaris )
-      AC_DEFINE(GC_SETJMP_WORKS, 1)
+      AC_DEFINE([GC_SETJMP_WORKS], [1])
       ;;
   esac
 fi                              dnl GCC?
@@ -5755,7 +5868,7 @@ AC_CACHE_CHECK([for _setjmp], [emacs_cv_func__setjmp],
      [emacs_cv_func__setjmp=yes],
      [emacs_cv_func__setjmp=no])])
 if test $emacs_cv_func__setjmp = yes; then
-  AC_DEFINE([HAVE__SETJMP], 1, [Define to 1 if _setjmp and _longjmp work.])
+  AC_DEFINE([HAVE__SETJMP], [1], [Define to 1 if _setjmp and _longjmp work.])
 fi
 
 # We need to preserve signal mask to handle C stack overflows.
@@ -5770,13 +5883,13 @@ AC_CACHE_CHECK([for sigsetjmp], 
[emacs_cv_func_sigsetjmp],
      [emacs_cv_func_sigsetjmp=yes],
      [emacs_cv_func_sigsetjmp=no])])
 if test $emacs_cv_func_sigsetjmp = yes; then
-  AC_DEFINE([HAVE_SIGSETJMP], 1,
+  AC_DEFINE([HAVE_SIGSETJMP], [1],
     [Define to 1 if sigsetjmp and siglongjmp work.])
 fi
 
 case $emacs_cv_func_sigsetjmp,$emacs_cv_alternate_stack,$opsys in
   yes,yes,* | *,*,mingw32)
-    AC_DEFINE([HAVE_STACK_OVERFLOW_HANDLING], 1,
+    AC_DEFINE([HAVE_STACK_OVERFLOW_HANDLING], [1],
       [Define to 1 if C stack overflow can be handled in some cases.]);;
 esac
 
@@ -5785,7 +5898,7 @@ case $opsys in
     dnl TIOCGPGRP is broken in SysVr4, so we can't send signals to PTY
     dnl subprocesses the usual way.  But TIOCSIGNAL does work for PTYs,
     dnl and this is all we need.
-    AC_DEFINE(TIOCSIGSEND, TIOCSIGNAL, [Some platforms redefine this.])
+    AC_DEFINE([TIOCSIGSEND], [TIOCSIGNAL], [Some platforms redefine this.])
     ;;
 esac
 
@@ -5793,7 +5906,7 @@ esac
 case $opsys in
   hpux* | solaris )
     dnl Used in xfaces.c.
-    AC_DEFINE(XOS_NEEDS_TIME_H, 1, [Compensate for a bug in Xos.h on
+    AC_DEFINE([XOS_NEEDS_TIME_H], [1], [Compensate for a bug in Xos.h on
       some systems, where it requires time.h.])
     ;;
 esac
@@ -5801,64 +5914,67 @@ esac
 
 dnl Define symbols to identify the version of Unix this is.
 dnl Define all the symbols that apply correctly.
-AH_TEMPLATE(DOS_NT, [Define if the system is MS DOS or MS Windows.])
-AH_TEMPLATE(MSDOS, [Define if the system is MS DOS.])
-AH_TEMPLATE(USG, [Define if the system is compatible with System III.])
-AH_TEMPLATE(USG5_4, [Define if the system is compatible with System V Release 
4.])
+AH_TEMPLATE([DOS_NT], [Define if the system is MS DOS or MS Windows.])
+AH_TEMPLATE([MSDOS], [Define if the system is MS DOS.])
+AH_TEMPLATE([USG], [Define if the system is compatible with System III.])
+AH_TEMPLATE([USG5_4],
+  [Define if the system is compatible with System V Release 4.])
 
 case $opsys in
   aix4-2)
-    AC_DEFINE(USG, [])
+    AC_DEFINE([USG], [])
     dnl This symbol should be defined on AIX Version 3  ???????
     AC_PREPROC_IFELSE([AC_LANG_PROGRAM([[
 #ifndef _AIX
 # error "_AIX not defined"
 #endif
-    ]], [[]])], [], AC_DEFINE(_AIX, [], [Define if the system is AIX.]))
+    ]], [[]])], [], [AC_DEFINE([_AIX], [], [Define if the system is AIX.])])
     ;;
 
   cygwin)
-    AC_DEFINE(CYGWIN, 1, [Define if the system is Cygwin.])
+    AC_DEFINE([CYGWIN], [1], [Define if the system is Cygwin.])
     ;;
 
   darwin)
     dnl Not __APPLE__, as this may not be defined on non-macOS Darwin.
     dnl Not DARWIN, because Panther and lower CoreFoundation.h use DARWIN to
     dnl distinguish macOS from pure Darwin.
-    AC_DEFINE(DARWIN_OS, [], [Define if the system is Darwin.])
+    AC_DEFINE([DARWIN_OS], [], [Define if the system is Darwin.])
     ;;
 
   gnu-linux | gnu-kfreebsd )
-    AC_DEFINE(USG, [])
-    AC_DEFINE(GNU_LINUX, [], [Define if ths system is compatible with 
GNU/Linux.])
+    AC_DEFINE([USG], [])
+    AC_DEFINE([GNU_LINUX], [],
+      [Define if ths system is compatible with GNU/Linux.])
     ;;
 
   hpux*)
-    AC_DEFINE(USG, [])
-    AC_DEFINE(HPUX, [], [Define if the system is HPUX.])
+    AC_DEFINE([USG], [])
+    AC_DEFINE([HPUX], [], [Define if the system is HPUX.])
     ;;
 
   mingw32)
-    AC_DEFINE(DOS_NT, [])
-    AC_DEFINE(WINDOWSNT, 1, [Define if compiling for native MS Windows.])
+    AC_DEFINE([DOS_NT], [])
+    AC_DEFINE([WINDOWSNT], [1], [Define if compiling for native MS Windows.])
     if test "x$ac_enable_checking" != "x" ; then
-      AC_DEFINE(EMACSDEBUG, 1, [Define to 1 to enable w32 debug facilities.])
+      AC_DEFINE([EMACSDEBUG], [1],
+       [Define to 1 to enable w32 debug facilities.])
     fi
     ;;
 
   solaris)
-    AC_DEFINE(USG, [])
-    AC_DEFINE(USG5_4, [])
-    AC_DEFINE(SOLARIS2, [], [Define if the system is Solaris.])
+    AC_DEFINE([USG], [])
+    AC_DEFINE([USG5_4], [])
+    AC_DEFINE([SOLARIS2], [], [Define if the system is Solaris.])
     ;;
 
   unixware)
-    AC_DEFINE(USG, [])
-    AC_DEFINE(USG5_4, [])
+    AC_DEFINE([USG], [])
+    AC_DEFINE([USG5_4], [])
     ;;
 
   haiku)
-    AC_DEFINE(HAIKU, [], [Define if the system is Haiku.])
+    AC_DEFINE([HAIKU], [], [Define if the system is Haiku.])
     ;;
 esac
 
@@ -5939,13 +6055,13 @@ case $opsys in
   hpux11)
     dnl It works to open the pty's tty in the parent (Emacs), then
     dnl close and reopen it in the child.
-    AC_DEFINE(USG_SUBTTY_WORKS, 1, [Define for USG systems where it
+    AC_DEFINE([USG_SUBTTY_WORKS], [1], [Define for USG systems where it
       works to open a pty's tty in the parent process, then close and
       reopen it in the child.])
     ;;
 
   solaris)
-    AC_DEFINE(_STRUCTURED_PROC, 1, [Needed for system_process_attributes
+    AC_DEFINE([_STRUCTURED_PROC], [1], [Needed for system_process_attributes
       on Solaris.])
     ;;
 esac
@@ -5968,72 +6084,72 @@ fi
 version=$PACKAGE_VERSION
 
 copyright="Copyright (C) 2022 Free Software Foundation, Inc."
-AC_DEFINE_UNQUOTED(COPYRIGHT, ["$copyright"],
+AC_DEFINE_UNQUOTED([COPYRIGHT], ["$copyright"],
   [Short copyright string for this version of Emacs.])
-AC_SUBST(copyright)
+AC_SUBST([copyright])
 
 ### Specify what sort of things we'll be editing into Makefile and config.h.
 ### Use configuration here uncanonicalized to avoid exceeding size limits.
-AC_SUBST(version)
-AC_SUBST(configuration)
+AC_SUBST([version])
+AC_SUBST([configuration])
 ## Unused?
-AC_SUBST(canonical)
-AC_SUBST(srcdir)
-AC_SUBST(prefix)
-AC_SUBST(exec_prefix)
-AC_SUBST(bindir)
-AC_SUBST(datadir)
-AC_SUBST(gsettingsschemadir)
-AC_SUBST(sharedstatedir)
-AC_SUBST(libexecdir)
-AC_SUBST(mandir)
-AC_SUBST(infodir)
-AC_SUBST(lispdirrel)
-AC_SUBST(lispdir)
-AC_SUBST(standardlisppath)
-AC_SUBST(locallisppath)
-AC_SUBST(lisppath)
-AC_SUBST(x_default_search_path)
-AC_SUBST(etcdir)
-AC_SUBST(archlibdir)
-AC_SUBST(etcdocdir)
-AC_SUBST(bitmapdir)
-AC_SUBST(gamedir)
-AC_SUBST(gameuser)
-AC_SUBST(gamegroup)
+AC_SUBST([canonical])
+AC_SUBST([srcdir])
+AC_SUBST([prefix])
+AC_SUBST([exec_prefix])
+AC_SUBST([bindir])
+AC_SUBST([datadir])
+AC_SUBST([gsettingsschemadir])
+AC_SUBST([sharedstatedir])
+AC_SUBST([libexecdir])
+AC_SUBST([mandir])
+AC_SUBST([infodir])
+AC_SUBST([lispdirrel])
+AC_SUBST([lispdir])
+AC_SUBST([standardlisppath])
+AC_SUBST([locallisppath])
+AC_SUBST([lisppath])
+AC_SUBST([x_default_search_path])
+AC_SUBST([etcdir])
+AC_SUBST([archlibdir])
+AC_SUBST([etcdocdir])
+AC_SUBST([bitmapdir])
+AC_SUBST([gamedir])
+AC_SUBST([gameuser])
+AC_SUBST([gamegroup])
 ## FIXME? Nothing uses @LD_SWITCH_X_SITE@.
 ## src/Makefile.in did add LD_SWITCH_X_SITE (as a cpp define) to the
 ## end of LIBX_BASE, but nothing ever set it.
-AC_SUBST(LD_SWITCH_X_SITE)
-AC_SUBST(C_SWITCH_X_SITE)
-AC_SUBST(GNUSTEP_CFLAGS)
-AC_SUBST(CFLAGS)
+AC_SUBST([LD_SWITCH_X_SITE])
+AC_SUBST([C_SWITCH_X_SITE])
+AC_SUBST([GNUSTEP_CFLAGS])
+AC_SUBST([CFLAGS])
 ## Used in lwlib/Makefile.in.
-AC_SUBST(X_TOOLKIT_TYPE)
-AC_SUBST(ns_appdir)
-AC_SUBST(ns_appbindir)
-AC_SUBST(ns_applibexecdir)
-AC_SUBST(ns_applibdir)
-AC_SUBST(ns_appresdir)
-AC_SUBST(ns_appsrc)
-AC_SUBST(GNU_OBJC_CFLAGS)
-AC_SUBST(OTHER_FILES)
+AC_SUBST([X_TOOLKIT_TYPE])
+AC_SUBST([ns_appdir])
+AC_SUBST([ns_appbindir])
+AC_SUBST([ns_applibexecdir])
+AC_SUBST([ns_applibdir])
+AC_SUBST([ns_appresdir])
+AC_SUBST([ns_appsrc])
+AC_SUBST([GNU_OBJC_CFLAGS])
+AC_SUBST([OTHER_FILES])
 
 if test -n "${term_header}"; then
-    AC_DEFINE_UNQUOTED(TERM_HEADER, "${term_header}",
+    AC_DEFINE_UNQUOTED([TERM_HEADER], ["${term_header}"],
         [Define to the header for the built-in window system.])
 fi
 
-AC_DEFINE_UNQUOTED(EMACS_CONFIGURATION,  "${canonical}",
+AC_DEFINE_UNQUOTED([EMACS_CONFIGURATION],  ["${canonical}"],
                   [Define to the canonical Emacs configuration name.])
-AC_DEFINE_UNQUOTED(EMACS_CONFIG_OPTIONS, "${emacs_config_options}",
+AC_DEFINE_UNQUOTED([EMACS_CONFIG_OPTIONS], "${emacs_config_options}",
                   [Define to the options passed to configure.])
 
 XMENU_OBJ=
 XOBJ=
 FONT_OBJ=
 if test "${HAVE_X_WINDOWS}" = "yes" ; then
-  AC_DEFINE(HAVE_X_WINDOWS, 1,
+  AC_DEFINE([HAVE_X_WINDOWS], [1],
            [Define to 1 if you want to use the X window system.])
   XMENU_OBJ=xmenu.o
   XOBJ="xterm.o xfns.o xselect.o xrdb.o xsmfns.o xsettings.o"
@@ -6060,20 +6176,20 @@ fi
 if test "${HAVE_HARFBUZZ}" = "yes" ; then
   FONT_OBJ="$FONT_OBJ hbfont.o"
 fi
-AC_SUBST(FONT_OBJ)
-AC_SUBST(XMENU_OBJ)
-AC_SUBST(XOBJ)
-AC_SUBST(FONT_OBJ)
+AC_SUBST([FONT_OBJ])
+AC_SUBST([XMENU_OBJ])
+AC_SUBST([XOBJ])
+AC_SUBST([FONT_OBJ])
 
 WIDGET_OBJ=
 MOTIF_LIBW=
 if test "${USE_X_TOOLKIT}" != "none" ; then
   WIDGET_OBJ=widget.o
-  AC_DEFINE(USE_X_TOOLKIT, 1, [Define to 1 if using an X toolkit.])
+  AC_DEFINE([USE_X_TOOLKIT], [1], [Define to 1 if using an X toolkit.])
   if test "${USE_X_TOOLKIT}" = "LUCID"; then
-    AC_DEFINE(USE_LUCID, 1, [Define to 1 if using the Lucid X toolkit.])
+    AC_DEFINE([USE_LUCID], [1], [Define to 1 if using the Lucid X toolkit.])
   elif test "${USE_X_TOOLKIT}" = "MOTIF"; then
-    AC_DEFINE(USE_MOTIF, 1, [Define to 1 if using the Motif X toolkit.])
+    AC_DEFINE([USE_MOTIF], [1], [Define to 1 if using the Motif X toolkit.])
     MOTIF_LIBW=-lXm
     case "$opsys" in
       gnu-linux)
@@ -6095,7 +6211,7 @@ if test "${USE_X_TOOLKIT}" != "none" ; then
     MOTIF_LIBW="$MOTIF_LIBW $LIBXP"
   fi
 fi
-AC_SUBST(WIDGET_OBJ)
+AC_SUBST([WIDGET_OBJ])
 
 TOOLKIT_LIBW=
 case "$USE_X_TOOLKIT" in
@@ -6106,7 +6222,7 @@ esac
 if test "$HAVE_XWIDGETS" = "yes"; then
   TOOLKIT_LIBW="$TOOLKIT_LIBW -lXcomposite"
 fi
-AC_SUBST(TOOLKIT_LIBW)
+AC_SUBST([TOOLKIT_LIBW])
 
 if test "${opsys}" != "mingw32"; then
   if test "$USE_X_TOOLKIT" = "none"; then
@@ -6115,16 +6231,16 @@ if test "${opsys}" != "mingw32"; then
     LIBXT_OTHER="\$(LIBXMU) -lXt \$(LIBXTR6) -lXext"
   fi
 fi
-AC_SUBST(LIBXT_OTHER)
+AC_SUBST([LIBXT_OTHER])
 
 if test "${HAVE_X11}" = "yes" ; then
-  AC_DEFINE(HAVE_X11, 1,
+  AC_DEFINE([HAVE_X11], [1],
            [Define to 1 if you want to use version 11 of X windows.])
   LIBX_OTHER="\$(LIBXT) \$(LIBX_EXTRA)"
 else
   LIBX_OTHER=
 fi
-AC_SUBST(LIBX_OTHER)
+AC_SUBST([LIBX_OTHER])
 
 HAVE_OLDXMENU=no
 if test "$HAVE_GTK" = yes || test "$HAVE_X11" != yes; then
@@ -6137,7 +6253,7 @@ else
   LIBXMENU='$(lwlibdir)/liblw.a'
   AUTODEPEND_PARENTS="$AUTODEPEND_PARENTS lwlib"
 fi
-AC_SUBST(LIBXMENU)
+AC_SUBST([LIBXMENU])
 
 AC_CACHE_CHECK([for struct alignment],
   [emacs_cv_struct_alignment],
@@ -6150,7 +6266,7 @@ AC_CACHE_CHECK([for struct alignment],
      [emacs_cv_struct_alignment=yes],
      [emacs_cv_struct_alignment=no])])
 if test "$emacs_cv_struct_alignment" = yes; then
-  AC_DEFINE([HAVE_STRUCT_ATTRIBUTE_ALIGNED], 1,
+  AC_DEFINE([HAVE_STRUCT_ATTRIBUTE_ALIGNED], [1],
     [Define to 1 if 'struct __attribute__ ((aligned (N)))' aligns the
      structure to an N-byte boundary.])
 fi
@@ -6164,24 +6280,24 @@ AC_CACHE_CHECK([for statement expressions],
      [emacs_cv_statement_expressions=yes],
      [emacs_cv_statement_expressions=no])])
 if test "$emacs_cv_statement_expressions" = yes; then
-  AC_DEFINE([HAVE_STATEMENT_EXPRESSIONS], 1,
+  AC_DEFINE([HAVE_STATEMENT_EXPRESSIONS], [1],
     [Define to 1 if statement expressions work.])
 fi
 
 if test "${GNU_MALLOC}" = "yes" ; then
-  AC_DEFINE(GNU_MALLOC, 1,
+  AC_DEFINE([GNU_MALLOC], [1],
            [Define to 1 if you want to use the GNU memory allocator.])
 fi
 
 RALLOC_OBJ=
 if test "${REL_ALLOC}" = "yes" ; then
-  AC_DEFINE(REL_ALLOC, 1,
+  AC_DEFINE([REL_ALLOC], [1],
            [Define REL_ALLOC if you want to use the relocating allocator for
             buffer space.])
 
   test "$system_malloc" != "yes" && RALLOC_OBJ=ralloc.o
 fi
-AC_SUBST(RALLOC_OBJ)
+AC_SUBST([RALLOC_OBJ])
 
 if test "$opsys" = "cygwin"; then
   CYGWIN_OBJ="cygw32.o"
@@ -6197,9 +6313,9 @@ else
   PRE_ALLOC_OBJ=lastfile.o
   POST_ALLOC_OBJ=
 fi
-AC_SUBST(CYGWIN_OBJ)
-AC_SUBST(PRE_ALLOC_OBJ)
-AC_SUBST(POST_ALLOC_OBJ)
+AC_SUBST([CYGWIN_OBJ])
+AC_SUBST([PRE_ALLOC_OBJ])
+AC_SUBST([POST_ALLOC_OBJ])
 
 dnl Call this 'FORTIFY_SOUR' so that it sorts before the 'FORTIFY_SOURCE'
 dnl verbatim defined above.  The tricky name is apropos, as this hack
@@ -6247,7 +6363,7 @@ LIBS=$SAVE_LIBS
 # timer_getoverrun needs the same library as timer_settime
 OLD_LIBS=$LIBS
 LIBS="$LIB_TIMER_TIME $LIBS"
-AC_CHECK_FUNCS(timer_getoverrun)
+AC_CHECK_FUNCS([timer_getoverrun])
 LIBS=$OLD_LIBS
 
 if test "${opsys}" = "mingw32"; then
@@ -6361,16 +6477,17 @@ fi
 
 LD_SWITCH_SYSTEM_TEMACS="$LDFLAGS_NOCOMBRELOC $LD_SWITCH_SYSTEM_TEMACS"
 
-AC_SUBST(LD_SWITCH_SYSTEM_TEMACS)
+AC_SUBST([LD_SWITCH_SYSTEM_TEMACS])
 
 ## Common for all window systems
 if test "$window_system" != "none"; then
-  AC_DEFINE(HAVE_WINDOW_SYSTEM, 1, [Define if you have a window system.])
-  AC_DEFINE(POLL_FOR_INPUT, 1, [Define if you poll periodically to detect 
C-g.])
+  AC_DEFINE([HAVE_WINDOW_SYSTEM], [1], [Define if you have a window system.])
+  AC_DEFINE([POLL_FOR_INPUT], [1],
+    [Define if you poll periodically to detect C-g.])
   WINDOW_SYSTEM_OBJ="fontset.o fringe.o image.o"
 fi
 
-AC_SUBST(WINDOW_SYSTEM_OBJ)
+AC_SUBST([WINDOW_SYSTEM_OBJ])
 
 AH_TOP([/* GNU Emacs site configuration template file.
 
@@ -6487,7 +6604,7 @@ for opt in ACL BE_APP CAIRO DBUS FREETYPE GCONF GIF GLIB 
GMP GNUTLS GPM GSETTING
     AS_VAR_APPEND([emacs_config_features], ["$optsep$opt"])
     optsep=' '
 done
-AC_DEFINE_UNQUOTED(EMACS_CONFIG_FEATURES, "${emacs_config_features}",
+AC_DEFINE_UNQUOTED([EMACS_CONFIG_FEATURES], ["${emacs_config_features}"],
   [Summary of some of the main features enabled by configure.])
 
 AS_ECHO(["  Does Emacs use -lXaw3d?                                 
${HAVE_XAW3D}
@@ -6531,7 +6648,7 @@ AS_ECHO(["  Does Emacs use -lXaw3d?                       
          ${HAVE_XAW3D
   Does Emacs support legacy unexec dumping?               ${with_unexec}
   Which dumping strategy does Emacs use?                  ${with_dumping}
   Does Emacs have native lisp compiler?                   ${HAVE_NATIVE_COMP}
-  Does Emacs use version 2 of the the X Input Extension?  ${HAVE_XINPUT2}
+  Does Emacs use version 2 of the X Input Extension?      ${HAVE_XINPUT2}
   Does Emacs generate a smaller-size Japanese dictionary? ${with_small_ja_dic}
 "])
 
@@ -6566,7 +6683,7 @@ case $opsys,$emacs_uname_r in
            echo
           ;;
   cygwin,3.0.[[0-7]]'('* | cygwin,3.1.[[0-2]]'('*)
-    AC_DEFINE([HAVE_CYGWIN_O_PATH_BUG], 1,
+    AC_DEFINE([HAVE_CYGWIN_O_PATH_BUG], [1],
       [Define to 1 if opening a FIFO, socket, or symlink with O_PATH is 
buggy.]);;
 esac
 
@@ -6588,7 +6705,7 @@ if test "$HAVE_NS" = "yes"; then
       
nextstep/Cocoa/Emacs.base/Contents/Resources/English.lproj/InfoPlist.strings:nextstep/templates/InfoPlist.strings.in])
     ns_check_file=Contents/Info.plist
   fi
-  AC_SUBST(ns_check_file)
+  AC_SUBST([ns_check_file])
 fi
 
 AC_CONFIG_FILES([Makefile lib/gnulib.mk])
@@ -6629,10 +6746,10 @@ fi                              dnl -d admin
 
 SUBDIR_MAKEFILES_IN=`echo " ${SUBDIR_MAKEFILES}" | sed -e 's| | $(srcdir)/|g' 
-e 's|Makefile|Makefile.in|g'`
 
-AC_SUBST(SUBDIR_MAKEFILES_IN)
+AC_SUBST([SUBDIR_MAKEFILES_IN])
 
 SMALL_JA_DIC=$with_small_ja_dic
-AC_SUBST(SMALL_JA_DIC)
+AC_SUBST([SMALL_JA_DIC])
 
 dnl You might wonder (I did) why epaths.h is generated by running make,
 dnl rather than just letting configure generate it from epaths.in.
diff --git a/doc/emacs/ChangeLog.1 b/doc/emacs/ChangeLog.1
index c1c5f5407d..048b7bd99a 100644
--- a/doc/emacs/ChangeLog.1
+++ b/doc/emacs/ChangeLog.1
@@ -8529,7 +8529,7 @@
        * text.texi (Cell Justification):
        * trouble.texi (After a Crash):
        * xresources.texi (GTK styles):
-       Delete duplicate duplicate words.
+       Delete duplicate words.
 
 2005-07-17  Richard M. Stallman  <rms@gnu.org>
 
diff --git a/doc/emacs/abbrevs.texi b/doc/emacs/abbrevs.texi
index 07f66ec10a..77f40c7df2 100644
--- a/doc/emacs/abbrevs.texi
+++ b/doc/emacs/abbrevs.texi
@@ -106,8 +106,10 @@ taken as the expansion.  For example, to define the abbrev 
@samp{foo} as
 mentioned above, insert the text @samp{find outer otter} and then type
 @kbd{C-u 3 C-x a g f o o @key{RET}}.
 
-  An argument of zero to @kbd{C-x a g} means to use the contents of the
-region as the expansion of the abbrev being defined.
+  If you're using @code{transient-mark-mode} (which is the default),
+the active region will be used as the expansion of the abbrev being
+defined.  If not, an argument of zero to @kbd{C-x a g} means to use
+the contents of the region.
 
 @kindex C-x a l
 @findex add-mode-abbrev
diff --git a/doc/emacs/buffers.texi b/doc/emacs/buffers.texi
index 94e9d2760e..120c957ff8 100644
--- a/doc/emacs/buffers.texi
+++ b/doc/emacs/buffers.texi
@@ -616,10 +616,11 @@ select it in another window 
(@code{clone-indirect-buffer-other-window}).
 
   The text of the indirect buffer is always identical to the text of its
 base buffer; changes made by editing either one are visible immediately
-in the other.  But in all other respects, the indirect buffer and its
+in the other.  ``Text'' here includes both the characters and their text
+properties.  But in all other respects, the indirect buffer and its
 base buffer are completely separate.  They can have different names,
 different values of point, different narrowing, different markers,
-different major modes, and different local variables.
+different overlays, different major modes, and different local variables.
 
   An indirect buffer cannot visit a file, but its base buffer can.  If
 you try to save the indirect buffer, that actually works by saving the
@@ -649,6 +650,14 @@ both using the minibuffer.
 When this hook runs, the newly created indirect buffer is the current
 buffer.
 
+Note: When a modification is made to the text of a buffer, the
+modification hooks are run only in the base buffer, because most of
+the functions on those hooks are not prepared to work correctly in
+indirect buffers.  So if you need a modification hook function in an
+indirect buffer, you need to manually add that function to the hook
+@emph{in the base buffer} and then make the function operate in the
+desired indirect buffer.
+
 @node Buffer Convenience
 @section Convenience Features and Customization of Buffer Handling
 
diff --git a/doc/emacs/custom.texi b/doc/emacs/custom.texi
index 46a2291b74..ff7ab83190 100644
--- a/doc/emacs/custom.texi
+++ b/doc/emacs/custom.texi
@@ -511,6 +511,9 @@ Set up a customization buffer for just one user option, 
@var{option}.
 @item M-x customize-face @key{RET} @var{face} @key{RET}
 Set up a customization buffer for just one face, @var{face}.
 
+@item M-x customize-icon @key{RET} @var{face} @key{RET}
+Set up a customization buffer for just one icon, @var{icon}.
+
 @item M-x customize-group @key{RET} @var{group} @key{RET}
 Set up a customization buffer for just one group, @var{group}.
 
@@ -2300,6 +2303,8 @@ as a function from Lisp programs.
 @cindex startup (init file)
 @cindex XDG_CONFIG_HOME
 
+@c When updating this, also update ``Setting up a customization file''
+@c in efaq.texi.
   When Emacs is started, it normally tries to load a Lisp program from
 an @dfn{initialization file}, or @dfn{init file} for short.  This
 file, if it exists, specifies how to initialize Emacs for you.
@@ -2449,6 +2454,9 @@ keys which send non-@acronym{ASCII} characters.
 Write a single-quote (@code{'}) followed by the Lisp object you want.
 @end table
 
+  For more information on the Emacs Lisp syntax, @pxref{Introduction,,,
+elisp, The Emacs Lisp Reference Manual}.
+
 @node Init Examples
 @subsection Init File Examples
 
diff --git a/doc/emacs/dired.texi b/doc/emacs/dired.texi
index 9e14e0f9a9..33e9270d42 100644
--- a/doc/emacs/dired.texi
+++ b/doc/emacs/dired.texi
@@ -41,6 +41,7 @@ you to operate on the listed files.  @xref{Directories}.
 * Operating on Files::        How to copy, rename, print, compress, etc.
                                 either one file or several files.
 * Shell Commands in Dired::   Running a shell command on the marked files.
+* Shell Command Guessing::    Guessing shell commands for files.
 * Transforming File Names::   Using patterns to rename multiple files.
 * Comparison in Dired::       Running @code{diff} by way of Dired.
 * Subdirectories in Dired::   Adding subdirectories to the Dired buffer.
@@ -844,6 +845,26 @@ This is like @samp{ln -s}.  The argument @var{new} is the 
directory to
 make the links in, or (if making just one link) the name to give the
 link.
 
+@findex dired-do-relsymlink
+@kindex Y @r{(Dired)}
+@item Y @var{new} @key{RET}
+Make relative symbolic links to the specified files
+(@code{dired-do-relsymlink}).  The argument @var{new} is the directory
+to make the links in, or (if making just one link) the name to give
+the link.  This is like @code{dired-do-symlink} but creates relative
+symbolic links.  For example:
+
+@example
+    foo -> ../bar/foo
+@end example
+
+@noindent
+It does not create absolute ones like:
+
+@example
+    foo -> /path/that/may/change/any/day/bar/foo
+@end example
+
 @findex dired-do-chmod
 @kindex M @r{(Dired)}
 @cindex changing file permissions (in Dired)
@@ -963,6 +984,18 @@ Byte compile the specified Emacs Lisp files
 (@code{dired-do-byte-compile}).  @xref{Byte Compilation,, Byte
 Compilation, elisp, The Emacs Lisp Reference Manual}.
 
+@findex dired-do-info
+@kindex I @r{(Dired)}
+@cindex running info on files (in Dired)
+@item I
+Run Info on this file (assumed to be a file in Info format).
+
+@findex dired-do-man
+@kindex N @r{(Dired)}
+@cindex running man on files (in Dired)
+@item N
+Run man on this file (assumed to be a file in @code{nroff} format).
+
 @kindex A @r{(Dired)}
 @findex dired-do-find-regexp
 @cindex search multiple files (in Dired)
@@ -1089,6 +1122,73 @@ buffer (@pxref{Dired Updating}).
   @xref{Single Shell}, for information about running shell commands
 outside Dired.
 
+@node Shell Command Guessing
+@section Shell Command Guessing
+@cindex guessing shell commands for files (in Dired)
+
+Based upon the name of a file, Dired tries to guess what shell command
+you might want to apply to it.  For example, if you have point on a
+file named @file{foo.tar} and you press @kbd{!}, Dired will guess that
+you want to run @samp{tar xvf}, and suggest that as the default shell
+command.
+
+You can type @kbd{M-n} to get the default into the minibuffer for
+editing.  If there are several commands for a given file, type
+@kbd{M-n} several times to see each matching command in order.
+
+Dired only tries to guess a command for a single file, never for a
+list of marked files.
+
+@defvar dired-guess-shell-alist-default
+This variable specifies the predefined rules for guessing shell
+commands suitable for certain files.  Set this to @code{nil} to turn
+guessing off.  The elements of @code{dired-guess-shell-alist-user}
+(defined by the user) will override these rules.
+@end defvar
+
+@defvar dired-guess-shell-alist-user
+If non-@code{nil}, this variable specifies the user-defined alist of
+file regexps and their suggested commands.  These rules take
+precedence over the predefined rules in the variable
+@code{dired-guess-shell-alist-default} when
+@code{dired-do-shell-command} is run).  The default is @code{nil}.
+
+Each element of the alist looks like
+
+@example
+(@var{regexp} @var{command}@dots{})
+@end example
+
+@noindent
+where each @var{command} can either be a string or a Lisp expression
+that evaluates to a string.  If several commands are given, all of
+them will temporarily be pushed onto the history.
+
+A @samp{*} in the shell command stands for the file name that matched
+@var{regexp}.  When Emacs invokes the @var{command}, it replaces each
+instance of @samp{*} with the matched file name.
+
+To add rules for @samp{.foo} and @samp{.bar} file extensions, add this
+to your Init file:
+
+@example
+(setq dired-guess-shell-alist-user
+      (list
+       (list "\\.foo$" "@var{foo-command}")  ; fixed rule
+       ;; possibly more rules...
+       (list "\\.bar$"  ; rule with condition test
+             '(if @var{condition}
+                  "@var{bar-command-1}"
+                "@var{bar-command-2}"))))
+@end example
+
+@noindent
+This will override any predefined rules for the same extensions.
+@end defvar
+
+You can find more user options with @kbd{M-x customize-group @key{RET}
+dired-guess @key{RET}}.
+
 @node Transforming File Names
 @section Transforming File Names in Dired
 
@@ -1138,9 +1238,12 @@ Rename each of the selected files to a lower-case name
 @itemx % S @var{from} @key{RET} @var{to} @key{RET}
 @kindex % S @r{(Dired)}
 @findex dired-do-symlink-regexp
-These four commands rename, copy, make hard links and make soft links,
-in each case computing the new name by regular-expression substitution
-from the name of the old file.
+@itemx % Y @var{from} @key{RET} @var{to} @key{RET}
+@kindex % Y @r{(Dired)}
+@findex dired-do-relsymlink-regexp
+These five commands rename, copy, make hard links, make soft links,
+and make relative soft links, in each case computing the new name by
+regular-expression substitution from the name of the old file.
 @end table
 
   The four regular-expression substitution commands effectively
@@ -1298,6 +1401,12 @@ parent directory.
 @kindex > @r{(Dired)}
 @item >
 Move down to the next directory-file line (@code{dired-next-dirline}).
+
+@findex dired-goto-subdir
+@kindex M-G @r{(Dired)}
+@item M-G
+Prompt for a directory and move to its directory-file line
+(@code{dired-goto-subdir}).
 @end table
 
 @node Hiding Subdirectories
diff --git a/doc/emacs/display.texi b/doc/emacs/display.texi
index 16d6d5567e..b7c8825efa 100644
--- a/doc/emacs/display.texi
+++ b/doc/emacs/display.texi
@@ -24,6 +24,7 @@ the text is displayed.
 * Faces::                  How to change the display style using faces.
 * Colors::                 Specifying colors for faces.
 * Standard Faces::         The main predefined faces.
+* Icons::                  How to change how icons look.
 * Text Scale::             Increasing or decreasing text size in a buffer.
 * Font Lock::              Minor mode for syntactic highlighting using faces.
 * Highlight Interactively:: Tell Emacs what text to highlight.
@@ -851,10 +852,44 @@ This face is used to display on text-mode terminals the 
menu item that
 would be selected if you click a mouse or press @key{RET}.
 @end table
 
+@node Icons
+@section Icons
+@cindex icons, on clickable buttons
+
+Emacs sometimes displays clickable buttons (or other informative
+icons), and you can customize how these look on display.
+
+@vindex icon-preference
+The main customization point here is the @code{icon-preference} user
+option.  By using this, you can tell Emacs your overall preferences
+for icons.  This is a list of icon types, and the first icon type
+that's supported will be used.  The supported types are:
+
+@table @code
+@item image
+Use an image for the icon.
+
+@item emoji
+Use a colorful emoji for the icon.
+
+@item symbol
+Use a monochrome symbol for the icon.
+
+@item text
+Use a simple text for the icon.
+@end table
+
+In addition, each individual icon can be customized with @kbd{M-x
+customize-icon}, and themes can further alter the looks of the icons.
+
+To get a quick description of an icon, use the @kbd{M-x describe-icon}
+command.
+
 @node Text Scale
 @section Text Scale
 
-@cindex adjust buffer face height
+@cindex adjust buffer font size
+@cindex font size of @code{default} face, increase or decrease
 @findex text-scale-adjust
 @kindex C-x C-+
 @kindex C-x C--
@@ -862,17 +897,27 @@ would be selected if you click a mouse or press @key{RET}.
 @kindex C-x C-0
 @kindex C-wheel-down
 @kindex C-wheel-up
-  To increase the height of the default face in the current buffer,
-type @kbd{C-x C-+} or @kbd{C-x C-=}.  To decrease it, type @kbd{C-x
-C--}.  To restore the default (global) face height, type @kbd{C-x
-C-0}.  These keys are all bound to the same command,
+  To increase the font size of the @code{default} face in the current
+buffer, type @kbd{C-x C-+} or @kbd{C-x C-=}.  To decrease it, type
+@kbd{C-x C--}.  To restore the default (global) font size, type
+@kbd{C-x C-0}.  These keys are all bound to the same command,
 @code{text-scale-adjust}, which looks at the last key typed to
-determine which action to take.
+determine which action to take and adjusts the font size accordingly
+by changing the height of the default face.
+
+  Most faces don't have an explicit setting of the @code{:height}
+attribute, and thus inherit the height from the @code{default} face.
+Those faces are also scaled by the above commands.
+
+  Faces other than @code{default} that have an explicit setting of the
+@code{:height} attribute are not affected by these font size changes.
+The @code{header-line} face is an exception: it will be scaled even if
+it has an explicit setting of the @code{:height} attribute.
 
   Similarly, scrolling the mouse wheel with the @kbd{Ctrl} modifier
 pressed, when the mouse pointer is above buffer text, will increase or
-decrease the height of the default face, depending on the direction of
-the scrolling.
+decrease the font size of the affected faces, depending on the
+direction of the scrolling.
 
   The final key of these commands may be repeated without the leading
 @kbd{C-x}.  For instance, @kbd{C-x C-= C-= C-=} increases the face
@@ -882,21 +927,37 @@ of 1.2; to change this factor, customize the variable
 to the @code{text-scale-adjust} command restores the default height,
 the same as typing @kbd{C-x C-0}.
 
-@cindex increase buffer face height
+@cindex adjust global font size
+@findex global-text-scale-adjust
+@vindex global-text-scale-adjust-resizes-frames
+@kindex C-x C-M-+
+@kindex C-x C-M-=
+@kindex C-x C-M--
+@kindex C-x C-M-0
+@kindex C-M-wheel-down
+@kindex C-M-wheel-up
+  Similarly, to change the sizes of the fonts globally, type @kbd{C-x
+C-M-+}, @kbd{C-x C-M-=}, @kbd{C-x C-M--} or @kbd{C-x C-M-0}, or scroll
+the mouse wheel with both the @kbd{Ctrl} and @kbd{Meta} modifiers
+pressed.  To enable frame resizing when the font size is changed
+globally, customize the variable
+@code{global-text-scale-adjust-resizes-frames} (@pxref{Easy
+Customization}).
+
+@cindex increase buffer font size
 @findex text-scale-increase
-@cindex decrease buffer face height
+@cindex decrease buffer font size
 @findex text-scale-decrease
   The commands @code{text-scale-increase} and
-@code{text-scale-decrease} increase or decrease the height of the
-default face, just like @kbd{C-x C-+} and @kbd{C-x C--} respectively.
-You may find it convenient to bind to these commands, rather than
-@code{text-scale-adjust}.
+@code{text-scale-decrease} increase or decrease the size of the font
+in the current buffer, just like @kbd{C-x C-+} and @kbd{C-x C--}
+respectively.  You may find it convenient to bind to these commands,
+rather than @code{text-scale-adjust}.
 
-@cindex set buffer face height
+@cindex set buffer font size
 @findex text-scale-set
-  The command @code{text-scale-set} scales the height of the default
-face in the current buffer to an absolute level specified by its
-prefix argument.
+  The command @code{text-scale-set} scales the size of the font in the
+current buffer to an absolute level specified by its prefix argument.
 
 @findex text-scale-mode
   The above commands automatically enable the minor mode
diff --git a/doc/emacs/emacs.texi b/doc/emacs/emacs.texi
index ad0fa5f0cd..b43c966f87 100644
--- a/doc/emacs/emacs.texi
+++ b/doc/emacs/emacs.texi
@@ -1183,7 +1183,6 @@ The Emacs Initialization File
 
 Dealing with Emacs Trouble
 
-* DEL Does Not Delete:: What to do if @key{DEL} doesn't delete.
 * Stuck Recursive::     '[...]' in mode line around the parentheses.
 * Screen Garbled::      Garbage on the screen.
 * Text Garbled::        Garbage in the text.
@@ -1191,7 +1190,7 @@ Dealing with Emacs Trouble
 * Crashing::            What Emacs does when it crashes.
 * After a Crash::       Recovering editing in an Emacs session that crashed.
 * Emergency Escape::    What to do if Emacs stops responding.
-* Long Lines::          Mitigating slowness due to extremely long lines.
+* DEL Does Not Delete:: What to do if @key{DEL} doesn't delete.
 
 Reporting Bugs
 
diff --git a/doc/emacs/files.texi b/doc/emacs/files.texi
index 062185fb4a..5b3b15cd38 100644
--- a/doc/emacs/files.texi
+++ b/doc/emacs/files.texi
@@ -420,6 +420,9 @@ With prefix argument (@kbd{C-u}), mark the current buffer 
as changed.
 Save the current buffer with a specified file name (@code{write-file}).
 @item M-x set-visited-file-name
 Change the file name under which the current buffer will be saved.
+@item M-x rename-visited-file
+The same as @kbd{M-x set-visited-file-name}, but also rename the file
+the buffer is visiting (if any).
 @end table
 
 @kindex C-x C-s
@@ -652,10 +655,10 @@ Never make numbered backups; always make single backups.
 The usual way to set this variable is globally, through your init file
 or the customization buffer.  However, you can set
 @code{version-control} locally in an individual buffer to control the
-making of backups for that buffer's file (@pxref{Locals}).  You can
-have Emacs set @code{version-control} locally whenever you visit a
-given file (@pxref{File Variables}).  Some modes, such as Rmail mode,
-set this variable.
+making of backups for that buffer's file (@pxref{Locals}).  Some
+modes, such as Rmail mode, set this variable.  You can also have Emacs
+set @code{version-control} locally whenever you visit a given file
+(@pxref{File Variables}).
 
 @cindex @env{VERSION_CONTROL} environment variable
   If you set the environment variable @env{VERSION_CONTROL}, to tell
@@ -2222,13 +2225,16 @@ recently-opened files, reading file names from a buffer.
 
 @findex recentf-mode
 @vindex recentf-mode
+@findex recentf-open
 @findex recentf-save-list
 @findex recentf-edit-list
-  If you enable Recentf mode, with @kbd{M-x recentf-mode}, the
-@samp{File} menu includes a submenu containing a list of recently
-opened files.  @kbd{M-x recentf-save-list} saves the current
-@code{recentf-list} to a file, and @kbd{M-x recentf-edit-list} edits
-it.
+  If you enable Recentf mode, with @kbd{M-x recentf-mode}, Emacs
+maintains a list of recently opened files.  To open a file from this
+list, use the @kbd{M-x recentf-open} command.  When this mode is
+enabled, the @samp{File} menu will include a submenu that you can use
+to visit one of these files.  @kbd{M-x recentf-save-list} saves the
+current @code{recentf-list} to a file, and @kbd{M-x recentf-edit-list}
+edits it.
 
 @c FIXME partial-completion-mode (complete.el) is obsolete.
   The @kbd{M-x ffap} command generalizes @code{find-file} with more
@@ -2267,12 +2273,14 @@ behavior by using the options @code{image-auto-resize} 
and
 @findex image-transform-set-scale
 @findex image-transform-reset
 To resize the image manually you can use the command
-@code{image-transform-fit-to-window} bound to @kbd{s w}
-that fits the image to both the window height and width.
-To scale the image specifying a scale factor, use the command
-@code{image-transform-set-scale} bound to @kbd{s s}.
-To reset all transformations to the initial state, use
-@code{image-transform-reset} bound to @kbd{s 0}.
+@code{image-transform-fit-to-window} bound to @kbd{s w} that fits the
+image to both the window height and width.  To scale the image to a
+percentage of its original size, use the command
+@code{image-transform-set-percent} bound to @kbd{s p}.  To scale
+the image specifying a scale factor, use the command
+@code{image-transform-set-scale} bound to @kbd{s s}.  To reset all
+transformations to the initial state, use @code{image-transform-reset}
+bound to @kbd{s 0}.
 
 @findex image-next-file
 @findex image-previous-file
@@ -2349,6 +2357,29 @@ can be used to transform the image in question to 
@acronym{PNG} before
 displaying.  GraphicsMagick, ImageMagick and @command{ffmpeg} are
 currently supported for image conversions.
 
+@findex image-converter-add-handler
+  In addition, you may wish to add special handlers for certain image
+formats.  These can be added with the
+@code{image-converter-add-handler} function.  For instance, to allow
+viewing Krita files as simple images, you could say something like:
+
+@lisp
+(image-converter-add-handler
+ "kra"
+ (lambda (file data-p)
+   (if data-p
+       (error "Can't decode non-files")
+     (call-process "unzip" nil t nil
+                   "-qq" "-c" "-x" file "mergedimage.png"))))
+@end lisp
+
+The function takes two parameters, where the first is a file name
+suffix, and the second is a function to do the ``conversion''.  This
+function takes two parameters, where the first is the file name or a
+string with the data, and the second says whether the first parameter
+is data or not, and should output an image in
+@code{image-convert-to-format} format in the current buffer.
+
 @findex thumbs-mode
 @cindex mode, Thumbs
   The Image-Dired package can also be used to view images as
diff --git a/doc/emacs/frames.texi b/doc/emacs/frames.texi
index fa248c1a58..d78cbffaa7 100644
--- a/doc/emacs/frames.texi
+++ b/doc/emacs/frames.texi
@@ -223,8 +223,8 @@ mouse-wheel-mode}.  The variables 
@code{mouse-wheel-follow-mouse} and
 buffers are scrolled.  The variable
 @code{mouse-wheel-progressive-speed} determines whether the scroll
 speed is linked to how fast you move the wheel.  This mode also
-supports increasing or decreasing the height of the default face, by
-default bound to scrolling with the @key{Ctrl} modifier.
+supports increasing or decreasing the font size, by default bound to
+scrolling with the @key{Ctrl} modifier.
 
 @vindex mouse-wheel-scroll-amount-horizontal
 Emacs also supports horizontal scrolling with the @key{Shift}
@@ -1249,6 +1249,13 @@ To drag text from Emacs to other programs, set the option
 @code{mouse-drag-and-drop-region-cross-program} to a non-@code{nil}
 value.
 
+  On the X window system, some programs can drop files on Emacs,
+expecting Emacs to save them.  Normally, Emacs will prompt for a file
+name under which the file will be saved, and then open the file, but
+that behavior can be changed by changing the variable
+@code{x-dnd-direct-save-function}.  @xref{Drag and Drop,,, elisp, The
+Emacs Lisp Reference Manual}.
+
 @node Menu Bars
 @section Menu Bars
 @cindex menu bar mode
diff --git a/doc/emacs/glossary.texi b/doc/emacs/glossary.texi
index a78a2c9e2d..9a53701997 100644
--- a/doc/emacs/glossary.texi
+++ b/doc/emacs/glossary.texi
@@ -182,6 +182,7 @@ corresponding Control character.  @xref{User Input,C-M-}.
 Case conversion means changing text from upper case to lower case or
 vice versa.  @xref{Case}.
 
+@cindex ignore case
 @item Case Folding
 Case folding means ignoring the differences between case variants of
 the same letter: upper-case, lower-case, and title-case.  Emacs
@@ -1456,8 +1457,8 @@ level by aborting (q.v.@:) and quitting (q.v.).  
@xref{Quitting}.
 @item Transient Mark Mode
 The default behavior of the mark (q.v.@:) and region (q.v.), in which
 setting the mark activates it and highlights the region, is called
-Transient Mark mode.  In GNU Emacs 23 and onwards, it is enabled by
-default.  @xref{Disabled Transient Mark}.
+Transient Mark mode.  It is enabled by default.  @xref{Disabled
+Transient Mark}.
 
 @item Transposition
 Transposing two units of text means putting each one into the place
diff --git a/doc/emacs/help.texi b/doc/emacs/help.texi
index 11ee9dc2b2..d206dee385 100644
--- a/doc/emacs/help.texi
+++ b/doc/emacs/help.texi
@@ -542,6 +542,11 @@ previous hyperlink.  These commands act cyclically; for 
instance,
 typing @key{TAB} at the last hyperlink moves back to the first
 hyperlink.
 
+@vindex help-clean-buttons
+  By default, many links in the help buffer are displayed surrounded
+by quote characters.  If the @code{help-clean-buttons} user option is
+non-@code{nil}, these quote characters are removed from the buffer.
+
 @kindex n @r{(Help mode)}
 @kindex p @r{(Help mode)}
 @findex help-goto-next-page
diff --git a/doc/emacs/killing.texi b/doc/emacs/killing.texi
index 4435f6e494..bb8d51158a 100644
--- a/doc/emacs/killing.texi
+++ b/doc/emacs/killing.texi
@@ -610,14 +610,14 @@ yanks the contents of the clipboard at point.
 @cindex primary selection
 @cindex selection, primary
 
-  Under the X Window System, there exists a @dfn{primary selection}
-containing the last stretch of text selected in an X application
-(usually by dragging the mouse).  Typically, this text can be inserted
-into other X applications by @kbd{mouse-2} clicks.  The primary
-selection is separate from the clipboard.  Its contents are more
-fragile; they are overwritten each time you select text with the
-mouse, whereas the clipboard is only overwritten by explicit cut
-or copy commands.
+  Under the X Window System, PGTK and Haiku, there exists a
+@dfn{primary selection} containing the last stretch of text selected
+in an X application (usually by dragging the mouse).  Typically, this
+text can be inserted into other X applications by @kbd{mouse-2}
+clicks.  The primary selection is separate from the clipboard.  Its
+contents are more fragile; they are overwritten each time you select
+text with the mouse, whereas the clipboard is only overwritten by
+explicit cut or copy commands.
 
   Under X, whenever the region is active (@pxref{Mark}), the text in
 the region is saved in the primary selection.  This applies regardless
@@ -639,6 +639,13 @@ regions to the primary selection entirely.
 (@kbd{C-y}) to insert this text if @code{select-enable-primary} is set
 (@pxref{Clipboard}).
 
+@cindex lost-selection-mode
+  By default, Emacs keeps the region active even after text is
+selected in another program; this is contrary to typical X behavior.
+To make Emacs deactivate the region after another program places data
+in the primary selection, enable the global minor mode
+@code{lost-selection-mode}.
+
 @cindex MS-Windows, and primary selection
   MS-Windows provides no primary selection, but Emacs emulates it
 within a single Emacs session by storing the selected text internally.
diff --git a/doc/emacs/maintaining.texi b/doc/emacs/maintaining.texi
index e5b3664a4c..60169d8d8c 100644
--- a/doc/emacs/maintaining.texi
+++ b/doc/emacs/maintaining.texi
@@ -2222,8 +2222,8 @@ where you were with @kbd{M-,}.
 
 @kindex C-M-,
 @findex xref-go-forward
-  Go forward to a place from where you previously went back using @kbd{M-,}.
-This is useful if you find that you went back too far.
+  If you previously went back too far with @kbd{M-,}, @kbd{C-M-,}
+(@code{xref-go-forward}) can be used to go forward again.
 
 @findex xref-etags-mode
   Some major modes install @code{xref} support facilities that might
diff --git a/doc/emacs/mini.texi b/doc/emacs/mini.texi
index 4e71793b66..e71d653210 100644
--- a/doc/emacs/mini.texi
+++ b/doc/emacs/mini.texi
@@ -734,11 +734,14 @@ highlighting.  This feature uses the special text property
 @section Minibuffer History
 @cindex minibuffer history
 @cindex history of minibuffer input
-
-  Every argument that you enter with the minibuffer is saved in a
-@dfn{minibuffer history list} so you can easily use it again later.
-You can use the following arguments to quickly fetch an earlier
-argument into the minibuffer:
+@cindex completion, walking through candidates
+
+  Everything you type in the minibuffer is saved in a @dfn{minibuffer
+history list} so you can easily use it again later.  This includes
+completion candidates (such as file names, buffer names, command
+names, etc.@:) and any other kind of minibuffer input.  You can use
+the following commands to quickly fetch an earlier or alternative
+response into the minibuffer:
 
 @table @kbd
 @item M-p
diff --git a/doc/emacs/misc.texi b/doc/emacs/misc.texi
index 9709c6ddc1..da1b87b48b 100644
--- a/doc/emacs/misc.texi
+++ b/doc/emacs/misc.texi
@@ -1,6 +1,5 @@
 @c This is part of the Emacs manual.
-@c Copyright (C) 1985--1987, 1993--1995, 1997, 2000--2022 Free Software
-@c Foundation, Inc.
+@c Copyright (C) 1985--2022 Free Software Foundation, Inc.
 @c See file emacs.texi for copying conditions.
 @iftex
 @chapter Miscellaneous Commands
@@ -1643,11 +1642,11 @@ interface is similar to the @code{more} program.
 @cindex remote host
 @cindex connecting to remote host
 @cindex Telnet
-@cindex Rlogin
+@cindex SSH
 
   You can login to a remote computer, using whatever commands you
-would from a regular terminal (e.g., using the @command{ssh} or
-@command{telnet} or @code{rlogin} commands), from a Term window.
+would from a regular terminal (e.g., the @command{ssh} command), from
+a Term window.
 
   A program that asks you for a password will normally suppress
 echoing of the password, so the password will not show up in the
@@ -2870,99 +2869,6 @@ new major mode which provides a command to switch back.  
These
 approaches give you more flexibility to go back to unfinished tasks in
 the order you choose.
 
-@ignore
-@c Apart from edt and viper, this is all obsolete.
-@c (Can't believe we were saying "most other editors" into 2014!)
-@c There seems no point having a node just for those, which both have
-@c their own manuals.
-@node Emulation
-@section Emulation
-@cindex emulating other editors
-@cindex other editors
-@cindex EDT
-@cindex vi
-@cindex WordStar
-
-  GNU Emacs can be programmed to emulate (more or less) most other
-editors.  Standard facilities can emulate these:
-
-@table @asis
-@item CRiSP/Brief (PC editor)
-@findex crisp-mode
-@vindex crisp-override-meta-x
-@findex scroll-all-mode
-@cindex CRiSP mode
-@cindex Brief emulation
-@cindex emulation of Brief
-@cindex mode, CRiSP
-@kbd{M-x crisp-mode} enables key bindings to emulate the CRiSP/Brief
-editor.  Note that this rebinds @kbd{M-x} to exit Emacs unless you set
-the variable @code{crisp-override-meta-x}.  You can also use the
-command @kbd{M-x scroll-all-mode} or set the variable
-@code{crisp-load-scroll-all} to emulate CRiSP's scroll-all feature
-(scrolling all windows together).
-
-@item EDT (DEC VMS editor)
-@findex edt-emulation-on
-@findex edt-emulation-off
-Turn on EDT emulation with @kbd{M-x edt-emulation-on}; restore normal
-command bindings with @kbd{M-x edt-emulation-off}.
-
-Most of the EDT emulation commands are keypad keys, and most standard
-Emacs key bindings are still available.  The EDT emulation rebindings
-are done in the global keymap, so there is no problem switching
-buffers or major modes while in EDT emulation.
-
-@item TPU (DEC VMS editor)
-@findex tpu-edt-on
-@cindex TPU
-@kbd{M-x tpu-edt-on} turns on emulation of the TPU editor emulating EDT.
-
-@item vi (Berkeley editor)
-@findex viper-mode
-Viper is an emulator for vi.  It implements several levels of
-emulation; level 1 is closest to vi itself, while level 5 departs
-somewhat from strict emulation to take advantage of the capabilities of
-Emacs.  To invoke Viper, type @kbd{M-x viper-mode}; it will guide you
-the rest of the way and ask for the emulation level.  @inforef{Top,
-Viper, viper}.
-
-@item vi (another emulator)
-@findex vi-mode
-@kbd{M-x vi-mode} enters a major mode that replaces the previously
-established major mode.  All of the vi commands that, in real vi, enter
-input mode are programmed instead to return to the previous major
-mode.  Thus, ordinary Emacs serves as vi's input mode.
-
-Because vi emulation works through major modes, it does not work
-to switch buffers during emulation.  Return to normal Emacs first.
-
-If you plan to use vi emulation much, you probably want to bind a key
-to the @code{vi-mode} command.
-
-@item vi (alternate emulator)
-@findex vip-mode
-@kbd{M-x vip-mode} invokes another vi emulator, said to resemble real vi
-more thoroughly than @kbd{M-x vi-mode}.  Input mode in this emulator
-is changed from ordinary Emacs so you can use @key{ESC} to go back to
-emulated vi command mode.  To get from emulated vi command mode back to
-ordinary Emacs, type @kbd{C-z}.
-
-This emulation does not work through major modes, and it is possible
-to switch buffers in various ways within the emulator.  It is not
-so necessary to assign a key to the command @code{vip-mode} as
-it is with @code{vi-mode} because terminating insert mode does
-not use it.
-
-@inforef{Top, VIP, vip}, for full information.
-
-@item WordStar (old wordprocessor)
-@findex wordstar-mode
-@kbd{M-x wordstar-mode} provides a major mode with WordStar-like
-key bindings.
-@end table
-@end ignore
-
 
 @node Hyperlinking
 @section Hyperlinking and Web Navigation Features
diff --git a/doc/emacs/msdos.texi b/doc/emacs/msdos.texi
index e30d623a77..dd0787cd38 100644
--- a/doc/emacs/msdos.texi
+++ b/doc/emacs/msdos.texi
@@ -986,9 +986,9 @@ printer, put this in your @file{.emacs} file:
 @section Specifying Fonts on MS-Windows
 @cindex font specification (MS Windows)
 
-  Starting with Emacs 23, fonts are specified by their name, size
-and optional properties.  The format for specifying fonts comes from the
-fontconfig library used in modern Free desktops:
+  Fonts are specified by their name, size and optional properties.
+The format for specifying fonts comes from the fontconfig library used
+in modern Free desktops:
 
 @example
   [Family[-PointSize]][:Option1=Value1[:Option2=Value2[...]]]
diff --git a/doc/emacs/package.texi b/doc/emacs/package.texi
index eb4f5b0eda..7e16c82cf5 100644
--- a/doc/emacs/package.texi
+++ b/doc/emacs/package.texi
@@ -483,6 +483,16 @@ The default value is just @code{'(all)}.
 installed will be ignored.  The @samp{muse} package will be listed in
 the package menu with the @samp{held} status.
 
+@findex package-recompile
+@findex package-recompile-all
+  Emacs byte code is quite stable, but it's possible for byte code to
+become outdated, or for the compiled files to rely on macros that have
+changed in new versions of Emacs.  You can use the command @w{@kbd{M-x
+package-recompile}} to recompile a particular package, or
+@w{@kbd{M-x package-recompile-all}} to recompile all the packages.  (The
+latter command might take quite a while to run if you have many
+installed packages.)
+
 @node Package Files
 @section Package Files and Directory Layout
 @cindex package directory
diff --git a/doc/emacs/search.texi b/doc/emacs/search.texi
index f4e12d29e9..582e764c55 100644
--- a/doc/emacs/search.texi
+++ b/doc/emacs/search.texi
@@ -228,8 +228,9 @@ customizing the @code{isearch-wrap-pause} user option.  If 
it is
 @code{t} (the default), signal an error.  (Repeating the search will
 wrap around.)  If @code{no}, issue a @code{ding} and wrap immediately
 after reaching the last match.  If @code{no-ding}, wrap immediately,
-but don't @code{ding}.  Finally, if @code{nil}, never wrap, but just
-stop at the last match.
+but don't @code{ding}.  With the values @code{no} and @code{no-ding}
+the search will try to wrap around also on typing a character.
+Finally, if @code{nil}, never wrap, but just stop at the last match.
 
 @cindex search ring
 @findex isearch-ring-advance
@@ -1428,16 +1429,18 @@ of its accented cousins like @code{@"a} and @code{@'a}, 
i.e., the
 match disregards the diacritics that distinguish these
 variants.  In addition, @code{a} matches other characters that
 resemble it, or have it as part of their graphical representation,
-such as U+249C @sc{parenthesized latin small letter a} and U+2100
-@sc{account of} (which looks like a small @code{a} over @code{c}).
+such as U+00AA @sc{feminine ordinal indicator} and U+24D0
+@sc{circled latin small letter a} (which looks like a small @code{a}
+inside a circle).
 Similarly, the @acronym{ASCII} double-quote character @code{"} matches
 all the other variants of double quotes defined by the Unicode
 standard.  Finally, character folding can make a sequence of one or
 more characters match another sequence of a different length: for
 example, the sequence of two characters @code{ff} matches U+FB00
-@sc{latin small ligature ff}.  Character sequences that are not identical,
-but match under character folding are known as @dfn{equivalent
-character sequences}.
+@sc{latin small ligature ff} and the sequence @code{(a)} matches
+U+249C @sc{parenthesized latin small letter a}.  Character sequences
+that are not identical, but match under character folding are known as
+@dfn{equivalent character sequences}.
 
 @kindex M-s ' @r{(Incremental Search)}
 @findex isearch-toggle-char-fold
diff --git a/doc/emacs/trouble.texi b/doc/emacs/trouble.texi
index 8da96de1cb..887e5c6170 100644
--- a/doc/emacs/trouble.texi
+++ b/doc/emacs/trouble.texi
@@ -151,7 +151,6 @@ garbled displays, running out of memory, and crashes and 
hangs.
 Emacs.
 
 @menu
-* DEL Does Not Delete::   What to do if @key{DEL} doesn't delete.
 * Stuck Recursive::       '[...]' in mode line around the parentheses.
 * Screen Garbled::        Garbage on the screen.
 * Text Garbled::          Garbage in the text.
@@ -159,66 +158,9 @@ Emacs.
 * Crashing::              What Emacs does when it crashes.
 * After a Crash::         Recovering editing in an Emacs session that crashed.
 * Emergency Escape::      What to do if Emacs stops responding.
-* Long Lines::            Mitigating slowness due to extremely long lines.
+* DEL Does Not Delete::   What to do if @key{DEL} doesn't delete.
 @end menu
 
-@node DEL Does Not Delete
-@subsection If @key{DEL} Fails to Delete
-@cindex @key{DEL} vs @key{BACKSPACE}
-@cindex @key{BACKSPACE} vs @key{DEL}
-@cindex @key{DEL} does not delete
-
-  Every keyboard has a large key, usually labeled @key{BACKSPACE},
-which is ordinarily used to erase the last character that you typed.
-In Emacs, this key is supposed to be equivalent to @key{DEL}.
-
-  When Emacs starts up on a graphical display, it determines
-automatically which key should be @key{DEL}.  In some unusual cases,
-Emacs gets the wrong information from the system, and @key{BACKSPACE}
-ends up deleting forwards instead of backwards.
-
-  Some keyboards also have a @key{Delete} key, which is ordinarily
-used to delete forwards.  If this key deletes backward in Emacs, that
-too suggests Emacs got the wrong information---but in the opposite
-sense.
-
-  On a text terminal, if you find that @key{BACKSPACE} prompts for a
-Help command, like @kbd{Control-h}, instead of deleting a character,
-it means that key is actually sending the @samp{BS} character.  Emacs
-ought to be treating @key{BS} as @key{DEL}, but it isn't.
-
-@findex normal-erase-is-backspace-mode
-  In all of those cases, the immediate remedy is the same: use the
-command @kbd{M-x normal-erase-is-backspace-mode}.  This toggles
-between the two modes that Emacs supports for handling @key{DEL}, so
-if Emacs starts in the wrong mode, this should switch to the right
-mode.  On a text terminal, if you want to ask for help when @key{BS}
-is treated as @key{DEL}, use @key{F1} instead of @kbd{C-h}; @kbd{C-?}
-may also work, if it sends character code 127.
-
-  To fix the problem in every Emacs session, put one of the following
-lines into your initialization file (@pxref{Init File}).  For the
-first case above, where @key{BACKSPACE} deletes forwards instead of
-backwards, use this line to make @key{BACKSPACE} act as @key{DEL}:
-
-@lisp
-(normal-erase-is-backspace-mode 0)
-@end lisp
-
-@noindent
-For the other two cases, use this line:
-
-@lisp
-(normal-erase-is-backspace-mode 1)
-@end lisp
-
-@vindex normal-erase-is-backspace
-  Another way to fix the problem for every Emacs session is to
-customize the variable @code{normal-erase-is-backspace}: the value
-@code{t} specifies the mode where @key{BS} or @key{BACKSPACE} is
-@key{DEL}, and @code{nil} specifies the other mode.  @xref{Easy
-Customization}.
-
 @node Stuck Recursive
 @subsection Recursive Editing Levels
 @cindex stuck in recursive editing
@@ -490,40 +432,62 @@ program.
 emergency escape---but there are cases where it won't work, when a
 system call hangs or when Emacs is stuck in a tight loop in C code.
 
-@node Long Lines
-@subsection Long Lines
-@cindex long lines
-
-  For a variety of reasons (some of which are fundamental to the Emacs
-redisplay code and the complex range of possibilities it handles;
-others of which are due to modes and features which do not scale well
-in unusual circumstances), Emacs can perform poorly when extremely
-long lines are present (where ``extremely long'' usually means at
-least many thousands of characters).
-
-@cindex @code{so-long} mode
-@findex global-so-long-mode
-@vindex so-long-action
-  A particular problem is that Emacs may ``hang'' for a long time at
-the point of visiting a file with extremely long lines.  This can be
-mitigated by enabling the @file{so-long} library, which detects when a
-visited file contains abnormally long lines, and takes steps to
-disable features which are liable to cause slowness in that situation.
-To enable this library, type @kbd{M-x global-so-long-mode @key{RET}},
-or turn on the @code{global-so-long-mode} in your init file
-(@pxref{Init File}), or customize the @code{global-so-long-mode}
-option.  You can tailor this mode's operation by customizing the
-variable @code{so-long-action}.
-
-  The @file{so-long} library can also significantly improve
-performance when moving and editing in a buffer with long lines.
-Performance is still likely to degrade as you get deeper into the long
-lines, but the improvements from using this library can nevertheless
-be substantial.
-
-@findex so-long-commentary
-  Use @kbd{M-x so-long-commentary} to view the documentation for this
-library and learn more about how to enable and configure it.
+@node DEL Does Not Delete
+@subsection If @key{DEL} Fails to Delete
+@cindex @key{DEL} vs @key{BACKSPACE}
+@cindex @key{BACKSPACE} vs @key{DEL}
+@cindex @key{DEL} does not delete
+
+  Every keyboard has a large key, usually labeled @key{BACKSPACE},
+which is ordinarily used to erase the last character that you typed.
+In Emacs, this key is supposed to be equivalent to @key{DEL}.
+
+  When Emacs starts up on a graphical display, it determines
+automatically which key should be @key{DEL}.  In some unusual cases,
+Emacs gets the wrong information from the system, and @key{BACKSPACE}
+ends up deleting forwards instead of backwards.
+
+  Some keyboards also have a @key{Delete} key, which is ordinarily
+used to delete forwards.  If this key deletes backward in Emacs, that
+too suggests Emacs got the wrong information---but in the opposite
+sense.
+
+  On a text terminal, if you find that @key{BACKSPACE} prompts for a
+Help command, like @kbd{Control-h}, instead of deleting a character,
+it means that key is actually sending the @samp{BS} character.  Emacs
+ought to be treating @key{BS} as @key{DEL}, but it isn't.
+
+@findex normal-erase-is-backspace-mode
+  In all of those cases, the immediate remedy is the same: use the
+command @kbd{M-x normal-erase-is-backspace-mode}.  This toggles
+between the two modes that Emacs supports for handling @key{DEL}, so
+if Emacs starts in the wrong mode, this should switch to the right
+mode.  On a text terminal, if you want to ask for help when @key{BS}
+is treated as @key{DEL}, use @key{F1} instead of @kbd{C-h}; @kbd{C-?}
+may also work, if it sends character code 127.
+
+  To fix the problem in every Emacs session, put one of the following
+lines into your initialization file (@pxref{Init File}).  For the
+first case above, where @key{BACKSPACE} deletes forwards instead of
+backwards, use this line to make @key{BACKSPACE} act as @key{DEL}:
+
+@lisp
+(normal-erase-is-backspace-mode 0)
+@end lisp
+
+@noindent
+For the other two cases, use this line:
+
+@lisp
+(normal-erase-is-backspace-mode 1)
+@end lisp
+
+@vindex normal-erase-is-backspace
+  Another way to fix the problem for every Emacs session is to
+customize the variable @code{normal-erase-is-backspace}: the value
+@code{t} specifies the mode where @key{BS} or @key{BACKSPACE} is
+@key{DEL}, and @code{nil} specifies the other mode.  @xref{Easy
+Customization}.
 
 @node Bugs
 @section Reporting Bugs
diff --git a/doc/emacs/xresources.texi b/doc/emacs/xresources.texi
index 2c2700bc15..ab0df3563f 100644
--- a/doc/emacs/xresources.texi
+++ b/doc/emacs/xresources.texi
@@ -382,7 +382,9 @@ which prevents blank areas of a frame that have not yet 
been painted
 from being displayed.  If set to @samp{extended}, it will enable use
 of an alternative frame synchronization protocol, which might be
 supported by some compositing window managers that don't support the
-protocol Emacs uses by default.
+protocol Emacs uses by default, and causes Emacs to synchronize
+display with the monitor refresh rate when a compatible compositing
+window manager is in use.
 
 @item @code{verticalScrollBars} (class @code{ScrollBars})
 Give frames scroll bars on the left if @samp{left}, on the right if
@@ -449,6 +451,12 @@ Foreground color for a selected item.
 Foreground color.
 @item disabledForeground
 Foreground color for a disabled menu item.
+@item highlightForeground
+Foreground color for a menu item highlighted by the mouse or key
+navigation.
+@item highlightBackground
+Background color for a menu item highlighted by the mouse or key
+navigation.
 @ifnottex
 @item horizontalSpacing
 Horizontal spacing in pixels between items.  Default is 3.
diff --git a/doc/lispintro/emacs-lisp-intro.texi 
b/doc/lispintro/emacs-lisp-intro.texi
index 049c8a65a8..47a5a870fd 100644
--- a/doc/lispintro/emacs-lisp-intro.texi
+++ b/doc/lispintro/emacs-lisp-intro.texi
@@ -2020,7 +2020,6 @@ the arguments to the function @code{concat} are the 
strings
 @w{@code{"The "}} and @w{@code{" red foxes."}} and the list
 @code{(number-to-string (+ 2 fill-column))}.
 
-@c For GNU Emacs 22, need number-to-string
 @smallexample
 (concat "The " (number-to-string (+ 2 fill-column)) " red foxes.")
 @end smallexample
@@ -10297,9 +10296,8 @@ loop with a list.
 
 @cindex @file{*scratch*} buffer
 The function requires several lines for its output.  If you are
-reading this in a recent instance of GNU Emacs,
-@c GNU Emacs 21, GNU Emacs 22, or a later version,
-you can evaluate the following expression inside of Info, as usual.
+reading this in a recent instance of GNU Emacs, you can evaluate the
+following expression inside of Info, as usual.
 
 If you are using an earlier version of Emacs, you need to copy the
 necessary expressions to your @file{*scratch*} buffer and evaluate
@@ -15134,16 +15132,16 @@ Emacs may produce different results.)
 @end group
 
 @group
-(lengths-list-file "./lisp/makesum.el")
-     @result{} (85 181)
+(lengths-list-file "./lisp/hex-util.el")
+     @result{} (82 71)
 @end group
 
 @group
   (recursive-lengths-list-many-files
    '("./lisp/macros.el"
      "./lisp/mail/mailalias.el"
-     "./lisp/makesum.el"))
-       @result{} (283 263 480 90 38 32 29 95 178 180 321 218 324 85 181)
+     "./lisp/hex-util.el"))
+       @result{} (283 263 480 90 38 32 29 95 178 180 321 218 324 82 71)
 @end group
 @end smallexample
 
@@ -15235,27 +15233,13 @@ Sorting the list returned by the
 @code{recursive-lengths-list-many-files} function is straightforward;
 it uses the @code{<} function:
 
-@ignore
-2006 Oct 29
-In GNU Emacs 22,  eval
-(progn
-  (cd "/usr/local/share/emacs/22.0.50/")
-  (sort
-   (recursive-lengths-list-many-files
-    '("./lisp/macros.el"
-      "./lisp/mail/mailalias.el"
-      "./lisp/makesum.el"))
-   '<))
-
-@end ignore
-
 @smallexample
 @group
 (sort
  (recursive-lengths-list-many-files
   '("./lisp/macros.el"
     "./lisp/mailalias.el"
-    "./lisp/makesum.el"))
+    "./lisp/hex-util.el"))
  '<)
 @end group
 @end smallexample
@@ -15265,7 +15249,7 @@ In GNU Emacs 22,  eval
 which produces:
 
 @smallexample
-(29 32 38 85 90 95 178 180 181 218 263 283 321 324 480)
+(29 32 38 71 82 90 95 178 180 218 263 283 321 324 480)
 @end smallexample
 
 @noindent
@@ -15313,7 +15297,7 @@ as a list that looks like this (but with more elements):
 @group
 ("./lisp/macros.el"
  "./lisp/mail/rmail.el"
- "./lisp/makesum.el")
+ "./lisp/hex-util.el")
 @end group
 @end smallexample
 
@@ -17711,17 +17695,6 @@ or start GNU Emacs with the command @code{emacs -nbc}.
 (setq grep-command "grep -i -nH -e ")
 @end smallexample
 
-@ignore
-@c Evidently, no longer needed in GNU Emacs 22
-
-item Automatically uncompress compressed files when visiting them
-
-smallexample
-(load "uncompress")
-end smallexample
-
-@end ignore
-
 @item Find an existing buffer, even if it has a different name@*
 This avoids problems with symbolic links.
 
diff --git a/doc/lispref/buffers.texi b/doc/lispref/buffers.texi
index 1cbe8bc093..6a1d125701 100644
--- a/doc/lispref/buffers.texi
+++ b/doc/lispref/buffers.texi
@@ -981,14 +981,22 @@ of
 Satisfied if @var{expr} doesn't satisfy @code{buffer-match-p} with
 the same buffer and @code{arg}.
 @item or
-Satisfied if @var{oper} is a list and @emph{any} condition if
+Satisfied if @var{expr} is a list and @emph{any} condition in
 @var{expr} satisfies @code{buffer-match-p}, with the same buffer and
 @code{arg}.
 @item and
-Satisfied if @var{oper} is a list and @emph{all} condition if
-@var{expr} satisfies @code{buffer-match-p}, with the same buffer and
+Satisfied if @var{expr} is a list and @emph{all} conditions in
+@var{expr} satisfy @code{buffer-match-p}, with the same buffer and
 @code{arg}.
+@item derived-mode
+Satisfied if the buffer's major mode derives from @var{expr}.
+@item major-mode
+Satisfied if the buffer's major mode is equal to @var{expr}.  Prefer
+using @code{derived-mode} instead when both can work.
 @end table
+@item t
+Satisfied by any buffer.  A convenient alternative to @code{""} (empty
+string), @code{(and)} (empty conjunction) or @code{always}.
 @end itemize
 @end defun
 
diff --git a/doc/lispref/commands.texi b/doc/lispref/commands.texi
index 0a82bba3bc..ede1c4d762 100644
--- a/doc/lispref/commands.texi
+++ b/doc/lispref/commands.texi
@@ -443,9 +443,9 @@ specification.  If the key sequence that invoked the 
command has
 and @acronym{ASCII} characters, do not count where @samp{e} is concerned.
 
 @item f
-A file name of an existing file (@pxref{File Names}).  The default
-directory is @code{default-directory}.  Existing, Completion, Default,
-Prompt.
+A file name of an existing file (@pxref{File Names}).  @xref{Reading
+File Names}, for details about default values.  Existing, Completion,
+Default, Prompt.
 
 @item F
 A file name.  The file need not exist.  Completion, Default, Prompt.
@@ -897,6 +897,10 @@ keymaps.  This command is the normal definition of 
@kbd{M-S-x}
 (that's ``meta shift x'').
 @end deffn
 
+Both these commands prompt for a command name, but with different
+completion rules.  You can toggle between these two modes by using the
+@kbd{M-S-x} command while being prompted.
+
 @node Distinguish Interactive
 @section Distinguish Interactive Calls
 @cindex distinguish interactive calls
@@ -2074,7 +2078,7 @@ and @var{kind} as arguments.
 @item load-changed
 This xwidget event indicates that the @var{xwidget} has reached a
 particular point of the page-loading process.  When these events are
-sent, @var{arg} will contain a string that futher describes the status
+sent, @var{arg} will contain a string that further describes the status
 of the widget:
 
 @table @samp
@@ -2208,6 +2212,17 @@ and @code{mouse-wheel-down-alternate-event} defined in
 @file{mwheel.el} to determine what event types to expect for the mouse
 wheel.
 
+@vindex mouse-wheel-left-event
+@vindex mouse-wheel-right-event
+Similarly, some mice can generate @code{mouse-wheel-left-event} and
+@code{mouse-wheel-right-event} and can be used to scroll if
+@code{mouse-wheel-tilt-scroll} is non-@code{nil}.  However, some mice
+also generate other events at the same time as they're generating
+these scroll events which may get in the way.  The way to fix this is
+generally to unbind these events (for instance, @code{mouse-6} or
+@code{mouse-7}, but this is very hardware and operating system
+dependent).
+
 @cindex @code{pinch} event
 @item (pinch @var{position} @var{dx} @var{dy} @var{scale} @var{angle})
 This kind of event is generated by the user performing a ``pinch''
@@ -2686,7 +2701,10 @@ the character at that position.
 @cindex timestamp of a mouse event
 @defun posn-timestamp position
 Return the timestamp in @var{position}.  This is the time at which the
-event occurred, in milliseconds.
+event occurred, in milliseconds.  Such a timestamp is reported
+relative to an arbitrary starting time that varies according to the
+window system in use.  On the X Window System, for example, it is the
+number of milliseconds since the X server was started.
 @end defun
 
   These functions compute a position list given particular buffer
@@ -2962,7 +2980,7 @@ returns the key sequence as a vector, never as a string.
 If an input character is upper-case (or has the shift modifier) and
 has no key binding, but its lower-case equivalent has one, then
 @code{read-key-sequence} converts the character to lower case.  (This
-behaviour can be disabled by setting the
+behavior can be disabled by setting the
 @code{translate-upper-case-key-bindings} user option to @code{nil}.)
 Note that @code{lookup-key} does not perform case conversion in this
 way.
@@ -3198,7 +3216,7 @@ causes it to evaluate @code{help-form} and display the 
result.  It
 then continues to wait for a valid input character, or keyboard-quit.
 @end defun
 
-@defun read-multiple-choice prompt choices &optional help-string show-help
+@defun read-multiple-choice prompt choices &optional help-string show-help 
long-form
 Ask user a multiple choice question.  @var{prompt} should be a string
 that will be displayed as the prompt.
 
@@ -3217,6 +3235,11 @@ If optional argument @var{show-help} is non-@code{nil}, 
the help
 buffer will be displayed immediately, before any user input.  If it is
 a string, use it as the name of the help buffer.
 
+If optional argument @var{long-form} is non-@code{nil}, the user
+will have to type in long-form answers (using @code{completing-read})
+instead of hitting a single key.  The answers must be among the second
+elements of the values in the @var{choices} list.
+
 The return value is the matching value from @var{choices}.
 
 @lisp
diff --git a/doc/lispref/compile.texi b/doc/lispref/compile.texi
index 3670225dc4..60fc11a22e 100644
--- a/doc/lispref/compile.texi
+++ b/doc/lispref/compile.texi
@@ -979,7 +979,11 @@ Its value should be a number between @minus{}1 and 3.  
Values between
 0 and 3 specify the optimization levels equivalent to the
 corresponding compiler @option{-O0}, @option{-O1}, etc.@: command-line
 options of the compiler.  The value @minus{}1 means disable
-native-compilation; functions and files will be only byte-compiled.
+native-compilation: functions and files will be only byte-compiled;
+however, the @file{*.eln} files will still be produced, they will just
+contain the compiled code in bytecode form.  (This can be achieved at
+function granularity by using the @w{@code{(declare (speed -1))}}
+form, @pxref{Declare Form}.)
 The default value is 2.
 @end defopt
 
diff --git a/doc/lispref/customize.texi b/doc/lispref/customize.texi
index 528421bf3b..6ba35cffff 100644
--- a/doc/lispref/customize.texi
+++ b/doc/lispref/customize.texi
@@ -672,6 +672,10 @@ The value must be a valid color name.  The widget provides 
completion
 for color names, as well as a sample and a button for selecting a
 color name from a list of color names shown in a @file{*Colors*}
 buffer.
+
+@item fringe-bitmap
+The value must be a valid fringe bitmap name.  The widget provides
+completion.
 @end table
 
 @node Composite Types
diff --git a/doc/lispref/debugging.texi b/doc/lispref/debugging.texi
index 058c931954..9ae40949d1 100644
--- a/doc/lispref/debugging.texi
+++ b/doc/lispref/debugging.texi
@@ -77,6 +77,7 @@ debugger recursively.  @xref{Recursive Editing}.
 
 @menu
 * Error Debugging::       Entering the debugger when an error happens.
+* Debugging Redisplay::   Getting backtraces from redisplay errors.
 * Infinite Loops::        Stopping and debugging a program that doesn't exit.
 * Function Debugging::    Entering it when a certain function is called.
 * Variable Debugging::    Entering it when a variable is modified.
@@ -105,6 +106,10 @@ debugger, set the variable @code{debug-on-error} to 
non-@code{nil}.
 (The command @code{toggle-debug-on-error} provides an easy way to do
 this.)
 
+Note that, for technical reasons, you cannot use the facilities
+defined in this subsection to debug errors in Lisp that the redisplay
+code has invoked.  @xref{Debugging Redisplay}, for help with these.
+
 @defopt debug-on-error
 This variable determines whether the debugger is called when an error
 is signaled and not handled.  If @code{debug-on-error} is @code{t},
@@ -213,6 +218,45 @@ file, use the option @samp{--debug-init}.  This binds
 bypasses the @code{condition-case} which normally catches errors in the
 init file.
 
+@node Debugging Redisplay
+@subsection Debugging Redisplay Errors
+@cindex redisplay errors
+@cindex debugging redisplay errors
+
+When an error occurs in Lisp code which redisplay has invoked, Emacs's
+usual debugging mechanisms are unusable, for technical reasons.  This
+subsection describes how to get a backtrace from such an error, which
+should be helpful in debugging it.
+
+These directions apply to Lisp forms used, for example, in
+@code{:eval} mode line constructs (@pxref{Mode Line Data}), and in all
+hooks invoked from redisplay, such as:
+
+@itemize
+@item
+@code{fontification-functions} (@pxref{Auto Faces}).
+@item
+@code{window-scroll-functions} (@pxref{Window Hooks}).
+@end itemize
+
+Note that if you have had an error in a hook function called from
+redisplay, the error handling might have removed this function from
+the hook.  You will thus need to reinitialize that hook somehow,
+perhaps with @code{add-hook}, to be able to replay the bug.
+
+To generate a backtrace in these circumstances, set the variable
+@code{backtrace-on-redisplay-error} to non-@code{nil}.  When the error
+occurs, Emacs will dump the backtrace to the buffer
+@file{*Redisplay-trace*}, but won't automatically display it in a
+window.  This is to avoid needlessly corrupting the redisplay you are
+debugging.  You will thus need to display the buffer yourself, with a
+command such as @code{switch-to-buffer-other-frame} @key{C-x 5 b}.
+
+@defvar backtrace-on-redisplay-error
+Set this variable to non-@code{nil} to enable the generation of a
+backtrace when an error occurs in any Lisp called from redisplay.
+@end defvar
+
 @node Infinite Loops
 @subsection Debugging Infinite Loops
 @cindex infinite loops
diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi
index b98c2f8fa9..a56f467e0b 100644
--- a/doc/lispref/display.texi
+++ b/doc/lispref/display.texi
@@ -27,6 +27,7 @@ that Emacs presents to the user.
 * Window Dividers::     Separating windows visually.
 * Display Property::    Images, margins, text size, etc.
 * Images::              Displaying images in Emacs buffers.
+* Icons::               Displaying icons in Emacs buffers.
 * Xwidgets::            Displaying native widgets in Emacs buffers.
 * Buttons::             Adding clickable buttons to Emacs buffers.
 * Abstract Display::    Emacs's Widget for Object Collections.
@@ -2474,6 +2475,7 @@ Otherwise, it returns @code{nil}.
 The following table lists all the face attributes, their possible
 values, and their effects.
 
+@cindex unspecified, face attribute value
   Apart from the values given below, each face attribute can have the
 value @code{unspecified}.  This special value means that the face
 doesn't specify that attribute directly.  An @code{unspecified}
@@ -2482,7 +2484,13 @@ description @code{:inherit} attribute below); or, 
failing that, to an
 underlying face (@pxref{Displaying Faces}).  (However,
 @code{unspecified} is not a valid value in @code{defface}.)
 
-  The @code{default} face must specify all attributes.
+@cindex reset, face attribute value
+  A face attribute can also have the value @code{reset}.  This special
+value stands for the value of the corresponding attribute of the
+@code{default} face.
+
+  The @code{default} face must explicitly specify all attributes, and
+cannot use the special value @code{reset}.
 
   Some of these attributes are meaningful only on certain kinds of
 displays.  If your display cannot handle a certain attribute, the
@@ -2615,14 +2623,17 @@ Draw a box with lines of width 1, in the foreground 
color.
 Draw a box with lines of width 1, in color @var{color}.
 
 @item @code{(:line-width (@var{vwidth} . @var{hwidth}) :color @var{color} 
:style @var{style})}
-This way you can explicitly specify all aspects of the box.  The values
-@var{vwidth} and @var{hwidth} specifies respectively the width of the
-vertical and horizontal lines to draw; they default to (1 . 1).
-A negative horizontal or vertical width @minus{}@var{n} means to draw a line
-of width @var{n} that occupies the space of the underlying text, thus
-avoiding any increase in the character height or width. For simplification
-the width could be specified with only a single number @var{n} instead
-of a list, such case is equivalent to @code{((abs @var{n}) . @var{n})}.
+You can explicitly specify all aspects of the box with a plist on this
+form.  Any element in this plist can be omitted.
+
+The values @var{vwidth} and @var{hwidth} specifies respectively the
+width of the vertical and horizontal lines to draw; they default to (1
+. 1).  A negative horizontal or vertical width @minus{}@var{n} means
+to draw a line of width @var{n} that occupies the space of the
+underlying text, thus avoiding any increase in the character height or
+width. For simplification the width could be specified with only a
+single number @var{n} instead of a list, such case is equivalent to
+@code{((abs @var{n}) . @var{n})}.
 
 The value @var{style} specifies whether to draw a 3D box.  If it is
 @code{released-button}, the box looks like a 3D button that is not
@@ -2706,6 +2717,13 @@ doesn't specify an explicit value for a face, the value 
from the
 original face definition by @code{defface} is inherited
 (@pxref{Defining Faces}).
 
+Some modes, like @code{hl-line-mode}, use a face with an
+@code{:extend} property to mark the entire current line.  Note,
+however, that Emacs will always allow you to move point after the
+final character in a buffer, and if the buffer ends with a newline
+character, point can be placed on what is seemingly a line at the end
+of the buffer---but Emacs can't highlight that ``line'', because it
+doesn't really exist.
 @end table
 
 @defun font-family-list &optional frame
@@ -3465,6 +3483,12 @@ function finishes are the ones that really matter.
 
 For efficiency, we recommend writing these functions so that they
 usually assign faces to around 400 to 600 characters at each call.
+
+When the buffer text includes very long lines, these functions are
+called with the buffer narrowed to a relatively small region around
+@var{pos}, and with narrowing locked, so the functions cannot use
+@code{widen} to gain access to the rest of the buffer.
+@xref{Narrowing}.
 @end defvar
 
 @node Basic Faces
@@ -4605,6 +4629,7 @@ Used to indicate buffer boundaries.
 Used for different types of fringe cursors.
 
 @item @code{exclamation-mark}, @code{question-mark}
+@itemx @code{large-circle}
 Not used by core Emacs features.
 @end table
 
@@ -5710,6 +5735,12 @@ are supported, unless the image type is 
@code{imagemagick}.  Positive
 values rotate clockwise, negative values counter-clockwise.  Rotation
 is performed after scaling and cropping.
 
+@item :flip @var{flip}
+If this is @code{t}, the image will be horizontally flipped.
+Currently it has no effect if the image type is @code{imagemagick}.
+Vertical flipping can be achieved by rotating the image 180 degrees
+and toggling this value.
+
 @item :transform-smoothing @var{smooth}
 If this is @code{t}, any image transform will have smoothing applied;
 if @code{nil}, no smoothing will be applied.  The exact algorithm used
@@ -5858,6 +5889,14 @@ When you click the mouse when the mouse pointer is over 
a hot-spot, an
 event is composed by combining the @var{id} of the hot-spot with the
 mouse event; for instance, @code{[area4 mouse-1]} if the hot-spot's
 @var{id} is @code{area4}.
+
+Note that the map's coordinates should reflect the displayed image
+after all transforms have been done (rotation, scaling and so on), and
+also note that Emacs (by default) performs auto-scaling of images, so
+to make things match up, you should either specify @code{:scale 1.0}
+when creating the image, or use the result of
+@code{image-compute-scaling-factor} to compute the elements of the
+map.
 @end table
 
 @defun image-mask-p spec &optional frame
@@ -5923,13 +5962,10 @@ There are three formats you can use for @var{data}:
 @itemize @bullet
 @item
 A vector of strings or bool-vectors, each specifying one line of the
-image.  Do specify @code{:height} and @code{:width}.
+image.  Do specify @code{:data-height} and @code{:data-width}.
 
 @item
 A string containing the same byte sequence as an XBM file would contain.
-You must not specify @code{:height} and @code{:width} in this case,
-because omitting them is what indicates the data has the format of an
-XBM file.  The file contents specify the height and width of the image.
 
 @item
 A string or a bool-vector containing the bits of the image (plus
@@ -5937,26 +5973,11 @@ perhaps some extra bits at the end that will not be 
used).  It should
 contain at least @w{@code{@var{stride} * @var{height}}} bits, where
 @var{stride} is the smallest multiple of 8 greater than or equal to
 the width of the image.  In this case, you should specify
-@code{:height}, @code{:width} and @code{:stride}, both to indicate
-that the string contains just the bits rather than a whole XBM file,
-and to specify the size of the image.
+@code{:data-height}, @code{:data-width} and @code{:stride}, both to
+indicate that the string contains just the bits rather than a whole
+XBM file, and to specify the size of the image.
 @end itemize
 
-@item :width @var{width}
-The value, @var{width}, specifies the width of the image, in pixels.
-
-@item :height @var{height}
-The value, @var{height}, specifies the height of the image, in pixels.
-
-Note that @code{:width} and @code{:height} can only be used if passing
-in data that doesn't specify the width and height (e.g., a string or a
-vector containing the bits of the image).  @acronym{XBM} files usually
-specify this themselves, and it's an error to use these two properties
-on these files.  Also note that @code{:width} and @code{:height} are
-used by most other image formats to specify what the displayed image
-is supposed to be, which usually means performing some sort of
-scaling.  This isn't supported for @acronym{XBM} images.
-
 @item :stride @var{stride}
 The number of bool vector entries stored for each row; the smallest
 multiple of 8 greater than or equal to @var{width}.
@@ -6977,6 +6998,165 @@ bytes.  An image of size 200x100 with 24 bits per color 
will have a
 cache size of 60000 bytes, for instance.
 @end defun
 
+@node Icons
+@section Icons
+
+Emacs sometimes uses buttons (for clicking on) or small graphics (to
+illustrate something).  Since Emacs is available on a wide variety of
+systems with different capabilities, and users have different
+preferences, Emacs provides a facility to handle this in a convenient
+way, allowing customization, graceful degradation, accessibility, as
+well as themability: @dfn{Icons}.
+
+The central macro here is @code{define-icon}, and here's a simple
+example:
+
+@lisp
+(define-icon outline-open button
+  '((image "right.svg" "open.xpm" "open.pbm" :height line)
+    (emoji "▶️")
+    (symbol "▶" "➤")
+    (text "open" :face icon-button))
+  "Icon used for buttons for opening a section in outline buffers."
+  :version "29.1"
+  :help-echo "Open this section")
+@end lisp
+
+Which alternative will actually be displayed depends on the value of
+the user option @code{icon-preference} (@pxref{Icons,,, emacs, The GNU
+Emacs Manual}) and on the results of run-time checks for what the
+current frame's terminal can actually display.
+
+The macro in the example above defines @code{outline-open} as an icon,
+and inherits properties from the icon called @code{button} (so this is
+meant as a clickable button to be inserted in a buffer).  It is
+followed by a list of @dfn{icon types} along with the actual icon
+shapes themselves.  In addition, there's a doc string and various
+keywords that contain additional information and properties.
+
+To instantiate an icon, you use @code{icon-string}, which will
+consult the current Customize theming, and the @code{icon-preference}
+user option, and finally what the Emacs is able to actually display.
+If @code{icon-preference} is @code{(image emoji symbol text)} (i.e.,
+allowing all of these forms of icons), in this case,
+@code{icon-string} will first check that Emacs is able to display
+images at all, and then whether it has support for each of those
+different image formats.  If that fails, Emacs will check whether
+Emacs can display emojis (in the current frame).  If that fails, it'll
+check whether it can display the symbol in question.  If that fails,
+it'll use the plain text version.
+
+For instance, if @code{icon-preference} doesn't contain @code{image}
+or @code{emoji}, it'll skip those entries.
+
+Code can confidently call @code{icon-string} in all circumstances and
+be sure that something readable will appear on the screen, no
+matter whether the user is on a graphical terminal or a text terminal,
+and no matter which features Emacs was built with.
+
+@defmac define-icon name parent specs doc &rest keywords
+Define an icon @var{name}, a symbol, with the display alternatives in
+@var{spec}, that can be later instantiated using @code{icon-string}.
+The @var{name} is the name of the resulting keyword.
+
+The resulting icon will inherit specs from @var{parent}, and from
+their parent's parents, and so on, and the lowest descendent element
+wins.
+
+@var{specs} is a list of icon specifications.  The first element of each
+specification is the type, and the rest is something that can be used
+as an icon of that type, and then optionally followed by a keyword
+list.  The following icon types are available:
+
+@cindex icon types
+@table @code
+@item image
+In this case, there may be many images listed as candidates.  Emacs
+will choose the first one that the current Emacs instance can show.
+If an image is listed is an absolute file name, it's used as is, but it's
+otherwise looked up in the list @code{image-load-path}
+(@pxref{Defining Images}).
+
+@item emoji
+This should be a (possibly colorful) emoji.
+
+@item symbol
+This should be a (monochrome) symbol character.
+
+@item text
+Icons should also have a textual fallback.  This can also be used for
+the visually impaired: if @code{icon-preference} is just
+@code{(text)}, all icons will be replaced by text.
+@end table
+
+Various keywords may follow the list of icon specifications.  For
+instance:
+
+@example
+(symbol "▶" "➤" :face icon-button)
+@end example
+
+Unknown keywords are ignored.  The following keywords are allowed:
+
+@cindex icon keywords
+@table @code
+@item :face
+The face to be used for the icon.
+
+@item :height
+This is only valid for @code{image} icons, and can be either a number
+(which specifies the height in pixels), or the symbol @code{line},
+which will use the default line height in the currently selected
+window.
+@end table
+
+@var{doc} should be a doc string.
+
+@var{keywords} is a list of keyword/value pairs.  The following
+keywords are allowed:
+
+@table @code
+@item :version
+The (approximate) Emacs version this button first appeared.  (This
+keyword is mandatory.)
+
+@item :group
+The customization group this icon belongs in.  If not present, it is
+inferred.
+
+@item :help-echo
+The help string shown when hovering over the icon with the mouse
+pointer.
+@end table
+@end defmac
+
+@defun icon-string icon
+This function returns a string suitable for display in the current
+buffer for @var{icon}.
+@end defun
+
+@defun icon-elements icon
+Alternatively, you can get a ``deconstructed'' version of @var{icon}
+with this function.  It returns a plist (@pxref{Property Lists}) where
+the keys are @code{string}, @code{face} and @var{image}.  (The latter
+is only present if the icon is represented by an image.)  This can be
+useful if the icon isn't to be inserted directly in the buffer, but
+needs some sort of pre-processing first.
+@end defun
+
+Icons can be customized with @kbd{M-x customize-icon}.  Themes can
+specify changes to icons with, for instance:
+
+@lisp
+(custom-theme-set-icons
+  'my-theme
+  '(outline-open ((image :height 100)
+                  (text " OPEN ")))
+  '(outline-close ((image :height 100)
+                   (text " CLOSE " :face warning))))
+@end lisp
+
+
 @node Xwidgets
 @section Embedded Native Widgets
 @cindex xwidget
@@ -7309,6 +7489,7 @@ the usual Emacs @code{highlight} face.
 
 @item keymap
 @kindex keymap @r{(button property)}
+@vindex button-map
 The button's keymap, defining bindings active within the button
 region.  By default this is the usual button region keymap, stored
 in the variable @code{button-map}, which defines @key{RET} and
@@ -7523,6 +7704,7 @@ Return @code{t} if button-type @var{type} is a subtype of 
@var{supertype}.
 These are commands and functions for locating and operating on
 buttons in an Emacs buffer.
 
+@cindex buffer-button-map
 @code{push-button} is the command that a user uses to actually push
 a button, and is bound by default in the button itself to @key{RET}
 and to @key{mouse-2} using a local keymap in the button's overlay or
@@ -8360,7 +8542,11 @@ hexadecimal notation.
 
 @item an @acronym{ASCII} string
 Display a box containing that string.  The string should contain at
-most 6 @acronym{ASCII} characters.
+most 6 @acronym{ASCII} characters.  As an exception, if the string
+includes just one character, on text-mode terminals that character
+will be displayed without a box; this allows to handle such
+``acronyms'' as a replacement character for characters that cannot be
+displayed by the terminal.
 
 @item a cons cell @code{(@var{graphical} . @var{text})}
 Display with @var{graphical} on graphical displays, and with
@@ -8426,9 +8612,9 @@ Characters of Unicode General Category [Cf], such as 
U+200E
 images, such as U+00AD @sc{soft hyphen}.
 
 @item variation-selectors
-Unicode VS-1 through VS-16 (U+FE00 through U+FE0F), which are used to
-select between different glyphs for the same codepoints (typically
-emojis).
+Unicode VS-1 through VS-256 (U+FE00 through U+FE0F and U+E0100 through
+U+E01EF), which are used to select between different glyphs for the same
+codepoints (typically emojis).
 
 @item no-font
 Characters for which there is no suitable font, or which cannot be
@@ -8556,7 +8742,7 @@ displayed in the echo area.
 @vindex use-system-tooltips
 When Emacs is built with the GTK+ toolkit or Haiku windowing support,
 it by default displays tooltips using toolkit functions, and the
-appearance of the tooltips is then controlled by by the toolkit's
+appearance of the tooltips is then controlled by the toolkit's
 settings.  Toolkit-provided tooltips can be disabled by changing the
 value of the variable @code{use-system-tooltips} to @code{nil}.  The
 rest of this subsection describes how to control non-toolkit tooltips,
diff --git a/doc/lispref/edebug.texi b/doc/lispref/edebug.texi
index 0fc5271d5a..56f7b7bdfa 100644
--- a/doc/lispref/edebug.texi
+++ b/doc/lispref/edebug.texi
@@ -701,7 +701,11 @@ on this process.
 @item e @var{exp} @key{RET}
 Evaluate expression @var{exp} in the context outside of Edebug
 (@code{edebug-eval-expression}).  That is, Edebug tries to minimize
-its interference with the evaluation.  By default, this command
+its interference with the evaluation.  The result is shown in the echo
+area, or, if this command is given a prefix, pop up a new buffer and
+pretty-print the result there.
+
+By default, this command
 suppresses the debugger during evaluation, so that an error in the
 evaluated expression won't add a new error on top of the existing one.
 Set the @code{debug-allow-recursive-debug} user option to a
@@ -715,7 +719,8 @@ Evaluate expression @var{exp} in the context of Edebug 
itself
 Evaluate the expression before point, in the context outside of Edebug
 (@code{edebug-eval-last-sexp}).  With the prefix argument of zero
 (@kbd{C-u 0 C-x C-e}), don't shorten long items (like strings and
-lists).
+lists).  Any other prefix will result in the value being
+pretty-printed in a separate buffer.
 @end table
 
 @cindex lexical binding (Edebug)
@@ -836,7 +841,6 @@ you continue execution, and recreated next time it is 
needed.
 
 @cindex printing (Edebug)
 @cindex printing circular structures
-@pindex cust-print
   If an expression in your program produces a value containing circular
 list structure, you may get an error when Edebug attempts to print it.
 
diff --git a/doc/lispref/files.texi b/doc/lispref/files.texi
index ea8683a6d8..986fb22c75 100644
--- a/doc/lispref/files.texi
+++ b/doc/lispref/files.texi
@@ -2445,6 +2445,15 @@ You can use this function for directory names and for 
file names,
 because it recognizes abbreviations even as part of the name.
 @end defun
 
+@defun file-parent-directory filename
+This function returns the directory name of the parent directory of
+@var{filename}.  If @var{filename} is at the root directory of the
+filesystem, it returns @code{nil}.  A relative @var{filename} is
+assumed to be relative to @code{default-directory}, and the return
+value will also be relative in that case.  If the return value is
+non-@code{nil}, it ends in a slash.
+@end defun
+
 @node File Name Expansion
 @subsection Functions that Expand Filenames
 @cindex expansion of file names
diff --git a/doc/lispref/frames.texi b/doc/lispref/frames.texi
index 16f7ad312a..262b86672d 100644
--- a/doc/lispref/frames.texi
+++ b/doc/lispref/frames.texi
@@ -1746,15 +1746,16 @@ fit will be clipped by the window manager.
 @item fullscreen
 This parameter specifies whether to maximize the frame's width, height
 or both.  Its value can be @code{fullwidth}, @code{fullheight},
-@code{fullboth}, or @code{maximized}.  A @dfn{fullwidth} frame is as
-wide as possible, a @dfn{fullheight} frame is as tall as possible, and
-a @dfn{fullboth} frame is both as wide and as tall as possible.  A
-@dfn{maximized} frame is like a ``fullboth'' frame, except that it
-usually keeps its title bar and the buttons for resizing and closing
-the frame.  Also, maximized frames typically avoid hiding any task bar
-or panels displayed on the desktop.  A ``fullboth'' frame, on the
-other hand, usually omits the title bar and occupies the entire
-available screen space.
+@code{fullboth}, or @code{maximized}.@footnote{On PGTK frames, setting
+the values @code{fullheight} and @code{fullwidth} has no effect.}  A
+@dfn{fullwidth} frame is as wide as possible, a @dfn{fullheight} frame
+is as tall as possible, and a @dfn{fullboth} frame is both as wide and
+as tall as possible.  A @dfn{maximized} frame is like a ``fullboth''
+frame, except that it usually keeps its title bar and the buttons for
+resizing and closing the frame.  Also, maximized frames typically
+avoid hiding any task bar or panels displayed on the desktop.  A
+``fullboth'' frame, on the other hand, usually omits the title bar and
+occupies the entire available screen space.
 
 Full-height and full-width frames are more similar to maximized
 frames in this regard.  However, these typically display an external
@@ -2179,10 +2180,20 @@ If non-@code{nil}, the frame is visible on all virtual 
desktops on systems
 with virtual desktops.
 
 @vindex shaded@r{, a frame parameter}
-@item sticky
+@item shaded
 If non-@code{nil}, tell the window manager to display the frame in a
 way that its contents are hidden, leaving only the title bar.
 
+@vindex use-frame-synchronization@r{, a frame parameter}
+@item use-frame-synchronization
+If non-@code{nil}, synchronize the frame redisplay with the refresh
+rate of the monitor to avoid graphics tearing.  At present, this is
+only implemented on Haiku and the X window system inside no-toolkit
+and X toolkit builds, does not work correctly with toolkit scroll
+bars, and requires a compositing manager supporting the relevant
+display synchronization protocols.  The @code{synchronizeResize} X
+resource must also be set to the string @code{"extended"}.
+
 @vindex inhibit-double-buffering@r{, a frame parameter}
 @item inhibit-double-buffering
 If non-@code{nil}, the frame is drawn to the screen without double
@@ -4090,6 +4101,20 @@ They can either be the same data types that are 
typically accepted by
 specific drag-n-drop protocol being used.  Plain text may be
 @code{"STRING"} or @code{"text/plain"}, for example.
 
+@vindex x-dnd-direct-save-function
+  However, @code{x-dnd-types-alist} does not handle a special kind of
+drop sent by a program which wants Emacs to save a file in a location
+Emacs must determine by itself.  These drops are handled via the
+variable @code{x-dnd-direct-save-function}, which should be a function
+that accepts two arguments.  If the first argument is non-@code{nil},
+then the second argument is a string describing the name (with no
+leading directory) that the other program recommends the file be saved
+under, and the function should return the complete file name under
+which it will be saved.  Otherwise, the file has already been saved,
+and the second argument is the complete name of the file.  The
+function should then perform whatever action is appropriate (i.e.,
+open the file or refresh the directory listing.)
+
 @cindex initiating drag-and-drop
   On capable window systems, Emacs also supports dragging contents
 from its frames to windows of other applications.
@@ -4186,6 +4211,13 @@ This function is like @code{dnd-begin-file-drag}, except 
that
 dropping multiple files, then the first file will be used instead.
 @end defun
 
+@defun dnd-direct-save file name &optional frame allow-same-frame
+This function is similar to @code{dnd-begin-file-drag} (with the
+default action of copy), but instead of specifying the action you
+specify the name of the copy created by the target program in
+@code{name}.
+@end defun
+
 @cindex initiating drag-and-drop, low-level
   The high-level interfaces described above are implemented on top of
 a lower-level primitive.  If you need to drag content other than files
@@ -4251,6 +4283,40 @@ chosen by the target.  For example, callers should 
delete the buffer
 text that was dragged if this function returns @code{XdndActionMove}.
 @end defun
 
+@cindex drag and drop protocols, X
+
+  On X Windows, several different drag-and-drop protocols are
+supported by @code{x-begin-drag}.  When dragging content that is known
+to not be supported by a specific drag-and-drop protocol, it might be
+desirable to turn that protocol off, by changing the values of the
+following variables:
+
+@defvar x-dnd-disable-motif-protocol
+When this is non-@code{nil}, the Motif drag and drop protocols are
+disabled, and dropping onto programs that only understand them will
+not work.
+@end defvar
+
+@defvar x-dnd-use-offix-drop
+When this is @code{nil}, the OffiX (old KDE) drag and drop protocol is
+disabled.  When this is the symbol @code{files}, the OffiX protocol
+will only be used if @code{"FILE_NAME"} is one of the targets given to
+@code{x-begin-drag}.  Any other value means to use the OffiX protocol
+to drop all supported content.
+@end defvar
+
+@defvar x-dnd-use-unsupported-drop
+When one of the @code{"STRING"}, @code{"UTF8_STRING"},
+@code{"COMPOUND_TEXT"} or @code{"TEXT"} targets is present in the list
+given to @code{x-begin-drag}, Emacs will try to use synthesized mouse
+events and the primary selection to insert the text if the drop target
+doesn't support any drag-and-drop protocol at all.
+
+A side effect is that Emacs will become the owner of the primary
+selection upon such a drop.  If that is not desired, then the drop
+emulation can be disabled by setting this variable to @code{nil}.
+@end defvar
+
 @node Color Names
 @section Color Names
 
diff --git a/doc/lispref/functions.texi b/doc/lispref/functions.texi
index e3de6009e9..983dfe2ec5 100644
--- a/doc/lispref/functions.texi
+++ b/doc/lispref/functions.texi
@@ -217,6 +217,16 @@ function.  For example:
 @end example
 @end defun
 
+@defun compiled-function-p object
+This function returns @code{t} if @var{object} is a function object
+that is not in the form of ELisp source code but something like
+machine code or byte code instead.  More specifically it returns
+@code{t} if the function is built-in (a.k.a.@: ``primitive'',
+@pxref{What Is a Function}), or byte-compiled (@pxref{Byte
+Compilation}), or natively-compiled (@pxref{Native Compilation}), or
+a function loaded from a dynamic module (@pxref{Dynamic Modules}).
+@end defun
+
 @defun subr-arity subr
 This works like @code{func-arity}, but only for built-in functions and
 without symbol indirection.  It signals an error for non-built-in
@@ -2497,6 +2507,34 @@ the current buffer.
 @item (modes @var{modes})
 Specify that this command is meant to be applicable for @var{modes}
 only.
+
+@item (interactive-args @var{arg} ...)
+Specify the arguments that should be stored for @code{repeat-command}.
+Each @var{arg} is on the form @code{@var{argument-name} @var{form}}.
+
+@item (pure @var{val})
+If @var{val} is non-@code{nil}, this function is @dfn{pure}
+(@pxref{What Is a Function}).  This is the same as the @code{pure}
+property of the function's symbol (@pxref{Standard Properties}).
+
+@item (side-effect-free @var{val})
+If @var{val} is non-@code{nil}, this function is free of side effects,
+so the byte compiler can ignore calls whose value is ignored.  This is
+the same as the @code{side-effect-free} property of the function's
+symbol, @pxref{Standard Properties}.
+
+@item (speed @var{n})
+Specify the value of @code{native-comp-speed} in effect for native
+compilation of this function (@pxref{Native-Compilation Variables}).
+This allows function-level control of the optimization level used for
+native code emitted for the function.  In particular, if @var{n} is
+@minus{}1, native compilation of the function will emit bytecode
+instead of native code for the function.
+
+@item no-font-lock-keyword
+This is valid for macros only.  Macros with this declaration are
+highlighted by font-lock (@pxref{Font Lock Mode}) as normal functions,
+not specially as macros.
 @end table
 
 @end defmac
diff --git a/doc/lispref/hash.texi b/doc/lispref/hash.texi
index a566d89824..25a56bd715 100644
--- a/doc/lispref/hash.texi
+++ b/doc/lispref/hash.texi
@@ -203,7 +203,8 @@ association in @var{table}.
 @defun puthash key value table
 This function enters an association for @var{key} in @var{table}, with
 value @var{value}.  If @var{key} already has an association in
-@var{table}, @var{value} replaces the old associated value.
+@var{table}, @var{value} replaces the old associated value.  This
+function always returns @var{value}.
 @end defun
 
 @defun remhash key table
@@ -219,10 +220,7 @@ otherwise.  In Emacs Lisp, @code{remhash} always returns 
@code{nil}.
 @defun clrhash table
 This function removes all the associations from hash table @var{table},
 so that it becomes empty.  This is also called @dfn{clearing} the hash
-table.
-
-@b{Common Lisp note:} In Common Lisp, @code{clrhash} returns the empty
-@var{table}.  In Emacs Lisp, it returns @code{nil}.
+table.  @code{clrhash} returns the empty @var{table}.
 @end defun
 
 @defun maphash function table
@@ -289,9 +287,13 @@ If two objects @var{obj1} and @var{obj2} are @code{equal}, 
then
 are the same integer.
 
 If the two objects are not @code{equal}, the values returned by
-@code{sxhash-equal} are usually different, but not always; once in a
-rare while, by luck, you will encounter two distinct-looking objects
-that give the same result from @code{sxhash-equal}.
+@code{sxhash-equal} are usually different, but not always.
+@code{sxhash-equal} is designed to be reasonably fast (since it's used
+for indexing hash tables) so it won't recurse deeply into nested
+structures.  In addition; once in a rare while, by luck, you will
+encounter two distinct-looking simple objects that give the same
+result from @code{sxhash-equal}.  So you can't, in general, use
+@code{sxhash-equal} to check whether an object has changed.
 
 @b{Common Lisp note:} In Common Lisp a similar function is called
 @code{sxhash}.  Emacs provides this name as a compatibility alias for
@@ -322,15 +324,13 @@ the same integer.
 compared case-insensitively.
 
 @example
-(defun case-fold-string= (a b)
-  (eq t (compare-strings a nil nil b nil nil t)))
-(defun case-fold-string-hash (a)
+(defun string-hash-ignore-case (a)
   (sxhash-equal (upcase a)))
 
-(define-hash-table-test 'case-fold
-  'case-fold-string= 'case-fold-string-hash)
+(define-hash-table-test 'ignore-case
+  'string-equal-ignore-case 'string-hash-ignore-case)
 
-(make-hash-table :test 'case-fold)
+(make-hash-table :test 'ignore-case)
 @end example
 
   Here is how you could define a hash table test equivalent to the
diff --git a/doc/lispref/hooks.texi b/doc/lispref/hooks.texi
index 107d036202..339e1387d2 100644
--- a/doc/lispref/hooks.texi
+++ b/doc/lispref/hooks.texi
@@ -280,7 +280,6 @@ kbd-macro-termination-hook
 signal-hook-function
 
 C functions:
-redisplay-end-trigger-functions
 x-lost-selection-functions
 x-sent-selection-functions
 
@@ -290,7 +289,6 @@ auto-fill-function
 command-error-function
 compose-chars-after-function
 composition-function-table
-deferred-action-function
 input-method-function
 load-read-function
 load-source-file-function
diff --git a/doc/lispref/keymaps.texi b/doc/lispref/keymaps.texi
index a037c228f1..2be31d63a6 100644
--- a/doc/lispref/keymaps.texi
+++ b/doc/lispref/keymaps.texi
@@ -374,7 +374,8 @@ number of keys.  Here's a very basic example:
 @end lisp
 
 This function creates a new sparse keymap, defines the keystrokes in
-@var{pairs}, and returns the new keymap.
+@var{pairs}, and returns the new keymap.  It signals an error if there
+are duplicate key bindings in @var{pairs}.
 
 @var{pairs} is a list of alternating key bindings and key definitions,
 as accepted by @code{keymap-set}.  In addition, the key can be the
@@ -438,7 +439,8 @@ variable.  This is what virtually all modes do---a mode 
called
 
 This macro defines @var{name} as a variable, passes @var{options}
 and @var{pairs} to @code{define-keymap}, and uses the result as the
-default value for the variable.
+default value for the variable.  It signals an error if there are
+duplicate key bindings in @var{pairs}.
 
 @var{options} is like the keywords in @code{define-keymap}, but
 there's an additional @code{:doc} keyword that provides the doc
@@ -579,11 +581,10 @@ override any non-@code{nil} binding in any other of the 
@var{maps}.
 @code{button-buffer-map} and @code{special-mode-map}:
 
 @example
-(defvar help-mode-map
-  (let ((map (make-sparse-keymap)))
-    (set-keymap-parent map
-      (make-composed-keymap button-buffer-map special-mode-map))
-    ... map) ... )
+(defvar-keymap help-mode-map
+  :parent (make-composed-keymap button-buffer-map
+                                special-mode-map)
+  ...)
 @end example
 
 
@@ -1064,6 +1065,20 @@ The optional argument @var{on-exit}, if non-@code{nil}, 
specifies a
 function that is called, with no arguments, after @var{keymap} is
 deactivated.
 
+The optional argument @var{message} specifies the message to display
+after activating the transient map.  If @var{message} is a string, it
+is the format string for the message, and any @samp{%k} specifier in
+that string is replaced with the list of keys from the transient map.
+Any other non-@code{nil} value of @var{message} stands for the default
+message format @samp{Repeat with %k}.
+
+@vindex set-transient-map-timeout
+If the optional argument @var{timeout} is non-@code{nil}, it should be
+a number that specifies how many seconds of idle time to wait before
+deactivating @var{keymap}.  The value of the variable
+@code{set-transient-map-timeout}, if non-@code{nil}, overrides the
+value of this argument.
+
 This function works by adding and removing @var{keymap} from the
 variable @code{overriding-terminal-local-map}, which takes precedence
 over all other active keymaps (@pxref{Searching Keymaps}).
@@ -1869,6 +1884,7 @@ to make entries in @code{input-decode-map} beyond those 
that can be
 deduced from Termcap and Terminfo.  @xref{Terminal-Specific}.
 @end defvar
 
+@cindex function-key-map
 @defvar local-function-key-map
 This variable holds a keymap similar to @code{input-decode-map} except
 that it describes key sequences which should be translated to
@@ -2209,6 +2225,11 @@ If @var{no-remap} is @code{nil}, return the bindings for
 non-@code{nil}, return the bindings for @var{command}, ignoring the
 fact that it is remapped.
 @end table
+
+If a command maps to a key binding like @code{[some-event]}, and
+@code{some-event} has a symbol plist containing a non-@code{nil}
+@code{non-key-event} property, then that binding is ignored by
+@code{where-is-internal}.
 @end defun
 
 @deffn Command describe-bindings &optional prefix buffer-or-name
diff --git a/doc/lispref/lists.texi b/doc/lispref/lists.texi
index 4a862ab0de..5c5c615f85 100644
--- a/doc/lispref/lists.texi
+++ b/doc/lispref/lists.texi
@@ -340,6 +340,44 @@ If @var{n} is zero, @code{nthcdr} returns all of
 @end example
 @end defun
 
+@defun take n list
+This function returns the @var{n} first elements of @var{list}.  Essentially,
+it returns the part of @var{list} that @code{nthcdr} skips.
+
+@code{take} returns @var{list} if shorter than @var{n} elements;
+it returns @code{nil} if @var{n} is zero or negative.
+
+@example
+@group
+(take 3 '(a b c d))
+     @result{} (a b c)
+@end group
+@group
+(take 10 '(a b c d))
+     @result{} (a b c d)
+@end group
+@group
+(take 0 '(a b c d))
+     @result{} nil
+@end group
+@end example
+@end defun
+
+@defun ntake n list
+This is a version of @code{take} that works by destructively modifying
+the list structure of the argument.  That makes it faster, but the
+original value of @var{list} may be lost.
+
+@code{ntake} returns @var{list} unmodified if shorter than @var{n}
+elements; it returns @code{nil} if @var{n} is zero or negative.
+Otherwise, it returns @var{list} truncated to its first @var{n}
+elements.
+
+This means that it is usually a good idea to use the return value and
+not just rely on the truncation effect unless @var{n} is known to be
+positive.
+@end defun
+
 @defun last list &optional n
 This function returns the last link of @var{list}.  The @code{car} of
 this link is the list's last element.  If @var{list} is null,
@@ -1925,9 +1963,10 @@ and later discarded; this is not possible with a 
property list.
   The following functions can be used to manipulate property lists.
 They all compare property names using @code{eq}.
 
-@defun plist-get plist property
+@defun plist-get plist property &optional predicate
 This returns the value of the @var{property} property stored in the
-property list @var{plist}.  It accepts a malformed @var{plist}
+property list @var{plist}.  Comparisons are done with @var{predicate},
+and defaults to @code{eq}.  It accepts a malformed @var{plist}
 argument.  If @var{property} is not found in the @var{plist}, it
 returns @code{nil}.  For example,
 
@@ -1943,9 +1982,10 @@ returns @code{nil}.  For example,
 @end example
 @end defun
 
-@defun plist-put plist property value
+@defun plist-put plist property value &optional predicate
 This stores @var{value} as the value of the @var{property} property in
-the property list @var{plist}.  It may modify @var{plist} destructively,
+the property list @var{plist}.  Comparisons are done with @var{predicate},
+and defaults to @code{eq}.  It may modify @var{plist} destructively,
 or it may construct a new list structure without altering the old.  The
 function returns the modified property list, so you can store that back
 in the place where you got @var{plist}.  For example,
@@ -1961,19 +2001,20 @@ in the place where you got @var{plist}.  For example,
 @end defun
 
 @defun lax-plist-get plist property
-Like @code{plist-get} except that it compares properties
-using @code{equal} instead of @code{eq}.
+This obsolete function is like @code{plist-get} except that it
+compares properties using @code{equal} instead of @code{eq}.
 @end defun
 
 @defun lax-plist-put plist property value
-Like @code{plist-put} except that it compares properties
-using @code{equal} instead of @code{eq}.
+This obsolete function is like @code{plist-put} except that it
+compares properties using @code{equal} instead of @code{eq}.
 @end defun
 
-@defun plist-member plist property
+@defun plist-member plist property &optional predicate
 This returns non-@code{nil} if @var{plist} contains the given
-@var{property}.  Unlike @code{plist-get}, this allows you to distinguish
-between a missing property and a property with the value @code{nil}.
-The value is actually the tail of @var{plist} whose @code{car} is
-@var{property}.
+@var{property}.  Comparisons are done with @var{predicate}, and
+defaults to @code{eq}.  Unlike @code{plist-get}, this allows you to
+distinguish between a missing property and a property with the value
+@code{nil}.  The value is actually the tail of @var{plist} whose
+@code{car} is @var{property}.
 @end defun
diff --git a/doc/lispref/loading.texi b/doc/lispref/loading.texi
index 8a2bb5fa2d..4e4f12dc32 100644
--- a/doc/lispref/loading.texi
+++ b/doc/lispref/loading.texi
@@ -149,10 +149,9 @@ up the execution of uncompiled code.  Sometimes, this 
macro expansion
 cannot be done, owing to a cyclic dependency.  In the simplest
 example of this, the file you are loading refers to a macro defined
 in another file, and that file in turn requires the file you are
-loading.  This is generally harmless.  Emacs prints a warning
+loading.  Emacs will issue an error about
 (@samp{Eager macro-expansion skipped due to cycle@dots{}})
-giving details of the problem, but it still loads the file, just
-leaving the macro unexpanded for now.  You may wish to restructure
+giving details of the problem.  You have to restructure
 your code so that this does not happen.  Loading a compiled file does
 not cause macroexpansion, because this should already have happened
 during compilation.  @xref{Compiling Macros}.
@@ -441,7 +440,7 @@ similarly-named file in a directory earlier on 
@code{load-path}.
 For instance, suppose @code{load-path} is set to
 
 @example
-  ("/opt/emacs/site-lisp" "/usr/share/emacs/23.3/lisp")
+  ("/opt/emacs/site-lisp" "/usr/share/emacs/29.1/lisp")
 @end example
 
 @noindent
@@ -699,14 +698,13 @@ Switch to *doctor* buffer and start giving psychotherapy.
 
 @noindent
 @cindex @code{fn} in function's documentation string
-The backslash and newline immediately following the double-quote are a
-convention used only in the preloaded uncompiled Lisp files such as
-@file{loaddefs.el}; they tell @code{make-docfile} to put the
-documentation string in the @file{etc/DOC} file.  @xref{Building Emacs}.
-See also the commentary in @file{lib-src/make-docfile.c}.  @samp{(fn)}
-in the usage part of the documentation string is replaced with the
-function's name when the various help functions (@pxref{Help
-Functions}) display it.
+While the @file{loaddefs.el} isn't for editing, we try to keep it
+somewhat readable for people.  For instance, control characters in
+@code{defvar} values are escaped, and we insert a backslash and
+newline immediately following the double-quote of the doc string to
+keep the line length down.  @samp{(fn)} in the usage part of the
+documentation string is replaced with the function's name when the
+various help functions (@pxref{Help Functions}) display it.
 
   If you write a function definition with an unusual macro that is not
 one of the known and recognized function definition methods, use of an
@@ -729,7 +727,7 @@ variables to control this:
 The value of this constant is a regexp that matches autoload cookies.
 @code{loaddefs-generate} copies the Lisp form that follows the
 cookie into the autoload file it generates.  This will match comments
-like like @samp{;;;###autoload} and @samp{;;;###calc-autoload}.
+like @samp{;;;###autoload} and @samp{;;;###calc-autoload}.
 @end defvar
 
 @defvar generated-autoload-file
@@ -768,7 +766,7 @@ the corresponding list of files to load for it.  Entries to 
this
 mapping are added by calls to @code{register-definition-prefixes}
 which are generated by @code{loaddefs-generate}
 (@pxref{Autoload}).  Files which don't contain any definitions worth
-loading (test files, for examples), should set
+loading (test files, for example), should set
 @code{autoload-compute-prefixes} to @code{nil} as a file-local
 variable.
 
@@ -1033,7 +1031,7 @@ with a call to @code{provide}.  The order of the elements 
in the
 @cindex symbol, where defined
 @cindex where was a symbol defined
 
-@defun symbol-file symbol &optional type
+@defun symbol-file symbol &optional type native-p
 This function returns the name of the file that defined @var{symbol}.
 If @var{type} is @code{nil}, then any kind of definition is acceptable.
 If @var{type} is @code{defun}, @code{defvar}, or @code{defface}, that
@@ -1044,6 +1042,14 @@ The value is normally an absolute file name.  It can 
also be @code{nil},
 if the definition is not associated with any file.  If @var{symbol}
 specifies an autoloaded function, the value can be a relative file name
 without extension.
+
+If the optional third argument @var{native-p} is non-@code{nil}, and
+Emacs was built with native compilation support (@pxref{Native
+Compilation}), this function will try to find the @file{.eln} file
+that defined @var{symbol}, instead of the @file{.elc} or @file{.el}
+file.  If such a @file{.eln} file is found and is not outdated, the
+function will return its absolute file name; otherwise it will report
+the name of either the source or the byte-compiled file.
 @end defun
 
   The basis for @code{symbol-file} is the data in the variable
diff --git a/doc/lispref/maps.texi b/doc/lispref/maps.texi
index 90497728a1..d18b553dc1 100644
--- a/doc/lispref/maps.texi
+++ b/doc/lispref/maps.texi
@@ -125,6 +125,7 @@ setup-language-environment-map, 
describe-language-environment-map,
 menu-bar-epatch-menu, menu-bar-ediff-merge-menu, menu-bar-ediff-menu, etc.
 @end ignore
 
+@cindex minibuffer-inactive-mode-map
 @item minibuffer-inactive-mode-map
 A full keymap used in the minibuffer when it is not active.@*
 @xref{Minibuffer Edit,, Editing in the Minibuffer, emacs, The GNU Emacs 
Manual}.
@@ -156,6 +157,7 @@ The global keymap used for the @kbd{C-x @key{RET}} prefix 
key.
 @vindex narrow-map
 A sparse keymap for subcommands of the prefix @kbd{C-x n}.
 
+@cindex prog-mode-map
 @item prog-mode-map
 The keymap used by Prog mode.@*
 @xref{Basic Major Modes}.
@@ -171,6 +173,7 @@ for multi-buffer replacements.  @xref{Search and Replace, 
query-replace-map}.
 @item search-map
 A sparse keymap that provides global bindings for search-related commands.
 
+@cindex special-mode-map
 @item special-mode-map
 The keymap used by Special mode.@*
 @xref{Basic Major Modes}.
@@ -179,6 +182,7 @@ The keymap used by Special mode.@*
 The global keymap used for the @kbd{C-x t} prefix key for tab-bar related 
commands.@*
 @xref{Tab Bars,,, emacs, The GNU Emacs Manual}.
 
+@cindex tab-bar-map
 @item tab-bar-map
 The keymap defining the contents of the tab bar.@*
 @xref{Tab Bars,,, emacs, The GNU Emacs Manual}.
diff --git a/doc/lispref/modes.texi b/doc/lispref/modes.texi
index 2e40cb25ef..ba8b548554 100644
--- a/doc/lispref/modes.texi
+++ b/doc/lispref/modes.texi
@@ -271,7 +271,7 @@ normal-mode}), but tries to force it not to choose any 
modes in
 
 @defun clean-mode
 Changing the major mode clears out most local variables, but it
-doesn't remove all artefacts in the buffer (like text properties and
+doesn't remove all artifacts in the buffer (like text properties and
 overlays).  It's rare to change a buffer from one major mode to
 another (except from @code{fundamental-mode} to everything else), so
 this is usually not a concern.  It can sometimes be convenient (mostly
@@ -1356,11 +1356,10 @@ the conventions listed above:
 ;; @r{Create the keymap for this mode.}
 @group
 (defvar-keymap text-mode-map
-  "C-M-i" #'ispell-complete-word
-  @dots{})
-  "Keymap for `text-mode'.
-Many other modes, such as `mail-mode', `outline-mode' and
-`indented-text-mode', inherit all the commands defined in this map.")
+  :doc "Keymap for `text-mode'.
+Many other modes, such as `mail-mode' and `outline-mode', inherit all
+the commands defined in this map."
+  "C-M-i" #'ispell-complete-word)
 @end group
 @end smallexample
 
@@ -3476,7 +3475,8 @@ fontification functions, and gives it two arguments, 
@var{start} and
 @var{end}, which specify the region to be fontified or refontified.
 If @var{function} performs fontifications, it can return a list of the
 form @w{@code{(jit-lock-bounds @var{beg} . @var{end})}}, to indicate
-the bounds of the region it actually fontified; JIT font-lock will use
+the bounds of the region it actually fontified; Just-In-Time (a.k.a.@:
+@acronym{``JIT''}) font-lock will use
 this information to optimize subsequent redisplay cycles and regions
 of buffer text it will pass to future calls to @var{function}.
 
@@ -3496,6 +3496,19 @@ If @var{function} was previously registered as a 
fontification
 function using @code{jit-lock-register}, this function unregisters it.
 @end defun
 
+@cindex debugging font-lock
+@cindex jit-lock functions, debugging
+@deffn Command jit-lock-debug-mode &optional arg
+This is a minor mode whose purpose is to help in debugging code that
+is run by JIT font-lock.  When this mode is enabled, most of the code
+that JIT font-lock normally runs during redisplay cycles, where Lisp
+errors are suppressed, is instead run by a timer.  Thus, this mode
+allows using debugging aids such as @code{debug-on-error}
+(@pxref{Error Debugging}) and Edebug (@pxref{Edebug}) for finding and
+fixing problems in font-lock code and any other code run by JIT
+font-lock.
+@end deffn
+
 @node Levels of Font Lock
 @subsection Levels of Font Lock
 
diff --git a/doc/lispref/objects.texi b/doc/lispref/objects.texi
index 1bae192455..7b5e9adee2 100644
--- a/doc/lispref/objects.texi
+++ b/doc/lispref/objects.texi
@@ -2022,6 +2022,9 @@ with references to further information.
 @item byte-code-function-p
 @xref{Byte-Code Type, byte-code-function-p}.
 
+@item compiled-function-p
+@xref{Byte-Code Type, compiled-function-p}.
+
 @item case-table-p
 @xref{Case Tables, case-table-p}.
 
diff --git a/doc/lispref/os.texi b/doc/lispref/os.texi
index 11a0d02338..3582801841 100644
--- a/doc/lispref/os.texi
+++ b/doc/lispref/os.texi
@@ -1541,20 +1541,20 @@ Year numbers count since the year 1 BCE, and do not 
skip zero
 as traditional Gregorian years do; for example, the year number
 @minus{}37 represents the Gregorian year 38 BCE@.
 
-@defun time-convert time &optional form
+@defun time-convert time form
 This function converts a time value into a Lisp timestamp.
 
-The optional @var{form} argument specifies the timestamp form to be
-returned.  If @var{form} is the symbol @code{integer}, this function
-returns an integer count of seconds.  If @var{form} is a positive
-integer, it specifies a clock frequency and this function returns an
-integer-pair timestamp @code{(@var{ticks} . @var{form})}.  If @var{form} is
+The @var{form} argument specifies the timestamp form to be returned.
+If @var{form} is the symbol @code{integer}, this function returns an
+integer count of seconds.  If @var{form} is a positive integer, it
+specifies a clock frequency and this function returns an integer-pair
+timestamp @code{(@var{ticks} . @var{form})}.  If @var{form} is
 @code{t}, this function treats it as a positive integer suitable for
 representing the timestamp; for example, it is treated as 1000000000
 if @var{time} is @code{nil} and the platform timestamp has nanosecond
 resolution.  If @var{form} is @code{list}, this function returns an
 integer list @code{(@var{high} @var{low} @var{micro} @var{pico})}.
-Although an omitted or @code{nil} @var{form} currently acts like
+Although a @code{nil} @var{form} currently acts like
 @code{list}, this is planned to change in a future Emacs version, so
 callers requiring list timestamps should pass @code{list} explicitly.
 
@@ -1754,9 +1754,10 @@ at the 15th of the month when adding months.  
Alternatively, you can use the
 @cindex time formatting
 @cindex formatting time values
 
-  These functions convert time values to text in a string, and vice versa.
-Time values include @code{nil}, finite numbers, and Lisp timestamps
-(@pxref{Time of Day}).
+  These functions convert time values to text in a string, and vice
+versa.  Time values are either represented as a Lisp timestamp
+(@pxref{Time of Day}) or a decoded time structure (@pxref{Time
+Conversion}).
 
 @defun date-to-time string
 This function parses the time-string @var{string} and returns the
@@ -1769,22 +1770,11 @@ The operating system limits the range of time and zone 
values.
 @end defun
 
 @defun parse-time-string string
-This function parses the time-string @var{string} into a list of the
-following form:
-
-@example
-(@var{sec} @var{min} @var{hour} @var{day} @var{mon} @var{year} @var{dow} 
@var{dst} @var{tz})
-@end example
-
-@noindent
-The format of this list is the same as what @code{decode-time} accepts
-(@pxref{Time Conversion}), and is described in more detail there.  Any
-@code{dst} element that cannot be determined from the input is set to
-@minus{}1, and any other unknown element is set to
-@code{nil}.  The argument @var{string} should resemble an RFC 822 (or later) or
-ISO 8601 string, like ``Fri, 25 Mar 2016 16:24:56 +0100'' or
-``1998-09-12T12:21:54-0200'', but this function will attempt to parse
-less well-formed time strings as well.
+This function parses the time-string @var{string} into a decoded time
+structure (@pxref{Time Conversion}).  The argument @var{string} should
+resemble an RFC 822 (or later) or ISO 8601 string, like ``Fri, 25 Mar
+2016 16:24:56 +0100'' or ``1998-09-12T12:21:54-0200'', but this
+function will attempt to parse less well-formed time strings as well.
 @end defun
 
 @vindex ISO 8601 date/time strings
@@ -1801,11 +1791,11 @@ time structures, except the final one, which returns 
three of them
 @end defun
 
 @defun format-time-string format-string &optional time zone
-
-This function converts @var{time} (or the current time, if
-@var{time} is omitted or @code{nil}) to a string according to
-@var{format-string}.  The conversion uses the time zone rule @var{zone}, which
-defaults to the current time zone rule.  @xref{Time Zone Rules}.  The argument
+This function converts @var{time} (which should be a Lisp timestamp,
+and defaults to the current time if @var{time} is omitted or
+@code{nil}) to a string according to @var{format-string}.  The
+conversion uses the time zone rule @var{zone}, which defaults to the
+current time zone rule.  @xref{Time Zone Rules}.  The argument
 @var{format-string} may contain @samp{%}-sequences which say to
 substitute parts of the time.  Here is a table of what the
 @samp{%}-sequences mean:
@@ -2077,7 +2067,12 @@ This returns @code{t} if the time value @var{t1} is less 
than the time value
 
 @defun time-equal-p t1 t2
 This returns @code{t} if the two time values @var{t1} and @var{t2} are
-equal.
+equal.  The result is @code{nil} if either argument is a NaN.
+For the purpose of comparison, a @code{nil} argument represents the
+current time with infinite resolution, so this function returns
+@code{nil} if one argument is @code{nil} and the other is not, and
+callers can therefore use @code{nil} to represent an unknown time
+value that does not equal any timestamp.
 @end defun
 
 @defun time-subtract t1 t2
@@ -2748,6 +2743,13 @@ if it is non-@code{nil}; this can be overridden by 
binding
 @code{coding-system-for-write} to a coding system of you choice
 (@pxref{Explicit Encoding}).
 
+In batch mode, Emacs will enlarge the value of the
+@code{gc-cons-percentage} variable from the default of @samp{0.1} up to
+@samp{1.0}.  Batch jobs that are supposed to run for a long time
+should adjust the limit back down again, because this means that less
+garbage collection will be performed by default (and more memory
+consumed).
+
 @defvar noninteractive
 This variable is non-@code{nil} when Emacs is running in batch mode.
 @end defvar
diff --git a/doc/lispref/positions.texi b/doc/lispref/positions.texi
index ca1166caac..7945232bf8 100644
--- a/doc/lispref/positions.texi
+++ b/doc/lispref/positions.texi
@@ -387,6 +387,16 @@ Return the position that @code{(end-of-line @var{count})}
 would move to.
 @end defun
 
+@defun pos-bol &optional count
+Like @code{line-beginning-position}, but ignores fields (and is more
+efficient).
+@end defun
+
+@defun pos-eol &optional count
+Like @code{line-end-position}, but ignores fields (and is more
+efficient).
+@end defun
+
 @deffn Command forward-line &optional count
 @cindex beginning of line
 This function moves point forward @var{count} lines, to the beginning of
@@ -1002,6 +1012,12 @@ positions.
 
 In an interactive call, @var{start} and @var{end} are set to the bounds
 of the current region (point and the mark, with the smallest first).
+
+Note that, in rare circumstances, Emacs may decide to leave, for
+performance reasons, the accessible portion of the buffer unchanged
+after a call to @code{narrow-to-region}.  This can happen when a Lisp
+program is called via low-level hooks, such as
+@code{jit-lock-functions}, @code{post-command-hook}, etc.
 @end deffn
 
 @deffn Command narrow-to-page &optional move-count
@@ -1027,6 +1043,12 @@ It is equivalent to the following expression:
 @end example
 @end deffn
 
+Note that, in rare circumstances, Emacs may decide to leave, for
+performance reasons, the accessible portion of the buffer unchanged
+after a call to @code{widen}.  This can happen when a Lisp program is
+called via low-level hooks, such as @code{jit-lock-functions},
+@code{post-command-hook}, etc.
+
 @defun buffer-narrowed-p
 This function returns non-@code{nil} if the buffer is narrowed, and
 @code{nil} otherwise.
diff --git a/doc/lispref/processes.texi b/doc/lispref/processes.texi
index 8c8f8fd6b2..db6b4c35ef 100644
--- a/doc/lispref/processes.texi
+++ b/doc/lispref/processes.texi
@@ -705,12 +705,13 @@ coding system will apply.  @xref{Default Coding Systems}.
 Initialize the type of device used to communicate with the subprocess.
 Possible values are @code{pty} to use a pty, @code{pipe} to use a
 pipe, or @code{nil} to use the default derived from the value of the
-@code{process-connection-type} variable.  This parameter and the value
-of @code{process-connection-type} are ignored if a non-@code{nil}
-value is specified for the @code{:stderr} parameter; in that case, the
-type will always be @code{pipe}.  On systems where ptys are not
-available (MS-Windows), this parameter is likewise ignored, and pipes
-are used unconditionally.
+@code{process-connection-type} variable.  If @var{type} is a cons cell
+@w{@code{(@var{input} . @var{output})}}, then @var{input} will be used
+for standard input and @var{output} for standard output (and standard
+error if @code{:stderr} is @code{nil}).
+
+On systems where ptys are not available (MS-Windows), this parameter
+is ignored, and pipes are used unconditionally.
 
 @item :noquery @var{query-flag}
 Initialize the process query flag to @var{query-flag}.
@@ -1242,15 +1243,24 @@ that are already closed, the value is either 0 or 256, 
depending on
 whether the connection was closed normally or abnormally.
 @end defun
 
-@defun process-tty-name process
+@defun process-tty-name process &optional stream
 This function returns the terminal name that @var{process} is using for
 its communication with Emacs---or @code{nil} if it is using pipes
 instead of a pty (see @code{process-connection-type} in
-@ref{Asynchronous Processes}).  If @var{process} represents a program
-running on a remote host, the terminal name used by that program on
-the remote host is provided as process property @code{remote-tty}.  If
-@var{process} represents a network, serial, or pipe connection, the
-value is @code{nil}.
+@ref{Asynchronous Processes}).  By default, this function returns the
+terminal name if any of @var{process}'s standard streams use a
+terminal.  If @var{stream} is one of @code{stdin}, @code{stdout}, or
+@code{stderr}, this function returns the terminal name (or @code{nil},
+as above) that @var{process} uses for that stream specifically.  You
+can use this to determine whether a particular stream uses a pipe or a
+pty.
+
+If @var{process} represents a program running on a remote host, this
+function returns the @emph{local} terminal name that communicates with
+@var{process}; you can get the terminal name used by that program on
+the remote host with the process property @code{remote-tty}.  If
+@var{process} represents a network, serial, or pipe connection, this
+function always returns @code{nil}.
 @end defun
 
 @defun process-coding-system process
@@ -1512,7 +1522,7 @@ This variable is a list of functions to be called for
 for @code{signal-process}.  These functions are called in the order of
 the list, until one of them returns non-@code{nil}.  The default
 function, which shall always be the last in this list, is
-@code{signal-default-interrupt-process}.
+@code{internal-default-signal-process}.
 
 This is the mechanism, how Tramp implements @code{signal-process}.
 @end defvar
@@ -1530,20 +1540,11 @@ a buffer, which is called the associated buffer of the 
process
 default filter discards the output.
 
   If the subprocess writes to its standard error stream, by default
-the error output is also passed to the process filter function.  If
-Emacs uses a pseudo-TTY (pty) for communication with the subprocess,
-then it is impossible to separate the standard output and standard
-error streams of the subprocess, because a pseudo-TTY has only one
-output channel.  In that case, if you want to keep the output to those
-streams separate, you should redirect one of them to a file---for
-example, by using an appropriate shell command via
-@code{start-process-shell-command} or a similar function.
-
-  Alternatively, you could use the @code{:stderr} parameter with a
+the error output is also passed to the process filter function.
+Alternatively, you could use the @code{:stderr} parameter with a
 non-@code{nil} value in a call to @code{make-process}
 (@pxref{Asynchronous Processes, make-process}) to make the destination
-of the error output separate from the standard output; in that case,
-Emacs will use pipes for communicating with the subprocess.
+of the error output separate from the standard output.
 
   When a subprocess terminates, Emacs reads any pending output,
 then stops reading output from that subprocess.  Therefore, if the
@@ -1959,7 +1960,6 @@ because @var{seconds} can be floating point to specify
 waiting a fractional number of seconds.  If @var{seconds} is 0, the
 function accepts whatever output is pending but does not wait.
 
-@c Emacs 22.1 feature
 If @var{process} is a process, and the argument @var{just-this-one} is
 non-@code{nil}, only output from that process is handled, suspending output
 from other processes until some output has been received from that
@@ -3204,20 +3204,39 @@ If the vector does not include the port number, 
@var{p}, or if
 @code{:@var{p}} suffix.
 @end defun
 
-@defun network-lookup-address-info name &optional family
-This function is used to perform hostname lookups on @var{name}, which
-is expected to be an ASCII-only string, otherwise an error is
-signaled. Call @code{puny-encode-domain} on @var{name}
-first if you wish to lookup internationalized hostnames.
+@defun network-lookup-address-info name &optional family hints
+This function perform hostname lookups on @var{name}, which is
+expected to be an ASCII-only string, otherwise it signals an error.  Call
+@code{puny-encode-domain} on @var{name} first if you wish to lookup
+internationalized hostnames.
 
-If successful it returns a list of Lisp representations of network
-addresses, otherwise it returns @code{nil}.  In the latter case, it
-also displays the error message hopefully explaining what went wrong.
+If successful, this function returns a list of Lisp representations of network
+addresses (@pxref{Network Processes}, for a description of the
+format), otherwise return @code{nil}.  In the latter case, it also logs
+an error message hopefully explaining what went wrong.
 
-By default both IPv4 and IPv6 lookups are attempted.  The optional
-argument @var{family} controls this behavior, specifying the symbol
-@code{ipv4} or @code{ipv6} restricts lookups to IPv4 and IPv6
+By default, this function attempts both IPv4 and IPv6 lookups.  The
+optional argument @var{family} controls this behavior, specifying the
+symbol @code{ipv4} or @code{ipv6} restricts lookups to IPv4 and IPv6
 respectively.
+
+If optional argument @var{hints} is @code{numeric}, the function
+treats the @var{name} as a numerical IP address (and does not perform DNS
+lookups).  This can be used to check whether a string is a valid
+numerical representation of an IP address, or to convert a numerical
+string to its canonical representation. e.g.@:
+
+@example
+(network-lookup-address-info "127.1" 'ipv4 'numeric)
+    @result{} ([127 0 0 1 0])
+
+(network-lookup-address-info "::1" nil 'numeric)
+    @result{} ([0 0 0 0 0 0 0 1 0])
+@end example
+
+Be warned that there are some surprising valid forms,
+especially for IPv4, e.g @samp{0xe3010203} and @samp{0343.1.2.3} are both
+valid, as are @samp{0} and @samp{1} (but they are invalid for IPv6).
 @end defun
 
 @node Serial Ports
@@ -3493,43 +3512,40 @@ any null bytes in the packed input string will appear 
in the unpacked
 output.
 
 @item strz &optional @var{len}
-If @var{len} is not provided: Variable-length null-terminated unibyte
-string (@pxref{Text Representations}).  When packing, the entire input
-string is copied to the packed output.  The following byte will be
-null (zero) unless a pre-allocated string was provided to
-@code{bindat-pack}, in which case that byte is left unmodified.  The
-length of the packed output is the length of the input string plus one
-(for the null terminator).  The input string must not contain any null
+If @var{len} is not provided, this is a variable-length
+null-terminated unibyte string (@pxref{Text Representations}).  When
+packing into @code{strz}, the entire input string is copied to the
+packed output followed by a null (zero) byte.  (If pre-allocated
+string is provided for packing into @code{strz}, that pre-allocated
+string should have enough space for the additional null byte appended
+to the output string contents, @pxref{Bindat Functions}).  The length
+of the packed output is the length of the input string plus one (for
+the null terminator).  The input string must not contain any null
 bytes.  If the input string is multibyte with only ASCII and
 @code{eight-bit} characters, it is converted to unibyte before it is
-packed; other multibyte strings signal an error.  When unpacking, the
-resulting string contains all bytes up to (but excluding) the null
-byte.
+packed; other multibyte strings signal an error.  When unpacking a
+@code{strz}, the resulting output string will contain all bytes up to
+(but excluding) the null byte that terminated the input string.
 
-@quotation Caution
-If a pre-allocated string is provided to @code{bindat-pack}, the
-packed output will not be properly null-terminated unless the
-pre-allocated string already has a null byte at the appropriate
-location.
-@end quotation
-
-If @var{len} is provided: @code{strz} behaves the same as @code{str}
-with one difference: When unpacking, the first null byte encountered
-in the packed string and all subsequent bytes are excluded from the
-unpacked result.
+If @var{len} is provided, @code{strz} behaves the same as @code{str},
+but with a couple of differences:
 
-@quotation Caution
-The packed output will not be null-terminated unless one of the
-following is true:
-@itemize
+@itemize @bullet
 @item
-The input string is shorter than @var{len} bytes and either no pre-allocated
-string was provided to @code{bindat-pack} or the appropriate byte in
-the pre-allocated string was already null.
+When packing, a null terminator is written after the packed input
+string if the number of characters in the input string is less than
+@var{len}.
+
 @item
-The input string contains a null byte within the first @var{len}
-bytes.
+When unpacking, the first null byte encountered in the packed string
+is interpreted as the terminating byte, and it and all subsequent
+bytes are excluded from the result of the unpacking.
 @end itemize
+
+@quotation Caution
+The packed output will not be null-terminated unless the input string
+is shorter than @var{len} bytes or it contains a null byte within the
+first @var{len} bytes.
 @end quotation
 
 @item vec @var{len} [@var{type}]
@@ -3550,7 +3566,7 @@ and @code{#x1c} @code{#x28} to @w{@code{(3 5 10 11 12)}}.
 
 @item fill @var{len}
 @var{len} bytes used as a mere filler.  In packing, these bytes are
-are left unchanged, which normally means they remain zero.
+left unchanged, which normally means they remain zero.
 When unpacking, this just returns nil.
 
 @item align @var{len}
diff --git a/doc/lispref/searching.texi b/doc/lispref/searching.texi
index 21a2c6c51e..5ee139a11d 100644
--- a/doc/lispref/searching.texi
+++ b/doc/lispref/searching.texi
@@ -1898,7 +1898,7 @@ attempts.  Other zero-width assertions may also bring 
benefits by
 causing a match to fail early.
 
 @item
-Avoid or-patterns in favour of character alternatives: write
+Avoid or-patterns in favor of character alternatives: write
 @samp{[ab]} instead of @samp{a\|b}.  Recall that @samp{\s-} and @samp{\sw}
 are equivalent to @samp{[[:space:]]} and @samp{[[:word:]]}, respectively.
 
@@ -1933,7 +1933,7 @@ purposes.
 
 @ifnottex
 @item
-Consider using @code{rx} (@pxref{Rx Notation}); it can optimise some
+Consider using @code{rx} (@pxref{Rx Notation}); it can optimize some
 or-patterns automatically and will never introduce capturing groups
 unless explicitly requested.
 @end ifnottex
diff --git a/doc/lispref/sequences.texi b/doc/lispref/sequences.texi
index c3f4cff301..39230d0adc 100644
--- a/doc/lispref/sequences.texi
+++ b/doc/lispref/sequences.texi
@@ -577,6 +577,20 @@ starting from the first one for which @var{predicate} 
returns @code{nil}.
 @end example
 @end defun
 
+@defun seq-split sequence length
+  This function returns a list consisting of sub-sequences of
+@var{sequence} of (at most) length @var{length}.  (The final element
+may be shorter than @var{length} if the length of @var{sequence} isn't
+a multiple of @var{length}.
+
+@example
+@group
+(seq-split [0 1 2 3 4] 2)
+@result{} ([0 1] [2 3] [4])
+@end group
+@end example
+@end defun
+
 @defun seq-do function sequence
   This function applies @var{function} to each element of
 @var{sequence} in turn (presumably for side effects), and returns
diff --git a/doc/lispref/strings.texi b/doc/lispref/strings.texi
index addf195fad..374381e595 100644
--- a/doc/lispref/strings.texi
+++ b/doc/lispref/strings.texi
@@ -560,6 +560,12 @@ Representations}.
 @code{string-equal} is another name for @code{string=}.
 @end defun
 
+@defun string-equal-ignore-case string1 string2
+@code{string-equal-ignore-case} compares strings ignoring case
+differences, like @code{char-equal} when @code{case-fold-search} is
+@code{t}.
+@end defun
+
 @cindex locale-dependent string equivalence
 @defun string-collate-equalp string1 string2 &optional locale ignore-case
 This function returns @code{t} if @var{string1} and @var{string2} are
@@ -567,11 +573,19 @@ equal with respect to collation rules.  A collation rule 
is not only
 determined by the lexicographic order of the characters contained in
 @var{string1} and @var{string2}, but also further rules about
 relations between these characters.  Usually, it is defined by the
-@var{locale} environment Emacs is running with.
-
-For example, characters with different coding points but
-the same meaning might be considered as equal, like different grave
-accent Unicode characters:
+@var{locale} environment Emacs is running with and by the Standard C
+library against which Emacs was linked@footnote{
+For more information about collation rules and their locale
+dependencies, see @uref{https://unicode.org/reports/tr10/, The Unicode
+Collation Algorithm}.  Some Standard C libraries, such as the
+@acronym{GNU} C Library (a.k.a.@: @dfn{glibc}) implement large
+portions of the Unicode Collation Algorithm and use the associated
+locale data, Common Locale Data Repository, or @acronym{CLDR}.
+}.
+
+For example, characters with different code points but the same
+meaning, like different grave accent Unicode characters, might, in
+some locales, be considered as equal:
 
 @example
 @group
@@ -759,7 +773,8 @@ The strings are compared by the numeric values of their 
characters.
 For instance, @var{str1} is considered less than @var{str2} if
 its first differing character has a smaller numeric value.  If
 @var{ignore-case} is non-@code{nil}, characters are converted to
-upper-case before comparing them.  Unibyte strings are converted to
+upper-case, using the current buffer's case-table (@pxref{Case
+Tables}), before comparing them.  Unibyte strings are converted to
 multibyte for comparison (@pxref{Text Representations}), so that a
 unibyte string and its conversion to multibyte are always regarded as
 equal.
diff --git a/doc/lispref/text.texi b/doc/lispref/text.texi
index 622f03d2a8..8b859042ad 100644
--- a/doc/lispref/text.texi
+++ b/doc/lispref/text.texi
@@ -243,10 +243,8 @@ using a function specified by the variable
 The default filter function consults the obsolete wrapper hook
 @code{filter-buffer-substring-functions} (see the documentation string
 of the macro @code{with-wrapper-hook} for the details about this
-obsolete facility), and the obsolete variable
-@code{buffer-substring-filters}.  If both of these are @code{nil}, it
-returns the unaltered text from the buffer, i.e., what
-@code{buffer-substring} would return.
+obsolete facility).  If it is @code{nil}, it returns the unaltered
+text from the buffer, i.e., what @code{buffer-substring} would return.
 
 If @var{delete} is non-@code{nil}, the function deletes the text
 between @var{start} and @var{end} after copying it, like
@@ -282,22 +280,12 @@ the same as those of @code{filter-buffer-substring}.
 
 The first hook function is passed a @var{fun} that is equivalent to
 the default operation of @code{filter-buffer-substring}, i.e., it
-returns the buffer-substring between @var{start} and @var{end}
-(processed by any @code{buffer-substring-filters}) and optionally
-deletes the original text from the buffer.  In most cases, the hook
-function will call @var{fun} once, and then do its own processing of
-the result.  The next hook function receives a @var{fun} equivalent to
-this, and so on.  The actual return value is the result of all the
-hook functions acting in sequence.
-@end defvar
-
-@defvar buffer-substring-filters
-The value of this obsolete variable should be a list of functions
-that accept a single string argument and return another string.
-The default @code{filter-buffer-substring} function passes the buffer
-substring to the first function in this list, and the return value of
-each function is passed to the next function.  The return value of the
-last function is passed to @code{filter-buffer-substring-functions}.
+returns the buffer-substring between @var{start} and @var{end} and
+optionally deletes the original text from the buffer.  In most cases,
+the hook function will call @var{fun} once, and then do its own
+processing of the result.  The next hook function receives a @var{fun}
+equivalent to this, and so on.  The actual return value is the result
+of all the hook functions acting in sequence.
 @end defvar
 
 @defun current-word &optional strict really-word
@@ -2378,6 +2366,9 @@ begins.  @xref{Usual Display}.
 amount of horizontal scrolling.  Consequently, a column value can be
 arbitrarily high.  The first (or leftmost) column is numbered 0.  They
 also ignore overlays and text properties, aside from invisibility.
+Invisible text is considered as having zero width, unless
+@code{buffer-invisibility-spec} specifies that invisible text should
+be displayed as ellipsis (@pxref{Invisible Text}).
 
 @defun current-column
 This function returns the horizontal position of point, measured in
@@ -2451,6 +2442,10 @@ This function returns the indentation of the current 
line, which is
 the horizontal position of the first nonblank character.  If the
 contents are entirely blank, then this is the horizontal position of the
 end of the line.
+
+This function considers invisible text as having zero width, unless
+@code{buffer-invisibility-spec} specifies that invisible text should
+be displayed as ellipsis.  @xref{Invisible Text}.
 @end defun
 
 @deffn Command indent-to column &optional minimum
@@ -3406,7 +3401,7 @@ for @var{object} is the current buffer.
 Search for the next region that has text property @var{prop} set to
 @var{value} according to @var{predicate}.
 
-This function is modelled after @code{search-forward} and friends in
+This function is modeled after @code{search-forward} and friends in
 that it moves point, but it returns a structure that describes the
 match instead of returning it in @code{match-beginning} and friends.
 
@@ -3485,7 +3480,7 @@ This will give you a list of all those URLs.
 @end defun
 
 @defun text-property-search-backward prop &optional value predicate not-current
-This is just like @code{text-property-search-backward}, but searches
+This is just like @code{text-property-search-forward}, but searches
 backward instead.  Point is placed at the beginning of the matched
 region instead of the end, though.
 @end defun
@@ -5478,12 +5473,15 @@ available in this Emacs session.
 When libxml2 support is available, the following functions can be used
 to parse HTML or XML text into Lisp object trees.
 
-@defun libxml-parse-html-region start end &optional base-url discard-comments
+@defun libxml-parse-html-region &optional start end base-url discard-comments
 This function parses the text between @var{start} and @var{end} as
 HTML, and returns a list representing the HTML @dfn{parse tree}.  It
 attempts to handle real-world HTML by robustly coping with syntax
 mistakes.
 
+If @var{start} or @var{end} are @code{nil}, they default to the values
+from @code{point-min} and @code{point-max}, respectively.
+
 The optional argument @var{base-url}, if non-@code{nil}, should be a
 string specifying the base URL for relative URLs occurring in links.
 
@@ -5529,7 +5527,7 @@ buffer.  The argument @var{dom} should be a list as 
generated by
 @end defun
 
 @cindex parsing xml
-@defun libxml-parse-xml-region start end &optional base-url discard-comments
+@defun libxml-parse-xml-region &optional start end base-url discard-comments
 This function is the same as @code{libxml-parse-html-region}, except
 that it parses the text as XML rather than HTML (so it is stricter
 about syntax).
diff --git a/doc/lispref/tips.texi b/doc/lispref/tips.texi
index 30146a89eb..3a1f6de12b 100644
--- a/doc/lispref/tips.texi
+++ b/doc/lispref/tips.texi
@@ -689,6 +689,18 @@ line.  This looks nice in the source code, but looks 
bizarre when users
 view the documentation.  Remember that the indentation before the
 starting double-quote is not part of the string!
 
+@item
+When documentation should display an ASCII apostrophe or grave accent,
+use @samp{\\='} or @samp{\\=`} in the documentation string literal so
+that the character is displayed as-is.
+
+@item
+In documentation strings, do not quote expressions that are not Lisp symbols,
+as these expressions can stand for themselves.  For example, write
+@samp{Return the list (NAME TYPE RANGE) ...}@: instead of
+@samp{Return the list `(NAME TYPE RANGE)' ...}@: or
+@samp{Return the list \\='(NAME TYPE RANGE) ...}.
+
 @anchor{Docstring hyperlinks}
 @item
 @cindex curly quotes
@@ -700,7 +712,7 @@ two exceptions: write @code{t} and @code{nil} without 
surrounding
 punctuation.  For example:
 
 @example
- CODE can be `lambda', nil, or t.
+CODE can be `lambda', nil, or t.
 @end example
 
 Note that when Emacs displays these doc strings, Emacs will usually
@@ -856,7 +868,7 @@ find an alternate phrasing that conveys the meaning.
 @item
 Try to avoid using abbreviations such as ``e.g.'' (for ``for
 example''), ``i.e.'' (for ``that is''), ``no.'' (for ``number''),
-``c.f.'' (for ``in contrast to'') and ``w.r.t.'' (for ``with respect
+``cf.'' (for ``compare''/``see also'') and ``w.r.t.'' (for ``with respect
 to'') as much as possible.  It is almost always clearer and easier to
 read the expanded version.@footnote{We do use these occasionally, but
 try not to overdo it.}
diff --git a/doc/lispref/variables.texi b/doc/lispref/variables.texi
index c29547d00d..80d6a01412 100644
--- a/doc/lispref/variables.texi
+++ b/doc/lispref/variables.texi
@@ -327,7 +327,7 @@ Example of a loop summing a list of numbers:
 
 @anchor{Tail recursion}
 Recursive calls to @var{name} that occur in @emph{tail
-positions} in @var{body} are guaranteed to be optimised as @emph{tail
+positions} in @var{body} are guaranteed to be optimized as @emph{tail
 calls}, which means that they will not consume any additional stack
 space no matter how deeply the recursion runs.  Such recursive calls
 will effectively jump to the top of the loop with new values for the
@@ -1363,7 +1363,7 @@ disappear without prior notice.
 
 The byte-compiler can also warn about lexical variables that are
 special in other Emacs Lisp files, often indicating a missing
-@code{defvar} declaration.  This useful but somewhat specialised check
+@code{defvar} declaration.  This useful but somewhat specialized check
 requires three steps:
 
 @enumerate
@@ -2679,17 +2679,46 @@ cdar      nthcdr
 A call to any of the following Emacs-specific functions:
 
 @smallexample
-alist-get                     process-get
-frame-parameter               process-sentinel
-terminal-parameter            window-buffer
-keymap-parent                 window-display-table
-match-data                    window-dedicated-p
-overlay-get                   window-hscroll
-overlay-start                 window-parameter
-overlay-end                   window-point
-process-buffer                window-start
-process-filter                default-value
+alist-get                     overlay-start
+default-value                 overlay-get
+face-background               process-buffer
+face-font                     process-filter
+face-foreground               process-get
+face-stipple                  process-sentinel
+face-underline-p              terminal-parameter
+file-modes                    window-buffer
+frame-parameter               window-dedicated-p
+frame-parameters              window-display-table
+get-register                  window-hscroll
+getenv                        window-parameter
+keymap-parent                 window-point
+match-data                    window-start
+overlay-end
 @end smallexample
+
+@item
+A call of the form @code{(substring @var{subplace} @var{n} [@var{m}])},
+where @var{subplace} is itself a valid generalized variable whose
+current value is a string, and where the value stored is also a
+string.  The new string is spliced into the specified part of the
+destination string.  For example:
+
+@example
+(setq a (list "hello" "world"))
+     @result{} ("hello" "world")
+(cadr a)
+     @result{} "world"
+(substring (cadr a) 2 4)
+     @result{} "rl"
+(setf (substring (cadr a) 2 4) "o")
+     @result{} "o"
+(cadr a)
+     @result{} "wood"
+a
+     @result{} ("hello" "wood")
+@end example
+
+@c FIXME?  Also 'eq'? (see gv.el)
 @end itemize
 
 @noindent
@@ -2822,6 +2851,16 @@ expression manipulating @var{place} via @var{getter} and 
@var{setter}.
 
 Consult the source file @file{gv.el} for more details.
 
+@defun make-obsolete-generalized-variable obsolete-name current-name when
+This function makes the byte compiler warn that the generalized
+variable @var{obsolete-name} is obsolete.  If @var{current-name} is a
+symbol, then the warning message says to use @var{current-name}
+instead of @var{obsolete-name}.  If @var{current-name} is a string,
+this is the message.  @var{when} should be a string indicating when
+the variable was first made obsolete (usually a version number
+string).
+@end defun
+
 @cindex CL note---no @code{setf} functions
 @quotation
 @b{Common Lisp note:} Common Lisp defines another way to specify the
@@ -2843,7 +2882,7 @@ Common Lisp, this is not an error since the function 
@code{(setf
 it, that value won't be automatically restored.  Users usually set
 normal variables in their startup files, or use Customize
 (@pxref{Customization}) to set user options permanently, and various
-packages have various files wher they store the data (e.g., Gnus
+packages have various files where they store the data (e.g., Gnus
 stores this in @file{.newsrc.eld} and the URL library stores cookies
 in @file{~/.emacs.d/url/cookies}).
 
diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi
index 704ed30366..c7f014e2f3 100644
--- a/doc/lispref/windows.texi
+++ b/doc/lispref/windows.texi
@@ -737,7 +737,7 @@ with any other @var{round} it returns the internal value of
 @cindex window width
 @cindex width of a window
 @cindex total width of a window
-The @dfn{total width} of a window is the number of lines comprising its
+The @dfn{total width} of a window is the number of columns comprising its
 body and its left and right decorations (@pxref{Basic Windows}).
 
 @defun window-total-width &optional window round
@@ -747,7 +747,7 @@ the selected window.  If @var{window} is internal, the 
return value is
 the total width occupied by its descendant windows.
 
   If a window's pixel width is not an integral multiple of its frame's
-character width, the number of lines occupied by the window is rounded
+character width, the number of columns occupied by the window is rounded
 internally.  This is done in a way such that, if the window is a parent
 window, the sum of the total widths of all its children internally
 equals the total width of their parent.  This means that although two
@@ -1158,11 +1158,13 @@ frame to its buffer using the command 
@code{fit-frame-to-buffer}.
 This command adjusts the size of @var{frame} to display the contents of
 its buffer exactly.  @var{frame} can be any live frame and defaults to
 the selected one.  Fitting is done only if @var{frame}'s root window is
-live.  The arguments @var{max-height}, @var{min-height}, @var{max-width}
-and @var{min-width} specify bounds on the new total size of
-@var{frame}'s root window.  @var{min-height} and @var{min-width} default
-to the values of @code{window-min-height} and @code{window-min-width}
-respectively.
+live.
+
+The arguments @var{max-height}, @var{min-height}, @var{max-width} and
+@var{min-width}, if non-@code{nil}, specify bounds on the new body size
+of @var{frame}'s root window.  A non-@code{nil} value specified by any
+of these arguments overrides the corresponding value specified by
+the option @code{fit-frame-to-buffer-sizes} described below.
 
 If the optional argument @var{only} is @code{vertically}, this function
 may resize the frame vertically only.  If @var{only} is
@@ -1187,10 +1189,10 @@ here can be overridden for a specific frame by that 
frame's
 
 @defopt fit-frame-to-buffer-sizes
 This option specifies size boundaries for @code{fit-frame-to-buffer}.
-It specifies the total maximum and minimum lines and maximum and minimum
-columns of the root window of any frame that shall be fit to its buffer.
-If any of these values is non-@code{nil}, it overrides the corresponding
-argument of @code{fit-frame-to-buffer}.
+It specifies the maximum and minimum lines and maximum and minimum
+columns of the root window's body of any frame that shall be fit to its
+buffer.  Any value this option specifies will be overridden by the
+corresponding argument of @code{fit-frame-to-buffer}, if non-@code{nil}.
 @end defopt
 
 @deffn Command shrink-window-if-larger-than-buffer &optional window
diff --git a/doc/misc/Makefile.in b/doc/misc/Makefile.in
index d9c5173c07..1d881a5fc7 100644
--- a/doc/misc/Makefile.in
+++ b/doc/misc/Makefile.in
@@ -248,6 +248,7 @@ emacs = "${EMACS}" -batch --no-site-file --no-site-lisp 
--eval '(setq load-prefe
 define org_template
  $(1:.org=.texi): $(1) ${top_srcdir}/lisp/org/ox-texinfo.el
        $${AM_V_GEN}cd "$${srcdir}" && $${emacs} -l ox-texinfo \
+         --eval '(setq gc-cons-threshold 50000000)' \
          -f org-texinfo-export-to-texinfo-batch $$(notdir $$<) $$(notdir $$@)
 endef
 
diff --git a/doc/misc/auth.texi b/doc/misc/auth.texi
index 829d7f4fa0..9dc63af6bc 100644
--- a/doc/misc/auth.texi
+++ b/doc/misc/auth.texi
@@ -384,7 +384,7 @@ This function creates a new item in @var{collection} with 
label
 @var{item} and password @var{password}.  The label @var{item} does not
 have to be unique in @var{collection}.  @var{attributes} are key-value
 pairs set for the created item.  The keys are keyword symbols,
-starting with a colon.  Example:
+starting with a colon; values are strings.  Example:
 
 @example
 ;;; The collection is "session", the label is "my item"
@@ -466,6 +466,10 @@ then fall back to @file{~/.authinfo.gpg}.
                      "~/.authinfo.gpg"))
 @end example
 
+Attribute values in the auth-source spec, which are not strings (like
+port numbers), are stringified prior calling the @file{secrets.el}
+functions.
+
 @node The Unix password store
 @chapter The Unix password store
 
@@ -652,14 +656,8 @@ before @file{~/.authinfo}, the auth-source library will 
try to
 read the GnuPG encrypted @file{.gpg} file first, before
 the unencrypted file.
 
-In Emacs 23 or later there is an option @code{auto-encryption-mode} to
-automatically decrypt @file{*.gpg} files.  It is enabled by default.
-If you are using earlier versions of Emacs, you will need:
-
-@lisp
-(require 'epa-file)
-(epa-file-enable)
-@end lisp
+There is an option @code{auto-encryption-mode} to automatically
+decrypt @file{*.gpg} files.  It is enabled by default.
 
 If you want your GnuPG passwords to be cached, set up @code{gpg-agent}
 or EasyPG Assistant
diff --git a/doc/misc/autotype.texi b/doc/misc/autotype.texi
index a3b0f16df9..93c65692d0 100644
--- a/doc/misc/autotype.texi
+++ b/doc/misc/autotype.texi
@@ -92,7 +92,6 @@ completions and expansions of text at point.
 * Copyrights::             Inserting and updating copyrights.
 * Executables::            Turning interpreter scripts into executables.
 * Timestamps::             Updating dates and times in modified files.
-* QuickURL::               Inserting URLs based on text at point.
 * Tempo::                  Flexible template insertion.
 * Hippie Expand::          Expansion of text trying various methods.
 * Skeleton Language::      Making skeleton commands insert what you want.
@@ -274,13 +273,13 @@ empty file is visited.  This is accomplished by putting
 
 @vindex auto-insert-alist
   What gets inserted, if anything, is determined by the variable
-@code{auto-insert-alist}.  The @sc{car}s of this list are each either
-a mode name, making an element applicable when a buffer is in that
-mode.  Or they can be a string, which is a regexp matched against the
-buffer's file name.  In that way different kinds of files that have
-the same mode in Emacs can be distinguished.  The @sc{car}s may also
-be cons cells consisting of mode name or regexp as above and an
-additional descriptive string.
+@code{auto-insert-alist}.  The @sc{car} of each element of this list
+is either a mode name, making the element applicable when a buffer is
+in that mode, or a string, which is a regexp matched against a
+buffer's file name (the latter allows to distinguish between different
+kinds of files that have the same mode in Emacs).  The @sc{car} of an
+element may also be a cons cell, consisting of mode name or regexp, as
+above, and an additional descriptive string.
 
   When a matching element is found, the @sc{cdr} says what to do.  It may
 be a string, which is a file name, whose contents are to be inserted, if
@@ -478,31 +477,6 @@ The time stamp is written between the brackets or quotes:
 Time-stamp: <1998-02-18 10:20:51 gildea>
 @end example
 
-@node QuickURL
-@chapter QuickURL: Inserting URLs Based on Text at Point
-
-@vindex quickurl-url-file
-@findex quickurl
-@cindex URLs
-@kbd{M-x quickurl} can be used to insert a URL into a buffer based on
-the text at point.  The URLs are stored in an external file defined by
-the variable @code{quickurl-url-file} as a list of either cons cells of
-the form @code{(@var{key} . @var{URL})} or
-lists of the form @code{(@var{key} @var{URL} @var{comment})}.  These
-specify that @kbd{M-x quickurl} should insert @var{URL} if the word
-@var{key} is at point, for example:
-
-@example
-(("FSF"      "https://www.fsf.org/"; "The Free Software Foundation")
- ("emacs"  . "https://www.gnu.org/software/emacs/";))
-@end example
-
-@findex quickurl-add-url
-@findex quickurl-list
-@kbd{M-x quickurl-add-url} can be used to add a new @var{key}/@var{URL}
-pair.  @kbd{M-x quickurl-list} provides interactive editing of the URL
-list.
-
 @node Tempo
 @chapter Tempo: Flexible Template Insertion
 
diff --git a/doc/misc/calc.texi b/doc/misc/calc.texi
index 9bda6af1c5..98f59b89c0 100644
--- a/doc/misc/calc.texi
+++ b/doc/misc/calc.texi
@@ -1,7 +1,7 @@
 \input texinfo @c -*- mode: texinfo; coding: utf-8 -*-
+@setfilename ../../info/calc.info
 @comment %**start of header (This is for running Texinfo on a region.)
 @c smallbook
-@setfilename ../../info/calc.info
 @c [title]
 @settitle GNU Emacs Calc Manual
 @include docstyle.texi
diff --git a/doc/misc/cl.texi b/doc/misc/cl.texi
index 6134b97751..a6747b1096 100644
--- a/doc/misc/cl.texi
+++ b/doc/misc/cl.texi
@@ -920,69 +920,6 @@ cl-caaar@dots{}cl-cddddr          cl-first@dots{}cl-tenth
 Note that for @code{cl-getf} (as for @code{nthcdr}), the list argument
 of the function must itself be a valid @var{place} form.
 
-@item
-General Emacs Lisp functions:
-@example
-buffer-file-name                   getenv
-buffer-modified-p                  global-key-binding
-buffer-name                        local-key-binding
-buffer-string                      mark
-buffer-substring                   mark-marker
-current-buffer                     marker-position
-current-case-table                 mouse-position
-current-column                     point
-current-global-map                 point-marker
-current-input-mode                 point-max
-current-local-map                  point-min
-current-window-configuration       read-mouse-position
-default-file-modes                 screen-height
-documentation-property             screen-width
-face-background                    selected-window
-face-background-pixmap             selected-screen
-face-font                          selected-frame
-face-foreground                    standard-case-table
-face-underline-p                   syntax-table
-file-modes                         visited-file-modtime
-frame-height                       window-height
-frame-parameters                   window-width
-frame-visible-p                    x-get-secondary-selection
-frame-width                        x-get-selection
-get-register
-@end example
-
-Most of these have directly corresponding ``set'' functions, like
-@code{use-local-map} for @code{current-local-map}, or @code{goto-char}
-for @code{point}.  A few, like @code{point-min}, expand to longer
-sequences of code when they are used with @code{setf}
-(@code{(narrow-to-region x (point-max))} in this case).
-
-@item
-A call of the form @code{(substring @var{subplace} @var{n} [@var{m}])},
-where @var{subplace} is itself a valid generalized variable whose
-current value is a string, and where the value stored is also a
-string.  The new string is spliced into the specified part of the
-destination string.  For example:
-
-@example
-(setq a (list "hello" "world"))
-     @result{} ("hello" "world")
-(cadr a)
-     @result{} "world"
-(substring (cadr a) 2 4)
-     @result{} "rl"
-(setf (substring (cadr a) 2 4) "o")
-     @result{} "o"
-(cadr a)
-     @result{} "wood"
-a
-     @result{} ("hello" "wood")
-@end example
-
-The generalized variable @code{buffer-substring}, listed above,
-also works in this way by replacing a portion of the current buffer.
-
-@c FIXME?  Also 'eq'? (see cl-lib.el)
-
 @c Currently commented out in cl.el.
 @ignore
 @item
@@ -1381,19 +1318,10 @@ bar
 
 A @code{setq} of a symbol macro is treated the same as a @code{setf}.
 I.e., @code{(setq foo 4)} in the above would be equivalent to
-@code{(setf foo 4)}, which in turn expands to @code{(setf (car bar) 4)}.
-
-Likewise, a @code{let} or @code{let*} binding a symbol macro is
-treated like a @code{cl-letf} or @code{cl-letf*}.  This differs from true
-Common Lisp, where the rules of lexical scoping cause a @code{let}
-binding to shadow a @code{symbol-macrolet} binding.  In this package,
-such shadowing does not occur, even when @code{lexical-binding} is
-@c See https://debbugs.gnu.org/12119
-@code{t}.  (This behavior predates the addition of lexical binding to
-Emacs Lisp, and may change in future to respect @code{lexical-binding}.)
-At present in this package, only @code{lexical-let} and
-@code{lexical-let*} will shadow a symbol macro.  @xref{Obsolete
-Lexical Binding}.
+@code{(setf foo 4)}, which in turn expands to @code{(setf (car bar)
+4)}.  A @code{let} (or @code{let*}, @code{lambda}, ...) binding of
+the same symbol will locally shadow the symbol macro as is the case in
+Common Lisp.
 
 There is no analogue of @code{defmacro} for symbol macros; all symbol
 macros are local.  A typical use of @code{cl-symbol-macrolet} is in the
@@ -3756,7 +3684,7 @@ a merged sequence which is (stably) sorted according to
 The functions described here operate on lists.
 
 @menu
-* List Functions::                @code{cl-caddr}, @code{cl-first}, 
@code{cl-list*}, etc.
+* List Functions::                @code{cl-first}, @code{cl-list*}, etc.
 * Substitution of Expressions::   @code{cl-subst}, @code{cl-sublis}, etc.
 * Lists as Sets::                 @code{cl-member}, @code{cl-adjoin}, 
@code{cl-union}, etc.
 * Association Lists::             @code{cl-assoc}, @code{cl-acons}, 
@code{cl-pairlis}, etc.
@@ -3769,14 +3697,6 @@ The functions described here operate on lists.
 This section describes a number of simple operations on lists,
 i.e., chains of cons cells.
 
-@defun cl-caddr x
-This function is equivalent to @code{(car (cdr (cdr @var{x})))}.
-Likewise, this package aliases all 24 @code{c@var{xxx}r} functions
-where @var{xxx} is up to four @samp{a}s and/or @samp{d}s.
-All of these functions are @code{setf}-able, and calls to them
-are expanded inline by the byte-compiler for maximum efficiency.
-@end defun
-
 @defun cl-first x
 This function is a synonym for @code{(car @var{x})}.  Likewise,
 the functions @code{cl-second}, @code{cl-third}, @dots{}, through
@@ -4553,8 +4473,8 @@ For example,
 @end example
 @end ignore
 
-Note that @code{cl-adjoin}, @code{cl-caddr}, and @code{cl-member} all
-have built-in compiler macros to optimize them in common cases.
+Note that @code{cl-adjoin} and @code{cl-member} have built-in compiler
+macros to optimize them in common cases.
 @end defun
 
 @appendixsec Error Checking
diff --git a/doc/misc/dired-x.texi b/doc/misc/dired-x.texi
index 754ccf4065..002164ed91 100644
--- a/doc/misc/dired-x.texi
+++ b/doc/misc/dired-x.texi
@@ -92,7 +92,6 @@ For @file{dired-x.el} as distributed with GNU Emacs 
@value{EMACSVER}.
 * Introduction::
 * Installation::
 * Omitting Files in Dired::
-* Shell Command Guessing::
 * Virtual Dired::
 * Advanced Mark Commands::
 * Multiple Dired Directories::
@@ -135,9 +134,6 @@ Some features provided by Dired Extra:
 Omitting uninteresting files from Dired listing
 (@pxref{Omitting Files in Dired}).
 @item
-Guessing shell commands in Dired buffers
-(@pxref{Shell Command Guessing}).
-@item
 Running Dired command in non-Dired buffers
 (@pxref{Virtual Dired}).
 @item
@@ -165,10 +161,6 @@ When @file{dired-x.el} is loaded, some standard Dired 
functions from
 Dired}), if it is active.  @code{dired-find-buffer-nocreate} and
 @code{dired-initial-position} respect the value of
 @code{dired-find-subdir} (@pxref{Miscellaneous Commands}).
-@code{dired-clean-up-after-deletion} respects the value of
-@code{dired-clean-up-buffers-too}.  @code{dired-read-shell-command} uses
-@code{dired-guess-shell-command} (@pxref{Shell Command Guessing}) to
-offer a smarter default command.
 
 @node Installation
 @chapter Installation
@@ -186,7 +178,6 @@ In your @file{~/.emacs} file, or in the system-wide 
initialization file
 (with-eval-after-load 'dired
   (require 'dired-x)
   ;; Set dired-x global variables here.  For example:
-  ;; (setq dired-guess-shell-gnutar "gtar")
   ;; (setq dired-x-hands-off-my-keys nil)
   ))
 (add-hook 'dired-mode-hook
@@ -438,111 +429,6 @@ Loading @file{dired-x.el} will install Dired Omit by 
putting
 call @code{dired-extra-startup}, which in turn calls @code{dired-omit-startup}
 in your @code{dired-mode-hook}.
 
-@node Shell Command Guessing
-@chapter Shell Command Guessing
-@cindex guessing shell commands for files.
-
-Based upon the name of a file, Dired tries to guess what shell
-command you might want to apply to it.  For example, if you have point
-on a file named @file{foo.tar} and you press @kbd{!}, Dired will guess
-you want to @samp{tar xvf} it and suggest that as the default shell
-command.
-
-The default is mentioned in brackets and you can type @kbd{M-n} to get
-the default into the minibuffer and then edit it, e.g., to change
-@samp{tar xvf} to @samp{tar tvf}.  If there are several commands for a given
-file, e.g., @samp{xtex} and @samp{dvips} for a @file{.dvi} file, you can type
-@kbd{M-n} several times to see each of the matching commands.
-
-Dired only tries to guess a command for a single file, never for a list
-of marked files.
-
-The following variables control guessing of shell commands:
-
-@defvar dired-guess-shell-alist-default
-This variable specifies the predefined rules for guessing shell
-commands suitable for certain files.  Set this to @code{nil} to turn
-guessing off.  The elements of @code{dired-guess-shell-alist-user}
-(defined by the user) will override these rules.
-@end defvar
-
-@defvar dired-guess-shell-alist-user
-If non-@code{nil}, this variables specifies the user-defined alist of
-file regexps and their suggested commands.  These rules take
-precedence over the predefined rules in the variable
-@code{dired-guess-shell-alist-default} (to which they are prepended)
-when @code{dired-do-shell-command} is run).  The default is
-@code{nil}.
-
-Each element of the alist looks like
-
-@example
-(@var{regexp} @var{command}@dots{})
-@end example
-
-@noindent
-where each @var{command} can either be a string or a Lisp expression
-that evaluates to a string.  If several commands are given, all of
-them will temporarily be pushed onto the history.
-
-A @samp{*} in the shell command stands for the file name that matched
-@var{regexp}.  When Emacs invokes the @var{command}, it replaces each
-instance of @samp{*} with the matched file name.
-
-You can set this variable in your @file{~/.emacs}.  For example,
-to add rules for @samp{.foo} and @samp{.bar} file extensions, write
-
-@example
-(setq dired-guess-shell-alist-user
-      (list
-       (list "\\.foo$" "@var{foo-command}");; fixed rule
-       ;; possibly more rules...
-       (list "\\.bar$";; rule with condition test
-              '(if @var{condition}
-                   "@var{bar-command-1}"
-                 "@var{bar-command-2}"))))
-@end example
-
-@noindent
-This will override any predefined rules for the same extensions.
-@end defvar
-
-@defvar dired-guess-shell-case-fold-search
-If this variable is non-@code{nil},
-@code{dired-guess-shell-alist-default} and
-@code{dired-guess-shell-alist-user} are matched case-insensitively.
-The default is @code{t}.
-@end defvar
-
-@cindex passing GNU Tar its @samp{z} switch.
-@defvar dired-guess-shell-gnutar
-If this variable is non-@code{nil}, it specifies the name of the GNU
-Tar executable (e.g., @file{tar} or @file{gnutar}).  GNU Tar's
-@samp{z} switch is used for compressed archives.  If you don't have
-GNU Tar, set this to @code{nil}: a pipe using @command{zcat} is then
-used instead.  The default is @code{nil}.
-@end defvar
-
-@cindex @code{gzip}
-@defvar dired-guess-shell-gzip-quiet
-A non-@code{nil} value of this variable means that @samp{-q} is passed
-to @command{gzip}, possibly overriding a verbose option in the @env{GZIP}
-environment variable.  The default is @code{t}.
-@end defvar
-
-@cindex @code{znew}
-@defvar dired-guess-shell-znew-switches nil
-This variable specifies a string of switches passed to @command{znew}.
-An example is @samp{-K} which will make @command{znew} keep a @file{.Z}
-file when it is smaller than the @file{.gz} file.  The default is
-@code{nil}: no additional switches are passed to @command{znew}.
-@end defvar
-
-@defvar dired-shell-command-history nil
-This variable holds the history list for commands that read
-dired-shell commands.
-@end defvar
-
 @node Virtual Dired
 @chapter Virtual Dired
 
@@ -884,15 +770,6 @@ normal and a wildcard buffer for the same directory, 
@kbd{C-x d @key{RET}}
 will toggle between those two.
 @end table
 
-@table @kbd
-@findex dired-goto-subdir
-@kindex M-G
-@item M-G
-(@code{dired-goto-subdir}) Go to the header line of an inserted directory.
-This command reads its argument, with completion derived from the names of the
-inserted subdirectories.
-@end table
-
 @table @code
 
 @item dired-vm
@@ -920,55 +797,6 @@ to @kbd{V}.  Otherwise, @code{dired-bind-rmail} will be 
bound.
 @findex dired-rmail
 Bound to @kbd{V} if @code{dired-bind-vm} is @code{nil}.  Run Rmail on this
 file (assumed to be mail folder in Rmail format).
-
-@item dired-info
-@kindex I
-@cindex running info.
-@findex dired-info
-Bound to @kbd{I}.  Run Info on this file (assumed to be a file in Info
-format).
-
-@vindex dired-bind-info
-If the variable @code{dired-bind-info} is @code{nil}, @code{dired-info} will
-not be bound to @kbd{I}.
-
-@item dired-man
-@cindex running man.
-@kindex N
-@findex dired-man
-Bound to @kbd{N}.  Run man on this file (assumed to be a file in @code{nroff}
-format).
-
-@vindex dired-bind-man
-If the variable @code{dired-bind-man} is @code{nil}, @code{dired-man} will not
-be bound to @kbd{N}.
-
-@item dired-do-relsymlink
-@cindex relative symbolic links.
-@kindex Y
-@findex dired-do-relsymlink
-Bound to @kbd{Y}.  Relative symlink all marked (or next ARG) files into a
-directory, or make a relative symbolic link to the current file.  This creates
-relative symbolic links like
-
-@example
-    foo -> ../bar/foo
-@end example
-
-@noindent
-not absolute ones like
-
-@example
-    foo -> /ugly/path/that/may/change/any/day/bar/foo
-@end example
-
-@item dired-do-relsymlink-regexp
-@kindex %Y
-@findex dired-do-relsymlink-regexp
-Bound to @kbd{%Y}.  Relative symlink all marked files containing
-@var{regexp} to @var{newname}.  See functions
-@code{dired-do-rename-regexp} and @code{dired-do-relsymlink} for more
-info.
 @end table
 
 @node Bugs
diff --git a/doc/misc/ede.texi b/doc/misc/ede.texi
index af8e2153dd..9867883b24 100644
--- a/doc/misc/ede.texi
+++ b/doc/misc/ede.texi
@@ -1551,14 +1551,14 @@ This is a URL to be sent to a web site for 
documentation.
 @item :web-site-directory @*
 
 A directory where web pages can be found by Emacs.
-For remote locations use a path compatible with ange-ftp or EFS@.
+For remote locations use a path compatible with ange-ftp.
 You can also use TRAMP for use with rcp & scp.
 
 @item :web-site-file @*
 
 A file which contains the website for this project.
 This file can be relative to slot @code{web-site-directory}.
-This can be a local file, use ange-ftp, EFS, or TRAMP.
+This can be a local file, use ange-ftp or TRAMP.
 
 @item :ftp-site
 Type: @code{string} @*
diff --git a/doc/misc/ediff.texi b/doc/misc/ediff.texi
index 39b09b29b3..cbc7556aa8 100644
--- a/doc/misc/ediff.texi
+++ b/doc/misc/ediff.texi
@@ -947,12 +947,14 @@ This function can also be invoked from the Menubar.  
However, in some
 cases, the change will take place only after you execute one of the Ediff
 commands, such as going to the next difference or redisplaying.
 
+@c --> The below can be revisited once the toolbar has been ported to Emacs:
+@ignore
 @item ediff-toggle-use-toolbar
 @findex ediff-toggle-use-toolbar
-Available in XEmacs only.  The Ediff toolbar provides quick access to some
-of the common Ediff functions.  This function toggles the display of the
-toolbar.  If invoked from the menubar, the function may take sometimes
-effect only after you execute an Ediff command, such as going to the next
+The Ediff toolbar provides quick access to some of the common Ediff
+functions.  This function toggles the display of the toolbar.  If
+invoked from the menubar, the function may take sometimes effect only
+after you execute an Ediff command, such as going to the next
 difference.
 
 @item ediff-use-toolbar-p
@@ -961,6 +963,7 @@ The use of the toolbar can also be specified via the 
variable
 @code{ediff-use-toolbar-p} (default is @code{t}).  This variable can be set
 only in @file{.emacs}: do @strong{not} change it interactively.  Use the
 function @code{ediff-toggle-use-toolbar} instead.
+@end ignore
 
 @item ediff-revert-buffers-then-recompute-diffs
 @findex ediff-revert-buffers-then-recompute-diffs
diff --git a/doc/misc/efaq-w32.texi b/doc/misc/efaq-w32.texi
index 55175a3b89..46c257e42e 100644
--- a/doc/misc/efaq-w32.texi
+++ b/doc/misc/efaq-w32.texi
@@ -130,10 +130,8 @@ from Windows 98 onward, and all versions of the NT family 
starting
 from NT 4.0; this includes all the modern versions from Windows XP and
 on.  The Windows port is built using the Win32 API and supports most
 features of the X version, including variable width fonts, images and
-tooltips.
-
-Emacs on Windows can be compiled as either a 32-bit or a 64-bit
-executable, using the MinGW GCC compiler and development tools.
+tooltips.  Emacs on Windows can be compiled as either a 64-bit or a
+32-bit executable.
 
 @node Other versions of Emacs
 @section What other versions of Emacs run on Windows?
@@ -177,8 +175,8 @@ best-effort basis in the @file{windows} subdirectory of the 
above ftp
 site (as zip files digitally signed by the person who built them).
 See the @file{README} file in that directory for more information.
 Building Emacs from source yourself should be straightforward,
-following the instructions in @file{nt/INSTALL}, so we encourage you
-to give it a try.  @xref{Compiling}.
+following the instructions in the @file{nt} directory, so we
+encourage you to give it a try.  @xref{Compiling}.
 
 @cindex latest development version of Emacs
 @cindex Emacs Development
@@ -190,21 +188,27 @@ development site.
 @section How can I compile Emacs myself?
 @cindex compiling Emacs
 
-To compile Emacs on Windows, you will need the MinGW port of GCC and
-Binutils, the MinGW runtime and development environment, and the MSYS
-suite of tools.  For the details, see the file @file{nt/INSTALL} in
-the Emacs source distribution.
+To compile Emacs on a 64-bit version of Windows 7 or newer, we
+recommend to use the MinGW-w64 port of GCC and Binutils with the MSYS2
+suite of tools.  For the details, see the file @file{nt/INSTALL.W64}
+in the Emacs source distribution.
+
+If you need to build or run Emacs on MS Windows before Windows 7, you
+have to use the MinGW port of GCC and the MSYS suite of tools.  The
+file @file{nt/INSTALL} in Emacs source distribution contains the
+details.
 
 Support for displaying images, as well as XML/HTML rendering and TLS
 networking requires external libraries, the headers and import
 libraries for which will need to be installed where your compiler can
 find them.  Again, the details, including URLs of sites where you can
-download these libraries are in @file{nt/INSTALL}.  @xref{Other useful
-ports}, for auxiliary tools you may wish to install and use in
-conjunction with Emacs.
+download these libraries are in @file{nt/INSTALL.W64} or
+@file{nt/INSTALL}.  @xref{Other useful ports}, for auxiliary tools you
+may wish to install and use in conjunction with Emacs.
 
 After unpacking the source, or checking out of the repository, be sure
-to read the instructions in @file{nt/README} and @file{nt/INSTALL}.
+to read the instructions in @file{nt/README} and the respective
+install file.
 
 @node Debugging
 @section How do I use a debugger on Emacs?
@@ -222,18 +226,18 @@ specific notes about debugging Emacs.
 
 @cindex debugging Emacs with GDB
 GDB is the GNU debugger, which can be used to debug Emacs when it has
-been compiled with MinGW GCC@.  The best results will be obtained if
-you start gdb from the @file{src} directory as @kbd{gdb ./emacs.exe}.
+been compiled with GCC@.  The best results will be obtained if you
+start gdb from the @file{src} directory as @kbd{gdb ./emacs.exe}.
 This will load the init file @file{.gdbinit}@footnote{
 Latest versions of GDB might refuse to load the init file for security
 reasons, unless you customize GDB; alternatively, use an explicit
 @kbd{source ./gdbinit} command after entering GDB.
 } in that directory, to define some extra commands for working with
-lisp while debugging, and set up breakpoints to catch abnormal
-aborts.
+lisp while debugging, and set up breakpoints to catch abnormal aborts.
 
-A Windows port of GDB can be found on MinGW download sites and on some
-others.
+A Windows port of GDB is installed with MinGW64-w64 and MSYS2
+(@samp{mingw-w64-<arch>-toolchain} group) or can be found on MinGW
+download sites and on some others.
 
 @c ------------------------------------------------------------
 @node Installing Emacs
@@ -307,8 +311,8 @@ bsdtar -xf emacs-@value{EMACSVER}.tar.xz
 Expect @command{bsdtar} to unpack the whole distribution without any
 complaints.
 
-Once you unpack the source distribution, look in @file{nt/INSTALL}
-file for build instructions.
+Once you unpack the source distribution, look in the @file{nt}
+directory for build instructions.
 
 @node Installing binaries
 @section How do I install Emacs after unpacking the binary zip?
@@ -926,9 +930,9 @@ an indication of whether the font is outline (.TTF, .ATM) 
or raster (.FON)
 based when fonts are listed, which may let you differentiate between two
 fonts with the same name and different technologies.
 
-Starting with Emacs 23, the preferred font name format will be moving
-to the simpler and more flexible fontconfig format.  XLFD names will
-continue to be supported for backward compatibility.
+Starting with Emacs 23, the preferred font name format is the simpler
+and more flexible fontconfig format.  XLFD names will continue to be
+supported for backward compatibility.
 
 @example
 XLFD: -*-Courier New-normal-r-*-*-13-*-*-*-c-*-iso8859-1
@@ -1645,8 +1649,8 @@ obtained the packages from if you want to use them.
 In your @env{HOME} directory create a file called @file{.mailcap},
 with contents like the following:
 @example
-application/zip "C:/Program Files/7-Zip/7zFM.exe"
-video/* "C:/Program Files/VideoLAN/VLC/vlc.exe"
+application/zip; "C:/Program Files/7-Zip/7zFM.exe"
+video/*; "C:/Program Files/VideoLAN/VLC/vlc.exe"
 @end example
 
 @strong{Warning:} Associating MIME types with @command{start} or other
@@ -1754,11 +1758,13 @@ A number of implementations are listed on the
 Emacs has support for spell checking on demand (@code{ispell}) and as
 your type (@code{flyspell}).  Both packages depend on a copy of
 @command{ispell} 3.2 or a compatible spell-checking program.
-GNU Aspell is a popular choice these days, Windows installers are
-available from the @uref{http://aspell.net/win32/, official site}.
+GNU Aspell is a popular choice these days, outdated Windows installers
+are available from the @uref{http://aspell.net/win32/, official site}.
 Another possibility is Hunspell, which is available from
 @uref{https://sourceforge.net/projects/ezwinports/files/?source=navbar,
-the ezwinports site}.
+the ezwinports site}.  If you're using the MSYS2 distribution, you can
+install a recent version of either GNU Aspell or Hunspell through the
+package manager Pacman.  @xref{Other useful ports}.
 
 Once installed, you will need to configure @code{ispell-program-name}
 to tell ispell and flyspell to use @command{aspell} or
@@ -2096,9 +2102,9 @@ suggestions} for improving the interaction of perldb and 
Emacs.
 
 @menu
 * Cygwin::
-* MinGW::
+* MinGW-w64::
 * EZWinPorts::
-* UWIN::
+* MinGW::
 * GnuWin32::
 * GTK::
 * Read man pages::
@@ -2133,22 +2139,25 @@ Cygwin on your system @env{PATH} for this reason.  
Instead you can
 make the Cygwin tools available within Emacs by setting @code{exec-path}
 in your init file.
 
-@node MinGW
-@section MinGW and MSYS
-@cindex mingw tools
-@cindex msys environment
-@cindex subprocesses, mingw and msys
+@node MinGW-w64
+@section MinGW-w64 and MSYS2
+@cindex mingw-w64 tools
+@cindex msys2 environment
+@cindex subprocesses, mingw-w64 and msys2
 
-@uref{http://www.mingw.org/}
+@uref{https://www.msys2.org/}
 
-MinGW is a set of development tools that produce native Windows
+MinGW-w64 is a set of development tools that produce native Windows
 executables, not dependent on Cygwin's POSIX emulation DLLs.
+MinGW-w64 has forked the original MinGW in 2007 in order to provide
+support for 64 bits and new APIs.
 
-MSYS is a POSIX shell and minimal set of tools that are commonly used in
-configure scripts.  Like Cygwin, this environment uses a non-native
-filesystem mapping to appear more POSIX like to the scripts that it
-runs.  This is intended to complement the MinGW tools to make it easier
-to port software to Windows.
+MSYS2 is software distribution and a building platform for Windows.
+MSYS2 is an independent rewrite of MSYS, based on modern Cygwin and
+MinGW-w64 with the aim of better interoperability with native Windows
+software.  It plays the same role MSYS does in MinGW.  Being a
+distribution, MSYS2 provides tools to build software as well as more
+than 2.600 precompiled packages ready for use.
 
 @node EZWinPorts
 @section EZWinPorts
@@ -2161,16 +2170,22 @@ software.  This includes all the optional libraries 
used by Emacs
 @command{man} command, Grep, xz, bzip2, bsdtar, ID Utils, Findutils,
 Hunspell, Gawk, GNU Make, Groff, GDB.
 
-@node UWIN
-@section UWIN
-@cindex uwin environment
-@cindex subprocesses, uwin
+@node MinGW
+@section MinGW and MSYS
+@cindex mingw tools
+@cindex msys environment
+@cindex subprocesses, mingw and msys
 
-@uref{http://www.research.att.com/sw/tools/uwin/}
+@uref{https://osdn.net/projects/mingw/}
 
-UWIN is another POSIX emulation environment, like Cygwin and MSYS,
-that provides a large number of ported tools.  The shell used by UWIN
-is @command{ksh}, the Korn shell.
+MinGW is another set of development tools that produce native Windows
+executables, not dependent on Cygwin's POSIX emulation DLLs.
+
+MSYS is a POSIX shell and minimal set of tools that are commonly used in
+configure scripts.  Like Cygwin, this environment uses a non-native
+filesystem mapping to appear more POSIX like to the scripts that it
+runs.  This is intended to complement the MinGW tools to make it easier
+to port software to Windows.
 
 @node GnuWin32
 @section GnuWin32
diff --git a/doc/misc/efaq.texi b/doc/misc/efaq.texi
index a98c4b6a61..a3459abd04 100644
--- a/doc/misc/efaq.texi
+++ b/doc/misc/efaq.texi
@@ -27,9 +27,6 @@ latest version of the FAQ is archived.
 The FAQ may be copied and redistributed under these conditions, except that
 the FAQ may not be embedded in a larger literary work unless that work
 itself allows free copying and redistribution.
-
-[This version has been heavily edited since it was included in the Emacs
-distribution in 1999.]
 @end quotation
 @end copying
 
@@ -545,11 +542,11 @@ printed manual}.
 @cindex Reference cards, in other languages
 @item
 You can get a printed reference card listing commands and keys to
-invoke them.  You can order one from the FSF for $2 (or 10 for $18),
-or you can print your own from the @file{etc/refcards/refcard.tex} or
-@file{etc/refcards/refcard.pdf} files in the Emacs distribution.
-The Emacs distribution comes with translations of the reference card
-into several languages; look for files named
+invoke them.  You can order one from the FSF, or you can print your
+own from the @file{etc/refcards/refcard.tex} or
+@file{etc/refcards/refcard.pdf} files in the Emacs distribution.  The
+Emacs distribution comes with translations of the reference card into
+several languages; look for files named
 @file{etc/refcards/@var{lang}-refcard.*}, where @var{lang} is a
 two-letter code of the language.  For example, the German version of
 the reference card is in the files @file{etc/refcards/de-refcard.tex}
@@ -696,9 +693,10 @@ of the file in parentheses, like this:
 @item
 You can create your own Info directory.  You can tell Emacs where that
 Info directory is by adding its pathname to the value of the variable
-@code{Info-default-directory-list}.  For example, to use a private Info
-directory which is a subdirectory of your home directory named @file{Info},
-you could put this in your @file{.emacs} file:
+@code{Info-default-directory-list}.  For example, to use a private
+Info directory which is a subdirectory of your home directory named
+@file{Info}, you could put this in your init file (@pxref{Setting up a
+customization file}):
 
 @lisp
 (add-to-list 'Info-default-directory-list "~/Info/")
@@ -1607,35 +1605,38 @@ is better to write ``Emacs and XEmacs.''
 @end menu
 
 @node Setting up a customization file
-@section How do I set up a @file{.emacs} file properly?
+@section How do I set up an init file properly?
 @cindex @file{.emacs} file, setting up
-@cindex @file{.emacs} file, locating
+@cindex @file{.emacs.d/init.el} file, setting up
 @cindex Init file, setting up
+@cindex Init file, locating
 @cindex Customization file, setting up
 
+When Emacs is started, it normally tries to load a Lisp program from
+an @dfn{initialization file}, or @dfn{init file} for short.  This
+file, if it exists, specifies how to initialize Emacs for you.
+Traditionally, file @file{~/.emacs} is used as the init file, although
+Emacs also looks at @file{~/.emacs.el}, @file{~/.emacs.d/init.el},
+@file{~/.config/emacs/init.el}, or other locations.
 @xref{Init File,,, emacs, The GNU Emacs Manual}.
 
-In general, new Emacs users should not be provided with @file{.emacs}
-files, because this can cause confusing non-standard behavior.  Then
-they send questions to
-@url{https://lists.gnu.org/mailman/listinfo/help-gnu-emacs,
-the help-gnu-emacs mailing list} asking why Emacs
-isn't behaving as documented.
-
 Emacs includes the Customize facility (@pxref{Using Customize}).  This
 allows users who are unfamiliar with Emacs Lisp to modify their
-@file{.emacs} files in a relatively straightforward way, using menus
+init files in a relatively straightforward way, using menus
 rather than Lisp code.
 
 While Customize might indeed make it easier to configure Emacs,
 consider taking a bit of time to learn Emacs Lisp and modifying your
-@file{.emacs} directly.  Simple configuration options are described
+init file directly.  Simple configuration options are described
 rather completely in @ref{Init File,,, emacs, The GNU Emacs Manual},
 for users interested in performing frequently requested, basic tasks.
 
-Sometimes users are unsure as to where their @file{.emacs} file should
-be found.  Visiting the file as @file{~/.emacs} from Emacs will find
-the correct file.
+In general, new Emacs users should not be provided with init
+files, because this can cause confusing non-standard behavior.  Then
+they send questions to
+@url{https://lists.gnu.org/mailman/listinfo/help-gnu-emacs,
+the help-gnu-emacs mailing list} asking why Emacs
+isn't behaving as documented.
 
 @node Using Customize
 @section How do I start using Customize?
@@ -1743,21 +1744,22 @@ always use custom terminal definition with 
@samp{setb24} and
 @samp{setf24}.
 
 @node Debugging a customization file
-@section How do I debug a @file{.emacs} file?
-@cindex Debugging @file{.emacs} file
-@cindex @file{.emacs} debugging
+@section How do I debug an init file?
+@cindex Debugging @file{.emacs.d/init.el} file
+@cindex Debugging init file
+@cindex @file{.emacs.d/init.el} debugging
 @cindex Init file debugging
 @cindex @samp{-debug-init} option
 
 Start Emacs with the @samp{-debug-init} command-line option.  This
-enables the Emacs Lisp debugger before evaluating your @file{.emacs}
+enables the Emacs Lisp debugger before evaluating your init
 file, and places you in the debugger if something goes wrong.  The top
 line in the @file{trace-back} buffer will be the error message, and the
 second or third line of that buffer will display the Lisp code from your
-@file{.emacs} file that caused the problem.
+init file that caused the problem.
 
 You can also evaluate an individual function or argument to a function
-in your @file{.emacs} file by moving the cursor to the end of the
+in your init file by moving the cursor to the end of the
 function or argument and typing @kbd{C-x C-e} (@kbd{M-x
 eval-last-sexp}).
 
@@ -1787,7 +1789,8 @@ You can similarly display the current column with
 @end lisp
 
 @noindent
-in your @file{.emacs} file.  This feature is off by default.
+in your init file (@pxref{Setting up a customization file}).  This
+feature is off by default.
 
 The @code{"%c"} format specifier in the variable @code{mode-line-format}
 will insert the current column's value into the mode line.  See the
@@ -1806,9 +1809,8 @@ optional display.  Alternatively, you can use the
 customize @code{display-line-numbers-type} with the same value as you
 would use with @code{display-line-numbers}.
 
-There is also the @samp{linum} package (distributed with Emacs since
-version 23.1) which will henceforth become obsolete.  Users and
-developers are encouraged to use @samp{display-line-numbers} instead.
+There is also the @samp{linum} package which will henceforth become
+obsolete.  We recommend using @samp{display-line-numbers} instead.
 
 @node Displaying the current file name in the titlebar
 @section How can I modify the titlebar to contain the current file name?
@@ -1834,7 +1836,7 @@ machine at which Emacs was invoked.  This is done by 
setting
 
 To modify the behavior such that frame titlebars contain the buffer's
 name regardless of the number of existing frames, include the following
-in your @file{.emacs}:
+in your init file (@pxref{Setting up a customization file}):
 
 @lisp
 (setq frame-title-format "%b")
@@ -1844,9 +1846,10 @@ in your @file{.emacs}:
 @section How do I turn on abbrevs by default just in mode @var{mymode}?
 @cindex Abbrevs, turning on by default
 
-Abbrev mode expands abbreviations as you type them.  To turn it on in a
-specific buffer, use @kbd{M-x abbrev-mode}.  To turn it on in every
-buffer by default, put this in your @file{.emacs} file:
+Abbrev mode expands abbreviations as you type them.  To turn it on in
+a specific buffer, use @kbd{M-x abbrev-mode}.  To turn it on in every
+buffer by default, put this in your init file (@pxref{Setting up a
+customization file}):
 
 @lisp
 (setq-default abbrev-mode t)
@@ -1896,7 +1899,8 @@ the script.  Use @kbd{C-h v} (or @kbd{M-x 
describe-variable}) on
 @cindex Highlighting and replacing text
 
 Use @code{delete-selection-mode}, which you can start automatically by
-placing the following Lisp form in your @file{.emacs} file:
+placing the following Lisp form in your init file (@pxref{Setting up a
+customization file}):
 
 @lisp
 (delete-selection-mode 1)
@@ -2034,9 +2038,10 @@ The default maximum line width is 70, determined by the 
variable
 To turn on @code{auto-fill-mode} just once for one buffer, use @kbd{M-x
 auto-fill-mode}.
 
-To turn it on for every buffer in a certain mode, you must use the hook
-for that mode.  For example, to turn on @code{auto-fill} mode for all
-text buffers, including the following in your @file{.emacs} file:
+To turn it on for every buffer in a certain mode, you must use the
+hook for that mode.  For example, to turn on @code{auto-fill} mode for
+all text buffers, including the following in your init file
+(@pxref{Setting up a customization file}):
 
 @lisp
 (add-hook 'text-mode-hook 'turn-on-auto-fill)
@@ -2091,7 +2096,8 @@ option:
 emacs -f server-start
 @end example
 
-or by invoking @code{server-start} from @file{.emacs}:
+or by invoking @code{server-start} from init file (@pxref{Setting up a
+customization file}):
 
 @lisp
 (if (@var{some conditions are met}) (server-start))
@@ -2162,7 +2168,8 @@ f()
 @}
 @end example
 
-@noindent To achieve this, add the following line to your @file{.emacs}:
+@noindent To achieve this, add the following line to your init file
+(@pxref{Setting up a customization file}):
 
 @lisp
 (c-set-offset 'case-label '+)
@@ -2213,7 +2220,8 @@ the line or the block according to what you just 
specified.
 
 @item
 If you don't like the result, go back to step 1.  Otherwise, add the
-following line to your @file{.emacs}:
+following line to your init file (@pxref{Setting up a customization
+file}):
 
 @lisp
 (c-set-offset '@var{syntactic-symbol} @var{offset})
@@ -2243,8 +2251,8 @@ customizations inside a C mode hook, like this:
 
 @noindent
 Using @code{c-mode-hook} avoids the need to put a @w{@code{(require
-'cc-mode)}} into your @file{.emacs} file, because @code{c-set-offset}
-might be unavailable when @code{cc-mode} is not loaded.
+'cc-mode)}} into your init file, because @code{c-set-offset} might be
+unavailable when @code{cc-mode} is not loaded.
 
 Note that @code{c-mode-hook} runs for C source files only; use
 @code{c++-mode-hook} for C@t{++} sources, @code{java-mode-hook} for
@@ -2316,8 +2324,8 @@ usage:  xset [-display host:dpy] option ...
 @cindex Previous line, indenting according to
 @cindex Text indentation
 
-Such behavior is automatic (in Text mode) in Emacs 20 and later.  From the
-@file{etc/NEWS} file for Emacs 20.2:
+Such behavior is automatic (in Text mode).  From the @file{etc/NEWS}
+file for Emacs 20.2:
 
 @example
 ** In Text mode, now only blank lines separate paragraphs.  This makes
@@ -2355,7 +2363,8 @@ new paragraph.  There are many packages available to deal 
with this
 @cindex Pairs of parentheses, highlighting
 @cindex Matching parentheses
 
-Call @code{show-paren-mode} in your @file{.emacs} file:
+Call @code{show-paren-mode} in your init file (@pxref{Setting up a
+customization file}):
 
 @lisp
 (show-paren-mode 1)
@@ -2460,8 +2469,9 @@ Emacs Lisp @dfn{form}:
 
 @item
 If you want it evaluated every time you run Emacs, put it in a file
-named @file{.emacs} in your home directory.  This is known as ``your
-@file{.emacs} file,'' and contains all of your personal customizations.
+named @file{.emacs.d/init.el} in your home directory.  This is known
+as ``your init file,'' and contains all of your personal
+customizations (@pxref{Setting up a customization file}).
 
 @item
 You can type the form in the @file{*scratch*} buffer, and then type
@@ -2499,7 +2509,7 @@ about them.
 
 Set the default value of the variable @code{tab-width}.  For example, to set
 @key{TAB} stops every 10 characters, insert the following in your
-@file{.emacs} file:
+init file (@pxref{Setting up a customization file}):
 
 @lisp
 (setq-default tab-width 10)
@@ -2641,8 +2651,9 @@ Quick command-line switch descriptions are also 
available.  For example,
 You probably don't want to do this, since backups are useful, especially
 when something goes wrong.
 
-To avoid seeing backup files (and other ``uninteresting'' files) in Dired,
-load @code{dired-x} by adding the following to your @file{.emacs} file:
+To avoid seeing backup files (and other ``uninteresting'' files) in
+Dired, load @code{dired-x} by adding the following to your init file
+(@pxref{Setting up a customization file}):
 
 @lisp
 (with-eval-after-load 'dired
@@ -2651,7 +2662,7 @@ load @code{dired-x} by adding the following to your 
@file{.emacs} file:
 
 With @code{dired-x} loaded, @kbd{C-x M-o} toggles omitting in each dired 
buffer.
 You can make omitting the default for new dired buffers by putting the
-following in your @file{.emacs}:
+following in your init file:
 
 @lisp
 (add-hook 'dired-mode-hook 'dired-omit-mode)
@@ -2891,31 +2902,32 @@ and cause an annoying delay in display, so several 
features exist to
 work around this.
 
 @cindex Just-In-Time syntax highlighting
-In Emacs 21 and later, turning on @code{font-lock-mode} automatically
-activates the new @dfn{Just-In-Time fontification} provided by
-@code{jit-lock-mode}.  @code{jit-lock-mode} defers the fontification of
-portions of buffer until you actually need to see them, and can also
-fontify while Emacs is idle.  This makes display of the visible portion
-of a buffer almost instantaneous.  For details about customizing
-@code{jit-lock-mode}, type @kbd{C-h f jit-lock-mode @key{RET}}.
+Turning on @code{font-lock-mode} automatically activates
+@dfn{Just-In-Time fontification} provided by @code{jit-lock-mode}.
+@code{jit-lock-mode} defers the fontification of portions of buffer
+until you actually need to see them, and can also fontify while Emacs
+is idle.  This makes display of the visible portion of a buffer almost
+instantaneous.  For details about customizing @code{jit-lock-mode},
+type @kbd{C-h f jit-lock-mode @key{RET}}.
 
 @cindex Levels of syntax highlighting
 @cindex Decoration level, in @code{font-lock-mode}
-In versions of Emacs before 21, different levels of decoration are
-available, from slight to gaudy.  More decoration means you need to wait
-more time for a buffer to be fontified (or a faster machine).  To
-control how decorated your buffers should become, set the value of
-@code{font-lock-maximum-decoration} in your @file{.emacs} file, with a
-@code{nil} value indicating default (usually minimum) decoration, and a
-@code{t} value indicating the maximum decoration.  For the gaudiest
-possible look, then, include the line
+Different levels of decoration are available, from slight to gaudy.
+More decoration means you need to wait more time for a buffer to be
+fontified (or a faster machine).  To control how decorated your
+buffers should become, set the value of
+@code{font-lock-maximum-decoration} in your init file (@pxref{Setting
+up a customization file}), with a @code{nil} value indicating default
+(usually minimum) decoration, and a @code{t} value indicating the
+maximum decoration.  For the gaudiest possible look, then, include the
+line
 
 @lisp
 (setq font-lock-maximum-decoration t)
 @end lisp
 
 @noindent
-in your @file{.emacs} file.  You can also set this variable such that
+in your init file.  You can also set this variable such that
 different modes are highlighted in a different ways; for more
 information, see the documentation for
 @code{font-lock-maximum-decoration} with @kbd{C-h v} (or @kbd{M-x
@@ -2942,7 +2954,8 @@ customize-variable @key{RET} scroll-conservatively 
@key{RET}} and set it
 to a large value like, say, 10000.  For an explanation of what this
 means, @pxref{Auto Scrolling,,, emacs, The GNU Emacs Manual}.
 
-Alternatively, use the following Lisp form in your @file{.emacs}:
+Alternatively, use the following Lisp form in your init file
+(@pxref{Setting up a customization file}):
 
 @lisp
 (setq scroll-conservatively most-positive-fixnum)
@@ -2971,7 +2984,8 @@ default, a backslash (@samp{\}) will appear in the mode 
line.
 @cindex Single space following periods
 @cindex Periods, one space following
 
-Add the following line to your @file{.emacs} file:
+Add the following line to your init file (@pxref{Setting up a
+customization file}):
 
 @lisp
 (setq sentence-end-double-space nil)
@@ -2985,11 +2999,7 @@ Add the following line to your @file{.emacs} file:
 In many systems, @code{ls} is aliased to @samp{ls --color}, which
 prints using ANSI color escape sequences.  Emacs includes the
 @code{ansi-color} package, which lets Shell mode recognize these
-escape sequences.  In Emacs 23.2 and later, the package is enabled by
-default; in earlier versions you can enable it by typing @kbd{M-x
-ansi-color-for-comint-mode} in the Shell buffer, or by adding
-@code{(add-hook 'shell-mode-hook 'ansi-color-for-comint-mode-on)} to
-your init file.
+escape sequences.  It is enabled by default.
 
 @node Fullscreen mode on MS-Windows
 @section How can I start Emacs in fullscreen mode on MS-Windows?
@@ -2997,15 +3007,15 @@ your init file.
 @cindex Fullscreen mode
 
 Beginning with Emacs 24.4 either run Emacs with the @samp{--maximized}
-command-line option or put the following form in your @file{.emacs}
-file:
+command-line option or put the following form in your init file
+(@pxref{Setting up a customization file}):
 
 @lisp
 (add-hook 'emacs-startup-hook 'toggle-frame-maximized)
 @end lisp
 
 With older versions use the function @code{w32-send-sys-command}.  For
-example, you can put the following in your @file{.emacs} file:
+example, you can put the following in your init file:
 
 @lisp
 (add-hook 'emacs-startup-hook
@@ -3063,10 +3073,9 @@ Emacs has an inherent fixed limitation on the size of 
buffers.  This
 limit is stricter than the maximum size of objects supported by other
 programs on the same architecture.
 
-The maximum buffer size on 32-bit machines is 512 MBytes beginning
-with version 23.2.  If Emacs was built using the
-@code{--with-wide-int} flag, the maximum buffer size on 32-bit
-machines is 2 GB.
+The maximum buffer size on 32-bit machines is 512 MBytes.  If Emacs
+was built using the @code{--with-wide-int} flag, the maximum buffer
+size on 32-bit machines is 2 GB.
 
 Emacs compiled on a 64-bit machine can handle much larger buffers; up
 to @code{most-positive-fixnum} (2.3 exabytes).
@@ -3130,8 +3139,8 @@ with the following Lisp form,
 The above solutions try to prevent the shell from producing the
 @samp{^M} characters in the first place.  If this is not possible
 (e.g., if you use a Windows shell), you can get Emacs to remove these
-characters from the buffer by adding this to your @file{.emacs} init
-file:
+characters from the buffer by adding this to your init file
+(@pxref{Setting up a customization file}):
 
 @smalllisp
 (add-hook 'comint-output-filter-functions #'comint-strip-ctrl-m)
@@ -3153,8 +3162,8 @@ stty -icrnl -onlcr -echo susp ^Z
 @cindex @code{explicit-shell-file-name}
 This might happen because Emacs tries to look for the shell in a wrong
 place.  If you know where your shell executable is, set the variable
-@code{explicit-shell-file-name} in your @file{.emacs} file to point to
-its full file name.
+@code{explicit-shell-file-name} in your init file (@pxref{Setting up a
+customization file}) to point to its full file name.
 
 @cindex Antivirus programs, and Shell Mode
 Some people have trouble with Shell Mode on MS-Windows because of
@@ -3196,18 +3205,18 @@ if ("$term" == emacs) set term=dumb
 
 @node Errors with init files
 @section Why does Emacs say @samp{Error in init file}?
-@cindex Error in @file{.emacs}
+@cindex Error in @file{.emacs.d/init.el}
 @cindex Error in init file
 @cindex Init file, errors in
-@cindex @file{.emacs} file, errors in
-@cindex Debugging @file{.emacs} file
+@cindex @file{.emacs.d/init.el} file, errors in
+@cindex Debugging init file
 
-An error occurred while loading either your @file{.emacs} file or the
+An error occurred while loading either your init file or the
 system-wide file @file{site-lisp/default.el}.  Emacs pops the
 @file{*Messages*} buffer, and puts there some additional information
 about the error, to provide some hints for debugging.
 
-For information on how to debug your @file{.emacs} file, see
+For information on how to debug your init file, see
 @ref{Debugging a customization file}.
 
 It may be the case that you need to load some package first, or use a
@@ -3493,8 +3502,8 @@ and any Emacs Info files that might be in 
@file{/usr/local/share/info/}.
 @cindex Apple computers, Emacs for
 @cindex Macintosh, Emacs for
 @cindex macOS, Emacs for
-Beginning with version 22.1, Emacs supports macOS natively.
-See the file @file{nextstep/INSTALL} in the distribution.
+Emacs supports macOS natively.  See the file @file{nextstep/INSTALL}
+in the distribution.
 
 @cindex FAQ for Emacs on MS-Windows
 @cindex Emacs for MS-Windows
@@ -3503,8 +3512,8 @@ There is a separate FAQ for Emacs on MS-Windows,
 @pxref{Top,,,efaq-w32,FAQ for Emacs on MS Windows}.
 
 @cindex GNUstep, Emacs for
-Beginning with version 23.1, Emacs supports GNUstep natively.
-See the file @file{nextstep/INSTALL} in the distribution.
+Emacs supports GNUstep natively.  See the file @file{nextstep/INSTALL}
+in the distribution.
 
 @cindex MS-DOS, Emacs for
 @cindex DOS, Emacs for
@@ -3720,9 +3729,10 @@ information is available from
 @cindex Keys, binding to commands
 @cindex Commands, binding keys to
 
-Keys can be bound to commands either interactively or in your
-@file{.emacs} file.  To interactively bind keys for all modes, type
-@kbd{M-x global-set-key @key{RET} @var{key} @var{cmd} @key{RET}}.
+Keys can be bound to commands either interactively or in your init
+file (@pxref{Setting up a customization file}).  To interactively bind
+keys for all modes, type @kbd{M-x global-set-key @key{RET} @var{key}
+@var{cmd} @key{RET}}.
 
 To bind a key just in the current major mode, type @kbd{M-x
 local-set-key @key{RET} @var{key} @var{cmd} @key{RET}}.
@@ -3733,7 +3743,7 @@ To make the process of binding keys interactively easier, 
use the
 following ``trick'': First bind the key interactively, then immediately
 type @kbd{C-x @key{ESC} @key{ESC} C-a C-k C-g}.  Now, the command needed
 to bind the key is in the kill ring, and can be yanked into your
-@file{.emacs} file.  If the key binding is global, no changes to the
+init file.  If the key binding is global, no changes to the
 command are required.  For example,
 
 @lisp
@@ -3741,9 +3751,9 @@ command are required.  For example,
 @end lisp
 
 @noindent
-can be placed directly into the @file{.emacs} file.  If the key binding is
-local, the command is used in conjunction with the @samp{add-hook} function.
-For example, in TeX mode, a local binding might be
+can be placed directly into your init file.  If the key binding is
+local, the command is used in conjunction with the @samp{add-hook}
+function.  For example, in TeX mode, a local binding might be
 
 @lisp
 (add-hook 'tex-mode-hook
@@ -3801,14 +3811,15 @@ of these forms before attempting to bind the key 
sequence:
 @end lisp
 
 @node Terminal setup code works after Emacs has begun
-@section Why doesn't this [terminal or window-system setup] code work in my 
@file{.emacs} file, but it works just fine after Emacs starts up?
-@cindex Terminal setup code in @file{.emacs}
+@section Why doesn't this [terminal or window-system setup] code work in my 
init file, but it works just fine after Emacs starts up?
+@cindex Terminal setup code in init file
 
-During startup, Emacs initializes itself according to a given code/file
-order.  If some of the code executed in your @file{.emacs} file needs to
-be postponed until the initial terminal or window-system setup code has
-been executed but is not, then you will experience this problem (this
-code/file execution order is not enforced after startup).
+During startup, Emacs initializes itself according to a given
+code/file order.  If some of the code executed in your init file
+(@pxref{Setting up a customization file}) needs to be postponed until
+the initial terminal or window-system setup code has been executed but
+is not, then you will experience this problem (this code/file
+execution order is not enforced after startup).
 
 To postpone the execution of Emacs Lisp code until after terminal or
 window-system setup, treat the code as a @dfn{lambda list} and add it to
@@ -4229,8 +4240,7 @@ Emacs Manual}.  For more sophisticated methods,
 @cindex bidirectional scripts
 
 Emacs supports display and editing of bidirectional scripts, such as
-Arabic, Farsi, and Hebrew, since version 24.1.
-@xref{New in Emacs 24, bidirectional display}.
+Arabic, Farsi, and Hebrew.
 
 
 @node How to add fonts
@@ -4258,7 +4268,8 @@ arrange for these two commands to run whenever you log 
in, e.g., by
 adding them to your window-system startup file, such as
 @file{~/.xsessionrc} or @file{~/.gnomerc}.
 
-Now, add the following line to your @file{~/.emacs} init file:
+Now, add the following line to your init file (@pxref{Setting up a
+customization file}):
 
 @lisp
   (add-to-list 'bdf-directory-list "/usr/share/emacs/fonts/bdf")
@@ -4268,15 +4279,15 @@ Now, add the following line to your @file{~/.emacs} 
init file:
 (Again, modify the file name if you installed the fonts elsewhere.)
 
 Finally, if you wish to use the installed fonts with @code{ps-print},
-add the following line to your @file{~/.emacs}:
+add the following line to your init file:
 
 @lisp
   (setq ps-multibyte-buffer 'bdf-font-except-latin)
 @end lisp
 
-You can now use the Emacs font menu to select the @samp{bdf: 16-dot medium}
-fontset, or you can select it by setting the default font in your
-@file{~/.emacs}:
+You can now use the Emacs font menu to select the @samp{bdf: 16-dot
+medium} fontset, or you can select it by setting the default font in
+your init file:
 
 @lisp
   (set-frame-font "fontset-bdf")
@@ -4338,9 +4349,9 @@ yourself by putting
 @end lisp
 
 @noindent
-in your @file{.emacs} file.  You can automatically include an @samp{FCC}
-field by putting something like the following in your @file{.emacs}
-file:
+in your init file (@pxref{Setting up a customization file}).  You can
+automatically include an @samp{FCC} field by putting something like
+the following in your init file:
 
 @lisp
 (setq mail-archive-file-name (expand-file-name "~/outgoing"))
@@ -4372,8 +4383,7 @@ To expand them before this, use @kbd{M-x 
expand-mail-aliases}.
 Emacs normally only reads the @file{.mailrc} file once per session, when
 you start to compose your first mail message.  If you edit the file
 after this, you can use @kbd{M-x build-mail-aliases} to make Emacs
-reread it.  Prior to Emacs 24.1, this is not an interactive command, so
-you must instead type @kbd{M-: (build-mail-aliases) @key{RET}}.
+reread it.
 
 @item
 If you like, you can expand mail aliases as abbrevs, as soon as you
@@ -4471,7 +4481,7 @@ gnus
 @end example
 
 It is probably unwise to automatically start your mail or news reader
-from your @file{.emacs} file.  This would cause problems if you needed to run
+from your init file.  This would cause problems if you needed to run
 two copies of Emacs at the same time.  Also, this would make it difficult for
 you to start Emacs quickly when you needed to.
 
diff --git a/doc/misc/emacs-mime.texi b/doc/misc/emacs-mime.texi
index 640712edf3..5f4e1a639b 100644
--- a/doc/misc/emacs-mime.texi
+++ b/doc/misc/emacs-mime.texi
@@ -403,9 +403,9 @@ This selects the function used to render @acronym{HTML}.  
The
 predefined renderers are selected by the symbols @code{shr},
 @code{gnus-w3m}, @code{w3m}@footnote{See
 @uref{http://emacs-w3m.namazu.org/} for more information about
-emacs-w3m}, @code{links}, @code{lynx}, @code{w3m-standalone} or
-@code{html2text}.  You can also specify a function, which will be
-called with a @acronym{MIME} handle as the argument.
+emacs-w3m}, @code{links}, @code{lynx}, or @code{w3m-standalone}.  You
+can also specify a function, which will be called with a
+@acronym{MIME} handle as the argument.
 
 @item mm-html-inhibit-images
 @vindex mm-html-inhibit-images
diff --git a/doc/misc/erc.texi b/doc/misc/erc.texi
index b9297738ea..3db83197f9 100644
--- a/doc/misc/erc.texi
+++ b/doc/misc/erc.texi
@@ -545,20 +545,27 @@ Non-interactively, it takes the following keyword 
arguments.
 @item @var{server}
 @item @var{port}
 @item @var{nick}
+@item @var{user}
 @item @var{password}
 @item @var{full-name}
+@item @var{id}
 @end itemize
 
-That is, if called with the following arguments, @var{server} and
-@var{full-name} will be set to those values, whereas
-@code{erc-compute-port} and @code{erc-compute-nick} will be invoked
-for the values of the other parameters.
+For example, calling the command like so
 
-@example
+@example lisp
 (erc :server "irc.libera.chat" :full-name "J. Random Hacker")
 @end example
+
+@noindent
+sets @var{server} and @var{full-name} directly while leaving the rest
+up to functions like @code{erc-compute-port}.  Note that some
+arguments can't be specified interactively.  @var{id}, in particular,
+is rarely needed (@pxref{Network Identifier}).
+
 @end defun
 
+@noindent
 To connect securely over an encrypted TLS connection, use @kbd{M-x
 erc-tls}.
 
@@ -570,21 +577,25 @@ Non-interactively, it takes the following keyword 
arguments.
 @item @var{server}
 @item @var{port}
 @item @var{nick}
+@item @var{user}
 @item @var{password}
 @item @var{full-name}
+@item @var{id}
 @item @var{client-certificate}
 @end itemize
 
-That is, if called with the following arguments, @var{server} and
-@var{full-name} will be set to those values, whereas
-@code{erc-compute-port} and @code{erc-compute-nick} will be invoked
-for the values of the other parameters, and @code{client-certificate}
-will be @code{nil}.
+That is, if called in the following manner
 
-@example
+@example lisp
 (erc-tls :server "irc.libera.chat" :full-name "J. Random Hacker")
 @end example
 
+@noindent
+the command will set @var{server} and @var{full-name} accordingly,
+while helpers, like @code{erc-compute-nick}, will determine other
+parameters, and some, like @code{client-certificate}, will just be
+@code{nil}.
+
 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
@@ -719,29 +730,139 @@ ERC should automatically attempt to connect with another 
nickname.
 You can manually set another nickname with the /NICK command.
 @end defopt
 
+@subheading User
+@defun erc-compute-user &optional user
+Determine a suitable value to send as the first argument of the
+opening @samp{USER} IRC command by consulting the following sources:
+
+@itemize
+@item
+@var{user}, the argument passed to this function
+@item
+The option @code{erc-email-userid}, assuming @code{erc-anonymous-login}
+is non-@code{nil}
+@item
+The result of calling the function @code{user-login-name}
+@end itemize
+
+@end defun
+
+@defopt erc-email-userid
+A permanent username value to send for all connections.  It should be
+a string abiding by the rules of the network.
+@end defopt
+
 @subheading Password
 @cindex password
 
 @defopt erc-prompt-for-password
-If non-@code{nil} (the default), @kbd{M-x erc} prompts for a password.
+If non-@code{nil} (the default), @kbd{M-x erc} and @kbd{M-x erc-tls}
+prompt for a server password.  This only affects interactive
+invocations of @code{erc} and @code{erc-tls}.
 @end defopt
 
+@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
-you use @file{~/.authinfo} as your auth-source backend, then put
+the option @code{auth-sources} contains @file{~/.authinfo}, put
 something like the following in that file:
 
 @example
-machine irc.example.net login "#fsf" password sEcReT
+machine irc.example.net login mynick password sEcReT
 @end example
 
 @noindent
-ERC also consults @code{auth-source} to find any channel keys required
-for the channels that you wish to autojoin, as specified by the
-variable @code{erc-autojoin-channels-alist}.
+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:
 
-For more details, @pxref{Top,,auth-source, auth, Emacs auth-source Library}.
+@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}.
+
+@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 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, and secrets are currently supported.
+@end defopt
 
 @subheading Full name
 
@@ -752,10 +873,14 @@ This tries a number of increasingly more default methods 
until a
 non-@code{nil} value is found.
 
 @itemize @bullet
-@item @var{full-name} (the argument passed to this function)
-@item The @code{erc-user-full-name} option
-@item The value of the IRCNAME environment variable
-@item The result from the @code{user-full-name} function
+@item
+@var{full-name} (the argument passed to this function)
+@item
+The @code{erc-user-full-name} option
+@item
+The value of the IRCNAME environment variable
+@item
+The result from the @code{user-full-name} function
 @end itemize
 
 @end defun
@@ -766,6 +891,31 @@ User full name.
 This can be either a string or a function to call.
 @end defopt
 
+
+@subheading ID
+@anchor{Network Identifier}
+
+ERC uses an abstract designation, called @dfn{network context
+identifier}, for referring to a connection internally.  While normally
+derived from a combination of logical and physical connection
+parameters, an ID can also be explicitly provided via an entry-point
+command (like @code{erc-tls}).  Use this in rare situations where ERC
+would otherwise have trouble discerning between connections.
+
+One such situation might arise when using multiple connections to the
+same network with the same nick but different (nonstandard) @samp{device}
+identifiers, which some bouncers may support.  Another might be when
+mimicking the experience offered by popular standalone clients, which
+normally offer ``named'' persistent configurations with server buffers
+reflecting those names.  Yet another use case might involve
+third-party code needing to identify a connection unequivocally, but in
+a human-friendly way suitable for UI components.
+
+When providing an ID as an entry-point argument, strings and symbols
+make the most sense, but any reasonably printable object is
+acceptable.
+
+
 @node Sample Configuration
 @section Sample Configuration
 @cindex configuration, sample
@@ -827,12 +977,6 @@ stuff, to the current ERC buffer."
 (setq erc-autojoin-channels-alist
       '(("Libera.Chat" "#emacs" "#erc")))
 
-;; Rename server buffers to reflect the current network name instead
-;; of SERVER:PORT (e.g., "Libera.Chat" instead of
-;; "irc.libera.chat:6667").  This is useful when using a bouncer like
-;; ZNC where you have multiple connections to the same server.
-(setq erc-rename-buffers t)
-
 ;; Interpret mIRC-style color commands in IRC chats
 (setq erc-interpret-mirc-color t)
 
@@ -891,15 +1035,6 @@ lurkers.  The function @code{erc-lurker-p} determines 
whether a given
 nickname is considered a lurker.
 @end defopt
 
-@defopt erc-rename-buffers
-If non, @code{nil}, this will rename server buffers to reflect the
-current network name instead of IP:PORT
-
-@example
-(setq erc-rename-buffers t)
-@end example
-@end defopt
-
 @node Getting Help and Reporting Bugs
 @chapter Getting Help and Reporting Bugs
 @cindex help, getting
@@ -924,7 +1059,7 @@ contributors are frequently around and willing to answer 
your
 questions.
 
 @item
-To report a bug in ERC, use @kbd{M-x report-emacs-bug}.
+To report a bug in ERC, use @kbd{M-x erc-bug}.
 
 @end itemize
 
diff --git a/doc/misc/ert.texi b/doc/misc/ert.texi
index 91288db45a..1b7f38daad 100644
--- a/doc/misc/ert.texi
+++ b/doc/misc/ert.texi
@@ -321,7 +321,7 @@ Show the list of @code{should} forms executed in the test
 @kindex m@r{, in ert results buffer}
 @findex ert-results-pop-to-messages-for-test-at-point
 Show any messages that were generated (with the Lisp function
-@code{message}) in in a test or any of the code that it invoked
+@code{message}) in a test or any of the code that it invoked
 (@code{ert-results-pop-to-messages-for-test-at-point}).
 
 @item L
@@ -822,7 +822,7 @@ that's pretty difficult to read and write, especially when 
the text in
 question is multi-line.
 
 So ert provides a function called @code{ert-test-erts-file} that takes
-two parameters: The name of a specially-formatted @dfn{erts} file, and
+two parameters: the name of a specially-formatted @dfn{erts} file, and
 (optionally) a function that performs the transform.
 
 @findex erts-mode
diff --git a/doc/misc/eshell.texi b/doc/misc/eshell.texi
index 85e5a4933f..13f13163dd 100644
--- a/doc/misc/eshell.texi
+++ b/doc/misc/eshell.texi
@@ -201,7 +201,7 @@ history and invoking commands in a script file.
 * Aliases::
 * History::
 * Completion::
-* for loop::
+* Control Flow::
 * Scripts::
 @end menu
 
@@ -219,12 +219,18 @@ same name; if there is no match, it then tries to execute 
it as an
 external command.
 
 The semicolon (@code{;}) can be used to separate multiple command
-invocations on a single line.  A command invocation followed by an
-ampersand (@code{&}) will be run in the background.  Eshell has no job
-control, so you can not suspend or background the current process, or
-bring a background process into the foreground.  That said, background
-processes invoked from Eshell can be controlled the same way as any
-other background process in Emacs.
+invocations on a single line.  You can also separate commands with
+@code{&&} or @code{||}. When using @code{&&}, Eshell will execute the
+second command only if the first succeeds (i.e.@: has an exit
+status of 0); with @code{||}, Eshell will execute the second command
+only if the first fails.
+
+A command invocation followed by an ampersand (@code{&}) will be run
+in the background.  Eshell has no job control, so you can not suspend
+or background the current process, or bring a background process into
+the foreground.  That said, background processes invoked from Eshell
+can be controlled the same way as any other background process in
+Emacs.
 
 @node Arguments
 @section Arguments
@@ -354,11 +360,11 @@ Giving the command @kbd{cd -} changes back to the 
previous working
 directory (this is the same as @kbd{cd $-}).
 
 @item
-The command @kbd{cd =} shows the directory stack.  Each line is
+The command @kbd{cd =} shows the directory ring.  Each line is
 numbered.
 
 @item
-With @kbd{cd =foo}, Eshell searches the directory stack for a directory
+With @kbd{cd =foo}, Eshell searches the directory ring for a directory
 matching the regular expression @samp{foo}, and changes to that
 directory.
 
@@ -845,46 +851,77 @@ For example, you could handle a subset of the options for 
the
 
 @end defmac
 
+@node Variables
+@section Variables
+Since Eshell is just an Emacs @acronym{REPL}@footnote{
+Short for ``Read-Eval-Print Loop''.
+}
+, it does not have its own scope, and simply stores variables the same
+you would in an Elisp program.  Eshell provides a command version of
+@code{setq} for convenience.
+
 @subsection Built-in variables
 Eshell knows a few built-in variables:
 
 @table @code
 
-@item $+
+@vindex $PWD
 @vindex $+
+@item $PWD
+@itemx $+
 This variable always contains the current working directory.
 
-@item $-
+@vindex $OLDPWD
 @vindex $-
+@item $OLDPWD
+@itemx $-
 This variable always contains the previous working directory (the
 current working directory from before the last @code{cd} command).
+When using @code{$-}, you can also access older directories in the
+directory ring via subscripting, e.g.@: @samp{$-[1]} refers to the
+working directory @emph{before} the previous one.
 
-@item $_
 @vindex $_
-It refers to the last argument of the last command.
+@item $_
+This refers to the last argument of the last command.  With a
+subscript, you can access any argument of the last command.  For
+example, @samp{$_[1]} refers to the second argument of the last
+command (excluding the command name itself).
 
-@item $$
 @vindex $$
-This is the result of the last command.  In case of an external
-command, it is @code{t} or @code{nil}.
+@item $$
+This is the result of the last command.  For external commands, it is
+@code{t} if the exit code was 0 or @code{nil} otherwise.
 
-@item $?
+@vindex eshell-lisp-form-nil-is-failure
 @vindex $?
-This variable contains the exit code of the last command (0 or 1 for
-Lisp functions, based on successful completion).
+@item $?
+This variable contains the exit code of the last command.  If the last
+command was a Lisp function, it is 0 for successful completion or 1
+otherwise.  If @code{eshell-lisp-form-nil-is-failure} is
+non-@code{nil}, then a command with a Lisp form, like
+@samp{(@var{command} @var{args}@dots{})}, that returns @code{nil} will
+set this variable to 2.
+
+@vindex $COLUMNS
+@vindex $LINES
+@item $COLUMNS
+@itemx $LINES
+These variables tell the number of columns and lines, respectively,
+that are currently visible in the Eshell window.  They are both
+copied to the environment, so external commands invoked from
+Eshell can consult them to do the right thing.
+
+@item $INSIDE_EMACS
+This variable indicates to external commands that they are being
+invoked from within Emacs so they can adjust their behavior if
+necessary.  Its value is @code{@var{emacs-version},eshell}.
 
 @end table
 
 @xref{Aliases}, for the built-in variables @samp{$*}, @samp{$1},
 @samp{$2}, @dots{}, in alias definitions.
 
-@node Variables
-@section Variables
-Since Eshell is just an Emacs REPL@footnote{Read-Eval-Print Loop}, it
-does not have its own scope, and simply stores variables the same you
-would in an Elisp program.  Eshell provides a command version of
-@code{setq} for convenience.
-
 @node Aliases
 @section Aliases
 
@@ -981,19 +1018,46 @@ command for which this function provides completions; 
you can also name
 the function @code{pcomplete/MAJOR-MODE/COMMAND} to define completions
 for a specific major mode.
 
-@node for loop
-@section @code{for} loop
+@node Control Flow
+@section Control Flow
 Because Eshell commands can not (easily) be combined with lisp forms,
-Eshell provides a command-oriented @command{for}-loop for convenience.
-The syntax is as follows:
+Eshell provides command-oriented control flow statements for
+convenience.
 
-@example
-@code{for VAR in TOKENS @{ command invocation(s) @}}
-@end example
+Most of Eshell's control flow statements accept a @var{conditional}.
+This can take a few different forms.  If @var{conditional} is a dollar
+expansion, the condition is satisfied if the result is a
+non-@code{nil} value.  If @var{conditional} is a @samp{@{
+@var{subcommand} @}} or @samp{(@var{lisp form})}, the condition is
+satisfied if the command's exit status is 0.
+
+@table @code
+
+@item if @var{conditional} @{ @var{true-commands} @}
+@itemx if @var{conditional} @{ @var{true-commands} @} @{ @var{false-commands} 
@}
+Evaluate @var{true-commands} if @var{conditional} is satisfied;
+otherwise, evaluate @var{false-commands}.
+
+@item unless @var{conditional} @{ @var{false-commands} @}
+@itemx unless @var{conditional} @{ @var{false-commands} @} @{ 
@var{true-commands} @}
+Evaluate @var{false-commands} if @var{conditional} is not satisfied;
+otherwise, evaluate @var{true-commands}.
+
+@item while @var{conditional} @{ @var{commands} @}
+Repeatedly evaluate @var{commands} so long as @var{conditional} is
+satisfied.
 
-where @samp{TOKENS} is a space-separated sequence of values of
-@var{VAR} for each iteration.  This can even be the output of a
-command if @samp{TOKENS} is replaced with @samp{@{ command invocation @}}.
+@item until @var{conditional} @{ @var{commands} @}
+Repeatedly evaluate @var{commands} until @var{conditional} is
+satisfied.
+
+@item for @var{var} in @var{list}@dots{} @{ @var{commands} @}
+Iterate over each element of of @var{list}, storing the element in
+@var{var} and evaluating @var{commands}.  If @var{list} is not a list,
+treat it as a list of one element.  If you specify multiple
+@var{lists}, this will iterate over each of them in turn.
+
+@end table
 
 @node Scripts
 @section Scripts
@@ -1045,7 +1109,7 @@ back to a number as above).  For example, @samp{$list("a" 
"b")c}
 returns @samp{("a" "bc")}.
 
 @item anything else
-Concatenate the string represenation of each value.
+Concatenate the string representation of each value.
 
 @end table
 
@@ -1570,7 +1634,7 @@ integration: using the remote shell's pipelining avoids 
copying the
 data which will flow through the pipeline to local Emacs buffers and
 then right back again.
 
-Eshell recognises a special syntax to make it easier to convert
+Eshell recognizes a special syntax to make it easier to convert
 pipelines so as to bypass Eshell's pipelining.  Prefixing at least one
 @code{|}, @code{<} or @code{>} with an asterisk marks a command as
 intended for the operating system shell.  To make it harder to invoke
@@ -1588,7 +1652,7 @@ nor the decoded data, into Emacs buffers, as would 
normally happen.
 The command is interpreted as extending up to the next @code{|}
 character which is not preceded by an unescaped asterisk following
 whitespace, or the end of the input if there is no such character.
-Thus, all @code{<} and @code{>} redirections occuring before the next
+Thus, all @code{<} and @code{>} redirections occurring before the next
 asterisk-unprefixed @code{|} are implicitly prefixed with (whitespace
 and) asterisks.  An exception is that Eshell-specific redirects right
 at the end of the command are excluded.  This allows input like this:
@@ -1784,11 +1848,6 @@ scrolls back.
 
 @item Menu support was removed, but never put back
 
-@item Using C-p and C-n with rebind gets into a locked state
-
-This happened a few times in Emacs 21, but has been irreproducible
-since.
-
 @item If an interactive process is currently running, @kbd{M-!} doesn't work
 
 @item Use a timer instead of @code{sleep-for} when killing child processes
@@ -1902,11 +1961,6 @@ glob match.
 
 At the moment, this is not supported.
 
-@item Error if a glob doesn't expand due to a predicate
-
-An error should be generated only if @code{eshell-error-if-no-glob} is
-non-@code{nil}.
-
 @item @samp{(+ @key{RET} @key{SPC} @key{TAB}} does not cause 
@code{indent-according-to-mode} to occur
 
 @item Create @code{eshell-auto-accumulate-list}
@@ -2082,11 +2136,10 @@ it).
 
 @item Make the shell spawning commands be visual
 
-That is, make (@command{su}, @command{bash}, @command{telnet},
-@command{rlogin}, @command{rsh}, etc.)@: be part of
-@code{eshell-visual-commands}.  The only exception is if the shell is
-being used to invoke a single command.  Then, the behavior should be
-based on what that command is.
+That is, make (@command{su}, @command{bash}, @command{ssh}, etc.)@: be
+part of @code{eshell-visual-commands}.  The only exception is if the
+shell is being used to invoke a single command.  Then, the behavior
+should be based on what that command is.
 
 @item Create a smart viewing command named @command{open}
 
diff --git a/doc/misc/eudc.texi b/doc/misc/eudc.texi
index 7fd5add67e..0037ba78d3 100644
--- a/doc/misc/eudc.texi
+++ b/doc/misc/eudc.texi
@@ -292,7 +292,7 @@ LDAP:
 (setopt eudc-server-hotlist
         '(("" . bbdb)
           ("ldaps://ldap.gnu.org" . ldap)))
-(setopt 'ldap-host-parameters-alist
+(setopt ldap-host-parameters-alist
         '(("ldaps://ldap.gnu.org"
                   base "ou=people,dc=gnu,dc=org"
                   binddn "gnu\\emacsuser"
@@ -346,10 +346,10 @@ configure EUDC for LDAP:
 @lisp
 (with-eval-after-load "message"
   (define-key message-mode-map (kbd "TAB") 'eudc-expand-try-all))
-(setopt 'eudc-server-hotlist
+(setopt eudc-server-hotlist
         '(("" . bbdb)
           ("ldaps://ldap.gnu.org" . ldap)))
-(setopt 'ldap-host-parameters-alist
+(setopt ldap-host-parameters-alist
         '(("ldaps://ldap.gnu.org"
                   auth-source t)))
 @end lisp
@@ -376,9 +376,9 @@ and the @file{.emacs} expressions become:
 @lisp
 (with-eval-after-load "message"
   (define-key message-mode-map (kbd "TAB") 'eudc-expand-try-all))
-(setopt 'eudc-server-hotlist
+(setopt eudc-server-hotlist
         '(("" . bbdb) ("" . ldap)))
-(setopt 'ldap-host-parameters-alist
+(setopt ldap-host-parameters-alist
         '(("" auth-source t)))
 @end lisp
 
@@ -423,11 +423,12 @@ all macOS versions since 10.0 (which was released 2001).
 configurations.
 
 @file{eudcb-mab.el} reverse engineers the format of the database file
-used by the macOS Contacts app, and accesses its contents directly.
-While this may promise some performance advantages, it comes at the
-cost of using an undocumented interface.  Hence, users of
-@file{eudcb-mab.el} are recommended to double check the compatibility
-of @file{eudcb-mab.el} before upgrading to a new version of macOS.
+using the external command-line utility named contacts, which needs to
+be installed separately.  While this may promise some performance
+advantages, it comes at the cost of using an undocumented interface.
+Hence, users of @file{eudcb-mab.el} are recommended to double check
+the compatibility of @file{eudcb-mab.el} and the required, external
+command-line utility before upgrading to a new version of macOS.
 @file{eudcb-mab.el} is retained for backwards compatibility with
 existing configurations, and may be removed in a future release.
 
diff --git a/doc/misc/eww.texi b/doc/misc/eww.texi
index f23180c1d4..1060cd805a 100644
--- a/doc/misc/eww.texi
+++ b/doc/misc/eww.texi
@@ -69,7 +69,7 @@ Indices
 @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.
+However, a GNU Emacs with @code{libxml2} support is required.
 
 @node Basics
 @chapter Basic Usage
@@ -213,7 +213,7 @@ switch EWW buffers through a minibuffer prompt, press 
@kbd{s}
 @cindex External Browser
   Although EWW and shr.el do their best to render webpages in GNU
 Emacs some websites use features which can not be properly represented
-or are not implemented (E.g., JavaScript).  If you have trouble
+or are not implemented (e.g., JavaScript).  If you have trouble
 viewing a website with EWW then hit @kbd{&}
 (@code{eww-browse-with-external-browser}) inside the EWW buffer to
 open the website in the external browser specified by
diff --git a/doc/misc/gnus-faq.texi b/doc/misc/gnus-faq.texi
index 630aaa282f..6d09fd4ec9 100644
--- a/doc/misc/gnus-faq.texi
+++ b/doc/misc/gnus-faq.texi
@@ -1,7 +1,7 @@
 @c \input texinfo @c -*-texinfo-*-
 @c Uncomment 1st line before texing this file alone.
 @c %**start of header
-@c Copyright (C) 1995, 2001--2022 Free Software Foundation, Inc.
+@c Copyright (C) 1995--2022 Free Software Foundation, Inc.
 @c
 @c @setfilename gnus-faq.info
 @c @settitle Frequently Asked Questions
@@ -13,7 +13,6 @@
 @section Frequently Asked Questions
 
 @menu
-* FAQ - Changes::
 * FAQ - Introduction::                       About Gnus and this FAQ.
 * FAQ 1 - Installation FAQ::                 Installation of Gnus.
 * FAQ 2 - Startup / Group buffer::           Start up questions and the
@@ -41,21 +40,6 @@ This is the new Gnus Frequently Asked Questions list.
 Please submit features and suggestions to the
 @email{ding@@gnus.org, ding list}.
 
-@node FAQ - Changes
-@subsection Changes
-
-
-
-@itemize @bullet
-
-@item
-2008-06-15: Adjust for message-fill-column.  Add x-face-file.
-Clarify difference between ding and gnu.emacs.gnus.  Remove
-reference to discontinued service.
-
-@item
-2006-04-15: Added tip on how to delete sent buffer on exit.
-@end itemize
 
 @node FAQ - Introduction
 @subsection Introduction
@@ -63,11 +47,11 @@ reference to discontinued service.
 This is the Gnus Frequently Asked Questions list.
 
 Gnus is a Usenet Newsreader and Electronic Mail User Agent implemented
-as a part of Emacs. It's been around in some form for almost a decade
-now, and has been distributed as a standard part of Emacs for much of
-that time. Gnus 5 is the latest (and greatest) incarnation. The
+as a part of Emacs.  It's been around in some form since the early
+1990s, and has been distributed as a standard part of Emacs for much
+of that time. Gnus 5 is the latest (and greatest) incarnation.  The
 original version was called GNUS, and was written by Masanobu UMEDA@.
-When autumn crept up in '94, Lars Magne Ingebrigtsen grew bored and
+When autumn crept up in 1994, Lars Magne Ingebrigtsen grew bored and
 decided to rewrite Gnus.
 
 Its biggest strength is the fact that it is extremely
@@ -84,11 +68,6 @@ would like to thank Steve Baur and Per Abrahamsen for doing 
a wonderful
 job with this FAQ before him. We would like to do the same: thanks,
 Justin!
 
-This version is much nicer than the unofficial hypertext
-versions that are archived at Utrecht, Oxford, Smart Pages, Ohio
-State, and other FAQ archives. See the resources question below
-if you want information on obtaining it in another format.
-
 The information contained here was compiled with the assistance
 of the Gnus development mailing list, and any errors or
 misprints are the Gnus team's fault, sorry.
@@ -98,11 +77,9 @@ misprints are the Gnus team's fault, sorry.
 
 @menu
 * FAQ 1-1::    What is the latest version of Gnus?
-* FAQ 1-2::    What's new in 5.10?
-* FAQ 1-3::    Where and how to get Gnus?
-* FAQ 1-4::    I sometimes read references to No Gnus and Oort Gnus,
+* FAQ 1-2::    Where and how to get Gnus?
+* FAQ 1-3::    I sometimes read references to No Gnus and Oort Gnus,
                what are those?
-* FAQ 1-5::    Which version of Emacs do I need?
 @end menu
 
 @node FAQ 1-1
@@ -112,80 +89,28 @@ What is the latest version of Gnus?
 
 @subsubheading Answer
 
-Jingle please: Gnus 5.10 is released, get it while it's
-hot! As well as the step in version number is rather
-small, Gnus 5.10 has tons of new features which you
-shouldn't miss. The current release (5.13) should be at
-least as stable as the latest release of the 5.8 series.
+The latest version of Gnus is bundled with Emacs.
 
 @node FAQ 1-2
 @subsubheading Question 1.2
 
-What's new in 5.10?
-
-@subsubheading Answer
-
-First of all, you should have a look into the file
-GNUS-NEWS in the toplevel directory of the Gnus tarball,
-there the most important changes are listed. Here's a
-short list of the changes I find especially
-important/interesting:
-
-@itemize @bullet
-
-@item
-Major rewrite of the Gnus agent, Gnus agent is now
-active by default.
-
-@item
-Many new article washing functions for dealing with
-ugly formatted articles.
-
-@item
-Anti Spam features.
-
-@item
-Message-utils now included in Gnus.
-
-@item
-New format specifiers for summary lines, e.g., %B for
-a complex trn-style thread tree.
-@end itemize
-
-@node FAQ 1-3
-@subsubheading Question 1.3
-
 Where and how to get Gnus?
 
 @subsubheading Answer
 
 Gnus is bundled with Emacs.
 
-@node FAQ 1-4
-@subsubheading Question 1.4
+@node FAQ 1-3
+@subsubheading Question 1.3
 
 I sometimes read references to No Gnus and Oort Gnus,
 what are those?
 
 @subsubheading Answer
 
-Oort Gnus was the name of the development version of
-Gnus, which became Gnus 5.10 in autumn 2003. No Gnus is
-the name of the current development version which will
-once become Gnus 5.12 or Gnus 6. (If you're wondering why
-not 5.11, the odd version numbers are normally used for
-the Gnus versions bundled with Emacs)
-
-@node FAQ 1-5
-@subsubheading Question 1.5
-
-Which version of Emacs do I need?
-
-@subsubheading Answer
-
-Gnus 5.13 requires an Emacs version that is greater than or equal
-to Emacs 23.1, although there are some features that
-only work on Emacs 24.
+Oort Gnus was the name of the development version of Gnus, which
+became Gnus 5.10 in autumn 2003.  No Gnus was the name of the
+development version that became Gnus 5.12.
 
 @node FAQ 2 - Startup / Group buffer
 @subsection Startup / Group buffer
@@ -718,9 +643,8 @@ in @file{~/.gnus.el} to load enough old articles to prevent 
teared threads, repl
 all articles (Warning: Both settings enlarge the amount of data which is
 fetched when you enter a group and slow down the process of entering a group).
 
-If you already use Gnus 5.10, you can say
-@samp{/o N}
-In summary buffer to load the last N messages, this feature is not available 
in 5.8.8
+You can say @samp{/o N} in the summary buffer to load the last N
+messages.
 
 If you don't want all old messages, but the parent of the message you're just 
reading,
 you can say @samp{^}, if you want to retrieve the whole thread
@@ -820,11 +744,10 @@ Can I use some other browser than w3m to render my 
HTML-mails?
 
 @subsubheading Answer
 
-Only if you use Gnus 5.10 or younger. In this case you've got the
-choice between shr, w3m, links, lynx and html2text, which
-one is used can be specified in the variable
-mm-text-html-renderer, so if you want links to render your
-mail say
+You've got the choice between @samp{shr}, @samp{w3m}, @samp{links},
+and @samp{lynx}.  Which one is used is specified in the variable
+@code{mm-text-html-renderer}, so if you want links to render your
+mail, say:
 
 @example
 (setq mm-text-html-renderer 'links)
@@ -847,8 +770,7 @@ long lines'' (@samp{W w}), ``Decode ROT13''
 the dumb quoting used by many users of Microsoft products
 (@samp{W Y f} gives you full deuglify.
 See @samp{W Y C-h} or have a look at the menus for
-other deuglifications).  Outlook deuglify is only available since
-Gnus 5.10.
+other deuglifications).
 
 @node FAQ 4-9
 @subsubheading Question 4.9
@@ -1038,7 +960,7 @@ you'll find useful things like positioning the cursor and
 tabulators which allow you a summary in table form, but
 sadly hard tabulators are broken in 5.8.8.
 
-Since 5.10, Gnus offers you some very nice new specifiers,
+Gnus offers you some very nice new specifiers,
 e.g., %B which draws a thread-tree and %&user-date which
 gives you a date where the details are dependent of the
 articles age. Here's an example which uses both:
@@ -1245,7 +1167,7 @@ How to set stuff like From, Organization, Reply-To, 
signature...?
 @subsubheading Answer
 
 There are other ways, but you should use posting styles
-for this. (See below why).
+for this.  (See below why.)
 This example should make the syntax clear:
 
 @example
@@ -1329,19 +1251,14 @@ Is there a spell-checker? Perhaps even on-the-fly 
spell-checking?
 
 @subsubheading Answer
 
-You can use ispell.el to spell-check stuff in Emacs. So the
-first thing to do is to make sure that you've got either
-@uref{https://www.cs.hmc.edu/~geoff/ispell.html, ispell}
-or @uref{http://aspell.net, aspell}
-installed and in your Path. Then you need
-ispell.el
-and for on-the-fly spell-checking
-@uref{https://www-sop.inria.fr/members/Manuel.Serrano/flyspell/flyspell.html, 
flyspell.el}.
-Ispell.el is shipped with Emacs,
-flyspell.el is shipped with Emacs, so there should be no need to install them
-manually.
+You can use ispell.el to spell-check stuff in Emacs, and flyspell.el
+for on-the-fly spell-checking.  So the first thing to do is to make
+sure that you've got either
+@uref{https://hunspell.github.io/, hunspell},
+@uref{https://www.cs.hmc.edu/~geoff/ispell.html, ispell} or
+@uref{http://aspell.net, aspell} installed and in your Path.
 
-Ispell.el assumes you use ispell, if you choose aspell say
+Ispell.el assumes you use ispell.  If you use aspell say
 
 @example
 (setq ispell-program-name "aspell")
@@ -1494,14 +1411,14 @@ Now you only have to tell Gnus to include the X-face in 
your postings by saying
 @end example
 @noindent
 
-in @file{~/.gnus.el}.  If you use Gnus 5.10, you can simply add an entry
+in @file{~/.gnus.el}.  You can add an entry
 
 @example
 (x-face-file "~/.xface")
 @end example
 @noindent
 
-to gnus-posting-styles.
+to @code{gnus-posting-styles}.
 
 @node FAQ 5-9
 @subsubheading Question 5.9
@@ -1519,21 +1436,6 @@ Put this in @file{~/.gnus.el}:
 @end example
 @noindent
 
-if you already use Gnus 5.10, if you still use 5.8.8 or
-5.9 try this instead:
-
-@example
-(with-eval-after-load "gnus-msg"
-  (unless (boundp 'gnus-confirm-mail-reply-to-news)
-    (defadvice gnus-summary-reply (around reply-in-news activate)
-      "Request confirmation when replying to news."
-      (interactive)
-      (when (or (not (gnus-news-group-p gnus-newsgroup-name))
-                (y-or-n-p "Really reply by mail to article author?"))
-        ad-do-it))))
-@end example
-@noindent
-
 @node FAQ 5-10
 @subsubheading Question 5.10
 
@@ -1541,14 +1443,7 @@ How to tell Gnus not to generate a sender header?
 
 @subsubheading Answer
 
-Since 5.10 Gnus doesn't generate a sender header by
-default. For older Gnus' try this in @file{~/.gnus.el}:
-
-@example
-(with-eval-after-load "message"
-  (add-to-list 'message-syntax-checks '(sender . disabled)))
-@end example
-@noindent
+Gnus doesn't generate a sender header by default.
 
 @node FAQ 5-11
 @subsubheading Question 5.11
@@ -1729,7 +1624,7 @@ more then one article."
 You can now say @samp{M-x
 my-archive-article} in summary buffer to
 archive the article under the cursor in a nnml
-group. (Change nnml to your preferred back end)
+group. (Change nnml to your preferred back end.)
 
 Of course you can also make sure the cache is enabled by saying
 
@@ -1756,7 +1651,7 @@ if you found the posting there, tell Google to display
 the raw message, look for the message-id, and say
 @samp{M-^ the@@message.id @key{RET}} in a
 summary buffer.
-Since Gnus 5.10 there's also a Gnus interface for
+There's a Gnus interface for
 groups.google.com which you can call with
 @samp{G W}) in group buffer.
 
@@ -1770,25 +1665,6 @@ instead. Further on there are the
 gnus-summary-limit-to-foo functions, which can help you,
 too.
 
-Of course you can also use grep to search through your
-local mail, but this is both slow for big archives and
-inconvenient since you are not displaying the found mail
-in Gnus.  Here nnir comes into action.  Nnir is a front end
-to search engines like swish-e or swish++ and
-others.  You index your mail with one of those search
-engines and with the help of nnir you can search through
-the indexed mail and generate a temporary group with all
-messages which met your search criteria.  If this sounds
-cool to you, get nnir.el from
-@c FIXME Isn't this file in Gnus?
-@ignore
-@c Dead link 2013/7.
-@uref{ftp://ls6-ftp.cs.uni-dortmund.de/pub/src/emacs/}
-or
-@end ignore
-@uref{ftp://ftp.is.informatik.uni-duisburg.de/pub/src/emacs/}.
-Instructions on how to use it are at the top of the file.
-
 @node FAQ 6-4
 @subsubheading Question 6.4
 
@@ -1937,16 +1813,9 @@ So what was this thing about the Agent?
 The Gnus agent is part of Gnus, it allows you to fetch
 mail and news and store them on disk for reading them
 later when you're offline. It kind of mimics offline
-newsreaders like Forte Agent. If you want to use
-the Agent place the following in @file{~/.gnus.el} if you are
-still using 5.8.8 or 5.9 (it's the default since 5.10):
-
-@example
-(setq gnus-agent t)
-@end example
-@noindent
+newsreaders like Forte Agent.  It is enabled by default.
 
-Now you've got to select the servers whose groups can be
+You've got to select the servers whose groups can be
 stored locally.  To do this, open the server buffer
 (that is press @samp{^} while in the
 group buffer).  Now select a server by moving point to
@@ -2051,10 +1920,9 @@ I can't find anything in the Gnus manual about X
 @subsubheading Answer
 
 There's not only the Gnus manual but also the manuals for message,
-emacs-mime, sieve, EasyPG Assistant, and pgg. Those packages are
-distributed with Gnus and used by Gnus but aren't really part of core
-Gnus, so they are documented in different info files, you should have
-a look in those manuals, too.
+emacs-mime, sieve, and EasyPG Assistant.  Those packages are
+distributed with Emacs and used by Gnus.  They are documented in
+separate info files, so you should have a look in those manuals, too.
 
 @node FAQ 8-3
 @subsubheading Question 8.3
@@ -2161,42 +2029,19 @@ How to speed up the process of entering a group?
 
 @subsubheading Answer
 
-A speed killer is setting the variable
-gnus-fetch-old-headers to anything different from @code{nil},
-so don't do this if speed is an issue. To speed up
-building of summary say
-
-@example
-(gnus-compile)
-@end example
-@noindent
+A speed killer is setting the variable @code{gnus-fetch-old-headers}
+to anything different from @code{nil}, so don't do this if speed is an
+issue.
 
-at the bottom of your @file{~/.gnus.el}, this will make gnus
-byte-compile things like
-gnus-summary-line-format.
-then you could increase the value of gc-cons-threshold
-by saying something like
+You could increase the value of @code{gc-cons-threshold} by saying
+something like:
 
 @example
 (setq gc-cons-threshold 3500000)
 @end example
 @noindent
 
-in ~/.emacs. If you don't care about width of CJK
-characters or use Gnus 5.10 or younger together with a
-recent GNU Emacs, you should say
-
-@example
-(setq gnus-use-correct-string-widths nil)
-@end example
-@noindent
-
-in @file{~/.gnus.el} (thanks to Jesper harder for the last
-two suggestions). Finally if you are still using 5.8.8
-or 5.9 and experience speed problems with summary
-buffer generation, you definitely should update to
-5.10 since there quite some work on improving it has
-been done.
+in ~/.emacs.
 
 @node FAQ 9-3
 @subsubheading Question 9.3
@@ -2227,10 +2072,6 @@ between core Gnus and the real NNTP-, POP3-, IMAP- or
 whatever-server which offers Gnus a standardized interface
 to functions like "get message", "get Headers" etc.
 
-@item Emacs
-When the term Emacs is used in this FAQ, it means GNU
-Emacs.
-
 @item Message
 In this FAQ message means either a mail or a posting to a
 Usenet Newsgroup or to some other fancy back end, no matter
diff --git a/doc/misc/gnus.texi b/doc/misc/gnus.texi
index a0be13dac8..738ff94b9f 100644
--- a/doc/misc/gnus.texi
+++ b/doc/misc/gnus.texi
@@ -883,10 +883,7 @@ History
 
 * Gnus Versions::               What Gnus versions have been released.
 * Why?::                        What's the point of Gnus?
-* Compatibility::               Just how compatible is Gnus with @sc{gnus}?
 * Conformity::                  Gnus tries to conform to all standards.
-* Emacsen::                     Gnus can be run on a few modern Emacsen.
-* Gnus Development::            How Gnus is developed.
 * Contributors::                Oodles of people.
 * New Features::                Pointers to some of the new stuff in Gnus.
 
@@ -1806,8 +1803,7 @@ long as Gnus is active.
 @end menu
 
 You can customize the Group Mode tool bar, see @kbd{M-x
-customize-apropos @key{RET} gnus-group-tool-bar}.  This feature is only
-available in Emacs.
+customize-apropos @key{RET} gnus-group-tool-bar}.
 
 The tool bar icons are now (de)activated correctly depending on the
 cursor position.  Therefore, moving around in the Group Buffer is
@@ -4839,8 +4835,7 @@ group buffer (@pxref{Selecting a Group}).
 You can have as many summary buffers open as you wish.
 
 You can customize the Summary Mode tool bar, see @kbd{M-x
-customize-apropos @key{RET} gnus-summary-tool-bar}.  This feature is only
-available in Emacs.
+customize-apropos @key{RET} gnus-summary-tool-bar}.
 
 @kindex v @r{(Summary)}
 @cindex keys, reserved for users (Summary)
@@ -5070,7 +5065,7 @@ Opening bracket for adopted articles.  The default is 
@samp{<}.
 
 @item ]
 Closing bracket, which is normally @samp{]}, but can also be @samp{>}
-for adopted articles.  This can be customised using following settings:
+for adopted articles.  This can be customized using following settings:
 
 @table @code
 @item gnus-sum-closing-bracket
@@ -8621,14 +8616,6 @@ uuencoded files that have had trailing spaces deleted.
 @vindex gnus-uu-pre-uudecode-hook
 Hook run before sending a message to @code{uudecode}.
 
-@item gnus-uu-view-with-metamail
-@vindex gnus-uu-view-with-metamail
-@cindex metamail
-Non-@code{nil} means that @code{gnus-uu} will ignore the viewing
-commands defined by the rule variables and just fudge a @acronym{MIME}
-content type based on the file name.  The result will be fed to
-@code{metamail} for viewing.
-
 @item gnus-uu-save-in-digest
 @vindex gnus-uu-save-in-digest
 Non-@code{nil} means that @code{gnus-uu}, when asked to save without
@@ -9359,14 +9346,11 @@ Use @uref{http://emacs-w3m.namazu.org/, emacs-w3m}.
 Use @uref{http://w3m.sourceforge.net/, w3m}.
 
 @item links
-Use @uref{https://almende.github.io/chap-links-library/, CHAP Links}.
+Use @uref{http://links.twibright.com/, Links}.
 
 @item lynx
 Use @uref{https://lynx.browser.org/, Lynx}.
 
-@item html2text
-Use html2text---a simple @acronym{HTML} converter included with Gnus.
-
 @end table
 
 @item W D F
@@ -11576,8 +11560,8 @@ things to work:
 To handle @acronym{PGP} and @acronym{PGP/MIME} messages, you have to
 install an OpenPGP implementation such as GnuPG@.  The Lisp interface
 to GnuPG included with Emacs is called EasyPG (@pxref{Top, ,EasyPG,
-epa, EasyPG Assistant user's manual}), but PGG (@pxref{Top, ,PGG, pgg,
-PGG Manual}), and Mailcrypt are also supported.
+epa, EasyPG Assistant user's manual}), but Mailcrypt is also
+supported.
 
 @item
 To handle @acronym{S/MIME} message, you need to install OpenSSL@.  OpenSSL 
0.9.6
@@ -11615,18 +11599,16 @@ public-key matching the @samp{From:} header as the 
recipient;
 @item mml1991-use
 @vindex mml1991-use
 Symbol indicating elisp interface to OpenPGP implementation for
-@acronym{PGP} messages.  The default is @code{epg}, but @code{pgg},
-and @code{mailcrypt} are also supported although
-deprecated.  By default, Gnus uses the first available interface in
-this order.
+@acronym{PGP} messages.  The default is @code{epg}, but
+@code{mailcrypt} is also supported although deprecated.  By default,
+Gnus uses the first available interface in this order.
 
 @item mml2015-use
 @vindex mml2015-use
 Symbol indicating elisp interface to OpenPGP implementation for
 @acronym{PGP/MIME} messages.  The default is @code{epg}, but
-@code{pgg}, and @code{mailcrypt} are also supported
-although deprecated.  By default, Gnus uses the first available
-interface in this order.
+@code{mailcrypt} is also supported although deprecated.  By default,
+Gnus uses the first available interface in this order.
 
 @end table
 
@@ -15440,8 +15422,6 @@ files.  If a positive number, delete files older than 
number of days
 (the deletion will only happen when receiving new mail).  You may also
 set @code{mail-source-delete-incoming} to @code{nil} and call
 @code{mail-source-delete-old-incoming} from a hook or interactively.
-@code{mail-source-delete-incoming} defaults to @code{10} in alpha Gnusae
-and @code{2} in released Gnusae.  @xref{Gnus Development}.
 
 @item mail-source-delete-old-incoming-confirm
 @vindex mail-source-delete-old-incoming-confirm
@@ -17357,11 +17337,6 @@ changes to a wiki (e.g., 
@url{https://cliki.net/site/recent-changes}).
 @acronym{RSS} has a quite regular and nice interface, and it's
 possible to get the information Gnus needs to keep groups updated.
 
-Note: you had better use Emacs which supports the @code{utf-8} coding
-system because @acronym{RSS} uses UTF-8 for encoding non-@acronym{ASCII}
-text by default.  It is also used by default for non-@acronym{ASCII}
-group names.
-
 @kindex G R @r{(Group)}
 Use @kbd{G R} from the group buffer to subscribe to a feed---you will be
 prompted for the location, the title and the description of the feed.
@@ -17410,7 +17385,7 @@ The directory where @code{nnrss} stores its files.  The 
default is
 @vindex nnrss-file-coding-system
 The coding system used when reading and writing the @code{nnrss} groups
 data files.  The default is the value of
-@code{mm-universal-coding-system} (which defaults to @code{emacs-mule}).
+@code{mm-universal-coding-system} (which defaults to @code{utf-8-emacs}).
 
 @item nnrss-ignore-article-fields
 @vindex nnrss-ignore-article-fields
@@ -17518,16 +17493,16 @@ If you have a directory that has lots of articles in 
separate files in
 it, you might treat it as a newsgroup.  The files have to have numerical
 names, of course.
 
-This might be an opportune moment to mention @code{ange-ftp} (and its
-successor @code{efs}), that most wonderful of all wonderful Emacs
-packages.  When I wrote @code{nndir}, I didn't think much about it---a
-back end to read directories.  Big deal.
+This might be an opportune moment to mention @code{ange-ftp}, that
+most wonderful of all wonderful Emacs packages.  When I wrote
+@code{nndir}, I didn't think much about it---a back end to read
+directories.  Big deal.
 
 @code{ange-ftp} changes that picture dramatically.  For instance, if you
 enter the @code{ange-ftp} file name
 @file{/ftp.hpc.uh.edu:/pub/emacs/ding-list/} as the directory name,
-@code{ange-ftp} or @code{efs} will actually allow you to read this
-directory over at @samp{sina} as a newsgroup.  Distributed news ahoy!
+@code{ange-ftp} will actually allow you to read this directory over at
+@samp{sina} as a newsgroup.  Distributed news ahoy!
 
 @code{nndir} will use @acronym{NOV} files if they are present.
 
@@ -21962,7 +21937,7 @@ you can set up a local @acronym{IMAP} server, which you 
then access via
 @code{nnimap}.  This is a rather massive setup for accessing some mbox
 files, so just change to MH or Maildir already...  However, if you're
 really, really passionate about using mbox, you might want to look into
-the package @file{mairix.el}, which comes with Emacs 23.
+the package @file{mairix.el}, which comes with Emacs.
 
 @node What nnmairix does
 @subsection What nnmairix does
@@ -24216,8 +24191,7 @@ people have started putting nonsense addresses into 
their @code{From}
 lines.  I think this is counterproductive---it makes it difficult for
 people to send you legitimate mail in response to things you write, as
 well as making it difficult to see who wrote what.  This rewriting may
-perhaps be a bigger menace than the unsolicited commercial email itself
-in the end.
+perhaps be a bigger menace than the spam itself in the end.
 
 The biggest problem I have with email spam is that it comes in under
 false pretenses.  I press @kbd{g} and Gnus merrily informs me that I
@@ -24243,33 +24217,13 @@ This is annoying.  Here's what you can do about it.
 @cindex UCE
 @cindex unsolicited commercial email
 
-First, some background on spam.
-
-If you have access to e-mail, you are familiar with spam (technically
-termed @acronym{UCE}, Unsolicited Commercial E-mail).  Simply put, it
-exists because e-mail delivery is very cheap compared to paper mail,
-so only a very small percentage of people need to respond to an UCE to
-make it worthwhile to the advertiser.  Ironically, one of the most
-common spams is the one offering a database of e-mail addresses for
-further spamming.  Senders of spam are usually called @emph{spammers},
-but terms like @emph{vermin}, @emph{scum}, @emph{sociopaths}, and
-@emph{morons} are in common use as well.
-
 Spam comes from a wide variety of sources.  It is simply impossible to
-dispose of all spam without discarding useful messages.  A good
-example is the TMDA system, which requires senders
-unknown to you to confirm themselves as legitimate senders before
-their e-mail can reach you.  Without getting into the technical side
-of TMDA, a downside is clearly that e-mail from legitimate sources may
-be discarded if those sources can't or won't confirm themselves
-through the TMDA system.  Another problem with TMDA is that it
-requires its users to have a basic understanding of e-mail delivery
-and processing.
+dispose of all spam without discarding useful messages.
 
 The simplest approach to filtering spam is filtering, at the mail
 server or when you sort through incoming mail.  If you get 200 spam
-messages per day from @samp{random-address@@vmadmin.com}, you block
-@samp{vmadmin.com}.  If you get 200 messages about @samp{VIAGRA}, you
+messages per day from @samp{random-address@@example.org}, you block
+@samp{example.org}.  If you get 200 messages about @samp{VIAGRA}, you
 discard all messages with @samp{VIAGRA} in the message.  If you get
 lots of spam from Bulgaria, for example, you try to filter all mail
 from Bulgarian IPs.
@@ -24380,7 +24334,7 @@ In my experience, this will sort virtually everything 
into the right
 group.  You still have to check the @samp{spam} group from time to time to
 check for legitimate mail, though.  If you feel like being a good net
 citizen, you can even send off complaints to the proper authorities on
-each unsolicited commercial email---at your leisure.
+each spam---at your leisure.
 
 This works for me.  It allows people an easy way to contact me (they can
 just press @kbd{r} in the usual way), and I'm not bothered at all with
@@ -24396,8 +24350,8 @@ Be careful with this approach.  Spammers are wise to it.
 @cindex Vipul's Razor
 @cindex DCC
 
-The days where the hints in the previous section were sufficient in
-avoiding spam are coming to an end.  There are many tools out there
+The days where the hints in the previous section were sufficient to
+avoid spam are over.  There are many tools out there
 that claim to reduce the amount of spam you get.  This section could
 easily become outdated fast, as new products replace old, but
 fortunately most of these tools seem to have similar interfaces.  Even
@@ -24478,7 +24432,7 @@ spam.  And here is the nifty function:
 @subsection Hashcash
 @cindex hashcash
 
-A novel technique to fight spam is to require senders to do something
+One technique to fight spam is to require senders to do something
 costly and demonstrably unique for each message they send.  This has
 the obvious drawback that you cannot rely on everyone in the world
 using this technique, since it is not part of the Internet standards,
@@ -25135,8 +25089,8 @@ The @code{gnus-article-sort-by-chars} entry simplifies 
detection of
 false positives for me.  I receive lots of worms (sweN, @dots{}), that all
 have a similar size.  Grouping them by size (i.e., chars) makes finding
 other false positives easier.  (Of course worms aren't @i{spam}
-(@acronym{UCE}, @acronym{UBE}) strictly speaking.  Anyhow, bogofilter is
-an excellent tool for filtering those unwanted mails for me.)
+strictly speaking.  Anyhow, bogofilter is an excellent tool for
+filtering those unwanted mails for me.)
 
 @item @b{Ham folders:}
 
@@ -26778,7 +26732,7 @@ on finding a separator line between the head and the 
body.  If this
 variable is @code{nil}, there is no upper read bound.  If it is
 @code{t}, the back ends won't try to read the articles piece by piece,
 but read the entire articles.  This makes sense with some versions of
-@code{ange-ftp} or @code{efs}.
+@code{ange-ftp}.
 
 @item nnheader-head-chop-length
 @vindex nnheader-head-chop-length
@@ -26917,10 +26871,7 @@ renamed it back again to ``Gnus''.  But in mixed case. 
 ``Gnus'' vs.
 @menu
 * Gnus Versions::               What Gnus versions have been released.
 * Why?::                        What's the point of Gnus?
-* Compatibility::               Just how compatible is Gnus with @sc{gnus}?
 * Conformity::                  Gnus tries to conform to all standards.
-* Emacsen::                     Gnus can be run on a few modern Emacsen.
-* Gnus Development::            How Gnus is developed.
 * Contributors::                Oodles of people.
 * New Features::                Pointers to some of the new stuff in Gnus.
 @end menu
@@ -27000,71 +26951,6 @@ every one of you to explore and invent.
 May Gnus never be complete.  @kbd{C-u 100 M-x all-hail-emacs}.
 
 
-@node Compatibility
-@subsection Compatibility
-
-@cindex compatibility
-Gnus was designed to be fully compatible with @sc{gnus}.  Almost all key
-bindings have been kept.  More key bindings have been added, of course,
-but only in one or two obscure cases have old bindings been changed.
-
-Our motto is:
-@quotation
-@cartouche
-@center In a cloud bones of steel.
-@end cartouche
-@end quotation
-
-All commands have kept their names.  Some internal functions have changed
-their names.
-
-The @code{gnus-uu} package has changed drastically.  @xref{Decoding
-Articles}.
-
-One major compatibility question is the presence of several summary
-buffers.  All variables relevant while reading a group are
-buffer-local to the summary buffer they belong in.  Although many
-important variables have their values copied into their global
-counterparts whenever a command is executed in the summary buffer, this
-change might lead to incorrect values being used unless you are careful.
-
-All code that relies on knowledge of @sc{gnus} internals will probably
-fail.  To take two examples: Sorting @code{gnus-newsrc-alist} (or
-changing it in any way, as a matter of fact) is strictly verboten.  Gnus
-maintains a hash table that points to the entries in this alist (which
-speeds up many functions), and changing the alist directly will lead to
-peculiar results.
-
-@cindex hilit19
-@cindex highlighting
-Old hilit19 code does not work at all.  In fact, you should probably
-remove all hilit code from all Gnus hooks
-(@code{gnus-group-prepare-hook} and @code{gnus-summary-prepare-hook}).
-Gnus provides various integrated functions for highlighting.  These are
-faster and more accurate.  To make life easier for everybody, Gnus will
-by default remove all hilit calls from all hilit hooks.  Uncleanliness!
-Away!
-
-Packages like @code{expire-kill} will no longer work.  As a matter of
-fact, you should probably remove all old @sc{gnus} packages (and other
-code) when you start using Gnus.  More likely than not, Gnus already
-does what you have written code to make @sc{gnus} do.  (Snicker.)
-
-Even though old methods of doing things are still supported, only the
-new methods are documented in this manual.  If you detect a new method of
-doing something while reading this manual, that does not mean you have
-to stop doing it the old way.
-
-Gnus understands all @sc{gnus} startup files.
-
-@findex gnus-bug
-@cindex reporting bugs
-@cindex bugs
-Overall, a casual user who hasn't written much code that depends on
-@sc{gnus} internals should suffer no problems.  If problems occur,
-please let me know by issuing that magic command @kbd{M-x gnus-bug}.
-
-
 @node Conformity
 @subsection Conformity
 
@@ -27147,79 +27033,6 @@ mentioned above, don't hesitate to drop a note to Gnus 
Towers and let us
 know.
 
 
-@node Emacsen
-@subsection Emacsen
-@cindex Emacsen
-@cindex Mule
-@cindex Emacs
-
-This version of Gnus should work on:
-
-@itemize @bullet
-
-@item
-Emacs 23.1 and up.
-
-@end itemize
-
-This Gnus version will absolutely not work on any Emacsen older than
-that.  Not reliably, at least.  Older versions of Gnus may work on older
-Emacs versions.  Particularly, Gnus 5.10.8 should also work on Emacs
-20.7.
-
-@c No-merge comment: The paragraph added in v5-10 here must not be
-@c synced here!
-
-@node Gnus Development
-@subsection Gnus Development
-
-Gnus is developed in a two-phased cycle.  The first phase involves much
-discussion on the development mailing list @samp{ding@@gnus.org}, where people
-propose changes and new features, post patches and new back ends.  This
-phase is called the @dfn{alpha} phase, since the Gnusae released in this
-phase are @dfn{alpha releases}, or (perhaps more commonly in other
-circles) @dfn{snapshots}.  During this phase, Gnus is assumed to be
-unstable and should not be used by casual users.  Gnus alpha releases
-have names like ``Oort Gnus'' and ``No Gnus''.  @xref{Gnus Versions}.
-
-After futzing around for 10--100 alpha releases, Gnus is declared
-@dfn{frozen}, and only bug fixes are applied.  Gnus loses the prefix,
-and is called things like ``Gnus 5.10.1'' instead.  Normal people are
-supposed to be able to use these, and these are mostly discussed on the
-@samp{gnu.emacs.gnus} newsgroup.  This newgroup is mirrored to the
-mailing list @samp{info-gnus-english@@gnu.org} which is carried on Gmane
-as @samp{gmane.emacs.gnus.user}.  These releases are finally integrated
-in Emacs.
-
-@cindex Incoming*
-@vindex mail-source-delete-incoming
-Some variable defaults differ between alpha Gnusae and released Gnusae,
-in particular, @code{mail-source-delete-incoming}.  This is to prevent
-lossage of mail if an alpha release hiccups while handling the mail.
-@xref{Mail Source Customization}.
-
-The division of discussion between the ding mailing list and the Gnus
-newsgroup is not purely based on publicity concerns.  It's true that
-having people write about the horrible things that an alpha Gnus release
-can do (sometimes) in a public forum may scare people off, but more
-importantly, talking about new experimental features that have been
-introduced may confuse casual users.  New features are frequently
-introduced, fiddled with, and judged to be found wanting, and then
-either discarded or totally rewritten.  People reading the mailing list
-usually keep up with these rapid changes, while people on the newsgroup
-can't be assumed to do so.
-
-So if you have problems with or questions about the alpha versions,
-direct those to the ding mailing list @samp{ding@@gnus.org}.  This list
-is also available on Gmane as @samp{gmane.emacs.gnus.general}.
-
-@cindex Incoming*
-@vindex mail-source-delete-incoming
-Some variable defaults differ between alpha Gnusae and released Gnusae,
-in particular, @code{mail-source-delete-incoming}.  This is to prevent
-lossage of mail if an alpha release hiccups while handling the mail.
-@xref{Mail Source Customization}.
-
 @node Contributors
 @subsection Contributors
 @cindex contributors
@@ -29796,19 +29609,6 @@ Ahem.
 @item
 Make sure your computer is switched on.
 
-@item
-Make sure that you really load the current Gnus version.  If you have
-been running @sc{gnus}, you need to exit Emacs and start it up again before
-Gnus will work.
-
-@item
-Try doing an @kbd{M-x gnus-version}.  If you get something that looks
-like @c
-@samp{Gnus v5.13} @c Adjust ../Makefile.in if you change this line!
-@c
-you have the right files loaded.  Otherwise you have some old @file{.el}
-files lying around.  Delete these.
-
 @item
 Read the help group (@kbd{G h} in the group buffer) for a
 @acronym{FAQ} and a how-to.
@@ -29817,7 +29617,7 @@ Read the help group (@kbd{G h} in the group buffer) for 
a
 @vindex max-lisp-eval-depth
 Gnus works on many recursive structures, and in some extreme (and very
 rare) cases Gnus may recurse down ``too deeply'' and Emacs will beep at
-you.  If this happens to you, set @code{max-lisp-eval-depth} to 500 or
+you.  If this happens to you, set @code{max-lisp-eval-depth} to 2000 or
 something like that.
 @end enumerate
 
@@ -29828,10 +29628,9 @@ If all else fails, report the problem as a bug.
 
 @findex gnus-bug
 If you find a bug in Gnus, you can report it with the @kbd{M-x
-gnus-bug} command.  @kbd{M-x set-variable @key{RET} debug-on-error
-@key{RET} t @key{RET}}, and send me the backtrace.  I will fix bugs,
-but I can only fix them if you send me a precise description as to how
-to reproduce the bug.
+gnus-bug} command.  @kbd{M-x toggle-debug-on-error}, and send me the
+backtrace.  I will fix bugs, but I can only fix them if you send me a
+precise description as to how to reproduce the bug.
 
 You really can never be too detailed in a bug report.  Always use the
 @kbd{M-x gnus-bug} command when you make bug reports, even if it creates
@@ -29862,7 +29661,7 @@ edebug.  Debugging Lisp code is documented in the Elisp 
manual
 (@pxref{Debugging, , Debugging Lisp Programs, elisp, The GNU Emacs
 Lisp Reference Manual}).  To get you started with edebug, consider if
 you discover some weird behavior when pressing @kbd{c}, the first
-step is to do @kbd{C-h k c} and click on the hyperlink (Emacs only) in
+step is to do @kbd{C-h k c} and click on the hyperlink in
 the documentation buffer that leads you to the function definition,
 then press @kbd{M-x edebug-defun @key{RET}} with point inside that function,
 return to Gnus and press @kbd{c} to invoke the code.  You will be
@@ -29874,7 +29673,7 @@ evaluate expressions using @kbd{M-:} or inspect 
variables using
 @cindex elp
 @cindex profile
 @cindex slow
-Sometimes, a problem do not directly generate an elisp error but
+Sometimes, a problem do not directly generate an Emacs Lisp error but
 manifests itself by causing Gnus to be very slow.  In these cases, you
 can use @kbd{M-x toggle-debug-on-quit} and press @kbd{C-g} when things are
 slow, and then try to analyze the backtrace (repeating the procedure
diff --git a/doc/misc/htmlfontify.texi b/doc/misc/htmlfontify.texi
index 0ab000b70f..dabe2e36ff 100644
--- a/doc/misc/htmlfontify.texi
+++ b/doc/misc/htmlfontify.texi
@@ -10,8 +10,7 @@
 This manual documents Htmlfontify, a source code -> crosslinked +
 formatted + syntax colorized html transformer.
 
-Copyright @copyright{} 2002--2003, 2013--2022 Free Software Foundation,
-Inc.
+Copyright @copyright{} 2002--2022 Free Software Foundation, Inc.
 
 @quotation
 Permission is granted to copy, distribute and/or modify this document
@@ -34,7 +33,7 @@ modify this GNU manual.''
 @titlepage
 @title Htmlfontify User Manual
 @sp 4
-@subtitle Htmlfontify version 0.20
+@subtitle Htmlfontify version 0.21
 @sp 1
 @subtitle Jun 2002
 @sp 5
@@ -1539,13 +1538,6 @@ Htmlfontify has a couple of external requirements:
 
 @itemize @bullet
 
-@item
-GNU Emacs 20.7+ or 21.1+
-
-Other versions may work---these have been used successfully by the
-author.  If you intend to use Htmlfontify in batch mode, 21.1+ is
-pretty much required.
-
 @item
 A copy of etags (exuberant-ctags or GNU etags).  Htmlfontify attempts
 to autodetect the version you have and customize itself accordingly,
diff --git a/doc/misc/idlwave.texi b/doc/misc/idlwave.texi
index 26a6e6c7a3..0ba87b2e58 100644
--- a/doc/misc/idlwave.texi
+++ b/doc/misc/idlwave.texi
@@ -217,7 +217,7 @@ Integrity checks and auto-termination of logical blocks.
 @item
 Routine name space conflict search with likelihood-of-use ranking.
 @item
-Support for @file{imenu} (Emacs) and @file{func-menu} (XEmacs).
+Support for @file{imenu}.
 @item
 Documentation support.
 @item
@@ -392,7 +392,7 @@ that IDLWAVE has many more capabilities than covered here, 
which can
 be discovered by reading the entire manual, or hovering over the
 shoulder of your nearest IDLWAVE guru for a few days.
 
-It is assumed that you have access to Emacs or XEmacs with the full
+It is assumed that you have access to Emacs with the full
 IDLWAVE package including online help.  We also assume that you are
 familiar with Emacs and can read the nomenclature of key presses in
 Emacs (in particular, @kbd{C} stands for @key{CONTROL} and @kbd{M} for
@@ -1011,9 +1011,9 @@ Non-@code{nil} means use last match on line for
 @cindex Font lock
 
 Highlighting of keywords, comments, strings etc.@: can be accomplished
-with @code{font-lock}.  If you are using @code{global-font-lock-mode}
-(in Emacs), or have @code{font-lock} turned on in any other buffer in
-XEmacs, it should also automatically work in IDLWAVE buffers.  If you'd
+with @code{font-lock}.  If you are using @code{global-font-lock-mode},
+or have @code{font-lock-mode} turned on in any other buffer,
+it should also automatically work in IDLWAVE buffers.  If you'd
 prefer invoking font-lock individually by mode, you can enforce it in
 @code{idlwave-mode} with the following line in your @file{.emacs}:
 
@@ -2298,12 +2298,11 @@ Regexp matching the start of a document library header.
 @cindex Motion commands
 @cindex Program structure, moving through
 @cindex Code structure, moving through
-@cindex @file{Func-menu}, XEmacs package
-@cindex @file{Imenu}, Emacs package
+@cindex @file{Imenu}
 @cindex Function definitions, jumping to
 @cindex Procedure definitions, jumping to
 
-IDLWAVE supports both @file{Imenu} and @file{Func-menu}, two packages
+IDLWAVE supports @file{Imenu}, a package
 which make it easy to jump to the definitions of functions and
 procedures in the current file with a pop-up selection.  To bind
 @file{Imenu} to a mouse-press, use in your @file{.emacs}:
@@ -4022,7 +4021,7 @@ user is King!
 
 IDLWAVE was developed on a UNIX system.  However, thanks to the
 portability of Emacs, much of IDLWAVE does also work under different
-operating systems like Windows (with NTEmacs or NTXEmacs).
+operating systems like Windows (with NTEmacs).
 
 The only real problem is that there is no command-line version of IDL
 for Windows with which IDLWAVE can interact.  As a
@@ -4117,24 +4116,6 @@ configuration files (e.g., @file{.cshrc}), but from the 
file
 @file{~/.MacOSX/environment.plist}.  Either include your path settings
 there, or start Emacs and IDLWAVE from the shell.
 
-@item @strong{I get errors like @samp{Symbol's function is void:
-overlayp}}
-
-You don't have the @samp{fsf-compat} package installed, which IDLWAVE
-needs to run under XEmacs.  Install it, or find an XEmacs distribution
-which includes it by default.
-
-@item @strong{I'm getting errors like @samp{Symbol's value as variable is void:
-cl-builtin-gethash} on completion or routine info.}
-
-This error arises if you upgraded Emacs from 20.x to 21.x without
-re-installing IDLWAVE@.  Old Emacs and new Emacs are not byte-compatible
-in compiled lisp files.  Presumably, you kept the original .elc files in
-place, and this is the source of the error.  If you recompile (or just
-"make; make install") from source, it should resolve this problem.
-Another option is to recompile the @file{idlw*.el} files by hand using
-@kbd{M-x byte-compile-file}.
-
 @item @strong{@kbd{M-@key{TAB}} doesn't complete words, it switches
 windows on my desktop.}
 
@@ -4262,20 +4243,6 @@ is updated).
 Starting with IDL 6.2, the HTML help and its catalog are
 distributed with IDL, and so should never be inconsistent.
 
-@item @strong{I get errors such as @samp{void-variable
-browse-url-browser-function} or similar when attempting to load IDLWAVE
-under XEmacs.}
-
-You don't have the @samp{browse-url} (or other required) XEmacs package.
-Unlike Emacs, XEmacs distributes many packages separately from the
-main program.  IDLWAVE is actually among these, but is not always the
-most up to date.  When installing IDLWAVE as an XEmacs package, it
-should prompt you for required additional packages.  When installing it
-from source, it won't and you'll get this error.  The easiest solution
-is to install all the packages when you install XEmacs (the so-called
-@samp{sumo} bundle).  The minimum set of XEmacs packages required by
-IDLWAVE is @samp{fsf-compat, xemacs-base, mail-lib}.
-
 @end enumerate
 
 @node GNU Free Documentation License
diff --git a/doc/misc/message.texi b/doc/misc/message.texi
index 29fbdfe178..6a6beb7a1f 100644
--- a/doc/misc/message.texi
+++ b/doc/misc/message.texi
@@ -1152,12 +1152,11 @@ programs are required to make things work, and some 
small general hints.
 @uref{https://www.gnupg.org/, GNU Privacy Guard} or
 @uref{https://www.openssl.org/, OpenSSL}.  The default Emacs interface
 to the S/MIME implementation is EasyPG (@pxref{Top,,EasyPG Assistant
-User's Manual, epa, EasyPG Assistant User's Manual}), which has been
-included in Emacs since version 23 and which relies on the command
-line tool @command{gpgsm} provided by @acronym{GnuPG}.  That tool
-implements certificate management, including certificate revocation
-and expiry, while such tasks need to be performed manually, if OpenSSL
-is used.
+User's Manual, epa, EasyPG Assistant User's Manual}), which is
+included in Emacs and relies on the command line tool @command{gpgsm}
+provided by @acronym{GnuPG}.  That tool implements certificate
+management, including certificate revocation and expiry, while such
+tasks need to be performed manually, if OpenSSL is used.
 
 The choice between EasyPG and OpenSSL is controlled by the variable
 @code{mml-smime-use}, which needs to be set to the value @code{epg}
@@ -1250,8 +1249,8 @@ as @uref{https://www.gnupg.org/, GNU Privacy Guard}.  
Pre-OpenPGP
 implementations such as PGP 2.x and PGP 5.x are also supported.  The
 default Emacs interface to the PGP implementation is EasyPG
 (@pxref{Top,,EasyPG Assistant User's Manual, epa, EasyPG Assistant
-User's Manual}), but PGG (@pxref{Top, ,PGG, pgg, PGG Manual}) and
-Mailcrypt are also supported.  @xref{PGP Compatibility}.
+User's Manual}), but Mailcrypt is also supported.  @xref{PGP
+Compatibility}.
 
 As stated earlier, messages encrypted with OpenPGP can be formatted
 according to two different standards, namely @acronym{PGP} or
@@ -1340,8 +1339,7 @@ your PGP implementation, so we refer to it.
 If you have imported your old PGP 2.x key into GnuPG, and want to send
 signed and encrypted messages to your fellow PGP 2.x users, you'll
 discover that the receiver cannot understand what you send. One
-solution is to use PGP 2.x instead (e.g., if you use @code{pgg}, set
-@code{pgg-default-scheme} to @code{pgp}). You could also convince your
+solution is to use PGP 2.x instead. You could also convince your
 fellow PGP 2.x users to convert to GnuPG@.
 @vindex mml-signencrypt-style-alist
 As a final workaround, you can make the sign and encryption work in
diff --git a/doc/misc/mh-e.texi b/doc/misc/mh-e.texi
index c1cf44a027..2106c674f3 100644
--- a/doc/misc/mh-e.texi
+++ b/doc/misc/mh-e.texi
@@ -213,10 +213,8 @@ more niceties about GNU Emacs and MH@. Now I'm fully 
hooked on both of
 them.
 
 The MH-E package is distributed with Emacs@footnote{Version
-@value{VERSION} of MH-E appeared in Emacs 24.4. It is supported in GNU
-Emacs 23 and higher, as well as XEmacs 21.4.22 and 21.5.31. MH-E is
-known not to work with GNU Emacs versions 20 and below, and XEmacs
-version 21.5.9--21.5.16. It is compatible with MH versions 6.8.4 and
+@value{VERSION} of MH-E appeared in Emacs 24.4.
+It is compatible with MH versions 6.8.4 and
 higher, all versions of nmh, and GNU mailutils 1.0 and higher}, so you
 shouldn't have to do anything special to use it. Gnus is also
 required; version 5.10 or higher is recommended. This manual covers
@@ -1490,7 +1488,7 @@ Binding} of @samp{m}.
 @cindex Unix commands, @command{xbuffy}
 
 You can use @command{xbuffy} to automate the incorporation of this
-mail using the Emacs 23 command @command{emacsclient} as follows:
+mail using the Emacs command @command{emacsclient} as follows:
 
 @smallexample
 box ~/mail/mh-e
@@ -1501,9 +1499,6 @@ box ~/mail/mh-e
     command emacsclient --eval '(mh-inc-spool-mh-e)'
 @end smallexample
 
-In XEmacs, the command @command{gnuclient} is used in a similar
-fashion.
-
 @findex mh-inc-folder
 @kindex i
 @vindex mh-inc-folder-hook
@@ -2090,8 +2085,7 @@ and @samp{X-Image-URL:} will be used. The option
 This feature will be turned on by default if your system supports it.
 
 The first header field used, if present, is the Gnus-specific
-@samp{Face:} field@footnote{The @samp{Face:} field appeared in GNU
-Emacs 21 and XEmacs. For more information, see
+@samp{Face:} field@footnote{For more information, see
 @uref{https://quimby.gnus.org/circus/face/}.}.
 
 @cindex @command{uncompface}
@@ -2104,12 +2098,9 @@ Emacs 21 and XEmacs. For more information, see
 Next is the traditional @samp{X-Face:} header field@footnote{The
 display of this field requires the
 @uref{ftp://ftp.cs.indiana.edu/pub/faces/compface/compface.tar.Z,
-@command{uncompface} program}. Recent versions of XEmacs have internal
-support for @samp{X-Face:} images. If your version of XEmacs does not,
-then you'll need both @command{uncompface} and the
-@uref{http://www.jpl.org/ftp/pub/elisp/, @samp{x-face} package}.}. MH-E
-renders the foreground and background of the image using the
-associated attributes of the face @code{mh-show-xface}.
+@command{uncompface} program}.} MH-E renders the foreground and
+background of the image using the associated attributes of the face
+@code{mh-show-xface}.
 
 @cindex @command{convert}
 @cindex @command{wget}
@@ -2562,13 +2553,6 @@ produces pretty nice output, and it highlights links. It 
renders
 @samp{&ndash;} and @samp{&reg;} okay. It sometimes fails to wrap lines
 properly. It always downloads remote images.
 @c -------------------------
-@cindex browser, @samp{html2text}
-@cindex @samp{html2text}
-@item @samp{html2text}
-The @samp{html2text} browser requires an external program. Some users
-have reported problems with it, such as filling the entire message as
-if it were one paragraph, or displaying chunks of raw HTML.
-@c -------------------------
 @cindex browser, @samp{links}
 @cindex @samp{links}
 @item @samp{links}
@@ -2830,24 +2814,6 @@ The appearance of the buttons is controlled by the faces
 @code{mh-show-pgg-unknown} depending on the validity of the signature.
 The latter is used whether the signature is unknown or untrusted.
 
-@cindex @samp{pgg} customization group
-@cindex PGG
-@cindex customization group, @samp{pgg}
-
-The @samp{pgg} customization group may have some settings which may
-interest you.
-@iftex
-See @cite{The PGG Manual}.
-@end iftex
-@ifinfo
-@xref{Top, , The PGG Manual, pgg, The PGG Manual}.
-@end ifinfo
-@ifhtml
-See
-@uref{https://www.gnu.org/software/emacs/manual/pgg.html,
-@cite{The PGG Manual}}.
-@end ifhtml
-
 @node Printing
 @section Printing Your Mail
 
@@ -5594,33 +5560,6 @@ variety of mail security mechanisms. The default is 
@samp{PGP (MIME)}
 if it is supported; otherwise, the default is @samp{None}. Other
 mechanisms include vanilla @samp{PGP} and @samp{S/MIME}.
 
-@cindex @samp{pgg} customization group
-@cindex PGG
-@cindex customization group, @samp{pgg}
-
-The @samp{pgg} customization group may have some settings which may
-interest you.
-@iftex
-See @cite{The PGG Manual}.
-@end iftex
-@ifinfo
-@xref{Top, , The PGG Manual, pgg, The PGG Manual}.
-@end ifinfo
-@ifhtml
-See
-@uref{https://www.gnu.org/software/emacs/manual/pgg.html,
-@cite{The PGG Manual}}.
-@end ifhtml
-
-@cindex header field, @samp{Fcc}
-@cindex @samp{Fcc} header field
-@vindex pgg-encrypt-for-me
-
-In particular, I turn on the option @code{pgg-encrypt-for-me} so that
-all messages I encrypt are encrypted with my public key as well. If
-you keep a copy of all of your outgoing mail with a @samp{Fcc:} header
-field, this setting is vital so that you can read the mail you write!
-
 @node Checking Recipients
 @section Checking Recipients
 
@@ -6448,17 +6387,9 @@ too long to list here).
 @item mh-tool-bar-search-function
 Function called by the tool bar search button (default:
 @code{mh-search}).
-@c -------------------------
-@item mh-xemacs-tool-bar-position
-Tool bar location (default: @samp{Same As Default Tool Bar}).
-@c -------------------------
-@item mh-xemacs-use-tool-bar-flag
-If @samp{on}, use tool bar (default: @samp{on}, if supported).
 @end vtable
 
-In GNU Emacs, icons for some of MH-E's functions are added to the tool
-bar. In XEmacs, you have the opportunity to create a separate tool bar for
-the MH-E icons.
+Icons for some of MH-E's functions are added to the tool bar.
 
 @vindex mh-tool-bar-folder-buttons
 @vindex mh-tool-bar-letter-buttons
@@ -6480,24 +6411,6 @@ option @code{mh-tool-bar-search-function}. By default, 
this is set to
 Function} from the @samp{Value Menu} and enter a function of your own
 choosing.
 
-@vindex mh-xemacs-use-tool-bar-flag
-
-XEmacs provides a couple of extra options. The first,
-@code{mh-xemacs-use-tool-bar-flag}, controls whether to show the MH-E
-icons at all. By default, this option is turned on if the window
-system supports tool bars. If your system doesn't support tool bars,
-then you won't be able to turn on this option.
-
-@vindex mh-xemacs-tool-bar-position
-
-The second extra option is @code{mh-xemacs-tool-bar-position} which
-controls the placement of the tool bar along the four edges of the
-frame. You can choose from one of @samp{Same As Default Tool Bar},
-@samp{Top}, @samp{Bottom}, @samp{Left}, or @samp{Right}. If this
-variable is set to anything other than @samp{Same As Default Tool Bar}
-and the default tool bar is in a different location, then two tool
-bars will be displayed: the MH-E tool bar and the default tool bar.
-
 @node Searching
 @chapter Searching Through Messages
 
diff --git a/doc/misc/modus-themes.org b/doc/misc/modus-themes.org
index 7b566f51c2..1b4bf88a0c 100644
--- a/doc/misc/modus-themes.org
+++ b/doc/misc/modus-themes.org
@@ -1,25 +1,23 @@
-#+title: Modus themes for GNU Emacs
-#+author: Protesilaos Stavrou
-#+email: info@protesilaos.com
-#+language: en
-#+options: ':t toc:nil author:t email:t num:t
-#+startup: content
-
-#+macro: stable-version 2.4.0
-#+macro: release-date 2022-06-01
-#+macro: development-version 2.5.0-dev
-#+macro: file @@texinfo:@file{@@$1@@texinfo:}@@
-#+macro: space @@texinfo:@: @@
-#+macro: kbd @@texinfo:@kbd{@@$1@@texinfo:}@@
-
-#+texinfo_filename: modus-themes.info
-#+texinfo_dir_category: Emacs misc features
-#+texinfo_dir_title: Modus Themes: (modus-themes)
-#+texinfo_dir_desc: Elegant, highly legible and customizable themes
-#+texinfo_header: @set MAINTAINERSITE @uref{https://protesilaos.com,maintainer 
webpage}
-#+texinfo_header: @set MAINTAINER Protesilaos Stavrou
-#+texinfo_header: @set MAINTAINEREMAIL @email{info@protesilaos.com}
-#+texinfo_header: @set MAINTAINERCONTACT 
@uref{mailto:info@protesilaos.com,contact the maintainer}
+#+title:                 Modus themes for GNU Emacs
+#+author:                Protesilaos Stavrou
+#+email:                 info@protesilaos.com
+#+language:              en
+#+options:               ':t toc:nil author:t email:t num:t
+#+startup:               content
+#+macro:                 stable-version 2.6.0
+#+macro:                 release-date 2022-08-19
+#+macro:                 development-version 2.7.0-dev
+#+macro:                 file @@texinfo:@file{@@$1@@texinfo:}@@
+#+macro:                 space @@texinfo:@: @@
+#+macro:                 kbd @@texinfo:@kbd{@@$1@@texinfo:}@@
+#+texinfo_filename:      modus-themes.info
+#+texinfo_dir_category:  Emacs misc features
+#+texinfo_dir_title:     Modus Themes: (modus-themes)
+#+texinfo_dir_desc:      Elegant, highly legible and customizable themes
+#+texinfo_header:        @set MAINTAINERSITE 
@uref{https://protesilaos.com,maintainer webpage}
+#+texinfo_header:        @set MAINTAINER Protesilaos Stavrou
+#+texinfo_header:        @set MAINTAINEREMAIL @email{info@protesilaos.com}
+#+texinfo_header:        @set MAINTAINERCONTACT 
@uref{mailto:info@protesilaos.com,contact the maintainer}
 
 #+texinfo: @insertcopying
 
@@ -198,6 +196,9 @@ sudo apt install elpa-modus-themes
 
 They are now ready to be used: 
[[#h:3f3c3728-1b34-437d-9d0c-b110f5b161a9][Enable and load]].
 
+NOTE that Debian's package is severely out-of-date as of this writing
+2022-07-24 09:57 +0300.
+
 *** GNU Guix
 :properties:
 :custom_id: h:a4ca52cd-869f-46a5-9e16-4d9665f5b88e
@@ -360,7 +361,7 @@ package configurations in their setup.  We use this as an 
example:
   :config
   ;; Load the theme of your choice:
   (load-theme 'modus-operandi) ;; OR (load-theme 'modus-vivendi)
-  :bind ("<f5>" . modus-themes-toggle)
+  :bind ("<f5>" . modus-themes-toggle))
 
 
 
@@ -618,7 +619,7 @@ By default, customizing a theme-related user option through 
the Custom
 interfaces or with {{{kbd(M-x customize-set-variable)}}} will not reload the
 currently active Modus theme.
 
-Enable this behaviour by setting this variable to ~nil~.
+Enable this behavior by setting this variable to ~nil~.
 
 Regardless of this option, the active theme must be reloaded for changes
 to user options to take effect 
([[#h:3f3c3728-1b34-437d-9d0c-b110f5b161a9][Enable and load]]).
@@ -1199,7 +1200,7 @@ Brief: Set the overall style of completion framework 
interfaces.
 
 Symbol: ~modus-themes-completions~ (=alist= type properties)
 
-This affects Company, Corfu, Flx, Helm, Icomplete/Fido, Ido, Ivy, Mct,
+This affects Company, Corfu, Flx, Helm, Icomplete/Fido, Ido, Ivy,
 Orderless, Selectrum, Vertico.  The value is an alist that takes the
 form of a =(key . properties)= combination.  Here is a sample, followed
 by a description of the particularities:
@@ -1252,7 +1253,7 @@ accepts is as follows (order is not significant):
 
 The ~popup~ key takes the same values as ~selection~.
 
-Apart from specfying each key separately, a fallback list is accepted.
+Apart from specifying each key separately, a fallback list is accepted.
 This is only useful when the desired aesthetic is the same across all
 keys that are not explicitly referenced.  For example, this:
 
@@ -1476,6 +1477,9 @@ with underlines.
 This style affects several packages that enable ~hl-line-mode~, such as
 =elfeed=, =notmuch=, and =mu4e=.
 
+[ Also check the =lin= package on GNU ELPA (by the author of the
+  modus-themes) for a stylistic enhancement to ~hl-line-mode~. ]
+
 ** Option for line numbers
 :properties:
 :alt_title: Line numbers
@@ -2000,16 +2004,21 @@ Putting it all together, the alist can look like this:
 :end:
 #+vindex: modus-themes-headings
 
-Brief: Control the style of headings.  This can be particularised for
-each level of heading (e.g. Org has eight levels).
+Brief: Heading styles with optional list of values for levels 0-8.
 
 Symbol: ~modus-themes-headings~ (=alist= type, multiple properties)
 
-This is an alist that accepts a =(key . list-of-values)= combination.  The
-key is either a number, representing the heading's level or ~t~, which
-pertains to the fallback style.  The list of values covers symbols that
-refer to properties, as described below.  Here is a sample, followed by
-a presentation of all available properties:
+This is an alist that accepts a =(key . list-of-values)= combination.
+The key is either a number, representing the heading's level (0-8) or t,
+which pertains to the fallback style.
+
+Level 0 is a special heading: it is used for what counts as a document
+title or equivalent, such as the =#+title= construct we find in Org
+files.  Levels 1-8 are regular headings.
+
+The list of values covers symbols that refer to properties, as described
+below.  Here is a complete sample, followed by a presentation of all
+available properties:
 
 #+begin_src emacs-lisp
 (setq modus-themes-headings
@@ -2162,7 +2171,7 @@ things with precision 
([[#h:bf1c82f2-46c7-4eb2-ad00-dd11fdd8b53f][Customization
 This section is of interest only to users who are prepared to maintain
 their own local tweaks and who are willing to deal with any possible
 incompatibilities between versioned releases of the themes.  As such,
-they are labelled as "do-it-yourself" or "DIY".
+they are labeled as "do-it-yourself" or "DIY".
 
 ** More accurate colors in terminal emulators
 :PROPERTIES:
@@ -2605,7 +2614,7 @@ this example:
 Whenever we enter a ~diff-mode~ buffer, we now get a magenta-colored
 region.
 
-Perhaps you may wish to generalise those findings in to a set of
+Perhaps you may wish to generalize those findings in to a set of
 functions that also accept an arbitrary face.  We shall leave the
 experimentation up to you.
 
@@ -2624,8 +2633,7 @@ contrast on an on-demand basis.
 
 One way to achieve this is to design a command that cycles through three
 distinct levels of intensity, though the following can be adapted to any
-kind of cyclic behaviour, such as to switch between red, green, and
-blue.
+kind of cyclic behavior, such as to switch between red, green, and blue.
 
 In the following example, we employ the ~modus-themes-color~ function
 which reads a symbol that represents an entry in the active theme's
@@ -2848,7 +2856,6 @@ both themes and expands to some more assosiations in the 
palette:
               (bg-inactive . "#f6ece5")
               (bg-region . "#c6bab1")
               (bg-header . "#ede3e0")
-              (bg-tab-bar . "#dcd3d3")
               (bg-tab-active . "#fdf6eb")
               (bg-tab-inactive . "#c8bab8"))
             modus-themes-vivendi-color-overrides
@@ -2860,7 +2867,6 @@ both themes and expands to some more assosiations in the 
palette:
               (bg-inactive . "#1a1e39")
               (bg-region . "#393a53")
               (bg-header . "#202037")
-              (bg-tab-bar . "#262b41")
               (bg-tab-active . "#120f18")
               (bg-tab-inactive . "#3a3a5a")))
     (setq modus-themes-operandi-color-overrides nil
@@ -2879,7 +2885,6 @@ look like this:
   (bg-inactive . "#e6e6e6")
   (bg-region . "#b5b5b5")
   (bg-header . "#e4e4e4")
-  (bg-tab-bar . "#d1d1d4")
   (bg-tab-active . "#f5f5f5")
   (bg-tab-inactive . "#c0c0c0"))
 #+end_src
@@ -2897,6 +2902,9 @@ fall below the minimum 7:1 contrast ratio that governs 
the design of the
 themes (the WCAG AAA legibility standard).  Alternatively, this can also
 be done programmatically ([[#h:4589acdc-2505-41fc-9f5e-699cfc45ab00][Override 
color saturation]]).
 
+The above are expanded into a fully fledged derivative elsewhere in this
+document ([[#h:736c0ff5-8c9c-4565-82cf-989e57d07d4a][Override colors 
completely]]).
+
 For manual interventions it is advised to inspect the source code of
 ~modus-themes-operandi-colors~ and ~modus-themes-vivendi-colors~ for the
 inline commentary: it explains what the intended use of each palette
@@ -3092,6 +3100,286 @@ Blend background colors with BG-BLEND and foreground 
colors with FG-BLEND."
 (modus-themes-tinted-mode 1)
 #+end_src
 
+** Override colors completely
+:PROPERTIES:
+:CUSTOM_ID: h:736c0ff5-8c9c-4565-82cf-989e57d07d4a
+:END:
+
+Based on the ideas we have already covered in these sections, the
+following code block provides a complete, bespoke pair of color palettes
+which override the defaults.  They are implemented as a minor mode, as
+explained before ([[#h:307d95dd-8dbd-4ece-a543-10ae86f155a6][Override 
colors]]).  We call them "Summertime" for
+convenience.
+
+#+begin_src emacs-lisp
+;; Read the relevant blog post:
+;; 
<https://protesilaos.com/codelog/2022-07-26-modus-themes-color-override-demo/>
+(define-minor-mode modus-themes-summertime
+  "Refashion the Modus themes by overriding their colors.
+
+This is a complete technology demonstration to show how to
+manually override the colors of the Modus themes.  I have taken
+good care of those overrides to make them work as a fully fledged
+color scheme that is compatible with all user options of the
+Modus themes.
+
+These overrides are usable by those who (i) like something more
+fancy than the comparatively austere looks of the Modus themes,
+and (ii) can cope with a lower contrast ratio.
+
+The overrides are set up as a minor mode, so that the user can
+activate the effect on demand.  Those who want to load the
+overrides at all times can either add them directly to their
+configuration or enable `modus-themes-summertime' BEFORE loading
+either of the Modus themes (if the overrides are evaluated after
+the theme, the theme must be reloaded).
+
+Remember that all changes to theme-related variables require a
+reload of the theme to take effect (the Modus themes have lots of
+user options, apart from those overrides).
+
+The `modus-themes-summertime' IS NOT an official extension to the
+Modus themes and DOES NOT comply with its lofty accessibility
+standards.  It is included in the official manual as guidance for
+those who want to make use of the color overriding facility we
+provide."
+  :init-value nil
+  :global t
+  (if modus-themes-summertime
+      (setq modus-themes-operandi-color-overrides
+            '((bg-main . "#fff0f2")
+              (bg-dim . "#fbe6ef")
+              (bg-alt . "#f5dae6")
+              (bg-hl-line . "#fad8e3")
+              (bg-active . "#efcadf")
+              (bg-inactive . "#f3ddef")
+              (bg-active-accent . "#ffbbef")
+              (bg-region . "#dfc5d1")
+              (bg-region-accent . "#efbfef")
+              (bg-region-accent-subtle . "#ffd6ef")
+              (bg-header . "#edd3e0")
+              (bg-tab-active . "#ffeff2")
+              (bg-tab-inactive . "#f8d3ef")
+              (bg-tab-inactive-accent . "#ffd9f5")
+              (bg-tab-inactive-alt . "#e5c0d5")
+              (bg-tab-inactive-alt-accent . "#f3cce0")
+              (fg-main . "#543f78")
+              (fg-dim . "#5f476f")
+              (fg-alt . "#7f6f99")
+              (fg-unfocused . "#8f6f9f")
+              (fg-active . "#563068")
+              (fg-inactive . "#8a5698")
+              (fg-docstring . "#5f5fa7")
+              (fg-comment-yellow . "#a9534f")
+              (fg-escape-char-construct . "#8b207f")
+              (fg-escape-char-backslash . "#a06d00")
+              (bg-special-cold . "#d3e0f4")
+              (bg-special-faint-cold . "#e0efff")
+              (bg-special-mild . "#c4ede0")
+              (bg-special-faint-mild . "#e0f0ea")
+              (bg-special-warm . "#efd0c4")
+              (bg-special-faint-warm . "#ffe4da")
+              (bg-special-calm . "#f0d3ea")
+              (bg-special-faint-calm . "#fadff9")
+              (fg-special-cold . "#405fb8")
+              (fg-special-mild . "#407f74")
+              (fg-special-warm . "#9d6f4f")
+              (fg-special-calm . "#af509f")
+              (bg-completion . "#ffc5e5")
+              (bg-completion-subtle . "#f7cfef")
+              (red . "#ed2f44")
+              (red-alt . "#e0403d")
+              (red-alt-other . "#e04059")
+              (red-faint . "#ed4f44")
+              (red-alt-faint . "#e0603d")
+              (red-alt-other-faint . "#e06059")
+              (green . "#217a3c")
+              (green-alt . "#417a1c")
+              (green-alt-other . "#006f3c")
+              (green-faint . "#318a4c")
+              (green-alt-faint . "#518a2c")
+              (green-alt-other-faint . "#20885c")
+              (yellow . "#b06202")
+              (yellow-alt . "#a95642")
+              (yellow-alt-other . "#a06f42")
+              (yellow-faint . "#b07232")
+              (yellow-alt-faint . "#a96642")
+              (yellow-alt-other-faint . "#a08042")
+              (blue . "#275ccf")
+              (blue-alt . "#475cc0")
+              (blue-alt-other . "#3340ef")
+              (blue-faint . "#476ce0")
+              (blue-alt-faint . "#575ccf")
+              (blue-alt-other-faint . "#3f60d7")
+              (magenta . "#bf317f")
+              (magenta-alt . "#d033c0")
+              (magenta-alt-other . "#844fe4")
+              (magenta-faint . "#bf517f")
+              (magenta-alt-faint . "#d053c0")
+              (magenta-alt-other-faint . "#846fe4")
+              (cyan . "#007a9f")
+              (cyan-alt . "#3f709f")
+              (cyan-alt-other . "#107f7f")
+              (cyan-faint . "#108aaf")
+              (cyan-alt-faint . "#3f80af")
+              (cyan-alt-other-faint . "#3088af")
+              (red-active . "#cd2f44")
+              (green-active . "#116a6c")
+              (yellow-active . "#993602")
+              (blue-active . "#475ccf")
+              (magenta-active . "#7f2ccf")
+              (cyan-active . "#007a8f")
+              (red-nuanced-bg . "#ffdbd0")
+              (red-nuanced-fg . "#ed6f74")
+              (green-nuanced-bg . "#dcf0dd")
+              (green-nuanced-fg . "#3f9a4c")
+              (yellow-nuanced-bg . "#fff3aa")
+              (yellow-nuanced-fg . "#b47232")
+              (blue-nuanced-bg . "#e3e3ff")
+              (blue-nuanced-fg . "#201f6f")
+              (magenta-nuanced-bg . "#fdd0ff")
+              (magenta-nuanced-fg . "#c0527f")
+              (cyan-nuanced-bg . "#dbefff")
+              (cyan-nuanced-fg . "#0f3f60")
+              (bg-diff-heading . "#b7cfe0")
+              (fg-diff-heading . "#041645")
+              (bg-diff-added . "#d6f0d6")
+              (fg-diff-added . "#004520")
+              (bg-diff-changed . "#fcefcf")
+              (fg-diff-changed . "#524200")
+              (bg-diff-removed . "#ffe0ef")
+              (fg-diff-removed . "#891626")
+              (bg-diff-refine-added . "#84cfa4")
+              (fg-diff-refine-added . "#002a00")
+              (bg-diff-refine-changed . "#cccf8f")
+              (fg-diff-refine-changed . "#302010")
+              (bg-diff-refine-removed . "#da92b0")
+              (fg-diff-refine-removed . "#500010")
+              (bg-diff-focus-added . "#a6e5c6")
+              (fg-diff-focus-added . "#002c00")
+              (bg-diff-focus-changed . "#ecdfbf")
+              (fg-diff-focus-changed . "#392900")
+              (bg-diff-focus-removed . "#efbbcf")
+              (fg-diff-focus-removed . "#5a0010"))
+            modus-themes-vivendi-color-overrides
+            '((bg-main . "#25152a")
+              (bg-dim . "#2a1930")
+              (bg-alt . "#382443")
+              (bg-hl-line . "#332650")
+              (bg-active . "#463358")
+              (bg-inactive . "#2d1f3a")
+              (bg-active-accent . "#50308f")
+              (bg-region . "#5d4a67")
+              (bg-region-accent . "#60509f")
+              (bg-region-accent-subtle . "#3f285f")
+              (bg-header . "#3a2543")
+              (bg-tab-active . "#26162f")
+              (bg-tab-inactive . "#362647")
+              (bg-tab-inactive-accent . "#36265a")
+              (bg-tab-inactive-alt . "#3e2f5a")
+              (bg-tab-inactive-alt-accent . "#3e2f6f")
+              (fg-main . "#debfe0")
+              (fg-dim . "#d0b0da")
+              (fg-alt . "#ae85af")
+              (fg-unfocused . "#8e7f9f")
+              (fg-active . "#cfbfef")
+              (fg-inactive . "#b0a0c0")
+              (fg-docstring . "#c8d9f7")
+              (fg-comment-yellow . "#cf9a70")
+              (fg-escape-char-construct . "#ff75aa")
+              (fg-escape-char-backslash . "#dbab40")
+              (bg-special-cold . "#2a3f58")
+              (bg-special-faint-cold . "#1e283f")
+              (bg-special-mild . "#0f3f31")
+              (bg-special-faint-mild . "#0f281f")
+              (bg-special-warm . "#44331f")
+              (bg-special-faint-warm . "#372213")
+              (bg-special-calm . "#4a314f")
+              (bg-special-faint-calm . "#3a223f")
+              (fg-special-cold . "#c0b0ff")
+              (fg-special-mild . "#bfe0cf")
+              (fg-special-warm . "#edc0a6")
+              (fg-special-calm . "#ff9fdf")
+              (bg-completion . "#502d70")
+              (bg-completion-subtle . "#451d65")
+              (red . "#ff5f6f")
+              (red-alt . "#ff8f6d")
+              (red-alt-other . "#ff6f9d")
+              (red-faint . "#ffa0a0")
+              (red-alt-faint . "#f5aa80")
+              (red-alt-other-faint . "#ff9fbf")
+              (green . "#51ca5c")
+              (green-alt . "#71ca3c")
+              (green-alt-other . "#51ca9c")
+              (green-faint . "#78bf78")
+              (green-alt-faint . "#99b56f")
+              (green-alt-other-faint . "#88bf99")
+              (yellow . "#f0b262")
+              (yellow-alt . "#f0e242")
+              (yellow-alt-other . "#d0a272")
+              (yellow-faint . "#d2b580")
+              (yellow-alt-faint . "#cabf77")
+              (yellow-alt-other-faint . "#d0ba95")
+              (blue . "#778cff")
+              (blue-alt . "#8f90ff")
+              (blue-alt-other . "#8380ff")
+              (blue-faint . "#82b0ec")
+              (blue-alt-faint . "#a0acef")
+              (blue-alt-other-faint . "#80b2f0")
+              (magenta . "#ff70cf")
+              (magenta-alt . "#ff77f0")
+              (magenta-alt-other . "#ca7fff")
+              (magenta-faint . "#e0b2d6")
+              (magenta-alt-faint . "#ef9fe4")
+              (magenta-alt-other-faint . "#cfa6ff")
+              (cyan . "#30cacf")
+              (cyan-alt . "#60caff")
+              (cyan-alt-other . "#40b79f")
+              (cyan-faint . "#90c4ed")
+              (cyan-alt-faint . "#a0bfdf")
+              (cyan-alt-other-faint . "#a4d0bb")
+              (red-active . "#ff6059")
+              (green-active . "#64dc64")
+              (yellow-active . "#ffac80")
+              (blue-active . "#4fafff")
+              (magenta-active . "#cf88ff")
+              (cyan-active . "#50d3d0")
+              (red-nuanced-bg . "#440a1f")
+              (red-nuanced-fg . "#ffcccc")
+              (green-nuanced-bg . "#002904")
+              (green-nuanced-fg . "#b8e2b8")
+              (yellow-nuanced-bg . "#422000")
+              (yellow-nuanced-fg . "#dfdfb0")
+              (blue-nuanced-bg . "#1f1f5f")
+              (blue-nuanced-fg . "#bfd9ff")
+              (magenta-nuanced-bg . "#431641")
+              (magenta-nuanced-fg . "#e5cfef")
+              (cyan-nuanced-bg . "#042f49")
+              (cyan-nuanced-fg . "#a8e5e5")
+              (bg-diff-heading . "#304466")
+              (fg-diff-heading . "#dae7ff")
+              (bg-diff-added . "#0a383a")
+              (fg-diff-added . "#94ba94")
+              (bg-diff-changed . "#2a2000")
+              (fg-diff-changed . "#b0ba9f")
+              (bg-diff-removed . "#50163f")
+              (fg-diff-removed . "#c6adaa")
+              (bg-diff-refine-added . "#006a46")
+              (fg-diff-refine-added . "#e0f6e0")
+              (bg-diff-refine-changed . "#585800")
+              (fg-diff-refine-changed . "#ffffcc")
+              (bg-diff-refine-removed . "#952838")
+              (fg-diff-refine-removed . "#ffd9eb")
+              (bg-diff-focus-added . "#1d4c3f")
+              (fg-diff-focus-added . "#b4dfb4")
+              (bg-diff-focus-changed . "#424200")
+              (fg-diff-focus-changed . "#d0daaf")
+              (bg-diff-focus-removed . "#6f0f39")
+              (fg-diff-focus-removed . "#eebdba")))
+    (setq modus-themes-operandi-color-overrides nil
+          modus-themes-vivendi-color-overrides nil)))
+#+end_src
+
 ** Font configurations for Org and others
 :properties:
 :custom_id: h:defcf4fc-8fa8-4c29-b12e-7119582cc929
@@ -3117,6 +3405,9 @@ the ~variable-pitch~ (proportional spacing) and 
~fixed-pitch~ (monospaced)
 faces respectively.  It may also be convenient to set your main typeface
 by configuring the ~default~ face the same way.
 
+[ The =fontaine= package on GNU ELPA (by the author of the modus-themes)
+  is designed to handle this case. ]
+
 Put something like this in your initialization file (also consider
 reading the doc string of ~set-face-attribute~):
 
@@ -3347,7 +3638,7 @@ it if you plan to control face attributes.
 :end:
 #+cindex: Org custom emphasis faces
 
-Org provides the user option ~org-emphasis-alist~ which assosiates a
+Org provides the user option ~org-emphasis-alist~ which associates a
 character with a face, list of faces, or face attributes.  The default
 specification of that variable looks like this:
 
@@ -4119,6 +4410,64 @@ Or include a ~let~ form, if needed:
 Normally, we do not touch user options, though this is an exception:
 otherwise the defaults are not always legible.
 
+** Add support for solaire-mode
+:PROPERTIES:
+:CUSTOM_ID: h:439c9e46-52e2-46be-b1dc-85841dd99671
+:END:
+
+The =solaire-mode= package dims the background of what it considers
+ancillary "UI" buffers, such as the minibuffer and Dired buffers.  The
+Modus themes used to support Solaire on the premise that the user was
+(i) opting in to it, (ii) understood why certain buffers were more gray,
+and (iii) knew what other adjustments had to be made to prevent broken
+visuals (e.g. the default style of the ~modus-themes-completions~ uses a
+subtle gray background for the selection, which with Solaire becomes
+practically invisible).
+
+However, the assumption that users opt in to this feature does not
+always hold true.  There are cases where it is enabled by defaultsuch as
+in the popular Doom Emacs configuration.  Thus, the unsuspecting user
+who loads ~modus-operandi~ or ~modus-vivendi~ without the requisite
+customizations is getting a sub-par experience; an experience that we
+did not intend and cannot genuinely fix.
+
+Because the Modus themes are meant to work everywhere, we cannot make an
+exception for Doom Emacs and/or Solaire users.  Furthermore, we shall
+not introduce hacks, such as by adding a check in all relevant faces to
+be adjusted based on Solaire or whatever other package.  Hacks of this
+sort are unsustainable and penalize the entire userbase.  Besides, the
+themes are built into Emacs and we must keep their standard high.
+
+The fundamental constraint with Solaire is that Emacs does not have a
+real distinction between "content" and "UI" buffers.  For themes to work
+with Solaire, they need to be designed around that package.  Such is an
+arrangement that compromises on our accessibility standards and/or
+hinders our efforts to provide the best possible experience while using
+the Modus themes.
+
+As such, =solaire-mode= is not---and will not be---supported by the
+Modus themes (or any other of my themes, for that matter).  Users who
+want it must style the faces manually.  Below is some sample code, based
+on what we cover at length elsewhere in this manual:
+
+[[#h:f4651d55-8c07-46aa-b52b-bed1e53463bb][Advanced customization]].
+
+[[#h:51ba3547-b8c8-40d6-ba5a-4586477fd4ae][Face specs at scale using the 
themes' palette]].
+
+#+begin_src emacs-lisp
+(defun my-modus-themes-custom-faces ()
+  (modus-themes-with-colors
+    (custom-set-faces
+     `(solaire-default-face ((,class :inherit default :background ,bg-alt 
:foreground ,fg-dim)))
+     `(solaire-line-number-face ((,class :inherit solaire-default-face 
:foreground ,fg-unfocused)))
+     `(solaire-hl-line-face ((,class :background ,bg-active)))
+     `(solaire-org-hide-face ((,class :background ,bg-alt :foreground 
,bg-alt))))))
+
+(add-hook 'modus-themes-after-load-theme-hook #'my-modus-themes-custom-faces)
+#+end_src
+
+As always, re-load the theme for changes to take effect.
+
 * Face coverage
 :properties:
 :custom_id: h:a9c8f29d-7f72-4b54-b74b-ddefe15d6a19
@@ -4165,9 +4514,9 @@ have lots of extensions, so the "full support" may not be 
100% true…
 + calendar and diary
 + calfw
 + calibredb
-+ centaur-tabs
 + cfrs
 + change-log and log-view (such as ~vc-print-log~, ~vc-print-root-log~)
++ chart
 + cider
 + circe
 + citar
@@ -4187,13 +4536,12 @@ have lots of extensions, so the "full support" may not 
be 100% true…
 + css-mode
 + csv-mode
 + ctrlf
-+ cursor-flash
 + custom (what you get with {{{kbd(M-x customize)}}})
 + dap-mode
-+ dashboard (emacs-dashboard)
 + deadgrep
 + debbugs
 + deft
++ denote
 + devdocs
 + dictionary
 + diff-hl
@@ -4210,7 +4558,6 @@ have lots of extensions, so the "full support" may not be 
100% true…
 + diredp (dired+)
 + display-fill-column-indicator-mode
 + doom-modeline
-+ dynamic-ruler
 + easy-jekyll
 + ebdb
 + ediff
@@ -4251,7 +4598,6 @@ have lots of extensions, so the "full support" may not be 
100% true…
 + flyspell
 + flx
 + freeze-it
-+ frog-menu
 + focus
 + fold-this
 + font-lock (generic syntax highlighting)
@@ -4289,6 +4635,7 @@ have lots of extensions, so the "full support" may not be 
100% true…
 + imenu-list
 + indium
 + info
++ info+ (info-plus)
 + info-colors
 + interaction-log
 + ioccur
@@ -4303,6 +4650,7 @@ have lots of extensions, so the "full support" may not be 
100% true…
 + kaocha-runner
 + keycast
 + ledger-mode
++ leerzeichen
 + line numbers (~display-line-numbers-mode~ and global variant)
 + lsp-mode
 + lsp-ui
@@ -4314,7 +4662,6 @@ have lots of extensions, so the "full support" may not be 
100% true…
 + marginalia
 + markdown-mode
 + markup-faces (~adoc-mode~)
-+ mct
 + mentor
 + messages
 + mini-modeline
@@ -4341,14 +4688,12 @@ have lots of extensions, so the "full support" may not 
be 100% true…
 + org-superstar
 + org-table-sticky-header
 + org-tree-slide
-+ org-treescope
 + origami
 + outline-mode
 + outline-minor-faces
 + package (what you get with {{{kbd(M-x list-packages)}}})
 + page-break-lines
 + pandoc-mode
-+ paradox
 + paren-face
 + pass
 + pdf-tools
@@ -4391,7 +4736,6 @@ have lots of extensions, so the "full support" may not be 
100% true…
 + smart-mode-line
 + smartparens
 + smerge
-+ solaire
 + spaceline
 + speedbar
 + stripes
@@ -4420,7 +4764,6 @@ have lots of extensions, so the "full support" may not be 
100% true…
 + typescript
 + undo-tree
 + vc (vc-dir.el, vc-hooks.el)
-+ vc-annotate (the output of {{{kbd(C-x v g)}}})
 + vertico
 + vertico-quick
 + vimish-fold
@@ -4464,9 +4807,11 @@ supported by the themes.
 + bufler
 + counsel-notmuch
 + counsel-org-capture-string
++ dashboard (emacs-dashboard)
 + define-word
 + disk-usage
 + dtache
++ dynamic-ruler
 + easy-kill
 + edit-indirect
 + egerrit
@@ -4542,7 +4887,7 @@ The =git-gutter= and =git-gutter-fr= packages default to 
drawing bitmaps
 for the indicators they display (e.g. bitmap of a plus sign for added
 lines).  In Doom Emacs, these bitmaps are replaced with contiguous lines
 which may look nicer, but require a change to the foreground of the
-relevant faces to yield the desired colour combinations.
+relevant faces to yield the desired color combinations.
 
 Since this is Doom-specific, we urge users to apply changes in their
 local setup.  Below is some sample code, based on what we cover at
@@ -4564,6 +4909,8 @@ length elsewhere in this manual:
 (add-hook 'modus-themes-after-load-theme-hook #'my-modus-themes-custom-faces)
 #+end_src
 
+As always, re-load the theme for changes to take effect.
+
 If the above does not work, try this instead:
 
 #+begin_src emacs-lisp
@@ -4599,6 +4946,8 @@ This seems to make all comments use the appropriate face:
 (add-hook 'php-mode-hook #'my-multine-comments)
 #+end_src
 
+As always, re-load the theme for changes to take effect.
+
 ** Note on underlines in compilation buffers
 :properties:
 :custom_id: h:420f5a33-c7a9-4112-9b04-eaf2cbad96bd
@@ -4838,6 +5187,8 @@ implementation:
 (add-hook 'modus-themes-after-load-theme-hook 
#'my-modus-themes-highlight-parentheses)
 #+end_src
 
+As always, re-load the theme for changes to take effect.
+
 ** Note on mmm-mode.el background colors
 :properties:
 :custom_id: h:99cf0d6c-e478-4e26-9932-3bf3427d13f6
@@ -5181,24 +5532,6 @@ candidates.  That style still meets the contrast ratio 
target of >= 7:1
 ANSI color number 1 (red) from the already-supported array of
 ~ansi-color-names-vector~.
 
-** Note on vc-annotate-background-mode
-:properties:
-:custom_id: h:5095cbd1-e17a-419c-93e8-951c186362a3
-:end:
-
-Due to the unique way ~vc-annotate~ ({{{kbd(C-x v g)}}}) applies colors, 
support
-for its background mode (~vc-annotate-background-mode~) is disabled at the
-theme level.
-
-Normally, such a drastic measure should not belong in a theme: assuming
-the user's preferences is bad practice.  However, it has been deemed
-necessary in the interest of preserving color contrast accessibility
-while still supporting a useful built-in tool.
-
-If there actually is a way to avoid such a course of action, without
-prejudice to the accessibility standard of this project, then please
-report as much or send patches 
([[#h:9c3cd842-14b7-44d7-84b2-a5c8bc3fc3b1][Contributing]]).
-
 ** Note on pdf-tools link hints
 :properties:
 :custom_id: h:2659d13e-b1a5-416c-9a89-7c3ce3a76574
@@ -5743,9 +6076,10 @@ The Modus themes are a collective effort.  Every bit of 
work matters.
   Carlo Zancanaro, Christian Tietze, Daniel Mendler, Eli Zaretskii,
   Fritz Grabo, Illia Ostapyshyn, Kévin Le Gouguec, Kostadin Ninev,
   Madhavan Krishnan, Manuel Giraud, Markus Beppler, Matthew Stevenson,
-  Mauro Aranda, Nicolas De Jaeghere, Philip Kaludercic, Pierre
-  Téchoueyres, Rudolf Adamkovič, Stephen Gildea, Shreyas Ragavan, Stefan
-  Kangas, Utkarsh Singh, Vincent Murphy, Xinglu Chen, Yuanchen Xie.
+  Mauro Aranda, Nicolas De Jaeghere, Paul David, Philip Kaludercic,
+  Pierre Téchoueyres, Rudolf Adamkovič, Stephen Gildea, Shreyas Ragavan,
+  Stefan Kangas, Utkarsh Singh, Vincent Murphy, Xinglu Chen, Yuanchen
+  Xie.
 
 + Ideas and user feedback :: Aaron Jensen, Adam Porter, Adam Spiers,
   Adrian Manea, Alex Griffin, Alex Koen, Alex Peitsinis, Alexey Shmalko,
@@ -5758,22 +6092,22 @@ The Modus themes are a collective effort.  Every bit of 
work matters.
   Gautier Ponsinet, Gerry Agbobada, Gianluca Recchia, Gonçalo Marrafa,
   Guilherme Semente, Gustavo Barros, Hörmetjan Yiltiz, Ilja Kocken, Iris
   Garcia, Ivan Popovych, Jeremy Friesen, Jerry Zhang, Johannes Grødem,
-  John Haman, Jorge Morais, Joshua O'Connor, Julio C. Villasante, Kenta
-  Usami, Kevin Fleming, Kévin Le Gouguec, Kostadin Ninev, Len Trigg,
-  Lennart C. Karssen, Magne Hov, Manuel Uberti, Mark Bestley, Mark
-  Burton, Markus Beppler, Mauro Aranda, Maxime Tréca, Michael
-  Goldenberg, Morgan Smith, Morgan Willcock, Murilo Pereira, Nicky van
-  Foreest, Nicolas De Jaeghere, Paul Poloskov, Pengji Zhang, Pete
-  Kazmier, Peter Wu, Philip Kaludercic, Pierre Téchoueyres, Przemysław
-  Kryger, Robert Hepple, Roman Rudakov, Ryan Phillips, Rytis Paškauskas,
-  Rudolf Adamkovič, Sam Kleinman, Samuel Culpepper, Saša Janiška,
-  Shreyas Ragavan, Simon Pugnet, Tassilo Horn, Thibaut Verron, Thomas
-  Heartman, Togan Muftuoglu, Tony Zorman, Trey Merkley, Tomasz
-  Hołubowicz, Toon Claes, Uri Sharf, Utkarsh Singh, Vincent Foley.  As
-  well as users: Ben, CsBigDataHub1, Emacs Contrib, Eugene, Fourchaux,
-  Fredrik, Moesasji, Nick, TheBlob42, Trey, bepolymathe, bit9tream,
-  derek-upham, doolio, fleimgruber, gitrj95, iSeeU, jixiuf, okamsn,
-  pRot0ta1p.
+  John Haman, Jonas Collberg, Jorge Morais, Joshua O'Connor, Julio
+  C. Villasante, Kenta Usami, Kevin Fleming, Kévin Le Gouguec, Kostadin
+  Ninev, Len Trigg, Lennart C. Karssen, Magne Hov, Manuel Uberti, Mark
+  Bestley, Mark Burton, Markus Beppler, Matt Armstrong, Mauro Aranda,
+  Maxime Tréca, Michael Goldenberg, Morgan Smith, Morgan Willcock,
+  Murilo Pereira, Nicky van Foreest, Nicolas De Jaeghere, Paul Poloskov,
+  Pengji Zhang, Pete Kazmier, Peter Wu, Philip Kaludercic, Pierre
+  Téchoueyres, Przemysław Kryger, Robert Hepple, Roman Rudakov, Ryan
+  Phillips, Rytis Paškauskas, Rudolf Adamkovič, Sam Kleinman, Samuel
+  Culpepper, Saša Janiška, Shreyas Ragavan, Simon Pugnet, Tassilo Horn,
+  Thibaut Verron, Thomas Heartman, Togan Muftuoglu, Tony Zorman, Trey
+  Merkley, Tomasz Hołubowicz, Toon Claes, Uri Sharf, Utkarsh Singh,
+  Vincent Foley.  As well as users: Ben, CsBigDataHub1, Emacs Contrib,
+  Eugene, Fourchaux, Fredrik, Moesasji, Nick, Summer Emacs, TheBlob42,
+  Trey, bepolymathe, bit9tream, derek-upham, doolio, fleimgruber,
+  gitrj95, iSeeU, jixiuf, okamsn, pRot0ta1p.
 
 + Packaging :: Basil L.{{{space()}}} Contovounesios, Eli Zaretskii,
   Glenn Morris, Mauro Aranda, Richard Stallman, Stefan Kangas (core
@@ -5784,10 +6118,12 @@ The Modus themes are a collective effort.  Every bit of 
work matters.
 + Inspiration for certain features :: Bozhidar Batsov (zenburn-theme),
   Fabrice Niessen (leuven-theme).
 
-Special thanks (from A-Z) to Gustavo Barros, Manuel Uberti, Nicolas De
-Jaeghere, and Omar Antolín Camarena for their long time contributions
-and insightful commentary on key aspects of the themes' design and/or
-aspects of their functionality.
+Special thanks (from A-Z) to Daniel Mendler, Gustavo Barros, Manuel
+Uberti, Nicolas De Jaeghere, and Omar Antolín Camarena for their long
+time contributions and insightful commentary on key aspects of the
+themes' design and/or aspects of their functionality.
+
+All errors are my own.
 
 * Other notes about the project
 :properties:
diff --git a/doc/misc/org.org b/doc/misc/org.org
index baab2efeda..7971c417a5 100644
--- a/doc/misc/org.org
+++ b/doc/misc/org.org
@@ -2866,12 +2866,12 @@ For more information and examples see the 
[[https://orgmode.org/worg/org-tutoria
 - transpose ::
 
   When =y=, =yes=, or =t= attempt to transpose the table data before
-  plotting.  Also recognises the shorthand option =trans=.
+  plotting.  Also recognizes the shorthand option =trans=.
 
 - =type= ::
 
   Specify the type of the plot, by default one of  =2d=, =3d=, =radar=, or 
=grid=.
-  Available types can be customised with ~org-plot/preset-plot-types~.
+  Available types can be customized with ~org-plot/preset-plot-types~.
 
 - =with= ::
 
@@ -3352,7 +3352,7 @@ current buffer:
   ~org-link-email-description-format~.  By default, it refers to the
   addressee and the subject.
 
-- /Web browsers: W3, W3M and EWW/ ::
+- /Web browsers: W3M and EWW/ ::
 
   Here the link is the current URL, with the page title as the
   description.
@@ -8544,8 +8544,8 @@ commands:
   Search for a regular expression in all agenda files and additionally
   in the files listed in ~org-agenda-text-search-extra-files~.  This
   uses the Emacs command ~multi-occur~.  A prefix argument can be used
-  to specify the number of context lines for each match, default is
-  1.
+  to specify the number of context lines for each match, the default
+  is 1.
 
 - {{{kbd(#)}}} ::
 
diff --git a/doc/misc/rcirc.texi b/doc/misc/rcirc.texi
index 8253e40408..8c798d6c33 100644
--- a/doc/misc/rcirc.texi
+++ b/doc/misc/rcirc.texi
@@ -639,9 +639,9 @@ password to use.
 @item certfp
 @cindex certfp authentication
 Use this symbol if you want to use CertFP authentication.  The
-necessary arguments are the path to the client certificate key and
-password.  The CertFP authentication requires a @acronym{TLS}
-connection.
+necessary arguments are the path to the key and to the client
+certificate associated with the account.  The CertFP authentication
+requires a @acronym{TLS} connection.
 
 @end table
 
diff --git a/doc/misc/reftex.texi b/doc/misc/reftex.texi
index c3b7b0b0f6..0c95b388cb 100644
--- a/doc/misc/reftex.texi
+++ b/doc/misc/reftex.texi
@@ -38,7 +38,6 @@ Con@TeX{}t
 @set SUPPORTADDRESS @AUCTeX{} user mailing list (@email{auctex@@gnu.org})
 @set DEVELADDRESS @AUCTeX{} developer mailing list 
(@email{auctex-devel@@gnu.org})
 @set BUGADDRESS @AUCTeX{} bug mailing list (@email{bug-auctex@@gnu.org})
-@set XEMACSFTP @uref{ftp://ftp.xemacs.org/pub/xemacs/packages/,XEmacs FTP site}
 @c %**end of header
 
 @copying
@@ -249,10 +248,7 @@ reports or suggestions.
 @cindex Installation
 
 @RefTeX{} has been bundled and pre-installed with Emacs since
-version 20.2.  It has also been bundled and pre-installed with XEmacs
-19.16--20.x.  XEmacs 21.x users want to install the corresponding
-plug-in package which is available from the @value{XEMACSFTP}.  See the
-XEmacs 21.x documentation on package installation for details.
+version 20.2.
 
 @findex turn-on-reftex
 @findex reftex-mode
@@ -3584,7 +3580,7 @@ the @value{BUGADDRESS}.
 
 There are also several Usenet groups which have competent readers who
 might be able to help: @code{comp.emacs}, @code{gnu.emacs.help},
-@code{comp.emacs.xemacs}, and @code{comp.text.tex}.
+and @code{comp.text.tex}.
 
 Thanks to the people on the Net who have used @RefTeX{} and helped
 developing it with their reports.  In particular thanks to @i{Ralf
diff --git a/doc/misc/texinfo.tex b/doc/misc/texinfo.tex
index 8872e5e055..f86af0db3e 100644
--- a/doc/misc/texinfo.tex
+++ b/doc/misc/texinfo.tex
@@ -3,7 +3,7 @@
 % Load plain if necessary, i.e., if running under initex.
 \expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi
 %
-\def\texinfoversion{2022-04-09.08}
+\def\texinfoversion{2022-08-20.19}
 %
 % Copyright 1985, 1986, 1988, 1990-2022 Free Software Foundation, Inc.
 %
@@ -725,32 +725,22 @@ where each line of input produces a line of output.}
   \dimen2 = \ht\strutbox
   \advance\dimen2 by \dp\strutbox
   \ifdim\dimen0 > \dimen2
+    % This is similar to the 'needspace' module in LaTeX.
+    % The first penalty allows a break if the end of the page is
+    % not too far away.  Following penalties and skips are discarded.
+    % Otherwise, require at least \dimen0 of vertical space.
     %
-    % Do a \strut just to make the height of this box be normal, so the
-    % normal leading is inserted relative to the preceding line.
-    % And a page break here is fine.
-    \vtop to #1\mil{\strut\vfil}%
-    %
-    % TeX does not even consider page breaks if a penalty added to the
-    % main vertical list is 10000 or more.  But in order to see if the
-    % empty box we just added fits on the page, we must make it consider
-    % page breaks.  On the other hand, we don't want to actually break the
-    % page after the empty box.  So we use a penalty of 9999.
-    %
-    % There is an extremely small chance that TeX will actually break the
-    % page at this \penalty, if there are no other feasible breakpoints in
-    % sight.  (If the user is using lots of big @group commands, which
-    % almost-but-not-quite fill up a page, TeX will have a hard time doing
-    % good page breaking, for example.)  However, I could not construct an
-    % example where a page broke at this \penalty; if it happens in a real
-    % document, then we can reconsider our strategy.
+    % (We used to use a \vtop to reserve space, but this had spacing issues
+    % when followed by a section heading, as it was not a "discardable item".
+    % This also has the benefit of providing glue before the page break if
+    % there isn't enough space.)
+    \vskip0pt plus \dimen0
+    \penalty-100
+    \vskip0pt plus -\dimen0
+    \vskip \dimen0
     \penalty9999
-    %
-    % Back up by the size of the box, whether we did a page break or not.
-    \kern -#1\mil
-    %
-    % Do not allow a page break right after this kern.
-    \nobreak
+    \vskip -\dimen0
+    \penalty0\relax % this hides the above glue from \safewhatsit and \dobreak
   \fi
 }
 
@@ -2558,7 +2548,7 @@ end
 \def\it{\fam=\itfam \setfontstyle{it}}
 \def\sl{\fam=\slfam \setfontstyle{sl}}
 \def\bf{\fam=\bffam \setfontstyle{bf}}\def\bfstylename{bf}
-\def\tt{\fam=\ttfam \setfontstyle{tt}}\def\ttstylename{tt}
+\def\tt{\fam=\ttfam \setfontstyle{tt}}
 
 % Texinfo sort of supports the sans serif font style, which plain TeX does not.
 % So we set up a \sf.
@@ -2691,6 +2681,14 @@ end
 %
 \def\ifmonospace{\ifdim\fontdimen3\font=0pt }
 
+% Check if internal flag is clear, i.e. has not been @set.
+\def\ifflagclear#1#2#3{%
+  \expandafter\ifx\csname SET#1\endcsname\relax
+  #2\else#3\fi
+}
+
+
+
 {
 \catcode`\'=\active
 \catcode`\`=\active
@@ -2707,14 +2705,14 @@ end
 %
 \def\codequoteright{%
   \ifmonospace
-    \expandafter\ifx\csname SETtxicodequoteundirected\endcsname\relax
-      \expandafter\ifx\csname SETcodequoteundirected\endcsname\relax
+    \ifflagclear{txicodequoteundirected}{%
+      \ifflagclear{codequoteundirected}{%
         '%
-      \else \char'15 \fi
-    \else \char'15 \fi
-   \else
-     '%
-   \fi
+      }{\char'15 }%
+    }{\char'15 }%
+  \else
+    '%
+  \fi
 }
 %
 % and a similar option for the left quote char vs. a grave accent.
@@ -2723,16 +2721,16 @@ end
 %
 \def\codequoteleft{%
   \ifmonospace
-    \expandafter\ifx\csname SETtxicodequotebacktick\endcsname\relax
-      \expandafter\ifx\csname SETcodequotebacktick\endcsname\relax
+    \ifflagclear{txicodequotebacktick}{%
+      \ifflagclear{codequotebacktick}{%
         % [Knuth] pp. 380,381,391
         % \relax disables Spanish ligatures ?` and !` of \tt font.
         \relax`%
-      \else \char'22 \fi
-    \else \char'22 \fi
-   \else
-     \relax`%
-   \fi
+      }{\char'22 }%
+    }{\char'22 }%
+  \else
+    \relax`%
+  \fi
 }
 
 % Commands to set the quote options.
@@ -2779,15 +2777,16 @@ end
 \def\dosmartslant#1#2{%
   \ifusingtt
     {{\ttsl #2}\let\next=\relax}%
-    {\def\next{{#1#2}\futurelet\next\smartitaliccorrection}}%
+    {\def\next{{#1#2}\smartitaliccorrection}}%
   \next
 }
 \def\smartslanted{\dosmartslant\sl}
 \def\smartitalic{\dosmartslant\it}
 
-% Output an italic correction unless \next (presumed to be the following
-% character) is such as not to need one.
-\def\smartitaliccorrection{%
+% Output an italic correction unless the following character is such as
+% not to need one.
+\def\smartitaliccorrection{\futurelet\next\smartitaliccorrectionx}
+\def\smartitaliccorrectionx{%
   \ifx\next,%
   \else\ifx\next-%
   \else\ifx\next.%
@@ -2798,18 +2797,18 @@ end
   \aftersmartic
 }
 
-% Unconditional use \ttsl, and no ic.  @var is set to this for defuns.
-\def\ttslanted#1{{\ttsl #1}}
-
-% @cite is like \smartslanted except unconditionally use \sl.  We never want
-% ttsl for book titles, do we?
-\def\cite#1{{\sl #1}\futurelet\next\smartitaliccorrection}
+% @cite unconditionally uses \sl with \smartitaliccorrection.
+\def\cite#1{{\sl #1}\smartitaliccorrection}
 
+% @var unconditionally uses \sl.  This gives consistency for
+% parameter names whether they are in @def, @table @code or a
+% regular paragraph.
+% The \null is to reset \spacefactor.
 \def\aftersmartic{}
 \def\var#1{%
   \let\saveaftersmartic = \aftersmartic
   \def\aftersmartic{\null\let\aftersmartic=\saveaftersmartic}%
-  \smartslanted{#1}%
+  {\sl #1}\smartitaliccorrection
 }
 
 \let\i=\smartitalic
@@ -2817,8 +2816,14 @@ end
 \let\dfn=\smartslanted
 \let\emph=\smartitalic
 
-% Explicit font changes: @r, @sc, undocumented @ii.
-\def\r#1{{\rm #1}}              % roman font
+% @r for roman font, used for code comment
+\def\r#1{{%
+  \usenormaldash % get --, --- ligatures even if in @code
+  \defcharsdefault  % in case on def line
+  \rm #1}}
+{\catcode`-=\active \gdef\usenormaldash{\let-\normaldash}}
+
+% @sc, undocumented @ii.
 \def\sc#1{{\smallcaps#1}}       % smallcaps font
 \def\ii#1{{\it #1}}             % italic font
 
@@ -2856,7 +2861,7 @@ end
 
 % @t, explicit typewriter.
 \def\t#1{%
-  {\tt \plainfrenchspacing #1}%
+  {\tt \defcharsdefault \plainfrenchspacing #1}%
   \null
 }
 
@@ -4432,7 +4437,7 @@ $$%
 
 \message{conditionals,}
 
-% @iftex, @ifnotdocbook, @ifnothtml, @ifnotinfo, @ifnotplaintext,
+% @iftex, @ifnotdocbook, @ifnothtml, @ifnotinfo, @ifnotlatex, @ifnotplaintext,
 % @ifnotxml always succeed.  They currently do nothing; we don't
 % attempt to check whether the conditionals are properly nested.  But we
 % have to remember that they are conditionals, so that @end doesn't
@@ -4446,6 +4451,7 @@ $$%
 \makecond{ifnotdocbook}
 \makecond{ifnothtml}
 \makecond{ifnotinfo}
+\makecond{ifnotlatex}
 \makecond{ifnotplaintext}
 \makecond{ifnotxml}
 
@@ -4458,10 +4464,12 @@ $$%
 \def\ifdocbook{\doignore{ifdocbook}}
 \def\ifhtml{\doignore{ifhtml}}
 \def\ifinfo{\doignore{ifinfo}}
+\def\iflatex{\doignore{iflatex}}
 \def\ifnottex{\doignore{ifnottex}}
 \def\ifplaintext{\doignore{ifplaintext}}
 \def\ifxml{\doignore{ifxml}}
 \def\ignore{\doignore{ignore}}
+\def\latex{\doignore{latex}}
 \def\menu{\doignore{menu}}
 \def\xml{\doignore{xml}}
 
@@ -4985,25 +4993,24 @@ $$%
 \catcode`\-=13
 \catcode`\`=13
   \gdef\indexnonalnumdisappear{%
-    \expandafter\ifx\csname SETtxiindexlquoteignore\endcsname\relax\else
+    \ifflagclear{txiindexlquoteignore}{}{%
       % @set txiindexlquoteignore makes us ignore left quotes in the sort term.
       % (Introduced for FSFS 2nd ed.)
       \let`=\empty
-    \fi
+    }%
     %
-    \expandafter\ifx\csname SETtxiindexbackslashignore\endcsname\relax\else
+    \ifflagclear{txiindexbackslashignore}{}{%
       \backslashdisappear
-    \fi
-    %
-    \expandafter\ifx\csname SETtxiindexhyphenignore\endcsname\relax\else
+    }%
+    \ifflagclear{txiindexhyphenignore}{}{%
       \def-{}%
-    \fi
-    \expandafter\ifx\csname SETtxiindexlessthanignore\endcsname\relax\else
+    }%
+    \ifflagclear{txiindexlessthanignore}{}{%
       \def<{}%
-    \fi
-    \expandafter\ifx\csname SETtxiindexatsignignore\endcsname\relax\else
+    }%
+    \ifflagclear{txiindexatsignignore}{}{%
       \def\@{}%
-    \fi
+    }%
   }
 
   \gdef\indexnonalnumreappear{%
@@ -5295,9 +5302,7 @@ $$%
   %
   \atdummies
   %
-  \expandafter\ifx\csname SETtxiindexescapeisbackslash\endcsname\relax\else
-    \escapeisbackslash
-  \fi
+  \ifflagclear{txiindexescapeisbackslash}{}{\escapeisbackslash}%
   %
   % For texindex which always views { and } as separators.
   \def\{{\lbracechar{}}%
@@ -5481,9 +5486,9 @@ $$%
 % old index files using \ as the escape character.  Reading this would
 % at best lead to typesetting garbage, at worst a TeX syntax error.
 \def\printindexzz#1#2\finish{%
-  \expandafter\ifx\csname SETtxiindexescapeisbackslash\endcsname\relax
+  \ifflagclear{txiindexescapeisbackslash}{%
     \uccode`\~=`\\ \uppercase{\if\noexpand~}\noexpand#1
-      \expandafter\ifx\csname SETtxiskipindexfileswithbackslash\endcsname\relax
+      \ifflagclear{txiskipindexfileswithbackslash}{%
 \errmessage{%
 ERROR: A sorted index file in an obsolete format was skipped.
 To fix this problem, please upgrade your version of 'texi2dvi'
@@ -5499,15 +5504,15 @@ this, Texinfo will try to use index files in the old 
format.
 If you continue to have problems, deleting the index files and starting again
 might help (with 'rm \jobname.?? \jobname.??s')%
 }%
-      \else
+      }{%
         (Skipped sorted index file in obsolete format)
-      \fi
+      }%
     \else
       \begindoublecolumns
       \input \jobname.\indexname s
       \enddoublecolumns
     \fi
-  \else
+  }{%
     \begindoublecolumns
     \catcode`\\=0\relax
     %
@@ -5517,7 +5522,7 @@ might help (with 'rm \jobname.?? \jobname.??s')%
     \catcode`\@=0\relax
     \input \jobname.\indexname s
     \enddoublecolumns
-  \fi
+  }%
 }
 
 % These macros are used by the sorted index file itself.
@@ -7277,22 +7282,6 @@ might help (with 'rm \jobname.?? \jobname.??s')%
 }
 \let\Eraggedright\par
 
-\envdef\raggedleft{%
-  \parindent=0pt \leftskip0pt plus2em
-  \spaceskip.3333em \xspaceskip.5em \parfillskip=0pt
-  \hbadness=10000 % Last line will usually be underfull, so turn off
-                  % badness reporting.
-}
-\let\Eraggedleft\par
-
-\envdef\raggedcenter{%
-  \parindent=0pt \rightskip0pt plus1em \leftskip0pt plus1em
-  \spaceskip.3333em \xspaceskip.5em \parfillskip=0pt
-  \hbadness=10000 % Last line will usually be underfull, so turn off
-                  % badness reporting.
-}
-\let\Eraggedcenter\par
-
 
 % @quotation does normal linebreaking (hence we can't use \nonfillstart)
 % and narrows the margins.  We keep \parskip nonzero in general, since
@@ -7515,9 +7504,11 @@ might help (with 'rm \jobname.?? \jobname.??s')%
 % file; b) letting users define the frontmatter in as flexible order as
 % possible is desirable.
 %
-\def\copying{\checkenv{}\begingroup\scanargctxt\docopying}
-\def\docopying#1@end copying{\endgroup\def\copyingtext{#1}}
-%
+\def\copying{\checkenv{}\begingroup\macrobodyctxt\docopying}
+{\catcode`\ =\other
+\gdef\docopying#1@end copying{\endgroup\def\copyingtext{#1}}
+}
+
 \def\insertcopying{%
   \begingroup
     \parindent = 0pt  % paragraph indentation looks wrong on title page
@@ -7599,21 +7590,15 @@ might help (with 'rm \jobname.?? \jobname.??s')%
 
 \def\Edefun{\endgraf\medbreak}
 
-% \makedefun{deffn} creates \deffn, \deffnx and \Edeffn;
-% the only thing remaining is to define \deffnheader.
+% \makedefun{deffoo}{ (definition of \deffooheader) }
 %
+% Define \deffoo, \deffoox  \Edeffoo and \deffooheader.
 \def\makedefun#1{%
   \expandafter\let\csname E#1\endcsname = \Edefun
   \edef\temp{\noexpand\domakedefun
     \makecsname{#1}\makecsname{#1x}\makecsname{#1header}}%
   \temp
 }
-
-% \domakedefun \deffn \deffnx \deffnheader { (defn. of \deffnheader) }
-%
-% Define \deffn and \deffnx, without parameters.
-% \deffnheader has to be defined explicitly.
-%
 \def\domakedefun#1#2#3{%
   \envdef#1{%
     \startdefun
@@ -7646,74 +7631,51 @@ might help (with 'rm \jobname.?? \jobname.??s')%
   \fi\fi
 }
 
-% \dosubind {index}{topic}{subtopic}
-%
-% If SUBTOPIC is present, precede it with a space, and call \doind.
-% (At some time during the 20th century, this made a two-level entry in an
-% index such as the operation index.  Nobody seemed to notice the change in
-% behaviour though.)
-\def\dosubind#1#2#3{%
-  \def\thirdarg{#3}%
-  \ifx\thirdarg\empty
-    \doind{#1}{#2}%
-  \else
-    \doind{#1}{#2\space#3}%
-  \fi
-}
-
 % Untyped functions:
 
 % @deffn category name args
-\makedefun{deffn}{\deffngeneral{}}
-
-% @deffn category class name args
-\makedefun{defop}#1 {\defopon{#1\ \putwordon}}
-
-% \defopon {category on}class name args
-\def\defopon#1#2 {\deffngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} }
+\makedefun{deffn}#1 #2 #3\endheader{%
+  \doind{fn}{\code{#2}}%
+  \defname{#1}{}{#2}\magicamp\defunargs{#3\unskip}%
+}
 
-% \deffngeneral {subind}category name args
-%
-\def\deffngeneral#1#2 #3 #4\endheader{%
-  \dosubind{fn}{\code{#3}}{#1}%
-  \defname{#2}{}{#3}\magicamp\defunargs{#4\unskip}%
+% @defop category class name args
+\makedefun{defop}#1 {\defopheaderx{#1\ \putwordon}}
+\def\defopheaderx#1#2 #3 #4\endheader{%
+  \doind{fn}{\code{#3}\space\putwordon\ \code{#2}}%
+  \defname{#1\ \code{#2}}{}{#3}\magicamp\defunargs{#4\unskip}%
 }
 
 % Typed functions:
 
 % @deftypefn category type name args
-\makedefun{deftypefn}{\deftypefngeneral{}}
+\makedefun{deftypefn}#1 #2 #3 #4\endheader{%
+  \doind{fn}{\code{#3}}%
+  \doingtypefntrue
+  \defname{#1}{#2}{#3}\defunargs{#4\unskip}%
+}
 
 % @deftypeop category class type name args
-\makedefun{deftypeop}#1 {\deftypeopon{#1\ \putwordon}}
-
-% \deftypeopon {category on}class type name args
-\def\deftypeopon#1#2 {\deftypefngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} }
-
-% \deftypefngeneral {subind}category type name args
-%
-\def\deftypefngeneral#1#2 #3 #4 #5\endheader{%
-  \dosubind{fn}{\code{#4}}{#1}%
+\makedefun{deftypeop}#1 {\deftypeopheaderx{#1\ \putwordon}}
+\def\deftypeopheaderx#1#2 #3 #4 #5\endheader{%
+  \doind{fn}{\code{#4}\space\putwordon\ \code{#1\ \code{#2}}}%
   \doingtypefntrue
-  \defname{#2}{#3}{#4}\defunargs{#5\unskip}%
+  \defname{#1\ \code{#2}}{#3}{#4}\defunargs{#5\unskip}%
 }
 
 % Typed variables:
 
 % @deftypevr category type var args
-\makedefun{deftypevr}{\deftypecvgeneral{}}
+\makedefun{deftypevr}#1 #2 #3 #4\endheader{%
+  \doind{vr}{\code{#3}}%
+  \defname{#1}{#2}{#3}\defunargs{#4\unskip}%
+}
 
 % @deftypecv category class type var args
-\makedefun{deftypecv}#1 {\deftypecvof{#1\ \putwordof}}
-
-% \deftypecvof {category of}class type var args
-\def\deftypecvof#1#2 {\deftypecvgeneral{\putwordof\ \code{#2}}{#1\ \code{#2}} }
-
-% \deftypecvgeneral {subind}category type var args
-%
-\def\deftypecvgeneral#1#2 #3 #4 #5\endheader{%
-  \dosubind{vr}{\code{#4}}{#1}%
-  \defname{#2}{#3}{#4}\defunargs{#5\unskip}%
+\makedefun{deftypecv}#1 {\deftypecvheaderx{#1\ \putwordof}}
+\def\deftypecvheaderx#1#2 #3 #4 #5\endheader{%
+  \doind{vr}{\code{#4}\space\putwordof\ \code{#2}}%
+  \defname{#1\ \code{#2}}{#3}{#4}\defunargs{#5\unskip}%
 }
 
 % Untyped variables:
@@ -7722,10 +7684,8 @@ might help (with 'rm \jobname.?? \jobname.??s')%
 \makedefun{defvr}#1 {\deftypevrheader{#1} {} }
 
 % @defcv category class var args
-\makedefun{defcv}#1 {\defcvof{#1\ \putwordof}}
-
-% \defcvof {category of}class var args
-\def\defcvof#1#2 {\deftypecvof{#1}#2 {} }
+\makedefun{defcv}#1 {\defcvheaderx{#1\ \putwordof}}
+\def\defcvheaderx#1#2 {\deftypecvheaderx{#1}#2 {} }
 
 % Types:
 
@@ -7743,10 +7703,10 @@ might help (with 'rm \jobname.?? \jobname.??s')%
 \makedefun{defvar}{\defvrheader{\putwordDefvar} }
 \makedefun{defopt}{\defvrheader{\putwordDefopt} }
 \makedefun{deftypevar}{\deftypevrheader{\putwordDefvar} }
-\makedefun{defmethod}{\defopon\putwordMethodon}
-\makedefun{deftypemethod}{\deftypeopon\putwordMethodon}
-\makedefun{defivar}{\defcvof\putwordInstanceVariableof}
-\makedefun{deftypeivar}{\deftypecvof\putwordInstanceVariableof}
+\makedefun{defmethod}{\defopheaderx\putwordMethodon}
+\makedefun{deftypemethod}{\deftypeopheaderx\putwordMethodon}
+\makedefun{defivar}{\defcvheaderx\putwordInstanceVariableof}
+\makedefun{deftypeivar}{\deftypecvheaderx\putwordInstanceVariableof}
 
 % \defname, which formats the name of the @def (not the args).
 % #1 is the category, such as "Function".
@@ -7765,9 +7725,7 @@ might help (with 'rm \jobname.?? \jobname.??s')%
   \rettypeownlinefalse
   \ifdoingtypefn  % doing a typed function specifically?
     % then check user option for putting return type on its own line:
-    \expandafter\ifx\csname SETtxideftypefnnl\endcsname\relax \else
-      \rettypeownlinetrue
-    \fi
+    \ifflagclear{txideftypefnnl}{}{\rettypeownlinetrue}%
   \fi
   %
   % How we'll format the category name.  Putting it in brackets helps
@@ -7832,30 +7790,18 @@ might help (with 'rm \jobname.?? \jobname.??s')%
     \fi           % no return type
     #3% output function name
   }%
-  {\rm\enskip}% hskip 0.5 em of \rmfont
+  \ifflagclear{txidefnamenospace}{%
+    {\rm\enskip}% hskip 0.5 em of \rmfont
+  }{}%
   %
   \boldbrax
   % arguments will be output next, if any.
 }
 
-% Print arguments in slanted roman (not ttsl), inconsistently with using
-% tt for the name.  This is because literal text is sometimes needed in
-% the argument list (groff manual), and ttsl and tt are not very
-% distinguishable.  Prevent hyphenation at `-' chars.
-%
+% Print arguments.  Use slanted for @def*, typewriter for @deftype*.
 \def\defunargs#1{%
-  % use sl by default (not ttsl),
-  % tt for the names.
-  \df \sl \hyphenchar\font=0
-  %
-  % On the other hand, if an argument has two dashes (for instance), we
-  % want a way to get ttsl.  We used to recommend @var for that, so
-  % leave the code in, but it's strange for @var to lead to typewriter.
-  % Nowadays we recommend @code, since the difference between a ttsl hyphen
-  % and a tt hyphen is pretty tiny.  @code also disables ?` !`.
-  \def\var##1{{\setregularquotes\ttslanted{##1}}}%
+  \df \ifdoingtypefn \tt \else \sl \fi
   #1%
-  \sl\hyphenchar\font=45
 }
 
 % We want ()&[] to print specially on the defun line.
@@ -7874,9 +7820,12 @@ might help (with 'rm \jobname.?? \jobname.??s')%
 % so TeX would otherwise complain about undefined control sequence.
 {
   \activeparens
-  \global\let(=\lparen \global\let)=\rparen
-  \global\let[=\lbrack \global\let]=\rbrack
-  \global\let& = \&
+  \gdef\defcharsdefault{%
+    \let(=\lparen \let)=\rparen
+    \let[=\lbrack \let]=\rbrack
+    \let& = \&%
+  }
+  \globaldefs=1 \defcharsdefault
 
   \gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb}
   \gdef\magicamp{\let&=\amprm}
@@ -8060,24 +8009,17 @@ might help (with 'rm \jobname.?? \jobname.??s')%
   \catcode`\_=\other
   \catcode`\|=\other
   \catcode`\~=\other
-  \passthroughcharstrue
-}
-
-\def\scanargctxt{% used for copying and captions, not macros.
-  \scanctxt
   \catcode`\@=\other
-  \catcode`\\=\other
   \catcode`\^^M=\other
+  \catcode`\\=\active
+  \passthroughcharstrue
 }
 
-\def\macrobodyctxt{% used for @macro definitions
+\def\macrobodyctxt{% used for @macro definitions and @copying
   \scanctxt
   \catcode`\ =\other
-  \catcode`\@=\other
   \catcode`\{=\other
   \catcode`\}=\other
-  \catcode`\^^M=\other
-  \usembodybackslash
 }
 
 % Used when scanning braced macro arguments.  Note, however, that catcode
@@ -8086,14 +8028,10 @@ might help (with 'rm \jobname.?? \jobname.??s')%
 \def\macroargctxt{%
   \scanctxt
   \catcode`\ =\active
-  \catcode`\@=\other
-  \catcode`\^^M=\other
-  \catcode`\\=\active
 }
 
 \def\macrolineargctxt{% used for whole-line arguments without braces
   \scanctxt
-  \catcode`\@=\other
   \catcode`\{=\other
   \catcode`\}=\other
 }
@@ -8137,7 +8075,7 @@ might help (with 'rm \jobname.?? \jobname.??s')%
      \global\expandafter\let\csname ismacro.\the\macname\endcsname=1%
      \addtomacrolist{\the\macname}%
   \fi
-  \begingroup \macrobodyctxt
+  \begingroup \macrobodyctxt \usembodybackslash
   \ifrecursive \expandafter\parsermacbody
   \else \expandafter\parsemacbody
   \fi}
@@ -8941,7 +8879,7 @@ might help (with 'rm \jobname.?? \jobname.??s')%
       % output the `[mynode]' via the macro below so it can be overridden.
       \xrefprintnodename\printedrefname
       %
-      \expandafter\ifx\csname SETtxiomitxrefpg\endcsname\relax
+      \ifflagclear{txiomitxrefpg}{%
         % But we always want a comma and a space:
         ,\space
         %
@@ -8956,7 +8894,7 @@ might help (with 'rm \jobname.?? \jobname.??s')%
                   \tokenafterxref ,%    @NL
         \else\ifx\tie\tokenafterxref ,% @tie
         \fi\fi\fi\fi\fi\fi
-      \fi
+      }{}%
     \fi\fi
   \fi
   \endlink
@@ -9604,7 +9542,7 @@ might help (with 'rm \jobname.?? \jobname.??s')%
 %
 \def\caption{\docaption\thiscaption}
 \def\shortcaption{\docaption\thisshortcaption}
-\def\docaption{\checkenv\float \bgroup\scanargctxt\defcaption}
+\def\docaption{\checkenv\float \bgroup\scanctxt\defcaption}
 \def\defcaption#1#2{\egroup \def#1{#2}}
 
 % The parameter is the control sequence identifying the counter we are
@@ -10324,9 +10262,9 @@ directory should work if nowhere else does.}
   % Given the value in \countUTFz as a Unicode code point, set \UTFviiiTmp
   % to the corresponding UTF-8 sequence.
   \gdef\parseXMLCharref{%
-    \ifnum\countUTFz < "A0\relax
+    \ifnum\countUTFz < "20\relax
       \errhelp = \EMsimple
-      \errmessage{Cannot define Unicode char value < 00A0}%
+      \errmessage{Cannot define Unicode char value < 0020}%
     \else\ifnum\countUTFz < "800\relax
       \parseUTFviiiA,%
       \parseUTFviiiB C\UTFviiiTwoOctetsName.,%
@@ -10396,6 +10334,103 @@ directory should work if nowhere else does.}
 % least make most of the characters not bomb out.
 %
 \def\unicodechardefs{%
+  \DeclareUnicodeCharacter{0020}{ } % space
+  \DeclareUnicodeCharacter{0021}{\char"21 }% % space to terminate number
+  \DeclareUnicodeCharacter{0022}{\char"22 }%
+  \DeclareUnicodeCharacter{0023}{\char"23 }%
+  \DeclareUnicodeCharacter{0024}{\char"24 }%
+  \DeclareUnicodeCharacter{0025}{\char"25 }%
+  \DeclareUnicodeCharacter{0026}{\char"26 }%
+  \DeclareUnicodeCharacter{0027}{\char"27 }%
+  \DeclareUnicodeCharacter{0028}{\char"28 }%
+  \DeclareUnicodeCharacter{0029}{\char"29 }%
+  \DeclareUnicodeCharacter{002A}{\char"2A }%
+  \DeclareUnicodeCharacter{002B}{\char"2B }%
+  \DeclareUnicodeCharacter{002C}{\char"2C }%
+  \DeclareUnicodeCharacter{002D}{\char"2D }%
+  \DeclareUnicodeCharacter{002E}{\char"2E }%
+  \DeclareUnicodeCharacter{002F}{\char"2F }%
+  \DeclareUnicodeCharacter{0030}{0}%
+  \DeclareUnicodeCharacter{0031}{1}%
+  \DeclareUnicodeCharacter{0032}{2}%
+  \DeclareUnicodeCharacter{0033}{3}%
+  \DeclareUnicodeCharacter{0034}{4}%
+  \DeclareUnicodeCharacter{0035}{5}%
+  \DeclareUnicodeCharacter{0036}{6}%
+  \DeclareUnicodeCharacter{0037}{7}%
+  \DeclareUnicodeCharacter{0038}{8}%
+  \DeclareUnicodeCharacter{0039}{9}%
+  \DeclareUnicodeCharacter{003A}{\char"3A }%
+  \DeclareUnicodeCharacter{003B}{\char"3B }%
+  \DeclareUnicodeCharacter{003C}{\char"3C }%
+  \DeclareUnicodeCharacter{003D}{\char"3D }%
+  \DeclareUnicodeCharacter{003E}{\char"3E }%
+  \DeclareUnicodeCharacter{003F}{\char"3F }%
+  \DeclareUnicodeCharacter{0040}{\char"40 }%
+  \DeclareUnicodeCharacter{0041}{A}%
+  \DeclareUnicodeCharacter{0042}{B}%
+  \DeclareUnicodeCharacter{0043}{C}%
+  \DeclareUnicodeCharacter{0044}{D}%
+  \DeclareUnicodeCharacter{0045}{E}%
+  \DeclareUnicodeCharacter{0046}{F}%
+  \DeclareUnicodeCharacter{0047}{G}%
+  \DeclareUnicodeCharacter{0048}{H}%
+  \DeclareUnicodeCharacter{0049}{I}%
+  \DeclareUnicodeCharacter{004A}{J}%
+  \DeclareUnicodeCharacter{004B}{K}%
+  \DeclareUnicodeCharacter{004C}{L}%
+  \DeclareUnicodeCharacter{004D}{M}%
+  \DeclareUnicodeCharacter{004E}{N}%
+  \DeclareUnicodeCharacter{004F}{O}%
+  \DeclareUnicodeCharacter{0050}{P}%
+  \DeclareUnicodeCharacter{0051}{Q}%
+  \DeclareUnicodeCharacter{0052}{R}%
+  \DeclareUnicodeCharacter{0053}{S}%
+  \DeclareUnicodeCharacter{0054}{T}%
+  \DeclareUnicodeCharacter{0055}{U}%
+  \DeclareUnicodeCharacter{0056}{V}%
+  \DeclareUnicodeCharacter{0057}{W}%
+  \DeclareUnicodeCharacter{0058}{X}%
+  \DeclareUnicodeCharacter{0059}{Y}%
+  \DeclareUnicodeCharacter{005A}{Z}%
+  \DeclareUnicodeCharacter{005B}{\char"5B }%
+  \DeclareUnicodeCharacter{005C}{\char"5C }%
+  \DeclareUnicodeCharacter{005D}{\char"5D }%
+  \DeclareUnicodeCharacter{005E}{\char"5E }%
+  \DeclareUnicodeCharacter{005F}{\char"5F }%
+  \DeclareUnicodeCharacter{0060}{\char"60 }%
+  \DeclareUnicodeCharacter{0061}{a}%
+  \DeclareUnicodeCharacter{0062}{b}%
+  \DeclareUnicodeCharacter{0063}{c}%
+  \DeclareUnicodeCharacter{0064}{d}%
+  \DeclareUnicodeCharacter{0065}{e}%
+  \DeclareUnicodeCharacter{0066}{f}%
+  \DeclareUnicodeCharacter{0067}{g}%
+  \DeclareUnicodeCharacter{0068}{h}%
+  \DeclareUnicodeCharacter{0069}{i}%
+  \DeclareUnicodeCharacter{006A}{j}%
+  \DeclareUnicodeCharacter{006B}{k}%
+  \DeclareUnicodeCharacter{006C}{l}%
+  \DeclareUnicodeCharacter{006D}{m}%
+  \DeclareUnicodeCharacter{006E}{n}%
+  \DeclareUnicodeCharacter{006F}{o}%
+  \DeclareUnicodeCharacter{0070}{p}%
+  \DeclareUnicodeCharacter{0071}{q}%
+  \DeclareUnicodeCharacter{0072}{r}%
+  \DeclareUnicodeCharacter{0073}{s}%
+  \DeclareUnicodeCharacter{0074}{t}%
+  \DeclareUnicodeCharacter{0075}{u}%
+  \DeclareUnicodeCharacter{0076}{v}%
+  \DeclareUnicodeCharacter{0077}{w}%
+  \DeclareUnicodeCharacter{0078}{x}%
+  \DeclareUnicodeCharacter{0079}{y}%
+  \DeclareUnicodeCharacter{007A}{z}%
+  \DeclareUnicodeCharacter{007B}{\char"7B }%
+  \DeclareUnicodeCharacter{007C}{\char"7C }%
+  \DeclareUnicodeCharacter{007D}{\char"7D }%
+  \DeclareUnicodeCharacter{007E}{\char"7E }%
+  % \DeclareUnicodeCharacter{007F}{} % DEL
+  %
   \DeclareUnicodeCharacter{00A0}{\tie}%
   \DeclareUnicodeCharacter{00A1}{\exclamdown}%
   \DeclareUnicodeCharacter{00A2}{{\tcfont \char162}}% 0242=cent
@@ -11080,24 +11115,26 @@ directory should work if nowhere else does.}
 % provide a definition macro to replace/pass-through a Unicode character
 %
 \def\DeclareUnicodeCharacterNative#1#2{%
-  \catcode"#1=\active
-  \def\dodeclareunicodecharacternative##1##2##3{%
+  \ifnum"#1>"7F % only make non-ASCII chars active
+    \catcode"#1=\active
+    \def\dodeclareunicodecharacternative##1##2##3{%
+      \begingroup
+        \uccode`\~="##2\relax
+        \uppercase{\gdef~}{%
+          \ifpassthroughchars
+            ##1%
+          \else
+            ##3%
+          \fi
+        }
+      \endgroup
+    }
     \begingroup
-      \uccode`\~="##2\relax
-      \uppercase{\gdef~}{%
-        \ifpassthroughchars
-          ##1%
-        \else
-          ##3%
-        \fi
-      }
+      \uccode`\.="#1\relax
+      \uppercase{\def\UTFNativeTmp{.}}%
+      \expandafter\dodeclareunicodecharacternative\UTFNativeTmp{#1}{#2}%
     \endgroup
-  }
-  \begingroup
-    \uccode`\.="#1\relax
-    \uppercase{\def\UTFNativeTmp{.}}%
-    \expandafter\dodeclareunicodecharacternative\UTFNativeTmp{#1}{#2}%
-  \endgroup
+  \fi
 }
 
 % Native Unicode handling (XeTeX and LuaTeX) character replacing definition.
@@ -11276,7 +11313,7 @@ directory should work if nowhere else does.}
   \textleading = 12.5pt
   %
   \internalpagesizes{160mm}{120mm}%
-                    {\voffset}{\hoffset}%
+                    {\voffset}{-11.4mm}%
                     {\bindingoffset}{8pt}%
                     {210mm}{148mm}%
   %
@@ -11358,6 +11395,7 @@ directory should work if nowhere else does.}
 \message{and turning on texinfo input format.}
 
 \def^^L{\par} % remove \outer, so ^L can appear in an @comment
+\catcode`\^^K = 10 % treat vertical tab as whitespace
 
 % DEL is a comment character, in case @c does not suffice.
 \catcode`\^^? = 14
diff --git a/doc/misc/tramp.texi b/doc/misc/tramp.texi
index 12d4987726..0e55b6c1d2 100644
--- a/doc/misc/tramp.texi
+++ b/doc/misc/tramp.texi
@@ -50,13 +50,10 @@ This file documents @w{@value{tramp} @value{trampver}}, a 
remote file
 editing package for Emacs.
 
 @value{tramp} stands for ``Transparent Remote (file) Access, Multiple
-Protocol''.  This package provides remote file editing, similar to
-Ange FTP@.
-
-The difference is that Ange FTP uses FTP to transfer files between the
-local and the remote host, whereas @value{tramp} uses a combination of
-@command{rsh} and @command{rcp} or other work-alike programs, such as
-@command{ssh}/@command{scp}.
+Protocol''.  This package provides an easy, convenient, and consistent
+interface to editing remote files transparently, just as if they are
+local files.  This extends to editing, version control, @code{dired},
+and more.
 
 You can find the latest version of this document on the web at
 @uref{@value{trampurl}}.
@@ -182,10 +179,10 @@ interface to remote files as if they are local files.  
@value{tramp}'s
 transparency extends to editing, version control, and @code{dired}.
 
 @value{tramp} can access remote hosts using any number of access
-methods, such as @command{rsh}, @command{rlogin}, @command{telnet},
-and related programs.  If these programs can successfully pass
-@acronym{ASCII} characters, @value{tramp} can use them.
-@value{tramp} does not require or mandate 8-bit clean connections.
+methods, such as @command{ssh}, @command{scp}, @command{telnet}, and
+related programs.  If these programs can successfully pass
+@acronym{ASCII} characters, @value{tramp} can use them.  @value{tramp}
+does not require or mandate 8-bit clean connections.
 
 @value{tramp}'s most common access method is through @command{ssh}, a
 more secure alternative to @command{ftp} and other older access
@@ -233,10 +230,10 @@ first time connecting to that host, here's what happens:
 
 @itemize
 @item
-@value{tramp} invokes @samp{telnet @var{host}} or @samp{rsh @var{host}
--l @var{user}} and establishes an external process to connect to the
-remote host.  @value{tramp} communicates with the process through an
-Emacs buffer, which also shows output from the remote host.
+@value{tramp} invokes @samp{telnet @var{host}} or @samp{ssh -l
+@var{user} @var{host}} and establishes an external process to connect
+to the remote host.  @value{tramp} communicates with the process
+through an Emacs buffer, which also shows output from the remote host.
 
 @item
 The remote host may prompt for a login name (for @command{telnet}, for
@@ -246,7 +243,7 @@ followed by a newline.
 
 @item
 The remote host may then prompt for a password or passphrase (for
-@command{rsh} or for @command{telnet}).  @value{tramp} displays the
+@command{ssh} or for @command{telnet}).  @value{tramp} displays the
 password prompt in the minibuffer.  @value{tramp} then sends whatever
 is entered to the remote host, followed by a newline.
 
@@ -312,7 +309,7 @@ I hope this has provided you with a basic overview of what 
happens
 behind the scenes when you open a file with @value{tramp}.
 
 
-@c For the end user
+@c For the end user.
 @node Obtaining @value{tramp}
 @chapter Obtaining @value{tramp}
 @cindex obtaining @value{tramp}
@@ -670,6 +667,11 @@ may be used in your init file:
 (with-eval-after-load 'tramp (tramp-change-syntax 'simplified))
 @end lisp
 
+@vindex enable-remote-dir-locals
+Changing other variables via directory-local variables on a remote
+directory must be enabled by setting @code{enable-remote-dir-locals}
+to non-@code{nil}, @xref{Directory Variables, , , emacs}.
+
 
 @menu
 * Connection types::            Types of connections to remote hosts.
@@ -2430,7 +2432,7 @@ example below:
 @end lisp
 
 @vindex password-word-equivalents
-This user option is, by default, initialised from
+This user option is, by default, initialized from
 @code{password-word-equivalents} when @value{tramp} is loaded, and it
 is usually more convenient to add new passphrases to that user option
 instead of altering this user option.
@@ -2973,14 +2975,31 @@ where @samp{192.168.0.26} is the Android device's IP 
address.
 (@pxref{Predefined connection information}).
 
 @item
-@value{tramp} requires preserving @env{PATH} environment variable from
-user settings.  Android devices prefer @file{/system/xbin} path over
-@file{/system/bin}.  Both of these are set as follows:
+On the Android device the directory names are prefixed with an
+application specific prefix, which is
+@file{/data/data/com.termux/files/usr/bin} instead of @file{/usr/bin}
+in the @code{Termux} case.  You must adapt the file names in
+@code{tramp-remote-path}, for example via connection-local
+@ifinfo
+settings (@pxref{Connection Variables, , , emacs}):
+@end ifinfo
+@ifnotinfo
+settings:
+@end ifnotinfo
 
 @lisp
 @group
-(add-to-list 'tramp-remote-path 'tramp-own-remote-path)
-(add-to-list 'tramp-remote-path "/system/xbin")
+(connection-local-set-profile-variables
+ 'tramp-connection-local-termux-profile
+ `((tramp-remote-path
+    . ,(mapcar
+       (lambda (x)
+         (if (stringp x) (concat "/data/data/com.termux/files" x) x))
+       (copy-tree tramp-remote-path)))))
+
+(connection-local-set-profiles
+ '(:application tramp :machine "192.168.0.26")
+ 'tramp-connection-local-termux-profile)
 @end group
 @end lisp
 
@@ -2989,7 +3008,9 @@ When the Android device is not @samp{rooted}, specify a 
writable
 directory for temporary files:
 
 @lisp
-(add-to-list 'tramp-remote-process-environment "TMPDIR=$HOME")
+(add-to-list 'tramp-connection-properties
+             (list (regexp-quote "192.168.0.26")
+                  "tmpdir" "/data/data/com.termux/files/home/tmp"))
 @end lisp
 
 @item
@@ -3017,11 +3038,17 @@ the previous example, fix the connection properties as 
follows:
 @group
 (add-to-list 'tramp-connection-properties
              (list (regexp-quote "android") "remote-shell" "sh"))
+(add-to-list 'tramp-connection-properties
+             (list (regexp-quote "android")
+                  "tmpdir" "/data/data/com.termux/files/home/tmp"))
+(connection-local-set-profiles
+ '(:application tramp :machine "android")
+ 'tramp-connection-local-termux-profile)
 @end group
 @end lisp
 
 @noindent
-Open a remote connection with a more concise command @kbd{C-x C-f
+Open a remote connection with the more concise command @kbd{C-x C-f
 @trampfn{ssh,android,} @key{RET}}.
 @end itemize
 
@@ -3124,6 +3151,14 @@ auto-saved files to the same directory as the original 
file.
 Alternatively, set the user option @code{tramp-auto-save-directory}
 to direct all auto saves to that location.
 
+@c Since Emacs 29.
+@vindex remote-file-name-inhibit-auto-save-visited
+An alternative to @code{auto-save-mode} is
+@code{auto-save-visited-mode}.  In this mode, auto-saving is identical
+to explicit saving.  If you want to disable this behavior for remote
+files, set user option
+@code{remote-file-name-inhibit-auto-save-visited} to non-@code{nil}.
+
 @vindex lock-file-name-transforms
 And still more issues to handle.  Since @w{Emacs 28}, file locks use a
 similar user option as auto-save files, called
@@ -3373,7 +3408,7 @@ names.  Beside the @code{default} value, @var{syntax} can 
be
 @item @code{simplified}
 @cindex simplified syntax
 
-The remote file name syntax is similar to the syntax used by Ange FTP@.
+This remote file name syntax is similar to the syntax used by Ange FTP@.
 A remote file name has the form
 @code{@value{prefix}user@@host@value{postfix}path/to/file}.  The
 @code{user@@} part is optional, and the method is determined by
@@ -3385,7 +3420,7 @@ A remote file name has the form
 @clear unified
 @set separate
 @include trampver.texi
-The remote file name syntax is similar to the syntax used by XEmacs.
+This remote file name syntax originated in the XEmacs text editor.
 A remote file name has the form
 @code{@trampfn{method,user@@host,path/to/file}}.  The @code{method}
 and @code{user@@} parts are optional.
@@ -4791,9 +4826,12 @@ authentication delays.  During these operations, 
@value{tramp}'s
 responsiveness slows down.  Some suggestions within the scope of
 @value{tramp}'s settings include:
 
+@itemize @minus
+@item
 Use an external method, such as @option{scp}, which are faster than
-internal methods.
+internal methods for large files.
 
+@item
 Keep the file @code{tramp-persistency-file-name}, which is where
 @value{tramp} caches remote information about hosts and files.  Caching
 is enabled by default.  Don't disable it.
@@ -4804,6 +4842,7 @@ files are not independently updated outside 
@value{tramp}'s control.
 That cache cleanup will be necessary if the remote directories or
 files are updated independent of @value{tramp}.
 
+@item
 Disable version control to avoid delays:
 
 @lisp
@@ -4823,9 +4862,17 @@ about, for example:
 (setq vc-handled-backends '(SVN Git))
 @end lisp
 
+@item
+@vindex remote-file-name-inhibit-locks
+Disable file locks.  Set @code{remote-file-name-inhibit-locks} to
+@code{t} if you know that different Emacs sessions are not modifying
+the same remote file.
+
+@item
 Disable excessive traces.  Set @code{tramp-verbose} to 3 or lower,
 default being 3.  Increase trace levels temporarily when hunting for
 bugs.
+@end itemize
 
 
 @item
@@ -5325,13 +5372,6 @@ minibuffer:
   (before my-minibuffer-complete activate)
   (expand-abbrev))
 @end group
-
-@group
-;; If you use partial-completion-mode
-(defadvice PC-do-completion
-  (before my-PC-do-completion activate)
-  (expand-abbrev))
-@end group
 @end lisp
 
 The reduced typing: @kbd{C-x C-f xy @key{TAB}}.
@@ -5621,6 +5661,7 @@ Disable @value{tramp} file name completion:
 (customize-set-variable 'ido-enable-tramp-completion nil)
 @end lisp
 
+@c Obsolete since Emacs 29.1.
 @item
 @file{rlogin.el}
 
@@ -5679,10 +5720,19 @@ local host's root directory as @file{/ssh:example.com:}.
 To unload @value{tramp}, type @kbd{M-x tramp-unload-tramp @key{RET}}.
 Unloading @value{tramp} resets Ange FTP plugins also.
 @end itemize
+
+
+@item
+What is the difference between Ange FTP and @value{tramp}?
+
+The difference is that Ange FTP uses @command{ftp} to transfer files
+between the local and the remote host, whereas @value{tramp} uses a
+combination of @command{ssh} and @command{scp} or other work-alike
+programs.
 @end itemize
 
 
-@c For the developer
+@c For the developer.
 @node Files directories and localnames
 @chapter How file names, directories and localnames are mangled and managed
 
@@ -5811,15 +5861,15 @@ The verbosity levels are
 @*@indent @w{ 4}  activities
 @*@indent @w{ 5}  internal
 @*@indent @w{ 6}  sent and received strings
-@*@indent @w{ 7}  file caching
-@*@indent @w{ 8}  connection properties
+@*@indent @w{ 7}  connection properties
+@*@indent @w{ 8}  file caching
 @*@indent @w{ 9}  test commands
 @*@indent @w{10}  traces (huge)
 @*@indent @w{11}  call traces (maintainer only)
 
 With @code{tramp-verbose} greater than or equal to 4, messages are
 also written to a @value{tramp} debug buffer.  Such debug buffers are
-essential to bug and problem analyses.  For @value{tramp} bug reports,
+essential to bug and problem analyzes.  For @value{tramp} bug reports,
 set the @code{tramp-verbose} level to 6 (@pxref{Bug Reports}).
 
 The debug buffer is in
diff --git a/doc/misc/transient.texi b/doc/misc/transient.texi
index d634ad5197..24c3090ef7 100644
--- a/doc/misc/transient.texi
+++ b/doc/misc/transient.texi
@@ -47,9 +47,9 @@ General Public License for more details.
 Taking inspiration from prefix keys and prefix arguments, Transient
 implements a similar abstraction involving a prefix command, infix
 arguments and suffix commands.  We could call this abstraction a
-``transient command'', but because it always involves at least two
+“transient command”, but because it always involves at least two
 commands (a prefix and a suffix) we prefer to call it just a
-``transient''.
+“transient”.
 
 When the user calls a transient prefix command, a transient
 (temporary) keymap is activated, which binds the transient's infix
@@ -97,7 +97,7 @@ Usage
 * Getting Help for Suffix Commands::
 * Enabling and Disabling Suffixes::
 * Other Commands::
-* Other Options::
+* Configuration::
 
 Defining New Commands
 
@@ -144,20 +144,20 @@ Related Abstractions and Packages
 Taking inspiration from prefix keys and prefix arguments, Transient
 implements a similar abstraction involving a prefix command, infix
 arguments and suffix commands.  We could call this abstraction a
-``transient command'', but because it always involves at least two
+“transient command”, but because it always involves at least two
 commands (a prefix and a suffix) we prefer to call it just a
-``transient''.
+“transient”.
 
+@cindex transient prefix command
 @quotation
 Transient keymaps are a feature provided by Emacs.  Transients as
 implemented by this package involve the use of transient keymaps.
 
-@cindex transient prefix command
 Emacs provides a feature that it calls @dfn{prefix commands}.  When we
-talk about ``prefix commands'' in this manual, then we mean our own kind
-of ``prefix commands'', unless specified otherwise.  To avoid ambiguity
+talk about “prefix commands” in this manual, then we mean our own kind
+of “prefix commands”, unless specified otherwise.  To avoid ambiguity
 we sometimes use the terms @dfn{transient prefix command} for our kind and
-``regular prefix command'' for the Emacs' kind.
+“regular prefix command” for Emacs' kind.
 
 @end quotation
 
@@ -208,7 +208,7 @@ looks a bit like this:
 
 @quotation
 This is a simplified version of @code{magit-tag}.  Info manuals do not
-support images or colored text, so the above ``screenshot'' lacks some
+support images or colored text, so the above “screenshot” lacks some
 information; in practice you would be able to tell whether the
 arguments @code{--force} and @code{--annotate} are enabled or not based on 
their
 color.
@@ -216,11 +216,11 @@ color.
 @end quotation
 
 @cindex command dispatchers
-Transient can be used to implement simple ``command dispatchers''.  The
+Transient can be used to implement simple “command dispatchers”.  The
 main benefit then is that the user can see all the available commands
 in a popup buffer.  That is useful by itself because it frees the user
 from having to remember all the keys that are valid after a certain
-prefix key or command.  Magit's @code{magit-dispatch} (on @code{C-x M-g}) 
command is
+prefix key or command.  Magit's @code{magit-dispatch} (on @kbd{C-x M-g}) 
command is
 an example of using Transient to merely implement a command
 dispatcher.
 
@@ -235,22 +235,22 @@ argument means to a certain command.
 
 Transient suffix commands, on the other hand, can accept dozens of
 different arguments without the user having to remember anything.
-When using Transient, one can call a command with arguments that
-are just as complex as when calling the same function non-interactively
+When using Transient, one can call a command with arguments that are
+just as complex as when calling the same function non-interactively
 from Lisp.
 
 Invoking a transient command with arguments is similar to invoking a
 command in a shell with command-line completion and history enabled.
 One benefit of the Transient interface is that it remembers history
-not only on a global level (``this command was invoked using these
-arguments, and previously it was invoked using those other arguments''),
+not only on a global level (“this command was invoked using these
+arguments, and previously it was invoked using those other arguments”),
 but also remembers the values of individual arguments independently.
 @xref{Using History}.
 
-After a transient prefix command is invoked, @kbd{C-h @var{key}} can be used to
-show the documentation for the infix or suffix command that @kbd{@var{key}} is
+After a transient prefix command is invoked, @kbd{C-h @var{KEY}} can be used to
+show the documentation for the infix or suffix command that @kbd{@var{KEY}} is
 bound to (@pxref{Getting Help for Suffix Commands}), and infixes and
-suffixes can be removed from the transient using @kbd{C-x l @var{key}}.  
Infixes
+suffixes can be removed from the transient using @kbd{C-x l @var{KEY}}.  
Infixes
 and suffixes that are disabled by default can be enabled the same way.
 @xref{Enabling and Disabling Suffixes}.
 
@@ -273,11 +273,12 @@ to implementing yet).
 * Getting Help for Suffix Commands::
 * Enabling and Disabling Suffixes::
 * Other Commands::
-* Other Options::
+* Configuration::
 @end menu
 
 @node Invoking Transients
 @section Invoking Transients
+
 @cindex invoking transients
 
 A transient prefix command is invoked like any other command by
@@ -290,9 +291,9 @@ disabled while the transient state is in effect.
 There are two kinds of commands that are available after invoking a
 transient prefix command; infix and suffix commands.  Infix commands
 set some value (which is then shown in a popup buffer), without
-leaving the transient.  Suffix commands, on the other hand, usually quit
-the transient and they may use the values set by the infix commands,
-i.e.@: the infix @strong{arguments}.
+leaving the transient.  Suffix commands, on the other hand, usually
+quit the transient and they may use the values set by the infix
+commands, i.e., the infix @strong{arguments}.
 
 Instead of setting arguments to be used by a suffix command, infix
 commands may also set some value by side-effect, e.g., by setting the
@@ -300,11 +301,12 @@ value of some variable.
 
 @node Aborting and Resuming Transients
 @section Aborting and Resuming Transients
+
 @cindex aborting transients
 @cindex resuming transients
 
 @cindex quit transient
-To quit the transient without invoking a suffix command press @code{C-g}.
+To quit the transient without invoking a suffix command press @kbd{C-g}.
 
 Key bindings in transient keymaps may be longer than a single event.
 After pressing a valid prefix key, all commands whose bindings do not
@@ -314,7 +316,7 @@ prefix key, but not the complete transient).
 
 A transient prefix command can be bound as a suffix of another
 transient.  Invoking such a suffix replaces the current transient
-state with a new transient state, i.e.@: the available bindings change
+state with a new transient state, i.e., the available bindings change
 and the information displayed in the popup buffer is updated
 accordingly.  Pressing @kbd{C-g} while a nested transient is active only
 quits the innermost transient, causing a return to the previous
@@ -325,13 +327,12 @@ the latter, then you can later resume the stack of 
transients using
 @kbd{M-x transient-resume}.
 
 @table @asis
+@item @kbd{C-g} (@code{transient-quit-seq})
+@itemx @kbd{C-g} (@code{transient-quit-one})
 @kindex C-g
-@findex transient-quit-seq
-@item @kbd{C-g} @tie{}@tie{}@tie{}@tie{}(@code{transient-quit-seq})
 @kindex C-g
+@findex transient-quit-seq
 @findex transient-quit-one
-@item @kbd{C-g} @tie{}@tie{}@tie{}@tie{}(@code{transient-quit-one})
-
 This key quits the currently active incomplete key sequence, if any,
 or else the current transient.  When quitting the current transient,
 it returns to the previous transient, if any.
@@ -342,22 +343,20 @@ To learn how to get that binding back see 
@code{transient-bind-q-to-quit}'s
 doc string.
 
 @table @asis
+@item @kbd{C-q} (@code{transient-quit-all})
 @kindex C-q
 @findex transient-quit-all
-@item @kbd{C-q} @tie{}@tie{}@tie{}@tie{}(@code{transient-quit-all})
-
 This command quits the currently active incomplete key sequence, if
 any, and all transients, including the active transient and all
 suspended transients, if any.
 
+@item @kbd{C-z} (@code{transient-suspend})
 @kindex C-z
 @findex transient-suspend
-@item @kbd{C-z} @tie{}@tie{}@tie{}@tie{}(@code{transient-suspend})
-
 Like @code{transient-quit-all}, this command quits an incomplete key
 sequence, if any, and all transients.  Additionally, it saves the
 stack of transients so that it can easily be resumed (which is
-particularly useful if you quickly need to do ``something else'', and
+particularly useful if you quickly need to do “something else” and
 the stack is deeper than a single transient, and/or you have already
 changed the values of some infix arguments).
 
@@ -365,43 +364,39 @@ Note that only a single stack of transients can be saved 
at a time.
 If another stack is already saved, then saving a new stack discards
 the previous stack.
 
-@kindex M-x transient-resume
+@item @kbd{M-x transient-resume}
 @findex transient-resume
-@item @kbd{M-x transient-resume} 
@tie{}@tie{}@tie{}@tie{}(@code{transient-resume})
-
 This command resumes the previously suspended stack of transients,
 if any.
 @end table
 
 @node Common Suffix Commands
 @section Common Suffix Commands
+
 @cindex common suffix commands
 
 A few shared suffix commands are available in all transients.  These
 suffix commands are not shown in the popup buffer by default.
 
-This includes the aborting commands mentioned in the previous section, as
-well as some other commands that are all bound to @kbd{C-x @var{key}}.  After
+This includes the aborting commands mentioned in the previous section,
+as well as some other commands that are all bound to @kbd{C-x @var{KEY}}.  
After
 @kbd{C-x} is pressed, a section featuring all these common commands is
 temporarily shown in the popup buffer.  After invoking one of them,
-the section disappears again.  Note, however, that one of these commands
-is described as ``Show common permanently''; invoke that if you want the
-common commands to always be shown for all transients.
+the section disappears again.  Note, however, that one of these
+commands is described as “Show common permanently”; invoke that if you
+want the common commands to always be shown for all transients.
 
 @table @asis
+@item @kbd{C-x t} (@code{transient-toggle-common})
 @kindex C-x t
 @findex transient-toggle-common
-@item @kbd{C-x t} @tie{}@tie{}@tie{}@tie{}(@code{transient-toggle-common})
-
 This command toggles whether the generic commands that are common to
 all transients are always displayed or only after typing the
 incomplete prefix key sequence @kbd{C-x}.  This only affects the current
 Emacs session.
-
 @end table
 
 @defopt transient-show-common-commands
-
 This option controls whether shared suffix commands are shown
 alongside the transient-specific infix and suffix commands.  By
 default, the shared commands are not shown to avoid overwhelming
@@ -412,14 +407,15 @@ commands.  The value of this option can be changed for 
the current
 Emacs session by typing @kbd{C-x t} while a transient is active.
 @end defopt
 
-The other common commands are described in either the previous or
-in one of the following sections.
+The other common commands are described in either the previous or in
+one of the following sections.
 
 Some of Transient's key bindings differ from the respective bindings
 of Magit-Popup; see @ref{FAQ} for more information.
 
 @node Saving Values
 @section Saving Values
+
 @cindex saving values of arguments
 
 After setting the infix arguments in a transient, the user can save
@@ -429,8 +425,7 @@ Most transients will start out with the saved arguments 
when they are
 invoked.  There are a few exceptions, though.  Some transients are
 designed so that the value that they use is stored externally as the
 buffer-local value of some variable.  Invoking such a transient again
-uses the buffer-local value.@footnote{
-@code{magit-diff} and @code{magit-log} are two prominent examples, and their
+uses the buffer-local value. @footnote{@code{magit-diff} and @code{magit-log} 
are two prominent examples, and their
 handling of buffer-local values is actually a bit more complicated
 than outlined above and even customizable.}
 
@@ -440,30 +435,32 @@ history.  That value won't be used when the transient is 
next invoked,
 but it is easily accessible (@pxref{Using History}).
 
 @table @asis
+@item @kbd{C-x s} (@code{transient-set})
 @kindex C-x s
 @findex transient-set
-@item @kbd{C-x s} @tie{}@tie{}@tie{}@tie{}(@code{transient-set})
-
 This command saves the value of the active transient for this Emacs
 session.
 
+@item @kbd{C-x C-s} (@code{transient-save})
 @kindex C-x C-s
 @findex transient-save
-@item @kbd{C-x C-s} @tie{}@tie{}@tie{}@tie{}(@code{transient-save})
-
 Save the value of the active transient persistently across Emacs
 sessions.
 
+@item @kbd{C-x C-k} (@code{transient-save})
+@kindex C-x C-k
+@findex transient-save
+Clear the set and saved value of the active transient.
 @end table
 
 @defopt transient-values-file
-
 This option names the file that is used to persist the values of
 transients between Emacs sessions.
 @end defopt
 
 @node Using History
 @section Using History
+
 @cindex value history
 
 Every time the user invokes a suffix command the transient's current
@@ -472,32 +469,28 @@ same way one can cycle through the history of commands 
that read
 user-input in the minibuffer.
 
 @table @asis
+@item @kbd{C-M-p} (@code{transient-history-prev})
+@itemx @kbd{C-x p}
 @kindex C-M-p
-@findex transient-history-prev
-@item @kbd{C-M-p} @tie{}@tie{}@tie{}@tie{}(@code{transient-history-prev})
 @kindex C-x p
 @findex transient-history-prev
-@item @kbd{C-x p} @tie{}@tie{}@tie{}@tie{}(@code{transient-history-prev})
-
 This command switches to the previous value used for the active
 transient.
 
+@item @kbd{C-M-n} (@code{transient-history-next})
+@itemx @kbd{C-x n}
 @kindex C-M-n
-@findex transient-history-next
-@item @kbd{C-M-n} @tie{}@tie{}@tie{}@tie{}(@code{transient-history-next})
 @kindex C-x n
 @findex transient-history-next
-@item @kbd{C-x n} @tie{}@tie{}@tie{}@tie{}(@code{transient-history-next})
-
 This command switches to the next value used for the active
 transient.
 @end table
 
 In addition to the transient-wide history, Transient of course
 supports per-infix history.  When an infix reads user-input using the
-minibuffer, the user can use the regular minibuffer history
-commands to cycle through previously used values.  Usually the same
-keys as those mentioned above are bound to those commands.
+minibuffer, the user can use the regular minibuffer history commands
+to cycle through previously used values.  Usually the same keys as
+those mentioned above are bound to those commands.
 
 Authors of transients should arrange for different infix commands that
 read the same kind of value to also use the same history key
@@ -506,19 +499,18 @@ read the same kind of value to also use the same history 
key
 Both kinds of history are saved to a file when Emacs is exited.
 
 @defopt transient-history-file
-
 This option names the file that is used to persist the history of
 transients and their infixes between Emacs sessions.
 @end defopt
 
 @defopt transient-history-limit
-
 This option controls how many history elements are kept at the time
 the history is saved in @code{transient-history-file}.
 @end defopt
 
 @node Getting Help for Suffix Commands
 @section Getting Help for Suffix Commands
+
 @cindex getting help
 
 Transients can have many suffixes and infixes that the user might not
@@ -527,14 +519,13 @@ provides access to the documentation directly from the 
active
 transient.
 
 @table @asis
+@item @kbd{C-h} (@code{transient-help})
 @kindex C-h
 @findex transient-help
-@item @kbd{C-h} @tie{}@tie{}@tie{}@tie{}(@code{transient-help})
-
-This command enters help mode.  When help mode is active,
-typing a key shows information about the suffix command that the key
-is normally bound to (instead of invoking it).  Pressing @kbd{C-h} a
-second time shows information about the @emph{prefix} command.
+This command enters help mode.  When help mode is active, typing a
+key shows information about the suffix command that the key normally
+is bound to (instead of invoking it).  Pressing @kbd{C-h} a second time
+shows information about the @emph{prefix} command.
 
 After typing a key, the stack of transient states is suspended and
 information about the suffix command is shown instead.  Typing @kbd{q} in
@@ -550,6 +541,7 @@ non-infix suffixes this is usually appropriate.
 
 @node Enabling and Disabling Suffixes
 @section Enabling and Disabling Suffixes
+
 @cindex enabling suffixes
 @cindex disabling suffixes
 
@@ -571,7 +563,7 @@ displayed at any level.
 
 The levels of individual transients and/or their individual suffixes
 can be changed interactively, by invoking the transient and then
-pressing @kbd{C-x l} to enter the ``edit'' mode, see below.
+pressing @kbd{C-x l} to enter the “edit” mode, see below.
 
 The default level for both transients and their suffixes is 4.  The
 @code{transient-default-level} option only controls the default for
@@ -582,23 +574,20 @@ very important suffixes on a lower level, so that they 
remain
 available even if the user lowers the transient level.
 
 @defopt transient-default-level
-
 This option controls which suffix levels are made available by
 default.  It sets the transient-level for transients for which the
 user has not set that individually.
 @end defopt
 
 @defopt transient-levels-file
-
 This option names the file that is used to persist the levels of
 transients and their suffixes between Emacs sessions.
 @end defopt
 
 @table @asis
+@item @kbd{C-x l} (@code{transient-set-level})
 @kindex C-x l
 @findex transient-set-level
-@item @kbd{C-x l} @tie{}@tie{}@tie{}@tie{}(@code{transient-set-level})
-
 This command enters edit mode.  When edit mode is active, then all
 infixes and suffixes that are currently usable are displayed along
 with their levels.  The colors of the levels indicate whether they
@@ -616,9 +605,9 @@ To change the transient level press @kbd{C-x l} again.
 To exit edit mode press @kbd{C-g}.
 
 Note that edit mode does not display any suffixes that are not
-currently usable.  @code{magit-rebase}, for example, shows different suffixes
-depending on whether a rebase is already in progress or not.  The
-predicates also apply in edit mode.
+currently usable.  @code{magit-rebase}, for example, shows different
+suffixes depending on whether a rebase is already in progress or
+not.  The predicates also apply in edit mode.
 
 Therefore, to control which suffixes are available given a certain
 state, you have to make sure that that state is currently active.
@@ -633,27 +622,29 @@ following commands.  These commands are never shown in 
the transient
 window, and the key bindings are the same as for @code{scroll-up-command} and
 @code{scroll-down-command} in other buffers.
 
-@findex transient-scroll-up arg
 @deffn Command transient-scroll-up arg
-
-This command scrolls text of transient popup window upward @var{arg}
-lines.  If @var{arg} is @code{nil}, then it scrolls near full screen.  This
+This command scrolls text of transient popup window upward @var{ARG}
+lines.  If @var{ARG} is @code{nil}, then it scrolls near full screen.  This
 is a wrapper around @code{scroll-up-command} (which see).
 @end deffn
 
-@findex transient-scroll-down arg
 @deffn Command transient-scroll-down arg
-
-This command scrolls text of transient popup window down @var{arg}
-lines.  If @var{arg} is @code{nil}, then it scrolls near full screen.  This
+This command scrolls text of transient popup window down @var{ARG}
+lines.  If @var{ARG} is @code{nil}, then it scrolls near full screen.  This
 is a wrapper around @code{scroll-down-command} (which see).
 @end deffn
 
-@node Other Options
-@section Other Options
+@node Configuration
+@section Configuration
 
-@defopt transient-show-popup
+More options are described in @ref{Common Suffix Commands}, in @ref{Saving 
Values}, in @ref{Using History} and in @ref{Enabling and Disabling Suffixes}.
+
+@anchor{Essential Options}
+@subheading Essential Options
+
+Also see @ref{Common Suffix Commands}.
 
+@defopt transient-show-popup
 This option controls whether the current transient's infix and
 suffix commands are shown in the popup buffer.
 
@@ -662,13 +653,11 @@ suffix commands are shown in the popup buffer.
 If @code{t} (the default) then the popup buffer is shown as soon as a
 transient prefix command is invoked.
 
-
 @item
 If @code{nil}, then the popup buffer is not shown unless the user
 explicitly requests it, by pressing an incomplete prefix key
 sequence.
 
-
 @item
 If a number, then the a brief one-line summary is shown instead of
 the popup buffer.  If zero or negative, then not even that summary
@@ -676,45 +665,43 @@ is shown; only the pressed key itself is shown.
 
 The popup is shown when the user explicitly requests it by
 pressing an incomplete prefix key sequence.  Unless this is zero,
-the popup is shown after that many seconds of inactivity
-(using the absolute value).
+the popup is shown after that many seconds of inactivity (using
+the absolute value).
 @end itemize
 @end defopt
 
 @defopt transient-enable-popup-navigation
-
 This option controls whether navigation commands are enabled in the
 transient popup buffer.
 
 While a transient is active the transient popup buffer is not the
 current buffer, making it necessary to use dedicated commands to act
 on that buffer itself.  This is disabled by default.  If this option
-is non-nil, then the following features are available:
+is non-@code{nil}, then the following features are available:
 
 @itemize
 @item
-@key{UP} moves the cursor to the previous suffix.
-@key{DOWN} moves the cursor to the next suffix.
-@key{RET} invokes the suffix the cursor is on.
-
+@kbd{@key{UP}} moves the cursor to the previous suffix.
 @item
-@key{mouse-1} invokes the clicked on suffix.
-
+@kbd{@key{DOWN}} moves the cursor to the next suffix.
+@item
+@kbd{@key{RET}} invokes the suffix the cursor is on.
+@item
+@kbd{mouse-1} invokes the clicked on suffix.
 @item
 @kbd{C-s} and @kbd{C-r} start isearch in the popup buffer.
 @end itemize
 @end defopt
 
 @defopt transient-display-buffer-action
-
 This option specifies the action used to display the transient popup
 buffer.  The transient popup buffer is displayed in a window using
-@code{(display-buffer @var{buffer} transient-display-buffer-action)}.
+@code{(display-buffer @var{BUFFER} transient-display-buffer-action)}.
 
-The value of this option has the form @code{(@var{function} . @var{alist})},
-where @var{function} is a function or a list of functions.  Each such
+The value of this option has the form @code{(@var{FUNCTION} . @var{ALIST})},
+where @var{FUNCTION} is a function or a list of functions.  Each such
 function should accept two arguments: a buffer to display and an
-alist of the same form as @var{alist}.  @xref{Choosing Window,,,elisp,},
+alist of the same form as @var{ALIST}.  @xref{Choosing Window,,,elisp,},
 for details.
 
 The default is:
@@ -727,7 +714,7 @@ The default is:
 @end lisp
 
 This displays the window at the bottom of the selected frame.
-Another useful @var{function} is @code{display-buffer-below-selected}, which
+Another useful @var{FUNCTION} is @code{display-buffer-below-selected}, which
 is what @code{magit-popup} used by default.  For more alternatives see
 @ref{Buffer Display Action Functions,,,elisp,}, and see @ref{Buffer Display
 Action Alists,,,elisp,}.
@@ -748,8 +735,20 @@ If you change the value of this option, then you might also
 want to change the value of @code{transient-mode-line-format}.
 @end defopt
 
-@defopt transient-mode-line-format
+@anchor{Accessibility Options}
+@subheading Accessibility Options
+
+@defopt transient-force-single-column
+This option controls whether the use of a single column to display
+suffixes is enforced.  This might be useful for users with low
+vision who use large text and might otherwise have to scroll in two
+dimensions.
+@end defopt
+
+@anchor{Auxiliary Options}
+@subheading Auxiliary Options
 
+@defopt transient-mode-line-format
 This option controls whether the transient popup buffer has a
 mode-line, separator line, or neither.
 
@@ -759,23 +758,28 @@ good value.
 
 If @code{line} (the default), then the buffer also has no mode-line, but a
 thin line is drawn instead, using the background color of the face
-@code{transient-separator}.  Text-mode frames cannot display thin lines, and
-therefore fall back to treating @code{line} like @code{nil}.
+@code{transient-separator}.  Text-mode frames cannot display thin lines,
+and therefore fall back to treating @code{line} like @code{nil}.
 
 Otherwise this can be any mode-line format.  @xref{Mode Line
 Format,,,elisp,}, for details.
 @end defopt
 
-@defopt transient-read-with-initial-input
+@defopt transient-semantic-coloring
+This option controls whether prefixes and suffixes are colored in
+a Hydra-like fashion.
 
-This option controls whether the last history element is used as the
-initial minibuffer input when reading the value of an infix argument
-from the user.  If @code{nil}, there is no initial input and the first
-element has to be accessed the same way as the older elements.
+If non-@code{nil}, then the key binding of each suffix is colorized to
+indicate whether it exits the transient state or not.  The color of
+the prefix is indicated using the line that is drawn when the value
+of @code{transient-mode-line-format} is @code{line}.
+
+For more information about how Hydra uses colors see
+@uref{https://github.com/abo-abo/hydra#color} and
+@uref{https://oremacs.com/2015/02/19/hydra-colors-reloaded}.
 @end defopt
 
 @defopt transient-highlight-mismatched-keys
-
 This option controls whether key bindings of infix commands that do
 not match the respective command-line argument should be highlighted.
 For other infix commands this option has no effect.
@@ -795,7 +799,6 @@ The highlighting is done using one of the faces
 @end defopt
 
 @defopt transient-substitute-key-function
-
 This function is used to modify key bindings.  If the value of this
 option is @code{nil} (the default), then no substitution is performed.
 
@@ -819,14 +822,52 @@ optimized for lisp.
 @end lisp
 @end defopt
 
-@defopt transient-detect-key-conflicts
+@defopt transient-read-with-initial-input
+This option controls whether the last history element is used as the
+initial minibuffer input when reading the value of an infix argument
+from the user.  If @code{nil}, there is no initial input and the first
+element has to be accessed the same way as the older elements.
+@end defopt
+
+@defopt transient-hide-during-minibuffer-read
+This option controls whether the transient buffer is hidden while
+user input is being read in the minibuffer.
+@end defopt
+
+@defopt transient-align-variable-pitch
+This option controls whether columns are aligned pixel-wise in the
+popup buffer.
+
+If this is non-@code{nil}, then columns are aligned pixel-wise to support
+variable-pitch fonts.  Keys are not aligned, so you should use a
+fixed-pitch font for the @code{transient-key} face.  Other key faces
+inherit from that face unless a theme is used that breaks that
+relationship.
+
+This option is intended for users who use a variable-pitch font for
+the @code{default} face.
+@end defopt
+
+@defopt transient-force-fixed-pitch
+This option controls whether to force the use of a monospaced font
+in popup buffer.  Even if you use a proportional font for the
+@code{default} face, you might still want to use a monospaced font in
+transient's popup buffer.  Setting this option to @code{t} causes 
@code{default}
+to be remapped to @code{fixed-pitch} in that buffer.
+@end defopt
+
+@anchor{Developer Options}
+@subheading Developer Options
 
+These options are mainly intended for developers.
+
+@defopt transient-detect-key-conflicts
 This option controls whether key binding conflicts should be
-detected at the time the transient is invoked.  If so, this
-results in an error, which prevents the transient from being used.
-Because of that, conflicts are ignored by default.
+detected at the time the transient is invoked.  If so, this results
+in an error, which prevents the transient from being used.  Because
+of that, conflicts are ignored by default.
 
-Conflicts cannot be determined earlier, i.e.@: when the transient is
+Conflicts cannot be determined earlier, i.e., when the transient is
 being defined and when new suffixes are being added, because at that
 time there can be false-positives.  It is actually valid for
 multiple suffixes to share a common key binding, provided the
@@ -834,48 +875,51 @@ predicates of those suffixes prevent that more than one 
of them is
 enabled at a time.
 @end defopt
 
-@defopt transient-force-fixed-pitch
+@defopt transient-highlight-higher-levels
+This option controls whether suffixes that would not be available by
+default are highlighted.
 
-This option controls whether to force the use of a monospaced font
-in popup buffer.  Even if you use a proportional font for the
-@code{default} face, you might still want to use a monospaced font in
-transient's popup buffer.  Setting this option to @code{t} causes 
@code{default}
-to be remapped to @code{fixed-pitch} in that buffer.
+When non-@code{nil} then the descriptions of suffixes are highlighted if
+their level is above 4, the default of @code{transient-default-level}.
+Assuming you have set that variable to 7, this highlights all
+suffixes that won't be available to users without them making the
+same customization.
 @end defopt
 
 @node Modifying Existing Transients
 @chapter Modifying Existing Transients
+
 @cindex modifying existing transients
 
-To an extent, transients can be customized interactively, see @ref{Enabling 
and Disabling Suffixes}.  This section explains how existing transients
-can be further modified non-interactively.
+To an extent, transients can be customized interactively, see
+@ref{Enabling and Disabling Suffixes}.  This section explains how existing
+transients can be further modified non-interactively.
 
 The following functions share a few arguments:
 
 @itemize
 @item
-@var{prefix} is a transient prefix command, a symbol.
-
+@var{PREFIX} is a transient prefix command, a symbol.
 
 @item
-@var{suffix} is a transient infix or suffix specification in the same form
+@var{SUFFIX} is a transient infix or suffix specification in the same form
 as expected by @code{transient-define-prefix}.  Note that an infix is a
-special kind of suffix.  Depending on context ``suffixes'' means
-``suffixes (including infixes)'' or ``non-infix suffixes''.  Here it
+special kind of suffix.  Depending on context “suffixes” means
+“suffixes (including infixes)” or “non-infix suffixes”.  Here it
 means the former.  @xref{Suffix Specifications}.
 
-@var{suffix} may also be a group in the same form as expected by
+@var{SUFFIX} may also be a group in the same form as expected by
 @code{transient-define-prefix}.  @xref{Group Specifications}.
 
 
 @item
-@var{loc} is a command, a key vector, a key description (a string as
+@var{LOC} is a command, a key vector, a key description (a string as
 returned by @code{key-description}), or a list specifying coordinates (the
 last element may also be a command or key).  For example @code{(1 0 -1)}
 identifies the last suffix (@code{-1}) of the first subgroup (@code{0}) of the
 second group (@code{1}).
 
-If @var{loc} is a list of coordinates, then it can be used to identify a
+If @var{LOC} is a list of coordinates, then it can be used to identify a
 group, not just an individual suffix command.
 
 The function @code{transient-get-suffix} can be useful to determine whether
@@ -885,55 +929,53 @@ at the definition of the transient prefix command.
 @end itemize
 
 These functions operate on the information stored in the
-@code{transient--layout} property of the @var{prefix} symbol.  Suffix entries 
in
-that tree are not objects but have the form @code{(@var{level}
-@var{class} @var{plist})}, where
-@var{plist} should set at least @code{:key}, @code{:description} and
-@code{:command}.
-
-@defun transient-insert-suffix prefix loc suffix
+@code{transient--layout} property of the @var{PREFIX} symbol.  Suffix entries 
in
+that tree are not objects but have the form @code{(@var{LEVEL} @var{CLASS} 
@var{PLIST})}, where
+@var{PLIST} should set at least @code{:key}, @code{:description} and 
@code{:command}.
 
-This function inserts suffix or group @var{suffix} into @var{prefix}
-before @var{loc}.
+@defun transient-insert-suffix prefix loc suffix &optional keep-other
 @end defun
-
-@defun transient-append-suffix prefix loc suffix
-
-This function inserts suffix or group @var{suffix} into @var{prefix}
-after @var{loc}.
+@defun transient-append-suffix prefix loc suffix &optional keep-other
+These functions insert the suffix or group @var{SUFFIX} into @var{PREFIX} 
before
+or after @var{LOC}.
+
+Conceptually adding a binding to a transient prefix is similar to
+adding a binding to a keymap, but this is complicated by the fact
+that multiple suffix commands can be bound to the same key, provided
+they are never active at the same time, see @ref{Predicate Slots}.
+
+Unfortunately both false-positives and false-negatives are possible.
+To deal with the former use non-nil @var{KEEP-OTHER@.}  To deal with the
+latter remove the conflicting binding explicitly.
 @end defun
 
 @defun transient-replace-suffix prefix loc suffix
-
-This function replaces the suffix or group at @var{loc} in @var{prefix} with
-suffix or group @var{suffix}.
+This function replaces the suffix or group at @var{LOC} in @var{PREFIX} with
+suffix or group @var{SUFFIX}.
 @end defun
 
 @defun transient-remove-suffix prefix loc
-
-This function removes the suffix or group at @var{loc} in @var{prefix}.
+This function removes the suffix or group at @var{LOC} in @var{PREFIX}.
 @end defun
 
 @defun transient-get-suffix prefix loc
-
-This function returns the suffix or group at @var{loc} in @var{prefix}.  The
+This function returns the suffix or group at @var{LOC} in @var{PREFIX}.  The
 returned value has the form mentioned above.
 @end defun
 
 @defun transient-suffix-put prefix loc prop value
-
-This function edits the suffix or group at @var{loc} in @var{prefix},
-by setting the @var{prop} of its plist to @var{value}.
+This function edits the suffix or group at @var{LOC} in @var{PREFIX}, by 
setting
+the @var{PROP} of its plist to @var{VALUE}.
 @end defun
 
 Most of these functions do not signal an error if they cannot perform
 the requested modification.  The functions that insert new suffixes
-show a warning if @var{loc} cannot be found in @var{prefix}, without
-signaling an error.  The reason for doing it like this is that
-establishing a key binding (and that is what we essentially are trying
-to do here) should not prevent the rest of the configuration from
-loading.  Among these functions only @code{transient-get-suffix} and
-@code{transient-suffix-put} may signal an error.
+show a warning if @var{LOC} cannot be found in @var{PREFIX} without signaling 
an
+error.  The reason for doing it like this is that establishing a key
+binding (and that is what we essentially are trying to do here) should
+not prevent the rest of the configuration from loading.  Among these
+functions only @code{transient-get-suffix} and @code{transient-suffix-put} may
+signal an error.
 
 @node Defining New Commands
 @chapter Defining New Commands
@@ -957,12 +999,11 @@ defines the complete transient, not just the transient 
prefix command
 that is used to invoke that transient.
 
 @defmac transient-define-prefix name arglist [docstring] [keyword 
value]@dots{} group@dots{} [body@dots{}]
-
-This macro defines @var{name} as a transient prefix command and binds the
+This macro defines @var{NAME} as a transient prefix command and binds the
 transient's infix and suffix commands.
 
-@var{arglist} are the arguments that the prefix command takes.
-@var{docstring} is the documentation string and is optional.
+@var{ARGLIST} are the arguments that the prefix command takes.
+@var{DOCSTRING} is the documentation string and is optional.
 
 These arguments can optionally be followed by keyword-value pairs.
 Each key has to be a keyword symbol, either @code{:class} or a keyword
@@ -970,11 +1011,11 @@ argument supported by the constructor of that class.  The
 @code{transient-prefix} class is used if the class is not specified
 explicitly.
 
-@var{group}s add key bindings for infix and suffix commands and specify
+@var{GROUP}s add key bindings for infix and suffix commands and specify
 how these bindings are presented in the popup buffer.  At least one
-@var{group} has to be specified.  @xref{Binding Suffix and Infix Commands}.
+@var{GROUP} has to be specified.  @xref{Binding Suffix and Infix Commands}.
 
-The @var{body} is optional.  If it is omitted, then @var{arglist} is ignored 
and
+The @var{BODY} is optional.  If it is omitted, then @var{ARGLIST} is ignored 
and
 the function definition becomes:
 
 @lisp
@@ -983,15 +1024,15 @@ the function definition becomes:
   (transient-setup 'NAME))
 @end lisp
 
-If @var{body} is specified, then it must begin with an @code{interactive} form
-that matches @var{arglist}, and it must call @code{transient-setup}.  It may,
+If @var{BODY} is specified, then it must begin with an @code{interactive} form
+that matches @var{ARGLIST}, and it must call @code{transient-setup}.  It may,
 however, call that function only when some condition is satisfied.
 
 @cindex scope of a transient
 All transients have a (possibly @code{nil}) value, which is exported when
 suffix commands are called, so that they can consume that value.
 For some transients it might be necessary to have a sort of
-secondary value, called a ``scope''.  Such a scope would usually be
+secondary value, called a “scope”.  Such a scope would usually be
 set in the command's @code{interactive} form and has to be passed to the
 setup function:
 
@@ -1013,8 +1054,8 @@ described below.
 
 Users and third-party packages can add additional bindings using
 functions such as @code{transient-insert-suffix} (@pxref{Modifying
-Existing Transients}).  These functions take a ``suffix
-specification'' as one of their arguments, which has the same form as
+Existing Transients}).  These functions take a “suffix
+specification” as one of their arguments, which has the same form as
 the specifications used in @code{transient-define-prefix}.
 
 @menu
@@ -1024,6 +1065,7 @@ the specifications used in @code{transient-define-prefix}.
 
 @node Group Specifications
 @subsection Group Specifications
+
 @cindex group specifications
 
 The suffix and infix commands of a transient are organized in groups.
@@ -1043,39 +1085,39 @@ brackets to do the latter.
 Group specifications then have this form:
 
 @lisp
-[@{@var{level}@} @{@var{description}@}
- @{@var{keyword} @var{value}@}...
- @var{element}...]
+[@{@var{LEVEL}@} @{@var{DESCRIPTION}@}
+ @{@var{KEYWORD} @var{VALUE}@}...
+ @var{ELEMENT}...]
 @end lisp
 
-The @var{level} is optional and defaults to 4.  @xref{Enabling and
+The @var{LEVEL} is optional and defaults to 4.  @xref{Enabling and
 Disabling Suffixes}.
 
-The @var{description} is optional.  If present, it is used as the heading of
+The @var{DESCRIPTION} is optional.  If present, it is used as the heading of
 the group.
 
-The @var{keyword}-@var{value} pairs are optional.  Each keyword has to be a
+The @var{KEYWORD}-@var{VALUE} pairs are optional.  Each keyword has to be a
 keyword symbol, either @code{:class} or a keyword argument supported by the
 constructor of that class.
 
 @itemize
 @item
 One of these keywords, @code{:description}, is equivalent to specifying
-@var{description} at the very beginning of the vector.  The recommendation
+@var{DESCRIPTION} at the very beginning of the vector.  The recommendation
 is to use @code{:description} if some other keyword is also used, for
-consistency, or @var{description} otherwise, because it looks better.
+consistency, or @var{DESCRIPTION} otherwise, because it looks better.
 
 @item
-Likewise @code{:level} is equivalent to @var{level}.
+Likewise @code{:level} is equivalent to @var{LEVEL}.
 
 @item
 Other important keywords include the @code{:if...} keywords.  These
 keywords control whether the group is available in a certain
 situation.
 
-For example, one group of the @code{magit-rebase} transient uses
-@code{:if magit-rebase-in-progress-p}, which contains the suffixes
-that are useful while rebase is already in progress; and another that uses
+For example, one group of the @code{magit-rebase} transient uses @code{:if
+  magit-rebase-in-progress-p}, which contains the suffixes that are
+useful while rebase is already in progress; and another that uses
 @code{:if-not magit-rebase-in-progress-p}, which contains the suffixes that
 initiate a rebase.
 
@@ -1096,9 +1138,9 @@ suffixes, which assumes that a predicate like this is 
used:
 @end lisp
 
 @item
-The value of @code{:setup-children}, if non-@code{nil}, is a function
-that takes two arguments the group object itself and a list of children.
-The children are given as a, potentially empty, list consisting
+The value of @code{:setup-children}, if non-@code{nil}, is a function that 
takes
+two arguments the group object itself and a list of children.
+The children are given as a (potentially empty) list consisting
 of either group or suffix specifications.  It can make arbitrary
 changes to the children including constructing new children from
 scratch.  Also see @code{transient-setup-children}.
@@ -1109,21 +1151,21 @@ contained in a group are right padded, effectively 
aligning the
 descriptions.
 @end itemize
 
-The @var{element}s are either all subgroups (vectors), or all suffixes
+The @var{ELEMENT}s are either all subgroups (vectors), or all suffixes
 (lists) and strings.  (At least currently no group type exists that
 would allow mixing subgroups with commands at the same level, though
 in principle there is nothing that prevents that.)
 
-If the @var{element}s are not subgroups, then they can be a mixture of lists
+If the @var{ELEMENT}s are not subgroups, then they can be a mixture of lists
 that specify commands and strings.  Strings are inserted verbatim.
 The empty string can be used to insert gaps between suffixes, which is
 particularly useful if the suffixes are outlined as a table.
 
 Variables are supported inside group specifications.  For example in
 place of a direct subgroup specification, a variable can be used whose
-value is a vector that qualifies as a group specification.  Likewise, a
-variable can be used where a suffix specification is expected.  Lists
-of group or suffix specifications are also supported.  Indirect
+value is a vector that qualifies as a group specification.  Likewise,
+a variable can be used where a suffix specification is expected.
+Lists of group or suffix specifications are also supported.  Indirect
 specifications are resolved when the transient prefix is being
 defined.
 
@@ -1131,6 +1173,7 @@ The form of suffix specifications is documented in the 
next node.
 
 @node Suffix Specifications
 @subsection Suffix Specifications
+
 @cindex suffix specifications
 
 A transient's suffix and infix commands are bound when the transient
@@ -1140,37 +1183,36 @@ prefix command is defined using 
@code{transient-define-prefix}, see
 individual suffix command.
 
 The same form is also used when later binding additional commands
-using functions such as @code{transient-insert-suffix},
-see @ref{Modifying Existing Transients}.
+using functions such as @code{transient-insert-suffix}, see @ref{Modifying 
Existing Transients}.
 
-Note that an infix is a special kind of suffix.  Depending on context
-``suffixes'' means ``suffixes (including infixes)'' or ``non-infix
-suffixes''.  Here it means the former.
+Note that an infix is a special kind of suffix. Depending on context
+“suffixes” means “suffixes (including infixes)” or “non-infix
+suffixes”.  Here it means the former.
 
 Suffix specifications have this form:
 
 @lisp
-([@var{level}]
- [@var{key}] [@var{description}]
- @var{command}|@var{argument} [@var{keyword} @var{value}]...)
+([@var{LEVEL}]
+ [@var{KEY}] [@var{DESCRIPTION}]
+ @var{COMMAND}|@var{ARGUMENT} [@var{KEYWORD} @var{VALUE}]...)
 @end lisp
 
-@var{level}, @var{key} and @var{description} can also be specified using the 
@var{keyword}s
+@var{LEVEL}, @var{KEY} and @var{DESCRIPTION} can also be specified using the 
@var{KEYWORD}s
 @code{:level}, @code{:key} and @code{:description}.  If the object that is 
associated with
-@var{command} sets these properties, then they do not have to be specified
+@var{COMMAND} sets these properties, then they do not have to be specified
 here.  You can however specify them here anyway, possibly overriding
 the object's values just for the binding inside this transient.
 
 @itemize
 @item
-@var{level} is the suffix level, an integer between 1 and 7.
+@var{LEVEL} is the suffix level, an integer between 1 and 7.
 @xref{Enabling and Disabling Suffixes}.
 
 @item
-@var{key} is the key binding, either a vector or key description string.
+@var{KEY} is the key binding, either a vector or key description string.
 
 @item
-@var{description} is the description, either a string or a function that
+@var{DESCRIPTION} is the description, either a string or a function that
 returns a string.  The function should be a lambda expression to
 avoid ambiguity.  In some cases a symbol that is bound as a function
 would also work but to be safe you should use @code{:description} in that
@@ -1182,7 +1224,7 @@ argument that is mandatory in all cases.
 
 @itemize
 @item
-Usually @var{command} is a symbol that is bound as a function, which has
+@var{COMMAND} should be a symbol that is bound as a function, which has
 to be defined or at least autoloaded as a command by the time the
 containing prefix command is invoked.
 
@@ -1190,15 +1232,13 @@ Any command will do; it does not need to have an object 
associated
 with it (as would be the case if @code{transient-define-suffix} or
 @code{transient-define-infix} were used to define it).
 
-The command can also be a closure or lambda expression, but that
-should only be used for dynamic transients whose suffixes are
-defined when the prefix command is invoked.  See information about
-the @code{:setup-children} function in @ref{Group Specifications}.
+Anonymous, dynamically defined suffix commands are also support.
+See information about the @code{:setup-children} function in @ref{Group 
Specifications}.
 
 As mentioned above, the object that is associated with a command can
 be used to set the default for certain values that otherwise have to
 be set in the suffix specification.  Therefore if there is no object,
-then you have to make sure to specify the @var{key} and the @var{description}.
+then you have to make sure to specify the @var{KEY} and the @var{DESCRIPTION}.
 
 As a special case, if you want to add a command that might be neither
 defined nor autoloaded, you can use a workaround like:
@@ -1209,8 +1249,8 @@ defined nor autoloaded, you can use a workaround like:
     :if (lambda () (featurep 'no-library))))
 @end lisp
 
-Instead of @code{featurep} you could also use @code{require} with a
-non-nil value for @var{noerror}.
+Instead of @code{featurep} you could also use @code{require} with a 
non-@code{nil} value
+for @var{NOERROR}.
 
 @item
 The mandatory argument can also be a command-line argument, a
@@ -1227,30 +1267,29 @@ used.
 
 Unless the class is specified explicitly, the appropriate class is
 guessed based on the long argument.  If the argument ends with @samp{=}
-(e.g. @samp{--format=}) then @code{transient-option} is used, otherwise
+(e.g., @samp{--format=}) then @code{transient-option} is used, otherwise
 @code{transient-switch}.
 @end itemize
 
-Finally, details can be specified using optional
-@var{keyword}-@var{value} pairs.
+Finally, details can be specified using optional @var{KEYWORD}-@var{VALUE} 
pairs.
 Each keyword has to be a keyword symbol, either @code{:class} or a keyword
 argument supported by the constructor of that class.  See @ref{Suffix Slots}.
 
 @node Defining Suffix and Infix Commands
 @section Defining Suffix and Infix Commands
+
 @cindex defining suffix commands
 @cindex defining infix commands
 
-Note that an infix is a special kind of suffix.  Depending on context
-``suffixes'' means ``suffixes (including infixes)'' or ``non-infix
-suffixes''.
+Note that an infix is a special kind of suffix. Depending on context
+“suffixes” means “suffixes (including infixes)” or “non-infix
+suffixes”.
 
 @defmac transient-define-suffix name arglist [docstring] [keyword 
value]@dots{} body@dots{}
+This macro defines @var{NAME} as a transient suffix command.
 
-This macro defines @var{name} as a transient suffix command.
-
-@var{arglist} are the arguments that the command takes.
-@var{docstring} is the documentation string and is optional.
+@var{ARGLIST} are the arguments that the command takes.
+@var{DOCSTRING} is the documentation string and is optional.
 
 These arguments can optionally be followed by keyword-value pairs.
 Each keyword has to be a keyword symbol, either @code{:class} or a keyword
@@ -1258,17 +1297,16 @@ argument supported by the constructor of that class.  
The
 @code{transient-suffix} class is used if the class is not specified
 explicitly.
 
-The @var{body} must begin with an @code{interactive} form that matches 
@var{arglist}.
+The @var{BODY} must begin with an @code{interactive} form that matches 
@var{ARGLIST}.
 The infix arguments are usually accessed by using @code{transient-args}
 inside @code{interactive}.
 @end defmac
 
 @defmac transient-define-infix name arglist [docstring] [keyword value]@dots{}
+This macro defines @var{NAME} as a transient infix command.
 
-This macro defines @var{name} as a transient infix command.
-
-@var{arglist} is always ignored (but mandatory never-the-less) and
-reserved for future use.  @var{docstring} is the documentation string and
+@var{ARGLIST} is always ignored (but mandatory never-the-less) and
+reserved for future use.  @var{DOCSTRING} is the documentation string and
 is optional.
 
 The keyword-value pairs are mandatory.  All transient infix commands
@@ -1297,13 +1335,12 @@ Different infix commands behave differently because the 
concrete
 methods are different for different infix command classes.  In rare
 cases the above command function might not be suitable, even if you
 define your own infix command class.  In that case you have to use
-@code{transient-suffix-command} to define the infix command and use @code{t} as
-the value of the @code{:transient} keyword.
+@code{transient-define-suffix} to define the infix command and use @code{t} as 
the
+value of the @code{:transient} keyword.
 @end defmac
 
 @defmac transient-define-argument name arglist [docstring] [keyword 
value]@dots{}
-
-This macro defines @var{name} as a transient infix command.
+This macro defines @var{NAME} as a transient infix command.
 
 This is an alias for @code{transient-define-infix}.  Only use this alias
 to define an infix command that actually sets an infix argument.
@@ -1313,7 +1350,6 @@ To define an infix command that, for example, sets a 
variable, use
 
 @node Using Infix Arguments
 @section Using Infix Arguments
-@cindex using infix arguments
 
 The functions and the variables described below allow suffix commands
 to access the value of the transient from which they were invoked;
@@ -1332,61 +1368,56 @@ function, which for infix arguments serves about the 
same purpose as
 @code{prefix-arg} serves for prefix arguments.
 
 @defun transient-args prefix
-
 This function returns the value of the transient prefix command
-@var{prefix}.
+@var{PREFIX}.
 
 If the current command was invoked from the transient prefix command
-@var{prefix}, then it returns the active infix arguments.  If the current
-command was not invoked from @var{prefix}, then it returns the set, saved
-or default value for @var{prefix}.
+@var{PREFIX}, then it returns the active infix arguments.  If the current
+command was not invoked from @var{PREFIX}, then it returns the set, saved
+or default value for @var{PREFIX}.
 @end defun
 
 @defun transient-arg-value arg args
-
-This function return the value of @var{arg} as it appears in @var{args}.
+This function return the value of @var{ARG} as it appears in @var{ARGS}.
 
 For a switch a boolean is returned.  For an option the value is
 returned as a string, using the empty string for the empty value,
-or @code{nil} if the option does not appear in @var{args}.
+or @code{nil} if the option does not appear in @var{ARGS}.
 @end defun
 
 @defun transient-suffixes prefix
-
 This function returns the suffixes of the transient prefix command
-@var{prefix}.  This is a list of objects.  This function should only be
+@var{PREFIX}.  This is a list of objects.  This function should only be
 used if you need the objects (as opposed to just their values) and
-if the current command is not being invoked from @var{prefix}.
+if the current command is not being invoked from @var{PREFIX}.
 @end defun
 
 @defvar transient-current-suffixes
-
 The suffixes of the transient from which this suffix command was
 invoked.  This is a list of objects.  Usually it is sufficient to
 instead use the function @code{transient-args}, which returns a list of
 values.  In complex cases it might be necessary to use this variable
-instead, i.e.@: if you need access to information beside the value.
+instead, i.e., if you need access to information beside the value.
 @end defvar
 
 @defvar transient-current-prefix
-
 The transient from which this suffix command was invoked.  The
 returned value is a @code{transient-prefix} object, which holds information
 associated with the transient prefix command.
 @end defvar
 
 @defvar transient-current-command
-
 The transient from which this suffix command was invoked.  The
 returned value is a symbol, the transient prefix command.
 @end defvar
 
 @node Transient State
 @section Transient State
+
 @cindex transient state
 
-Invoking a transient prefix command ``activates'' the respective
-transient, i.e.@: it puts a transient keymap into effect, which binds
+Invoking a transient prefix command “activates” the respective
+transient, i.e., it puts a transient keymap into effect, which binds
 the transient's infix and suffix commands.
 
 The default behavior while a transient is active is as follows:
@@ -1397,20 +1428,20 @@ Invoking an infix command does not affect the transient 
state; the
 transient remains active.
 
 @item
-Invoking a (non-infix) suffix command ``deactivates'' the transient
+Invoking a (non-infix) suffix command “deactivates” the transient
 state by removing the transient keymap and performing some
 additional cleanup.
 
 @item
 Invoking a command that is bound in a keymap other than the
 transient keymap is disallowed and trying to do so results in a
-warning.  This does not ``deactivate'' the transient.
+warning.  This does not “deactivate” the transient.
 @end itemize
 
 But these are just the defaults.  Whether a certain command
-deactivates or ``exits'' the transient is configurable.  There is more
-than one way in which a command can be ``transient'' or ``non-transient'';
-the exact behavior is implemented by calling a so-called ``pre-command''
+deactivates or “exits” the transient is configurable.  There is more
+than one way in which a command can be “transient” or “non-transient”;
+the exact behavior is implemented by calling a so-called “pre-command”
 function.  Whether non-suffix commands are allowed to be called is
 configurable per transient.
 
@@ -1426,10 +1457,8 @@ Valid values are booleans and the pre-commands described 
below.
 @itemize
 @item
 @code{t} is equivalent to @code{transient--do-stay}.
-
 @item
 @code{nil} is equivalent to @code{transient--do-exit}.
-
 @item
 If @code{transient} is unbound (and that is actually the default for
 non-infix suffixes) then the value of the prefix's
@@ -1439,18 +1468,18 @@ essentially equivalent to it being @code{nil}.
 @end itemize
 
 @item
-A suffix command can be a prefix command itself, i.e. a
-``sub-prefix''.  While a sub-prefix is active we nearly always want
-@kbd{C-g} to take the user back to the ``super-prefix''.  However in rare
+A suffix command can be a prefix command itself, i.e., a
+“sub-prefix”.  While a sub-prefix is active we nearly always want
+@kbd{C-g} to take the user back to the “super-prefix”.  However in rare
 cases this may not be desirable, and that makes the following
 complication necessary:
 
 For @code{transient-suffix} objects the @code{transient} slot is unbound.  We 
can
 ignore that for the most part because, as stated above, @code{nil} and the
-slot being unbound are equivalent, and mean ``do exit''.  That isn't
+slot being unbound are equivalent, and mean “do exit”.  That isn't
 actually true for suffixes that are sub-prefixes though.  For such
-suffixes unbound means ``do exit but allow going back'', which is the
-default, while @code{nil} means ``do exit permanently'', which requires that
+suffixes unbound means “do exit but allow going back”, which is the
+default, while @code{nil} means “do exit permanently”, which requires that
 slot to be explicitly set to that value.
 
 @item
@@ -1465,7 +1494,7 @@ called by @code{transient--pre-command}, a function on 
@code{pre-command-hook} a
 the value that they return determines whether the transient is exited.
 To do so the value of one of the constants @code{transient--exit} or
 @code{transient--stay} is used (that way we don't have to remember if @code{t} 
means
-``exit'' or ``stay'').
+“exit” or “stay”).
 
 Additionally, these functions may change the value of @code{this-command}
 (which explains why they have to be called using @code{pre-command-hook}),
@@ -1480,7 +1509,6 @@ The default for infixes is @code{transient--do-stay}.  
This is also the only
 function that makes sense for infixes.
 
 @defun transient--do-stay
-
 Call the command without exporting variables and stay transient.
 @end defun
 
@@ -1490,27 +1518,55 @@ Call the command without exporting variables and stay 
transient.
 The default for suffixes is @code{transient--do-exit}.
 
 @defun transient--do-exit
-
 Call the command after exporting variables and exit the transient.
 @end defun
 
-@defun transient--do-call
+@defun transient--do-return
+Call the command after exporting variables and return to parent
+prefix.  If there is no parent prefix, then call @code{transient--do-exit}.
+@end defun
 
+@defun transient--do-call
 Call the command after exporting variables and stay transient.
 @end defun
 
-@defun transient--do-replace
+The following pre-commands are suitable for sub-prefixes.  Only the
+first should ever explicitly be set as the value of the @code{transient}
+slot.
+
+@defun transient--do-recurse
+Call the transient prefix command, preparing for return to active
+transient.
+
+Whether we actually return to the parent transient is ultimately
+under the control of each invoked suffix.  The difference between
+this pre-command and @code{transient--do-replace} is that it changes the
+value of the @code{transient-suffix} slot to @code{transient--do-return}.
+
+If there is no parent transient, then only call this command and
+skip the second step.
+@end defun
 
+@defun transient--do-replace
 Call the transient prefix command, replacing the active transient.
 
-This is used for suffixes that are prefixes themselves, i.e.@: for
-sub-prefixes.
+Unless @code{transient--do-recurse} is explicitly used, this pre-command
+is automatically used for suffixes that are prefixes themselves,
+i.e., for sub-prefixes.
+@end defun
+
+@defun transient--do-suspend
+Suspend the active transient, saving the transient stack.
+
+This is used by the command @code{transient-suspend} and optionally also by
+“external events” such as @code{handle-switch-frame}.  Such bindings should
+be added to @code{transient-predicate-map}.
 @end defun
 
 @anchor{Pre-commands for Non-Suffixes}
 @subheading Pre-commands for Non-Suffixes
 
-The default for non-suffixes, i.e@: commands that are bound in other
+The default for non-suffixes, i.e., commands that are bound in other
 keymaps beside the transient keymap, is @code{transient--do-warn}.  Silently
 ignoring the user-error is also an option, though probably not a good
 one.
@@ -1520,12 +1576,10 @@ If you want to let the user invoke non-suffix commands, 
then use
 slot.
 
 @defun transient--do-warn
-
 Call @code{transient-undefined} and stay transient.
 @end defun
 
 @defun transient--do-noop
-
 Call @code{transient-noop} and stay transient.
 @end defun
 
@@ -1533,21 +1587,18 @@ Call @code{transient-noop} and stay transient.
 @subheading Special Pre-Commands
 
 @defun transient--do-quit-one
-
 If active, quit help or edit mode, else exit the active transient.
 
 This is used when the user pressed @kbd{C-g}.
 @end defun
 
 @defun transient--do-quit-all
-
 Exit all transients without saving the transient stack.
 
 This is used when the user pressed @kbd{C-q}.
 @end defun
 
 @defun transient--do-suspend
-
 Suspend the active transient, saving the transient stack.
 
 This is used when the user pressed @kbd{C-z}.
@@ -1555,6 +1606,7 @@ This is used when the user pressed @kbd{C-z}.
 
 @node Classes and Methods
 @chapter Classes and Methods
+
 @cindex classes and methods
 
 Transient uses classes and generic functions to make it possible to
@@ -1591,7 +1643,7 @@ holds a function that is used to read a new value for an 
infix
 command.  The values of such slots are regular functions.
 
 Generic functions are used when a function should do something
-different based on the type of the command, i.e. when all commands
+different based on the type of the command, i.e., when all commands
 of a certain type should behave the same way but different from the
 behavior for other types.  Object slots that hold a regular function
 as value are used when the task that they perform is likely to
@@ -1613,7 +1665,7 @@ differ even between different commands of the same type.
 @section Group Classes
 
 The type of a group can be specified using the @code{:class} property at the
-beginning of the class specification, e.g. @code{[:class transient-columns
+beginning of the class specification, e.g., @code{[:class transient-columns
 ...]} in a call to @code{transient-define-prefix}.
 
 @itemize
@@ -1622,7 +1674,7 @@ The abstract @code{transient-child} class is the base 
class of both
 @code{transient-group} (and therefore all groups) as well as of
 @code{transient-suffix} (and therefore all suffix and infix commands).
 
-This class exists because the elements (a.k.a.@: ``children'') of certain
+This class exists because the elements (or “children”) of certain
 groups can be other groups instead of suffix and infix commands.
 
 @item
@@ -1632,8 +1684,8 @@ group classes.
 @item
 The @code{transient-column} class is the simplest group.
 
-This is the default ``flat'' group.  If the class is not specified
-explicitly and the first element is not a vector (i.e. not a group),
+This is the default “flat” group.  If the class is not specified
+explicitly and the first element is not a vector (i.e., not a group),
 then this class is used.
 
 This class displays each element on a separate line.
@@ -1648,8 +1700,8 @@ Direct elements have to be groups whose elements have to 
be commands
 or strings.  Each subgroup represents a column.  This class takes
 care of inserting the subgroups' elements.
 
-This is the default ``nested'' group.  If the class is not specified
-explicitly and the first element is a vector (i.e.@: a group), then
+This is the default “nested” group.  If the class is not specified
+explicitly and the first element is a vector (i.e., a group), then
 this class is used.
 
 @item
@@ -1665,12 +1717,11 @@ elements.
 @section Group Methods
 
 @defun transient-setup-children group children
-
 This generic function can be used to setup the children or a group.
 
 The default implementation usually just returns the children
-unchanged, but if the @code{setup-children} slot of @var{group} is non-nil, 
then
-it calls that function with @var{children} as the only argument and
+unchanged, but if the @code{setup-children} slot of @var{GROUP} is 
non-@code{nil}, then
+it calls that function with @var{CHILDREN} as the only argument and
 returns the value.
 
 The children are given as a (potentially empty) list consisting of
@@ -1680,7 +1731,6 @@ children from scratch.
 @end defun
 
 @defun transient--insert-group group
-
 This generic function formats the group and its elements and inserts
 the result into the current buffer, which is a temporary buffer.
 The contents of that buffer are later inserted into the popup buffer.
@@ -1698,7 +1748,6 @@ commands and there is only a single generic function that 
can be
 specialized based on the class of a prefix command.
 
 @defun transient--history-init obj
-
 This generic function is called while setting up the transient and
 is responsible for initializing the @code{history} slot.  This is the
 transient-wide history; many individual infixes also have a history
@@ -1784,8 +1833,7 @@ functions use @code{describe-function}.
 @subsection Suffix Value Methods
 
 @defun transient-init-value obj
-
-This generic function sets the initial value of the object @var{obj}.
+This generic function sets the initial value of the object @var{OBJ}.
 
 This function is called for all suffix commands, but unless a
 concrete method is implemented this falls through to the default
@@ -1797,9 +1845,8 @@ a method.
 @end defun
 
 @defun transient-infix-read obj
-
 This generic function determines the new value of the infix object
-@var{obj}.
+@var{OBJ}.
 
 This function merely determines the value; @code{transient-infix-set} is
 used to actually store the new value in the object.
@@ -1809,40 +1856,36 @@ user using the reader specified by the @code{reader} 
slot (using the
 @code{transient-infix-value} method described below).
 
 For some infix classes the value is changed without reading
-anything in the minibuffer, i.e.@: the mere act of invoking the
+anything in the minibuffer, i.e., the mere act of invoking the
 infix command determines what the new value should be, based
 on the previous value.
 @end defun
 
 @defun transient-prompt obj
-
 This generic function returns the prompt to be used to read infix
-object @var{obj}'s value.
+object @var{OBJ}'s value.
 @end defun
 
 @defun transient-infix-set obj value
-
-This generic function sets the value of infix object @var{obj} to @var{value}.
+This generic function sets the value of infix object @var{OBJ} to @var{VALUE}.
 @end defun
 
 @defun transient-infix-value obj
-
-This generic function returns the value of the suffix object @var{obj}.
+This generic function returns the value of the suffix object @var{OBJ}.
 
 This function is called by @code{transient-args} (which see), meaning this
 function is how the value of a transient is determined so that the
 invoked suffix command can use it.
 
 Currently most values are strings, but that is not set in stone.
-@code{nil} is not a value, it means ``no value''.
+@code{nil} is not a value, it means “no value”.
 
 Usually only infixes have a value, but see the method for
 @code{transient-suffix}.
 @end defun
 
 @defun transient-init-scope obj
-
-This generic function sets the scope of the suffix object @var{obj}.
+This generic function sets the scope of the suffix object @var{OBJ}.
 
 The scope is actually a property of the transient prefix, not of
 individual suffixes.  However it is possible to invoke a suffix
@@ -1859,8 +1902,7 @@ implementation, which is a noop.
 @subsection Suffix Format Methods
 
 @defun transient-format obj
-
-This generic function formats and returns @var{obj} for display.
+This generic function formats and returns @var{OBJ} for display.
 
 When this function is called, then the current buffer is some
 temporary buffer.  If you need the buffer from which the prefix
@@ -1869,27 +1911,23 @@ making @code{transient--source-buffer} current.
 @end defun
 
 @defun transient-format-key obj
-
-This generic function formats @var{obj}'s @code{key} for display and returns 
the
+This generic function formats @var{OBJ}'s @code{key} for display and returns 
the
 result.
 @end defun
 
 @defun transient-format-description obj
-
-This generic function formats @var{obj}'s @code{description} for display and
+This generic function formats @var{OBJ}'s @code{description} for display and
 returns the result.
 @end defun
 
 @defun transient-format-value obj
-
-This generic function formats @var{obj}'s value for display and returns
+This generic function formats @var{OBJ}'s value for display and returns
 the result.
 @end defun
 
 @defun transient-show-help obj
-
 Show help for the prefix, infix or suffix command represented by
-@var{obj}.
+@var{OBJ}.
 
 For prefixes, show the info manual, if that is specified using the
 @code{info-manual} slot.  Otherwise, show the manpage if that is specified
@@ -1906,10 +1944,10 @@ the command's doc string.
 
 @itemize
 @item
-@code{man-page} or @code{info-manual} can be used to specify the documentation 
for
-the prefix and its suffixes.  The command @code{transient-help} uses the
-method @code{transient-show-help} (which see) to lookup and use these
-values.
+@code{show-help}, @code{man-page} or @code{info-manual} can be used to specify 
the
+documentation for the prefix and its suffixes.  The command
+@code{transient-help} uses the method @code{transient-show-help} (which see) to
+lookup and use these values.
 
 @item
 @code{history-key} If multiple prefix commands should share a single value,
@@ -1930,7 +1968,7 @@ multiple sub-lists.
 
 @item
 @code{scope} For some transients it might be necessary to have a sort of
-secondary value, called a ``scope''.  See @code{transient-define-prefix}.
+secondary value, called a “scope”.  See @code{transient-define-prefix}.
 @end itemize
 
 @anchor{Internal Prefix Slots}
@@ -1995,10 +2033,8 @@ It must contain the following %-placeholders:
 @itemize
 @item
 @code{%k} For the key.
-
 @item
 @code{%d} For the description.
-
 @item
 @code{%v} For the infix value.  Non-infix suffixes don't have a value.
 @end itemize
@@ -2006,6 +2042,11 @@ It must contain the following %-placeholders:
 @item
 @code{description} The description, either a string or a function that is
 called with no argument and returns a string.
+
+@item
+@code{show-help} A function used to display help for the suffix.  If
+unspecified, the prefix controls how hlep is displayed for its
+suffixes.
 @end itemize
 
 @anchor{Slots of @code{transient-infix}}
@@ -2016,10 +2057,10 @@ They are defined here anyway to allow sharing certain 
methods.
 
 @itemize
 @item
-@code{argument} The long argument, e.g. @code{--verbose}.
+@code{argument} The long argument, e.g., @code{--verbose}.
 
 @item
-@code{shortarg} The short argument, e.g. @code{-v}.
+@code{shortarg} The short argument, e.g., @code{-v}.
 
 @item
 @code{value} The value.  Should not be accessed directly.
@@ -2036,7 +2077,34 @@ the prefixes.
 
 @item
 @code{multi-value} For options, whether the option can have multiple
-values.  If non-nil, then default to use @code{completing-read-multiple}.
+values.  If this is non-@code{nil}, then the values are read using
+@code{completing-read-multiple} by default and if you specify your own
+reader, then it should read the values using that function or
+similar.
+
+Supported non-@code{nil} values are:
+
+@itemize
+@item
+Use @code{rest} for an option that can have multiple values.  This is
+useful e.g., for an @code{--} argument that indicates that all remaining
+arguments are files (such as @code{git log -- file1 file2}).
+
+In the list returned by @code{transient-args} such an option and its
+values are represented by a single list of the form @code{(ARGUMENT
+    . VALUES)}.
+
+@item
+Use @code{repeat} for an option that can be specified multiple times.
+
+In the list returned by @code{transient-args} each instance of the option
+and its value appears separately in the usual from, for example:
+@code{("--another-argument" "--option=first" "--option=second")}.
+@end itemize
+
+In both cases the option's values have to be specified in the
+default value of a prefix using the same format as returned by
+@code{transient-args}, e.g., @code{("--other" "--o=1" "--o=2" ("--" "f1" 
"f2"))}.
 
 @item
 @code{always-read} For options, whether to read a value on every invocation.
@@ -2053,8 +2121,8 @@ same history because their values are of the same kind.
 
 @item
 @code{reader} The function used to read the value of an infix.  Not used
-for switches.  The function takes three arguments, @var{prompt},
-@var{initial-input} and @var{history}, and must return a string.
+for switches.  The function takes three arguments, @var{PROMPT},
+@var{INITIAL-INPUT} and @var{HISTORY}, and must return a string.
 
 @item
 @code{prompt} The prompt used when reading the value, either a string or a
@@ -2098,25 +2166,18 @@ what happens if you use more than one.
 @itemize
 @item
 @code{if} Enable if predicate returns non-@code{nil}.
-
 @item
 @code{if-not} Enable if predicate returns @code{nil}.
-
 @item
 @code{if-non-nil} Enable if variable's value is non-@code{nil}.
-
 @item
 @code{if-nil} Enable if variable's value is @code{nil}.
-
 @item
 @code{if-mode} Enable if major-mode matches value.
-
 @item
 @code{if-not-mode} Enable if major-mode does not match value.
-
 @item
 @code{if-derived} Enable if major-mode derives from value.
-
 @item
 @code{if-not-derived} Enable if major-mode does not derive from value.
 @end itemize
@@ -2146,16 +2207,13 @@ The following diagrams illustrate some of the 
differences.
 
 @itemize
 @item
-@code{(c)} represents a return to the command loop.
-
+@samp{(c)} represents a return to the command loop.
 @item
-@code{(+)} represents the user's choice to press one key or another.
-
+@samp{(+)} represents the user's choice to press one key or another.
 @item
-@code{@{@var{word}@}} are possible behaviors.
-
+@samp{@{WORD@}} are possible behaviors.
 @item
-@code{@{@var{number}@}} is a footnote.
+@samp{@{NUMBER@}} is a footnote.
 @end itemize
 
 @anchor{Regular Prefix Commands}
@@ -2331,7 +2389,7 @@ and also takes external state into account.
 
 @itemize
 @item
-@code{@{1@}} Transients can be configured to be exited when a suffix command
+@samp{@{1@}} Transients can be configured to be exited when a suffix command
 is invoked.  The default is to do so for all suffixes except for
 those that are common to all transients and which are used to
 perform tasks such as providing help and saving the value of the
@@ -2340,7 +2398,7 @@ specified for individual suffix commands and may even 
depend on
 state.
 
 @item
-@code{@{2@}} Transients can be configured to allow the user to invoke
+@samp{@{2@}} Transients can be configured to allow the user to invoke
 non-suffix commands.  The default is to not allow that and instead
 warn the user.
 @end itemize
@@ -2386,9 +2444,9 @@ Both packages use transient keymaps to make a set of 
commands
 temporarily available and show the available commands in a popup
 buffer.
 
-A Hydra ``body'' is equivalent to a Transient ``prefix'' and a Hydra
-``head'' is equivalent to a Transient ``suffix''.  Hydra has no equivalent
-of a Transient ``infix''.
+A Hydra “body” is equivalent to a Transient “prefix” and a Hydra
+“head” is equivalent to a Transient “suffix”.  Hydra has no equivalent
+of a Transient “infix”.
 
 Both hydras and transients can be used as simple command dispatchers.
 Used like this they are similar to regular prefix commands and prefix
@@ -2406,7 +2464,7 @@ command dispatchers:
 @item
 Invoking a command from a hydra does not necessarily exit the hydra.
 That makes it possible to invoke the same command again, but using a
-shorter key sequence (i.e. the key that was used to enter the hydra
+shorter key sequence (i.e., the key that was used to enter the hydra
 does not have to be pressed again).
 
 Transient supports that too, but for now this feature is not a focus
@@ -2421,7 +2479,6 @@ using the current interface:
    ("n" "next visible heading" outline-next-visible-heading)])
 @end lisp
 
-
 @item
 Transient supports infix arguments; values that are set by infix
 commands and then consumed by the invoked suffix command(s).
@@ -2465,13 +2522,13 @@ currently exist.
 @anchor{Can I control how the popup buffer is displayed?}
 @appendixsec Can I control how the popup buffer is displayed?
 
-Yes, see @code{transient-display-buffer-action} in @ref{Other Options}.
+Yes, see @code{transient-display-buffer-action} in @ref{Configuration}.
 
 @anchor{Why did some of the key bindings change?}
 @appendixsec Why did some of the key bindings change?
 
 You may have noticed that the bindings for some of the common commands
-do @strong{not} have the prefix @code{C-x} and that furthermore some of these 
commands
+do @strong{not} have the prefix @kbd{C-x} and that furthermore some of these 
commands
 are grayed out while others are not.  That unfortunately is a bit
 confusing if the section of common commands is not shown permanently,
 making the following explanation necessary.
@@ -2486,42 +2543,41 @@ bindings.  The bindings that do use a prefix do so to 
avoid wasting
 too many non-prefix bindings, keeping them available for use in
 individual transients.  The bindings that do not use a prefix and that
 are @strong{not} grayed out are very important bindings that are 
@strong{always}
-available, even when invoking the ``common command key prefix'' or @strong{any
+available, even when invoking the “common command key prefix” or @strong{any
 other} transient-specific prefix.  The non-prefix keys that @strong{are} grayed
 out however, are not available when any incomplete prefix key sequence
-is active.  They do not use the ``common command key prefix'' because it
+is active.  They do not use the “common command key prefix” because it
 is likely that users want to invoke them several times in a row and
-e.g. @kbd{M-p M-p M-p} is much more convenient than
-@kbd{C-x M-p C-x M-p C-x M-p}.
+e.g., @kbd{M-p M-p M-p} is much more convenient than @kbd{C-x M-p C-x M-p C-x 
M-p}.
 
-You may also have noticed that the "Set" command is bound to @kbd{C-x s},
+You may also have noticed that the “Set” command is bound to @kbd{C-x s},
 while Magit-Popup used to bind @kbd{C-c C-c} instead.  I have seen several
 users praise the latter binding (sic), so I did not change it
 willy-nilly.  The reason that I changed it is that using different
 prefix keys for different common commands, would have made the
-temporary display of the common commands even more confusing,
-i.e. after pressing @kbd{C-c} all the @kbd{C-x ...} bindings would be grayed 
out.
+temporary display of the common commands even more confusing, i.e.,
+after pressing @kbd{C-c} all the bindings that begin with the @kbd{C-x} prefix
+would be grayed out.
 
 Using a single prefix for common commands key means that all other
 potential prefix keys can be used for transient-specific commands
-@strong{without} the section of common commands also popping up.  @code{C-c} in
+@strong{without} the section of common commands also popping up.  @kbd{C-c} in
 particular is a prefix that I want to (and already do) use for Magit, and
 also using that for a common command would prevent me from doing so.
 
 (Also see the next question.)
 
-@anchor{Why does @code{q} not quit popups anymore?}
-@appendixsec Why does @code{q} not quit popups anymore?
+@anchor{Why does @kbd{q} not quit popups anymore?}
+@appendixsec Why does @kbd{q} not quit popups anymore?
 
 I agree that @kbd{q} is a good binding for commands that quit something.
 This includes quitting whatever transient is currently active, but it
 also includes quitting whatever it is that some specific transient is
-controlling.  The transient @code{magit-blame} for example binds @code{q} to 
the
+controlling.  The transient @code{magit-blame} for example binds @kbd{q} to the
 command that turns @code{magit-blame-mode} off.
 
 So I had to decide if @kbd{q} should quit the active transient (like
-Magit-Popup used to) or whether @kbd{C-g} should do that instead, so
-that @kbd{q}
+Magit-Popup used to) or whether @kbd{C-g} should do that instead, so that 
@kbd{q}
 could be bound in individual transient to whatever commands make sense
 for them.  Because all other letters are already reserved for use by
 individual transients, I have decided to no longer make an exception
@@ -2548,7 +2604,7 @@ necessary changes.  See its doc string for more 
information.
 @printindex vr
 
 @node Concept Index
-@appendix Concept and Feature Index
+@appendix Concept Index
 
 @printindex cp
 
diff --git a/doc/misc/url.texi b/doc/misc/url.texi
index a9d06d7f5b..5644027f95 100644
--- a/doc/misc/url.texi
+++ b/doc/misc/url.texi
@@ -950,7 +950,6 @@ containing the data cached for that URL.
 @node Proxies
 @section Proxies and Gatewaying
 
-@c fixme: check/document url-ns stuff
 @cindex proxy servers
 @cindex proxies
 @cindex environment variables
diff --git a/doc/misc/viper.texi b/doc/misc/viper.texi
index b0deb31d10..0703667ecc 100644
--- a/doc/misc/viper.texi
+++ b/doc/misc/viper.texi
@@ -1842,7 +1842,7 @@ usually most effective:
 (set-face-background viper-replace-overlay-face "yellow")
 @end smallexample
 For a complete list of colors available to you, evaluate the expression
-@code{(x-defined-colors)}.  (Type it in the buffer @file{*scratch*} and then
+@code{(defined-colors)}.  (Type it in the buffer @file{*scratch*} and then
 hit the @kbd{C-j} key.
 
 @item viper-replace-overlay-cursor-color  "Red"
@@ -2571,7 +2571,7 @@ The GNU Emacs Manual}, for more information on tags.
 
 The following two commands are normally bound to a mouse click and are part
 of Viper.  They work only if Emacs runs as an application under X
-Windows (or under some other window system for which a port of GNU Emacs 20
+Windows (or under some other window system for which a port of GNU Emacs
 is available).  Clicking the mouse when Emacs is invoked in an Xterm window
 (using @code{emacs -nw}) will do no good.
 
diff --git a/doc/misc/vtable.texi b/doc/misc/vtable.texi
index 296dc520a1..59cd9d0f56 100644
--- a/doc/misc/vtable.texi
+++ b/doc/misc/vtable.texi
@@ -465,9 +465,9 @@ When point is placed on a vtable, the following keys are 
bound:
 Sort the table by the current column
 (@code{vtable-sort-by-current-column}).  Note that the table is sorted
 according to the data returned by the getter function (@pxref{Making A
-Table}), not by how it's
-displayed in the buffer.  Columns that have only numerical data is
-sorted as numbers, the rest are sorted as strings.
+Table}), not by how it's displayed in the buffer.  Columns that have
+only numerical data are sorted as numbers, the rest are sorted as
+strings.
 
 @findex vtable-narrow-current-column
 @item @{
diff --git a/etc/AUTHORS b/etc/AUTHORS
index f961852cee..f6349df5bc 100644
--- a/etc/AUTHORS
+++ b/etc/AUTHORS
@@ -105,9 +105,9 @@ and co-wrote cc-align.el cc-cmds.el cc-defs.el cc-engine.el 
cc-fonts.el
   cc-langs.el cc-mode.el cc-styles.el cc-vars.el
 and changed cc-mode.texi minibuf.c bytecomp.el edebug.el follow.el
   window.c display.texi subr.el syntax.texi progmodes/compile.el
-  programs.texi keyboard.c lisp.h modes.texi window.el windows.texi
-  cus-start.el eval.c font-lock.el isearch.el newcomment.el
-  and 166 other files
+  programs.texi eval.c keyboard.c lisp.h modes.texi window.el
+  windows.texi cus-start.el font-lock.el frame.c isearch.el
+  and 167 other files
 
 Alan Modra: changed unexelf.c
 
@@ -127,8 +127,7 @@ and changed nsterm.m nsterm.h nsfns.m image.c nsmenu.m 
configure.ac
 Alastair Burt: changed gnus-art.el smiley.el
 
 Albert Krewinkel: co-wrote sieve-manage.el
-and changed sieve.el gnus-msg.el gnus.texi mail/sieve-manage.el
-  message.el sieve.texi
+and changed sieve.el gnus-msg.el gnus.texi message.el sieve.texi
 
 Albert L. Ting: changed gnus-group.el mail-hist.el
 
@@ -181,7 +180,7 @@ Alexandre Julliard: wrote vc-git.el
 and changed vc.el ewoc.el
 
 Alexandre Oliva: wrote gnus-mlspl.el
-and changed unexelf.c emacs-regex.c format.el iris4d.h iris5d.h unexsgi.c
+and changed unexelf.c format.el iris4d.h iris5d.h regex-emacs.c unexsgi.c
 
 Alexandre Veyrenc: changed fr-refcard.tex
 
@@ -282,8 +281,8 @@ Andrea Corallo: wrote comp-cstr-tests.el comp-cstr.el 
comp-tests.el
   comp.el
 and changed comp.c pdumper.c lread.c bytecomp.el comp.h configure.ac
   lisp.h startup.el loadup.el alloc.c data.c emacs.c .gitlab-ci.yml
-  nadvice.el cl-macs.el advice.el help.el lisp/Makefile.in package.el
-  Makefile.in comp-test-funcs.el and 62 other files
+  nadvice.el cl-macs.el advice.el comp-test-funcs.el help.el
+  lisp/Makefile.in package.el Makefile.in and 61 other files
 
 André A. Gomes: changed ispell.el
 
@@ -332,9 +331,9 @@ Andreas Schwab: changed configure.ac lisp.h xdisp.c 
process.c alloc.c
 
 Andreas Seltenreich: changed nnweb.el gnus.texi message.el gnus-sum.el
   gnus.el nnslashdot.el gnus-srvr.el gnus-util.el mm-url.el mm-uu.el
-  url-http.el xterm.c battery.el comint.el doc/misc/gnus.texi
-  easy-mmode.el gmm-utils.el gnus-art.el gnus-cite.el gnus-draft.el
-  gnus-group.el and 7 other files
+  url-http.el xterm.c battery.el comint.el easy-mmode.el gmm-utils.el
+  gnus-art.el gnus-cite.el gnus-draft.el gnus-group.el gnus-ml.el
+  and 6 other files
 
 Andreas Vögele: changed pgg-def.el
 
@@ -376,9 +375,9 @@ Andrew Hyatt: changed bug-triage CONTRIBUTE org-archive.el 
org.el
   org.texi
 
 Andrew Innes: changed makefile.nt w32fns.c w32term.c w32.c w32proc.c
-  fileio.c w32-fns.el dos-w32.el inc/ms-w32.h w32term.h makefile.def
+  fileio.c ms-w32.h w32-fns.el dos-w32.el w32term.h makefile.def
   unexw32.c w32menu.c w32xfns.c addpm.c cmdproxy.c emacs.c w32-win.el
-  w32inevt.c configure.bat lread.c and 129 other files
+  w32inevt.c configure.bat lread.c and 128 other files
 
 Andrew L. Moore: changed executable.el
 
@@ -442,8 +441,9 @@ Antoine Levitt: changed gnus-group.el gnus-sum.el 
message.texi
 
 Antonin Houska: changed newcomment.el
 
-Arash Esbati: changed reftex-vars.el reftex-auc.el reftex-ref.el
-  reftex.el nnmaildir.el reftex-cite.el reftex-dcr.el reftex-toc.el
+Arash Esbati: changed reftex-vars.el efaq-w32.texi reftex-auc.el
+  reftex-ref.el reftex.el gnus.texi nnmaildir.el reftex-cite.el
+  reftex-dcr.el reftex-toc.el
 
 Arik Mitschang: changed smime.el
 
@@ -479,11 +479,11 @@ Arthur Miller: changed help-fns.el ange-ftp.el 
bytecomp.el comp.c comp.el
 
 Artur Malabarba: wrote char-fold-tests.el faces-tests.el isearch-tests.el
   let-alist.el simple-tests.el sort-tests.el tabulated-list-tests.el
-and changed package.el isearch.el lisp/char-fold.el files.el
-  tabulated-list.el package-test.el menu-bar.el replace.el bytecomp.el
-  faces.el files-x.el custom.el custom.texi help-fns.el
-  let-alist-tests.el simple.el subr-tests.el align.el bindings.el
-  cl-lib-tests.el cl-macs.el and 43 other files
+and changed package.el isearch.el char-fold.el files.el tabulated-list.el
+  package-test.el menu-bar.el replace.el bytecomp.el faces.el files-x.el
+  custom.el custom.texi help-fns.el let-alist-tests.el simple.el
+  subr-tests.el align.el bindings.el cl-lib-tests.el cl-macs.el
+  and 43 other files
 
 Artyom Loenko: changed Info.plist.in
 
@@ -543,7 +543,7 @@ Basil L. Contovounesios: changed simple.el message.el 
subr.el eww.el
   custom.el bibtex.el text.texi gnus-sum.el modes.texi customize.texi
   files.texi gnus-group.el gnus-win.el gravatar.el internals.texi json.el
   shr.el window.c battery-tests.el button.el custom-tests.el
-  and 278 other files
+  and 279 other files
 
 Bastian Beischer: changed semantic/complete.el calc-yank.el include.el
   mru-bookmark.el refs.el senator.el
@@ -576,7 +576,7 @@ and changed org-clock.el org.el
 Benjamin Ragheb: changed fortune.el
 
 Benjamin Riefenstahl: changed files.el image-mode.el nnrss-tests.el
-  w32select.c emacs.c image.el inc/ms-w32.h lisp.h mac-win.el macterm.c
+  w32select.c emacs.c image.el lisp.h mac-win.el macterm.c ms-w32.h
   mule-cmds.el nnrss.el runemacs.c tcl.el w32.c w32.h
 
 Benjamin Rutt: co-wrote gnus-dired.el
@@ -584,7 +584,7 @@ and changed vc.el gnus-msg.el message.el diff-mode.el 
ffap.el nnimap.el
   nnmbox.el simple.el vc-cvs.el
 
 Ben Key: changed w32.c w32fns.c w32menu.c configure.bat INSTALL w32.h
-  w32term.c configure.ac emacs.c inc/ms-w32.h keyboard.c make-docfile.c
+  w32term.c configure.ac emacs.c keyboard.c make-docfile.c ms-w32.h
   nsfont.m nsterm.m sound.c xfaces.c
 
 Ben Menasha: changed nnmh.el
@@ -656,8 +656,8 @@ Bob Nnamtrop: changed viper-cmd.el
 Bob Olson: co-wrote cperl-mode.el
 
 Bob Rogers: changed vc-dir.el vc-svn.el cperl-mode.el diff.el ewoc.el
-  ffap.el files.el maintaining.texi sql.el thingatpt.el vc.el
-  vc1-xtra.texi
+  ffap.el files.el ietf-drums.el maintaining.texi sql.el thingatpt.el
+  vc.el vc1-xtra.texi
 
 Bob Weiner: changed info.el quail.el dframe.el etags.c rmail.el
   rmailsum.el speedbar.el
@@ -709,7 +709,8 @@ Brian Fox: changed Makefile.in Makefile configure.ac 
minibuf.c dired.el
 Brian Jenkins: changed frame.c frames.texi hooks.texi
 
 Brian Leung: changed comint.el gud.el advice.el comp.c comp.el em-hist.el
-  files.el find-func.el gdb-mi.el help.el nadvice.el shell.el shortdoc.el
+  files.el find-func.el flymake.el gdb-mi.el help.el nadvice.el shell.el
+  shortdoc.el
 
 Brian Marick: co-wrote hideif.el
 
@@ -850,8 +851,8 @@ Chris Hall: changed callproc.c frame.c
 
 Chris Hanson: changed xscheme.el scheme.el xterm.c hpux.h x11term.c
   hp9000s300.h keyboard.c process.c texinfmt.el sort.el syntax.c
-  texnfo-upd.el x11fns.c xfns.c dired.el emacs-regex.c emacsclient.c
-  fileio.c hp9000s800.h indent.c info.el and 17 other files
+  texnfo-upd.el x11fns.c xfns.c dired.el emacsclient.c fileio.c
+  hp9000s800.h indent.c info.el man.el and 17 other files
 
 Chris Hecker: changed calc-aent.el
 
@@ -973,12 +974,10 @@ Claudio Fontana: changed Makefile.in leim/Makefile.in 
lib-src/Makefile.in
 
 Clemens Radermacher: changed cus-start.el frame.c minibuf.texi window.el
 
-Clément Pit--Claudel: changed debugging.texi emacs-lisp/debug.el eval.c
-  progmodes/python.el subr-tests.el subr.el url-http.el url-vars.el
-
 Clément Pit-Claudel: changed Dockerfile.emba button.el configure.ac
-  display.texi ert.el gitlab-ci.yml keyboard.c tex-mode.el text.texi
-  xdisp.c
+  debugging.texi display.texi emacs-lisp/debug.el ert.el eval.c
+  gitlab-ci.yml keyboard.c progmodes/python.el subr-tests.el subr.el
+  tex-mode.el text.texi url-http.el url-vars.el xdisp.c
 
 Codruț Constantin Gușoi: changed files.el
 
@@ -1032,11 +1031,11 @@ Dale Sedivec: changed sgml-mode.el wisent/python.el
 Damien Cassou: wrote auth-source-pass-tests.el hierarchy-tests.el
   hierarchy.el
 and co-wrote auth-source-pass.el auth-source-tests.el
-and changed auth.texi checkdoc.el ispell.el message.el seq-tests.el
-  seq.el simple-tests.el simple.el auth-source.el autorevert.el
+and changed simple.el auth.texi checkdoc.el ispell.el message.el
+  seq-tests.el seq.el simple-tests.el auth-source.el autorevert.el
   checkdoc-tests.el imenu-tests.el imenu.el info.el isearch.el
-  json-tests.el json.el message-tests.el package.el rmc.el sequences.texi
-  xref.el
+  json-tests.el json.el message-tests.el package.el rmc.el sending.texi
+  and 3 other files
 
 Damien Elmes: changed erc.el erc-dcc.el erc-track.el erc-log.el
   erc-pcomplete.el README erc-button.el erc-nets.el erc-ring.el Makefile
@@ -1114,9 +1113,9 @@ Daniel Lublin: changed dns-mode.el
 
 Daniel Martín: changed shortdoc.el nsterm.m erc.texi files.el files.texi
   msdos-xtra.texi ns-win.el basic.texi cmacexp.el compilation.txt
-  compile-tests.el cscope.el diff.el dired.el editfns.c emacs.texi
-  files-tests.el find-func-tests.el find-func.el frame.c frame.el
-  and 16 other files
+  compile-tests.el cscope.el diff.el dired.el display.texi editfns.c
+  emacs.texi files-tests.el find-func-tests.el find-func.el frame.c
+  and 18 other files
 
 Daniel McClanahan: changed lisp-mode.el
 
@@ -1273,7 +1272,7 @@ David Hedbor: changed nnmail.el
 
 David Hull: changed etags.c vc-hg.el
 
-David Hunter: changed flymake.el inc/ms-w32.h process.c
+David Hunter: changed flymake.el ms-w32.h process.c
 
 David J. Biesack: changed antlr-mode.el quickurl.el
 
@@ -1477,7 +1476,7 @@ and changed xref.el ruby-mode.el project.el vc-git.el 
elisp-mode.el
   etags.el ruby-mode-tests.el js.el vc.el vc-hg.el package.el
   symref/grep.el dired-aux.el simple.el log-edit.el minibuffer.el
   progmodes/grep.el ido.el maintaining.texi menu-bar.el package-test.el
-  and 123 other files
+  and 122 other files
 
 Dmitry Kurochkin: changed isearch.el
 
@@ -1515,8 +1514,8 @@ and changed dired.el cus-edit.el imenu.el info.el 
ls-lisp.el menu-bar.el
   apropos.el bindings.el and 22 other files
 
 Earl Hyatt: changed ffap.el seq-tests.el sequences.texi windows.texi
-  control.texi cus-edit.el hi-lock.el misc.texi pcase-tests.el pcase.el
-  replace.el search.texi seq.el tab-bar.el
+  autotype.texi control.texi cus-edit.el hi-lock.el misc.texi
+  pcase-tests.el pcase.el replace.el search.texi seq.el tab-bar.el
 
 E. Choroba: changed cperl-mode.el simple.el
 
@@ -1573,8 +1572,8 @@ Eli Zaretskii: wrote [bidirectional display in xdisp.c]
   chartab-tests.el coding-tests.el etags-tests.el rxvt.el tty-colors.el
 and co-wrote help-tests.el
 and changed xdisp.c display.texi w32.c msdos.c w32fns.c simple.el
-  files.el fileio.c keyboard.c emacs.c w32term.c text.texi dispnew.c
-  w32proc.c files.texi frames.texi configure.ac dispextern.h lisp.h
+  files.el fileio.c emacs.c keyboard.c w32term.c text.texi dispnew.c
+  w32proc.c files.texi frames.texi configure.ac lisp.h dispextern.h
   process.c ms-w32.h and 1236 other files
 
 Eliza Velasquez: changed server.el
@@ -1734,6 +1733,8 @@ Etienne Prud’Homme: changed align.el css-mode-tests.el 
css-mode.el
 
 Eugene Exarevsky: changed sql.el
 
+Eugene Ha: changed configure.ac
+
 Evangelos Evangelou: changed progmodes/f90.el
 
 Evan Moses: changed progmodes/python.el
@@ -1763,10 +1764,10 @@ Fabrice Nicol: changed etags.c etags.1
 Fabrice Niessen: wrote leuven-theme.el
 and changed org-agenda.el
 
-Fabrice Popineau: changed w32.c ms-w32.h w32fns.c w32heap.c w32term.c
+Fabrice Popineau: changed ms-w32.h w32.c w32fns.c w32heap.c w32term.c
   configure.ac lisp.h unexw32.c buffer.c emacs.c image.c w32heap.h
   w32proc.c w32term.h INSTALL addsection.c alloc.c dispextern.h
-  emacs-regex.c emacs-x64.manifest emacs-x86.manifest and 25 other files
+  emacs-x64.manifest emacs-x86.manifest etags.c and 24 other files
 
 Fan Kai: changed esh-arg.el
 
@@ -1784,6 +1785,8 @@ Felicián Németh: changed project.el xref.el
 
 Felipe Ochoa: changed faces.el js.el paren.el
 
+Felix Dietrich: changed tramp-archive.el
+
 Felix E. Klee: co-wrote svg.el
 and changed display.texi
 
@@ -1821,7 +1824,7 @@ Florian Adamsky: changed recentf.el
 
 Florian Beck: changed org.el
 
-Florian Ragwitz: changed gnus-html.el mail/sieve-manage.el
+Florian Ragwitz: changed gnus-html.el sieve-manage.el
 
 Florian V. Savigny: changed sql.el
 
@@ -1949,7 +1952,7 @@ and changed edebug.el cl-print.el edebug.texi 
emacs-lisp/debug.el
   cl-print-tests.el debugging.texi cl-macs.el edebug-test-code.el subr.el
   testcases.el testcover.el cl-generic.el ert-x.el eval.c eieio-compat.el
   elisp.texi ert.el ert.texi eval-tests.el generator.el print.c
-  and 24 other files
+  and 23 other files
 
 Geoff Gole: changed align.el ibuffer.el whitespace.el
 
@@ -1960,9 +1963,9 @@ Geoff Kuenning: changed gnus-art.el gnus.texi
 Geoff Voelker: wrote ms-w32.h w32-fns.el w32.c w32.h w32heap.c w32heap.h
   w32inevt.c w32proc.c w32term.c
 and changed makefile.nt w32fns.c fileio.c makefile.def callproc.c
-  s/ms-w32.h emacs.bat.in unexw32.c w32term.h dos-w32.el loadup.el
-  w32-win.el emacs.c keyboard.c ntterm.c process.c w32console.c addpm.c
-  cmdproxy.c comint.el files.el and 100 other files
+  emacs.bat.in unexw32.c w32term.h dos-w32.el loadup.el w32-win.el
+  emacs.c keyboard.c ntterm.c process.c w32console.c addpm.c cmdproxy.c
+  comint.el files.el sysdep.c and 97 other files
 
 Georg C. F. Greve: changed pgg-gpg.el
 
@@ -1980,7 +1983,7 @@ Gerd Möllmann: wrote authors.el ebrowse.el jit-lock.el 
tooltip.el
 and changed xdisp.c xterm.c dispnew.c dispextern.h xfns.c xfaces.c
   window.c keyboard.c lisp.h faces.el alloc.c buffer.c startup.el xterm.h
   fns.c simple.el term.c configure.ac frame.c xmenu.c emacs.c
-  and 607 other files
+  and 609 other files
 
 Gergely Nagy: changed erc.el
 
@@ -2008,7 +2011,7 @@ and changed configure.ac Makefile.in src/Makefile.in 
calendar.el
   lisp/Makefile.in diary-lib.el files.el make-dist rmail.el
   progmodes/f90.el bytecomp.el admin.el misc/Makefile.in simple.el
   authors.el startup.el emacs.texi lib-src/Makefile.in display.texi
-  ack.texi subr.el and 1790 other files
+  ack.texi subr.el and 1786 other files
 
 Glynn Clements: wrote gamegrid.el snake.el tetris.el
 
@@ -2120,6 +2123,8 @@ Harald Meland: changed gnus-art.el gnus-salt.el 
gnus-score.el
 
 Harri Kiiskinen: changed org-protocol.el ox-publish.el
 
+Hayden Shenk: changed tramp-adb.el
+
 H. Dieter Wilhelm: changed calc-help.el maintaining.texi paragraphs.el
 
 Heiko Muenkel: changed b2m.c
@@ -2218,7 +2223,8 @@ Ihor Radchenko: changed fns.c
 
 Iku Iwasa: changed auth-source-pass-tests.el auth-source-pass.el
 
-Ikumi Keita: changed characters.el japan-util.el kinsoku.el minibuf.c
+Ikumi Keita: changed characters.el display.texi files.el japan-util.el
+  kinsoku.el minibuf.c
 
 Ilja Weis: co-wrote gnus-topic.el
 
@@ -2232,7 +2238,7 @@ Ilya Shlyakhter: changed org.el ob-lilypond.el 
org-clock.el
 Ilya Zakharevich: wrote tmm.el
 and co-wrote cperl-mode.el
 and changed w32fns.c syntax.c intervals.c syntax.h textprop.c dired.c
-  emacs-regex.c emacs-regex.h font-lock.el intervals.h search.c
+  font-lock.el intervals.h regex-emacs.c regex-emacs.h search.c
 
 Ilya Zonov: changed org-mouse.el
 
@@ -2456,7 +2462,7 @@ Jason Rumney: wrote w32-vars.el
 and changed w32fns.c w32term.c w32font.c w32menu.c w32-win.el w32term.h
   w32.c w32uniscribe.c w32-fns.el makefile.nt w32console.c w32bdf.c
   configure.bat keyboard.c w32proc.c w32select.c font.c image.c w32font.h
-  w32gui.h xdisp.c and 153 other files
+  w32gui.h xdisp.c and 152 other files
 
 Jason S. Cornez: changed keyboard.c
 
@@ -2521,7 +2527,7 @@ and changed mh-e.el mh-comp.el mh-utils.el mh-mime.el 
mh-customize.el
 
 Jeff Spencer: changed dired.el
 
-Jeff Walsh: changed xwidget.c
+Jeff Walsh: changed comp.c xwidget.c
 
 Jelle Licht: changed auth-source-pass-tests.el auth-source-pass.el
 
@@ -2573,8 +2579,8 @@ Jesper Harder: wrote yenc.el
 and changed gnus-sum.el gnus-art.el message.el gnus-group.el gnus-msg.el
   gnus.el gnus-util.el rfc2047.el mm-bodies.el mm-util.el mml.el
   mm-decode.el nnrss.el gnus-srvr.el gnus-topic.el nnmail.el
-  gnus-start.el gnus-uu.el spam-stat.el gnus-score.el gnus.texi
-  and 202 other files
+  gnus-start.el gnus-uu.el gnus.texi spam-stat.el gnus-score.el
+  and 200 other files
 
 Jhair Tocancipa Triana: changed gnus-audio.el
 
@@ -2796,7 +2802,7 @@ and changed epa.el epa-file.el lisp-mnt.el tips.texi 
dired-aux.el
   dired-x.el dired.el eieio.el epa-dired.el font-lock.el
   progmodes/compile.el simple.el allout.el button.el comint.el
   cus-edit.el eldoc.el emacs-module-tests.el epa-hook.el epg-config.el
-  epg.el and 9 other files
+  epg.el and 11 other files
 
 Jonas Hoersch: changed org-inlinetask.el org.el
 
@@ -2903,7 +2909,7 @@ and co-wrote help-tests.el keymap-tests.el
 and changed subr.el desktop.el w32fns.c faces.el simple.el emacsclient.c
   files.el server.el bs.el help-fns.el xdisp.c org.el w32term.c w32.c
   buffer.c keyboard.c ido.el image.c window.c eval.c allout.el
-  and 1226 other files
+  and 1223 other files
 
 Juan Pechiar: changed ob-octave.el
 
@@ -2926,7 +2932,7 @@ Julien Danjou: wrote erc-desktop-notifications.el 
gnus-gravatar.el
 and co-wrote color.el
 and changed shr.el org-agenda.el gnus-art.el nnimap.el gnus-html.el
   gnus.el message.el gnus-group.el gnus-sum.el gnus-util.el mm-decode.el
-  mm-view.el org.el gnus.texi mail/sieve-manage.el nnir.el mm-uu.el
+  mm-view.el org.el gnus.texi nnir.el sieve-manage.el mm-uu.el
   color-lab.el gnus-demon.el gnus-int.el gnus-msg.el and 96 other files
 
 Julien Gilles: wrote gnus-ml.el
@@ -2942,8 +2948,8 @@ Jure Cuhalev: changed ispell.el
 Jürgen Hartmann: changed window.el
 
 Jürgen Hötzel: wrote tramp-adb.el
-and changed tramp-gvfs.el tramp-sh.el comint.el em-unix.el esh-util.el
-  tramp-cache.el tramp.el url-handlers.el wid-edit.el
+and changed tramp-gvfs.el tramp-sh.el callproc.c comint.el em-unix.el
+  esh-util.el tramp-cache.el tramp.el url-handlers.el wid-edit.el
 
 Juri Linkov: wrote compose.el files-x.el misearch.el repeat-tests.el
   replace-tests.el tab-bar-tests.el tab-bar.el tab-line.el
@@ -3048,7 +3054,7 @@ Katsumi Yamaoka: wrote canlock.el
 and changed gnus-art.el gnus-sum.el message.el mm-decode.el gnus.texi
   mm-util.el mm-view.el gnus-group.el gnus-util.el gnus-msg.el mml.el
   shr.el rfc2047.el gnus-start.el gnus.el nntp.el gnus-agent.el nnrss.el
-  mm-uu.el nnmail.el emacs-mime.texi and 161 other files
+  mm-uu.el nnmail.el emacs-mime.texi and 159 other files
 
 Kaushal Modi: changed dired-aux.el files.el isearch.el apropos.el
   calc-yank.el custom.texi desktop.el dired.el dired.texi ediff-diff.el
@@ -3062,7 +3068,7 @@ Kaveh R. Ghazi: changed delta88k.h xterm.c
 Kayvan Sylvan: changed supercite.el
 
 Kazuhiro Ito: changed coding.c uudecode.el flow-fill.el font.c
-  japan-util.el keyboard.c make-mode.el net/starttls.el xdisp.c
+  japan-util.el keyboard.c make-mode.el starttls.el xdisp.c
 
 Kazushi Marukawa: changed filelock.c hexl.c profile.c unexalpha.c
 
@@ -3147,7 +3153,7 @@ and changed edt.texi
 Kevin Gallo: wrote w32-win.el
 and changed makefile.nt dispnew.c addpm.c config.w95 dispextern.h emacs.c
   facemenu.el faces.el fns.c frame.c frame.h keyboard.c makefile.def
-  mouse.el ntterm.c process.c s/ms-w32.h scroll.c startup.el sysdep.c
+  mouse.el ms-w32.h ntterm.c process.c scroll.c startup.el sysdep.c
   term.c and 18 other files
 
 Kevin Greiner: wrote legacy-gnus-agent.el
@@ -3304,10 +3310,10 @@ and co-wrote gnus-kill.el gnus-mh.el gnus-msg.el 
gnus-score.el
   mm-encode.el mm-util.el nnbabyl.el nndoc.el nneething.el nnfolder.el
   nnheader.el nnimap.el nnmbox.el nnmh.el nnml.el nnspool.el nnvirtual.el
   rfc2047.el svg.el time-date.el
-and changed gnus.texi simple.el subr.el files.el process.c text.texi
-  display.texi dired.el gnutls.c gnus-ems.el smtpmail.el help-fns.el
+and changed gnus.texi simple.el subr.el files.el process.c display.texi
+  text.texi dired.el gnutls.c gnus-ems.el smtpmail.el help-fns.el
   auth-source.el url-http.el edebug.el image.el gnus-cite.el pop3.el
-  dired-aux.el fns.c image.c and 860 other files
+  dired-aux.el fns.c image.c and 867 other files
 
 Lars Rasmusson: changed ebrowse.c
 
@@ -3379,6 +3385,8 @@ Liang Wang: changed etags.el
 
 Liāu, Kiong-Gē 廖宮毅: changed comp.c mingw-cfg.site
 
+Lin Zhou: changed w32fns.c w32term.h
+
 Lixin Chin: changed bibtex.el
 
 Lloyd Zusman: changed mml.el pgg-gpg.el
@@ -3732,7 +3740,7 @@ Mattias Engdegård: changed byte-opt.el rx.el rx-tests.el 
searching.texi
   bytecomp-tests.el bytecomp.el calc-tests.el progmodes/compile.el
   subr.el autorevert.el gdb-mi.el files.el regex-emacs-tests.el mouse.el
   regexp-opt.el replace.el calc.el coding.c filenotify.el regex-emacs.c
-  calc-ext.el and 537 other files
+  calc-ext.el and 539 other files
 
 Mattias M: changed asm-mode-tests.el asm-mode.el
 
@@ -3775,7 +3783,7 @@ and co-wrote tramp-cache.el tramp-sh.el tramp.el
 and changed tramp.texi tramp-adb.el trampver.el trampver.texi dbusbind.c
   files.el ange-ftp.el file-notify-tests.el files.texi dbus.texi
   autorevert.el tramp-fish.el kqueue.c tramp-gw.el os.texi shell.el
-  tramp-imap.el gitlab-ci.yml lisp.h README xesam.el and 280 other files
+  tramp-imap.el gitlab-ci.yml lisp.h README xesam.el and 278 other files
 
 Michael Ben-Gershon: changed acorn.h configure.ac riscix1-1.h riscix1-2.h
   unexec.c
@@ -3878,8 +3886,8 @@ Michael Staats: wrote pc-select.el
 Michael Vehrs: changed quail.el woman.el
 
 Michael Welsh Duggan: changed nnimap.el lisp.h sh-script.el w32term.c
-  buffer.c gnus-spec.el gud.el keyboard.c mail/sieve-manage.el nnir.el
-  nnmail.el print.c termhooks.h url-http.el w32-win.el w32fns.c w32menu.c
+  buffer.c gnus-spec.el gud.el keyboard.c nnir.el nnmail.el print.c
+  sieve-manage.el termhooks.h url-http.el w32-win.el w32fns.c w32menu.c
   w32term.h woman.el xdisp.c xterm.c
 
 Michael Weylandt: changed ox-latex.el
@@ -3897,11 +3905,11 @@ Michał Krzywkowski: changed elide-head.el
 Michal Nazarewicz: wrote cc-mode-tests.el descr-text-tests.el
   tildify-tests.el
 and co-wrote tildify.el
-and changed emacs-regex.c casefiddle.c simple.el
-  test/src/regex-emacs-tests.el casefiddle-tests.el emacs-regex.h
-  message.el search.c buffer.h cc-mode.el cc-mode.texi ert-x.el files.el
-  frame.c remember.el sgml-mode.el unidata-gen.el README
-  SpecialCasing.txt bindings.el buffer.c and 41 other files
+and changed regex-emacs.c casefiddle.c regex-emacs-tests.el simple.el
+  casefiddle-tests.el message.el regex-emacs.h search.c buffer.h
+  cc-mode.el cc-mode.texi ert-x.el files.el frame.c remember.el
+  sgml-mode.el unidata-gen.el README SpecialCasing.txt bindings.el
+  buffer.c and 41 other files
 
 Michal Nowak: changed gnutls.el
 
@@ -3924,8 +3932,8 @@ Miguel Ruiz: changed ob-gnuplot.el
 Mihai Olteanu: changed hexl.el
 
 Miha Rihtaršič: changed keyboard.c commands.texi minibuf.c minibuffer.el
-  simple.el comint.el data.c delsel.el errors.texi esh-mode.el eval.c
-  ibuffer.el macros.c process.c sh-script.el
+  simple.el bindings.el comint.el data.c delsel.el errors.texi
+  esh-mode.el eval.c ibuffer.el macros.c process.c sh-script.el
 
 Mihir Rege: changed js.el
 
@@ -4168,7 +4176,7 @@ Nils Ackermann: changed message.el nnmh.el reftex-vars.el
 
 Nitish Chinta: changed progmodes/python.el sendmail.el simple.el
 
-N. Jackson: changed emacs.texi forms.texi os.texi
+N. Jackson: changed emacs.texi forms.texi gnus.info os.texi
 
 Noah Evans: changed follow.el
 
@@ -4187,7 +4195,7 @@ Noam Postavsky: changed progmodes/python.el lisp-mode.el 
bytecomp.el
   lisp-mode-tests.el term.el xdisp.c cl-macs.el eval.c simple.el data.c
   emacs-lisp/debug.el modes.texi help-fns.el subr.el elisp-mode.el ert.el
   isearch.el processes.texi search.c cl-print.el diff-mode.el
-  and 363 other files
+  and 362 other files
 
 Nobuyoshi Nakada: co-wrote ruby-mode.el
 and changed ruby-mode-tests.el
@@ -4307,7 +4315,7 @@ and co-wrote cal-dst.el
 and changed lisp.h configure.ac alloc.c fileio.c process.c editfns.c
   sysdep.c xdisp.c fns.c image.c keyboard.c data.c emacs.c lread.c
   xterm.c eval.c gnulib-comp.m4 callproc.c Makefile.in frame.c buffer.c
-  and 1854 other files
+  and 1847 other files
 
 Paul Fisher: changed fns.c
 
@@ -4321,9 +4329,9 @@ and changed message.el gnus-util.el gnus-int.el gnus.el 
gnus-agent.el
 
 Paul Pogonyshev: changed subr.el byte-opt.el bytecomp.el
   emacs-lisp/debug.el eval.c progmodes/python.el which-func.el align.el
-  bytecode.c cc-langs.el cl-macs.el configure.ac dabbrev.el display.texi
-  eldoc.el elisp-mode.el ert.el ert.texi etags.el fns-tests.el fns.c
-  and 20 other files
+  bytecode.c cc-langs.el cl-macs.el configure.ac dabbrev.el desktop.el
+  display.texi eldoc.el elisp-mode.el ert.el ert.texi etags.el
+  fns-tests.el and 21 other files
 
 Paul Rankin: changed outline.el
 
@@ -4508,9 +4516,9 @@ Philipp Stephani: wrote callint-tests.el checkdoc-tests.el
   cl-preloaded-tests.el ediff-diff-tests.el eval-tests.el ido-tests.el
   lread-tests.el mouse-tests.el startup-tests.el xt-mouse-tests.el
 and changed emacs-module.c emacs-module-tests.el configure.ac json.c
-  process.c eval.c json-tests.el process-tests.el internals.texi alloc.c
+  process.c eval.c internals.texi json-tests.el process-tests.el alloc.c
   emacs-module.h.in emacs.c lread.c nsterm.m lisp.h pdumper.c bytecomp.el
-  callproc.c seccomp-filter.c gtkutil.c files.el and 179 other files
+  callproc.c seccomp-filter.c gtkutil.c files.el and 184 other files
 
 Phillip Lord: wrote ps-print-tests.el w32-feature.el
 and changed build-zips.sh build-dep-zips.py lisp/Makefile.in undo.c
@@ -4565,8 +4573,8 @@ and changed xdisp.c comp.c fns.c pdumper.c alloc.c 
byte-opt.el
   comp-tests.el comp.el composite.c and 28 other files
 
 Po Lu: changed xdisp.c anti.texi browse-url.el callproc.c cc-compat.el
-  config.bat esh-cmd.el fileio.c langinfo.h loadup.el msdos.c msdos.h
-  nsfns.m nsterm.m process.c sed1v2.inp sed2v2.inp sed3v2.inp
+  config.bat esh-cmd.el fileio.c langinfo.h loadup.el mouse.el msdos.c
+  msdos.h nsfns.m nsterm.m process.c sed1v2.inp sed2v2.inp sed3v2.inp
   sedlibmk.inp tooltip.el xterm.c
 
 Pontus Michael: changed simple.el
@@ -4663,7 +4671,7 @@ Reiner Steib: wrote gmm-utils.el
 and changed message.el gnus.texi gnus-art.el gnus-sum.el gnus-group.el
   gnus.el mml.el gnus-faq.texi mm-util.el gnus-score.el message.texi
   gnus-msg.el gnus-start.el gnus-util.el spam-report.el mm-uu.el spam.el
-  mm-decode.el files.el gnus-agent.el nnmail.el and 172 other files
+  mm-decode.el files.el gnus-agent.el nnmail.el and 171 other files
 
 Remek Trzaska: changed gnus-ems.el
 
@@ -4697,6 +4705,8 @@ Richard Dawe: changed config.in src/Makefile.in
 
 Richard G. Bielawski: changed modes.texi paren.el
 
+Richard Hansen: changed easy-mmode.el
+
 Richard Hoskins: changed message.el
 
 Richard Kim: wrote wisent/python.el
@@ -4727,7 +4737,7 @@ and co-wrote cc-align.el cc-cmds.el cc-defs.el 
cc-engine.el cc-langs.el
 and changed files.el keyboard.c simple.el xterm.c xdisp.c rmail.el
   fileio.c process.c sysdep.c buffer.c xfns.c window.c subr.el
   configure.ac startup.el sendmail.el emacs.c Makefile.in editfns.c
-  info.el dired.el and 1338 other files
+  info.el dired.el and 1336 other files
 
 Richard Ryniker: changed sendmail.el
 
@@ -4777,7 +4787,7 @@ Robert Pluim: wrote nsm-tests.el
 and changed configure.ac process.c blocks.awk network-stream-tests.el
   font.c processes.texi ftfont.c gtkutil.c vc-git.el process-tests.el
   emoji-zwj.awk gnutls.el network-stream.el nsm.el tramp.texi mml-sec.el
-  nsterm.m unicode xfns.c auth.texi composite.c and 134 other files
+  nsterm.m unicode xfns.c auth.texi composite.c and 138 other files
 
 Robert Thorpe: changed cus-start.el indent.el rmail.texi
 
@@ -5033,6 +5043,7 @@ Sergey Poznyakoff: changed rmail.el mh-mime.el rmail.texi 
smtpmail.el
 Sergey Trofimov: changed window.el
 
 Sergey Vinokurov: changed emacs-module-tests.el emacs-module.c
+  memory-report.el
 
 Sergio Durigan Junior: changed eudcb-bbdb.el gdb-mi.el
 
@@ -5114,9 +5125,8 @@ and co-wrote gnus-sieve.el gssapi.el mml1991.el 
nnfolder.el nnimap.el
   nnml.el rot13.el sieve-manage.el
 and changed message.el gnus-sum.el gnus-art.el smtpmail.el pgg-gpg.el
   pgg.el gnus-agent.el mml2015.el mml.el gnus-group.el mm-decode.el
-  gnus-msg.el gnus.texi mail/sieve-manage.el pgg-pgp5.el browse-url.el
-  gnus-int.el gnus.el hashcash.el mm-view.el password.el
-  and 101 other files
+  gnus-msg.el gnus.texi pgg-pgp5.el browse-url.el gnus-int.el gnus.el
+  hashcash.el mm-view.el password.el gnus-cache.el and 99 other files
 
 Simon Lang: changed building.texi icomplete.el misterioso-theme.el
   progmodes/grep.el
@@ -5171,7 +5181,7 @@ and co-wrote help-tests.el keymap-tests.el
 and changed efaq.texi checkdoc.el package.el cperl-mode.el bookmark.el
   help.el keymap.c subr.el simple.el erc.el ediff-util.el idlwave.el
   time.el bytecomp-tests.el comp.el speedbar.el bytecomp.el edebug.el
-  emacs-lisp-intro.texi flyspell.el ibuffer.el and 1337 other files
+  emacs-lisp-intro.texi flyspell.el ibuffer.el and 1344 other files
 
 Stefan Merten: co-wrote rst.el
 
@@ -5188,7 +5198,7 @@ and co-wrote font-lock.el gitmerge.el pcvs.el
 and changed subr.el simple.el keyboard.c bytecomp.el cl-macs.el files.el
   lisp.h vc.el xdisp.c alloc.c eval.c sh-script.el progmodes/compile.el
   keymap.c buffer.c window.c tex-mode.el lisp-mode.el newcomment.el
-  help-fns.el lread.c and 1616 other files
+  help-fns.el lread.c and 1612 other files
 
 Stefano Facchini: changed gtkutil.c
 
@@ -5336,10 +5346,9 @@ Svante Carl V. Erichsen: changed cl-indent.el
 Svend Tollak Munkejord: changed deuglify.el
 
 Sven Joachim: changed files.el de-refcard.tex dired-aux.el emacs.1
-  arc-mode.el dired-x.el doc/misc/gnus.texi em-cmpl.el em-hist.el
-  em-ls.el esh-cmd.el esh-ext.el esh-io.el files.texi gnus-sum.el
-  gnus.texi help.el make-dist message.el movemail.c mule.texi
-  and 9 other files
+  gnus.texi arc-mode.el dired-x.el em-cmpl.el em-hist.el em-ls.el
+  esh-cmd.el esh-ext.el esh-io.el files.texi gnus-sum.el help.el
+  make-dist message.el movemail.c mule.texi sed3v2.inp and 8 other files
 
 Sylvain Chouleur: changed gnus-icalendar.el icalendar.el
 
@@ -5366,7 +5375,7 @@ Takahashi Naoto: wrote ethio-util.el language/ethiopic.el 
latin-post.el
 and co-wrote latin-ltx.el quail.el
 and changed ethiopic.el fontset.el mule-conf.el
 
-Takai Kousuke: changed ccl.el image/compface.el
+Takai Kousuke: changed ccl.el compface.el
 
 Takeshi Yamada: changed fns.c
 
@@ -5471,7 +5480,7 @@ Thomas Dye: changed org.texi org-bibtex.el ob-R.el org.el
 
 Thomas Fitzsimmons: wrote soap-client.el
 and changed soap-inspect.el ldap.el eudc.texi eudc-vars.el eudc.el
-  ntlm.el url-http.el eudcb-ldap.el eudcb-bbdb.el ntlm-tests.el
+  ntlm.el url-http.el eudcb-bbdb.el eudcb-ldap.el ntlm-tests.el
   eudc-bob.el eudc-export.el eudcb-ph.el package.el README authinfo
   diary-lib.el display.texi eudc-hotlist.el eudcb-macos-contacts.el
   icalendar.el and 3 other files
@@ -5676,8 +5685,8 @@ Tsuchiya Masatoshi: changed gnus-art.el mm-view.el 
gnus-sum.el
 
 Tsugutomo Enami: changed frame.c keyboard.c configure.ac dispnew.c
   fileio.c process.c simple.el sysdep.c xdisp.c add-log.el bytecomp.el
-  editfns.c emacs-regex.c emacs-regex.h emacs.c frame.h gnus-group.el
-  netbsd.h nnheader.el nnimap.el perl-mode.el and 6 other files
+  editfns.c emacs.c frame.h gnus-group.el netbsd.h nnheader.el nnimap.el
+  perl-mode.el regex-emacs.c regex-emacs.h and 6 other files
 
 Tsuyoshi Akiho: changed gnus-sum.el nnrss.el
 
@@ -5786,6 +5795,8 @@ and changed ps-prin1.ps ps-bdf.el ps-prin0.ps 
blank-mode.el ps-prin3.ps
   easymenu.el loading.texi menu-bar.el misc.texi progmodes/compile.el
   ps-print-def.el ps-vars.el
 
+Visuwesh M: changed dired-aux.el
+
 Vitalie Spinu: changed comint.el eieio-base.el message.el ob-R.el
   ob-core.el ob-tangle.el subr.el
 
@@ -6051,6 +6062,6 @@ Zoran Milojevic: changed avoid.el
 উৎসব রায়: changed quail/indian.el
 
 Local Variables:
-mode: etc-authors
+mode: emacs-authors
 coding: utf-8
 End:
diff --git a/etc/DEBUG b/etc/DEBUG
index 7d2f810d07..f57e6f197b 100644
--- a/etc/DEBUG
+++ b/etc/DEBUG
@@ -661,10 +661,10 @@ Setting a breakpoint in the function 'x_error_quitter' 
and looking at
 the backtrace when Emacs stops inside that function will show what
 code causes the X protocol errors.
 
-Note that the -xrm option may have no effect when you make an Emacs
-process invoked with the -nw option a server and want to trace X
-protocol errors from subsequent invocations of emacsclient in a GUI
-frame.  In that case calling the initial Emacs via
+Note that the -xrm option may have no effect when you start a server
+in an Emacs session invoked with the -nw command-line option, and want
+to trace X protocol errors from GUI frames created by subsequent
+invocations of emacsclient.  In that case starting Emacs via
 
   emacs -nw --eval '(setq x-command-line-resources "emacs.synchronous: true")'
 
@@ -1036,6 +1036,42 @@ recovering the contents of Emacs buffers from a core 
dump file.  You
 might also find those commands useful for displaying the list of
 buffers in human-readable format from within the debugger.
 
+*** Debugging Emacs with LLDB
+
+On systems where GDB is not available, like macOS with M1 chip, you
+can also use LLDB for Emacs debugging.
+
+To start LLDB to debug Emacs, you can simply type "lldb ./emacs RET"
+at the shell prompt in directory of the Emacs executable, usually the
+'src' sub-directory of the Emacs tree).
+
+When you debug Emacs with LLDB, you should start LLDB in the directory
+where the Emacs executable was built.  That directory has an .lldbinit
+file that loads a Python module emacs_lldb.py from the 'etc' directory
+of the Emacs source tree.  The Python module defines "user-defined"
+commands for debugging Emacs.
+
+LLDB by default does not automatically load .lldbinit files in the
+current directory.  The simplest way to fix this is to add the
+following line to your ~/.lldbinit file (creating such a file if it
+doesn't already exist):
+
+  settings set target.load-cwd-lldbinit true
+
+Alternatively, you can type "lldb --local-lldbinit ./emacs RET".
+
+If everything worked, you should see something like "Emacs debugging
+support has been installed" after starting LLDB.  You can see which
+Emacs-specific commands are defined with
+
+  (lldb) help
+
+User-defined commands for Emacs debugging start with an "x".
+
+Please refer to the LLDB reference on the web for more information
+about LLDB.  If you already know GDB, you will also find a mapping
+from GDB commands to corresponding LLDB commands there.
+
 
 This file is part of GNU Emacs.
 
diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS
index bdcd943c37..7f95cdd39a 100644
--- a/etc/ERC-NEWS
+++ b/etc/ERC-NEWS
@@ -12,6 +12,96 @@ extensible IRC (Internet Relay Chat) client distributed with
 GNU Emacs since Emacs version 22.1.
 
 
+* Changes in ERC 5.5
+
+** Smarter buffer naming for withstanding collisions.
+ERC buffers now remain tied to their logical network contexts, even
+while offline.  These associations can survive regional server changes
+and the intercession of proxies.  As has long been practiced in other
+areas of Emacs, "uniquified" buffer renaming prevents collisions
+between buffers of different contexts.  ERC's approach prioritizes
+predictability over economy, favoring fully qualified suffixes without
+elided or omitted components.  Potential avenues for confusion remain
+but will die out with the adoption of emerging protocol extensions.
+
+** Option 'erc-rename-buffers' deprecated.
+The promises made by its old "on" state are now fully realized and
+enabled permanently by default.  Its old behavior when disabled has
+been preserved and will remain available (with warnings) for years to
+come.
+
+** Option 'erc-reuse-buffers' deprecated.
+This ancient option has been a constant source of confusion, as
+exhibited most recently when its "disabled" meaning was partially
+inverted.  Introduced in ERC 5.4 (Emacs 28.1), this regression saw
+existing channel buffers transparently reassociated instead of created
+anew.  The pre-5.4 "disabled" behavior has been restored and will
+remain accessible for the foreseeable future, warts and all (e.g.,
+with its often superfluous "/DIALED-HOST" suffixing always present).
+
+** Tighter auth-source integration with bigger changes on the horizon.
+The days of hit-and-miss auth-source queries are hopefully behind us.
+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".
+
+If you require SASL immediately, please participate in ERC development
+by volunteering to try (and give feedback on) edge features, one of
+which is SASL.  All known external offerings, past and present, are
+valiant efforts whose use is nevertheless discouraged.
+
+** Username argument for entry-point commands.
+Commands 'erc' and 'erc-tls' now accept a ':user' keyword argument,
+which, when present, becomes the first argument passed to the "USER"
+IRC command.  The traditional way of setting this globally, via
+'erc-email-userid', is still honored.
+
+** Additional display options for updated buffers.
+Additional flexibility is now available for controlling the behavior
+of newly created target buffers, especially during reconnection.
+
+** Improved handling of multiline prompt input.
+This means better detection and handling of intervening and trailing
+blanks when 'erc-send-whitespace-lines' is active.  New options have
+also been added for warning when input spans multiple lines.  Although
+off by default, new users are encouraged to enable them.
+
+** Miscellaneous behavioral changes impacting the user experience.
+A bug has been fixed that saw prompts being mangled, doubled, or
+erased in server buffers upon disconnection.  Instead, input prompts
+now collapse into an alternate form designated by the option
+'erc-prompt-hidden'.  Behavior differs for query and channel buffers
+but can be fine-tuned via the repurposed, formerly abandoned option
+'erc-hide-prompt'.
+
+A bug has been fixed affecting users of the Soju bouncer: outgoing
+messages during periods of heavy traffic no longer disappear.
+
+Although rare, server passwords containing white space are now handled
+correctly.
+
+** Miscellaneous behavioral changes in the library API.
+The function 'erc-network' always returns non-nil in server and target
+buffers belonging to a successfully established IRC connection, even
+after that connection has been closed.
+
+In 5.4, support for network symbols as keys was added for
+'erc-autojoin-channels-alist'.  This has been extended to include
+explicit symbols passed to 'erc-tls' and 'erc' as so-called
+network-context identifiers via a new ':id' keyword.  The latter
+carries wider significance beyond autojoin and can be used for
+unequivocally identifying a connection in a human-readable way.
+
+The function 'erc-auto-query', unused internally, and basically
+inscrutable when read, has been deprecated with no public replacement.
+This raises a related issue: if you use ERC as a library and need
+something only offered internally, please lobby to have it exported by
+writing to emacs-erc@gnu.org.
+
+
 * Changes in ERC 5.4.1
 
 ** No user-visible changes since ERC 5.4, but a few tweaks in some ERC
diff --git a/etc/NEWS b/etc/NEWS
index 19ca21f666..1317cd0128 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -39,16 +39,12 @@ C++ compiler to be present on your system.  If Emacs is not 
built with
 the option '--with-be-app', the resulting Emacs will only run in
 text-mode terminals.
 
-+++
-** Cairo drawing support has been enabled for Haiku builds.
 To enable Cairo support, ensure that the Cairo and FreeType
 development files are present on your system, and configure Emacs with
 '--with-be-cairo'.
 
----
-** Double buffering is now enabled on the Haiku operating system.
 Unlike X, there is no compile-time option to enable or disable
-double-buffering.  If you wish to disable double-buffering, change the
+double-buffering; it is always enabled.  To disable it, change the
 frame parameter 'inhibit-double-buffering' instead.
 
 ---
@@ -59,7 +55,7 @@ If a constant file name is required, the file can be renamed 
to
 "emacs.pdmp", and Emacs will find it during startup anyway.
 
 ---
-** Emacs now uses of XInput 2 for input events.
+** Emacs now uses XInput 2 for input events.
 If your X server has support and you have the XInput 2 development
 headers installed, Emacs will use the X Input Extension for handling
 input.  If this causes problems, you can configure Emacs with the
@@ -81,11 +77,11 @@ by saying
 
     make -C leim generate-ja-dic JA_DIC_NO_REDUCTION_OPTION=''
 
-after deleting lisp/leim/ja-dic/ja-dic.el.
+after deleting "lisp/leim/ja-dic/ja-dic.el".
 
 +++
 ** Emacs now supports being built with pure GTK.
-To use this option, make sure the GTK 3 (version 3.20 or later) and
+To use this option, make sure the GTK 3 (version 3.22.23 or later) and
 Cairo development files are installed, and configure Emacs with the
 option '--with-pgtk'.  Unlike the default X and GTK build, the
 resulting Emacs binary will work on any underlying window system
@@ -116,6 +112,14 @@ Emacs Sessions" node in the Emacs manual for more details.
 
 * Startup Changes in Emacs 29.1
 
++++
+** '--batch' and '--script' now adjust the garbage collection levels.
+These switches now set 'gc-cons-percentage' to 1.0 (up from the
+default of 0.1).  This means that batch processes will typically use
+more memory than before, but use less time doing garbage collection.
+Batch jobs that are supposed to run for a long time should adjust the
+limit back down again.
+
 +++
 ** Emacs can now be used more easily in an executable script.
 If you start an executable script with
@@ -140,37 +144,77 @@ This is run at the end of the Emacs startup process, and 
is meant to
 be used to reinitialize structures that would normally be done at load
 time.
 
+** Native Compilation
+
 ---
-** New function 'startup-redirect-eln-cache'.
+*** New command 'native-compile-prune-cache'.
+This command deletes older ".eln" cache entries (but not the ones for
+the current Emacs version).
+
+---
+*** New function 'startup-redirect-eln-cache'.
 This function can be called in your init files to change the
 user-specific directory where Emacs stores the "*.eln" files produced
 by native compilation of Lisp packages Emacs loads.  The default
-eln-cache directory is unchanged: it is the 'eln-cache' subdirectory
+eln-cache directory is unchanged: it is the "eln-cache" subdirectory
 of 'user-emacs-directory'.
 
 
 * Incompatible changes in Emacs 29.1
 
 +++
-** 'E' in 'query-replace' now edits the replacement with exact case.
-Previously, this command did the same as 'e'.
+*** Explicitly-set read-only state is preserved when reverting a buffer.
+If you use the 'C-x C-q' command to change the read-only state of the
+buffer and then revert it, Emacs would previously use the file
+permission bits to determine whether the buffer should be read-only
+after reverting the buffer.  Emacs now remembers the decision made in
+'C-x C-q'.
 
 ---
-** '/ a' in *Packages* now limits by package name(s) instead of regexp.
+*** The Gtk selection face is no longer used for the region.
+The combination of a Gtk-controlled background and a foreground color
+controlled by the internal Emacs machinery led to low-contrast faces
+in common default setups.  Emacs now uses the same 'region' face on
+Gtk and non-Gtk setups.
 
-+++
-** Setting the goal columns now also affects '<prior>' and '<next>'.
-Previously, 'C-x C-n' only affected 'next-line' and 'previous-line',
-but it now also affects 'scroll-up-command' and 'scroll-down-command'.
+** Dired
 
 ---
-** The 'd' command in Dired now more consistently skip dot files.
-In previous Emacs versions, commands like `C-u 10 d' would put the "D"
+*** 'w' ('dired-copy-filename-as-kill') has changed behavior.
+If there are several files marked, file names containing space and
+quote characters will be quoted "like this".
+
+---
+*** The 'd' command now more consistently skips dot files.
+In previous Emacs versions, commands like 'C-u 10 d' would put the "D"
 mark on the next ten files, no matter whether they were dot files
 (i.e., "." and "..") or not, while marking the next ten lines with the
 mouse (in 'transient-mark-mode') and then hitting 'd' would skip dot
 files.  These now work equivalently.
 
++++
+** Warning about "eager macro-expansion failure" is changed into an error.
+
+---
+** Previously, the X "reverseVideo" value at startup was heeded for all frames.
+This meant that if you had a "reverseVideo" resource on the initial
+display, and then opened up a new frame on a display without any
+explicit "reverseVideo" setting, it would get heeded there, too.  (This
+included terminal frames.)  In Emacs 29, the "reverseVideo" X resource
+is handled like all the other X resources, and set on a per-frame basis.
+
++++
+** 'E' in 'query-replace' now edits the replacement with exact case.
+Previously, this command did the same as 'e'.
+
+---
+** '/ a' in "*Packages*" buffer now limits by archive name(s) instead of 
regexp.
+
++++
+** Setting the goal columns now also affects '<prior>' and '<next>'.
+Previously, 'C-x C-n' only affected 'next-line' and 'previous-line',
+but it now also affects 'scroll-up-command' and 'scroll-down-command'.
+
 ---
 ** Isearch in "*Help*" and "*info*" now char-folds quote characters by default.
 This means that you can say 'C-s `foo' (GRAVE ACCENT) if the buffer
@@ -288,18 +332,145 @@ variable set to nil, as it will default to nil in a 
future Emacs
 version and will be removed some time after that.
 
 +++
-** Functions which recreate the "*scratch*" buffer now also initialize it.
+** Functions that recreate the "*scratch*" buffer now also initialize it.
 When functions like 'other-buffer' and 'server-execute' recreate
 "*scratch*", they now also insert 'initial-scratch-message' and set
 the major mode according to 'initial-major-mode', like at Emacs
 startup.  Previously, these functions ignored
 'initial-scratch-message' and left "*scratch*" in 'fundamental-mode'.
 
+---
+** The autoarg.el library is now marked obsolete.
+This library provides the 'autoarg-mode' and 'autoarg-kp-mode' minor
+modes to emulate the behavior of the historical editor Twenex Emacs.
+It is believed to no longer be useful.
+
+---
+** The quickurl.el library is now obsolete.
+Use 'abbrev', 'skeleton' or 'tempo' instead.
+
+---
+** The rlogin.el library, and the 'rsh' command are now obsolete.
+Use something like 'M-x shell RET ssh <host> RET' instead.
+
+---
+** The url-about.el library is now obsolete.
+
+---
+** The autoload.el library is now obsolete.
+It is superseded by the loaddefs-gen.el library.
+
+---
+** The netrc.el library is now obsolete.
+Use the 'auth-source-netrc-parse-all' function in auth-source.el
+instead.
+
+---
+** The url-dired.el library is now obsolete.
+
+---
+** The fast-lock.el and lazy-lock.el library have been removed.
+They have been obsolete since Emacs 22.1.
+
+The variable 'font-lock-support-mode' is occasionally useful for
+debugging purposes.  It is now a regular variable (instead of a user
+option) and can be set to nil to disable Just-in-time Lock mode.
+
 
 * Changes in Emacs 29.1
 
 ---
-** Files with the '.eld' extension are now visited in 'lisp-data-mode'.
+** New user option 'electric-quote-replace-consecutive'.
+
+---
+** Emacs is now capable of editing files with very long lines.
+The display of long lines has been optimized, and Emacs should no
+longer choke when a buffer on display contains long lines.  The
+variable 'long-line-threshold' controls whether and when these display
+optimizations are in effect.
+
+A companion variable 'large-hscroll-threshold' controls when another
+set of display optimizations are in effect, which are aimed
+specifically at speeding up display of long lines that are truncated.
+
+If you still experience slowdowns while editing files with long lines,
+this may be due to line truncation, or to one of the enabled minor
+modes, or to the current major mode.  Try turning off line truncation
+with 'C-x x t', or try disabling all known slow minor modes with
+'M-x so-long-minor-mode', or try disabling both known slow minor modes
+and the major mode with 'M-x so-long-mode', or visit the file with
+'M-x find-file-literally' instead of the usual 'C-x C-f'.
+
+Note that the display optimizations in these cases may cause the
+buffer to be occasionally mis-fontified.
+
+The new function 'long-line-optimizations-p' returns non-nil when
+these optimizations are in effect in the current buffer.
+
++++
+** New command to change the font size globally.
+To increase the font size, type 'C-x C-M-+' or 'C-x C-M-='; to
+decrease it, type 'C-x C-M--'; to restore the font size, type 'C-x
+C-M-0'.  The final key in these commands may be repeated without the
+leading 'C-x' and without the modifiers, e.g. 'C-x C-M-+ C-M-+ C-M-+'
+and 'C-x C-M-+ + +' increase the font size by three steps.  When
+'mouse-wheel-mode' is enabled, 'C-M-wheel-up' and 'C-M-wheel-down' also
+increase and decrease the font size globally.  Additionally, the
+user option 'global-text-scale-adjust-resizes-frames' controls whether
+the frames are resized when the font size is changed.
+
++++
+** New function 'file-parent-directory'.
+Get the parent directory of a file.
+
+** New config variable 'syntax-wholeline-max' to reduce the cost of long lines.
+This variable is used by some operations (mostly syntax-propertization
+and font-locking) to treat lines longer than this variable as if they
+were made up of various smaller lines.  This can help reduce the
+slowdowns seen in buffers made of a single long line, but can also
+cause misbehavior in the presence of such long lines (tho most of that
+misbehavior should usually be limited to mis-highlighting).  You can
+recover the previous behavior with:
+
+    (setq syntax-wholeline-max most-positive-fixnum)
+
+---
+** New bindings in 'find-function-setup-keys' for 'find-library'.
+When 'find-function-setup-keys' is enabled, 'C-x L' is now bound to
+'find-library', 'C-x 4 L' is now bound to 'find-library-other-window'
+and 'C-x 5 L' is now bound to 'find-library-other-frame'.
+
++++
+** New key binding after 'M-x' or 'M-X': 'M-X'.
+Emacs allows different completion predicates to be used with 'M-x'
+(i.e., 'execute-extended-command') via the
+'read-extended-command-predicate' user option.  Emacs also has the
+'M-X' (note upper case) command, which only displays commands
+especially relevant to the current buffer.  Emacs now allows toggling
+between these modes while the user is inputting a command by hitting
+'M-X' while in the minibuffer.
+
+---
+** Interactively, 'kill-buffer' will now offer to save the buffer if unsaved.
+
+---
+** New commands 'duplicate-line' and 'duplicate-dwim'.
+'duplicate-line' duplicates the current line the specified number of times.
+'duplicate-dwim' duplicates the region if it is active.  If not, it
+works like 'duplicate-line'.  An active rectangular region is
+duplicated on its right-hand side.
+
+---
+** Files with the ".eld" extension are now visited in 'lisp-data-mode'.
+
++++
+** 'network-lookup-address-info' can now check numeric IP address validity.
+Specifying 'numeric' as the new optional 'hints' argument makes it
+check if the passed address is a valid IPv4/IPv6 address (without DNS
+traffic).
+
+    (network-lookup-address-info "127.1" 'ipv4 'numeric)
+    => ([127 0 0 1 0])
 
 +++
 ** New command 'find-sibling-file'.
@@ -317,6 +488,11 @@ This should be a regexp or a list of regexps; buffers 
whose names
 match those regexps will be ignored by 'switch-to-prev-buffer' and
 'switch-to-next-buffer'.
 
++++
+** New command 'rename-visited-file'.
+This command renames the file visited by the current buffer by moving
+it to a new location, and also makes the buffer visit this new file.
+
 ** Menus
 
 ---
@@ -365,6 +541,19 @@ This inhibits putting empty strings onto the kill ring.
 These options allow adjusting point and scrolling a window when
 dragging items from another program.
 
++++
+** The X Direct Save (XDS) protocol is now supported.
+This means dropping an image or file link from programs such as
+Firefox will no longer create a temporary file in a random directory,
+instead asking you where to save the file first.
+
++++
+** New user option 'record-all-keys'.
+If non-nil, this option will force recording of all input keys,
+including those typed in response to passwords prompt (this was the
+previous behavior).  The default is nil, which inhibits recording of
+passwords.
+
 +++
 ** New function 'command-query'.
 This function makes its argument command prompt the user for
@@ -417,6 +606,12 @@ mixed.
 This inherits from the 'mode-line' face, but is the face actually used
 on the mode lines (along with 'mode-line-inactive').
 
++++
+** New face attribute pseudo-value 'reset'.
+This value stands for the value of the corresponding attribute of the
+'default' face.  It can be used to reset attribute values produced by
+inheriting from other faces.
+
 +++
 ** New function 'buffer-text-pixel-size'.
 This is similar to 'window-text-pixel-size', but can be used when the
@@ -433,13 +628,30 @@ This controls the style of the pre-edit and status areas 
of X input
 methods.
 
 +++
-** On X11, Emacs now tries to synchronize window resize with the window 
manager.
+** New X resources: "highlightForeground" and "highlightBackground".
+Only in the Lucid build, this controls colors used for highlighted
+menu item widgets.
+
++++
+** On X, Emacs now tries to synchronize window resize with the window manager.
 This leads to less flicker and empty areas of a frame being displayed
 when a frame is being resized.  Unfortunately, it does not work on
 some ancient buggy window managers, so if Emacs appears to freeze, but
 is still responsive to input, you can turn it off by setting the X
 resource "synchronizeResize" to "off".
 
++++
+** On X, Emacs can optionally synchronize display with the graphics hardware.
+When this is enabled by setting the X resource "synchronizeResize" to
+"extended", frame content "tearing" is drastically reduced.  This is
+only supported on the Motif, Lucid, and no-toolkit builds, and
+requires an X compositing manager supporting the extended frame
+synchronization protocol (see
+https://fishsoup.net/misc/wm-spec-synchronization.html).
+
+This behavior can be toggled on and off via the frame parameter
+'use-frame-synchronization'.
+
 +++
 ** New frame parameter 'alpha-background' and X resource "alphaBackground".
 This controls the opacity of the text background when running on a
@@ -502,6 +714,12 @@ This is in addition to previously-supported ways of 
discovering 24-bit
 color support: either via the "RGB" or "setf24" capabilities, or if
 the 'COLORTERM' environment variable is set to the value "truecolor".
 
+*** Select active regions with xterm selection support.
+On terminals with xterm setSelection support, the active region may be
+saved to the X primary selection, following the
+'select-active-regions' variable.  This support is enabled when
+'tty-select-active-regions' is non-nil.
+
 ** ERT
 
 +++
@@ -556,6 +774,11 @@ inserted.
 This command will tell you the name of the Emoji at point.  (This
 command also works for non-Emoji characters.)
 
+---
+*** New commands 'emoji-zoom-increase' and 'emoji-zoom-decrease'.
+These are bound to 'C-x 8 e +' and 'C-x 8 e -', respectively.  They
+can be used on any character, but are mainly useful for emoji.
+
 ---
 *** New input method 'emoji'.
 This allows you to enter emoji using short strings, eg ':face_palm:'
@@ -563,12 +786,20 @@ or ':scream:'.
 
 ** Help
 
+---
+*** Variable values displayed by 'C-h v' in "*Help*" are now font-locked.
+
++++
+*** New user option 'help-clean-buttons'.
+If non-nil, link buttons in "*Help*" will have any surrounding quotes
+removed.
+
 ---
 *** 'M-x apropos-variable' output now includes values of variables.
 
 +++
-*** New doc string syntax to indicate that symbols shouldn't be links.
-When displaying doc strings in "*Help*" buffers, strings that are
+*** New docstring syntax to indicate that symbols shouldn't be links.
+When displaying docstrings in "*Help*" buffers, strings that are
 "`like-this'" are made into links (if they point to a bound
 function/variable).  This can lead to false positives when talking
 about values that are symbols that happen to have the same names as
@@ -658,11 +889,8 @@ or is itself too long.
 +++
 *** New user option 'outline-minor-mode-use-buttons'.
 If non-nil, Outline Minor Mode will use buttons to hide/show outlines
-in addition to the ellipsis.  The default is nil.
-
----
-*** New user option 'outline-minor-mode-buttons'.
-This is a list of pairs of open/close strings used to display buttons.
+in addition to the ellipsis.  The default is nil in editing modes, but
+non-nil in 'special-mode' and its derivatives.
 
 +++
 ** Support for the WebP image format.
@@ -673,6 +901,7 @@ specifiers can now use ':type webp'.
 
 ** Windows
 
++++
 *** New user option 'display-buffer-avoid-small-windows'.
 If non-nil, this should be a window height, a number.  Windows smaller
 than this will be avoided by 'display-buffer', if possible.
@@ -745,7 +974,7 @@ are met.  The conditions are given by the argument, which 
can be
 +++
 *** New user option 'rcirc-cycle-completion-flag'.
 Rcirc will use the default 'completion-at-point' mechanism.  The
-conventional IRC behaviour of completing by cycling through the
+conventional IRC behavior of completing by cycling through the
 available options can be restored by enabling this option.
 
 ** Imenu
@@ -758,6 +987,14 @@ available options can be restored by enabling this option.
 Use it if you want Imenu to forget the buffer's index alist and
 recreate it anew next time 'imenu' is invoked.
 
++++
+** Emacs is now capable of abandoning a window's redisplay that takes too long.
+This is controlled by the new variable 'max-redisplay-ticks'.  If that
+variable is set to a non-zero value, display of a window will be
+aborted after that many low-level redisplay operations, thus
+preventing Emacs from becoming wedged when visiting files with very
+long lines.
+
 * Editing Changes in Emacs 29.1
 
 +++
@@ -770,7 +1007,7 @@ option 'cycle-spacing-actions'.
 ** 'zap-to-char' and 'zap-up-to-char' are case-sensitive for upper-case chars.
 These commands now behave as case-sensitive for interactive calls when
 they are invoked with an uppercase character, regardless of the
-`case-fold-search' value.
+'case-fold-search' value.
 
 ---
 ** 'scroll-other-window' and 'scroll-other-window-down' now respect remapping.
@@ -841,6 +1078,12 @@ The user option 'comint-terminfo-terminal' and the 
variable
 'system-uses-terminfo' can now be set as connection-local variables to
 change the terminal used on a remote host.
 
+---
+*** New user option 'comint-delete-old-input'.
+When nil, this prevents comint from deleting the current input when
+inserting previous input using '<mouse-2>'.  The default is t, to
+preserve past behavior.
+
 ** Mwheel
 
 ---
@@ -870,31 +1113,31 @@ now has font-selection and character composition rules, 
a language
 environment, and an input method.  The newly-added scripts and the
 corresponding language environments are:
 
-**** Tai Tham script and the Northern Thai language environment
-**** Brahmi script and language environment
-**** Kaithi script and language environment
-**** Tirhuta script and language environment
-**** Sharada script and language environment
-**** Siddham script and language environment
-**** Syloti Nagri script and language environment
-**** Modi script and language environment
-**** Baybayin script and Tagalog language environment
-**** Hanunoo script and language environment
-**** Buhid script and language environment
-**** Tagbanwa script and language environment
-**** Limbu script and language environment
-**** Balinese script and language environment
-**** Javanese script and language environment
-**** Sundanese script and language environment
-**** Batak script and language environment
-**** Rejang script and language environment
-**** Makasar script and language environment
-**** Lontara script and language environment
-**** Hanifi Rohingya script and language environment
-**** Grantha script and language environment
-**** Kharoshthi script and language environment
-**** Lepcha script and language environment
-**** Meetei Mayek script and language environment
+Tai Tham script and the Northern Thai language environment
+Brahmi script and language environment
+Kaithi script and language environment
+Tirhuta script and language environment
+Sharada script and language environment
+Siddham script and language environment
+Syloti Nagri script and language environment
+Modi script and language environment
+Baybayin script and Tagalog language environment
+Hanunoo script and language environment
+Buhid script and language environment
+Tagbanwa script and language environment
+Limbu script and language environment
+Balinese script and language environment
+Javanese script and language environment
+Sundanese script and language environment
+Batak script and language environment
+Rejang script and language environment
+Makasar script and language environment
+Lontara script and language environment
+Hanifi Rohingya script and language environment
+Grantha script and language environment
+Kharoshthi script and language environment
+Lepcha script and language environment
+Meetei Mayek script and language environment
 
 ---
 *** The "Oriya" language environment was renamed to "Odia".
@@ -908,9 +1151,86 @@ supported.
 Type 'C-u C-h t' to select it in case your language setup does not do
 so automatically.
 
+---
+*** New default phonetic input method for the Tamil language environment.
+The default input method for the Tamil language environment is now
+"tamil-phonetic" which is a customizable phonetic input method.  To
+change the input method's translation rules, customize the user option
+'tamil-translation-rules'.
+
 
 * Changes in Specialized Modes and Packages in Emacs 29.1
 
+** Dired
+
++++
+*** 'dired-guess-shell-command' moved from dired-x to dired.
+This means that 'dired-do-shell-command' will now provide smarter
+defaults without first having to require 'dired-x'.  See the node
+"(emacs) Shell Command Guessing" in the Emacs manual for more details.
+
+---
+*** 'dired-clean-up-buffers-too' moved from dired-x to dired.
+This means that Dired now offers to kill buffers visiting files and
+dirs when they are deleted in Dired.  Before, you had to require
+'dired-x' to enable this behavior.  To disable this behavior,
+customize the user option 'dired-clean-up-buffers-too' to nil.  The
+related user option 'dired-clean-confirm-killing-deleted-buffers'
+(which see) has also been moved to 'dired'.
+
++++
+*** 'dired-do-relsymlink' moved from dired-x to dired.
+The corresponding key 'Y' is now bound by default in Dired.
+
++++
+*** 'dired-do-relsymlink-regexp' moved from dired-x to dired.
+The corresponding key '% Y' is now bound by default in Dired.
+
+---
+*** 'M-G' is now bound to 'dired-goto-subdir'.
+Before, that binding was only available if the dired-x package was
+loaded.
+
++++
+*** 'dired-info' and 'dired-man' moved from dired-x to dired.
+The 'dired-info' and 'dired-man' commands have been moved from the
+dired-x package to dired.  They have also been renamed to
+'dired-do-info' and 'dired-do-man'; the old command names are obsolete
+aliases.
+
+The keys 'I' ('dired-do-info') and 'N' ('dired-do-man') are now bound
+in Dired mode by default.  The user options 'dired-bind-man' and
+'dired-bind-info' no longer have any effect and are obsolete.
+
+To get the old behavior back and unbind these keys in Dired mode, add
+the following to your Init file:
+
+    (with-eval-after-load 'dired
+      (keymap-set dired-mode-map "N" nil)
+      (keymap-set dired-mode-map "I" nil))
+
+---
+*** New command 'dired-do-eww'.
+This command visits the file on the current line with EWW.
+
+** Elisp
+
+---
+*** New command 'elisp-eval-buffer' (bound to 'C-c C-e').
+This command evals the forms in the current buffer.
+
+---
+*** New commands 'elisp-byte-compile-file' and 'elisp-byte-compile-buffer'.
+These commands (bound to 'C-c C-f' and 'C-c C-b', respectively)
+byte-compile the visited file and the current buffer, respectively.
+
+** Games
+
+---
+*** New user option 'tetris-allow-repetitions'.
+This controls how randomness is implemented (whether to use pure
+randomness as before or whether to use a bag).
+
 ** Battery
 
 +++
@@ -922,7 +1242,7 @@ This can be used to trigger actions based on the battery 
status.
 +++
 *** New command 'enriched-toggle-markup'.
 This allows you to see the markup in 'enriched-mode' buffers (e.g.,
-the HELLO file).
+the "HELLO" file).
 
 ** Shell Script Mode
 
@@ -934,6 +1254,7 @@ This controls how statements like the following are 
indented:
         bar
 
 ** Cperl Mode
+
 ---
 *** New user option 'cperl-file-style'.
 This option determines the indentation style to be used.  It can also
@@ -946,6 +1267,12 @@ be used as a file-local variable.
 If given a prefix, it will query the user for an argument to use for
 the run/continue command.
 
+---
+*** 'perldb' now recognizes '-E'.
+As of Perl 5.10, 'perl -E 0' behaves like 'perl -e 0' but also activates
+all optional features of the Perl version in use.  'perldb' now uses
+this invocation as its default.
+
 ** Customize
 
 ---
@@ -953,6 +1280,14 @@ the run/continue command.
 This is bound to 'H' and toggles whether to hide or show the widget
 contents.
 
+** Diff mode
+
+---
+*** New user option 'diff-whitespace-style'.
+Sets the value of the buffer-local variable 'whitespace-style' in
+'diff-mode' buffers.  By default, this variable is '(face trailing)',
+which preserves behavior from previous Emacs versions.
+
 ** Ispell
 
 ---
@@ -982,6 +1317,11 @@ list-packages'.
 *** New command 'package-update-all'.
 This command allows updating all packages without any queries.
 
++++
+*** New commands 'package-recompile' and 'package-recompile-all'.
+These commands can be useful if the ".elc" files are out of date
+(invalid byte code and macros).
+
 +++
 *** New DWIM action on 'x' in "*Packages*" buffer.
 If no packages are marked, 'x' will install the package under point if
@@ -998,7 +1338,7 @@ inadvertently delete the "*scratch*" buffer.
 ** Debugging
 
 ---
-*** 'q' in a *Backtrace* buffer no longer clears the buffer.
+*** 'q' in a "*Backtrace*" buffer no longer clears the buffer.
 Instead it just buries the buffer and switches the mode from
 'debugger-mode' to 'backtrace-mode', since commands like 'e' are no
 longer available after exiting the recursive edit.
@@ -1008,7 +1348,25 @@ longer available after exiting the recursive edit.
 This user option controls whether the 'e' (in a "*Backtrace*"
 buffer or while edebugging) and 'C-x C-e' (while edebugging) commands
 lead to a (further) backtrace.  By default, this variable is nil,
-which is a change in behaviour from previous Emacs versions.
+which is a change in behavior from previous Emacs versions.
+
++++
+*** 'e' in edebug can now take a prefix arg to pretty-print the results.
+When invoked with a prefix argument, as in 'C-u e', this command will
+pop up a new buffer and show the full pretty-printed value there.
+
++++
+*** 'C-x C-e' now interprets a non-zero prefix arg to pretty-print the results.
+When invoked with a non-zero prefix argument, as in 'C-u C-x C-e',
+this command will pop up a new buffer and show the full pretty-printed
+value there.
+
++++
+*** You can now generate a backtrace from Lisp errors in redisplay.
+To do this, set the new variable 'backtrace-on-redisplay-error' to a
+non-nil value.  The backtrace will be written to a special buffer
+named "*Redisplay-trace*".  This buffer will not be automatically
+displayed in a window.
 
 ** Compile
 
@@ -1037,12 +1395,16 @@ files that have few newlines.
 +++
 ** New minor mode 'word-wrap-whitespace-mode' for extending 'word-wrap'.
 This mode switches 'word-wrap' on, and breaks on all the whitespace
-characters instead of just SPC and TAB.
+characters instead of just 'SPC' and 'TAB'.
 
 ---
 ** New mode, 'emacs-news-mode', for editing the NEWS file.
 This mode adds some highlighting, fixes the 'M-q' command, and has
-commands for doing maintenance.
+commands for doing maintenance of the Emacs NEWS files.  In addition,
+this mode turns on 'outline-minor-mode', and thus displays
+customizable icons (see 'icon-preference') on heading lines.  To
+disable these icons, customize 'outline-minor-mode-use-buttons' to a
+nil value.
 
 ---
 ** Kmacro
@@ -1098,9 +1460,9 @@ the completions if they are already visible.  The default 
value 't'
 always hides the completion buffer after some completion is made.
 
 *** New commands to complete the minibuffer history.
-'minibuffer-complete-history' ('C-x up') is like 'minibuffer-complete'
+'minibuffer-complete-history' ('C-x <up>') is like 'minibuffer-complete'
 but completes on the history items instead of the default completion
-table.  'minibuffer-complete-defaults' ('C-x down') completes
+table.  'minibuffer-complete-defaults' ('C-x <down>') completes
 on the list of default items.
 
 +++
@@ -1132,6 +1494,11 @@ This means that typing 'C-u RET' on a completion 
candidate in the
 "*Completions*" buffer inserts the completion to the minibuffer,
 but doesn't exit the minibuffer.
 
++++
+*** You can now define abbrevs for the fundamental minibuffer modes.
+'minibuffer-mode-abbrev-table' and
+'minibuffer-inactive-mode-abbrev-table' are now defined.
+
 ** Isearch and Replace
 
 +++
@@ -1141,6 +1508,11 @@ outside the echo area, Emacs will, by default, end the 
Isearch and
 yank the text at mouse cursor.  But if 'mouse-yank-at-point' is
 non-nil, the text will now be added to the Isearch instead.
 
++++
+*** Changes for values 'no' and 'no-ding' of 'isearch-wrap-pause'.
+Now with these values the search will wrap around not only on repeating
+with 'C-s C-s', but also after typing a character.
+
 +++
 *** New user option 'char-fold-override'.
 Non-nil means that the default definitions of equivalent characters
@@ -1153,11 +1525,24 @@ command accepts the Unicode name of an Emoji (for 
example, "smiling
 face" or "heart with arrow"), like 'C-x 8 e e', with minibuffer
 completion, and adds the Emoji into the search string.
 
+** Glyphless characters
+
 +++
-** New minor mode 'glyphless-display-mode'.
+*** New minor mode 'glyphless-display-mode'.
 This allows an easy way to toggle seeing all glyphless characters in
 the current buffer.
 
+*** The extra slot of 'glyphless-char-display' can now have cons values.
+The extra slot of the 'glyphless-char-display' char-table can now have
+values that are cons cells, specifying separate values for text-mode
+and GUI terminals.
+
+*** "Replacement character" feature for undisplayable characters on TTYs.
+The 'acronym' method of displaying glyphless characters on text-mode
+frames treats single-character acronyms specially: they are displayed
+without the surrounding [..] "box", thus in effect treating such
+"acronyms" as replacement characters.
+
 ** Registers
 
 +++
@@ -1223,7 +1608,7 @@ header before sending a message.
 ** Texinfo Mode
 
 ---
-*** 'texinfo-mode' now has a specialised 'narrow-to-defun' definition.
+*** 'texinfo-mode' now has a specialized 'narrow-to-defun' definition.
 It narrows to the current node.
 
 ** EUDC
@@ -1268,6 +1653,12 @@ EUDC can now contribute email addresses to 
'completion-at-point' by
 adding the new function 'eudc-capf-complete' to
 'completion-at-point-functions' in 'message-mode'.
 
++++
+*** Additional attributes of query and results in eudcb-macos-contacts.el.
+The EUDC back-end for the macOS Contacts app now provides a wider set
+of attributes to use for queries, and delivers more attributes in
+query results.
+
 ** EWW/SHR
 
 +++
@@ -1295,6 +1686,14 @@ doesn't work on other systems.  Also see etc/PROBLEMS.
 These are used to alter an URL before using it.  By default it removes
 the common "utm_" trackers from URLs.
 
+** Find-Dired
+
+---
+*** New command 'find-dired-with-command'.
+This enables users to run 'find-dired' with an arbitrary command,
+enabling running commands previously unsupported and also enabling new
+commands to be built on top.
+
 ** Gnus
 
 +++
@@ -1307,10 +1706,16 @@ Message, referred to as 'gnus-summary-tool-bar-retro',
 well as the icons used), and the "Gnome" tool bars are now the only
 pre-defined toolbars.
 
+---
+*** 'gnus-summary-up-thread' and 'gnus-summary-down-thread' bindings removed.
+The 'gnus-summary-down-thread' binding to "M-C-d" was shadowed by
+'gnus-summary-read-document', and these commands are also available on
+"T-u" and "T-d" respectively.
+
 ---
 *** Gnus now uses a variable-pitch font in the headers by default.
 To get the monospace font back, you can put something like the
-following in your .gnus file:
+following in your ".gnus" file:
 
     (set-face-attribute 'gnus-header nil :inherit 'unspecified)
 
@@ -1378,11 +1783,6 @@ The new ':doc-spec-function' element can be used to 
compute the
 ':doc-spec' element when the user asks for info on that particular
 mode (instead of at load time).
 
-** Subr-x
-
-+++
-*** New macro 'with-memoization' provides a very primitive form of memoization.
-
 ** Ansi-color
 
 ---
@@ -1476,6 +1876,21 @@ This controls whether or not to show a message when 
opening certain
 image formats saying how to edit it as text.  The default is to show
 this message for SVG and XPM.
 
++++
+*** New commands: 'image-flip-horizontally' and 'image-flip-vertically'.
+These commands horizontally and vertically flip the image under point.
+
++++
+*** New command 'image-transform-set-percent'.
+It allows setting the image size to a percentage of its original size,
+and is bound to "s p" in Image mode.
+
+** Images
+
++++
+*** Users can now add special image conversion functions.
+This is done via 'image-converter-add-handler'.
+
 ** Image-Dired
 
 +++
@@ -1579,6 +1994,11 @@ the thumbnail file.
 
 ** Dired
 
+---
+*** New user option 'dired-omit-lines'.
+This is used by 'dired-omit-mode', and now allows you to hide based on
+other things than just the file names.
+
 +++
 *** New user option 'dired-mouse-drag-files'.
 If non-nil, dragging file names with the mouse in a Dired buffer will
@@ -1603,7 +2023,31 @@ the buffer will take you to that directory.
 *** Search and replace in Dired/Wdired supports more regexps.
 For example, the regexp ".*" will match only characters that are part
 of the file name.  Also "^.*$" can be used to match at the beginning
-of the file name and at the end of the file name.
+of the file name and at the end of the file name.  This is used only
+when searching on file names.  In Wdired this can be used when the new
+user option 'wdired-search-replace-filenames' is non-nil (which is the
+default).
+
+** Bookmarks
+
+---
+*** 'list-bookmarks' now includes a type column.
+Types are registered via a 'bookmark-handler-type' symbol property on
+the jumping function.
+
++++
+*** 'bookmark-sort-flag' can now be set to 'last-modified'.
+This will display bookmark list from most recently set to least
+recently set.
+
+---
+*** When editing a bookmark annotation, 'C-c C-k' will now cancel.
+It is bound to the new command 'bookmark-edit-annotation-cancel'.
+
+---
+*** New option 'bookmark-fringe-mark'.
+This option controls the bitmap used to indicate bookmarks in the
+fringe (or 'nil' to disable showing this marker).
 
 ** Exif
 
@@ -1641,7 +2085,7 @@ This command displays a buffer containing the page load 
history of
 the current WebKit widget, and allows you to navigate it.
 
 ---
-*** On X11, the WebKit inspector is now available inside xwidgets.
+*** On X, the WebKit inspector is now available inside xwidgets.
 To access the inspector, right click on the widget and select "Inspect
 Element".
 
@@ -1674,6 +2118,12 @@ related 'auth-sources' entry were wrong.
 
 ** Browse URL
 
+---
+*** New user option 'browse-url-default-scheme'.
+This user option decides which URL scheme that 'browse-url' and
+related functions will use by default.  For example, you could
+customize this to "https" to always prefer HTTPS URLs.
+
 ---
 *** Support for the Netscape web browser has been removed.
 This support has been obsolete since Emacs 25.1.  The final version of
@@ -1684,6 +2134,11 @@ the Netscape web browser was released in February, 2008.
 This support has been obsolete since Emacs 25.1.  The final version of
 the Galeon web browser was released in September, 2008.
 
+---
+*** Support for the Mozilla web browser is now obsolete.
+Note that this historical web browser is different from Mozilla
+Firefox; it is its predecessor.
+
 ** Ruby Mode
 
 ---
@@ -1738,12 +2193,25 @@ values passed as a single token, such as '-oVALUE' or
 'eshell-eval-using-options' macro.  See "Defining new built-in
 commands" in the "(eshell) Built-ins" node of the Eshell manual.
 
+---
+*** Eshell globs ending with '/' now match only directories.
+Additionally, globs ending with '**/' or '***/' no longer raise an
+error, and now expand to all directories recursively (following
+symlinks in the latter case).
+
++++
+*** Lisp forms in Eshell now treat a 'nil' result as a failed exit status.
+When executing a command that looks like '(lisp form)', Eshell will
+set the exit status (available in the '$?' variable) to 2.  This
+allows commands like that to be used as conditionals.  To change this
+behavior, customize the new 'eshell-lisp-form-nil-is-failure' option.
+
 ** Shell
 
 ---
 *** New user option 'shell-kill-buffer-on-exit'.
-Enabling this will automatically kill a *shell* buffer as soon as the
-shell session terminates.
+Enabling this will automatically kill a "*shell*" buffer as soon as
+the shell session terminates.
 
 ** Calc
 
@@ -1753,11 +2221,28 @@ Set it to nil to exclude line numbering from kills and 
copies.
 
 ** Miscellaneous
 
+---
+*** New user option 'webjump-use-internal-browser'.
+When non-nil, WebJump will use an internal browser to open web pages,
+instead of the default external browser.
+
 +++
 *** New user option 'font-lock-ignore'.
 This option provides a mechanism to selectively disable font-lock
 keyword-driven fontifications.
 
+---
+*** New user option 'auto-save-visited-predicate'.
+This user option is a predicate function which is called by
+'auto-save-visited-mode' to decide whether or not to save a buffer.
+You can use it to automatically save only specific buffers, for
+example buffers using a particular mode or in some directory.
+
+---
+*** New user option 'remote-file-name-inhibit-auto-save-visited'.
+If this user option is non-nil, 'auto-save-visited-mode' will not
+auto-save remote buffers.  The default is nil.
+
 +++
 *** New package vtable.el for formatting tabular data.
 This package allows formatting data using variable-pitch fonts.
@@ -1765,16 +2250,6 @@ The resulting tables can display text in variable pitch 
fonts, text
 using fonts of different sizes, and images.  See the "(vtable) Top"
 manual for more details.
 
----
-*** 'list-bookmarks' now includes a type column.
-Types are registered via a 'bookmark-handler-type' symbol property on
-the jumping function.
-
-+++
-*** 'bookmark-sort-flag' can now be set to 'last-modified'.
-This will display bookmark list from most recently set to least
-recently set.
-
 ---
 *** New minor mode 'elide-head-mode'.
 Enabling this minor mode turns on hiding header material, like
@@ -1787,19 +2262,47 @@ If non-nil, files untracked by a VCS are considered to 
be part of
 the project by a VC project based on that VCS.
 
 ---
-** The autoarg.el library is now marked obsolete.
-This library provides the 'autoarg-mode' and 'autoarg-kp-mode' minor
-modes to emulate the behavior of the historical editor Twenex Emacs.
-It is believed to no longer be useful.
+*** 'recentf-mode' now uses abbreviated file names by default.
+This means that e.g. "/home/foo/bar" is now displayed as "~/bar".
+Customize the user option 'recentf-filename-handlers' to nil to get
+back the old behavior.
+
+---
+*** New command 'recentf-open'.
+This command prompts for a recently opened file in the minibuffer, and
+visits it.
+
+---
+*** 'ffap-machine-at-point' no longer pings hosts by default.
+It will now simply look at a hostname to determine if it is valid,
+instead of also trying to ping it.  Customize the user option
+'ffap-machine-p-known' to 'ping' to get the old behavior back.
+
+---
+*** The 'run-dig' command is now obsolete; use 'dig' instead.
+
+---
+*** Some `bib-mode' commands and variables have been renamed.
+To respect Emacs naming conventions, the variable 'unread-bib-file'
+has been renamed to 'bib-unread-file'.  The following commands have
+also been renamed:
+    'addbib'           to  'bib-add'
+    'return-key-bib'   to  'bib-return-key'
+    'mark-bib'         to  'bib-mark'
+    'unread-bib'       to  'bib-unread'
 
 ---
-** proced.el shows system processes of remote hosts.
+*** proced.el shows system processes of remote hosts.
 When 'default-directory' is remote, and 'proced' is invoked with a
 negative argument like 'C-u - proced', the system processes of that
 remote host are shown.  Alternatively, the user option
 'proced-show-remote-processes' can be set to non-nil.
 'proced-signal-function' has been marked obsolete.
 
+---
+*** 'outlineify-sticky' command is renamed to 'allout-outlinify-sticky'.
+The old name is still available as an obsolete function alias.
+
 
 * New Modes and Packages in Emacs 29.1
 
@@ -1808,6 +2311,7 @@ remote host are shown.  Alternatively, the user option
 Allows the creation of "functions with slots" or "function objects"
 via the macros 'oclosure-define' and 'oclosure-lambda'.
 
++++
 *** New generic function 'oclosure-interactive-form'.
 Used by 'interactive-form' when called on an OClosure.
 This allows specific OClosure types to compute their interactive specs
@@ -1823,23 +2327,46 @@ This mode is used to edit files geared towards testing 
actions in
 Emacs buffers, like indentation and the like.  The new ert function
 'ert-test-erts-file' is used to parse these files.
 
+---
+** New mode 'js-json-mode'.
+This is a lightweight variant of 'js-mode' that is used by default
+when visiting JSON files.
+
 
 * Incompatible Lisp Changes in Emacs 29.1
 
+---
+** 'find-image' now uses 'create-image'.
+This means that images found through 'find-image' also have
+auto-scaling applied.  (This only makes a difference on HiDPI
+displays.)
+
 +++
-** loaddefs.el generation has been reimplemented.
-The various loaddefs.el files in the Emacs tree (which contain
+** Changes to "raw" in-memory xbm images are specified.
+Some years back Emacs gained the ability to scale images, and you
+could then specify ':width' and ':height' when using 'create-image' on all
+image types -- except xbm images, because this format already used the
+':width' and ':height' arguments to specify the width/height of the "raw"
+in-memory format.  This meant that if you used these specifications
+on, for instance, xbm files, Emacs would refuse to display them.  This
+has been changed, and ':width'/':height' now works as with all other image
+formats, and the way to specify the width/height of the "raw"
+in-memory format is now by using ':data-width' and ':data-height'.
+
++++
+** "loaddefs.el" generation has been reimplemented.
+The various "loaddefs.el" files in the Emacs tree (which contain
 information about autoloads, built-in packages and package prefixes)
-used to be generated by functions in autoloads.el.  These are now
-generated by loaddefs-gen.el instead.  This leads to functionally
+used to be generated by functions in "autoloads.el".  These are now
+generated by "loaddefs-gen.el" instead.  This leads to functionally
 equivalent loaddef files, but they do not use exactly the same syntax,
 so using 'M-x update-file-autoloads' no longer works.  (This didn't
 work well in most files in the past, either, but it will now signal an
 error in any file.)
 
 In addition, files are scanned in a slightly different way.
-Previously ;;;### specs inside a top-level form (i.e., something like
-(when ... ;;;### ...) would be ignored.  They are now parsed as
+Previously ';;;###' specs inside a top-level form (i.e., something
+like '(when ... ;;;### ...)' would be ignored.  They are now parsed as
 normal.
 
 +++
@@ -1880,6 +2407,12 @@ they will still be escaped, so the '.foo' symbol is 
still printed as
 and remapping parent of basic faces does not work reliably.
 Instead of remapping 'mode-line', you have to remap 'mode-line-active'.
 
++++
+** 'make-process' has been extended to support ptys when ':stderr' is set.
+Previously, setting ':stderr' to a non-nil value would force the
+process's connection to use pipes.  Now, Emacs will use a pty for
+stdin and stdout if requested no matter the value of ':stderr'.
+
 ---
 ** User option 'mail-source-ignore-errors' is now obsolete.
 The whole mechanism for prompting users to continue in case of
@@ -1964,14 +2497,85 @@ Use 'exif-parse-file' and 'exif-field' instead.
 ** 'insert-directory' alternatives should not change the free disk space line.
 This change is now applied in 'dired-insert-directory'.
 
+---
+** 'compilation-last-buffer' is (finally) declared obsolete.
+It's been obsolete since Emacs-22.1, actually.
+
+---
+** Calling 'lsh' now elicits a byte-compiler warning.
+'lsh' behaves in somewhat surprising and platform-dependent ways for
+negative arguments, and is generally slower than 'ash', which should be
+used instead.  This warning can be suppressed by surrounding calls to
+'lsh' with the construct '(with-suppressed-warnings ((suspicious lsh)) ...)',
+but switching to `ash` is generally much preferable.
+
+---
+** Some functions and variables obsolete since Emacs 24 have been removed:
+'Info-edit-map', 'allout-abbreviate-flattened-numbering',
+'allout-mode-deactivate-hook', 'ansi-color-unfontify-region',
+'auth-source-forget-user-or-password', 'auth-source-hide-passwords',
+'auth-source-user-or-password', 'bibtex-complete',
+'bibtex-entry-field-alist', 'buffer-substring-filters',
+'byte-compile-disable-print-circle', 'cfengine-mode-abbrevs',
+'chart-map', 'comint-dynamic-complete',
+'comint-dynamic-complete-as-filename',
+'comint-dynamic-simple-complete', 'command-history-map',
+'compilation-parse-errors-function', 'completion-annotate-function',
+'condition-case-no-debug', 'count-lines-region', 'data-debug-map',
+'deferred-action-list', 'deferred-action-function',
+'dired-x-submit-report', 'eieio-defgeneric', 'eieio-defmethod',
+'emacs-lock-from-exiting', 'erc-complete-word',
+'eshell-cmpl-suffix-list', 'eshell-for', 'font-lock-maximum-size',
+'font-lock-reference-face', 'gnus-carpal',
+'gnus-debug-exclude-variables', 'gnus-debug-files',
+'gnus-local-domain', 'gnus-outgoing-message-group',
+'gnus-secondary-servers', 'gnus-registry-user-format-function-M',
+'image-extension-data', 'image-library-alist',
+'inhibit-first-line-modes-regexps',
+'inhibit-first-line-modes-suffixes', 'intdos',
+'mail-complete-function', 'mail-completion-at-point-function',
+'mail-mailer-swallows-blank-line', 'mail-sent-via', 'make-register',
+'makefile-complete', 'menu-bar-kill-ring-save',
+'meta-complete-symbol', 'meta-mode-map',
+'minibuffer-completing-symbol',
+'minibuffer-local-filename-must-match-map', 'mode25', 'mode4350',
+'msb-after-load-hooks', 'nnimap-split-rule', 'nntp-authinfo-file',
+'ns-alternatives-map', 'ns-store-cut-buffer-internal',
+'package-menu-view-commentary', 'pascal-last-completions',
+'pascal-show-completions', 'pascal-toggle-completions',
+'prolog-char-quote-workaround', 'read-filename-at-point',
+'reftex-index-map', 'reftex-index-phrases-map',
+'reftex-select-bib-map', 'reftex-select-label-map', 'reftex-toc-map',
+'register-name-alist', 'register-value',
+'report-emacs-bug-pretest-address',
+'rmail-default-dont-reply-to-names', 'rmail-dont-reply-to',
+'rmail-dont-reply-to-names', 'rst-block-face', 'rst-comment-face',
+'rst-definition-face', 'rst-directive-face', 'rst-emphasis1-face',
+'rst-emphasis2-face', 'rst-external-face', 'rst-literal-face',
+'rst-reference-face', 'semantic-grammar-map',
+'semantic-grammar-syntax-table', 'set-register-value',
+'speedbar-key-map', 'speedbar-syntax-table',
+'starttls-any-program-available', 'strokes-report-bug',
+'toggle-emacs-lock', 'tooltip-use-echo-area', 'turn-on-cwarn-mode',
+'turn-on-iimage-mode', 'vc-toggle-read-only', 'view-return-to-alist',
+'view-return-to-alist-update', 'w32-default-color-map' (function),
+'which-func-mode' (function), 'x-cut-buffer-or-selection-value'.
+
 ---
 ** Some functions and variables obsolete since Emacs 23 have been removed:
 'find-emacs-lisp-shadows', 'newsticker-cache-filename',
+'process-filter-multibyte-p', 'redisplay-end-trigger-functions',
+'set-process-filter-multibyte', 'set-window-redisplay-end-trigger',
 'unify-8859-on-decoding-mode', 'unify-8859-on-encoding-mode',
-'vc-arch-command'.
+'vc-arch-command', 'window-redisplay-end-trigger', 'x-selection'.
+
+---
+** Some functions and variables obsolete since Emacs 21 or 22 have been 
removed:
+'c-toggle-auto-state', 'find-file-not-found-hooks',
+'ls-lisp-dired-ignore-case', 'query-replace-regexp-eval'.
 
 +++
-** New generic function 'function-doumentation'.
+** New generic function 'function-documentation'.
 Can dynamically generate a raw docstring depending on the type of
 a function.
 Used mainly for docstrings of OClosures.
@@ -1994,11 +2598,100 @@ functions.
 ---
 ** '?\' at the end of a line now signals an error.
 Previously it produced a nonsense value, -1, that was never intended.
+
+---
+** Some libraries obsolete since Emacs 24.1 and 24.3 have been removed:
+abbrevlist.el, assoc.el, complete.el, cust-print.el,
+erc-hecomplete.el, mailpost.el, mouse-sel.el, old-emacs-lock.el,
+patcomp.el, pc-mode.el, pc-select.el, s-region.el, and sregex.el.
+
++++
+** Many seldom-used generalized variables have been made obsolete.
+Emacs has a number of rather obscure generalized variables defined,
+that, for instance, allowed you to say things like:
+
+   (setf (point-min) 4)
+
+These never caught on and have been made obsolete.  The form above,
+for instance, is the same as saying
+
+   (narrow-to-region 4 (point-max))
+
+The following generalized variables have been made obsolete:
+'buffer-file-name', 'buffer-local-value', 'buffer-modified-p',
+'buffer-name', 'buffer-string', 'buffer-substring', 'current-buffer',
+'current-column', 'current-global-map', 'current-input-mode',
+'current-local-map', 'current-window-configuration',
+'default-file-modes', 'documentation-property', 'frame-height',
+'frame-width', 'frame-visible-p', 'global-key-binding',
+'local-key-binding', 'mark', 'mark-marker', 'marker-position',
+'mouse-position', 'point', 'point-marker', 'point-max', 'point-min',
+'read-mouse-position', 'screen-height', 'screen-width',
+'selected-frame', 'selected-screen', 'selected-window',
+'standard-case-table', 'syntax-table', 'visited-file-modtime',
+'window-height', 'window-width', and 'x-get-secondary-selection'.
+
 
 * Lisp Changes in Emacs 29.1
 
 +++
-** 'read-regexp' now allows the user to indicate whether to use case folding.
+** New function 'make-obsolete-generalized-variable'.
+This can be used to mark setters used by 'setf' as obsolete, and the
+byte-compiler will then warn about using them.
+
++++
+** New functions 'pos-eol' and 'pos-bol'.
+These are like 'line-end-position' and 'line-beginning-position'
+(respectively), but ignore fields (and are more efficient).
+
++++
+** New function 'compiled-function-p'.
+This returns non-nil if its argument is either a built-in, or a
+byte-compiled, or a natively-compiled function object, or a function
+loaded from a dynamic module.
+
+---
+** 'deactivate-mark' can have new value 'dont-save'.
+This value means that Emacs should deactivate the mark as usual, but
+without setting the primary selection, if 'select-active-regions' is
+enabled.
+
++++
+** New 'declare' form 'interactive-args'.
+This can be used to specify what forms to put into 'command-history'
+when executing commands interactively.
+
++++
+** The FORM arg of 'time-convert' is mandatory.
+'time-convert' can still be called without it, as before, but the
+compiler now emits a warning about this deprecated usage.
+
++++
+** Emacs now supports user-customizable and themable icons.
+These can be used for buttons in buffers and the like.  See the
+"(elisp) Icons" and "(emacs) Icons" nodes in the manuals for details.
+
++++
+** New arguments MESSAGE and TIMEOUT of 'set-transient-map'.
+MESSAGE specifies a message to display after activating the transient
+map, including a special formatting spec to list available keys.
+TIMEOUT is the idle time after which to deactivate the transient map.
+The default timeout value can be defined by the new variable
+'set-transient-map-timeout'.
+
++++
+** New function 'seq-split'.
+This returns a list of sub-sequences of the specified sequence.
+
++++
+** 'plist-get', 'plist-put' and 'plist-member' are no longer limited to 'eq'.
+These function now take an optional comparison predicate argument.
+
++++
+** 'read-multiple-choice' can now use long-form answers.
+
++++
+** 'M-c' in 'read-regexp' now toggles case folding.
 
 +++
 ** 'completing-read' now allows a function as its REQUIRE-MATCH argument.
@@ -2022,15 +2715,28 @@ If DATA is a string, then its text properties are 
searched for values
 for each specific data type while the selection is being converted.
 
 ---
-** New eldoc function: 'elisp-eldoc-var-docstring-with-value'.
+** New eldoc function 'elisp-eldoc-var-docstring-with-value'.
 This function includes the current value of the variable in eldoc display
 and can be used as a more detailed alternative to 'elisp-eldoc-var-docstring'.
 
++++
 ** 'save-some-buffers' can now be extended to save other things.
 Traditionally, 'save-some-buffers' saved buffers, and also saved
 abbrevs.  This has been generalized via the
-'save-some-buffers-functions', and packages can now register things to
-be saved.
+'save-some-buffers-functions' variable, and packages can now register
+things to be saved.
+
++++
+** New function 'string-equal-ignore-case'.
+This compares strings ignoring case differences.
+
+** 'symbol-file' can now report natively-compiled ".eln" files.
+If Emacs was built with native-compilation enabled, Lisp programs can
+now call 'symbol-file' with the new optional 3rd argument non-nil to
+request the name of the ".eln" file which defined a given symbol.
+
++++
+** New macro 'with-memoization' provides a very primitive form of memoization.
 
 ** Themes
 
@@ -2058,6 +2764,20 @@ This is meant to be used in modes that have a header 
line that should
 be kept aligned with the buffer contents when the user switches
 'display-line-numbers-mode' on or off.
 
++++
+** New minor mode 'lost-selection-mode'.
+This minor mode makes Emacs deactivate the mark in all buffers when
+the primary selection is obtained by another program.
+
+---
+** On X, Emacs will try to preserve selection ownership when a frame is 
deleted.
+This means that if you make Emacs the owner of a selection, such as by
+selecting some text into the clipboard or primary selection, and then
+delete the current frame, you will still be able to insert the
+contents of that selection into other programs as long as another
+frame is open on the same display.  This behavior can be disabled by
+setting the user option 'x-auto-preserve-selections' to nil.
+
 +++
 ** New predicate 'char-uppercase-p'.
 This returns non-nil if its argument its an uppercase character.
@@ -2065,18 +2785,18 @@ This returns non-nil if its argument its an uppercase 
character.
 ** Byte compilation
 
 ---
-*** Byte compilation will now warn about some quoting mistakes in doc strings.
-When writing code snippets that contains the ' character (APOSTROPHE),
+*** Byte compilation will now warn about some quoting mistakes in docstrings.
+When writing code snippets that contains the "'" character (APOSTROPHE),
 that quote character has to be escaped to avoid Emacs displaying it as
-’ (LEFT SINGLE QUOTATION MARK), which would make code examples like
+"’" (LEFT SINGLE QUOTATION MARK), which would make code examples like
 
     (setq foo '(1 2 3))
 
 invalid.  Emacs will now warn during byte compilation if it seems
 something like that, and also warn about when using RIGHT/LEFT SINGLE
 QUOTATION MARK directly.  In both these cases, if these characters
-should really be present in the doc string, they should be quoted with
-\=.
+should really be present in the docstring, they should be quoted with
+"\=".
 
 ---
 *** Byte compilation will now warn about some malformed 'defcustom' types.
@@ -2089,12 +2809,12 @@ value.  The byte compiler will now issue a warning if 
it encounters
 these forms.
 
 +++
-*** 'restore-buffer-modified-p' can now alter buffer auto-save state.
+** 'restore-buffer-modified-p' can now alter buffer auto-save state.
 With a FLAG value of 'autosaved', it will mark the buffer as having
 been auto-saved since the time of last modification.
 
 ---
-*** New minor mode 'isearch-fold-quotes-mode'.
+** New minor mode 'isearch-fold-quotes-mode'.
 This sets up 'search-default-mode' so that quote characters are
 char-folded into each other.  It is used, by default, in "*Help*" and
 "*info*" buffers.
@@ -2178,9 +2898,10 @@ list in reported motion events if there is no frame 
underneath the
 mouse pointer.
 
 +++
-** New functions 'x-begin-drag', 'dnd-begin-text-drag' and 
'dnd-begin-file-drag'.
-These functions allow dragging contents (such as files and text) from
-Emacs to other programs.
+** New functions for dragging items from Emacs to other programs.
+The new functions 'x-begin-drag', 'dnd-begin-file-drag',
+'dnd-begin-drag-files', and 'dnd-direct-save' allow dragging contents
+(such as files and text) from Emacs to other programs.
 
 ---
 ** New function 'ietf-drums-parse-date-string'.
@@ -2247,7 +2968,7 @@ This is like 'get-text-property', but works on the 
'display' text
 property.
 
 +++
-** New function 'add-text-display-property'.
+** New function 'add-display-text-property'.
 This is like 'put-text-property', but works on the 'display' text
 property.
 
@@ -2278,6 +2999,12 @@ them towards or away from each other.
 This hook is run before 'x-popup-menu' is about to display a
 deck-of-cards menu on screen.
 
+---
+** New hook 'post-select-region-hook'.
+This hook is run immediately after 'select-active-regions' causes the
+region to be set as the primary selection.
+
++++
 ** New function 'buffer-match-p'.
 Check if a buffer satisfies some condition.  Some examples for
 conditions can be regular expressions that match a buffer name, a
@@ -2285,6 +3012,7 @@ cons-cell like '(major-mode . shell-mode)' that matches 
any buffer
 where 'major-mode' is 'shell-mode' or a combined with a condition like
 '(and "\\`\\*.+\\*\\'" (major-mode . special-mode))'.
 
++++
 ** New function 'match-buffers'.
 Use 'buffer-match-p' to gather a list of buffers that match a
 condition.
@@ -2322,6 +3050,12 @@ option.
 
 ** Keymaps and key definitions
 
++++
+*** 'where-is-internal' can now filter events marked as non key events.
+If a command maps to a key binding like '[some-event]', and 'some-event'
+has a symbol plist containing a non-nil 'non-key-event' property, then
+that binding is ignored by 'where-is-internal'.
+
 +++
 *** New functions for defining and manipulating keystrokes.
 These all take the syntax defined by 'key-valid-p'.  None of the older
@@ -2716,6 +3450,10 @@ when used as part of a property list specification for 
the
 ** 'defalias' records a more precise history of definitions.
 This is recorded in the 'function-history' symbol property.
 
+---
+** New hook 'save-place-after-find-file-hook'.
+This is called at the end of 'save-place-find-file-hook'.
+
 ---
 ** 'indian-tml-base-table' no longer translates digits.
 Use 'indian-tml-base-digits-table' if you want digits translation.
@@ -2730,12 +3468,21 @@ translation.
 This is useful when quoting shell arguments for a remote shell
 invocation.  Such shells are POSIX conformant by default.
 
++++
+** 'make-process' can set connection type independently for input and output.
+When calling 'make-process', communication via pty can be enabled
+selectively for just input or output by passing a cons cell for
+':connection-type', e.g. '(pipe . pty)'.  When examining a process
+later, you can determine whether a particular stream for a process
+uses a pty by passing one of 'stdin', 'stdout', or 'stderr' as the
+second argument to 'process-tty-name'.
+
 +++
 ** 'signal-process' now consults the list 'signal-process-functions'.
 This is to determine which function has to be called in order to
 deliver the signal.  This allows Tramp to send the signal to remote
 asynchronous processes.  The hitherto existing implementation has been
-moved to 'signal-default-interrupt-process'.
+moved to 'internal-default-signal-process'.
 
 +++
 ** 'list-system-processes' now returns remote process IDs.
@@ -2754,6 +3501,11 @@ to preserve the old behavior, apply
     (let ((default-directory temporary-file-directory))
       (process-attributes pid))
 
++++
+** New functions 'take' and 'ntake'.
+'(take N LIST)' returns the first N elements of LIST; 'ntake' does
+the same but works by modifying LIST destructively.
+
 
 
 * Changes in Emacs 29.1 on Non-Free Operating Systems
diff --git a/etc/NEWS.1-17 b/etc/NEWS.1-17
index ee6fa82b29..9d7bacc9ec 100644
--- a/etc/NEWS.1-17
+++ b/etc/NEWS.1-17
@@ -41,10 +41,10 @@ that Emacs has not been run on before.
 
 See etc/MACHINES.
 
-** Portable `alloca' provided.
+** Portable 'alloca' provided.
 
 Emacs can now run on machines that do not and cannot support the library
-subroutine `alloca' in the canonical fashion, using an `alloca' emulation
+subroutine 'alloca' in the canonical fashion, using an 'alloca' emulation
 written in C.
 
 ** On-line manual.
@@ -74,39 +74,39 @@ highest previously used.
 Thus, the active, current file does not have a version number.
 Only the backups have them.
 
-This feature is controlled by the variable `version-control'.  If it
-is `nil', as normally, then numbered backups are made only for files
+This feature is controlled by the variable 'version-control'.  If it
+is 'nil', as normally, then numbered backups are made only for files
 that already have numbered backups.  Backup names with just `~' are
 used for files that have no numbered backups.
 
-If `version-control' is `never', then the backup file's name is
+If 'version-control' is 'never', then the backup file's name is
 made with just `~' in any case.
 
-If `version-control' is not `nil' or `never', numbered backups are
+If 'version-control' is not 'nil' or 'never', numbered backups are
 made unconditionally.
 
 To prevent unlimited consumption of disk space, Emacs can delete
 old backup versions automatically.  Generally Emacs keeps the first
 few backups and the latest few backups, deleting any in between.
 This happens every time a new backup is made.  The two variables that
-control the deletion are `kept-old-versions' and `kept-new-versions'.
+control the deletion are 'kept-old-versions' and 'kept-new-versions'.
 Their values are, respectively, the number of oldest backups to keep
 and the number of newest ones to keep, each time a new backup is made.
-The value of `kept-new-versions' includes the backup just created.
+The value of 'kept-new-versions' includes the backup just created.
 By default, both values are 2.
 
-If `trim-versions-without-asking' is non-`nil', the excess middle versions
-are deleted without a murmur.  If it is `nil', the default, then you
+If 'trim-versions-without-asking' is non-'nil', the excess middle versions
+are deleted without a murmur.  If it is 'nil', the default, then you
 are asked whether the excess middle versions should really be deleted.
 
 Dired has a new command `.' which marks for deletion all but the latest
-and oldest few of every numeric series of backups.  `kept-old-versions'
-controls the number of oldest versions to keep, and `dired-kept-versions'
+and oldest few of every numeric series of backups.  'kept-old-versions'
+controls the number of oldest versions to keep, and 'dired-kept-versions'
 controls the number of latest versions to keep.  A numeric argument to
 the `.' command, if positive, specifies the number of latest versions
-to keep, overriding `dired-kept-versions'.  A negative argument specifies
+to keep, overriding 'dired-kept-versions'.  A negative argument specifies
 the number of oldest versions to keep, using minus the argument to override
-`kept-old-versions'.
+'kept-old-versions'.
 
 ** Immediate conflict detection.
 
@@ -182,17 +182,17 @@ is now C-c C-o, and C-x C-v (show output) is now C-c C-r.
 
 The old M-= (copy previous input) command is now C-c C-y.
 
-** Shell mode recognizes aliases for `pushd', `popd' and `cd'.
+** Shell mode recognizes aliases for 'pushd', 'popd' and 'cd'.
 
-Shell mode now uses the variable `shell-pushd-regexp' as a
+Shell mode now uses the variable 'shell-pushd-regexp' as a
 regular expression to recognize any command name that is
-equivalent to a `pushd' command.  By default it is set up
-to recognize just `pushd' itself.  If you use aliases for
-`pushd', change the regexp to recognize them as well.
+equivalent to a 'pushd' command.  By default it is set up
+to recognize just 'pushd' itself.  If you use aliases for
+'pushd', change the regexp to recognize them as well.
 
-There are also `shell-popd-regexp' to recognize commands
-with the effect of a `popd', and `shell-cd-regexp' to recognize
-commands with the effect of a `cd'.
+There are also 'shell-popd-regexp' to recognize commands
+with the effect of a 'popd', and 'shell-cd-regexp' to recognize
+commands with the effect of a 'cd'.
 
 ** "Exit" command in certain modes now C-c C-c.
 
@@ -203,7 +203,7 @@ modes, the command to exit used to be just C-c.
 ** Outline mode changes.
 
 Lines that are not heading lines are now called "body" lines.
-The command `hide-text' is renamed to `hide-body'.
+The command 'hide-text' is renamed to 'hide-body'.
 The key M-H is renamed to C-c C-h.
 The key M-S is renamed to C-c C-s.
 The key M-s is renamed to C-c C-i.
@@ -229,7 +229,7 @@ o now outputs to an Rmail file, and C-o to a Unix mail file.
 The F command (rmail-find) is renamed to M-s (rmail-search).
 Various new commands and features exist; see the Emacs manual.
 
-** Local bindings described first in describe-bindings.
+** Local bindings described first in 'describe-bindings'.
 
 ** [...], {...} now balance in Fundamental mode.
 
@@ -238,9 +238,9 @@ Various new commands and features exist; see the Emacs 
manual.
 There are two new major modes for editing nroff input and TeX input.
 See the Emacs manual for full information.
 
-** New C indentation style variable `c-brace-imaginary-offset'.
+** New C indentation style variable 'c-brace-imaginary-offset'.
 
-The value of `c-brace-imaginary-offset', normally zero, controls the
+The value of 'c-brace-imaginary-offset', normally zero, controls the
 indentation of a statement inside a brace-group where the open-brace
 is not the first thing on a line.  The value says where the open-brace
 is imagined to be, relative to the first nonblank character on the line.
@@ -251,47 +251,47 @@ Dired now normally keeps the cursor at the beginning of 
the file name,
 not at the beginning of the line.  The most used motion commands are
 redefined in Dired to position the cursor this way.
 
-`n' and `p' are now equivalent in dired to `C-n' and `C-p'.
+'n' and 'p' are now equivalent in dired to 'C-n' and 'C-p'.
 
 If any files to be deleted cannot be deleted, their names are
 printed in an error message.
 
-If the `v' command is invoked on a file which is a directory,
+If the 'v' command is invoked on a file which is a directory,
 dired is run on that directory.
 
-** `visit-tag-table' renamed `visit-tags-table'.
+** 'visit-tag-table' renamed 'visit-tags-table'.
 
-This is so apropos of `tags' finds everything you need to
+This is so apropos of 'tags' finds everything you need to
 know about in connection with Tags.
 
-** `mh-e' library uses C-c as prefix.
+** 'mh-e' library uses C-c as prefix.
 
-All the special commands of `mh-rmail' now are placed on a
+All the special commands of 'mh-rmail' now are placed on a
 C-c prefix rather than on the C-x prefix.  This is for
 consistency with other special modes with their own commands.
 
-** M-$ or `spell-word' checks word before point.
+** M-$ or 'spell-word' checks word before point.
 
 It used to check the word after point.
 
 ** Quitting during autoloading no longer causes trouble.
 
 Now, when a file is autoloaded, all function redefinitions
-and `provide' calls are recorded and are undone if you quit
+and 'provide' calls are recorded and are undone if you quit
 before the file is finished loading.
 
 As a result, it no longer happens that some of the entry points
 which are normally autoloading have been defined already, but the
 entire file is not really present to support them.
 
-** `else' can now be indented correctly in C mode.
+** 'else' can now be indented correctly in C mode.
 
-TAB in C mode now knows which `if' statement an `else' matches
-up with, and can indent the `else' correctly under the `if',
-even if the `if' contained such things as another `if' statement,
-or a `while' or `for' statement, with no braces around it.
+TAB in C mode now knows which 'if' statement an 'else' matches
+up with, and can indent the 'else' correctly under the 'if',
+even if the 'if' contained such things as another 'if' statement,
+or a 'while' or 'for' statement, with no braces around it.
 
-** `batch-byte-compile'
+** 'batch-byte-compile'
 
 Runs byte-compile-file on the files specified on the command line.
 All the rest of the command line arguments are taken as files to
@@ -300,10 +300,10 @@ Must be used only with -batch, and kills emacs on 
completion.
 Each file will be processed even if an error occurred previously.
 For example, invoke `emacs -batch -f batch-byte-compile *.el'.
 
-** `-batch' changes.
+** '-batch' changes.
 
-`-batch' now implies `-q': no init file is loaded by Emacs when
-`-batch' is used.  Also, no `term/TERMTYPE.el' file is loaded.  Auto
+'-batch' now implies '-q': no init file is loaded by Emacs when
+'-batch' is used.  Also, no `term/TERMTYPE.el' file is loaded.  Auto
 saving is not done except in buffers in which it is explicitly
 requested.  Also, many echo-area printouts describing what is going on
 are inhibited in batch mode, so that the only output you get is the
@@ -311,7 +311,7 @@ output you program specifically.
 
 One echo-area message that is not suppressed is the one that says
 that a file is being loaded.  That is because you can prevent this
-message by passing `t' as the third argument to `load'.
+message by passing 't' as the third argument to 'load'.
 
 ** Display of search string in incremental search.
 
@@ -324,12 +324,12 @@ is actually going on.
 ** View commands.
 
 The commands C-x ], C-x [, C-x /, C-x j and C-x o are now
-available inside `view-buffer' and `view-file', with their
+available inside 'view-buffer' and 'view-file', with their
 normal meanings.
 
 ** Full-width windows preferred.
 
-The ``other-window'' commands prefer other full width windows,
+The 'other-window' commands prefer other full width windows,
 and will split only full width windows.
 
 ** M-x rename-file can copy if necessary.
@@ -367,7 +367,7 @@ distance rather than a single column if used with no 
argument.
 
 ** Auto Save Files Deleted.
 
-The default value of `delete-auto-save-files' is now `t', so that
+The default value of 'delete-auto-save-files' is now 't', so that
 when you save a file for real, its auto save file is deleted.
 
 ** Rnews changes.
@@ -392,18 +392,18 @@ to specify files in which copies of the message should be 
put.
 The message is written into those files in Unix mail file format.
 The message as sent does not contain any Fcc fields in its header.
 You can use any number of Fcc fields, but only one file name in each one.
-The variable `mail-archive-file-name', if non-`nil', can be a string
+The variable 'mail-archive-file-name', if non-'nil', can be a string
 which is a file name; an Fcc to that file will be inserted in every
 message when you begin to compose it.
 
 A new command C-c q now exists in Mail mode.  It fills the
 paragraphs of an old message that had been inserted with C-c y.
 
-When the *mail* buffer is put in Mail mode, text-mode-hook
-is now run in addition to mail-mode-hook.  text-mode-hook
+When the *mail* buffer is put in Mail mode, 'text-mode-hook'
+is now run in addition to 'mail-mode-hook'.  text-mode-hook
 is run first.
 
-The new variable `mail-header-separator' now specifies the string
+The new variable 'mail-header-separator' now specifies the string
 to use on the line that goes between the headers and the message text.
 By default it is still "--text follows this line--".
 
@@ -434,38 +434,38 @@ with
 
    (defun foo-1 (x y z) ...
 
-** Functions `region-to-string' and `region-around-match' removed.
+** Functions 'region-to-string' and 'region-around-match' removed.
 
 These functions were made for compatibility with Gosling Emacs, but it
 turns out to be undesirable to use them in GNU Emacs because they use
 the mark.  They have been eliminated from Emacs proper, but are
 present in mlsupport.el for the sake of converted mocklisp programs.
 
-If you were using `region-to-string', you should instead use
-`buffer-substring'; then you can pass the bounds as arguments and
+If you were using 'region-to-string', you should instead use
+'buffer-substring'; then you can pass the bounds as arguments and
 can avoid setting the mark.
 
-If you were using `region-around-match', you can use instead
-the two functions `match-beginning' and `match-end'.  These give
+If you were using 'region-around-match', you can use instead
+the two functions 'match-beginning' and 'match-end'.  These give
 you one bound at a time, as a numeric value, without changing
 point or the mark.
 
-** Function `function-type' removed.
+** Function 'function-type' removed.
 
 This just appeared not to be very useful.  It can easily be written in
-Lisp if you happen to want it.  Just use `symbol-function' to get the
+Lisp if you happen to want it.  Just use 'symbol-function' to get the
 function definition of a symbol, and look at its data type or its car
 if it is a list.
 
-** Variable `buffer-number' removed.
+** Variable 'buffer-number' removed.
 
-You can still use the function `buffer-number' to find out
+You can still use the function 'buffer-number' to find out
 a buffer's unique number (assigned in order of creation).
 
-** Variable `executing-macro' renamed `executing-kbd-macro'.
+** Variable 'executing-macro' renamed 'executing-kbd-macro'.
 
 This variable is the currently executing keyboard macro, as
-a string, or `nil' when no keyboard macro is being executed.
+a string, or 'nil' when no keyboard macro is being executed.
 
 ** Loading term/$TERM.
 
@@ -478,15 +478,15 @@ term-$TERM; thus, for example, term-vt100.el, but now 
they live
 in a special subdirectory named term, and have names like
 term/vt100.el.
 
-** `command-history' format changed.
+** 'command-history' format changed.
 
 The elements of this list are now Lisp expressions which can
 be evaluated directly to repeat a command.
 
 ** Unused editing commands removed.
 
-The functions `forward-to-word', `backward-to-word',
-`upcase-char', `mark-beginning-of-buffer' and `mark-end-of-buffer'
+The functions 'forward-to-word', 'backward-to-word',
+'upcase-char', 'mark-beginning-of-buffer' and 'mark-end-of-buffer'
 have been removed.  Their definitions can be found in file
 lisp/unused.el if you need them.
 
@@ -496,53 +496,53 @@ lisp/unused.el if you need them.
 ** You can now continue after errors and quits.
 
 When the debugger is entered because of a C-g, due to
-a non-`nil' value of `debug-on-quit', the `c' command in the debugger
+a non-'nil' value of 'debug-on-quit', the 'c' command in the debugger
 resumes execution of the code that was running when the quit happened.
-Use the `q' command to go ahead and quit.
+Use the 'q' command to go ahead and quit.
 
 The same applies to some kinds of errors, but not all.  Errors
-signaled with the Lisp function `signal' can be continued; the `c'
-command causes `signal' to return.  The `r' command causes `signal' to
-return the value you specify.  The `c' command is equivalent to `r'
-with the value `nil'.
+signaled with the Lisp function 'signal' can be continued; the 'c'
+command causes 'signal' to return.  The 'r' command causes 'signal' to
+return the value you specify.  The 'c' command is equivalent to 'r'
+with the value 'nil'.
 
-For a `wrong-type-argument' error, the value returned with the `r'
+For a 'wrong-type-argument' error, the value returned with the 'r'
 command is used in place of the invalid argument.  If this new value
 is not valid, another error occurs.
 
-Errors signaled with the function `error' cannot be continued.
+Errors signaled with the function 'error' cannot be continued.
 If you try to continue, the error just happens again.
 
-** `dot' renamed `point'.
+** 'dot' renamed 'point'.
 
-The word `dot' has been replaced with `point' in all
+The word 'dot' has been replaced with 'point' in all
 function and variable names, including:
 
-  point, point-min, point-max,
-  point-marker, point-min-marker, point-max-marker,
-  window-point, set-window-point,
-  point-to-register, register-to-point,
-  exchange-point-and-mark.
+  'point', 'point-min', 'point-max',
+  'point-marker', 'point-min-marker', 'point-max-marker',
+  'window-point', 'set-window-point',
+  'point-to-register', 'register-to-point',
+  'exchange-point-and-mark'.
 
 The old names are still supported, for now.
 
-** `string-match' records position of end of match.
+** 'string-match' records position of end of match.
 
-After a successful call to `string-match', `(match-end 0)' will
+After a successful call to 'string-match', `(match-end 0)' will
 return the index in the string of the first character after the match.
-Also, `match-begin' and `match-end' with nonzero arguments can be
+Also, 'match-begin' and 'match-end' with nonzero arguments can be
 used to find the indices of beginnings and ends of substrings matched
 by subpatterns surrounded by parentheses.
 
-** New function `insert-before-markers'.
+** New function 'insert-before-markers'.
 
-This function is just like `insert' except in the handling of any
+This function is just like 'insert' except in the handling of any
 relocatable markers that are located at the point of insertion.
-With `insert', such markers end up pointing before the inserted text.
-With `insert-before-markers', they end up pointing after the inserted
+With 'insert', such markers end up pointing before the inserted text.
+With 'insert-before-markers', they end up pointing after the inserted
 text.
 
-** New function `copy-alist'.
+** New function 'copy-alist'.
 
 This function takes one argument, a list, and makes a disjoint copy
 of the alist structure.  The list itself is copied, and each element
@@ -550,32 +550,32 @@ that is a cons cell is copied, but the cars and cdrs of 
elements
 remain shared with the original argument.
 
 This is what it takes to get two alists disjoint enough that changes
-in one do not change the result of `assq' on the other.
+in one do not change the result of 'assq' on the other.
 
-** New function `copy-keymap'.
+** New function 'copy-keymap'.
 
 This function takes a keymap as argument and returns a new keymap
 containing initially the same bindings.  Rebindings in either one of
 them will not alter the bindings in the other.
 
-** New function `copy-syntax-table'.
+** New function 'copy-syntax-table'.
 
 This function takes a syntax table as argument and returns a new
 syntax table containing initially the same syntax settings.  Changes
 in either one of them will not alter the other.
 
-** Randomizing the random numbers.
+** Randomizing the 'random' numbers.
 
 `(random t)' causes the random number generator's seed to be set
 based on the current time and Emacs's process id.
 
-** Third argument to `modify-syntax-entry'.
+** Third argument to 'modify-syntax-entry'.
 
-The optional third argument to `modify-syntax-entry', if specified
+The optional third argument to 'modify-syntax-entry', if specified
 should be a syntax table.  The modification is made in that syntax table
 rather than in the current syntax table.
 
-** New function `run-hooks'.
+** New function 'run-hooks'.
 
 This function takes any number of symbols as arguments.
 It processes the symbols in order.  For each symbol which
@@ -584,29 +584,29 @@ called as a function, with no arguments.
 
 This is useful in major mode commands.
 
-** Second arg to `switch-to-buffer'.
+** Second arg to 'switch-to-buffer'.
 
-If this function is given a non-`nil' second argument, then the
+If this function is given a non-'nil' second argument, then the
 selection being done is not recorded on the selection history.
 The buffer's position in the history remains unchanged.  This
 feature is used by the view commands, so that the selection history
 after exiting from viewing is the same as it was before.
 
-** Second arg to `display-buffer' and `pop-to-buffer'.
+** Second arg to 'display-buffer' and 'pop-to-buffer'.
 
 These two functions both accept an optional second argument which
-defaults to `nil'.  If the argument is not `nil', it means that
+defaults to 'nil'.  If the argument is not 'nil', it means that
 another window (not the selected one) must be found or created to
 display the specified buffer in, even if it is already shown in
 the selected window.
 
-This feature is used by `switch-to-buffer-other-window'.
+This feature is used by 'switch-to-buffer-other-window'.
 
-** New variable `completion-ignore-case'.
+** New variable 'completion-ignore-case'.
 
-If this variable is non-`nil', completion allows strings
+If this variable is non-'nil', completion allows strings
 in different cases to be considered matching.  The global value
-is `nil'
+is 'nil'
 
 This variable exists for the sake of commands that are completing
 an argument in which case is not significant.  It is possible
@@ -617,13 +617,13 @@ where case makes a difference.
 ** Major modes related to Text mode call text-mode-hook, then their own hooks.
 
 For example, turning on Outline mode first calls the value of
-`text-mode-hook' as a function, if it exists and is non-`nil',
-and then does likewise for the variable `outline-mode-hook'.
+'text-mode-hook' as a function, if it exists and is non-'nil',
+and then does likewise for the variable 'outline-mode-hook'.
 
 ** Defining new command line switches.
 
 You can define a new command line switch in your .emacs file
-by putting elements on the value of `command-switch-alist'.
+by putting elements on the value of 'command-switch-alist'.
 Each element of this list should look like
       (SWITCHSTRING . FUNCTION)
 where SWITCHSTRING is a string containing the switch to be
@@ -633,35 +633,35 @@ receives the command line argument, a string, as its 
argument.
 
 To implement a switch that uses up one or more following arguments,
 use the fact that the remaining command line arguments are kept
-as a list in the variable `command-line-args'.  FUNCTION can
+as a list in the variable 'command-line-args'.  FUNCTION can
 examine this variable, and do
     (setq command-line-args (cdr command-line-args)
 to "use up" an argument.
 
-** New variable `load-in-progress'.
+** New variable 'load-in-progress'.
 
-This variable is non-`nil' when a file of Lisp code is being read
-and executed by `load'.
+This variable is non-'nil' when a file of Lisp code is being read
+and executed by 'load'.
 
-** New variable `print-length'.
+** New variable 'print-length'.
 
-The value of this variable is normally `nil'.  It may instead be
-a number; in that case, when a list is printed by `prin1' or
-`princ' only that many initial elements are printed; the rest are
+The value of this variable is normally 'nil'.  It may instead be
+a number; in that case, when a list is printed by 'prin1' or
+'princ' only that many initial elements are printed; the rest are
 replaced by `...'.
 
-** New variable `find-file-not-found-hook'.
+** New variable 'find-file-not-found-hook'.
 
-If `find-file' or any of its variants is used on a nonexistent file,
-the value of `find-file-not-found-hook' is called (if it is not `nil')
+If 'find-file' or any of its variants is used on a nonexistent file,
+the value of 'find-file-not-found-hook' is called (if it is not 'nil')
 with no arguments, after creating an empty buffer.  The file's name
-can be found as the value of `buffer-file-name'.
+can be found as the value of 'buffer-file-name'.
 
 ** Processes without buffers.
 
-In the function `start-process', you can now specify `nil' as
-the process's buffer.  You can also set a process's buffer to `nil'
-using `set-process-buffer'.
+In the function 'start-process', you can now specify 'nil' as
+the process's buffer.  You can also set a process's buffer to 'nil'
+using 'set-process-buffer'.
 
 The reason you might want to do this is to prevent the process
 from being killed because any particular buffer is killed.
@@ -672,18 +672,18 @@ When a process has no buffer, its output is lost unless 
it has a
 filter, and no indication of its being stopped or killed is given
 unless it has a sentinel.
 
-** New function `user-variable-p'.  `v' arg prompting changed.
+** New function 'user-variable-p'.  'v' arg prompting changed.
 
-This function takes a symbol as argument and returns `t' if
+This function takes a symbol as argument and returns 't' if
 the symbol is defined as a user option variable.  This means
-that it has a `variable-documentation' property whose value is
+that it has a 'variable-documentation' property whose value is
 a string starting with `*'.
 
-Code `v' in an interactive arg reading string now accepts
+Code 'v' in an interactive arg reading string now accepts
 user variables only, and completion is limited to the space of
 user variables.
 
-The function `read-variable' also now accepts and completes
+The function 'read-variable' also now accepts and completes
 over user variables only.
 
 ** CBREAK mode input is the default in Unix 4.3 bsd.
@@ -691,33 +691,33 @@ over user variables only.
 In Berkeley 4.3 Unix, there are sufficient features for Emacs to
 work fully correctly using CBREAK mode and not using SIGIO.
 Therefore, this mode is the default when running under 4.3.
-This mode corresponds to `nil' as the first argument to
-`set-input-mode'.  You can still select either mode by calling
+This mode corresponds to 'nil' as the first argument to
+'set-input-mode'.  You can still select either mode by calling
 that function.
 
 ** Information on memory usage.
 
-The new variable `data-bytes-used' contains the number
+The new variable 'data-bytes-used' contains the number
 of bytes of impure space allocated in Emacs.
-`data-bytes-free' contains the number of additional bytes
+'data-bytes-free' contains the number of additional bytes
 Emacs could allocate.  Note that space formerly allocated
-and freed again still counts as `used', since it is still
+and freed again still counts as 'used', since it is still
 in Emacs's address space.
 
-** No limit on size of output from `format'.
+** No limit on size of output from 'format'.
 
-The string output from `format' used to be truncated to
+The string output from 'format' used to be truncated to
 100 characters in length.  Now it can have any length.
 
-** New errors `void-variable' and `void-function' replace `void-symbol'.
+** New errors 'void-variable' and 'void-function' replace 'void-symbol'.
 
 This change makes it possible to have error messages that
 clearly distinguish undefined variables from undefined functions.
-It also allows `condition-case' to handle one case without the other.
+It also allows 'condition-case' to handle one case without the other.
 
-** `replace-match' handling of `\'.
+** 'replace-match' handling of `\'.
 
-In `replace-match', when the replacement is not literal,
+In 'replace-match', when the replacement is not literal,
 `\' in the replacement string is always treated as an
 escape marker.  The only two special `\' constructs
 are `\&' and `\DIGIT', so `\' followed by anything other than
@@ -728,21 +728,21 @@ This level of escaping is comparable with what goes on in
 a regular expression.  It is over and above the level of `\'
 escaping that goes on when strings are read in Lisp syntax.
 
-** New error `invalid-regexp'.
+** New error 'invalid-regexp'.
 
 A regexp search signals this type of error if the argument does
 not meet the rules for regexp syntax.
 
-** `kill-emacs' with argument.
+** 'kill-emacs' with argument.
 
 If the argument is a number, it is returned as the exit status code
 of the Emacs process.  If the argument is a string, its contents
 are stuffed as pending terminal input, to be read by another program
 after Emacs is dead.
 
-** New fifth argument to `subst-char-in-region'.
+** New fifth argument to 'subst-char-in-region'.
 
-This argument is optional and defaults to `nil'.  If it is not `nil',
+This argument is optional and defaults to 'nil'.  If it is not 'nil',
 then the substitutions made by this function are not recorded
 in the Undo mechanism.
 
@@ -757,25 +757,25 @@ another while in the debugger.
 Exiting from the debugger kills the `*Backtrace*' buffer, so you will
 not try to give commands in it when no longer really in the debugger.
 
-** New function `switch-to-buffer-other-window'.
+** New function 'switch-to-buffer-other-window'.
 
 This is the new primitive to select a specified buffer (the
 argument) in another window.  It is not quite the same as
-`pop-to-buffer', because it is guaranteed to create another
+'pop-to-buffer', because it is guaranteed to create another
 window (assuming there is room on the screen) so that it can
 leave the current window's old buffer displayed as well.
 
 All functions to select a buffer in another window should
 do so by calling this new function.
 
-** New variable `minibuffer-help-form'.
+** New variable 'minibuffer-help-form'.
 
-At entry to the minibuffer, the variable `help-form' is bound
-to the value of `minibuffer-help-form'.
+At entry to the minibuffer, the variable 'help-form' is bound
+to the value of 'minibuffer-help-form'.
 
-`help-form' is expected at all times to contain either `nil'
+'help-form' is expected at all times to contain either 'nil'
 or an expression to be executed when C-h is typed (overriding
-the definition of C-h as a command).  `minibuffer-help-form'
+the definition of C-h as a command).  'minibuffer-help-form'
 can be used to provide a different default way of handling
 C-h while in the minibuffer.
 
@@ -791,7 +791,7 @@ be quoted with a second `\', to include it in the doc 
string.)
 This construct is normally used on a line by itself, with no blank
 lines before or after.
 
-For example, the documentation string for the function `c-mode' contains
+For example, the documentation string for the function 'c-mode' contains
     ...
     Paragraphs are separated by blank lines only.
     Delete converts tabs to spaces as it moves back.
@@ -803,13 +803,13 @@ For example, the documentation string for the function 
`c-mode' contains
 
 Punctuation characters behave like whitespace in word and
 list parsing, but can be distinguished in regexps and in the
-function `char-syntax'.  Punctuation syntax is represented by
-a period in `modify-syntax-entry'.
+function 'char-syntax'.  Punctuation syntax is represented by
+a period in 'modify-syntax-entry'.
 
-** `auto-mode-alist' no longer needs entries for backup-file names,
+** 'auto-mode-alist' no longer needs entries for backup-file names,
 
 Backup suffixes of all kinds are now stripped from a file's name
-before searching `auto-mode-alist'.
+before searching 'auto-mode-alist'.
 
 
 
@@ -846,14 +846,14 @@ arguments and then confirm, or abort with C-g.
 
 ** Incremental search does less redisplay on slow terminals.
 
-If the terminal baud rate is <= the value of `isearch-slow-speed',
+If the terminal baud rate is <= the value of 'isearch-slow-speed',
 incremental searching outside the text on the screen creates
 a single-line window and uses that to display the line on which
 a match has been found.  Exiting or quitting the search restores
 the previous window configuration and redisplays the window you
 were searching in.
 
-The initial value of `isearch-slow-speed' is 1200.
+The initial value of 'isearch-slow-speed' is 1200.
 
 This feature is courtesy of crl@purdue.
 
@@ -871,17 +871,17 @@ if you know enough to switch windows while in the 
minibuffer,
 you can probably understand recursive minibuffers.
 
 This may be overridden by binding the variable
-`enable-recursive-minibuffers' to t.
+'enable-recursive-minibuffers' to t.
 
 ** New major mode Emacs-Lisp mode, for editing Lisp code to run in Emacs.
 
-The mode in which emacs lisp files is edited is now called emacs-lisp-mode
-and is distinct from lisp-mode.  The latter is intended for use with
-lisps external to emacs.
+The mode in which emacs lisp files is edited is now called 'emacs-lisp-mode'
+and is distinct from 'lisp-mode'.  The latter is intended for use with
+lisps external to Emacs.
 
 The hook which is funcalled (if non-nil) on entry to elisp-mode is now
-called emacs-lisp-mode-hook.  A consequence of this changes is that
-.emacs init files which set the value of lisp-mode-hook may need to be
+called 'emacs-lisp-mode-hook'.  A consequence of this changes is that
+.emacs init files which set the value of 'lisp-mode-hook' may need to be
 changed to use the new names.
 
 ** Correct matching of parentheses is checked on insertion.
@@ -898,18 +898,18 @@ This feature was originally written by shane@mit-ajax.
 ** M-x command-history-mode
 ** M-x electric-command-history
 
-`list-command-history' displays forms from the command history subject
+'list-command-history' displays forms from the command history subject
 to user controlled filtering and limit on number of forms.  It leaves
-the buffer in `command-history-mode'.  M-x command-history-mode
+the buffer in 'command-history-mode'.  M-x command-history-mode
 recomputes the command history each time it is invoked via
-`list-command-history'.  It is like Emacs-Lisp mode except that characters
+'list-command-history'.  It is like Emacs-Lisp mode except that characters
 don't insert themselves and provision is made for re-evaluating an
-expression from the list.  `electric-command-history' pops up a type
+expression from the list.  'electric-command-history' pops up a type
 out window with the command history displayed.  If the very next
 character is Space, the window goes away and the previous window
 configuration is restored.  Otherwise you can move around in the
 history and select an expression for evaluation *inside* the buffer
-which invoked `electric-command-history'.  The original window
+which invoked 'electric-command-history'.  The original window
 configuration is restored on exit unless the command selected changes
 it.
 
@@ -924,7 +924,7 @@ Special commands for hacking tabs and tab stops are 
provided.  Special
 commands for killing rectangles and overlaying them are provided.  See
 the documentation of function  edit-picture  for more details.
 
-Calls value of `edit-picture-hook' on entry if non-nil.
+Calls value of 'edit-picture-hook' on entry if non-nil.
 
 ** Stupid C-s/C-q `flow control' supported.
 
@@ -977,15 +977,15 @@ lisp-mode-hook, in that order, if non-nil.
 Meanwhile, in lisp-mode, the command C-M-x is defined to
 send the current defun as input to the `*lisp*' subprocess.
 
-** Mode line says `Narrow' when buffer is clipped.
+** Mode line says 'Narrow' when buffer is clipped.
 
-If a buffer has a clipping restriction (made by `narrow-to-region')
-then its mode line contains the word `Narrow' after the major and
+If a buffer has a clipping restriction (made by 'narrow-to-region')
+then its mode line contains the word 'Narrow' after the major and
 minor modes.
 
-** Mode line says `Abbrev' when abbrev mode is on.
+** Mode line says 'Abbrev' when abbrev mode is on.
 
-** add-change-log-entry takes prefix argument
+** 'add-change-log-entry' takes prefix argument
 
 Giving a prefix argument makes it prompt for login name, full name,
 and site name, with defaults.  Otherwise the defaults are used
@@ -994,27 +994,27 @@ with no confirmation.
 ** M-x view-buffer and M-x view-file
 
 view-buffer selects the named buffer, view-file finds the named file; the
-resulting buffer is placed into view-mode (a recursive edit).  The normal
+resulting buffer is placed into 'view-mode' (a recursive edit).  The normal
 emacs commands are not available.  Instead a set of special commands is
 provided which facilitate moving around in the buffer, searching and
 scrolling by screenfuls.  Exiting view-mode returns to the buffer in which
 the view-file or view-buffer command was given.
 Type ? or h when viewing for a complete list of view commands.
-Each calls value of `view-hook' if non-nil on entry.
+Each calls value of 'view-hook' if non-nil on entry.
 
 written by shane@mit-ajax.
 
 ** New key commands in dired.
 
-`v' views (like more) the file on the current line.
+'v' views (like more) the file on the current line.
 `#' marks auto-save files for deletion.
 `~' marks backup files for deletion.
-`r' renames a file and updates the directory listing if the
+'r' renames a file and updates the directory listing if the
 file is renamed to same directory.
-`c' copies a file and updates the directory listing if the file is
+'c' copies a file and updates the directory listing if the file is
 copied to the same directory.
 
-** New function `electric-buffer-list'.
+** New function 'electric-buffer-list'.
 
 This pops up a buffer describing the set of emacs buffers.
 Immediately typing space makes the buffer list go away and returns
@@ -1026,18 +1026,18 @@ cursor's line.  There are a number of other commands 
which are the same
 as those of buffer-menu-mode.
 
 This is a useful thing to bind to c-x c-b in your `.emacs' file if the
-rather non-standard `electric' behavior of the buffer list suits your taste.
+rather non-standard 'electric' behavior of the buffer list suits your taste.
 Type C-h after invoking electric-buffer-list for more information.
 
-Calls value of `electric-buffer-menu-mode-hook' if non-nil on entry.
-Calls value of `after-electric-buffer-menu' on exit (select) if non-nil.
+Calls value of 'electric-buffer-menu-mode-hook' if non-nil on entry.
+Calls value of 'after-electric-buffer-menu' on exit (select) if non-nil.
 
 ** Changes in version 16 for mail reading and sending
 
 *** sendmail prefix character is C-c (and not C-z).  New command C-c w.
 
 For instance C-c C-c (or C-c C-s) sends mail now rather than C-z C-z.
-C-c w inserts your `signature' (contents of ~/.signature) at the end
+C-c w inserts your 'signature' (contents of ~/.signature) at the end
 of mail.
 
 *** New feature in C-c y command in sending mail.
@@ -1063,26 +1063,26 @@ C-c and C-] are the only ways "back into Rmail", but you
 can switch to other buffers and edit them as usual.
 C-r in Rmail changes only the handling of the Rmail buffer.
 
-*** Rmail command `t' toggles header display.
+*** Rmail command 't' toggles header display.
 
 Normally Rmail reformats messages to hide most header fields.
-`t' switches to display of all the header fields of the
+'t' switches to display of all the header fields of the
 current message, as long as it remains current.
-Another `t' switches back to the usual display.
+Another 't' switches back to the usual display.
 
 *** Rmail command '>' goes to the last message.
 
-*** Rmail commands `a' and `k' set message attributes.
-`a' adds an attribute and `k' removes one.  You specify
+*** Rmail commands 'a' and 'k' set message attributes.
+'a' adds an attribute and 'k' removes one.  You specify
 the attribute by name.  You can specify either a built-in
 flag such as "deleted" or "filed", or a user-defined keyword
 (anything not recognized as built-in).
 
-*** Rmail commands `l' and `L' summarize by attributes.
+*** Rmail commands 'l' and 'L' summarize by attributes.
 
 These commands create a summary with one line per message,
-like `h', but they list only some of the messages.  You
-specify which attribute (for `l') or attributes (for `L')
+like 'h', but they list only some of the messages.  You
+specify which attribute (for 'l') or attributes (for 'L')
 the messages should have.
 
 *** Rmail can parse mmdf mail files.
@@ -1092,11 +1092,11 @@ the messages should have.
 mh-e is a front end for GNU emacs and the MH mail system.  It
 provides a friendly and convenient interface to the MH commands.
 
-To read mail, invoke mh-rmail.  This will inc new mail and display the
+To read mail, invoke 'mh-rmail'.  This will inc new mail and display the
 scan listing on the screen.  To see a summary of the mh-e commands,
 type ?.  Help is available through the usual facilities.
 
-To send mail, invoke mh-smail.
+To send mail, invoke 'mh-smail'.
 
 mh-e requires a copy of MH.5 that has been compiled with the MHE
 compiler switch.
@@ -1105,39 +1105,39 @@ From larus@berkeley.
 
 ** New hooks and parameters in version 16
 
-*** New variable `blink-matching-paren-distance'.
+*** New variable 'blink-matching-paren-distance'.
 
 This is the maximum number of characters to search for
 an open-paren to match an inserted close-paren.
 The matching open-paren is shown and checked if it is found
 within this distance.
 
-`nil' means search all the way to the beginning of the buffer.
+'nil' means search all the way to the beginning of the buffer.
 In this case, a warning message is printed if no matching
 open-paren is found.
 
 This feature was originally written by shane@mit-ajax.
 
-*** New variable `find-file-run-dired'
+*** New variable 'find-file-run-dired'
 
 If nil, find-file will report an error if an attempt to visit a
 directory is detected; otherwise, it runs dired on that directory.
 The default is t.
 
-*** Variable `dired-listing-switches' holds switches given to `ls' by dired.
+*** Variable 'dired-listing-switches' holds switches given to 'ls' by dired.
 
-The value should be a string containing `-' followed by letters.
-The letter `l' had better be included and letter 'F' had better be excluded!
+The value should be a string containing '-' followed by letters.
+The letter 'l' had better be included and letter 'F' had better be excluded!
 The default is "-al".
 
 This feature was originally written by shane@mit-ajax.
 
-*** New variable `display-time-day-and-date'.
+*** New variable 'display-time-day-and-date'.
 
-If this variable is set non-`nil', the function M-x display-time
+If this variable is set non-'nil', the function M-x display-time
 displays the day and date, as well as the time.
 
-*** New parameter `c-continued-statement-indent'.
+*** New parameter 'c-continued-statement-indent'.
 
 This controls the extra indentation given to a line
 that continues a C statement started on the previous line.
@@ -1147,19 +1147,20 @@ By default it is 2, which is why you would see
          bar ();
 
 
-*** Changed meaning of `c-indent-level'.
+*** Changed meaning of 'c-indent-level'.
 
-The value of `c-brace-offset' used to be
-subtracted from the value of `c-indent-level' whenever
+The value of 'c-brace-offset' used to be
+subtracted from the value of 'c-indent-level' whenever
 that value was used.  Now it is not.
 
-As a result, `c-indent-level' is now the offset of
+As a result, 'c-indent-level' is now the offset of
 statements within a block, relative to the line containing
 the open-brace that starts the block.
 
-*** turn-on-auto-fill is useful value for text-mode-hook.
+*** 'turn-on-auto-fill' is useful value for 'text-mode-hook'.
+
+    (setq text-mode-hook 'turn-on-auto-fill)
 
-(setq text-mode-hook 'turn-on-auto-fill)
 is all you have to do to make sure Auto Fill mode is turned
 on whenever you enter Text mode.
 
@@ -1187,8 +1188,8 @@ the following text, up to the next `]', is taken as a 
function name.
 Instead of printing that function name, the command that runs it is printed.
 (M-x is used to construct a command if no shorter one exists.)
 
-For example, instead of putting `C-n' in a documentation string
-to refer to the C-n command, put in `\[next-line]'.  (In practice
+For example, instead of putting 'C-n' in a documentation string
+to refer to the 'next-line' command, put in `\[next-line]'.  (In practice
 you will need to quote the backslash with another backslash,
 due to the syntax for strings in Lisp and C.)
 
@@ -1197,34 +1198,34 @@ precede them with `\='.  To include the characters 
`\=', precede
 them with `\='.  For example, "\\=\\= is the way to quote \\=\\["
 will come out as `\= is the way to quote \['.
 
-The new function `substitute-command-keys' takes a string possibly
+The new function 'substitute-command-keys' takes a string possibly
 containing \[...] constructs and replaces those constructs with
 the key sequences they currently stand for.
 
-*** Primitives `find-line-comment' and `find-line-comment-body' flushed.
+*** Primitives 'find-line-comment' and 'find-line-comment-body' flushed.
 
-Search for the value of `comment-start-skip' if you want to find
+Search for the value of 'comment-start-skip' if you want to find
 whether and where a line has a comment.
 
-*** New function `auto-save-file-name-p'
+*** New function 'auto-save-file-name-p'
 
-Should return non-`nil' if given a string which is the name of an
+Should return non-'nil' if given a string which is the name of an
 auto-save file (sans directory name).  If you redefine
-`make-auto-save-file-name', you should redefine this accordingly.  By
-default, this function returns `t' for filenames beginning with
+'make-auto-save-file-name', you should redefine this accordingly.  By
+default, this function returns 't' for filenames beginning with
 character `#'.
 
-*** The value of `exec-directory' now ends in a slash.
+*** The value of 'exec-directory' now ends in a slash.
 
 This is to be compatible with most directory names in GNU Emacs.
 
 *** Dribble files and termscript files.
 
-(open-dribble-file FILE) opens a dribble file named FILE.  When a
+'open-dribble-file' opens a dribble file.  When a
 dribble file is open, every character Emacs reads from the terminal is
 written to the dribble file.
 
-(open-termscript FILE) opens a termscript file named FILE.  When a
+'open-termscript' opens a termscript file.  When a
 termscript file is open, all characters sent to the terminal by Emacs
 are also written in the termscript file.
 
@@ -1240,15 +1241,15 @@ a synonym for C-x u (undo).
 
 *** Undefined function errors versus undefined variable errors.
 
-Void-symbol errors now say "boundp" if the symbol's value was void
-or "fboundp" if the function definition was void.
+Void-symbol errors now say 'boundp' if the symbol's value was void
+or 'fboundp' if the function definition was void.
 
-*** New function `bury-buffer'.
+*** New function 'bury-buffer'.
 
-The new function `bury-buffer' takes one argument, a buffer object,
+The new function 'bury-buffer' takes one argument, a buffer object,
 and puts that buffer at the end of the internal list of buffers.
 So it is the least preferred candidate for use as the default value
-of C-x b, or for other-buffer to return.
+of C-x b, or for 'other-buffer' to return.
 
 *** Already-displayed buffers have low priority for display.
 
@@ -1256,14 +1257,14 @@ When a buffer is chosen automatically for display, or 
to be the
 default in C-x b, buffers already displayed in windows have lower
 priority than buffers not currently visible.
 
-*** `set-window-start' accepts a third argument NOFORCE.
+*** 'set-window-start' accepts a third argument NOFORCE.
 
 This argument, if non-nil, prevents the window's force_start flag
 from being set.  Setting the force_start flag causes the next
 redisplay to insist on starting display at the specified starting
 point, even if dot must be moved to get it onto the screen.
 
-*** New function `send-string-to-terminal'.
+*** New function 'send-string-to-terminal'.
 
 This function takes one argument, a string, and outputs its contents
 to the terminal exactly as specified: control characters, escape
@@ -1273,9 +1274,9 @@ sequences, and all.
 
 The terminal's keypad is now put into command mode, as opposed to
 numeric mode, while Emacs is running.  This is done by means of the
-termcap `ks' and `ke' strings.
+termcap 'ks' and 'ke' strings.
 
-*** New function `generate-new-buffer'
+*** New function 'generate-new-buffer'
 
 This function takes a string as an argument NAME and looks for a
 creates and returns a buffer called NAME if one did not already exist.
@@ -1283,38 +1284,38 @@ Otherwise, it successively tries appending suffixes of 
the form "<1>",
 "<2>" etc to NAME until it creates a string which does not name an
 existing buffer.  A new buffer with that name is the created and returned.
 
-*** New function `prin1-to-string'
+*** New function 'prin1-to-string'
 This function takes one argument, a lisp object, and returns a string
-containing that object's printed representation, such as `prin1'
+containing that object's printed representation, such as 'prin1'
 would output.
 
-*** New function `read-from-minibuffer'
+*** New function 'read-from-minibuffer'
 Lets you supply a prompt, initial-contents, a keymap, and specify
 whether the result should be interpreted as a string or a lisp object.
 
-Old functions `read-minibuffer', `eval-minibuffer', `read-string' all
+Old functions 'read-minibuffer', 'eval-minibuffer', 'read-string' all
 take second optional string argument which is initial contents of
 minibuffer.
 
 *** minibuffer variable names changed (names of keymaps)
 
-minibuf-local-map -> minibuffer-local-map
-minibuf-local-ns-map -> minibuffer-local-ns-map
-minibuf-local-completion-map -> minibuffer-local-completion-map
-minibuf-local-must-match-map -> minibuffer-local-must-match-map
+'minibuf-local-map' -> 'minibuffer-local-map'
+'minibuf-local-ns-map' -> 'minibuffer-local-ns-map'
+'minibuf-local-completion-map' -> 'minibuffer-local-completion-map'
+'minibuf-local-must-match-map' -> 'minibuffer-local-must-match-map'
 
 ** Changes in version 16 affecting configuring and building Emacs
 
 *** Configuration switch VT100_INVERSE eliminated.
 
 You can control the use of inverse video on any terminal by setting
-the variable `inverse-video', or by changing the termcap entry.  If
-you like, set `inverse-video' in your `.emacs' file based on
+the variable 'inverse-video', or by changing the termcap entry.  If
+you like, set 'inverse-video' in your `.emacs' file based on
 examination of (getenv "TERM").
 
-*** New switch `-batch' makes Emacs run noninteractively.
+*** New switch '-batch' makes Emacs run noninteractively.
 
-If the switch `-batch' is used, Emacs treats its standard output
+If the switch '-batch' is used, Emacs treats its standard output
 and input like ordinary files (even if they are a terminal).
 It does not display buffers or windows; the only output to standard output
 is what would appear as messages in the echo area, and each
@@ -1322,13 +1323,13 @@ message is followed by a newline.
 
 The terminal modes are not changed, so that C-z and C-c retain
 their normal Unix meanings.  Emacs does still read commands from
-the terminal, but the idea of `-batch' is that you use it with
+the terminal, but the idea of '-batch' is that you use it with
 other command line arguments that tell Emacs a complete task to perform,
-including killing itself.  `-kill' used as the last argument is a good
+including killing itself.  '-kill' used as the last argument is a good
 way to accomplish this.
 
-The Lisp variable `noninteractive' is now defined, to be `nil'
-except when `-batch' has been specified.
+The Lisp variable 'noninteractive' is now defined, to be 'nil'
+except when '-batch' has been specified.
 
 *** Emacs can be built with output redirected to a file.
 
@@ -1359,7 +1360,7 @@ This is because -batch (see above) is now used in 
building Emacs.
  Note that lisp code converted from Mocklisp code will not necessarily
  run as fast as code specifically written for GNU Emacs, nor will it use
  the many features of GNU Emacs which are not present in Gosling's emacs.
- (In particular, the byte-compiler (m-x byte-compile-file) knows little
+ (In particular, the byte-compiler (M-x byte-compile-file) knows little
  about compilation of code directly converted from mocklisp.)
  It is envisaged that old mocklisp code will be incrementally converted
  to GNU lisp code, with M-x convert-mocklisp-buffer being the first
@@ -1382,63 +1383,66 @@ This is because -batch (see above) is now used in 
building Emacs.
  specify the tag table file name initially, or to switch
  to a new tag table.
 
-** If truncate-partial-width-windows is non-nil (as it initially is),
+** If 'truncate-partial-width-windows' is non-nil (as it initially is),
  all windows less than the full screen width (that is,
  made by side-by-side splitting) truncate lines rather than continuing
  them.
 
 ** Emacs now checks for Lisp stack overflow to avoid fatal errors.
- The depth in eval, apply and funcall may not exceed max-lisp-eval-depth.
+ The depth in 'eval', 'apply' and 'funcall' may not exceed
+ 'max-lisp-eval-depth'.
  The depth in variable bindings and unwind-protects may not exceed
- max-specpdl-size.  If either limit is exceeded, an error occurs.
+ 'max-specpdl-size'.  If either limit is exceeded, an error occurs.
  You can set the limits to larger values if you wish, but if you make them
  too large, you are vulnerable to a fatal error if you invoke
  Lisp code that does infinite recursion.
 
-** New hooks  find-file-hook  and  write-file-hook.
+** New hooks 'find-file-hook' and 'write-file-hook'.
  Both of these variables if non-nil should be functions of no arguments.
  At the time they are called (current-buffer) will be the buffer being
  read or written respectively.
 
- find-file-hook  is called whenever a file is read into its own buffer,
- such as by calling  find-file,  revert-buffer, etc.  It is not called by
- functions such as  insert-file  which do not read the file into a buffer of
+ 'find-file-hook' is called whenever a file is read into its own buffer,
+ such as by calling 'find-file', 'revert-buffer', etc.  It is not called by
+ functions such as 'insert-file' which do not read the file into a buffer of
  its own.
- find-file-hook  is called after the file has been read in and its
+ 'find-file-hook' is called after the file has been read in and its
  local variables (if any) have been processed.
 
- write-file-hook  is called just before writing out a file from a buffer.
+ 'write-file-hook' is called just before writing out a file from a buffer.
 
-** The initial value of shell-prompt-pattern is now  "^[^#$%>]*[#$%>] *"
+** The initial value of 'shell-prompt-pattern' is now  "^[^#$%>]*[#$%>] *"
 
-** If the .emacs file sets inhibit-startup-message to non-nil,
+** If the .emacs file sets 'inhibit-startup-message' to non-nil,
  the messages normally printed by Emacs at startup time
  are inhibited.
 
 ** Facility for run-time conditionalization on the basis of emacs features.
 
- The new variable  features  is a list of symbols which represent "features"
+ The new variable 'features' is a list of symbols which represent "features"
  of the executing emacs, for use in run-time conditionalization.
 
- The function  featurep  of one argument may be used to test for the
+ The function 'featurep' of one argument may be used to test for the
  presence of a feature.  It is just the same as
- (not (null (memq FEATURE features))) where FEATURE is its argument.
- For example, (if (featurep 'magic-window-hack)
-                 (transmogrify-window 'vertical)
-               (split-window-vertically))
+    (not (null (memq FEATURE features)))
+ where FEATURE is its argument.  For example,
+
+    (if (featurep 'magic-window-hack)
+        (transmogrify-window 'vertical)
+      (split-window-vertically))
 
- The function  provide  of one argument "announces" that FEATURE is present.
+ The function 'provide' of one argument "announces" that FEATURE is present.
  It is much the same as (if (not (featurep FEATURE))
                            (setq features (cons FEATURE features)))
 
- The function  require  with arguments FEATURE and FILE-NAME loads FILE-NAME
+ The function 'require' with arguments FEATURE and FILE-NAME loads FILE-NAME
  (which should contain the form (provide FEATURE)) unless FEATURE is present.
  It is much the same as (if (not (featurep FEATURE))
                            (progn (load FILE-NAME)
                                   (if (not featurep FEATURE) (error ...))))
  FILE-NAME is optional and defaults to FEATURE.
 
-** New function load-average.
+** New function 'load-average'.
 
  This returns a list of three integers, which are
  the current 1 minute, 5 minute and 15 minute load averages,
@@ -1460,10 +1464,10 @@ This is because -batch (see above) is now used in 
building Emacs.
 ** Programmer's note: detecting killed buffers.
 
  Buffers are eliminated by explicitly killing them, using
- the function kill-buffer.  This does not eliminate or affect
+ the function 'kill-buffer'.  This does not eliminate or affect
  the pointers to the buffer which may exist in list structure.
  If you have a pointer to a buffer and wish to tell whether
- the buffer has been killed, use the function buffer-name.
+ the buffer has been killed, use the function 'buffer-name'.
  It returns nil on a killed buffer, and a string on a live buffer.
 
 ** New ways to access the last command input character.
@@ -1471,13 +1475,13 @@ This is because -batch (see above) is now used in 
building Emacs.
  The function last-key-struck, which used to return the last
  input character that was read by command input, is eliminated.
  Instead, you can find this information as the value of the
- variable last-command-char.  (This variable used to be called
+ variable 'last-command-char'.  (This variable used to be called
  last-key).
 
- Another new variable, last-input-char, holds the last character
+ Another new variable, 'last-input-char', holds the last character
  read from the command input stream regardless of what it was
  read for.  last-input-char and last-command-char are different
- only inside a command that has called read-char to read input.
+ only inside a command that has called 'read-char' to read input.
 
 ** The new switch -kill causes Emacs to exit after processing the
  preceding command line arguments.  Thus,
@@ -1517,9 +1521,9 @@ This is because -batch (see above) is now used in 
building Emacs.
  user can explain why it is not called mdl-mode.
  You must load the library mim-mode explicitly to use this.
 
-** GNU documentation formatter `texinfo'.
+** GNU documentation formatter 'texinfo'.
 
- The `texinfo' library defines a format for documentation
+ The 'texinfo' library defines a format for documentation
  files which can be passed through Tex to make a printed manual
  or passed through texinfo to make an Info file.  Texinfo is
  documented fully by its own Info file; compare this file
@@ -1532,7 +1536,7 @@ This is because -batch (see above) is now used in 
building Emacs.
  This is not ready for distribution yet, but will appear at
  a later time.
 
-** New function read-from-string (emacs 15.29)
+** New function 'read-from-string' (emacs 15.29)
 
  read-from-string takes three arguments: a string to read from,
  and optionally start and end indices which delimit a substring
@@ -1558,25 +1562,25 @@ This is because -batch (see above) is now used in 
building Emacs.
  These messages appear after the text in the minibuffer, and remain
  on the screen until a few seconds go by or you type a key.
 
-** The buffer-read-only flag is implemented.
+** The 'buffer-read-only' flag is implemented.
  Setting or binding this per-buffer variable to a non-nil value
  makes illegal any operation which would modify the textual content of
  the buffer.  (Such operations signal a  buffer-read-only  error)
- The read-only state of a buffer may be altered using toggle-read-only
+ The read-only state of a buffer may be altered using 'toggle-read-only'
  (C-x C-q)
  The buffers used by Rmail, Dired, Rnews, and Info are now read-only
  by default to prevent accidental damage to the information in those
  buffers.
 
-** Functions car-safe and cdr-safe.
+** Functions 'car-safe' and 'cdr-safe'.
  These functions are like car and cdr when the argument is a cons.
  Given an argument not a cons, car-safe always returns nil, with
  no error; the same for cdr-safe.
 
-** The new function user-real-login-name returns the name corresponding
+** The new function 'user-real-login-name' returns the name corresponding
  to the real uid of the Emacs process.  This is usually the same
- as what user-login-name returns; however, when Emacs is invoked
- from su, user-real-login-name returns "root" but user-login-name
+ as what 'user-login-name' returns; however, when Emacs is invoked
+ from su, 'user-real-login-name' returns "root" but user-login-name
  returns the name of the user who invoked su.
 
 
@@ -1603,7 +1607,7 @@ This is because -batch (see above) is now used in 
building Emacs.
 
  This syntax can be used in strings too.  Note, however, that
  Meta characters are not meaningful in key sequences being passed
- to define-key or lookup-key; you must use ESC characters (\e)
+ to 'define-key' or 'lookup-key'; you must use ESC characters (\e)
  in them instead.
 
  ?\C- can be used likewise for control characters.  (13.9)
@@ -1627,14 +1631,14 @@ This is because -batch (see above) is now used in 
building Emacs.
  This is a shift key which causes the high bit to be turned on
  in all input characters typed while it is held down.
 
- read-char now returns a value in the range 128-255 if
+ 'read-char' now returns a value in the range 128-255 if
  a Meta character is typed.  When interpreted as command
  input, a Meta character is equivalent to a two character
  sequence, the meta prefix character followed by the unmetized
  character (Meta-G unmetized is G).
 
  The meta prefix character
- is specified by the value of the variable meta-prefix-char.
+ is specified by the value of the variable 'meta-prefix-char'.
  If this character (normally Escape) has been redefined locally
  with a non-prefix definition (such as happens in completing
  minibuffers) then the local redefinition is suppressed when
@@ -1643,10 +1647,10 @@ This is because -batch (see above) is now used in 
building Emacs.
  explicitly, but not effective if the character comes from
  the use of the Meta key.
 
-** `-' is no longer a completion command in the minibuffer.
+** '-' is no longer a completion command in the minibuffer.
  It is an ordinary self-inserting character.
 
-** The list load-path of directories load to search for Lisp files
+** The list 'load-path' of directories load to search for Lisp files
  is now controlled by the EMACSLOADPATH environment variable
 [[ Note this was originally EMACS-LOAD-PATH and has been changed
  again; sh does not deal properly with hyphens in env variable names]]
@@ -1720,20 +1724,20 @@ you will not on its account be queried about active 
subprocesses.
 
 ** The commands C-c and C-z have been interchanged,
  for greater compatibility with normal Unix usage.
- C-z now runs suspend-emacs and C-c runs exit-recursive-edit.
+ C-z now runs suspend-emacs and C-c runs 'exit-recursive-edit'.
 
-** The value returned by file-name-directory now ends
+** The value returned by 'file-name-directory' now ends
  with a slash.  (file-name-directory "foo/bar") => "foo/".
  This avoids confusing results when dealing with files
  in the root directory.
 
- The value of the per-buffer variable default-directory
+ The value of the per-buffer variable 'default-directory'
  is also supposed to have a final slash now.
 
 ** There are now variables to control the switches passed to
- `ls' by the C-x C-d command (list-directory).
- list-directory-brief-switches is a string, initially "-CF",
- used for brief listings, and list-directory-verbose-switches
+ 'ls' by the C-x C-d command (list-directory).
+ 'list-directory-brief-switches' is a string, initially "-CF",
+ used for brief listings, and 'list-directory-verbose-switches'
  is a string, initially "-l", used for verbose ones.
 
 ** For Ann Arbor Ambassador terminals, the termcap "ti" string
@@ -1757,7 +1761,7 @@ you will not on its account be queried about active 
subprocesses.
  to the specified filename BEFORE it tries the filename
  without change.
 
-** rmail now makes the mode line display the total number
+** 'rmail' now makes the mode line display the total number
  of messages and the current message number.
  The "f" command now means forward a message to another user.
  The command to search through all messages for a string is now "F".
@@ -1767,13 +1771,13 @@ you will not on its account be queried about active 
subprocesses.
 ** The hyphen character is now equivalent to a Space while
  in completing minibuffers.  Both mean to complete an additional word.
 
-** The Lisp function error now takes args like format
+** The Lisp function 'error' now takes args like 'format'
  which are used to construct the error message.
 
 ** Redisplay will refuse to start its display at the end of the buffer.
  It will pick a new place to display from, rather than use that.
 
-** The value returned by garbage-collect has been changed.
+** The value returned by 'garbage-collect' has been changed.
  Its first element is no longer a number but a cons,
  whose car is the number of cons cells now in use,
  and whose cdr is the number of cons cells that have been
@@ -1782,9 +1786,9 @@ you will not on its account be queried about active 
subprocesses.
  The third element is similar but describes markers.
 
 ** The variable buffer-name has been eliminated.
- The function buffer-name still exists.  This is to prevent
+ The function 'buffer-name' still exists.  This is to prevent
  user programs from changing buffer names without going
- through the rename-buffer function.
+ through the 'rename-buffer' function.
 
 
 
@@ -1795,7 +1799,7 @@ you will not on its account be queried about active 
subprocesses.
  Also, a line which consists of the fill prefix followed by
  white space separates paragraphs.
 
-** C-x C-v runs the new function find-alternate-file.
+** C-x C-v runs the new function 'find-alternate-file'.
  It finds the specified file, switches to that buffer,
  and kills the previous current buffer.  (It requires
  confirmation if that buffer had changes.)  This is
@@ -1807,18 +1811,18 @@ you will not on its account be queried about active 
subprocesses.
 ** Meta-g (fill-region) now fills each paragraph in the
  region individually.  To fill the region as if it were
  a single paragraph (for when the paragraph-delimiting mechanism
- does the wrong thing), use fill-region-as-paragraph.
+ does the wrong thing), use 'fill-region-as-paragraph'.
 
-** Tab in text mode now runs the function tab-to-tab-stop.
- A new mode called indented-text-mode is like text-mode
- except that in it Tab runs the function indent-relative,
+** Tab in text mode now runs the function 'tab-to-tab-stop'.
+ A new mode called 'indented-text-mode' is like 'text-mode'
+ except that in it Tab runs the function 'indent-relative',
  which indents the line under the previous line.
  If auto fill is enabled while in indented-text-mode,
  the new lines that it makes are indented.
 
-** Functions kill-rectangle and yank-rectangle.
+** Functions 'kill-rectangle' and 'yank-rectangle'.
  kill-rectangle deletes the rectangle specified by dot and mark
- (or by two arguments) and saves it in the variable killed-rectangle.
+ (or by two arguments) and saves it in the variable 'killed-rectangle'.
  yank-rectangle inserts the rectangle in that variable.
 
  Tab characters in a rectangle being saved are replaced
@@ -1859,7 +1863,7 @@ you will not on its account be queried about active 
subprocesses.
   C-r -- enter a recursive edit, then on exit ask again for a character
   C-l -- redisplay screen and ask again."
 
-** write-kbd-macro and append-kbd-macro are used to save
+** 'write-kbd-macro' and 'append-kbd-macro' are used to save
  a kbd macro definition in a file (as Lisp code to
  redefine the macro when the file is loaded).
  These commands differ in that write-kbd-macro
@@ -1868,11 +1872,11 @@ you will not on its account be queried about active 
subprocesses.
  record the keys which invoke the macro as well as the
  macro's definition.
 
-** The variable global-minor-modes is used to display
+** The variable 'global-minor-modes' is used to display
  strings in the mode line of all buffers.  It should be
  a list of elements that are conses whose cdrs are strings
  to be displayed.  This complements the variable
- minor-modes, which has the same effect but has a separate
+ 'minor-modes', which has the same effect but has a separate
  value in each buffer.
 
 ** C-x = describes horizontal scrolling in effect, if any.
@@ -1887,7 +1891,7 @@ you will not on its account be queried about active 
subprocesses.
 
 This release mostly fixes bugs.  There are a few new features:
 
-** apropos now sorts the symbols before displaying them.
+** 'apropos' now sorts the symbols before displaying them.
  Also, it returns a list of the symbols found.
 
  apropos now accepts a second arg PRED which should be a function
@@ -1898,7 +1902,7 @@ This release mostly fixes bugs.  There are a few new 
features:
  If the third argument to apropos is non-nil, apropos does not
  display anything; it merely returns the list of symbols found.
 
- C-h a now runs the new function command-apropos rather than
+ C-h a now runs the new function 'command-apropos' rather than
  apropos, and shows only symbols with definitions as commands.
 
 ** M-x shell sends the command
@@ -1908,8 +1912,8 @@ This release mostly fixes bugs.  There are a few new 
features:
  as it came from your ESHELL or SHELL environment variable
  but with directory name, if any, removed.
 
-** M-, now runs the command tags-loop-continue, which is used
- to resume a terminated tags-search or tags-query-replace.
+** M-, now runs the command 'tags-loop-continue', which is used
+ to resume a terminated 'tags-search' or 'tags-query-replace'.
 
 
 
@@ -1921,60 +1925,60 @@ It's Beat CCA Week.
  so that all buffer names used automatically by Emacs now have *'s.
 
 ** Undo information is now stored separately for each buffer.
- The Undo command (C-x u) always applies to the current
- buffer only.
+The Undo command (C-x u) always applies to the current
+buffer only.
 
  C-_ is now a synonym for C-x u.
 
- (buffer-flush-undo BUFFER) causes undo information not to
- be kept for BUFFER, and frees the space that would have
- been used to hold it.  In any case, no undo information is
- kept for buffers whose names start with spaces.  (These
- buffers also do not appear in the C-x C-b display.)
+'buffer-flush-undo' causes undo information not to
+be kept for BUFFER, and frees the space that would have
+been used to hold it.  In any case, no undo information is
+kept for buffers whose names start with spaces.  (These
+buffers also do not appear in the C-x C-b display.)
 
 ** Rectangle operations are now implemented.
- C-x r stores the rectangle described by dot and mark
- into a register; it reads the register name from the keyboard.
- C-x g, the command to insert the contents of a register,
- can be used to reinsert the rectangle elsewhere.
+C-x r stores the rectangle described by dot and mark
+into a register; it reads the register name from the keyboard.
+C-x g, the command to insert the contents of a register,
+can be used to reinsert the rectangle elsewhere.
 
  Other rectangle commands include
-  open-rectangle:
+  'open-rectangle':
     insert a blank rectangle in the position and size
     described by dot and mark, at its corners;
     the existing text is pushed to the right.
-  clear-rectangle:
+  'clear-rectangle':
     replace the rectangle described by dot and mark
     with blanks.  The previous text is deleted.
-  delete-rectangle:
+  'delete-rectangle':
     delete the text of the specified rectangle,
     moving the text beyond it on each line leftward.
 
 ** Side-by-side windows are allowed.  Use C-x 5 to split the
- current window into two windows side by side.
- C-x } makes the selected window ARG columns wider at the
- expense of the windows at its sides.  C-x { makes the selected
- window ARG columns narrower.  An argument to C-x 5 specifies
- how many columns to give to the leftmost of the two windows made.
+current window into two windows side by side.
+C-x } makes the selected window ARG columns wider at the
+expense of the windows at its sides.  C-x { makes the selected
+window ARG columns narrower.  An argument to C-x 5 specifies
+how many columns to give to the leftmost of the two windows made.
 
- C-x 2 now accepts a numeric argument to specify the number of
- lines to give to the uppermost of the two windows it makes.
+C-x 2 now accepts a numeric argument to specify the number of
+lines to give to the uppermost of the two windows it makes.
 
 ** Horizontal scrolling of the lines in a window is now implemented.
- C-x < (scroll-left) scrolls all displayed lines left,
- with the numeric argument (default 1) saying how far to scroll.
- When the window is scrolled left, some amount of the beginning
- of each nonempty line is replaced by an "$".
- C-x > scrolls right.  If a window has no text hidden at the left
- margin, it cannot be scrolled any farther right than that.
- When nonzero leftwards scrolling is in effect in a window.
- lines are automatically truncated at the window's right margin
- regardless of the value of the variable truncate-lines in the
- buffer being displayed.
-
-** C-x C-d now uses the default output format of `ls',
- which gives just file names in multiple columns.
- C-u C-x C-d passes the -l switch to `ls'.
+C-x < (scroll-left) scrolls all displayed lines left,
+with the numeric argument (default 1) saying how far to scroll.
+When the window is scrolled left, some amount of the beginning
+of each nonempty line is replaced by an "$".
+C-x > scrolls right.  If a window has no text hidden at the left
+margin, it cannot be scrolled any farther right than that.
+When nonzero leftwards scrolling is in effect in a window.
+lines are automatically truncated at the window's right margin
+regardless of the value of the variable 'truncate-lines' in the
+buffer being displayed.
+
+** C-x C-d now uses the default output format of 'ls',
+which gives just file names in multiple columns.
+C-u C-x C-d passes the -l switch to 'ls'.
 
 ** C-t at the end of a line now exchanges the two preceding characters.
 
@@ -1995,7 +1999,7 @@ It's Beat CCA Week.
 ** The mode line will now say "Def" after the major mode
  while a keyboard macro is being defined.
 
-** The variable fill-prefix is now used by Meta-q.
+** The variable 'fill-prefix' is now used by Meta-q.
  Meta-q removes the fill prefix from lines that start with it
  before filling, and inserts the fill prefix on each line
  after filling.
@@ -2057,7 +2061,7 @@ It's Beat CCA Week.
  including the terminating slash, requests the use
  of the default file name (usually the visited file's name).
 
- Set the variable insert-default-directory to nil
+ Set the variable 'insert-default-directory' to nil
  to turn off this feature.
 
 ** M-x shell now uses the environment variable ESHELL,
@@ -2095,83 +2099,82 @@ It's Beat CCA Week.
 ** The file of Lisp code Emacs reads on startup is now
  called ~/.emacs rather than ~/.emacs_pro.
 
-** copy-file now gives the copied file the same mode bits
+** 'copy-file' now gives the copied file the same mode bits
  as the original file.
 
 ** Output from a process inserted into the process's buffer
  no longer sets the buffer's mark.  Instead it sets a
  marker associated with the process to point to the end
  of the inserted text.  You can access this marker with
-    (process-mark PROCESS)
- and then either examine its position with marker-position
- or set its position with set-marker.
+ 'process-mark' and then either examine its position with
+ 'marker-position' or set its position with 'set-marker'.
 
-** completing-read takes a new optional fifth argument which,
+** 'completing-read' takes a new optional fifth argument which,
  if non-nil, should be a string of text to insert into
  the minibuffer before reading user commands.
 
-** The Lisp function elt now exists:
+** The Lisp function 'elt' now exists:
  (elt ARRAY N) is like (aref ARRAY N),
  (elt LIST N) is like (nth N LIST).
 
-** rplaca is now a synonym for setcar, and rplacd for setcdr.
- eql is now a synonym for eq; it turns out that the Common Lisp
+** 'rplaca' is now a synonym for 'setcar', and 'rplacd' for 'setcdr'.
+ 'eql' is now a synonym for 'eq'; it turns out that the Common Lisp
  distinction between eq and eql is insignificant in Emacs.
- numberp is a new synonym for integerp.
+ 'numberp' is a new synonym for 'integerp'.
 
-** auto-save has been renamed to auto-save-mode.
+** auto-save has been renamed to 'auto-save-mode'.
 
 ** Auto save file names for buffers are now created by the
- function make-auto-save-file-name.  This is so you can
+ function 'make-auto-save-file-name'.  This is so you can
  redefine that function to change the way auto save file names
  are chosen.
 
-** expand-file-name no longer discards a final slash.
+** 'expand-file-name' no longer discards a final slash.
     (expand-file-name "foo" "/lose") => "/lose/foo"
     (expand-file-name "foo/" "/lose") => "/lose/foo/"
 
- Also, expand-file-name no longer substitutes $ constructs.
- A new function substitute-in-file-name does this.  Reading
- a file name with read-file-name or the `f' or`F' option
- of interactive calling uses substitute-in-file-name
- on the file name that was read and returns the result.
+Also, expand-file-name no longer substitutes $ constructs.
+A new function 'substitute-in-file-name' does this.  Reading
+a file name with 'read-file-name' or the 'f' or'F' option
+of 'interactive' calling uses substitute-in-file-name
+on the file name that was read and returns the result.
 
- All I/O primitives including insert-file-contents and
- delete-file call expand-file-name on the file name supplied.
- This change makes them considerably faster in the usual case.
+All I/O primitives including 'insert-file-contents' and
+'delete-file' call 'expand-file-name' on the file name supplied.
+This change makes them considerably faster in the usual case.
 
 ** Interactive calling spec strings allow the new code letter 'D'
- which means to read a directory name.  It is like 'f' except
- that the default if the user makes no change in the minibuffer
- is to return the current default directory rather than the
- current visited file name.
+which means to read a directory name.  It is like 'f' except
+that the default if the user makes no change in the minibuffer
+is to return the current default directory rather than the
+current visited file name.
 
 
 
 * Changes in Emacs 1.5
 
-** suspend-emacs now accepts an optional argument
- which is a string to be stuffed as terminal input
- to be read by Emacs's superior shell after Emacs exits.
+** 'suspend-emacs' now accepts an optional argument
+which is a string to be stuffed as terminal input
+to be read by Emacs's superior shell after Emacs exits.
 
  A library called ledit exists which uses this feature
  to transmit text to a Lisp job running as a sibling of
  Emacs.
 
-** If find-file is given the name of a directory,
+** If 'find-file' is given the name of a directory,
  it automatically invokes dired on that directory
  rather than reading in the binary data that make up
  the actual contents of the directory according to Unix.
 
 ** Saving an Emacs buffer now preserves the file modes
  of any previously existing file with the same name.
- This works using new Lisp functions file-modes and
- set-file-modes, which can be used to read or set the mode
+ This works using new Lisp functions 'file-modes' and
+ 'set-file-modes', which can be used to read or set the mode
  bits of any file.
 
-** The Lisp function  cond  now exists, with its traditional meaning.
+** The Lisp function 'cond' now exists, with its traditional meaning.
 
-** defvar and defconst now permit the documentation string
+** 'defvar' and 'defconst' now permit the documentation string
  to be omitted.  defvar also permits the initial value
  to be omitted; then it acts only as a comment.
 
@@ -2180,9 +2183,9 @@ It's Beat CCA Week.
 * Changes in Emacs 1.4
 
 ** Auto-filling now normally indents the new line it creates
- by calling indent-according-to-mode.  This function, meanwhile,
+ by calling 'indent-according-to-mode'.  This function, meanwhile,
  has in Fundamental and Text modes the effect of making the line
- have an indentation of the value of left-margin, a per-buffer variable.
+ have an indentation of the value of 'left-margin', a per-buffer variable.
 
  Tab no longer precisely does indent-according-to-mode;
  it does that in all modes that supply their own indentation routine,
@@ -2215,33 +2218,33 @@ It's Beat CCA Week.
  an integer.
 
 ** The Lisp function 'function' now exists.  function is the
- same as quote, except that it serves as a signal to the
+ same as 'quote', except that it serves as a signal to the
  Lisp compiler that the argument should be compiled as
  a function.  Example:
    (mapcar (function (lambda (x) (+ x 5))) list)
 
-** The function set-key has been renamed to global-set-key.
- undefine-key and local-undefine-key has been renamed to
- global-unset-key and local-unset-key.
+** The function set-key has been renamed to 'global-set-key'.
+ 'undefine-key' and 'local-undefine-key' has been renamed to
+ 'global-unset-key' and 'local-unset-key'.
 
 ** Emacs now collects input from asynchronous subprocesses
- while waiting in the functions sleep-for and sit-for.
+ while waiting in the functions 'sleep-for' and 'sit-for'.
 
 ** Shell mode's Newline command attempts to distinguish subshell
  prompts from user input when issued in the middle of the buffer.
  It no longer reexecutes from dot to the end of the line;
  it reeexecutes the entire line minus any prompt.
  The prompt is recognized by searching for the value of
- shell-prompt-pattern, starting from the beginning of the line.
+ 'shell-prompt-pattern', starting from the beginning of the line.
  Anything thus skipped is not reexecuted.
 
 
 
 * Changes in Emacs 1.3
 
-** An undo facility exists now.  Type C-x u to undo a batch of
+** An undo facility exists now.  Type C-x u to 'undo' a batch of
  changes (usually one command's changes, but some commands
- such as query-replace divide their changes into multiple
+ such as 'query-replace' divide their changes into multiple
  batches.  You can repeat C-x u to undo further.  As long
  as no commands other than C-x u intervene, each one undoes
  another batch.  A numeric argument to C-x u acts as a repeat
@@ -2283,12 +2286,12 @@ It's Beat CCA Week.
  to be in effect when the file is edited.  See the file DIFF
  in the same directory as this file for full details.
 
-** A function nth is defined.  It means the same thing as in Common Lisp.
+** A function 'nth' is defined.  It means the same thing as in Common Lisp.
 
 ** The function install-command has been renamed to set-key.
  It now takes the key sequence as the first argument
  and the definition for it as the second argument.
- Likewise, local-install-command has been renamed to local-set-key.
+ Likewise, local-install-command has been renamed to 'local-set-key'.
 
 
 
@@ -2296,11 +2299,11 @@ It's Beat CCA Week.
 
 ** A Lisp single-stepping and debugging facility exists.
  To cause the debugger to be entered when an error
- occurs, set the variable debug-on-error non-nil.
+ occurs, set the variable 'debug-on-error' non-nil.
 
  To cause the debugger to be entered whenever function foo
- is called, do (debug-on-entry 'foo).  To cancel this,
- do (cancel-debug-on-entry 'foo).  debug-on-entry does
+ is called, use 'debug-on-entry'.  To cancel this,
+ use 'cancel-debug-on-entry'.  debug-on-entry does
  not work for primitives (written in C), only functions
  written in Lisp.  Most standard Emacs commands are in Lisp.
 
@@ -2311,31 +2314,31 @@ It's Beat CCA Week.
  by the argument values unless arguments are still being
  calculated.  At the beginning of the buffer is a description
  of why the debugger was entered: function entry, function exit,
- error, or simply that the user called the function `debug'.
+ error, or simply that the user called the function 'debug'.
 
- To exit the debugger and return to top level, type `q'.
+ To exit the debugger and return to top level, type 'q'.
 
  In the debugger, you can evaluate Lisp expressions by
- typing `e'.  This is equivalent to `M-ESC'.
+ typing 'e'.  This is equivalent to 'M-ESC'.
 
  When the debugger is entered due to an error, that is
  all you can do.  When it is entered due to function entry
  (such as, requested by debug-on-entry), you have two
  options:
   Continue execution and reenter debugger after the
-    completion of the function being entered.  Type `c'.
+    completion of the function being entered.  Type 'c'.
   Continue execution but enter the debugger before
-    the next subexpression.  Type `d'.
+    the next subexpression.  Type 'd'.
 
  You will see that some stack frames are marked with *.
  This means the debugger will be entered when those
  frames exit.  You will see the value being returned
  in the first line of the backtrace buffer.  Your options:
-  Continue execution, and return that value.  Type `c'.
-  Continue execution, and return a specified value.  Type `r'.
+  Continue execution, and return that value.  Type 'c'.
+  Continue execution, and return a specified value.  Type 'r'.
 
  You can mark a frame to enter the debugger on exit
- with the `b' command, or clear such a mark with `u'.
+ with the 'b' command, or clear such a mark with 'u'.
 
 ** Lisp macros now exist.
  For example, you can write
@@ -2373,7 +2376,7 @@ It's Beat CCA Week.
 ** The value of a Lisp expression evaluated using M-ESC
  is now printed in the minibuffer.
 
-** M-q now runs fill-paragraph, independent of major mode.
+** M-q now runs 'fill-paragraph', independent of major mode.
 
 ** C-h m now prints documentation on the current buffer's
  major mode.  What it prints is the documentation of the
@@ -2429,12 +2432,12 @@ It's Beat CCA Week.
   All editing commands treat hidden outline-mode lines
  as part of the preceding visible line.
 
-** C-x C-z runs save-buffers-kill-emacs
+** C-x C-z runs 'save-buffers-kill-emacs'
  offers to save each file buffer, then exits.
 
-** C-c's function is now called suspend-emacs.
+** C-c's function is now called 'suspend-emacs'.
 
-** The command C-x m runs mail, which switches to a buffer *mail*
+** The command C-x m runs 'mail', which switches to a buffer *mail*
  and lets you compose a message to send.  C-x 4 m runs mail in
  another window.  Type C-z C-s in the mail buffer to send the
  message according to what you have entered in the buffer.
@@ -2442,7 +2445,7 @@ It's Beat CCA Week.
   You must separate the headers from the message text with
  an empty line.
 
-** You can now dired partial directories (specified with names
+** You can now 'dired' partial directories (specified with names
  containing *'s, etc, all processed by the shell).  Also, you
  can dired more than one directory; dired names the buffer
  according to the filespec or directory name.  Reinvoking
@@ -2464,13 +2467,13 @@ It's Beat CCA Week.
  contains text put there for some other reason, it is cleared
  first.
 
-  t is now the top-level value of standard-output.
+  t is now the top-level value of 'standard-output'.
 
   t as an input stream now means "read via the minibuffer".
  The minibuffer is used to read a line of input, with editing,
- and this line is then parsed.  Any excess not used by `read'
- is ignored; each `read' from t reads fresh input.
- t is now the top-level value of standard-input.
+ and this line is then parsed.  Any excess not used by 'read'
+ is ignored; each 'read' from t reads fresh input.
+ t is now the top-level value of 'standard-input'.
 
 *** A marker may be used as an input stream or an output stream.
  The effect is to grab input from where the marker points,
@@ -2482,29 +2485,32 @@ It's Beat CCA Week.
  and the buffer's mark is set to the end of the inserted output
  each time output is inserted.
 
-*** (pos-visible-in-window-p POS WINDOW)
- returns t if position POS in WINDOW's buffer is in the range
- that is being displayed in WINDOW; nil if it is scrolled
- vertically out of visibility.
+*** New function 'pos-visible-in-window-p'
+
+    (pos-visible-in-window-p POS WINDOW)
+
+returns t if position POS in WINDOW's buffer is in the range
+that is being displayed in WINDOW; nil if it is scrolled
+vertically out of visibility.
 
-  If display in WINDOW is not currently up to date, this function
- calculates carefully whether POS would appear if display were
- done immediately based on the current (window-start WINDOW).
+If display in WINDOW is not currently up to date, this function
+calculates carefully whether POS would appear if display were
+done immediately based on the current 'window-start'.
 
-  POS defaults to (dot), and WINDOW to (selected-window).
+POS defaults to (dot), and WINDOW to (selected-window).
 
 *** Variable buffer-alist replaced by function (buffer-list).
- The actual alist of buffers used internally by Emacs is now
- no longer accessible, to prevent the user from crashing Emacs
- by modifying it.  The function buffer-list returns a list
- of all existing buffers.  Modifying this list cannot hurt anything
- as a new list is constructed by each call to buffer-list.
+The actual alist of buffers used internally by Emacs is now
+no longer accessible, to prevent the user from crashing Emacs
+by modifying it.  The function buffer-list returns a list
+of all existing buffers.  Modifying this list cannot hurt anything
+as a new list is constructed by each call to buffer-list.
 
-*** load now takes an optional third argument NOMSG which, if non-nil,
- prevents load from printing a message when it starts and when
- it is done.
+*** 'load' now takes an optional third argument NOMSG which, if non-nil,
+prevents load from printing a message when it starts and when
+it is done.
 
-*** byte-recompile-directory is a new function which finds all
+*** 'byte-recompile-directory' is a new function which finds all
  the .elc files in a directory, and regenerates each one which
  is older than the corresponding .el (Lisp source) file.
 
diff --git a/etc/NEWS.18 b/etc/NEWS.18
index 78d63e5db7..a90d0bd0ea 100644
--- a/etc/NEWS.18
+++ b/etc/NEWS.18
@@ -29,18 +29,18 @@ run, Emacs now tries the entire terminal type first.  If 
that doesn't
 yield a file that exists, the last hyphen and what follows it is
 stripped.  If that doesn't yield a file that exists, the previous
 hyphen is stripped, and so on until all hyphens are gone.  For
-example, if the terminal type is `aaa-48-foo', Emacs will try first
+example, if the terminal type is 'aaa-48-foo', Emacs will try first
 `term/aaa-48-foo.el', then `term/aaa-48.el' and finally `term/aaa.el'.
 
 Underscores now receive the same treatment as hyphens.
 
-** Texinfo features: @defun, etc.  texinfo-show-structure.
-New template commands.  texinfo-format-region.
+** Texinfo features: @defun, etc.  'texinfo-show-structure'.
+New template commands.  'texinfo-format-region'.
 
-** The special "local variable" `eval' is now ignored if you are running
+** The special "local variable" 'eval' is now ignored if you are running
 as root.
 
-** New command `c-macro-expand' shows the result of C macro expansion
+** New command 'c-macro-expand' shows the result of C macro expansion
 in the region.  It works using the C preprocessor, so its results
 are completely accurate.
 
@@ -50,21 +50,21 @@ are completely accurate.
 
 ** New hooks.
 
-*** `spell-region' now allows you to filter the text before spelling-checking.
-If the value of `spell-filter' is non-nil, it is called, with no arguments,
+*** 'spell-region' now allows you to filter the text before spelling-checking.
+If the value of 'spell-filter' is non-nil, it is called, with no arguments,
 looking at a temporary buffer containing a copy of the text to be checked.
 It can alter the text freely before the spell program sees it.
 
-*** The variable `lpr-command' now specifies the command to be used when
+*** The variable 'lpr-command' now specifies the command to be used when
 you use the commands to print text (such as M-x print-buffer).
 
-*** Posting netnews now calls the value of `news-inews-hook' (if not nil)
+*** Posting netnews now calls the value of 'news-inews-hook' (if not nil)
 as a function of no arguments before the actual posting.
 
-*** Rmail now calls the value of `rmail-show-message-hook' (if not nil)
+*** Rmail now calls the value of 'rmail-show-message-hook' (if not nil)
 as a function of no arguments, each time a new message is selected.
 
-*** `kill-emacs' calls the value of `kill-emacs-hook' as a function of no args.
+*** 'kill-emacs' calls the value of 'kill-emacs-hook' as a function of no args.
 
 ** New libraries.
 See the source code of each library for more information.
@@ -100,20 +100,20 @@ comes from a directory of files created by you.
 
 ** New programming features.
 
-*** The variable `window-system-version' now contains the version number
+*** The variable 'window-system-version' now contains the version number
 of the window system you are using (if appropriate).  When using X windows,
 its value is either 10 or 11.
 
 *** (interactive "N") uses the prefix argument if any; otherwise, it reads
 a number using the minibuffer.
 
-*** VMS: there are two new functions `vms-system-info' and `shrink-to-icon'.
+*** VMS: there are two new functions 'vms-system-info' and 'shrink-to-icon'.
 The former allows you to get many kinds of system status information.
 See its self-documentation for full details.
 The second is used with the window system: it iconifies the Emacs window.
 
-*** VMS: the new function `define-logical-name' allows you to create
-job-wide logical names.  The old function `define-dcl-symbol' has been
+*** VMS: the new function 'define-logical-name' allows you to create
+job-wide logical names.  The old function 'define-dcl-symbol' has been
 removed.
 
 
@@ -134,8 +134,8 @@ code is displayed in another window with an arrow added to 
the line
 where the program is executing.
 
 Special GDB-mode commands include M-s, M-n, M-i, M-u, M-d, and C-c C-f
-which send the GDB commands `step', `next', `stepi', `up', `down'
-and `finish'.
+which send the GDB commands 'step', 'next', 'stepi', 'up', 'down'
+and 'finish'.
 
 In any source file, the commands C-x SPC tells GDB to set a breakpoint
 on the current line.
@@ -146,28 +146,28 @@ on the current line.
 
 This is a way you can explicitly request not to make a backup.
 
-** `term-setup-hook' is for users only.
+** 'term-setup-hook' is for users only.
 
 Emacs never uses this variable for internal purposes, so you can freely
 set it in your `.emacs' file to make Emacs do something special after
 loading any terminal-specific setup file from `lisp/term'.
 
-** `copy-keymap' now copies recursive submaps.
+** 'copy-keymap' now copies recursive submaps.
 
 ** New overlay-arrow feature.
 
-If you set the variable `overlay-arrow-string' to a string
-and `overlay-arrow-position' to a marker, that string is displayed on
+If you set the variable 'overlay-arrow-string' to a string
+and 'overlay-arrow-position' to a marker, that string is displayed on
 the screen at the position of that marker, hiding whatever text would
 have appeared there.  If that position isn't on the screen, or if
 the buffer the marker points into isn't displayed, there is no effect.
 
 ** -batch mode can read from the terminal.
 
-It now works to use `read-char' to do terminal input in a noninteractive
+It now works to use 'read-char' to do terminal input in a noninteractive
 Emacs run.  End of file causes Emacs to exit.
 
-** Variables `data-bytes-used' and `data-bytes-free' removed.
+** Variables 'data-bytes-used' and 'data-bytes-free' removed.
 
 These variables cannot really work because the 24-bit range of an
 integer in (most ports of) GNU Emacs is not large enough to hold their
@@ -177,7 +177,7 @@ values on many systems.
 
 * Changes in Emacs 18.45, since version 18.41.
 
-** C indentation parameter `c-continued-brace-offset'.
+** C indentation parameter 'c-continued-brace-offset'.
 
 This parameter's value is added to the indentation of any
 line that is in a continuation context and starts with an open-brace.
@@ -195,7 +195,7 @@ abbreviation, if the expansion found is all lower case 
except perhaps
 for its first letter, then the case pattern of the abbreviation
 is carried over to the expansion that replaces it.
 
-** TeX-mode syntax.
+** 'TeX-mode' syntax.
 
 \ is no longer given "escape character" syntax in TeX mode.  It now
 has the syntax of an ordinary punctuation character.  As a result,
@@ -203,13 +203,13 @@ has the syntax of an ordinary punctuation character.  As 
a result,
 
 ** Mail-mode automatic Reply-To field.
 
-If the variable `mail-default-reply-to' is non-`nil', then each time
+If the variable 'mail-default-reply-to' is non-'nil', then each time
 you start to compose a message, a Reply-To field is inserted with
-its contents taken from the value of `mail-default-reply-to'.
+its contents taken from the value of 'mail-default-reply-to'.
 
 ** Where is your .emacs file?
 
-If you run Emacs under `su', so your real and effective uids are
+If you run Emacs under 'su', so your real and effective uids are
 different, Emacs uses the home directory associated with the real uid
 (the name you actually logged in under) to find the .emacs file.
 
@@ -228,7 +228,7 @@ case.  You can use either upper or lower case 
indiscriminately.
 ** VMS-only function 'define-dcl-symbol'.
 
 This is a new name for the function formerly called
-`define-logical-name'.
+'define-logical-name'.
 
 
 
@@ -288,26 +288,26 @@ normally print such a message.
 
 *** Cursor appears in last line during y-or-n questions.
 
-Questions that want a `y' or `n' answer now move the cursor
+Questions that want a 'y' or 'n' answer now move the cursor
 to the last line, following the question.
 
 ** Library loading changes.
 
-`load' now considers all possible suffixes (`.elc', `.el' and none)
-for each directory in `load-path' before going on to the next directory.
+'load' now considers all possible suffixes (`.elc', `.el' and none)
+for each directory in 'load-path' before going on to the next directory.
 It now accepts an optional fourth argument which, if non-nil, says to
 use no suffixes; then the file name must be given in full.  The search
-of the directories in `load-path' goes on as usual in this case, but
+of the directories in 'load-path' goes on as usual in this case, but
 it too can be prevented by passing an absolute file name.
 
-The value of `load-path' no longer by default includes nil (meaning to
-look in the current default directory).  The idea is that `load' should
+The value of 'load-path' no longer by default includes nil (meaning to
+look in the current default directory).  The idea is that 'load' should
 be used to search the path only for libraries to be found in the standard
 places.  If you want to override system libraries with your own, place
 your own libraries in one special directory and add that directory to the
-front of `load-path'.
+front of 'load-path'.
 
-The function `load' is no longer a command; that is to say, `M-x load'
+The function 'load' is no longer a command; that is to say, `M-x load'
 is no longer allowed.  Instead, there are two commands for loading files.
 `M-x load-library' is equivalent to the old meaning of `M-x load'.
 `M-x load-file' reads a file name with completion and defaulting
@@ -315,11 +315,11 @@ and then loads exactly that file, with no searching and 
no suffixes.
 
 ** Emulation of other editors.
 
-*** `edt-emulation-on' starts emulating DEC's EDT editor.
+*** 'edt-emulation-on' starts emulating DEC's EDT editor.
 
-Do `edt-emulation-off' to return Emacs to normal.
+Do 'edt-emulation-off' to return Emacs to normal.
 
-*** `vi-mode' and `vip-mode' starts emulating vi.
+*** 'vi-mode' and 'vip-mode' starts emulating vi.
 
 These are two different vi emulations provided by GNU Emacs users.
 We are interested in feedback as to which emulation is preferable.
@@ -327,18 +327,18 @@ We are interested in feedback as to which emulation is 
preferable.
 See the documentation and source code for these functions
 for more information.
 
-*** `set-gosmacs-bindings' emulates Gosling Emacs.
+*** 'set-gosmacs-bindings' emulates Gosling Emacs.
 
 This command changes many global bindings to resemble those of
 Gosling Emacs.  The previous bindings are saved and can be restored using
-`set-gnu-bindings'.
+'set-gnu-bindings'.
 
 ** Emulation of a display terminal.
 
 Within Emacs it is now possible to run programs (such as emacs or
 supdup) which expect to do output to a visual display terminal.
 
-See the function `terminal-emulator' for more information.
+See the function 'terminal-emulator' for more information.
 
 ** New support for keypads and function keys.
 
@@ -366,7 +366,7 @@ assigned to the standard key-names.
 One other change in terminal-specific files: if the value of the TERM
 variable contains a hyphen, only the part before the first hyphen is
 used in forming the name of the terminal-specific file.  Thus, for
-terminal type `aaa-48', the file loaded is now `term/aaa.el' rather
+terminal type 'aaa-48', the file loaded is now `term/aaa.el' rather
 than `term/aaa-48.el'.
 
 ** New startup command line options.
@@ -375,53 +375,54 @@ than `term/aaa-48.el'.
 insert the contents of FILE into the current buffer at that point in
 command line processing.  This is like using the command M-x insert-file.
 
-`-funcall', `-load', `-user' and `-no-init-file' are new synonyms for
-`-f', `-l', `-u' and `-q'.
+'-funcall', '-load', '-user' and '-no-init-file' are new synonyms for
+'-f', '-l', '-u' and '-q'.
 
-`-nw' means don't use a window system.  If you are using a terminal
+'-nw' means don't use a window system.  If you are using a terminal
 emulator on the X window system and you want to run Emacs to work through
 the terminal emulator instead of working directly with the window system,
 use this switch.
 
 ** Buffer-sorting commands.
 
-Various M-x commands whose names start with `sort-' sort parts of
+Various M-x commands whose names start with 'sort-' sort parts of
 the region:
 
-sort-lines     divides the region into lines and sorts them alphabetically.
-sort-pages     divides into pages and sorts them alphabetically.
-sort-paragraphs        divides into paragraphs and sorts them alphabetically.
-sort-fields    divides into lines and sorts them alphabetically
+'sort-lines'   divides the region into lines and sorts them alphabetically.
+'sort-pages'   divides into pages and sorts them alphabetically.
+'sort-paragraphs'
+               divides into paragraphs and sorts them alphabetically.
+'sort-fields'  divides into lines and sorts them alphabetically
                according to one field in the line.
                The numeric argument specifies which field (counting
                from field 1 at the beginning of the line).  Fields in a line
                are separated by whitespace.
-sort-numeric-fields
+'sort-numeric-fields'
                is similar but converts the specified fields to numbers
                and sorts them numerically.
-sort-columns   divides into lines and sorts them according to the contents
+'sort-columns' divides into lines and sorts them according to the contents
                of a specified range of columns.
 
 Refer to the self-documentation of these commands for full usage information.
 
 ** Changes in various commands.
 
-*** `tags-query-replace' and `tags-search' change.
+*** 'tags-query-replace' and 'tags-search' change.
 
 These functions now display the name of the file being searched at the moment.
 
-*** `occur' output now serves as a menu.  `occur-menu' command deleted.
+*** 'occur' output now serves as a menu.  'occur-menu' command deleted.
 
 `M-x occur' now allows you to move quickly to any of the occurrences
-listed.  Select the `*Occur*' buffer that contains the output of `occur',
+listed.  Select the `*Occur*' buffer that contains the output of 'occur',
 move point to the occurrence you want, and type C-c C-c.
 This will move point to the same occurrence in the buffer that the
 occurrences were found in.
 
-The command `occur-menu' is thus obsolete, and has been deleted.
+The command 'occur-menu' is thus obsolete, and has been deleted.
 
 One way to get a list of matching lines without line numbers is to
-copy the text to another buffer and use the command `keep-lines'.
+copy the text to another buffer and use the command 'keep-lines'.
 
 *** Incremental search changes.
 
@@ -441,20 +442,20 @@ incremental regexp search with C-M-s C-r.
 
 If you add a `*', `?' or `\|' to an incremental search regexp,
 point will back up if that is appropriate.  For example, if
-you have searched for `ab' and add a `*', point moves to the
-first match for `ab*', which may be before the match for `ab'
+you have searched for 'ab' and add a `*', point moves to the
+first match for `ab*', which may be before the match for 'ab'
 that was previously found.
 
 If an incremental search is failing and you ask to repeat it,
 it will start again from the beginning of the buffer (or the end,
 if it is a backward search).
 
-The search-controlling parameters `isearch-slow-speed' and
-`isearch-slow-window-lines' have now been renamed to start with
-`search' instead of `isearch'.  Now all the parameters' names start
-with `search'.
+The search-controlling parameters 'isearch-slow-speed' and
+'isearch-slow-window-lines' have now been renamed to start with
+'search' instead of 'isearch'.  Now all the parameters' names start
+with 'search'.
 
-If `search-slow-window-lines' is negative, the slow search window
+If 'search-slow-window-lines' is negative, the slow search window
 is put at the top of the screen, and the absolute value or the
 negative number specifies the height of it.
 
@@ -490,9 +491,9 @@ by searching the buffer for words that start with the 
abbreviation.
 
 *** Changes in saving kbd macros.
 
-The commands `write-kbd-macro' and `append-kbd-macro' have been
+The commands 'write-kbd-macro' and 'append-kbd-macro' have been
 deleted.  The way to save a keyboard macro is to use the new command
-`insert-kbd-macro', which inserts Lisp code to define the macro as
+'insert-kbd-macro', which inserts Lisp code to define the macro as
 it is currently defined into the buffer before point.  Visit a Lisp
 file such as your Emacs init file `~/.emacs', insert the macro
 definition (perhaps deleting an old definition for the same macro)
@@ -507,14 +508,14 @@ an abbrev, even if abbrev-mode is not turned on.
 
 The command C-M-x in Lisp mode, which sends the current defun to
 an inferior Lisp process, now works by writing the text into a temporary
-file and actually sending only a `load'-form to load the file.
+file and actually sending only a 'load'-form to load the file.
 As a result, it avoids the Unix bugs that used to strike when the
 text was above a certain length.
 
 With a prefix argument, this command now makes the inferior Lisp buffer
 appear on the screen and scrolls it so that the bottom is showing.
 
-Two variables `inferior-lisp-load-command' and `inferior-lisp-prompt',
+Two variables 'inferior-lisp-load-command' and 'inferior-lisp-prompt',
 exist to customize these feature for different Lisp implementations.
 
 *** C-x p now disabled.
@@ -552,7 +553,7 @@ When you change the visited file name of a buffer, the auto 
save file
 is now renamed to belong to the new visited file name.
 
 You can customize the way auto save file names are made by redefining
-the two functions `make-auto-save-file-name' and `auto-save-file-name-p',
+the two functions 'make-auto-save-file-name' and 'auto-save-file-name-p',
 both of which are defined in `files.el'.
 
 *** Modifying a buffer whose file is changed on disk is detected instantly.
@@ -566,7 +567,7 @@ If it has, you are asked to confirm that you want to change 
the buffer.
 
 Emacs can now know about buffers that it should offer to save on exit
 even though they are not visiting files.  This is done for any buffer
-which has a non-nil local value of `buffer-offer-save'.  By default,
+which has a non-nil local value of 'buffer-offer-save'.  By default,
 Mail mode provides such a local value.
 
 *** Backup file changes.
@@ -592,9 +593,9 @@ give the user name and password for use on that host.  FTP 
is reinvoked
 each time you ask to use it, but previously specified user names and
 passwords are remembered automatically.
 
-*** Dired `g' command.
+*** Dired 'g' command.
 
-`g' in Dired mode is equivalent to M-x revert-buffer; it causes the
+'g' in Dired mode is equivalent to M-x revert-buffer; it causes the
 current contents of the same directory to be read in.
 
 ** Changes in major modes.
@@ -608,11 +609,11 @@ afterward.
 The old definition did one additional thing: it reindented the line
 before the new newline.  This has been removed because it made the
 command twice as slow.  The only time it was really useful was after the
-insertion of an `else', since the fact of starting with `else' may change
+insertion of an 'else', since the fact of starting with 'else' may change
 the way that line is indented.  Now you will have to type TAB again
-yourself to reindent the `else' properly.
+yourself to reindent the 'else' properly.
 
-If the variable `c-tab-always-indent' is set to `nil', the TAB command
+If the variable 'c-tab-always-indent' is set to 'nil', the TAB command
 in C mode, with no argument, will just insert a tab character if there
 is non-whitespace preceding point on the current line.  Giving it a
 prefix argument will force reindentation of the line (as well as
@@ -622,7 +623,7 @@ of the compound statement that begins after point, if any).
 
 This mode provides commands for motion and indentation of Fortran code,
 plus built-in abbrevs for Fortran keywords.  For details, see the manual
-or the on-line documentation of the command `fortran-mode'.
+or the on-line documentation of the command 'fortran-mode'.
 
 *** Scribe mode now exists.
 
@@ -641,7 +642,7 @@ Most of them are the same as in Shell mode.
 
 *** Picture mode changes.
 
-The special picture-mode commands to specify the direction of cursor
+The special 'picture-mode' commands to specify the direction of cursor
 motion after insertion have been moved to C-c keys.  The commands to
 specify diagonal motion were already C-c keys; they are unchanged.
 The keys to specify horizontal or vertical motion are now
@@ -659,7 +660,7 @@ LaTeX mode now exists.  Use M-x latex-mode to select this 
mode, and
 M-x plain-tex-mode to select the previously existing mode for Plain
 TeX.  M-x tex-mode attempts to examine the contents of the buffer and
 choose between latex-mode and plain-tex-mode accordingly; if the
-buffer is empty or it cannot tell, the variable `TeX-default-mode'
+buffer is empty or it cannot tell, the variable 'TeX-default-mode'
 controls the choice.  Its value should be the symbol for the mode to
 be used.
 
@@ -693,7 +694,7 @@ C-c C-f   Move to next visible heading at the same level.
 C-c C-b   Move to previous visible heading at the same level.
 C-c C-u   Move up to previous visible heading at a higher level.
 
-The variable `outline-regexp' now controls recognition of heading lines.
+The variable 'outline-regexp' now controls recognition of heading lines.
 Any line whose beginning matches this regexp is a heading line.
 The depth in outline structure is determined by the length of
 the string that matches.
@@ -729,7 +730,7 @@ Thus, C-c LETTER is always unassigned.
 
 *** Rmail C-r command changed to w.
 
-The Rmail command to edit the current message is now `w'.  This change
+The Rmail command to edit the current message is now 'w'.  This change
 has been made because people frequently type C-r while in Rmail hoping
 to do a reverse incremental search.  That now works.
 
@@ -742,7 +743,7 @@ decryption of the body of a news message.  It defaults to 
the USENET
 standard of 13, and accepts any numeric arg between 1 to 25 and -25 to -1.
 The function is bound to C-c C-r in both news-mode and news-reply-mode.
 
-*** rmail-output command added.
+*** 'rmail-output' command added.
 
 The C-o command has been bound to rmail-output in news-mode.
 This allows one to append an article to a file which is in either Unix
@@ -785,7 +786,7 @@ either you are using a window system and give Emacs a 
separate window
 or you run the other programs as inferiors of Emacs (such as, using
 M-x shell).
 
-First prepare the existing Emacs process by loading the `server'
+First prepare the existing Emacs process by loading the 'server'
 library and executing M-x server-start.  (Your .emacs can do this
 automatically.)
 
@@ -820,24 +821,24 @@ Emacs will no longer load a file named `.emacs.el' or 
`emacs.elc'
 in place of `.emacs'.  This is so that it will take less time to
 find `.emacs'.  If you want to compile your init file, give it another
 name and make `.emacs' a link to the `.elc' file, or make it contain
-a call to `load' to load the `.elc' file.
+a call to 'load' to load the `.elc' file.
 
-*** `default-profile' renamed to `default', and loaded after `.emacs'.
+*** 'default-profile' renamed to 'default', and loaded after `.emacs'.
 
-It used to be the case that the file `default-profile' was loaded if
+It used to be the case that the file 'default-profile' was loaded if
 and only if `.emacs' was not found.
 
-Now the name `default-profile' is not used at all.  Instead, a library
-named `default' is loaded after the `.emacs' file.  `default' is loaded
-whether the `.emacs' file exists or not.  However, loading of `default'
-can be prevented if the `.emacs' file sets `inhibit-default-init' to non-nil.
+Now the name 'default-profile' is not used at all.  Instead, a library
+named 'default' is loaded after the `.emacs' file.  'default' is loaded
+whether the `.emacs' file exists or not.  However, loading of 'default'
+can be prevented if the `.emacs' file sets 'inhibit-default-init' to non-nil.
 
 In fact, you would call the default file `default.el' and probably would
-byte-compile it to speed execution.
+'byte-compile' it to speed execution.
 
-Note that for most purposes you are better off using a `site-init' library
+Note that for most purposes you are better off using a 'site-init' library
 since that will be loaded before the runnable Emacs is dumped.  By using
-a `site-init' library, you avoid taking up time each time Emacs is started.
+a 'site-init' library, you avoid taking up time each time Emacs is started.
 
 *** inhibit-command-line has been eliminated.
 
@@ -845,79 +846,79 @@ This variable used to exist for .emacs files to set.  It 
has been
 eliminated because you can get the same effect by setting
 command-line-args to nil and setting inhibit-startup-message to t.
 
-** `apply' is more general.
+** 'apply' is more general.
 
-`apply' now accepts any number of arguments.  The first one is a function;
+'apply' now accepts any number of arguments.  The first one is a function;
 the rest are individual arguments to pass to that function, except for the
 last, which is a list of arguments to pass.
 
-Previously, `apply' required exactly two arguments.  Its old behavior
+Previously, 'apply' required exactly two arguments.  Its old behavior
 follows as a special case of the new definition.
 
-** New code-letter for `interactive'.
+** New code-letter for 'interactive'.
 
 (interactive "NFoo: ") is like (interactive "nFoo: ") in reading
 a number using the minibuffer to serve as the argument; however,
 if a prefix argument was specified, it uses the prefix argument
 value as the argument, and does not use the minibuffer at all.
 
-This is used by the `goto-line' and `goto-char' commands.
+This is used by the 'goto-line' and 'goto-char' commands.
 
 ** Semantics of variables.
 
 *** Built-in per-buffer variables improved.
 
 Several built-in variables which in the past had a different value in
-each buffer now behave exactly as if `make-variable-buffer-local' had
+each buffer now behave exactly as if 'make-variable-buffer-local' had
 been done to them.
 
-These variables are `tab-width', `ctl-arrow', `truncate-lines',
-`fill-column', `left-margin', `mode-line-format', `abbrev-mode',
-`overwrite-mode', `case-fold-search', `auto-fill-hook',
-`selective-display', `selective-display-ellipses'.
+These variables are 'tab-width', 'ctl-arrow', 'truncate-lines',
+'fill-column', 'left-margin', 'mode-line-format', 'abbrev-mode',
+'overwrite-mode', 'case-fold-search', 'auto-fill-hook',
+'selective-display', 'selective-display-ellipses'.
 
 To be precise, each variable has a default value which shows through
-in most buffers and can be accessed with `default-value' and set with
-`set-default'.  Setting the variable with `setq' makes the variable
+in most buffers and can be accessed with 'default-value' and set with
+'set-default'.  Setting the variable with 'setq' makes the variable
 local to the current buffer.  Changing the default value has retroactive
 effect on all buffers in which the variable is not local.
 
-The variables `default-case-fold-search', etc., are now obsolete.
+The variables 'default-case-fold-search', etc., are now obsolete.
 They now refer to the default value of the variable, which is not
 quite the same behavior as before, but it should enable old init files
 to continue to work.
 
 *** New per-buffer variables.
 
-The variables `fill-prefix', `comment-column' and `indent-tabs-mode'
-are now per-buffer.  They work just like `fill-column', etc.
+The variables 'fill-prefix', 'comment-column' and 'indent-tabs-mode'
+are now per-buffer.  They work just like 'fill-column', etc.
 
-*** New function `setq-default'.
+*** New function 'setq-default'.
 
-`setq-default' sets the default value of a variable, and uses the
-same syntax that `setq' accepts: the variable name is not evaluated
+'setq-default' sets the default value of a variable, and uses the
+same syntax that 'setq' accepts: the variable name is not evaluated
 and need not be quoted.
 
 `(setq-default case-fold-search nil)' would make searches case-sensitive
-in all buffers that do not have local values for `case-fold-search'.
+in all buffers that do not have local values for 'case-fold-search'.
 
-*** Functions `global-set' and `global-value' deleted.
+*** Functions 'global-set' and 'global-value' deleted.
 
 These functions were never used except by mistake by users expecting
-the functionality of `set-default' and `default-value'.
+the functionality of 'set-default' and 'default-value'.
 
 ** Changes in defaulting of major modes.
 
-When `default-major-mode' is `nil', new buffers are supposed to
+When 'default-major-mode' is 'nil', new buffers are supposed to
 get their major mode from the buffer that is current.  However,
 certain major modes (such as Dired mode, Rmail mode, Rmail Summary mode,
 and others) are not reasonable to use in this way.
 
-Now such modes' names have been given non-`nil' `mode-class' properties.
+Now such modes' names have been given non-'nil' 'mode-class' properties.
 If the current buffer's mode has such a property, Fundamental mode is
 used as the default for newly created buffers.
 
-** `where-is-internal' requires additional arguments.
+** 'where-is-internal' requires additional arguments.
 
 This function now accepts three arguments, two of them required:
 DEFINITION, the definition to search for; LOCAL-KEYMAP, the keymap
@@ -934,7 +935,7 @@ are required when previously only one argument was allowed. 
 To get
 the old behavior of this function, write `(current-local-map)' as
 the expression for the second argument.
 
-The incompatibility is sad, but `nil' is a legitimate value for the
+The incompatibility is sad, but 'nil' is a legitimate value for the
 second argument (it means there is no local keymap), so it cannot also
 serve as a default meaning to use the current local keymap.
 
@@ -945,9 +946,9 @@ usual replacement of the abbrev with the expansion before 
running the
 hook.  Previously the abbrev itself was deleted but the expansion was
 not inserted.
 
-** Function `scan-buffer' deleted.
+** Function 'scan-buffer' deleted.
 
-Use `search-forward' or `search-backward' in place of `scan-buffer'.
+Use 'search-forward' or 'search-backward' in place of 'scan-buffer'.
 You will have to rearrange the arguments.
 
 ** X window interface improvements.
@@ -959,7 +960,7 @@ for details.
 
 *** New pop-up menu facility.
 
-The new function `x-popup-menu' pops up a menu (in a X window)
+The new function 'x-popup-menu' pops up a menu (in a X window)
 and returns an indication of which selection the user made.
 For more information, see its self-documentation.
 
@@ -969,7 +970,7 @@ This command prints the disassembly of a byte-compiled 
Emacs Lisp function.
 
 Would anyone like to interface this to the debugger?
 
-** `insert-buffer-substring' can insert part of the current buffer.
+** 'insert-buffer-substring' can insert part of the current buffer.
 
 The old restriction that the text being inserted had to come from
 a different buffer is now lifted.
@@ -977,41 +978,42 @@ a different buffer is now lifted.
 When inserting text from the current buffer, the text to be inserted
 is determined from the specified bounds before any copying takes place.
 
-** New function `substitute-key-definition'.
+** New function 'substitute-key-definition'.
 
 This is a new way to replace one command with another command as the
 binding of whatever keys may happen to refer to it.
 
-(substitute-key-definition OLDDEF NEWDEF KEYMAP) looks through KEYMAP
-for keys defined to run OLDDEF, and rebinds those keys to run NEWDEF
-instead.
+   (substitute-key-definition OLDDEF NEWDEF KEYMAP)
 
-** New function `insert-char'.
+looks through KEYMAP for keys defined to run OLDDEF, and rebinds those keys to
+run NEWDEF instead.
+
+** New function 'insert-char'.
 
 Insert a specified character, a specified number of times.
 
-** `mark-marker' changed.
+** 'mark-marker' changed.
 
 When there is no mark, this now returns a marker that points
-nowhere, rather than `nil'.
+nowhere, rather than 'nil'.
 
-** `ding' accepts argument.
+** 'ding' accepts argument.
 
-When given an argument, the function `ding' does not terminate
-execution of a keyboard macro.  Normally, `ding' does terminate
+When given an argument, the function 'ding' does not terminate
+execution of a keyboard macro.  Normally, 'ding' does terminate
 all macros that are currently executing.
 
-** New function `minibuffer-depth'.
+** New function 'minibuffer-depth'.
 
 This function returns the current depth in minibuffer activations.
 The value is zero when the minibuffer is not in use.
 Values greater than one are possible if the user has entered the
 minibuffer recursively.
 
-** New function `documentation-property'.
+** New function 'documentation-property'.
 
 (documentation-property SYMBOL PROPNAME) is like (get SYMBOL PROPNAME),
-except that if the property value is a number `documentation-property'
+except that if the property value is a number 'documentation-property'
 will take that number (or its absolute value) as a character position
 in the DOC file and return the string found there.
 
@@ -1032,8 +1034,8 @@ will expand into
   "ESC C-x evaluates the defun containing point."
 
 regardless of the current major mode, because ESC C-x is defined to
-run `eval-defun' in the keymap `emacs-lisp-mode-map'.  The effect is
-to show the key for `eval-defun' in Emacs Lisp mode regardless of the
+run 'eval-defun' in the keymap 'emacs-lisp-mode-map'.  The effect is
+to show the key for 'eval-defun' in Emacs Lisp mode regardless of the
 current major mode.
 
 The `\<...>' construct applies to all `\[...]' constructs that follow it,
@@ -1047,50 +1049,50 @@ has been used or not.
 
 ** Multiple hooks allowed in certain contexts.
 
-The old hook variables `find-file-hook', `find-file-not-found-hook' and
-`write-file-hook' have been replaced.
+The old hook variables 'find-file-hook', 'find-file-not-found-hook' and
+'write-file-hook' have been replaced.
 
-The replacements are `find-file-hooks', `find-file-not-found-hooks'
-and `write-file-hooks'.  Each holds a list of functions to be called;
-by default, `nil', for no functions.  The functions are called in
+The replacements are 'find-file-hooks', 'find-file-not-found-hooks'
+and 'write-file-hooks'.  Each holds a list of functions to be called;
+by default, 'nil', for no functions.  The functions are called in
 order of appearance in the list.
 
-In the case of `find-file-hooks', all the functions are executed.
+In the case of 'find-file-hooks', all the functions are executed.
 
-In the case of `find-file-not-found-hooks', if any of the functions
-returns non-`nil', the rest of the functions are not called.
+In the case of 'find-file-not-found-hooks', if any of the functions
+returns non-'nil', the rest of the functions are not called.
 
-In the case of `write-file-hooks', if any of the functions returns
-non-`nil', the rest of the functions are not called, and the file is
+In the case of 'write-file-hooks', if any of the functions returns
+non-'nil', the rest of the functions are not called, and the file is
 considered to have been written already; so actual writing in the
-usual way is not done.  If `write-file-hooks' is local to a buffer,
-it is set to its global value if `set-visited-file-name' is called
+usual way is not done.  If 'write-file-hooks' is local to a buffer,
+it is set to its global value if 'set-visited-file-name' is called
 (and thus by C-x C-w as well).
 
-`find-file-not-found-hooks' and `write-file-hooks' can be used
+'find-file-not-found-hooks' and 'write-file-hooks' can be used
 together to implement editing of files that are not stored as Unix
 files: stored in archives, or inside version control systems, or on
 other machines running other operating systems and accessible via ftp.
 
 ** New hooks for suspending Emacs.
 
-Suspending Emacs runs the hook `suspend-hook' before suspending
-and the hook `suspend-resume-hook' if the suspended Emacs is resumed.
+Suspending Emacs runs the hook 'suspend-hook' before suspending
+and the hook 'suspend-resume-hook' if the suspended Emacs is resumed.
 Running a hook is done by applying the variable's value to no arguments
-if the variable has a non-`nil' value.  If `suspend-hook' returns
-non-`nil', then suspending is inhibited and so is running the
-`suspend-resume-hook'.  The non-`nil' value means that the `suspend-hook'
+if the variable has a non-'nil' value.  If 'suspend-hook' returns
+non-'nil', then suspending is inhibited and so is running the
+'suspend-resume-hook'.  The non-'nil' value means that the 'suspend-hook'
 has done whatever suspending is required.
 
 ** Disabling commands can print a special message.
 
-A command is disabled by giving it a non-`nil' `disabled' property.
+A command is disabled by giving it a non-'nil' 'disabled' property.
 Now, if this property is a string, it is included in the message
 printed when the user tries to run the command.
 
 ** Emacs can open TCP connections.
 
-The function `open-network-stream' opens a TCP connection to
+The function 'open-network-stream' opens a TCP connection to
 a specified host and service.  Its value is a Lisp object that represents
 the connection.  The object is a kind of "subprocess", and I/O are
 done like I/O to subprocesses.
@@ -1100,7 +1102,7 @@ done like I/O to subprocesses.
 *** New mode-line control features.
 
 The display of the mode line used to be controlled by a format-string
-that was the value of the variable `mode-line-format'.
+that was the value of the variable 'mode-line-format'.
 
 This variable still exists, but it now allows more general values,
 not just strings.  Lists, cons cells and symbols are also meaningful.
@@ -1139,16 +1141,16 @@ used as mode elements, and what they do in the display:
                at most the width specified by the integer.
 
 There is always one mode element to start with, that being the value of
-`mode-line-format', but if this value is a list then it leads to several
+'mode-line-format', but if this value is a list then it leads to several
 more mode elements, which can lead to more, and so on.
 
 There is one new %-construct for mode elements that are strings:
 `%n' displays ` Narrow' for a buffer that is narrowed.
 
-The default value of `mode-line-format' refers to several other variables.
-These variables are `mode-name', `mode-line-buffer-identification',
-`mode-line-process', `mode-line-modified', `global-mode-string' and
-`minor-mode-alist'.  The first four are local in every buffer in which they
+The default value of 'mode-line-format' refers to several other variables.
+These variables are 'mode-name', 'mode-line-buffer-identification',
+'mode-line-process', 'mode-line-modified', 'global-mode-string' and
+'minor-mode-alist'.  The first four are local in every buffer in which they
 are changed from the default.
 
 mode-name      Name of buffer's major mode.  Local in every buffer.
@@ -1156,7 +1158,7 @@ mode-name Name of buffer's major mode.  Local in every 
buffer.
 mode-line-buffer-identification
                Normally the list ("Emacs: %17b"), it is responsible
                for displaying text to indicate what buffer is being shown
-               and what kind of editing it is doing.  `Emacs' means
+               and what kind of editing it is doing.  'Emacs' means
                that a file of characters is being edited.  Major modes
                such as Info and Dired which edit or view other kinds
                of data often change this value.  This variables becomes
@@ -1188,72 +1190,72 @@ global-mode-string
 The idea of these variables is to eliminate the need for major modes
 to alter mode-line-format itself.
 
-*** `window-point' valid for selected window.
+*** 'window-point' valid for selected window.
 
-The value returned by `window-point' used to be incorrect when its
+The value returned by 'window-point' used to be incorrect when its
 argument was the selected window.  Now the value is correct.
 
 *** Window configurations may be saved as Lisp objects.
 
-The function `current-window-configuration' returns a special type of
+The function 'current-window-configuration' returns a special type of
 Lisp object that represents the current layout of windows: the
 sizes and positions of windows, which buffers appear in them, and
 which parts of the buffers appear on the screen.
 
-The function `set-window-configuration' takes one argument, which must
+The function 'set-window-configuration' takes one argument, which must
 be a window configuration object, and restores that configuration.
 
-*** New hook `temp-output-buffer-show-hook'.
+*** New hook 'temp-output-buffer-show-hook'.
 
 This hook allows you to control how help buffers are displayed.
-Whenever `with-output-to-temp-buffer' has executed its body and wants
-to display the temp buffer, if this variable is bound and non-`nil'
+Whenever 'with-output-to-temp-buffer' has executed its body and wants
+to display the temp buffer, if this variable is bound and non-'nil'
 then its value is called with one argument, the temp buffer.
 The hook function is solely responsible for displaying the buffer.
 The standard manner of display--making the buffer appear in a window--is
 used only if there is no hook function.
 
-*** New function `minibuffer-window'.
+*** New function 'minibuffer-window'.
 
 This function returns the window used (sometimes) for displaying
 the minibuffer.  It can be used even when the minibuffer is not active.
 
-*** New feature to `next-window'.
+*** New feature to 'next-window'.
 
-If the optional second argument is neither `nil' nor `t', the minibuffer
+If the optional second argument is neither 'nil' nor 't', the minibuffer
 window is omitted from consideration even when active; if the starting
 window was the last non-minibuffer window, the value will be the first
 non-minibuffer window.
 
-*** New variable `minibuffer-scroll-window'.
+*** New variable 'minibuffer-scroll-window'.
 
-When this variable is non-`nil', the command `scroll-other-window'
+When this variable is non-'nil', the command 'scroll-other-window'
 uses it as the window to be scrolled.  Displays of completion-lists
 set this variable to the window containing the display.
 
-*** New argument to `sit-for'.
+*** New argument to 'sit-for'.
 
-A non-nil second argument to `sit-for' means do not redisplay;
+A non-nil second argument to 'sit-for' means do not redisplay;
 just wait for the specified time or until input is available.
 
-*** Deleted function `set-minor-mode'; minor modes must be changed.
+*** Deleted function 'set-minor-mode'; minor modes must be changed.
 
-The function `set-minor-mode' has been eliminated.  The display
+The function 'set-minor-mode' has been eliminated.  The display
 of minor mode names in the mode line is now controlled by the
-variable `minor-mode-alist'.  To specify display of a new minor
+variable 'minor-mode-alist'.  To specify display of a new minor
 mode, it is sufficient to add an element to this list.  Once that
 is done, you can turn the mode on and off just by setting a variable,
 and the display will show its status automatically.
 
-*** New variable `cursor-in-echo-area'.
+*** New variable 'cursor-in-echo-area'.
 
 If this variable is non-nil, the screen cursor appears on the
 last line of the screen, at the end of the text displayed there.
 
 Binding this variable to t is useful at times when reading single
-characters of input with `read-char'.
+characters of input with 'read-char'.
 
-*** New per-buffer variable `selective-display-ellipses'.
+*** New per-buffer variable 'selective-display-ellipses'.
 
 If this variable is non-nil, an ellipsis (`...') appears on the screen
 at the end of each text line that is followed by invisible text.
@@ -1262,16 +1264,16 @@ If this variable is nil, no ellipses appear.  Then 
there is no sign
 on the screen that invisible text is present.
 
 Text is made invisible under the control of the variable
-`selective-display'; this is how Outline mode and C-x $ work.
+'selective-display'; this is how Outline mode and C-x $ work.
 
-*** New variable `no-redraw-on-reenter'.
+*** New variable 'no-redraw-on-reenter'.
 
 If you set this variable non-nil, Emacs will not clear the screen when
 you resume it after suspending it.  This is for the sake of terminals
 with multiple screens of memory, where the termcap entry has been set
 up to switch between screens when Emacs is suspended and resumed.
 
-*** New argument to `set-screen-height' or `set-screen-width'.
+*** New argument to 'set-screen-height' or 'set-screen-width'.
 
 These functions now take an optional second argument which says
 what significance the newly specified height or width has.
@@ -1295,21 +1297,21 @@ needed.
 
 ** File-related changes.
 
-*** New parameter `backup-by-copying-when-mismatch'.
+*** New parameter 'backup-by-copying-when-mismatch'.
 
-If this variable is non-`nil', then when Emacs is about to save a
+If this variable is non-'nil', then when Emacs is about to save a
 file, it will create the backup file by copying if that would avoid
 changing the file's uid or gid.
 
-The default value of this variable is `nil', because usually it is
+The default value of this variable is 'nil', because usually it is
 useful to have the uid of a file change according to who edited it
-last.  I recommend that this variable be left normally `nil' and
+last.  I recommend that this variable be left normally 'nil' and
 changed with a local variables list in those particular files where
 the uid needs to be preserved.
 
-*** New parameter `file-precious-flag'.
+*** New parameter 'file-precious-flag'.
 
-If this variable is non-`nil', saving the buffer tries to avoid
+If this variable is non-'nil', saving the buffer tries to avoid
 leaving an incomplete file due to disk full or other I/O errors.
 It renames the old file before saving.  If saving is successful,
 the renamed file is deleted; if saving gets an error, the renamed
@@ -1317,29 +1319,29 @@ file is renamed back to the name you visited.
 
 Backups are always made by copying for such files.
 
-*** New variable `buffer-offer-save'.
+*** New variable 'buffer-offer-save'.
 
-If the value of this variable is non-`nil' in a buffer then exiting
+If the value of this variable is non-'nil' in a buffer then exiting
 Emacs will offer to save the buffer (if it is modified and nonempty)
 even if the buffer is not visiting a file.  This variable is
 automatically made local to the current buffer whenever it is set.
 
-*** `rename-file', `copy-file', `add-name-to-file' and `make-symbolic-link'.
+*** 'rename-file', 'copy-file', 'add-name-to-file' and 'make-symbolic-link'.
 
-The third argument to these functions used to be `t' or `nil'; `t'
+The third argument to these functions used to be 't' or 'nil'; 't'
 meaning go ahead even if the specified new file name already has a file,
-and `nil' meaning to get an error.
+and 'nil' meaning to get an error.
 
 Now if the third argument is a number it means to ask the user for
 confirmation in this case.
 
-*** New optional argument to `copy-file'.
+*** New optional argument to 'copy-file'.
 
-If `copy-file' receives a non-nil fourth argument, it attempts
+If 'copy-file' receives a non-nil fourth argument, it attempts
 to give the new copy the same time-of-last-modification that the
 original file has.
 
-*** New function `file-newer-than-file-p'.
+*** New function 'file-newer-than-file-p'.
 
 (file-newer-than-file-p FILE1 FILE2) returns non-nil if FILE1 has been
 modified more recently than FILE2.  If FILE1 does not exist, the value
@@ -1347,19 +1349,19 @@ is always nil; otherwise, if FILE2 does not exist, the 
value is t.
 This is meant for use when FILE2 depends on FILE1, to see if changes
 in FILE1 make it necessary to recompute FILE2 from it.
 
-*** Changed function `file-exists-p'.
+*** Changed function 'file-exists-p'.
 
-This function is no longer the same as `file-readable-p'.
-`file-exists-p' can now return t for a file that exists but which
+This function is no longer the same as 'file-readable-p'.
+'file-exists-p' can now return t for a file that exists but which
 the fascists won't allow you to read.
 
-*** New function `file-locked-p'.
+*** New function 'file-locked-p'.
 
-This function receives a file name as argument and returns `nil'
-if the file is not locked, `t' if locked by this Emacs, or a
+This function receives a file name as argument and returns 'nil'
+if the file is not locked, 't' if locked by this Emacs, or a
 string giving the name of the user who has locked it.
 
-*** New function `file-name-sans-versions'.
+*** New function 'file-name-sans-versions'.
 
 (file-name-sans-versions NAME) returns a substring of NAME, with any
 version numbers or other backup suffixes deleted from the end.
@@ -1379,9 +1381,9 @@ directory, but the name of the file that holds that 
directory is
 `du:[rms]foo.dir'.
 
 There are two new functions for converting between directory names
-and file names.  `directory-file-name' takes a directory name and
+and file names.  'directory-file-name' takes a directory name and
 returns the name of the file in which that directory's data is stored.
-`file-name-as-directory' takes the name of a file and returns
+'file-name-as-directory' takes the name of a file and returns
 the corresponding directory name.  These always understand Unix file name
 syntax; on VMS, they understand VMS syntax as well.
 
@@ -1390,30 +1392,30 @@ and (directory-file-name "/usr/rms/") returns 
"/usr/rms".
 On VMS, (file-name-as-directory "du:[rms]foo.dir") returns "du:[rms.foo]"
 and (directory-file-name "du:[rms.foo]") returns "du:[rms]foo.dir".
 
-*** Value of `file-attributes' changed.
+*** Value of 'file-attributes' changed.
 
 The function file-attributes returns a list containing many kinds of
 information about a file.  Now the list has eleven elements.
 
-The tenth element is `t' if deleting the file and creating another
+The tenth element is 't' if deleting the file and creating another
 file of the same name would result in a change in the file's group;
-`nil' if there would be no change.  You can also think of this as
+'nil' if there would be no change.  You can also think of this as
 comparing the file's group with the default group for files created in
 the same directory by you.
 
 The eleventh element is the inode number of the file.
 
-*** VMS-only function `file-name-all-versions'.
+*** VMS-only function 'file-name-all-versions'.
 
 This function returns a list of all the completions, including version
 number, of a specified version-number-less file name.  This is like
-`file-name-all-completions', except that the latter returns values
+'file-name-all-completions', except that the latter returns values
 that do not include version numbers.
 
-*** VMS-only variable `vms-stmlf-recfm'.
+*** VMS-only variable 'vms-stmlf-recfm'.
 
 On a VMS system, if this variable is non-nil, Emacs will give newly
-created files the record format `stmlf'.  This is necessary for files
+created files the record format 'stmlf'.  This is necessary for files
 that must contain lines of arbitrary length, such as compiled Emacs
 Lisp.
 
@@ -1423,35 +1425,35 @@ no effect.
 
 This variable has no effect on Unix systems.
 
-*** `insert-file-contents' on an empty file.
+*** 'insert-file-contents' on an empty file.
 
 This no longer sets the buffer's "modified" flag.
 
-*** New function (VMS only) `define-logical-name':
+*** New function (VMS only) 'define-logical-name':
 
 (define-logical-name LOGICAL TRANSLATION) defines a VMS logical name
 LOGICAL whose translation is TRANSLATION.  The new name applies to
 the current process only.
 
-*** Deleted variable `ask-about-buffer-names'.
+*** Deleted variable 'ask-about-buffer-names'.
 
 If you want buffer names for files to be generated in a special way,
-you must redefine `create-file-buffer'.
+you must redefine 'create-file-buffer'.
 
 ** Subprocess-related changes.
 
-*** New function `process-list'.
+*** New function 'process-list'.
 
 This function takes no arguments and returns a list of all
 of Emacs's asynchronous subprocesses.
 
-*** New function `process-exit-status'.
+*** New function 'process-exit-status'.
 
 This function, given a process, process name or buffer as argument,
 returns the exit status code or signal number of the process.
 If the process has not yet exited or died, this function returns 0.
 
-*** Process output ignores `buffer-read-only'.
+*** Process output ignores 'buffer-read-only'.
 
 Output from a process will go into the process's buffer even if the
 buffer is read only.
@@ -1464,57 +1466,57 @@ permanently alter the selected buffer in a 
straightforward manner.
 
 *** Specifying environment variables for subprocesses.
 
-When a subprocess is started with `start-process' or `call-process',
-the value of the variable `process-environment' is taken to
+When a subprocess is started with 'start-process' or 'call-process',
+the value of the variable 'process-environment' is taken to
 specify the environment variables to give the subprocess.  The
 value should be a list of strings, each of the form "VAR=VALUE".
 
-`process-environment' is initialized when Emacs starts up
+'process-environment' is initialized when Emacs starts up
 based on Emacs's environment.
 
-*** New variable `process-connection-type'.
+*** New variable 'process-connection-type'.
 
-If this variable is `nil', when a subprocess is created, Emacs uses
+If this variable is 'nil', when a subprocess is created, Emacs uses
 a pipe rather than a pty to communicate with it.  Normally this
-variable is `t', telling Emacs to use a pty if ptys are supported
+variable is 't', telling Emacs to use a pty if ptys are supported
 and one is available.
 
-*** New function `waiting-for-user-input-p'.
+*** New function 'waiting-for-user-input-p'.
 
-This function, given a subprocess as argument, returns `t' if that
+This function, given a subprocess as argument, returns 't' if that
 subprocess appears to be waiting for input sent from Emacs,
-or `nil' otherwise.
+or 'nil' otherwise.
 
-*** New hook `shell-set-directory-error-hook'.
+*** New hook 'shell-set-directory-error-hook'.
 
 The value of this variable is called, with no arguments, whenever
 Shell mode gets an error trying to keep track of directory-setting
-commands (such as `cd' and `pushd') used in the shell buffer.
+commands (such as 'cd' and 'pushd') used in the shell buffer.
 
-** New functions `user-uid' and `user-real-uid'.
+** New functions 'user-uid' and 'user-real-uid'.
 
 These functions take no arguments and return, respectively,
 the effective uid and the real uid of the Emacs process.
 The value in each case is an integer.
 
-** New variable `print-escape-newlines' controls string printing.
+** New variable 'print-escape-newlines' controls string printing.
 
-If this variable is non-`nil', then when a Lisp string is printed
-by the Lisp printing function `prin1' or `print', newline characters
+If this variable is non-'nil', then when a Lisp string is printed
+by the Lisp printing function 'prin1' or 'print', newline characters
 are printed as `\n' rather than as a literal newline.
 
-** New function `sysnetunam' on HPUX.
+** New function 'sysnetunam' on HPUX.
 
 This function takes two arguments, a network address PATH and a
-login string LOGIN, and executes the system call `netunam'.
-It returns `t' if the call succeeds, otherwise `nil'.
+login string LOGIN, and executes the system call 'netunam'.
+It returns 't' if the call succeeds, otherwise 'nil'.
 
 News regarding installation:
 
 ** Many `s-...' file names changed.
 
 Many `s-...' files have been renamed.  All periods in such names,
-except the ones just before the final `h', have been changed to
+except the ones just before the final 'h', have been changed to
 hyphens.  Thus, `s-bsd4.2.h' has been renamed to `s-bsd4-2.h'.
 
 This is so a Unix distribution can be moved mechanically to VMS.
@@ -1533,7 +1535,7 @@ well as functions.
 
 This may make it easier to port to some machines.
 
-** Macros `XPNTR' and `XSETPNTR'; flag `DATA_SEG_BITS'.
+** Macros 'XPNTR' and 'XSETPNTR'; flag `DATA_SEG_BITS'.
 
 These macros exclusively are used to unpack a pointer from a Lisp_Object
 and to insert a pointer into a Lisp_Object.  Redefining them may help
@@ -1557,7 +1559,7 @@ for more information.
 
 ** `SYSTEM_MALLOC' prevents use of GNU `malloc.c'.
 
-SYSTEM_MALLOC, if defined, means use the system's own `malloc' routines
+SYSTEM_MALLOC, if defined, means use the system's own 'malloc' routines
 rather than those that come with Emacs.
 
 Use this only if absolutely necessary, because if it is used you do
@@ -1580,23 +1582,23 @@ These flags just say whether certain system calls are 
available.
 ** New macros control compiler switches, linker switches and libraries.
 
 The m- and s- files can now control in a modular fashion the precise
-arguments passed to `cc' and `ld'.
+arguments passed to 'cc' and 'ld'.
 
-LIBS_STANDARD defines the standard C libraries.  Default is `-lc'.
-LIBS_DEBUG defines the extra libraries to use when debugging.  Default `-lg'.
+LIBS_STANDARD defines the standard C libraries.  Default is '-lc'.
+LIBS_DEBUG defines the extra libraries to use when debugging.  Default '-lg'.
 LIBS_SYSTEM can be defined by the s- file to specify extra libraries.
 LIBS_MACHINE can be defined by the m- file to specify extra libraries.
 LIBS_TERMCAP defines the libraries for Termcap or Terminfo.
   It is defined by default in a complicated fashion but the m- or s- file
   can override it.
 
-LD_SWITCH_SYSTEM can be defined by the s- file to specify extra `ld' switches.
-  The default is `-X' on BSD systems except those few that use COFF object 
files.
-LD_SWITCH_MACHINE can be defined by the m- file to specify extra `ld' switches.
+LD_SWITCH_SYSTEM can be defined by the s- file to specify extra 'ld' switches.
+  The default is '-X' on BSD systems except those few that use COFF object 
files.
+LD_SWITCH_MACHINE can be defined by the m- file to specify extra 'ld' switches.
 
-C_DEBUG_SWITCH defines the switches to give `cc' when debugging.  Default `-g'.
-C_OPTIMIZE_SWITCH defines the switches to give `cc' to optimize.  Default `-O'.
-C_SWITCH_MACHINE can be defined by the m- file to specify extra `cc' switches.
+C_DEBUG_SWITCH defines the switches to give 'cc' when debugging.  Default '-g'.
+C_OPTIMIZE_SWITCH defines the switches to give 'cc' to optimize.  Default '-O'.
+C_SWITCH_MACHINE can be defined by the m- file to specify extra 'cc' switches.
 
 
 
diff --git a/etc/NEWS.19 b/etc/NEWS.19
index 7eb4deaeba..d21cd8187f 100644
--- a/etc/NEWS.19
+++ b/etc/NEWS.19
@@ -17,8 +17,8 @@ This file is about changes in Emacs versions 19.
 ** Bibtex mode no longer turns on Auto Fill automatically.  (No major
 mode should do that--it is the user's choice.)
 
-** The variable normal-auto-fill-function specifies the function to
-use for auto-fill-function, if and when Auto Fill is turned on.
+** The variable 'normal-auto-fill-function' specifies the function to
+use for 'auto-fill-function', if and when Auto Fill is turned on.
 Major modes can set this locally to alter how Auto Fill works.
 
 
@@ -53,7 +53,7 @@ This feature is not enabled by default; since the Alt key is 
also the
 Meta key, it is too easy and painful to activate this feature by
 accident.
 
-** The command apply-macro-to-region-lines repeats the last defined
+** The command 'apply-macro-to-region-lines' repeats the last defined
 keyboard macro once for each complete line within the current region.
 It does this line by line, by moving point to the beginning of that
 line and then executing the macro.
@@ -71,13 +71,13 @@ characters.
 
 Font Lock can be configured to use Fast Lock mode and Lazy Lock mode (see
 below) in a flexible way.  Rather than adding the appropriate function to the
-hook font-lock-mode-hook, you can use the new variable font-lock-support-mode
+hook font-lock-mode-hook, you can use the new variable 'font-lock-support-mode'
 to control which modes have Fast Lock mode or Lazy Lock mode turned on when
 Font Lock mode is enabled.
 
 For example, to use Fast Lock mode when Font Lock mode is turned on, put:
 
- (setq font-lock-support-mode 'fast-lock-mode)
+    (setq font-lock-support-mode 'fast-lock-mode)
 
 in your ~/.emacs.
 
@@ -93,9 +93,9 @@ Emacs has been idle for a given amount of time.
 
 To use this package, put in your ~/.emacs:
 
- (setq font-lock-support-mode 'lazy-lock-mode)
+    (setq font-lock-support-mode 'lazy-lock-mode)
 
-To control the package behavior, see the documentation for `lazy-lock-mode'.
+To control the package behavior, see the documentation for 'lazy-lock-mode'.
 
 ** Changes in BibTeX mode.
 
@@ -142,7 +142,7 @@ referred.
 *** An nn-like pick-and-read minor mode is available for the summary
 buffers.
 
-    (add-hook 'gnus-summary-mode-hook 'gnus-pick-mode)
+    (add-hook 'gnus-summary-mode-hook #'gnus-pick-mode)
 
 *** In binary groups you can use a special binary minor mode:
 
@@ -150,7 +150,7 @@ buffers.
 
 *** Groups can be grouped in a folding topic hierarchy.
 
-    (add-hook 'gnus-group-mode-hook 'gnus-topic-mode)
+    (add-hook 'gnus-group-mode-hook #'gnus-topic-mode)
 
 *** Gnus can re-send and bounce mail.
 
@@ -159,7 +159,7 @@ buffers.
 *** Groups can now have a score, and bubbling based on entry frequency
 is possible.
 
-    (add-hook 'gnus-summary-exit-hook 'gnus-summary-bubble-group)
+    (add-hook 'gnus-summary-exit-hook #'gnus-summary-bubble-group)
 
 *** Groups can be process-marked, and commands can be performed on
 groups of groups.
@@ -175,7 +175,7 @@ batches, ClariNet briefs collections, and just about 
everything else.
 
 *** Groups can be sorted according to many criteria.
 
-    For instance: (setq gnus-group-sort-function 'gnus-group-sort-by-rank)
+    For instance: (setq gnus-group-sort-function #'gnus-group-sort-by-rank)
 
 *** New group parameters have been introduced to set list-address and
 expiration times.
@@ -196,17 +196,17 @@ articles with the `*' command.
 
 *** Article headers can be buttonized.
 
-    (add-hook 'gnus-article-display-hook 'gnus-article-add-buttons-to-head)
+    (add-hook 'gnus-article-display-hook #'gnus-article-add-buttons-to-head)
 
 *** All mail backends support fetching articles by Message-ID.
 
 *** Duplicate mail can now be treated properly.  See the
-`nnmail-treat-duplicates' variable.
+'nnmail-treat-duplicates' variable.
 
 *** All summary mode commands are available directly from the article
 buffer.
 
-*** Frames can be part of `gnus-buffer-configuration'.
+*** Frames can be part of 'gnus-buffer-configuration'.
 
 *** Mail can be re-scanned by a daemonic process.
 
@@ -235,7 +235,7 @@ refetching.
 *** A clean copy of the current article is always stored in a separate
 buffer to allow easier treatment.
 
-*** Gnus can suggest where to save articles.  See `gnus-split-methods'.
+*** Gnus can suggest where to save articles.  See 'gnus-split-methods'.
 
 *** Gnus doesn't have to do as much prompting when saving.
 
@@ -255,7 +255,7 @@ cited text to hide is now customizable.
 
 *** Boring headers can be hidden.
 
-    (add-hook 'gnus-article-display-hook 'gnus-article-hide-boring-headers)
+    (add-hook 'gnus-article-display-hook #'gnus-article-hide-boring-headers)
 
 *** Default scoring values can now be set from the menu bar.
 
@@ -275,10 +275,10 @@ exists.
 ** The variable print-length applies to printing vectors and bitvectors,
 as well as lists.
 
-** The new function keymap-parent returns the parent keymap
+** The new function 'keymap-parent' returns the parent keymap
 of a given keymap.
 
-** The new function set-keymap-parent specifies a new parent for a
+** The new function 'set-keymap-parent' specifies a new parent for a
 given keymap.  The arguments are KEYMAP and PARENT.  PARENT must be a
 keymap or nil.
 
@@ -357,17 +357,17 @@ This command, not previously mentioned in NEWS, toggles a 
mode in
 which the minibuffer window expands to show as many lines as the
 minibuffer contains.
 
-** `title' frame parameter and resource.
+** 'title' frame parameter and resource.
 
-The `title' X resource now specifies just the frame title, nothing else.
+The 'title' X resource now specifies just the frame title, nothing else.
 It does not affect the name used for looking up other X resources.
-It works by setting the new `title' frame parameter, which likewise
+It works by setting the new 'title' frame parameter, which likewise
 affects just the displayed title of the frame.
 
-The `name' parameter continues to do what it used to do:
+The 'name' parameter continues to do what it used to do:
 it specifies the frame name for looking up X resources,
 and also serves as the default for the displayed title
-when the `title' parameter is unspecified or nil.
+when the 'title' parameter is unspecified or nil.
 
 ** Emacs now uses the X toolkit by default, if you have a new
 enough version of X installed (X11R5 or newer).
@@ -406,7 +406,7 @@ Emacs or the operating system crashes, the file remains for 
M-x
 recover-session.
 
 You can turn off the writing of these files by setting
-auto-save-list-file-name to nil.  If you do this, M-x recover-session
+'auto-save-list-file-name' to nil.  If you do this, M-x recover-session
 will not work.
 
 Some previous Emacs versions failed to delete these files even on
@@ -417,13 +417,13 @@ now that the bug is fixed.
 
 ** Changes to Version Control (VC)
 
-There is a new variable, vc-follow-symlinks.  It indicates what to do
+There is a new variable, 'vc-follow-symlinks'.  It indicates what to do
 when you visit a link to a file that is under version control.
 Editing the file through the link bypasses the version control system,
 which is dangerous and probably not what you want.
 
 If this variable is t, VC follows the link and visits the real file,
-telling you about it in the echo area.  If it is `ask' (the default),
+telling you about it in the echo area.  If it is 'ask' (the default),
 VC asks for confirmation whether it should follow the link.  If nil,
 the link is visited and a warning displayed.
 
@@ -449,27 +449,27 @@ Completion in fields that hold mail addresses works based 
on the list
 of local users plus your aliases.  Additionally, if your site provides
 a mail directory or a specific host to use for any unrecognized user
 name, you can arrange to query that host for completion also.  (See the
-documentation of variables `mail-directory-process' and
-`mail-directory-stream'.)
+documentation of variables 'mail-directory-process' and
+'mail-directory-stream'.)
 
-** A greatly extended sgml-mode offers new features such as (to be configured)
+** A greatly extended 'sgml-mode' offers new features such as (to be 
configured)
 skeletons with completing read for tags and attributes, typing named
 characters including optionally all 8bit characters, making tags invisible
 with optional alternate display text, skipping and deleting tag(pair)s.
 
 Note: since Emacs' syntax feature cannot limit the special meaning of ', " and
 - to inside <>, for some texts the result, especially of font locking, may be
-wrong (see `sgml-specials' if you get wrong results).
+wrong (see 'sgml-specials' if you get wrong results).
 
-The derived html-mode configures this with tags and attributes more or
+The derived 'html-mode' configures this with tags and attributes more or
 less HTML3ish.  It also offers optional quick keys like C-c 1 for
-headline or C-c u for unordered list (see `html-quick-keys').  Edit /
+headline or C-c u for unordered list (see 'html-quick-keys').  Edit /
 Text Properties / Face or M-g combinations create tags as applicable.
 Outline minor mode is supported and level 1 font-locking tries to
 fontify tag contents (which only works when they fit on one line, due
 to a limitation in font-lock).
 
-External viewing via browse-url can occur automatically upon saving.
+External viewing via 'browse-url' can occur automatically upon saving.
 
 ** M-x imenu-add-to-menubar now adds to the menu bar for the current
 buffer only.  If you want to put an Imenu item in the menu bar for all
@@ -494,7 +494,7 @@ isn't in sorted order, so you should finish each entry with 
C-c C-c
 (bibtex-close-entry) after you have inserted or modified it.
 The default value of bibtex-maintain-sorted-entries is nil.
 
-*** Function `show-all' is no longer bound to a key, since C-u C-c C-q
+*** Function 'show-all' is no longer bound to a key, since C-u C-c C-q
 does the same job.
 
 *** Entries with quotes inside quote-delimited fields (as `author =
@@ -509,13 +509,13 @@ text.
 
 Font Lock mode can be turned on globally, in buffers that support it, by the
 new command global-font-lock-mode.  You can use the new variable
-font-lock-global-modes to control which modes have Font Lock mode automagically
-turned on.  By default, this variable is set so that Font Lock mode is turned
-on globally where the buffer mode supports it.
+'font-lock-global-modes' to control which modes have Font Lock mode
+automagically turned on.  By default, this variable is set so that
+Font Lock mode is turned on globally where the buffer mode supports it.
 
 For example, to automagically turn on Font Lock mode where supported, put:
 
- (global-font-lock-mode t)
+    (global-font-lock-mode t)
 
 in your ~/.emacs.
 
@@ -524,10 +524,10 @@ in your ~/.emacs.
 In Font Lock mode, editing a line automatically refontifies that line only.
 However, if your change alters the syntactic context for following lines,
 those lines remain incorrectly fontified.  To refontify them, use the new
-command M-g M-g (font-lock-fontify-block).
+command M-g M-g ('font-lock-fontify-block').
 
 In certain major modes, M-g M-g refontifies the entire current function.
-(The variable font-lock-mark-block-function controls how to find the
+(The variable 'font-lock-mark-block-function' controls how to find the
 current function.)  In other major modes, M-g M-g refontifies 16 lines
 above and below point.
 
@@ -535,7 +535,7 @@ With a prefix argument N, M-g M-g refontifies N lines above 
and below point.
 
 ** Follow mode
 
-Follow mode is a new minor mode combining windows showing the same
+'follow-mode' is a new minor mode combining windows showing the same
 buffer into one tall "virtual window".  The windows are typically two
 side-by-side windows.  Follow mode makes them scroll together as if
 they were a unit.  To use it, go to a frame with just one window,
@@ -554,7 +554,7 @@ to hs-hide-hook and hs-show-hook, to follow the convention 
for
 normal hooks.
 
 ** Simula mode now has a menu containing the most important commands.
-The new command simula-indent-exp is bound to C-M-q.
+The new command 'simula-indent-exp' is bound to C-M-q.
 
 ** etags can now handle programs written in Erlang.  Files are
 recognized by the extensions .erl and .hrl.  The tagged lines are
@@ -577,23 +577,23 @@ pressing both mouse buttons.
 restricted functionality on MS-DOS, now work.  The most important ones
 are:
 
-**** Printing (both with `M-x lpr-buffer' and with `ps-print' package)
+**** Printing (both with `M-x lpr-buffer' and with 'ps-print' package)
 now works.
 
-**** `Ediff' works (in a single-frame mode).
+**** 'Ediff' works (in a single-frame mode).
 
 **** `M-x display-time' can be used on MS-DOS (due to the new
 implementation of Emacs timers, see below).
 
-**** `Dired' supports Unix-style shell wildcards.
+**** 'Dired' supports Unix-style shell wildcards.
 
-**** The `c-macro-expand' command now works as on other platforms.
+**** The 'c-macro-expand' command now works as on other platforms.
 
 **** `M-x recover-session' works.
 
 **** `M-x list-colors-display' displays all the available colors.
 
-**** The `TPU-EDT' package works.
+**** The 'TPU-EDT' package works.
 
 
 * Lisp changes in Emacs 19.31.
@@ -606,17 +606,17 @@ behavior, and invoking it with any other value 
deactivates it.
 
 ** Change in system-type and system-configuration values.
 
-The value of system-type on a Linux-based GNU system is now `lignux',
-not `linux'.  This means that some programs which use `system-type'
-need to be changed.  The value of `system-configuration' will also
+The value of system-type on a Linux-based GNU system is now 'lignux',
+not 'linux'.  This means that some programs which use 'system-type'
+need to be changed.  The value of 'system-configuration' will also
 be different.
 
-It is generally recommended to use `system-configuration' rather
-than `system-type'.
+It is generally recommended to use 'system-configuration' rather
+than 'system-type'.
 
 See <https://www.gnu.org/gnu/linux-and-gnu.html> for more about this.
 
-** The functions shell-command and dired-call-process
+** The functions 'shell-command' and 'dired-call-process'
 now run file name handlers for default-directory, if it has them.
 
 ** Undoing the deletion of text now restores the positions of markers
@@ -626,7 +626,7 @@ that pointed into or next to the deleted text.
 no longer use a separate process.  Therefore, they now work more
 reliably and can be used for shorter time delays.
 
-The new function run-with-timer is a convenient way to set up a timer
+The new function 'run-with-timer' is a convenient way to set up a timer
 to run a specified amount of time after the present.  A call looks
 like this:
 
@@ -687,13 +687,13 @@ asks the question PROMPT (just like y-or-n-p).  If the 
user answers
 within SECONDS seconds, it returns the answer that the user gave.
 Otherwise it gives up after SECONDS seconds, and returns DEFAULT-VALUE.
 
-** Minor change to `encode-time': you can now pass more than seven
+** Minor change to 'encode-time': you can now pass more than seven
 arguments.  If you do that, the first six arguments have the usual
 meaning, the last argument is interpreted as the time zone, and the
 arguments in between are ignored.
 
-This means that it works to use the list returned by `decode-time' as
-the list of arguments for `encode-time'.
+This means that it works to use the list returned by 'decode-time' as
+the list of arguments for 'encode-time'.
 
 ** The default value of load-path now includes the directory
 /usr/local/share/emacs/VERSION/site-lisp In addition to
@@ -717,9 +717,9 @@ convert-standard-filename to convert the file name to a 
proper form
 for each operating system.  Here is an example of use, from the file
 completions.el:
 
-(defvar save-completions-file-name
-        (convert-standard-filename "~/.completions")
-  "*The filename to save completions to.")
+    (defvar save-completions-file-name
+            (convert-standard-filename "~/.completions")
+      "*The filename to save completions to.")
 
 This sets the variable save-completions-file-name to a value that
 depends on the operating system, because the definition of
@@ -734,11 +734,11 @@ minibuffer if there is no prefix argument at all.)
 ** When a process is deleted, this no longer disconnects the process
 marker from its buffer position.
 
-** The variable garbage-collection-messages now controls whether
+** The variable 'garbage-collection-messages' now controls whether
 Emacs displays a message at the beginning and end of garbage collection.
 The default is nil, meaning there are no messages.
 
-** The variable debug-ignored-errors specifies certain kinds of errors
+** The variable 'debug-ignored-errors' specifies certain kinds of errors
 that should not enter the debugger.  Its value is a list of error
 condition symbols and/or regular expressions.  If the error has any
 of the condition symbols listed, or if any of the regular expressions
@@ -748,27 +748,28 @@ regardless of the value of debug-on-error.
 This variable is initialized to match certain common but uninteresting
 errors that happen often during editing.
 
-** The new function error-message-string converts an error datum
+** The new function 'error-message-string' converts an error datum
 into its error message.  The error datum is what condition-case
 puts into the variable, to describe the error that happened.
 
 ** Anything that changes which buffer appears in a given window
 now runs the window-scroll-functions for that window.
 
-** The new function get-buffer-window-list returns a list of windows displaying
-a buffer.  The function is called with the buffer (a buffer object or a buffer
-name) and two optional arguments specifying the minibuffer windows and frames
-to search.  Therefore this function takes optional args like next-window etc.,
-and not get-buffer-window.
+** The new function 'get-buffer-window-list' returns a list of windows
+displaying a buffer.  The function is called with the buffer (a buffer
+object or a buffer name) and two optional arguments specifying the
+minibuffer windows and frames to search.
+Therefore this function takes optional args like 'next-window' etc.,
+and not 'get-buffer-window'.
 
-** buffer-substring now runs the hook buffer-access-fontify-functions,
+** 'buffer-substring' now runs the hook 'buffer-access-fontify-functions',
 calling each function with two arguments--the range of the buffer
-being accessed.  buffer-substring-no-properties does not call them.
+being accessed.  'buffer-substring-no-properties' does not call them.
 
 If you use this feature, you should set the variable
-buffer-access-fontified-property to a non-nil symbol, which is a
+'buffer-access-fontified-property' to a non-nil symbol, which is a
 property name.  Then, if all the characters in the buffer range have a
-non-nil value for that property, the buffer-access-fontify-functions
+non-nil value for that property, the 'buffer-access-fontify-functions'
 are not called.  When called, these functions should put a non-nil
 property on the text that they fontify, so that they won't get called
 over and over for the same text.
@@ -776,7 +777,7 @@ over and over for the same text.
 ** Changes in lisp-mnt.el
 
 *** The lisp-mnt package can now recognize file headers that are written
-in the formats used by the `what' command and the RCS `ident' command:
+in the formats used by the 'what' command and the RCS 'ident' command:
 
 ;; @(#) HEADER: text
 ;; $HEADER: text $
@@ -813,12 +814,13 @@ when narrowing is in effect.
 ** If you type a M-x command that has an equivalent key binding,
 the equivalent is shown in the minibuffer before the command executes.
 This feature is enabled by default for the sake of beginning users.
-You can turn the feature off by setting suggest-key-bindings to nil.
+You can turn the feature off by setting 'suggest-key-bindings' to nil.
 
 ** The menu bar is now visible on text-only terminals.  To choose a
 command from the menu bar when you have no mouse, type M-`
-(Meta-Backquote) or F10.  To turn off menu bar display,
-do (menu-bar-mode -1).
+(Meta-Backquote) or F10.  To turn off menu bar display, do:
+
+    (menu-bar-mode -1).
 
 ** Whenever you invoke a minibuffer, it appears in the minibuffer
 window that the current frame uses.
@@ -848,7 +850,7 @@ Use M-x xterm-mouse-mode to let emacs take control over the 
mouse.
 *** C-mouse-1 now once again provides a menu of buffers to select.
 S-mouse-1 is now the way to select a default font for the frame.
 
-*** There is a new mouse-scroll-min-lines variable to control the
+*** There is a new 'mouse-scroll-min-lines' variable to control the
 minimum number of lines scrolled by dragging the mouse outside a
 window's edge.
 
@@ -869,11 +871,11 @@ you have already seen.
 
 ** Filling changes.
 
-*** If the variable colon-double-space is non-nil, the explicit fill
+*** If the variable 'colon-double-space' is non-nil, the explicit fill
 commands put two spaces after a colon.
 
 *** Auto-Fill mode now supports Adaptive Fill mode just as the
-explicit fill commands do.  The variable adaptive-fill-regexp
+explicit fill commands do.  The variable 'adaptive-fill-regexp'
 specifies a regular expression to match text at the beginning of
 a line that should be the fill prefix.
 
@@ -885,14 +887,14 @@ paragraph because they are indented.  This indentation 
shouldn't
 be copied to additional lines.
 
 Whether indented lines are paragraph lines depends on the value of the
-variable paragraph-start.  Some major modes set this; you can set it
+variable 'paragraph-start'.  Some major modes set this; you can set it
 by hand or in mode hooks as well.  For editing text in which paragraph
 first lines are not indented, and which contains paragraphs in which
 all lines are indented, you should use Indented Text mode or arrange
 for paragraph-start not to match these lines.
 
 *** You can specify more complex ways of choosing a fill prefix
-automatically by setting `adaptive-fill-function'.  This function
+automatically by setting 'adaptive-fill-function'.  This function
 is called with point after the left margin of a line, and it should
 return the appropriate fill prefix based on that line.
 If it returns nil, that means it sees no fill prefix in that line.
@@ -910,7 +912,7 @@ fail, though.
 functions have changed names.
 
 **** The summary mode gnus-uu commands have been moved from the `C-c
-C-v' keymap to the `X' keymap.
+C-v' keymap to the 'X' keymap.
 
 **** There can now be several summary buffers active at once.
 Variables that are relevant to each summary buffer are buffer-local to
@@ -920,7 +922,7 @@ that buffer.
 highlighting based not only on what's visible in the buffer, but on
 other data structures.
 
-**** Old packages like `expire-kill' will no longer work.
+**** Old packages like 'expire-kill' will no longer work.
 
 **** `C-c C-l' in the group buffer no longer switches to a different
 buffer, but instead lists killed groups in the group buffer.
@@ -987,8 +989,8 @@ to the servers.
 *** General changes (all backends).
 
 VC directory listings (C-x v d) are now kept up to date when you do a
-vc-next-action (C-x v v) on the marked files.  The `g' command updates
-the buffer properly.  `=' in a VC dired buffer produces a version
+vc-next-action (C-x v v) on the marked files.  The 'g' command updates
+the buffer properly.  '=' in a VC dired buffer produces a version
 control diff, not an ordinary diff.
 
 *** CVS changes.
@@ -1033,14 +1035,14 @@ locking for a file, use the "rcs -U" command.
 
 If you share RCS subdirs with other users (through symbolic links),
 and you always want to work on the latest version, set
-vc-consult-headers to nil and vc-mistrust-permissions to `t'.
+vc-consult-headers to nil and vc-mistrust-permissions to 't'.
 Then you see the state of the *latest* version on the mode line, not
 that of your working file.  When you do a check out, VC overwrites
 your working file with the latest version from the master.
 
 *** RCS customization.
 
-There is a new variable vc-consult-headers.  If it is t (the default),
+There is a new variable 'vc-consult-headers'.  If it is t (the default),
 VC searches for RCS headers in working files (like `$Id$') and
 determines the state of the file from them, not from the master file.
 This is fast and more reliable when you use branches.  (The variable
@@ -1065,7 +1067,7 @@ Here are the commands for converting to and from these 
calendars:
 
 Calendar mode now has commands to produce fancy printed calendars via
 LaTeX.  You can ask for a calendar for one or more days, weeks, months
-or years.  The commands all start with `t'; see the manual for a list
+or years.  The commands all start with 't'; see the manual for a list
 of them.
 
 *** New sexp diary entry type
@@ -1094,12 +1096,12 @@ you can do
 
 to turn the mode on.
 
-** The new pc-select package emulates the key bindings for cutting and
+** The new 'pc-select' package emulates the key bindings for cutting and
 pasting, and selection of regions, found in Windows, Motif, and the
 Macintosh.
 
-** Help buffers now use a special major mode, Help mode.  This mode
-normally turns on View mode; it also provides a hook, help-mode-hook,
+** Help buffers now use a special major mode, 'help-mode'.  This mode
+normally turns on View mode; it also provides a hook, 'help-mode-hook',
 which you can use for other customization.
 
 ** Apropos now uses faces for enhanced legibility.  It now describes
@@ -1114,7 +1116,7 @@ function definition, variable, or property.
 For example, to automatically turn on Font Lock mode in the *Help*
 buffer, put:
 
- (add-hook 'help-mode-hook 'turn-on-font-lock)
+    (add-hook 'help-mode-hook #'turn-on-font-lock)
 
 in your ~/.emacs.
 
@@ -1129,13 +1131,13 @@ before resuming with the keyword item of which it is 
part.
 
 For example, a typical keyword item might be:
 
- ("\\<anchor\\>" (0 anchor-face))
+    ("\\<anchor\\>" (0 anchor-face))
 
 which fontifies each occurrence of the discrete word "anchor" in the value of
 the variable anchor-face.  However, the highlighting information can be used to
 fontify text that is anchored to the word "anchor".  For example:
 
- ("\\<anchor\\>" (0 anchor-face) ("\\=[ ,]*\\(item\\)" nil nil (1 item-face)))
+   ("\\<anchor\\>" (0 anchor-face) ("\\=[ ,]*\\(item\\)" nil nil (1 
item-face)))
 
 which fontifies each occurrence of "anchor" as above, but for each occurrence
 of "anchor", each occurrence of "item", in any following comma separated list,
@@ -1163,7 +1165,7 @@ These variables can now specify values for individual 
modes, by supplying
 lists of mode names and values.  For example, to use the above mentioned level
 3 decoration for buffers in C/C++ modes, and default decoration otherwise, put:
 
- (setq font-lock-maximum-decoration '((c-mode . 3) (c++-mode . 3)))
+    (setq font-lock-maximum-decoration '((c-mode . 3) (c++-mode . 3)))
 
 in your ~/.emacs.  Maximum buffer size values for individual modes are
 specified in the same way with the variable font-lock-maximum-size.
@@ -1171,15 +1173,16 @@ specified in the same way with the variable 
font-lock-maximum-size.
 *** Font Lock configuration
 
 The mechanism to provide default settings for Font Lock mode are the variables
-font-lock-defaults and font-lock-maximum-decoration.  Typically, you should
+'font-lock-defaults' and 'font-lock-maximum-decoration'.  Typically, you should
 only need to change the value of font-lock-maximum-decoration.  However, to
 support Font Lock mode for buffers in modes that currently do not support Font
 Lock mode, you should set a buffer local value of font-lock-defaults for that
 mode, typically via its mode hook.
 
 These variables are used by Font Lock mode to set the values of the variables
-font-lock-keywords, font-lock-keywords-only, font-lock-syntax-table,
-font-lock-beginning-of-syntax-function and font-lock-keywords-case-fold-search.
+'font-lock-keywords', 'font-lock-keywords-only', 'font-lock-syntax-table',
+'font-lock-beginning-of-syntax-function'
+and 'font-lock-keywords-case-fold-search'.
 
 You need not set these variables directly, and should not set them yourself
 since the underlining mechanism may change in future.
@@ -1188,13 +1191,16 @@ since the underlining mechanism may change in future.
 archive files (files whose names end with .arc, .lzh, .zip, and .zoo).
 
 ** You can automatically update the years in copyright notice by
-means of (add-hook 'write-file-hooks 'copyright-update).
+means of
+
+    (add-hook 'write-file-hooks #'copyright-update).
+
 Optionally it can update the GPL version as well.
 
 ** Scripts of various languages (Shell, AWK, Perl, makefiles ...) can
 be automatically provided with a magic number and be made executable
 by their respective modes under control of various user variables.
-The mode must call (executable-set-magic "perl") or
+The mode must call 'executable-set-magic', such as
 (executable-set-magic "make" "-f").  The latter for example has no
 effect on [Mm]akefile.
 
@@ -1202,15 +1208,15 @@ effect on [Mm]akefile.
 command C-c ! executes the region, and optionally beginning of script
 as well, by passing them to the shell.
 
-Cases such as `sh' being a `bash' are now accounted for.
+Cases such as 'sh' being a 'bash' are now accounted for.
 Fontification now also does variables, the magic number and all
-builtin commands.  Shell script mode no longer mingles `tab-width' and
-indentation style.  The variable `sh-tab-width' has been renamed to
-`sh-indentation'.  Empty lines are now indented like previous
+builtin commands.  Shell script mode no longer mingles 'tab-width' and
+indentation style.  The variable 'sh-tab-width' has been renamed to
+'sh-indentation'.  Empty lines are now indented like previous
 non-empty line, rather than just previous line.
 
 The annoying $ variable prompting has been eliminated.  Instead, shell
-script mode uses `comint-dynamic-completion' for commands, variables
+script mode uses 'comint-dynamic-completion' for commands, variables
 and filenames.
 
 ** Two-column mode now automatically scrolls both buffers together,
@@ -1229,7 +1235,7 @@ element < no longer exists, ' is a new element.
 
 ** The autoinsert insert facility for prefilling empty files as soon
 as they are found has been extended to accommodate skeletons or calling
-functions.  See the function auto-insert.
+functions.  See the function 'auto-insert'.
 
 ** TPU-edt Changes
 
@@ -1290,7 +1296,7 @@ from the command line.
 ** etags has now the ability to tag Perl files.  They are recognized
 either by the .pm and .pl suffixes or by a first line which starts
 with `#!' and specifies a Perl interpreter.  The tagged lines are
-those beginning with the `sub' keyword.
+those beginning with the 'sub' keyword.
 
 New suffixes recognized are .hpp for C++; .f90 for Fortran; .bib,
 .ltx, .TeX for TeX (.bbl, .dtx removed); .ml for Lisp; .prolog for
@@ -1322,25 +1328,25 @@ character table.  It can be any of these values:
   keyboard-translate-table
   case-table
 
-The function `char-table-subtype' returns the subtype of a char-table.
+The function 'char-table-subtype' returns the subtype of a char-table.
 You cannot alter the subtype of an existing char-table.
 
 A char-table has an element for each character code.  It also has some
 "extra slots".  The number of extra slots depends on the subtype and
 their use depends on the subtype.  (Each subtype symbol has a
-`char-table-extra-slots' property that says how many extra slots to
-make.)  Use (char-table-extra-slot TABLE N) to access extra slot N and
-(set-char-table-extra-slot TABLE N VALUE) to store VALUE in slot N.
+'char-table-extra-slots' property that says how many extra slots to
+make.)  Use 'char-table-extra-slot' to access extra slots and
+'set-char-table-extra-slot' to store a value in a slot.
 
 A char-table T can have a parent, which should be another char-table
 P.  If you look for the value in T for character C, and the table T
 actually holds nil, P's element for character C is used instead.
-The functions `char-table-parent' and `set-char-table-parent'
+The functions 'char-table-parent' and 'set-char-table-parent'
 let you read or set the parent of a char-table.
 
 To scan all the values in a char-table, do not try to loop through all
 possible character codes.  That would work for now, but will not work
-in the future.  Instead, call map-char-table.  (map-char-table
+in the future.  Instead, call 'map-char-table'.  (map-char-table
 FUNCTION TABLE) calls FUNCTION once for each character or character
 set that has a distinct value in TABLE.  FUNCTION gets two arguments,
 RANGE and VALUE.  RANGE specifies a range of TABLE that has one
@@ -1349,23 +1355,23 @@ uniform value, and VALUE is the value in TABLE for that 
range.
 Currently, RANGE is always a vector containing a single character
 and it refers to that character alone.  In the future, other kinds
 of ranges will occur.  You can set the value for a given range
-with (set-char-table-range TABLE RANGE VALUE) and examine the value
-for a range with (char-table-range TABLE RANGE).
+with 'set-char-table-range' and examine the value
+for a range with 'char-table-range'.
 
 *** Syntax tables are now represented as char-tables.
 All syntax tables other than the standard syntax table
 normally have the standard syntax table as their parent.
-Their subtype is `syntax-table'.
+Their subtype is 'syntax-table'.
 
 *** Display tables are now represented as char-tables.
-Their subtype is `display-table'.
+Their subtype is 'display-table'.
 
 *** Case tables are now represented as char-tables.
-Their subtype is `case-table'.
+Their subtype is 'case-table'.
 
 *** The value of keyboard-translate-table may now be a char-table
 instead of a string.  Normally the char-tables used for this purpose
-have the subtype `keyboard-translate-table', but that is not required.
+have the subtype 'keyboard-translate-table', but that is not required.
 
 *** A new data type called a bool-vector is a vector of values
 that are either t or nil.  To create one, do
@@ -1375,25 +1381,25 @@ that are either t or nil.  To create one, do
 text is inserted at the place where the marker points.  This is called
 the "insertion type" of the marker.
 
-To set the insertion type, do (set-marker-insertion-type MARKER TYPE).
+To set the insertion type, use 'set-marker-insertion-type'.
 If TYPE is t, it means the marker advances when text is inserted.  If
 TYPE is nil, it means the marker does not advance.  (In Emacs 19.29,
 markers did not advance.)
 
-The function marker-insertion-type reports the insertion type of a
-given marker.  The function copy-marker takes a second argument TYPE
+The function 'marker-insertion-type' reports the insertion type of a
+given marker.  The function 'copy-marker' takes a second argument TYPE
 which specifies the insertion type of the new copied marker.
 
 ** When you create an overlay, you can specify the insertion type of
 the beginning and of the end.  To do this, you can use two new
-arguments to make-overlay: front-advance and rear-advance.
+arguments to 'make-overlay': front-advance and rear-advance.
 
-** The new function overlays-in returns a list of the overlays that
+** The new function 'overlays-in' returns a list of the overlays that
 overlap a specified range of the buffer.  The returned list includes
 empty overlays at the beginning of this range, as well as within the
 range.
 
-** The new hook window-scroll-functions is run when a window has been
+** The new hook 'window-scroll-functions' is run when a window has been
 scrolled.  The functions in this list are called just before
 redisplay, after the new window-start has been computed.  Each function
 is called with two arguments--the window that has been scrolled, and its
@@ -1402,7 +1408,7 @@ new window-start position.
 This hook is useful for on-the-fly fontification and other features
 that affect how the redisplayed text will look when it is displayed.
 
-The window-end value of the window is not valid when these functions
+The 'window-end' value of the window is not valid when these functions
 are called.  The computation of window-end is byproduct of actual
 redisplay of the window contents, which means it has not yet happened
 when the hook is run.  Computing window-end specially in advance for
@@ -1411,21 +1417,21 @@ the sake of these functions would cause a slowdown.
 The hook functions can determine where the text on the window will end
 by calling vertical-motion starting with the window-start position.
 
-** The new hook redisplay-end-trigger-functions is run whenever
+** The new hook 'redisplay-end-trigger-functions' is run whenever
 redisplay in window uses text that extends past a specified end
 trigger position.  You set the end trigger position with the function
-set-window-redisplay-end-trigger.  The functions are called with two
+'set-window-redisplay-end-trigger'.  The functions are called with two
 arguments: the window, and the end trigger position.  Storing nil for
 the end trigger position turns off the feature, and the trigger value
 is automatically reset to nil just after the hook is run.
 
-You can use the function window-redisplay-end-trigger to read a
+You can use the function 'window-redisplay-end-trigger' to read a
 window's current end trigger value.
 
-** The new function insert-file-contents-literally inserts the
+** The new function 'insert-file-contents-literally' inserts the
 contents of a file without any character set translation or decoding.
 
-** The new function safe-length computes the length of a list.
+** The new function 'safe-length' computes the length of a list.
 It never gets an error--it treats any non-list like nil.
 If given a circular list, it returns an upper bound for the number
 of elements before the circularity.
@@ -1436,19 +1442,19 @@ regexp that was matched, not the entire match.  For 
example, after
 matching `foo \(ba*r\)' calling replace-match with 1 as SUBEXP means
 to replace just the text that matched `\(ba*r\)'.
 
-** The new keymap special-event-map defines bindings for certain
+** The new keymap 'special-event-map' defines bindings for certain
 events that should be handled at a very low level--as soon as they
-are read.  The read-event function processes these events itself,
+are read.  The 'read-event' function processes these events itself,
 and never returns them.
 
 Events that are handled in this way do not echo, they are never
 grouped into key sequences, and they never appear in the value of
-last-command-event or (this-command-keys).  They do not discard a
-numeric argument, they cannot be unread with unread-command-events,
+'last-command-event' or (this-command-keys).  They do not discard a
+numeric argument, they cannot be unread with 'unread-command-events',
 they may not appear in a keyboard macro, and they are not recorded
 in a keyboard macro while you are defining one.
 
-These events do, however, appear in last-input-event immediately after
+These events do, however, appear in 'last-input-event' immediately after
 they are read, and this is the way for the event's definition to find
 the actual event.
 
@@ -1460,7 +1466,7 @@ out-of-range values for its SEC, MINUTE, HOUR, DAY, and 
MONTH
 arguments; for example, day 0 means the day preceding the given month.
 Also, the ZONE argument can now be a TZ-style string.
 
-** command-execute and call-interactively now accept an optional third
+** 'command-execute' and 'call-interactively' now accept an optional third
 argument KEYS.  If specified and non-nil, this specifies the key
 sequence containing the events that were used to invoke the command.
 
@@ -1542,7 +1548,7 @@ contain items that were formerly in the Files and Edit 
menus, as well
 as some that did not exist in the menu bar menus before.
 
 ** Emacs can now display on more than one X display at the same time.
-Use the command make-frame-on-display to create a frame, specifying
+Use the command 'make-frame-on-display' to create a frame, specifying
 which display to use.
 
 ** M-x talk-connect sets up a multi-user talk connection
@@ -1559,7 +1565,7 @@ This means the maximum size of a buffer is at least 
2**27-1,
 or 134,217,727.
 
 ** When you start Emacs, you can now specify option names in
-long GNU form (starting with `--') and you can abbreviate the names.
+long GNU form (starting with '--') and you can abbreviate the names.
 
 You can now specify the options in any order.
 The previous requirements about the order of options
@@ -1574,7 +1580,7 @@ active, now leaves the mark active and does not change 
its position.
 You can make incremental search deactivate the mark once again with
 this expression.
 
-    (add-hook 'isearch-mode-hook 'deactivate-mark)
+    (add-hook 'isearch-mode-hook #'deactivate-mark)
 
 ** C-delete now deletes a word backwards.  This is for compatibility
 with some editors in the PC world.  (This key is not available on
@@ -1602,7 +1608,7 @@ If you prefer the old ESC ESC binding, put in your 
`~/.emacs':
        (global-set-key "\e\e" 'eval-expression)
 
 ** The f1 function key is now equivalent to the help key.  This is
-done with key-translation-map; delete the binding for f1 in that map
+done with 'key-translation-map'; delete the binding for f1 in that map
 if you want to use f1 for something else.
 
 ** Mouse-3, in the simplest case, still sets the region.  But now, it
@@ -1638,15 +1644,15 @@ are used.
 *** All fill functions now indent every line to the left-margin.  If
 there is also a fill-prefix, that goes after the margin indentation.
 
-*** Open-line and newline also make sure that the lines they create
+*** 'open-line' and 'newline' also make sure that the lines they create
 are indented to the left margin.
 
 *** It also allows you to set the "justification" of the region:
 whether it should be centered, flush right, and so forth.  The fill
-functions (including auto-fill-mode) will maintain the justification
+functions (including 'auto-fill-mode') will maintain the justification
 and indentation that you request.
 
-*** The new function `list-colors-display' shows you what colors are
+*** The new function 'list-colors-display' shows you what colors are
 available.  This is also accessible from the C-mouse-2 menu.
 
 ** You can now save and load files including their faces and other
@@ -1676,7 +1682,7 @@ middle of an ordinary key sequence.
 character.
 
 ** Echo area messages are now logged in the "*Messages*" buffer.  The
-size of this buffer is limited to message-log-max lines.
+size of this buffer is limited to 'message-log-max' lines.
 
 ** RET in various special modes for read-only buffers that contain
 lists of items now selects the item point is on.  These modes include
@@ -1684,12 +1690,12 @@ Dired, Compilation buffers, Buffer-menu, Tar mode, and 
Occur mode.
 (In Info, RET follows the reference near point; in completion list
 buffers, RET chooses the completion around point.)
 
-** set-background-color now updates the modeline face in a special
+** 'set-background-color' now updates the modeline face in a special
 way.  If that face was previously set up to be reverse video, the
 reverse of the default face, then set-background-color updates it so
 that it remains the reverse of the default face.
 
-** The functions raise-frame and lower-frame are now commands.
+** The functions 'raise-frame' and 'lower-frame' are now commands.
 When used interactively, they apply to the selected frame.
 
 ** M-x buffer-menu now displays the buffer list in the selected window.
@@ -1706,16 +1712,16 @@ default value, if there is one.  Normal execution of 
defvar does not
 alter the variable if it already has a non-void value.
 
 ** In completion list buffers, the left and right arrow keys run the
-new commands previous-completion and next-completion.  They move one
+new commands 'previous-completion' and 'next-completion'.  They move one
 completion at a time.
 
-** While doing completion in the minibuffer, the `prior' or `pageup'
+** While doing completion in the minibuffer, the 'prior' or 'pageup'
 key switches to the completion list window.
 
 ** When you exit the minibuffer with empty contents, the empty string
 is not put in the minibuffer history.
 
-** The default buffer for insert-buffer is now the "first" buffer
+** The default buffer for 'insert-buffer' is now the "first" buffer
 other than the current one.  If you have more than one window, this
 is a buffer visible in another window.  (Usually it is the buffer
 that C-M-v would scroll.)
@@ -1747,8 +1753,8 @@ and scribe-underline-word is on C-c C-u.
 gomoku-human-plays is on C-c C-p, gomoku-human-resigns is on C-c C-r,
 and gomoku-emacs-plays is on C-c C-e.
 
-*** In the Outline mode defined in allout.el,
-outline-rebullet-current-heading is now on C-c *.
+*** In the Outline mode defined in 'allout',
+'outline-rebullet-current-heading' is now on C-c *.
 
 ** M-s in Info now searches through the nodes of the Info file,
 just like s.  The alias M-s was added so that you can use the same
@@ -1760,14 +1766,14 @@ with the sequences ~! and ~?.
 ** M-x compare-windows now pushes mark in both windows before
 it starts moving point.
 
-** There are two new commands in Dired, A (dired-do-search)
-and Q (dired-do-query-replace).  These are similar to tags-search and
+** There are two new commands in Dired, A ('dired-do-search')
+and Q ('dired-do-query-replace').  These are similar to tags-search and
 tags-query-replace, but instead of searching the list of files that
 appears in a tags table, they search all the files marked in Dired.
 
 ** Changes to dabbrev.
 
-A new function, `dabbrev-completion' (bound to M-C-/), expands the
+A new function, 'dabbrev-completion' (bound to M-C-/), expands the
 unique part of an abbreviation.
 
 Dabbrev now looks for expansions in other buffers, looks for symbols
@@ -1788,7 +1794,7 @@ another way.
 *** Bookmarks can have annotations; type "C-h m" after doing
 "M-x list-bookmarks", for more information on annotations.
 
-*** The bookmark-jump popup menu function is now `bookmark-menu-jump', for
+*** The 'bookmark-jump' popup menu function is now 'bookmark-menu-jump', for
 those who bind it to a mouse click.
 
 *** The default bookmarks file name is now "~/.emacs.bmk".  If you
@@ -1816,18 +1822,18 @@ command M-x cpp-highlight-buffer.
 variable symbols.  Also ++ and -- which mean 2* positive and negative
 c-basic-offset respectively.
 
-*** New variable, c-recognize-knr-p, which controls whether K&R C
+*** New variable, 'c-recognize-knr-p', which controls whether K&R C
 constructs will be recognized.  Trying to recognize K&R constructs is a
 time hog so if you're programming strictly in ANSI C, set this
 variable to nil (it should already be nil in c++-mode).
 
-*** New variable, c-hanging-comment-ender-p for controlling
+*** New variable, 'c-hanging-comment-ender-p' for controlling
 c-fill-paragraph's behavior.
 
 *** New syntactic symbol: statement-case-open.  This is assigned to lines
 containing an open brace just after a case/default label.
 
-*** New variable, c-progress-interval, which controls minibuffer update
+*** New variable, 'c-progress-interval', which controls minibuffer update
 message displays during long re-indentation.  This is a new feature
 which prints percentage complete messages at specified intervals.
 
@@ -1844,7 +1850,7 @@ which prints percentage complete messages at specified 
intervals.
 ** icomplete.el now works more like a minor mode.  Use M-x icomplete-mode
 to turn it on and off.
 
-Icomplete now supports an `icomplete-minibuffer-setup-hook', which is
+Icomplete now supports an 'icomplete-minibuffer-setup-hook', which is
 run on minibuffer setup whenever icompletion will be occurring.  This
 hook can be used to customize interoperation of icomplete with other
 minibuffer-specific packages, eg rsz-mini.  See the doc string for
@@ -1852,10 +1858,10 @@ more info.
 
 ** Ediff change.
 
-Use ediff-revision instead of vc-ediff.  It also replaces rcs-ediff,
+Use 'ediff-revision' instead of 'vc-ediff'.  It also replaces rcs-ediff,
 for those who use that; if you want to use a version control package
 other than vc.el, you must set the variable
-ediff-version-control-package to specify which package.
+'ediff-version-control-package' to specify which package.
 
 ** VC now supports branches with RCS.
 
@@ -1878,7 +1884,7 @@ branch, then the new version automatically creates a new 
branch.
 ** VC now supports CVS as well as RCS and SCCS.
 
 Since there are no locks in CVS, some things behave slightly
-different when the backend is CVS.  When vc-next-action is invoked
+different when the backend is CVS.  When 'vc-next-action' is invoked
 in a directory handled by CVS, it does the following:
 
    If the file is not already registered, this registers it for version
@@ -1895,7 +1901,7 @@ file remains in existence.
    If vc-next-action changes the repository file, it asks you
 whether to merge in the changes into your working copy.
 
-vc-directory, when started in a CVS file hierarchy, reports
+'vc-directory', when started in a CVS file hierarchy, reports
 all files that are modified (and thus need to be committed).
 (When the backend is RCS or SCCS vc-directory reports all
 locked files).
@@ -1908,7 +1914,7 @@ You can disable the CVS support as follows:
 
   (setq vc-master-templates (delq 'vc-find-cvs-master vc-master-templates))
 
-or by setting vc-handle-cvs to nil.
+or by setting 'vc-handle-cvs' to nil.
 
 This may be desirable if you run a non-standard version of CVS, or
 if CVS was compiled with FORCE_USE_EDITOR or (possibly)
@@ -1929,8 +1935,8 @@ of lines, specified by the variable 
comint-buffer-maximum-size.  Just
 like the command comint-strip-ctrl-m, this can be run automatically
 during process output by doing this:
 
-(add-hook 'comint-output-filter-functions
-         'comint-truncate-buffer)
+    (add-hook 'comint-output-filter-functions
+              #'comint-truncate-buffer)
 
 ** Telnet mode buffer name changed.
 
@@ -1941,32 +1947,32 @@ The buffer name for a Telnet buffer is now 
*telnet-HOST*, not
 entire man page is indented, the indentation is removed.
 
 The user option names that used to end in -p now end in -flag.  The
-new names are: Man-reuse-okay-flag, Man-downcase-section-letters-flag,
-Man-circular-pages-flag.  The Man-notify user option has been renamed to
-Man-notify-method and accepts one more value, `pushy', that just
+new names are: 'Man-reuse-okay-flag', 'Man-downcase-section-letters-flag',
+'Man-circular-pages-flag'.  The 'Man-notify' user option has been renamed to
+'Man-notify-method' and accepts one more value, 'pushy', that just
 switches the current buffer to the manpage buffer, without switching
 frames nor changing your windows configuration.
 
-A new user option Man-fontify-manpage-flag disables fontification
+A new user option 'Man-fontify-manpage-flag' disables fontification
 (thus speeding up man) when set to nil.  Default is to fontify if a
-window system is used.  Two new user options Man-overstrike-face
-(default 'bold) and Man-underline-face (default 'underline) can be set
+window system is used.  Two new user options 'Man-overstrike-face'
+(default 'bold) and 'Man-underline-face' (default 'underline) can be set
 to the preferred faces to be used for the words that man overstrikes
 and underlines.  Useful for those who like colored man pages.
 
-Two new interactive functions are provided: Man-cleanup-manpage and
-Man-fontify-manpage.  Both can be used on a buffer that contains the
+Two new interactive functions are provided: 'Man-cleanup-manpage' and
+'Man-fontify-manpage'.  Both can be used on a buffer that contains the
 output of a `rsh host man manpage' command, or the output of an
 `nroff -man -Tman manpage' command to make them readable.
 Man-cleanup-manpage is faster, but does not fontify.
 
-** The new function modify-face makes it easy to specify
+** The new function 'modify-face' makes it easy to specify
 all the attributes of a face, all at once.
 
 ** Faces now support background stippling.
 
-Use the command set-face-stipple to specify the stipple-pattern for a
-face.  Use face-stipple to access the specified stipple pattern.  The
+Use the command 'set-face-stipple' to specify the stipple-pattern for a
+face.  Use 'face-stipple' to access the specified stipple pattern.  The
 existing face functions now handle the stipple pattern when
 appropriate.
 
@@ -1978,14 +1984,14 @@ stipple instead to get the same effect.
 
 *** Fontification
 
-Two new default faces are provided; `font-lock-variable-name-face' and
-`font-lock-reference-face'.  The face `font-lock-doc-string-face' has
+Two new default faces are provided; 'font-lock-variable-name-face' and
+'font-lock-reference-face'.  The face 'font-lock-doc-string-face' has
 been removed since it is the same as the existing
-`font-lock-string-face'.  Where appropriate, fontification
+'font-lock-string-face'.  Where appropriate, fontification
 automatically uses these new faces.
 
-Fontification via commands `font-lock-mode' and
-`font-lock-fontify-buffer' is now cleanly interruptible (i.e., with
+Fontification via commands 'font-lock-mode' and
+'font-lock-fontify-buffer' is now cleanly interruptible (i.e., with
 C-g).  If you interrupt during the fontification process, the buffer
 remains in its previous modified state and all highlighting is removed
 from the buffer.
@@ -1994,14 +2000,14 @@ For C/C++ modes, Font Lock mode is much faster but 
highlights much
 more.  Other modes are faster/more extensive/more discriminatory, or a
 combination of these.
 
-To enable Font Lock mode, add the new function `turn-on-font-lock' in
+To enable Font Lock mode, add the new function 'turn-on-font-lock' in
 one of the following ways:
 
- (add-hook 'c-mode-hook 'turn-on-font-lock)
+    (add-hook 'c-mode-hook #'turn-on-font-lock)
 
 Or for any visited file with:
 
- (add-hook 'find-file-hooks 'turn-on-font-lock)
+    (add-hook 'find-file-hooks #'turn-on-font-lock)
 
 *** Supports color and grayscale displays
 
@@ -2010,26 +2016,26 @@ the type of display and background shade.  Attributes 
(face color,
 bold, italic and underline, and display type and background mode) can
 be controlled either from Emacs Lisp or X resources.
 
-See the new variables `font-lock-display-type' and
-`font-lock-face-attributes'.
+See the new variables 'font-lock-display-type' and
+'font-lock-face-attributes'.
 
 *** Supports more modes
 
 The following modes are directly supported:
 
-ada-mode, asm-mode, bibtex-mode, c++-c-mode, c++-mode, c-mode,
-change-log-mode, compilation-mode, dired-mode, emacs-lisp-mode,
-fortran-mode, latex-mode, lisp-mode, mail-mode, makefile-mode,
-outline-mode, pascal-mode, perl-mode, plain-tex-mode, rmail-mode,
-rmail-summary-mode, scheme-mode, shell-mode, slitex-mode, tex-mode,
-texinfo-mode.
+'ada-mode', 'asm-mode', 'bibtex-mode', 'c++-c-mode', 'c++-mode', 'c-mode',
+'change-log-mode', 'compilation-mode', 'dired-mode', 'emacs-lisp-mode',
+'fortran-mode', 'latex-mode', 'lisp-mode', 'mail-mode', 'makefile-mode',
+'outline-mode', 'pascal-mode', 'perl-mode', 'plain-tex-mode', 'rmail-mode',
+'rmail-summary-mode', 'scheme-mode', 'shell-mode', 'slitex-mode', 'tex-mode',
+'texinfo-mode'.
 
-See the new variables `font-lock-defaults-alist' and
-`font-lock-defaults'.
+See the new variables 'font-lock-defaults-alist' and
+'font-lock-defaults'.
 
 Some modes support different levels of fontification.  You can choose
 to use the minimum or maximum available decoration by changing the
-value of the new variable `font-lock-maximum-decoration'.
+value of the new variable 'font-lock-maximum-decoration'.
 
 Programmers are urged to make available to the community their own
 keywords for modes not yet supported.  See font-lock.el for
@@ -2047,18 +2053,18 @@ highlighting.
 
 To use this package, put in your `~/.emacs':
 
- (add-hook 'font-lock-mode-hook 'turn-on-fast-lock)
+    (add-hook 'font-lock-mode-hook #'turn-on-fast-lock)
 
-To control the use of caches, see the documentation for `fast-lock-mode'.
+To control the use of caches, see the documentation for 'fast-lock-mode'.
 
-** You can tell pop-to-buffer to display certain buffers in the selected
+** You can tell 'pop-to-buffer' to display certain buffers in the selected
 window rather than finding some other window to display them in.
 There are two variables you can use to specify these buffers.
 
-same-window-buffer-names holds a list of buffer names; if a buffer's
+'same-window-buffer-names' holds a list of buffer names; if a buffer's
 name appears in this list, pop-to-buffer puts it in the selected window.
 
-same-window-regexps holds a list of regexps--if any one of them
+'same-window-regexps' holds a list of regexps--if any one of them
 matches a buffer's name, then pop-to-buffer puts that buffer in the
 selected window.
 
@@ -2068,7 +2074,7 @@ window.  These include shell buffers, mail buffers, 
telnet buffers,
 and others.  By removing elements from these variables, you can ask
 Emacs to display those buffers in separate windows.
 
-** The special-display-buffer-names and special-display-regexps lists
+** The 'special-display-buffer-names' and 'special-display-regexps' lists
 have been generalized.  An element may now be a list.  The car of the list
 is the buffer name or regular expression for matching buffer names.
 
@@ -2084,17 +2090,17 @@ FUNCTION; its first argument is the buffer, and its 
remaining
 arguments are ARGS.
 
 ** If the environment variable REPLYTO is set, its value is the default
-for mail-default-reply-to.
+for 'mail-default-reply-to'.
 
 ** When you send a message in Emacs, if you specify an Rmail file with
 the Fcc: header field, Emacs converts the message to Rmail format
 before writing it.  Thus, the file never contains anything but Rmail
 format messages.
 
-** The new variable mail-from-style controls whether the From: header
+** The new variable 'mail-from-style' controls whether the From: header
 should include the sender's full name, and if so, which format to use.
 
-** The new variable mail-personal-alias-file specifies the name of the
+** The new variable 'mail-personal-alias-file' specifies the name of the
 user's personal aliases.  This defaults to the file ~/.mailrc.
 mailabbrev.el used to have its own variable for this purpose
 (mail-abbrev-mailrc-file).  That variable is no longer used.
@@ -2111,33 +2117,33 @@ crossreference entries are object to completion.
 *** Braces are supported as field delimiters in addition to quotes.
 BibTeX entries may have brace-delimited and quote-delimited fields
 intermixed.  The delimiters generated for new entries are specified by
-the variables bibtex-field-left-delimiter and
-bibtex-field-right-delimiter on a buffer-local basis. Those variables
+the variables 'bibtex-field-left-delimiter' and
+'bibtex-field-right-delimiter' on a buffer-local basis. Those variables
 default to braces, since it is easier to put quote accented characters
 (as the german umlauts) into a brace-delimited entry.
 
-*** The function bibtex-clean-entry can now be invoked with a prefix
+*** The function 'bibtex-clean-entry' can now be invoked with a prefix
 argument.  In this case, a label is automatically generated from
 various fields in the record.  If bibtex-clean-entry is invoked on a
 record without label, a label is also generated automatically.
-Various variables (all beginning with `bibtex-autokey-') control the
-creation of that key.  The variable bibtex-autokey-edit-before-use
+Various variables (all beginning with 'bibtex-autokey-') control the
+creation of that key.  The variable 'bibtex-autokey-edit-before-use'
 determines, if the user is allowed to edit auto-generated reference
 keys before they are used.
 
-*** A New function bibtex-complete-string completes strings with
+*** A New function 'bibtex-complete-string' completes strings with
 respect to the strings defined in this buffer and a set of predefined
 strings (initialized to the string macros defined in the standard
 BibTeX style files) in the same way in which ispell-complete-word
 works with respect to words in a dictionary.  Candidates for
 bibtex-complete-string are initialized from variable
-bibtex-predefined-strings and by parsing the files found in
-bibtex-string-files for @String definitions.
+'bibtex-predefined-strings' and by parsing the files found in
+'bibtex-string-files' for @String definitions.
 
 *** Every reference/field pair has now attached a comment which
 appears in the echo area when this field is edited.  These comments
 should provide useful hints for BibTeX usage, especially for BibTeX
-beginners.  New variable bibtex-help-message determines if these help
+beginners.  New variable 'bibtex-help-message' determines if these help
 messages are to appear in the minibuffer when moving to a text entry.
 
 *** Inscriptions of menu bar changed from "Entry Types" to
@@ -2164,7 +2170,7 @@ didn't.
 *** Default value for variables bibtex-maintain-sorted-entries and
 bibtex-sort-ignore-string-entries is now t.
 
-*** All interactive functions are renamed to begin with `bibtex-'.
+*** All interactive functions are renamed to begin with 'bibtex-'.
 
 *** Keybindings with \C-c\C-e entry changed for unification.  Often
 used reference types are now on control-modified keys, mediocre used
@@ -2184,8 +2190,8 @@ use --with-x if you need to request X support explicitly.
 automatically enable X support if X is installed on your machine.)
 
 ** If you use the site-init.el file to set the variable
-mail-host-address to a string in the dumped Emacs, that string becomes
-the default host address for initializing user-mail-address.
+'mail-host-address' to a string in the dumped Emacs, that string becomes
+the default host address for initializing 'user-mail-address'.
 It is used instead of the value of (system-name).
 
 
@@ -2202,11 +2208,11 @@ macros.  Thus, you can now write `(x ,y z) instead of 
(` (x (, y) z)).
 
 The old syntax is still accepted.
 
-*** The new function rassoc is like assoc, except that it compares the
+*** The new function 'rassoc' is like 'assoc', except that it compares the
 key against the cdr of each alist element, where assoc would compare
 it against the car of each alist element.
 
-*** The new function unintern deletes a symbol from an obarray.  The
+*** The new function 'unintern' deletes a symbol from an obarray.  The
 first argument can be the symbol to delete, or a string giving its
 name.  The second argument specifies the obarray (nil means the
 current default obarray).
@@ -2215,18 +2221,18 @@ If the specified symbol is not in the obarray, or if 
there's no symbol
 in the obarray matching the specified string, unintern does nothing
 and returns nil.  If it does delete a symbol, it returns t.
 
-*** You can specify an alternative read function for use by load and
-eval-region by binding the variable load-read-function to some other
+*** You can specify an alternative read function for use by 'load' and
+'eval-region' by binding the variable 'load-read-function' to some other
 function.  This function should accept one argument just like read.
 If load-read-function is nil, load and eval-region use ordinary read.
 
-*** The new function `type-of' takes any object as argument, and
-returns a symbol identifying the type of that object--one of `symbol',
-`integer', `float', `string', `cons', `vector', `marker', `overlay',
-`window', `buffer', `subr', `compiled-function',
-`window-configuration', `process'.
+*** The new function 'type-of' takes any object as argument, and
+returns a symbol identifying the type of that object--one of 'symbol',
+'integer', 'float', 'string', 'cons', 'vector', 'marker', 'overlay',
+'window', 'buffer', 'subr', 'compiled-function',
+'window-configuration', 'process'.
 
-*** When you use eval-after-load for a file that is already loaded, it
+*** When you use 'eval-after-load' for a file that is already loaded, it
 executes the FORM right away.  As before, if the file is not yet
 loaded, it arranges to execute FORM if and when the file is loaded
 later.  The result is: if you have called eval-after-load for a file,
@@ -2239,24 +2245,24 @@ treating them as a comment.
 You would not want to use this in a file you edit by hand, but it is
 useful for commenting out parts of machine-generated files.
 
-*** Two new functions, `plist-get' and `plist-put',
+*** Two new functions, 'plist-get' and 'plist-put',
 allow you to modify and retrieve values from lists formatted as property-lists.
-They work like `get' and `put', but operate on any list.
-`plist-put' returns the modified property-list; you must store it
+They work like 'get' and 'put', but operate on any list.
+'plist-put' returns the modified property-list; you must store it
 back where you got it.
 
-*** The new function add-to-list is called with two elements,
+*** The new function 'add-to-list' is called with two elements,
 a variable that holds a list and a new element.
 It adds the element to the list unless it is already present.
-It compares elements using `equal'.  Here is an example:
+It compares elements using 'equal'.  Here is an example:
 
-(setq foo '(a b)) => (a b)
+    (setq foo '(a b)) => (a b)
 
-(add-to-list 'foo 'c) => (c a b)
+    (add-to-list 'foo 'c) => (c a b)
 
-(add-to-list 'foo 'b) => (c a b)
+    (add-to-list 'foo 'b) => (c a b)
 
-foo => (c a b)
+    foo => (c a b)
 
 ** Changes in compilation.
 
@@ -2281,7 +2287,7 @@ loading the compiled file does not actually bring the 
function
 definitions into core.  Instead it creates references to the compiled
 file, and brings each function's definition into core the first time
 you call that function, or when you force it with the new function
-`fetch-bytecode'.
+'fetch-bytecode'.
 
 Using the lazy loading feature has a few consequences:
 
@@ -2294,7 +2300,7 @@ Using the lazy loading feature has a few consequences:
    will get nonsense results.
 
 To enable the lazy loading feature, set up a non-nil file local
-variable binding for the variable `byte-compile-dynamic' in the Lisp
+variable binding for the variable 'byte-compile-dynamic' in the Lisp
 source file.  For example, put this on the first line:
 
     -*-byte-compile-dynamic: t;-*-
@@ -2304,26 +2310,26 @@ contains many functions, most of which are not actually 
used by a
 given user in a given session.
 
 To turn off the basic feature of referring to the file for doc
-strings, set byte-compile-dynamic-docstrings to nil.  You can do this
+strings, set 'byte-compile-dynamic-docstrings' to nil.  You can do this
 globally, or for one source file by adding this to the first line:
 
     -*-byte-compile-dynamic-docstrings: nil;-*-
 
 ** Strings
 
-*** Do not pass integer arguments to `concat' (or `vconcat' or
-`append').  We are phasing out the old unrecommended support for
+*** Do not pass integer arguments to 'concat' (or 'vconcat' or
+'append').  We are phasing out the old unrecommended support for
 integers as arguments to these functions, in preparation for treating
 numbers as single characters in a future release.  To concatenate
-numbers in string form, use `number-to-string' first, or rewrite the
-call to use `format' instead of `concat'.
+numbers in string form, use 'number-to-string' first, or rewrite the
+call to use 'format' instead of 'concat'.
 
-*** The new function match-string returns the string of text matched at
+*** The new function 'match-string' returns the string of text matched at
 the given parenthesized expression by the last regexp search, or nil
-if there was no match.  If the last match was by `string-match' on a
+if there was no match.  If the last match was by 'string-match' on a
 string, the string must be given.  Therefore, this function can be
-used in place of `buffer-substring' and `substring', when using
-`match-beginning' and `match-end' to find match positions.
+used in place of 'buffer-substring' and 'substring', when using
+'match-beginning' and 'match-end' to find match positions.
 
    (match-string N)   or   (match-string N STRING)
 
@@ -2333,11 +2339,11 @@ the portion of STRING that was matched.  When used in 
this way,
 replace-match returns a newly created string which is the same as
 STRING except for the matched portion.
 
-*** The new function buffer-substring-no-properties
-is like buffer-substring except that the string it returns
+*** The new function 'buffer-substring-no-properties'
+is like 'buffer-substring' except that the string it returns
 has no text properties.
 
-*** The function `equal' now considers two strings to be different
+*** The function 'equal' now considers two strings to be different
 if they don't have the same text properties.
 
 ** Completion
@@ -2352,7 +2358,7 @@ are ignored unless the initial string also starts with a 
space.
 *** Local hook variables.
 
 There is now a clean way to give a hook variable a buffer-local value.
-Call the function `make-local-hook' to do this.
+Call the function 'make-local-hook' to do this.
 
 Once a hook variable is buffer-local, you can add hooks to it either
 globally or locally.  run-hooks runs the local hook functions
@@ -2365,12 +2371,12 @@ function or a global one.
 Local hooks use t as an element of the (local) value of the hook
 variable as a flag meaning to use the global value also.
 
-*** The new function local-variable-p tells you whether a particular
+*** The new function 'local-variable-p' tells you whether a particular
 variable is buffer-local in the current buffer or a specified buffer.
 
 ** Editing Facilities
 
-*** The function copy-region-as-kill no longer sets this-command;
+*** The function 'copy-region-as-kill' no longer sets this-command;
 as a result, a following kill command will not normally append
 to the text saved by copy-region-as-kill.
 
@@ -2380,18 +2386,18 @@ instead of looking for the longest match--just as they 
did in Emacs 18.
 The reason for this change is to get higher speed.
 
 There are new functions you can use if you really want to search or
-match with Posix behavior: posix-search-forward,
-posix-search-backward, posix-looking-at, and posix-string-match.  Call
-these just like re-search-forward, re-search-backward, looking-at, and
-string-match.
+match with Posix behavior: 'posix-search-forward',
+'posix-search-backward', 'posix-looking-at', and 'posix-string-match'.
+Call these just like 're-search-forward', 're-search-backward',
+'looking-at', and 'string-match'.
 
 ** Files
 
-*** The new variable `format-alist' defines file formats,
+*** The new variable 'format-alist' defines file formats,
 which are ways of translating between the data in a file and things
 (text, text-properties, and possibly other information) in a buffer.
 
-`format-alist' has one element for each format.  Each element is a
+'format-alist' has one element for each format.  Each element is a
 list like this:
   (NAME DOC-STRING REGEXP FROM-FN TO-FN MODIFY MODE-FN)
 containing the name of the format, a documentation string, a regular
@@ -2405,41 +2411,41 @@ FROM-FN is called to decode files in that format; it 
gets two args, BEGIN
        longer matches REGEXP, or else it will get called again.
 TO-FN   is called to encode a region into that format; it is also passed BEGIN
         and END, and either returns a list of annotations as in
-        `write-region-annotate-functions', or modifies the region and returns
+        'write-region-annotate-functions', or modifies the region and returns
         the new end position.
 MODIFY, if non-nil, means the TO-FN modifies the region.  If nil, TO-FN may
         not make any changes and should return a list of annotations.
 
-`insert-file-contents' checks the beginning of the file that it is
+'insert-file-contents' checks the beginning of the file that it is
 inserting to see if it matches one of the regexps.  If so, then it
 calls the decoding function, and then looks for another match.  When
 visiting a file, it also calls the mode function, and sets the
-variable `buffer-file-format' to the list of formats that the file
+variable 'buffer-file-format' to the list of formats that the file
 used.
 
-`write-region' calls the encoding functions for each format in
-`buffer-file-format' before it writes the file.  To save a file in a
-different format, either set `buffer-file-format' to a different
-value, or call the new function `format-write-file'.
+'write-region' calls the encoding functions for each format in
+'buffer-file-format' before it writes the file.  To save a file in a
+different format, either set 'buffer-file-format' to a different
+value, or call the new function 'format-write-file'.
 
 Since some encoding functions may be slow, you can request that
 auto-save use a format different from the buffer's default by setting
-the variable `auto-save-file-format' to the desired format.  This will
+the variable 'auto-save-file-format' to the desired format.  This will
 determine the format of all auto-save files.
 
-*** The new function file-ownership-preserved-p tells you whether
+*** The new function 'file-ownership-preserved-p' tells you whether
 deleting a file and recreating it would keep the file's owner
 unchanged.
 
-*** The new function file-regular-p returns t if a file
+*** The new function 'file-regular-p' returns t if a file
 is a "regular" file (not a directory, symlink, named pipe,
 terminal, or other I/O device).
 
-*** The new function file-name-sans-extension discards the extension
+*** The new function 'file-name-sans-extension' discards the extension
 of a file name.  You call it with a file name, and returns a string
 lacking the extension.
 
-*** The variable path-separator is a string which says which
+*** The variable 'path-separator' is a string which says which
 character separates directories in a search path.  It is ":"
 for Unix and GNU systems, ";" for MSDOG and Windows NT.
 
@@ -2462,20 +2468,20 @@ like (ctrl meta newline) or (meta ?d), as in XEmacs.  
(ctrl meta newline)
 is equivalent to the event type symbol C-M-newline, and (meta ?d)
 is equivalent to the character ?\M-d.
 
-*** The function event-convert-list converts a list such as
+*** The function 'event-convert-list' converts a list such as
 (meta ?d) into the corresponding event type (a symbol or integer).
 
-*** In an interactive spec, `k' means to read a key sequence.  In this
+*** In an interactive spec, 'k' means to read a key sequence.  In this
 key sequence, upper case characters and shifted function keys which
 have no bindings are converted to lower case if that makes them
 defined.
 
-The new interactive code `K' reads a key sequence similarly, but does
-not convert the last event.  `K' is useful for reading a key sequence
+The new interactive code 'K' reads a key sequence similarly, but does
+not convert the last event.  'K' is useful for reading a key sequence
 to be given a binding.
 
-*** The variable overriding-local-map now has no effect on the menu bar
-display unless overriding-local-map-menu-flag is non-nil.  This is why
+*** The variable 'overriding-local-map' now has no effect on the menu bar
+display unless 'overriding-local-map-menu-flag' is non-nil.  This is why
 incremental search no longer temporarily changes the menu bars.
 
 Note that overriding-local-map does still affect the execution of key
@@ -2486,10 +2492,10 @@ looked up and executed.  But this is what you'd 
normally do anyway:
 programs that use overriding-local-map normally exit and "put back"
 any event such as menu-bar that they do not handle specially.
 
-*** The new variable `overriding-terminal-local-map' is like
-overriding-local-map, but is specific to a single terminal.
+*** The new variable 'overriding-terminal-local-map' is like
+'overriding-local-map', but is specific to a single terminal.
 
-*** delete-frame events.
+*** 'delete-frame' events.
 
 When you use the X window manager's "delete window" command, this now
 generates a delete-frame event.  The standard definition of this event
@@ -2497,7 +2503,7 @@ is a command that deletes the frame that received the 
event, and kills
 Emacs when the last visible or iconified frame is deleted.  You can
 rebind the event to some other command if you wish.
 
-*** Two new types of events, iconify-frame and make-frame-visible,
+*** Two new types of events, 'iconify-frame' and 'make-frame-visible',
 indicate that the user iconified or deiconified a frame with the
 window manager.  Since the window manager has already done the work,
 the default definition for both event types in Emacs is to do nothing.
@@ -2508,49 +2514,49 @@ the default definition for both event types in Emacs is 
to do nothing.
 words, all the screens of a single X server).  The value in effect, at
 any given time, is the one that belongs to the terminal of the
 selected frame.  The terminal-local variables are
-default-minibuffer-frame, system-key-alist, defining-kbd-macro, and
-last-kbd-macro.  There is no way for Lisp programs to create others.
+'default-minibuffer-frame', 'system-key-alist', 'defining-kbd-macro', and
+'last-kbd-macro'.  There is no way for Lisp programs to create others.
 
 The terminal-local variables cannot be buffer-local.
 
-*** When you create an X frame, for the `top' and `left' frame
+*** When you create an X frame, for the 'top' and 'left' frame
 parameters, you can now use values of the form (+ N) or (- N), where N
 is an integer.  (+ N) means N pixels to the right of the left edge of
 the screen and (- N) means N pixels to the left of the right edge.  In
 both cases, N may be zero (exactly at the edge) or negative (putting
 the window partly off the screen).
 
-The function x-parse-geometry can return values of these forms
+The function 'x-parse-geometry' can return values of these forms
 for certain inputs.
 
-*** The variable menu-bar-file-menu has been renamed to
-menu-bar-files-menu to match the actual item that appears in the menu.
+*** The variable 'menu-bar-file-menu' has been renamed to
+'menu-bar-files-menu' to match the actual item that appears in the menu.
 (All the other such variable names do match.)
 
-*** The new function active-minibuffer-window returns the minibuffer window
+*** The new function 'active-minibuffer-window' returns the minibuffer window
 currently active, or nil if none is now active.
 
-*** In the functions next-window, previous-window, next-frame,
-previous-frame, get-buffer-window, get-lru-window, get-largest-window
-and delete-windows-on, if you specify 0 for the last argument,
+*** In the functions 'next-window', 'previous-window', 'next-frame',
+'previous-frame', 'get-buffer-window', 'get-lru-window', 'get-largest-window'
+and 'delete-windows-on', if you specify 0 for the last argument,
 it means to consider all visible and iconified frames.
 
-*** When you set a frame's cursor type with modify-frame-parameters,
+*** When you set a frame's cursor type with 'modify-frame-parameters',
 you can now specify (bar . INTEGER) as the cursor type.  This stands
 for a bar cursor of width INTEGER.
 
-*** The new function facep returns t if its argument is a face name
+*** The new function 'facep' returns t if its argument is a face name
 (or if it is a vector such as is used internally by the Lisp code
 to represent a face).
 
 *** Each frame can now have a buffer-predicate function,
-which is the `buffer-predicate' frame parameter.
-When `other-buffer' looks for an alternative buffer, it considers
+which is the 'buffer-predicate' frame parameter.
+When 'other-buffer' looks for an alternative buffer, it considers
 only the buffers that fit the selected frame's buffer predicate (if it
 has one).  This is useful for applications that make their own frames.
 
 *** When you create an X frame, you can now specify the frame parameter
-`display'.  This says which display to put the frame on.  The value
+'display'.  This says which display to put the frame on.  The value
 should be a display name--a string of the form
 "HOST:DPYNUMBER.SCREENNUMBER".
 
@@ -2560,11 +2566,11 @@ a display name string or a frame.  A value of nil 
stands for the
 selected frame.
 
 To close the connection to an X display, use the function
-x-close-connection.  Specify which display with a display name.  You
+'x-close-connection'.  Specify which display with a display name.  You
 cannot close the connection if Emacs still has frames open on that
 display.
 
-x-display-list returns a list indicating which displays Emacs has
+'x-display-list' returns a list indicating which displays Emacs has
 connections to.  Its elements are display names (strings).
 
 *** The icon-type frame parameter may now be a file name.
@@ -2572,27 +2578,28 @@ Then the contents of that file specify the icon bitmap 
to use
 for that frame.
 
 *** The title of an Emacs frame, displayed by most window managers, is
-set from frame-title-format or icon-title-format.  These have the same
-structure as mode-line-format.
+set from 'frame-title-format' or 'icon-title-format'.  These have the same
+structure as 'mode-line-format'.
 
-*** x-display-grayscale-p is a new function that returns non-nil if
+*** 'x-display-grayscale-p' is a new function that returns non-nil if
 your X server can display shades of gray.  Currently it returns
 non-nil for color displays (because they can display shades of gray);
 we may change it in the next version to return nil for color displays.
 
-*** The frame parameter scroll-bar-width specifies the width of the
+*** The frame parameter 'scroll-bar-width' specifies the width of the
 scrollbar in pixels.
 
 ** Buffers
 
-*** Creating a buffer with get-buffer-create does not obey
-default-major-mode.  That variable is now handled in a separate
-function, set-buffer-major-mode.  get-buffer-create and generate-new-buffer
-always leave the newly created buffer in Fundamental mode.
+*** Creating a buffer with 'get-buffer-create' does not obey
+'default-major-mode'.  That variable is now handled in a separate
+function, 'set-buffer-major-mode'.  'get-buffer-create' and
+'generate-new-buffer' always leave the newly created buffer
+in Fundamental mode.
 
-Creating a new buffer by visiting a file or with switch-to-buffer,
-pop-to-buffer, and similar functions does call set-buffer-major-mode
-to select the default major mode specified with default-major-mode.
+Creating a new buffer by visiting a file or with 'switch-to-buffer',
+'pop-to-buffer', and similar functions does call 'set-buffer-major-mode'
+to select the default major mode specified with 'default-major-mode'.
 
 *** You can now create an "indirect buffer".  An indirect buffer shares
 its text, including text properties, with another buffer (the "base
@@ -2602,24 +2609,24 @@ those of the base buffer and all other buffers.  An 
indirect buffer
 cannot itself be visiting a file (though its base buffer can be).
 The base buffer cannot itself be indirect.
 
-Use (make-indirect-buffer BASE-BUFFER NAME) to make an indirect buffer
-named NAME whose base is BASE-BUFFER.  If BASE-BUFFER is an indirect
-buffer, its base buffer is used as the base for the new buffer.
+Use 'make-indirect-buffer' to make an indirect buffer.
+If the base buffer is an indirect buffer, its base buffer is used as
+the base for the new buffer.
 
 You can make an indirect buffer current, or switch to it in a window,
 just as you would a non-indirect buffer.
 
-The function buffer-base-buffer, given an indirect buffer, returns its
+The function 'buffer-base-buffer', given an indirect buffer, returns its
 base buffer.  It returns nil when given an ordinary buffer (not
 indirect).
 
-The library `noutline' has versions of Outline mode and Outline minor
+The library 'noutline' has versions of Outline mode and Outline minor
 mode which let you display different parts of the outline in different
 indirect buffers.
 
 ** Subprocesses
 
-*** The functions call-process and call-process-region now allow
+*** The functions 'call-process' and 'call-process-region' now allow
 you to direct error message output from the subprocess into a
 separate destination, instead of mixing it with ordinary output.
 To do this, specify for the third argument, BUFFER, a list of the form
@@ -2646,42 +2653,42 @@ names, respectively.
 
 ** Text properties
 
-*** You can now specify which values of the `invisible' property
+*** You can now specify which values of the 'invisible' property
 make text invisible in a given buffer.  The variable
-`buffer-invisibility-spec', which is always local in all buffers,
+'buffer-invisibility-spec', which is always local in all buffers,
 controls this.
 
-If its value is t, then any non-nil `invisible' property makes
+If its value is t, then any non-nil 'invisible' property makes
 a character invisible.
 
 If its value is a list, then a character is invisible if its
-`invisible' property value appears as a member of the list, or if it
+'invisible' property value appears as a member of the list, or if it
 appears as the car of a member of the list.
 
-When the `invisible' property value appears as the car of a member of
-the `buffer-invisibility-spec' list, then the cdr of that member has
+When the 'invisible' property value appears as the car of a member of
+the 'buffer-invisibility-spec' list, then the cdr of that member has
 an effect.  If it is non-nil, then an ellipsis appears in place of the
 character.  (This happens only for the *last* invisible character in a
 series of consecutive invisible characters, and only at the end of a
 line.)
 
-If a character's `invisible' property is a list, then Emacs checks each
-element of the list against `buffer-invisibility-spec'.  If any element
+If a character's 'invisible' property is a list, then Emacs checks each
+element of the list against 'buffer-invisibility-spec'.  If any element
 matches, the character is invisible.
 
-*** The command `list-text-properties-at' shows what text properties
+*** The command 'list-text-properties-at' shows what text properties
 are in effect at point.
 
 *** Frame objects now exist in Emacs even on systems that don't support
 X Windows.  You can create multiple frames, and switch between them
-using select-frame.  The selected frame is actually displayed on your
+using 'select-frame'.  The selected frame is actually displayed on your
 terminal; other frames are not displayed at all.  The selected frame
-number appears in the mode line after `Emacs', except for frame 1.
+number appears in the mode line after 'Emacs', except for frame 1.
 
 Switching frames on ASCII terminals is therefore more or less
 equivalent to switching between different window configurations.
 
-*** The new variable window-size-change-functions holds a list of
+*** The new variable 'window-size-change-functions' holds a list of
 functions to be called if window sizes change (or if windows are
 created or deleted).  The functions are called once for each frame on
 which changes have occurred, with the frame as the sole argument.
@@ -2712,16 +2719,16 @@ are the same arguments that the after-change-functions 
receive.
 This means the function must accept either four or five arguments.
 
 *** You can set defaults for text-properties with the new variable
-`default-text-properties'.  Its value is a property list; the values
+'default-text-properties'.  Its value is a property list; the values
 specified there are used whenever a character (or its category) does
 not specify a value.
 
-*** The `face' property of a character or an overlay can now be a list
+*** The 'face' property of a character or an overlay can now be a list
 of face names.  Formerly it had to be just one face name.
 
-*** Changes in handling the `intangible' text property.
+*** Changes in handling the 'intangible' text property.
 
-**** If inhibit-point-motion-hooks is non-nil, then `intangible' properties
+**** If inhibit-point-motion-hooks is non-nil, then 'intangible' properties
 are ignored.
 
 **** Moving to just before a stretch of intangible text
@@ -2740,26 +2747,26 @@ place point between them.
 
 *** Overlay changes.
 
-**** The new function previous-overlay-change returns the position of
+**** The new function 'previous-overlay-change' returns the position of
 the previous overlay start or end, before a specified position.  This
-is the backwards-moving counterpart of next-overlay-change.
+is the backwards-moving counterpart of 'next-overlay-change'.
 
-**** overlay-get now supports category properties on an overlay
-the same way get-text-property supports them as text properties.
+**** 'overlay-get' now supports category properties on an overlay
+the same way 'get-text-property' supports them as text properties.
 
 Specifically, if an overlay does not have the property PROP that you
-ask for, but it does have a `category' property which is a symbol,
+ask for, but it does have a 'category' property which is a symbol,
 then that symbol's PROP property is used.
 
-**** If an overlay has a non-nil `evaporate' property, it will be
+**** If an overlay has a non-nil 'evaporate' property, it will be
 deleted if it ever becomes empty (i.e., when it spans no characters).
 
-**** If an overlay has a `before-string' and/or `after-string' property,
+**** If an overlay has a 'before-string' and/or 'after-string' property,
 these strings are displayed at the overlay's endpoints.
 
 ** Filling
 
-*** The new variable fill-paragraph-function provides a way for major
+*** The new variable 'fill-paragraph-function' provides a way for major
 modes to override the filling of paragraphs.  If this is non-nil,
 fill-paragraph calls it as a function, passing along its sole
 argument.  If the function returns non-nil, fill-paragraph assumes it
@@ -2770,57 +2777,57 @@ language modes.
 
 *** Text filling and justification changes:
 
-**** The new variable use-hard-newlines can be used to make a
+**** The new variable 'use-hard-newlines' can be used to make a
 distinction between "hard" and "soft" newlines; the fill functions
 will then never remove a newline that was manually inserted.  Hard
-newlines are marked with a non-nil `hard' text-property.
+newlines are marked with a non-nil 'hard' text-property.
 
-**** The fill-column and left-margin can now be modified by text-properties.
+**** The 'fill-column' and 'left-margin' can now be modified by 
text-properties.
 Most lisp programs should use the new functions (current-fill-column) and
 (current-left-margin), which return the proper values to use for the
 current line.
 
 **** There are new functions for dealing with margins:
 
-***** Set-left-margin and set-right-margin (set the value for a region
+***** 'set-left-margin' and 'set-right-margin' (set the value for a region
 and re-fill).  These functions take three arguments: two to specify
 a region, and the desired margin value.
 
-***** Increase-left-margin, decrease-left-margin, increase-right-margin, and
-decrease-right-margin (change settings relative to current values, and
+***** 'increase-left-margin', 'decrease-left-margin', 'increase-right-margin',
+and 'decrease-right-margin' (change settings relative to current values, and
 re-fill).
 
-***** move-to-left-margin moves point there, optionally adding
+***** 'move-to-left-margin' moves point there, optionally adding
 indentation or changing tabs to spaces in order to make that possible.
-beginning-of-line-text also moves past the fill-prefix and any
+'beginning-of-line-text' also moves past the 'fill-prefix' and any
 indentation added to center or right-justify a line, to the beginning
 of the text that the user actually typed.
 
-***** delete-to-left-margin removes any left-margin indentation, but
+***** 'delete-to-left-margin' removes any left-margin indentation, but
 does not change the property.
 
-**** The paragraph-movement functions look for the paragraph-start and
-paragraph-separate regexps at the current left margin, not at the
+**** The paragraph-movement functions look for the 'paragraph-start' and
+'paragraph-separate' regexps at the current left margin, not at the
 beginning of the line.  This means that those regexps should NOT use ^
 to anchor the search.  However, for backwards compatibility, a ^ at
 the beginning of the regexp will be ignored, so most packages won't break.
 
-**** justify-current-line is now capable of doing left, center, or
+**** 'justify-current-line' is now capable of doing left, center, or
 right justification as well as full justification.
 
 **** The fill functions can do any kind of justification based on the new
-`justification' text-property and `default-justification' variable,
+'justification' text-property and 'default-justification' variable,
 or arguments to the functions.  They also have a new option which
 defeats the normal removal of extra whitespace.
 
-**** The new function `current-justification' returns the kind of
+**** The new function 'current-justification' returns the kind of
 justification used for the current line.  The new function
-`set-justification' can be used to change it, including re-justifying
+'set-justification' can be used to change it, including re-justifying
 the text of the region according to the new value.
 
-**** Filling and auto-fill are disabled if justification is `none'.
+**** Filling and auto-fill are disabled if justification is 'none'.
 
-**** The auto-fill-function is now called regardless of whether
+**** The 'auto-fill-function' is now called regardless of whether
 the fill-column has been exceeded; the function can determine on its
 own whether filling (or justification) is necessary.
 
@@ -2828,14 +2835,14 @@ own whether filling (or justification) is necessary.
 
 ** Processes
 
-*** process-tty-name is a new function that returns the name of the
+*** 'process-tty-name' is a new function that returns the name of the
 terminal that the process itself reads and writes on (not the name of
 the pty that Emacs uses to talk with that terminal).
 
 *** Errors in process filters and sentinels are now normally caught
 automatically, so that they don't abort other Lisp programs.
 
-Setting debug-on-error non-nil turns off this feature; then errors in
+Setting 'debug-on-error' non-nil turns off this feature; then errors in
 filters and sentinels are not caught.  As a result, they can invoke
 the debugger, under the control of debug-on-error.
 
@@ -2846,10 +2853,10 @@ match data.
 
 ** Display
 
-*** The variable message-log-max controls how messages are logged in the
+*** The variable 'message-log-max' controls how messages are logged in the
 "*Messages*" buffer.  An integer value means to keep that many lines;
 t means to log with no limit; nil means disable message logging.  Lisp
-code that calls `message' excessively (e.g. isearch.el) should probably
+code that calls 'message' excessively (e.g. isearch.el) should probably
 bind this variable to nil.
 
 *** Display tables now have a new element, at index 261, specifying the
@@ -2859,22 +2866,22 @@ other useful character to store for this element is a 
space, to make
 less visual separation between two side-by-side windows displaying
 related information.
 
-*** The new mode-line-format spec %c displays the current column number.
+*** The new 'mode-line-format' spec %c displays the current column number.
 
-*** The new variable blink-matching-delay specifies how long to keep
+*** The new variable 'blink-matching-delay' specifies how long to keep
 the cursor at the matching open-paren, after you insert a close-paren.
 This is useful mainly on systems which can wait for a fraction of a
 second--you can then specify fractional values such as 0.5.
 
 *** Faster processing of buffers with long lines
 
-The new variable cache-long-line-scans determines whether Emacs
+The new variable 'cache-long-line-scans' determines whether Emacs
 should use caches to handle long lines more quickly.  This variable is
 buffer-local, in all buffers.
 
 Normally, the line-motion functions work by scanning the buffer for
-newlines.  Columnar operations (like `move-to-column' and
-`compute-motion') also work by scanning the buffer, summing character
+newlines.  Columnar operations (like 'move-to-column' and
+'compute-motion') also work by scanning the buffer, summing character
 widths as they go.  This works well for ordinary text, but if the
 buffer's lines are very long (say, more than 500 characters), these
 motion functions will take longer to execute.  Emacs may also take
@@ -2899,30 +2906,30 @@ it should only affect their performance.
 
 ** System Interface
 
-*** The function user-login-name now accepts an optional
+*** The function 'user-login-name' now accepts an optional
 argument uid.  If the argument is non-nil, user-login-name
 returns the login name for that user id.
 
-*** system-name, user-name, user-full-name and user-real-name are now
-variables as well as functions.  The variables hold the same values
-that the functions would return.  The new variable multiple-frames
+*** 'system-name', 'user-name', 'user-full-name' and 'user-real-name' are
+now variables as well as functions.  The variables hold the same values
+that the functions would return.  The new variable 'multiple-frames'
 is non-nil if at least two non-minibuffer frames are visible.  These
-variables may be useful in constructing the value of frame-title-format
-or icon-title-format.
+variables may be useful in constructing the value of 'frame-title-format'
+or 'icon-title-format'.
 
 *** Changes in time-conversion functions.
 
-**** The new function format-time-string takes a format string and a
+**** The new function 'format-time-string' takes a format string and a
 time value.  It converts the time to a string, according to the format
 specified.  You can specify what kind of conversion to use with
 %-specifications.
 
-**** The new function decode-time converts a time value into a list of
+**** The new function 'decode-time' converts a time value into a list of
 specific items of information: the year, month, day of week, day of
 month, hour, minute and second.  (A time value is a list of two or
 three integers.)
 
-**** The new function encode-time converts specific items of time
+**** The new function 'encode-time' converts specific items of time
 information--the second, minute, hour, day, month, year, and time
 zone--into a time value.
 
@@ -2977,7 +2984,7 @@ You must still explicitly load either iso-transl or 
iso-acc.
 ** For a read-only buffer that is also modified, the mode line now displays
 %* instead of %%.
 
-** M-prior (scroll-other-window-down) is a new command that works like
+** M-prior ('scroll-other-window-down') is a new command that works like
 M-next (and C-M-v) but scrolls in the opposite direction.
 
 M-home moves to the beginning of the buffer, in the other window.
@@ -3001,7 +3008,7 @@ your .signature file, you now get a -- before the 
signature.
 ** Setting rmail-highlighted-headers to nil entirely turns off
 highlighting in Rmail.  However, if your motivation for doing this is
 that the highlighted text doesn't look good on your display, it might
-be better to change the appearance of the `highlight' face.  Once
+be better to change the appearance of the 'highlight' face.  Once
 you've done that, you may find Rmail highlighting is useful.
 
 ** In the calendar, mouse-2 is now used only for commands that apply to a date.
@@ -3018,18 +3025,18 @@ is now C-c C-v C-d, not C-c C-v C-h.  Thus, C-c C-v C-h 
is now available
 for asking for a list of the subcommands of C-c C-v.
 
 ** You can now specify "who you are" for various Emacs packages by
-setting just one variable, user-mail-address.  This currently applies
+setting just one variable, 'user-mail-address'.  This currently applies
 to posting news with GNUS and to making change log entries.  It may
 apply to additional Emacs features in the future.
 
 
 * Lisp-Level Changes in Emacs 19.26:
 
-** The function insert-char now takes an optional third argument
+** The function 'insert-char' now takes an optional third argument
 which, if non-nil, says the inserted characters should inherit sticky
 text properties from the surrounding text.
 
-** The `diary' library has been renamed to `diary-lib'.  If you refer
+** The 'diary' library has been renamed to 'diary-lib'.  If you refer
 to this library in your Lisp code, you must update the references.
 
 ** Sending text to a subprocess can read input from subprocesses if it
@@ -3051,23 +3058,23 @@ The old meaning of %+ is now available on %&.
 It displays * for a modified buffer and - for an unmodified buffer,
 regardless of read-only status.
 
-** You can now use `underline' in the color list of a face.
+** You can now use 'underline' in the color list of a face.
 It serves as a last resort, and says to underline the face
 (if previous color list elements can't be used).
 
-** The new function x-color-values returns the list of color values
+** The new function 'x-color-values' returns the list of color values
 for a given color name (a string).  The list contains three integers
 which give the amounts of red, green and blue in the color: (R G B).
 
-** In run-at-time, 0 as the repeat interval means "don't repeat".
+** In 'run-at-time', 0 as the repeat interval means "don't repeat".
 
-** The variable trim-versions-without-asking has been renamed to
-delete-old-versions.
+** The variable 'trim-versions-without-asking' has been renamed to
+'delete-old-versions'.
 
-** The new function other-window-for-scrolling returns the choice of
+** The new function 'other-window-for-scrolling' returns the choice of
 other window for C-M-v to scroll.
 
-** Note that the function fceiling was mistakenly documented as fceil before.
+** Note that the function 'fceiling' was mistakenly documented as 'fceil' 
before.
 
 
 * Changes in cc-mode.el in Emacs 19.26:
@@ -3081,7 +3088,7 @@ other window for C-M-v to scroll.
   Note that the custom indent function c-adaptive-block-open has been
   removed as obsolete.
 
-** You can now specify the `hanginess' of closing braces.  See
+** You can now specify the 'hanginess' of closing braces.  See
   c-hanging-braces-alist.
 
 ** Recognizes try and catch blocks in C++.  They are given the
@@ -3102,9 +3109,9 @@ other window for C-M-v to scroll.
   cc-mode.el.
 
 ** internal defun c-indent-via-language-element has been renamed
-  c-indent-line for compatibility with c-mode.el and awk-mode.
+  c-indent-line for compatibility with c-mode.el and 'awk-mode'.
 
-** new buffer-local variable c-comment-start-regexp for (potential)
+** new buffer-local variable 'c-comment-start-regexp' for (potential)
   flexibility in adding new modes based on cc-mode.el
 
 
@@ -3112,7 +3119,7 @@ other window for C-M-v to scroll.
 * Changes in Emacs 19.25
 
 The variable x-cross-pointer-shape (which didn't really exist) has
-been renamed to x-sensitive-text-pointer-shape, and now does exist.
+been renamed to 'x-sensitive-text-pointer-shape', and now does exist.
 
 
 
@@ -3207,7 +3214,7 @@ move the mouse over them.
 ** In a completion list buffer, the command RET now chooses the completion
 that is around or next to point.
 
-** If you specify the foreground color for the `mode-line' face, and
+** If you specify the foreground color for the 'mode-line' face, and
 mode-line-inverse-video is non-nil, then the default background color
 is the usual foreground color.
 
@@ -3228,7 +3235,7 @@ auto-save (as has been possible in Emacs 19).
 
 ** C-x r d now runs the command delete-rectangle.
 
-** The new command imenu shows you a menu of interesting places in the
+** The new command 'imenu' shows you a menu of interesting places in the
 current buffer and lets you select one; then it moves point there.
 The definition of interesting places depends on the major mode, but
 typically this includes function definitions and such.  Normally,
@@ -3237,29 +3244,29 @@ event, it shows a mouse popup menu.
 
 ** You can make certain chosen buffers, that normally appear in a
 separate window, appear in special frames of their own.  To do this,
-set special-display-buffer-names to a list of buffer names; any buffer
+set 'special-display-buffer-names' to a list of buffer names; any buffer
 whose name is in that list automatically gets a special frame when it
 is to be displayed in another window.
 
 A good value to try is ("*compilation*" "*grep*" "*TeX Shell*").
 
-More generally, you can set special-display-regexps to a list of regular
+More generally, you can set 'special-display-regexps' to a list of regular
 expressions; then each buffer whose name matches any of those regular
 expressions gets its own frame.
 
-The variable special-display-frame-alist specifies the frame
+The variable 'special-display-frame-alist' specifies the frame
 parameters for these frames.  It has a default value, so you don't
 need to set it.
 
-** If you set sentence-end-double-space to nil, the fill commands
+** If you set 'sentence-end-double-space' to nil, the fill commands
 expect just one space at the end of a sentence.  (If you want the
 sentence commands to accept single spaces, you must modify the regexp
-sentence-end also.)
+'sentence-end' also.)
 
 ** You can suppress the startup echo area message by adding text like
 this to your .emacs file:
 
-(setq inhibit-startup-echo-area-message "YOUR-LOGIN-NAME")
+    (setq inhibit-startup-echo-area-message "YOUR-LOGIN-NAME")
 
 Simply setting inhibit-startup-echo-area-message to your login name is
 not sufficient to inhibit the message; Emacs explicitly checks whether
@@ -3272,7 +3279,7 @@ message for someone else.
 
 ** Outline minor mode now uses C-c C-o as a prefix instead of just C-c.
 
-** In Outline mode, hide-subtree is now C-c C-d.  (It was C-c C-h; but
+** In Outline mode, 'hide-subtree' is now C-c C-d.  (It was C-c C-h; but
 that is now a conventional way to ask for help about C-c commands.)
 
 ** There are two additional commands in Outline mode.
@@ -3315,19 +3322,19 @@ buffer to show the last batch of output from the 
subprogram.
 point, rather than the word that point is within.
 
 *** Comint mode file name completion ignores those files that end with a
-string in the new variable comint-completion-fignore.  This variable's
+string in the new variable 'comint-completion-fignore'.  This variable's
 default value is nil.
 
 *** Shell mode uses the variable shell-completion-fignore to set
 comint-completion-fignore.  The default value is nil, but some
 people prefer ("~" "#" "%").
 
-*** The function `comint-watch-for-password-prompt' can be used to
+*** The function 'comint-watch-for-password-prompt' can be used to
 suppress echoing when a subprocess asks for a password.  To use it,
 do this:
 
-(add-hook 'comint-output-filter-functions
-         'comint-watch-for-password-prompt)
+    (add-hook 'comint-output-filter-functions
+              #'comint-watch-for-password-prompt)
 
 *** You can use M-x shell-strip-ctrl-m to strip ^M characters from
 process output.
@@ -3353,23 +3360,23 @@ GDB-style symbol completion.  This will work with GDB 
4.13.
 
 ** Rmail no longer gets new mail automatically when you visit an Rmail
 file specified by name--not even if it is your primary Rmail file.  To
-get new mail, type `g'.  This feature is an advantage because you now
+get new mail, type 'g'.  This feature is an advantage because you now
 have a choice of whether to get new mail.  (This change actually
 occurred in an earlier version, but wasn't listed here then, since it
 made the code do what the documentation already said.)
 
 ** Rmail now highlights certain fields automatically, when you use X
-windows.  The variable rmail-highlighted-headers controls which
+windows.  The variable 'rmail-highlighted-headers' controls which
 fields.
 
-** If you set rmail-summary-window-size to an integer, Rmail uses
+** If you set 'rmail-summary-window-size' to an integer, Rmail uses
 a window that many lines high for the summary buffer.
 
-** rmail-input-menu is a new command that visits an Rmail file letting
-you choose which file with a mouse menu.  rmail-output-menu is
+** 'rmail-input-menu' is a new command that visits an Rmail file letting
+you choose which file with a mouse menu.  'rmail-output-menu' is
 similar; it outputs the current message, using a mouse menu to choose
 which Rmail file.  These commands use the variables
-rmail-secondary-file-directory and rmail-secondary-file-regexp.
+'rmail-secondary-file-directory' and 'rmail-secondary-file-regexp'.
 
 ** The mh-e package has been changed substantially.
 See the file ./MH-E-NEWS for details.
@@ -3384,8 +3391,8 @@ date in the calendar window and common 
three-month-related commands
 when clicked elsewhere in the calendar window.
 
 You can set up colored/shaded highlighting of holidays, diary entry
-dates, and today's date, by setting calendar-holiday-marker,
-diary-entry-marker, and calendar-today-marker to a face instead of a
+dates, and today's date, by setting 'calendar-holiday-marker',
+'diary-entry-marker', and 'calendar-today-marker' to a face instead of a
 character.  Using a special face is now the default if you are using a
 window system.
 
@@ -3393,16 +3400,16 @@ window system.
 features.
 
 *** The appt alarm window stays for the full duration of
-appt-display-duration.  It no longer disappears when you start typing
+'appt-display-duration'.  It no longer disappears when you start typing
 text.
 
 *** You can change the way the appointment window is created/deleted by
-setting the variables appt-disp-window-function and
-appt-delete-window-function.
+setting the variables 'appt-disp-window-function' and
+'appt-delete-window-function'.
 
 For instance, these variables can be set to functions that display
 appointments in pop-up frames, which are lowered or iconified after
-appt-display-duration seconds.
+'appt-display-duration' seconds.
 
 ** desktop.el can now save a list of buffer-local variables,
 and saves more global ones.
@@ -3423,8 +3430,8 @@ now be debugged with Edebug.
 *** Edebug specifications may now contain body, &define, name, arg or
 arglist, def-body, and def-form, to support definitions.
 
-*** edebug-all-defuns is renamed to edebug-all-defs.
-def-edebug-form-spec is replaced by def-edebug-form whose arguments
+*** edebug-all-defuns is renamed to 'edebug-all-defs'.
+def-edebug-form-spec is replaced by 'def-edebug-form' whose arguments
 are unevaluated.  The old names are still available for now.
 
 *** Frequency counts and coverage data may be displayed for functions being
@@ -3436,13 +3443,13 @@ debugged.
 
 *** A new "next" mode stops only after expression evaluation.
 
-*** A new command, top-level-nonstop, does not even stop for unwind-protect,
+*** A new command, 'top-level-nonstop', does not even stop for 
'unwind-protect',
 as top-level would.
 
 
 * Changes in CC mode in Emacs 19.23.
 
-`cc-mode' provides ANSI C, K&R C, and ARM C++ language editing.  It
+'cc-mode' provides ANSI C, K&R C, and ARM C++ language editing.  It
 represents the merge of c++-mode.el and c-mode.el.  cc-mode provides a
 new, more flexible indentation engine so that indentation
 customization is more intuitive.  There are two steps to calculating
@@ -3450,8 +3457,8 @@ indentation: first, CC mode analyzes the line for 
syntactic content,
 then based on this content it applies user defined offsets and adds
 this offset to the indentation of some previous line.
 
-The syntactic analysis determines if the line describes a `statement',
-`substatement', `class-open', `member-init-intro', etc.  These are
+The syntactic analysis determines if the line describes a 'statement',
+'substatement', 'class-open', 'member-init-intro', etc.  These are
 described in detail with C-h v c-offsets-alist.  You can change the
 offsets interactively with C-c C-o (c-set-offsets), or
 programmatically in your c-mode-common-hook, which is run both by
@@ -3489,75 +3496,75 @@ int foo (int i)
 
 you could add the following to your .emacs file:
 
-(defun my-c-mode-common-hook ()
-  (c-set-offset 'case-label 2)
-  (c-set-offset 'statement-case-intro 2))
-(add-hook 'c-mode-common-hook 'my-c-mode-common-hook)
+    (defun my-c-mode-common-hook ()
+      (c-set-offset 'case-label 2)
+      (c-set-offset 'statement-case-intro 2))
+    (add-hook 'c-mode-common-hook #'my-c-mode-common-hook)
 
 ** New variables:
 
-c-offsets-alist contains an association list of syntactic symbols and
+'c-offsets-alist' contains an association list of syntactic symbols and
 their relative offsets.  Do a "C-h v c-offsets-alist" to get a list of
 all syntactic symbols currently defined, and their meanings.  You
 should not change this variable directly; use the supplied interface
-commands c-set-offset and c-set-style.
+commands 'c-set-offset' and 'c-set-style'.
 
-c-mode-common-hook is run by both c-mode and c++-mode during their
+'c-mode-common-hook' is run by both 'c-mode' and 'c++-mode' during their
 common initializations.  You should put any customizations that are
 the same for both C and C++ into this hook.
 
-The variable c-strict-semantics-p is used mainly for debugging.  When
+The variable 'c-strict-semantics-p' is used mainly for debugging.  When
 non-nil, CC mode signals an error if it returns a syntactic symbol
 that can't be found in c-offsets-alist.
 
 If you want CC mode to echo the syntactic analysis for a particular
-line when you hit the TAB key, set c-echo-semantic-information-p to
+line when you hit the TAB key, set 'c-echo-semantic-information-p' to
 non-nil.
 
-c-basic-offset controls the standard amount of offset for a level of
+'c-basic-offset' controls the standard amount of offset for a level of
 indentation.  You can set a syntactic symbol's offset to + or - as a
 short-hand for positive or negative c-basic-offset.
 
-c-comment-only-line-offset lets you control indentation given to lines
+'c-comment-only-line-offset' lets you control indentation given to lines
 which contain only a comment, in the case of C++ line style comments,
 or the introduction to a C block comment.  Comment-only lines at
 column zero can be anchored there independent of the indentation given
 to other comment-only lines.
 
-c-block-comments-indent-p controls the style of C block comment
+'c-block-comments-indent-p' controls the style of C block comment
 re-indentation.  If you put leading stars in front of comment
 continuation lines, you should set this variable to nil.
 
-c-cleanup-list is a list describing certain C and C++ constructs to be
+'c-cleanup-list' is a list describing certain C and C++ constructs to be
 "cleaned up" as they are typed, but only when the auto-newline feature
 is turned on.  In C++, make sure this variable contains at least
 'scope-operator so that double colons will not be separated by a
 newline.
 
-Colons (`:') and braces (`{` and `}') are special in C and C++.  For
+Colons (':') and braces (`{` and `}') are special in C and C++.  For
 certain constructs, you may like them to hang on the right edge of the
 code, or you may like them to start a new line of code.  You can use
-the two variables c-hanging-braces-alist and c-hanging-colons-alist
+the two variables 'c-hanging-braces-alist' and 'c-hanging-colons-alist'
 to control whether newlines are placed before and/or after colons and
 braces when certain C and C++ constructs are entered.  For example,
 you can control whether the colon that introduces a C++ member
 initialization list hangs on the right edge, starts a new line, or has
 no newlines either before or after it.
 
-c-special-indent-hook is run after a line is indented by CC mode.  You
+'c-special-indent-hook' is run after a line is indented by CC mode.  You
 can perform any custom indentations here.
 
-c-delete-function is the function that is called when a single
+'c-delete-function' is the function that is called when a single
 character is deleted with the c-electric-delete command (DEL).
 
-c-electric-pound-behavior describes what happens when you enter the
+'c-electric-pound-behavior' describes what happens when you enter the
 `#' that introduces a cpp macro.
 
-If c-tab-always-indent is neither t nor nil, then TAB inserts a tab
+If 'c-tab-always-indent' is neither t nor nil, then TAB inserts a tab
 when within strings, comments, and cpp directives, but it reindents
 the line unconditionally.
 
-c-inhibit-startup-warnings-p inhibits warnings about any old
+'c-inhibit-startup-warnings-p' inhibits warnings about any old
 version of Emacs you might be running, which could be incompatible
 with cc-mode.
 
@@ -3613,7 +3620,7 @@ convention of 
VariableNamesWithoutUnderscoresButEachWordCapitalized.
 
 * Lisp programming changes in Emacs 19.23.
 
-** To pop up a dialog box, call x-popup-dialog.
+** To pop up a dialog box, call 'x-popup-dialog'.
 It takes two arguments, POSITION and CONTENTS.
 
 POSITION specifies which frame to place the dialog box over;
@@ -3635,12 +3642,12 @@ If your Emacs is not using an X toolkit, then it cannot 
display a
 real dialog box; so instead it displays a pop-up menu in the center
 of the frame.
 
-** y-or-n-p, yes-or-no-p and map-y-or-n-p now use menus or dialog boxes
+** 'y-or-n-p', 'yes-or-no-p' and 'map-y-or-n-p' now use menus or dialog boxes
 to ask their question(s) if the command that is running was reached by
 a mouse event.
 
 If you want to control which way these functions work, bind the
-variable last-nonmenu-event around the call.  These functions use the
+variable 'last-nonmenu-event' around the call.  These functions use the
 keyboard if that variable holds a keyboard event (actually, any
 non-list); they use the mouse if that variable holds a mouse event
 (actually, any list).
@@ -3649,49 +3656,49 @@ non-list); they use the mouse if that variable holds a 
mouse event
 a text property.  It specifies a face to use when the mouse is in the
 range of text for which the property is specified.
 
-** When text has a non-nil `intangible' property, you cannot move point
+** When text has a non-nil 'intangible' property, you cannot move point
 within it or right before it.  If you try, point actually moves to the
-end of the intangible text.  Note that this means that backward-char
+end of the intangible text.  Note that this means that 'backward-char'
 is a no-op when there is an intangible character to the left of point.
 
-** minibuffer-exit-hook is a new normal hook that is run when you
+** 'minibuffer-exit-hook' is a new normal hook that is run when you
 exit the minibuffer.
 
-** The variable x-cross-pointer-shape specifies the cursor shape to use
+** The variable 'x-cross-pointer-shape' specifies the cursor shape to use
 when the mouse is over text that has a mouse-face property.
 
-** The new variable interpreter-mode-alist specifies major modes to use
+** The new variable 'interpreter-mode-alist' specifies major modes to use
 for shell scripts that specify a command interpreter.  Its elements
 look like (INTERPRETER . MODE); for example, ("perl" . perl-mode) is
 one element present by default.  This feature applies only when the
 file name doesn't indicate which mode to use.
 
 ** If you use a minibuffer-only frame, set the variable
-minibuffer-auto-raise to t, and entering the minibuffer will then
+'minibuffer-auto-raise' to t, and entering the minibuffer will then
 raise the minibuffer frame.
 
-** If pop-up-frames is t, display-buffer now looks for an existing
+** If 'pop-up-frames' is t, display-buffer now looks for an existing
 window in any visible frame, showing the specified buffer, and uses
 such a window in preference to making a new frame.
 
-** In the functions next-window, previous-window, next-frame,
-previous-frame, get-buffer-window, get-lru-window, get-largest-window
-and delete-windows-on, if you specify `visible' for the last argument,
+** In the functions 'next-window', 'previous-window', 'next-frame',
+'previous-frame', 'get-buffer-window', 'get-lru-window', 'get-largest-window'
+and 'delete-windows-on', if you specify 'visible' for the last argument,
 it means to consider all visible frames.
 
 ** Mouse events now give the X and Y coordinates in pixels, rather than
 in characters.  You can convert these values to characters by dividing by
 the values of (frame-char-width) and (frame-char-height).
 
-** The new functions mouse-pixel-position and set-mouse-pixel-position
+** The new functions 'mouse-pixel-position' and 'set-mouse-pixel-position'
 read and set the mouse position in units of pixels.  The existing
-functions mouse-position and set-mouse-position continue to work with
+functions 'mouse-position' and 'set-mouse-position' continue to work with
 units of characters.
 
-** The new function compute-motion is useful for computing the width
+** The new function 'compute-motion' is useful for computing the width
 of certain text when it is displayed.
 
-** The function vertical-motion now takes an option second argument WINDOW
+** The function 'vertical-motion' now takes an option second argument WINDOW
 which says which window to use for the display calculations.
 
 vertical-motion always operates on the current buffer.
@@ -3699,7 +3706,7 @@ It is ok to specify a window displaying some other buffer.
 Then vertical-motion uses the width, hscroll and display-table of
 the specified window, but still scans the current buffer.
 
-** An error no longer sets last-command to t; the value of last-command
+** An error no longer sets 'last-command' to t; the value of last-command
 does reflect the previous command (the one that got an error).
 
 If you do not want a particular command to be recognized as the
@@ -3728,20 +3735,20 @@ The undo and yank commands do this.
 ** If you specify an explicit title for a new frame when you create it,
 the title is used as the resource name when looking up X resources to
 control the shape of that frame.  If you don't specify the frame title,
-the value of x-resource-name is used, as before.
+the value of 'x-resource-name' is used, as before.
 
 ** The frame parameter user-position, if non-nil, says that the user
 has specified the frame position.  Emacs reports this to the window
 manager, to tell it not to override the position that the user
 specified.
 
-** Major modes can now set change-major-mode-hook to arrange for state
+** Major modes can now set 'change-major-mode-hook' to arrange for state
 to be cleaned up when the user switches to a new major mode.  The function
-kill-all-local-variables runs this hook.  For best results, make the hook a
+'kill-all-local-variables' runs this hook.  For best results, make the hook a
 buffer-local variable so that it will disappear after doing its job and will
 not interfere with the subsequent major mode.
 
-** The new variable overriding-local-map, if non-nil, specifies a keymap
+** The new variable 'overriding-local-map', if non-nil, specifies a keymap
 that overrides the current local map, all minor mode keymaps, and all
 text property keymaps.  Incremental search uses this feature to override
 all other keymaps temporarily.
@@ -3756,7 +3763,7 @@ key sequences that run the same command COMMAND.  
Displaying the menu
 automatically creates and updates the sublist when appropriate; you
 need never set these up yourself.
 
-lookup-key, key-binding, and similar functions return just COMMAND,
+'lookup-key', 'key-binding', and similar functions return just COMMAND,
 not the whole binding.
 
 To precompute this information for a given keymap, you can do
@@ -3783,7 +3790,7 @@ from the specifications above.)
 If you pass the value of overriding-local-map as KEYMAP, where-is-internal
 searches in exactly the same was as command execution does.
 
-** Use the macro define-derived-mode to define a new major mode that
+** Use the macro 'define-derived-mode' to define a new major mode that
 inherits the definition of another major mode.  Here's how to define a
 command named hypertext-mode that inherits from the command text-mode:
 
@@ -3800,11 +3807,11 @@ its own mode hook.  All are given names made by 
appending a suffix
 to the name of the new mode.
 
 ** A syntax table can now inherit the data for some characters from
-standard-syntax-table, while specifying other characters itself.
+'standard-syntax-table', while specifying other characters itself.
 Syntax code 13 means "inherit this character from the standard syntax
-table."  In modify-syntax-entry, the character `@' represents this code.
+table."  In 'modify-syntax-entry', the character `@' represents this code.
 
-The function `make-syntax-table' now creates a syntax table which
+The function 'make-syntax-table' now creates a syntax table which
 inherits all letters and control characters (0 to 31 and 128 to 255)
 from the standard syntax table, while copying the other characters
 from the standard syntax table.  Most syntax tables in Emacs are set
@@ -3815,15 +3822,15 @@ sets with additional alphabetic characters in the range 
128 to 255.
 Just changing the standard syntax for these characters affects all
 major modes.
 
-** The new function transpose-regions swaps two regions of the buffer.
+** The new function 'transpose-regions' swaps two regions of the buffer.
 It preserves the markers in those two regions, so that they stay with
 the surrounding text as it is swapped.
 
-** revert-buffer now runs before-revert-hook at the beginning and
-after-revert-hook at the end.  These can be used by minor modes
+** 'revert-buffer' now runs 'before-revert-hook' at the beginning and
+'after-revert-hook' at the end.  These can be used by minor modes
 that need to clean up state variables.
 
-** The new function get-char-property is like get-text-property, but
+** The new function 'get-char-property' is like 'get-text-property', but
 checks for overlays with properties as well as for text properties.
 It checks for overlays first, in order of descending priority, and
 text properties last.
@@ -3832,9 +3839,9 @@ get-char-property allows windows as the OBJECT argument, 
as well
 as buffers and strings.  If you specify a window, then only overlays
 active on that window are considered.
 
-** Overlays can have the `invisible' property.
+** Overlays can have the 'invisible' property.
 
-** The function insert-file-contents now takes an optional fifth
+** The function 'insert-file-contents' now takes an optional fifth
 argument called REPLACE.  If this is t, it means to replace the
 contents of the buffer (actually, just the accessible portion)
 with the contents of the file.
@@ -3843,72 +3850,72 @@ This is better than simply deleting and inserting the 
whole thing
 because (1) it preserves some marker positions and (2) it puts less
 data in the undo list.
 
-** The variable inhibit-first-line-modes-regexps specifies classes of
+** The variable 'inhibit-first-line-modes-regexps' specifies classes of
 file names for which -*- on the first line should not be looked for.
 
-** The variables before-change-functions and after-change-functions
+** The variables 'before-change-functions' and 'after-change-functions'
 hold lists of functions to call before and after a change in the
 buffer's text.  They work much like before-change-function and
 after-change-function, except that they hold a list of functions
 instead of just one.
 
-These variables will eventually make before-change-function and
-after-change-function obsolete.
+These variables will eventually make 'before-change-function' and
+'after-change-function' obsolete.
 
-** The variable kill-buffer-query-functions holds a list of functions
+** The variable 'kill-buffer-query-functions' holds a list of functions
 to be called with no arguments when a buffer is about to be killed.
 (That buffer is the current buffer when the function is called.)
 If any of the functions returns nil, the buffer is not killed
 (and the remaining functions in the list are not called).
 
-** The variable kill-emacs-query-functions holds a list of functions
+** The variable 'kill-emacs-query-functions' holds a list of functions
 to be called with no arguments when you ask to exit Emacs.
 If any of the functions returns nil, the exit is canceled
 (and the remaining functions in the list are not called).
 
-** The argument for buffer-disable-undo is now optional,
-like the argument for buffer-enable-undo.
+** The argument for 'buffer-disable-undo' is now optional,
+like the argument for 'buffer-enable-undo'.
 
-** The new variable system-configuration holds the canonical three-part
+** The new variable 'system-configuration' holds the canonical three-part
 GNU configuration name for which Emacs was built.
 
-** The function system-name now tries harder to return a fully qualified
+** The function 'system-name' now tries harder to return a fully qualified
 domain name.
 
-** The variable emacs-major-version holds the major version number
+** The variable 'emacs-major-version' holds the major version number
 of Emacs.  (Currently 19.)
 
-** The variable emacs-minor-version holds the minor version number
+** The variable 'emacs-minor-version' holds the minor version number
 of Emacs.  (Currently 23.)
 
-** The default value of comint-input-autoexpand is now nil.
+** The default value of 'comint-input-autoexpand' is now nil.
 However, Shell mode sets it from the value of shell-input-autoexpand,
-whose default value is `history'.
+whose default value is 'history'.
 
-** The new function set-process-window-size specifies the terminal window
+** The new function 'set-process-window-size' specifies the terminal window
 size for a subprocess.  On some systems it sends the subprocess a signal
 to let it know that the size has changed.
 
 ** %P is a new way to display a percentage in the mode line.  It
 displays the percentage of the buffer text that is above the *bottom*
 of the window (which includes the text visible, in the window as well
-as the text above the top).  It displays `Top' as well as the
+as the text above the top).  It displays 'Top' as well as the
 percentage if the top of the buffer is visible on screen.
 
 ** %+ in the mode line specs displays `*' if the buffer is modified,
-and otherwise `-'.  It never displays `%', as `%*' would do; whether the
+and otherwise '-'.  It never displays `%', as `%*' would do; whether the
 buffer is read-only has no effect on %+.
 
-** The new functions ffloor, fceiling, fround and ftruncate take a
+** The new functions 'ffloor', 'fceiling', 'fround' and 'ftruncate' take a
 floating point argument and return a floating point result whose value
 is a nearby integer.  ffloor returns the nearest integer below; fceiling,
 the nearest integer above; ftruncate, the nearest integer in the
 direction towards zero; fround, the nearest integer.
 
-** Setting `print-escape-newlines' to a non-nil value now also makes
+** Setting 'print-escape-newlines' to a non-nil value now also makes
 formfeeds print as ``\f''.
 
-** auto-mode-alist now has a new feature.  If an element has the form
+** 'auto-mode-alist' now has a new feature.  If an element has the form
 (REGEXP FUNCTION t), and REGEXP matches the file name, then after calling
 FUNCTION, Emacs deletes the part of the file name that matched REGEXP
 and then searches auto-mode-alist again for a new match.
@@ -3917,26 +3924,26 @@ This is useful for uncompression packages.  An entry of 
this sort for
 .gz can uncompress the file and then put the uncompressed file in the
 proper mode according to the name sans .gz.
 
-** The new function emacs-pid returns the process ID number of Emacs.
+** The new function 'emacs-pid' returns the process ID number of Emacs.
 
-** user-login-name now consistently checks the LOGNAME environment
-variable before USER.  user-original-login-name is obsolete, since it
+** 'user-login-name' now consistently checks the LOGNAME environment
+variable before USER.  'user-original-login-name' is obsolete, since it
 provides the same functionality.  To ignore the environment variables,
 use user-real-login-name.
 
 ** There is a more general way of handling the system-specific X
-keysyms.  Set the variable system-key-alist to an alist containing
+keysyms.  Set the variable 'system-key-alist' to an alist containing
 elements of the form (CODE . SYMBOL), where CODE is the numeric keysym
 code minus the "vendor specific" bit, and symbol is the name for the
 function key.
 
-** You can use the variable command-line-functions to set up functions
+** You can use the variable 'command-line-functions' to set up functions
 to process unrecognized command line arguments.  The variable's value
 should be a list of functions of no arguments.  The functions are
 called successively until one of them returns non-nil.
 
-Each function should access the free variables argi (the current
-argument) and command-line-args-left (the remaining arguments).  The
+Each function should access the free variables 'argi' (the current
+argument) and 'command-line-args-left' (the remaining arguments).  The
 function should return non-nil only if it recognizes and processes the
 argument in argi.  If it does so, it may consume following arguments
 as well by removing them from command-line-args-left.
@@ -3944,14 +3951,14 @@ as well by removing them from command-line-args-left.
 ** There's a new way for a magic file name handler to run a primitive
 and inhibit handling of the file name.  Here is how to do it:
 
-(let ((inhibit-file-name-handlers
-       (cons 'ange-ftp-file-handler
-             (and (eq inhibit-file-name-operation operation)
-                      inhibit-file-name-handlers)))
-      (inhibit-file-name-operation operation))
-  (apply this-operation args))
+    (let ((inhibit-file-name-handlers
+           (cons 'ange-ftp-file-handler
+                 (and (eq inhibit-file-name-operation operation)
+                          inhibit-file-name-handlers)))
+          (inhibit-file-name-operation operation))
+      (apply this-operation args))
 
-The function find-file-name-handler now takes two arguments.  The
+The function 'find-file-name-handler' now takes two arguments.  The
 second argument is OPERATION, the operation for which the handler is
 being sought.
 
@@ -3961,11 +3968,11 @@ it is not.  There is simply no way for 
find-file-name-handler to do
 the right thing without receiving the proper value for its second
 argument.
 
-** The variable completion-regexp-list affects the completion
-primitives try-completion and all-completions.  They consider
+** The variable 'completion-regexp-list' affects the completion
+primitives 'try-completion' and 'all-completions'.  They consider
 only the possible completions that match each regexp in the list.
 
-** Case conversion in the function replace-match has been changed.
+** Case conversion in the function 'replace-match' has been changed.
 
 The old behavior was this: if any word in the old text was
 capitalized, replace-match capitalized each word of the replacement
@@ -3977,24 +3984,24 @@ replace-match capitalizes the first word of the 
replacement text.
 ** You can now specify a case table with CANON non-nil and EQV nil.
 Then the EQV part of the case table is deduced from CANON.
 
-** The new function minibuffer-prompt takes no arguments and returns
+** The new function 'minibuffer-prompt' takes no arguments and returns
 the current minibuffer prompt string.
 
-The new function minibuffer-prompt-width takes no arguments and
+The new function 'minibuffer-prompt-width' takes no arguments and
 returns the display width of the minibuffer prompt string.
 
-** The new function frame-first-window returns the window at the
+** The new function 'frame-first-window' returns the window at the
 upper left corner of a given frame.
 
-** wholenump is a new alias for natnump.
+** 'wholenump' is a new alias for 'natnump'.
 
-** The variable installation-directory, if non-@code{nil}, names a
-directory within which to look for the `lib-src' and `etc'
+** The variable 'installation-directory', if non-@code{nil}, names a
+directory within which to look for the 'lib-src' and 'etc'
 subdirectories.  This is non-nil when Emacs can't find those
 directories in their standard installed locations, but can find them
 near where the Emacs executable was found.
 
-** invocation-name and invocation-directory are now variables as well
+** 'invocation-name' and 'invocation-directory' are now variables as well
 as functions.  The variable values are the same values that the
 functions return: the Emacs program name sans directories, and the
 directory it was found in.  (invocation-directory may be nil, if Emacs
@@ -4019,9 +4026,9 @@ by building Emacs.
 ** The mouse click M-mouse-2 now inserts the current secondary
 selection (from Emacs or any other X client) where you click.
 It does not move point.
-This command is called mouse-yank-secondary.
+This command is called 'mouse-yank-secondary'.
 
-mouse-kill-secondary no longer has a key binding by default.
+'mouse-kill-secondary' no longer has a key binding by default.
 Clicking M-mouse-3 (mouse-secondary-save-then-kill) twice
 may be a convenient enough way of killing the secondary selection.
 Or perhaps there should be a keyboard binding for killing the
@@ -4029,13 +4036,13 @@ secondary selection.  Any suggestions?
 
 ** New packages:
 
-*** `icomplete' provides character-by-character information
+*** 'icomplete' provides character-by-character information
 about what you could complete if you type TAB.
 
-*** `avoid' moves the mouse away from point so that it doesn't hide
+*** 'avoid' moves the mouse away from point so that it doesn't hide
 your typing.
 
-*** `shadowfile' helps you update files that are supposed to be stored
+*** 'shadowfile' helps you update files that are supposed to be stored
 identically in different places (perhaps on different machines).
 
 ** C-h p now knows about four additional keywords: data, faces, mouse,
@@ -4058,13 +4065,13 @@ This feature was added in 19.21 but did not work 
smoothly enough.
 
 ** Display of buffers with text properties is much faster now.
 
-** The feature previously announced whereby `insert' does not inherit
+** The feature previously announced whereby 'insert' does not inherit
 text properties from surrounding text was not fully implemented
-before; but now it is.  use `insert-and-inherit' if you wish to
+before; but now it is.  use 'insert-and-inherit' if you wish to
 inherit sticky properties from the surrounding text.
 
-** The functions next-property-change, previous-property-change,
-next-single-property-change, and previous-single-property-change
+** The functions 'next-property-change', 'previous-property-change',
+'next-single-property-change', and 'previous-single-property-change'
 now take one additional optional argument LIMIT that is a position at
 which to stop scanning.  If scan ends without finding the property
 change sought, these functions return the specified limit.
@@ -4151,7 +4158,7 @@ is expected.
 To define case-conversion for these characters for ISO 8859/1,
 load the library iso-syntax.  (This is not new.)
 
-** M-TAB in Text mode now runs the command ispell-complete-word
+** M-TAB in Text mode now runs the command 'ispell-complete-word'
 which performs completion using the spelling dictionary.
 
 The spelling correction submenu now includes this command
@@ -4162,7 +4169,7 @@ beginning of a word.
 ** In incremental search, you can use M-y to yank the most recent kill
 into the search string.
 
-** The new function ispell-message checks the spelling of a message
+** The new function 'ispell-message' checks the spelling of a message
 you are about to send or post.  It ignores text cited from other
 messages.
 
@@ -4188,8 +4195,8 @@ Indented lines continue the paragraph that is in 
progress.  This makes
 the user option variable adaptive-fill-mode have its intended effect.
 
 ** Local variable specifications in files for variables whose names end
-in `-hook' and `-function' are now controlled by the variable
-`enable-local-eval', just like the `eval' variable.
+in '-hook' and '-function' are now controlled by the variable
+'enable-local-eval', just like the 'eval' variable.
 
 ** C-x r j (jump-to-register) when restoring a frame configuration now
 makes all unwanted frames (existing frames not mentioned in the
@@ -4199,7 +4206,7 @@ If you want to delete these unwanted frames, use a prefix 
argument for
 C-x r j.
 
 ** You can customize the calendar to display weeks beginning on
-Monday: set the variable `calendar-week-start-day' to 1.
+Monday: set the variable 'calendar-week-start-day' to 1.
 
 ** Rmail changes.
 
@@ -4220,7 +4227,7 @@ There are new menu bar items for 
completion/input/output/signal commands.
 
 Input behavior is configurable.  Variables control whether some windows
 showing the buffer scroll to the bottom before insertion.  These are
-`comint-scroll-to-bottom-on-input' and `before-change-function'.  By default,
+'comint-scroll-to-bottom-on-input' and 'before-change-function'.  By default,
 insertion causes the selected window to scroll to the bottom before insertion
 occurs.
 
@@ -4228,33 +4235,33 @@ Subprocess output now keeps point at the end of the 
buffer in each
 window individually if point was already at the end of the buffer in
 that window.
 
-If `comint-scroll-show-maximum-output' is non-nil (which is the
+If 'comint-scroll-show-maximum-output' is non-nil (which is the
 default), then scrolling due to arrival of output tries to place the
 last line of text at the bottom line of the window, so as to show as
 much useful text as possible.  (This mimics the scrolling behavior of
 many terminals.)
 
-By setting `comint-scroll-to-bottom-on-output', you can opt for having
+By setting 'comint-scroll-to-bottom-on-output', you can opt for having
 point jump to the end of the buffer whenever output arrives--no matter
-where in the buffer point was before.  If the value is `this', point
-jumps in the selected window.  If the value is `all', point jumps in
-each window that shows the comint buffer.  If the value is `other',
+where in the buffer point was before.  If the value is 'this', point
+jumps in the selected window.  If the value is 'all', point jumps in
+each window that shows the comint buffer.  If the value is 'other',
 point jumps in all nonselected windows that show the current buffer.
 The default value is nil, which means point does not jump to the end.
 
 Input history insertion is configurable.  A variable controls whether only the
 first instance of successive identical inputs is stored in the input history.
-This is `comint-input-ignoredups'.
+This is 'comint-input-ignoredups'.
 
 Completion (bound to TAB) is now more general.  Depending on context,
 completion now operates on the input history, on command names, or (as
 before) on filenames.
 
 Filename completion is configurable.  Variables control whether
-file/directory suffix characters are added (`comint-completion-addsuffix'),
+file/directory suffix characters are added ('comint-completion-addsuffix'),
 whether shortest completion is acceptable when no further unambiguous
-completion is possible (`comint-completion-recexact'), and the timing of
-completion candidate listing (`comint-completion-autolist').
+completion is possible ('comint-completion-recexact'), and the timing of
+completion candidate listing ('comint-completion-autolist').
 
 Comint mode now provides history expansion.  Insert input using `!'
 and `^', in the same syntax that typical shells use; then type TAB.
@@ -4264,12 +4271,12 @@ comint buffer in place of the original input.
 
 History references in the input may be expanded before insertion into
 the input ring, or on input to the interpreter (and therefore
-visibly).  The variable `comint-input-autoexpand' specifies which.
+visibly).  The variable 'comint-input-autoexpand' specifies which.
 
 You can make the SPC key perform history expansion by binding
-SPC to the command `comint-magic-space'.
+SPC to the command 'comint-magic-space'.
 
-The command `comint-dynamic-complete-variable' does variable name
+The command 'comint-dynamic-complete-variable' does variable name
 completion using the environment variables as set within Emacs.  The
 variables controlling filename completion apply to variable name
 completion too.  This command is normally available through the menu
@@ -4283,54 +4290,54 @@ on output groups (i.e., shell prompt plus associated 
shell output).
 TAB now completes commands, as well as file names and expand history.
 Commands are searched for along the path that Emacs has on startup.
 
-C-c C-f now moves forward a command (`shell-forward-command') and
-C-c C-b now moves backward a command (`shell-backward-command').
+C-c C-f now moves forward a command ('shell-forward-command') and
+C-c C-b now moves backward a command ('shell-backward-command').
 
 Command completion is configurable.  The variables controlling
 filename completion in comint mode apply, together with a variable
 controlling whether to restrict possible completions to only files
-that are executable (`shell-command-execonly').
+that are executable ('shell-command-execonly').
 
 The input history is initialized from the file name given in the
-variable `shell-input-ring-file-name'--normally `.history' in your
+variable 'shell-input-ring-file-name'--normally `.history' in your
 home directory.
 
 Directory tracking is more robust.  It can cope with command sequences
 and forked commands, and can detect the failure of directory changing
 commands in most circumstances.  It's still not infallible, of course.
 
-You can now configure the behavior of `pushd'.  Variables control
-whether `pushd' behaves like `cd' if no argument is given
-(`shell-pushd-tohome'), pop rather than rotate with a numeric argument
-(`shell-pushd-dextract'), and only add directories to the directory
-stack if they are not already on it (`shell-pushd-dunique').  The
+You can now configure the behavior of 'pushd'.  Variables control
+whether 'pushd' behaves like 'cd' if no argument is given
+('shell-pushd-tohome'), pop rather than rotate with a numeric argument
+('shell-pushd-dextract'), and only add directories to the directory
+stack if they are not already on it ('shell-pushd-dunique').  The
 configuration you choose should match the underlying shell, of course.
 
 
 * Emacs Lisp programming changes in Emacs 19.20.
 
-** A new function `remove-hook' is now used to remove a hook that you might
-have added with `add-hook'.
+** A new function 'remove-hook' is now used to remove a hook that you might
+have added with 'add-hook'.
 
-** There is now a Lisp pretty-printer in the library `pp'.
+** There is now a Lisp pretty-printer in the library 'pp'.
 
 ** The partial Common Lisp support has been entirely reimplemented.
 
-** When you insert text using `insert', `insert-before-markers' or
-`insert-buffer-substring', text properties are no longer inherited
+** When you insert text using 'insert', 'insert-before-markers' or
+'insert-buffer-substring', text properties are no longer inherited
 from the surrounding text.
 
 When you want to inherit text properties, use the new functions
-`insert-and-inherit' or `insert-before-markers-and-inherit'.
+'insert-and-inherit' or 'insert-before-markers-and-inherit'.
 
 The self-inserting character command does do inheritance.
 
 ** Frame creation hooks.
 
-The function make-frame now runs the normal hooks
-before-make-frame-hook and after-make-frame-hook.
+The function 'make-frame' now runs the normal hooks
+'before-make-frame-hook' and 'after-make-frame-hook'.
 
-** You can now use function-key-map to make a key an alias for other
+** You can now use 'function-key-map' to make a key an alias for other
 key sequences that can vary depending on circumstances.  To do this,
 give the key a definition in function-key-map which is a function
 rather than a specific expansion key sequence.
@@ -4339,22 +4346,22 @@ If the function reads input itself, it can have the 
effect of altering
 the event that follows.  For example, here's how to define C-c h to
 turn the character that follows into a hyper character:
 
-(define-key function-key-map "\C-ch" 'hyperify)
+    (define-key function-key-map "\C-ch" 'hyperify)
 
-(defun hyperify (prompt)
-  (let ((e (read-event)))
-    (vector (if (numberp e)
-               (logior (ash 1 20) e)
-             (if (memq 'hyper (event-modifiers e))
-                 e
-               (add-event-modifier "H-" e))))))
+    (defun hyperify (prompt)
+      (let ((e (read-event)))
+        (vector (if (numberp e)
+                    (logior (ash 1 20) e)
+                  (if (memq 'hyper (event-modifiers e))
+                      e
+                    (add-event-modifier "H-" e))))))
 
-(defun add-event-modifier (string e)
-  (let ((symbol (if (symbolp e) e (car e))))
-    (setq symbol (intern (concat string (symbol-name symbol))))
-    (if (symbolp e)
-       symbol
-      (cons symbol (cdr e)))))
+    (defun add-event-modifier (string e)
+      (let ((symbol (if (symbolp e) e (car e))))
+        (setq symbol (intern (concat string (symbol-name symbol))))
+        (if (symbolp e)
+            symbol
+          (cons symbol (cdr e)))))
 
 The character translation function gets one argument, which is the
 prompt that was specified in read-key-sequence--or nil if the key
@@ -4367,8 +4374,8 @@ New low-level Lisp features make it possible to write 
Lisp programs to
 save text properties in files, and read text properties from files.
 You can program any file format you like.
 
-The variable `write-region-annotation-functions' should contain a list
-of functions to be run by `write-region' to encode text properties in
+The variable 'write-region-annotation-functions' should contain a list
+of functions to be run by 'write-region' to encode text properties in
 some fashion as annotations to the text that is written.
 
 Each function in the list is called with two arguments: the start and
@@ -4384,13 +4391,13 @@ add there.
 
 Each list returned by one of these functions must be already sorted in
 increasing order by POSITION.  If there is more than one function,
-`write-region' merges the lists destructively into one sorted list.
+'write-region' merges the lists destructively into one sorted list.
 
-When `write-region' actually writes the text from the buffer to the
+When 'write-region' actually writes the text from the buffer to the
 file, it intermixes the specified annotations at the corresponding
 positions.  All this takes place without modifying the buffer.
 
-The variable `after-insert-file-functions' should contain a list of
+The variable 'after-insert-file-functions' should contain a list of
 functions to be run each time a file's contents have been inserted into
 a buffer.  Each function receives one argument, the length of the
 inserted text; point indicates the start of that text.  The function
@@ -4400,7 +4407,7 @@ value returned by one function is used as the argument to 
the next.
 These functions should always return with point at the beginning of
 the inserted text.
 
-The intended use of `after-insert-file-functions' is for converting
+The intended use of 'after-insert-file-functions' is for converting
 some sort of textual annotations into actual text properties.  But many
 other uses may be possible.
 
@@ -4453,16 +4460,16 @@ mode might want to set this to '("." "(" ")") or some 
such.
 
 ** Comint output hook.
 
-There is now a hook, comint-output-filter-hook, that is run-hooks'ed by the
-output filter, comint-output-filter.  This is useful for scrolling (see
+There is now a hook, 'comint-output-filter-hook', that is run by the
+output filter, 'comint-output-filter'.  This is useful for scrolling (see
 below), but also things like processing output for specific text, output
 highlighting, etc.
 
 So that such output processing may be done efficiently, there is a new
-variable, comint-last-output-start, that records the position of the start of
+variable, 'comint-last-output-start', that records the position of the start of
 the last output inserted into the buffer (effectively the previous value
 of process-mark).  Output processing functions should process the text
-between comint-last-output-start (or perhaps the beginning of the line that
+between 'comint-last-output-start' (or perhaps the beginning of the line that
 the position lies on) and process-mark.
 
 ** Comint scrolling.
@@ -4478,8 +4485,8 @@ possible.  But, then again, there is a 
comint-show-maximum-output command.
 
 The input following point is not deleted when moving around the input history
 (with M-p etc.).  Emacs maintainers may not like this.  However, I feel this
-is a useful feature.  The simple remedy is to put end-of-line in before
-delete-region in comint-previous-matching-input.
+is a useful feature.  The simple remedy is to put 'end-of-line' in before
+'delete-region' in 'comint-previous-matching-input'.
 
 The input history retrieval commands still wrap-around the input ring, unlike
 Emacs command history.
@@ -4495,23 +4502,23 @@ sessions.
 ** Another simpler package saveplace.el records your position in each
 file when you kill its buffer (or kill Emacs), and jumps to the same
 position when you visit the file again (even in another Emacs
-session).  Use `toggle-save-place' to turn on place-saving in a given file;
+session).  Use 'toggle-save-place' to turn on place-saving in a given file;
 use (setq-default save-place t) to turn it on for all files.
 
 ** In Outline mode, you can now customize how to compute the level of a
-heading line.  Set `outline-level' to a function of no arguments which
+heading line.  Set 'outline-level' to a function of no arguments which
 returns the level, assuming point is at the beginning of a heading
 line.
 
 ** You can now specify the prefix key to use for Outline minor mode.
-(The default is C-c.)  Set the variable outline-minor-mode-prefix to
+(The default is C-c.)  Set the variable 'outline-minor-mode-prefix' to
 the key sequence you want to use (as a string or vector).
 
 ** In Bibtex mode, C-c e has been changed to C-c C-b.  This is because
 C-c followed by a letter is reserved for users.
 
-** The `mod' function is no longer an alias for `%', but is a separate function
-that yields a result with the same sign as the divisor.  `floor' now takes an
+** The 'mod' function is no longer an alias for `%', but is a separate function
+that yields a result with the same sign as the divisor.  'floor' now takes an
 optional second argument, which divides the first argument before the floor is
 taken.
 
@@ -4542,7 +4549,7 @@ does for windows.
 command history.
 
 ** If the directory containing the Emacs executable has a sibling named
-`lisp', that `lisp' directory is added to the end of `load-path'
+'lisp', that 'lisp' directory is added to the end of 'load-path'
 (provided you don't override the normal value with the EMACSLOADPATH
 environment variable).  This feature may make it easier to move
 an installed Emacs from place to place.
@@ -4568,9 +4575,9 @@ COMPATIBLE with the old (version 18) format.  See the 
documentation of
 the variable calendar-holidays for details of the new, improved
 format.
 
-The hook `diary-display-hook' has been split into two:
+The hook 'diary-display-hook' has been split into two:
 diary-display-hook which should be used ONLY for the display and
-`diary-hook' which should be used for appointment notification.  If
+'diary-hook' which should be used for appointment notification.  If
 diary-display-hook is nil (the default), simple-diary-display is
 used.  This allows the diary hooks to be correctly set with add-hook.
 
@@ -4592,23 +4599,23 @@ events, which are then discarded if not defined.  
Triple events that
 are not defined convert to the corresponding double event; if that is
 also not defined, it may convert further.
 
-** The new function event-click-count returns the number of clicks,
+** The new function 'event-click-count' returns the number of clicks,
 from an event which is a list.  It is 1 for an ordinary click, drag,
 or button-down event, 2 for a double event, and 3 or more for a triple
 event.
 
-** The new function previous-frame is like next-frame, but moves
+** The new function 'previous-frame' is like 'next-frame', but moves
 around through the set of existing frames in the opposite order.
 
-** The post-command-hook now runs even after commands that get an error
+** The 'post-command-hook' now runs even after commands that get an error
 and return to top level.  As a consequence of the same change, this
 hook also runs before Emacs reads the first command.  That might sound
-paradoxical, as if this hook were the same as the pre-command-hook.
+paradoxical, as if this hook were the same as the 'pre-command-hook'.
 Actually, they are not similar; the latter runs before *execution* of
 a command, but after it has been read.
 
 ** You can turn off the text property hooks that run when point moves
-to certain places in the buffer, by binding inhibit-point-motion-hooks
+to certain places in the buffer, by binding 'inhibit-point-motion-hooks'
 to a non-nil value.
 
 ** Inserting a string with no text properties into the buffer normally
@@ -4642,7 +4649,7 @@ rear-sticky for the property, and the property is 
non-nil, it
 dominates.  Otherwise, the following character's property value is
 used if it is front-sticky for that property.
 
-** If you give a character a non-nil `invisible' text property, the
+** If you give a character a non-nil 'invisible' text property, the
 character does not appear on the screen.  This works much like
 selective display.
 
@@ -4652,12 +4659,12 @@ versions.
 ** In Info, when you go to a node, it runs the normal hook
 Info-selection-hook.
 
-** You can use the new function `invocation-directory' to get the name
+** You can use the new function 'invocation-directory' to get the name
 of the directory containing the Emacs executable that was run.
 
-** Entry to the minibuffer runs the normal hook minibuffer-setup-hook.
+** Entry to the minibuffer runs the normal hook 'minibuffer-setup-hook'.
 
-** The new function minibuffer-window-active-p takes one argument, a
+** The new function 'minibuffer-window-active-p' takes one argument, a
 minibuffer window, and returns t if the window is currently active.
 
 
@@ -4668,7 +4675,7 @@ minibuffer window, and returns t if the window is 
currently active.
 you can select a completion by clicking mouse button 2
 on that completion.
 
-** Use the command `list-faces-display' to display a list of
+** Use the command 'list-faces-display' to display a list of
 all the currently defined faces, showing what they look like.
 
 ** Menu bar items from local maps now come after the usual items.
@@ -4690,9 +4697,9 @@ suitable menu bar items to other major modes.
 ** The key binding C-x a C-h has been eliminated.
 This is because it got in the way of the general feature of typing
 C-h after a prefix character.  If you want to run
-inverse-add-global-abbrev, you can use C-x a - or C-x a i g instead.
+'inverse-add-global-abbrev', you can use C-x a - or C-x a i g instead.
 
-** If you set the variable `rmail-mail-new-frame' to a non-nil value,
+** If you set the variable 'rmail-mail-new-frame' to a non-nil value,
 all the Rmail commands to send mail make a new frame to do it in.
 When you send the message, or use the menu bar command not to send it,
 that frame is deleted.
@@ -4703,43 +4710,43 @@ the message to it in Rmail format if it is an Rmail 
file, and in
 inbox file format otherwise.  C-o and o are different only when you
 specify a new file.
 
-** The function `copy-face' now takes an optional fourth argument
+** The function 'copy-face' now takes an optional fourth argument
 NEW-FRAME.  If you specify this, it copies the definition of face
 OLD-FACE on frame FRAME to face NEW-NAME on frame NEW-FRAME.
 
 ** A local map can now cancel out one of the global map's menu items.
-Just define that subcommand of the menu item with `undefined'
-as the definition.  For example, this cancels out the `Buffers' item
+Just define that subcommand of the menu item with 'undefined'
+as the definition.  For example, this cancels out the 'Buffers' item
 for the current major mode:
 
     (local-set-key [menu-bar buffer] 'undefined)
 
 ** To put global items at the end of the menu bar, use the new variable
-`menu-bar-final-items'.  It should be a list of symbols--event types
+'menu-bar-final-items'.  It should be a list of symbols--event types
 bound in the menu bar.  The menu bar items for these symbols are
 moved to the end.
 
-** The list returned by `buffer-local-variables' now contains cons-cell
+** The list returned by 'buffer-local-variables' now contains cons-cell
 elements of the form (SYMBOL . VALUE) only for buffer-local variables
 that have values.  For unbound buffer-local variables, the variable
 name (symbol) appears directly as an element of the list.
 
-** The `modification-hooks' property of a character no longer affects
+** The 'modification-hooks' property of a character no longer affects
 insertion; it runs only for deletion and modification of the character.
 
-To detect insertion, use `insert-in-front-hooks' and
-`insert-behind-hooks' properties.  The former runs when text is
+To detect insertion, use 'insert-in-front-hooks' and
+'insert-behind-hooks' properties.  The former runs when text is
 inserted immediately preceding the character that has the property;
 the latter runs when text is inserted immediately following the
 character.
 
 ** Buffer modification now runs hooks belonging to overlays as well as
 hooks belonging to characters.  If an overlay has a
-`modification-hooks' property, it applies to any change to text in the
+'modification-hooks' property, it applies to any change to text in the
 overlay, and any insertion within the overlay.  If the overlay has a
-`insert-in-front-hooks' property, it runs for insertion at the
+'insert-in-front-hooks' property, it runs for insertion at the
 beginning boundary of the overlay.  If the overlay has an
-`insert-behind-hooks' property, it runs for insertion at the end
+'insert-behind-hooks' property, it runs for insertion at the end
 boundary of the overlay.
 
 The values of these properties should be lists of functions.  Each
@@ -4747,7 +4754,7 @@ function is called, receiving as arguments the overlay in 
question,
 followed by the bounds of the range being modified.
 
 ** The new `-name NAME' option directs Emacs to search for its X
-resources using the name `NAME', and sets the title of the initial
+resources using the name 'NAME', and sets the title of the initial
 frame.  This argument was added for consistency with other X clients.
 
 ** The new `-xrm DATABASE' option tells Emacs to treat the string
@@ -4786,7 +4793,7 @@ Emacs searches for X resources
 
 The paths in the variables XFILESEARCHPATH, XUSERFILESEARCHPATH, and
 XAPPLRESDIR may contain %-escapes (like the control strings passed to
-the Emacs lisp `format' function or C printf function), which Emacs expands.
+the Emacs lisp 'format' function or C printf function), which Emacs expands.
 
 %N is replaced by the string "Emacs" wherever it occurs.
 %T is replaced by "app-defaults" wherever it occurs.
@@ -4823,29 +4830,29 @@ If XFILESEARCHPATH is unset, Emacs uses the default 
value
 
 This feature was added for consistency with other X applications.
 
-** The new function `text-property-any' scans the region of text from
-START to END to see if any character's property PROP is `eq' to
+** The new function 'text-property-any' scans the region of text from
+START to END to see if any character's property PROP is 'eq' to
 VALUE.  If so, it returns the position of the first such character.
 Otherwise, it returns nil.
 
 The optional fifth argument, OBJECT, specifies the string or buffer to
 be examined.
 
-** The new function `text-property-not-all' scans the region of text from
-START to END to see if any character's property PROP is not `eq' to
+** The new function 'text-property-not-all' scans the region of text from
+START to END to see if any character's property PROP is not 'eq' to
 VALUE.  If so, it returns the position of the first such character.
 Otherwise, it returns nil.
 
 The optional fifth argument, OBJECT, specifies the string or buffer to
 be examined.
 
-** The function `delete-windows-on' now takes an optional second
+** The function 'delete-windows-on' now takes an optional second
 argument FRAME, which specifies which frames it should affect.
-  + If FRAME is nil or omitted, then `delete-windows-on' deletes windows
+  + If FRAME is nil or omitted, then 'delete-windows-on' deletes windows
     showing BUFFER (its first argument) on all frames.
-  + If FRAME is t, then `delete-windows-on' only deletes windows on the
+  + If FRAME is t, then 'delete-windows-on' only deletes windows on the
     selected frame; other frames are unaffected.
-  + If FRAME is a frame, then `delete-windows-on' only deletes windows on
+  + If FRAME is a frame, then 'delete-windows-on' only deletes windows on
     the given frame; other frames are unaffected.
 
 
@@ -4858,21 +4865,21 @@ continue the drag beyond the boundaries of the window, 
Emacs scrolls
 the window at a steady rate until you either move the mouse back into
 the window or release the button.
 
-** RET now exits `query-replace' and `query-replace-regexp'; this makes it
+** RET now exits 'query-replace' and 'query-replace-regexp'; this makes it
 more consistent with the incremental search facility, which uses RET
 to end the search.
 
 ** In C mode, C-c C-u now runs c-up-conditional.
 C-c C-n and C-c C-p now run new commands that move forward
-and back over balanced sets of C conditionals (c-forward-conditional
-and c-backward-conditional).
+and back over balanced sets of C conditionals ('c-forward-conditional'
+and 'c-backward-conditional').
 
 ** The Edit entry in the menu bar has a new alternative:
 "Choose Next Paste".  It gives you a menu showing the various
 strings in the kill ring; click on one to select it as the text
 to be yanked ("pasted") the next time you yank.
 
-** If you enable Transient Mark mode and set `mark-even-if-inactive' to
+** If you enable Transient Mark mode and set 'mark-even-if-inactive' to
 non-nil, then the region is highlighted in a transient fashion just as
 normally in Transient Mark mode, but the mark really remains active
 all the time; commands that use the region can be used even if the
@@ -4882,33 +4889,33 @@ region highlighting turns off.
 that start with that prefix.
 
 ** The VC package now searches for version control commands in the
-directories named by the variable `vc-path'; its value should be a
+directories named by the variable 'vc-path'; its value should be a
 list of strings.
 
 ** If you are visiting a file that has locks registered under RCS,
 VC now displays each lock's owner and version number in the mode line
-after the string `RCS'.  If there are no locks, VC displays the head
+after the string 'RCS'.  If there are no locks, VC displays the head
 version number.
 
-** When using X, if you load the `paren' library, Emacs automatically
+** When using X, if you load the 'paren' library, Emacs automatically
 underlines or highlights the matching paren whenever point is
 next to the outside of a paren.  When point is before an open-paren,
 this shows the matching close; when point is after a close-paren,
 this shows the matching open.
 
-** The new function `define-key-after' is like `define-key',
+** The new function 'define-key-after' is like 'define-key',
 but takes an extra argument AFTER.  It places the newly defined
 binding after the binding for the event AFTER.
 
-** `accessible-keymaps' now takes an optional second argument, PREFIX.
+** 'accessible-keymaps' now takes an optional second argument, PREFIX.
 If PREFIX is non-nil, it means the value should include only maps for
 keys that start with PREFIX.
 
-`describe-bindings' also accepts an optional argument PREFIX which
+'describe-bindings' also accepts an optional argument PREFIX which
 means to describe only the keys that start with PREFIX.
 
-** The variable `prefix-help-command' hold a command to run to display help
-whenever the character `help-char' follows a prefix key and does not have
+** The variable 'prefix-help-command' hold a command to run to display help
+whenever the character 'help-char' follows a prefix key and does not have
 a key binding in that context.
 
 ** Emacs now detects double- and triple-mouse clicks.  A single mouse
@@ -4928,18 +4935,18 @@ their timestamps.
 To count as double- and triple-clicks, mouse clicks must be at the
 same location as the first click, and the number of milliseconds
 between the first release and the second must be less than the value
-of the lisp variable `double-click-time'.  Setting `double-click-time'
+of the lisp variable 'double-click-time'.  Setting 'double-click-time'
 to nil disables multi-click detection.  Setting it to t removes the
 time limit; Emacs then detects multi-clicks by position only.
 
-If `read-key-sequence' finds no binding for a double-click event, but
+If 'read-key-sequence' finds no binding for a double-click event, but
 the corresponding single-click event would be bound,
-`read-key-sequence' demotes it to a single-click.  Similarly, it
+'read-key-sequence' demotes it to a single-click.  Similarly, it
 demotes unbound triple-clicks to double- or single-clicks.  This means
 you don't have to distinguish between single- and multi-clicks if you
 don't want to.
 
-Emacs reports all clicks after the third as `triple-mouse-N' clicks,
+Emacs reports all clicks after the third as 'triple-mouse-N' clicks,
 but increments the click count after POSITION.  For example, a fourth
 click, soon after the third and at the same location, produces a pair
 of events of the form:
@@ -4952,25 +4959,25 @@ slightly.  If a mouse event includes a position list of 
the form:
 this denotes exactly the same position as the list:
        (WINDOW  PLACE-SYMBOL  (COLUMN . ROW) TIMESTAMP)
 That is, the event occurred over a non-textual area of the frame,
-specified by PLACE-SYMBOL, a symbol like `mode-line' or
-`vertical-scroll-bar'.
+specified by PLACE-SYMBOL, a symbol like 'mode-line' or
+'vertical-scroll-bar'.
 
 Enclosing PLACE-SYMBOL in a singleton list does not change the
-position denoted, but the `read-key-sequence' function uses the
+position denoted, but the 'read-key-sequence' function uses the
 presence or absence of the singleton list to tell whether or not it
 should prefix the event with its place symbol.
 
-Normally, `read-key-sequence' prefixes mouse events occurring over
+Normally, 'read-key-sequence' prefixes mouse events occurring over
 non-textual areas with their PLACE-SYMBOLs, to select the sub-keymap
 appropriate for the event; for example, clicking on the mode line
 produces a sequence like
        [mode-line (mouse-1 POSN)]
 However, if lisp code elects to unread the resulting key sequence by
-placing it in the `unread-command-events' variable, it is important
-that `read-key-sequence' not insert the prefix symbol again; that
+placing it in the 'unread-command-events' variable, it is important
+that 'read-key-sequence' not insert the prefix symbol again; that
 would produce a malformed key sequence like
        [mode-line mode-line (mouse-1 POSN)]
-For this reason, `read-key-sequence' encloses the event's PLACE-SYMBOL
+For this reason, 'read-key-sequence' encloses the event's PLACE-SYMBOL
 in a singleton list when it first inserts the prefix, but doesn't
 insert the prefix when processing events whose PLACE-SYMBOLs are
 already thus enclosed.
@@ -4979,7 +4986,7 @@ already thus enclosed.
 
 * Changes in version 19.15.
 
-** `make-frame-visible', which uniconified frames, is now a command,
+** 'make-frame-visible', which uniconified frames, is now a command,
 and thus may be bound to a key.  This makes sense because frames
 respond to user input while iconified.
 
@@ -4998,11 +5005,11 @@ at the other end.
 
 Emacs has only one secondary selection at any time.  Starting to set
 a new one cancels any previous one.  The secondary selection displays
-using a face named `secondary-selection'.
+using a face named 'secondary-selection'.
 
-** There's a new way to request use of Supercite (sc.el).  Do this:
+** New hook 'mail-citation-hook'.  E.g. to request use of Supercite (sc.el):
 
-    (add-hook 'mail-citation-hook 'sc-cite-original)
+    (add-hook 'mail-citation-hook #'sc-cite-original)
 
 Currently this works with Rmail.  In the future, other Emacs based
 mail-readers should be modified to understand this hook also.
@@ -5011,7 +5018,7 @@ for those other mail readers.
 
 ** When a regular expression contains `\(...\)' inside a repetition
 operator such as `*' or `+', and you ask about the range that was matched
-using `match-beginning' and `match-end', the range you get corresponds
+using 'match-beginning' and 'match-end', the range you get corresponds
 to the *last* repetition *only*.  In Emacs 18, you would get a range
 corresponding to all the repetitions.
 
@@ -5027,18 +5034,18 @@ and thus didn't document it.)
 
 * Changes in version 19.14.
 
-** To modify read-only text, bind the variable `inhibit-read-only'
+** To modify read-only text, bind the variable 'inhibit-read-only'
 to a non-nil value.  If the value is t, then all reasons that might
-make text read-only are inhibited (including `read-only' text properties).
-If the value is a list, then a `read-only' property is inhibited
-if it is `memq' in the list.
+make text read-only are inhibited (including 'read-only' text properties).
+If the value is a list, then a 'read-only' property is inhibited
+if it is 'memq' in the list.
 
-** If you call `get-buffer-window' passing t as its second argument, it
+** If you call 'get-buffer-window' passing t as its second argument, it
 will only search for windows on visible frames.  Previously, passing t
-as the second argument caused `get-buffer-window' to search all
+as the second argument caused 'get-buffer-window' to search all
 frames, visible or not.
 
-** If you call `other-buffer' with a nil or omitted second argument, it
+** If you call 'other-buffer' with a nil or omitted second argument, it
 will ignore buffers displayed windows on any visible frame, not just
 the selected frame.
 
@@ -5048,22 +5055,22 @@ to the window or frame that you want.
 
 ** The command M-( now inserts spaces outside the open-parentheses in
 some cases--depending on the syntax classes of the surrounding
-characters.  If the variable `parens-dont-require-spaces' is non-nil,
+characters.  If the variable 'parens-dont-require-spaces' is non-nil,
 it inhibits insertion of these spaces.
 
 ** The GUD package now supports the debugger known as xdb on HP/UX
-systems.  Use M-x xdb.  The variable `gud-xdb-directories' lets you
+systems.  Use M-x xdb.  The variable 'gud-xdb-directories' lets you
 specify a list of directories to search for source code.
 
 ** If you are using the mailabbrev package, you should note that its
-function for defining an alias is now called `define-mail-abbrev'.
-This package no longer contains a definition for `define-mail-alias';
+function for defining an alias is now called 'define-mail-abbrev'.
+This package no longer contains a definition for 'define-mail-alias';
 that name is used only in mailaliases.
 
 ** Inserted characters now inherit the properties of the text before
 them, by default, rather than those of the following text.
 
-** The function `insert-file-contents' now takes optional arguments BEG
+** The function 'insert-file-contents' now takes optional arguments BEG
 and END that specify which part of the file to insert.  BEG defaults to
 0 (the beginning of the file), and END defaults to the end of the file.
 
@@ -5073,7 +5080,7 @@ If you specify BEG or END, then the argument VISIT must 
be nil.
 
 * Changes in version 19.13.
 
-** Magic file names can now handle the `load' operation.
+** Magic file names can now handle the 'load' operation.
 
 ** Bibtex mode now sets up special entries in the menu bar.
 
@@ -5094,7 +5101,7 @@ We may move them again for greater consistency with other 
modes.
 * Changes in version 19.12.
 
 ** You can now make many of the sort commands ignore case by setting
-`sort-fold-case' to a non-nil value.
+'sort-fold-case' to a non-nil value.
 
 
 
@@ -5102,15 +5109,15 @@ We may move them again for greater consistency with 
other modes.
 
 ** Supercite is installed.
 
-** `write-file-hooks' functions that return non-nil are responsible
+** 'write-file-hooks' functions that return non-nil are responsible
 for making a backup file if you want that to be done.
 To do so, execute the following code:
 
    (or buffer-backed-up (backup-buffer))
 
 You might wish to save the file modes value returned by
-`backup-buffer' and use that to set the mode bits of the file
-that you write.  This is what `basic-save-buffer' does when
+'backup-buffer' and use that to set the mode bits of the file
+that you write.  This is what 'basic-save-buffer' does when
 it writes a file in the usual way.
 
 (This is not actually new, but wasn't documented before.)
@@ -5119,12 +5126,12 @@ it writes a file in the usual way.
 
 * Changes in version 19.10.
 
-** The command `repeat-complex-command' is now on C-x ESC ESC.
+** The command 'repeat-complex-command' is now on C-x ESC ESC.
 It used to be bound to C-x ESC.
 
 The reason for this change is to make function keys work after C-x.
 
-** The variable `highlight-nonselected-windows' now controls whether
+** The variable 'highlight-nonselected-windows' now controls whether
 the region is highlighted in windows other than the selected window
 (in Transient Mark mode only, of course, and currently only when
 using X).
@@ -5139,26 +5146,26 @@ buffer text according to the ISO Latin-1 standard.  
With a prefix
 argument, this command enables European character display if and only
 if the argument is positive.
 
-** The `-i' command-line argument tells Emacs to use a picture of the
+** The '-i' command-line argument tells Emacs to use a picture of the
 GNU gnu as its icon, instead of letting the window manager choose an
 icon for it.  This option used to insert a file into the current
-buffer; use `-insert' to do that now.
+buffer; use '-insert' to do that now.
 
-** The `configure' script now supports `--prefix' and `--exec-prefix'
+** The 'configure' script now supports '--prefix' and '--exec-prefix'
 options.
 
-The `--prefix=PREFIXDIR' option specifies where the installation process
+The '--prefix=PREFIXDIR' option specifies where the installation process
 should put emacs and its data files.  This defaults to `/usr/local'.
 - Emacs (and the other utilities users run) go in PREFIXDIR/bin
-  (unless the `--exec-prefix' option says otherwise).
+  (unless the '--exec-prefix' option says otherwise).
 - The architecture-independent files go in PREFIXDIR/lib/emacs/VERSION
   (where VERSION is the version number of Emacs, like `19.7').
 - The architecture-dependent files go in
   PREFIXDIR/lib/emacs/VERSION/CONFIGURATION
   (where CONFIGURATION is the configuration name, like mips-dec-ultrix4.2),
-  unless the `--exec-prefix' option says otherwise.
+  unless the '--exec-prefix' option says otherwise.
 
-The `--exec-prefix=EXECDIR' option allows you to specify a separate
+The '--exec-prefix=EXECDIR' option allows you to specify a separate
 portion of the directory tree for installing architecture-specific
 files, like executables and utility programs.  If specified,
 - Emacs (and the other utilities users run) go in EXECDIR/bin, and
@@ -5166,14 +5173,14 @@ files, like executables and utility programs.  If 
specified,
   EXECDIR/lib/emacs/VERSION/CONFIGURATION.
 EXECDIR/bin should be a directory that is normally in users' PATHs.
 
-** When running under X, the new lisp function `x-list-fonts'
+** When running under X, the new lisp function 'x-list-fonts'
 allows code to find out which fonts are available from the X server.
 The first argument PATTERN is a string, perhaps with wildcard characters;
   the * character matches any substring, and
   the ? character matches any single character.
   PATTERN is case-insensitive.
 If the optional arguments FACE and FRAME are specified, then
-`x-list-fonts' returns only fonts the same size as FACE on FRAME.
+'x-list-fonts' returns only fonts the same size as FACE on FRAME.
 
 
 
@@ -5188,7 +5195,7 @@ their sizes, or reused by other processes if Emacs 
doesn't need it.
 for input, which often avoids the need to do these things while you
 are typing.
 
-The variable `auto-save-timeout' says how many seconds Emacs should
+The variable 'auto-save-timeout' says how many seconds Emacs should
 wait, after you stop typing, before it does an auto save and a garbage
 collection.
 
@@ -5200,12 +5207,12 @@ warning again.
 If you reenable Auto Save mode in that buffer, Emacs will start saving
 it again with no further warnings.
 
-** A new minor mode called Line Number mode displays the current line
+** A new minor mode called 'line-number-mode' displays the current line
 number in the mode line, updating it as necessary when you move
 point.
 
 However, if the buffer is very large (larger than the value of
-`line-number-display-limit'), then the line number doesn't appear.
+'line-number-display-limit'), then the line number doesn't appear.
 This is because computing the line number can be painfully slow if the
 buffer is very large.
 
@@ -5215,7 +5222,7 @@ buffer is very large.
 directions.
 
 ** You can suppress next-line's habit of inserting a newline when
-called at the end of a buffer by setting next-line-add-newlines to nil
+called at the end of a buffer by setting 'next-line-add-newlines' to nil
 (it defaults to t).
 
 ** You can now get back recent minibuffer inputs conveniently.  While
@@ -5233,8 +5240,8 @@ The history feature is available for all uses of the 
minibuffer, but
 there are separate history lists for different kinds of input.  For
 example, there is a list for file names, used by all the commands that
 read file names.  There is a list for arguments of commands like
-`query-replace'.  There are also very specific history lists, such
-as the one that `compile' uses for compilation commands.
+'query-replace'.  There are also very specific history lists, such
+as the one that 'compile' uses for compilation commands.
 
 ** You can now display text in a mixture of fonts and colors, using the
 "face" feature, together with the overlay and text property features.
@@ -5258,30 +5265,30 @@ C-x n is a prefix for narrowing.
 C-x a is a prefix for abbrev commands.
 
 C-x r C-SPC
-C-x r SPC      point-to-register    (Was C-x /)
-C-x r j                jump-to-register     (Was C-x j)
-C-x r s                copy-to-register     (Was C-x x)
-C-x r i                insert-register      (Was C-x g)
-C-x r r                copy-rectangle-to-register  (Was C-x r)
-C-x r k                kill-rectangle
-C-x r y                yank-rectangle
-C-x r o                open-rectangle
-C-x r f                frame-configuration-to-register
+C-x r SPC      'point-to-register'    (Was C-x /)
+C-x r j                'jump-to-register'     (Was C-x j)
+C-x r s                'copy-to-register'     (Was C-x x)
+C-x r i                'insert-register'      (Was C-x g)
+C-x r r                'copy-rectangle-to-register'  (Was C-x r)
+C-x r k                'kill-rectangle'
+C-x r y                'yank-rectangle'
+C-x r o                'open-rectangle'
+C-x r f                'frame-configuration-to-register'
                  (This saves the state of all windows in all frames.)
-C-x r w                window-configuration-to-register
+C-x r w                'window-configuration-to-register'
                  (This saves the state of all windows in the selected  frame.)
 
 (Use C-x r j to restore a configuration saved with C-x r f or C-x r w.)
 
-C-x n n                narrow-to-region        (Was C-x n)
-C-x n p                narrow-to-page          (Was C-x p)
-C-x n w                widen                   (Was C-x w)
+C-x n n                'narrow-to-region'      (Was C-x n)
+C-x n p                'narrow-to-page'        (Was C-x p)
+C-x n w                'widen'                 (Was C-x w)
 
-C-x a l                add-mode-abbrev         (Was C-x C-a)
-C-x a g                add-global-abbrev       (Was C-x +)
-C-x a i l      inverse-add-mode-abbrev (Was C-x C-h)
-C-x a i g      inverse-add-global-abbrev  (Was C-x -)
-C-x a e                expand-abbrev           (Was C-x ')
+C-x a l                'add-mode-abbrev'       (Was C-x C-a)
+C-x a g                'add-global-abbrev'     (Was C-x +)
+C-x a i l      'inverse-add-mode-abbrev'    (Was C-x C-h)
+C-x a i g      'inverse-add-global-abbrev'  (Was C-x -)
+C-x a e                'expand-abbrev'         (Was C-x ')
 
 (The old key bindings C-x /, C-x j, C-x x and C-x g
 have not yet been removed.)
@@ -5300,12 +5307,12 @@ but that you don't want to keep in buffers all the time.
 ** The keys M-g (fill-region) and C-x a (append-to-buffer)
 have been eliminated.
 
-** The new command `string-rectangle' inserts a specified string on
+** The new command 'string-rectangle' inserts a specified string on
 each line of the region-rectangle.
 
-** C-x 4 r is now `find-file-read-only-other-window'.
+** C-x 4 r is now 'find-file-read-only-other-window'.
 
-** C-x 4 C-o is now `display-buffer', which displays a specified buffer
+** C-x 4 C-o is now 'display-buffer', which displays a specified buffer
 in another window without selecting it.
 
 ** Picture mode has been substantially improved.  The picture editing commands
@@ -5330,17 +5337,17 @@ to enable and disable the new mode.
 M-x outline-mode is unchanged; it still switches to Outline mode as a
 major mode.
 
-** The default setting of `version-control' comes from the environment
+** The default setting of 'version-control' comes from the environment
 variable VERSION_CONTROL.
 
 ** The user option for controlling whether files can set local
-variables is now called `enable-local-variables'.  A value of t means
+variables is now called 'enable-local-variables'.  A value of t means
 local-variables lists are obeyed; nil means they are ignored; anything
 else means query the user.
 
-The user option for controlling use of the `eval' local variable is
-now called is `enable-local-eval'; its values are interpreted like
-those of `enable-local-variables'.
+The user option for controlling use of the 'eval' local variable is
+now called is 'enable-local-eval'; its values are interpreted like
+those of 'enable-local-variables'.
 
 ** X Window System changes:
 
@@ -5366,8 +5373,8 @@ one in the future.
 deletion.
 
 ** The variables that control how much undo information to save have
-been renamed to `undo-limit' and `undo-strong-limit'.  They used to be
-called `undo-threshold' and `undo-high-threshold'.
+been renamed to 'undo-limit' and 'undo-strong-limit'.  They used to be
+called 'undo-threshold' and 'undo-high-threshold'.
 
 ** You can now use kill commands in read-only buffers.  They don't
 actually change the buffer, and Emacs will beep and warn you that the
@@ -5378,7 +5385,7 @@ the kill ring, so you can yank it into other buffers.
 M-^ deletes the prefix (if it occurs) after the newline that it
 deletes.
 
-** C-M-l now runs the command `reposition-window'.  It scrolls the
+** C-M-l now runs the command 'reposition-window'.  It scrolls the
 window heuristically in a way designed to get useful information onto
 the screen.
 
@@ -5433,14 +5440,14 @@ subsequently.  You can no longer use M-, to find the 
next similar tag;
 you must use M-. with a prefix argument, instead.
 
 The motive for this change is so that you can more reliably use
-M-, to resume a suspended `tags-search' or `tags-query-replace'.
+M-, to resume a suspended 'tags-search' or 'tags-query-replace'.
 
-** C-x s (`save-some-buffers') now gives you more options when it asks
-whether to save a particular buffer.  In addition to `y' or `n', you
+** C-x s ('save-some-buffers') now gives you more options when it asks
+whether to save a particular buffer.  In addition to 'y' or 'n', you
 can answer `!' to save all the remaining buffers, `.' to save this
 buffer but not save any others, ESC to stop saving and exit the
 command, and C-h to get help.  These options are analogous to those
-of `query-replace'.
+of 'query-replace'.
 
 ** M-x make-symbolic-link does not expand its first argument.
 This lets you make a link with a target that is a relative file name.
@@ -5454,22 +5461,22 @@ makes filling work conveniently.  Each bunch of grouped 
entries is one
 paragraph, and each collection of entries from one person on one day
 is considered a page.
 
-** The `comment-region' command adds comment delimiters to the lines that
+** The 'comment-region' command adds comment delimiters to the lines that
 start in the region, thus commenting them out.  With a negative argument,
 it deletes comment delimiters from the lines in the region--this cancels
-the effect of `comment-region' without an argument.
+the effect of 'comment-region' without an argument.
 
-With a positive argument, `comment-region' adds comment delimiters
+With a positive argument, 'comment-region' adds comment delimiters
 but duplicates the last character of the comment start sequence as many
 times as the argument specifies.  This is a way of calling attention to
 the comment.  In Lisp, you should use an argument at least two, because
 the indentation convention for single semicolon comments does not leave
 them at the beginning of a line.
 
-** If `split-window-keep-point' is non-nil, C-x 2 tries to avoid
+** If 'split-window-keep-point' is non-nil, C-x 2 tries to avoid
 shifting any text on the screen by putting point in whichever window
 happens to contain the screen line the cursor is already on.
-The default is that `split-window-keep-point' is non-nil on slow
+The default is that 'split-window-keep-point' is non-nil on slow
 terminals.
 
 ** M-x super-apropos is like M-x apropos except that it searches both
@@ -5506,10 +5513,10 @@ compilation buffers, and any Emacs feature which 
creates a special
 buffer with a particular name.
 
 ** M-x compare-windows with a prefix argument ignores changes in whitespace.
-If `compare-ignore-case' is non-nil, then differences in case are also
+If 'compare-ignore-case' is non-nil, then differences in case are also
 ignored.
 
-** `backward-paragraph' is now bound to M-{ by default, and `forward-paragraph'
+** 'backward-paragraph' is now bound to M-{ by default, and 'forward-paragraph'
 to M-}.  Originally, these commands were bound to M-[ and M-], but they were
 running into conflicts with the use of function keys.  On many terminals,
 function keys send a sequence beginning ESC-[, so many users have defined this
@@ -5519,25 +5526,25 @@ as a prefix key.
 default; these commands seem to be often hit by accident, and can be
 quite destructive if their effects are not noticed immediately.
 
-** The function `erase-buffer' is now interactive, but disabled by default.
+** The function 'erase-buffer' is now interactive, but disabled by default.
 
 ** When visiting a new file, Emacs attempts to abbreviate the file's
-path using the symlinks listed in `directory-abbrev-alist'.
+path using the symlinks listed in 'directory-abbrev-alist'.
 
 ** When you visit the same file in under two names that translate into
 the same name once symbolic links are handled, Emacs warns you that
 you have two buffers for the same file.
 
 ** If you wish to avoid visiting the same file in two buffers under
-different names, set the variable `find-file-existing-other-name'
-non-nil.  Then `find-file' uses the existing buffer visiting the file,
+different names, set the variable 'find-file-existing-other-name'
+non-nil.  Then 'find-file' uses the existing buffer visiting the file,
 no matter which of the file's names you specify.
 
-** If you set `find-file-visit-truename' non-nil, then the file name
+** If you set 'find-file-visit-truename' non-nil, then the file name
 recorded for a buffer is the file's truename (in which all symbolic
 links have been removed), rather than the name you specify.  Setting
-`find-file-visit-truename' also implies the effect of
-`find-file-existing-other-name'.
+'find-file-visit-truename' also implies the effect of
+'find-file-existing-other-name'.
 
 ** C-x C-v now inserts the entire current file name in the minibuffer.
 This is convenient if you made a small mistake in typing it.  Point
@@ -5550,40 +5557,40 @@ it.
 ** C-x q now uses ESC to terminate all iterations of the keyboard
 macro, rather than C-d as before.
 
-** Use the command `setenv' to set an individual environment variable
+** Use the command 'setenv' to set an individual environment variable
 for Emacs subprocesses.  Specify a variable name and a value, both as
 strings.  This command applies only to subprocesses yet to be
 started.
 
-** Use `rot13-other-window' to examine a buffer with rot13.
+** Use 'rot13-other-window' to examine a buffer with rot13.
 
 This command does not change the text in the buffer.  Instead, it
 creates a window with a funny display table that applies the code when
 displaying the text.
 
 ** The command `M-x version' now prints the current Emacs version; The
-`version' command is an alias for the `emacs-version' command.
+'version' command is an alias for the 'emacs-version' command.
 
 ** More complex changes in existing packages.
 
-*** `fill-nonuniform-paragraphs' is a new command, much like
-`fill-individual-paragraphs' except that only separator lines separate
+*** 'fill-nonuniform-paragraphs' is a new command, much like
+'fill-individual-paragraphs' except that only separator lines separate
 paragraphs.  Since this means that the lines of one paragraph may have
 different amounts of indentation, the fill prefix used is the smallest
 amount of indentation of any of the lines of the paragraph.
 
-*** Filling is now partially controlled by a new minor mode, Adaptive
-Fill mode.  When this mode is enabled (and it is enabled by default),
-if you use M-x fill-region-as-paragraph on an indented paragraph and
-you don't have a fill prefix, it uses the indentation of the second
-line of the paragraph as the fill prefix.
+*** Filling is now partially controlled by a new minor mode,
+'adaptive-fill-mode'.  When this mode is enabled (and it is enabled
+by default), if you use M-x fill-region-as-paragraph on an indented
+paragraph and you don't have a fill prefix, it uses the indentation
+of the second line of the paragraph as the fill prefix.
 
 Adaptive Fill mode doesn't have much effect on M-q in most major
 modes, because an indented line will probably count as a paragraph
 starter and thus each line of an indented paragraph will be considered
 a paragraph of its own.
 
-*** M-q in C mode now runs `c-fill-paragraph', which is designed
+*** M-q in C mode now runs 'c-fill-paragraph', which is designed
 for filling C comments.  (We assume you don't want to fill
 the code in a C program.)
 
@@ -5610,7 +5617,7 @@ i Insert this word in your private dictionary
 r      Replace the word this time with a string typed by you.
 
 When the Ispell process starts, it reads your private dictionary which
-is the file `~/ispell.words'.  If you "insert" words with the `i' command,
+is the file `~/ispell.words'.  If you "insert" words with the 'i' command,
 these words are added to that file, but not right away--only at the end
 of the interactive replacement process.
 
@@ -5654,7 +5661,7 @@ superseding C-c C-y (copy-last-shell-input):
 The C-x C-a bindings are also active in source files.
 
 *** The old TeX mode bindings of M-{ and M-} have been moved to C-c {
-and C-c }.  (These commands are `up-list' and `tex-insert-braces';
+and C-c }.  (These commands are 'up-list' and 'tex-insert-braces';
 they are the TeX equivalents of M-( and M-).)  This is because M-{
 and M-} are now globally defined commands.
 
@@ -5662,22 +5669,22 @@ and M-} are now globally defined commands.
 
 `%' is now a word-separator character in Mail mode.
 
-`mail-signature', if non-nil, tells M-x mail to insert your
+'mail-signature', if non-nil, tells M-x mail to insert your
 `.signature' file automatically.  If you don't want your signature in
 a particular message, just delete it before you send the message.
 
 You can specify the text to insert at the beginning of each line when
 you use C-c C-y to yank the message you are replying to.  Set
-`mail-yank-prefix' to the desired string.  A value of `nil' (the
+'mail-yank-prefix' to the desired string.  A value of 'nil' (the
 default) means to use indentation, as in Emacs 18.  If you use just
 C-u as the prefix argument to C-c C-y, then it does not insert
 anything at the beginning of the lines, regardless of the value of
-`mail-yank-prefix'.
+'mail-yank-prefix'.
 
 If you like, you can expand mail aliases as abbrevs, as soon as you
 type them in.  To enable this feature, execute the following:
 
-    (add-hook 'mail-setup-hook 'mail-abbrevs-setup)
+    (add-hook 'mail-setup-hook #'mail-abbrevs-setup)
 
 This can go in your .emacs file.
 
@@ -5691,25 +5698,25 @@ Rmail by default gets new mail only from the system 
inbox file,
 not from `~/mbox'.
 
 In Rmail, you can retry sending a message that failed
-by typing `M-m' on the failure message.
+by typing 'M-m' on the failure message.
 
 By contrast, another new command M-x rmail-resend is used for
 forwarding a message and marking it as "resent from" you
 with header fields "Resent-From:" and "Resent-To:".
 
-`e' is now the command to edit a message.
-To expunge, type `x'.  We know this will surprise people
+'e' is now the command to edit a message.
+To expunge, type 'x'.  We know this will surprise people
 some of the time, but the surprise will not be disastrous--if
-you type `e' meaning to expunge, just turn off editing with C-c C-c
-and then type `x'.
+you type 'e' meaning to expunge, just turn off editing with C-c C-c
+and then type 'x'.
 
 Another new Rmail command is `<', which moves to the first message.
 This is for symmetry with `>'.
 
-Use the `b' command to bury the Rmail buffer and its summary buffer,
+Use the 'b' command to bury the Rmail buffer and its summary buffer,
 if any, removing both of them from display on the screen.
 
-The variable `rmail-output-file-alist' now controls the default
+The variable 'rmail-output-file-alist' now controls the default
 for the file to output a message to.
 
 In the Rmail summary buffer, all cursor motion commands select
@@ -5724,7 +5731,7 @@ line.
 
 Conversely, motion and deletion commands in the Rmail buffer also
 update the summary buffer.  If you set the variable
-`rmail-redisplay-summary' to a non-nil value, then they bring the
+'rmail-redisplay-summary' to a non-nil value, then they bring the
 summary buffer (if one exists) back onto the screen.
 
 C-M-t is a new command to make a summary by topic.  It uses regexp
@@ -5732,13 +5739,13 @@ matching against just the subjects of the messages to 
decide which
 messages to show in the summary.
 
 You can easily convert an Rmail file to system mailbox format with the
-command `unrmail'.  This command reads two arguments, the name of
+command 'unrmail'.  This command reads two arguments, the name of
 the Rmail file to convert, and the name of the new mailbox file.
 (This command does not change the Rmail file itself.)
 
 Rmail now handles Content Length fields in messages.
 
-*** `mail-extract-address-components' unpacks mail addresses.
+*** 'mail-extract-address-components' unpacks mail addresses.
 It takes an address as a string (the contents of the From field, for
 example) and returns a list of the form (FULL-NAME
 CANONICAL-ADDRESS).
@@ -5747,7 +5754,7 @@ CANONICAL-ADDRESS).
 
 **** M-x c-up-conditional
 
-In C mode, `c-up-conditional' moves back to the containing
+In C mode, 'c-up-conditional' moves back to the containing
 preprocessor conditional, setting the mark where point was
 previously.
 
@@ -5757,7 +5764,7 @@ conditional.  When going backwards, `#elif' acts like 
`#else' followed
 by `#if'.  When going forwards, `#elif' is ignored.
 
 **** In C mode, M-a and M-e are now defined as
-`c-beginning-of-statement' and `c-end-of-statement'.
+'c-beginning-of-statement' and 'c-end-of-statement'.
 
 **** In C mode, M-x c-backslash-region is a new command to insert or
 align `\' characters at the ends of the lines of the region, except
@@ -5770,7 +5777,7 @@ whitespace before it.  Otherwise, it inserts a new `\'.
 *** New features in info.
 
 When Info looks for an Info file, it searches the directories
-in `Info-directory-list'.  This makes it easy to install the Info files
+in 'Info-directory-list'.  This makes it easy to install the Info files
 that come with various packages.  You can specify the path with
 the environment variable INFOPATH.
 
@@ -5790,15 +5797,15 @@ next node in depth-first order (like `]').
 DEL scrolls backwards in the current node; at the end, it moves to the
 previous node in depth-first order (like `[').
 
-After a menu select, the info `up' command now restores point in the
+After a menu select, the info 'up' command now restores point in the
 menu.  The combination of this and the previous two changes means that
 repeated SPC keystrokes do the right (depth-first traverse forward) thing.
 
 `i STRING RET' moves to the node associated with STRING in the index
 or indices of this manual.  If there is more than one match for
-STRING, the `i' command finds the first match.
+STRING, the 'i' command finds the first match.
 
-`,' finds the next match for the string in the previous `i' command
+`,' finds the next match for the string in the previous 'i' command
 
 If you click the middle mouse button near a cross-reference,
 menu item or node pointer while in Info, you will go to the node
@@ -5810,7 +5817,7 @@ You can repeat any previous compilation command 
conveniently using the
 minibuffer history commands, while in the minibuffer entering the
 compilation command.
 
-While a compilation is going on, the string `Compiling' appears in
+While a compilation is going on, the string 'Compiling' appears in
 the mode line.  When this string disappears, that tells you the
 compilation is finished.
 
@@ -5828,8 +5835,8 @@ error, no matter how big the buffer is.
 *** M-x diff and M-x diff-backup.
 
 This new command compares two files, displaying the differences in an
-Emacs buffer.  The options for the `diff' program come from the
-variable `diff-switches', whose value should be a string.
+Emacs buffer.  The options for the 'diff' program come from the
+variable 'diff-switches', whose value should be a string.
 
 The buffer of differences has Compilation mode as its major mode, so you
 can use C-x ` to visit successive changed locations in the two
@@ -5839,7 +5846,7 @@ other special commands of Compilation mode: SPC and DEL 
for
 scrolling, and M-n and M-p for cursor motion.
 
 M-x diff-backup compares a file with its most recent backup.
-If you specify the name of a backup file, `diff-backup' compares it
+If you specify the name of a backup file, 'diff-backup' compares it
 with the source file that it is a backup of.
 
 *** The View commands (such as M-x view-buffer and M-x view-file) no
@@ -5877,12 +5884,12 @@ it easier to customize that behavior.
 Emacs 19 eliminates the old variables `search-...-char' that used to
 be the way to specify the characters to use for various special
 purposes in incremental search.  Instead, you can define the meaning
-of a character in incremental search by modifying `isearch-mode-map'.
+of a character in incremental search by modifying 'isearch-mode-map'.
 
 *** New commands in Buffer Menu mode.
 
 The command C-o now displays the current line's buffer in another
-window but does not select it.  This is like the existing command `o'
+window but does not select it.  This is like the existing command 'o'
 which selects the current line's buffer in another window.
 
 The command % toggles the read-only flag of the current line's buffer.
@@ -5919,18 +5926,18 @@ perform initial checkin on an unregistered file.
 
 By default, VC uses RCS if RCS is installed on your machine;
 otherwise, SCCS.  If you want to make the choice explicitly, you can do
-it by setting `vc-default-back-end' to the symbol `RCS' or the symbol
-`SCCS'.
+it by setting 'vc-default-back-end' to the symbol 'RCS' or the symbol
+'SCCS'.
 
 You can tell when a file you visit is maintained with version control
-because either `RCS' or `SCCS' appears in the mode line.
+because either 'RCS' or 'SCCS' appears in the mode line.
 
 *** A new Calendar mode has been added, the work of Edward M. Reingold.
 The mode can display the Gregorian calendar and a variety of other
 calendars at any date, and interacts with a diary facility similar to
-the UNIX `calendar' utility.
+the UNIX 'calendar' utility.
 
-*** There is a new major mode for editing binary files: Hexl mode.
+*** There is a new major mode for editing binary files: 'hexl-mode'.
 To use it, use M-x hexl-find-file instead of C-x C-f to visit the file.
 This command converts the file's contents to hexadecimal and lets you
 edit the translation.  When you save the file, it is converted
@@ -5977,22 +5984,22 @@ in the Emacs distribution.
 and certain other differences between C and C++.  It also has a command
 `fill-c++-comment' which fills a paragraph made of comment lines.
 
-The command `comment-region' is useful in C++ mode for commenting out
+The command 'comment-region' is useful in C++ mode for commenting out
 several consecutive lines, or removing the commenting out of such lines.
 
 *** A new package for merging two variants of the same text.
 
 It's not unusual for programmers to get their signals crossed and
 modify the same program in two different directions.  Then somebody
-has to merge the two versions.  The command `emerge-files' makes this
+has to merge the two versions.  The command 'emerge-files' makes this
 easier.
 
-`emerge-files' reads two file names and compares them.  Then it
+'emerge-files' reads two file names and compares them.  Then it
 displays three buffers: one for each file, and one for the
 differences.
 
 If the original version of the file is available, you can make things
-even easier using `emerge-files-with-ancestor'.  It reads three file
+even easier using 'emerge-files-with-ancestor'.  It reads three file
 names--variant 1, variant 2, and the common ancestor--and uses diff3
 to compare them.
 
@@ -6007,7 +6014,7 @@ prevents you from doing more than selecting the A or the 
B version of
 differences.  In Edit mode, all emerge commands use the C-c prefix,
 and the usual Emacs commands are available.  This allows editing the
 merge buffer, but slows down Emerge operations.  Edit and fast modes
-are indicated by `F' and `E' in the minor modes in the mode line.
+are indicated by 'F' and 'E' in the minor modes in the mode line.
 
 The Emerge commands are:
 
@@ -6067,7 +6074,7 @@ If you use a prefix argument, Emerge reads another file 
name to use
 for the output file.
 
 Once Emerge has prepared the buffer of differences, it runs the hooks
-in `emerge-startup-hooks'.
+in 'emerge-startup-hooks'.
 
 *** Asm mode is a new major mode for editing files of assembler code.
 It defines these commands:
@@ -6124,7 +6131,7 @@ type C-x 6 d, is empty, C-x 6 d kills it.)
 *** You can supply command arguments such as files to visit to an Emacs
 that is already running.  To do this, you must do this in your .emacs
 file:
-   (add-hook 'suspend-hook 'resume-suspend-hook)
+   (add-hook 'suspend-hook #'resume-suspend-hook)
 Also you must use the shellscript emacs.csh or emacs.sh, found in the
 etc subdirectory.
 
@@ -6183,7 +6190,7 @@ VT-100 and H19 terminals; put the following in your 
`.emacs' file:
 When flow control is enabled, you must type C-\ to get the effect of a
 C-s, and type C-^ to get the effect of a C-q.
 
-The function `enable-flow-control' enables flow control unconditionally.
+The function 'enable-flow-control' enables flow control unconditionally.
 
 ** Changes in Dired
 
@@ -6199,15 +6206,15 @@ parent directory.
 *** Setting and Clearing Marks
 
 There are now two kinds of marker that you can put on a file in Dired:
-`D' for deletion, and `*' for any other kind of operation.
-The `x' command deletes only files marked with `D', and most
+'D' for deletion, and `*' for any other kind of operation.
+The 'x' command deletes only files marked with 'D', and most
 other Dired commands operate only on the files marked with `*'.
 
-To mark files with `D' (also called "flagging" the files), you
-can use `d' as usual.  Here are some commands for marking with
+To mark files with 'D' (also called "flagging" the files), you
+can use 'd' as usual.  Here are some commands for marking with
 `*' (and also for unmarking):
 
-**** `m' marks the current file with `*', for an operation other than
+**** 'm' marks the current file with `*', for an operation other than
 deletion.
 
 **** `*' marks all executable files.  With a prefix argument, it
@@ -6223,7 +6230,7 @@ argument, it unmarks all those files.
 argument, queries for each marked file.  Type your help character,
 usually C-h, at that time for help.
 
-**** `c' replaces all marks that use the character OLD with marks that
+**** 'c' replaces all marks that use the character OLD with marks that
 use the character NEW.  You can use almost any character as a mark
 character by means of this command, to distinguish various classes of
 files.  If OLD is ` ', then the command operates on all unmarked
@@ -6248,48 +6255,48 @@ marked files.
 
 These are the commands:
 
-**** `C' copies the specified files.  You must specify a directory to
+**** 'C' copies the specified files.  You must specify a directory to
 copy into, or (if copying a single file) a new name.
 
-If `dired-copy-preserve-time' is non-`nil', then copying sets
+If 'dired-copy-preserve-time' is non-'nil', then copying sets
 the modification time of the new file to be the same as that of the old
 file.
 
-**** `R' renames the specified files.  You must specify a directory to
+**** 'R' renames the specified files.  You must specify a directory to
 rename into, or (if renaming a single file) a new name.
 
 Dired automatically changes the visited file name of buffers associated
 with renamed files so that they refer to the new names.
 
-**** `H' makes hard links to the specified files.  You must specify a
+**** 'H' makes hard links to the specified files.  You must specify a
 directory to make the links in, or (if making just one link) the name
 to give the link.
 
-**** `S' makes symbolic links to the specified files.  You must specify
+**** 'S' makes symbolic links to the specified files.  You must specify
 a directory to make the links in, or (if making just one link) the
 name to give the link.
 
-**** `M' changes the mode of the specified files.  This calls the
-`chmod' program, so you can describe the desired mode change with any
-argument that `chmod' would handle.
+**** 'M' changes the mode of the specified files.  This calls the
+'chmod' program, so you can describe the desired mode change with any
+argument that 'chmod' would handle.
 
-**** `G' changes the group of the specified files.
+**** 'G' changes the group of the specified files.
 
-**** `O' changes the owner of the specified files.  (On normal systems,
+**** 'O' changes the owner of the specified files.  (On normal systems,
 only the superuser can do this.)
 
-The variable `dired-chown-program' specifies the name of the
-program to use to do the work (different systems put `chown' in
+The variable 'dired-chown-program' specifies the name of the
+program to use to do the work (different systems put 'chown' in
 different places.
 
-**** `Z' compresses or uncompresses the specified files.
+**** 'Z' compresses or uncompresses the specified files.
 
-**** `L' loads the specified Emacs Lisp files.
+**** 'L' loads the specified Emacs Lisp files.
 
-**** `B' byte compiles the specified Emacs Lisp files.
+**** 'B' byte compiles the specified Emacs Lisp files.
 
-**** `P' prints the specified files.  It uses the variables
-`lpr-command' and `lpr-switches' just as `lpr-file' does.
+**** 'P' prints the specified files.  It uses the variables
+'lpr-command' and 'lpr-switches' just as 'lpr-file' does.
 
 *** Shell Commands in Dired
 
@@ -6300,17 +6307,17 @@ shell command to multiple files:
 - If you use `*' in the command, then the shell command runs just
 once, with the list of file names substituted for the `*'.
 
-Thus, `! tar cf foo.tar * RET' runs `tar' on the entire list of file
+Thus, `! tar cf foo.tar * RET' runs 'tar' on the entire list of file
 names, putting them into one tar file `foo.tar'.  The file names are
 inserted in the order that they appear in the Dired buffer.
 
 - If the command string doesn't contain `*', then it runs once for
 each file, with the file name attached at the end.  For example, `!
-uudecode RET' runs `uudecode' on each file.
+uudecode RET' runs 'uudecode' on each file.
 
 To run the shell command once for each file but without being limited
 to putting the file name inserted in the middle, use a shell loop.
-For example, this shell command would run `uuencode' on each of the
+For example, this shell command would run 'uuencode' on each of the
 specified files, writing the output into a corresponding `.uu' file:
 
     for file in *; uuencode $file $file >$file.uu; done
@@ -6334,7 +6341,7 @@ the regular expression REGEXP.
 These four commands rename, copy, make hard links and make soft links,
 in each case computing the new name by regular expression substitution
 from the name of the old file.  They  effectively perform
-`query-replace-regexp' on the selected file names in the Dired buffer.
+'query-replace-regexp' on the selected file names in the Dired buffer.
 
 The commands read two arguments: a regular expression, and a
 substitution pattern.  Each selected file name is matched against the
@@ -6362,30 +6369,30 @@ as a default the last regular expression specified in a 
`%' command.
 
 *** File Comparison with Dired
 
-**** `=' compares the current file with another file (the file at the
-mark), by running the `diff' program.  The file at the mark is given
-to `diff' first.
+**** '=' compares the current file with another file (the file at the
+mark), by running the 'diff' program.  The file at the mark is given
+to 'diff' first.
 
-**** `M-=' compares the current file with its backup file.  If there
+**** 'M-=' compares the current file with its backup file.  If there
 are several numerical backups, it uses the most recent one.  If this
 file is a backup, it is compared with its original.
 
-The backup file is the first file given to `diff'.
+The backup file is the first file given to 'diff'.
 
 *** Subdirectories in Dired
 
 You can display more than one directory in one Dired buffer.
-The simplest way to do this is to specify the options `-lR' for
-running `ls'.  That produces a recursive directory listing showing
+The simplest way to do this is to specify the options '-lR' for
+running 'ls'.  That produces a recursive directory listing showing
 all subdirectories, all within the same Dired buffer.
 
 You can also insert the contents of a particular subdirectory with the
-`i' command.  Use this command on the line that describes a file which
+'i' command.  Use this command on the line that describes a file which
 is a directory.  Inserted subdirectory contents follow the top-level
 directory of the Dired buffer, just as they do in `ls -lR' output.
 
 If the subdirectory's contents are already present in the buffer, the
-`i' command just moves to it (type `l' to refresh it).  It sets the
+'i' command just moves to it (type 'l' to refresh it).  It sets the
 Emacs mark before moving, so C-x C-x takes you back to the old
 position in the buffer.
 
@@ -6423,18 +6430,18 @@ away.
 
 *** Editing the Dired Buffer
 
-**** `l' updates the specified files in a Dired buffer.  This means
+**** 'l' updates the specified files in a Dired buffer.  This means
 reading their current status from the file system and changing the
 buffer to reflect it properly.
 
 If you use this command on a subdirectory header line, it updates the
 contents of the subdirectory.
 
-**** `g' updates the entire contents of the Dired buffer.  It preserves
+**** 'g' updates the entire contents of the Dired buffer.  It preserves
 all marks except for those on files that have vanished.  Hidden
 subdirectories are updated but remain hidden.
 
-**** `k' kills all marked lines (not the files).  With a prefix
+**** 'k' kills all marked lines (not the files).  With a prefix
 argument, it kills that many lines starting with the current line.
 
 This command does not delete files; it just deletes text from the Dired
@@ -6445,10 +6452,10 @@ are also deleted from the buffer.  Typing `C-u k' on 
the header line
 for a subdirectory is another way to delete a subdirectory from the
 Dired buffer.
 
-*** `find' and Dired.
+*** 'find' and Dired.
 
 To search for files with names matching a wildcard pattern use
-`find-name-dired'.  Its arguments are DIRECTORY and
+'find-name-dired'.  Its arguments are DIRECTORY and
 PATTERN.  It selects all the files in DIRECTORY or its
 subdirectories whose own names match PATTERN.
 
@@ -6456,17 +6463,17 @@ The files thus selected are displayed in a Dired buffer 
in which the
 ordinary Dired commands are available.
 
 If you want to test the contents of files, rather than their names, use
-`find-grep-dired'.  This command takes two minibuffer arguments,
+'find-grep-dired'.  This command takes two minibuffer arguments,
 DIRECTORY and REGEXP; it selects all the files in
 DIRECTORY or its subdirectories that contain a match for
-REGEXP.  It works by running `find' and `grep'.
+REGEXP.  It works by running 'find' and 'grep'.
 
-The most general command in this series is `find-dired', which lets
-you specify any condition that `find' can test.  It takes two
-minibuffer arguments, DIRECTORY and FIND-ARGS; it runs `find' in
-DIRECTORY with using FIND-ARGS as the arguments to `find' specifying
+The most general command in this series is 'find-dired', which lets
+you specify any condition that 'find' can test.  It takes two
+minibuffer arguments, DIRECTORY and FIND-ARGS; it runs 'find' in
+DIRECTORY with using FIND-ARGS as the arguments to 'find' specifying
 which files to accept.  To use this command, you need to know how to
-use `find'.
+use 'find'.
 
 ** New amusements and novelties.
 
@@ -6498,14 +6505,14 @@ description of the steps required for installation.
 *** If you create a Lisp file named `site-start.el', Emacs loads the file
 whenever it starts up.
 
-*** A new Lisp variable, `data-directory', indicates the directory
+*** A new Lisp variable, 'data-directory', indicates the directory
 containing the DOC file, tutorial, copying agreement, and other
-familiar `etc' files.  The value of `data-directory' is a simple string.
+familiar 'etc' files.  The value of 'data-directory' is a simple string.
 The default should be set at build time, and the person installing
 Emacs should place all the data files in this directory.  The `help.el'
 functions that look for docstrings and information files check this
 variable.  All Emacs Lisp packages should also be coded so that they
-refer to `data-directory' to find data files.
+refer to 'data-directory' to find data files.
 
 *** The PURESIZE definition has been moved from config.h to its own
 file, puresize.h.  Since almost every file of C source in the
@@ -6514,7 +6521,7 @@ on puresize.h, this means that changing the value of 
PURESIZE causes
 only those two files to be recompiled.
 
 *** The makefile at the top of the Emacs source tree now supports a
-`dist' target, which creates a compressed tar file suitable for
+'dist' target, which creates a compressed tar file suitable for
 distribution, using the contents of the source tree.  Object files,
 old file versions, executables, DOC files, and other
 architecture-specific or easy-to-recreate files are not included in
diff --git a/etc/NEWS.20 b/etc/NEWS.20
index 2a9b0b2d25..332d6ded92 100644
--- a/etc/NEWS.20
+++ b/etc/NEWS.20
@@ -55,11 +55,11 @@ Formerly the name had to be `.emacs'.  If you use the name
 If both `.emacs' and `.emacs.el' exist, the latter file
 is the one that is used.
 
-** shell-command, and shell-command-on-region, now return
+** 'shell-command', and 'shell-command-on-region', now return
 the exit code of the command (unless it is asynchronous).
 Also, you can specify a place to put the error output,
 separate from the command's regular output.
-Interactively, the variable shell-command-default-error-buffer
+Interactively, the variable 'shell-command-default-error-buffer'
 says where to put error output; set it to a buffer name.
 In calls from Lisp, an optional argument ERROR-BUFFER specifies
 the buffer name.
@@ -69,8 +69,8 @@ output is inserted before point in that buffer, with \f\n to 
separate
 it from the previous batch of error output.  The error buffer is not
 cleared, so error output from successive commands accumulates there.
 
-** Setting the default value of enable-multibyte-characters to nil in
-the .emacs file, either explicitly using setq-default, or via Custom,
+** Setting the default value of 'enable-multibyte-characters' to nil in
+the .emacs file, either explicitly using 'setq-default', or via Custom,
 is now essentially equivalent to using --unibyte: all buffers
 created during startup will be made unibyte after loading .emacs.
 
@@ -79,8 +79,8 @@ example, typing C-x C-f c*.c RET visits all the files whose 
names
 match c*.c.  To visit a file whose name contains * or ?, add the
 quoting sequence /: to the beginning of the file name.
 
-** The M-x commands keep-lines, flush-lines and count-matches
-now have the same feature as occur and query-replace:
+** The M-x commands 'keep-lines', 'flush-lines' and 'count-matches'
+now have the same feature as 'occur' and 'query-replace':
 if the pattern contains any upper case letters, then
 they never ignore case.
 
@@ -96,10 +96,10 @@ If you subsequently save the buffer, Emacs converts the 
text back to
 the same format that was used in the file before.
 
 You can turn off end-of-line conversion by setting the variable
-`inhibit-eol-conversion' to non-nil, e.g. with Custom in the MULE group.
+'inhibit-eol-conversion' to non-nil, e.g. with Custom in the MULE group.
 
-** The character set property `prefered-coding-system' has been
-renamed to `preferred-coding-system', for the sake of correct spelling.
+** The character set property 'prefered-coding-system' has been
+renamed to 'preferred-coding-system', for the sake of correct spelling.
 This is a fairly internal feature, so few programs should be affected.
 
 ** Mode-line display of end-of-line format is changed.
@@ -110,22 +110,22 @@ is displayed as "(DOS)" on Unix and GNU/Linux systems.  
The usual
 end-of-line format is still displayed as a single character (colon for
 Unix, backslash for DOS and Windows, and forward slash for the Mac).
 
-The values of the variables eol-mnemonic-unix, eol-mnemonic-dos,
-eol-mnemonic-mac, and eol-mnemonic-undecided, which are strings,
+The values of the variables 'eol-mnemonic-unix', 'eol-mnemonic-dos',
+'eol-mnemonic-mac', and 'eol-mnemonic-undecided', which are strings,
 control what is displayed in the mode line for each end-of-line
 format.  You can now customize these variables.
 
-** In the previous version of Emacs, tar-mode didn't work well if a
+** In the previous version of Emacs, 'tar-mode' didn't work well if a
 filename contained non-ASCII characters.  Now this is fixed.  Such a
 filename is decoded by file-name-coding-system if the default value of
 enable-multibyte-characters is non-nil.
 
-** The command temp-buffer-resize-mode toggles a minor mode
+** The command 'temp-buffer-resize-mode' toggles a minor mode
 in which temporary buffers (such as help buffers) are given
 windows just big enough to hold the whole contents.
 
 ** If you use completion.el, you must now run the function
-dynamic-completion-mode to enable it.  Just loading the file
+'dynamic-completion-mode' to enable it.  Just loading the file
 doesn't have any effect.
 
 ** In Flyspell mode, the default is now to make just one Ispell process,
@@ -133,11 +133,11 @@ not one per buffer.
 
 ** If you use iswitchb but do not call (iswitchb-default-keybindings) to
 use the default keybindings, you will need to add the following line:
-  (add-hook 'minibuffer-setup-hook 'iswitchb-minibuffer-setup)
+  (add-hook 'minibuffer-setup-hook #'iswitchb-minibuffer-setup)
 
 ** Auto-show mode is no longer enabled just by loading auto-show.el.
-To control it, set `auto-show-mode' via Custom or use the
-`auto-show-mode' command.
+To control it, set 'auto-show-mode' via Custom or use the
+'auto-show-mode' command.
 
 ** Handling of X fonts' ascent/descent parameters has been changed to
 avoid redisplay problems.  As a consequence, compared with previous
@@ -183,7 +183,7 @@ current codepage when it starts.
 ** Mail changes
 
 *** When mail is sent using compose-mail (C-x m), and if
-`mail-send-nonascii' is set to the new default value `mime',
+'mail-send-nonascii' is set to the new default value 'mime',
 appropriate MIME headers are added.  The headers are added only if
 non-ASCII characters are present in the body of the mail, and no other
 MIME headers are already present.  For example, the following three
@@ -194,11 +194,11 @@ latin-1:
   Content-type: text/plain; charset=iso-8859-1
   Content-Transfer-Encoding: 8bit
 
-*** The new variable default-sendmail-coding-system specifies the
+*** The new variable 'default-sendmail-coding-system' specifies the
 default way to encode outgoing mail.  This has higher priority than
-default-buffer-file-coding-system but has lower priority than
-sendmail-coding-system and the local value of
-buffer-file-coding-system.
+'default-buffer-file-coding-system' but has lower priority than
+'sendmail-coding-system' and the local value of
+'buffer-file-coding-system'.
 
 You should not set this variable manually.  Instead, set
 sendmail-coding-system to specify a fixed encoding for all outgoing
@@ -248,11 +248,11 @@ brace.  These used to be recognized as brace-list-entry's.
 c-electric-brace also recognizes brace-entry-open braces
 (brace-list-entry's can no longer be electrified).
 
-*** New command c-indent-line-or-region, not bound by default.
+*** New command 'c-indent-line-or-region', not bound by default.
 
 *** `#' is only electric when typed in the indentation of a line.
 
-*** Parentheses are now electric (via the new command c-electric-paren)
+*** Parentheses are now electric (via the new command 'c-electric-paren')
 for auto-reindenting lines when parens are typed.
 
 *** In "gnu" style, inline-open offset is now set to zero.
@@ -273,10 +273,10 @@ Gnus manual for the full story.
 before.  All Message buffers are now also articles in the nndraft
 group, which is created automatically.
 
-*** `gnus-alter-header-function' can now be used to alter header
+*** 'gnus-alter-header-function' can now be used to alter header
 values.
 
-*** `gnus-summary-goto-article' now accept Message-ID's.
+*** 'gnus-summary-goto-article' now accept Message-ID's.
 
 *** A new Message command for deleting text in the body of a message
 outside the region: `C-c C-v'.
@@ -284,20 +284,20 @@ outside the region: `C-c C-v'.
 *** You can now post to component group in nnvirtual groups with
 `C-u C-c C-c'.
 
-*** `nntp-rlogin-program' -- new variable to ease customization.
+*** 'nntp-rlogin-program' -- new variable to ease customization.
 
-*** `C-u C-c C-c' in `gnus-article-edit-mode' will now inhibit
+*** `C-u C-c C-c' in 'gnus-article-edit-mode' will now inhibit
 re-highlighting of the article buffer.
 
-*** New element in `gnus-boring-article-headers' -- `long-to'.
+*** New element in 'gnus-boring-article-headers' -- 'long-to'.
 
-*** `M-i' symbolic prefix command.  See the section "Symbolic
+*** 'M-i' symbolic prefix command.  See the section "Symbolic
 Prefixes" in the Gnus manual for details.
 
-*** `L' and `I' in the summary buffer now take the symbolic prefix
-`a' to add the score rule to the "all.SCORE" file.
+*** 'L' and 'I' in the summary buffer now take the symbolic prefix
+'a' to add the score rule to the "all.SCORE" file.
 
-*** `gnus-simplify-subject-functions' variable to allow greater
+*** 'gnus-simplify-subject-functions' variable to allow greater
 control over simplification.
 
 *** `A T' -- new command for fetching the current thread.
@@ -305,21 +305,21 @@ control over simplification.
 *** `/ T' -- new command for including the current thread in the
 limit.
 
-*** `M-RET' is a new Message command for breaking cited text.
+*** 'M-RET' is a new Message command for breaking cited text.
 
-*** \\1-expressions are now valid in `nnmail-split-methods'.
+*** \\1-expressions are now valid in 'nnmail-split-methods'.
 
-*** The `custom-face-lookup' function has been removed.
+*** The 'custom-face-lookup' function has been removed.
 If you used this function in your initialization files, you must
-rewrite them to use `face-spec-set' instead.
+rewrite them to use 'face-spec-set' instead.
 
 *** Canceling now uses the current select method.  Symbolic prefix
-`a' forces normal posting method.
+'a' forces normal posting method.
 
 *** New command to translate M******** sm*rtq**t*s into proper text
 -- `W d'.
 
-*** For easier debugging of nntp, you can set `nntp-record-commands'
+*** For easier debugging of nntp, you can set 'nntp-record-commands'
 to a non-nil value.
 
 *** nntp now uses ~/.authinfo, a .netrc-like file, for controlling
@@ -330,49 +330,49 @@ has been added.
 
 *** A history of where mails have been split is available.
 
-*** A new article date command has been added -- `article-date-iso8601'.
+*** A new article date command has been added -- 'article-date-iso8601'.
 
 *** Subjects can be simplified when threading by setting
-`gnus-score-thread-simplify'.
+'gnus-score-thread-simplify'.
 
 *** A new function for citing in Message has been added --
-`message-cite-original-without-signature'.
+'message-cite-original-without-signature'.
 
-*** `article-strip-all-blank-lines' -- new article command.
+*** 'article-strip-all-blank-lines' -- new article command.
 
 *** A new Message command to kill to the end of the article has
 been added.
 
 *** A minimum adaptive score can be specified by using the
-`gnus-adaptive-word-minimum' variable.
+'gnus-adaptive-word-minimum' variable.
 
 *** The "lapsed date" article header can be kept continually
-updated by the `gnus-start-date-timer' command.
+updated by the 'gnus-start-date-timer' command.
 
 *** Web listserv archives can be read with the nnlistserv backend.
 
 *** Old dejanews archives can now be read by nnweb.
 
-*** `gnus-posting-styles' has been re-activated.
+*** 'gnus-posting-styles' has been re-activated.
 
 ** Changes to TeX and LaTeX mode
 
-*** The new variable `tex-start-options-string' can be used to give
+*** The new variable 'tex-start-options-string' can be used to give
 options for the TeX run.  The default value causes TeX to run in
 nonstopmode.  For an interactive TeX run set it to nil or "".
 
-*** The command `tex-feed-input' sends input to the Tex Shell.  In a
+*** The command 'tex-feed-input' sends input to the Tex Shell.  In a
 TeX buffer it is bound to the keys C-RET, C-c RET, and C-c C-m (some
 of these keys may not work on all systems).  For instance, if you run
 TeX interactively and if the TeX run stops because of an error, you
 can continue it without leaving the TeX buffer by typing C-RET.
 
-*** The Tex Shell Buffer is now in `compilation-shell-minor-mode'.
+*** The Tex Shell Buffer is now in 'compilation-shell-minor-mode'.
 All error-parsing commands of the Compilation major mode are available
 but bound to keys that don't collide with the shell.  Thus you can use
 the Tex Shell for command line executions like a usual shell.
 
-*** The commands `tex-validate-region' and `tex-validate-buffer' check
+*** The commands 'tex-validate-region' and 'tex-validate-buffer' check
 the matching of braces and $'s.  The errors are listed in a *Occur*
 buffer and you can use C-c C-c or mouse-2 to go to a particular
 mismatch.
@@ -380,7 +380,7 @@ mismatch.
 ** Changes to RefTeX mode
 
 *** The table of contents buffer can now also display labels and
-file boundaries in addition to sections. Use `l', `i', and `c' keys.
+file boundaries in addition to sections. Use 'l', 'i', and 'c' keys.
 
 *** Labels derived from context (the section heading) are now
 lowercase by default.  To make the label legal in LaTeX, latin-1
@@ -388,25 +388,25 @@ characters will lose their accent.  All Mule characters 
will be
 removed from the label.
 
 *** The automatic display of cross reference information can also use
-a window instead of the echo area.  See variable `reftex-auto-view-crossref'.
+a window instead of the echo area.  See variable 'reftex-auto-view-crossref'.
 
 *** kpsewhich can be used by RefTeX to find TeX and BibTeX files.  See the
-customization group `reftex-finding-files'.
+customization group 'reftex-finding-files'.
 
-*** The option `reftex-bibfile-ignore-list' has been renamed to
-`reftex-bibfile-ignore-regexps' and indeed can be fed with regular
+*** The option 'reftex-bibfile-ignore-list' has been renamed to
+'reftex-bibfile-ignore-regexps' and indeed can be fed with regular
 expressions.
 
 *** Multiple Selection buffers are now hidden buffers.
 
 ** New/deleted modes and packages
 
-*** The package snmp-mode.el provides major modes for editing SNMP and
-SNMPv2 MIBs.  It has entries on `auto-mode-alist'.
+*** 'snmp-mode' provides major modes for editing SNMP and SNMPv2 MIBs.
+It has entries on 'auto-mode-alist'.
 
 *** The package sql.el provides a major mode, M-x sql-mode, for
 editing SQL files, and M-x sql-interactive-mode for interacting with
-SQL interpreters.  It has an entry on `auto-mode-alist'.
+SQL interpreters.  It has an entry on 'auto-mode-alist'.
 
 *** ispell4.el has been deleted.  It got in the way of ispell.el and
 this was hard to fix reliably.  It has long been obsolete -- use
@@ -431,7 +431,7 @@ controls whether an external program is invoked or output 
is written
 directly to a printer port.  Similarly, in the previous version of
 Emacs, the value of ps-lpr-command did not affect PostScript printing
 on MS-DOS unless ps-printer-name was set to something other than a
-string (eg. t or `pipe'), but now it controls whether an external
+string (eg. t or 'pipe'), but now it controls whether an external
 program is used.  (These changes were made so that configuration of
 printing variables would be almost identical across all platforms.)
 
@@ -442,11 +442,11 @@ input, on those systems the data to be output is now 
written to a
 temporary file whose name is passed as the last argument to the external
 program.
 
-An exception is made for `print', a standard program on Windows NT,
-and `nprint', a standard program on Novell Netware.  For both of these
+An exception is made for 'print', a standard program on Windows NT,
+and 'nprint', a standard program on Novell Netware.  For both of these
 programs, the command line is constructed in the appropriate syntax
 automatically, using only the value of printer-name or ps-printer-name
-as appropriate--the value of the relevant `-switches' variable is
+as appropriate--the value of the relevant '-switches' variable is
 ignored, as both programs have no useful switches.
 
 ** The value of the variable dos-printer (cf. dos-ps-printer), if it has
@@ -460,10 +460,10 @@ This includes Tetris and Snake.
 
 * Lisp changes in Emacs 20.4
 
-** New functions line-beginning-position and line-end-position
+** New functions 'line-beginning-position' and 'line-end-position'
 return the position of the beginning or end of the current line.
 They both accept an optional argument, which has the same
-meaning as the argument to beginning-of-line or end-of-line.
+meaning as the argument to 'beginning-of-line' or 'end-of-line'.
 
 ** find-file and allied functions now have an optional argument
 WILDCARD.  If this is non-nil, they do wildcard processing,
@@ -478,54 +478,54 @@ It is an integer if the size fits in a Lisp integer, 
float otherwise.
 the number fits in a Lisp integer) or a cons cell containing two
 integers.
 
-** The new function directory-files-and-attributes returns a list of
+** The new function 'directory-files-and-attributes' returns a list of
 files in a directory and their attributes.  It accepts the same
-arguments as directory-files and has similar semantics, except that
+arguments as 'directory-files' and has similar semantics, except that
 file names and attributes are returned.
 
-** The new function file-attributes-lessp is a helper function for
+** The new function 'file-attributes-lessp' is a helper function for
 sorting the list generated by directory-files-and-attributes.  It
 accepts two arguments, each a list of a file name and its attributes.
-It compares the file names of each according to string-lessp and
+It compares the file names of each according to 'string-lessp' and
 returns the result.
 
-** The new function file-expand-wildcards expands a wildcard-pattern
+** The new function 'file-expand-wildcards' expands a wildcard-pattern
 to produce a list of existing files that match the pattern.
 
 ** New functions for base64 conversion:
 
-The function base64-encode-region converts a part of the buffer
-into the base64 code used in MIME.  base64-decode-region
+The function 'base64-encode-region' converts a part of the buffer
+into the base64 code used in MIME.  'base64-decode-region'
 performs the opposite conversion.  Line-breaking is supported
 optionally.
 
-Functions base64-encode-string and base64-decode-string do a similar
+Functions 'base64-encode-string' and 'base64-decode-string' do a similar
 job on the text in a string.  They return the value as a new string.
 
 **
-The new function process-running-child-p
+The new function 'process-running-child-p'
 will tell you if a subprocess has given control of its
 terminal to its own child process.
 
-** interrupt-process and such functions have a new feature:
-when the second argument is `lambda', they send a signal
+** 'interrupt-process' and such functions have a new feature:
+when the second argument is 'lambda', they send a signal
 to the running child of the subshell, if any, but if the shell
 itself owns its terminal, no signal is sent.
 
-** There are new widget types `plist' and `alist' which can
+** There are new widget types 'plist' and 'alist' which can
 be used for customizing variables whose values are plists or alists.
 
-** easymenu.el now understands `:key-sequence' and `:style button'.
+** easymenu.el now understands ':key-sequence' and `:style button'.
 :included is an alias for :visible.
 
-easy-menu-add-item now understands the values returned by
-easy-menu-remove-item and easy-menu-item-present-p.  This can be used
+'easy-menu-add-item' now understands the values returned by
+'easy-menu-remove-item' and 'easy-menu-item-present-p'.  This can be used
 to move or copy menu entries.
 
 ** Multibyte editing changes
 
-*** The definitions of sref and char-bytes are changed.  Now, sref is
-an alias of aref and char-bytes always returns 1.  This change is to
+*** The definitions of 'sref' and 'char-bytes' are changed.  Now, 'sref' is
+an alias of 'aref' and 'char-bytes' always returns 1.  This change is to
 make some Emacs Lisp code which works on 20.2 and earlier also
 work on the latest Emacs.  Such code uses a combination of sref and
 char-bytes in a loop typically as below:
@@ -546,50 +546,50 @@ deleting at the head or the end of the region may signal 
this error:
 This is to avoid some bytes being combined together into a character
 across the boundary.
 
-*** The functions find-charset-region and find-charset-string include
-`unknown' in the returned list in the following cases:
+*** The functions 'find-charset-region' and 'find-charset-string' include
+'unknown' in the returned list in the following cases:
     o The current buffer or the target string is unibyte and
       contains 8-bit characters.
     o The current buffer or the target string is multibyte and
       contains invalid characters.
 
-*** The functions decode-coding-region and encode-coding-region remove
+*** The functions 'decode-coding-region' and 'encode-coding-region' remove
 text properties of the target region.  Ideally, they should correctly
 preserve text properties, but for the moment, it's hard.  Removing
 text properties is better than preserving them in a less-than-correct
 way.
 
-*** prefer-coding-system sets EOL conversion of default coding systems.
+*** 'prefer-coding-system' sets EOL conversion of default coding systems.
 If the argument to prefer-coding-system specifies a certain type of
 end of line conversion, the default coding systems set by
 prefer-coding-system will specify that conversion type for end of line.
 
-*** The new function thai-compose-string can be used to properly
+*** The new function 'thai-compose-string' can be used to properly
 compose Thai characters in a string.
 
-** The primitive `define-prefix-command' now takes an optional third
+** The primitive 'define-prefix-command' now takes an optional third
 argument NAME, which should be a string.  It supplies the menu name
 for the created keymap.  Keymaps created in order to be displayed as
 menus should always use the third argument.
 
-** The meanings of optional second arguments for read-char,
-read-event, and read-char-exclusive are flipped.  Now the second
+** The meanings of optional second arguments for 'read-char',
+'read-event', and 'read-char-exclusive' are flipped.  Now the second
 arguments are INHERIT-INPUT-METHOD.  These functions use the current
 input method (if any) if and only if INHERIT-INPUT-METHOD is non-nil.
 
-** The new function clear-this-command-keys empties out the contents
+** The new function 'clear-this-command-keys' empties out the contents
 of the vector that (this-command-keys) returns.  This is useful in
 programs that read passwords, to prevent the passwords from echoing
 inadvertently as part of the next command in certain cases.
 
-** The new macro `with-temp-message' displays a temporary message in
-the echo area, while executing some Lisp code.  Like `progn', it
+** The new macro 'with-temp-message' displays a temporary message in
+the echo area, while executing some Lisp code.  Like 'progn', it
 returns the value of the last form, but it also restores the previous
 echo area contents.
 
    (with-temp-message MESSAGE &rest BODY)
 
-** The function `require' now takes an optional third argument
+** The function 'require' now takes an optional third argument
 NOERROR.  If it is non-nil, then there is no error if the
 requested feature cannot be loaded.
 
@@ -597,7 +597,7 @@ requested feature cannot be loaded.
 foreground color, background color or stipple pattern
 means to clear out that attribute.
 
-** The `outer-window-id' frame property of an X frame
+** The 'outer-window-id' frame property of an X frame
 gives the window number of the outermost X window for the frame.
 
 ** Temporary buffers made with with-output-to-temp-buffer are now
@@ -605,14 +605,14 @@ read-only by default, and normally use the major mode 
Help mode
 unless you put them in some other non-Fundamental mode before the
 end of with-output-to-temp-buffer.
 
-** The new functions gap-position and gap-size return information on
+** The new functions 'gap-position' and 'gap-size' return information on
 the gap of the current buffer.
 
-** The new functions position-bytes and byte-to-position provide a way
+** The new functions 'position-bytes' and 'byte-to-position' provide a way
 to convert between character positions and byte positions in the
 current buffer.
 
-** vc.el defines two new macros, `edit-vc-file' and `with-vc-file', to
+** vc.el defines two new macros, 'edit-vc-file' and 'with-vc-file', to
 facilitate working with version-controlled files from Lisp programs.
 These macros check out a given file automatically if needed, and check
 it back in after any modifications have been made.
@@ -694,10 +694,10 @@ C-x RET x specifies a coding system for all subsequent 
cutting and
 pasting operations.
 
 ** You can specify the printer to use for commands that do printing by
-setting the variable `printer-name'.  Just what a printer name looks
+setting the variable 'printer-name'.  Just what a printer name looks
 like depends on your operating system.  You can specify a different
 printer for the PostScript printing commands by setting
-`ps-printer-name'.
+'ps-printer-name'.
 
 ** Emacs now supports on-the-fly spell checking by the means of a
 minor mode.  It is called M-x flyspell-mode.  You don't have to remember
@@ -735,17 +735,17 @@ You can use the ENTER key to accept the current 
conversion.
 If you type TAB to display a list of alternatives, you can select one
 of the alternatives with Mouse-2.
 
-The meaning of the variable `input-method-verbose-flag' is changed so
-that you can set it to t, nil, `default', or `complex-only'.
+The meaning of the variable 'input-method-verbose-flag' is changed so
+that you can set it to t, nil, 'default', or 'complex-only'.
 
   If the value is nil, extra guidance is never given.
 
   If the value is t, extra guidance is always given.
 
-  If the value is `complex-only', extra guidance is always given only
+  If the value is 'complex-only', extra guidance is always given only
   when you are using complex input methods such as chinese-py.
 
-  If the value is `default' (this is the default), extra guidance is
+  If the value is 'default' (this is the default), extra guidance is
   given in the following case:
     o When you are using a complex input method.
     o When you are using a simple input method but not in the minibuffer.
@@ -755,7 +755,7 @@ input-method-verbose-flag to nil or to complex-only is a 
good choice,
 and if you are using an input method you are not familiar with,
 setting it to t is helpful.
 
-The old command select-input-method is now called set-input-method.
+The old command 'select-input-method' is now called 'set-input-method'.
 
 In the language environment "Korean", you can use the following
 keys:
@@ -787,7 +787,7 @@ Lisp variables in user-loaded libraries.
 ** C-x r t (string-rectangle) now deletes the existing rectangle
 contents before inserting the specified string on each line.
 
-** There is a new command delete-whitespace-rectangle
+** There is a new command 'delete-whitespace-rectangle'
 which deletes whitespace starting from a particular column
 in all the lines on a rectangle.  The column is specified
 by the left edge of the rectangle.
@@ -815,7 +815,7 @@ confirmation before overwriting an existing file.  When you 
call
 the function from a Lisp program, a new optional argument CONFIRM
 says whether to ask for confirmation in this case.
 
-** If you use find-file-literally and the file is already visited
+** If you use 'find-file-literally' and the file is already visited
 non-literally, the command asks you whether to revisit the file
 literally.  If you say no, it signals an error.
 
@@ -824,22 +824,22 @@ now use the proper name for the mode hook: 
WHATEVER-mode-hook.
 Formerly they used the name WHATEVER-mode-hooks, but that is
 inconsistent with Emacs conventions.
 
-** shell-command-on-region (and shell-command) reports success or
+** 'shell-command-on-region' (and shell-command) reports success or
 failure if the command produces no output.
 
-** Set focus-follows-mouse to nil if your window system or window
+** Set 'focus-follows-mouse' to nil if your window system or window
 manager does not transfer focus to another window when you just move
 the mouse.
 
-** mouse-menu-buffer-maxlen has been renamed to
-mouse-buffer-menu-maxlen to be consistent with the other related
+** 'mouse-menu-buffer-maxlen' has been renamed to
+'mouse-buffer-menu-maxlen' to be consistent with the other related
 function and variable names.
 
-** The new variable auto-coding-alist specifies coding systems for
+** The new variable 'auto-coding-alist' specifies coding systems for
 reading specific files.  This has higher priority than
-file-coding-system-alist.
+'file-coding-system-alist'.
 
-** If you set the variable unibyte-display-via-language-environment to
+** If you set the variable 'unibyte-display-via-language-environment' to
 t, then Emacs displays non-ASCII characters are displayed by
 converting them to the equivalent multibyte characters according to
 the current language environment.  As a result, they are displayed
@@ -848,7 +848,7 @@ according to the current fontset.
 ** C-q's handling of codes in the range 0200 through 0377 is changed.
 
 The codes in the range 0200 through 0237 are inserted as one byte of
-that code regardless of the values of nonascii-translation-table and
+that code regardless of the values of 'nonascii-translation-table' and
 nonascii-insert-offset.
 
 For the codes in the range 0240 through 0377, if
@@ -869,14 +869,14 @@ command keys.
 ** M-x apropos-command, with a prefix argument, no longer looks for
 user option variables--instead it looks for noninteractive functions.
 
-Meanwhile, the command apropos-variable normally searches for
+Meanwhile, the command 'apropos-variable' normally searches for
 user option variables; with a prefix argument, it looks at
 all variables that have documentation.
 
 ** When you type a long line in the minibuffer, and the minibuffer
 shows just one line, automatically scrolling works in a special way
 that shows you overlap with the previous line of text.  The variable
-minibuffer-scroll-overlap controls how many characters of overlap
+'minibuffer-scroll-overlap' controls how many characters of overlap
 it should show; the default is 20.
 
 Meanwhile, Resize Minibuffer mode is still available; in that mode,
@@ -904,19 +904,19 @@ the tag around point and puts that into the default grep 
command.
 buffer positions from which M-. or other tag-finding commands were
 invoked.
 
-** The new variable comment-padding specifies the number of spaces
-that `comment-region' will insert before the actual text of the comment.
+** The new variable 'comment-padding' specifies the number of spaces
+that 'comment-region' will insert before the actual text of the comment.
 The default is 1.
 
 ** In Fortran mode the characters `.', `_' and `$' now have symbol
-syntax, not word syntax.  Fortran mode now supports `imenu' and has
-new commands fortran-join-line (M-^) and fortran-narrow-to-subprogram
+syntax, not word syntax.  Fortran mode now supports 'imenu' and has
+new commands 'fortran-join-line' (M-^) and 'fortran-narrow-to-subprogram'
 (C-x n d).  M-q can be used to fill a statement or comment block
 sensibly.
 
-** GUD now supports jdb, the Java debugger, and pdb, the Python debugger.
+** GUD now supports 'jdb', the Java debugger, and 'pdb', the Python debugger.
 
-** If you set the variable add-log-keep-changes-together to a non-nil
+** If you set the variable 'add-log-keep-changes-together' to a non-nil
 value, the command `C-x 4 a' will automatically notice when you make
 two entries in one day for one file, and combine them.
 
@@ -931,13 +931,13 @@ every night.
 the variable desktop-enable to t with Custom.
 
 *** Minor modes are now restored.  Which minor modes are restored
-and how modes are restored is controlled by `desktop-minor-mode-table'.
+and how modes are restored is controlled by 'desktop-minor-mode-table'.
 
 ** There is no need to do anything special, now, to enable Gnus to
 read and post multi-lingual articles.
 
 ** Outline mode has now support for showing hidden outlines when
-doing an isearch.  In order for this to happen search-invisible should
+doing an isearch.  In order for this to happen 'search-invisible' should
 be set to open (the default).  If an isearch match is inside a hidden
 outline the outline is made visible.  If you continue pressing C-s and
 the match moves outside the formerly invisible outline, the outline is
@@ -998,7 +998,7 @@ function for something else (10-20 lines of Lisp code).
 *** The Dired function dired-do-toggle, which toggles marked and unmarked
 files, is now bound to "t" instead of "T".
 
-*** dired-at-point has been added to ffap.el.  It allows one to easily
+*** 'dired-at-point' has been added to ffap.el.  It allows one to easily
 run Dired on the directory name at point.
 
 *** Dired has a new command: %g.  It searches the contents of
@@ -1007,7 +1007,7 @@ for a specified regexp.
 
 ** VC Changes
 
-*** New option vc-ignore-vc-files lets you turn off version control
+*** New option 'vc-ignore-vc-files' lets you turn off version control
 conveniently.
 
 *** VC Dired has been completely rewritten.  It is now much
@@ -1022,14 +1022,14 @@ currently locked (for CVS, all files not up-to-date are 
shown).
 You can change the listing format by setting vc-dired-recurse to nil,
 then it shows only the given directory, and you may also set
 vc-dired-terse-display to nil, then it shows all files under version
-control plus the names of any subdirectories, so that you can type `i'
+control plus the names of any subdirectories, so that you can type 'i'
 on such lines to insert them manually, as in ordinary Dired.
 
-All Dired commands operate normally in VC Dired, except for `v', which
+All Dired commands operate normally in VC Dired, except for 'v', which
 is redefined as the version control prefix.  That means you may type
-`v l', `v =' etc. to invoke `vc-print-log', `vc-diff' and the like on
+`v l', `v =' etc. to invoke 'vc-print-log', 'vc-diff' and the like on
 the file named in the current Dired buffer line.  `v v' invokes
-`vc-next-action' on this file, or on all files currently marked.
+'vc-next-action' on this file, or on all files currently marked.
 
 The new command `v t' (vc-dired-toggle-terse-mode) allows you to
 toggle between terse display (only locked files) and full display (all
@@ -1044,13 +1044,13 @@ command in the minibuffer, to fine-tune VC Dired's 
output.
 file, and CVS detects conflicts, VC now offers to start an ediff
 session to resolve them.
 
-Alternatively, you can use the new command `vc-resolve-conflicts' to
+Alternatively, you can use the new command 'vc-resolve-conflicts' to
 resolve conflicts in a file at any time.  It works in any buffer that
 contains conflict markers as generated by rcsmerge (which is what CVS
 uses as well).
 
 *** You can now transfer changes between branches, using the new
-command vc-merge (C-x v m).  It is implemented for RCS and CVS.  When
+command 'vc-merge' (C-x v m).  It is implemented for RCS and CVS.  When
 you invoke it in a buffer under version-control, you can specify
 either an entire branch or a pair of versions, and the changes on that
 branch or between the two versions are merged into the working file.
@@ -1059,16 +1059,16 @@ using ediff.
 
 ** Changes in Font Lock
 
-*** The face and variable previously known as font-lock-reference-face
-are now called font-lock-constant-face to better reflect their typical
+*** The face and variable previously known as 'font-lock-reference-face'
+are now called 'font-lock-constant-face' to better reflect their typical
 use for highlighting constants and labels.  (Its face properties are
-unchanged.)  The variable font-lock-reference-face remains for now for
-compatibility reasons, but its value is font-lock-constant-face.
+unchanged.)  The variable 'font-lock-reference-face' remains for now for
+compatibility reasons, but its value is 'font-lock-constant-face'.
 
 ** Frame name display changes
 
-*** The command set-frame-name lets you set the name of the current
-frame.  You can use the new command select-frame-by-name to select and
+*** The command 'set-frame-name' lets you set the name of the current
+frame.  You can use the new command 'select-frame-by-name' to select and
 raise a frame; this is mostly useful on character-only terminals, or
 when many frames are invisible or iconified.
 
@@ -1096,11 +1096,11 @@ C-c C-a if repeated twice consecutively now moves to 
the process mark,
 which separates the pending input from the subprocess output and the
 previously sent input.
 
-C-c M-r now runs comint-previous-matching-input-from-input;
+C-c M-r now runs 'comint-previous-matching-input-from-input';
 it searches for a previous command, using the current pending input
 as the search string.
 
-*** New option compilation-scroll-output can be set to scroll
+*** New option 'compilation-scroll-output' can be set to scroll
 automatically in compilation-mode windows.
 
 ** C mode changes
@@ -1117,7 +1117,7 @@ style is still the default however.
 
 *** "java" style now conforms to Sun's JDK coding style.
 
-*** There are new commands c-beginning-of-defun, c-end-of-defun which
+*** There are new commands 'c-beginning-of-defun', 'c-end-of-defun' which
 are alternatives which you could bind to C-M-a and C-M-e if you prefer
 them.  They do not have key bindings by default.
 
@@ -1130,40 +1130,40 @@ namespace-open, namespace-close, and innamespace.
 *** File local variable settings of c-file-style and c-file-offsets
 makes the style variables local to that buffer only.
 
-*** New indentation functions c-lineup-close-paren,
-c-indent-one-line-block, c-lineup-dont-change.
+*** New indentation functions 'c-lineup-close-paren',
+'c-indent-one-line-block', 'c-lineup-dont-change'.
 
 *** Improvements (hopefully!) to the way CC Mode is loaded.  You
 should now be able to do a (require 'cc-mode) to get the entire
 package loaded properly for customization in your .emacs file.  A new
-variable c-initialize-on-load controls this and is t by default.
+variable 'c-initialize-on-load' controls this and is t by default.
 
-** Changes to hippie-expand.
+** Changes to 'hippie-expand'.
 
-*** New customization variable `hippie-expand-dabbrev-skip-space'. If
+*** New customization variable 'hippie-expand-dabbrev-skip-space'. If
 non-nil, trailing spaces may be included in the abbreviation to search for,
-which then gives the same behavior as the original `dabbrev-expand'.
+which then gives the same behavior as the original 'dabbrev-expand'.
 
-*** New customization variable `hippie-expand-dabbrev-as-symbol'. If
+*** New customization variable 'hippie-expand-dabbrev-as-symbol'. If
 non-nil, characters of syntax '_' is considered part of the word when
 expanding dynamically.
 
-*** New customization variable `hippie-expand-no-restriction'. If
+*** New customization variable 'hippie-expand-no-restriction'. If
 non-nil, narrowed buffers are widened before they are searched.
 
-*** New customization variable `hippie-expand-only-buffers'. If
+*** New customization variable 'hippie-expand-only-buffers'. If
 non-empty, buffers searched are restricted to the types specified in
 this list. Useful for example when constructing new special-purpose
-expansion functions with `make-hippie-expand-function'.
+expansion functions with 'make-hippie-expand-function'.
 
 *** Text properties of the expansion are no longer copied.
 
 ** Changes in BibTeX mode.
 
 *** Any titleword matching a regexp in the new variable
-bibtex-autokey-titleword-ignore (case sensitive) is ignored during
+'bibtex-autokey-titleword-ignore' (case sensitive) is ignored during
 automatic key generation.  This replaces variable
-bibtex-autokey-titleword-first-ignore, which only checked for matches
+'bibtex-autokey-titleword-first-ignore', which only checked for matches
 against the first word in the title.
 
 *** Autokey generation now uses all words from the title, not just
@@ -1182,9 +1182,9 @@ bibtex-autokey-name-case-convert.
 
 *** Support for character terminals is available: there is a new keymap
 and the vcursor will appear as an arrow between buffer text.  A
-variable `vcursor-interpret-input' allows input from the vcursor to be
+variable 'vcursor-interpret-input' allows input from the vcursor to be
 entered exactly as if typed.  Numerous functions, including
-`vcursor-compare-windows', have been rewritten to improve consistency
+'vcursor-compare-windows', have been rewritten to improve consistency
 in the selection of windows and corresponding keymaps.
 
 *** vcursor options can now be altered with M-x customize under the
@@ -1194,7 +1194,7 @@ Editing group once the package is loaded.
 generally a bad side effect.  Use M-x customize to set
 vcursor-key-bindings to t to restore the old behavior.
 
-*** vcursor-auto-disable can be `copy', which turns off copying from the
+*** vcursor-auto-disable can be 'copy', which turns off copying from the
 vcursor, but doesn't disable it, after any non-vcursor command.
 
 ** Ispell changes.
@@ -1219,7 +1219,7 @@ include:
 RefTeX has been updated in order to make it more usable with very
 large projects (like a several volume math book).  The parser has been
 re-written from scratch.  To get maximum speed from RefTeX, check the
-section `Optimizations' in the manual.
+section 'Optimizations' in the manual.
 
 *** New recursive parser.
 
@@ -1231,7 +1231,7 @@ recursive parser scans the individual files.
 
 Reparsing of changed document parts can now be made faster by enabling
 partial scans.  To use this feature, read the documentation string of
-the variable `reftex-enable-partial-scans' and set the variable to t.
+the variable 'reftex-enable-partial-scans' and set the variable to t.
 
     (setq reftex-enable-partial-scans t)
 
@@ -1250,13 +1250,13 @@ for large documents), you can reuse these buffers by 
setting
 
 *** References to external documents.
 
-The LaTeX package `xr' allows to cross-reference labels in external
+The LaTeX package 'xr' allows to cross-reference labels in external
 documents.  RefTeX can provide information about the external
 documents as well.  To use this feature, set up the \externaldocument
-macros required by the `xr' package and rescan the document with
-RefTeX.  The external labels can then be accessed with the `x' key in
-the selection buffer provided by `reftex-reference' (bound to `C-c )').
-The `x' key also works in the table of contents buffer.
+macros required by the 'xr' package and rescan the document with
+RefTeX.  The external labels can then be accessed with the 'x' key in
+the selection buffer provided by 'reftex-reference' (bound to `C-c )').
+The 'x' key also works in the table of contents buffer.
 
 *** Many more labeled LaTeX environments are recognized by default.
 
@@ -1269,13 +1269,13 @@ the enumeration of sections in the *toc* buffer 
accordingly.
 *** Mouse support for selection and *toc* buffers
 
 The mouse can now be used to select items in the selection and *toc*
-buffers.  See also the new option `reftex-highlight-selection'.
+buffers.  See also the new option 'reftex-highlight-selection'.
 
 *** New keymaps for selection and table of contents modes.
 
 The selection processes for labels and citation keys, and the table of
-contents buffer now have their own keymaps: `reftex-select-label-map',
-`reftex-select-bib-map', `reftex-toc-map'.  The selection processes
+contents buffer now have their own keymaps: 'reftex-select-label-map',
+'reftex-select-bib-map', 'reftex-toc-map'.  The selection processes
 have a number of new keys predefined.  In particular, TAB lets you
 enter a label with completion.  Check the on-the-fly help (press `?'
 at the selection prompt) or read the Info documentation to find out
@@ -1283,18 +1283,18 @@ more.
 
 *** Support for the varioref package
 
-The `v' key in the label selection buffer toggles \ref versus \vref.
+The 'v' key in the label selection buffer toggles \ref versus \vref.
 
 *** New hooks
 
 Three new hooks can be used to redefine the way labels, references,
 and citations are created. These hooks are
-`reftex-format-label-function', `reftex-format-ref-function',
-`reftex-format-cite-function'.
+'reftex-format-label-function', 'reftex-format-ref-function',
+'reftex-format-cite-function'.
 
 *** Citations outside LaTeX
 
-The command `reftex-citation' may also be used outside LaTeX (e.g. in
+The command 'reftex-citation' may also be used outside LaTeX (e.g. in
 a mail buffer).  See the Info documentation for details.
 
 *** Short context is no longer fontified.
@@ -1305,7 +1305,7 @@ fontified, use
 
    (setq reftex-refontify-context t)
 
-** file-cache-minibuffer-complete now accepts a prefix argument.
+** 'file-cache-minibuffer-complete' now accepts a prefix argument.
 With a prefix argument, it does not try to do completion of
 the file name within its directory; it only checks for other
 directories that contain the same file name.
@@ -1339,50 +1339,50 @@ uses it for keeping notes about his postal Chess games, 
but it should
 be helpful for other two-player games as well, as long as they have an
 established system of notation similar to Chess.
 
-*** The new minor mode checkdoc-minor-mode provides Emacs Lisp
+*** The new minor mode 'checkdoc-minor-mode' provides Emacs Lisp
 documentation string checking for style and spelling.  The style
 guidelines are found in the Emacs Lisp programming manual.
 
 *** The net-utils package makes some common networking features
 available in Emacs.  Some of these functions are wrappers around
-system utilities (ping, nslookup, etc.); others are implementations of
-simple protocols (finger, whois) in Emacs Lisp.  There are also
+system utilities ('ping', 'nslookup', etc.); others are implementations of
+simple protocols ('finger', 'whois') in Emacs Lisp.  There are also
 functions to make simple connections to TCP/IP ports for debugging and
 the like.
 
-*** highlight-changes-mode is a minor mode that uses colors to
+*** 'highlight-changes-mode' is a minor mode that uses colors to
 identify recently changed parts of the buffer text.
 
-*** The new package `midnight' lets you specify things to be done
+*** The new package 'midnight' lets you specify things to be done
 within Emacs at midnight--by default, kill buffers that you have not
 used in a considerable time.  To use this feature, customize
-the user option `midnight-mode' to t.
+the user option 'midnight-mode' to t.
 
 *** The file generic-x.el defines a number of simple major modes.
 
-  apache-generic-mode: For Apache and NCSA httpd configuration files
-  samba-generic-mode: Samba configuration files
-  fvwm-generic-mode: For fvwm initialization files
-  x-resource-generic-mode: For X resource files
-  hosts-generic-mode: For hosts files (.rhosts, /etc/hosts, etc.)
-  mailagent-rules-generic-mode: For mailagent .rules files
-  javascript-generic-mode: For JavaScript files
-  vrml-generic-mode: For VRML files
-  java-manifest-generic-mode: For Java MANIFEST files
-  java-properties-generic-mode: For Java property files
-  mailrc-generic-mode: For .mailrc files
+  'apache-generic-mode': For Apache and NCSA httpd configuration files
+  'samba-generic-mode': Samba configuration files
+  'fvwm-generic-mode': For fvwm initialization files
+  'x-resource-generic-mode': For X resource files
+  'hosts-generic-mode': For hosts files (.rhosts, /etc/hosts, etc.)
+  'mailagent-rules-generic-mode': For mailagent .rules files
+  'javascript-generic-mode': For JavaScript files
+  'vrml-generic-mode': For VRML files
+  'java-manifest-generic-mode': For Java MANIFEST files
+  'java-properties-generic-mode': For Java property files
+  'mailrc-generic-mode': For .mailrc files
 
   Platform-specific modes:
 
-  prototype-generic-mode: For Solaris/Sys V prototype files
-  pkginfo-generic-mode: For Solaris/Sys V pkginfo files
-  alias-generic-mode: For C shell alias files
-  inf-generic-mode: For MS-Windows INF files
-  ini-generic-mode: For MS-Windows INI files
-  reg-generic-mode: For MS-Windows Registry files
-  bat-generic-mode: For MS-Windows BAT scripts
-  rc-generic-mode: For MS-Windows Resource files
-  rul-generic-mode: For InstallShield scripts
+  'prototype-generic-mode': For Solaris/Sys V prototype files
+  'pkginfo-generic-mode': For Solaris/Sys V pkginfo files
+  'alias-generic-mode': For C shell alias files
+  'inf-generic-mode': For MS-Windows INF files
+  'ini-generic-mode': For MS-Windows INI files
+  'reg-generic-mode': For MS-Windows Registry files
+  'bat-generic-mode': For MS-Windows BAT scripts
+  'rc-generic-mode': For MS-Windows Resource files
+  'rul-generic-mode': For InstallShield scripts
 
 
 * Lisp changes in Emacs 20.3 since the Emacs Lisp Manual was published
@@ -1396,22 +1396,22 @@ Thus, each lisp file is read in a consistent way 
regardless of whether
 you started Emacs with --unibyte, so that a Lisp program gives
 consistent results regardless of how Emacs was started.
 
-** The new function assoc-default is useful for searching an alist,
+** The new function 'assoc-default' is useful for searching an alist,
 and using a default value if the key is not found there.  You can
 specify a comparison predicate, so this function is useful for
 searching comparing a string against an alist of regular expressions.
 
-** The functions unibyte-char-to-multibyte and
-multibyte-char-to-unibyte convert between unibyte and multibyte
+** The functions 'unibyte-char-to-multibyte' and
+'multibyte-char-to-unibyte' convert between unibyte and multibyte
 character codes, in a way that is appropriate for the current language
 environment.
 
-** The functions read-event, read-char and read-char-exclusive now
+** The functions 'read-event', 'read-char' and 'read-char-exclusive' now
 take two optional arguments.  PROMPT, if non-nil, specifies a prompt
 string.  SUPPRESS-INPUT-METHOD, if non-nil, says to disable the
 current input method for reading this one event.
 
-** Two new variables print-escape-nonascii and print-escape-multibyte
+** Two new variables 'print-escape-nonascii' and 'print-escape-multibyte'
 now control whether to output certain characters as
 backslash-sequences.  print-escape-nonascii applies to single-byte
 non-ASCII characters; print-escape-multibyte applies to multibyte
@@ -1433,7 +1433,7 @@ considered obsolete.  The function char-boundary-p has 
been deleted.
 
 See below for additional changes relating to multibyte characters.
 
-** defcustom, defface and defgroup now accept the keyword `:version'.
+** 'defcustom', 'defface' and 'defgroup' now accept the keyword ':version'.
 Use this to specify in which version of Emacs a certain variable's
 default value changed.  For example,
 
@@ -1446,9 +1446,9 @@ default value changed.  For example,
      :version "20.3")
 
 If an entire new group is added or the variables in it have the
-default values changed, then just add a `:version' to that group. It
+default values changed, then just add a ':version' to that group. It
 is recommended that new packages added to the distribution contain a
-`:version' in the top level group.
+':version' in the top level group.
 
 This information is used to control the customize-changed-options command.
 
@@ -1489,25 +1489,25 @@ clear that this would be very useful; windows tend to 
come and go in a
 very transitory fashion, so that trying to produce any specific effect
 through a window-local binding would not be very robust.
 
-** `sregexq' and `sregex' are two new functions for constructing
+** 'sregexq' and 'sregex' are two new functions for constructing
 "symbolic regular expressions."  These are Lisp expressions that, when
 evaluated, yield conventional string-based regexps.  The symbolic form
 makes it easier to construct, read, and maintain complex patterns.
 See the documentation in sregex.el.
 
-** parse-partial-sexp's return value has an additional element which
+** 'parse-partial-sexp's return value has an additional element which
 is used to pass information along if you pass it to another call to
 parse-partial-sexp, starting its scan where the first call ended.
 The contents of this field are not yet finalized.
 
-** eval-region now accepts a fourth optional argument READ-FUNCTION.
-If it is non-nil, that function is used instead of `read'.
+** 'eval-region' now accepts a fourth optional argument READ-FUNCTION.
+If it is non-nil, that function is used instead of 'read'.
 
-** unload-feature by default removes the feature's functions from
+** 'unload-feature' by default removes the feature's functions from
 known hooks to avoid trouble, but a package providing FEATURE can
 define a hook FEATURE-unload-hook to be run by unload-feature instead.
 
-** read-from-minibuffer no longer returns the argument DEFAULT-VALUE
+** 'read-from-minibuffer' no longer returns the argument DEFAULT-VALUE
 when the user enters empty input.  It now returns the null string, as
 it did in Emacs 19.  The default value is made available in the
 history via M-n, but it is not applied here as a default.
@@ -1516,66 +1516,66 @@ The other, more specialized minibuffer-reading 
functions continue to
 return the default value (not the null string) when the user enters
 empty input.
 
-** The new variable read-buffer-function controls which routine to use
+** The new variable 'read-buffer-function' controls which routine to use
 for selecting buffers.  For example, if you set this variable to
-`iswitchb-read-buffer', iswitchb will be used to read buffer names.
+'iswitchb-read-buffer', iswitchb will be used to read buffer names.
 Other functions can also be used if they accept the same arguments as
-`read-buffer' and return the selected buffer name as a string.
+'read-buffer' and return the selected buffer name as a string.
 
-** The new function read-passwd reads a password from the terminal,
+** The new function 'read-passwd' reads a password from the terminal,
 echoing a period for each character typed.  It takes three arguments:
 a prompt string, a flag which says "read it twice to make sure", and a
 default password to use if the user enters nothing.
 
-** The variable fill-nobreak-predicate gives major modes a way to
+** The variable 'fill-nobreak-predicate' gives major modes a way to
 specify not to break a line at certain places.  Its value is a
 function which is called with no arguments, with point located at the
 place where a break is being considered.  If the function returns
 non-nil, then the line won't be broken there.
 
-** window-end now takes an optional second argument, UPDATE.
+** 'window-end' now takes an optional second argument, UPDATE.
 If this is non-nil, then the function always returns an accurate
 up-to-date value for the buffer position corresponding to the
 end of the window, even if this requires computation.
 
-** other-buffer now takes an optional argument FRAME
+** 'other-buffer' now takes an optional argument FRAME
 which specifies which frame's buffer list to use.
 If it is nil, that means use the selected frame's buffer list.
 
-** The new variable buffer-display-time, always local in every buffer,
+** The new variable 'buffer-display-time', always local in every buffer,
 holds the value of (current-time) as of the last time that a window
 was directed to display this buffer.
 
 ** It is now meaningful to compare two window-configuration objects
-with `equal'.  Two window-configuration objects are equal if they
+with 'equal'.  Two 'window-configuration' objects are equal if they
 describe equivalent arrangements of windows, in the same frame--in
 other words, if they would give the same results if passed to
-set-window-configuration.
+'set-window-configuration'.
 
-** compare-window-configurations is a new function that compares two
+** 'compare-window-configurations' is a new function that compares two
 window configurations loosely.  It ignores differences in saved buffer
 positions and scrolling, and considers only the structure and sizes of
 windows and the choice of buffers to display.
 
-** The variable minor-mode-overriding-map-alist allows major modes to
+** The variable 'minor-mode-overriding-map-alist' allows major modes to
 override the key bindings of a minor mode.  The elements of this alist
-look like the elements of minor-mode-map-alist: (VARIABLE . KEYMAP).
+look like the elements of 'minor-mode-map-alist': (VARIABLE . KEYMAP).
 
 If the VARIABLE in an element of minor-mode-overriding-map-alist has a
 non-nil value, the paired KEYMAP is active, and totally overrides the
 map (if any) specified for the same variable in minor-mode-map-alist.
 
-minor-mode-overriding-map-alist is automatically local in all buffers,
+'minor-mode-overriding-map-alist' is automatically local in all buffers,
 and it is meant to be set by major modes.
 
-** The function match-string-no-properties is like match-string
+** The function 'match-string-no-properties' is like 'match-string'
 except that it discards all text properties from the result.
 
-** The function load-average now accepts an optional argument
+** The function 'load-average' now accepts an optional argument
 USE-FLOATS.  If it is non-nil, the load average values are returned as
 floating point numbers, rather than as integers to be divided by 100.
 
-** The new variable temporary-file-directory specifies the directory
+** The new variable 'temporary-file-directory' specifies the directory
 to use for creating temporary files.  The default value is determined
 in a reasonable way for your operating system; on GNU and Unix systems
 it is based on the TMP and TMPDIR environment variables.
@@ -1586,7 +1586,7 @@ it is based on the TMP and TMPDIR environment variables.
 keywords :visible and :filter.  The existing keyword :keys is now
 better supported.
 
-The variable `easy-menu-precalculate-equivalent-keybindings' controls
+The variable 'easy-menu-precalculate-equivalent-keybindings' controls
 a new feature which calculates keyboard equivalents for the menu when
 you define the menu.  The default is t.  If you rarely use menus, you
 can set the variable to nil to disable this precalculation feature;
@@ -1597,7 +1597,7 @@ then the calculation is done only if you use the menu bar.
 In a keymap, a key binding that has the format
  (STRING . REAL-BINDING) or (STRING HELP-STRING . REAL-BINDING)
 defines a menu item. Now a menu item definition may also be a list that
-starts with the symbol `menu-item'.
+starts with the symbol 'menu-item'.
 
 The format is:
  (menu-item ITEM-NAME) or
@@ -1617,7 +1617,7 @@ The supported properties include
 :keys DESCRIPTION
                  DESCRIPTION is a string that describes an equivalent keyboard
                   binding for REAL-BINDING.  DESCRIPTION is expanded with
-                  `substitute-command-keys' before it is used.
+                  'substitute-command-keys' before it is used.
 :key-sequence KEY-SEQUENCE
                  KEY-SEQUENCE is a key-sequence for an equivalent
                   keyboard binding.
@@ -1637,7 +1637,7 @@ Eventually ordinary X-buttons may be supported.
 
 ** New event types
 
-*** The new event type `mouse-wheel' is generated by a wheel on a
+*** The new event type 'mouse-wheel' is generated by a wheel on a
 mouse (such as the MS Intellimouse).  The event contains a delta that
 corresponds to the amount and direction that the wheel is rotated,
 which is typically used to implement a scroll or zoom.  The format is:
@@ -1653,7 +1653,7 @@ forward, away from the user.
 
 As of now, this event type is generated only on MS Windows.
 
-*** The new event type `drag-n-drop' is generated when a group of
+*** The new event type 'drag-n-drop' is generated when a group of
 files is selected in an application outside of Emacs, and then dragged
 and dropped onto an Emacs frame.  The event contains a list of
 filenames that were dragged and dropped, which are then typically
@@ -1669,9 +1669,9 @@ As of now, this event type is generated only on MS 
Windows.
 
 ** Changes relating to multibyte characters.
 
-*** The variable enable-multibyte-characters is now read-only;
+*** The variable 'enable-multibyte-characters' is now read-only;
 any attempt to set it directly signals an error.  The only way
-to change this value in an existing buffer is with set-buffer-multibyte.
+to change this value in an existing buffer is with 'set-buffer-multibyte'.
 
 *** In a string constant, `\ ' now stands for "nothing at all".  You
 can use it to terminate a hex escape which is followed by a character
@@ -1681,9 +1681,9 @@ that could otherwise be read as part of the hex escape.
 in Emacs 19 and before.
 
 The function chars-in-string has been deleted.
-The function concat-chars has been renamed to `string'.
+The function concat-chars has been renamed to 'string'.
 
-*** The function set-buffer-multibyte sets the flag in the current
+*** The function 'set-buffer-multibyte' sets the flag in the current
 buffer that says whether the buffer uses multibyte representation or
 unibyte representation.  If the argument is nil, it selects unibyte
 representation.  Otherwise it selects multibyte representation.
@@ -1694,12 +1694,12 @@ viewed as characters; a sequence of two bytes which is 
treated as
 one character when the buffer uses multibyte representation
 will count as two characters using unibyte representation.
 
-This function sets enable-multibyte-characters to record which
+This function sets 'enable-multibyte-characters' to record which
 representation is in use.  It also adjusts various data in the buffer
 (including its markers, overlays and text properties) so that they are
 consistent with the new representation.
 
-*** string-make-multibyte takes a string and converts it to multibyte
+*** 'string-make-multibyte' takes a string and converts it to multibyte
 representation.  Most of the time, you don't need to care
 about the representation, because Emacs converts when necessary;
 however, it makes a difference when you compare strings.
@@ -1708,7 +1708,7 @@ The conversion of non-ASCII characters works by adding 
the value of
 nonascii-insert-offset to each character, or by translating them
 using the table nonascii-translation-table.
 
-*** string-make-unibyte takes a string and converts it to unibyte
+*** 'string-make-unibyte' takes a string and converts it to unibyte
 representation.  Most of the time, you don't need to care about the
 representation, but it makes a difference when you compare strings.
 
@@ -1716,18 +1716,18 @@ The conversion from multibyte to unibyte representation
 loses information; the only time Emacs performs it automatically
 is when inserting a multibyte string into a unibyte buffer.
 
-*** string-as-multibyte takes a string, and returns another string
+*** 'string-as-multibyte' takes a string, and returns another string
 which contains the same bytes, but treats them as multibyte.
 
-*** string-as-unibyte takes a string, and returns another string
+*** 'string-as-unibyte' takes a string, and returns another string
 which contains the same bytes, but treats them as unibyte.
 
-*** The new function compare-strings lets you compare
+*** The new function 'compare-strings' lets you compare
 portions of two strings.  Unibyte strings are converted to multibyte,
 so that a unibyte string can match a multibyte string.
 You can specify whether to ignore case or not.
 
-*** assoc-ignore-case now uses compare-strings so that
+*** 'assoc-ignore-case' now uses compare-strings so that
 it can treat unibyte and multibyte strings as equal.
 
 *** Regular expression operations and buffer string searches now
@@ -1745,21 +1745,21 @@ expression [^\0-\177] works for it.
 *** Structure of coding system changed.
 
 All coding systems (including aliases and subsidiaries) are named
-by symbols; the symbol's `coding-system' property is a vector
+by symbols; the symbol's 'coding-system' property is a vector
 which defines the coding system.  Aliases share the same vector
 as the principal name, so that altering the contents of this
 vector affects the principal name and its aliases.  You can define
 your own alias name of a coding system by the function
-define-coding-system-alias.
+'define-coding-system-alias'.
 
 The coding system definition includes a property list of its own.  Use
-the new functions `coding-system-get' and `coding-system-put' to
-access such coding system properties as post-read-conversion,
-pre-write-conversion, character-translation-table-for-decode,
-character-translation-table-for-encode, mime-charset, and
-safe-charsets.  For instance, (coding-system-get 'iso-latin-1
+the new functions 'coding-system-get' and 'coding-system-put' to
+access such coding system properties as 'post-read-conversion',
+'pre-write-conversion', 'character-translation-table-for-decode',
+'character-translation-table-for-encode', 'mime-charset', and
+'safe-charsets'.  For instance, (coding-system-get 'iso-latin-1
 'mime-charset) gives the corresponding MIME-charset parameter
-`iso-8859-1'.
+'iso-8859-1'.
 
 Among the coding system properties listed above, safe-charsets is new.
 The value of this property is a list of character sets which this
@@ -1771,54 +1771,54 @@ also be handled safely by systems other than Emacs as 
far as they
 are capable of that coding system.  Though, Emacs itself can encode
 the other character sets and read it back correctly.
 
-*** The new function select-safe-coding-system can be used to find a
+*** The new function 'select-safe-coding-system' can be used to find a
 proper coding system for encoding the specified region or string.
 This function requires a user interaction.
 
-*** The new functions find-coding-systems-region and
-find-coding-systems-string are helper functions used by
-select-safe-coding-system.  They return a list of all proper coding
+*** The new functions 'find-coding-systems-region' and
+'find-coding-systems-string' are helper functions used by
+'select-safe-coding-system'.  They return a list of all proper coding
 systems to encode a text in some region or string.  If you don't want
 a user interaction, use one of these functions instead of
-select-safe-coding-system.
+'select-safe-coding-system'.
 
 *** The explicit encoding and decoding functions, such as
-decode-coding-region and encode-coding-string, now set
-last-coding-system-used to reflect the actual way encoding or decoding
+'decode-coding-region' and 'encode-coding-string', now set
+'last-coding-system-used' to reflect the actual way encoding or decoding
 was done.
 
-*** The new function detect-coding-with-language-environment can be
+*** The new function 'detect-coding-with-language-environment' can be
 used to detect a coding system of text according to priorities of
 coding systems used by some specific language environment.
 
-*** The functions detect-coding-region and detect-coding-string always
+*** The functions 'detect-coding-region' and 'detect-coding-string' always
 return a list if the arg HIGHEST is nil.  Thus, if only ASCII
 characters are found, they now return a list of single element
-`undecided' or its subsidiaries.
+'undecided' or its subsidiaries.
 
-*** The new functions coding-system-change-eol-conversion and
-coding-system-change-text-conversion can be used to get a different
+*** The new functions 'coding-system-change-eol-conversion' and
+'coding-system-change-text-conversion' can be used to get a different
 coding system than what specified only in how end-of-line or text is
 converted.
 
-*** The new function set-selection-coding-system can be used to set a
+*** The new function 'set-selection-coding-system' can be used to set a
 coding system for communicating with other X clients.
 
-*** The function `map-char-table' now passes as argument only valid
+*** The function 'map-char-table' now passes as argument only valid
 character codes, plus generic characters that stand for entire
 character sets or entire subrows of a character set.  In other words,
-each time `map-char-table' calls its FUNCTION argument, the key value
+each time 'map-char-table' calls its FUNCTION argument, the key value
 either will be a valid individual character code, or will stand for a
 range of characters.
 
-*** The new function `char-valid-p' can be used for checking whether a
+*** The new function 'char-valid-p' can be used for checking whether a
 Lisp object is a valid character code or not.
 
-*** The new function `charset-after' returns a charset of a character
+*** The new function 'charset-after' returns a charset of a character
 in the current buffer at position POS.
 
 *** Input methods are now implemented using the variable
-input-method-function.  If this is non-nil, its value should be a
+'input-method-function'.  If this is non-nil, its value should be a
 function; then, whenever Emacs reads an input event that is a printing
 character with no modifier bits, it calls that function, passing the
 event as an argument.  Often this function will read more input, first
@@ -1834,10 +1834,10 @@ The input method function is not called when reading 
the second and
 subsequent events of a key sequence.
 
 *** You can customize any language environment by using
-set-language-environment-hook and exit-language-environment-hook.
+'set-language-environment-hook' and 'exit-language-environment-hook'.
 
-The hook `exit-language-environment-hook' should be used to undo
-customizations that you made with set-language-environment-hook.  For
+The hook 'exit-language-environment-hook' should be used to undo
+customizations that you made with 'set-language-environment-hook'.  For
 instance, if you set up a special key binding for a specific language
 environment by set-language-environment-hook, you should set up
 exit-language-environment-hook to restore the normal key binding.
@@ -1859,9 +1859,9 @@ session or permanently.  (Permanent settings are stored 
automatically
 in your .emacs file.)
 
 ** Scroll bars are now on the left side of the window.
-You can change this with M-x customize-option scroll-bar-mode.
+You can change this with M-x customize-option 'scroll-bar-mode'.
 
-** The mode line no longer includes the string `Emacs'.
+** The mode line no longer includes the string 'Emacs'.
 This makes more space in the mode line for other information.
 
 ** When you select a region with the mouse, it is highlighted
@@ -1873,7 +1873,7 @@ delete the character before point, as usual.
 
 ** In an incremental search the whole current match is highlighted
 on terminals which support this.  (You can disable this feature
-by setting search-highlight to nil.)
+by setting 'search-highlight' to nil.)
 
 ** In the minibuffer, in some cases, you can now use M-n to
 insert the default value into the minibuffer as text.  In effect,
@@ -1885,7 +1885,7 @@ past.)
 ** In Text mode, now only blank lines separate paragraphs.
 This makes it possible to get the full benefit of Adaptive Fill mode
 in Text mode, and other modes derived from it (such as Mail mode).
-TAB in Text mode now runs the command indent-relative; this
+TAB in Text mode now runs the command 'indent-relative'; this
 makes a practical difference only when you use indented paragraphs.
 
 As a result, the old Indented Text mode is now identical to Text mode,
@@ -1897,18 +1897,18 @@ use the new mode, Paragraph Indent Text mode.
 ** Scrolling changes
 
 *** Scroll commands to scroll a whole screen now preserve the screen
-position of the cursor, if scroll-preserve-screen-position is non-nil.
+position of the cursor, if 'scroll-preserve-screen-position' is non-nil.
 
 In this mode, if you scroll several screens back and forth, finishing
 on the same screen where you started, the cursor goes back to the line
 where it started.
 
-*** If you set scroll-conservatively to a small number, then when you
+*** If you set 'scroll-conservatively' to a small number, then when you
 move point a short distance off the screen, Emacs will scroll the
 screen just far enough to bring point back on screen, provided that
-does not exceed `scroll-conservatively' lines.
+does not exceed 'scroll-conservatively' lines.
 
-*** The new variable scroll-margin says how close point can come to the
+*** The new variable 'scroll-margin' says how close point can come to the
 top or bottom of a window.  It is a number of screen lines; if point
 comes within that many lines of the top or bottom of the window, Emacs
 recenters the window.
@@ -2005,7 +2005,7 @@ sequences already in the buffer, byte by byte.  This is 
probably not
 what you want.
 
 If you want to edit a file of unibyte characters (Latin-1, for
-example), you can do it by specifying `no-conversion' as the coding
+example), you can do it by specifying 'no-conversion' as the coding
 system when reading the file.  This coding system also turns off
 multibyte characters in that buffer.
 
@@ -2038,18 +2038,18 @@ characters).
 
 Emacs does not use any fontset by default.  Its default font is still
 chosen as in previous versions.  You can tell Emacs to use a fontset
-with the `-fn' option or the `Font' X resource.
+with the '-fn' option or the 'Font' X resource.
 
 Emacs creates a standard fontset automatically according to the value
-of standard-fontset-spec.  This fontset's short name is
-`fontset-standard'.  Bold, italic, and bold-italic variants of the
+of 'standard-fontset-spec'.  This fontset's short name is
+'fontset-standard'.  Bold, italic, and bold-italic variants of the
 standard fontset are created automatically.
 
-If you specify a default ASCII font with the `Font' resource or `-fn'
+If you specify a default ASCII font with the 'Font' resource or '-fn'
 argument, a fontset is generated from it.  This works by replacing the
 FOUNDRY, FAMILY, ADD_STYLE, and AVERAGE_WIDTH fields of the font name
 with `*' then using this to specify a fontset.  This fontset's short
-name is `fontset-startup'.
+name is 'fontset-startup'.
 
 Emacs checks resources of the form Fontset-N where N is 0, 1, 2...
 The resource value should have this form:
@@ -2081,7 +2081,7 @@ Here is the substitution rule:
     (This is to prevent use of auto-scaled fonts.)
 
 The function which processes the fontset resource value to create the
-fontset is called create-fontset-from-fontset-spec.  You can also call
+fontset is called 'create-fontset-from-fontset-spec'.  You can also call
 that function explicitly to create a fontset.
 
 With the X resource Emacs.Font, you can specify a fontset name just
@@ -2127,7 +2127,7 @@ If the immediately following command does not use the 
coding system,
 then C-x RET c ultimately has no effect.
 
 For example, C-x RET c iso-8859-1 RET C-x C-f temp RET
-visits the file `temp' treating it as ISO Latin-1.
+visits the file 'temp' treating it as ISO Latin-1.
 
 *** You can specify the coding system for a file using the -*-
 construct.  Include `coding: CODINGSYSTEM;' inside the -*-...-*-
@@ -2169,7 +2169,7 @@ in the corresponding buffer.
 
 By default, process input and output are not translated at all.
 
-*** The variable file-name-coding-system specifies the coding system
+*** The variable 'file-name-coding-system' specifies the coding system
 to use for encoding file names before operating on them.
 It is also used for decoding file names obtained from the system.
 
@@ -2203,7 +2203,7 @@ the coding system used in the visited file.  It normally 
follows the
 first dash.
 
 A dash indicates the default state of affairs: no code conversion
-(except CRLF => newline if appropriate).  `=' means no conversion
+(except CRLF => newline if appropriate).  '=' means no conversion
 whatsoever.  The ISO 8859 coding systems are represented by digits
 1 through 9.  Other coding systems are represented by letters:
 
@@ -2232,7 +2232,7 @@ two additional characters appear in between the dash and 
the file
 coding system.  These two characters describe the coding system for
 keyboard input, and the coding system for terminal output.
 
-*** The new variable rmail-file-coding-system specifies the code
+*** The new variable 'rmail-file-coding-system' specifies the code
 conversion to use for RMAIL files.  The default value is nil.
 
 When you read mail with Rmail, each message is decoded automatically
@@ -2240,7 +2240,7 @@ into Emacs' internal format.  This has nothing to do with
 rmail-file-coding-system.  That variable controls reading and writing
 Rmail files themselves.
 
-*** The new variable sendmail-coding-system specifies the code
+*** The new variable 'sendmail-coding-system' specifies the code
 conversion for outgoing mail.  The default value is nil.
 
 Actually, there are three different ways of specifying the coding system
@@ -2259,7 +2259,7 @@ translations.
 
 ** An easy new way to visit a file with no code or format conversion
 of any kind: Use M-x find-file-literally.  There is also a command
-insert-file-literally which inserts a file into the current buffer
+'insert-file-literally' which inserts a file into the current buffer
 without any conversion.
 
 ** C-q's handling of octal character codes is changed.
@@ -2277,7 +2277,7 @@ Precisely which Info files are used to look it up depends 
on the major
 mode.  For example, in C mode, the GNU libc manual is used.
 
 ** M-TAB in most programming language modes now runs the command
-complete-symbol.  This command performs completion on the symbol name
+'complete-symbol'.  This command performs completion on the symbol name
 in the buffer before point.
 
 With a numeric argument, it performs completion based on the set of
@@ -2310,19 +2310,19 @@ tell Emacs to go ahead anyway.
 
 ** If you wish to use Show Paren mode to display matching parentheses,
 it is no longer sufficient to load paren.el.  Instead you must call
-show-paren-mode.
+'show-paren-mode'.
 
 ** If you wish to use Delete Selection mode to replace a highlighted
 selection when you insert new text, it is no longer sufficient to load
-delsel.el.  Instead you must call the function delete-selection-mode.
+delsel.el.  Instead you must call the function 'delete-selection-mode'.
 
 ** If you wish to use Partial Completion mode to complete partial words
 within symbols or filenames, it is no longer sufficient to load
-complete.el.  Instead you must call the function partial-completion-mode.
+complete.el.  Instead you must call the function 'partial-completion-mode'.
 
 ** If you wish to use uniquify to rename buffers for you,
 it is no longer sufficient to load uniquify.el.  You must also
-set uniquify-buffer-name-style to one of the non-nil legitimate values.
+set 'uniquify-buffer-name-style' to one of the non-nil legitimate values.
 
 ** Changes in View mode.
 
@@ -2330,23 +2330,23 @@ set uniquify-buffer-name-style to one of the non-nil 
legitimate values.
 Do H in view mode for a list of commands.
 
 *** There are two new commands for entering View mode:
-view-file-other-frame and view-buffer-other-frame.
+'view-file-other-frame' and 'view-buffer-other-frame'.
 
 *** Exiting View mode does a better job of restoring windows to their
 previous state.
 
-*** New customization variable view-scroll-auto-exit. If non-nil,
+*** New customization variable 'view-scroll-auto-exit'. If non-nil,
 scrolling past end of buffer makes view mode exit.
 
-*** New customization variable view-exits-all-viewing-windows.  If
+*** New customization variable 'view-exits-all-viewing-windows'.  If
 non-nil, view-mode will at exit restore all windows viewing buffer,
 not just the selected window.
 
-*** New customization variable view-read-only.  If non-nil, visiting a
-read-only file automatically enters View mode, and toggle-read-only
+*** New customization variable 'view-read-only'.  If non-nil, visiting a
+read-only file automatically enters View mode, and 'toggle-read-only'
 turns View mode on or off.
 
-*** New customization variable view-remove-frame-by-deleting controls
+*** New customization variable 'view-remove-frame-by-deleting' controls
 how to remove a not needed frame at view mode exit. If non-nil,
 delete the frame, if nil make an icon of it.
 
@@ -2363,10 +2363,10 @@ blocks if a match is inside the block.
 
 The block is hidden again if the search is continued and the next match
 is outside the block.  By customizing the variable
-isearch-hide-immediately you can choose to hide all the temporarily
+'isearch-hide-immediately' you can choose to hide all the temporarily
 shown blocks only when exiting from incremental search.
 
-By customizing the variable hs-isearch-open you can choose what kind
+By customizing the variable 'hs-isearch-open' you can choose what kind
 of blocks to temporarily show during isearch: comment blocks, code
 blocks, all of them or none.
 
@@ -2384,7 +2384,7 @@ However, the mode will not be changed if
 
 This applies to M-x set-visited-file-name as well.
 
-However, if you set change-major-mode-with-file-name to nil, then
+However, if you set 'change-major-mode-with-file-name' to nil, then
 these commands do not change the major mode.
 
 ** M-x occur changes.
@@ -2440,30 +2440,30 @@ The expansion is also copied verbatim if the 
abbreviation itself has
 mixed case.  And using SPC M-/ to copy an additional word always
 copies it verbatim except when the previous copied word is all caps.
 
-*** The values of `dabbrev-case-replace' and `dabbrev-case-fold-search'
+*** The values of 'dabbrev-case-replace' and 'dabbrev-case-fold-search'
 are no longer Lisp expressions.  They have simply three possible
 values.
 
-`dabbrev-case-replace' has these three values: nil (don't preserve
-case), t (do), or `case-replace' (do like M-x query-replace).
-`dabbrev-case-fold-search' has these three values: nil (don't ignore
-case), t (do), or `case-fold-search' (do like search).
+'dabbrev-case-replace' has these three values: nil (don't preserve
+case), t (do), or 'case-replace' (do like M-x query-replace).
+'dabbrev-case-fold-search' has these three values: nil (don't ignore
+case), t (do), or 'case-fold-search' (do like search).
 
 ** Minibuffer history lists are truncated automatically now to a
-certain length.  The variable history-length specifies how long they
+certain length.  The variable 'history-length' specifies how long they
 can be.  The default value is 30.
 
 ** Changes in Mail mode.
 
-*** The key C-x m no longer runs the `mail' command directly.
-Instead, it runs the command `compose-mail', which invokes the mail
+*** The key C-x m no longer runs the 'mail' command directly.
+Instead, it runs the command 'compose-mail', which invokes the mail
 composition mechanism you have selected with the variable
-`mail-user-agent'.  The default choice of user agent is
-`sendmail-user-agent', which gives behavior compatible with the old
+'mail-user-agent'.  The default choice of user agent is
+'sendmail-user-agent', which gives behavior compatible with the old
 behavior.
 
-C-x 4 m now runs compose-mail-other-window, and C-x 5 m runs
-compose-mail-other-frame.
+C-x 4 m now runs 'compose-mail-other-window', and C-x 5 m runs
+'compose-mail-other-frame'.
 
 *** While composing a reply to a mail message, from Rmail, you can use
 the command C-c C-r to cite just the region from the message you are
@@ -2480,23 +2480,23 @@ need to expand mail aliases yourself before sending 
mail.
 
 *** New features in the mail-complete command.
 
-**** The mail-complete command now inserts the user's full name,
-for local users or if that is known.  The variable mail-complete-style
+**** The 'mail-complete' command now inserts the user's full name,
+for local users or if that is known.  The variable 'mail-complete-style'
 controls the style to use, and whether to do this at all.
-Its values are like those of mail-from-style.
+Its values are like those of 'mail-from-style'.
 
-**** The variable mail-passwd-command lets you specify a shell command
+**** The variable 'mail-passwd-command' lets you specify a shell command
 to run to fetch a set of password-entries that add to the ones in
 /etc/passwd.
 
-**** The variable mail-passwd-file now specifies a list of files to read
+**** The variable 'mail-passwd-file' now specifies a list of files to read
 to get the list of user ids.  By default, one file is used:
 /etc/passwd.
 
 ** You can "quote" a file name to inhibit special significance of
 special syntax, by adding `/:' to the beginning.  Thus, if you have a
 directory named `/foo:', you can prevent it from being treated as a
-reference to a remote host named `foo' by writing it as `/:/foo:'.
+reference to a remote host named 'foo' by writing it as `/:/foo:'.
 
 Emacs uses this new construct automatically when necessary, such as
 when you start it with a working directory whose name might otherwise
@@ -2560,7 +2560,7 @@ for output.
 Gnus.
 
 *** Scoring can now be performed with logical operators like
-`and', `or', `not', and parent redirection.
+'and', 'or', 'not', and parent redirection.
 
 *** Article washing status can be displayed in the
 article mode line.
@@ -2569,18 +2569,18 @@ article mode line.
 
 *** Suppression of duplicate articles based on Message-ID.
 
-(setq gnus-suppress-duplicates t)
+    (setq gnus-suppress-duplicates t)
 
 *** New variables for specifying what score and adapt files
 are to be considered home score and adapt files.  See
-`gnus-home-score-file' and `gnus-home-adapt-files'.
+'gnus-home-score-file' and 'gnus-home-adapt-files'.
 
 *** Groups can inherit group parameters from parent topics.
 
 *** Article editing has been revamped and is now usable.
 
 *** Signatures can be recognized in more intelligent fashions.
-See `gnus-signature-separator' and `gnus-signature-limit'.
+See 'gnus-signature-separator' and 'gnus-signature-limit'.
 
 *** Summary pick mode has been made to look more nn-like.
 Line numbers are displayed and the `.' command can be
@@ -2597,7 +2597,7 @@ generating lines in buffers.
 *** Several commands in the group buffer can be undone with
 `C-M-_'.
 
-*** Scoring can be done on words using the new score type `w'.
+*** Scoring can be done on words using the new score type 'w'.
 
 *** Adaptive scoring can be done on a Subject word-by-word basis:
 
@@ -2616,7 +2616,7 @@ the native server.
    `M-x gnus-group-clear-data-on-native-groups'
 
 *** A new command for reading collections of documents
-(nndoc with nnvirtual on top) has been added -- `C-M-d'.
+(nndoc with nnvirtual on top) has been added -- 'C-M-d'.
 
 *** Process mark sets can be pushed and popped.
 
@@ -2651,14 +2651,14 @@ sorting functions, and each topic can be sorted 
independently.
 *** More hooks and functions have been added to remove junk
 from incoming mail before saving the mail.
 
-    See `nnmail-prepare-incoming-header-hook'.
+    See 'nnmail-prepare-incoming-header-hook'.
 
 *** The nnml mail backend now understands compressed article files.
 
 *** To enable Gnus to read/post multi-lingual articles, you must execute
 the following code, for instance, in your .emacs.
 
-       (add-hook 'gnus-startup-hook 'gnus-mule-initialize)
+       (add-hook 'gnus-startup-hook #'gnus-mule-initialize)
 
 Then, when you start Gnus, it will decode non-ASCII text automatically
 and show appropriate characters.  (Note: if you are using gnus-mime
@@ -2712,17 +2712,17 @@ share the same style variable settings; to make them 
buffer local, set
 c-style-variables-are-local-p to t in your .emacs file.  Note that you
 must do this *before* CC Mode is loaded.
 
-*** The new variable c-indentation-style holds the C style name
+*** The new variable 'c-indentation-style' holds the C style name
 of the current buffer.
 
-*** The variable c-block-comments-indent-p has been deleted, because
+*** The variable 'c-block-comments-indent-p' has been deleted, because
 it is no longer necessary.  C mode now handles all the supported styles
 of block comments, with no need to say which one you will use.
 
 *** There is a new indentation style "python", which specifies the C
 style that the Python developers like.
 
-*** There is a new c-cleanup-list option: brace-elseif-brace.
+*** There is a new 'c-cleanup-list' option: brace-elseif-brace.
 This says to put ...} else if (...) {... on one line,
 just as brace-else-brace says to put ...} else {... on one line.
 
@@ -2744,17 +2744,17 @@ other developers.  Such files are made read-only by 
CVS.  To get a
 writable copy, type C-x C-q in a buffer visiting such a file.  VC then
 calls "cvs edit", which notifies the other developers of it.
 
-*** vc-version-diff (C-u C-x v =) now suggests reasonable defaults for
+*** 'vc-version-diff' (C-u C-x v =) now suggests reasonable defaults for
 version numbers, based on the current state of the file.
 
 ** Calendar changes.
 
-*** A new function, list-holidays, allows you list holidays or
+*** A new function, 'list-holidays', allows you list holidays or
 subclasses of holidays for ranges of years.  Related menu items allow
 you do this for the year of the selected date, or the
 following/previous years.
 
-*** There is now support for the Baha'i calendar system.  Use `pb' in
+*** There is now support for the Baha'i calendar system.  Use 'pb' in
 the *Calendar* buffer to display the current Baha'i date.  The Baha'i
 calendar, or "Badi calendar" is a system of 19 months with 19 days
 each, and 4 intercalary days (5 during a Gregorian leap year).  The
@@ -2771,17 +2771,17 @@ layout.
 Some printer systems print a header page and force the first page to
 be printed on the back of the header page when using duplex.  If your
 printer system has this behavior, set variable
-`ps-banner-page-when-duplexing' to t.
+'ps-banner-page-when-duplexing' to t.
 
-If variable `ps-banner-page-when-duplexing' is non-nil, it prints a
+If variable 'ps-banner-page-when-duplexing' is non-nil, it prints a
 blank page as the very first printed page.  So, it behaves as if the
 very first character of buffer (or region) were a form feed ^L (\014).
 
-The variable `ps-spool-config' specifies who is responsible for
+The variable 'ps-spool-config' specifies who is responsible for
 setting duplex mode and page size.  Valid values are:
 
- lpr-switches    duplex and page size are configured by `ps-lpr-switches'.
-                Don't forget to set `ps-lpr-switches' to select duplex
+ lpr-switches    duplex and page size are configured by 'ps-lpr-switches'.
+                Don't forget to set 'ps-lpr-switches' to select duplex
                 printing for your printer.
 
  setpagedevice   duplex and page size are configured by ps-print using the
@@ -2790,15 +2790,15 @@ setting duplex mode and page size.  Valid values are:
  nil             duplex and page size are configured by ps-print *not* using
                 the setpagedevice PostScript operator.
 
-The variable `ps-spool-tumble' specifies how the page images on
+The variable 'ps-spool-tumble' specifies how the page images on
 opposite sides of a sheet are oriented with respect to each other.  If
-`ps-spool-tumble' is nil, ps-print produces output suitable for
-bindings on the left or right.  If `ps-spool-tumble' is non-nil,
+'ps-spool-tumble' is nil, ps-print produces output suitable for
+bindings on the left or right.  If 'ps-spool-tumble' is non-nil,
 ps-print produces output suitable for bindings at the top or bottom.
-This variable takes effect only if `ps-spool-duplex' is non-nil.
+This variable takes effect only if 'ps-spool-duplex' is non-nil.
 The default value is nil.
 
-The variable `ps-header-frame-alist' specifies a header frame
+The variable 'ps-header-frame-alist' specifies a header frame
 properties alist.  Valid frame properties are:
 
   fore-color   Specify the foreground frame color.
@@ -2824,25 +2824,25 @@ properties alist.  Valid frame properties are:
 Any other property is ignored.
 
 Don't change this alist directly; instead use Custom, or the
-`ps-value', `ps-get', `ps-put' and `ps-del' functions (see there for
+'ps-value', 'ps-get', 'ps-put' and 'ps-del' functions (see there for
 documentation).
 
 Ps-print can also print footers.  The footer variables are:
-`ps-print-footer', `ps-footer-offset', `ps-print-footer-frame',
-`ps-footer-font-family', `ps-footer-font-size', `ps-footer-line-pad',
-`ps-footer-lines', `ps-left-footer', `ps-right-footer' and
-`ps-footer-frame-alist'.  These variables are similar to those
+'ps-print-footer', 'ps-footer-offset', 'ps-print-footer-frame',
+'ps-footer-font-family', 'ps-footer-font-size', 'ps-footer-line-pad',
+'ps-footer-lines', 'ps-left-footer', 'ps-right-footer' and
+'ps-footer-frame-alist'.  These variables are similar to those
 controlling headers.
 
 *** Color management (subgroup)
 
-If `ps-print-color-p' is non-nil, the buffer's text will be printed in
+If 'ps-print-color-p' is non-nil, the buffer's text will be printed in
 color.
 
 *** Face Management (subgroup)
 
 If you need to print without worrying about face background colors,
-set the variable `ps-use-face-background' which specifies if face
+set the variable 'ps-use-face-background' which specifies if face
 background should be used.  Valid values are:
 
  t             always use face background color.
@@ -2851,47 +2851,47 @@ background should be used.  Valid values are:
 
 *** N-up printing (subgroup)
 
-The variable `ps-n-up-printing' specifies the number of pages per
+The variable 'ps-n-up-printing' specifies the number of pages per
 sheet of paper.
 
-The variable `ps-n-up-margin' specifies the margin in points (pt)
+The variable 'ps-n-up-margin' specifies the margin in points (pt)
 between the sheet border and the n-up printing.
 
-If variable `ps-n-up-border-p' is non-nil, a border is drawn around
+If variable 'ps-n-up-border-p' is non-nil, a border is drawn around
 each page.
 
-The variable `ps-n-up-filling' specifies how the page matrix is filled
+The variable 'ps-n-up-filling' specifies how the page matrix is filled
 on each sheet of paper.  Following are the valid values for
-`ps-n-up-filling' with a filling example using a 3x4 page matrix:
+'ps-n-up-filling' with a filling example using a 3x4 page matrix:
 
-   `left-top'   1  2  3  4         `left-bottom'    9  10 11 12
+   'left-top'   1  2  3  4         'left-bottom'    9  10 11 12
                5  6  7  8                          5  6  7  8
                9  10 11 12                         1  2  3  4
 
-   `right-top'  4  3  2  1         `right-bottom'   12 11 10 9
+   'right-top'  4  3  2  1         'right-bottom'   12 11 10 9
                8  7  6  5                          8  7  6  5
                12 11 10 9                          4  3  2  1
 
-   `top-left'   1  4  7  10        `bottom-left'    3  6  9  12
+   'top-left'   1  4  7  10        'bottom-left'    3  6  9  12
                2  5  8  11                         2  5  8  11
                3  6  9  12                         1  4  7  10
 
-   `top-right'  10 7  4  1         `bottom-right'   12 9  6  3
+   'top-right'  10 7  4  1         'bottom-right'   12 9  6  3
                11 8  5  2                          11 8  5  2
                12 9  6  3                          10 7  4  1
 
-Any other value is treated as `left-top'.
+Any other value is treated as 'left-top'.
 
 *** Zebra stripes (subgroup)
 
-The variable `ps-zebra-color' controls the zebra stripes grayscale or
+The variable 'ps-zebra-color' controls the zebra stripes grayscale or
 RGB color.
 
-The variable `ps-zebra-stripe-follow' specifies how zebra stripes
+The variable 'ps-zebra-stripe-follow' specifies how zebra stripes
 continue on next page.  Visually, valid values are (the character `+'
 to the right of each column indicates that a line is printed):
 
-                  `nil'        `follow'        `full'        `full-follow'
+                  'nil'        'follow'        'full'        'full-follow'
    Current Page --------     -----------     ---------     ----------------
                1  XXXXX +   1  XXXXXXXX +   1  XXXXXX +   1  XXXXXXXXXXXXX +
                2  XXXXX +   2  XXXXXXXX +   2  XXXXXX +   2  XXXXXXXXXXXXX +
@@ -2919,86 +2919,86 @@ to the right of each column indicates that a line is 
printed):
                22       +   22          +
                --------     -----------     ---------     ----------------
 
-Any other value is treated as `nil'.
+Any other value is treated as 'nil'.
 
 
 *** Printer management (subgroup)
 
-The variable `ps-printer-name-option' determines the option used by
+The variable 'ps-printer-name-option' determines the option used by
 some utilities to indicate the printer name; it's used only when
-`ps-printer-name' is a non-empty string.  If you're using the lpr
-utility to print, for example, `ps-printer-name-option' should be set
+'ps-printer-name' is a non-empty string.  If you're using the lpr
+utility to print, for example, 'ps-printer-name-option' should be set
 to "-P".
 
-The variable `ps-manual-feed' indicates if the printer requires manual
+The variable 'ps-manual-feed' indicates if the printer requires manual
 paper feeding.  If it's nil, automatic feeding takes place.  If it's
 non-nil, manual feeding takes place.
 
-The variable `ps-end-with-control-d' specifies whether C-d (\x04)
+The variable 'ps-end-with-control-d' specifies whether C-d (\x04)
 should be inserted at end of the generated PostScript.  Non-nil means
 do so.
 
 *** Page settings (subgroup)
 
-If variable `ps-warn-paper-type' is nil, it's *not* treated as an
+If variable 'ps-warn-paper-type' is nil, it's *not* treated as an
 error if the PostScript printer doesn't have a paper with the size
-indicated by `ps-paper-type'; the default paper size will be used
-instead.  If `ps-warn-paper-type' is non-nil, an error is signaled if
+indicated by 'ps-paper-type'; the default paper size will be used
+instead.  If 'ps-warn-paper-type' is non-nil, an error is signaled if
 the PostScript printer doesn't support a paper with the size indicated
-by `ps-paper-type'.  This is used when `ps-spool-config' is set to
-`setpagedevice'.
+by 'ps-paper-type'.  This is used when 'ps-spool-config' is set to
+'setpagedevice'.
 
-The variable `ps-print-upside-down' determines the orientation for
-printing pages: nil means `normal' printing, non-nil means
-`upside-down' printing (that is, the page is rotated by 180 degrees).
+The variable 'ps-print-upside-down' determines the orientation for
+printing pages: nil means 'normal' printing, non-nil means
+'upside-down' printing (that is, the page is rotated by 180 degrees).
 
-The variable `ps-selected-pages' specifies which pages to print.  If
+The variable 'ps-selected-pages' specifies which pages to print.  If
 it's nil, all pages are printed.  If it's a list, list elements may be
 integers specifying a single page to print, or cons cells (FROM . TO)
 specifying to print from page FROM to TO.  Invalid list elements, that
 is integers smaller than one, or elements whose FROM is greater than
 its TO, are ignored.
 
-The variable `ps-even-or-odd-pages' specifies how to print even/odd
+The variable 'ps-even-or-odd-pages' specifies how to print even/odd
 pages.  Valid values are:
 
    nil         print all pages.
 
-   `even-page' print only even pages.
+   'even-page' print only even pages.
 
-   `odd-page'  print only odd pages.
+   'odd-page'  print only odd pages.
 
-   `even-sheet'        print only even sheets.
-               That is, if `ps-n-up-printing' is 1, it behaves like
-               `even-page', but for values greater than 1, it'll
+   'even-sheet'        print only even sheets.
+               That is, if 'ps-n-up-printing' is 1, it behaves like
+               'even-page', but for values greater than 1, it'll
                print only the even sheet of paper.
 
-   `odd-sheet' print only odd sheets.
-               That is, if `ps-n-up-printing' is 1, it behaves like
-               `odd-page'; but for values greater than 1, it'll print
+   'odd-sheet' print only odd sheets.
+               That is, if 'ps-n-up-printing' is 1, it behaves like
+               'odd-page'; but for values greater than 1, it'll print
                only the odd sheet of paper.
 
 Any other value is treated as nil.
 
-If you set `ps-selected-pages' (see there for documentation), pages
-are filtered by `ps-selected-pages', and then by
-`ps-even-or-odd-pages'.  For example, if we have:
+If you set 'ps-selected-pages' (see there for documentation), pages
+are filtered by 'ps-selected-pages', and then by
+'ps-even-or-odd-pages'.  For example, if we have:
 
    (setq ps-selected-pages '(1 4 (6 . 10) (12 . 16) 20))
 
-and we combine this with `ps-even-or-odd-pages' and
-`ps-n-up-printing', we get:
+and we combine this with 'ps-even-or-odd-pages' and
+'ps-n-up-printing', we get:
 
-`ps-n-up-printing' = 1:
-   `ps-even-or-odd-pages'      PAGES PRINTED
+'ps-n-up-printing' = 1:
+   'ps-even-or-odd-pages'      PAGES PRINTED
        nil                     1, 4, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 20
        even-page               4, 6, 8, 10, 12, 14, 16, 20
        odd-page                1, 7, 9, 13, 15
        even-sheet              4, 6, 8, 10, 12, 14, 16, 20
        odd-sheet               1, 7, 9, 13, 15
 
-`ps-n-up-printing' = 2:
-   `ps-even-or-odd-pages'      PAGES PRINTED
+'ps-n-up-printing' = 2:
+   'ps-even-or-odd-pages'      PAGES PRINTED
        nil                     1/4, 6/7, 8/9, 10/12, 13/14, 15/16, 20
        even-page               4/6, 8/10, 12/14, 16/20
        odd-page                1/7, 9/13, 15
@@ -3007,23 +3007,23 @@ and we combine this with `ps-even-or-odd-pages' and
 
 *** Miscellany (subgroup)
 
-The variable `ps-error-handler-message' specifies where error handler
+The variable 'ps-error-handler-message' specifies where error handler
 messages should be sent.
 
 It is also possible to add a user-defined PostScript prologue code in
 front of all generated prologue code by setting the variable
-`ps-user-defined-prologue'.
+'ps-user-defined-prologue'.
 
-The variable `ps-line-number-font' specifies the font for line numbers.
+The variable 'ps-line-number-font' specifies the font for line numbers.
 
-The variable `ps-line-number-font-size' specifies the font size in
+The variable 'ps-line-number-font-size' specifies the font size in
 points for line numbers.
 
-The variable `ps-line-number-color' specifies the color for line
-numbers.  See `ps-zebra-color' for documentation.
+The variable 'ps-line-number-color' specifies the color for line
+numbers.  See 'ps-zebra-color' for documentation.
 
-The variable `ps-line-number-step' specifies the interval in which
-line numbers are printed.  For example, if `ps-line-number-step' is set
+The variable 'ps-line-number-step' specifies the interval in which
+line numbers are printed.  For example, if 'ps-line-number-step' is set
 to 2, the printing will look like:
 
    1 one line
@@ -3040,14 +3040,14 @@ integer         an integer specifying the interval in 
which line numbers are
                printed.  If it's smaller than or equal to zero, 1
                is used.
 
-`zebra'                specifies that only the line number of the first line 
in a
+'zebra'                specifies that only the line number of the first line 
in a
                zebra stripe is to be printed.
 
-Any other value is treated as `zebra'.
+Any other value is treated as 'zebra'.
 
-The variable `ps-line-number-start' specifies the starting point in
-the interval given by `ps-line-number-step'.  For example, if
-`ps-line-number-step' is set to 3, and `ps-line-number-start' is set to
+The variable 'ps-line-number-start' specifies the starting point in
+the interval given by 'ps-line-number-step'.  For example, if
+'ps-line-number-step' is set to 3, and 'ps-line-number-start' is set to
 3, the output will look like:
 
      one line
@@ -3062,20 +3062,20 @@ the interval given by `ps-line-number-step'.  For 
example, if
      one line
      ...
 
-The variable `ps-postscript-code-directory' specifies the directory
+The variable 'ps-postscript-code-directory' specifies the directory
 where the PostScript prologue file used by ps-print is found.
 
-The variable `ps-line-spacing' determines the line spacing in points,
+The variable 'ps-line-spacing' determines the line spacing in points,
 for ordinary text, when generating PostScript (similar to
-`ps-font-size').
+'ps-font-size').
 
-The variable `ps-paragraph-spacing' determines the paragraph spacing,
+The variable 'ps-paragraph-spacing' determines the paragraph spacing,
 in points, for ordinary text, when generating PostScript (similar to
-`ps-font-size').
+'ps-font-size').
 
-The variable `ps-paragraph-regexp' specifies the paragraph delimiter.
+The variable 'ps-paragraph-regexp' specifies the paragraph delimiter.
 
-The variable `ps-begin-cut-regexp' and `ps-end-cut-regexp' specify the
+The variable 'ps-begin-cut-regexp' and 'ps-end-cut-regexp' specify the
 start and end of a region to cut out when printing.
 
 ** hideshow changes.
@@ -3083,33 +3083,33 @@ start and end of a region to cut out when printing.
 *** now supports hiding of blocks of single line comments (like // for
 C++, ; for lisp).
 
-*** Support for java-mode added.
+*** Support for 'java-mode' added.
 
-*** When doing `hs-hide-all' it is now possible to also hide the comments
-in the file if `hs-hide-comments-when-hiding-all' is set.
+*** When doing 'hs-hide-all' it is now possible to also hide the comments
+in the file if 'hs-hide-comments-when-hiding-all' is set.
 
-*** The new function `hs-hide-initial-comment' hides the comments at
+*** The new function 'hs-hide-initial-comment' hides the comments at
 the beginning of the files.  Finally those huge RCS logs don't stay in your
-way!  This is run by default when entering the `hs-minor-mode'.
+way!  This is run by default when entering the 'hs-minor-mode'.
 
-*** Now uses overlays instead of `selective-display', so is more
+*** Now uses overlays instead of 'selective-display', so is more
 robust and a lot faster.
 
 *** A block beginning can span multiple lines.
 
-*** The new variable `hs-show-hidden-short-form' if t, directs hideshow
+*** The new variable 'hs-show-hidden-short-form' if t, directs hideshow
 to show only the beginning of a block when it is hidden.  See the
 documentation for more details.
 
 ** Changes in Enriched mode.
 
-*** When you visit a file in enriched-mode, Emacs will make sure it is
+*** When you visit a file in 'enriched-mode', Emacs will make sure it is
 filled to the current fill-column.  This behavior is now independent
 of the size of the window.  When you save the file, the fill-column in
 use is stored as well, so that the whole buffer need not be refilled
 the next time unless the fill-column is different.
 
-*** use-hard-newlines is now a minor mode.  When it is enabled, Emacs
+*** 'use-hard-newlines' is now a minor mode.  When it is enabled, Emacs
 distinguishes between hard and soft newlines, and treats hard newlines
 as paragraph boundaries.  Otherwise all newlines inserted are marked
 as soft, and paragraph boundaries are determined solely from the text.
@@ -3118,8 +3118,8 @@ as soft, and paragraph boundaries are determined solely 
from the text.
 
 *** Custom support
 
-The variables font-lock-face-attributes, font-lock-display-type and
-font-lock-background-mode are now obsolete; the recommended way to specify
+The variables 'font-lock-face-attributes', 'font-lock-display-type' and
+'font-lock-background-mode' are now obsolete; the recommended way to specify
 the faces to use for Font Lock mode is with M-x customize-group on the new
 custom group font-lock-faces.  If you set font-lock-face-attributes in your
 ~/.emacs file, Font Lock mode will respect its value.  However, you should
@@ -3145,9 +3145,9 @@ support Font Lock mode, via the command 
global-font-lock-mode.
 *** Configurable support
 
 Support for C, C++, Objective-C and Java can be more easily configured for
-additional types and classes via the new variables c-font-lock-extra-types,
-c++-font-lock-extra-types, objc-font-lock-extra-types and, you guessed it,
-java-font-lock-extra-types.  These value of each of these variables should be a
+additional types and classes via the new variables 'c-font-lock-extra-types',
+'c++-font-lock-extra-types', 'objc-font-lock-extra-types' and, you guessed it,
+'java-font-lock-extra-types'.  The value of each of these variables should be a
 list of regexps matching the extra type names.  For example, the default value
 of c-font-lock-extra-types is ("\\sw+_t") which means fontification follows the
 convention that C type names end in _t.  This results in slower fontification.
@@ -3158,38 +3158,38 @@ it easier to make specific and common changes for the 
fontification of types.
 
 *** Adding highlighting patterns to existing support
 
-You can use the new function font-lock-add-keywords to add your own
+You can use the new function 'font-lock-add-keywords' to add your own
 highlighting patterns, such as for project-local or user-specific constructs,
 for any mode.
 
-For example, to highlight `FIXME:' words in C comments, put:
+For example, to highlight 'FIXME:' words in C comments, put:
 
- (font-lock-add-keywords 'c-mode '(("\\<FIXME:" 0 font-lock-warning-face t)))
+    (font-lock-add-keywords 'c-mode '(("\\<FIXME:" 0 font-lock-warning-face 
t)))
 
 in your ~/.emacs.
 
 *** New faces
 
-Font Lock now defines two new faces, font-lock-builtin-face and
-font-lock-warning-face.  These are intended to highlight builtin keywords,
+Font Lock now defines two new faces, 'font-lock-builtin-face' and
+'font-lock-warning-face'.  These are intended to highlight builtin keywords,
 distinct from a language's normal keywords, and objects that should be brought
 to user attention, respectively.  Various modes now use these new faces.
 
 *** Changes to fast-lock support mode
 
 The fast-lock package, one of the two Font Lock support modes, can now process
-cache files silently.  You can use the new variable fast-lock-verbose, in the
-same way as font-lock-verbose, to control this feature.
+cache files silently.  You can use the new variable 'fast-lock-verbose', in the
+same way as 'font-lock-verbose', to control this feature.
 
 *** Changes to lazy-lock support mode
 
 The lazy-lock package, one of the two Font Lock support modes, can now fontify
 according to the true syntactic context relative to other lines.  You can use
-the new variable lazy-lock-defer-contextually to control this feature.  If
+the new variable 'lazy-lock-defer-contextually' to control this feature.  If
 non-nil, changes to the buffer will cause subsequent lines in the buffer to be
-refontified after lazy-lock-defer-time seconds of idle time.  If nil, then only
-the modified lines will be refontified; this is the same as the previous Lazy
-Lock mode behavior and the behavior of Font Lock mode.
+refontified after 'lazy-lock-defer-time' seconds of idle time.  If nil, then
+only the modified lines will be refontified; this is the same as the previous
+Lazy Lock mode behavior and the behavior of Font Lock mode.
 
 This feature is useful in modes where strings or comments can span lines.
 For example, if a string or comment terminating character is deleted, then if
@@ -3200,10 +3200,10 @@ the command M-o M-o (font-lock-fontify-block) to 
refontify some lines.
 
 As a consequence of this new feature, two other variables have changed:
 
-Variable `lazy-lock-defer-driven' is renamed `lazy-lock-defer-on-scrolling'.
-Variable `lazy-lock-defer-time' can now only be a time, i.e., a number.
+Variable 'lazy-lock-defer-driven' is renamed 'lazy-lock-defer-on-scrolling'.
+Variable 'lazy-lock-defer-time' can now only be a time, i.e., a number.
 Buffer modes for which on-the-fly deferral applies can be specified via the
-new variable `lazy-lock-defer-on-the-fly'.
+new variable 'lazy-lock-defer-on-the-fly'.
 
 If you set these variables in your ~/.emacs, then you may have to change those
 settings.
@@ -3217,18 +3217,18 @@ you try to switch to its body file, Ada mode now 
generates procedure
 stubs.
 
 *** There are two new commands:
- - `ada-make-local'   : invokes gnatmake on the current buffer
- - `ada-check-syntax' : check syntax of current buffer.
+ - 'ada-make-local'   : invokes gnatmake on the current buffer
+ - 'ada-check-syntax' : check syntax of current buffer.
 
-The user options `ada-compiler-make', `ada-make-options',
-`ada-language-version', `ada-compiler-syntax-check', and
-`ada-compile-options' are used within these commands.
+The user options 'ada-compiler-make', 'ada-make-options',
+'ada-language-version', 'ada-compiler-syntax-check', and
+'ada-compile-options' are used within these commands.
 
 *** Ada mode can now work with Outline minor mode.  The outline level
 is calculated from the indenting, not from syntactic constructs.
 Outlining does not work if your code is not correctly indented.
 
-*** The new function `ada-gnat-style' converts the buffer to the style of
+*** The new function 'ada-gnat-style' converts the buffer to the style of
 formatting used in GNAT.  It places two blanks after a comment start,
 places one blank between a word end and an opening '(', and puts one
 space between a comma and the beginning of a word.
@@ -3237,13 +3237,13 @@ space between a comma and the beginning of a word.
 
 *** Scheme mode indentation now uses many of the facilities of Lisp
 mode; therefore, the variables to customize it are the variables used
-for Lisp mode which have names starting with `lisp-'.  The variables
-with names starting with `scheme-' which used to do this no longer
+for Lisp mode which have names starting with 'lisp-'.  The variables
+with names starting with 'scheme-' which used to do this no longer
 have any effect.
 
 If you want to use different indentation for Scheme and Lisp, this is
 still possible, but now you must do it by adding a hook to
-scheme-mode-hook, which could work by setting the `lisp-' indentation
+scheme-mode-hook, which could work by setting the 'lisp-' indentation
 variables as buffer-local variables.
 
 *** DSSSL mode is a variant of Scheme mode, for editing DSSSL scripts.
@@ -3269,11 +3269,11 @@ option takes precedence.
 constantly shows the parameter list for function being called at point
 (in Emacs Lisp and Lisp Interaction modes only).
 
-** C-x n d now runs the new command narrow-to-defun,
+** C-x n d now runs the new command 'narrow-to-defun',
 which narrows the accessible parts of the buffer to just
 the current defun.
 
-** Emacs now handles the `--' argument in the standard way; all
+** Emacs now handles the '--' argument in the standard way; all
 following arguments are treated as ordinary file names.
 
 ** On MSDOS and Windows, the bookmark file is now called _emacs.bmk,
@@ -3293,16 +3293,16 @@ be useful for Emacs to revert the file without querying 
you whenever
 you visit the file afresh with C-x C-f.
 
 You can request this behavior for certain files by setting the
-variable revert-without-query to a list of regular expressions.  If a
+variable 'revert-without-query' to a list of regular expressions.  If a
 file's name matches any of these regular expressions, find-file and
 revert-buffer revert the buffer without asking for permission--but
 only if you have not edited the buffer text yourself.
 
-** set-default-font has been renamed to set-frame-font
+** set-default-font has been renamed to 'set-frame-font'
 since it applies only to the current frame.
 
-** In TeX mode, you can use the variable tex-main-file to specify the
-file for tex-file to run TeX on.  (By default, tex-main-file is nil,
+** In TeX mode, you can use the variable 'tex-main-file' to specify the
+file for 'tex-file' to run TeX on.  (By default, tex-main-file is nil,
 and tex-file runs TeX on the current visited file.)
 
 This is useful when you are editing a document that consists of
@@ -3319,22 +3319,22 @@ different environments (equation, figure, ...) and has 
full support for
 multifile documents.  To use it, select a buffer with a LaTeX document and
 turn the mode on with M-x reftex-mode.  Here are the main user commands:
 
-C-c (    reftex-label
+C-c (    'reftex-label'
    Creates a label semi-automatically.  RefTeX is context sensitive and
    knows which kind of label is needed.
 
-C-c )    reftex-reference
+C-c )    'reftex-reference'
    Offers in a menu all labels in the document, along with context of the
    label definition.  The selected label is referenced as \ref{LABEL}.
 
-C-c [    reftex-citation
+C-c [    'reftex-citation'
    Prompts for a regular expression and displays a list of matching BibTeX
    database entries.  The selected entry is cited with a \cite{KEY} macro.
 
-C-c &    reftex-view-crossref
+C-c &    'reftex-view-crossref'
    Views the cross reference of a \ref or \cite command near point.
 
-C-c =    reftex-toc
+C-c =    'reftex-toc'
    Shows a table of contents of the (multifile) document.  From there you
    can quickly jump to every section.
 
@@ -3364,13 +3364,13 @@ appropriate functions.
 *** New interactive functions for repositioning and marking of
 entries. They are bound by default to C-M-l and C-M-h.
 
-*** New hook bibtex-clean-entry-hook. It is called after entry has
+*** New hook 'bibtex-clean-entry-hook'. It is called after entry has
 been cleaned.
 
-*** New variable bibtex-field-delimiters, which replaces variables
+*** New variable 'bibtex-field-delimiters', which replaces variables
 bibtex-field-{left|right}-delimiter.
 
-*** New variable bibtex-entry-delimiters to determine how entries
+*** New variable 'bibtex-entry-delimiters' to determine how entries
 shall be delimited.
 
 *** Allow preinitialization of fields. See documentation of
@@ -3379,9 +3379,9 @@ bibtex-include-OPTkey for details.
 
 *** Book and InBook entries require either an author or an editor
 field. This is now supported by bibtex.el. Alternative fields are
-prefixed with `ALT'.
+prefixed with 'ALT'.
 
-*** New variable bibtex-entry-format, which replaces variable
+*** New variable 'bibtex-entry-format', which replaces variable
 bibtex-clean-entry-zap-empty-opts and allows specification of many
 formatting options performed on cleaning an entry (see variable
 documentation).
@@ -3390,43 +3390,43 @@ documentation).
 documentation of bibtex-generate-autokey for details. Transcriptions
 for foreign languages other than German are now handled, too.
 
-*** New boolean user option bibtex-comma-after-last-field to decide if
+*** New boolean user option 'bibtex-comma-after-last-field' to decide if
 comma should be inserted at end of last field.
 
-*** New boolean user option bibtex-align-at-equal-sign to determine if
+*** New boolean user option 'bibtex-align-at-equal-sign' to determine if
 alignment should be made at left side of field contents or at equal
 signs. New user options to control entry layout (e.g. indentation).
 
-*** New function bibtex-fill-entry to realign entries.
+*** New function 'bibtex-fill-entry' to realign entries.
 
-*** New function bibtex-reformat to reformat region or buffer.
+*** New function 'bibtex-reformat' to reformat region or buffer.
 
-*** New function bibtex-convert-alien to convert a BibTeX database
+*** New function 'bibtex-convert-alien' to convert a BibTeX database
 from alien sources.
 
-*** New function bibtex-complete-key (similar to bibtex-complete-string)
+*** New function 'bibtex-complete-key' (similar to bibtex-complete-string)
 to complete prefix to a key defined in buffer. Mainly useful in
 crossref entries.
 
-*** New function bibtex-count-entries to count entries in buffer or
+*** New function 'bibtex-count-entries' to count entries in buffer or
 region.
 
 *** Added support for imenu.
 
-*** The function `bibtex-validate' now checks current region instead
+*** The function 'bibtex-validate' now checks current region instead
 of buffer if mark is active. Now it shows all errors of buffer in a
 `compilation mode' buffer. You can use the normal commands (e.g.
-`next-error') for compilation modes to jump to errors.
+'next-error') for compilation modes to jump to errors.
 
-*** New variable `bibtex-string-file-path' to determine where the files
-from `bibtex-string-files' are searched.
+*** New variable 'bibtex-string-file-path' to determine where the files
+from 'bibtex-string-files' are searched.
 
 ** Iso Accents mode now supports Latin-3 as an alternative.
 
-** The command next-error now opens blocks hidden by hideshow.
+** The command 'next-error' now opens blocks hidden by hideshow.
 
-** The function using-unix-filesystems has been replaced by the
-functions add-untranslated-filesystem and remove-untranslated-filesystem.
+** The function 'using-unix-filesystems' has been replaced by the
+functions 'add-untranslated-filesystem' and 'remove-untranslated-filesystem'.
 Each of these functions takes the name of a drive letter or directory
 as an argument.
 
@@ -3441,11 +3441,11 @@ Lynx in a separate xterm (browse-url-lynx-xterm) or in 
an Emacs window
 non-remote-controlled browsers (browse-url-generic) and associated
 customization variables.
 
-*** New commands `browse-url-of-region' and `browse-url'.
+*** New commands 'browse-url-of-region' and 'browse-url'.
 
 *** URLs marked up with <URL:...> (RFC1738) work if broken across
 lines.  Browsing methods can be associated with URL regexps
-(e.g. mailto: URLs) via `browse-url-browser-function'.
+(e.g. mailto: URLs) via 'browse-url-browser-function'.
 
 ** Changes in Ediff
 
@@ -3512,7 +3512,7 @@ paragraph name.
 an interval is \{M,N\}, and it means to match the preceding expression
 at least M times and as many as N times.
 
-** The format for specifying a custom format for time-stamp to insert
+** The format for specifying a custom format for 'time-stamp' to insert
 in files has changed slightly.
 
 With the new enhancements to the functionality of format-time-string,
@@ -3528,7 +3528,7 @@ reasons.
 In the old time-stamp-format, all numeric fields defaulted to their
 natural width.  (With format-time-string, each format has a
 fixed-width default.)  In this version, you can specify the colon
-(`:') modifier to a numeric conversion to mean "give me the historical
+(':') modifier to a numeric conversion to mean "give me the historical
 time-stamp-format width default."  Do not use colon if you are
 specifying an explicit width, as in "%02d".
 
@@ -3546,11 +3546,11 @@ details.
 
 ** There are some additional major modes:
 
-dcl-mode, for editing VMS DCL files.
-m4-mode, for editing files of m4 input.
-meta-mode, for editing MetaFont and MetaPost source files.
+'dcl-mode', for editing VMS DCL files.
+'m4-mode', for editing files of m4 input.
+'meta-mode', for editing MetaFont and MetaPost source files.
 
-** In Shell mode, the command shell-copy-environment-variable lets you
+** In Shell mode, the command 'shell-copy-environment-variable' lets you
 copy the value of a specified environment variable from the subshell
 into Emacs.
 
@@ -3567,8 +3567,8 @@ be used for adding some indecent words to your email.
 in shell buffers.
 
 *** The new library elint.el provides for linting of Emacs Lisp code.
-See the documentation for `elint-initialize', `elint-current-buffer'
-and `elint-defun'.
+See the documentation for 'elint-initialize', 'elint-current-buffer'
+and 'elint-defun'.
 
 *** M-x expand-add-abbrevs defines a special kind of abbrev which is
 meant for programming constructs.  These abbrevs expand like ordinary
@@ -3594,7 +3594,7 @@ switch-buffer, but it reads the argument in a more 
helpful way.
 
 *** M-x landmark implements a neural network for landmark learning.
 
-*** M-x locate provides a convenient interface to the `locate' program.
+*** M-x locate provides a convenient interface to the 'locate' program.
 
 *** M4 mode is a new mode for editing files of m4 input.
 
@@ -3656,7 +3656,7 @@ these servers.
 You can move the virtual cursor with special commands
 while the real cursor does not move.
 
-*** webjump.el is a "hot list" package which you can set up
+*** 'webjump' is a "hot list" package which you can set up
 for visiting your favorite web sites.
 
 *** M-x winner-mode is a minor mode which saves window configurations,
@@ -3709,41 +3709,41 @@ don't want to praise a non-free Microsoft system, so we 
don't call it
 *** A symbol whose name starts with a colon now automatically
 evaluates to itself.  Therefore such a symbol can be used as a constant.
 
-*** The defined purpose of `defconst' has been changed.  It should now
+*** The defined purpose of 'defconst' has been changed.  It should now
 be used only for values that should not be changed whether by a program
 or by the user.
 
 The actual behavior of defconst has not been changed.
 
-*** There are new macros `when' and `unless'
+*** There are new macros 'when' and 'unless'
 
 (when CONDITION BODY...)  is short for  (if CONDITION (progn BODY...))
 (unless CONDITION BODY...)  is short for  (if CONDITION nil BODY...)
 
-*** Emacs now defines functions caar, cadr, cdar and cddr with their
+*** Emacs now defines functions 'caar', 'cadr', 'cdar' and 'cddr' with their
 usual Lisp meanings.  For example, caar returns the car of the car of
 its argument.
 
-*** equal, when comparing strings, now ignores their text properties.
+*** 'equal', when comparing strings, now ignores their text properties.
 
-*** The new function `functionp' tests whether an object is a function.
+*** The new function 'functionp' tests whether an object is a function.
 
-*** arrayp now returns t for char-tables and bool-vectors.
+*** 'arrayp' now returns t for char-tables and bool-vectors.
 
 *** Certain primitives which use characters (as integers) now get an
 error if the integer is not a valid character code.  These primitives
-include insert-char, char-to-string, and the %c construct in the
-`format' function.
+include 'insert-char', 'char-to-string', and the %c construct in the
+'format' function.
 
-*** The `require' function now insists on adding a suffix, either .el
+*** The 'require' function now insists on adding a suffix, either .el
 or .elc, to the file name.  Thus, (require 'foo) will not use a file
 whose name is just foo.  It insists on foo.el or foo.elc.
 
-*** The `autoload' function, when the file name does not contain
+*** The 'autoload' function, when the file name does not contain
 either a directory name or the suffix .el or .elc, insists on
 adding one of these suffixes.
 
-*** string-to-number now takes an optional second argument BASE
+*** 'string-to-number' now takes an optional second argument BASE
 which specifies the base to use when converting an integer.
 If BASE is omitted, base 10 is used.
 
@@ -3753,9 +3753,9 @@ because that would be much more work and does not seem 
useful.
 *** substring now handles vectors as well as strings.
 
 *** The Common Lisp function eql is no longer defined normally.
-You must load the `cl' library to define it.
+You must load the 'cl' library to define it.
 
-*** The new macro `with-current-buffer' lets you evaluate an expression
+*** The new macro 'with-current-buffer' lets you evaluate an expression
 conveniently with a different current buffer.  It looks like this:
 
   (with-current-buffer BUFFER BODY-FORMS...)
@@ -3763,35 +3763,35 @@ conveniently with a different current buffer.  It looks 
like this:
 BUFFER is the expression that says which buffer to use.
 BODY-FORMS say what to do in that buffer.
 
-*** The new primitive `save-current-buffer' saves and restores the
-choice of current buffer, like `save-excursion', but without saving or
-restoring the value of point or the mark.  `with-current-buffer'
-works using `save-current-buffer'.
+*** The new primitive 'save-current-buffer' saves and restores the
+choice of current buffer, like 'save-excursion', but without saving or
+restoring the value of point or the mark.  'with-current-buffer'
+works using 'save-current-buffer'.
 
-*** The new macro `with-temp-file' lets you do some work in a new buffer and
-write the output to a specified file.  Like `progn', it returns the value
+*** The new macro 'with-temp-file' lets you do some work in a new buffer and
+write the output to a specified file.  Like 'progn', it returns the value
 of the last form.
 
-*** The new macro `with-temp-buffer' lets you do some work in a new buffer,
-which is discarded after use.  Like `progn', it returns the value of the
+*** The new macro 'with-temp-buffer' lets you do some work in a new buffer,
+which is discarded after use.  Like 'progn', it returns the value of the
 last form.  If you wish to return the buffer contents, use (buffer-string)
 as the last form.
 
-*** The new function split-string takes a string, splits it at certain
+*** The new function 'split-string' takes a string, splits it at certain
 characters, and returns a list of the substrings in between the
 matches.
 
 For example, (split-string "foo bar lose" " +") returns ("foo" "bar" "lose").
 
-*** The new macro with-output-to-string executes some Lisp expressions
+*** The new macro 'with-output-to-string' executes some Lisp expressions
 with standard-output set up so that all output feeds into a string.
 Then it returns that string.
 
-For example, if the current buffer name is `foo',
+For example, if the current buffer name is 'foo',
 
-(with-output-to-string
-  (princ "The buffer is ")
-  (princ (buffer-name)))
+    (with-output-to-string
+      (princ "The buffer is ")
+      (princ (buffer-name)))
 
 returns "The buffer is foo".
 
@@ -3808,7 +3808,7 @@ a buffer or string can be two or more bytes (as many as 
four).
 Buffers and strings are still made up of unibyte elements;
 character positions and string indices are always measured in bytes.
 Therefore, moving forward one character can increase the buffer
-position by 2, 3 or 4.  The function forward-char moves by whole
+position by 2, 3 or 4.  The function 'forward-char' moves by whole
 characters, and therefore is no longer equivalent to
   (lambda (n) (goto-char (+ (point) n))).
 
@@ -3823,9 +3823,9 @@ through 159 (octal 0200 through 0237).  These values are 
called
 range 160 through 255 (octal 0240 through 0377).  The first byte, the
 leading code, determines how many bytes long the sequence is.
 
-*** The function forward-char moves over characters, and therefore
+*** The function 'forward-char' moves over characters, and therefore
 (forward-char 1) may increase point by more than 1 if it moves over a
-multibyte character.  Likewise, delete-char always deletes a
+multibyte character.  Likewise, 'delete-char' always deletes a
 character, which may be more than one buffer position.
 
 This means that some Lisp programs, which assume that a character is
@@ -3854,7 +3854,7 @@ When the value is non-nil, it says what kind of character 
follows POS:
 *** The function char-bytes returns how many bytes the character CHAR uses.
 
 *** Strings can contain multibyte characters.  The function
-`length' returns the string length counting bytes, which may be
+'length' returns the string length counting bytes, which may be
 more than the number of characters.
 
 You can include a multibyte character in a string constant by writing
@@ -3864,27 +3864,27 @@ is not a valid hex digit terminates this construct.  If 
you want to
 follow it with a character that is a hex digit, write backslash and
 newline in between; that will terminate the hex escape.
 
-*** The function concat-chars takes arguments which are characters
+*** The function 'concat-chars' takes arguments which are characters
 and returns a string containing those characters.
 
-*** The function sref access a multibyte character in a string.
+*** The function 'sref' access a multibyte character in a string.
 (sref STRING INDX) returns the character in STRING at INDEX.  INDEX
 counts from zero.  If INDEX is at a position in the middle of a
 character, sref signals an error.
 
-*** The function chars-in-string returns the number of characters
+*** The function 'chars-in-string' returns the number of characters
 in a string.  This is less than the length of the string, if the
 string contains multibyte characters (the length counts bytes).
 
-*** The function chars-in-region returns the number of characters
+*** The function 'chars-in-region' returns the number of characters
 in a region from BEG to END.  This is less than (- END BEG) if the
 region contains multibyte characters (the length counts bytes).
 
-*** The function string-to-list converts a string to a list of
-the characters in it.  string-to-vector converts a string
+*** The function 'string-to-list' converts a string to a list of
+the characters in it.  'string-to-vector' converts a string
 to a vector of the characters in it.
 
-*** The function store-substring alters part of the contents
+*** The function 'store-substring' alters part of the contents
 of a string.  You call it as follows:
 
    (store-substring STRING IDX OBJ)
@@ -3895,18 +3895,18 @@ This function really does alter the contents of STRING.
 Since it is impossible to change the length of an existing string,
 it is an error if OBJ doesn't fit within STRING's actual length.
 
-*** char-width returns the width (in columns) of the character CHAR,
+*** 'char-width' returns the width (in columns) of the character CHAR,
 if it were displayed in the current buffer and the selected window.
 
-*** string-width returns the width (in columns) of the text in STRING,
+*** 'string-width' returns the width (in columns) of the text in STRING,
 if it were displayed in the current buffer and the selected window.
 
-*** truncate-string-to-width shortens a string, if necessary,
+*** 'truncate-string-to-width' shortens a string, if necessary,
 to fit within a certain number of columns.  (Of course, it does
 not alter the string that you give it; it returns a new string
 which contains all or just part of the existing string.)
 
-(truncate-string-to-width STR END-COLUMN &optional START-COLUMN PADDING)
+    (truncate-string-to-width STR END-COLUMN &optional START-COLUMN PADDING)
 
 This returns the part of STR up to column END-COLUMN.
 
@@ -3926,7 +3926,7 @@ PADDING is added one or more times at the beginning of 
the result
 string, so that its columns line up as if it really did start at
 column START-COLUMN.
 
-*** When the functions in the list after-change-functions are called,
+*** When the functions in the list 'after-change-functions' are called,
 the third argument is the number of bytes in the pre-change text, not
 necessarily the number of characters.  It is, in effect, the
 difference in buffer position between the beginning and the end of the
@@ -3936,42 +3936,42 @@ changed text, before the change.
 sets, each of which has a name which is a symbol.  In general there is
 one character set for each script, not for each language.
 
-**** The function charsetp tests whether an object is a character set name.
+**** The function 'charsetp' tests whether an object is a character set name.
 
-**** The variable charset-list holds a list of character set names.
+**** The variable 'charset-list' holds a list of character set names.
 
-**** char-charset, given a character code, returns the name of the character
+**** 'char-charset', given a character code, returns the name of the character
 set that the character belongs to.  (The value is a symbol.)
 
-**** split-char, given a character code, returns a list containing the
+**** 'split-char', given a character code, returns a list containing the
 name of the character set, followed by one or two byte-values
 which identify the character within that character set.
 
-**** make-char, given a character set name and one or two subsequent
+**** 'make-char', given a character set name and one or two subsequent
 byte-values, constructs a character code.  This is roughly the
 opposite of split-char.
 
-**** find-charset-region returns a list of the character sets
+**** 'find-charset-region' returns a list of the character sets
 of all the characters between BEG and END.
 
-**** find-charset-string returns a list of the character sets
+**** 'find-charset-string' returns a list of the character sets
 of all the characters in a string.
 
 *** Here are the Lisp facilities for working with coding systems
 and specifying coding systems.
 
-**** The function coding-system-list returns a list of all coding
+**** The function 'coding-system-list' returns a list of all coding
 system names (symbols).  With optional argument t, it returns a list
 of all distinct base coding systems, not including variants.
 (Variant coding systems are those like latin-1-dos, latin-1-unix
 and latin-1-mac which specify the end-of-line conversion as well
 as what to do about code conversion.)
 
-**** coding-system-p tests a symbol to see if it is a coding system
+**** 'coding-system-p' tests a symbol to see if it is a coding system
 name.  It returns t if so, nil if not.
 
-**** file-coding-system-alist specifies which coding systems to use
-for certain file names.  It works like network-coding-system-alist,
+**** 'file-coding-system-alist' specifies which coding systems to use
+for certain file names.  It works like 'network-coding-system-alist',
 except that the PATTERN is matched against the file name.
 
 Each element has the format (PATTERN . VAL), where PATTERN determines
@@ -3988,7 +3988,7 @@ specifies the coding system for encoding.
 If VAL is a function symbol, the function must return a coding system
 or a cons cell containing two coding systems, which is used as above.
 
-**** The variable network-coding-system-alist specifies
+**** The variable 'network-coding-system-alist' specifies
 the coding system to use for network sockets.
 
 Each element has the format (PATTERN . VAL), where PATTERN determines
@@ -4011,13 +4011,13 @@ for certain subprocess.  It works like 
network-coding-system-alist,
 except that the PATTERN is matched against the program name used to
 start the subprocess.
 
-**** The variable default-process-coding-system specifies the coding
+**** The variable 'default-process-coding-system' specifies the coding
 systems to use for subprocess (and net connection) input and output,
 when nothing else specifies what to do.  The value is a cons cell
 (OUTPUT-CODING . INPUT-CODING).  OUTPUT-CODING applies to output
 to the subprocess, and INPUT-CODING applies to input from it.
 
-**** The variable coding-system-for-write, if non-nil, specifies the
+**** The variable 'coding-system-for-write', if non-nil, specifies the
 coding system to use for writing a file, or for output to a synchronous
 subprocess.
 
@@ -4026,17 +4026,17 @@ but in a different way: the value of 
coding-system-for-write when you
 start the subprocess or connection affects that subprocess or
 connection permanently or until overridden.
 
-The variable coding-system-for-write takes precedence over
-file-coding-system-alist, process-coding-system-alist and
-network-coding-system-alist, and all other methods of specifying a
+The variable 'coding-system-for-write' takes precedence over
+'file-coding-system-alist', 'process-coding-system-alist' and
+'network-coding-system-alist', and all other methods of specifying a
 coding system for output.  But most of the time this variable is nil.
 It exists so that Lisp programs can bind it to a specific coding
 system for one operation at a time.
 
-**** coding-system-for-read applies similarly to input from
+**** 'coding-system-for-read' applies similarly to input from
 files, subprocesses or network connections.
 
-**** The function process-coding-system tells you what
+**** The function 'process-coding-system' tells you what
 coding systems(s) an existing subprocess is using.
 The value is a cons cell,
  (DECODING-CODING-SYSTEM . ENCODING-CODING-SYSTEM)
@@ -4044,12 +4044,12 @@ where DECODING-CODING-SYSTEM is used for decoding 
output from
 the subprocess, and ENCODING-CODING-SYSTEM is used for encoding
 input to the subprocess.
 
-**** The function set-process-coding-system can be used to
+**** The function 'set-process-coding-system' can be used to
 change the coding systems in use for an existing subprocess.
 
 ** Emacs has a new facility to help users manage the many
 customization options.  To make a Lisp program work with this facility,
-you need to use the new macros defgroup and defcustom.
+you need to use the new macros 'defgroup' and 'defcustom'.
 
 You use defcustom instead of defvar, for defining a user option
 variable.  The difference is that you specify two additional pieces of
@@ -4069,7 +4069,7 @@ you would now write this:
       :type 'boolean
       :group foo)
 
-The type `boolean' means that this variable has only
+The type 'boolean' means that this variable has only
 two meaningful states: nil and non-nil.  Other type values
 describe other possibilities; see the manual for Custom
 for a description of them.
@@ -4082,8 +4082,8 @@ should belong to.  You define a new group like this:
       :group 'processes)
 
 The "group" argument in defgroup specifies the parent group.  The root
-group is called `emacs'; it should not contain any variables itself,
-but only other groups.  The immediate subgroups of `emacs' correspond
+group is called 'emacs'; it should not contain any variables itself,
+but only other groups.  The immediate subgroups of 'emacs' correspond
 to the keywords used by C-h p.  Under these subgroups come
 second-level subgroups that belong to individual packages.
 
@@ -4093,7 +4093,7 @@ have a hierarchy of its own groups.  The sole or root 
group of a
 package should be a subgroup of one or more of the "keyword"
 first-level subgroups.
 
-** New `widget' library for inserting UI components in buffers.
+** New 'widget' library for inserting UI components in buffers.
 
 This library, used by the new custom library, is documented in a
 separate manual that accompanies Emacs.
@@ -4104,16 +4104,16 @@ The easy-mmode package provides macros and functions 
that make
 developing minor modes easier.  Roughly, the programmer has to code
 only the functionality of the minor mode.  All the rest--toggles,
 predicate, and documentation--can be done in one call to the macro
-`easy-mmode-define-minor-mode' (see the documentation).  See also
-`easy-mmode-define-keymap'.
+'easy-mmode-define-minor-mode' (see the documentation).  See also
+'easy-mmode-define-keymap'.
 
 ** Text property changes
 
-*** The `intangible' property now works on overlays as well as on a
+*** The 'intangible' property now works on overlays as well as on a
 text property.
 
-*** The new functions next-char-property-change and
-previous-char-property-change scan through the buffer looking for a
+*** The new functions 'next-char-property-change' and
+'previous-char-property-change' scan through the buffer looking for a
 place where either a text property or an overlay might change.  The
 functions take two arguments, POSITION and LIMIT.  POSITION is the
 starting position for the scan.  LIMIT says where to stop the scan.
@@ -4123,7 +4123,7 @@ LIMIT is nil, scan goes to the beginning or end of the 
accessible part
 of the buffer.  If no property change is found, the value is the
 position of the beginning or end of the buffer.
 
-*** In the `local-map' text property or overlay property, the property
+*** In the 'local-map' text property or overlay property, the property
 value can now be a symbol whose function definition is a keymap.  This
 is an alternative to using the keymap itself.
 
@@ -4146,47 +4146,47 @@ t when it should hide it.
 
 Modes that use overlays to hide portions of a buffer should set the
 invisible property of the overlay to the mode's name (or another symbol)
-and modify the `buffer-invisibility-spec' to include that symbol.
-Use  `add-to-invisibility-spec' and `remove-from-invisibility-spec' to
-manipulate the `buffer-invisibility-spec'.
+and modify the 'buffer-invisibility-spec' to include that symbol.
+Use  'add-to-invisibility-spec' and 'remove-from-invisibility-spec' to
+manipulate the 'buffer-invisibility-spec'.
 Here is an example of how to do this:
 
- ;; If we want to display an ellipsis:
- (add-to-invisibility-spec '(my-symbol . t))
- ;; If you don't want ellipsis:
- (add-to-invisibility-spec 'my-symbol)
+    ;; If we want to display an ellipsis:
+    (add-to-invisibility-spec '(my-symbol . t))
+    ;; If you don't want ellipsis:
+    (add-to-invisibility-spec 'my-symbol)
 
-  ...
- (overlay-put  (make-overlay beginning end)  'invisible 'my-symbol)
+     ...
+    (overlay-put  (make-overlay beginning end)  'invisible 'my-symbol)
 
- ...
- ;; When done with the overlays:
- (remove-from-invisibility-spec '(my-symbol . t))
- ;; Or respectively:
- (remove-from-invisibility-spec 'my-symbol)
+    ...
+    ;; When done with the overlays:
+    (remove-from-invisibility-spec '(my-symbol . t))
+    ;; Or respectively:
+    (remove-from-invisibility-spec 'my-symbol)
 
 ** Changes in syntax parsing.
 
 *** The syntax-directed buffer-scan functions (such as
-`parse-partial-sexp', `forward-word' and similar functions) can now
+'parse-partial-sexp', 'forward-word' and similar functions) can now
 obey syntax information specified by text properties, if the variable
-`parse-sexp-lookup-properties' is non-nil.
+'parse-sexp-lookup-properties' is non-nil.
 
-If the value of `parse-sexp-lookup-properties' is nil, the behavior
+If the value of 'parse-sexp-lookup-properties' is nil, the behavior
 is as before: the syntax-table of the current buffer is always
 used to determine the syntax of the character at the position.
 
-When `parse-sexp-lookup-properties' is non-nil, the syntax of a
+When 'parse-sexp-lookup-properties' is non-nil, the syntax of a
 character in the buffer is calculated thus:
 
-       a) if the `syntax-table' text-property of that character
+       a) if the 'syntax-table' text-property of that character
           is a cons, this cons becomes the syntax-type;
 
-          Valid values of `syntax-table' text-property are: nil, a valid
+          Valid values of 'syntax-table' text-property are: nil, a valid
           syntax-table, and a valid syntax-table element, i.e.,
           a cons cell of the form (SYNTAX-CODE . MATCHING-CHAR).
 
-       b) if the character's `syntax-table' text-property
+       b) if the character's 'syntax-table' text-property
           is a syntax table, this syntax table is used
           (instead of the syntax-table of the current buffer) to
           determine the syntax type of the character.
@@ -4195,7 +4195,7 @@ character in the buffer is calculated thus:
           of the current buffer.
 
 *** The meaning of \s in regular expressions is also affected by the
-value of `parse-sexp-lookup-properties'.  The details are the same as
+value of 'parse-sexp-lookup-properties'.  The details are the same as
 for the syntax-directed buffer-scan functions.
 
 *** There are two new syntax-codes, `!' and `|' (numeric values 14
@@ -4204,41 +4204,41 @@ only by another character with the same code (unless 
quoted).  A
 character with a code `|' starts a string which is ended only by
 another character with the same code (unless quoted).
 
-These codes are mainly meant for use as values of the `syntax-table'
+These codes are mainly meant for use as values of the 'syntax-table'
 text property.
 
-*** The function `parse-partial-sexp' has new semantics for the sixth
-arg COMMENTSTOP.  If it is `syntax-table', parse stops after the start
+*** The function 'parse-partial-sexp' has new semantics for the sixth
+arg COMMENTSTOP.  If it is 'syntax-table', parse stops after the start
 of a comment or a string, or after end of a comment or a string.
 
-*** The state-list which the return value from `parse-partial-sexp'
+*** The state-list which the return value from 'parse-partial-sexp'
 (and can also be used as an argument) now has an optional ninth
 element: the character address of the start of last comment or string;
 nil if none.  The fourth and eighth elements have special values if the
 string/comment is started by a "!"  or "|" syntax-code.
 
-*** Since new features of `parse-partial-sexp' allow a complete
-syntactic parsing, `font-lock' no longer supports
-`font-lock-comment-start-regexp'.
+*** Since new features of 'parse-partial-sexp' allow a complete
+syntactic parsing, 'font-lock' no longer supports
+'font-lock-comment-start-regexp'.
 
 ** Changes in face features
 
 *** The face functions are now unconditionally defined in Emacs, even
 if it does not support displaying on a device that supports faces.
 
-*** The function face-documentation returns the documentation string
+*** The function 'face-documentation' returns the documentation string
 of a face (or nil if it doesn't have one).
 
-*** The function face-bold-p returns t if a face should be bold.
-set-face-bold-p sets that flag.
+*** The function 'face-bold-p' returns t if a face should be bold.
+'set-face-bold-p' sets that flag.
 
-*** The function face-italic-p returns t if a face should be italic.
-set-face-italic-p sets that flag.
+*** The function 'face-italic-p' returns t if a face should be italic.
+'set-face-italic-p' sets that flag.
 
 *** You can now specify foreground and background colors for text
 by adding elements of the form (foreground-color . COLOR-NAME)
 and (background-color . COLOR-NAME) to the list of faces in
-the `face' property (either the character's text property or an
+the 'face' property (either the character's text property or an
 overlay property).
 
 This means that you no longer need to create named faces to use
@@ -4249,21 +4249,21 @@ arbitrary colors in a Lisp package.
 *** File-access primitive functions no longer discard an extra redundant
 directory name from the beginning of the file name.  In other words,
 they no longer do anything special with // or /~.  That conversion
-is now done only in substitute-in-file-name.
+is now done only in 'substitute-in-file-name'.
 
 This makes it possible for a Lisp program to open a file whose name
 begins with ~.
 
-*** If copy-file is unable to set the date of the output file,
-it now signals an error with the condition file-date-error.
+*** If 'copy-file' is unable to set the date of the output file,
+it now signals an error with the condition 'file-date-error'.
 
-*** The inode number returned by file-attributes may be an integer (if
+*** The inode number returned by 'file-attributes' may be an integer (if
 the number fits in a Lisp integer) or a list of integers.
 
-*** insert-file-contents can now read from a special file,
+*** 'insert-file-contents' can now read from a special file,
 as long as the arguments VISIT and REPLACE are nil.
 
-*** The RAWFILE arg to find-file-noselect, if non-nil, now suppresses
+*** The RAWFILE arg to 'find-file-noselect', if non-nil, now suppresses
 character code conversion as well as other things.
 
 Meanwhile, this feature does work with remote file names
@@ -4282,21 +4282,21 @@ any `//' or `/~' sequence.  Now it passes them straight 
through.
 substitute-in-file-name continues to treat those sequences specially,
 in the same way as before.
 
-*** The variable `format-alist' is more general now.
+*** The variable 'format-alist' is more general now.
 The FROM-FN and TO-FN in a format definition can now be strings
 which specify shell commands to use as filters to perform conversion.
 
-*** The new function access-file tries to open a file, and signals an
+*** The new function 'access-file' tries to open a file, and signals an
 error if that fails.  If the open succeeds, access-file does nothing
 else, and returns nil.
 
-*** The function insert-directory now signals an error if the specified
+*** The function 'insert-directory' now signals an error if the specified
 directory cannot be listed.
 
 ** Changes in minibuffer input
 
-*** The functions read-buffer, read-variable, read-command, read-string
-read-file-name, read-from-minibuffer and completing-read now take an
+*** The functions 'read-buffer', 'read-variable', 'read-command', 'read-string'
+'read-file-name', 'read-from-minibuffer' and 'completing-read' now take an
 additional argument which specifies the default value.  If this
 argument is non-nil, it should be a string; that string is used in two
 ways:
@@ -4304,8 +4304,8 @@ ways:
   It is returned if the user enters empty input.
   It is available through the history command M-n.
 
-*** The functions read-string, read-from-minibuffer,
-read-no-blanks-input and completing-read now take an additional
+*** The functions 'read-string', 'read-from-minibuffer',
+'read-no-blanks-input' and 'completing-read' now take an additional
 argument INHERIT-INPUT-METHOD.  If this is non-nil, then the
 minibuffer inherits the current input method and the setting of
 enable-multibyte-characters from the previously current buffer.
@@ -4315,34 +4315,34 @@ argument in this way.
 
 *** All minibuffer input functions discard text properties
 from the text you enter in the minibuffer, unless the variable
-minibuffer-allow-text-properties is non-nil.
+'minibuffer-allow-text-properties' is non-nil.
 
 ** Echo area features
 
 *** Clearing the echo area now runs the normal hook
-echo-area-clear-hook.  Note that the echo area can be used while the
+'echo-area-clear-hook'.  Note that the echo area can be used while the
 minibuffer is active; in that case, the minibuffer is still active
 after the echo area is cleared.
 
-*** The function current-message returns the message currently displayed
+*** The function 'current-message' returns the message currently displayed
 in the echo area, or nil if there is none.
 
 ** Keyboard input features
 
-*** tty-erase-char is a new variable that reports which character was
+*** 'tty-erase-char' is a new variable that reports which character was
 set up as the terminal's erase character when time Emacs was started.
 
-*** num-nonmacro-input-events is the total number of input events
+*** 'num-nonmacro-input-events' is the total number of input events
 received so far from the terminal.  It does not count those generated
 by keyboard macros.
 
 ** Frame-related changes
 
-*** make-frame runs the normal hook before-make-frame-hook just before
+*** 'make-frame' runs the normal hook 'before-make-frame-hook' just before
 creating a frame, and just after creating a frame it runs the abnormal
-hook after-make-frame-functions with the new frame as arg.
+hook 'after-make-frame-functions' with the new frame as arg.
 
-*** The new hook window-configuration-change-hook is now run every time
+*** The new hook 'window-configuration-change-hook' is now run every time
 the window configuration has changed.  The frame whose configuration
 has changed is the selected frame when the hook is run.
 
@@ -4351,20 +4351,20 @@ selected buffers, in its buffer-list frame parameter, 
so that the
 value of other-buffer is now based on the buffers recently displayed
 in the selected frame.
 
-*** The value of the frame parameter vertical-scroll-bars
-is now `left', `right' or nil.  A non-nil value specifies
+*** The value of the frame parameter 'vertical-scroll-bars'
+is now 'left', 'right' or nil.  A non-nil value specifies
 which side of the window to put the scroll bars on.
 
 ** X Windows features
 
 *** You can examine X resources for other applications by binding
-x-resource-class around a call to x-get-resource.  The usual value of
-x-resource-class is "Emacs", which is the correct value for Emacs.
+'x-resource-class' around a call to 'x-get-resource'.  The usual value of
+'x-resource-class' is "Emacs", which is the correct value for Emacs.
 
 *** In menus, checkboxes and radio buttons now actually work.
 The menu displays the current status of the box or button.
 
-*** The function x-list-fonts now takes an optional fourth argument
+*** The function 'x-list-fonts' now takes an optional fourth argument
 MAXIMUM which sets a limit on how many matching fonts to return.
 A smaller value of MAXIMUM makes the function faster.
 
@@ -4374,24 +4374,24 @@ it is good to supply 1 for this argument.
 ** Subprocess features
 
 *** A reminder: it is no longer necessary for subprocess filter
-functions and sentinels to do save-match-data, because Emacs does this
+functions and sentinels to do 'save-match-data', because Emacs does this
 automatically.
 
-*** The new function shell-command-to-string executes a shell command
+*** The new function 'shell-command-to-string' executes a shell command
 and returns the output from the command as a string.
 
-*** The new function process-contact returns t for a child process,
+*** The new function 'process-contact' returns t for a child process,
 and (HOSTNAME SERVICE) for a net connection.
 
 ** An error in running pre-command-hook or post-command-hook
 does clear the variable to nil.  The documentation was wrong before.
 
-** In define-key-after, if AFTER is t, the new binding now always goes
+** In 'define-key-after', if AFTER is t, the new binding now always goes
 at the end of the keymap.  If the keymap is a menu, this means it
 goes after the other menu items.
 
 ** If you have a program that makes several changes in the same area
-of the buffer, you can use the macro combine-after-change-calls
+of the buffer, you can use the macro 'combine-after-change-calls'
 around that Lisp code to make it faster when after-change hooks
 are in use.
 
@@ -4402,14 +4402,14 @@ Don't alter the variables after-change-functions and
 after-change-function within the body of a combine-after-change-calls
 form.
 
-** If you define an abbrev (with define-abbrev) whose EXPANSION
+** If you define an abbrev (with 'define-abbrev') whose EXPANSION
 is not a string, then the abbrev does not expand in the usual sense,
 but its hook is still run.
 
 ** Normally, the Lisp debugger is not used (even if you have enabled it)
 for errors that are handled by condition-case.
 
-If you set debug-on-signal to a non-nil value, then the debugger is called
+If you set 'debug-on-signal' to a non-nil value, then the debugger is called
 regardless of whether there is a handler for the condition.  This is
 useful for debugging problems that happen inside of a condition-case.
 
@@ -4418,58 +4418,58 @@ are normal and ought to be handled, perhaps in timers 
or process
 filters, will instead invoke the debugger.  So don't say you weren't
 warned.
 
-** The new variable ring-bell-function lets you specify your own
+** The new variable 'ring-bell-function' lets you specify your own
 way for Emacs to "ring the bell".
 
-** If run-at-time's TIME argument is t, the action is repeated at
+** If 'run-at-time's TIME argument is t, the action is repeated at
 integral multiples of REPEAT from the epoch; this is useful for
 functions like display-time.
 
-** You can use the function locate-library to find the precise file
+** You can use the function 'locate-library' to find the precise file
 name of a Lisp library.  This isn't new, but wasn't documented before.
 
 ** Commands for entering view mode have new optional arguments that
 can be used from Lisp.  Low-level entrance to and exit from view mode
-is done by functions view-mode-enter and view-mode-exit.
+is done by functions 'view-mode-enter' and 'view-mode-exit'.
 
-** batch-byte-compile-file now makes Emacs return a nonzero status code
+** 'batch-byte-compile-file' now makes Emacs return a nonzero status code
 if there is an error in compilation.
 
-** pop-to-buffer, switch-to-buffer-other-window and
-switch-to-buffer-other-frame now accept an additional optional
-argument NORECORD, much like switch-to-buffer.  If it is non-nil,
+** 'pop-to-buffer', 'switch-to-buffer-other-window' and
+'switch-to-buffer-other-frame' now accept an additional optional
+argument NORECORD, much like 'switch-to-buffer'.  If it is non-nil,
 they don't put the buffer at the front of the buffer list.
 
 ** If your .emacs file leaves the *scratch* buffer non-empty,
 Emacs does not display the startup message, so as to avoid changing
 the *scratch* buffer.
 
-** The new function regexp-opt returns an efficient regexp to match a string.
+** The new function 'regexp-opt' returns an efficient regexp to match a string.
 The arguments are STRINGS and (optionally) PAREN.  This function can be used
 where regexp matching or searching is intensively used and speed is important,
 e.g., in Font Lock mode.
 
-** The variable buffer-display-count is local to each buffer,
+** The variable 'buffer-display-count' is local to each buffer,
 and is incremented each time the buffer is displayed in a window.
 It starts at 0 when the buffer is created.
 
-** The new function compose-mail starts composing a mail message
+** The new function 'compose-mail' starts composing a mail message
 using the user's chosen mail composition agent (specified with the
 variable mail-user-agent).  It has variants compose-mail-other-window
 and compose-mail-other-frame.
 
-** The `user-full-name' function now takes an optional parameter which
+** The 'user-full-name' function now takes an optional parameter which
 can either be a number (the UID) or a string (the login name).  The
 full name of the specified user will be returned.
 
 ** Lisp packages that load files of customizations, or any other sort
-of user profile, should obey the variable init-file-user in deciding
+of user profile, should obey the variable 'init-file-user' in deciding
 where to find it.  They should load the profile of the user name found
 in that variable.  If init-file-user is nil, meaning that the -q
 option was used, then Lisp packages should not load the customization
 files at all.
 
-** format-time-string now allows you to specify the field width
+** 'format-time-string' now allows you to specify the field width
 and type of padding.  This works as in printf: you write the field
 width as digits in the middle of a %-construct.  If you start
 the field width with 0, it means to pad with zeros.
@@ -4479,7 +4479,7 @@ minute; %03S means to pad this with zeros to 3 positions, 
%_3S to pad
 with spaces to 3 positions.  Plain %3S pads with zeros, because that
 is how %S normally pads to two positions.
 
-** thing-at-point now supports a new kind of "thing": url.
+** 'thing-at-point' now supports a new kind of "thing": url.
 
 ** imenu.el changes.
 
diff --git a/etc/NEWS.21 b/etc/NEWS.21
index 52d2eb6c52..6c25a76378 100644
--- a/etc/NEWS.21
+++ b/etc/NEWS.21
@@ -31,17 +31,17 @@ in UTF-8 locales).
 
 ** Translation tables are available between equivalent characters in
 different Emacs charsets -- for instance `e with acute' coming from the
-Latin-1 and Latin-2 charsets.  User options `unify-8859-on-encoding-mode'
-and `unify-8859-on-decoding-mode' respectively turn on translation
-between ISO 8859 character sets (`unification') on encoding
+Latin-1 and Latin-2 charsets.  User options 'unify-8859-on-encoding-mode'
+and 'unify-8859-on-decoding-mode' respectively turn on translation
+between ISO 8859 character sets ('unification') on encoding
 (e.g. writing a file) and decoding (e.g. reading a file).  Note that
-`unify-8859-on-encoding-mode' is useful and safe, but
-`unify-8859-on-decoding-mode' can cause text to change when you read
+'unify-8859-on-encoding-mode' is useful and safe, but
+'unify-8859-on-decoding-mode' can cause text to change when you read
 it and write it out again without edits, so it is not generally advisable.
-By default `unify-8859-on-encoding-mode' is turned on.
+By default 'unify-8859-on-encoding-mode' is turned on.
 
 ** In Emacs running on the X window system, the default value of
-`selection-coding-system' is now `compound-text-with-extensions'.
+'selection-coding-system' is now 'compound-text-with-extensions'.
 
 If you want the old behavior, set selection-coding-system to
 compound-text, which may be significantly more efficient.  Using
@@ -66,19 +66,19 @@ X applications can use `extended segments' to encode 
characters in
 compound text that belong to character sets which are not part of the
 list of approved standard encodings for X, e.g. Big5.  To paste
 selections with such characters into Emacs, use the new coding system
-compound-text-with-extensions as the value of selection-coding-system.
+'compound-text-with-extensions' as the value of 'selection-coding-system'.
 
-** The default values of `tooltip-delay' and `tooltip-hide-delay'
+** The default values of 'tooltip-delay' and 'tooltip-hide-delay'
 were changed.
 
 ** On terminals whose erase-char is ^H (Backspace), Emacs
-now uses normal-erase-is-backspace-mode.
+now uses 'normal-erase-is-backspace-mode'.
 
 ** When the *scratch* buffer is recreated, its mode is set from
-initial-major-mode, which normally is lisp-interaction-mode,
-instead of using default-major-mode.
+'initial-major-mode', which normally is 'lisp-interaction-mode',
+instead of using 'default-major-mode'.
 
-** The new option `Info-scroll-prefer-subnodes' causes Info to behave
+** The new option 'Info-scroll-prefer-subnodes' causes Info to behave
 like the stand-alone Info reader (from the GNU Texinfo package) as far
 as motion between nodes and their subnodes is concerned.  If it is t
 (the default), Emacs behaves as before when you type SPC in a menu: it
@@ -92,11 +92,11 @@ NEWS.
 
 * Lisp Changes in Emacs 21.2
 
-** The meanings of scroll-up-aggressively and scroll-down-aggressively
+** The meanings of 'scroll-up-aggressively' and 'scroll-down-aggressively'
 have been interchanged, so that the former now controls scrolling up,
 and the latter now controls scrolling down.
 
-** The variable `compilation-parse-errors-filename-function' can
+** The variable 'compilation-parse-errors-filename-function' can
 be used to transform filenames found in compilation output.
 
 
@@ -112,7 +112,7 @@ charsets in this release.
 ** Support for LynxOS has been added.
 
 ** There are new configure options associated with the support for
-images and toolkit scrollbars.  Use the --help option in `configure'
+images and toolkit scrollbars.  Use the --help option in 'configure'
 to list them.
 
 ** You can build a 64-bit Emacs for SPARC/Solaris systems which
@@ -121,13 +121,13 @@ maximum buffer size.  See etc/MACHINES for instructions.  
Changes to
 build on other 64-bit systems should be straightforward modulo any
 necessary changes to unexec.
 
-** There is a new configure option `--disable-largefile' to omit
+** There is a new configure option '--disable-largefile' to omit
 Unix-98-style support for large files if that is available.
 
-** There is a new configure option `--without-xim' that instructs
+** There is a new configure option '--without-xim' that instructs
 Emacs to not use X Input Methods (XIM), if these are available.
 
-** `movemail' defaults to supporting POP.  You can turn this off using
+** 'movemail' defaults to supporting POP.  You can turn this off using
 the --without-pop configure option, should that be necessary.
 
 ** This version can be built for the Macintosh, but does not implement
@@ -169,10 +169,10 @@ Faces with a weight greater than normal are displayed 
extra-bright, if
 the terminal supports it.  Faces with a weight less than normal and
 italic faces are displayed dimmed, if the terminal supports it.
 Underlined faces are displayed underlined if possible.  Other face
-attributes such as `overline', `strike-through', and `box' are ignored
+attributes such as 'overline', 'strike-through', and 'box' are ignored
 on terminals.
 
-The command-line options `-fg COLOR', `-bg COLOR', and `-rv' are now
+The command-line options `-fg COLOR', `-bg COLOR', and '-rv' are now
 supported on character terminals.
 
 Emacs automatically remaps all X-style color specifications to one of
@@ -187,7 +187,7 @@ a TTY or when Emacs is invoked with the -nw option.
 Emacs supports playing sound files on GNU/Linux and FreeBSD (Voxware
 driver and native BSD driver, a.k.a. Luigi's driver).  Currently
 supported file formats are RIFF-WAVE (*.wav) and Sun Audio (*.au).
-You must configure Emacs with the option `--with-sound=yes' to enable
+You must configure Emacs with the option '--with-sound=yes' to enable
 sound support.
 
 ** Emacs now resizes mini-windows if appropriate.
@@ -197,7 +197,7 @@ longer than one line, Emacs can resize the minibuffer 
window unless it
 is on a frame of its own.  You can control resizing and the maximum
 minibuffer window size by setting the following variables:
 
-- User option: max-mini-window-height
+- User option: 'max-mini-window-height'
 
 Maximum height for resizing mini-windows.  If a float, it specifies a
 fraction of the mini-window frame's height.  If an integer, it
@@ -205,14 +205,14 @@ specifies a number of lines.
 
 Default is 0.25.
 
-- User option: resize-mini-windows
+- User option: 'resize-mini-windows'
 
 How to resize mini-windows.  If nil, don't resize.  If t, always
-resize to fit the size of the text.  If `grow-only', let mini-windows
+resize to fit the size of the text.  If 'grow-only', let mini-windows
 grow only, until they become empty, at which point they are shrunk
 again.
 
-Default is `grow-only'.
+Default is 'grow-only'.
 
 ** LessTif support.
 
@@ -222,7 +222,7 @@ Emacs now runs with the LessTif toolkit (see
 ** LessTif/Motif file selection dialog.
 
 When Emacs is configured to use LessTif or Motif, reading a file name
-from a menu will pop up a file selection dialog if `use-dialog-box' is
+from a menu will pop up a file selection dialog if 'use-dialog-box' is
 non-nil.
 
 ** File selection dialog on MS-Windows is supported.
@@ -237,12 +237,12 @@ Emacs now uses toolkit scroll bars if available.  When 
configured for
 LessTif/Motif, it will use that toolkit's scroll bar.  Otherwise, when
 configured for Lucid and Athena widgets, it will use the Xaw3d scroll
 bar if Xaw3d is available.  You can turn off the use of toolkit scroll
-bars by specifying `--with-toolkit-scroll-bars=no' when configuring
+bars by specifying '--with-toolkit-scroll-bars=no' when configuring
 Emacs.
 
 When you encounter problems with the Xaw3d scroll bar, watch out how
 Xaw3d is compiled on your system.  If the Makefile generated from
-Xaw3d's Imakefile contains a `-DNARROWPROTO' compiler option, and your
+Xaw3d's Imakefile contains a '-DNARROWPROTO' compiler option, and your
 Emacs system configuration file `s/your-system.h' does not contain a
 define for NARROWPROTO, you might consider adding it.  Take
 `s/freebsd.h' as an example.
@@ -254,8 +254,8 @@ different systems).  You will find files `*.cf' there.  If 
your
 system's cf-file contains a line like `#define NeedWidePrototypes NO',
 add a `#define NARROWPROTO' to your Emacs system configuration file.
 
-The reason for this is that one Xaw3d function uses `double' or
-`float' function parameters depending on the setting of NARROWPROTO.
+The reason for this is that one Xaw3d function uses 'double' or
+'float' function parameters depending on the setting of NARROWPROTO.
 This is not a problem when Imakefiles are used because each system's
 imake configuration file contains the necessary information.  Since
 Emacs doesn't use imake, this has do be done manually.
@@ -275,22 +275,22 @@ for specific modes (with copyright assignments).
 ** Tooltips.
 
 Tooltips are small X windows displaying a help string at the current
-mouse position.  The Lisp package `tooltip' implements them.  You can
-turn them off via the user option `tooltip-mode'.
+mouse position.  The Lisp package 'tooltip' implements them.  You can
+turn them off via the user option 'tooltip-mode'.
 
 Tooltips also provides support for GUD debugging.  If activated,
 variable values can be displayed in tooltips by pointing at them with
 the mouse in source buffers.  You can customize various aspects of the
-tooltip display in the group `tooltip'.
+tooltip display in the group 'tooltip'.
 
 ** Automatic Hscrolling
 
 Horizontal scrolling now happens automatically if
-`automatic-hscrolling' is set (the default).  This setting can be
+'automatic-hscrolling' is set (the default).  This setting can be
 customized.
 
-If a window is scrolled horizontally with set-window-hscroll, or
-scroll-left/scroll-right (C-x <, C-x >), this serves as a lower bound
+If a window is scrolled horizontally with 'set-window-hscroll', or
+'scroll-left'/'scroll-right' (C-x <, C-x >), this serves as a lower bound
 for automatic horizontal scrolling.  Automatic scrolling will scroll
 the text more to the left if necessary, but won't scroll the text more
 to the right than the column set with set-window-hscroll etc.
@@ -298,25 +298,25 @@ to the right than the column set with set-window-hscroll 
etc.
 ** When using a windowing terminal, each Emacs window now has a cursor
 of its own.  By default, when a window is selected, the cursor is
 solid; otherwise, it is hollow.  The user-option
-`cursor-in-non-selected-windows' controls how to display the
+'cursor-in-non-selected-windows' controls how to display the
 cursor in non-selected windows.  If nil, no cursor is shown, if
 non-nil a hollow box cursor is shown.
 
 ** Fringes to the left and right of windows are used to display
 truncation marks, continuation marks, overlay arrows and alike.  The
 foreground, background, and stipple of these areas can be changed by
-customizing face `fringe'.
+customizing face 'fringe'.
 
 ** The mode line under X is now drawn with shadows by default.
-You can change its appearance by modifying the face `mode-line'.
+You can change its appearance by modifying the face 'mode-line'.
 In particular, setting the `:box' attribute to nil turns off the 3D
 appearance of the mode line.  (The 3D appearance makes the mode line
 occupy more space, and thus might cause the first or the last line of
 the window to be partially obscured.)
 
-The variable `mode-line-inverse-video', which was used in older
+The variable 'mode-line-inverse-video', which was used in older
 versions of emacs to make the mode-line stand out, is now deprecated.
-However, setting it to nil will cause the `mode-line' face to be
+However, setting it to nil will cause the 'mode-line' face to be
 ignored, and mode-lines to be drawn using the default text face.
 
 ** Mouse-sensitive mode line.
@@ -344,20 +344,20 @@ Currently, the following actions have been defined:
 ** Hourglass pointer
 
 Emacs can optionally display an hourglass pointer under X.  You can
-turn the display on or off by customizing group `cursor'.
+turn the display on or off by customizing group 'cursor'.
 
 ** Blinking cursor
 
 M-x blink-cursor-mode toggles a blinking cursor under X and on
-terminals having terminal capabilities `vi', `vs', and `ve'.  Blinking
+terminals having terminal capabilities 'vi', 'vs', and 've'.  Blinking
 and related parameters like frequency and delay can be customized in
-the group `cursor'.
+the group 'cursor'.
 
-** New font-lock support mode `jit-lock-mode'.
+** New font-lock support mode 'jit-lock-mode'.
 
-This support mode is roughly equivalent to `lazy-lock' but is
+This support mode is roughly equivalent to 'lazy-lock' but is
 generally faster.  It supports stealth and deferred fontification.
-See the documentation of the function `jit-lock-mode' for more
+See the documentation of the function 'jit-lock-mode' for more
 details.
 
 Font-lock uses jit-lock-mode as default support mode, so you don't
@@ -365,7 +365,7 @@ have to do anything to activate it.
 
 ** The default binding of the Delete key has changed.
 
-The new user-option `normal-erase-is-backspace' can be set to
+The new user-option 'normal-erase-is-backspace' can be set to
 determine the effect of the Delete and Backspace function keys.
 
 On window systems, the default value of this option is chosen
@@ -380,14 +380,14 @@ set to nil, and these keys delete backward.
 If not running under a window system, setting this option accomplishes
 a similar effect by mapping C-h, which is usually generated by the
 Backspace key, to DEL, and by mapping DEL to C-d via
-`keyboard-translate'.  The former functionality of C-h is available on
+'keyboard-translate'.  The former functionality of C-h is available on
 the F1 key.  You should probably not use this setting on a text-only
 terminal if you don't have both Backspace, Delete and F1 keys.
 
-Programmatically, you can call function normal-erase-is-backspace-mode
+Programmatically, you can call function 'normal-erase-is-backspace-mode'
 to toggle the behavior of the Delete and Backspace keys.
 
-** The default for user-option `next-line-add-newlines' has been
+** The default for user-option 'next-line-add-newlines' has been
 changed to nil, i.e. C-n will no longer add newlines at the end of a
 buffer by default.
 
@@ -396,14 +396,14 @@ current line, respectively.  C-<home> and C-<end> move to 
the
 beginning and end of the buffer.
 
 ** Emacs now checks for recursive loads of Lisp files.  If the
-recursion depth exceeds `recursive-load-depth-limit', an error is
+recursion depth exceeds 'recursive-load-depth-limit', an error is
 signaled.
 
 ** When an error is signaled during the loading of the user's init
 file, Emacs now pops up the *Messages* buffer.
 
 ** Emacs now refuses to load compiled Lisp files which weren't
-compiled with Emacs.  Set `load-dangerous-libraries' to t to change
+compiled with Emacs.  Set 'load-dangerous-libraries' to t to change
 this behavior.
 
 The reason for this change is an incompatible change in XEmacs's byte
@@ -425,24 +425,24 @@ using that menu.
 
 ** Highlighting of trailing whitespace.
 
-When `show-trailing-whitespace' is non-nil, Emacs displays trailing
-whitespace in the face `trailing-whitespace'.  Trailing whitespace is
+When 'show-trailing-whitespace' is non-nil, Emacs displays trailing
+whitespace in the face 'trailing-whitespace'.  Trailing whitespace is
 defined as spaces or tabs at the end of a line.  To avoid busy
 highlighting when entering new text, trailing whitespace is not
 displayed if point is at the end of the line containing the
 whitespace.
 
-** C-x 5 1 runs the new command delete-other-frames which deletes
+** C-x 5 1 runs the new command 'delete-other-frames' which deletes
 all frames except the selected one.
 
-** The new user-option `confirm-kill-emacs' can be customized to
+** The new user-option 'confirm-kill-emacs' can be customized to
 let Emacs ask for confirmation before exiting.
 
 ** The header line in an Info buffer is now displayed as an emacs
 header-line (which is like a mode-line, but at the top of the window),
 so that it remains visible even when the buffer has been scrolled.
 This behavior may be disabled by customizing the option
-`Info-use-header-line'.
+'Info-use-header-line'.
 
 ** Polish, Czech, German, and French translations of Emacs' reference card
 have been added.  They are named `pl-refcard.tex', `cs-refcard.tex',
@@ -459,66 +459,66 @@ displayed it pops up a menu containing the items which 
would be on the
 menu bar.  If the menu bar is displayed, it pops up the major mode
 menu or the Edit menu if there is no major mode menu.
 
-** Variable `load-path' is no longer customizable through Customize.
+** Variable 'load-path' is no longer customizable through Customize.
 
-You can no longer use `M-x customize-variable' to customize `load-path'
+You can no longer use `M-x customize-variable' to customize 'load-path'
 because it now contains a version-dependent component.  You can still
-use `add-to-list' and `setq' to customize this variable in your
+use 'add-to-list' and 'setq' to customize this variable in your
 `~/.emacs' init file or to modify it from any Lisp program in general.
 
 ** C-u C-x = provides detailed information about the character at
 point in a pop-up window.
 
 ** Emacs can now support 'wheeled' mice (such as the MS IntelliMouse)
-under XFree86.  To enable this, use the `mouse-wheel-mode' command, or
-customize the variable `mouse-wheel-mode'.
+under XFree86.  To enable this, use the 'mouse-wheel-mode' command, or
+customize the variable 'mouse-wheel-mode'.
 
-The variables `mouse-wheel-follow-mouse' and `mouse-wheel-scroll-amount'
+The variables 'mouse-wheel-follow-mouse' and 'mouse-wheel-scroll-amount'
 determine where and by how much buffers are scrolled.
 
 ** Emacs' auto-save list files are now by default stored in a
 sub-directory `.emacs.d/auto-save-list/' of the user's home directory.
 (On MS-DOS, this subdirectory's name is `_emacs.d/auto-save.list/'.)
-You can customize `auto-save-list-file-prefix' to change this location.
+You can customize 'auto-save-list-file-prefix' to change this location.
 
-** The function `getenv' is now callable interactively.
+** The function 'getenv' is now callable interactively.
 
-** The new user-option `even-window-heights' can be set to nil
-to prevent `display-buffer' from evening out window heights.
+** The new user-option 'even-window-heights' can be set to nil
+to prevent 'display-buffer' from evening out window heights.
 
 ** The new command M-x delete-trailing-whitespace RET will delete the
 trailing whitespace within the current restriction.  You can also add
-this function to `write-file-hooks' or `local-write-file-hooks'.
+this function to 'write-file-hooks' or 'local-write-file-hooks'.
 
 ** When visiting a file with M-x find-file-literally, no newlines will
-be added to the end of the buffer even if `require-final-newline' is
+be added to the end of the buffer even if 'require-final-newline' is
 non-nil.
 
-** The new user-option `find-file-suppress-same-file-warnings' can be
+** The new user-option 'find-file-suppress-same-file-warnings' can be
 set to suppress warnings ``X and Y are the same file'' when visiting a
 file that is already visited under a different name.
 
-** The new user-option `electric-help-shrink-window' can be set to
+** The new user-option 'electric-help-shrink-window' can be set to
 nil to prevent adjusting the help window size to the buffer size.
 
 ** New command M-x describe-character-set reads a character set name
 and displays information about that.
 
-** The new variable `auto-mode-interpreter-regexp' contains a regular
+** The new variable 'auto-mode-interpreter-regexp' contains a regular
 expression matching interpreters, for file mode determination.
 
 This regular expression is matched against the first line of a file to
-determine the file's mode in `set-auto-mode' when Emacs can't deduce a
+determine the file's mode in 'set-auto-mode' when Emacs can't deduce a
 mode from the file's name.  If it matches, the file is assumed to be
 interpreted by the interpreter matched by the second group of the
 regular expression.  The mode is then determined as the mode
-associated with that interpreter in `interpreter-mode-alist'.
+associated with that interpreter in 'interpreter-mode-alist'.
 
-** New function executable-make-buffer-file-executable-if-script-p is
-suitable as an after-save-hook as an alternative to `executable-chmod'.
+** New function 'executable-make-buffer-file-executable-if-script-p' is
+suitable as an 'after-save-hook' as an alternative to 'executable-chmod'.
 
 ** The most preferred coding-system is now used to save a buffer if
-buffer-file-coding-system is `undecided' and it is safe for the buffer
+buffer-file-coding-system is 'undecided' and it is safe for the buffer
 contents.  (The most preferred is set by set-language-environment or
 by M-x prefer-coding-system.)  Thus if you visit an ASCII file and
 insert a non-ASCII character from your current language environment,
@@ -526,22 +526,22 @@ the file will be saved silently with the appropriate 
coding.
 Previously you would be prompted for a safe coding system.
 
 ** The many obsolete language `setup-...-environment' commands have
-been removed -- use `set-language-environment'.
+been removed -- use 'set-language-environment'.
 
-** The new Custom option `keyboard-coding-system' specifies a coding
+** The new Custom option 'keyboard-coding-system' specifies a coding
 system for keyboard input.
 
-** New variable `inhibit-iso-escape-detection' determines if Emacs'
+** New variable 'inhibit-iso-escape-detection' determines if Emacs'
 coding system detection algorithm should pay attention to ISO2022's
 escape sequences.  If this variable is non-nil, the algorithm ignores
 such escape sequences.  The default value is nil, and it is
 recommended not to change it except for the special case that you
 always want to read any escape code verbatim.  If you just want to
 read a specific file without decoding escape codes, use C-x RET c
-(`universal-coding-system-argument').  For instance, C-x RET c latin-1
+('universal-coding-system-argument').  For instance, C-x RET c latin-1
 RET C-x C-f filename RET.
 
-** Variable `default-korean-keyboard' is initialized properly from the
+** Variable 'default-korean-keyboard' is initialized properly from the
 environment variable `HANGUL_KEYBOARD_TYPE'.
 
 ** New command M-x list-charset-chars reads a character set name and
@@ -554,15 +554,15 @@ coding systems such as cpXXX and cyrillic-koi8.
 and preferred and locale coding systems systematically from the
 LC_ALL, LC_CTYPE, and LANG environment variables during startup.
 
-** New language environments `Polish', `Latin-8' and `Latin-9'.
+** New language environments 'Polish', 'Latin-8' and 'Latin-9'.
 Latin-8 and Latin-9 correspond respectively to the ISO character sets
 8859-14 (Celtic) and 8859-15 (updated Latin-1, with the Euro sign).
 GNU Intlfonts doesn't support these yet but recent X releases have
 8859-15.  See etc/INSTALL for information on obtaining extra fonts.
 There are new Leim input methods for Latin-8 and Latin-9 prefix (only)
-and Polish `slash'.
+and Polish 'slash'.
 
-** New language environments `Dutch' and `Spanish'.
+** New language environments 'Dutch' and 'Spanish'.
 These new environments mainly select appropriate translations
 of the tutorial.
 
@@ -570,22 +570,22 @@ of the tutorial.
 function keys are changed as follows.  This is to conform to "Emacs
 Lisp Coding Convention".
 
-    new  command                            old-binding
-    ---  -------                            -----------
-    f3   ethio-fidel-to-sera-buffer         f5
-    S-f3 ethio-fidel-to-sera-region         f5
-    C-f3 ethio-fidel-to-sera-mail-or-marker f5
+    new  command                              old-binding
+    ---  -------                              -----------
+    f3   'ethio-fidel-to-sera-buffer'         f5
+    S-f3 'ethio-fidel-to-sera-region'         f5
+    C-f3 'ethio-fidel-to-sera-mail-or-marker' f5
 
-    f4   ethio-sera-to-fidel-buffer         unchanged
-    S-f4 ethio-sera-to-fidel-region         unchanged
-    C-f4 ethio-sera-to-fidel-mail-or-marker unchanged
+    f4   'ethio-sera-to-fidel-buffer'         unchanged
+    S-f4 'ethio-sera-to-fidel-region'         unchanged
+    C-f4 'ethio-sera-to-fidel-mail-or-marker' unchanged
 
-    S-f5 ethio-toggle-punctuation           f3
-    S-f6 ethio-modify-vowel                 f6
-    S-f7 ethio-replace-space                f7
-    S-f8 ethio-input-special-character      f8
-    S-f9 ethio-replace-space                unchanged
-    C-f9 ethio-toggle-space                 f2
+    S-f5 'ethio-toggle-punctuation'           f3
+    S-f6 'ethio-modify-vowel'                 f6
+    S-f7 'ethio-replace-space'                f7
+    S-f8 'ethio-input-special-character'      f8
+    S-f9 'ethio-replace-space'                unchanged
+    C-f9 'ethio-toggle-space'                 f2
 
 ** There are new Leim input methods.
 New input methods "turkish-postfix", "turkish-alt-postfix",
@@ -602,49 +602,49 @@ typing them inserts "q" and "Q" respectively.  Rules for 
translating
 8859 character sets but can display Latin-1, you can display
 more-or-less mnemonic sequences of ASCII/Latin-1 characters instead of
 empty boxes (under a window system) or question marks (not under a
-window system).  Customize the option `latin1-display' to turn this
+window system).  Customize the option 'latin1-display' to turn this
 on.
 
-** M-; now calls comment-dwim which tries to do something clever based
-on the context.  M-x kill-comment is now an alias to comment-kill,
+** M-; now calls 'comment-dwim' which tries to do something clever based
+on the context.  M-x kill-comment is now an alias to 'comment-kill',
 defined in newcomment.el.  You can choose different styles of region
-commenting with the variable `comment-style'.
+commenting with the variable 'comment-style'.
 
-** New user options `display-time-mail-face' and
-`display-time-use-mail-icon' control the appearance of mode-line mail
+** New user options 'display-time-mail-face' and
+'display-time-use-mail-icon' control the appearance of mode-line mail
 indicator used by the display-time package.  On a suitable display the
 indicator can be an icon and is mouse-sensitive.
 
 ** On window-systems, additional space can be put between text lines
 on the display using several methods
 
-- By setting frame parameter `line-spacing' to PIXELS.  PIXELS must be
+- By setting frame parameter 'line-spacing' to PIXELS.  PIXELS must be
 a positive integer, and specifies that PIXELS number of pixels should
 be put below text lines on the affected frame or frames.
 
-- By setting X resource `lineSpacing', class `LineSpacing'.  This is
+- By setting X resource 'lineSpacing', class 'LineSpacing'.  This is
 equivalent to specifying the frame parameter.
 
-- By specifying `--line-spacing=N' or `-lsp N' on the command line.
+- By specifying '--line-spacing=N' or `-lsp N' on the command line.
 
-- By setting buffer-local variable `line-spacing'.  The meaning is
+- By setting buffer-local variable 'line-spacing'.  The meaning is
 the same, but applies to the a particular buffer only.
 
-** The new command `clone-indirect-buffer' can be used to create
+** The new command 'clone-indirect-buffer' can be used to create
 an indirect buffer that is a twin copy of the current buffer.  The
-command `clone-indirect-buffer-other-window', bound to C-x 4 c,
+command 'clone-indirect-buffer-other-window', bound to C-x 4 c,
 does the same but displays the indirect buffer in another window.
 
-** New user options `backup-directory-alist' and
-`make-backup-file-name-function' control the placement of backups,
+** New user options 'backup-directory-alist' and
+'make-backup-file-name-function' control the placement of backups,
 typically in a single directory or in an invisible sub-directory.
 
-** New commands iso-iso2sgml and iso-sgml2iso convert between Latin-1
+** New commands 'iso-iso2sgml' and 'iso-sgml2iso' convert between Latin-1
 characters and the corresponding SGML (HTML) entities.
 
 ** New X resources recognized
 
-*** The X resource `synchronous', class `Synchronous', specifies
+*** The X resource 'synchronous', class 'Synchronous', specifies
 whether Emacs should run in synchronous mode.  Synchronous mode
 is useful for debugging X problems.
 
@@ -652,9 +652,9 @@ Example:
 
   emacs.synchronous: true
 
-*** The X resource `visualClass, class `VisualClass', specifies the
+*** The X resource `visualClass, class 'VisualClass', specifies the
 visual Emacs should use.  The resource's value should be a string of
-the form `CLASS-DEPTH', where CLASS is the name of the visual class,
+the form 'CLASS-DEPTH', where CLASS is the name of the visual class,
 and DEPTH is the requested color depth as a decimal number.  Valid
 visual class names are
 
@@ -666,22 +666,22 @@ visual class names are
   StaticGray
 
 Visual class names specified as X resource are case-insensitive, i.e.
-`pseudocolor', `Pseudocolor' and `PseudoColor' all have the same
+'pseudocolor', 'Pseudocolor' and 'PseudoColor' all have the same
 meaning.
 
-The program `xdpyinfo' can be used to list the visual classes
+The program 'xdpyinfo' can be used to list the visual classes
 supported on your display, and which depths they have.  If
-`visualClass' is not specified, Emacs uses the display's default
+'visualClass' is not specified, Emacs uses the display's default
 visual.
 
 Example:
 
   emacs.visualClass: TrueColor-8
 
-*** The X resource `privateColormap', class `PrivateColormap',
+*** The X resource 'privateColormap', class 'PrivateColormap',
 specifies that Emacs should use a private colormap if it is using the
 default visual, and that visual is of class PseudoColor.  Recognized
-resource values are `true' or `on'.
+resource values are 'true' or 'on'.
 
 Example:
 
@@ -689,26 +689,26 @@ Example:
 
 ** Faces and frame parameters.
 
-There are four new faces `scroll-bar', `border', `cursor' and `mouse'.
-Setting the frame parameters `scroll-bar-foreground' and
-`scroll-bar-background' sets foreground and background color of face
-`scroll-bar' and vice versa.  Setting frame parameter `border-color'
-sets the background color of face `border' and vice versa.  Likewise
-for frame parameters `cursor-color' and face `cursor', and frame
-parameter `mouse-color' and face `mouse'.
+There are four new faces 'scroll-bar', 'border', 'cursor' and 'mouse'.
+Setting the frame parameters 'scroll-bar-foreground' and
+'scroll-bar-background' sets foreground and background color of face
+'scroll-bar' and vice versa.  Setting frame parameter 'border-color'
+sets the background color of face 'border' and vice versa.  Likewise
+for frame parameters 'cursor-color' and face 'cursor', and frame
+parameter 'mouse-color' and face 'mouse'.
 
-Changing frame parameter `font' sets font-related attributes of the
-`default' face and vice versa.  Setting frame parameters
-`foreground-color' or `background-color' sets the colors of the
-`default' face and vice versa.
+Changing frame parameter 'font' sets font-related attributes of the
+'default' face and vice versa.  Setting frame parameters
+'foreground-color' or 'background-color' sets the colors of the
+'default' face and vice versa.
 
-** New face `menu'.
+** New face 'menu'.
 
-The face `menu' can be used to change colors and font of Emacs' menus.
+The face 'menu' can be used to change colors and font of Emacs' menus.
 
-** New frame parameter `screen-gamma' for gamma correction.
+** New frame parameter 'screen-gamma' for gamma correction.
 
-The new frame parameter `screen-gamma' specifies gamma-correction for
+The new frame parameter 'screen-gamma' specifies gamma-correction for
 colors.  Its value may be nil, the default, in which case no gamma
 correction occurs, or a number > 0, usually a float, that specifies
 the screen gamma of a frame's display.
@@ -717,8 +717,8 @@ PC monitors usually have a screen gamma of 2.2.  smaller 
values result
 in darker colors.  You might want to try a screen gamma of 1.5 for LCD
 color displays.  The viewing gamma Emacs uses is 0.4545. (1/2.2).
 
-The X resource name of this parameter is `screenGamma', class
-`ScreenGamma'.
+The X resource name of this parameter is 'screenGamma', class
+'ScreenGamma'.
 
 ** Tabs and variable-width text.
 
@@ -743,24 +743,24 @@ LessTif and Motif.
 
 As an example: if a block cursor is over a tab character, it will be
 drawn as wide as that tab on the display.  To do this, set
-`x-stretch-cursor' to a non-nil value.
+'x-stretch-cursor' to a non-nil value.
 
 ** Empty display lines at the end of a buffer may be marked with a
 bitmap (this is similar to the tilde displayed by vi and Less).
 
 This behavior is activated by setting the buffer-local variable
-`indicate-empty-lines' to a non-nil value.  The default value of this
-variable is found in `default-indicate-empty-lines'.
+'indicate-empty-lines' to a non-nil value.  The default value of this
+variable is found in 'default-indicate-empty-lines'.
 
 ** There is a new "aggressive" scrolling method.
 
 When scrolling up because point is above the window start, if the
-value of the buffer-local variable `scroll-up-aggressively' is a
+value of the buffer-local variable 'scroll-up-aggressively' is a
 number, Emacs chooses a new window start so that point ends up that
 fraction of the window's height from the top of the window.
 
 When scrolling down because point is below the window end, if the
-value of the buffer-local variable `scroll-down-aggressively' is a
+value of the buffer-local variable 'scroll-down-aggressively' is a
 number, Emacs chooses a new window start so that point ends up that
 fraction of the window's height from the bottom of the window.
 
@@ -769,14 +769,14 @@ M-x clone-buffer, C-u m <entry> RET or C-u g <entry> RET.
 M-x clone-buffer can also be used on *Help* and several other special
 buffers.
 
-** The command `Info-search' now uses a search history.
+** The command 'Info-search' now uses a search history.
 
 ** Listing buffers with M-x list-buffers (C-x C-b) now shows
 abbreviated file names.  Abbreviations can be customized by changing
-`directory-abbrev-alist'.
+'directory-abbrev-alist'.
 
-** A new variable, backup-by-copying-when-privileged-mismatch, gives
-the highest file uid for which backup-by-copying-when-mismatch will be
+** A new variable, 'backup-by-copying-when-privileged-mismatch', gives
+the highest file uid for which 'backup-by-copying-when-mismatch' will be
 forced on.  The assumption is that uids less than or equal to this
 value are special uids (root, bin, daemon, etc.--not real system
 users) and that files owned by these users should not change ownership,
@@ -790,25 +790,25 @@ notably at the end of lines.
 All these functions have been rewritten to avoid inserting unwanted
 spaces, and an optional prefix now allows them to behave the old way.
 
-** The function `replace-rectangle' is an alias for `string-rectangle'.
+** The function 'replace-rectangle' is an alias for 'string-rectangle'.
 
-** The new command M-x string-insert-rectangle is like `string-rectangle',
+** The new command M-x string-insert-rectangle is like 'string-rectangle',
 but inserts text instead of replacing it.
 
 ** The new command M-x query-replace-regexp-eval acts like
 query-replace-regexp, but takes a Lisp expression which is evaluated
 after each match to get the replacement text.
 
-** M-x query-replace recognizes a new command `e' (or `E') that lets
+** M-x query-replace recognizes a new command 'e' (or 'E') that lets
 you edit the replacement string.
 
-** The new command mail-abbrev-complete-alias, bound to `M-TAB'
-(if you load the library `mailabbrev'), lets you complete mail aliases
-in the text, analogous to lisp-complete-symbol.
+** The new command 'mail-abbrev-complete-alias', bound to 'M-TAB'
+(if you load the library 'mailabbrev'), lets you complete mail aliases
+in the text, analogous to 'lisp-complete-symbol'.
 
-** The variable `echo-keystrokes' may now have a floating point value.
+** The variable 'echo-keystrokes' may now have a floating point value.
 
-** If your init file is compiled (.emacs.elc), `user-init-file' is set
+** If your init file is compiled (.emacs.elc), 'user-init-file' is set
 to the source name (.emacs.el), if that exists, after loading it.
 
 ** The help string specified for a menu-item whose definition contains
@@ -817,10 +817,10 @@ MS-DOS, either in the echo area or with tooltips.  Many 
standard menus
 displayed by Emacs now have help strings.
 
 --
-** New user option `read-mail-command' specifies a command to use to
+** New user option 'read-mail-command' specifies a command to use to
 read mail from the menu etc.
 
-** The environment variable `EMACSLOCKDIR' is no longer used on MS-Windows.
+** The environment variable 'EMACSLOCKDIR' is no longer used on MS-Windows.
 This environment variable was used when creating lock files.  Emacs on
 MS-Windows does not use this variable anymore.  This change was made
 before Emacs 21.1, but wasn't documented until now.
@@ -828,7 +828,7 @@ before Emacs 21.1, but wasn't documented until now.
 ** Highlighting of mouse-sensitive regions is now supported in the
 MS-DOS version of Emacs.
 
-** The new command `msdos-set-mouse-buttons' forces the MS-DOS version
+** The new command 'msdos-set-mouse-buttons' forces the MS-DOS version
 of Emacs to behave as if the mouse had a specified number of buttons.
 This comes handy with mice that don't report their number of buttons
 correctly.  One example is the wheeled mice, which report 3 buttons,
@@ -838,22 +838,22 @@ of Emacs.
 ** Customize changes
 
 *** Customize now supports comments about customized items.  Use the
-`State' menu to add comments, or give a prefix argument to
+'State' menu to add comments, or give a prefix argument to
 M-x customize-set-variable or M-x customize-set-value.  Note that
 customization comments will cause the customizations to fail in
 earlier versions of Emacs.
 
-*** The new option `custom-buffer-done-function' says whether to kill
+*** The new option 'custom-buffer-done-function' says whether to kill
 Custom buffers when you've done with them or just bury them (the
 default).
 
-*** If Emacs was invoked with the `-q' or `--no-init-file' options, it
+*** If Emacs was invoked with the '-q' or '--no-init-file' options, it
 does not allow you to save customizations in your `~/.emacs' init
 file.  This is because saving customizations from such a session would
 wipe out all the other customizations you might have on your init
 file.
 
-** If Emacs was invoked with the `-q' or `--no-init-file' options, it
+** If Emacs was invoked with the '-q' or '--no-init-file' options, it
 does not save disabled and enabled commands for future sessions, to
 avoid overwriting existing customizations of this kind that are
 already in your init file.
@@ -862,12 +862,12 @@ already in your init file.
 
 *** The commands to evaluate Lisp expressions, such as C-M-x in Lisp
 modes, C-j in Lisp Interaction mode, and M-:, now bind the variables
-print-level, print-length, and debug-on-error based on the new
-customizable variables eval-expression-print-level,
-eval-expression-print-length, and eval-expression-debug-on-error.
+'print-level', 'print-length', and 'debug-on-error' based on the new
+customizable variables 'eval-expression-print-level',
+'eval-expression-print-length', and 'eval-expression-debug-on-error'.
 
 The default values for the first two of these variables are 12 and 4
-respectively, which means that `eval-expression' now prints at most
+respectively, which means that 'eval-expression' now prints at most
 the first 12 members of a list and at most 4 nesting levels deep (if
 the list is longer or deeper than that, an ellipsis `...'  is
 printed).
@@ -878,7 +878,7 @@ printed representation and an unabbreviated one.
 The default value of eval-expression-debug-on-error is t, so any error
 during evaluation produces a backtrace.
 
-*** The function `eval-defun' (C-M-x) now loads Edebug and instruments
+*** The function 'eval-defun' (C-M-x) now loads Edebug and instruments
 code when called with a prefix argument.
 
 ** CC mode changes.
@@ -1069,10 +1069,10 @@ the empty string (which it commonly does).  A patch for 
that is
 available from the CC Mode web site (http://www.python.org/emacs/
 cc-mode/).
 
-**** The variables `c-hanging-comment-starter-p' and
-`c-hanging-comment-ender-p', which controlled how comment starters and
+**** The variables 'c-hanging-comment-starter-p' and
+'c-hanging-comment-ender-p', which controlled how comment starters and
 enders were filled, are not used anymore.  The new version of the
-function `c-fill-paragraph' keeps the comment starters and enders as
+function 'c-fill-paragraph' keeps the comment starters and enders as
 they were before the filling.
 
 **** It's now possible to selectively turn off auto filling.
@@ -1080,8 +1080,8 @@ The variable c-ignore-auto-fill is used to ignore auto 
fill mode in
 specific contexts, e.g. in preprocessor directives and in string
 literals.
 
-**** New context sensitive line break function c-context-line-break.
-It works like newline-and-indent in normal code, and adapts the line
+**** New context sensitive line break function 'c-context-line-break'.
+It works like 'newline-and-indent' in normal code, and adapts the line
 prefix according to the comment style when used inside comments.  If
 you're normally using newline-and-indent, you might want to switch to
 this function.
@@ -1114,7 +1114,7 @@ prefix.  This is intended for the type of large block 
comments that
 contain documentation with its own formatting.  In these you normally
 don't want CC Mode to change the indentation.
 
-*** The `c' syntactic symbol is now relative to the comment start
+*** The 'c' syntactic symbol is now relative to the comment start
 instead of the previous line, to make integers usable as lineup
 arguments.
 
@@ -1130,33 +1130,33 @@ Provan).
 
 ** Dired changes
 
-*** New variable `dired-recursive-deletes' determines if the delete
+*** New variable 'dired-recursive-deletes' determines if the delete
 command will delete non-empty directories recursively.  The default
 is, delete only empty directories.
 
-*** New variable `dired-recursive-copies' determines if the copy
+*** New variable 'dired-recursive-copies' determines if the copy
 command will copy directories recursively.  The default is, do not
 copy directories recursively.
 
-*** In command `dired-do-shell-command' (usually bound to `!') a `?'
+*** In command 'dired-do-shell-command' (usually bound to `!') a `?'
 in the shell command has a special meaning similar to `*', but with
 the difference that the command will be run on each file individually.
 
-*** The new command `dired-find-alternate-file' (usually bound to `a')
+*** The new command 'dired-find-alternate-file' (usually bound to 'a')
 replaces the Dired buffer with the buffer for an alternate file or
 directory.
 
-*** The new command `dired-show-file-type' (usually bound to `y') shows
+*** The new command 'dired-show-file-type' (usually bound to 'y') shows
 a message in the echo area describing what type of file the point is on.
-This command invokes the external program `file' do its work, and so
+This command invokes the external program 'file' do its work, and so
 will only work on systems with that program, and will be only as
 accurate or inaccurate as it is.
 
-*** Dired now properly handles undo changes of adding/removing `-R'
+*** Dired now properly handles undo changes of adding/removing '-R'
 from ls switches.
 
 *** Dired commands that prompt for a destination file now allow the use
-of the `M-n' command in the minibuffer to insert the source filename,
+of the 'M-n' command in the minibuffer to insert the source filename,
 which the user can then edit.  This only works if there is a single
 source file, not when operating on multiple marked files.
 
@@ -1171,16 +1171,16 @@ many details.  In particular, all procmail fetching 
variables are gone.
 
 If you used procmail like in
 
-(setq nnmail-use-procmail t)
-(setq nnmail-spool-file 'procmail)
-(setq nnmail-procmail-directory "~/mail/incoming/")
-(setq nnmail-procmail-suffix "\\.in")
+    (setq nnmail-use-procmail t)
+    (setq nnmail-spool-file 'procmail)
+    (setq nnmail-procmail-directory "~/mail/incoming/")
+    (setq nnmail-procmail-suffix "\\.in")
 
 this now has changed to
 
-(setq mail-sources
-      '((directory :path "~/mail/incoming/"
-                  :suffix ".in")))
+    (setq mail-sources
+          '((directory :path "~/mail/incoming/"
+                       :suffix ".in")))
 
 More information is available in the info doc at Select Methods ->
 Getting Mail -> Mail Sources
@@ -1208,8 +1208,8 @@ called to position point.
 *** The user can now decide which extra headers should be included in
 summary buffers and NOV files.
 
-*** `gnus-article-display-hook' has been removed.  Instead, a number
-of variables starting with `gnus-treat-' have been added.
+*** 'gnus-article-display-hook' has been removed.  Instead, a number
+of variables starting with 'gnus-treat-' have been added.
 
 *** The Gnus posting styles have been redone again and now work in a
 subtly different manner.
@@ -1242,15 +1242,15 @@ macros
 ** Changes in Outline mode.
 
 There is now support for Imenu to index headings.  A new command
-`outline-headers-as-kill' copies the visible headings in the region to
+'outline-headers-as-kill' copies the visible headings in the region to
 the kill ring, e.g. to produce a table of contents.
 
 ** Changes to Emacs Server
 
-*** The new option `server-kill-new-buffers' specifies what to do
+*** The new option 'server-kill-new-buffers' specifies what to do
 with buffers when done with them.  If non-nil, the default, buffers
 are killed, unless they were already present before visiting them with
-Emacs Server.  If nil, `server-temp-file-regexp' specifies which
+Emacs Server.  If nil, 'server-temp-file-regexp' specifies which
 buffers to kill, as before.
 
 Please note that only buffers are killed that still have a client,
@@ -1263,7 +1263,7 @@ of the form +LINE:COLUMN in addition to +LINE.
 ** Changes to Show Paren mode.
 
 *** Overlays used by Show Paren mode now use a priority property.
-The new user option show-paren-priority specifies the priority to
+The new user option 'show-paren-priority' specifies the priority to
 use.  Default is 1000.
 
 ** New command M-x check-parens can be used to find unbalanced paren
@@ -1275,31 +1275,31 @@ groups and strings in buffers in Lisp mode (or other 
modes).
 
 A block is now recognized by its start and end regexps (both strings),
 and an integer specifying which sub-expression in the start regexp
-serves as the place where a `forward-sexp'-like function can operate.
-See the documentation of variable `hs-special-modes-alist'.
+serves as the place where a 'forward-sexp'-like function can operate.
+See the documentation of variable 'hs-special-modes-alist'.
 
 *** During incremental search, if Hideshow minor mode is active,
-hidden blocks are temporarily shown.  The variable `hs-headline' can
+hidden blocks are temporarily shown.  The variable 'hs-headline' can
 be used in the mode line format to show the line at the beginning of
 the open block.
 
-*** User option `hs-hide-all-non-comment-function' specifies a
+*** User option 'hs-hide-all-non-comment-function' specifies a
 function to be called at each top-level block beginning, instead of
 the normal block-hiding function.
 
-*** The command `hs-show-region' has been removed.
+*** The command 'hs-show-region' has been removed.
 
 *** The key bindings have changed to fit the Emacs conventions,
 roughly imitating those of Outline minor mode.  Notably, the prefix
 for all bindings is now `C-c @'.  For details, see the documentation
-for `hs-minor-mode'.
+for 'hs-minor-mode'.
 
-*** The variable `hs-show-hidden-short-form' has been removed, and
+*** The variable 'hs-show-hidden-short-form' has been removed, and
 hideshow.el now always behaves as if this variable were set to t.
 
 ** Changes to Change Log mode and Add-Log functions
 
-*** If you invoke `add-change-log-entry' from a backup file, it makes
+*** If you invoke 'add-change-log-entry' from a backup file, it makes
 an entry appropriate for the file's parent.  This is useful for making
 log entries by comparing a version with deleted functions.
 
@@ -1310,38 +1310,38 @@ current buffer.
 in a log file.
 
 *** Change Log mode now adds a file's version number to change log
-entries if user-option `change-log-version-info-enabled' is non-nil.
+entries if user-option 'change-log-version-info-enabled' is non-nil.
 Unless the file is under version control the search for a file's
 version number is performed based on regular expressions from
-`change-log-version-number-regexp-list' which can be customized.
+'change-log-version-number-regexp-list' which can be customized.
 Version numbers are only found in the first 10 percent of a file.
 
 *** Change Log mode now defines its own faces for font-lock highlighting.
 
 ** Changes to cmuscheme
 
-*** The user-option `scheme-program-name' has been renamed
-`cmuscheme-program-name' due to conflicts with xscheme.el.
+*** The user-option 'scheme-program-name' has been renamed
+'cmuscheme-program-name' due to conflicts with xscheme.el.
 
 ** Changes in Font Lock
 
-*** The new function `font-lock-remove-keywords' can be used to remove
+*** The new function 'font-lock-remove-keywords' can be used to remove
 font-lock keywords from the current buffer or from a specific major mode.
 
 *** Multi-line patterns are now supported.  Modes using this, should
-set font-lock-multiline to t in their font-lock-defaults.
+set 'font-lock-multiline' to t in their 'font-lock-defaults'.
 
-*** `font-lock-syntactic-face-function' allows major-modes to choose
+*** 'font-lock-syntactic-face-function' allows major-modes to choose
 the face used for each string/comment.
 
-*** A new standard face `font-lock-doc-face'.
+*** A new standard face 'font-lock-doc-face'.
 Meant for Lisp docstrings, Javadoc comments and other "documentation in code".
 
 ** Changes to Shell mode
 
-*** The `shell' command now accepts an optional argument to specify the buffer
+*** The 'shell' command now accepts an optional argument to specify the buffer
 to use, which defaults to "*shell*".  When used interactively, a
-non-default buffer may be specified by giving the `shell' command a
+non-default buffer may be specified by giving the 'shell' command a
 prefix argument (causing it to prompt for the buffer name).
 
 ** Comint (subshell) changes
@@ -1353,17 +1353,17 @@ include shell-mode, gdb-mode, scheme-interaction-mode, 
etc.
 Comint now removes CRs from CR LF sequences, and treats single CRs and
 BSs in the output in a way similar to a terminal (by deleting to the
 beginning of the line, or deleting the previous character,
-respectively).  This is achieved by adding `comint-carriage-motion' to
-the `comint-output-filter-functions' hook by default.
+respectively).  This is achieved by adding 'comint-carriage-motion' to
+the 'comint-output-filter-functions' hook by default.
 
-*** By default, comint no longer uses the variable `comint-prompt-regexp'
+*** By default, comint no longer uses the variable 'comint-prompt-regexp'
 to distinguish prompts from user-input.  Instead, it notices which
 parts of the text were output by the process, and which entered by the
-user, and attaches `field' properties to allow emacs commands to use
+user, and attaches 'field' properties to allow emacs commands to use
 this information.  Common movement commands, notably beginning-of-line,
 respect field boundaries in a fairly natural manner.  To disable this
 feature, and use the old behavior, customize the user option
-`comint-use-prompt-regexp-instead-of-fields'.
+'comint-use-prompt-regexp-instead-of-fields'.
 
 *** Comint now includes new features to send commands to running processes
 and redirect the output to a designated buffer or buffers.
@@ -1378,77 +1378,77 @@ the buffer whose process should be used from the 
mini-buffer.
 
 *** Packages based on comint now highlight user input and program prompts,
 and support choosing previous input with mouse-2.  To control these features,
-see the user-options `comint-highlight-input' and `comint-highlight-prompt'.
+see the user-options 'comint-highlight-input' and 'comint-highlight-prompt'.
 
-*** The new command `comint-write-output' (usually bound to `C-c C-s')
+*** The new command 'comint-write-output' (usually bound to `C-c C-s')
 saves the output from the most recent command to a file.  With a prefix
 argument, it appends to the file.
 
-*** The command `comint-kill-output' has been renamed `comint-delete-output'
+*** The command 'comint-kill-output' has been renamed 'comint-delete-output'
 (usually bound to `C-c C-o'); the old name is aliased to it for
 compatibility.
 
-*** The new function `comint-add-to-input-history' adds commands to the input
+*** The new function 'comint-add-to-input-history' adds commands to the input
 ring (history).
 
-*** The new variable `comint-input-history-ignore' is a regexp for
+*** The new variable 'comint-input-history-ignore' is a regexp for
 identifying history lines that should be ignored, like tcsh time-stamp
 strings, starting with a `#'.  The default value of this variable is "^#".
 
 ** Changes to Rmail mode
 
-*** The new user-option rmail-user-mail-address-regexp can be
+*** The new user-option 'rmail-user-mail-address-regexp' can be
 set to fine tune the identification of the correspondent when
 receiving new mail.  If it matches the address of the sender, the
 recipient is taken as correspondent of a mail.  If nil, the default,
-`user-login-name' and `user-mail-address' are used to exclude yourself
+'user-login-name' and 'user-mail-address' are used to exclude yourself
 as correspondent.
 
 Usually you don't have to set this variable, except if you collect
 mails sent by you under different user names.  Then it should be a
 regexp matching your mail addresses.
 
-*** The new user-option rmail-confirm-expunge controls whether and how
+*** The new user-option 'rmail-confirm-expunge' controls whether and how
 to ask for confirmation before expunging deleted messages from an
 Rmail file.  You can choose between no confirmation, confirmation
 with y-or-n-p, or confirmation with yes-or-no-p.  Default is to ask
 for confirmation with yes-or-no-p.
 
-*** RET is now bound in the Rmail summary to rmail-summary-goto-msg,
-like `j'.
+*** RET is now bound in the Rmail summary to 'rmail-summary-goto-msg',
+like 'j'.
 
-*** There is a new user option `rmail-digest-end-regexps' that
+*** There is a new user option 'rmail-digest-end-regexps' that
 specifies the regular expressions to detect the line that ends a
 digest message.
 
-*** The new user option `rmail-automatic-folder-directives' specifies
+*** The new user option 'rmail-automatic-folder-directives' specifies
 in which folder to put messages automatically.
 
-*** The new function `rmail-redecode-body' allows to fix a message
+*** The new function 'rmail-redecode-body' allows to fix a message
 with non-ASCII characters if Emacs happens to decode it incorrectly
 due to missing or malformed "charset=" header.
 
-** The new user-option `mail-envelope-from' can be used to specify
+** The new user-option 'mail-envelope-from' can be used to specify
 an envelope-from address different from user-mail-address.
 
-** The variable mail-specify-envelope-from controls whether to
+** The variable 'mail-specify-envelope-from' controls whether to
 use the -f option when sending mail.
 
-** The Rmail command `o' (`rmail-output-to-rmail-file') now writes the
-current message in the internal `emacs-mule' encoding, rather than in
-the encoding taken from the variable `buffer-file-coding-system'.
+** The Rmail command 'o' ('rmail-output-to-rmail-file') now writes the
+current message in the internal 'emacs-mule' encoding, rather than in
+the encoding taken from the variable 'buffer-file-coding-system'.
 This allows to save messages whose characters cannot be safely encoded
 by the buffer's coding system, and makes sure the message will be
 displayed correctly when you later visit the target Rmail file.
 
 If you want your Rmail files be encoded in a specific coding system
-other than `emacs-mule', you can customize the variable
-`rmail-file-coding-system' to set its value to that coding system.
+other than 'emacs-mule', you can customize the variable
+'rmail-file-coding-system' to set its value to that coding system.
 
 ** Changes to TeX mode
 
-*** The default mode has been changed from `plain-tex-mode' to
-`latex-mode'.
+*** The default mode has been changed from 'plain-tex-mode' to
+'latex-mode'.
 
 *** latex-mode now has a simple indentation algorithm.
 
@@ -1466,13 +1466,13 @@ other than `emacs-mule', you can customize the variable
     can be edited from that buffer.
 
 *** Label and citation key selection now allow to select several
-    items and reference them together (use `m' to mark items, `a' or
-    `A' to use all marked entries).
+    items and reference them together (use 'm' to mark items, 'a' or
+    'A' to use all marked entries).
 
 *** reftex.el has been split into a number of smaller files to reduce
     memory use when only a part of RefTeX is being used.
 
-*** a new command `reftex-view-crossref-from-bibtex' (bound to `C-c &'
+*** a new command 'reftex-view-crossref-from-bibtex' (bound to `C-c &'
     in BibTeX-mode) can be called in a BibTeX database buffer in order
     to show locations in LaTeX documents where a particular entry has
     been cited.
@@ -1502,7 +1502,7 @@ file names.
 
 ** Ispell changes
 
-*** The command `ispell' now spell-checks a region if
+*** The command 'ispell' now spell-checks a region if
 transient-mark-mode is on, and the mark is active.  Otherwise it
 spell-checks the current buffer.
 
@@ -1525,20 +1525,20 @@ end of the buffer.
 
 *** Spell checking now works in the MS-DOS version of Emacs.
 
-*** The variable `ispell-format-word' has been renamed to
-`ispell-format-word-function'.  The old name is still available as
+*** The variable 'ispell-format-word' has been renamed to
+'ispell-format-word-function'.  The old name is still available as
 alias.
 
 ** Makefile mode changes
 
-*** The mode now uses the abbrev table `makefile-mode-abbrev-table'.
+*** The mode now uses the abbrev table 'makefile-mode-abbrev-table'.
 
 *** Conditionals and include statements are now highlighted when
 Fontlock mode is active.
 
 ** Isearch changes
 
-*** Isearch now puts a call to `isearch-resume' in the command history,
+*** Isearch now puts a call to 'isearch-resume' in the command history,
 so that searches can be resumed.
 
 *** In Isearch mode, C-M-s and C-M-r are now bound like C-s and C-r,
@@ -1551,11 +1551,11 @@ selection into the search string rather than giving an 
error.
 *** There is a new lazy highlighting feature in incremental search.
 
 Lazy highlighting is switched on/off by customizing variable
-`isearch-lazy-highlight'.  When active, all matches for the current
+'isearch-lazy-highlight'.  When active, all matches for the current
 search string are highlighted.  The current match is highlighted as
-before using face `isearch' or `region'.  All other matches are
-highlighted using face `isearch-lazy-highlight-face' which defaults to
-`secondary-selection'.
+before using face 'isearch' or 'region'.  All other matches are
+highlighted using face 'isearch-lazy-highlight-face' which defaults to
+'secondary-selection'.
 
 The extra highlighting makes it easier to anticipate where the cursor
 will end up each time you press C-s or C-r to repeat a pending search.
@@ -1563,7 +1563,7 @@ Highlighting of these additional matches happens in a 
deferred fashion
 using "idle timers," so the cycles needed do not rob isearch of its
 usual snappy response.
 
-If `isearch-lazy-highlight-cleanup' is set to t, highlights for
+If 'isearch-lazy-highlight-cleanup' is set to t, highlights for
 matches are automatically cleared when you end the search.  If it is
 set to nil, you can remove the highlights manually with `M-x
 isearch-lazy-highlight-cleanup'.
@@ -1575,7 +1575,7 @@ easier to plug-in arbitrary version control backends.  
(See Lisp
 Changes for details on the new structure.)  As a result, the mechanism
 to enable and disable support for particular version systems has
 changed: everything is now controlled by the new variable
-`vc-handled-backends'.  Its value is a list of symbols that identify
+'vc-handled-backends'.  Its value is a list of symbols that identify
 version systems; the default is '(RCS CVS SCCS).  When finding a file,
 each of the backends in that list is tried in order to see whether the
 file is registered in that backend.
@@ -1585,29 +1585,29 @@ backends to see if any of them considers itself 
"responsible" for the
 directory of the file (e.g. because a corresponding subdirectory for
 master files exists).  If none of the backends is responsible, then
 the first backend in the list that could register the file is chosen.
-As a consequence, the variable `vc-default-back-end' is now obsolete.
+As a consequence, the variable 'vc-default-back-end' is now obsolete.
 
-The old variable `vc-master-templates' is also obsolete, although VC
+The old variable 'vc-master-templates' is also obsolete, although VC
 still supports it for backward compatibility.  To define templates for
 RCS or SCCS, you should rather use the new variables
 vc-{rcs,sccs}-master-templates.  (There is no such feature under CVS
 where it doesn't make sense.)
 
-The variables `vc-ignore-vc-files' and `vc-handle-cvs' are also
-obsolete now, you must set `vc-handled-backends' to nil or exclude
-`CVS' from the list, respectively, to achieve their effect now.
+The variables 'vc-ignore-vc-files' and 'vc-handle-cvs' are also
+obsolete now, you must set 'vc-handled-backends' to nil or exclude
+'CVS' from the list, respectively, to achieve their effect now.
 
 *** General Changes
 
-The variable `vc-checkout-carefully' is obsolete: the corresponding
+The variable 'vc-checkout-carefully' is obsolete: the corresponding
 checks are always done now.
 
 VC Dired buffers are now kept up-to-date during all version control
 operations.
 
-`vc-diff' output is now displayed in `diff-mode'.
-`vc-print-log' uses `log-view-mode'.
-`vc-log-mode' (used for *VC-Log*) has been replaced by `log-edit-mode'.
+'vc-diff' output is now displayed in 'diff-mode'.
+'vc-print-log' uses 'log-view-mode'.
+'vc-log-mode' (used for *VC-Log*) has been replaced by 'log-edit-mode'.
 
 The command C-x v m (vc-merge) now accepts an empty argument as the
 first revision number.  This means that any recent changes on the
@@ -1627,9 +1627,9 @@ commit your changes back to CVS, or pick up changes from 
CVS into your
 local RCS archives.
 
 To make this work, the ``more local'' backend (RCS in our example)
-should come first in `vc-handled-backends', and the ``more remote''
+should come first in 'vc-handled-backends', and the ``more remote''
 backend (CVS) should come later.  (The default value of
-`vc-handled-backends' already has it that way.)
+'vc-handled-backends' already has it that way.)
 
 You can then commit changes to another backend (say, RCS), by typing
 C-u C-x v v RCS RET (i.e. vc-next-action now accepts a backend name as
@@ -1649,15 +1649,15 @@ buffer is initialized to contain the entire RCS change 
log of the file.
 
 *** Changes for CVS
 
-There is a new user option, `vc-cvs-stay-local'.  If it is `t' (the
+There is a new user option, 'vc-cvs-stay-local'.  If it is 't' (the
 default), then VC avoids network queries for files registered in
 remote repositories.  The state of such files is then only determined
-by heuristics and past information.  `vc-cvs-stay-local' can also be a
+by heuristics and past information.  'vc-cvs-stay-local' can also be a
 regexp to match against repository hostnames; only files from hosts
 that match it are treated locally.  If the variable is nil, then VC
 queries the repository just as often as it does for local files.
 
-If `vc-cvs-stay-local' is on, then VC also makes local backups of
+If 'vc-cvs-stay-local' is on, then VC also makes local backups of
 repository versions.  This means that ordinary diffs (C-x v =) and
 revert operations (C-x v u) can be done completely locally, without
 any repository interactions at all.  The name of a local version
@@ -1670,15 +1670,15 @@ automatically after commit.  (This feature doesn't work 
on MS-DOS,
 since DOS disallows more than a single dot in the trunk of a file
 name.)
 
-If `vc-cvs-stay-local' is on, and there have been changes in the
+If 'vc-cvs-stay-local' is on, and there have been changes in the
 repository, VC notifies you about it when you actually try to commit.
 If you want to check for updates from the repository without trying to
 commit, you can either use C-x v m RET to perform an update on the
 current file, or you can use C-x v r RET to get an update for an
 entire directory tree.
 
-The new user option `vc-cvs-use-edit' indicates whether VC should call
-"cvs edit" to make files writable; it defaults to `t'.  (This option
+The new user option 'vc-cvs-use-edit' indicates whether VC should call
+"cvs edit" to make files writable; it defaults to 't'.  (This option
 is only meaningful if the CVSREAD variable is set, or if files are
 "watched" by other developers.)
 
@@ -1697,7 +1697,7 @@ a version system named SYS, you write a library named 
vc-sys.el, which
 provides a number of functions vc-sys-... (see commentary at the top
 of vc.el for a detailed list of them).  To make VC use that library,
 you need to put it somewhere into Emacs' load path and add the symbol
-`SYS' to the list `vc-handled-backends'.
+'SYS' to the list 'vc-handled-backends'.
 
 ** The customizable EDT emulation package now supports the EDT
 SUBS command and EDT scroll margins.  It also works with more
@@ -1706,7 +1706,7 @@ See etc/edt-user.doc for more information.
 
 ** New modes and packages
 
-*** The new global minor mode `minibuffer-electric-default-mode'
+*** The new global minor mode 'minibuffer-electric-default-mode'
 automatically hides the `(default ...)' part of minibuffer prompts when
 the default is not applicable.
 
@@ -1716,7 +1716,7 @@ shapes are made up with the ascii characters |, -, / and 
\.
 
 Features are:
 
-- Intersecting: When a `|' intersects with a `-', a `+' is
+- Intersecting: When a `|' intersects with a '-', a `+' is
   drawn, like this:   |         \ /
                     --+--        X
                       |         / \
@@ -1792,8 +1792,8 @@ of interactively entered regexps.  For example,
 
   M-x highlight-regexp RET clearly RET RET
 
-will highlight all occurrences of `clearly' using a yellow background
-face.  New occurrences of `clearly' will be highlighted as they are
+will highlight all occurrences of 'clearly' using a yellow background
+face.  New occurrences of 'clearly' will be highlighted as they are
 typed.  `M-x unhighlight-regexp RET' will remove the highlighting.
 Any existing face can be used for highlighting and a set of
 appropriate faces is provided.  The regexps can be written into the
@@ -1813,7 +1813,7 @@ parser. It doesn't parse the DTDs however.
 *** The comment operations are now provided by the newcomment.el
 package which allows different styles of comment-region and should
 be more robust while offering the same functionality.
-`comment-region' now doesn't always comment a-line-at-a-time, but only
+'comment-region' now doesn't always comment a-line-at-a-time, but only
 comments the region, breaking the line at point if necessary.
 
 *** The Ebrowse package implements a C++ class browser and tags
@@ -1823,17 +1823,17 @@ separate Texinfo file.
 *** The PCL-CVS package available by either running M-x cvs-examine or
 by visiting a CVS administrative directory (with a prefix argument)
 provides an alternative interface to VC-dired for CVS.  It comes with
-`log-view-mode' to view RCS and SCCS logs and `log-edit-mode' used to
+'log-view-mode' to view RCS and SCCS logs and 'log-edit-mode' used to
 enter check-in log messages.
 
-*** The new package called `woman' allows to browse Unix man pages
+*** The new package called 'woman' allows to browse Unix man pages
 without invoking external programs.
 
 The command `M-x woman' formats manual pages entirely in Emacs Lisp
 and then displays them, like `M-x manual-entry' does.  Unlike
-`manual-entry', `woman' does not invoke any external programs, so it
-is useful on systems such as MS-DOS/MS-Windows where the `man' and
-Groff or `troff' commands are not readily available.
+'manual-entry', 'woman' does not invoke any external programs, so it
+is useful on systems such as MS-DOS/MS-Windows where the 'man' and
+Groff or 'troff' commands are not readily available.
 
 The command `M-x woman-find-file' asks for the file name of a man
 page, then formats and displays it like `M-x woman' does.
@@ -1853,11 +1853,11 @@ matching parens to make them stand out.  On such a 
setup you will
 probably also want to use the sub-expression mode when the regexp
 contains such to get feedback about their respective limits.
 
-*** glasses-mode is a minor mode that makes
+*** 'glasses-mode' is a minor mode that makes
 unreadableIdentifiersLikeThis readable.  It works as glasses, without
 actually modifying content of a buffer.
 
-*** The package ebnf2ps translates an EBNF to a syntactic chart in
+*** The package 'ebnf2ps' translates an EBNF to a syntactic chart in
 PostScript.
 
 Currently accepts ad-hoc EBNF, ISO EBNF and Bison/Yacc.
@@ -1895,51 +1895,51 @@ determine where the columns should be split.  In C and 
C++, for
 example, it will align variable names in declaration lists, or the
 equal signs of assignments.
 
-*** `paragraph-indent-minor-mode' is a new minor mode supporting
-paragraphs in the same style as `paragraph-indent-text-mode'.
+*** 'paragraph-indent-minor-mode' is a new minor mode supporting
+paragraphs in the same style as 'paragraph-indent-text-mode'.
 
 *** bs.el is a new package for buffer selection similar to
-list-buffers or electric-buffer-list.  Use M-x bs-show to display a
-buffer menu with this package.  See the Custom group `bs'.
+'list-buffers' or 'electric-buffer-list'.  Use M-x bs-show to display a
+buffer menu with this package.  See the Custom group 'bs'.
 
 *** find-lisp.el is a package emulating the Unix find command in Lisp.
 
-*** calculator.el is a small calculator package that is intended to
+*** 'calculator' is a small calculator package that is intended to
 replace desktop calculators such as xcalc and calc.exe.  Actually, it
 is not too small - it has more features than most desktop calculators,
 and can be customized easily to get many more functions.  It should
-not be confused with "calc" which is a much bigger mathematical tool
+not be confused with 'calc' which is a much bigger mathematical tool
 which answers different needs.
 
-*** The minor modes cwarn-mode and global-cwarn-mode highlights
+*** The minor modes 'cwarn-mode' and 'global-cwarn-mode' highlights
 suspicious C and C++ constructions.  Currently, assignments inside
-expressions, semicolon following `if', `for' and `while' (except, of
+expressions, semicolon following 'if', 'for' and 'while' (except, of
 course, after a `do .. while' statement), and C++ functions with
 reference parameters are recognized.  The modes require font-lock mode
 to be enabled.
 
-*** smerge-mode.el provides `smerge-mode', a simple minor-mode for files
+*** smerge-mode.el provides 'smerge-mode', a simple minor-mode for files
 containing diff3-style conflict markers, such as generated by RCS.
 
-*** 5x5.el is a simple puzzle game.
+*** '5x5' is a simple puzzle game.
 
-*** hl-line.el provides `hl-line-mode', a minor mode to highlight the
+*** hl-line.el provides 'hl-line-mode', a minor mode to highlight the
 current line in the current buffer.  It also provides
-`global-hl-line-mode' to provide the same behavior in all buffers.
+'global-hl-line-mode' to provide the same behavior in all buffers.
 
 *** ansi-color.el translates ANSI terminal escapes into text-properties.
 
-Please note: if `ansi-color-for-comint-mode' and
-`global-font-lock-mode' are non-nil, loading ansi-color.el will
-disable font-lock and add `ansi-color-apply' to
-`comint-preoutput-filter-functions' for all shell-mode buffers.  This
+Please note: if 'ansi-color-for-comint-mode' and
+'global-font-lock-mode' are non-nil, loading ansi-color.el will
+disable font-lock and add 'ansi-color-apply' to
+'comint-preoutput-filter-functions' for all shell-mode buffers.  This
 displays the output of "ls --color=yes" using the correct foreground
 and background colors.
 
 *** delphi.el provides a major mode for editing the Delphi (Object
 Pascal) language.
 
-*** quickurl.el provides a simple method of inserting a URL based on
+*** 'quickurl' provides a simple method of inserting a URL based on
 the text at point.
 
 *** sql.el provides an interface to SQL data bases.
@@ -1985,22 +1985,22 @@ It results:
 
 delim-col has the following options:
 
-   delimit-columns-str-before          Specify a string to be inserted
+   'delimit-columns-str-before'                Specify a string to be inserted
                                        before all columns.
 
-   delimit-columns-str-separator       Specify a string to be inserted
+   'delimit-columns-str-separator'     Specify a string to be inserted
                                        between each column.
 
-   delimit-columns-str-after           Specify a string to be inserted
+   'delimit-columns-str-after'         Specify a string to be inserted
                                        after all columns.
 
-   delimit-columns-separator           Specify a regexp which separates
+   'delimit-columns-separator'         Specify a regexp which separates
                                        each column.
 
 delim-col has the following commands:
 
-   delimit-columns-region      Prettify all columns in a text region.
-   delimit-columns-rectangle   Prettify all columns in a text rectangle.
+   'delimit-columns-region'    Prettify all columns in a text region.
+   'delimit-columns-rectangle' Prettify all columns in a text rectangle.
 
 *** Recentf mode maintains a menu for visiting files that were
 operated on recently.  User option recentf-menu-filter specifies a
@@ -2011,17 +2011,17 @@ recent file list can be displayed:
 - sorted by file paths, file names, ascending or descending.
 - showing paths relative to the current default-directory
 
-The `recentf-filter-changer' menu filter function allows to
+The 'recentf-filter-changer' menu filter function allows to
 dynamically change the menu appearance.
 
-*** elide-head.el provides a mechanism for eliding boilerplate header
+*** 'elide-head' provides a mechanism for eliding boilerplate header
 text.
 
-*** footnote.el provides `footnote-mode', a minor mode supporting use
+*** footnote.el provides 'footnote-mode', a minor mode supporting use
 of footnotes.  It is intended for use with Message mode, but isn't
 specific to Message mode.
 
-*** diff-mode.el provides `diff-mode', a major mode for
+*** diff-mode.el provides 'diff-mode', a major mode for
 viewing/editing context diffs (patches).  It is selected for files
 with extension `.diff', `.diffs', `.patch' and `.rej'.
 
@@ -2037,29 +2037,29 @@ for Autoconf, selected automatically.
 *** crm.el provides a facility to read multiple strings from the
 minibuffer with completion.
 
-*** todo-mode.el provides management of TODO lists and integration
+*** 'todo-mode' provides management of TODO lists and integration
 with the diary features.
 
 *** autoarg.el provides a feature reported from Twenex Emacs whereby
 numeric keys supply prefix args rather than self inserting.
 
-*** The function `turn-off-auto-fill' unconditionally turns off Auto
+*** The function 'turn-off-auto-fill' unconditionally turns off Auto
 Fill mode.
 
-*** pcomplete.el is a library that provides programmable completion
+*** 'pcomplete' is a library that provides programmable completion
 facilities for Emacs, similar to what zsh and tcsh offer.  The main
 difference is that completion functions are written in Lisp, meaning
 they can be profiled, debugged, etc.
 
-*** antlr-mode is a new major mode for editing ANTLR grammar files.
+*** 'antlr-mode' is a new major mode for editing ANTLR grammar files.
 It is automatically turned on for files whose names have the extension
 `.g'.
 
 ** Changes in sort.el
 
-The function sort-numeric-fields interprets numbers starting with `0'
-as octal and numbers starting with `0x' or `0X' as hexadecimal.  The
-new user-option sort-numeric-base can be used to specify a default
+The function 'sort-numeric-fields' interprets numbers starting with '0'
+as octal and numbers starting with '0x' or '0X' as hexadecimal.  The
+new user-option 'sort-numeric-base' can be used to specify a default
 numeric base.
 
 ** Changes to Ange-ftp
@@ -2068,42 +2068,43 @@ numeric base.
 names cleanly.  It is appended to the host name, separated by a hash
 sign, e.g. `/foo@bar.org#666:mumble'.  (This syntax comes from EFS.)
 
-*** If the new user-option `ange-ftp-try-passive-mode' is set, passive
+*** If the new user-option 'ange-ftp-try-passive-mode' is set, passive
 ftp mode will be used if the ftp client supports that.
 
 *** Ange-ftp handles the output of the w32-style clients which
 output ^M at the end of lines.
 
 ** The recommended way of using Iswitchb is via the new global minor
-mode `iswitchb-mode'.
+mode 'iswitchb-mode'.
 
 ** Just loading the msb package doesn't switch on Msb mode anymore.
-If you have `(require 'msb)' in your .emacs, please replace it with
-`(msb-mode 1)'.
+If you have `(require 'msb)' in your .emacs, please replace it with:
+
+    (msb-mode 1)
 
 ** Changes in Flyspell mode
 
-*** Flyspell mode has various new options.  See the `flyspell' Custom
+*** Flyspell mode has various new options.  See the 'flyspell' Custom
 group.
 
-*** The variable `flyspell-generic-check-word-p' has been renamed
-to `flyspell-generic-check-word-predicate'.  The old name is still
+*** The variable 'flyspell-generic-check-word-p' has been renamed
+to 'flyspell-generic-check-word-predicate'.  The old name is still
 available as alias.
 
-** The user option `backward-delete-char-untabify-method' controls the
-behavior of `backward-delete-char-untabify'.  The following values
+** The user option 'backward-delete-char-untabify-method' controls the
+behavior of 'backward-delete-char-untabify'.  The following values
 are recognized:
 
-`untabify' -- turn a tab to many spaces, then delete one space;
-`hungry'   -- delete all whitespace, both tabs and spaces;
-`all'      -- delete all whitespace, including tabs, spaces and newlines;
+'untabify' -- turn a tab to many spaces, then delete one space;
+'hungry'   -- delete all whitespace, both tabs and spaces;
+'all'      -- delete all whitespace, including tabs, spaces and newlines;
 nil        -- just delete one character.
 
-Default value is `untabify'.
+Default value is 'untabify'.
 
 [This change was made in Emacs 20.3 but not mentioned then.]
 
-** In Cperl mode `cperl-invalid-face' should now be a normal face
+** In Cperl mode 'cperl-invalid-face' should now be a normal face
 symbol, not double-quoted.
 
 ** Some packages are declared obsolete, to be removed in a future
@@ -2112,21 +2113,21 @@ profile, rnews, rnewspost, and sc.  Their 
implementations have been
 moved to lisp/obsolete.
 
 ** auto-compression mode is no longer enabled just by loading jka-compr.el.
-To control it, set `auto-compression-mode' via Custom or use the
-`auto-compression-mode' command.
+To control it, set 'auto-compression-mode' via Custom or use the
+'auto-compression-mode' command.
 
-** `browse-url-gnome-moz' is a new option for
-`browse-url-browser-function', invoking Mozilla in GNOME, and
-`browse-url-kde' can be chosen for invoking the KDE browser.
+** 'browse-url-gnome-moz' is a new option for
+'browse-url-browser-function', invoking Mozilla in GNOME, and
+'browse-url-kde' can be chosen for invoking the KDE browser.
 
-** The user-option `browse-url-new-window-p' has been renamed to
-`browse-url-new-window-flag'.
+** The user-option 'browse-url-new-window-p' has been renamed to
+'browse-url-new-window-flag'.
 
-** The functions `keep-lines', `flush-lines' and `how-many' now
+** The functions 'keep-lines', 'flush-lines' and 'how-many' now
 operate on the active region in Transient Mark mode.
 
-** `gnus-user-agent' is a new possibility for `mail-user-agent'.  It
-is like `message-user-agent', but with all the Gnus paraphernalia.
+** 'gnus-user-agent' is a new possibility for 'mail-user-agent'.  It
+is like 'message-user-agent', but with all the Gnus paraphernalia.
 
 ** The Strokes package has been updated.  If your Emacs has XPM
 support, you can use it for pictographic editing.  In Strokes mode,
@@ -2135,7 +2136,7 @@ buffer.  You can encode or decode a strokes buffer with 
new commands
 M-x strokes-encode-buffer and M-x strokes-decode-buffer.  There is a
 new command M-x strokes-list-strokes.
 
-** Hexl contains a new command `hexl-insert-hex-string' which inserts
+** Hexl contains a new command 'hexl-insert-hex-string' which inserts
 a string of hexadecimal numbers read from the mini-buffer.
 
 ** Hexl mode allows to insert non-ASCII characters.
@@ -2166,8 +2167,8 @@ declarations when given the --declarations option.
 "operator+", without spaces between the keyword and the operator.
 
 *** You shouldn't generally need any more the -C or -c++ option: etags
-automatically switches to C++ parsing when it meets the `class' or
-`template' keywords.
+automatically switches to C++ parsing when it meets the 'class' or
+'template' keywords.
 
 *** Etags now is able to delve at arbitrary deeps into nested structures in
 C-like languages.  Previously, it was limited to one or two brace levels.
@@ -2175,7 +2176,7 @@ C-like languages.  Previously, it was limited to one or 
two brace levels.
 *** New language Ada: tags are functions, procedures, packages, tasks, and
 types.
 
-*** In Fortran, `procedure' is not tagged.
+*** In Fortran, 'procedure' is not tagged.
 
 *** In Java, tags are created for "interface".
 
@@ -2194,12 +2195,12 @@ for PSWrap.
 
 ** Changes in etags.el
 
-*** The new user-option tags-case-fold-search can be used to make
+*** The new user-option 'tags-case-fold-search' can be used to make
 tags operations case-sensitive or case-insensitive.  The default
-is to use the same setting as case-fold-search.
+is to use the same setting as 'case-fold-search'.
 
 *** You can display additional output with M-x tags-apropos by setting
-the new variable tags-apropos-additional-actions.
+the new variable 'tags-apropos-additional-actions'.
 
 If non-nil, the variable's value should be a list of triples (TITLE
 FUNCTION TO-SEARCH).  For each triple, M-x tags-apropos processes
@@ -2237,15 +2238,15 @@ auto-compression-mode is active.  You can tag (with 
Etags) and search
 in buffers where no match is found.  In buffers where a match is
 found, the original value of point is pushed on the marker ring.
 
-** Fortran mode has a new command `fortran-strip-sequence-nos' to
+** Fortran mode has a new command 'fortran-strip-sequence-nos' to
 remove text past column 72.  The syntax class of `\' in Fortran is now
 appropriate for C-style escape sequences in strings.
 
-** SGML mode's default `sgml-validate-command' is now `nsgmls'.
+** SGML mode's default 'sgml-validate-command' is now 'nsgmls'.
 
-** A new command `view-emacs-problems' (C-h P) displays the PROBLEMS file.
+** A new command 'view-emacs-problems' (C-h P) displays the PROBLEMS file.
 
-** The Dabbrev package has a new user-option `dabbrev-ignored-regexps'
+** The Dabbrev package has a new user-option 'dabbrev-ignored-regexps'
 containing a list of regular expressions.  Buffers matching a regular
 expression from that list, are not checked.
 
@@ -2256,20 +2257,20 @@ the buffer, just like for the local files.
 
 ** The buffer menu (C-x C-b) no longer lists the *Buffer List* buffer.
 
-** When invoked with a prefix argument, the command `list-abbrevs' now
+** When invoked with a prefix argument, the command 'list-abbrevs' now
 displays local abbrevs, only.
 
 ** Refill minor mode provides preliminary support for keeping
 paragraphs filled as you modify them.
 
-** The variable `double-click-fuzz' specifies how much the mouse
+** The variable 'double-click-fuzz' specifies how much the mouse
 may be moved between clicks that are recognized as a pair.  Its value
 is measured in pixels.
 
-** The new global minor mode `auto-image-file-mode' allows image files
+** The new global minor mode 'auto-image-file-mode' allows image files
 to be visited as images.
 
-** Two new user-options `grep-command' and `grep-find-command'
+** Two new user-options 'grep-command' and 'grep-find-command'
 were added to compile.el.
 
 ** Withdrawn packages
@@ -2288,13 +2289,13 @@ There are a few Lisp changes which are not 
backwards-compatible and
 may require changes to existing code. Here is a list for reference.
 See the sections below for details.
 
-** Since `format' preserves text properties, the idiom
+** Since 'format' preserves text properties, the idiom
 `(format "%s" foo)' no longer works to copy and remove properties.
-Use `copy-sequence' to copy the string, then use `set-text-properties'
+Use 'copy-sequence' to copy the string, then use 'set-text-properties'
 to remove the properties of the copy.
 
-** Since the `keymap' text property now has significance, some code
-which uses both `local-map' and `keymap' properties (for portability)
+** Since the 'keymap' text property now has significance, some code
+which uses both 'local-map' and 'keymap' properties (for portability)
 may, for instance, give rise to duplicate menus when the keymaps from
 these properties are active.
 
@@ -2302,36 +2303,36 @@ these properties are active.
 ranges may affect some code.
 
 ** A non-nil value for the LOCAL arg of add-hook makes the hook
-buffer-local even if `make-local-hook' hasn't been called, which might
+buffer-local even if 'make-local-hook' hasn't been called, which might
 make a difference to some code.
 
 ** The new treatment of the minibuffer prompt might affect code which
 operates on the minibuffer.
 
-** The new character sets `eight-bit-control' and `eight-bit-graphic'
-cause `no-conversion' and `emacs-mule-unix' coding systems to produce
+** The new character sets 'eight-bit-control' and 'eight-bit-graphic'
+cause 'no-conversion' and 'emacs-mule-unix' coding systems to produce
 different results when reading files with non-ASCII characters
 (previously, both coding systems would produce the same results).
-Specifically, `no-conversion' interprets each 8-bit byte as a separate
-character.  This makes `no-conversion' inappropriate for reading
+Specifically, 'no-conversion' interprets each 8-bit byte as a separate
+character.  This makes 'no-conversion' inappropriate for reading
 multibyte text, e.g. buffers written to disk in their internal MULE
 encoding (auto-saving does that, for example).  If a Lisp program
-reads such files with `no-conversion', each byte of the multibyte
+reads such files with 'no-conversion', each byte of the multibyte
 sequence, including the MULE leading codes such as \201, is treated as
 a separate character, which prevents them from being interpreted in
 the buffer as multibyte characters.
 
 Therefore, Lisp programs that read files which contain the internal
-MULE encoding should use `emacs-mule-unix'.  `no-conversion' is only
+MULE encoding should use 'emacs-mule-unix'.  'no-conversion' is only
 appropriate for reading truly binary files.
 
-** Code that relies on the obsolete `before-change-function' and
-`after-change-function' to detect buffer changes will now fail.  Use
-`before-change-functions' and `after-change-functions' instead.
+** Code that relies on the obsolete 'before-change-function' and
+'after-change-function' to detect buffer changes will now fail.  Use
+'before-change-functions' and 'after-change-functions' instead.
 
-** Code that uses `concat' with integer args now gets an error, as
-long promised.  So does any code that uses derivatives of `concat',
-such as `mapconcat'.
+** Code that uses 'concat' with integer args now gets an error, as
+long promised.  So does any code that uses derivatives of 'concat',
+such as 'mapconcat'.
 
 ** The function base64-decode-string now always returns a unibyte
 string.
@@ -2345,9 +2346,9 @@ the emacs-mule encoding.  Also, files stored in the 
emacs-mule
 encoding using Emacs 20 with additional private charsets defined will
 probably not be read correctly by Emacs 21.
 
-** The variable `directory-sep-char' is slated for removal.
+** The variable 'directory-sep-char' is slated for removal.
 Not really a change (yet), but a projected one that you should be
-aware of: The variable `directory-sep-char' is deprecated, and should
+aware of: The variable 'directory-sep-char' is deprecated, and should
 not be used.  It was always ignored on GNU/Linux and Unix systems and
 on MS-DOS, but the MS-Windows port tried to support it by adapting the
 behavior of certain primitives to the value of this variable.  It
@@ -2360,12 +2361,12 @@ will not have any effect when support for this variable 
is removed.
 * Lisp changes made after edition 2.6 of the Emacs Lisp Manual,
 (Display-related features are described in a page of their own below.)
 
-** Function assq-delete-all replaces function assoc-delete-all.
+** Function 'assq-delete-all' replaces function 'assoc-delete-all'.
 
-** The new function animate-string, from lisp/play/animate.el
+** The new function 'animate-string', from lisp/play/animate.el
 allows the animated display of strings.
 
-** The new function `interactive-form' can be used to obtain the
+** The new function 'interactive-form' can be used to obtain the
 interactive form of a function.
 
 ** The keyword :set-after in defcustom allows to specify dependencies
@@ -2374,36 +2375,36 @@ between custom options.  Example:
   (defcustom default-input-method nil
     "*Default input method for multilingual text (a string).
   This is the input method activated automatically by the command
-  `toggle-input-method' (\\[toggle-input-method])."
+  'toggle-input-method' (\\[toggle-input-method])."
     :group 'mule
     :type '(choice (const nil) string)
     :set-after '(current-language-environment))
 
-This specifies that default-input-method should be set after
-current-language-environment even if default-input-method appears
-first in a custom-set-variables statement.
+This specifies that 'default-input-method' should be set after
+'current-language-environment' even if default-input-method appears
+first in a 'custom-set-variables' statement.
 
-** The new hook `kbd-macro-termination-hook' is run at the end of
-function execute-kbd-macro.  Functions on this hook are called with no
+** The new hook 'kbd-macro-termination-hook' is run at the end of
+function 'execute-kbd-macro'.  Functions on this hook are called with no
 args.  The hook is run independent of how the macro was terminated
 (signal or normal termination).
 
-** Functions `butlast' and `nbutlast' for removing trailing elements
+** Functions 'butlast' and 'nbutlast' for removing trailing elements
 from a list are now available without requiring the CL package.
 
-** The new user-option `even-window-heights' can be set to nil
-to prevent `display-buffer' from evening out window heights.
+** The new user-option 'even-window-heights' can be set to nil
+to prevent 'display-buffer' from evening out window heights.
 
-** The user-option `face-font-registry-alternatives' specifies
+** The user-option 'face-font-registry-alternatives' specifies
 alternative font registry names to try when looking for a font.
 
-** Function `md5' calculates the MD5 "message digest"/"checksum".
+** Function 'md5' calculates the MD5 "message digest"/"checksum".
 
-** Function `delete-frame' runs `delete-frame-hook' before actually
+** Function 'delete-frame' runs 'delete-frame-hook' before actually
 deleting the frame.  The hook is called with one arg, the frame
 being deleted.
 
-** `add-hook' now makes the hook local if called with a non-nil LOCAL arg.
+** 'add-hook' now makes the hook local if called with a non-nil LOCAL arg.
 
 ** The treatment of non-ASCII characters in search ranges has changed.
 If a range in a regular expression or the arg of
@@ -2412,11 +2413,11 @@ with a multibyte character C2, the range is divided 
into two: one is
 C..?\377, the other is C1..C2, where C1 is the first character of C2's
 charset.
 
-** The new function `display-message-or-buffer' displays a message in
+** The new function 'display-message-or-buffer' displays a message in
 the echo area or pops up a buffer, depending on the length of the
 message.
 
-** The new macro `with-auto-compression-mode' allows evaluating an
+** The new macro 'with-auto-compression-mode' allows evaluating an
 expression with auto-compression-mode enabled.
 
 ** In image specifications, `:heuristic-mask' has been replaced
@@ -2435,49 +2436,49 @@ is running in batch mode.  For example,
 will read a Lisp expression from standard input and print the result
 to standard output.
 
-** The argument of `down-list', `backward-up-list', `up-list',
-`kill-sexp', `backward-kill-sexp' and `mark-sexp' is now optional.
+** The argument of 'down-list', 'backward-up-list', 'up-list',
+'kill-sexp', 'backward-kill-sexp' and 'mark-sexp' is now optional.
 
-** If `display-buffer-reuse-frames' is set, function `display-buffer'
+** If 'display-buffer-reuse-frames' is set, function 'display-buffer'
 will raise frames displaying a buffer, instead of creating a new
 frame or window.
 
 ** Two new functions for removing elements from lists/sequences
 were added
 
-- Function: remove ELT SEQ
+- Function: 'remove' ELT SEQ
 
 Return a copy of SEQ with all occurrences of ELT removed.  SEQ must be
-a list, vector, or string.  The comparison is done with `equal'.
+a list, vector, or string.  The comparison is done with 'equal'.
 
-- Function: remq ELT LIST
+- Function: 'remq' ELT LIST
 
 Return a copy of LIST with all occurrences of ELT removed.  The
-comparison is done with `eq'.
+comparison is done with 'eq'.
 
-** The function `delete' now also works with vectors and strings.
+** The function 'delete' now also works with vectors and strings.
 
-** The meaning of the `:weakness WEAK' argument of make-hash-table
-has been changed: WEAK can now have new values `key-or-value' and
-`key-and-value', in addition to `nil', `key', `value', and `t'.
+** The meaning of the `:weakness WEAK' argument of 'make-hash-table'
+has been changed: WEAK can now have new values 'key-or-value' and
+'key-and-value', in addition to 'nil', 'key', 'value', and 't'.
 
-** Function `aset' stores any multibyte character in any string
+** Function 'aset' stores any multibyte character in any string
 without signaling "Attempt to change char length of a string".  It may
 convert a unibyte string to multibyte if necessary.
 
-** The value of the `help-echo' text property is called as a function
+** The value of the 'help-echo' text property is called as a function
 or evaluated, if it is not a string already, to obtain a help string.
 
-** Function `make-obsolete' now has an optional arg to say when the
+** Function 'make-obsolete' now has an optional arg to say when the
 function was declared obsolete.
 
-** Function `plist-member' is renamed from `widget-plist-member' (which is
+** Function 'plist-member' is renamed from 'widget-plist-member' (which is
 retained as an alias).
 
 ** Easy-menu's :filter now takes the unconverted form of the menu and
 the result is automatically converted to Emacs' form.
 
-** The new function `window-list' has been defined
+** The new function 'window-list' has been defined
 
 - Function: window-list &optional FRAME WINDOW MINIBUF
 
@@ -2488,13 +2489,13 @@ even if it isn't active.  MINIBUF nil or omitted means 
include the
 minibuffer window only if it's active.  MINIBUF neither nil nor t
 means never include the minibuffer window.
 
-** There's a new function `get-window-with-predicate' defined as follows
+** There's a new function 'get-window-with-predicate' defined as follows
 
 - Function: get-window-with-predicate PREDICATE &optional MINIBUF ALL-FRAMES 
DEFAULT
 
 Return a window satisfying PREDICATE.
 
-This function cycles through all visible windows using `walk-windows',
+This function cycles through all visible windows using 'walk-windows',
 calling PREDICATE on each one.  PREDICATE is called with a window as
 argument.  The first window for which PREDICATE returns a non-nil
 value is returned.  If no window satisfies PREDICATE, DEFAULT is
@@ -2509,61 +2510,61 @@ Several frames may share a single minibuffer; if the 
minibuffer
 counts, all windows on all frames that share that minibuffer count
 too.  Therefore, if you are using a separate minibuffer frame
 and the minibuffer is active and MINIBUF says it counts,
-`walk-windows' includes the windows in the frame from which you
+'walk-windows' includes the windows in the frame from which you
 entered the minibuffer, as well as the minibuffer window.
 
 ALL-FRAMES is the optional third argument.
 ALL-FRAMES nil or omitted means cycle within the frames as specified above.
-ALL-FRAMES = `visible' means include windows on all visible frames.
+ALL-FRAMES = 'visible' means include windows on all visible frames.
 ALL-FRAMES = 0 means include windows on all visible and iconified frames.
 ALL-FRAMES = t means include windows on all frames including invisible frames.
 If ALL-FRAMES is a frame, it means include windows on that frame.
 Anything else means restrict to the selected frame.
 
-** The function `single-key-description' now encloses function key and
+** The function 'single-key-description' now encloses function key and
 event names in angle brackets.  When called with a second optional
 argument non-nil, angle brackets won't be printed.
 
-** If the variable `message-truncate-lines' is bound to t around a
-call to `message', the echo area will not be resized to display that
+** If the variable 'message-truncate-lines' is bound to t around a
+call to 'message', the echo area will not be resized to display that
 message; it will be truncated instead, as it was done in 20.x.
 Default value is nil.
 
-** The user option `line-number-display-limit' can now be set to nil,
+** The user option 'line-number-display-limit' can now be set to nil,
 meaning no limit.
 
-** The new user option `line-number-display-limit-width' controls
+** The new user option 'line-number-display-limit-width' controls
 the maximum width of lines in a buffer for which Emacs displays line
 numbers in the mode line.  The default is 200.
 
-** `select-safe-coding-system' now also checks the most preferred
-coding-system if buffer-file-coding-system is `undecided' and
+** 'select-safe-coding-system' now also checks the most preferred
+coding-system if buffer-file-coding-system is 'undecided' and
 DEFAULT-CODING-SYSTEM is not specified,
 
-** The function `subr-arity' provides information about the argument
+** The function 'subr-arity' provides information about the argument
 list of a primitive.
 
-** `where-is-internal' now also accepts a list of keymaps.
+** 'where-is-internal' now also accepts a list of keymaps.
 
-** The text property `keymap' specifies a key map which overrides the
-buffer's local map and the map specified by the `local-map' property.
-This is probably what most current uses of `local-map' want, rather
+** The text property 'keymap' specifies a key map which overrides the
+buffer's local map and the map specified by the 'local-map' property.
+This is probably what most current uses of 'local-map' want, rather
 than replacing the local map.
 
-** The obsolete variables `before-change-function' and
-`after-change-function' are no longer acted upon and have been
-removed.  Use `before-change-functions' and `after-change-functions'
+** The obsolete variables 'before-change-function' and
+'after-change-function' are no longer acted upon and have been
+removed.  Use 'before-change-functions' and 'after-change-functions'
 instead.
 
-** The function `apropos-mode' runs the hook `apropos-mode-hook'.
+** The function 'apropos-mode' runs the hook 'apropos-mode-hook'.
 
-** `concat' no longer accepts individual integer arguments,
+** 'concat' no longer accepts individual integer arguments,
 as promised long ago.
 
-** The new function `float-time' returns the current time as a float.
+** The new function 'float-time' returns the current time as a float.
 
-** The new variable auto-coding-regexp-alist specifies coding systems
-for reading specific files, analogous to auto-coding-alist, but
+** The new variable 'auto-coding-regexp-alist' specifies coding systems
+for reading specific files, analogous to 'auto-coding-alist', but
 patterns are checked against file contents instead of file names.
 
 
@@ -2572,11 +2573,11 @@ patterns are checked against file contents instead of 
file names.
 ** The new package rx.el provides an alternative sexp notation for
 regular expressions.
 
-- Function: rx-to-string SEXP
+- Function: 'rx-to-string' SEXP
 
 Translate SEXP into a regular expression in string notation.
 
-- Macro: rx SEXP
+- Macro: 'rx' SEXP
 
 Translate SEXP into a regular expression in string notation.
 
@@ -2589,56 +2590,56 @@ STRING
 CHAR
      matches character CHAR literally.
 
-`not-newline'
+'not-newline'
      matches any character except a newline.
                        .
-`anything'
+'anything'
      matches any character
 
 `(any SET)'
      matches any character in SET.  SET may be a character or string.
-     Ranges of characters can be specified as `A-Z' in strings.
+     Ranges of characters can be specified as 'A-Z' in strings.
 
 '(in SET)'
-     like `any'.
+     like 'any'.
 
 `(not (any SET))'
      matches any character not in SET
 
-`line-start'
+'line-start'
      matches the empty string, but only at the beginning of a line
      in the text being matched
 
-`line-end'
-     is similar to `line-start' but matches only at the end of a line
+'line-end'
+     is similar to 'line-start' but matches only at the end of a line
 
-`string-start'
+'string-start'
      matches the empty string, but only at the beginning of the
      string being matched against.
 
-`string-end'
+'string-end'
      matches the empty string, but only at the end of the
      string being matched against.
 
-`buffer-start'
+'buffer-start'
      matches the empty string, but only at the beginning of the
      buffer being matched against.
 
-`buffer-end'
+'buffer-end'
      matches the empty string, but only at the end of the
      buffer being matched against.
 
-`point'
+'point'
      matches the empty string, but only at point.
 
-`word-start'
+'word-start'
      matches the empty string, but only at the beginning or end of a
      word.
 
-`word-end'
+'word-end'
      matches the empty string, but only at the end of a word.
 
-`word-boundary'
+'word-boundary'
      matches the empty string, but only at the beginning or end of a
      word.
 
@@ -2646,73 +2647,73 @@ CHAR
      matches the empty string, but not at the beginning or end of a
      word.
 
-`digit'
+'digit'
      matches 0 through 9.
 
-`control'
+'control'
      matches ASCII control characters.
 
-`hex-digit'
+'hex-digit'
      matches 0 through 9, a through f and A through F.
 
-`blank'
+'blank'
      matches space and tab only.
 
-`graphic'
+'graphic'
      matches graphic characters--everything except ASCII control chars,
      space, and DEL.
 
-`printing'
+'printing'
      matches printing characters--everything except ASCII control chars
      and DEL.
 
-`alphanumeric'
+'alphanumeric'
      matches letters and digits.  (But at present, for multibyte characters,
      it matches anything that has word syntax.)
 
-`letter'
+'letter'
      matches letters.  (But at present, for multibyte characters,
      it matches anything that has word syntax.)
 
-`ascii'
+'ascii'
      matches ASCII (unibyte) characters.
 
-`nonascii'
+'nonascii'
      matches non-ASCII (multibyte) characters.
 
-`lower'
+'lower'
      matches anything lower-case.
 
-`upper'
+'upper'
      matches anything upper-case.
 
-`punctuation'
+'punctuation'
      matches punctuation.  (But at present, for multibyte characters,
      it matches anything that has non-word syntax.)
 
-`space'
+'space'
      matches anything that has whitespace syntax.
 
-`word'
+'word'
      matches anything that has word syntax.
 
 `(syntax SYNTAX)'
      matches a character with syntax SYNTAX.  SYNTAX must be one
      of the following symbols.
 
-     `whitespace'              (\\s- in string notation)
-     `punctuation'             (\\s.)
-     `word'                    (\\sw)
-     `symbol'                  (\\s_)
-     `open-parenthesis'                (\\s()
-     `close-parenthesis'       (\\s))
-     `expression-prefix'       (\\s')
-     `string-quote'            (\\s\")
-     `paired-delimiter'                (\\s$)
-     `escape'                  (\\s\\)
-     `character-quote'         (\\s/)
-     `comment-start'           (\\s<)
-     `comment-end'             (\\s>)
+     'whitespace'              (\\s- in string notation)
+     'punctuation'             (\\s.)
+     'word'                    (\\sw)
+     'symbol'                  (\\s_)
+     'open-parenthesis'                (\\s()
+     'close-parenthesis'       (\\s))
+     'expression-prefix'       (\\s')
+     'string-quote'            (\\s\")
+     'paired-delimiter'                (\\s$)
+     'escape'                  (\\s\\)
+     'character-quote'         (\\s/)
+     'comment-start'           (\\s<)
+     'comment-end'             (\\s>)
 
 `(not (syntax SYNTAX))'
      matches a character that has not syntax SYNTAX.
@@ -2721,44 +2722,44 @@ CHAR
      matches a character with category CATEGORY.  CATEGORY must be
      either a character to use for C, or one of the following symbols.
 
-     `consonant'                       (\\c0 in string notation)
-     `base-vowel'                      (\\c1)
-     `upper-diacritical-mark'          (\\c2)
-     `lower-diacritical-mark'          (\\c3)
-     `tone-mark'                       (\\c4)
-     `symbol'                          (\\c5)
-     `digit'                           (\\c6)
-     `vowel-modifying-diacritical-mark'        (\\c7)
-     `vowel-sign'                      (\\c8)
-     `semivowel-lower'                 (\\c9)
-     `not-at-end-of-line'              (\\c<)
-     `not-at-beginning-of-line'                (\\c>)
-     `alpha-numeric-two-byte'          (\\cA)
-     `chinse-two-byte'                 (\\cC)
-     `greek-two-byte'                  (\\cG)
-     `japanese-hiragana-two-byte'      (\\cH)
-     `indian-two-byte'                 (\\cI)
-     `japanese-katakana-two-byte'      (\\cK)
-     `korean-hangul-two-byte'          (\\cN)
-     `cyrillic-two-byte'               (\\cY)
-     `ascii'                           (\\ca)
-     `arabic'                          (\\cb)
-     `chinese'                         (\\cc)
-     `ethiopic'                                (\\ce)
-     `greek'                           (\\cg)
-     `korean'                          (\\ch)
-     `indian'                          (\\ci)
-     `japanese'                                (\\cj)
-     `japanese-katakana'               (\\ck)
-     `latin'                           (\\cl)
-     `lao'                             (\\co)
-     `tibetan'                         (\\cq)
-     `japanese-roman'                  (\\cr)
-     `thai'                            (\\ct)
-     `vietnamese'                      (\\cv)
-     `hebrew'                          (\\cw)
-     `cyrillic'                                (\\cy)
-     `can-break'                       (\\c|)
+     'consonant'                       (\\c0 in string notation)
+     'base-vowel'                      (\\c1)
+     'upper-diacritical-mark'          (\\c2)
+     'lower-diacritical-mark'          (\\c3)
+     'tone-mark'                       (\\c4)
+     'symbol'                          (\\c5)
+     'digit'                           (\\c6)
+     'vowel-modifying-diacritical-mark'        (\\c7)
+     'vowel-sign'                      (\\c8)
+     'semivowel-lower'                 (\\c9)
+     'not-at-end-of-line'              (\\c<)
+     'not-at-beginning-of-line'                (\\c>)
+     'alpha-numeric-two-byte'          (\\cA)
+     'chinse-two-byte'                 (\\cC)
+     'greek-two-byte'                  (\\cG)
+     'japanese-hiragana-two-byte'      (\\cH)
+     'indian-two-byte'                 (\\cI)
+     'japanese-katakana-two-byte'      (\\cK)
+     'korean-hangul-two-byte'          (\\cN)
+     'cyrillic-two-byte'               (\\cY)
+     'ascii'                           (\\ca)
+     'arabic'                          (\\cb)
+     'chinese'                         (\\cc)
+     'ethiopic'                                (\\ce)
+     'greek'                           (\\cg)
+     'korean'                          (\\ch)
+     'indian'                          (\\ci)
+     'japanese'                                (\\cj)
+     'japanese-katakana'               (\\ck)
+     'latin'                           (\\cl)
+     'lao'                             (\\co)
+     'tibetan'                         (\\cq)
+     'japanese-roman'                  (\\cr)
+     'thai'                            (\\ct)
+     'vietnamese'                      (\\cv)
+     'hebrew'                          (\\cw)
+     'cyrillic'                                (\\cy)
+     'can-break'                       (\\c|)
 
 `(not (category CATEGORY))'
      matches a character that has not category CATEGORY.
@@ -2767,15 +2768,15 @@ CHAR
      matches what SEXP1 matches, followed by what SEXP2 matches, etc.
 
 `(submatch SEXP1 SEXP2 ...)'
-     like `and', but makes the match accessible with `match-end',
-     `match-beginning', and `match-string'.
+     like 'and', but makes the match accessible with 'match-end',
+     'match-beginning', and 'match-string'.
 
 `(group SEXP1 SEXP2 ...)'
-     another name for `submatch'.
+     another name for 'submatch'.
 
 `(or SEXP1 SEXP2 ...)'
      matches anything that matches SEXP1 or SEXP2, etc.  If all
-     args are strings, use `regexp-opt' to optimize the resulting
+     args are strings, use 'regexp-opt' to optimize the resulting
      regular expression.
 
 `(minimal-match SEXP)'
@@ -2791,37 +2792,37 @@ CHAR
      matches zero or more occurrences of what SEXP matches.
 
 `(0+ SEXP)'
-     like `zero-or-more'.
+     like 'zero-or-more'.
 
 `(* SEXP)'
-     like `zero-or-more', but always produces a greedy regexp.
+     like 'zero-or-more', but always produces a greedy regexp.
 
 `(*? SEXP)'
-     like `zero-or-more', but always produces a non-greedy regexp.
+     like 'zero-or-more', but always produces a non-greedy regexp.
 
 `(one-or-more SEXP)'
      matches one or more occurrences of A.
 
 `(1+ SEXP)'
-     like `one-or-more'.
+     like 'one-or-more'.
 
 `(+ SEXP)'
-     like `one-or-more', but always produces a greedy regexp.
+     like 'one-or-more', but always produces a greedy regexp.
 
 `(+? SEXP)'
-     like `one-or-more', but always produces a non-greedy regexp.
+     like 'one-or-more', but always produces a non-greedy regexp.
 
 `(zero-or-one SEXP)'
      matches zero or one occurrences of A.
 
 `(optional SEXP)'
-     like `zero-or-one'.
+     like 'zero-or-one'.
 
 `(? SEXP)'
-     like `zero-or-one', but always produces a greedy regexp.
+     like 'zero-or-one', but always produces a greedy regexp.
 
 `(?? SEXP)'
-     like `zero-or-one', but always produces a non-greedy regexp.
+     like 'zero-or-one', but always produces a non-greedy regexp.
 
 `(repeat N SEXP)'
      matches N occurrences of what SEXP matches.
@@ -2831,26 +2832,26 @@ CHAR
 
 `(eval FORM)'
       evaluate FORM and insert result.  If result is a string,
-      `regexp-quote' it.
+      'regexp-quote' it.
 
 `(regexp REGEXP)'
       include REGEXP in string notation in the result.
 
-*** The features `md5' and `overlay' are now provided by default.
+*** The features 'md5' and 'overlay' are now provided by default.
 
-*** The special form `save-restriction' now works correctly even if the
+*** The special form 'save-restriction' now works correctly even if the
 buffer is widened inside the save-restriction and changes made outside
 the original restriction.  Previously, doing this would cause the saved
 restriction to be restored incorrectly.
 
-*** The functions `find-charset-region' and `find-charset-string' include
-`eight-bit-control' and/or `eight-bit-graphic' in the returned list
-when they find 8-bit characters.  Previously, they included `ascii' in a
-multibyte buffer and `unknown' in a unibyte buffer.
+*** The functions 'find-charset-region' and 'find-charset-string' include
+'eight-bit-control' and/or 'eight-bit-graphic' in the returned list
+when they find 8-bit characters.  Previously, they included 'ascii' in a
+multibyte buffer and 'unknown' in a unibyte buffer.
 
-*** The functions `set-buffer-multibyte', `string-as-multibyte' and
-`string-as-unibyte' change the byte sequence of a buffer or a string
-if it contains a character from the `eight-bit-control' character set.
+*** The functions 'set-buffer-multibyte', 'string-as-multibyte' and
+'string-as-unibyte' change the byte sequence of a buffer or a string
+if it contains a character from the 'eight-bit-control' character set.
 
 *** The handling of multibyte sequences in a multibyte buffer is
 changed.  Previously, a byte sequence matching the pattern
@@ -2867,7 +2868,7 @@ A fontset can now be specified for each independent 
character, for
 a group of characters or for a character set rather than just for a
 character set as previously.
 
-*** The arguments of the function `set-fontset-font' are changed.
+*** The arguments of the function 'set-fontset-font' are changed.
 They are NAME, CHARACTER, FONTNAME, and optional FRAME.  The function
 modifies fontset NAME to use FONTNAME for CHARACTER.
 
@@ -2883,11 +2884,11 @@ name of a font and REGISTRY is a registry name of a 
font.
 registries of character sets are set in the default fontset
 "fontset-default".
 
-*** The function `create-fontset-from-fontset-spec' ignores the second
+*** The function 'create-fontset-from-fontset-spec' ignores the second
 argument STYLE-VARIANT.  It never creates style-variant fontsets.
 
 ** The method of composing characters is changed.  Now character
-composition is done by a special text property `composition' in
+composition is done by a special text property 'composition' in
 buffers and strings.
 
 *** Charset composition is deleted.  Emacs never creates a `composite
@@ -2901,32 +2902,32 @@ also been deleted.
 
 *** Three more glyph reference points are added.  They can be used to
 specify a composition rule.  See the documentation of the variable
-`reference-point-alist' for more detail.
+'reference-point-alist' for more detail.
 
-*** The function `compose-region' takes new arguments COMPONENTS and
+*** The function 'compose-region' takes new arguments COMPONENTS and
 MODIFICATION-FUNC.  With COMPONENTS, you can specify not only a
 composition rule but also characters to be composed.  Such characters
 may differ between buffer and string text.
 
-*** The function `compose-string' takes new arguments START, END,
+*** The function 'compose-string' takes new arguments START, END,
 COMPONENTS, and MODIFICATION-FUNC.
 
-*** The function `compose-string' puts text property `composition'
+*** The function 'compose-string' puts text property 'composition'
 directly on the argument STRING instead of returning a new string.
-Likewise, the function `decompose-string' just removes text property
-`composition' from STRING.
+Likewise, the function 'decompose-string' just removes text property
+'composition' from STRING.
 
-*** The new function `find-composition' returns information about
+*** The new function 'find-composition' returns information about
 a composition at a specified position in a buffer or a string.
 
-*** The function `decompose-composite-char' is now labeled as
+*** The function 'decompose-composite-char' is now labeled as
 obsolete.
 
-** The new coding system `mac-roman' is primarily intended for use on
+** The new coding system 'mac-roman' is primarily intended for use on
 the Macintosh but may be used generally for Macintosh-encoded text.
 
-** The new character sets `mule-unicode-0100-24ff',
-`mule-unicode-2500-33ff', and `mule-unicode-e000-ffff' have been
+** The new character sets 'mule-unicode-0100-24ff',
+'mule-unicode-2500-33ff', and 'mule-unicode-e000-ffff' have been
 introduced for Unicode characters in the range U+0100..U+24FF,
 U+2500..U+33FF, U+E000..U+FFFF respectively.
 
@@ -2937,18 +2938,18 @@ different characters, as far as Emacs is concerned.  
For example, text
 which includes Unicode characters from the Latin-2 locale cannot be
 encoded by Emacs with ISO 8859-2 coding system.
 
-** The new coding system `mule-utf-8' has been added.
+** The new coding system 'mule-utf-8' has been added.
 It provides limited support for decoding/encoding UTF-8 text.  For
 details, please see the documentation string of this coding system.
 
-** The new character sets `japanese-jisx0213-1' and
-`japanese-jisx0213-2' have been introduced for the new Japanese
+** The new character sets 'japanese-jisx0213-1' and
+'japanese-jisx0213-2' have been introduced for the new Japanese
 standard JIS X 0213 Plane 1 and Plane 2.
 
-** The new character sets `latin-iso8859-14' and `latin-iso8859-15'
+** The new character sets 'latin-iso8859-14' and 'latin-iso8859-15'
 have been introduced.
 
-** The new character sets `eight-bit-control' and `eight-bit-graphic'
+** The new character sets 'eight-bit-control' and 'eight-bit-graphic'
 have been introduced for 8-bit characters in the ranges 0x80..0x9F and
 0xA0..0xFF respectively.  Note that the multibyte representation of
 eight-bit-control is never exposed; this leads to an exception in the
@@ -2958,24 +2959,24 @@ eight-bit-graphic characters in a multibyte buffer, the 
search string
 must be multibyte, otherwise such characters will be converted to
 their multibyte equivalent.
 
-** If the APPEND argument of `write-region' is an integer, it seeks to
+** If the APPEND argument of 'write-region' is an integer, it seeks to
 that offset in the file before writing.
 
-** The function `add-minor-mode' has been added for convenience and
+** The function 'add-minor-mode' has been added for convenience and
 compatibility with XEmacs (and is used internally by define-minor-mode).
 
-** The function `shell-command' now sets the default directory of the
+** The function 'shell-command' now sets the default directory of the
 `*Shell Command Output*' buffer to the default directory of the buffer
 from which the command was issued.
 
-** The functions `query-replace', `query-replace-regexp',
-`query-replace-regexp-eval' `map-query-replace-regexp',
-`replace-string', `replace-regexp', and `perform-replace' take two
+** The functions 'query-replace', 'query-replace-regexp',
+'query-replace-regexp-eval' 'map-query-replace-regexp',
+'replace-string', 'replace-regexp', and 'perform-replace' take two
 additional optional arguments START and END that specify the region to
 operate on.
 
-** The new function `count-screen-lines' is a more flexible alternative
-to `window-buffer-height'.
+** The new function 'count-screen-lines' is a more flexible alternative
+to 'window-buffer-height'.
 
 - Function: count-screen-lines &optional BEG END COUNT-FINAL-NEWLINE WINDOW
 
@@ -2983,7 +2984,7 @@ Return the number of screen lines in the region between 
BEG and END.
 The number of screen lines may be different from the number of actual
 lines, due to line breaking, display table, etc.
 
-Optional arguments BEG and END default to `point-min' and `point-max'
+Optional arguments BEG and END default to 'point-min' and 'point-max'
 respectively.
 
 If region ends with a newline, ignore it unless optional third argument
@@ -2993,45 +2994,45 @@ The optional fourth argument WINDOW specifies the 
window used for
 obtaining parameters such as width, horizontal scrolling, and so
 on. The default is to use the selected window's parameters.
 
-Like `vertical-motion', `count-screen-lines' always uses the current
+Like 'vertical-motion', 'count-screen-lines' always uses the current
 buffer, regardless of which buffer is displayed in WINDOW. This makes
-possible to use `count-screen-lines' in any buffer, whether or not it
+possible to use 'count-screen-lines' in any buffer, whether or not it
 is currently displayed in some window.
 
-** The new function `mapc' is like `mapcar' but doesn't collect the
+** The new function 'mapc' is like 'mapcar' but doesn't collect the
 argument function's results.
 
-** The functions base64-decode-region and base64-decode-string now
+** The functions 'base64-decode-region' and 'base64-decode-string' now
 signal an error instead of returning nil if decoding fails.  Also,
-`base64-decode-string' now always returns a unibyte string (in Emacs
+'base64-decode-string' now always returns a unibyte string (in Emacs
 20, it returned a multibyte string when the result was a valid multibyte
 sequence).
 
-** The function sendmail-user-agent-compose now recognizes a `body'
+** The function 'sendmail-user-agent-compose' now recognizes a 'body'
 header in the list of headers passed to it.
 
-** The new function member-ignore-case works like `member', but
+** The new function 'member-ignore-case' works like 'member', but
 ignores differences in case and text representation.
 
-** The buffer-local variable cursor-type can be used to specify the
+** The buffer-local variable 'cursor-type' can be used to specify the
 cursor to use in windows displaying a buffer.  Values are interpreted
 as follows:
 
   t            use the cursor specified for the frame (default)
   nil          don't display a cursor
-  `bar'                display a bar cursor with default width
+  'bar'                display a bar cursor with default width
   (bar . WIDTH)        display a bar cursor with width WIDTH
   others       display a box cursor.
 
-** The variable open-paren-in-column-0-is-defun-start controls whether
+** The variable 'open-paren-in-column-0-is-defun-start' controls whether
 an open parenthesis in column 0 is considered to be the start of a
 defun.  If set, the default, it is considered a defun start.  If not
 set, an open parenthesis in column 0 has no special meaning.
 
-** The new function `string-to-syntax' can be used to translate syntax
-specifications in string form as accepted by `modify-syntax-entry' to
-the cons-cell form that is used for the values of the `syntax-table'
-text property, and in `font-lock-syntactic-keywords'.
+** The new function 'string-to-syntax' can be used to translate syntax
+specifications in string form as accepted by 'modify-syntax-entry' to
+the cons-cell form that is used for the values of the 'syntax-table'
+text property, and in 'font-lock-syntactic-keywords'.
 
 Example:
 
@@ -3066,22 +3067,22 @@ INTEGER optionally contains a sign.
   #25rah
     => 267
 
-** The function `documentation-property' now evaluates the value of
+** The function 'documentation-property' now evaluates the value of
 the given property to obtain a string if it doesn't refer to etc/DOC
 and isn't a string.
 
-** If called for a symbol, the function `documentation' now looks for
-a `function-documentation' property of that symbol.  If it has a non-nil
+** If called for a symbol, the function 'documentation' now looks for
+a 'function-documentation' property of that symbol.  If it has a non-nil
 value, the documentation is taken from that value.  If the value is
 not a string, it is evaluated to obtain a string.
 
-** The last argument of `define-key-after' defaults to t for convenience.
+** The last argument of 'define-key-after' defaults to t for convenience.
 
-** The new function `replace-regexp-in-string' replaces all matches
+** The new function 'replace-regexp-in-string' replaces all matches
 for a regexp in a string.
 
-** `mouse-position' now runs the abnormal hook
-`mouse-position-function'.
+** 'mouse-position' now runs the abnormal hook
+'mouse-position-function'.
 
 ** The function string-to-number now returns a float for numbers
 that don't fit into a Lisp integer.
@@ -3089,37 +3090,37 @@ that don't fit into a Lisp integer.
 ** The variable keyword-symbols-constants-flag has been removed.
 Keywords are now always considered constants.
 
-** The new function `delete-and-extract-region' deletes text and
+** The new function 'delete-and-extract-region' deletes text and
 returns it.
 
-** The function `clear-this-command-keys' now also clears the vector
-returned by function `recent-keys'.
+** The function 'clear-this-command-keys' now also clears the vector
+returned by function 'recent-keys'.
 
-** Variables `beginning-of-defun-function' and `end-of-defun-function'
+** Variables 'beginning-of-defun-function' and 'end-of-defun-function'
 can be used to define handlers for the functions that find defuns.
 Major modes can define these locally instead of rebinding C-M-a
 etc. if the normal conventions for defuns are not appropriate for the
 mode.
 
 ** easy-mmode-define-minor-mode now takes an additional BODY argument
-and is renamed `define-minor-mode'.
+and is renamed 'define-minor-mode'.
 
 ** If an abbrev has a hook function which is a symbol, and that symbol
-has a non-nil `no-self-insert' property, the return value of the hook
+has a non-nil 'no-self-insert' property, the return value of the hook
 function specifies whether an expansion has been done or not.  If it
-returns nil, abbrev-expand also returns nil, meaning "no expansion has
+returns nil, 'abbrev-expand' also returns nil, meaning "no expansion has
 been performed."
 
 When abbrev expansion is done by typing a self-inserting character,
-and the abbrev has a hook with the `no-self-insert' property, and the
+and the abbrev has a hook with the 'no-self-insert' property, and the
 hook function returns non-nil meaning expansion has been done,
 then the self-inserting character is not inserted.
 
-** The function `intern-soft' now accepts a symbol as first argument.
+** The function 'intern-soft' now accepts a symbol as first argument.
 In this case, that exact symbol is looked up in the specified obarray,
 and the function's value is nil if it is not found.
 
-** The new macro `with-syntax-table' can be used to evaluate forms
+** The new macro 'with-syntax-table' can be used to evaluate forms
 with the syntax table of the current buffer temporarily set to a
 specified table.
 
@@ -3134,44 +3135,44 @@ what BODY returns.
 Perl's shy-groups \(?:...\) and non-greedy *? +? and ?? operators.
 Also back-references like \2 are now considered as an error if the
 corresponding subgroup does not exist (or is not closed yet).
-Previously it would have been silently turned into `2' (ignoring the `\').
+Previously it would have been silently turned into '2' (ignoring the `\').
 
-** The optional argument BUFFER of function file-local-copy has been
+** The optional argument BUFFER of function 'file-local-copy' has been
 removed since it wasn't used by anything.
 
-** The file name argument of function `file-locked-p' is now required
+** The file name argument of function 'file-locked-p' is now required
 instead of being optional.
 
-** The new built-in error `text-read-only' is signaled when trying to
+** The new built-in error 'text-read-only' is signaled when trying to
 modify read-only text.
 
 ** New functions and variables for locales.
 
-The new variable `locale-coding-system' specifies how to encode and
+The new variable 'locale-coding-system' specifies how to encode and
 decode strings passed to low-level message functions like strerror and
 time functions like strftime.  The new variables
-`system-messages-locale' and `system-time-locale' give the system
+'system-messages-locale' and 'system-time-locale' give the system
 locales to be used when invoking these two types of functions.
 
-The new function `set-locale-environment' sets the language
+The new function 'set-locale-environment' sets the language
 environment, preferred coding system, and locale coding system from
 the system locale as specified by the LC_ALL, LC_CTYPE, and LANG
 environment variables.  Normally, it is invoked during startup and need
 not be invoked thereafter.  It uses the new variables
-`locale-language-names', `locale-charset-language-names', and
-`locale-preferred-coding-systems' to make its decisions.
+'locale-language-names', 'locale-charset-language-names', and
+'locale-preferred-coding-systems' to make its decisions.
 
 ** syntax tables now understand nested comments.
-To declare a comment syntax as allowing nesting, just add an `n'
+To declare a comment syntax as allowing nesting, just add an 'n'
 modifier to either of the characters of the comment end and the comment
 start sequences.
 
-** The function `pixmap-spec-p' has been renamed `bitmap-spec-p'
-because `bitmap' is more in line with the usual X terminology.
+** The function 'pixmap-spec-p' has been renamed 'bitmap-spec-p'
+because 'bitmap' is more in line with the usual X terminology.
 
-** New function `propertize'
+** New function 'propertize'
 
-The new function `propertize' can be used to conveniently construct
+The new function 'propertize' can be used to conveniently construct
 strings with text properties.
 
 - Function: propertize STRING &rest PROPERTIES
@@ -3183,7 +3184,7 @@ specified value of that property.  Example:
 
   (propertize "foo" 'face 'bold 'read-only t)
 
-** push and pop macros.
+** 'push' and 'pop' macros.
 
 Simple versions of the push and pop macros of Common Lisp
 are now defined in Emacs Lisp.  These macros allow only symbols
@@ -3193,7 +3194,7 @@ as the place that holds the list to be changed.
 (pop LISTNAME)          return first elt of LISTNAME, and remove it
                        (thus altering the value of LISTNAME).
 
-** New dolist and dotimes macros.
+** New 'dolist' and 'dotimes' macros.
 
 Simple versions of the dolist and dotimes macros of Common Lisp
 are now defined in Emacs Lisp.
@@ -3248,9 +3249,9 @@ are optional.  The following arguments are defined:
 
 :test TEST
 
-TEST must be a symbol specifying how to compare keys.  Default is `eql'.
-Predefined are `eq', `eql' and `equal'.  If TEST is not predefined,
-it must have been defined with `define-hash-table-test'.
+TEST must be a symbol specifying how to compare keys.  Default is 'eql'.
+Predefined are 'eq', 'eql' and 'equal'.  If TEST is not predefined,
+it must have been defined with 'define-hash-table-test'.
 
 :size SIZE
 
@@ -3273,82 +3274,82 @@ hash table.  It is resized when the ratio of (number of 
entries) /
 
 :weakness WEAK
 
-WEAK must be either nil, one of the symbols `key, `value',
-`key-or-value', `key-and-value', or t, meaning the same as
-`key-and-value'.  Entries are removed from weak tables during garbage
+WEAK must be either nil, one of the symbols `key, 'value',
+'key-or-value', 'key-and-value', or t, meaning the same as
+'key-and-value'.  Entries are removed from weak tables during garbage
 collection if their key and/or value are not referenced elsewhere
 outside of the hash table.  Default are non-weak hash tables.
 
-- Function: makehash &optional TEST
+- Function: 'makehash' &optional TEST
 
 Similar to make-hash-table, but only TEST can be specified.
 
-- Function: hash-table-p TABLE
+- Function: 'hash-table-p' TABLE
 
 Returns non-nil if TABLE is a hash table object.
 
-- Function: copy-hash-table TABLE
+- Function: 'copy-hash-table' TABLE
 
 Returns a copy of TABLE.  Only the table itself is copied, keys and
 values are shared.
 
-- Function: hash-table-count TABLE
+- Function: 'hash-table-count' TABLE
 
 Returns the number of entries in TABLE.
 
-- Function: hash-table-rehash-size TABLE
+- Function: 'hash-table-rehash-size' TABLE
 
 Returns the rehash size of TABLE.
 
-- Function: hash-table-rehash-threshold TABLE
+- Function: 'hash-table-rehash-threshold' TABLE
 
 Returns the rehash threshold of TABLE.
 
-- Function: hash-table-rehash-size TABLE
+- Function: 'hash-table-rehash-size' TABLE
 
 Returns the size of TABLE.
 
-- Function: hash-table-test TABLE
+- Function: 'hash-table-test' TABLE
 
 Returns the test TABLE uses to compare keys.
 
-- Function: hash-table-weakness TABLE
+- Function: 'hash-table-weakness' TABLE
 
 Returns the weakness specified for TABLE.
 
-- Function: clrhash TABLE
+- Function: 'clrhash' TABLE
 
 Clear TABLE.
 
-- Function: gethash KEY TABLE &optional DEFAULT
+- Function: 'gethash' KEY TABLE &optional DEFAULT
 
 Look up KEY in TABLE and return its associated VALUE or DEFAULT if
 not found.
 
-- Function: puthash KEY VALUE TABLE
+- Function: 'puthash' KEY VALUE TABLE
 
 Associate KEY with VALUE in TABLE.  If KEY is already associated with
 another value, replace the old value with VALUE.
 
-- Function: remhash KEY TABLE
+- Function: 'remhash' KEY TABLE
 
 Remove KEY from TABLE if it is there.
 
-- Function: maphash FUNCTION TABLE
+- Function: 'maphash' FUNCTION TABLE
 
 Call FUNCTION for all elements in TABLE.  FUNCTION must take two
 arguments KEY and VALUE.
 
-- Function: sxhash OBJ
+- Function: 'sxhash' OBJ
 
 Return a hash code for Lisp object OBJ.
 
-- Function: define-hash-table-test NAME TEST-FN HASH-FN
+- Function: 'define-hash-table-test' NAME TEST-FN HASH-FN
 
 Define a new hash table test named NAME.  If NAME is specified as
-a test in `make-hash-table', the table created will use TEST-FN for
+a test in 'make-hash-table', the table created will use TEST-FN for
 comparing keys, and HASH-FN to compute hash codes for keys.  Test
-and hash function are stored as symbol property `hash-table-test'
+and hash function are stored as symbol property 'hash-table-test'
 of NAME with a value of (TEST-FN HASH-FN).
 
 TEST-FN must take two arguments and return non-nil if they are the same.
@@ -3379,10 +3380,10 @@ a cons cell which is its own cdr.
 
 ** The Lisp printer handles circular structure.
 
-If you bind print-circle to a non-nil value, the Lisp printer outputs
+If you bind 'print-circle' to a non-nil value, the Lisp printer outputs
 #N= and #N# constructs to represent circular and shared structure.
 
-** If the second argument to `move-to-column' is anything but nil or
+** If the second argument to 'move-to-column' is anything but nil or
 t, that means replace a tab with spaces if necessary to reach the
 specified column, but do not add spaces at the end of the line if it
 is too short to reach that column.
@@ -3393,50 +3394,50 @@ after each match to get the replacement text.  FUNCTION 
is called with
 two arguments: DATA, and the number of replacements already made.
 
 If the FROM-STRING contains any upper-case letters,
-perform-replace also turns off `case-fold-search' temporarily
+perform-replace also turns off 'case-fold-search' temporarily
 and inserts the replacement text without altering case in it.
 
-** The function buffer-size now accepts an optional argument
+** The function 'buffer-size' now accepts an optional argument
 to specify which buffer to return the size of.
 
 ** The calendar motion commands now run the normal hook
-calendar-move-hook after moving point.
+'calendar-move-hook' after moving point.
 
-** The new variable small-temporary-file-directory specifies a
+** The new variable 'small-temporary-file-directory' specifies a
 directory to use for creating temporary files that are likely to be
 small.  (Certain Emacs features use this directory.)  If
 small-temporary-file-directory is nil, they use
-temporary-file-directory instead.
+'temporary-file-directory' instead.
 
-** The variable `inhibit-modification-hooks', if non-nil, inhibits all
+** The variable 'inhibit-modification-hooks', if non-nil, inhibits all
 the hooks that track changes in the buffer.  This affects
-`before-change-functions' and `after-change-functions', as well as
+'before-change-functions' and 'after-change-functions', as well as
 hooks attached to text properties and overlay properties.
 
-** assq-delete-all is a new function that deletes all the
-elements of an alist which have a car `eq' to a particular value.
+** 'assq-delete-all' is a new function that deletes all the
+elements of an alist which have a car 'eq' to a particular value.
 
-** make-temp-file provides a more reliable way to create a temporary file.
+** 'make-temp-file' provides a more reliable way to create a temporary file.
 
-make-temp-file is used like make-temp-name, except that it actually
+'make-temp-file' is used like 'make-temp-name', except that it actually
 creates the file before it returns.  This prevents a timing error,
 ensuring that no other job can use the same name for a temporary file.
 
-** New exclusive-open feature in `write-region'
+** New exclusive-open feature in 'write-region'
 
 The optional seventh arg is now called MUSTBENEW.  If non-nil, it insists
 on a check for an existing file with the same name.  If MUSTBENEW
-is `excl', that means to get an error if the file already exists;
-never overwrite. If MUSTBENEW is neither nil nor `excl', that means
+is 'excl', that means to get an error if the file already exists;
+never overwrite. If MUSTBENEW is neither nil nor 'excl', that means
 ask for confirmation before overwriting, but do go ahead and
 overwrite the file if the user gives confirmation.
 
-If the MUSTBENEW argument in `write-region' is `excl',
-that means to use a special feature in the `open' system call
+If the MUSTBENEW argument in 'write-region' is 'excl',
+that means to use a special feature in the 'open' system call
 to get an error if the file exists at that time.
-The error reported is `file-already-exists'.
+The error reported is 'file-already-exists'.
 
-** Function `format' now handles text properties.
+** Function 'format' now handles text properties.
 
 Text properties of the format string are applied to the result string.
 If the result string is longer than the format string, text properties
@@ -3446,7 +3447,7 @@ result string.
 Text properties from string arguments are applied to the result
 string where arguments appear in the result string.
 
-Example:
+Example, using 'put-text-property':
 
   (let ((s1 "hello, %s")
         (s2 "world"))
@@ -3454,11 +3455,11 @@ Example:
      (put-text-property 0 (length s2) 'face 'italic s2)
      (format s1 s2))
 
-results in a bold-face string with an italic `world' at the end.
+results in a bold-face string with an italic 'world' at the end.
 
 ** Messages can now be displayed with text properties.
 
-Text properties are handled as described above for function `format'.
+Text properties are handled as described above for function 'format'.
 The following example displays a bold-face message with an italic
 argument in it.
 
@@ -3474,13 +3475,13 @@ Emacs supports playing sound files on GNU/Linux and the 
free BSDs
 (Voxware driver and native BSD driver, aka as Luigi's driver).
 
 Currently supported file formats are RIFF-WAVE (*.wav) and Sun Audio
-(*.au).  You must configure Emacs with the option `--with-sound=yes'
+(*.au).  You must configure Emacs with the option '--with-sound=yes'
 to enable sound support.
 
-Sound files can be played by calling (play-sound SOUND).  SOUND is a
+Sound files can be played by calling 'play-sound'.  The argument is a
 list of the form `(sound PROPERTY...)'.  The function is only defined
 when sound support is present for the system on which Emacs runs.  The
-functions runs `play-sound-functions' with one argument which is the
+functions runs 'play-sound-functions' with one argument which is the
 sound to play, before playing the sound.
 
 The following sound properties are supported:
@@ -3488,7 +3489,7 @@ The following sound properties are supported:
 - `:file FILE'
 
 FILE is a file name.  If FILE isn't an absolute name, it will be
-searched relative to `data-directory'.
+searched relative to 'data-directory'.
 
 - `:data DATA'
 
@@ -3508,37 +3509,38 @@ sound.  The default device is system-dependent.
 Other properties are ignored.
 
 An alternative interface is called as
-(play-sound-file FILE &optional VOLUME DEVICE).
 
-** `multimedia' is a new Finder keyword and Custom group.
+    (play-sound-file FILE &optional VOLUME DEVICE)
+
+** 'multimedia' is a new Finder keyword and Custom group.
 
-** keywordp is a new predicate to test efficiently for an object being
+** 'keywordp' is a new predicate to test efficiently for an object being
 a keyword symbol.
 
 ** Changes to garbage collection
 
-*** The function garbage-collect now additionally returns the number
+*** The function 'garbage-collect' now additionally returns the number
 of live and free strings.
 
-*** There is a new variable `strings-consed' holding the number of
+*** There is a new variable 'strings-consed' holding the number of
 strings that have been consed so far.
 
 
 * Lisp-level Display features added after release 2.6 of the Emacs
 Lisp Manual
 
-** The user-option `resize-mini-windows' controls how Emacs resizes
+** The user-option 'resize-mini-windows' controls how Emacs resizes
 mini-windows.
 
-** The function `pos-visible-in-window-p' now has a third optional
+** The function 'pos-visible-in-window-p' now has a third optional
 argument, PARTIALLY.  If a character is only partially visible, nil is
 returned, unless PARTIALLY is non-nil.
 
-** On window systems, `glyph-table' is no longer used.
+** On window systems, 'glyph-table' is no longer used.
 
-** Help strings in menu items are now used to provide `help-echo' text.
+** Help strings in menu items are now used to provide 'help-echo' text.
 
-** The function `image-size' can be used to determine the size of an
+** The function 'image-size' can be used to determine the size of an
 image.
 
 - Function: image-size SPEC &optional PIXELS FRAME
@@ -3551,7 +3553,7 @@ character units (fractions of the width/height of the 
frame's default
 font).  FRAME is the frame on which the image will be displayed.
 FRAME nil or omitted means use the selected frame.
 
-** The function `image-mask-p' can be used to determine if an image
+** The function 'image-mask-p' can be used to determine if an image
 has a mask bitmap.
 
 - Function: image-mask-p SPEC &optional FRAME
@@ -3560,10 +3562,10 @@ Return t if image SPEC has a mask bitmap.
 FRAME is the frame on which the image will be displayed.  FRAME nil
 or omitted means use the selected frame.
 
-** The function `find-image' can be used to find a usable image
+** The function 'find-image' can be used to find a usable image
 satisfying one of a list of specifications.
 
-** The STRING argument of `put-image' and `insert-image' is now
+** The STRING argument of 'put-image' and 'insert-image' is now
 optional.
 
 ** Image specifications may contain the property `:ascent center' (see
@@ -3601,13 +3603,13 @@ Each face can specify the following display attributes:
    1. Font family or fontset alias name.
 
    2. Relative proportionate width, aka character set width or set
-   width (swidth), e.g. `semi-compressed'.
+   width (swidth), e.g. 'semi-compressed'.
 
    3. Font height in 1/10pt
 
-   4. Font weight, e.g. `bold'.
+   4. Font weight, e.g. 'bold'.
 
-   5. Font slant, e.g. `italic'.
+   5. Font slant, e.g. 'italic'.
 
    6. Foreground color.
 
@@ -3631,30 +3633,30 @@ Faces are frame-local by nature because Emacs allows to 
define the
 same named face (face names are symbols) differently for different
 frames.  Each frame has an alist of face definitions for all named
 faces.  The value of a named face in such an alist is a Lisp vector
-with the symbol `face' in slot 0, and a slot for each of the face
+with the symbol 'face' in slot 0, and a slot for each of the face
 attributes mentioned above.
 
-There is also a global face alist `face-new-frame-defaults'.  Face
+There is also a global face alist 'face-new-frame-defaults'.  Face
 definitions from this list are used to initialize faces of newly
 created frames.
 
 A face doesn't have to specify all attributes.  Those not specified
 have a nil value.  Faces specifying all attributes are called
-`fully-specified'.
+'fully-specified'.
 
 *** Face merging.
 
 The display style of a given character in the text is determined by
 combining several faces.  This process is called `face merging'.  Any
 aspect of the display style that isn't specified by overlays or text
-properties is taken from the `default' face.  Since it is made sure
+properties is taken from the 'default' face.  Since it is made sure
 that the default face is always fully-specified, face merging always
 results in a fully-specified face.
 
 *** Face realization.
 
 After all face attributes for a character have been determined by
-merging faces of that character, that face is `realized'.  The
+merging faces of that character, that face is 'realized'.  The
 realization process maps face attributes to what is physically
 available on the system where Emacs runs.  The result is a `realized
 face' in form of an internal structure which is stored in the face
@@ -3672,20 +3674,20 @@ the new font selection stage is better than what can be 
done with
 statically defined font name patterns in fontsets.
 
 In unibyte text, Emacs' charsets aren't applicable; function
-`char-charset' reports ASCII for all characters, including those >
+'char-charset' reports ASCII for all characters, including those >
 0x7f.  The X registry and encoding of fonts to use is determined from
-the variable `face-default-registry' in this case.  The variable is
+the variable 'face-default-registry' in this case.  The variable is
 initialized at Emacs startup time from the font the user specified for
 Emacs.
 
 Currently all unibyte text, i.e. all buffers with
-`enable-multibyte-characters' nil are displayed with fonts of the same
-registry and encoding `face-default-registry'.  This is consistent
+'enable-multibyte-characters' nil are displayed with fonts of the same
+registry and encoding 'face-default-registry'.  This is consistent
 with the fact that languages can also be set globally, only.
 
 **** Clearing face caches.
 
-The Lisp function `clear-face-cache' can be called to clear face caches
+The Lisp function 'clear-face-cache' can be called to clear face caches
 on all frames.  If called with a non-nil argument, it will also unload
 unused fonts.
 
@@ -3698,7 +3700,7 @@ for faces specifying a fontset, or a font family name.
 If the face specifies a fontset name, that fontset determines a
 pattern for fonts of the given charset.  If the face specifies a font
 family, a font pattern is constructed.  Charset symbols have a
-property `x-charset-registry' for that purpose that maps a charset to
+property 'x-charset-registry' for that purpose that maps a charset to
 an XLFD registry and encoding in the font pattern constructed.
 
 Available fonts on the system on which Emacs runs are then matched
@@ -3709,24 +3711,24 @@ Font selection can be influenced by the user.
 
 The user can specify the relative importance he gives the face
 attributes width, height, weight, and slant by setting
-face-font-selection-order (faces.el) to a list of face attribute
+'face-font-selection-order' (faces.el) to a list of face attribute
 names.  The default is (:width :height :weight :slant), and means
 that font selection first tries to find a good match for the font
 width specified by a face, then---within fonts with that width---tries
 to find a best match for the specified font height, etc.
 
-Setting `face-font-family-alternatives' allows the user to specify
+Setting 'face-font-family-alternatives' allows the user to specify
 alternative font families to try if a family specified by a face
 doesn't exist.
 
-Setting `face-font-registry-alternatives' allows the user to specify
+Setting 'face-font-registry-alternatives' allows the user to specify
 all alternative font registry names to try for a face specifying a
 registry.
 
 Please note that the interpretations of the above two variables are
 slightly different.
 
-Setting face-ignored-fonts allows the user to ignore specific fonts.
+Setting 'face-ignored-fonts' allows the user to ignore specific fonts.
 
 
 **** Scalable fonts
@@ -3736,7 +3738,7 @@ since the use of too many or too big scalable fonts may 
crash XFree86
 servers.
 
 To enable scalable font use, set the variable
-`scalable-fonts-allowed'.  A value of nil, the default, means never use
+'scalable-fonts-allowed'.  A value of nil, the default, means never use
 scalable fonts.  A value of t means any scalable font may be used.
 Otherwise, the value must be a list of regular expressions.  A
 scalable font may then be used if it matches a regular expression from
@@ -3744,11 +3746,11 @@ that list.  Example:
 
   (setq scalable-fonts-allowed '("muleindian-2$"))
 
-allows the use of scalable fonts with registry `muleindian-2'.
+allows the use of scalable fonts with registry 'muleindian-2'.
 
 *** Functions and variables related to font selection.
 
-- Function: x-family-fonts &optional FAMILY FRAME
+- Function: 'x-family-fonts' &optional FAMILY FRAME
 
 Return a list of available fonts of family FAMILY on FRAME.  If FAMILY
 is omitted or nil, list all families.  Otherwise, FAMILY must be a
@@ -3765,14 +3767,14 @@ REGISTRY-AND-ENCODING is a string giving the registry 
and encoding of
 the font.  The result list is sorted according to the current setting
 of the face font sort order.
 
-- Function: x-font-family-list
+- Function: 'x-font-family-list'
 
 Return a list of available font families on FRAME.  If FRAME is
 omitted or nil, use the selected frame.  Value is a list of conses
 (FAMILY . FIXED-P) where FAMILY is a font family, and FIXED-P is
 non-nil if fonts of that family are fixed-pitch.
 
-- Variable: font-list-limit
+- Variable: 'font-list-limit'
 
 Limit for font matching.  If an integer > 0, font matching functions
 won't load more than that number of fonts when searching for a
@@ -3782,26 +3784,26 @@ matching font.  The default is currently 100.
 
 For the most part, the new face implementation is interface-compatible
 with the old one.  Old face attribute related functions are now
-implemented in terms of the new functions `set-face-attribute' and
-`face-attribute'.
+implemented in terms of the new functions 'set-face-attribute' and
+'face-attribute'.
 
 Face attributes are identified by their names which are keyword
-symbols.  All attributes can be set to `unspecified'.
+symbols.  All attributes can be set to 'unspecified'.
 
 The following attributes are recognized:
 
 `:family'
 
-VALUE must be a string specifying the font family, e.g. ``courier'',
+VALUE must be a string specifying the font family, e.g. "courier",
 or a fontset alias name.  If a font family is specified, wild-cards `*'
 and `?' are allowed.
 
 `:width'
 
 VALUE specifies the relative proportionate width of the font to use.
-It must be one of the symbols `ultra-condensed', `extra-condensed',
-`condensed', `semi-condensed', `normal', `semi-expanded', `expanded',
-`extra-expanded', or `ultra-expanded'.
+It must be one of the symbols 'ultra-condensed', 'extra-condensed',
+'condensed', 'semi-condensed', 'normal', 'semi-expanded', 'expanded',
+'extra-expanded', or 'ultra-expanded'.
 
 `:height'
 
@@ -3813,14 +3815,14 @@ height (from the underlying face), and should return 
the new height.
 `:weight'
 
 VALUE specifies the weight of the font to use.  It must be one of the
-symbols `ultra-bold', `extra-bold', `bold', `semi-bold', `normal',
-`semi-light', `light', `extra-light', `ultra-light'.
+symbols 'ultra-bold', 'extra-bold', 'bold', 'semi-bold', 'normal',
+'semi-light', 'light', 'extra-light', 'ultra-light'.
 
 `:slant'
 
 VALUE specifies the slant of the font to use.  It must be one of the
-symbols `italic', `oblique', `normal', `reverse-italic', or
-`reverse-oblique'.
+symbols 'italic', 'oblique', 'normal', 'reverse-italic', or
+'reverse-oblique'.
 
 `:foreground', `:background'
 
@@ -3861,8 +3863,8 @@ specified below.  WIDTH specifies the width of the lines 
to draw; it
 defaults to 1.  COLOR is the name of the color to draw in, default is
 the foreground color of the face for simple boxes, and the background
 color of the face for 3D boxes.  STYLE specifies whether a 3D box
-should be draw.  If STYLE is `released-button', draw a box looking
-like a released 3D button.  If STYLE is `pressed-button' draw a box
+should be draw.  If STYLE is 'released-button', draw a box looking
+like a released 3D button.  If STYLE is 'pressed-button' draw a box
 that appears like a pressed button.  If STYLE is nil, the default if
 the property list doesn't contain a style specification, draw a 2D
 box.
@@ -3875,7 +3877,7 @@ inverse video. VALUE must be one of t or nil.
 `:stipple'
 
 If VALUE is a string, it must be the name of a file of pixmap data.
-The directories listed in the `x-bitmap-file-path' variable are
+The directories listed in the 'x-bitmap-file-path' variable are
 searched.  Alternatively, VALUE may be a list of the form (WIDTH
 HEIGHT DATA) where WIDTH and HEIGHT are the size in pixels, and DATA
 is a string containing the raw bits of the bitmap.  VALUE nil means
@@ -3893,10 +3895,10 @@ versions of Emacs.
 
 For compatibility with Emacs 20, keywords `:bold' and `:italic' can
 be used to specify that a bold or italic font should be used.  VALUE
-must be t or nil in that case.  A value of `unspecified' is not allowed."
+must be t or nil in that case.  A value of 'unspecified' is not allowed."
 
-Please see also the documentation of `set-face-attribute' and
-`defface'.
+Please see also the documentation of 'set-face-attribute' and
+'defface'.
 
 `:inherit'
 
@@ -3931,9 +3933,9 @@ from X resources:
   :italic              attributeItalic .       Face.AttributeItalic
   :font                        attributeFont           Face.AttributeFont
 
-*** Text property `face'.
+*** Text property 'face'.
 
-The value of the `face' text property can now be a single face
+The value of the 'face' text property can now be a single face
 specification or a list of such specifications.  Each face
 specification can be
 
@@ -3941,7 +3943,7 @@ specification can be
 
 2. A property list of the form (KEYWORD VALUE ...) where each
    KEYWORD is a face attribute name, and VALUE is an appropriate value
-   for that attribute.  Please see the doc string of `set-face-attribute'
+   for that attribute.  Please see the doc string of 'set-face-attribute'
    for face attribute names.
 
 3. Conses of the form (FOREGROUND-COLOR . COLOR) or
@@ -3950,68 +3952,68 @@ specification can be
 
 ** Support functions for colors on text-only terminals.
 
-The function `tty-color-define' can be used to define colors for use
+The function 'tty-color-define' can be used to define colors for use
 on TTY and MSDOS frames.  It maps a color name to a color number on
 the terminal.  Emacs defines a couple of common color mappings by
 default.  You can get defined colors with a call to
-`defined-colors'.  The function `tty-color-clear' can be
+'defined-colors'.  The function 'tty-color-clear' can be
 used to clear the mapping table.
 
 ** Unified support for colors independent of frame type.
 
-The new functions `defined-colors', `color-defined-p', `color-values',
-and `display-color-p' work for any type of frame.  On frames whose
+The new functions 'defined-colors', 'color-defined-p', 'color-values',
+and 'display-color-p' work for any type of frame.  On frames whose
 type is neither x nor w32, these functions transparently map X-style
 color specifications to the closest colors supported by the frame
 display.  Lisp programs should use these new functions instead of the
-old `x-defined-colors', `x-color-defined-p', `x-color-values', and
-`x-display-color-p'.  (The old function names are still available for
+old 'x-defined-colors', 'x-color-defined-p', 'x-color-values', and
+'x-display-color-p'.  (The old function names are still available for
 compatibility; they are now aliases of the new names.)  Lisp programs
 should no more look at the value of the variable window-system to
 modify their color-related behavior.
 
-The primitives `color-gray-p' and `color-supported-p' also work for
+The primitives 'color-gray-p' and 'color-supported-p' also work for
 any frame type.
 
 ** Platform-independent functions to describe display capabilities.
 
-The new functions `display-mouse-p', `display-popup-menus-p',
-`display-graphic-p', `display-selections-p', `display-screens',
-`display-pixel-width', `display-pixel-height', `display-mm-width',
-`display-mm-height', `display-backing-store', `display-save-under',
-`display-planes', `display-color-cells', `display-visual-class', and
-`display-grayscale-p' describe the basic capabilities of a particular
+The new functions 'display-mouse-p', 'display-popup-menus-p',
+'display-graphic-p', 'display-selections-p', 'display-screens',
+'display-pixel-width', 'display-pixel-height', 'display-mm-width',
+'display-mm-height', 'display-backing-store', 'display-save-under',
+'display-planes', 'display-color-cells', 'display-visual-class', and
+'display-grayscale-p' describe the basic capabilities of a particular
 display.  Lisp programs should call these functions instead of testing
-the value of the variables `window-system' or `system-type', or calling
-platform-specific functions such as `x-display-pixel-width'.
+the value of the variables 'window-system' or 'system-type', or calling
+platform-specific functions such as 'x-display-pixel-width'.
 
-The new function `display-images-p' returns non-nil if a particular
+The new function 'display-images-p' returns non-nil if a particular
 display can display image files.
 
 ** The minibuffer prompt is now actually inserted in the minibuffer.
 
 This makes it possible to scroll through the prompt, if you want to.
 To disallow this completely (like previous versions of emacs), customize
-the variable `minibuffer-prompt-properties', and turn on the
-`Inviolable' option.
+the variable 'minibuffer-prompt-properties', and turn on the
+'Inviolable' option.
 
-The function `minibuffer-prompt-end' returns the current position of the
+The function 'minibuffer-prompt-end' returns the current position of the
 end of the minibuffer prompt, if the minibuffer is current.
 Otherwise, it returns `(point-min)'.
 
-** New `field' abstraction in buffers.
+** New 'field' abstraction in buffers.
 
-There is now code to support an abstraction called `fields' in emacs
-buffers.  A field is a contiguous region of text with the same `field'
+There is now code to support an abstraction called 'fields' in emacs
+buffers.  A field is a contiguous region of text with the same 'field'
 property (which can be a text property or an overlay).
 
-Many emacs functions, such as forward-word, forward-sentence,
-forward-paragraph, beginning-of-line, etc., stop moving when they come
+Many Emacs functions, such as 'forward-word', 'forward-sentence',
+'forward-paragraph', 'beginning-of-line', etc., stop moving when they come
 to the boundary between fields; beginning-of-line and end-of-line will
 not let the point move past the field boundary, but other movement
 commands continue into the next field if repeated.  Stopping at field
 boundaries can be suppressed programmatically by binding
-`inhibit-field-text-motion' to a non-nil value around calls to these
+'inhibit-field-text-motion' to a non-nil value around calls to these
 functions.
 
 Now that the minibuffer prompt is inserted into the minibuffer, it is in
@@ -4020,22 +4022,22 @@ editing commands treat the user's text separately from 
the prompt.
 
 The following functions are defined for operating on fields:
 
-- Function: constrain-to-field NEW-POS OLD-POS &optional ESCAPE-FROM-EDGE 
ONLY-IN-LINE INHIBIT-CAPTURE-PROPERTY
+- Function: 'constrain-to-field' NEW-POS OLD-POS &optional ESCAPE-FROM-EDGE 
ONLY-IN-LINE INHIBIT-CAPTURE-PROPERTY
 
 Return the position closest to NEW-POS that is in the same field as OLD-POS.
 
-A field is a region of text with the same `field' property.
+A field is a region of text with the same 'field' property.
 If NEW-POS is nil, then the current point is used instead, and set to the
 constrained position if that is different.
 
 If OLD-POS is at the boundary of two fields, then the allowable
 positions for NEW-POS depends on the value of the optional argument
 ESCAPE-FROM-EDGE: If ESCAPE-FROM-EDGE is nil, then NEW-POS is
-constrained to the field that has the same `field' char-property
+constrained to the field that has the same 'field' char-property
 as any new characters inserted at OLD-POS, whereas if ESCAPE-FROM-EDGE
 is non-nil, NEW-POS is constrained to the union of the two adjacent
 fields.  Additionally, if two fields are separated by another field with
-the special value `boundary', then any point within this special field is
+the special value 'boundary', then any point within this special field is
 also considered to be `on the boundary'.
 
 If the optional argument ONLY-IN-LINE is non-nil and constraining
@@ -4047,47 +4049,47 @@ only in the case where they can still move to the right 
line.
 If the optional argument INHIBIT-CAPTURE-PROPERTY is non-nil, and OLD-POS has
 a non-nil property of that name, then any field boundaries are ignored.
 
-Field boundaries are not noticed if `inhibit-field-text-motion' is non-nil.
+Field boundaries are not noticed if 'inhibit-field-text-motion' is non-nil.
 
-- Function: delete-field &optional POS
+- Function: 'delete-field' &optional POS
 
 Delete the field surrounding POS.
-A field is a region of text with the same `field' property.
+A field is a region of text with the same 'field' property.
 If POS is nil, the value of point is used for POS.
 
-- Function: field-beginning &optional POS ESCAPE-FROM-EDGE
+- Function: 'field-beginning' &optional POS ESCAPE-FROM-EDGE
 
 Return the beginning of the field surrounding POS.
-A field is a region of text with the same `field' property.
+A field is a region of text with the same 'field' property.
 If POS is nil, the value of point is used for POS.
 If ESCAPE-FROM-EDGE is non-nil and POS is at the beginning of its
 field, then the beginning of the *previous* field is returned.
 
-- Function: field-end &optional POS ESCAPE-FROM-EDGE
+- Function: 'field-end' &optional POS ESCAPE-FROM-EDGE
 
 Return the end of the field surrounding POS.
-A field is a region of text with the same `field' property.
+A field is a region of text with the same 'field' property.
 If POS is nil, the value of point is used for POS.
 If ESCAPE-FROM-EDGE is non-nil and POS is at the end of its field,
 then the end of the *following* field is returned.
 
-- Function: field-string &optional POS
+- Function: 'field-string' &optional POS
 
 Return the contents of the field surrounding POS as a string.
-A field is a region of text with the same `field' property.
+A field is a region of text with the same 'field' property.
 If POS is nil, the value of point is used for POS.
 
-- Function: field-string-no-properties &optional POS
+- Function: 'field-string-no-properties' &optional POS
 
 Return the contents of the field around POS, without text-properties.
-A field is a region of text with the same `field' property.
+A field is a region of text with the same 'field' property.
 If POS is nil, the value of point is used for POS.
 
 ** Image support.
 
 Emacs can now display images.  Images are inserted into text by giving
-strings or buffer text a `display' text property containing one of
-(AREA IMAGE) or IMAGE.  The display of the `display' property value
+strings or buffer text a 'display' text property containing one of
+(AREA IMAGE) or IMAGE.  The display of the 'display' property value
 replaces the display of the characters having that property.
 
 If the property value has the form (AREA IMAGE), AREA must be one of
@@ -4103,21 +4105,21 @@ IMAGE is an image specification.
 Image specifications are lists of the form `(image PROPS)' where PROPS
 is a property list whose keys are keyword symbols.  Each
 specifications must contain a property `:type TYPE' with TYPE being a
-symbol specifying the image type, e.g. `xbm'.  Properties not
+symbol specifying the image type, e.g. 'xbm'.  Properties not
 described below are ignored.
 
 The following is a list of properties all image types share.
 
 `:ascent ASCENT'
 
-ASCENT must be a number in the range 0..100, or the symbol `center'.
+ASCENT must be a number in the range 0..100, or the symbol 'center'.
 If it is a number, it specifies the percentage of the image's height
 to use for its ascent.
 
 If not specified, ASCENT defaults to the value 50 which means that the
 image will be centered with the base line of the row it appears in.
 
-If ASCENT is `center' the image is vertically centered around a
+If ASCENT is 'center' the image is vertically centered around a
 centerline which is the vertical center of text drawn at the position
 of the image, in the manner specified by the text properties and
 overlays that apply to the image.
@@ -4137,7 +4139,7 @@ around an image.
 
 Apply an image algorithm to the image before displaying it.
 
-ALGO `laplace' or `emboss' means apply a Laplace or ``emboss''
+ALGO 'laplace' or 'emboss' means apply a Laplace or ``emboss''
 edge-detection algorithm to the image.
 
 ALGO `(edge-detection :matrix MATRIX :color-adjust ADJUST)' means
@@ -4171,12 +4173,12 @@ Emboss edge-detection uses a matrix of
    -1  0  1
     0  1 -2)
 
-ALGO `disabled' means transform the image so that it looks
+ALGO 'disabled' means transform the image so that it looks
 ``disabled''.
 
 `:mask MASK'
 
-If MASK is `heuristic' or `(heuristic BG)', build a clipping mask for
+If MASK is 'heuristic' or `(heuristic BG)', build a clipping mask for
 the image, so that the background of a frame is visible behind the
 image.  If BG is not specified, or if BG is t, determine the
 background color of the image by looking at the 4 corners of the
@@ -4192,20 +4194,20 @@ in some formats include a mask which can be removed by 
specifying
 `:file FILE'
 
 Load image from FILE.  If FILE is not absolute after expanding it,
-search for the image in `data-directory'.  Some image types support
+search for the image in 'data-directory'.  Some image types support
 building images from data.  When this is done, no `:file' property
 may be present in the image specification.
 
 `:data DATA'
 
 Get image data from DATA.  (As of this writing, this is not yet
-supported for image type `postscript').  Either :file or :data may be
+supported for image type 'postscript').  Either :file or :data may be
 present in an image specification, but not both.  All image types
 support strings as DATA, some types allow additional types of DATA.
 
 *** Supported image types
 
-**** XBM, image type `xbm'.
+**** XBM, image type 'xbm'.
 
 XBM images don't require an external library.  Additional image
 properties supported are:
@@ -4248,12 +4250,12 @@ DATA must be either
    height may be specified in this case because these are defined
    in the file.
 
-**** XPM, image type `xpm'
+**** XPM, image type 'xpm'
 
-XPM images require the external library `libXpm', package
+XPM images require the external library 'libXpm', package
 `xpm-3.4k.tar.gz', version 3.4k or later.  Make sure the library is
 found when Emacs is configured by supplying appropriate paths via
-`--x-includes' and `--x-libraries'.
+'--x-includes' and '--x-libraries'.
 
 Additional image properties supported are:
 
@@ -4269,7 +4271,7 @@ add a `:data' property instead of a `:file' property.
 The XPM library uses libz in its implementation so that it is able
 to display compressed images.
 
-**** PBM, image type `pbm'
+**** PBM, image type 'pbm'
 
 PBM images don't require an external library.  Color, gray-scale and
 mono images are supported.  Additional image properties supported for
@@ -4285,21 +4287,21 @@ meaning to use the default.  Default is the frame's 
foreground color.
 BG must be a string specifying the image background color, or nil
 meaning to use the default.  Default is the frame's background color.
 
-**** JPEG, image type `jpeg'
+**** JPEG, image type 'jpeg'
 
-Support for JPEG images requires the external library `libjpeg',
+Support for JPEG images requires the external library 'libjpeg',
 package `jpegsrc.v6a.tar.gz', or later.  There are no additional image
 properties defined.
 
-**** TIFF, image type `tiff'
+**** TIFF, image type 'tiff'
 
-Support for TIFF images requires the external library `libtiff',
+Support for TIFF images requires the external library 'libtiff',
 package `tiff-v3.4-tar.gz', or later.  There are no additional image
 properties defined.
 
-**** GIF, image type `gif'
+**** GIF, image type 'gif'
 
-Support for GIF images requires the external library `libungif', package
+Support for GIF images requires the external library 'libungif', package
 `libungif-4.1.0', or later.
 
 Additional image properties supported are:
@@ -4315,28 +4317,27 @@ For example, the following function displays a 
multi-image GIF file
 at point-min in the current buffer, switching between sub-images
 every 0.1 seconds.
 
-(defun show-anim (file max)
-  "Display multi-image GIF file FILE which contains MAX subimages."
-  (display-anim (current-buffer) file 0 max t))
+    (defun show-anim (file max)
+      "Display multi-image GIF file FILE which contains MAX subimages."
+      (display-anim (current-buffer) file 0 max t))
 
-(defun display-anim (buffer file idx max first-time)
-  (when (= idx max)
-    (setq idx 0))
-  (let ((img (create-image file nil nil :index idx)))
-    (save-excursion
-      (set-buffer buffer)
-      (goto-char (point-min))
-      (unless first-time (delete-char 1))
-      (insert-image img "x"))
-    (run-with-timer 0.1 nil 'display-anim buffer file (1+ idx) max nil)))
+    (defun display-anim (buffer file idx max first-time)
+      (when (= idx max)
+        (setq idx 0))
+      (let ((img (create-image file nil nil :index idx)))
+        (with-current-buffer buffer
+          (goto-char (point-min))
+          (unless first-time (delete-char 1))
+          (insert-image img "x"))
+        (run-with-timer 0.1 nil 'display-anim buffer file (1+ idx) max nil)))
 
-**** PNG, image type `png'
+**** PNG, image type 'png'
 
-Support for PNG images requires the external library `libpng',
+Support for PNG images requires the external library 'libpng',
 package `libpng-1.0.2.tar.gz', or later.  There are no additional image
 properties defined.
 
-**** Ghostscript, image type `postscript'.
+**** Ghostscript, image type 'postscript'.
 
 Additional image properties supported are:
 
@@ -4353,7 +4354,7 @@ must be an integer.  This is a required property.
 `:bounding-box BOX'
 
 BOX must be a list or vector of 4 integers giving the bounding box of
-the PS image, analogous to the `BoundingBox' comment found in PS
+the PS image, analogous to the 'BoundingBox' comment found in PS
 files.  This is an required property.
 
 Part of the Ghostscript interface is implemented in Lisp.  See
@@ -4361,22 +4362,22 @@ lisp/gs.el.
 
 *** Lisp interface.
 
-The variable `image-types' contains a list of those image types
+The variable 'image-types' contains a list of those image types
 which are supported in the current configuration.
 
 Images are stored in an image cache and removed from the cache when
-they haven't been displayed for `image-cache-eviction-delay seconds.
-The function `clear-image-cache' can be used to clear the image cache
-manually.  Images in the cache are compared with `equal', i.e. all
-images with `equal' specifications share the same image.
+they haven't been displayed for 'image-cache-eviction-delay' seconds.
+The function 'clear-image-cache' can be used to clear the image cache
+manually.  Images in the cache are compared with 'equal', i.e. all
+images with 'equal' specifications share the same image.
 
 *** Simplified image API, image.el
 
 The new Lisp package image.el contains functions that simplify image
-creation and putting images into text.  The function `create-image'
-can be used to create images.  The macro `defimage' can be used to
+creation and putting images into text.  The function 'create-image'
+can be used to create images.  The macro 'defimage' can be used to
 define an image based on available image types.  The functions
-`put-image' and `insert-image' can be used to insert an image into a
+'put-image' and 'insert-image' can be used to insert an image into a
 buffer.
 
 ** Display margins.
@@ -4385,16 +4386,16 @@ Windows can now have margins which are used for special 
text
 and images.
 
 To give a window margins, either set the buffer-local variables
-`left-margin-width' and `right-margin-width', or call
-`set-window-margins'.  The function `window-margins' can be used to
-obtain the current settings.  To make `left-margin-width' and
-`right-margin-width' take effect, you must set them before displaying
-the buffer in a window, or use `set-window-buffer' to force an update
+'left-margin-width' and 'right-margin-width', or call
+'set-window-margins'.  The function 'window-margins' can be used to
+obtain the current settings.  To make 'left-margin-width' and
+'right-margin-width' take effect, you must set them before displaying
+the buffer in a window, or use 'set-window-buffer' to force an update
 of the display margins.
 
-You can put text in margins by giving it a `display' text property
+You can put text in margins by giving it a 'display' text property
 containing a pair of the form `(LOCATION . VALUE)', where LOCATION is
-one of `left-margin' or `right-margin' or nil.  VALUE can be either a
+one of 'left-margin' or 'right-margin' or nil.  VALUE can be either a
 string, an image specification or a stretch specification (see later
 in this file).
 
@@ -4402,24 +4403,24 @@ in this file).
 
 Emacs displays short help messages in the echo area, when the mouse
 moves over a tool-bar item or a piece of text that has a text property
-`help-echo'.  This feature also applies to strings in the mode line
-that have a `help-echo' property.
+'help-echo'.  This feature also applies to strings in the mode line
+that have a 'help-echo' property.
 
-If the value of the `help-echo' property is a function, that function
+If the value of the 'help-echo' property is a function, that function
 is called with three arguments WINDOW, OBJECT and POSITION.  WINDOW is
 the window in which the help was found.
 
 If OBJECT is a buffer, POS is the position in the buffer where the
-`help-echo' text property was found.
+'help-echo' text property was found.
 
-If OBJECT is an overlay, that overlay has a `help-echo' property, and
+If OBJECT is an overlay, that overlay has a 'help-echo' property, and
 POS is the position in the overlay's buffer under the mouse.
 
 If OBJECT is a string (an overlay string or a string displayed with
-the `display' property), POS is the position in that string under the
+the 'display' property), POS is the position in that string under the
 mouse.
 
-If the value of the `help-echo' property is neither a function nor a
+If the value of the 'help-echo' property is neither a function nor a
 string, it is evaluated to obtain a help string.
 
 For tool-bar and menu-bar items, their key definition is used to
@@ -4428,7 +4429,7 @@ property `:help FORM', FORM is evaluated to determine the 
help string.
 For tool-bar items without a help form, the caption of the item is
 used as help string.
 
-The hook `show-help-function' can be set to a function that displays
+The hook 'show-help-function' can be set to a function that displays
 the help string differently.  For example, enabling a tooltip window
 causes the help display to appear there instead of in the echo area.
 
@@ -4437,9 +4438,9 @@ causes the help display to appear there instead of in the 
echo area.
 The display of text in windows can be scrolled smoothly in pixels.
 This is useful, for example, for making parts of large images visible.
 
-The function `window-vscroll' returns the current value of vertical
+The function 'window-vscroll' returns the current value of vertical
 scrolling, a non-negative fraction of the canonical character height.
-The function `set-window-vscroll' can be used to set the vertical
+The function 'set-window-vscroll' can be used to set the vertical
 scrolling value.  Here is an example of how these function might be
 used.
 
@@ -4454,32 +4455,32 @@ used.
        (set-window-vscroll (selected-window)
                            (- (window-vscroll) 0.5)))))
 
-** New hook `fontification-functions'.
+** New hook 'fontification-functions'.
 
-Functions from `fontification-functions' are called from redisplay
+Functions from 'fontification-functions' are called from redisplay
 when it encounters a region of text that is not yet fontified.  This
 variable automatically becomes buffer-local when set.  Each function
 is called with one argument, POS.
 
 At least one of the hook functions should fontify one or more
 characters starting at POS in the current buffer.  It should mark them
-as fontified by giving them a non-nil value of the `fontified' text
+as fontified by giving them a non-nil value of the 'fontified' text
 property.  It may be reasonable for these functions to check for the
-`fontified' property and not put it back on, but they do not have to.
+'fontified' property and not put it back on, but they do not have to.
 
 ** Tool bar support.
 
 Emacs supports a tool bar at the top of a frame under X.  The frame
-parameter `tool-bar-lines' (X resource "toolBar", class "ToolBar")
+parameter 'tool-bar-lines' (X resource "toolBar", class "ToolBar")
 controls how may lines to reserve for the tool bar.  A zero value
 suppresses the tool bar.  If the value is non-zero and
-`auto-resize-tool-bars' is non-nil the tool bar's size will be changed
+'auto-resize-tool-bars' is non-nil the tool bar's size will be changed
 automatically so that all tool bar items are visible.
 
 *** Tool bar item definitions
 
-Tool bar items are defined using `define-key' with a prefix-key
-`tool-bar'.  For example `(define-key global-map [tool-bar item1] ITEM)'
+Tool bar items are defined using 'define-key' with a prefix-key
+'tool-bar'.  For example `(define-key global-map [tool-bar item1] ITEM)'
 where ITEM is a list `(menu-item CAPTION BINDING PROPS...)'.
 
 CAPTION is the caption of the item, If it's not a string, it is
@@ -4533,31 +4534,31 @@ algorithm is used on that image to draw the image in 
disabled state.
 Gives a help string to display for the tool bar item.  This help
 is displayed when the mouse is moved over the item.
 
-The function `toolbar-add-item' is a convenience function for adding
-toolbar items generally, and `tool-bar-add-item-from-menu' can be used
+The function 'toolbar-add-item' is a convenience function for adding
+toolbar items generally, and 'tool-bar-add-item-from-menu' can be used
 to define a toolbar item with a binding copied from an item on the
 menu bar.
 
 The default bindings use a menu-item :filter to derive the tool-bar
-dynamically from variable `tool-bar-map' which may be set
+dynamically from variable 'tool-bar-map' which may be set
 buffer-locally to override the global map.
 
 *** Tool-bar-related variables.
 
-If `auto-resize-tool-bar' is non-nil, the tool bar will automatically
+If 'auto-resize-tool-bar' is non-nil, the tool bar will automatically
 resize to show all defined tool bar items.  It will never grow larger
 than 1/4 of the frame's size.
 
-If `auto-raise-tool-bar-buttons' is non-nil, tool bar buttons will be
+If 'auto-raise-tool-bar-buttons' is non-nil, tool bar buttons will be
 raised when the mouse moves over them.
 
 You can add extra space between tool bar items by setting
-`tool-bar-button-margin' to a positive integer specifying a number of
+'tool-bar-button-margin' to a positive integer specifying a number of
 pixels, or a pair of integers (X . Y) specifying horizontal and
 vertical margins .  Default is 1.
 
 You can change the shadow thickness of tool bar buttons by setting
-`tool-bar-button-relief' to an integer.  Default is 3.
+'tool-bar-button-relief' to an integer.  Default is 3.
 
 *** Tool-bar clicks with modifiers.
 
@@ -4572,7 +4573,7 @@ is the original tool bar item definition, then
 
   (define-key global-map [tool-bar S-shell] 'some-command)
 
-makes a binding to run `some-command' for a shifted click on the same
+makes a binding to run 'some-command' for a shifted click on the same
 item.
 
 ** Mode line changes.
@@ -4580,20 +4581,20 @@ item.
 *** Mouse-sensitive mode line.
 
 The mode line can be made mouse-sensitive by displaying strings there
-that have a `local-map' text property.  There are three ways to display
-a string with a `local-map' property in the mode line.
+that have a 'local-map' text property.  There are three ways to display
+a string with a 'local-map' property in the mode line.
 
 1. The mode line spec contains a variable whose string value has
-a `local-map' text property.
+a 'local-map' text property.
 
 2. The mode line spec contains a format specifier (e.g. `%12b'), and
-that format specifier has a `local-map' property.
+that format specifier has a 'local-map' property.
 
 3. The mode line spec contains a list containing `:eval FORM'.  FORM
 is evaluated.  If the result is a string, and that string has a
-`local-map' property.
+'local-map' property.
 
-The same mechanism is used to determine the `face' and `help-echo'
+The same mechanism is used to determine the 'face' and 'help-echo'
 properties of strings in the mode line.  See `bindings.el' for an
 example.
 
@@ -4606,28 +4607,28 @@ variable mode-line-format to nil.
 *** A headerline can now be displayed at the top of a window.
 
 This mode line's contents are controlled by the new variable
-`header-line-format' and `default-header-line-format' which are
-completely analogous to `mode-line-format' and
-`default-mode-line-format'.  A value of nil means don't display a top
+'header-line-format' and 'default-header-line-format' which are
+completely analogous to 'mode-line-format' and
+'default-mode-line-format'.  A value of nil means don't display a top
 line.
 
 The appearance of top mode lines is controlled by the face
-`header-line'.
+'header-line'.
 
-The function `coordinates-in-window-p' returns `header-line' for a
+The function 'coordinates-in-window-p' returns 'header-line' for a
 position in the header-line.
 
-** Text property `display'
+** Text property 'display'
 
-The `display' text property is used to insert images into text,
+The 'display' text property is used to insert images into text,
 replace text with other text, display text in marginal area, and it is
 also used to control other aspects of how text displays.  The value of
-the `display' property should be a display specification, as described
+the 'display' property should be a display specification, as described
 below, or a list or vector containing display specifications.
 
 *** Replacing text, displaying text in marginal areas
 
-To replace the text having the `display' property with some other
+To replace the text having the 'display' property with some other
 text, use a display specification of the form `(LOCATION STRING)'.
 
 If LOCATION is `(margin left-margin)', STRING is displayed in the left
@@ -4651,7 +4652,7 @@ PROPS)', where PROPS is a property list which can contain 
the
 properties described below.
 
 The display of the fractional space replaces the display of the
-characters having the `display' property.
+characters having the 'display' property.
 
 - :width WIDTH
 
@@ -4662,7 +4663,7 @@ character width.  WIDTH can be an integer or floating 
point number.
 
 Specifies that the width of the stretch should be computed from the
 first character in a group of consecutive characters that have the
-same `display' property.  The computation is done by multiplying the
+same 'display' property.  The computation is done by multiplying the
 width of that character by FACTOR.
 
 - :align-to HPOS
@@ -4680,7 +4681,7 @@ normal line height.
 - :relative-height FACTOR
 
 The height of the space is computed as the product of the height
-of the text having the `display' property and FACTOR.
+of the text having the 'display' property and FACTOR.
 
 - :ascent ASCENT
 
@@ -4696,7 +4697,7 @@ You should not use both `:height' and `:relative-height' 
together.
 A display specification for an image has the form `(LOCATION
 . IMAGE)', where IMAGE is an image specification.  The image replaces,
 in the display, the characters having this display specification in
-their `display' text property.  If LOCATION is `(margin left-margin)',
+their 'display' text property.  If LOCATION is `(margin left-margin)',
 the image will be displayed in the left marginal area, if it is
 `(margin right-margin)' it will be displayed in the right marginal
 area, and if LOCATION is `(margin nil)' the image will be displayed in
@@ -4728,7 +4729,7 @@ If HEIGHT is a symbol, it is called as a function with 
the current
 height as argument.  The function should return the new height to use.
 
 Otherwise, HEIGHT is evaluated to get the new height, with the symbol
-`height' bound to the current specified font height.
+'height' bound to the current specified font height.
 
 - (raise FACTOR)
 
@@ -4736,16 +4737,16 @@ FACTOR must be a number, specifying a multiple of the 
current
 font's height.  If it is positive, that means to display the characters
 raised.  If it is negative, that means to display them lower down.  The
 amount of raising or lowering is computed without taking account of the
-`height' subproperty.
+'height' subproperty.
 
 *** Conditional display properties
 
 All display specifications can be conditionalized.  If a specification
 has the form `(when CONDITION . SPEC)', the specification SPEC applies
 only when CONDITION yields a non-nil value when evaluated.  During the
-evaluation, `object' is bound to the string or buffer having the
-conditional display property; `position' and `buffer-position' are
-bound to the position within `object' and the buffer position where
+evaluation, 'object' is bound to the string or buffer having the
+conditional display property; 'position' and 'buffer-position' are
+bound to the position within 'object' and the buffer position where
 the display property was found, respectively.  Both positions can be
 different when object is a string.
 
@@ -4759,57 +4760,57 @@ item names consisting of dashes only (including zero 
dashes) are
 treated like before.  In addition, the following item names are used
 to specify other menu separator types.
 
-- `--no-line' or `--space', or `--:space', or `--:noLine'
+- '--no-line' or '--space', or `--:space', or `--:noLine'
 
 No separator lines are drawn, but a small space is inserted where the
 separator occurs.
 
-- `--single-line' or `--:singleLine'
+- '--single-line' or `--:singleLine'
 
 A single line in the menu's foreground color.
 
-- `--double-line' or `--:doubleLine'
+- '--double-line' or `--:doubleLine'
 
 A double line in the menu's foreground color.
 
-- `--single-dashed-line' or `--:singleDashedLine'
+- '--single-dashed-line' or `--:singleDashedLine'
 
 A single dashed line in the menu's foreground color.
 
-- `--double-dashed-line' or `--:doubleDashedLine'
+- '--double-dashed-line' or `--:doubleDashedLine'
 
 A double dashed line in the menu's foreground color.
 
-- `--shadow-etched-in' or `--:shadowEtchedIn'
+- '--shadow-etched-in' or `--:shadowEtchedIn'
 
 A single line with 3D sunken appearance.  This is the form
 displayed for item names consisting of dashes only.
 
-- `--shadow-etched-out' or `--:shadowEtchedOut'
+- '--shadow-etched-out' or `--:shadowEtchedOut'
 
 A single line with 3D raised appearance.
 
-- `--shadow-etched-in-dash' or `--:shadowEtchedInDash'
+- '--shadow-etched-in-dash' or `--:shadowEtchedInDash'
 
 A single dashed line with 3D sunken appearance.
 
-- `--shadow-etched-out-dash' or `--:shadowEtchedOutDash'
+- '--shadow-etched-out-dash' or `--:shadowEtchedOutDash'
 
 A single dashed line with 3D raise appearance.
 
-- `--shadow-double-etched-in' or `--:shadowDoubleEtchedIn'
+- '--shadow-double-etched-in' or `--:shadowDoubleEtchedIn'
 
 Two lines with 3D sunken appearance.
 
-- `--shadow-double-etched-out' or `--:shadowDoubleEtchedOut'
+- '--shadow-double-etched-out' or `--:shadowDoubleEtchedOut'
 
 Two lines with 3D raised appearance.
 
-- `--shadow-double-etched-in-dash' or `--:shadowDoubleEtchedInDash'
+- '--shadow-double-etched-in-dash' or `--:shadowDoubleEtchedInDash'
 
 Two dashed lines with 3D sunken appearance.
 
-- `--shadow-double-etched-out-dash' or `--:shadowDoubleEtchedOutDash'
+- '--shadow-double-etched-out-dash' or `--:shadowDoubleEtchedOutDash'
 
 Two dashed lines with 3D raised appearance.
 
@@ -4818,22 +4819,22 @@ the corresponding single-line separators.
 
 ** New frame parameters for scroll bar colors.
 
-The new frame parameters `scroll-bar-foreground' and
-`scroll-bar-background' can be used to change scroll bar colors.
+The new frame parameters 'scroll-bar-foreground' and
+'scroll-bar-background' can be used to change scroll bar colors.
 Their value must be either a color name, a string, or nil to specify
 that scroll bars should use a default color.  For toolkit scroll bars,
 default colors are toolkit specific.  For non-toolkit scroll bars, the
 default background is the background color of the frame, and the
 default foreground is black.
 
-The X resource name of these parameters are `scrollBarForeground'
-(class ScrollBarForeground) and `scrollBarBackground' (class
-`ScrollBarBackground').
+The X resource name of these parameters are 'scrollBarForeground'
+(class ScrollBarForeground) and 'scrollBarBackground' (class
+'ScrollBarBackground').
 
 Setting these parameters overrides toolkit specific X resource
 settings for scroll bar colors.
 
-** You can set `redisplay-dont-pause' to a non-nil value to prevent
+** You can set 'redisplay-dont-pause' to a non-nil value to prevent
 display updates from being interrupted when input is pending.
 
 ** Changing a window's width may now change its window start if it
@@ -4842,15 +4843,15 @@ on the window's new width, starting from the start of 
the continued
 line as the start of the screen line with the minimum distance from
 the original window start.
 
-** The variable `hscroll-step' and the functions
-`hscroll-point-visible' and `hscroll-window-column' have been removed
+** The variable 'hscroll-step' and the functions
+'hscroll-point-visible' and 'hscroll-window-column' have been removed
 now that proper horizontal scrolling is implemented.
 
 ** Windows can now be made fixed-width and/or fixed-height.
 
 A window is fixed-size if its buffer has a buffer-local variable
-`window-size-fixed' whose value is not nil.  A value of `height' makes
-windows fixed-height, a value of `width' makes them fixed-width, any
+'window-size-fixed' whose value is not nil.  A value of 'height' makes
+windows fixed-height, a value of 'width' makes them fixed-width, any
 other non-nil value makes them both fixed-width and fixed-height.
 
 The following code makes all windows displaying the current buffer
@@ -4861,7 +4862,7 @@ fixed-width and fixed-height.
 A call to enlarge-window on a window gives an error if that window is
 fixed-width and it is tried to change the window's width, or if the
 window is fixed-height, and it is tried to change its height.  To
-change the size of a fixed-size window, bind `window-size-fixed'
+change the size of a fixed-size window, bind 'window-size-fixed'
 temporarily to nil, for example
 
   (let ((window-size-fixed nil))
@@ -4872,7 +4873,7 @@ or a fixed-width window horizontally results in an error.
 
 ** The cursor-type frame parameter is now supported on MS-DOS
 terminals.  When Emacs starts, it by default changes the cursor shape
-to a solid box, as it does on Unix.  The `cursor-type' frame parameter
+to a solid box, as it does on Unix.  The 'cursor-type' frame parameter
 overrides this as it does on Unix, except that the bar cursor is
 horizontal rather than vertical (since the MS-DOS display doesn't
 support a vertical-bar cursor).
diff --git a/etc/NEWS.22 b/etc/NEWS.22
index be3167dace..926b9f489e 100644
--- a/etc/NEWS.22
+++ b/etc/NEWS.22
@@ -11,7 +11,7 @@ This file is about changes in Emacs version 22.
 See files NEWS.21, NEWS.20, NEWS.19, NEWS.18, and NEWS.1-17 for changes
 in older Emacs versions.
 
-You can narrow news to a specific version by calling `view-emacs-news'
+You can narrow news to a specific version by calling 'view-emacs-news'
 with a prefix argument or by typing C-u C-h C-n.
 
 * About external Lisp packages
@@ -28,7 +28,7 @@ version is used.  You can use M-x list-load-path-shadows to 
find such
 older packages.
 
 Some specific packages that are known to cause problems are given
-below.  Emacs tries to warn you about these through `bad-packages-alist'.
+below.  Emacs tries to warn you about these through 'bad-packages-alist'.
 
 ** Semantic (used by CEDET, ECB, JDEE): upgrade to latest version.
 
@@ -97,14 +97,14 @@ nextstep, ux4800, uxpds, and uxpv
 
 * Changes in Emacs 22.2
 
-** `describe-project' is renamed to `describe-gnu-project'.
+** 'describe-project' is renamed to 'describe-gnu-project'.
 
-** `view-todo' is renamed to `view-emacs-todo'.
+** 'view-todo' is renamed to 'view-emacs-todo'.
 
-** `find-name-dired' now uses -iname rather than -name
+** 'find-name-dired' now uses -iname rather than -name
 for case-insensitive filesystems.  The default behavior is determined
-by the value of `read-file-name-completion-ignore-case'; if you don't
-like that, customize the value of the new option `find-name-arg'.
+by the value of 'read-file-name-completion-ignore-case'; if you don't
+like that, customize the value of the new option 'find-name-arg'.
 
 ** In Image mode, whenever the displayed image is wider and/or higher
 than the window, the usual keys for moving the cursor cause the image
@@ -130,14 +130,14 @@ Windows installations. Users of software which modifies 
the behavior of
 Windows to cause focus to follow the mouse will now need to explicitly set
 this variable.
 
-** `bad-packages-alist' will warn about external packages that are known
+** 'bad-packages-alist' will warn about external packages that are known
 to cause problems in this version of Emacs.
 
-** The values of `dired-recursive-deletes' and `dired-recursive-copies'
-have been changed to `top'.  This means that the user is asked once,
+** The values of 'dired-recursive-deletes' and 'dired-recursive-copies'
+have been changed to 'top'.  This means that the user is asked once,
 before deleting/copying the indicated directory recursively.
 
-** `browse-url-emacs' loads a URL into an Emacs buffer.  Handy for *.el URLs.
+** 'browse-url-emacs' loads a URL into an Emacs buffer.  Handy for *.el URLs.
 
 ** The command gdba has been removed as gdb works now for those cases where it
 was needed.  In text command mode, if you have problems before execution has
@@ -146,21 +146,21 @@ started, use M-x gud-gdb.
 ** desktop.el now detects conflicting uses of the desktop file.
 When loading the desktop, desktop.el can now detect that the file is already
 in use.  The default behavior is to ask the user what to do, but you can
-customize it with the new option `desktop-load-locked-desktop'.  When saving,
+customize it with the new option 'desktop-load-locked-desktop'.  When saving,
 desktop.el warns about attempts to overwrite a desktop file if it determines
 that the desktop being saved is not an update of the one on disk.
 
 ** Compilation mode now correctly respects the value of
-`compilation-scroll-output' between invocations.  Previously, output
+'compilation-scroll-output' between invocations.  Previously, output
 was mistakenly scrolled on compiles after the first.  Customize
-`compilation-scroll-output' if you want to retain the scrolling.
+'compilation-scroll-output' if you want to retain the scrolling.
 
-** `font-lock-comment-face' no longer differs from the default on
+** 'font-lock-comment-face' no longer differs from the default on
 displays with fewer than 16 colors and dark background (e.g. older
 xterms and the Linux console).  On such displays, only the comment
 delimiters will appear to be fontified (in the new face
-`font-lock-comment-delimiter-face').  To restore the old appearance,
-customize `font-lock-comment-face'. Another alternative is to use a
+'font-lock-comment-delimiter-face').  To restore the old appearance,
+customize 'font-lock-comment-face'. Another alternative is to use a
 newer terminal emulator that supports more colors (256 is now common).
 For example, for xterm compatible emulators that support 256 colors,
 you can run emacs like this:
@@ -171,13 +171,13 @@ the case anymore).
 
 * New Modes and Packages in Emacs 22.2
 
-** bibtex-style-mode helps you write BibTeX's *.bst files.
+** 'bibtex-style-mode' helps you write BibTeX's *.bst files.
 
-** The new package css-mode.el provides a major mode for editing CSS files.
+** The new package 'css-mode' provides a major mode for editing CSS files.
 
-** The new package vera-mode.el provides a major mode for editing Vera files.
+** The new package 'vera-mode' provides a major mode for editing Vera files.
 
-** The new package verilog-mode.el provides a major mode for editing Verilog 
files.
+** The new package 'verilog-mode' provides a major mode for editing Verilog 
files.
 
 ** The new package socks.el implements the SOCKS v5 protocol.
 
@@ -198,48 +198,48 @@ This can be used to add menu entries for backend specific 
functions.
 
 * Incompatible Lisp Changes in Emacs 22.2
 
-** shell.el no longer defines the aliases `dirtrack-toggle' and
-`dirtrack-mode' for `shell-dirtrack-mode'.  These names were removed
+** shell.el no longer defines the aliases 'dirtrack-toggle' and
+'dirtrack-mode' for 'shell-dirtrack-mode'.  These names were removed
 because they clash with commands provided by dirtrack.el.  Use
-`shell-dirtrack-mode' instead.
+'shell-dirtrack-mode' instead.
 
 * Lisp Changes in Emacs 22.2.
 
 ** Frame-local variables are deprecated and are slated for removal.
-They can easily be emulated.  Rather than calling `make-variable-frame-local'
+They can easily be emulated.  Rather than calling 'make-variable-frame-local'
 and accessing the variable value directly, explicitly check for a
-frame-parameter, and if there is one, use its value in preference to
+'frame-parameter', and if there is one, use its value in preference to
 that of the variable.  Note that buffer-local values should take
-precedence over frame-local ones, so you may wish to check `local-variable-p'
+precedence over frame-local ones, so you may wish to check 'local-variable-p'
 first.
 
-** The function invisible-p returns non-nil if the character
+** The function 'invisible-p' returns non-nil if the character
 after a specified position is invisible.
 
-** inhibit-modification-hooks is bound to t while running modification hooks.
+** 'inhibit-modification-hooks' is bound to t while running modification hooks.
 As a happy consequence, after-change-functions and before-change-functions
 are not bound to nil any more while running an (after|before)-change-function.
 
-** New function `window-full-width-p' returns t if a window is as wide
+** New function 'window-full-width-p' returns t if a window is as wide
 as its frame.
 
-** The new function `image-refresh' refreshes all images associated
+** The new function 'image-refresh' refreshes all images associated
 with a given image specification.
 
-** The new function `combine-and-quote-strings' concatenates a list of strings
+** The new function 'combine-and-quote-strings' concatenates a list of strings
 using a specified separator.  If a string contains double quotes, they
 are escaped in the output.
 
-** The new function `split-string-and-unquote' performs the inverse operation 
to
-`combine-and-quote-strings', i.e. splits a single string into a list
-of strings, undoing any quoting added by `combine-and-quote-strings'.
+** The new function 'split-string-and-unquote' performs the inverse operation 
to
+'combine-and-quote-strings', i.e. splits a single string into a list
+of strings, undoing any quoting added by 'combine-and-quote-strings'.
 (For some separator/string combinations, the original strings cannot
 be recovered.)
 
 
 * Installation Changes in Emacs 22.1
 
-** You can build Emacs with Gtk+ widgets by specifying `--with-x-toolkit=gtk'
+** You can build Emacs with Gtk+ widgets by specifying '--with-x-toolkit=gtk'
 when you run configure.  This requires Gtk+ 2.4 or newer.  This port
 provides a way to display multilingual text in menus (with some caveats).
 
@@ -266,7 +266,7 @@ Emacs with Leim.
 See the files mac/README and mac/INSTALL for build instructions.
 
 ** Mac OS 9 port now uses the Carbon API by default.  You can also
-create a non-Carbon build by specifying `NonCarbon' as a target.  See
+create a non-Carbon build by specifying 'NonCarbon' as a target.  See
 the files mac/README and mac/INSTALL for build instructions.
 
 ** Support for a Cygwin build of Emacs was added.
@@ -282,38 +282,38 @@ the files mac/README and mac/INSTALL for build 
instructions.
 ** New translations of the Emacs Tutorial are available in the
 following languages: Brazilian Portuguese, Bulgarian, Chinese (both
 with simplified and traditional characters), French, Russian, and
-Italian.  Type `C-u C-h t' to choose one of them in case your language
+Italian.  Type 'C-u C-h t' to choose one of them in case your language
 setup doesn't automatically select the right one.
 
 ** New translations of the Emacs reference card are available in the
 Brazilian Portuguese and Russian.  The corresponding PostScript files
 are also included.
 
-** A French translation of the `Emacs Survival Guide' is available.
+** A French translation of the 'Emacs Survival Guide' is available.
 
-** Emacs now supports new configure options `--program-prefix',
-`--program-suffix' and `--program-transform-name' that affect the names of
+** Emacs now supports new configure options '--program-prefix',
+'--program-suffix' and '--program-transform-name' that affect the names of
 installed programs.
 
 ** By default, Emacs now uses a setgid helper program to update game
 scores.  The directory ${localstatedir}/games/emacs is the normal
 place for game scores to be stored.  You can control this with the
-configure option `--with-game-dir'.  The specific user that Emacs uses
-to own the game scores is controlled by `--with-game-user'.  If access
+configure option '--with-game-dir'.  The specific user that Emacs uses
+to own the game scores is controlled by '--with-game-user'.  If access
 to a game user is not available, then scores will be stored separately
 in each user's home directory.
 
 ** Emacs now includes support for loading image libraries on demand.
 (Currently this feature is only used on MS Windows.)  You can configure
 the supported image types and their associated dynamic libraries by
-setting the variable `image-library-alist'.
+setting the variable 'image-library-alist'.
 
 ** Emacs can now be built without sound support.
 
-** Emacs Lisp source files are compressed by default if `gzip' is available.
+** Emacs Lisp source files are compressed by default if 'gzip' is available.
 
 ** All images used in Emacs have been consolidated in etc/images and subdirs.
-See also the changes to `find-image', documented below.
+See also the changes to 'find-image', documented below.
 
 ** Emacs comes with a new set of icons.
 These icons are displayed on the taskbar and/or titlebar when Emacs
@@ -323,9 +323,9 @@ Emacs by changing these files directly.  On X, the icon is 
compiled
 into the Emacs executable; see gnu.h in the source tree.  On MS
 Windows, see nt/icons/emacs.ico.)
 
-** The `emacsserver' program has been removed, replaced with Lisp code.
+** The 'emacsserver' program has been removed, replaced with Lisp code.
 
-** The `yow' program has been removed.
+** The 'yow' program has been removed.
 Use the corresponding Emacs feature instead.
 
 ** The Emacs terminal emulation in term.el uses a different terminfo name.
@@ -352,18 +352,18 @@ If the init file ~/.emacs does not exist, Emacs will try
 
 ** Emacs can now be invoked in full-screen mode on a windowed display.
 When Emacs is invoked on a window system, the new command-line options
-`--fullwidth', `--fullheight', and `--fullscreen' produce a frame
+'--fullwidth', '--fullheight', and '--fullscreen' produce a frame
 whose width, height, or both width and height take up the entire
 screen size.  (For now, this does not work with some window managers.)
 
 ** Emacs now displays a splash screen by default even if command-line
 arguments were given.  The new command-line option --no-splash
 disables the splash screen; see also the variable
-`inhibit-splash-screen' (which is also aliased as
-`inhibit-startup-message').
+'inhibit-splash-screen' (which is also aliased as
+'inhibit-startup-message').
 
-** New user option `inhibit-startup-buffer-menu'.
-When loading many files, for instance with `emacs *', Emacs normally
+** New user option 'inhibit-startup-buffer-menu'.
+When loading many files, for instance with 'emacs *', Emacs normally
 displays a buffer menu.  This option turns the buffer menu off.
 
 ** New command line option -nbc or --no-blinking-cursor disables
@@ -379,14 +379,14 @@ can start with this line:
 now reads arguments for the function interactively if it is
 an interactively callable function.
 
-** The option --directory DIR now modifies `load-path' immediately.
-Directories are added to the front of `load-path' in the order they
+** The option --directory DIR now modifies 'load-path' immediately.
+Directories are added to the front of 'load-path' in the order they
 appear on the command line.  For example, with this command line:
 
   emacs -batch -L .. -L /tmp --eval "(require 'foo)"
 
-Emacs looks for library `foo' in the parent directory, then in /tmp, then
-in the other directories in `load-path'.  (-L is short for --directory.)
+Emacs looks for library 'foo' in the parent directory, then in /tmp, then
+in the other directories in 'load-path'.  (-L is short for --directory.)
 
 ** When you specify a frame size with --geometry, the size applies to
 all frames you create.  A position specified with --geometry only
@@ -408,7 +408,7 @@ Emacs will now startup as if invoked with the 
--no-window-system option.
 automatically at startup, if it exists.  When Emacs offers to save
 modified buffers, it saves the abbrevs too if they have changed.  It
 can do this either silently or asking for confirmation first,
-according to the value of `save-abbrevs'.
+according to the value of 'save-abbrevs'.
 
 ** New command line option -Q or --quick.
 This is like using -q --no-site-file, but in addition it also disables
@@ -423,8 +423,8 @@ The command-line options --icon-type, -i have been replaced 
with
 options --no-bitmap-icon, -nbi to turn the bitmap icon off.
 
 ** If the environment variable EMAIL is defined, Emacs now uses its value
-to compute the default value of `user-mail-address', in preference to
-concatenation of `user-login-name' with the name of your host machine.
+to compute the default value of 'user-mail-address', in preference to
+concatenation of 'user-login-name' with the name of your host machine.
 
 
 * Incompatible Editing Changes in Emacs 22.1
@@ -434,7 +434,7 @@ concatenation of `user-login-name' with the name of your 
host machine.
 See below for more details.
 
 ** When the undo information of the current command gets really large
-(beyond the value of `undo-outer-limit'), Emacs discards it and warns
+(beyond the value of 'undo-outer-limit'), Emacs discards it and warns
 you about it.
 
 ** When Emacs prompts for file names, SPC no longer completes the file name.
@@ -460,9 +460,9 @@ it remains unchanged.
 See below under "incremental search changes".
 
 ** M-g is now a prefix key.
-M-g g and M-g M-g run goto-line.
-M-g n and M-g M-n run next-error (like C-x `).
-M-g p and M-g M-p run previous-error.
+M-g g and M-g M-g run 'goto-line'.
+M-g n and M-g M-n run 'next-error' (like C-x `).
+M-g p and M-g M-p run 'previous-error'.
 
 ** C-u M-g M-g switches to the most recent previous buffer,
 and goes to the specified line in that buffer.
@@ -483,23 +483,23 @@ directory with Dired.
 You can get the old behavior by typing C-x C-f M-n RET, which fetches
 the actual file name into the minibuffer.
 
-** In Dired's ! command (dired-do-shell-command), `*' and `?' now
+** In Dired's ! command (dired-do-shell-command), '*' and '?' now
 control substitution of the file names only when they are surrounded
 by whitespace.  This means you can now use them as shell wildcards
-too.  If you want to use just plain `*' as a wildcard, type `*""'; the
+too.  If you want to use just plain '*' as a wildcard, type '*""'; the
 doublequotes make no difference in the shell, but they prevent
-special treatment in `dired-do-shell-command'.
+special treatment in 'dired-do-shell-command'.
 
 ** The info-search bindings on C-h C-f, C-h C-k and C-h C-i
 have been moved to C-h F, C-h K and C-h S.
 
-** `apply-macro-to-region-lines' now operates on all lines that begin
+** 'apply-macro-to-region-lines' now operates on all lines that begin
 in the region, rather than on all complete lines in the region.
 
-** line-move-ignore-invisible now defaults to t.
+** 'line-move-ignore-invisible' now defaults to t.
 
 ** Adaptive filling misfeature removed.
-It no longer treats `NNN.' or `(NNN)' as a prefix.
+It no longer treats 'NNN.' or '(NNN)' as a prefix.
 
 ** The old bindings C-M-delete and C-M-backspace have been deleted,
 since there are situations where one or the other will shut down
@@ -507,10 +507,10 @@ the operating system or your X server.
 
 ** The register compatibility key bindings (deprecated since Emacs 19)
 have been removed:
-  C-x /   point-to-register (Use: C-x r SPC)
-  C-x j   jump-to-register  (Use: C-x r j)
-  C-x x   copy-to-register  (Use: C-x r s)
-  C-x g   insert-register   (Use: C-x r i)
+  C-x /   'point-to-register' (Use: C-x r SPC)
+  C-x j   'jump-to-register'  (Use: C-x r j)
+  C-x x   'copy-to-register'  (Use: C-x r s)
+  C-x g   'insert-register'   (Use: C-x r i)
 
 
 * Editing Changes in Emacs 22.1
@@ -525,14 +525,14 @@ killing buffers will get out of this state.  If killing 
buffers does
 not make !MEM FULL! disappear, you should save your work and start
 a new Emacs.
 
-** `undo-only' does an undo which does not redo any previous undo.
+** 'undo-only' does an undo which does not redo any previous undo.
 
 ** Yanking text now discards certain text properties that can
 be inconvenient when you did not expect them.  The variable
-`yank-excluded-properties' specifies which ones.  Insertion
+'yank-excluded-properties' specifies which ones.  Insertion
 of register contents and rectangles also discards these properties.
 
-** New command `kill-whole-line' kills an entire line at once.
+** New command 'kill-whole-line' kills an entire line at once.
 By default, it is bound to C-S-<backspace>.
 
 ** M-SPC (just-one-space) when given a numeric argument N
@@ -547,20 +547,20 @@ cycle for each frame, using the frame-local buffer list.
 but does not switch to that frame.  It's the multi-frame
 analogue of C-x 4 C-o.
 
-** `special-display-buffer-names' and `special-display-regexps' now
-understand two new boolean pseudo-frame-parameters `same-frame' and
-`same-window'.
+** 'special-display-buffer-names' and 'special-display-regexps' now
+understand two new boolean pseudo-frame-parameters 'same-frame' and
+'same-window'.
 
 ** New commands to operate on pairs of open and close characters:
-`insert-pair', `delete-pair', `raise-sexp'.
+'insert-pair', 'delete-pair', 'raise-sexp'.
 
 ** M-x setenv now expands environment variable references.
 
-Substrings of the form `$foo' and `${foo}' in the specified new value
-now refer to the value of environment variable foo.  To include a `$'
-in the value, use `$$'.
+Substrings of the form '$foo' and '${foo}' in the specified new value
+now refer to the value of environment variable foo.  To include a '$'
+in the value, use '$$'.
 
-** The default values of paragraph-start and indent-line-function have
+** The default values of 'paragraph-start' and 'indent-line-function' have
 been changed to reflect those used in Text mode rather than those used
 in Paragraph-Indent Text mode.
 
@@ -573,7 +573,7 @@ from the locale.
 
 C-h e displays the *Messages* buffer.
 
-C-h d runs apropos-documentation.
+C-h d runs 'apropos-documentation'.
 
 C-h r visits the Emacs Manual in Info.
 
@@ -607,56 +607,56 @@ When more than one word is specified, at least two of 
those words must
 be present for an item to match.  Regular expression matching is still
 available.
 
-*** The new option `apropos-sort-by-scores' causes the matching items
+*** The new option 'apropos-sort-by-scores' causes the matching items
 to be sorted according to their score.  The score for an item is a
 number calculated to indicate how well the item matches the words or
 regular expression that you entered to the apropos command.  The best
 match is listed first, and the calculated score is shown for each
 matching item.
 
-*** Help commands `describe-function' and `describe-key' now show function
+*** Help commands 'describe-function' and 'describe-key' now show function
 arguments in lowercase italics on displays that support it.  To change the
-default, customize face `help-argument-name' or redefine the function
-`help-default-arg-highlight'.
+default, customize face 'help-argument-name' or redefine the function
+'help-default-arg-highlight'.
 
 *** C-h v and C-h f commands now include a hyperlink to the C source for
 variables and functions defined in C (if the C source is available).
 
 *** Help mode now only makes hyperlinks for faces when the face name is
-preceded or followed by the word `face'.  It no longer makes
+preceded or followed by the word 'face'.  It no longer makes
 hyperlinks for variables without variable documentation, unless
-preceded by one of the words `variable' or `option'.  It now makes
+preceded by one of the words 'variable' or 'option'.  It now makes
 hyperlinks to Info anchors (or nodes) if the anchor (or node) name is
-enclosed in single quotes and preceded by `info anchor' or `Info
-anchor' (in addition to earlier `info node' and `Info node').  In
+enclosed in single quotes and preceded by 'info anchor' or 'Info
+anchor' (in addition to earlier 'info node' and 'Info node').  In
 addition, it now makes hyperlinks to URLs as well if the URL is
-enclosed in single quotes and preceded by `URL'.
+enclosed in single quotes and preceded by 'URL'.
 
-*** The new command `describe-char' (C-u C-x =) pops up a buffer with
+*** The new command 'describe-char' (C-u C-x =) pops up a buffer with
 description various information about a character, including its
 encodings and syntax, its text properties, how to input, overlays, and
 widgets at point.  You can get more information about some of them, by
 clicking on mouse-sensitive areas or moving there and pressing RET.
 
-*** The command `list-text-properties-at' has been deleted because
+*** The command 'list-text-properties-at' has been deleted because
 C-u C-x = gives the same information and more.
 
-*** New command `display-local-help' displays any local help at point
-in the echo area.  It is bound to `C-h .'.  It normally displays the
+*** New command 'display-local-help' displays any local help at point
+in the echo area.  It is bound to 'C-h .'.  It normally displays the
 same string that would be displayed on mouse-over using the
-`help-echo' property, but, in certain cases, it can display a more
+'help-echo' property, but, in certain cases, it can display a more
 keyboard oriented alternative.
 
-*** New user option `help-at-pt-display-when-idle' allows you to
-automatically show the help provided by `display-local-help' on
+*** New user option 'help-at-pt-display-when-idle' allows you to
+automatically show the help provided by 'display-local-help' on
 point-over, after suitable idle time.  The amount of idle time is
-determined by the user option `help-at-pt-timer-delay' and defaults
+determined by the user option 'help-at-pt-timer-delay' and defaults
 to one second.  This feature is turned off by default.
 
 ** Mark command changes:
 
 *** A prefix argument is no longer required to repeat a jump to a
-previous mark if you set `set-mark-command-repeat-pop' to t.  I.e. C-u
+previous mark if you set 'set-mark-command-repeat-pop' to t.  I.e. C-u
 C-SPC C-SPC C-SPC ... cycles through the mark ring.  Use C-u C-u C-SPC
 to set the mark immediately after a jump.
 
@@ -666,7 +666,7 @@ If you type C-M-SPC (mark-sexp), M-@ (mark-word), M-h
 (mark-paragraph), or C-M-h (mark-defun) repeatedly, the marked region
 extends each time, so you can mark the next two sexps with M-C-SPC
 M-C-SPC, for example.  This feature also works for
-mark-end-of-sentence, if you bind that to a key.  It also extends the
+'mark-end-of-sentence', if you bind that to a key.  It also extends the
 region when the mark is active in Transient Mark mode, regardless of
 the last command.  To start a new region with one of marking commands
 in Transient Mark mode, you can deactivate the active region with C-g,
@@ -689,8 +689,8 @@ deactivate the mark.  That typically happens when you type 
a command
 that alters the buffer, but you can also deactivate the mark by typing
 C-g.
 
-*** Movement commands `beginning-of-buffer', `end-of-buffer',
-`beginning-of-defun', `end-of-defun' do not set the mark if the mark
+*** Movement commands 'beginning-of-buffer', 'end-of-buffer',
+'beginning-of-defun', 'end-of-defun' do not set the mark if the mark
 is already active in Transient Mark mode.
 
 *** M-h (mark-paragraph) now accepts a prefix arg.
@@ -701,52 +701,52 @@ paragraphs.
 
 ** Incremental Search changes:
 
-*** M-% typed in isearch mode invokes `query-replace' or
-`query-replace-regexp' (depending on search mode) with the current
+*** M-% typed in isearch mode invokes 'query-replace' or
+'query-replace-regexp' (depending on search mode) with the current
 search string used as the string to replace.
 
 *** C-w in incremental search now grabs either a character or a word,
 making the decision in a heuristic way.  This new job is done by the
-command `isearch-yank-word-or-char'.  To restore the old behavior,
-bind C-w to `isearch-yank-word' in `isearch-mode-map'.
+command 'isearch-yank-word-or-char'.  To restore the old behavior,
+bind C-w to 'isearch-yank-word' in 'isearch-mode-map'.
 
 *** C-y in incremental search now grabs the next line if point is already
 at the end of a line.
 
 *** C-M-w deletes and C-M-y grabs a character in isearch mode.
-Another method to grab a character is to enter the minibuffer by `M-e'
-and to type `C-f' at the end of the search string in the minibuffer.
+Another method to grab a character is to enter the minibuffer by 'M-e'
+and to type 'C-f' at the end of the search string in the minibuffer.
 
 *** Vertical scrolling is now possible within incremental search.
 To enable this feature, customize the new user option
-`isearch-allow-scroll'.  User written commands which satisfy stringent
+'isearch-allow-scroll'.  User written commands which satisfy stringent
 constraints can be marked as "scrolling commands".  See the Emacs manual
 for details.
 
-*** Isearch no longer adds `isearch-resume' commands to the command
+*** Isearch no longer adds 'isearch-resume' commands to the command
 history by default.  To enable this feature, customize the new
-user option `isearch-resume-in-command-history'.
+user option 'isearch-resume-in-command-history'.
 
 ** Replace command changes:
 
-*** When used interactively, the commands `query-replace-regexp' and
-`replace-regexp' allow \,expr to be used in a replacement string,
+*** When used interactively, the commands 'query-replace-regexp' and
+'replace-regexp' allow \,expr to be used in a replacement string,
 where expr is an arbitrary Lisp expression evaluated at replacement
-time.  `\#' in a replacement string now refers to the count of
+time.  '\#' in a replacement string now refers to the count of
 replacements already made by the replacement command.  All regular
-expression replacement commands now allow `\?' in the replacement
+expression replacement commands now allow '\?' in the replacement
 string to specify a position where the replacement string can be
-edited for each replacement.  `query-replace-regexp-eval' is now
+edited for each replacement.  'query-replace-regexp-eval' is now
 deprecated since it offers no additional functionality.
 
 *** query-replace uses isearch lazy highlighting when the new user option
-`query-replace-lazy-highlight' is non-nil.
+'query-replace-lazy-highlight' is non-nil.
 
 *** The current match in query-replace is highlighted in new face
-`query-replace' which by default inherits from isearch face.
+'query-replace' which by default inherits from isearch face.
 
-*** New user option `query-replace-skip-read-only': when non-nil,
-`query-replace' and related functions simply ignore
+*** New user option 'query-replace-skip-read-only': when non-nil,
+'query-replace' and related functions simply ignore
 a match if part of it has a read-only property.
 
 ** Local variables lists:
@@ -755,31 +755,31 @@ a match if part of it has a read-only property.
 are not known to be safe, Emacs shows a prompt asking whether to apply
 the local variables list as a whole.  In earlier versions, a prompt
 was only issued for variables explicitly marked as risky (for the
-definition of risky variables, see `risky-local-variable-p').
+definition of risky variables, see 'risky-local-variable-p').
 
 At the prompt, you can choose to save the contents of this local
-variables list to `safe-local-variable-values'.  This new customizable
+variables list to 'safe-local-variable-values'.  This new customizable
 option is a list of variable-value pairs that are known to be safe.
 Variables can also be marked as safe with the existing
-`safe-local-variable' property (see `safe-local-variable-p').
+'safe-local-variable' property (see 'safe-local-variable-p').
 However, risky variables will not be added to
-`safe-local-variable-values' in this way.
+'safe-local-variable-values' in this way.
 
-*** The variable `enable-local-variables' controls how local variable
+*** The variable 'enable-local-variables' controls how local variable
 lists are handled.  t, the default, specifies the standard querying
 behavior.  :safe means use only safe values, and ignore the rest.
 :all means set all variables, whether or not they are safe.
 nil means ignore them all.  Anything else means always query.
 
-*** The variable `safe-local-eval-forms' specifies a list of forms that
-are ok to evaluate when they appear in an `eval' local variables
+*** The variable 'safe-local-eval-forms' specifies a list of forms that
+are ok to evaluate when they appear in an 'eval' local variables
 specification.  Normally Emacs asks for confirmation before evaluating
 such a form, but if the form appears in this list, no confirmation is
 needed.
 
-*** If a function has a non-nil `safe-local-eval-function' property,
+*** If a function has a non-nil 'safe-local-eval-function' property,
 that means it is ok to evaluate some calls to that function when it
-appears in an `eval' local variables specification.  If the property
+appears in an 'eval' local variables specification.  If the property
 is t, then any form calling that function with constant arguments is
 ok.  If the property is a function or list of functions, they are called
 with the form as argument, and if any returns t, the form is ok to call.
@@ -797,9 +797,9 @@ properties--any specified text properties are discarded.
 
 ** File operation changes:
 
-*** Unquoted `$' in file names do not signal an error any more when
+*** Unquoted '$' in file names do not signal an error any more when
 the corresponding environment variable does not exist.
-Instead, the `$ENVVAR' text is left as is, so that `$$' quoting
+Instead, the '$ENVVAR' text is left as is, so that '$$' quoting
 is only rarely needed.
 
 *** C-x C-f RET, typing nothing in the minibuffer, is no longer a special case.
@@ -808,12 +808,12 @@ Since the default input is the current directory, this 
has the effect
 of specifying the current directory.  Normally that means to visit the
 directory with Dired.
 
-*** C-x s (save-some-buffers) now offers an option `d' to diff a buffer
+*** C-x s (save-some-buffers) now offers an option 'd' to diff a buffer
 against its file, so you can see what changes you would be saving.
 
 *** Auto Compression mode is now enabled by default.
 
-*** If the user visits a file larger than `large-file-warning-threshold',
+*** If the user visits a file larger than 'large-file-warning-threshold',
 Emacs asks for confirmation.
 
 *** The commands copy-file, rename-file, make-symbolic-link and
@@ -825,10 +825,10 @@ commands cp, mv, and ln follow.)  Thus, M-x copy-file RET 
~/foo RET
 
 *** require-final-newline now has two new possible values:
 
-`visit' means add a newline (as an undoable change) if it's needed
+'visit' means add a newline (as an undoable change) if it's needed
 when visiting the file.
 
-`visit-save' means add a newline (as an undoable change) if it's
+'visit-save' means add a newline (as an undoable change) if it's
 needed when visiting the file, and also add a newline if it's needed
 when saving the file.
 
@@ -844,23 +844,23 @@ read-only, the Emacs buffer is now read-only too.  Type 
C-x C-q if you
 want to make the buffer writable.  (As root, you can in fact alter the
 file.)
 
-*** find-file-read-only visits multiple files in read-only mode,
+*** 'find-file-read-only' visits multiple files in read-only mode,
 when the file name contains wildcard characters.
 
-*** find-alternate-file replaces the current file with multiple files,
+*** 'find-alternate-file' replaces the current file with multiple files,
 when the file name contains wildcard characters.  It now asks if you
 wish save your changes and not just offer to kill the buffer.
 
-*** When used interactively, `format-write-file' now asks for confirmation
+*** When used interactively, 'format-write-file' now asks for confirmation
 before overwriting an existing file, unless a prefix argument is
-supplied.  This behavior is analogous to `write-file'.
+supplied.  This behavior is analogous to 'write-file'.
 
-*** The variable `auto-save-file-name-transforms' now has a third element that
-controls whether or not the function `make-auto-save-file-name' will
+*** The variable 'auto-save-file-name-transforms' now has a third element that
+controls whether or not the function 'make-auto-save-file-name' will
 attempt to construct a unique auto-save name (e.g. for remote files).
 
-*** The new option `write-region-inhibit-fsync' disables calls to fsync
-in `write-region'.  This can be useful on laptops to avoid spinning up
+*** The new option 'write-region-inhibit-fsync' disables calls to fsync
+in 'write-region'.  This can be useful on laptops to avoid spinning up
 the hard drive upon each file save.  Enabling this variable may result
 in data loss, use with care.
 
@@ -873,50 +873,50 @@ it remains unchanged.
 *** The new file-name-shadow-mode is turned ON by default, so that when
 entering a file name, any prefix which Emacs will ignore is dimmed.
 
-*** There's a new face `minibuffer-prompt'.
+*** There's a new face 'minibuffer-prompt'.
 Emacs adds this face to the list of text properties stored in the
-variable `minibuffer-prompt-properties', which is used to display the
+variable 'minibuffer-prompt-properties', which is used to display the
 prompt string.
 
-*** Enhanced visual feedback in `*Completions*' buffer.
+*** Enhanced visual feedback in '*Completions*' buffer.
 
 Completions lists use faces to highlight what all completions
 have in common and where they begin to differ.
 
 The common prefix shared by all possible completions uses the face
-`completions-common-part', while the first character that isn't the
-same uses the face `completions-first-difference'.  By default,
-`completions-common-part' inherits from `default', and
-`completions-first-difference' inherits from `bold'.  The idea of
-`completions-common-part' is that you can use it to make the common
+'completions-common-part', while the first character that isn't the
+same uses the face 'completions-first-difference'.  By default,
+'completions-common-part' inherits from 'default', and
+'completions-first-difference' inherits from 'bold'.  The idea of
+'completions-common-part' is that you can use it to make the common
 parts less visible than normal, so that the rest of the differing
 parts is, by contrast, slightly highlighted.
 
 Above fontification is always done when listing completions is
 triggered at minibuffer.  If you want to fontify completions whose
 listing is triggered at the other normal buffer, you have to pass
-the common prefix of completions to `display-completion-list' as
+the common prefix of completions to 'display-completion-list' as
 its second argument.
 
 *** File-name completion can now ignore specified directories.
-If an element of the list in `completion-ignored-extensions' ends in a
-slash `/', it indicates a subdirectory that should be ignored when
-completing file names.  Elements of `completion-ignored-extensions'
+If an element of the list in 'completion-ignored-extensions' ends in a
+slash '/', it indicates a subdirectory that should be ignored when
+completing file names.  Elements of 'completion-ignored-extensions'
 which do not end in a slash are never considered when a completion
 candidate is a directory.
 
-*** New user option `history-delete-duplicates'.
+*** New user option 'history-delete-duplicates'.
 If set to t when adding a new history element, all previous identical
 elements are deleted from the history list.
 
 ** Redisplay changes:
 
-*** The new face `mode-line-inactive' is used to display the mode line
-of non-selected windows.  The `mode-line' face is now used to display
+*** The new face 'mode-line-inactive' is used to display the mode line
+of non-selected windows.  The 'mode-line' face is now used to display
 the mode line of the currently selected window.
 
-The new variable `mode-line-in-non-selected-windows' controls whether
-the `mode-line-inactive' face is used.
+The new variable 'mode-line-in-non-selected-windows' controls whether
+the 'mode-line-inactive' face is used.
 
 *** The mode line position information now comes before the major mode.
 When the file is maintained under version control, that information
@@ -924,7 +924,7 @@ appears between the position information and the major mode.
 
 *** You can now customize the use of window fringes.  To control this
 for all frames, use M-x fringe-mode or the Show/Hide submenu of the
-top-level Options menu, or customize the `fringe-mode' variable.  To
+top-level Options menu, or customize the 'fringe-mode' variable.  To
 control this for a specific frame, use the command M-x
 set-fringe-style.
 
@@ -933,10 +933,10 @@ addition, up and down arrow bitmaps in the fringe 
indicate which ways
 the window can be scrolled.
 
 This behavior is activated by setting the buffer-local variable
-`indicate-buffer-boundaries' to a non-nil value.  The default value of
-this variable is found in `default-indicate-buffer-boundaries'.
+'indicate-buffer-boundaries' to a non-nil value.  The default value of
+this variable is found in 'default-indicate-buffer-boundaries'.
 
-If value is `left' or `right', both angle and arrow bitmaps are
+If value is 'left' or 'right', both angle and arrow bitmaps are
 displayed in the left or right fringe, resp.
 
 The value can also be an alist which specifies the presence and
@@ -967,26 +967,26 @@ or when the frame is resized.
 displayed between the margins and the buffer's text area, rather than
 outside those margins.
 
-*** New face `escape-glyph' highlights control characters and escape glyphs.
+*** New face 'escape-glyph' highlights control characters and escape glyphs.
 
 *** Non-breaking space and hyphens are now displayed with a special
-face, either nobreak-space or escape-glyph.  You can turn this off or
-specify a different mode by setting the variable `nobreak-char-display'.
+face, either 'nobreak-space' or 'escape-glyph'.  You can turn this off or
+specify a different mode by setting the variable 'nobreak-char-display'.
 
 *** The parameters of automatic hscrolling can now be customized.
-The variable `hscroll-margin' determines how many columns away from
+The variable 'hscroll-margin' determines how many columns away from
 the window edge point is allowed to get before automatic hscrolling
 will horizontally scroll the window.  The default value is 5.
 
-The variable `hscroll-step' determines how many columns automatic
+The variable 'hscroll-step' determines how many columns automatic
 hscrolling scrolls the window when point gets too close to the
 window edge.  If its value is zero, the default, Emacs scrolls the
 window so as to center point.  If its value is an integer, it says how
 many columns to scroll.  If the value is a floating-point number, it
 gives the fraction of the window's width to scroll the window.
 
-The variable `automatic-hscrolling' was renamed to
-`auto-hscroll-mode'.  The old name is still available as an alias.
+The variable 'automatic-hscrolling' was renamed to
+'auto-hscroll-mode'.  The old name is still available as an alias.
 
 *** Moving or scrolling through images (and other lines) taller than
 the window now works sensibly, by automatically adjusting the window's
@@ -996,7 +996,7 @@ vscroll property.
 
 To avoid preempting redisplay on fast computers, networks, and displays,
 the arrival of new input is now performed at regular intervals during
-redisplay.  The new variable `redisplay-preemption-period' specifies
+redisplay.  The new variable 'redisplay-preemption-period' specifies
 the period; the default is to check for input every 0.1 seconds.
 
 *** The %c and %l constructs are now ignored in frame-title-format.
@@ -1004,34 +1004,34 @@ Due to technical limitations in how Emacs interacts 
with windowing
 systems, these constructs often failed to render properly, and could
 even cause Emacs to crash.
 
-*** If value of `auto-resize-tool-bars' is `grow-only', the tool bar
+*** If value of 'auto-resize-tool-bars' is 'grow-only', the tool bar
 will expand as needed, but not contract automatically.  To contract
 the tool bar, you must type C-l.
 
-*** New customize option `overline-margin' controls the space between
+*** New customize option 'overline-margin' controls the space between
 overline and text.
 
-*** New variable `x-underline-at-descent-line' controls the relative
+*** New variable 'x-underline-at-descent-line' controls the relative
 position of the underline.  When set, it overrides the
-`x-use-underline-position-properties' variables.
+'x-use-underline-position-properties' variables.
 
 ** New faces:
 
-*** `mode-line-highlight' is the standard face indicating mouse sensitive
-elements on mode-line (and header-line) like `highlight' face on text
+*** 'mode-line-highlight' is the standard face indicating mouse sensitive
+elements on mode-line (and header-line) like 'highlight' face on text
 areas.
 
-*** `mode-line-buffer-id' is the standard face for buffer identification
+*** 'mode-line-buffer-id' is the standard face for buffer identification
 parts of the mode line.
 
-*** `shadow' face defines the appearance of the "shadowed" text, i.e.
+*** 'shadow' face defines the appearance of the "shadowed" text, i.e.
 the text which should be less noticeable than the surrounding text.
 This can be achieved by using shades of gray in contrast with either
 black or white default foreground color.  This generic shadow face
 allows customization of the appearance of shadowed text in one place,
 so package-specific faces can inherit from it.
 
-*** `vertical-border' face is used for the vertical divider between windows.
+*** 'vertical-border' face is used for the vertical divider between windows.
 
 ** Font-Lock (syntax highlighting) changes:
 
@@ -1039,20 +1039,20 @@ so package-specific faces can inherit from it.
 fontification, even those such as Occur, Info, and comint-derived
 modes that do their own fontification in a special way.
 
-The variable `Info-fontify' is no longer applicable; to disable
-fontification in Info, remove `turn-on-font-lock' from
-`Info-mode-hook'.
+The variable 'Info-fontify' is no longer applicable; to disable
+fontification in Info, remove 'turn-on-font-lock' from
+'Info-mode-hook'.
 
-*** New standard font-lock face `font-lock-comment-delimiter-face'.
+*** New standard font-lock face 'font-lock-comment-delimiter-face'.
 This is used for the characters that indicate the start of a comment,
-e.g. `;' in Lisp mode.
+e.g. ';' in Lisp mode.
 
-*** New standard font-lock face `font-lock-preprocessor-face'.
+*** New standard font-lock face 'font-lock-preprocessor-face'.
 
 *** Easy to overlook single character negation can now be font-locked.
-You can use the new variable `font-lock-negation-char-face' and the face of
-the same name to customize this.  Currently the cc-modes, sh-script-mode,
-cperl-mode and make-mode support this.
+You can use the new variable 'font-lock-negation-char-face' and the face of
+the same name to customize this.  Currently the cc-modes, 'sh-script-mode',
+'cperl-mode' and 'make-mode' support this.
 
 *** Font-Lock mode: in major modes such as Lisp mode, where some Emacs
 features assume that an open-paren in column 0 is always outside of
@@ -1065,39 +1065,39 @@ the open-paren is not in column 0.
 M-o M-o requests refontification.
 
 *** The default settings for JIT stealth lock parameters are changed.
-The default value for the user option jit-lock-stealth-time is now nil
-instead of 3.  This setting of jit-lock-stealth-time disables stealth
+The default value for the user option 'jit-lock-stealth-time' is now nil
+instead of 3.  This setting of 'jit-lock-stealth-time' disables stealth
 fontification: on today's machines, it may be a bug in font lock
 patterns if fontification otherwise noticeably degrades interactivity.
 If you find movement in infrequently visited buffers sluggish (and the
 major mode maintainer has no better idea), customizing
-jit-lock-stealth-time to a non-nil value will let Emacs fontify
+'jit-lock-stealth-time' to a non-nil value will let Emacs fontify
 buffers in the background when it considers the system to be idle.
-jit-lock-stealth-nice is now 0.5 instead of 0.125 which is supposed to
+'jit-lock-stealth-nice' is now 0.5 instead of 0.125 which is supposed to
 cause less load than the old defaults.
 
-*** jit-lock can now be delayed with `jit-lock-defer-time'.
+*** jit-lock can now be delayed with 'jit-lock-defer-time'.
 
 If this variable is non-nil, its value should be the amount of Emacs
 idle time in seconds to wait before starting fontification.  For
-example, if you set `jit-lock-defer-time' to 0.25, fontification will
+example, if you set 'jit-lock-defer-time' to 0.25, fontification will
 only happen after 0.25s of idle time.
 
 *** contextual refontification is now separate from stealth fontification.
 
-jit-lock-defer-contextually is renamed jit-lock-contextually and
-jit-lock-context-time determines the delay after which contextual
+'jit-lock-defer-contextually' is renamed 'jit-lock-contextually' and
+'jit-lock-context-time' determines the delay after which contextual
 refontification takes place.
 
 *** lazy-lock is considered obsolete.
 
-The `lazy-lock' package is superseded by `jit-lock' and is considered
-obsolete.  `jit-lock' is activated by default; if you wish to continue
-using `lazy-lock', activate it in your ~/.emacs like this:
+The 'lazy-lock' package is superseded by 'jit-lock' and is considered
+obsolete.  'jit-lock' is activated by default; if you wish to continue
+using 'lazy-lock', activate it in your ~/.emacs like this:
   (setq font-lock-support-mode 'lazy-lock-mode)
 
-If you invoke `lazy-lock-mode' directly rather than through
-`font-lock-support-mode', it now issues a warning:
+If you invoke 'lazy-lock-mode' directly rather than through
+'font-lock-support-mode', it now issues a warning:
   "Use font-lock-support-mode rather than calling lazy-lock-mode"
 
 ** Menu support:
@@ -1116,7 +1116,7 @@ and "Open File...".  "Open File..." now opens only 
existing files.  This is
 to support existing GUI file selection dialogs better.
 
 *** The file selection dialog for Gtk+, Mac, W32 and Motif/LessTif can be
-disabled by customizing the variable `use-file-dialog'.
+disabled by customizing the variable 'use-file-dialog'.
 
 *** The pop up menus for Lucid now stay up if you do a fast click and can
 be navigated with the arrow keys (like Gtk+, Mac and W32).
@@ -1127,41 +1127,41 @@ the arrow keys, select with the return key and cancel 
with the escape keys.
 
 *** The Lucid menus can display multilingual text in your locale.  You have
 to explicitly specify a fontSet resource for this to work, for example
-`-xrm "Emacs*fontSet:  -*-helvetica-medium-r-*--*-120-*-*-*-*-*-*,*"'.
+'-xrm "Emacs*fontSet:  -*-helvetica-medium-r-*--*-120-*-*-*-*-*-*,*"'.
 
 *** Dialogs for Lucid/Athena and LessTif/Motif now pop down on pressing
 ESC, like they do for Gtk+, Mac and W32.
 
 *** For the Gtk+ version, you can make Emacs use the old file dialog
-by setting the variable `x-gtk-use-old-file-dialog' to t.  Default is to use
+by setting the variable 'x-gtk-use-old-file-dialog' to t.  Default is to use
 the new dialog.
 
 *** You can exit dialog windows and menus by typing C-g.
 
 ** Buffer Menu changes:
 
-*** The new options `buffers-menu-show-directories' and
-`buffers-menu-show-status' let you control how buffers are displayed
+*** The new options 'buffers-menu-show-directories' and
+'buffers-menu-show-status' let you control how buffers are displayed
 in the menu dropped down when you click "Buffers" from the menu bar.
 
-`buffers-menu-show-directories' controls whether the menu displays
+'buffers-menu-show-directories' controls whether the menu displays
 leading directories as part of the file name visited by the buffer.
-If its value is `unless-uniquify', the default, directories are
+If its value is 'unless-uniquify', the default, directories are
 shown unless uniquify-buffer-name-style' is non-nil.  The value of nil
 and t turn the display of directories off and on, respectively.
 
-`buffers-menu-show-status' controls whether the Buffers menu includes
+'buffers-menu-show-status' controls whether the Buffers menu includes
 the modified and read-only status of the buffers.  By default it is
 t, and the status is shown.
 
 Setting these variables directly does not take effect until next time
 the Buffers menu is regenerated.
 
-*** New command `Buffer-menu-toggle-files-only' toggles display of file
+*** New command 'Buffer-menu-toggle-files-only' toggles display of file
 buffers only in the Buffer Menu.  It is bound to T in Buffer Menu
 mode.
 
-*** `buffer-menu' and `list-buffers' now list buffers whose names begin
+*** 'buffer-menu' and 'list-buffers' now list buffers whose names begin
 with a space, when those buffers are visiting files.  Normally buffers
 whose names begin with space are omitted.
 
@@ -1174,12 +1174,12 @@ click to follow a link, whereas most other applications 
use a Mouse-1
 click for both purposes, depending on whether you click outside or
 inside a link.  Now the behavior of a Mouse-1 click has been changed
 to match this context-sensitive dual behavior.  (If you prefer the old
-behavior, set the user option `mouse-1-click-follows-link' to nil.)
+behavior, set the user option 'mouse-1-click-follows-link' to nil.)
 
 Depending on the current mode, a Mouse-2 click in Emacs can do much
 more than just follow a link, so the new Mouse-1 behavior is only
 activated for modes which explicitly mark a clickable text as a "link"
-(see the new function `mouse-on-link-p' for details).  The Lisp
+(see the new function 'mouse-on-link-p' for details).  The Lisp
 packages that are included in release 22.1 have been adapted to do
 this, but external packages may not yet support this.  However, there
 is no risk in using such packages, as the worst thing that could
@@ -1195,9 +1195,9 @@ Dragging the Mouse-1 inside a link still performs the 
original
 drag-mouse-1 action, typically copy the text.
 
 You can customize the new Mouse-1 behavior via the new user options
-`mouse-1-click-follows-link' and `mouse-1-click-in-non-selected-windows'.
+'mouse-1-click-follows-link' and 'mouse-1-click-in-non-selected-windows'.
 
-*** If you set the new variable `mouse-autoselect-window' to a non-nil
+*** If you set the new variable 'mouse-autoselect-window' to a non-nil
 value, windows are automatically selected as you move the mouse from
 one Emacs window to another, even within a frame.  A minibuffer window
 can be selected only when it is active.
@@ -1205,43 +1205,44 @@ can be selected only when it is active.
 *** On X, when the window manager requires that you click on a frame to
 select it (give it focus), the selected window and cursor position
 normally changes according to the mouse click position.  If you set
-the variable x-mouse-click-focus-ignore-position to t, the selected
+the variable 'x-mouse-click-focus-ignore-position' to t, the selected
 window and cursor position do not change when you click on a frame
 to give it focus.
 
 *** Emacs normally highlights mouse sensitive text whenever the mouse
-is over the text.  By setting the new variable `mouse-highlight', you
+is over the text.  By setting the new variable 'mouse-highlight', you
 can optionally enable mouse highlighting only after you move the
 mouse, so that highlighting disappears when you press a key.  You can
 also disable mouse highlighting.
 
 *** You can now customize if selecting a region by dragging the mouse
-shall not copy the selected text to the kill-ring by setting the new
-variable mouse-drag-copy-region to nil.
+shall not copy the selected text to the 'kill-ring' by setting the new
+variable 'mouse-drag-copy-region' to nil.
 
-*** Under X, mouse-wheel-mode is turned on by default.
+*** Under X, 'mouse-wheel-mode' is turned on by default.
 
 *** Emacs ignores mouse-2 clicks while the mouse wheel is being moved.
 
 People tend to push the mouse wheel (which counts as a mouse-2 click)
 unintentionally while turning the wheel, so these clicks are now
-ignored.  You can customize this with the mouse-wheel-click-event and
-mouse-wheel-inhibit-click-time variables.
+ignored.  You can customize this with the 'mouse-wheel-click-event' and
+'mouse-wheel-inhibit-click-time' variables.
 
 *** mouse-wheels can now scroll a specific fraction of the window
-(rather than a fixed number of lines) and the scrolling is `progressive'.
+(rather than a fixed number of lines) and the scrolling is 'progressive'.
 
 ** Multilingual Environment (Mule) changes:
 
-*** You can disable character translation for a file using the -*-
-construct.  Include `enable-character-translation: nil' inside the
+*** You can disable character translation for a file using
+the 'enable-character-translation' variable set in the -*-
+construct.  Include 'enable-character-translation: nil' inside the
 -*-...-*- to disable any character translation that may happen by
 various global and per-coding-system translation tables.  You can also
 specify it in a local variable list at the end of the file.  For
 shortcut, instead of using this long variable name, you can append the
 character "!" at the end of coding-system name specified in -*-
 construct or in a local variable list.  For example, if a file has the
-following header, it is decoded by the coding system `iso-latin-1'
+following header, it is decoded by the coding system 'iso-latin-1'
 without any character translation:
 ;; -*- coding: iso-latin-1!; -*-
 
@@ -1255,32 +1256,32 @@ default in some locale (e.g. vi_VN).
 current locale settings if you are not using a window system.  This
 can mean that the META key doesn't work but generates non-ASCII
 characters instead, depending on how the terminal (or terminal
-emulator) works.  Use `set-keyboard-coding-system' (or customize
+emulator) works.  Use 'set-keyboard-coding-system' (or customize
 keyboard-coding-system) if you prefer META to work (the old default)
 or if the locale doesn't describe the character set actually generated
-by the keyboard.  See Info node `Unibyte Mode'.
+by the keyboard.  See Info node 'Unibyte Mode'.
 
-*** The new command `set-file-name-coding-system' (C-x RET F) sets
+*** The new command 'set-file-name-coding-system' (C-x RET F) sets
 coding system for encoding and decoding file names.  A new menu item
 (Options->Mule->Set Coding Systems->For File Name) invokes this
 command.
 
-*** The new command `revert-buffer-with-coding-system' (C-x RET r)
+*** The new command 'revert-buffer-with-coding-system' (C-x RET r)
 revisits the current file using a coding system that you specify.
 
-*** New command `recode-region' decodes the region again by a specified
+*** New command 'recode-region' decodes the region again by a specified
 coding system.
 
-*** The new command `recode-file-name' changes the encoding of the name
+*** The new command 'recode-file-name' changes the encoding of the name
 of a file.
 
-*** New command `ucs-insert' inserts a character specified by its
+*** New command 'ucs-insert' inserts a character specified by its
 Unicode code point or character name.
 
 *** New command quail-show-key shows what key (or key sequence) to type
 in the current input method to input a character at point.
 
-*** Limited support for character `unification' has been added.
+*** Limited support for character 'unification' has been added.
 Emacs now knows how to translate between different representations of
 the same characters in various Emacs charsets according to standard
 Unicode mappings.  This applies mainly to characters in the ISO 8859
@@ -1317,7 +1318,7 @@ either Unicode (the mule-unicode charsets) or the 
iso-8859 charsets,
 when possible.  The latter are more space-efficient.
   This is controlled by user option utf-fragment-on-decoding.
 
-*** Improved Thai support.  A new minor mode `thai-word-mode' (which is
+*** Improved Thai support.  A new minor mode 'thai-word-mode' (which is
 automatically activated if you select Thai as a language
 environment) changes key bindings of most word-oriented commands to
 versions which recognize Thai words.  Affected commands are
@@ -1335,33 +1336,33 @@ but currently only Devanagari, Malayalam and Tamil are 
supported.
 
 *** The utf-8/16 coding systems have been enhanced.
 By default, untranslatable utf-8 sequences are simply composed into
-single quasi-characters.  User option `utf-translate-cjk-mode' (it is
+single quasi-characters.  User option 'utf-translate-cjk-mode' (it is
 turned on by default) arranges to translate many utf-8 CJK character
 sequences into real Emacs characters in a similar way to the Mule-UCS
 system.  As this loads a fairly big data on demand, people who are not
 interested in CJK characters may want to customize it to nil.
 You can augment/amend the CJK translation via hash tables
-`ucs-mule-cjk-to-unicode' and `ucs-unicode-to-mule-cjk'.  The utf-8
+'ucs-mule-cjk-to-unicode' and 'ucs-unicode-to-mule-cjk'.  The utf-8
 coding system now also encodes characters from most of Emacs's
 one-dimensional internal charsets, specifically the ISO-8859 ones.
 The utf-16 coding system is affected similarly.
 
-*** A UTF-7 coding system is available in the library `utf-7'.
+*** A UTF-7 coding system is available in the library 'utf-7'.
 
-*** A new coding system `euc-tw' has been added for traditional Chinese
+*** A new coding system 'euc-tw' has been added for traditional Chinese
 in CNS encoding; it accepts both Big 5 and CNS as input; on saving,
 Big 5 is then converted to CNS.
 
-*** Many new coding systems are available in the `code-pages' library.
+*** Many new coding systems are available in the 'code-pages' library.
 These include complete versions of most of those in codepage.el, based
-on Unicode mappings.  `codepage-setup' is now obsolete and is used
+on Unicode mappings.  'codepage-setup' is now obsolete and is used
 only in the MS-DOS port of Emacs.  All coding systems defined in
-`code-pages' are auto-loaded.
+'code-pages' are auto-loaded.
 
-*** New variable `utf-translate-cjk-unicode-range' controls which
-Unicode characters to translate in `utf-translate-cjk-mode'.
+*** New variable 'utf-translate-cjk-unicode-range' controls which
+Unicode characters to translate in 'utf-translate-cjk-mode'.
 
-*** iso-10646-1 (`Unicode') fonts can be used to display any range of
+*** iso-10646-1 ('Unicode') fonts can be used to display any range of
 characters encodable by the utf-8 coding system.  Just specify the
 fontset appropriately.
 
@@ -1379,7 +1380,7 @@ faces.
 
 *** The face-customization widget has been reworked to be less confusing.
 In particular, when you enable a face attribute using the corresponding
-check-box, there's no longer a redundant `*' option in value selection
+check-box, there's no longer a redundant '*' option in value selection
 for that attribute; the values you can choose are only those which make
 sense for the attribute.  When an attribute is de-selected by unchecking
 its check-box, then the (now ignored, but still present temporarily in
@@ -1392,24 +1393,24 @@ under the "[State]" button.
 
 ** Dired mode:
 
-*** In Dired's ! command (dired-do-shell-command), `*' and `?' now
+*** In Dired's ! command (dired-do-shell-command), '*' and '?' now
 control substitution of the file names only when they are surrounded
 by whitespace.  This means you can now use them as shell wildcards
-too.  If you want to use just plain `*' as a wildcard, type `*""'; the
+too.  If you want to use just plain '*' as a wildcard, type '*""'; the
 double quotes make no difference in the shell, but they prevent
-special treatment in `dired-do-shell-command'.
+special treatment in 'dired-do-shell-command'.
 
-*** The Dired command `dired-goto-file' is now bound to j, not M-g.
+*** The Dired command 'dired-goto-file' is now bound to j, not M-g.
 This is to avoid hiding the global key binding of M-g.
 
-*** New faces dired-header, dired-mark, dired-marked, dired-flagged,
-dired-ignored, dired-directory, dired-symlink, dired-warning
+*** New faces 'dired-header', 'dired-mark', 'dired-marked', 'dired-flagged',
+'dired-ignored', 'dired-directory', 'dired-symlink', 'dired-warning'
 introduced for Dired mode instead of font-lock faces.
 
-*** New Dired command `dired-compare-directories' marks files
+*** New Dired command 'dired-compare-directories' marks files
 with different file attributes in two dired buffers.
 
-*** New Dired command `dired-do-touch' (bound to T) changes timestamps
+*** New Dired command 'dired-do-touch' (bound to T) changes timestamps
 of marked files with the value entered in the minibuffer.
 
 *** In Dired, the w command now stores the current line's file name
@@ -1418,13 +1419,13 @@ into the kill ring.  With a zero prefix arg, it stores 
the absolute file name.
 *** In Dired-x, Omitting files is now a minor mode, dired-omit-mode.
 
 The mode toggling command is bound to M-o.  A new command
-dired-mark-omitted, bound to * O, marks omitted files.  The variable
-dired-omit-files-p is obsoleted, use the mode toggling function
+'dired-mark-omitted', bound to * O, marks omitted files.  The variable
+'dired-omit-files-p' is obsoleted, use the mode toggling function
 instead.
 
-*** The variables dired-free-space-program and dired-free-space-args
-have been renamed to directory-free-space-program and
-directory-free-space-args, and they now apply whenever Emacs puts a
+*** The variables 'dired-free-space-program' and 'dired-free-space-args'
+have been renamed to 'directory-free-space-program' and
+'directory-free-space-args', and they now apply whenever Emacs puts a
 directory listing into a buffer.
 
 ** Comint changes:
@@ -1436,33 +1437,33 @@ to know whether they are started inside Emacs should 
check INSIDE_EMACS
 instead of EMACS.
 
 *** The comint prompt can now be made read-only, using the new user
-option `comint-prompt-read-only'.  This is not enabled by default,
+option 'comint-prompt-read-only'.  This is not enabled by default,
 except in IELM buffers.  The read-only status of IELM prompts can be
-controlled with the new user option `ielm-prompt-read-only', which
-overrides `comint-prompt-read-only'.
+controlled with the new user option 'ielm-prompt-read-only', which
+overrides 'comint-prompt-read-only'.
 
-The new commands `comint-kill-whole-line' and `comint-kill-region'
+The new commands 'comint-kill-whole-line' and 'comint-kill-region'
 support editing comint buffers with read-only prompts.
 
-`comint-kill-whole-line' is like `kill-whole-line', but ignores both
+'comint-kill-whole-line' is like 'kill-whole-line', but ignores both
 read-only and field properties.  Hence, it always kill entire
 lines, including any prompts.
 
-`comint-kill-region' is like `kill-region', except that it ignores
+'comint-kill-region' is like 'kill-region', except that it ignores
 read-only properties, if it is safe to do so.  This means that if any
 part of a prompt is deleted, then the entire prompt must be deleted
 and that all prompts must stay at the beginning of a line.  If this is
-not the case, then `comint-kill-region' behaves just like
-`kill-region' if read-only properties are involved: it copies the text
+not the case, then 'comint-kill-region' behaves just like
+'kill-region' if read-only properties are involved: it copies the text
 to the kill-ring, but does not delete it.
 
-*** The new command `comint-insert-previous-argument' in comint-derived
+*** The new command 'comint-insert-previous-argument' in comint-derived
 modes (shell-mode, etc.) inserts arguments from previous command lines,
-like bash's `ESC .' binding.  It is bound by default to `C-c .', but
+like bash's 'ESC .' binding.  It is bound by default to 'C-c .', but
 otherwise behaves quite similarly to the bash version.
 
-*** `comint-use-prompt-regexp-instead-of-fields' has been renamed
-`comint-use-prompt-regexp'.  The old name has been kept as an alias,
+*** 'comint-use-prompt-regexp-instead-of-fields' has been renamed
+'comint-use-prompt-regexp'.  The old name has been kept as an alias,
 but declared obsolete.
 
 ** M-x Compile changes:
@@ -1471,36 +1472,36 @@ but declared obsolete.
 
 Quite a few more kinds of messages are recognized.  Messages that are
 recognized as warnings or informational come in orange or green, instead of
-red.  Informational messages are by default skipped with `next-error'
-(controlled by `compilation-skip-threshold').
+red.  Informational messages are by default skipped with 'next-error'
+(controlled by 'compilation-skip-threshold').
 
 Location data is collected on the fly as the *compilation* buffer changes.
 This means you could modify messages to make them point to different files.
 This also means you can not go to locations of messages you may have deleted.
 
-The variable `compilation-error-regexp-alist' has now become customizable.  If
+The variable 'compilation-error-regexp-alist' has now become customizable.  If
 you had added your own regexps to this, you'll probably need to include a
-leading `^', otherwise they'll match anywhere on a line.  There is now also a
-`compilation-mode-font-lock-keywords' and it nicely handles all the checks
+leading '^', otherwise they'll match anywhere on a line.  There is now also a
+'compilation-mode-font-lock-keywords' and it nicely handles all the checks
 that configure outputs and -o options so you see at a glance where you are.
 
 The new file etc/compilation.txt gives examples of each type of message.
 
-*** New user option `compilation-environment'.
+*** New user option 'compilation-environment'.
 This option allows you to specify environment variables for inferior
 compilation processes without affecting the environment that all
 subprocesses inherit.
 
-*** New user option `compilation-disable-input'.
+*** New user option 'compilation-disable-input'.
 If this is non-nil, send end-of-file as compilation process input.
 
-*** New options `next-error-highlight' and `next-error-highlight-no-select'
+*** New options 'next-error-highlight' and 'next-error-highlight-no-select'
 specify the method of highlighting of the corresponding source line
-in new face `next-error'.
+in new face 'next-error'.
 
-*** A new minor mode `next-error-follow-minor-mode' can be used in
-compilation-mode, grep-mode, occur-mode, and diff-mode (i.e. all the
-modes that can use `next-error').  In this mode, cursor motion in the
+*** A new minor mode 'next-error-follow-minor-mode' can be used in
+'compilation-mode', 'grep-mode', 'occur-mode', and 'diff-mode' (i.e. all the
+modes that can use 'next-error').  In this mode, cursor motion in the
 buffer causes automatic display in another window of the corresponding
 matches, compilation errors, etc.  This minor mode can be toggled with
 C-c C-f.
@@ -1508,7 +1509,7 @@ C-c C-f.
 *** When the left fringe is displayed, an arrow points to current message in
 the compilation buffer.
 
-*** The new variable `compilation-context-lines' controls lines of leading
+*** The new variable 'compilation-context-lines' controls lines of leading
 context before the current message.  If nil and the left fringe is displayed,
 it doesn't scroll the compilation output window.  If there is no left fringe,
 no arrow is displayed and a value of nil means display the message at the top
@@ -1516,9 +1517,9 @@ of the window.
 
 ** Occur mode changes:
 
-*** The new command `multi-occur' is just like `occur', except it can
+*** The new command 'multi-occur' is just like 'occur', except it can
 search multiple buffers.  There is also a new command
-`multi-occur-in-matching-buffers' which allows you to specify the
+'multi-occur-in-matching-buffers' which allows you to specify the
 buffers to search by their filenames or buffer names.  Internally,
 Occur mode has been rewritten, and now uses font-lock, among other
 changes.
@@ -1526,7 +1527,7 @@ changes.
 *** You can now use next-error (C-x `) and previous-error to advance to
 the next/previous matching line found by M-x occur.
 
-*** In the *Occur* buffer, `o' switches to it in another window, and
+*** In the *Occur* buffer, 'o' switches to it in another window, and
 C-o displays the current line's occurrence in another window without
 switching to it.
 
@@ -1537,75 +1538,75 @@ switching to it.
 There's a new separate package grep.el, with its own submenu and
 customization group.
 
-*** `grep-find' is now also available under the name `find-grep' where
-people knowing `find-grep-dired' would probably expect it.
+*** 'grep-find' is now also available under the name 'find-grep' where
+people knowing 'find-grep-dired' would probably expect it.
 
-*** New commands `lgrep' (local grep) and `rgrep' (recursive grep) are
-more user-friendly versions of `grep' and `grep-find', which prompt
+*** New commands 'lgrep' (local grep) and 'rgrep' (recursive grep) are
+more user-friendly versions of 'grep' and 'grep-find', which prompt
 separately for the regular expression to match, the files to search,
 and the base directory for the search.  Case sensitivity of the
-search is controlled by the current value of `case-fold-search'.
+search is controlled by the current value of 'case-fold-search'.
 
 These commands build the shell commands based on the new variables
-`grep-template' (lgrep) and `grep-find-template' (rgrep).
+'grep-template' (lgrep) and 'grep-find-template' (rgrep).
 
-The files to search can use aliases defined in `grep-files-aliases'.
+The files to search can use aliases defined in 'grep-files-aliases'.
 
-Subdirectories listed in `grep-find-ignored-directories' such as those
+Subdirectories listed in 'grep-find-ignored-directories' such as those
 typically used by various version control systems, like CVS and arch,
-are automatically skipped by `rgrep'.
+are automatically skipped by 'rgrep'.
 
 *** The grep commands provide highlighting support.
 
 Hits are fontified in green, and hits in binary files in orange.  Grep buffers
 can be saved and automatically revisited.
 
-*** New option `grep-highlight-matches' highlights matches in *grep*
+*** New option 'grep-highlight-matches' highlights matches in *grep*
 buffer.  It uses a special feature of some grep programs which accept
 --color option to output markers around matches.  When going to the next
-match with `next-error' the exact match is highlighted in the source
-buffer.  Otherwise, if `grep-highlight-matches' is nil, the whole
+match with 'next-error' the exact match is highlighted in the source
+buffer.  Otherwise, if 'grep-highlight-matches' is nil, the whole
 source line is highlighted.
 
 *** New key bindings in grep output window:
 SPC and DEL scrolls window up and down.  C-n and C-p moves to next and
 previous match in the grep window.  RET jumps to the source line of
-the current match.  `n' and `p' shows next and previous match in
-other window, but does not switch buffer.  `{' and `}' jumps to the
+the current match.  'n' and 'p' shows next and previous match in
+other window, but does not switch buffer.  '{' and '}' jumps to the
 previous or next file in the grep output.  TAB also jumps to the next
 file.
 
-*** M-x grep now tries to avoid appending `/dev/null' to the command line
-by using GNU grep `-H' option instead.  M-x grep automatically
+*** M-x grep now tries to avoid appending '/dev/null' to the command line
+by using GNU grep '-H' option instead.  M-x grep automatically
 detects whether this is possible or not the first time it is invoked.
-When `-H' is used, the grep command line supplied by the user is passed
+When '-H' is used, the grep command line supplied by the user is passed
 unchanged to the system to execute, which allows more complicated
 command lines to be used than was possible before.
 
-*** The new variables `grep-window-height' and `grep-scroll-output' override
+*** The new variables 'grep-window-height' and 'grep-scroll-output' override
 the corresponding compilation mode settings, for grep commands only.
 
 ** Cursor display changes:
 
 *** Emacs can produce an underscore-like (horizontal bar) cursor.
-The underscore cursor is set by putting `(cursor-type . hbar)' in
-default-frame-alist.  It supports variable heights, like the `bar'
+The underscore cursor is set by putting '(cursor-type . hbar)' in
+'default-frame-alist'.  It supports variable heights, like the 'bar'
 cursor does.
 
-*** The variable `cursor-in-non-selected-windows' can now be set to any
+*** The variable 'cursor-in-non-selected-windows' can now be set to any
 of the recognized cursor types.
 
 *** Display of hollow cursors now obeys the buffer-local value (if any)
-of `cursor-in-non-selected-windows' in the buffer that the cursor
+of 'cursor-in-non-selected-windows' in the buffer that the cursor
 appears in.
 
-*** On text terminals, the variable `visible-cursor' controls whether Emacs
+*** On text terminals, the variable 'visible-cursor' controls whether Emacs
 uses the "very visible" cursor (the default) or the normal cursor.
 
 *** The X resource cursorBlink can be used to turn off cursor blinking.
 
 *** On X, MS Windows, and Mac OS, the blinking cursor's "off" state is
-now controlled by the variable `blink-cursor-alist'.
+now controlled by the variable 'blink-cursor-alist'.
 
 ** X Windows Support:
 
@@ -1614,8 +1615,8 @@ opens it, dropping text inserts the text.  Dropping a 
file on a dired
 buffer copies or moves the file to that directory.
 
 *** Under X11, it is possible to swap Alt and Meta (and Super and Hyper).
-The new variables `x-alt-keysym', `x-hyper-keysym', `x-meta-keysym',
-and `x-super-keysym' can be used to choose which keysyms Emacs should
+The new variables 'x-alt-keysym', 'x-hyper-keysym', 'x-meta-keysym',
+and 'x-super-keysym' can be used to choose which keysyms Emacs should
 use for the modifiers.  For example, the following two lines swap
 Meta and Alt:
     (setq x-alt-keysym 'meta)
@@ -1624,10 +1625,10 @@ Meta and Alt:
 *** The X resource useXIM can be used to turn off use of XIM, which can
 speed up Emacs with slow networking to the X server.
 
-If the configure option `--without-xim' was used to turn off use of
+If the configure option '--without-xim' was used to turn off use of
 XIM by default, the X resource useXIM can be used to turn it on.
 
-*** The new variable `x-select-request-type' controls how Emacs
+*** The new variable 'x-select-request-type' controls how Emacs
 requests X selection.  The default value is nil, which means that
 Emacs requests X selection with types COMPOUND_TEXT and UTF8_STRING,
 and use the more appropriately result.
@@ -1658,13 +1659,13 @@ mode for a tty color support.  It is meant to be used 
on character
 terminals whose capabilities are not set correctly in the terminal
 database, or with terminal emulators which support colors, but don't
 set the TERM environment variable to a name of a color-capable
-terminal.  "emacs --color" uses the same color commands as GNU `ls'
+terminal.  "emacs --color" uses the same color commands as GNU 'ls'
 when invoked with "ls --color", so if your terminal can support colors
 in "ls --color", it will support "emacs --color" as well.  See the
 user manual for the possible values of the MODE parameter.
 
 *** Emacs now supports several character terminals which provide more
-than 8 colors.  For example, for `xterm', 16-color, 88-color, and
+than 8 colors.  For example, for 'xterm', 16-color, 88-color, and
 256-color modes are supported.  Emacs automatically notes at startup
 the extended number of colors, and defines the appropriate entries for
 all of these colors.
@@ -1675,16 +1676,16 @@ faces when running on a color terminal, including 16-, 
88-, and
 88-color or 256-color xterm, you will see essentially the same face
 colors as on X.
 
-*** There's a new support for colors on `rxvt' terminal emulator.
+*** There's a new support for colors on 'rxvt' terminal emulator.
 
 ** ebnf2ps changes:
 
-*** New option `ebnf-arrow-extra-width' which specify extra width for arrow
+*** New option 'ebnf-arrow-extra-width' which specify extra width for arrow
 shape drawing.
 The extra width is used to avoid that the arrowhead and the terminal border
-overlap.  It depends on `ebnf-arrow-shape' and `ebnf-line-width'.
+overlap.  It depends on 'ebnf-arrow-shape' and 'ebnf-line-width'.
 
-*** New option `ebnf-arrow-scale' which specify the arrow scale.
+*** New option 'ebnf-arrow-scale' which specify the arrow scale.
 Values lower than 1.0, shrink the arrow.
 Values greater than 1.0, expand the arrow.
 
@@ -1695,11 +1696,11 @@ Values greater than 1.0, expand the arrow.
 The new cua package provides CUA-like keybindings using C-x for
 cut (kill), C-c for copy, C-v for paste (yank), and C-z for undo.
 With cua, the region can be set and extended using shifted movement
-keys (like pc-selection-mode) and typed text replaces the active
-region (like delete-selection-mode).  Do not enable these modes with
-cua-mode.  Customize the variable `cua-mode' to enable cua.
+keys (like 'pc-selection-mode') and typed text replaces the active
+region (like 'delete-selection-mode').  Do not enable these modes with
+cua-mode.  Customize the variable 'cua-mode' to enable cua.
 
-The cua-selection-mode enables the CUA keybindings for the region but
+The 'cua-selection-mode' enables the CUA keybindings for the region but
 does not change the bindings for C-z/C-x/C-c/C-v. It can be used as a
 replacement for pc-selection-mode.
 
@@ -1708,7 +1709,7 @@ rectangle highlighting: Use C-return to start a 
rectangle, extend it
 using the movement commands (or mouse-3), and cut or copy it using C-x
 or C-c (using C-w and M-w also works).
 
-Use M-o and M-c to `open' or `close' the rectangle, use M-b or M-f, to
+Use M-o and M-c to 'open' or 'close' the rectangle, use M-b or M-f, to
 fill it with blanks or another character, use M-u or M-l to upcase or
 downcase the rectangle, use M-i to increment the numbers in the
 rectangle, use M-n to fill the rectangle with a numeric sequence (such
@@ -1731,7 +1732,7 @@ commentary in cua-base.el for more global mark related 
commands.
 The features of cua also works with the standard Emacs bindings for
 kill, copy, yank, and undo.  If you want to use cua mode, but don't
 want the C-x, C-c, C-v, and C-z bindings, you can customize the
-`cua-enable-cua-keys' variable.
+'cua-enable-cua-keys' variable.
 
 Note: This version of cua mode is not backwards compatible with older
 versions of cua.el and cua-mode.el.  To ensure proper operation, you
@@ -1745,13 +1746,13 @@ files.  But whereas Ange-FTP uses FTP to access the 
remote host,
 Tramp uses a shell connection.  The shell connection is always used
 for filename completion and directory listings and suchlike, but for
 the actual file transfer, you can choose between the so-called
-`inline' methods (which transfer the files through the shell
-connection using base64 or uu encoding) and the `out-of-band' methods
-(which invoke an external copying program such as `rcp' or `scp' or
-`rsync' to do the copying).
+'inline' methods (which transfer the files through the shell
+connection using base64 or uu encoding) and the 'out-of-band' methods
+(which invoke an external copying program such as 'rcp' or 'scp' or
+'rsync' to do the copying).
 
-Shell connections can be acquired via `rsh', `ssh', `telnet' and also
-`su' and `sudo'.  Ange-FTP is still supported via the `ftp' method.
+Shell connections can be acquired via 'rsh', 'ssh', 'telnet' and also
+'su' and 'sudo'.  Ange-FTP is still supported via the 'ftp' method.
 
 If you want to disable Tramp you should set
 
@@ -1760,7 +1761,7 @@ If you want to disable Tramp you should set
 Removing Tramp, and re-enabling Ange-FTP, can be achieved by M-x
 tramp-unload-tramp.
 
-** The image-dired.el package allows you to easily view, tag and in
+** The 'image-dired' package allows you to easily view, tag and in
 other ways manipulate image files and their thumbnails, using dired as
 the main interface.  Image-Dired provides functionality to generate
 simple image galleries.
@@ -1775,11 +1776,11 @@ between viewing the image and viewing the text using 
C-c C-c.
 ** Calc is now part of the Emacs distribution.
 
 Calc is an advanced desk calculator and mathematical tool written in
-Emacs Lisp.  The prefix for Calc has been changed to `C-x *' and Calc
-can be started with `C-x * *'.  The Calc manual is separate from the
+Emacs Lisp.  The prefix for Calc has been changed to 'C-x *' and Calc
+can be started with 'C-x * *'.  The Calc manual is separate from the
 Emacs manual; within Emacs, type "C-h i m calc RET" to read the
-manual.  A reference card is available in `etc/calccard.tex' and
-`etc/calccard.ps'.
+manual.  A reference card is available in 'etc/calccard.tex' and
+'etc/calccard.ps'.
 
 ** Org mode is now part of the Emacs distribution
 
@@ -1791,9 +1792,9 @@ capabilities.
 The Org mode table editor can be integrated into any major mode by
 activating the minor mode, Orgtbl mode.
 
-The documentation for org-mode is in a separate manual; within Emacs,
+The documentation for 'org-mode' is in a separate manual; within Emacs,
 type "C-h i m org RET" to read that manual.  A reference card is
-available in `etc/orgcard.tex' and `etc/orgcard.ps'.
+available in 'etc/orgcard.tex' and 'etc/orgcard.ps'.
 
 ** ERC is now part of the Emacs distribution.
 
@@ -1818,7 +1819,7 @@ To start an IRC session using the default parameters, 
type M-x irc.
 If you type C-u M-x irc, it prompts you for the server, nick, port and
 startup channel parameters before connecting.
 
-** The new package ibuffer provides a powerful, completely
+** The new package 'ibuffer' provides a powerful, completely
 customizable replacement for buff-menu.el.
 
 ** Newsticker is now part of the Emacs distribution.
@@ -1838,12 +1839,12 @@ package to do interactive opening of files and 
directories in addition
 to interactive buffer switching.  Ido is a superset of iswitchb (with
 a few exceptions), so don't enable both packages.
 
-** The new global minor mode `file-name-shadow-mode' modifies the way
+** The new global minor mode 'file-name-shadow-mode' modifies the way
 filenames being entered by the user in the minibuffer are displayed, so
 that it's clear when part of the entered filename will be ignored due to
 Emacs' filename parsing rules.  The ignored portion can be made dim,
 invisible, or otherwise less visually noticeable.  The display method can
-be displayed by customizing the variable `file-name-shadow-properties'.
+be displayed by customizing the variable 'file-name-shadow-properties'.
 
 ** Emacs' keyboard macro facilities have been enhanced by the new
 kmacro package.
@@ -1870,9 +1871,9 @@ The C-x e command now automatically terminates the 
current macro
 before calling it, if used while defining a macro.
 
 In addition, when ending or calling a macro with C-x e, the macro can
-be repeated immediately by typing just the `e'.  You can customize
-this behavior via the variables kmacro-call-repeat-key and
-kmacro-call-repeat-with-arg.
+be repeated immediately by typing just the 'e'.  You can customize
+this behavior via the variables 'kmacro-call-repeat-key' and
+'kmacro-call-repeat-with-arg'.
 
 Keyboard macros can now be debugged and edited interactively.
 C-x C-k SPC steps through the last keyboard macro one key sequence
@@ -1884,21 +1885,21 @@ keypad typically has the digits 0 to 9, a decimal 
point, keys marked
 +, -, /, and *, an Enter key, and a NumLock toggle key.  The keypad
 package only controls the use of the digit and decimal keys.
 
-By customizing the variables `keypad-setup', `keypad-shifted-setup',
-`keypad-numlock-setup', and `keypad-numlock-shifted-setup', or by
-using the function `keypad-setup', you can rebind all digit keys and
+By customizing the variables 'keypad-setup', 'keypad-shifted-setup',
+'keypad-numlock-setup', and 'keypad-numlock-shifted-setup', or by
+using the function 'keypad-setup', you can rebind all digit keys and
 the decimal key of the keypad in one step for each of the four
 possible combinations of the Shift key state (not pressed/pressed) and
 the NumLock toggle state (off/on).
 
 The choices for the keypad keys in each of the above states are:
-`Plain numeric keypad' where the keys generates plain digits,
-`Numeric keypad with decimal key' where the character produced by the
+'Plain numeric keypad' where the keys generates plain digits,
+'Numeric keypad with decimal key' where the character produced by the
 decimal key can be customized individually (for internationalization),
-`Numeric Prefix Arg' where the keypad keys produce numeric prefix args
-for Emacs editing commands, `Cursor keys' and `Shifted Cursor keys'
+'Numeric Prefix Arg' where the keypad keys produce numeric prefix args
+for Emacs editing commands, 'Cursor keys' and 'Shifted Cursor keys'
 where the keys work like (shifted) arrow keys, home/end, etc., and
-`Unspecified/User-defined' where the keypad keys (kp-0, kp-1, etc.)
+'Unspecified/User-defined' where the keypad keys (kp-0, kp-1, etc.)
 are left unspecified and can be bound individually through the global
 or local keymaps.
 
@@ -1909,17 +1910,17 @@ the .emacs file, the normal Print item on the File menu 
is replaced
 with a Print sub-menu which allows you to preview output through
 ghostview, use ghostscript to print (if you don't have a PostScript
 printer) or send directly to printer a PostScript code generated by
-`ps-print' package.  Use M-x pr-help for more information.
+'ps-print' package.  Use M-x pr-help for more information.
 
 ** The new package longlines.el provides a minor mode for editing text
-files composed of long lines, based on the `use-hard-newlines'
+files composed of long lines, based on the 'use-hard-newlines'
 mechanism.  The long lines are broken up by inserting soft newlines,
 which are automatically removed when saving the file to disk or
 copying into the kill ring, clipboard, etc.  By default, Longlines
 mode inserts soft newlines automatically during editing, a behavior
 referred to as "soft word wrap" in other text editors.  This is
 similar to Refill mode, but more reliable.  To turn the word wrap
-feature off, set `longlines-auto-wrap' to nil.
+feature off, set 'longlines-auto-wrap' to nil.
 
 ** SES mode (ses-mode) is a new major mode for creating and editing
 spreadsheet files.  Besides the usual Emacs features (intuitive command
@@ -1927,7 +1928,7 @@ letters, undo, cell formulas in Lisp, plaintext files, 
etc.) it also offers
 viral immunity and import/export of tab-separated values.
 
 ** The new package table.el implements editable, WYSIWYG, embedded
-`text tables' in Emacs buffers.  It simulates the effect of putting
+'text tables' in Emacs buffers.  It simulates the effect of putting
 these tables in a special major mode.  The package emulates WYSIWYG
 table editing available in modern word processors.  The package also
 can generate a table source in typesetting and markup languages such
@@ -1950,17 +1951,17 @@ There is also Global Reveal mode which affects all 
buffers.
 
 ** New minor mode, Visible mode, toggles invisibility in the current buffer.
 When enabled, it makes all invisible text visible.  When disabled, it
-restores the previous value of `buffer-invisibility-spec'.
+restores the previous value of 'buffer-invisibility-spec'.
 
 ** The new package flymake.el does on-the-fly syntax checking of program
 source files.  See the Flymake's Info manual for more details.
 
 ** savehist saves minibuffer histories between sessions.
-To use this feature, turn on savehist-mode in your `.emacs' file.
+To use this feature, turn on 'savehist-mode' in your '.emacs' file.
 
-** The ruler-mode.el library provides a minor mode for displaying an
+** The 'ruler-mode' library provides a minor mode for displaying an
 "active" ruler in the header line.  You can use the mouse to visually
-change the `fill-column', `window-margins' and `tab-stop-list'
+change the 'fill-column', 'window-margins' and 'tab-stop-list'
 settings.
 
 ** The file t-mouse.el is now part of Emacs and provides access to mouse
@@ -1973,10 +1974,10 @@ paragraph will scroll the buffer by the respective 
amount of lines
 instead and point will be kept vertically fixed relative to window
 boundaries during scrolling.
 
-** The new global minor mode `size-indication-mode' (off by default)
+** The new global minor mode 'size-indication-mode' (off by default)
 shows the size of accessible part of the buffer on the mode line.
 
-** The new package conf-mode.el handles thousands of configuration files, with
+** The new package 'conf-mode' handles thousands of configuration files, with
 varying syntaxes for comments (;, #, //, /* */ or !), assignment (var = value,
 var : value, var value or keyword var value) and sections ([section] or
 section { }).  Many files under /etc/, or with suffixes like .cf through
@@ -1985,10 +1986,10 @@ recognized.
 
 ** GDB-Script-mode is used for files like .gdbinit.
 
-** The new package dns-mode.el adds syntax highlighting of DNS master files.
-It is a modern replacement for zone-mode.el, which is now obsolete.
+** The new package 'dns-mode' adds syntax highlighting of DNS master files.
+It is a modern replacement for 'zone-mode', which is now obsolete.
 
-** `cfengine-mode' is a major mode for editing GNU Cfengine
+** 'cfengine-mode' is a major mode for editing GNU Cfengine
 configuration files.
 
 ** The TCL package tcl-mode.el was replaced by tcl.el.
@@ -2012,10 +2013,10 @@ Info pages show embedded images, in Emacs frames with 
image support.
 Info documentation that includes images, processed with makeinfo
 version 4.7 or newer, compiles to Info pages with embedded images.
 
-*** `Info-index' offers completion.
+*** 'Info-index' offers completion.
 
 *** http and ftp links in Info are now operational: they look like cross
-references and following them calls `browse-url'.
+references and following them calls 'browse-url'.
 
 *** isearch in Info uses Info-search and searches through multiple nodes.
 
@@ -2023,43 +2024,43 @@ Before leaving the initial Info node isearch fails once 
with the error
 message [initial node], and with subsequent C-s/C-r continues through
 other nodes.  When isearch fails for the rest of the manual, it wraps
 around the whole manual to the top/final node.  The user option
-`Info-isearch-search' controls whether to use Info-search for isearch,
+'Info-isearch-search' controls whether to use Info-search for isearch,
 or the default isearch search function that wraps around the current
 Info node.
 
-*** New search commands: `Info-search-case-sensitively' (bound to S),
-`Info-search-backward', and `Info-search-next' which repeats the last
+*** New search commands: 'Info-search-case-sensitively' (bound to S),
+'Info-search-backward', and 'Info-search-next' which repeats the last
 search without prompting for a new search string.
 
-*** New command `info-apropos' searches the indices of the known
+*** New command 'info-apropos' searches the indices of the known
 Info files on your system for a string, and builds a menu of the
 possible matches.
 
-*** New command `Info-history-forward' (bound to r and new toolbar icon)
+*** New command 'Info-history-forward' (bound to r and new toolbar icon)
 moves forward in history to the node you returned from after using
-`Info-history-back' (renamed from `Info-last').
+'Info-history-back' (renamed from 'Info-last').
 
-*** New command `Info-history' (bound to L) displays a menu of visited nodes.
+*** New command 'Info-history' (bound to L) displays a menu of visited nodes.
 
-*** New command `Info-toc' (bound to T) creates a node with table of contents
+*** New command 'Info-toc' (bound to T) creates a node with table of contents
 from the tree structure of menus of the current Info file.
 
-*** New command `Info-copy-current-node-name' (bound to w) copies
+*** New command 'Info-copy-current-node-name' (bound to w) copies
 the current Info node name into the kill ring.  With a zero prefix
-arg, puts the node name inside the `info' function call.
+arg, puts the node name inside the 'info' function call.
 
-*** New face `info-xref-visited' distinguishes visited nodes from unvisited
-and a new option `Info-fontify-visited-nodes' to control this.
+*** New face 'info-xref-visited' distinguishes visited nodes from unvisited
+and a new option 'Info-fontify-visited-nodes' to control this.
 
-*** A numeric prefix argument of `info' selects an Info buffer
-with the number appended to the `*info*' buffer name (e.g. "*info*<2>").
+*** A numeric prefix argument of 'info' selects an Info buffer
+with the number appended to the '*info*' buffer name (e.g. "*info*<2>").
 
 *** Info now hides node names in menus and cross references by default.
 
 If you prefer the old behavior, you can set the new user option
-`Info-hide-note-references' to nil.
+'Info-hide-note-references' to nil.
 
-*** The default value for `Info-scroll-prefer-subnodes' is now nil.
+*** The default value for 'Info-scroll-prefer-subnodes' is now nil.
 
 ** Emacs server changes
 
@@ -2070,27 +2071,27 @@ If you prefer the old behavior, you can set the new 
user option
        % emacsclient -s foo file1
        % emacsclient -s bar file2
 
-*** The `emacsclient' command understands the options `--eval' and
-`--display' which tell Emacs respectively to evaluate the given Lisp
+*** The 'emacsclient' command understands the options '--eval' and
+'--display' which tell Emacs respectively to evaluate the given Lisp
 expression and to use the given display when visiting files.
 
-*** User option `server-mode' can be used to start a server process.
+*** User option 'server-mode' can be used to start a server process.
 
 ** Locate changes
 
 *** By default, reverting the *Locate* buffer now just runs the last
-`locate' command back over again without offering to update the locate
+'locate' command back over again without offering to update the locate
 database (which normally only works if you have root privileges).  If
 you prefer the old behavior, set the new customizable option
-`locate-update-when-revert' to t.
+'locate-update-when-revert' to t.
 
 ** Desktop package
 
-*** Desktop saving is now a minor mode, `desktop-save-mode'.
+*** Desktop saving is now a minor mode, 'desktop-save-mode'.
 
-*** The variable `desktop-enable' is obsolete.
+*** The variable 'desktop-enable' is obsolete.
 
-Customize `desktop-save-mode' to enable desktop saving.
+Customize 'desktop-save-mode' to enable desktop saving.
 
 *** Buffers are saved in the desktop file in the same order as that in the
 buffer list.
@@ -2102,58 +2103,58 @@ idle).
 *** New command line option --no-desktop
 
 *** New commands:
-  - desktop-revert reverts to the last loaded desktop.
-  - desktop-change-dir kills current desktop and loads a new.
-  - desktop-save-in-desktop-dir saves desktop in the directory from which
-    it was loaded.
-  - desktop-lazy-complete runs the desktop load to completion.
-  - desktop-lazy-abort aborts lazy loading of the desktop.
+- 'desktop-revert' reverts to the last loaded desktop.
+- 'desktop-change-dir' kills current desktop and loads a new.
+- 'desktop-save-in-desktop-dir' saves desktop in the directory from which
+  it was loaded.
+- 'desktop-lazy-complete' runs the desktop load to completion.
+- 'desktop-lazy-abort' aborts lazy loading of the desktop.
 
 *** New customizable variables:
-  - desktop-save. Determines whether the desktop should be saved when it is
-    killed.
-  - desktop-file-name-format. Format in which desktop file names should be 
saved.
-  - desktop-path. List of directories in which to lookup the desktop file.
-  - desktop-locals-to-save. List of local variables to save.
-  - desktop-globals-to-clear. List of global variables that `desktop-clear' 
will clear.
-  - desktop-clear-preserve-buffers-regexp. Regexp identifying buffers that 
`desktop-clear'
-    should not delete.
-  - desktop-restore-eager. Number of buffers to restore immediately. Remaining 
buffers are
-    restored lazily (when Emacs is idle).
-  - desktop-lazy-verbose. Verbose reporting of lazily created buffers.
-  - desktop-lazy-idle-delay. Idle delay before starting to create buffers.
+- 'desktop-save'. Determines whether the desktop should be saved when it is
+  killed.
+- 'desktop-file-name-format'. Format in which desktop file names should be 
saved.
+- 'desktop-path'. List of directories in which to lookup the desktop file.
+- 'desktop-locals-to-save'. List of local variables to save.
+- 'desktop-globals-to-clear'. List of global variables that 'desktop-clear' 
will clear.
+- 'desktop-clear-preserve-buffers-regexp'. Regexp identifying buffers that 
'desktop-clear'
+  should not delete.
+- 'desktop-restore-eager'. Number of buffers to restore immediately. Remaining 
buffers are
+  restored lazily (when Emacs is idle).
+- 'desktop-lazy-verbose'. Verbose reporting of lazily created buffers.
+- 'desktop-lazy-idle-delay'. Idle delay before starting to create buffers.
 
 *** New hooks:
-  - desktop-after-read-hook run after a desktop is loaded.
-  - desktop-no-desktop-file-hook run when no desktop file is found.
+- 'desktop-after-read-hook' run after a desktop is loaded.
+- 'desktop-no-desktop-file-hook' run when no desktop file is found.
 
 ** Recentf changes
 
-The recent file list is now automatically cleaned up when recentf mode is
-enabled.  The new option `recentf-auto-cleanup' controls when to do
+The recent file list is now automatically cleaned up when 'recentf-mode' is
+enabled.  The new option 'recentf-auto-cleanup' controls when to do
 automatic cleanup.
 
 The ten most recent files can be quickly opened by using the shortcut
 keys 1 to 9, and 0, when the recent list is displayed in a buffer via
-the `recentf-open-files', or `recentf-open-more-files' commands.
+the 'recentf-open-files', or 'recentf-open-more-files' commands.
 
-The `recentf-keep' option replaces `recentf-keep-non-readable-files-p'
+The 'recentf-keep' option replaces 'recentf-keep-non-readable-files-p'
 and provides a more general mechanism to customize which file names to
 keep in the recent list.
 
-With the more advanced option `recentf-filename-handlers', you can
+With the more advanced option 'recentf-filename-handlers', you can
 specify functions that successively transform recent file names.  For
-example, if set to `file-truename' plus `abbreviate-file-name', the
+example, if set to 'file-truename' plus 'abbreviate-file-name', the
 same file will not be in the recent list with different symbolic
 links, and the file name will be abbreviated.
 
-To follow naming convention, `recentf-menu-append-commands-flag'
-replaces the misnamed option `recentf-menu-append-commands-p'.  The
+To follow naming convention, 'recentf-menu-append-commands-flag'
+replaces the misnamed option 'recentf-menu-append-commands-p'.  The
 old name remains available as alias, but has been marked obsolete.
 
 ** Auto-Revert changes
 
-*** You can now use Auto Revert mode to `tail' a file.
+*** You can now use Auto Revert mode to 'tail' a file.
 
 If point is at the end of a file buffer before reverting, Auto Revert
 mode keeps it at the end after reverting.  Similarly if point is
@@ -2165,20 +2166,20 @@ dependent.
 
 If you are sure that the file will only change by growing at the end,
 then you can tail the file more efficiently by using the new minor
-mode Auto Revert Tail mode.  The function `auto-revert-tail-mode'
+mode Auto Revert Tail mode.  The function 'auto-revert-tail-mode'
 toggles this mode.
 
 *** Auto Revert mode is now more careful to avoid excessive reverts and
 other potential problems when deciding which non-file buffers to
 revert.  This matters especially if Global Auto Revert mode is enabled
-and `global-auto-revert-non-file-buffers' is non-nil.  Auto Revert
+and 'global-auto-revert-non-file-buffers' is non-nil.  Auto Revert
 mode only reverts a non-file buffer if the buffer has a non-nil
-`revert-buffer-function' and a non-nil `buffer-stale-function', which
+'revert-buffer-function' and a non-nil 'buffer-stale-function', which
 decides whether the buffer should be reverted.  Currently, this means
 that auto reverting works for Dired buffers (although this may not
 work properly on all operating systems) and for the Buffer Menu.
 
-*** If the new user option `auto-revert-check-vc-info' is non-nil, Auto
+*** If the new user option 'auto-revert-check-vc-info' is non-nil, Auto
 Revert mode reliably updates version control info (such as the version
 control number in the mode line), in all version controlled buffers in
 which it is active.  If the option is nil, the default, then this info
@@ -2192,11 +2193,11 @@ is similar to the way sequential output to a terminal 
works.)
 
 ** Changes in Hi Lock
 
-*** hi-lock-mode now only affects a single buffer, and a new function
-`global-hi-lock-mode' enables Hi Lock in all buffers.  By default, if
+*** 'hi-lock-mode' now only affects a single buffer, and a new function
+'global-hi-lock-mode' enables Hi Lock in all buffers.  By default, if
 hi-lock-mode is used in what appears to be the initialization file, a
 warning message suggests to use global-hi-lock-mode instead.  However,
-if the new variable `hi-lock-archaic-interface-deduce' is non-nil,
+if the new variable 'hi-lock-archaic-interface-deduce' is non-nil,
 using hi-lock-mode in an initialization file will turn on Hi Lock in all
 buffers and no warning will be issued (for compatibility with the
 behavior in older versions of Emacs).
@@ -2214,7 +2215,7 @@ allout-encryption customization group.
 
 *** Default command prefix was changed to "\C-c " (control-c space), to
 avoid intruding on user's keybinding space.  Customize the
-`allout-command-prefix' variable to your preference.
+'allout-command-prefix' variable to your preference.
 
 *** Some previously rough topic-header format edge cases are reconciled.
 Level 1 topics use the mode's comment format, and lines starting with the
@@ -2247,29 +2248,29 @@ leaving them hidden or raising an error.
 *** Navigation within an item is easier.  Repeated beginning-of-line and
 end-of-line key commands (usually, ^A and ^E) cycle through the
 beginning/end-of-line and then beginning/end of topic, etc.  See new
-customization vars `allout-beginning-of-line-cycles' and
-`allout-end-of-line-cycles'.
+customization vars 'allout-beginning-of-line-cycles' and
+'allout-end-of-line-cycles'.
 
 *** New or revised allout-mode activity hooks enable creation of
 cooperative enhancements to allout mode without changes to the mode,
 itself.
 
-See `allout-exposure-change-hook', `allout-structure-added-hook',
-`allout-structure-deleted-hook', and `allout-structure-shifted-hook'.
+See 'allout-exposure-change-hook', 'allout-structure-added-hook',
+'allout-structure-deleted-hook', and 'allout-structure-shifted-hook'.
 
-`allout-exposure-change-hook' replaces the existing
-`allout-view-change-hook', which is being deprecated.  Both are still
-invoked, but `allout-view-change-hook' will eventually be ignored.
-`allout-exposure-change-hook' is called with explicit arguments detailing
+'allout-exposure-change-hook' replaces the existing
+'allout-view-change-hook', which is being deprecated.  Both are still
+invoked, but 'allout-view-change-hook' will eventually be ignored.
+'allout-exposure-change-hook' is called with explicit arguments detailing
 the specifics of each change (as are the other new hooks), making it easier
 to use than the old version.
 
-There is a new mode deactivation hook, `allout-mode-deactivate-hook', for
+There is a new mode deactivation hook, 'allout-mode-deactivate-hook', for
 coordinating with deactivation of allout-mode.  Both that and the mode
-activation hook, `allout-mode-hook' are now run after the `allout-mode'
+activation hook, 'allout-mode-hook' are now run after the 'allout-mode'
 variable is changed, rather than before.
 
-*** Allout now uses text overlay's `invisible' property for concealed text,
+*** Allout now uses text overlay's 'invisible' property for concealed text,
 instead of selective-display.  This simplifies the code, in particular
 avoiding the need for kludges for isearch dynamic-display, discretionary
 handling of edits of concealed text, undo concerns, etc.
@@ -2279,34 +2280,34 @@ handling of edits of concealed text, undo concerns, etc.
    - repaired inhibition of inadvertent edits to concealed text, without
      inhibiting undo; we now reveal undo changes within concealed text.
    - auto-fill-mode is now left inactive when allout-mode starts, if it
-     already was inactive.  also, `allout-inhibit-auto-fill' custom
+     already was inactive.  also, 'allout-inhibit-auto-fill' custom
      configuration variable makes it easy to disable auto fill in allout
      outlines in general or on a per-buffer basis.
    - allout now tolerates fielded text in outlines without disruption.
    - hot-spot navigation now is modularized with a new function,
-     `allout-hotspot-key-handler', enabling easier use and enhancement of
+     'allout-hotspot-key-handler', enabling easier use and enhancement of
      the functionality in allout addons.
    - repaired retention of topic body hanging indent upon topic depth shifts
    - bulleting variation is simpler and more accommodating, both in the
      default behavior and in ability to vary when creating new topics
    - mode deactivation now does cleans up effectively, more properly
      restoring affected variables and hooks to former state, removing
-     overlays, etc.  see `allout-add-resumptions' and
-     `allout-do-resumptions', which replace the old `allout-resumptions'.
+     overlays, etc.  see 'allout-add-resumptions' and
+     'allout-do-resumptions', which replace the old 'allout-resumptions'.
    - included a few unit-tests for interior functionality.  developers can
      have them automatically run at the end of module load by customizing
-     the option `allout-run-unit-tests-on-load'.
+     the option 'allout-run-unit-tests-on-load'.
    - many, many other, more minor tweaks, fixes, and refinements.
    - version number incremented to 2.2
 
 ** Hideshow mode changes
 
-*** New variable `hs-set-up-overlay' allows customization of the overlay
+*** New variable 'hs-set-up-overlay' allows customization of the overlay
 used to effect hiding for hideshow minor mode.  Integration with isearch
-handles the overlay property `display' specially, preserving it during
+handles the overlay property 'display' specially, preserving it during
 temporary overlay showing in the course of an isearch operation.
 
-*** New variable `hs-allow-nesting' non-nil means that hiding a block does
+*** New variable 'hs-allow-nesting' non-nil means that hiding a block does
 not discard the hidden state of any "internal" blocks; when the parent
 block is later shown, the internal blocks remain hidden.  Default is nil.
 
@@ -2314,30 +2315,30 @@ block is later shown, the internal blocks remain 
hidden.  Default is nil.
 
 *** New ffap commands and keybindings:
 
-C-x C-r (`ffap-read-only'),
-C-x C-v (`ffap-alternate-file'), C-x C-d (`ffap-list-directory'),
-C-x 4 r (`ffap-read-only-other-window'), C-x 4 d (`ffap-dired-other-window'),
-C-x 5 r (`ffap-read-only-other-frame'), C-x 5 d (`ffap-dired-other-frame').
+C-x C-r ('ffap-read-only'),
+C-x C-v ('ffap-alternate-file'), C-x C-d ('ffap-list-directory'),
+C-x 4 r ('ffap-read-only-other-window'), C-x 4 d ('ffap-dired-other-window'),
+C-x 5 r ('ffap-read-only-other-frame'), C-x 5 d ('ffap-dired-other-frame').
 
 *** FFAP accepts wildcards in a file name by default.
 
-C-x C-f passes the file name to `find-file' with non-nil WILDCARDS
-argument, which visits multiple files, and C-x d passes it to `dired'.
+C-x C-f passes the file name to 'find-file' with non-nil WILDCARDS
+argument, which visits multiple files, and C-x d passes it to 'dired'.
 
 ** Changes in Skeleton
 
-*** In skeleton.el, `-' marks the `skeleton-point' without interregion 
interaction.
+*** In skeleton.el, '-' marks the 'skeleton-point' without interregion 
interaction.
 
-`@' has reverted to only setting `skeleton-positions' and no longer
-sets `skeleton-point'.  Skeletons which used @ to mark
-`skeleton-point' independent of `_' should now use `-' instead.  The
-updated `skeleton-insert' docstring explains these new features along
+'@' has reverted to only setting 'skeleton-positions' and no longer
+sets 'skeleton-point'.  Skeletons which used @ to mark
+'skeleton-point' independent of '_' should now use '-' instead.  The
+updated 'skeleton-insert' docstring explains these new features along
 with other details of skeleton construction.
 
-*** The variables `skeleton-transformation', `skeleton-filter', and
-`skeleton-pair-filter' have been renamed to
-`skeleton-transformation-function', `skeleton-filter-function', and
-`skeleton-pair-filter-function'.  The old names are still available
+*** The variables 'skeleton-transformation', 'skeleton-filter', and
+'skeleton-pair-filter' have been renamed to
+'skeleton-transformation-function', 'skeleton-filter-function', and
+'skeleton-pair-filter-function'.  The old names are still available
 as aliases.
 
 ** HTML/SGML changes
@@ -2346,17 +2347,17 @@ as aliases.
 automatically.
 
 *** SGML mode has indentation and supports XML syntax.
-The new variable `sgml-xml-mode' tells SGML mode to use XML syntax.
+The new variable 'sgml-xml-mode' tells SGML mode to use XML syntax.
 When this option is enabled, SGML tags are inserted in XML style,
 i.e., there is always a closing tag.
 By default, its setting is inferred on a buffer-by-buffer basis
 from the file name or buffer contents.
 
-*** The variable `sgml-transformation' has been renamed to
-`sgml-transformation-function'.  The old name is still available as
+*** The variable 'sgml-transformation' has been renamed to
+'sgml-transformation-function'.  The old name is still available as
 alias.
 
-*** `xml-mode' is now an alias for `sgml-mode', which has XML support.
+*** 'xml-mode' is now an alias for 'sgml-mode', which has XML support.
 
 ** TeX modes
 
@@ -2364,9 +2365,9 @@ alias.
 
 *** C-c C-c prompts for a command to run, and tries to offer a good default.
 
-*** The user option `tex-start-options-string' has been replaced
-by two new user options: `tex-start-options', which should hold
-command-line options to feed to TeX, and `tex-start-commands' which should hold
+*** The user option 'tex-start-options-string' has been replaced
+by two new user options: 'tex-start-options', which should hold
+command-line options to feed to TeX, and 'tex-start-commands' which should hold
 TeX commands to use at startup.
 
 *** verbatim environments are now highlighted in courier by font-lock
@@ -2380,121 +2381,121 @@ The new command keys "<" and ">" in the TOC buffer 
promote/demote the
 section at point or all sections in the current region, with full
 support for multifile documents.
 
-The new command `reftex-toc-recenter' (`C-c -') shows the current
+The new command 'reftex-toc-recenter' ('C-c -') shows the current
 section in the TOC buffer without selecting the TOC window.
 Recentering can happen automatically in idle time when the option
-`reftex-auto-recenter-toc' is turned on.  The highlight in the TOC
+'reftex-auto-recenter-toc' is turned on.  The highlight in the TOC
 buffer stays when the focus moves to a different window.  A dedicated
 frame can show the TOC with the current section always automatically
 highlighted.  The frame is created and deleted from the toc buffer
-with the `d' key.
+with the 'd' key.
 
 The toc window can be split off horizontally instead of vertically.
-See new option `reftex-toc-split-windows-horizontally'.
+See new option 'reftex-toc-split-windows-horizontally'.
 
 Labels can be renamed globally from the table of contents using the
-key `M-%'.
+key 'M-%'.
 
-The new command `reftex-goto-label' jumps directly to a label
+The new command 'reftex-goto-label' jumps directly to a label
 location.
 
 *** Changes related to citations and BibTeX database files
 
 Commands that insert a citation now prompt for optional arguments when
 called with a prefix argument.  Related new options are
-`reftex-cite-prompt-optional-args' and `reftex-cite-cleanup-optional-args'.
+'reftex-cite-prompt-optional-args' and 'reftex-cite-cleanup-optional-args'.
 
-The new command `reftex-create-bibtex-file' creates a BibTeX database
+The new command 'reftex-create-bibtex-file' creates a BibTeX database
 with all entries referenced in the current document.  The keys "e" and
 "E" allow to produce a BibTeX database file from entries marked in a
 citation selection buffer.
 
-The command `reftex-citation' uses the word in the buffer before the
+The command 'reftex-citation' uses the word in the buffer before the
 cursor as a default search string.
 
 The support for chapterbib has been improved.  Different chapters can
-now use BibTeX or an explicit `thebibliography' environment.
+now use BibTeX or an explicit 'thebibliography' environment.
 
 The macros which specify the bibliography file (like \bibliography)
-can be configured with the new option `reftex-bibliography-commands'.
+can be configured with the new option 'reftex-bibliography-commands'.
 
 Support for jurabib has been added.
 
 *** Global index matched may be verified with a user function.
 
 During global indexing, a user function can verify an index match.
-See new option `reftex-index-verify-function'.
+See new option 'reftex-index-verify-function'.
 
 *** Parsing documents with many labels can be sped up.
 
 Operating in a document with thousands of labels can be sped up
 considerably by allowing RefTeX to derive the type of a label directly
-from the label prefix like `eq:' or `fig:'.  The option
-`reftex-trust-label-prefix' needs to be configured in order to enable
+from the label prefix like 'eq:' or 'fig:'.  The option
+'reftex-trust-label-prefix' needs to be configured in order to enable
 this feature.  While the speed-up is significant, this may reduce the
 quality of the context offered by RefTeX to describe a label.
 
 *** Miscellaneous changes
 
 The macros which input a file in LaTeX (like \input, \include) can be
-configured in the new option `reftex-include-file-commands'.
+configured in the new option 'reftex-include-file-commands'.
 
 RefTeX supports global incremental search.
 
 ** BibTeX mode
 
-*** The new command `bibtex-url' browses a URL for the BibTeX entry at
+*** The new command 'bibtex-url' browses a URL for the BibTeX entry at
 point (bound to C-c C-l and mouse-2, RET on clickable fields).
 
-*** The new command `bibtex-entry-update' (bound to C-c C-u) updates
+*** The new command 'bibtex-entry-update' (bound to C-c C-u) updates
 an existing BibTeX entry by inserting fields that may occur but are not
 present.
 
-*** New `bibtex-entry-format' option `required-fields', enabled by default.
+*** New 'bibtex-entry-format' option 'required-fields', enabled by default.
 
-*** `bibtex-maintain-sorted-entries' can take values `plain',
-`crossref', and `entry-class' which control the sorting scheme used
-for BibTeX entries.  `bibtex-sort-entry-class' controls the sorting
-scheme `entry-class'.  TAB completion for reference keys and
+*** 'bibtex-maintain-sorted-entries' can take values 'plain',
+'crossref', and 'entry-class' which control the sorting scheme used
+for BibTeX entries.  'bibtex-sort-entry-class' controls the sorting
+scheme 'entry-class'.  TAB completion for reference keys and
 automatic detection of duplicates does not require anymore that
-`bibtex-maintain-sorted-entries' is non-nil.
+'bibtex-maintain-sorted-entries' is non-nil.
 
-*** The new command `bibtex-complete' completes word fragment before
+*** The new command 'bibtex-complete' completes word fragment before
 point according to context (bound to M-tab).
 
-*** In BibTeX mode the command `fill-paragraph' (M-q) fills
+*** In BibTeX mode the command 'fill-paragraph' (M-q) fills
 individual fields of a BibTeX entry.
 
-*** The new variable `bibtex-autofill-types' contains a list of entry
+*** The new variable 'bibtex-autofill-types' contains a list of entry
 types for which fields are filled automatically (if possible).
 
-*** The new commands `bibtex-find-entry' and `bibtex-find-crossref'
+*** The new commands 'bibtex-find-entry' and 'bibtex-find-crossref'
 locate entries and crossref'd entries (bound to C-c C-s and C-c C-x).
 Crossref fields are clickable (bound to mouse-2, RET).
 
-*** The new variables `bibtex-files' and `bibtex-file-path' define a set
+*** The new variables 'bibtex-files' and 'bibtex-file-path' define a set
 of BibTeX files that are searched for entry keys.
 
-*** The new command `bibtex-validate-globally' checks for duplicate keys
+*** The new command 'bibtex-validate-globally' checks for duplicate keys
 in multiple BibTeX files.
 
-*** If the new variable `bibtex-autoadd-commas' is non-nil,
+*** If the new variable 'bibtex-autoadd-commas' is non-nil,
 automatically add missing commas at end of BibTeX fields.
 
-*** The new command `bibtex-copy-summary-as-kill' pushes summary
+*** The new command 'bibtex-copy-summary-as-kill' pushes summary
 of BibTeX entry to kill ring (bound to C-c C-t).
 
-*** If the new variable `bibtex-parse-keys-fast' is non-nil,
+*** If the new variable 'bibtex-parse-keys-fast' is non-nil,
 use fast but simplified algorithm for parsing BibTeX keys.
 
 *** The new variables bibtex-expand-strings and
 bibtex-autokey-expand-strings control the expansion of strings when
 extracting the content of a BibTeX field.
 
-*** The variables `bibtex-autokey-name-case-convert' and
-`bibtex-autokey-titleword-case-convert' have been renamed to
-`bibtex-autokey-name-case-convert-function' and
-`bibtex-autokey-titleword-case-convert-function'.  The old names are
+*** The variables 'bibtex-autokey-name-case-convert' and
+'bibtex-autokey-titleword-case-convert' have been renamed to
+'bibtex-autokey-name-case-convert-function' and
+'bibtex-autokey-titleword-case-convert-function'.  The old names are
 still available as aliases.
 
 ** GUD changes
@@ -2518,7 +2519,7 @@ counter to the specified source line (the one where point 
is).
 
 *** The variable tooltip-gud-tips-p has been removed.  GUD tooltips can now be
 toggled independently of normal tooltips with the minor mode
-`gud-tooltip-mode'.
+'gud-tooltip-mode'.
 
 *** In graphical mode, with a C program, GUD Tooltips have been extended to
 display the #define directive associated with an identifier when program is
@@ -2529,12 +2530,12 @@ not executing.
 **** Search for source files using jdb classpath and class information.
 Fast startup since there is no need to scan all source files up front.
 There is also no need to create and maintain lists of source
-directories to scan.  Look at `gud-jdb-use-classpath' and
-`gud-jdb-classpath' customization variables documentation.
+directories to scan.  Look at 'gud-jdb-use-classpath' and
+'gud-jdb-classpath' customization variables documentation.
 
 **** The previous method of searching for source files has been
 preserved in case someone still wants/needs to use it.
-Set `gud-jdb-use-classpath' to nil.
+Set 'gud-jdb-use-classpath' to nil.
 
 **** Supports the standard breakpoint (gud-break, gud-clear)
 set/clear operations from Java source files under the classpath, stack
@@ -2546,42 +2547,42 @@ traversal (gud-up, gud-down), and run until current 
stack finish
 
 *** Added jdb Customization Variables
 
-**** `gud-jdb-command-name'.  What command line to use to invoke jdb.
+**** 'gud-jdb-command-name'.  What command line to use to invoke jdb.
 
-**** `gud-jdb-use-classpath'.  Allows selection of java source file searching
-method: set to t for new method, nil to scan `gud-jdb-directories' for
+**** 'gud-jdb-use-classpath'.  Allows selection of java source file searching
+method: set to t for new method, nil to scan 'gud-jdb-directories' for
 java sources (previous method).
 
-**** `gud-jdb-directories'.  List of directories to scan and search for Java
-classes using the original gud-jdb method (if `gud-jdb-use-classpath'
+**** 'gud-jdb-directories'.  List of directories to scan and search for Java
+classes using the original gud-jdb method (if 'gud-jdb-use-classpath'
 is nil).
 
 *** Minor Improvements
 
 **** The STARTTLS wrapper (starttls.el) can now use GnuTLS
-instead of the OpenSSL based `starttls' tool.  For backwards
-compatibility, it prefers `starttls', but you can toggle
-`starttls-use-gnutls' to switch to GnuTLS (or simply remove the
-`starttls' tool).
+instead of the OpenSSL based 'starttls' tool.  For backwards
+compatibility, it prefers 'starttls', but you can toggle
+'starttls-use-gnutls' to switch to GnuTLS (or simply remove the
+'starttls' tool).
 
 **** Do not allow debugger output history variable to grow without bounds.
 
 ** Lisp mode changes
 
-*** Lisp mode now uses `font-lock-doc-face' for doc strings.
+*** Lisp mode now uses 'font-lock-doc-face' for doc strings.
 
 *** C-u C-M-q in Emacs Lisp mode pretty-prints the list after point.
 
 *** New features in evaluation commands
 
-**** The function `eval-defun' (C-M-x) called on defface reinitializes
+**** The function 'eval-defun' (C-M-x) called on defface reinitializes
 the face to the value specified in the defface expression.
 
 **** Typing C-x C-e twice prints the value of the integer result
 in additional formats (octal, hexadecimal, character) specified
-by the new function `eval-expression-print-format'.  The same
-function also defines the result format for `eval-expression' (M-:),
-`eval-print-last-sexp' (C-j) and some edebug evaluation functions.
+by the new function 'eval-expression-print-format'.  The same
+function also defines the result format for 'eval-expression' (M-:),
+'eval-print-last-sexp' (C-j) and some edebug evaluation functions.
 
 ** Changes to cmuscheme
 
@@ -2593,16 +2594,16 @@ is the name of the Scheme interpreter) exists, its 
contents are sent
 to the Scheme subprocess upon startup.
 
 *** There are new commands to instruct the Scheme interpreter to trace
-procedure calls (`scheme-trace-procedure') and to expand syntactic forms
-(`scheme-expand-current-form').  The commands actually sent to the Scheme
-subprocess are controlled by the user options `scheme-trace-command',
-`scheme-untrace-command' and `scheme-expand-current-form'.
+procedure calls ('scheme-trace-procedure') and to expand syntactic forms
+('scheme-expand-current-form').  The commands actually sent to the Scheme
+subprocess are controlled by the user options 'scheme-trace-command',
+'scheme-untrace-command' and 'scheme-expand-current-form'.
 
 ** Ewoc changes
 
-*** The new function `ewoc-delete' deletes specified nodes.
+*** The new function 'ewoc-delete' deletes specified nodes.
 
-*** `ewoc-create' now takes optional arg NOSEP, which inhibits insertion of
+*** 'ewoc-create' now takes optional arg NOSEP, which inhibits insertion of
 a newline after each pretty-printed entry and after the header and footer.
 This allows you to create multiple-entry ewocs on a single line and to
 effect "invisible" nodes by arranging for the pretty-printer to not print
@@ -2610,13 +2611,13 @@ anything for those nodes.
 
 For example, these two sequences of expressions behave identically:
 
-;; NOSEP nil
-(defun PP (data) (insert (format "%S" data)))
-(ewoc-create 'PP "start\n")
+    ;; NOSEP nil
+    (defun PP (data) (insert (format "%S" data)))
+    (ewoc-create 'PP "start\n")
 
-;; NOSEP t
-(defun PP (data) (insert (format "%S\n" data)))
-(ewoc-create 'PP "start\n\n" "\n" t)
+    ;; NOSEP t
+    (defun PP (data) (insert (format "%S\n" data)))
+    (ewoc-create 'PP "start\n\n" "\n" t)
 
 ** CC mode changes
 
@@ -2645,9 +2646,9 @@ Here is a summary:
 **** Indentation Engine
 The CC Mode indentation engine fully supports AWK mode.
 
-AWK mode handles code formatted in the conventional AWK fashion: `{'s
+AWK mode handles code formatted in the conventional AWK fashion: '{'s
 which start actions, user-defined functions, or compound statements are
-placed on the same line as the associated construct; the matching `}'s
+placed on the same line as the associated construct; the matching '}'s
 are normally placed under the start of the respective pattern, function
 definition, or structured statement.
 
@@ -2752,7 +2753,7 @@ key-sequence.  [N.B. "DEL" is the <backspace> key.]
 
 **** The new command c-subword-mode is bound to C-c C-w.
 
-*** C-c C-s (`c-show-syntactic-information') now highlights the anchor
+*** C-c C-s ('c-show-syntactic-information') now highlights the anchor
 position(s).
 
 *** New syntactic symbols in IDL mode.
@@ -2762,25 +2763,25 @@ module-open, module-close, inmodule, composition-open,
 composition-close, and incomposition.
 
 *** New functions to do hungry delete without enabling hungry delete mode.
-The new functions `c-hungry-backspace' and `c-hungry-delete-forward'
+The new functions 'c-hungry-backspace' and 'c-hungry-delete-forward'
 provide hungry deletion without having to toggle a mode.  They are
 bound to C-c C-DEL and C-c C-d (and several variants, for the benefit
 of different keyboard setups.  See "Changes in key sequences" above).
 
-*** Better control over `require-final-newline'.
+*** Better control over 'require-final-newline'.
 
-The variable `c-require-final-newline' specifies which of the modes
+The variable 'c-require-final-newline' specifies which of the modes
 implemented by CC mode should insert final newlines.  Its value is a
 list of modes, and only those modes should do it.  By default the list
 includes C, C++ and Objective-C modes.
 
-Whichever modes are in this list will set `require-final-newline'
-based on `mode-require-final-newline'.
+Whichever modes are in this list will set 'require-final-newline'
+based on 'mode-require-final-newline'.
 
 *** Format change for syntactic context elements.
 
-The elements in the syntactic context returned by `c-guess-basic-syntax'
-and stored in `c-syntactic-context' has been changed somewhat to allow
+The elements in the syntactic context returned by 'c-guess-basic-syntax'
+and stored in 'c-syntactic-context' has been changed somewhat to allow
 attaching more information.  They are now lists instead of single cons
 cells.  E.g. a line that previously had the syntactic analysis
 
@@ -2793,9 +2794,9 @@ is now analyzed as
 In some cases there are more than one position given for a syntactic
 symbol.
 
-This change might affect code that calls `c-guess-basic-syntax'
+This change might affect code that calls 'c-guess-basic-syntax'
 directly, and custom lineup functions if they use
-`c-syntactic-context'.  However, the argument given to lineup
+'c-syntactic-context'.  However, the argument given to lineup
 functions is still a single cons cell with nil or an integer in the
 cdr.
 
@@ -2813,8 +2814,8 @@ languages.  See the comment blurb near the top of 
cc-langs.el.
 
 **** New initialization functions.
 The initialization procedure has been split up into more functions to
-give better control: `c-basic-common-init', `c-font-lock-init', and
-`c-init-language-vars'.
+give better control: 'c-basic-common-init', 'c-font-lock-init', and
+'c-init-language-vars'.
 
 *** Changes in analysis of nested syntactic constructs.
 The syntactic analysis engine has better handling of cases where
@@ -2840,31 +2841,31 @@ its substatement.  E.g:
 **** Syntactic indentation inside macros.
 The contents of multiline #define's are now analyzed and indented
 syntactically just like other code.  This can be disabled by the new
-variable `c-syntactic-indentation-in-macros'.  A new syntactic symbol
-`cpp-define-intro' has been added to control the initial indentation
-inside `#define's.
+variable 'c-syntactic-indentation-in-macros'.  A new syntactic symbol
+'cpp-define-intro' has been added to control the initial indentation
+inside '#define's.
 
-**** New lineup function `c-lineup-cpp-define'.
+**** New lineup function 'c-lineup-cpp-define'.
 
 Now used by default to line up macro continuation lines.  The behavior
 of this function closely mimics the indentation one gets if the macro
 is indented while the line continuation backslashes are temporarily
 removed.  If syntactic indentation in macros is turned off, it works
-much line `c-lineup-dont-change', which was used earlier, but handles
+much line 'c-lineup-dont-change', which was used earlier, but handles
 empty lines within the macro better.
 
 **** Automatically inserted newlines continues the macro if used within one.
 This applies to the newlines inserted by the auto-newline mode, and to
-`c-context-line-break' and `c-context-open-line'.
+'c-context-line-break' and 'c-context-open-line'.
 
 **** Better alignment of line continuation backslashes.
-`c-backslash-region' tries to adapt to surrounding backslashes.  New
-variable `c-backslash-max-column' puts a limit on how far out
+'c-backslash-region' tries to adapt to surrounding backslashes.  New
+variable 'c-backslash-max-column' puts a limit on how far out
 backslashes can be moved.
 
 **** Automatic alignment of line continuation backslashes.
-This is controlled by the new variable `c-auto-align-backslashes'.  It
-affects `c-context-line-break', `c-context-open-line' and newlines
+This is controlled by the new variable 'c-auto-align-backslashes'.  It
+affects 'c-context-line-break', 'c-context-open-line' and newlines
 inserted in Auto-Newline mode.
 
 **** Line indentation works better inside macros.
@@ -2876,48 +2877,48 @@ backslash) in the macro.
 
 *** indent-for-comment is more customizable.
 The behavior of M-; (indent-for-comment) is now configurable through
-the variable `c-indent-comment-alist'.  The indentation behavior is
+the variable 'c-indent-comment-alist'.  The indentation behavior is
 based on the preceding code on the line, e.g. to get two spaces after
-#else and #endif but indentation to `comment-column' in most other
+#else and #endif but indentation to 'comment-column' in most other
 cases (something which was hardcoded earlier).
 
-*** New function `c-context-open-line'.
-It's the open-line equivalent of `c-context-line-break'.
+*** New function 'c-context-open-line'.
+It's the open-line equivalent of 'c-context-line-break'.
 
 *** New clean-ups
 
-**** `comment-close-slash'.
+**** 'comment-close-slash'.
 With this clean-up, a block (i.e. c-style) comment can be terminated by
 typing a slash at the start of a line.
 
-**** `c-one-liner-defun'
+**** 'c-one-liner-defun'
 This clean-up compresses a short enough defun (for example, an AWK
 pattern/action pair) onto a single line.  "Short enough" is configurable.
 
 *** New lineup functions
 
-**** `c-lineup-string-cont'
+**** 'c-lineup-string-cont'
 This lineup function lines up a continued string under the one it
 continues.  E.g:
 
 result = prefix + "A message "
                   "string.";      <- c-lineup-string-cont
 
-**** `c-lineup-cascaded-calls'
+**** 'c-lineup-cascaded-calls'
 Lines up series of calls separated by "->" or ".".
 
-**** `c-lineup-knr-region-comment'
+**** 'c-lineup-knr-region-comment'
 Gives (what most people think is) better indentation of comments in
 the "K&R region" between the function header and its body.
 
-**** `c-lineup-gcc-asm-reg'
+**** 'c-lineup-gcc-asm-reg'
 Provides better indentation inside asm blocks.
 
-**** `c-lineup-argcont'
+**** 'c-lineup-argcont'
 Lines up continued function arguments after the preceding comma.
 
 *** Added toggle for syntactic indentation.
-The function `c-toggle-syntactic-indentation' can be used to toggle
+The function 'c-toggle-syntactic-indentation' can be used to toggle
 syntactic indentation.
 
 *** Better caching of the syntactic context.
@@ -2938,7 +2939,7 @@ Statements are recognized most of the time even when they 
occur in an
 "invalid" context, e.g. in a function argument.  In practice that can
 happen when macros are involved.
 
-*** Improved the way `c-indent-exp' chooses the block to indent.
+*** Improved the way 'c-indent-exp' chooses the block to indent.
 It now indents the block for the closest sexp following the point
 whose closing paren ends on a different line.  This means that the
 point doesn't have to be immediately before the block to indent.
@@ -2953,13 +2954,13 @@ The former two couldn't be differentiated before, and 
the latter three
 are new.  Font-locking is robust now and offers new customizable
 faces.
 
-*** The variable `makefile-query-one-target-method' has been renamed
-to `makefile-query-one-target-method-function'.  The old name is still
+*** The variable 'makefile-query-one-target-method' has been renamed
+to 'makefile-query-one-target-method-function'.  The old name is still
 available as alias.
 
 ** Sql changes
 
-*** The variable `sql-product' controls the highlighting of different
+*** The variable 'sql-product' controls the highlighting of different
 SQL dialects.  This variable can be set globally via Customize, on a
 buffer-specific basis via local variable settings, or for the current
 session using the new SQL->Product submenu.  (This menu replaces the
@@ -2984,24 +2985,23 @@ The following values are supported:
 The current product name will be shown on the mode line following the
 SQL mode indicator.
 
-The technique of setting `sql-mode-font-lock-defaults' directly in
-your `.emacs' will no longer establish the default highlighting -- Use
-`sql-product' to accomplish this.
+The technique of setting 'sql-mode-font-lock-defaults' directly in
+your '.emacs' will no longer establish the default highlighting -- Use
+'sql-product' to accomplish this.
 
 ANSI keywords are always highlighted.
 
-*** The function `sql-add-product-keywords' can be used to add
+*** The function 'sql-add-product-keywords' can be used to add
 font-lock rules to the product specific rules.  For example, to have
-all identifiers ending in `_t' under MS SQLServer treated as a type,
+all identifiers ending in '_t' under MS SQLServer treated as a type,
 you would use the following line in your .emacs file:
 
-  (sql-add-product-keywords 'ms
-             '(("\\<\\w+_t\\>" . font-lock-type-face)))
+  (sql-add-product-keywords 'ms '(("\\<\\w+_t\\>" . font-lock-type-face)))
 
 *** Oracle support includes keyword highlighting for Oracle 9i.
 
 Most SQL and PL/SQL keywords are implemented.  SQL*Plus commands are
-highlighted in `font-lock-doc-face'.
+highlighted in 'font-lock-doc-face'.
 
 *** Microsoft SQLServer support has been significantly improved.
 
@@ -3011,13 +3011,13 @@ osql flushes its error stream more frequently.  Thus 
error messages
 are displayed when they occur rather than when the session is
 terminated.
 
-If the username and password are not provided to `sql-ms', osql is
-called with the `-E' command line argument to use the operating system
+If the username and password are not provided to 'sql-ms', osql is
+called with the '-E' command line argument to use the operating system
 credentials to authenticate the user.
 
 *** Postgres support is enhanced.
 Keyword highlighting of Postgres 7.3 is implemented.  Prompting for
-the username and the pgsql `-U' option is added.
+the username and the pgsql '-U' option is added.
 
 *** MySQL support is enhanced.
 Keyword highlighting of MySql 4.0 is implemented.
@@ -3027,30 +3027,30 @@ packages, procedures, functions, triggers, sequences, 
rules, and
 defaults.
 
 *** Added SQL->Start SQLi Session menu entry which calls the
-appropriate `sql-interactive-mode' wrapper for the current setting of
-`sql-product'.
+appropriate 'sql-interactive-mode' wrapper for the current setting of
+'sql-product'.
 
 *** sql.el supports the SQLite interpreter--call 'sql-sqlite'.
 
 ** Fortran mode changes
 
-*** F90 mode and Fortran mode have support for `hs-minor-mode' (hideshow).
+*** F90 mode and Fortran mode have support for 'hs-minor-mode' (hideshow).
 It cannot deal with every code format, but ought to handle a sizable
 majority.
 
 *** F90 mode and Fortran mode have new navigation commands
-`f90-end-of-block', `f90-beginning-of-block', `f90-next-block',
-`f90-previous-block', `fortran-end-of-block',
-`fortran-beginning-of-block'.
+'f90-end-of-block', 'f90-beginning-of-block', 'f90-next-block',
+'f90-previous-block', 'fortran-end-of-block',
+'fortran-beginning-of-block'.
 
 *** Fortran mode does more font-locking by default.  Use level 3
 highlighting for the old default.
 
-*** Fortran mode has a new variable `fortran-directive-re'.
+*** Fortran mode has a new variable 'fortran-directive-re'.
 Adapt this to match the format of any compiler directives you use.
 Lines that match are never indented, and are given distinctive font-locking.
 
-*** The new function `f90-backslash-not-special' can be used to change
+*** The new function 'f90-backslash-not-special' can be used to change
 the syntax of backslashes in F90 buffers.
 
 ** Miscellaneous programming mode changes
@@ -3058,38 +3058,38 @@ the syntax of backslashes in F90 buffers.
 *** In sh-script, a continuation line is only indented if the backslash was
 preceded by a SPC or a TAB.
 
-*** Perl mode has a new variable `perl-indent-continued-arguments'.
+*** Perl mode has a new variable 'perl-indent-continued-arguments'.
 
 *** The old Octave mode bindings C-c f and C-c i have been changed
 to C-c C-f and C-c C-i.  The C-c C-i subcommands now have duplicate
 bindings on control characters--thus, C-c C-i C-b is the same as
 C-c C-i b, and so on.
 
-*** Prolog mode has a new variable `prolog-font-lock-keywords'
+*** Prolog mode has a new variable 'prolog-font-lock-keywords'
 to support use of font-lock.
 
 ** VC Changes
 
 *** New backends for Subversion and Meta-CVS.
 
-*** The new variable `vc-cvs-global-switches' specifies switches that
+*** The new variable 'vc-cvs-global-switches' specifies switches that
 are passed to any CVS command invoked by VC.
 
 These switches are used as "global options" for CVS, which means they
 are inserted before the command name.  For example, this allows you to
-specify a compression level using the `-z#' option for CVS.
+specify a compression level using the '-z#' option for CVS.
 
 *** The key C-x C-q only changes the read-only state of the buffer
 (toggle-read-only).  It no longer checks files in or out.
 
 We made this change because we held a poll and found that many users
 were unhappy with the previous behavior.  If you do prefer this
-behavior, you can bind `vc-toggle-read-only' to C-x C-q in your
-`.emacs' file:
+behavior, you can bind 'vc-toggle-read-only' to C-x C-q in your
+'.emacs' file:
 
     (global-set-key "\C-x\C-q" 'vc-toggle-read-only)
 
-The function `vc-toggle-read-only' will continue to exist.
+The function 'vc-toggle-read-only' will continue to exist.
 
 *** VC-Annotate mode enhancements
 
@@ -3107,13 +3107,13 @@ to view diffs or log entries directly from 
vc-annotate-mode:
 
 ** pcl-cvs changes
 
-*** In pcl-cvs mode, there is a new `d y' command to view the diffs
+*** In pcl-cvs mode, there is a new 'd y' command to view the diffs
 between the local version of the file and yesterday's head revision
 in the repository.
 
-*** In pcl-cvs mode, there is a new `d r' command to view the changes
+*** In pcl-cvs mode, there is a new 'd r' command to view the changes
 anyone has committed to the repository since you last executed
-`checkout', `update' or `commit'.  That means using cvs diff options
+'checkout', 'update' or 'commit'.  That means using cvs diff options
 -rBASE -rHEAD.
 
 ** Diff changes
@@ -3124,11 +3124,11 @@ anyone has committed to the repository since you last 
executed
 
 These are the new bindings:
 
-C-c C-e   diff-ediff-patch  (old M-A)
-C-c C-n   diff-restrict-view   (old M-r)
-C-c C-r   diff-reverse-direction  (old M-R)
-C-c C-u   diff-context->unified   (old M-U)
-C-c C-w   diff-refine-hunk  (old C-c C-r)
+C-c C-e   'diff-ediff-patch'        (old M-A)
+C-c C-n   'diff-restrict-view'      (old M-r)
+C-c C-r   'diff-reverse-direction'  (old M-R)
+C-c C-u   'diff-context->unified'   (old M-U)
+C-c C-w   'diff-refine-hunk'        (old C-c C-r)
 
 To convert unified to context format, use C-u C-c C-u.
 In addition, C-c C-u now operates on the region
@@ -3147,9 +3147,9 @@ currently highlighted regions in an inferior Ediff 
session.  If you answer 'n'
 then it reverts to the old behavior and asks the user to select regions for
 comparison.
 
-*** The new command `ediff-backup' compares a file with its most recent
-backup using `ediff'.  If you specify the name of a backup file,
-`ediff-backup' compares it with the file of which it is a backup.
+*** The new command 'ediff-backup' compares a file with its most recent
+backup using 'ediff'.  If you specify the name of a backup file,
+'ediff-backup' compares it with the file of which it is a backup.
 
 ** Etags changes.
 
@@ -3160,11 +3160,11 @@ backup using `ediff'.  If you specify the name of a 
backup file,
 The syntax --ignore-case-regexp=/regex/ is now undocumented and retained
 only for backward compatibility.  The new equivalent syntax is
 --regex=/regex/i.  More generally, it is --regex=/TAGREGEX/TAGNAME/MODS,
-where `/TAGNAME' is optional, as usual, and MODS is a string of 0 or
-more characters among `i' (ignore case), `m' (multi-line) and `s'
-(single-line).  The `m' and `s' modifiers behave as in Perl regular
-expressions: `m' allows regexps to match more than one line, while `s'
-(which implies `m') means that `.' matches newlines.  The ability to
+where '/TAGNAME' is optional, as usual, and MODS is a string of 0 or
+more characters among 'i' (ignore case), 'm' (multi-line) and 's'
+(single-line).  The 'm' and 's' modifiers behave as in Perl regular
+expressions: 'm' allows regexps to match more than one line, while 's'
+(which implies 'm') means that '.' matches newlines.  The ability to
 span newlines allows writing of much more powerful regular expressions
 and rapid prototyping for tagging new languages.
 
@@ -3189,8 +3189,8 @@ per line.  Lines beginning with space or tab are ignored.
 
 **** New language HTML.
 
-Tags are generated for `title' as well as `h1', `h2', and `h3'.  Also,
-when `name=' is used inside an anchor and whenever `id=' is used.
+Tags are generated for 'title' as well as 'h1', 'h2', and 'h3'.  Also,
+when 'name=' is used inside an anchor and whenever 'id=' is used.
 
 **** New language PHP.
 
@@ -3201,9 +3201,9 @@ specified to etags, variables are tags also.
 
 All functions are tagged.
 
-**** The `::' qualifier triggers C++ parsing in C file.
+**** The '::' qualifier triggers C++ parsing in C file.
 
-Previously, only the `template' and `class' keywords had this effect.
+Previously, only the 'template' and 'class' keywords had this effect.
 
 **** The GCC __attribute__ keyword is now recognized and ignored.
 
@@ -3248,16 +3248,16 @@ the file FILE.
 
 ** Rmail changes
 
-*** Support for `movemail' from GNU mailutils was added to Rmail.
+*** Support for 'movemail' from GNU mailutils was added to Rmail.
 
-This version of `movemail' allows you to read mail from a wide range of
+This version of 'movemail' allows you to read mail from a wide range of
 mailbox formats, including remote POP3 and IMAP4 mailboxes with or
 without TLS encryption.  If GNU mailutils is installed on the system
-and its version of `movemail' can be found in exec-path, it will be
+and its version of 'movemail' can be found in exec-path, it will be
 used instead of the native one.
 
-*** The new commands rmail-end-of-message and rmail-summary end-of-message,
-by default bound to `/', go to the end of the current mail message in
+*** The new commands 'rmail-end-of-message' and 'rmail-summary-end-of-message',
+by default bound to '/', go to the end of the current mail message in
 Rmail and Rmail summary buffers.
 
 *** Rmail now displays 5-digit message ids in its summary buffer.
@@ -3280,13 +3280,13 @@ version 5.0.2; see MH-E-NEWS for details.
 
 ** Miscellaneous mail changes
 
-*** The new variable `mail-default-directory' specifies
-`default-directory' for mail buffers.  This directory is used for
+*** The new variable 'mail-default-directory' specifies
+'default-directory' for mail buffers.  This directory is used for
 auto-save files of mail buffers.  It defaults to "~/".
 
 *** The mode line can indicate new mail in a directory or file.
 
-See the documentation of the user option `display-time-mail-directory'.
+See the documentation of the user option 'display-time-mail-directory'.
 
 ** Calendar changes
 
@@ -3296,24 +3296,24 @@ convert Emacs diary entries to/from the iCalendar 
format.
 *** The new package cal-html.el writes HTML files with calendar and
 diary entries.
 
-*** The new functions `diary-from-outlook', `diary-from-outlook-gnus',
-and `diary-from-outlook-rmail' can be used to import diary entries
+*** The new functions 'diary-from-outlook', 'diary-from-outlook-gnus',
+and 'diary-from-outlook-rmail' can be used to import diary entries
 from Outlook-format appointments in mail messages.  The variable
-`diary-outlook-formats' can be customized to recognize additional
+'diary-outlook-formats' can be customized to recognize additional
 formats.
 
 *** The procedure for activating appointment reminders has changed:
-use the new function `appt-activate'.  The new variable
-`appt-display-format' controls how reminders are displayed, replacing
-`appt-issue-message', `appt-visible', and `appt-msg-window'.
+use the new function 'appt-activate'.  The new variable
+'appt-display-format' controls how reminders are displayed, replacing
+'appt-issue-message', 'appt-visible', and 'appt-msg-window'.
 
-*** The function `simple-diary-display' now by default sets a header line.
-This can be controlled through the variables `diary-header-line-flag'
-and `diary-header-line-format'.
+*** The function 'simple-diary-display' now by default sets a header line.
+This can be controlled through the variables 'diary-header-line-flag'
+and 'diary-header-line-format'.
 
 *** Diary sexp entries can have custom marking in the calendar.
 Diary sexp functions which only apply to certain days (such as
-`diary-block' or `diary-cyclic') now take an optional parameter MARK,
+'diary-block' or 'diary-cyclic') now take an optional parameter MARK,
 which is the name of a face or a single-character string indicating
 how to highlight the day in the calendar display.  Specifying a
 single-character string as @var{mark} places the character next to the
@@ -3327,76 +3327,76 @@ appointments, paydays or anything else using a sexp.
 *** You can now use < and >, instead of C-x < and C-x >, to scroll
 the calendar left or right.
 
-*** The new function `calendar-goto-day-of-year' (g D) prompts for a
+*** The new function 'calendar-goto-day-of-year' (g D) prompts for a
 year and day number, and moves to that date.  Negative day numbers
 count backward from the end of the year.
 
-*** The new Calendar function `calendar-goto-iso-week' (g w)
+*** The new Calendar function 'calendar-goto-iso-week' (g w)
 prompts for a year and a week number, and moves to the first
 day of that ISO week.
 
-*** The functions `holiday-easter-etc' and `holiday-advent' now take
+*** The functions 'holiday-easter-etc' and 'holiday-advent' now take
 optional arguments, in order to only report on the specified holiday
 rather than all.  This makes customization of variables such as
-`christian-holidays' simpler.
+'christian-holidays' simpler.
 
-*** The new variable `calendar-minimum-window-height' affects the
-window generated by the function `generate-calendar-window'.
+*** The new variable 'calendar-minimum-window-height' affects the
+window generated by the function 'generate-calendar-window'.
 
 ** Speedbar changes
 
 *** Speedbar items can now be selected by clicking mouse-1, based on
-the `mouse-1-click-follows-link' mechanism.
+the 'mouse-1-click-follows-link' mechanism.
 
-*** The new command `speedbar-toggle-line-expansion', bound to SPC,
+*** The new command 'speedbar-toggle-line-expansion', bound to SPC,
 contracts or expands the line under the cursor.
 
-*** New command `speedbar-create-directory', bound to `M'.
+*** New command 'speedbar-create-directory', bound to 'M'.
 
-*** The new commands `speedbar-expand-line-descendants' and
-`speedbar-contract-line-descendants', bound to `[' and `]'
+*** The new commands 'speedbar-expand-line-descendants' and
+'speedbar-contract-line-descendants', bound to '[' and ']'
 respectively, expand and contract the line under cursor with all of
 its descendants.
 
-*** The new user option `speedbar-use-tool-tips-flag', if non-nil,
+*** The new user option 'speedbar-use-tool-tips-flag', if non-nil,
 means to display tool-tips for speedbar items.
 
-*** The new user option `speedbar-query-confirmation-method' controls
+*** The new user option 'speedbar-query-confirmation-method' controls
 how querying is performed for file operations.  A value of 'always
 means to always query before file operations; 'none-but-delete means
 to not query before any file operations, except before a file
 deletion.
 
-*** The new user option `speedbar-select-frame-method' specifies how
+*** The new user option 'speedbar-select-frame-method' specifies how
 to select a frame for displaying a file opened with the speedbar.  A
 value of 'attached means to use the attached frame (the frame that
 speedbar was started from.)  A number such as 1 or -1 means to pass
-that number to `other-frame'.
+that number to 'other-frame'.
 
 *** SPC and DEL are no longer bound to scroll up/down in the speedbar
 keymap.
 
 *** The frame management code in speedbar.el has been split into a new
-`dframe' library.  Emacs Lisp code that makes use of the speedbar
-should use `dframe-attached-frame' instead of
-`speedbar-attached-frame', `dframe-timer' instead of `speedbar-timer',
-`dframe-close-frame' instead of `speedbar-close-frame', and
-`dframe-activity-change-focus-flag' instead of
-`speedbar-activity-change-focus-flag'.  The variables
-`speedbar-update-speed' and `speedbar-navigating-speed' are also
-obsolete; use `dframe-update-speed' instead.
+'dframe' library.  Emacs Lisp code that makes use of the speedbar
+should use 'dframe-attached-frame' instead of
+'speedbar-attached-frame', 'dframe-timer' instead of 'speedbar-timer',
+'dframe-close-frame' instead of 'speedbar-close-frame', and
+'dframe-activity-change-focus-flag' instead of
+'speedbar-activity-change-focus-flag'.  The variables
+'speedbar-update-speed' and 'speedbar-navigating-speed' are also
+obsolete; use 'dframe-update-speed' instead.
 
 ** battery.el changes
 
-*** display-battery-mode replaces display-battery.
+*** 'display-battery-mode' replaces 'display-battery'.
 
 *** battery.el now works on recent versions of Mac OS X.
 
 ** Games
 
-*** The game `mpuz' is enhanced.
+*** The game 'mpuz' is enhanced.
 
-`mpuz' now allows the 2nd factor not to have two identical digits.  By
+'mpuz' now allows the 2nd factor not to have two identical digits.  By
 default, all trivial operations involving whole lines are performed
 automatically.  The game uses faces for better visual feedback.
 
@@ -3412,70 +3412,70 @@ automatically.  The game uses faces for better visual 
feedback.
 
 ** Miscellaneous
 
-*** The variable `woman-topic-at-point' is renamed
-to `woman-use-topic-at-point' and behaves differently: if this
-variable is non-nil, the `woman' command uses the word at point
+*** The variable 'woman-topic-at-point' is renamed
+to 'woman-use-topic-at-point' and behaves differently: if this
+variable is non-nil, the 'woman' command uses the word at point
 automatically, without asking for a confirmation.  Otherwise, the word
 at point is suggested as default, but not inserted at the prompt.
 
-*** You can now customize `fill-nobreak-predicate' to control where
+*** You can now customize 'fill-nobreak-predicate' to control where
 filling can break lines.  The value is now normally a list of
 functions, but it can also be a single function, for compatibility.
 
-Emacs provide two predicates, `fill-single-word-nobreak-p' and
-`fill-french-nobreak-p', for use as the value of
-`fill-nobreak-predicate'.
+Emacs provide two predicates, 'fill-single-word-nobreak-p' and
+'fill-french-nobreak-p', for use as the value of
+'fill-nobreak-predicate'.
 
 *** M-x view-file and commands that use it now avoid interfering
 with special modes such as Tar mode.
 
-*** `global-whitespace-mode' is a new alias for `whitespace-global-mode'.
+*** 'global-whitespace-mode' is a new alias for 'whitespace-global-mode'.
 
 *** The saveplace.el package now filters out unreadable files.
 
 When you exit Emacs, the saved positions in visited files no longer
 include files that aren't readable, e.g. files that don't exist.
-Customize the new option `save-place-forget-unreadable-files' to nil
-to get the old behavior.  The new options `save-place-save-skipped'
-and `save-place-skip-check-regexp' allow further fine-tuning of this
+Customize the new option 'save-place-forget-unreadable-files' to nil
+to get the old behavior.  The new options 'save-place-save-skipped'
+and 'save-place-skip-check-regexp' allow further fine-tuning of this
 feature.
 
-*** Commands `winner-redo' and `winner-undo', from winner.el, are now
+*** Commands 'winner-redo' and 'winner-undo', from winner.el, are now
 bound to C-c <left> and C-c <right>, respectively.  This is an
 incompatible change.
 
-*** The type-break package now allows `type-break-file-name' to be nil
+*** The 'type-break' package now allows 'type-break-file-name' to be nil
 and if so, doesn't store any data across sessions.  This is handy if
-you don't want the `.type-break' file in your home directory or are
+you don't want the '.type-break' file in your home directory or are
 annoyed by the need for interaction when you kill Emacs.
 
-*** `ps-print' can now print characters from the mule-unicode charsets.
+*** 'ps-print' can now print characters from the mule-unicode charsets.
 
 Printing text with characters from the mule-unicode-* sets works with
-`ps-print', provided that you have installed the appropriate BDF
+'ps-print', provided that you have installed the appropriate BDF
 fonts.  See the file INSTALL for URLs where you can find these fonts.
 
-*** New command `strokes-global-set-stroke-string'.
-This is like `strokes-global-set-stroke', but it allows you to bind
+*** New command 'strokes-global-set-stroke-string'.
+This is like 'strokes-global-set-stroke', but it allows you to bind
 the stroke directly to a string to insert.  This is convenient for
 using strokes as an input method.
 
-*** In Outline mode, `hide-body' no longer hides lines at the top
+*** In Outline mode, 'hide-body' no longer hides lines at the top
 of the file that precede the first header line.
 
-*** `hide-ifdef-mode' now uses overlays rather than selective-display
+*** 'hide-ifdef-mode' now uses overlays rather than selective-display
 to hide its text.  This should be mostly transparent but slightly
 changes the behavior of motion commands like C-e and C-p.
 
-*** In Artist mode the variable `artist-text-renderer' has been
-renamed to `artist-text-renderer-function'.  The old name is still
+*** In Artist mode the variable 'artist-text-renderer' has been
+renamed to 'artist-text-renderer-function'.  The old name is still
 available as alias.
 
-*** In Enriched mode, `set-left-margin' and `set-right-margin' are now
-by default bound to `C-c [' and `C-c ]' instead of the former `C-c C-l'
-and `C-c C-r'.
+*** In Enriched mode, 'set-left-margin' and 'set-right-margin' are now
+by default bound to 'C-c [' and 'C-c ]' instead of the former 'C-c C-l'
+and 'C-c C-r'.
 
-*** `partial-completion-mode' now handles partial completion on directory 
names.
+*** 'partial-completion-mode' now handles partial completion on directory 
names.
 
 *** You can now disable pc-selection-mode after enabling it.
 
@@ -3483,10 +3483,10 @@ M-x pc-selection-mode behaves like a proper minor mode, 
and with no
 argument it toggles the mode.  Turning off PC-Selection mode restores
 the global key bindings that were replaced by turning on the mode.
 
-*** `uniquify-strip-common-suffix' tells uniquify to prefer
-`file|dir1' and `file|dir2' to `file|dir1/subdir' and `file|dir2/subdir'.
+*** 'uniquify-strip-common-suffix' tells uniquify to prefer
+'file|dir1' and 'file|dir2' to 'file|dir1/subdir' and 'file|dir2/subdir'.
 
-*** New user option `add-log-always-start-new-record'.
+*** New user option 'add-log-always-start-new-record'.
 
 When this option is enabled, M-x add-change-log-entry always
 starts a new record regardless of when the last record is.
@@ -3501,17 +3501,17 @@ when Emacs visits them.
 
 *** calculator.el now has radix grouping mode.
 
-To enable this, set `calculator-output-radix' non-nil.  In this mode a
+To enable this, set 'calculator-output-radix' non-nil.  In this mode a
 separator character is used every few digits, making it easier to see
 byte boundaries etc.  For more info, see the documentation of the
-variable `calculator-radix-grouping-mode'.
+variable 'calculator-radix-grouping-mode'.
 
 *** LDAP support now defaults to ldapsearch from OpenLDAP version 2.
 
 *** The terminal emulation code in term.el has been improved; it can
 run most curses applications now.
 
-*** Support for `magic cookie' standout modes has been removed.
+*** Support for 'magic cookie' standout modes has been removed.
 
 Emacs still works on terminals that require magic cookies in order to
 use standout mode, but they can no longer display mode-lines in
@@ -3523,14 +3523,14 @@ inverse-video.
 ** The HOME directory defaults to Application Data under the user profile.
 
 If you used a previous version of Emacs without setting the HOME
-environment variable and a `.emacs' was saved, then Emacs will continue
+environment variable and a '.emacs' was saved, then Emacs will continue
 using C:/ as the default HOME.  But if you are installing Emacs afresh,
 the default location will be the "Application Data" (or similar
 localized name) subdirectory of your user profile.  A typical location
 of this directory is "C:\Documents and Settings\USERNAME\Application Data",
 where USERNAME is your user name.
 
-This change means that users can now have their own `.emacs' files on
+This change means that users can now have their own '.emacs' files on
 shared computers, and the default HOME directory is less likely to be
 read-only on computers that are administered by someone else.
 
@@ -3556,7 +3556,7 @@ See the Emacs 21.1 NEWS entry for tooltips for details.
 
 ** Pointing devices with more than 3 buttons are now supported on MS Windows.
 
-The new variable `w32-pass-extra-mouse-buttons-to-system' controls
+The new variable 'w32-pass-extra-mouse-buttons-to-system' controls
 whether Emacs should handle the extra buttons itself (the default), or
 pass them to Windows to be handled with system-wide functions.
 
@@ -3577,7 +3577,7 @@ the same way as wildcard X Resources do on X.  Emacs now 
adds these
 colors to the colormap prefixed by System (eg SystemMenu for the
 default Menu background, SystemMenuText for the foreground), and uses
 some of them to initialize some of the default faces.
-`list-colors-display' shows the list of System color names, in case
+'list-colors-display' shows the list of System color names, in case
 you wish to use them in other faces.
 
 ** Running in a console window in Windows now uses the console size.
@@ -3614,30 +3614,30 @@ MS Windows, Emacs now uses the appropriate locale 
coding-system, so
 the clipboard should work correctly for your local language without
 any customizations.
 
-** On Mac OS, `keyboard-coding-system' changes based on the keyboard script.
+** On Mac OS, 'keyboard-coding-system' changes based on the keyboard script.
 
-** The variable `mac-keyboard-text-encoding' and the constants
-`kTextEncodingMacRoman', `kTextEncodingISOLatin1', and
-`kTextEncodingISOLatin2' are obsolete.
+** The variable 'mac-keyboard-text-encoding' and the constants
+'kTextEncodingMacRoman', 'kTextEncodingISOLatin1', and
+'kTextEncodingISOLatin2' are obsolete.
 
-** The variable `mac-command-key-is-meta' is obsolete.  Use
-`mac-command-modifier' and `mac-option-modifier' instead.
+** The variable 'mac-command-key-is-meta' is obsolete.  Use
+'mac-command-modifier' and 'mac-option-modifier' instead.
 
 * Incompatible Lisp Changes in Emacs 22.1
 
 ** Mode line display ignores text properties as well as the
 :propertize and :eval forms in the value of a variable whose
-`risky-local-variable' property is nil.
+'risky-local-variable' property is nil.
 
-The function `comint-send-input' now accepts 3 optional arguments:
+The function 'comint-send-input' now accepts 3 optional arguments:
 
   (comint-send-input &optional no-newline artificial)
 
 Callers sending input not from the user should use bind the 3rd
-argument `artificial' to a non-nil value, to prevent Emacs from
+argument 'artificial' to a non-nil value, to prevent Emacs from
 deleting the part of subprocess output that matches the input.
 
-** The `read-file-name' function now returns a null string if the
+** The 'read-file-name' function now returns a null string if the
 user just types RET.
 
 ** The variables post-command-idle-hook and post-command-idle-delay have
@@ -3650,28 +3650,28 @@ be multibyte or unibyte, respectively.
 combining a face number and a character code into a numeric
 glyph code is deprecated.
 
-Instead, the new functions `make-glyph-code', `glyph-char', and
-`glyph-face' must be used to create and decode glyph codes in
+Instead, the new functions 'make-glyph-code', 'glyph-char', and
+'glyph-face' must be used to create and decode glyph codes in
 display tables.
 
-** `suppress-keymap' now works by remapping `self-insert-command' to
-the command `undefined'.  (In earlier Emacs versions, it used
-`substitute-key-definition' to rebind self inserting characters to
-`undefined'.)
+** 'suppress-keymap' now works by remapping 'self-insert-command' to
+the command 'undefined'.  (In earlier Emacs versions, it used
+'substitute-key-definition' to rebind self inserting characters to
+'undefined'.)
 
-** The third argument of `accept-process-output' is now milliseconds.
+** The third argument of 'accept-process-output' is now milliseconds.
 It used to be microseconds.
 
-** The function find-operation-coding-system may be called with a cons
+** The function 'find-operation-coding-system' may be called with a cons
 (FILENAME . BUFFER) in the second argument if the first argument
-OPERATION is `insert-file-contents', and thus a function registered in
-`file-coding-system-alist' is also called with such an argument.
+OPERATION is 'insert-file-contents', and thus a function registered in
+'file-coding-system-alist' is also called with such an argument.
 
 ** When Emacs receives a USR1 or USR2 signal, this generates
 input events: sigusr1 or sigusr2.  Use special-event-map to
 handle these events.
 
-** The variable `memory-full' now remains t until
+** The variable 'memory-full' now remains t until
 there is no longer a shortage of memory.
 
 ** Support for Mocklisp has been removed.
@@ -3683,139 +3683,139 @@ there is no longer a shortage of memory.
 
 *** New syntax: \s now stands for the SPACE character.
 
-`?\s' is a new way to write the space character.  You must make sure
-it is not followed by a dash, since `?\s-...' indicates the "super"
+'?\s' is a new way to write the space character.  You must make sure
+it is not followed by a dash, since '?\s-...' indicates the "super"
 modifier.  However, it would be strange to write a character constant
-and a following symbol (beginning with `-') with no space between
+and a following symbol (beginning with '-') with no space between
 them.
 
-`\s' stands for space in strings, too, but it is not really meant for
+'\s' stands for space in strings, too, but it is not really meant for
 strings; it is easier and nicer just to write a space.
 
 *** New syntax: \uXXXX and \UXXXXXXXX specify Unicode code points in hex.
 
 For instance, you can use "\u0428" to specify a string consisting of
-CYRILLIC CAPITAL LETTER SHA, or `"U0001D6E2" to specify one consisting
+CYRILLIC CAPITAL LETTER SHA, or "\U0001D6E2" to specify one consisting
 of MATHEMATICAL ITALIC CAPITAL ALPHA (the latter is greater than
 #xFFFF and thus needs the longer syntax).
 
 This syntax works for both character constants and strings.
 
-*** New function `unsafep' determines whether a Lisp form is safe.
+*** New function 'unsafep' determines whether a Lisp form is safe.
 
 It returns nil if the given Lisp form can't possibly do anything
 dangerous; otherwise it returns a reason why the form might be unsafe
 (calls unknown function, alters global variable, etc.).
 
-*** The function `eql' is now available without requiring the CL package.
+*** The function 'eql' is now available without requiring the CL package.
 
-*** The new function `memql' is like `memq', but uses `eql' for comparison,
-that is, floats are compared by value and other elements with `eq'.
+*** The new function 'memql' is like 'memq', but uses 'eql' for comparison,
+that is, floats are compared by value and other elements with 'eq'.
 
-*** New functions `string-or-null-p' and `booleanp'.
+*** New functions 'string-or-null-p' and 'booleanp'.
 
-`string-or-null-p' returns non-nil if OBJECT is a string or nil.
-`booleanp' returns non-nil if OBJECT is t or nil.
+'string-or-null-p' returns non-nil if OBJECT is a string or nil.
+'booleanp' returns non-nil if OBJECT is t or nil.
 
-*** `makehash' is now obsolete.  Use `make-hash-table' instead.
+*** 'makehash' is now obsolete.  Use 'make-hash-table' instead.
 
-*** Minor change in the function `format'.
+*** Minor change in the function 'format'.
 
 Some flags that were accepted but not implemented (such as "*") are no
 longer accepted.
 
-*** `add-to-list' takes an optional third argument, APPEND.
+*** 'add-to-list' takes an optional third argument, APPEND.
 
 If APPEND is non-nil, the new element gets added at the end of the
 list instead of at the beginning.  This change actually occurred in
 Emacs 21.1, but was not documented then.
 
-*** New function `add-to-ordered-list' is like `add-to-list' but
+*** New function 'add-to-ordered-list' is like 'add-to-list' but
 associates a numeric ordering of each element added to the list.
 
-*** New function `add-to-history' adds an element to a history list.
+*** New function 'add-to-history' adds an element to a history list.
 
 Lisp packages should use this function to add elements to their
 history lists.
 
-If `history-delete-duplicates' is non-nil, it removes duplicates of
+If 'history-delete-duplicates' is non-nil, it removes duplicates of
 the new element from the history list it updates.
 
-*** New function `copy-tree' makes a copy of a tree.
+*** New function 'copy-tree' makes a copy of a tree.
 
 It recursively copies through both CARs and CDRs.
 
-*** New function `delete-dups' deletes `equal' duplicate elements from a list.
+*** New function 'delete-dups' deletes 'equal' duplicate elements from a list.
 
-It modifies the list destructively, like `delete'.  Of several `equal'
+It modifies the list destructively, like 'delete'.  Of several 'equal'
 occurrences of an element in the list, the one that's kept is the
 first one.
 
-*** New function `rassq-delete-all'.
+*** New function 'rassq-delete-all'.
 
 (rassq-delete-all VALUE ALIST) deletes, from ALIST, each element whose
-CDR is `eq' to the specified value.
+CDR is 'eq' to the specified value.
 
-*** Functions `get' and `plist-get' no longer give errors for bad plists.
+*** Functions 'get' and 'plist-get' no longer give errors for bad plists.
 
 They return nil for a malformed property list or if the list is
 cyclic.
 
-*** New functions `lax-plist-get' and `lax-plist-put'.
+*** New functions 'lax-plist-get' and 'lax-plist-put'.
 
-They are like `plist-get' and `plist-put', except that they compare
-the property name using `equal' rather than `eq'.
+They are like 'plist-get' and 'plist-put', except that they compare
+the property name using 'equal' rather than 'eq'.
 
-*** The function `number-sequence' makes a list of equally-separated numbers.
+*** The function 'number-sequence' makes a list of equally-separated numbers.
 
 For instance, (number-sequence 4 9) returns (4 5 6 7 8 9).  By
 default, the separation is 1, but you can specify a different
 separation as the third argument.  (number-sequence 1.5 6 2) returns
 (1.5 3.5 5.5).
 
-*** New variables `most-positive-fixnum' and `most-negative-fixnum'.
+*** New variables 'most-positive-fixnum' and 'most-negative-fixnum'.
 
 They hold the largest and smallest possible integer values.
 
-*** The function `expt' handles negative exponents differently.
-The value for `(expt A B)', if both A and B are integers and B is
+*** The function 'expt' handles negative exponents differently.
+The value for '(expt A B)', if both A and B are integers and B is
 negative, is now a float.  For example: (expt 2 -2) => 0.25.
 
-*** The function `atan' now accepts an optional second argument.
+*** The function 'atan' now accepts an optional second argument.
 
-When called with 2 arguments, as in `(atan Y X)', `atan' returns the
+When called with 2 arguments, as in '(atan Y X)', 'atan' returns the
 angle in radians between the vector [X, Y] and the X axis.  (This is
-equivalent to the standard C library function `atan2'.)
+equivalent to the standard C library function 'atan2'.)
 
-*** New macro `with-case-table'
+*** New macro 'with-case-table'
 
 This executes the body with the case table temporarily set to a given
 case table.
 
-*** New macro `with-local-quit' temporarily allows quitting.
+*** New macro 'with-local-quit' temporarily allows quitting.
 
-A quit inside the body of `with-local-quit' is caught by the
-`with-local-quit' form itself, but another quit will happen later once
+A quit inside the body of 'with-local-quit' is caught by the
+'with-local-quit' form itself, but another quit will happen later once
 the code that has inhibited quitting exits.
 
 This is for use around potentially blocking or long-running code
-inside timer functions and `post-command-hook' functions.
+inside timer functions and 'post-command-hook' functions.
 
-*** New macro `define-obsolete-function-alias'.
+*** New macro 'define-obsolete-function-alias'.
 
-This combines `defalias' and `make-obsolete'.
+This combines 'defalias' and 'make-obsolete'.
 
-*** New macro `eval-at-startup' specifies expressions to
+*** New macro 'eval-at-startup' specifies expressions to
 evaluate when Emacs starts up.  If this is done after startup,
 it evaluates those expressions immediately.
 
 This is useful in packages that can be preloaded.
 
-*** New function `macroexpand-all' expands all macros in a form.
+*** New function 'macroexpand-all' expands all macros in a form.
 
 It is similar to the Common-Lisp function of the same name.
 One difference is that it guarantees to return the original argument
-if no expansion is done, which can be tested using `eq'.
+if no expansion is done, which can be tested using 'eq'.
 
 *** A function or macro's doc string can now specify the calling pattern.
 
@@ -3824,60 +3824,60 @@ formatted so as to match the regexp "\n\n(fn .*)\\'".  
If you don't
 specify this explicitly, Emacs determines it from the actual argument
 names.  Usually that default is right, but not always.
 
-*** New variable `print-continuous-numbering'.
+*** New variable 'print-continuous-numbering'.
 
 When this is non-nil, successive calls to print functions use a single
 numbering scheme for circular structure references.  This is only
-relevant when `print-circle' is non-nil.
+relevant when 'print-circle' is non-nil.
 
-When you bind `print-continuous-numbering' to t, you should
-also bind `print-number-table' to nil.
+When you bind 'print-continuous-numbering' to t, you should
+also bind 'print-number-table' to nil.
 
-*** `list-faces-display' takes an optional argument, REGEXP.
+*** 'list-faces-display' takes an optional argument, REGEXP.
 
 If it is non-nil, the function lists only faces matching this regexp.
 
-*** New hook `command-error-function'.
+*** New hook 'command-error-function'.
 
 By setting this variable to a function, you can control
 how the editor command loop shows the user an error message.
 
-*** `debug-on-entry' accepts primitive functions that are not special forms.
+*** 'debug-on-entry' accepts primitive functions that are not special forms.
 
 ** Lisp code indentation features:
 
-*** The `defmacro' form can contain indentation and edebug declarations.
+*** The 'defmacro' form can contain indentation and edebug declarations.
 
 These declarations specify how to indent the macro calls in Lisp mode
 and how to debug them with Edebug.  You write them like this:
 
    (defmacro NAME LAMBDA-LIST [DOC-STRING] [DECLARATION ...] ...)
 
-DECLARATION is a list `(declare DECLARATION-SPECIFIER ...)'.  The
+DECLARATION is a list '(declare DECLARATION-SPECIFIER ...)'.  The
 possible declaration specifiers are:
 
 (indent INDENT)
-       Set NAME's `lisp-indent-function' property to INDENT.
+       Set NAME's 'lisp-indent-function' property to INDENT.
 
 (edebug DEBUG)
-       Set NAME's `edebug-form-spec' property to DEBUG.  (This is
-       equivalent to writing a `def-edebug-spec' for the macro,
+       Set NAME's 'edebug-form-spec' property to DEBUG.  (This is
+       equivalent to writing a 'def-edebug-spec' for the macro,
        but this is cleaner.)
 
 *** cl-indent now allows customization of Indentation of backquoted forms.
 
-See the new user option `lisp-backquote-indentation'.
+See the new user option 'lisp-backquote-indentation'.
 
-*** cl-indent now handles indentation of simple and extended `loop' forms.
+*** cl-indent now handles indentation of simple and extended 'loop' forms.
 
-The new user options `lisp-loop-keyword-indentation',
-`lisp-loop-forms-indentation', and `lisp-simple-loop-indentation' can
+The new user options 'lisp-loop-keyword-indentation',
+'lisp-loop-forms-indentation', and 'lisp-simple-loop-indentation' can
 be used to customize the indentation of keywords and forms in loop
 forms.
 
 ** Variable aliases:
 
-*** New function: defvaralias ALIAS-VAR BASE-VAR [DOCSTRING]
+*** New function: 'defvaralias' ALIAS-VAR BASE-VAR [DOCSTRING]
 
 This function defines the symbol ALIAS-VAR as a variable alias for
 symbol BASE-VAR.  This means that retrieving the value of ALIAS-VAR
@@ -3887,10 +3887,10 @@ changes the value of BASE-VAR.
 DOCSTRING, if present, is the documentation for ALIAS-VAR; else it has
 the same documentation as BASE-VAR.
 
-*** The macro `define-obsolete-variable-alias' combines `defvaralias' and
-`make-obsolete-variable'.
+*** The macro 'define-obsolete-variable-alias' combines 'defvaralias' and
+'make-obsolete-variable'.
 
-*** New function: indirect-variable VARIABLE
+*** New function: 'indirect-variable' VARIABLE
 
 This function returns the variable at the end of the chain of aliases
 of VARIABLE.  If VARIABLE is not a symbol, or if VARIABLE is not
@@ -3901,12 +3901,12 @@ variables, including buffer-local and frame-local 
variables.
 
 ** defcustom changes:
 
-*** The package-version keyword has been added to provide
-`customize-changed-options' functionality to packages in the future.
+*** The ':package-version' keyword has been added to provide
+'customize-changed-options' functionality to packages in the future.
 Developers who make use of this keyword must also update the new
-variable `customize-package-emacs-version-alist'.
+variable 'customize-package-emacs-version-alist'.
 
-*** The new customization type `float' requires a floating point number.
+*** The new customization type 'float' requires a floating point number.
 
 ** String changes:
 
@@ -3914,27 +3914,27 @@ variable `customize-package-emacs-version-alist'.
 
 *** An octal escape in a string constant forces the string to be unibyte.
 
-*** New function `string-to-multibyte' converts a unibyte string to a
+*** New function 'string-to-multibyte' converts a unibyte string to a
 multibyte string with the same individual character codes.
 
-*** `split-string' now includes null substrings in the returned list if
+*** 'split-string' now includes null substrings in the returned list if
 the optional argument SEPARATORS is non-nil and there are matches for
 SEPARATORS at the beginning or end of the string.  If SEPARATORS is
 nil, or if the new optional third argument OMIT-NULLS is non-nil, all
 empty matches are omitted from the returned list.
 
-*** The new function `assoc-string' replaces `assoc-ignore-case' and
-`assoc-ignore-representation', which are still available, but have
+*** The new function 'assoc-string' replaces 'assoc-ignore-case' and
+'assoc-ignore-representation', which are still available, but have
 been declared obsolete.
 
-*** New function `substring-no-properties' returns a substring without
+*** New function 'substring-no-properties' returns a substring without
 text properties.
 
 ** Displaying warnings to the user.
 
-See the functions `warn' and `display-warning', or the Lisp Manual.
+See the functions 'warn' and 'display-warning', or the Lisp Manual.
 If you want to be sure the warning will not be overlooked, this
-facility is much better than using `message', since it displays
+facility is much better than using 'message', since it displays
 warnings in a separate window.
 
 ** Progress reporters.
@@ -3942,112 +3942,112 @@ warnings in a separate window.
 These provide a simple and uniform way for commands to present
 progress messages for the user.
 
-See the new functions `make-progress-reporter',
-`progress-reporter-update', `progress-reporter-force-update',
-`progress-reporter-done', and `dotimes-with-progress-reporter'.
+See the new functions 'make-progress-reporter',
+'progress-reporter-update', 'progress-reporter-force-update',
+'progress-reporter-done', and 'dotimes-with-progress-reporter'.
 
 ** Buffer positions:
 
-*** Function `compute-motion' now calculates the usable window
+*** Function 'compute-motion' now calculates the usable window
 width if the WIDTH argument is nil.  If the TOPOS argument is nil,
 the usable window height and width is used.
 
-*** The `line-move', `scroll-up', and `scroll-down' functions will now
+*** The 'line-move', 'scroll-up', and 'scroll-down' functions will now
 modify the window vscroll to scroll through display rows that are
 taller that the height of the window, for example in the presence of
 large images.  To disable this feature, bind the new variable
-`auto-window-vscroll' to nil.
+'auto-window-vscroll' to nil.
 
-*** The argument to `forward-word', `backward-word' is optional.
+*** The argument to 'forward-word', 'backward-word' is optional.
 
 It defaults to 1.
 
-*** Argument to `forward-to-indentation' and `backward-to-indentation' is 
optional.
+*** Argument to 'forward-to-indentation' and 'backward-to-indentation' is 
optional.
 
 It defaults to 1.
 
-*** `field-beginning' and `field-end' take new optional argument, LIMIT.
+*** 'field-beginning' and 'field-end' take new optional argument, LIMIT.
 
 This argument tells them not to search beyond LIMIT.  Instead they
 give up and return LIMIT.
 
-*** New function `window-line-height' is an efficient way to get
+*** New function 'window-line-height' is an efficient way to get
 information about a specific text line in a window provided that the
 window's display is up-to-date.
 
-*** New function `line-number-at-pos' returns the line number of a position.
+*** New function 'line-number-at-pos' returns the line number of a position.
 
 It an optional buffer position argument that defaults to point.
 
-*** Function `pos-visible-in-window-p' now returns the pixel coordinates
+*** Function 'pos-visible-in-window-p' now returns the pixel coordinates
 and partial visibility state of the corresponding row, if the PARTIALLY
 arg is non-nil.
 
-*** New functions `posn-at-point' and `posn-at-x-y' return
+*** New functions 'posn-at-point' and 'posn-at-x-y' return
 click-event-style position information for a given visible buffer
 position or for a given window pixel coordinate.
 
-*** New function `mouse-on-link-p' tests if a position is in a clickable link.
+*** New function 'mouse-on-link-p' tests if a position is in a clickable link.
 
-This is the function used by the new `mouse-1-click-follows-link'
+This is the function used by the new 'mouse-1-click-follows-link'
 functionality.
 
 ** Text modification:
 
-*** The new function `buffer-chars-modified-tick' returns a buffer's
+*** The new function 'buffer-chars-modified-tick' returns a buffer's
 tick counter for changes to characters.  Each time text in that buffer
 is inserted or deleted, the character-change counter is updated to the
-tick counter (`buffer-modified-tick').  Text property changes leave it
+tick counter ('buffer-modified-tick').  Text property changes leave it
 unchanged.
 
-*** The new function `insert-for-yank' normally works like `insert', but
-removes the text properties in the `yank-excluded-properties' list
-and handles the `yank-handler' text property.
+*** The new function 'insert-for-yank' normally works like 'insert', but
+removes the text properties in the 'yank-excluded-properties' list
+and handles the 'yank-handler' text property.
 
-*** The new function `insert-buffer-substring-as-yank' is like
-`insert-for-yank' except that it gets the text from another buffer as
-in `insert-buffer-substring'.
+*** The new function 'insert-buffer-substring-as-yank' is like
+'insert-for-yank' except that it gets the text from another buffer as
+in 'insert-buffer-substring'.
 
-*** The new function `insert-buffer-substring-no-properties' is like
-`insert-buffer-substring', but removes all text properties from the
+*** The new function 'insert-buffer-substring-no-properties' is like
+'insert-buffer-substring', but removes all text properties from the
 inserted substring.
 
-*** The new function `filter-buffer-substring' extracts a buffer
+*** The new function 'filter-buffer-substring' extracts a buffer
 substring, passes it through a set of filter functions, and returns
-the filtered substring.  Use it instead of `buffer-substring' or
-`delete-and-extract-region' when copying text into a user-accessible
+the filtered substring.  Use it instead of 'buffer-substring' or
+'delete-and-extract-region' when copying text into a user-accessible
 data structure, such as the kill-ring, X clipboard, or a register.
 
 The list of filter function is specified by the new variable
-`buffer-substring-filters'.  For example, Longlines mode adds to
-`buffer-substring-filters' to remove soft newlines from the copied
+'buffer-substring-filters'.  For example, Longlines mode adds to
+'buffer-substring-filters' to remove soft newlines from the copied
 text.
 
-*** Function `translate-region' accepts also a char-table as TABLE
+*** Function 'translate-region' accepts also a char-table as TABLE
 argument.
 
-*** The new translation table `translation-table-for-input'
+*** The new translation table 'translation-table-for-input'
 is used for customizing self-insertion.  The character to
 be inserted is translated through it.
 
 *** Text clones.
 
-The new function `text-clone-create'.  Text clones are chunks of text
+The new function 'text-clone-create'.  Text clones are chunks of text
 that are kept identical by transparently propagating changes from one
 clone to the other.
 
-*** The function `insert-string' is now obsolete.
+*** The function 'insert-string' is now obsolete.
 
 ** Filling changes.
 
 *** In determining an adaptive fill prefix, Emacs now tries the function in
-`adaptive-fill-function' _before_ matching the buffer line against
-`adaptive-fill-regexp' rather than _after_ it.
+'adaptive-fill-function' _before_ matching the buffer line against
+'adaptive-fill-regexp' rather than _after_ it.
 
 ** Atomic change groups.
 
 To perform some changes in the current buffer "atomically" so that
-they either all succeed or are all undone, use `atomic-change-group'
+they either all succeed or are all undone, use 'atomic-change-group'
 around the code that makes changes.  For instance:
 
   (atomic-change-group
@@ -4055,45 +4055,45 @@ around the code that makes changes.  For instance:
     (delete-region x y))
 
 If an error (or other nonlocal exit) occurs inside the body of
-`atomic-change-group', it unmakes all the changes in that buffer that
+'atomic-change-group', it unmakes all the changes in that buffer that
 were during the execution of the body.  The change group has no effect
 on any other buffers--any such changes remain.
 
 If you need something more sophisticated, you can directly call the
-lower-level functions that `atomic-change-group' uses.  Here is how.
+lower-level functions that 'atomic-change-group' uses.  Here is how.
 
-To set up a change group for one buffer, call `prepare-change-group'.
+To set up a change group for one buffer, call 'prepare-change-group'.
 Specify the buffer as argument; it defaults to the current buffer.
 This function returns a "handle" for the change group.  You must save
 the handle to activate the change group and then finish it.
 
 Before you change the buffer again, you must activate the change
-group.  Pass the handle to `activate-change-group' afterward to
+group.  Pass the handle to 'activate-change-group' afterward to
 do this.
 
 After you make the changes, you must finish the change group.  You can
 either accept the changes or cancel them all.  Call
-`accept-change-group' to accept the changes in the group as final;
-call `cancel-change-group' to undo them all.
-
-You should use `unwind-protect' to make sure the group is always
-finished.  The call to `activate-change-group' should be inside the
-`unwind-protect', in case the user types C-g just after it runs.
-(This is one reason why `prepare-change-group' and
-`activate-change-group' are separate functions.)  Once you finish the
+'accept-change-group' to accept the changes in the group as final;
+call 'cancel-change-group' to undo them all.
+
+You should use 'unwind-protect' to make sure the group is always
+finished.  The call to 'activate-change-group' should be inside the
+'unwind-protect', in case the user types C-g just after it runs.
+(This is one reason why 'prepare-change-group' and
+'activate-change-group' are separate functions.)  Once you finish the
 group, don't use the handle again--don't try to finish the same group
 twice.
 
-To make a multibuffer change group, call `prepare-change-group' once
-for each buffer you want to cover, then use `nconc' to combine the
+To make a multibuffer change group, call 'prepare-change-group' once
+for each buffer you want to cover, then use 'nconc' to combine the
 returned values, like this:
 
   (nconc (prepare-change-group buffer-1)
          (prepare-change-group buffer-2))
 
 You can then activate the multibuffer change group with a single call
-to `activate-change-group', and finish it with a single call to
-`accept-change-group' or `cancel-change-group'.
+to 'activate-change-group', and finish it with a single call to
+'accept-change-group' or 'cancel-change-group'.
 
 Nested use of several change groups for the same buffer works as you
 would expect.  Non-nested use of change groups for the same buffer
@@ -4103,91 +4103,91 @@ finished.
 
 ** Buffer-related changes:
 
-*** The new function `buffer-local-value' returns the buffer-local
+*** The new function 'buffer-local-value' returns the buffer-local
 binding of VARIABLE (a symbol) in buffer BUFFER.  If VARIABLE does not
 have a buffer-local binding in buffer BUFFER, it returns the default
 value of VARIABLE instead.
 
-*** `list-buffers-noselect' now takes an additional argument, BUFFER-LIST.
+*** 'list-buffers-noselect' now takes an additional argument, BUFFER-LIST.
 
 If it is non-nil, it specifies which buffers to list.
 
-*** `kill-buffer-hook' is now a permanent local.
+*** 'kill-buffer-hook' is now a permanent local.
 
-*** The function `frame-or-buffer-changed-p' now lets you maintain
+*** The function 'frame-or-buffer-changed-p' now lets you maintain
 various status records in parallel.
 
 It takes a variable (a symbol) as argument.  If the variable is non-nil,
 then its value should be a vector installed previously by
-`frame-or-buffer-changed-p'.  If the frame names, buffer names, buffer
+'frame-or-buffer-changed-p'.  If the frame names, buffer names, buffer
 order, or their read-only or modified flags have changed, since the
 time the vector's contents were recorded by a previous call to
-`frame-or-buffer-changed-p', then the function returns t.  Otherwise
+'frame-or-buffer-changed-p', then the function returns t.  Otherwise
 it returns nil.
 
-On the first call to `frame-or-buffer-changed-p', the variable's
-value should be nil.  `frame-or-buffer-changed-p' stores a suitable
+On the first call to 'frame-or-buffer-changed-p', the variable's
+value should be nil.  'frame-or-buffer-changed-p' stores a suitable
 vector into the variable and returns t.
 
-If the variable is itself nil, then `frame-or-buffer-changed-p' uses,
+If the variable is itself nil, then 'frame-or-buffer-changed-p' uses,
 for compatibility, an internal variable which exists only for this
 purpose.
 
-*** The function `read-buffer' follows the convention for reading from
+*** The function 'read-buffer' follows the convention for reading from
 the minibuffer with a default value: if DEF is non-nil, the minibuffer
 prompt provided in PROMPT is edited to show the default value provided
 in DEF before the terminal colon and space.
 
 ** Searching and matching changes:
 
-*** New function `looking-back' checks whether a regular expression matches
+*** New function 'looking-back' checks whether a regular expression matches
 the text before point.  Specifying the LIMIT argument bounds how far
 back the match can start; this is a way to keep it from taking too long.
 
-*** The new variable `search-spaces-regexp' controls how to search
+*** The new variable 'search-spaces-regexp' controls how to search
 for spaces in a regular expression.  If it is non-nil, it should be a
 regular expression, and any series of spaces stands for that regular
 expression.  If it is nil, spaces stand for themselves.
 
-Spaces inside of constructs such as `[..]' and inside loops such as
-`*', `+', and `?' are never replaced with `search-spaces-regexp'.
+Spaces inside of constructs such as '[..]' and inside loops such as
+'*', '+', and '?' are never replaced with 'search-spaces-regexp'.
 
-*** New regular expression operators, `\_<' and `\_>'.
+*** New regular expression operators, '\_<' and '\_>'.
 
 These match the beginning and end of a symbol.  A symbol is a
 non-empty sequence of either word or symbol constituent characters, as
 specified by the syntax table.
 
-*** `skip-chars-forward' and `skip-chars-backward' now handle
-character classes such as `[:alpha:]', along with individual
+*** 'skip-chars-forward' and 'skip-chars-backward' now handle
+character classes such as '[:alpha:]', along with individual
 characters and ranges.
 
-*** In `replace-match', the replacement text no longer inherits
+*** In 'replace-match', the replacement text no longer inherits
 properties from surrounding text.
 
-*** The list returned by `(match-data t)' now has the buffer as a final
-element, if the last match was on a buffer.  `set-match-data'
+*** The list returned by '(match-data t)' now has the buffer as a final
+element, if the last match was on a buffer.  'set-match-data'
 accepts such a list for restoring the match state.
 
-*** Functions `match-data' and `set-match-data' now have an optional
-argument `reseat'.  When non-nil, all markers in the match data list
+*** Functions 'match-data' and 'set-match-data' now have an optional
+argument 'reseat'.  When non-nil, all markers in the match data list
 passed to these functions will be reseated to point to nowhere.
 
-*** rx.el has new corresponding `symbol-start' and `symbol-end' elements.
+*** rx.el has new corresponding 'symbol-start' and 'symbol-end' elements.
 
-*** The default value of `sentence-end' is now defined using the new
-variable `sentence-end-without-space', which contains such characters
+*** The default value of 'sentence-end' is now defined using the new
+variable 'sentence-end-without-space', which contains such characters
 that end a sentence without following spaces.
 
-The function `sentence-end' should be used to obtain the value of the
-variable `sentence-end'.  If the variable `sentence-end' is nil, then
+The function 'sentence-end' should be used to obtain the value of the
+variable 'sentence-end'.  If the variable 'sentence-end' is nil, then
 this function returns the regexp constructed from the variables
-`sentence-end-without-period', `sentence-end-double-space' and
-`sentence-end-without-space'.
+'sentence-end-without-period', 'sentence-end-double-space' and
+'sentence-end-without-space'.
 
 ** Undo changes:
 
-*** `buffer-undo-list' allows programmable elements.
+*** 'buffer-undo-list' allows programmable elements.
 
 These elements have the form (apply FUNNAME . ARGS), where FUNNAME is
 a symbol other than t or nil.  That stands for a high-level change
@@ -4198,124 +4198,124 @@ which indicates that the change which took place was 
limited to the
 range BEG...END and increased the buffer size by DELTA.
 
 *** If the buffer's undo list for the current command gets longer than
-`undo-outer-limit', garbage collection empties it.  This is to prevent
+'undo-outer-limit', garbage collection empties it.  This is to prevent
 it from using up the available memory and choking Emacs.
 
 ** Killing and yanking changes:
 
-*** New `yank-handler' text property can be used to control how
+*** New 'yank-handler' text property can be used to control how
 previously killed text on the kill ring is reinserted.
 
-The value of the `yank-handler' property must be a list with one to four
+The value of the 'yank-handler' property must be a list with one to four
 elements with the following format:
   (FUNCTION PARAM NOEXCLUDE UNDO).
 
-The `insert-for-yank' function looks for a yank-handler property on
+The 'insert-for-yank' function looks for a yank-handler property on
 the first character on its string argument (typically the first
-element on the kill-ring).  If a `yank-handler' property is found,
-the normal behavior of `insert-for-yank' is modified in various ways:
+element on the kill-ring).  If a 'yank-handler' property is found,
+the normal behavior of 'insert-for-yank' is modified in various ways:
 
-  When FUNCTION is present and non-nil, it is called instead of `insert'
+  When FUNCTION is present and non-nil, it is called instead of 'insert'
 to insert the string.  FUNCTION takes one argument--the object to insert.
   If PARAM is present and non-nil, it replaces STRING as the object
-passed to FUNCTION (or `insert'); for example, if FUNCTION is
-`yank-rectangle', PARAM should be a list of strings to insert as a
+passed to FUNCTION (or 'insert'); for example, if FUNCTION is
+'yank-rectangle', PARAM should be a list of strings to insert as a
 rectangle.
   If NOEXCLUDE is present and non-nil, the normal removal of the
-`yank-excluded-properties' is not performed; instead FUNCTION is
+'yank-excluded-properties' is not performed; instead FUNCTION is
 responsible for removing those properties.  This may be necessary
 if FUNCTION adjusts point before or after inserting the object.
   If UNDO is present and non-nil, it is a function that will be called
-by `yank-pop' to undo the insertion of the current object.  It is
+by 'yank-pop' to undo the insertion of the current object.  It is
 called with two arguments, the start and end of the current region.
-FUNCTION can set `yank-undo-function' to override the UNDO value.
+FUNCTION can set 'yank-undo-function' to override the UNDO value.
 
-*** The functions `kill-new', `kill-append', and `kill-region' now have an
-optional argument to specify the `yank-handler' text property to put on
+*** The functions 'kill-new', 'kill-append', and 'kill-region' now have an
+optional argument to specify the 'yank-handler' text property to put on
 the killed text.
 
-*** The function `yank-pop' will now use a non-nil value of the variable
-`yank-undo-function' (instead of `delete-region') to undo the previous
-`yank' or `yank-pop' command (or a call to `insert-for-yank').  The function
-`insert-for-yank' automatically sets that variable according to the UNDO
-element of the string argument's `yank-handler' text property if present.
+*** The function 'yank-pop' will now use a non-nil value of the variable
+'yank-undo-function' (instead of 'delete-region') to undo the previous
+'yank' or 'yank-pop' command (or a call to 'insert-for-yank').  The function
+'insert-for-yank' automatically sets that variable according to the UNDO
+element of the string argument's 'yank-handler' text property if present.
 
-*** The function `insert-for-yank' now supports strings where the
-`yank-handler' property does not span the first character of the
+*** The function 'insert-for-yank' now supports strings where the
+'yank-handler' property does not span the first character of the
 string.  The old behavior is available if you call
-`insert-for-yank-1' instead.
+'insert-for-yank-1' instead.
 
 ** Syntax table changes:
 
-*** The new function `syntax-ppss' provides an efficient way to find the
+*** The new function 'syntax-ppss' provides an efficient way to find the
 current syntactic context at point.
 
-*** The new function `syntax-after' returns the syntax code
+*** The new function 'syntax-after' returns the syntax code
 of the character after a specified buffer position, taking account
 of text properties as well as the character code.
 
-*** `syntax-class' extracts the class of a syntax code (as returned
-by `syntax-after').
+*** 'syntax-class' extracts the class of a syntax code (as returned
+by 'syntax-after').
 
-*** The macro `with-syntax-table' no longer copies the syntax table.
+*** The macro 'with-syntax-table' no longer copies the syntax table.
 
 ** File operation changes:
 
-*** New vars `exec-suffixes' and `load-suffixes' used when
+*** New vars 'exec-suffixes' and 'load-suffixes' used when
 searching for an executable or an Emacs Lisp file.
 
-*** New function `locate-file' searches for a file in a list of directories.
-`locate-file' accepts a name of a file to search (a string), and two
+*** New function 'locate-file' searches for a file in a list of directories.
+'locate-file' accepts a name of a file to search (a string), and two
 lists: a list of directories to search in and a list of suffixes to
-try; typical usage might use `exec-path' and `load-path' for the list
-of directories, and `exec-suffixes' and `load-suffixes' for the list
+try; typical usage might use 'exec-path' and 'load-path' for the list
+of directories, and 'exec-suffixes' and 'load-suffixes' for the list
 of suffixes.  The function also accepts a predicate argument to
 further filter candidate files.
 
 One advantage of using this function is that the list of suffixes in
-`exec-suffixes' is OS-dependent, so this function will find
+'exec-suffixes' is OS-dependent, so this function will find
 executables without polluting Lisp code with OS dependencies.
 
-*** The new function `file-remote-p' tests a file name and returns
+*** The new function 'file-remote-p' tests a file name and returns
 non-nil if it specifies a remote file (one that Emacs accesses using
 its own special methods and not directly through the file system).
 The value in that case is an identifier for the remote file system.
 
-*** The new hook `before-save-hook' is invoked by `basic-save-buffer'
+*** The new hook 'before-save-hook' is invoked by 'basic-save-buffer'
 before saving buffers.  This allows packages to perform various final
 tasks.  For example, it can be used by the copyright package to make
 sure saved files have the current year in any copyright headers.
 
-*** `file-chase-links' now takes an optional second argument LIMIT which
+*** 'file-chase-links' now takes an optional second argument LIMIT which
 specifies the maximum number of links to chase through.  If after that
 many iterations the file name obtained is still a symbolic link,
-`file-chase-links' returns it anyway.
+'file-chase-links' returns it anyway.
 
-*** Functions `file-name-sans-extension' and `file-name-extension' now
+*** Functions 'file-name-sans-extension' and 'file-name-extension' now
 ignore the leading dots in file names, so that file names such as
-`.emacs' are treated as extensionless.
+'.emacs' are treated as extensionless.
 
-*** If `buffer-save-without-query' is non-nil in some buffer,
-`save-some-buffers' will always save that buffer without asking (if
+*** If 'buffer-save-without-query' is non-nil in some buffer,
+'save-some-buffers' will always save that buffer without asking (if
 it's modified).
 
-*** `buffer-auto-save-file-format' is the new name for what was
-formerly called `auto-save-file-format'.  It is now a permanent local.
+*** 'buffer-auto-save-file-format' is the new name for what was
+formerly called 'auto-save-file-format'.  It is now a permanent local.
 
-*** `visited-file-modtime' and `calendar-time-from-absolute' now return
+*** 'visited-file-modtime' and 'calendar-time-from-absolute' now return
 a list of two integers, instead of a cons.
 
 *** The precedence of file name handlers has been changed.
 
 Instead of choosing the first handler that matches,
-`find-file-name-handler' now gives precedence to a file name handler
+'find-file-name-handler' now gives precedence to a file name handler
 that matches nearest the end of the file name.  More precisely, the
 handler whose (match-beginning 0) is the largest is chosen.  In case
 of ties, the old "first matched" rule applies.
 
 *** A file name handler can declare which operations it handles.
 
-You do this by putting an `operation' property on the handler name
+You do this by putting an 'operation' property on the handler name
 symbol.  The property value should be a list of the operations that
 the handler really handles.  It won't be called for any other
 operations.
@@ -4323,88 +4323,88 @@ operations.
 This is useful for autoloaded handlers, to prevent them from being
 autoloaded when not really necessary.
 
-*** The function `make-auto-save-file-name' is now handled by file
+*** The function 'make-auto-save-file-name' is now handled by file
 name handlers.  This will be exploited for remote files mainly.
 
-*** The function `file-name-completion' accepts an optional argument
+*** The function 'file-name-completion' accepts an optional argument
 PREDICATE, and rejects completion candidates that don't satisfy PREDICATE.
 
-*** The new primitive `set-file-times' sets a file's access and
+*** The new primitive 'set-file-times' sets a file's access and
 modification times.  Magic file name handlers can handle this
 operation.
 
 ** Input changes:
 
-*** Functions `y-or-n-p', `read-char', `read-key-sequence' and the like, that
+*** Functions 'y-or-n-p', 'read-char', 'read-key-sequence' and the like, that
 display a prompt but don't use the minibuffer, now display the prompt
 using the text properties (esp. the face) of the prompt string.
 
-*** The functions `read-event', `read-char', and `read-char-exclusive'
+*** The functions 'read-event', 'read-char', and 'read-char-exclusive'
 have a new optional argument SECONDS.  If non-nil, this specifies a
 maximum time to wait for input, in seconds.  If no input arrives after
 this time elapses, the functions stop waiting and return nil.
 
-*** An interactive specification can now use the code letter `U' to get
+*** An interactive specification can now use the code letter 'U' to get
 the up-event that was discarded in case the last key sequence read for a
-previous `k' or `K' argument was a down-event; otherwise nil is used.
+previous 'k' or 'K' argument was a down-event; otherwise nil is used.
 
-*** The new interactive-specification `G' reads a file name
-much like `F', but if the input is a directory name (even defaulted),
+*** The new interactive-specification 'G' reads a file name
+much like 'F', but if the input is a directory name (even defaulted),
 it returns just the directory name.
 
 *** (while-no-input BODY...) runs BODY, but only so long as no input
 arrives.  If the user types or clicks anything, BODY stops as if a
-quit had occurred.  `while-no-input' returns the value of BODY, if BODY
+quit had occurred.  'while-no-input' returns the value of BODY, if BODY
 finishes.  It returns nil if BODY was aborted by a quit, and t if
 BODY was aborted by arrival of input.
 
-*** `recent-keys' now returns the last 300 keys.
+*** 'recent-keys' now returns the last 300 keys.
 
 ** Minibuffer changes:
 
-*** The new function `minibufferp' returns non-nil if its optional
+*** The new function 'minibufferp' returns non-nil if its optional
 buffer argument is a minibuffer.  If the argument is omitted, it
 defaults to the current buffer.
 
-*** New function `minibuffer-selected-window' returns the window which
+*** New function 'minibuffer-selected-window' returns the window which
 was selected when entering the minibuffer.
 
-*** The `read-file-name' function now takes an additional argument which
+*** The 'read-file-name' function now takes an additional argument which
 specifies a predicate which the file name read must satisfy.  The
-new variable `read-file-name-predicate' contains the predicate argument
+new variable 'read-file-name-predicate' contains the predicate argument
 while reading the file name from the minibuffer; the predicate in this
-variable is used by read-file-name-internal to filter the completion list.
+variable is used by 'read-file-name-internal' to filter the completion list.
 
-*** The new variable `read-file-name-function' can be used by Lisp code
-to override the built-in `read-file-name' function.
+*** The new variable 'read-file-name-function' can be used by Lisp code
+to override the built-in 'read-file-name' function.
 
-*** The new variable `read-file-name-completion-ignore-case' specifies
+*** The new variable 'read-file-name-completion-ignore-case' specifies
 whether completion ignores case when reading a file name with the
-`read-file-name' function.
+'read-file-name' function.
 
-*** The new function `read-directory-name' is for reading a directory name.
+*** The new function 'read-directory-name' is for reading a directory name.
 
-It is like `read-file-name' except that the defaulting works better
+It is like 'read-file-name' except that the defaulting works better
 for directories, and completion inside it shows only directories.
 
-*** The new variable `history-add-new-input' specifies whether to add new
+*** The new variable 'history-add-new-input' specifies whether to add new
 elements in history.  If set to nil, minibuffer reading functions don't
 add new elements to the history list, so it is possible to do this
-afterwards by calling `add-to-history' explicitly.
+afterwards by calling 'add-to-history' explicitly.
 
 ** Completion changes:
 
-*** The new function `minibuffer-completion-contents' returns the contents
+*** The new function 'minibuffer-completion-contents' returns the contents
 of the minibuffer just before point.  That is what completion commands
 operate on.
 
-*** The functions `all-completions' and `try-completion' now accept lists
+*** The functions 'all-completions' and 'try-completion' now accept lists
 of strings as well as hash-tables additionally to alists, obarrays
-and functions.  Furthermore, the function `test-completion' is now
+and functions.  Furthermore, the function 'test-completion' is now
 exported to Lisp.  The keys in alists and hash tables can be either
 strings or symbols, which are automatically converted with to strings.
 
-*** The new macro `dynamic-completion-table' supports using functions
+*** The new macro 'dynamic-completion-table' supports using functions
 as a dynamic completion table.
 
   (dynamic-completion-table FUN)
@@ -4414,30 +4414,30 @@ and it should return an alist containing all the 
intended possible
 completions.  This alist can be a full list of possible completions so that FUN
 can ignore the value of its argument.  If completion is performed in the
 minibuffer, FUN will be called in the buffer from which the minibuffer was
-entered.  `dynamic-completion-table' then computes the completion.
+entered.  'dynamic-completion-table' then computes the completion.
 
-*** The new macro `lazy-completion-table' initializes a variable
+*** The new macro 'lazy-completion-table' initializes a variable
 as a lazy completion table.
 
   (lazy-completion-table VAR FUN)
 
 If the completion table VAR is used for the first time (e.g., by passing VAR
-as an argument to `try-completion'), the function FUN is called with no
+as an argument to 'try-completion'), the function FUN is called with no
 arguments.  FUN must return the completion table that will be stored in VAR.
 If completion is requested in the minibuffer, FUN will be called in the buffer
 from which the minibuffer was entered.  The return value of
-`lazy-completion-table' must be used to initialize the value of VAR.
+'lazy-completion-table' must be used to initialize the value of VAR.
 
 ** Abbrev changes:
 
-*** `define-abbrev' now accepts an optional argument SYSTEM-FLAG.
+*** 'define-abbrev' now accepts an optional argument SYSTEM-FLAG.
 
 If non-nil, this marks the abbrev as a "system" abbrev, which means
 that it won't be stored in the user's abbrevs file if he saves the
 abbrevs.  Major modes that predefine some abbrevs should always
 specify this flag.
 
-*** The new function `copy-abbrev-table' copies an abbrev table.
+*** The new function 'copy-abbrev-table' copies an abbrev table.
 
 It returns a new abbrev table that is a copy of a given abbrev table.
 
@@ -4446,7 +4446,7 @@ It returns a new abbrev table that is a copy of a given 
abbrev table.
 *** Cleaner way to enter key sequences.
 
 You can enter a constant key sequence in a more natural format, the
-same one used for saving keyboard macros, using the macro `kbd'.  For
+same one used for saving keyboard macros, using the macro 'kbd'.  For
 example,
 
 (kbd "C-x C-f") => "\^x\^f"
@@ -4455,7 +4455,7 @@ Actually, this format has existed since Emacs 20.1.
 
 *** Interactive commands can be remapped through keymaps.
 
-This is an alternative to using `defadvice' or `substitute-key-definition'
+This is an alternative to using 'defadvice' or 'substitute-key-definition'
 to modify the behavior of a key binding using the normal keymap
 binding and lookup functionality.
 
@@ -4464,48 +4464,48 @@ remapped to another command, that command is run 
instead of the
 original command.
 
 Example:
-Suppose that minor mode `my-mode' has defined the commands
-`my-kill-line' and `my-kill-word', and it wants C-k (and any other key
-bound to `kill-line') to run the command `my-kill-line' instead of
-`kill-line', and likewise it wants to run `my-kill-word' instead of
-`kill-word'.
+Suppose that minor mode 'my-mode' has defined the commands
+'my-kill-line' and 'my-kill-word', and it wants C-k (and any other key
+bound to 'kill-line') to run the command 'my-kill-line' instead of
+'kill-line', and likewise it wants to run 'my-kill-word' instead of
+'kill-word'.
 
 Instead of rebinding C-k and the other keys in the minor mode map,
-command remapping allows you to directly map `kill-line' into
-`my-kill-line' and `kill-word' into `my-kill-word' using `define-key':
+command remapping allows you to directly map 'kill-line' into
+'my-kill-line' and 'kill-word' into 'my-kill-word' using 'define-key':
 
    (define-key my-mode-map [remap kill-line] 'my-kill-line)
    (define-key my-mode-map [remap kill-word] 'my-kill-word)
 
-When `my-mode' is enabled, its minor mode keymap is enabled too.  So
-when the user types C-k, that runs the command `my-kill-line'.
+When 'my-mode' is enabled, its minor mode keymap is enabled too.  So
+when the user types C-k, that runs the command 'my-kill-line'.
 
 Only one level of remapping is supported.  In the above example, this
-means that if `my-kill-line' is remapped to `other-kill', then C-k still
-runs `my-kill-line'.
+means that if 'my-kill-line' is remapped to 'other-kill', then C-k still
+runs 'my-kill-line'.
 
 The following changes have been made to provide command remapping:
 
-- Command remappings are defined using `define-key' with a prefix-key
-  `remap', i.e. `(define-key MAP [remap CMD] DEF)' remaps command CMD
+- Command remappings are defined using 'define-key' with a prefix-key
+  'remap', i.e. '(define-key MAP [remap CMD] DEF)' remaps command CMD
   to definition DEF in keymap MAP.  The definition is not limited to
   another command; it can be anything accepted for a normal binding.
 
-- The new function `command-remapping' returns the binding for a
+- The new function 'command-remapping' returns the binding for a
   remapped command in the current keymaps, or nil if not remapped.
 
-- `key-binding' now remaps interactive commands unless the optional
+- 'key-binding' now remaps interactive commands unless the optional
   third argument NO-REMAP is non-nil.
 
-- `where-is-internal' now returns nil for a remapped command (e.g.
-  `kill-line', when `my-mode' is enabled), and the actual key binding for
+- 'where-is-internal' now returns nil for a remapped command (e.g.
+  'kill-line', when 'my-mode' is enabled), and the actual key binding for
   the command it is remapped to (e.g. C-k for my-kill-line).
   It also has a new optional fifth argument, NO-REMAP, which inhibits
-  remapping if non-nil (e.g. it returns "C-k" for `kill-line', and
-  "<kill-line>" for `my-kill-line').
+  remapping if non-nil (e.g. it returns "C-k" for 'kill-line', and
+  "<kill-line>" for 'my-kill-line').
 
-- The new variable `this-original-command' contains the original
-  command before remapping.  It is equal to `this-command' when the
+- The new variable 'this-original-command' contains the original
+  command before remapping.  It is equal to 'this-command' when the
   command was not remapped.
 
 *** The definition of a key-binding passed to define-key can use XEmacs-style
@@ -4513,43 +4513,42 @@ key-sequences, such as [(control a)].
 
 *** New keymaps for typing file names
 
-Two new keymaps, `minibuffer-local-filename-completion-map'  and
-`minibuffer-local-must-match-filename-map', apply whenever
+Two new keymaps, 'minibuffer-local-filename-completion-map'  and
+'minibuffer-local-must-match-filename-map', apply whenever
 Emacs reads a file name in the minibuffer.  These key maps override
-the usual binding of SPC to `minibuffer-complete-word' (so that file
+the usual binding of SPC to 'minibuffer-complete-word' (so that file
 names with embedded spaces could be typed without the need to quote
 the spaces).
 
-*** New function `current-active-maps' returns a list of currently
+*** New function 'current-active-maps' returns a list of currently
 active keymaps.
 
-*** New function `describe-buffer-bindings' inserts the list of all
+*** New function 'describe-buffer-bindings' inserts the list of all
 defined keys and their definitions.
 
-*** New function `keymap-prompt' returns the prompt string of a keymap.
+*** New function 'keymap-prompt' returns the prompt string of a keymap.
 
-*** If text has a `keymap' property, that keymap takes precedence
+*** If text has a 'keymap' property, that keymap takes precedence
 over minor mode keymaps.
 
-*** The `keymap' property now also works at the ends of overlays and
+*** The 'keymap' property now also works at the ends of overlays and
 text properties, according to their stickiness.  This also means that it
-works with empty overlays.  The same hold for the `local-map' property.
+works with empty overlays.  The same hold for the 'local-map' property.
 
-*** `key-binding' will now look up mouse-specific bindings.  The
-keymaps consulted by `key-binding' will get adapted if the key
+*** 'key-binding' will now look up mouse-specific bindings.  The
+keymaps consulted by 'key-binding' will get adapted if the key
 sequence is started with a mouse event.  Instead of letting the click
 position be determined from the key sequence itself, it is also
 possible to specify it with an optional argument explicitly.
 
-*** `define-key-after' now accepts keys longer than 1.
+*** 'define-key-after' now accepts keys longer than 1.
 
-*** (map-keymap FUNCTION KEYMAP) applies the function to each binding
-in the keymap.
+*** 'map-keymap' applies a function to each binding in a keymap.
 
-*** New variable `emulation-mode-map-alists'.
+*** New variable 'emulation-mode-map-alists'.
 
 Lisp packages using many minor mode keymaps can now maintain their own
-keymap alist separate from `minor-mode-map-alist' by adding their
+keymap alist separate from 'minor-mode-map-alist' by adding their
 keymap alist to this list.
 
 *** Dense keymaps now handle inheritance correctly.
@@ -4564,7 +4563,7 @@ bindings of the parent keymap.
 On some systems, when Emacs reads the output from a subprocess, the
 output data is read in very small blocks, potentially resulting in
 very poor performance.  This behavior can be remedied to some extent
-by setting the new variable `process-adaptive-read-buffering' to a
+by setting the new variable 'process-adaptive-read-buffering' to a
 non-nil value (the default), as it will automatically delay reading
 from such processes, allowing them to produce more output before
 Emacs tries to read it.
@@ -4572,32 +4571,32 @@ Emacs tries to read it.
 *** Processes now have an associated property list where programs can
 maintain process state and other per-process related information.
 
-Use the new functions `process-get' and `process-put' to access, add,
+Use the new functions 'process-get' and 'process-put' to access, add,
 and modify elements on this property list.  Use the new functions
-`process-plist' and `set-process-plist' to access and replace the
+'process-plist' and 'set-process-plist' to access and replace the
 entire property list of a process.
 
-*** Function `list-processes' now has an optional argument; if non-nil,
+*** Function 'list-processes' now has an optional argument; if non-nil,
 it lists only the processes whose query-on-exit flag is set.
 
-*** New fns `set-process-query-on-exit-flag' and `process-query-on-exit-flag'.
+*** New fns 'set-process-query-on-exit-flag' and 'process-query-on-exit-flag'.
 
-These replace the old function `process-kill-without-query'.  That
+These replace the old function 'process-kill-without-query'.  That
 function is still supported, but new code should use the new
 functions.
 
-*** The new function `call-process-shell-command'.
+*** The new function 'call-process-shell-command'.
 
 This executes a shell command synchronously in a separate process.
 
-*** The new function `process-file' is similar to `call-process', but
+*** The new function 'process-file' is similar to 'call-process', but
 obeys file handlers.  The file handler is chosen based on
-`default-directory'.
+'default-directory'.
 
-*** Function `signal-process' now accepts a process object or process
+*** Function 'signal-process' now accepts a process object or process
 name in addition to a process id to identify the signaled process.
 
-*** Function `accept-process-output' has a new optional fourth arg
+*** Function 'accept-process-output' has a new optional fourth arg
 JUST-THIS-ONE.  If non-nil, only output from the specified process
 is handled, suspending output from other processes.  If value is an
 integer, also inhibit running timers.  This feature is generally not
@@ -4608,24 +4607,24 @@ speech synthesis.
 if the process specifies t for its filter's multibyteness.
 
 That multibyteness is decided by the value of
-`default-enable-multibyte-characters' when the process is created, and
-you can change it later with `set-process-filter-multibyte'.
+'default-enable-multibyte-characters' when the process is created, and
+you can change it later with 'set-process-filter-multibyte'.
 
-*** The new function `set-process-filter-multibyte' sets the
+*** The new function 'set-process-filter-multibyte' sets the
 multibyteness of the strings passed to the process's filter.
 
-*** The new function `process-filter-multibyte-p' returns the
+*** The new function 'process-filter-multibyte-p' returns the
 multibyteness of the strings passed to the process's filter.
 
-*** If a process's coding system is `raw-text' or `no-conversion' and its
+*** If a process's coding system is 'raw-text' or 'no-conversion' and its
 buffer is multibyte, the output of the process is at first converted
-to multibyte by `string-to-multibyte' then inserted in the buffer.
-Previously, it was converted to multibyte by `string-as-multibyte',
+to multibyte by 'string-to-multibyte' then inserted in the buffer.
+Previously, it was converted to multibyte by 'string-as-multibyte',
 which was not compatible with the behavior of file reading.
 
 ** Enhanced networking support.
 
-*** The new `make-network-process' function makes network connections.
+*** The new 'make-network-process' function makes network connections.
 It allows opening of stream and datagram connections to a server, as well as
 create a stream or datagram server inside Emacs.
 
@@ -4644,9 +4643,9 @@ To test for the availability of a given feature, use 
featurep like this:
   (featurep 'make-network-process '(:type datagram))
   (featurep 'make-network-process '(:family ipv6))
 
-*** The old `open-network-stream' now uses `make-network-process'.
+*** The old 'open-network-stream' now uses 'make-network-process'.
 
-*** `process-contact' has an optional KEY argument.
+*** 'process-contact' has an optional KEY argument.
 
 Depending on this argument, you can get the complete list of network
 process properties or a specific property.  Using :local or :remote as
@@ -4655,14 +4654,14 @@ the KEY, you get the address of the local or remote 
end-point.
 An Inet address is represented as a 5 element vector, where the first
 4 elements contain the IP address and the fifth is the port number.
 
-*** New functions `stop-process' and `continue-process'.
+*** New functions 'stop-process' and 'continue-process'.
 
 These functions stop and restart communication through a network
 connection.  For a server process, no connections are accepted in the
 stopped state.  For a client process, no input is received in the
 stopped state.
 
-*** New function `format-network-address'.
+*** New function 'format-network-address'.
 
 This function reformats the Lisp representation of a network address
 to a printable string.  For example, an IP address A.B.C.D and port
@@ -4670,22 +4669,22 @@ number P is represented as a five element vector [A B C 
D P], and the
 printable string returned for this vector is "A.B.C.D:P".  See the doc
 string for other formatting options.
 
-*** New function `network-interface-list'.
+*** New function 'network-interface-list'.
 
 This function returns a list of network interface names and their
 current network addresses.
 
-*** New function `network-interface-info'.
+*** New function 'network-interface-info'.
 
 This function returns the network address, hardware address, current
 status, and other information about a specific network interface.
 
-*** New functions `process-datagram-address', `set-process-datagram-address'.
+*** New functions 'process-datagram-address', 'set-process-datagram-address'.
 
 These functions are used with datagram-based network processes to get
 and set the current address of the remote partner.
 
-*** Deleting a network process with `delete-process' calls the sentinel.
+*** Deleting a network process with 'delete-process' calls the sentinel.
 
 The status message passed to the sentinel for a deleted network
 process is "deleted".  The message passed to the sentinel when the
@@ -4697,82 +4696,82 @@ connection is closed by the remote peer has been 
changed to
 *** You can now make a window as short as one line.
 
 A window that is just one line tall does not display either a mode
-line or a header line, even if the variables `mode-line-format' and
-`header-line-format' call for them.  A window that is two lines tall
+line or a header line, even if the variables 'mode-line-format' and
+'header-line-format' call for them.  A window that is two lines tall
 cannot display both a mode line and a header line at once; if the
 variables call for both, only the mode line actually appears.
 
-*** The new function `window-inside-edges' returns the edges of the
+*** The new function 'window-inside-edges' returns the edges of the
 actual text portion of the window, not including the scroll bar or
 divider line, the fringes, the display margins, the header line and
 the mode line.
 
-*** The new functions `window-pixel-edges' and `window-inside-pixel-edges'
+*** The new functions 'window-pixel-edges' and 'window-inside-pixel-edges'
 return window edges in units of pixels, rather than columns and lines.
 
-*** New function `window-body-height'.
+*** New function 'window-body-height'.
 
-This is like `window-height' but does not count the mode line or the
+This is like 'window-height' but does not count the mode line or the
 header line.
 
-*** The new function `adjust-window-trailing-edge' moves the right
+*** The new function 'adjust-window-trailing-edge' moves the right
 or bottom edge of a window.  It does not move other window edges.
 
-*** The new macro `with-selected-window' temporarily switches the
-selected window without impacting the order of `buffer-list'.
+*** The new macro 'with-selected-window' temporarily switches the
+selected window without impacting the order of 'buffer-list'.
 It saves and restores the current buffer, too.
 
-*** `select-window' takes an optional second argument NORECORD.
+*** 'select-window' takes an optional second argument NORECORD.
 
-This is like `switch-to-buffer'.
+This is like 'switch-to-buffer'.
 
-*** `save-selected-window' now saves and restores the selected window
+*** 'save-selected-window' now saves and restores the selected window
 of every frame.  This way, it restores everything that can be changed
-by calling `select-window'.  It also saves and restores the current
+by calling 'select-window'.  It also saves and restores the current
 buffer.
 
-*** `set-window-buffer' has an optional argument KEEP-MARGINS.
+*** 'set-window-buffer' has an optional argument KEEP-MARGINS.
 
 If non-nil, that says to preserve the window's current margin, fringe,
 and scroll-bar settings.
 
-*** The new function `window-tree' returns a frame's window tree.
+*** The new function 'window-tree' returns a frame's window tree.
 
-*** The functions `get-lru-window' and `get-largest-window' take an optional
-argument `dedicated'.  If non-nil, those functions do not ignore
+*** The functions 'get-lru-window' and 'get-largest-window' take an optional
+argument 'dedicated'.  If non-nil, those functions do not ignore
 dedicated windows.
 
 ** Customizable fringe bitmaps
 
-*** There are new display properties, `left-fringe' and `right-fringe',
+*** There are new display properties, 'left-fringe' and 'right-fringe',
 that can be used to show a specific bitmap in the left or right fringe
 bitmap of the display line.
 
-Format is `display (left-fringe BITMAP [FACE])', where BITMAP is a
+Format is 'display (left-fringe BITMAP [FACE])', where BITMAP is a
 symbol identifying a fringe bitmap, either built-in or defined with
-`define-fringe-bitmap', and FACE is an optional face name to be used
-for displaying the bitmap instead of the default `fringe' face.
-When specified, FACE is automatically merged with the `fringe' face.
+'define-fringe-bitmap', and FACE is an optional face name to be used
+for displaying the bitmap instead of the default 'fringe' face.
+When specified, FACE is automatically merged with the 'fringe' face.
 
-*** New buffer-local variables `fringe-indicator-alist' and
-`fringe-cursor-alist' maps between logical (internal) fringe indicator
+*** New buffer-local variables 'fringe-indicator-alist' and
+'fringe-cursor-alist' maps between logical (internal) fringe indicator
 and cursor symbols and the actual fringe bitmaps to be displayed.
 This decouples the logical meaning of the fringe indicators from the
 physical appearance, as well as allowing different fringe bitmaps to
 be used in different windows showing different buffers.
 
-*** New function `define-fringe-bitmap' can now be used to create new
+*** New function 'define-fringe-bitmap' can now be used to create new
 fringe bitmaps, as well as change the built-in fringe bitmaps.
 
-*** New function `destroy-fringe-bitmap' deletes a fringe bitmap
+*** New function 'destroy-fringe-bitmap' deletes a fringe bitmap
 or restores a built-in one to its default value.
 
-*** New function `set-fringe-bitmap-face' specifies the face to be
+*** New function 'set-fringe-bitmap-face' specifies the face to be
 used for a specific fringe bitmap.  The face is automatically merged
-with the `fringe' face, so normally, the face should only specify the
+with the 'fringe' face, so normally, the face should only specify the
 foreground color of the bitmap.
 
-*** New function `fringe-bitmaps-at-pos' returns the current fringe
+*** New function 'fringe-bitmaps-at-pos' returns the current fringe
 bitmaps in the display line at a given buffer position.
 
 ** Other window fringe features:
@@ -4780,7 +4779,7 @@ bitmaps in the display line at a given buffer position.
 *** Controlling the default left and right fringe widths.
 
 The default left and right fringe widths for all windows of a frame
-can now be controlled by setting the `left-fringe' and `right-fringe'
+can now be controlled by setting the 'left-fringe' and 'right-fringe'
 frame parameters to an integer value specifying the width in pixels.
 Setting the width to 0 effectively removes the corresponding fringe.
 
@@ -4802,113 +4801,113 @@ fringe bitmaps is 8 pixels.
 position settings.
 
 To control the fringe widths of a window, either set the buffer-local
-variables `left-fringe-width', `right-fringe-width', or call
-`set-window-fringes'.
+variables 'left-fringe-width', 'right-fringe-width', or call
+'set-window-fringes'.
 
 To control the fringe position in a window, that is, whether fringes
 are positioned between the display margins and the window's text area,
 or at the edges of the window, either set the buffer-local variable
-`fringes-outside-margins' or call `set-window-fringes'.
+'fringes-outside-margins' or call 'set-window-fringes'.
 
-The function `window-fringes' can be used to obtain the current
-settings.  To make `left-fringe-width', `right-fringe-width', and
-`fringes-outside-margins' take effect, you must set them before
-displaying the buffer in a window, or use `set-window-buffer' to force
+The function 'window-fringes' can be used to obtain the current
+settings.  To make 'left-fringe-width', 'right-fringe-width', and
+'fringes-outside-margins' take effect, you must set them before
+displaying the buffer in a window, or use 'set-window-buffer' to force
 an update of the display margins.
 
 **** Windows can now have their own individual scroll-bar settings
 controlling the width and position of scroll-bars.
 
 To control the scroll-bar of a window, either set the buffer-local
-variables `scroll-bar-mode' and `scroll-bar-width', or call
-`set-window-scroll-bars'.  The function `window-scroll-bars' can be
-used to obtain the current settings.  To make `scroll-bar-mode' and
-`scroll-bar-width' take effect, you must set them before displaying
-the buffer in a window, or use `set-window-buffer' to force an update
+variables 'scroll-bar-mode' and 'scroll-bar-width', or call
+'set-window-scroll-bars'.  The function 'window-scroll-bars' can be
+used to obtain the current settings.  To make 'scroll-bar-mode' and
+'scroll-bar-width' take effect, you must set them before displaying
+the buffer in a window, or use 'set-window-buffer' to force an update
 of the display margins.
 
 ** Redisplay features:
 
-*** `sit-for' can now be called with args (SECONDS &optional NODISP).
+*** 'sit-for' can now be called with args (SECONDS &optional NODISP).
 
 *** Iconifying or deiconifying a frame no longer makes sit-for return.
 
-*** New function `redisplay' causes an immediate redisplay if no input is
+*** New function 'redisplay' causes an immediate redisplay if no input is
 available, equivalent to (sit-for 0).  The call (redisplay t) forces
 an immediate redisplay even if input is pending.
 
-*** New function `force-window-update' can initiate a full redisplay of
+*** New function 'force-window-update' can initiate a full redisplay of
 one or all windows.  Normally, this is not needed as changes in window
 contents are detected automatically.  However, certain implicit
 changes to mode lines, header lines, or display properties may require
 forcing an explicit window update.
 
-*** (char-displayable-p CHAR) returns non-nil if Emacs ought to be able
-to display CHAR.  More precisely, if the selected frame's fontset has
-a font to display the character set that CHAR belongs to.
+*** 'char-displayable-p' returns non-nil if Emacs ought to be able to
+display its char argument.  More precisely, if the selected frame's fontset has
+a font to display the character set that char belongs to.
 
 Fontsets can specify a font on a per-character basis; when the fontset
 does that, this value cannot be accurate.
 
 *** You can define multiple overlay arrows via the new
-variable `overlay-arrow-variable-list'.
+variable 'overlay-arrow-variable-list'.
 
 It contains a list of variables which contain overlay arrow position
-markers, including the original `overlay-arrow-position' variable.
+markers, including the original 'overlay-arrow-position' variable.
 
-Each variable on this list can have individual `overlay-arrow-string'
-and `overlay-arrow-bitmap' properties that specify an overlay arrow
+Each variable on this list can have individual 'overlay-arrow-string'
+and 'overlay-arrow-bitmap' properties that specify an overlay arrow
 string (for non-window terminals) or fringe bitmap (for window
 systems) to display at the corresponding overlay arrow position.
-If either property is not set, the default `overlay-arrow-string' or
+If either property is not set, the default 'overlay-arrow-string' or
 'overlay-arrow-fringe-bitmap' will be used.
 
-*** New `line-height' and `line-spacing' properties for newline characters
+*** New 'line-height' and 'line-spacing' properties for newline characters
 
-A newline can now have `line-height' and `line-spacing' text or overlay
+A newline can now have 'line-height' and 'line-spacing' text or overlay
 properties that control the height of the corresponding display row.
 
-If the `line-height' property value is t, the newline does not
+If the 'line-height' property value is t, the newline does not
 contribute to the height of the display row; instead the height of the
-newline glyph is reduced.  Also, a `line-spacing' property on this
+newline glyph is reduced.  Also, a 'line-spacing' property on this
 newline is ignored.  This can be used to tile small images or image
 slices without adding blank areas between the images.
 
-If the `line-height' property value is a positive integer, the value
+If the 'line-height' property value is a positive integer, the value
 specifies the minimum line height in pixels.  If necessary, the line
 height it increased by increasing the line's ascent.
 
-If the `line-height' property value is a float, the minimum line
+If the 'line-height' property value is a float, the minimum line
 height is calculated by multiplying the default frame line height by
 the given value.
 
-If the `line-height' property value is a cons (FACE . RATIO), the
+If the 'line-height' property value is a cons (FACE . RATIO), the
 minimum line height is calculated as RATIO * height of named FACE.
 RATIO is int or float.  If FACE is t, it specifies the current face.
 
-If the `line-height' property value is a cons (nil . RATIO), the line
+If the 'line-height' property value is a cons (nil . RATIO), the line
 height is calculated as RATIO * actual height of the line's contents.
 
-If the `line-height' value is a cons (HEIGHT . TOTAL), HEIGHT specifies
+If the 'line-height' value is a cons (HEIGHT . TOTAL), HEIGHT specifies
 the line height as described above, while TOTAL is any of the forms
 described above and specifies the total height of the line, causing a
 varying number of pixels to be inserted after the line to make it line
 exactly that many pixels high.
 
-If the `line-spacing' property value is a positive integer, the value
+If the 'line-spacing' property value is a positive integer, the value
 is used as additional pixels to insert after the display line; this
-overrides the default frame `line-spacing' and any buffer local value of
-the `line-spacing' variable.
+overrides the default frame 'line-spacing' and any buffer local value of
+the 'line-spacing' variable.
 
-If the `line-spacing' property is a float or cons, the line spacing
-is calculated as specified above for the `line-height' property.
+If the 'line-spacing' property is a float or cons, the line spacing
+is calculated as specified above for the 'line-height' property.
 
-*** The buffer local `line-spacing' variable can now have a float value,
+*** The buffer local 'line-spacing' variable can now have a float value,
 which is used as a height relative to the default frame line height.
 
 *** Enhancements to stretch display properties
 
-The display property stretch specification form `(space PROPS)', where
+The display property stretch specification form '(space PROPS)', where
 PROPS is a property list, now allows pixel based width and height
 specifications, as well as enhanced horizontal text alignment.
 
@@ -4925,22 +4924,22 @@ POS  ::= left | center | right
 FORM ::= (NUM . EXPR) | (OP EXPR ...)
 OP   ::= + | -
 
-The form `NUM' specifies a fractional width or height of the default
-frame font size.  The form `(NUM)' specifies an absolute number of
+The form 'NUM' specifies a fractional width or height of the default
+frame font size.  The form '(NUM)' specifies an absolute number of
 pixels.  If a symbol is specified, its buffer-local variable binding
-is used.  The `in', `mm', and `cm' units specifies the number of
-pixels per inch, milli-meter, and centi-meter, resp.  The `width' and
-`height' units correspond to the width and height of the current face
+is used.  The 'in', 'mm', and 'cm' units specifies the number of
+pixels per inch, milli-meter, and centi-meter, resp.  The 'width' and
+'height' units correspond to the width and height of the current face
 font.  An image specification corresponds to the width or height of
 the image.
 
-The `left-fringe', `right-fringe', `left-margin', `right-margin',
-`scroll-bar', and `text' elements specify to the width of the
+The 'left-fringe', 'right-fringe', 'left-margin', 'right-margin',
+'scroll-bar', and 'text' elements specify to the width of the
 corresponding area of the window.
 
-The `left', `center', and `right' positions can be used with :align-to
+The 'left', 'center', and 'right' positions can be used with :align-to
 to specify a position relative to the left edge, center, or right edge
-of the text area.  One of the above window elements (except `text')
+of the text area.  One of the above window elements (except 'text')
 can also be used with :align-to to specify that the position is
 relative to the left edge of the given area.  Once the base offset for
 a relative position has been set (by the first occurrence of one of
@@ -4954,18 +4953,18 @@ If no specific base offset is set for alignment, it is 
always relative
 to the left edge of the text area.  For example, :align-to 0 in a
 header line aligns with the first text column in the text area.
 
-The value of the form `(NUM . EXPR)' is the value of NUM multiplied by
+The value of the form '(NUM . EXPR)' is the value of NUM multiplied by
 the value of the expression EXPR.  For example, (2 . in) specifies a
 width of 2 inches, while (0.5 . IMAGE) specifies half the width (or
 height) of the specified image.
 
-The form `(+ EXPR ...)' adds up the value of the expressions.
-The form `(- EXPR ...)' negates or subtracts the value of the expressions.
+The form '(+ EXPR ...)' adds up the value of the expressions.
+The form '(- EXPR ...)' negates or subtracts the value of the expressions.
 
 *** Normally, the cursor is displayed at the end of any overlay and
 text property string that may be present at the current window
 position.  The cursor can now be placed on any character of such
-strings by giving that character a non-nil `cursor' text property.
+strings by giving that character a non-nil 'cursor' text property.
 
 *** The display space :width and :align-to text properties are now
 supported on text terminals.
@@ -4975,10 +4974,10 @@ supported on text terminals.
 **** New display property (slice X Y WIDTH HEIGHT) can be used with
 an image property to display only a specific slice of the image.
 
-**** Function `insert-image' has new optional fourth arg to
+**** Function 'insert-image' has new optional fourth arg to
 specify image slice (X Y WIDTH HEIGHT).
 
-**** New function `insert-sliced-image' inserts a given image as a
+**** New function 'insert-sliced-image' inserts a given image as a
 specified number of evenly sized slices (rows x columns).
 
 *** Images can now have an associated image map via the :map property.
@@ -4993,20 +4992,20 @@ A polygon is a cons (poly . [X0 Y0 X1 Y1 ...]) where 
each pair in the
 vector describes one corner in the polygon.
 
 When the mouse pointer is above a hot-spot area of an image, the
-PLIST of that hot-spot is consulted; if it contains a `help-echo'
+PLIST of that hot-spot is consulted; if it contains a 'help-echo'
 property it defines a tool-tip for the hot-spot, and if it contains
-a `pointer' property, it defines the shape of the mouse cursor when
-it is over the hot-spot.  See the variable `void-area-text-pointer'
+a 'pointer' property, it defines the shape of the mouse cursor when
+it is over the hot-spot.  See the variable 'void-area-text-pointer'
 for possible pointer shapes.
 
 When you click the mouse when the mouse pointer is over a hot-spot,
 an event is composed by combining the ID of the hot-spot with the
-mouse event, e.g. [area4 mouse-1] if the hot-spot's ID is `area4'.
+mouse event, e.g. [area4 mouse-1] if the hot-spot's ID is 'area4'.
 
-*** The function `find-image' now searches in etc/images/ and etc/.
-The new variable `image-load-path' is a list of locations in which to
+*** The function 'find-image' now searches in etc/images/ and etc/.
+The new variable 'image-load-path' is a list of locations in which to
 search for image files.  The default is to search in etc/images, then
-in etc/, and finally in the directories specified by `load-path'.
+in etc/, and finally in the directories specified by 'load-path'.
 Subdirectories of etc/ and etc/images are not recursively searched; if
 you put an image file in a subdirectory, you have to specify it
 explicitly; for example, if an image is put in etc/images/foo/bar.xpm:
@@ -5016,31 +5015,31 @@ explicitly; for example, if an image is put in 
etc/images/foo/bar.xpm:
 Note that all images formerly located in the lisp directory have been
 moved to etc/images.
 
-*** New function `image-load-path-for-library' returns a suitable
+*** New function 'image-load-path-for-library' returns a suitable
 search path for images relative to library. This function is useful in
 external packages to save users from having to update
-`image-load-path'.
+'image-load-path'.
 
-*** The new variable `max-image-size' defines the maximum size of
+*** The new variable 'max-image-size' defines the maximum size of
 images that Emacs will load and display.
 
-*** The new variable `display-mm-dimensions-alist' can be used to
+*** The new variable 'display-mm-dimensions-alist' can be used to
 override incorrect graphical display dimensions returned by functions
-`display-mm-height' and `display-mm-width'.
+'display-mm-height' and 'display-mm-width'.
 
 ** Mouse pointer features:
 
 *** The mouse pointer shape in void text areas (i.e. after the end of a
 line or below the last line in the buffer) of the text window is now
-controlled by the new variable `void-text-area-pointer'.  The default
-is to use the `arrow' (non-text) pointer.  Other choices are `text'
-(or nil), `hand', `vdrag', `hdrag', `modeline', and `hourglass'.
+controlled by the new variable 'void-text-area-pointer'.  The default
+is to use the 'arrow' (non-text) pointer.  Other choices are 'text'
+(or nil), 'hand', 'vdrag', 'hdrag', 'modeline', and 'hourglass'.
 
 *** The mouse pointer shape over an image can now be controlled by the
 :pointer image property.
 
 *** The mouse pointer shape over ordinary text or images can now be
-controlled/overridden via the `pointer' text property.
+controlled/overridden via the 'pointer' text property.
 
 ** Mouse event enhancements:
 
@@ -5048,8 +5047,8 @@ controlled/overridden via the `pointer' text property.
 you clicked.  For mouse clicks in window margins and fringes, this is
 a sensible buffer position corresponding to the surrounding text.
 
-*** Mouse events for clicks on window fringes now specify `left-fringe'
-or `right-fringe' as the area.
+*** Mouse events for clicks on window fringes now specify 'left-fringe'
+or 'right-fringe' as the area.
 
 *** Mouse events include actual glyph column and row for all event types
 and all areas.
@@ -5062,14 +5061,14 @@ the top left corner of the object (image or character) 
clicked on.
 *** Mouse events include the pixel width and height of the object
 (image or character) clicked on.
 
-*** Function `mouse-set-point' now works for events outside text area.
+*** Function 'mouse-set-point' now works for events outside text area.
 
-*** `posn-point' now returns buffer position for non-text area events.
+*** 'posn-point' now returns buffer position for non-text area events.
 
-*** New function `posn-area' returns window area clicked on (nil means
+*** New function 'posn-area' returns window area clicked on (nil means
 text area).
 
-*** New function `posn-actual-col-row' returns the actual glyph coordinates
+*** New function 'posn-actual-col-row' returns the actual glyph coordinates
 of the mouse event position.
 
 *** New functions 'posn-object', 'posn-object-x-y', 'posn-object-width-height'.
@@ -5080,70 +5079,70 @@ the total width and height of that object.
 
 ** Text property and overlay changes:
 
-*** Arguments for `remove-overlays' are now optional, so that you can
+*** Arguments for 'remove-overlays' are now optional, so that you can
 remove all overlays in the buffer with just (remove-overlays).
 
-*** New variable `char-property-alias-alist'.
+*** New variable 'char-property-alias-alist'.
 
 This variable allows you to create alternative names for text
-properties.  It works at the same level as `default-text-properties',
+properties.  It works at the same level as 'default-text-properties',
 although it applies to overlays as well.  This variable was introduced
-to implement the `font-lock-face' property.
+to implement the 'font-lock-face' property.
 
-*** New function `get-char-property-and-overlay' accepts the same
-arguments as `get-char-property' and returns a cons whose car is the
-return value of `get-char-property' called with those arguments and
+*** New function 'get-char-property-and-overlay' accepts the same
+arguments as 'get-char-property' and returns a cons whose car is the
+return value of 'get-char-property' called with those arguments and
 whose cdr is the overlay in which the property was found, or nil if
 it was found as a text property or not found at all.
 
-*** The new function `remove-list-of-text-properties'.
+*** The new function 'remove-list-of-text-properties'.
 
-It is like `remove-text-properties' except that it takes a list of
+It is like 'remove-text-properties' except that it takes a list of
 property names as argument rather than a property list.
 
 ** Face changes
 
-*** The variable `facemenu-unlisted-faces' has been removed.
+*** The variable 'facemenu-unlisted-faces' has been removed.
 Emacs has a lot more faces than in the past, and nearly all of them
-needed to be excluded.  The new variable `facemenu-listed-faces' lists
+needed to be excluded.  The new variable 'facemenu-listed-faces' lists
 the faces to include in the face menu.
 
-*** The new face attribute condition `min-colors' can be used to tailor
+*** The new face attribute condition 'min-colors' can be used to tailor
 the face color to the number of colors supported by a display, and
 define the foreground and background colors accordingly so that they
 look best on a terminal that supports at least this many colors.  This
 is now the preferred method for defining default faces in a way that
 makes a good use of the capabilities of the display.
 
-*** New function `display-supports-face-attributes-p' can be used to test
+*** New function 'display-supports-face-attributes-p' can be used to test
 whether a given set of face attributes is actually displayable.
 
-A new predicate `supports' has also been added to the `defface' face
+A new predicate 'supports' has also been added to the 'defface' face
 specification language, which can be used to do this test for faces
-defined with `defface'.
+defined with 'defface'.
 
-*** The special treatment of faces whose names are of the form `fg:COLOR'
-or `bg:COLOR' has been removed.  Lisp programs should use the
-`defface' facility for defining faces with specific colors, or use
+*** The special treatment of faces whose names are of the form 'fg:COLOR'
+or 'bg:COLOR' has been removed.  Lisp programs should use the
+'defface' facility for defining faces with specific colors, or use
 the feature of specifying the face attributes :foreground and :background
-directly in the `face' property instead of using a named face.
+directly in the 'face' property instead of using a named face.
 
 *** The first face specification element in a defface can specify
-`default' instead of frame classification.  Then its attributes act as
+'default' instead of frame classification.  Then its attributes act as
 defaults that apply to all the subsequent cases (and can be overridden
 by them).
 
-*** The function `face-differs-from-default-p' now truly checks
+*** The function 'face-differs-from-default-p' now truly checks
 whether the given face displays differently from the default face or
 not (previously it did only a very cursory check).
 
-*** `face-attribute', `face-foreground', `face-background', `face-stipple'.
+*** 'face-attribute', 'face-foreground', 'face-background', 'face-stipple'.
 
 These now accept a new optional argument, INHERIT, which controls how
 face inheritance is used when determining the value of a face
 attribute.
 
-*** New functions `face-attribute-relative-p' and `merge-face-attribute'
+*** New functions 'face-attribute-relative-p' and 'merge-face-attribute'
 help with handling relative face attributes.
 
 *** The priority of faces in an :inherit attribute face list is reversed.
@@ -5152,9 +5151,9 @@ If a face contains an :inherit attribute with a list of 
faces, earlier
 faces in the list override later faces in the list; in previous
 releases of Emacs, the order was the opposite.  This change was made
 so that :inherit face lists operate identically to face lists in text
-`face' properties.
+'face' properties.
 
-*** The variable `face-font-rescale-alist' specifies how much larger
+*** The variable 'face-font-rescale-alist' specifies how much larger
 (or smaller) font we should use.  For instance, if the value is
 '((SOME-FONTNAME-PATTERN . 1.3)) and a face requests a font of 10
 point, we actually use a font of 13 point if the font matches
@@ -5166,33 +5165,33 @@ not specified.  In previous releases of Emacs, if 
either foreground
 or background color was unspecified, colors were not swapped.  This
 was inconsistent with the face behavior under X.
 
-*** `set-fontset-font', `fontset-info', `fontset-font' now operate on
+*** 'set-fontset-font', 'fontset-info', 'fontset-font' now operate on
 the default fontset if the argument NAME is nil..
 
 ** Font-Lock changes:
 
-*** New special text property `font-lock-face'.
+*** New special text property 'font-lock-face'.
 
-This property acts like the `face' property, but it is controlled by
+This property acts like the 'face' property, but it is controlled by
 M-x font-lock-mode.  It is not, strictly speaking, a builtin text
 property.  Instead, it is implemented inside font-core.el, using the
-new variable `char-property-alias-alist'.
+new variable 'char-property-alias-alist'.
 
-*** font-lock can manage arbitrary text-properties beside `face'.
+*** font-lock can manage arbitrary text-properties beside 'face'.
 
-**** the FACENAME returned in `font-lock-keywords' can be a list of the
+**** the FACENAME returned in 'font-lock-keywords' can be a list of the
 form (face FACE PROP1 VAL1 PROP2 VAL2 ...) so you can set other
-properties than `face'.
+properties than 'face'.
 
-**** `font-lock-extra-managed-props' can be set to make sure those
+**** 'font-lock-extra-managed-props' can be set to make sure those
 extra properties are automatically cleaned up by font-lock.
 
-*** jit-lock obeys a new text-property `jit-lock-defer-multiline'.
+*** jit-lock obeys a new text-property 'jit-lock-defer-multiline'.
 
 If a piece of text with that property gets contextually refontified
-(see `jit-lock-defer-contextually'), then all of that text will
+(see 'jit-lock-defer-contextually'), then all of that text will
 be refontified.  This is useful when the syntax of a textual element
-depends on text several lines further down (and when `font-lock-multiline'
+depends on text several lines further down (and when 'font-lock-multiline'
 is not appropriate to solve that problem).  For example in Perl:
 
        s{
@@ -5201,85 +5200,85 @@ is not appropriate to solve that problem).  For example 
in Perl:
                bar
        }e
 
-Adding/removing the last `e' changes the `bar' from being a piece of
-text to being a piece of code, so you'd put a `jit-lock-defer-multiline'
+Adding/removing the last 'e' changes the 'bar' from being a piece of
+text to being a piece of code, so you'd put a 'jit-lock-defer-multiline'
 property over the second half of the command to force (deferred)
-refontification of `bar' whenever the `e' is added/removed.
+refontification of 'bar' whenever the 'e' is added/removed.
 
-*** `font-lock-extend-region-functions' makes it possible to alter the way
+*** 'font-lock-extend-region-functions' makes it possible to alter the way
 the fontification region is chosen.  This can be used to prevent rounding
 up to whole lines, or to extend the region to include all related lines
 of multiline constructs so that such constructs get properly recognized.
 
 ** Major mode mechanism changes:
 
-*** New variable `magic-mode-alist' determines major mode for a file by
-looking at the file contents.  It takes precedence over `auto-mode-alist'.
+*** New variable 'magic-mode-alist' determines major mode for a file by
+looking at the file contents.  It takes precedence over 'auto-mode-alist'.
 
-*** New variable `magic-fallback-mode-alist' determines major mode for a file 
by
-looking at the file contents.  It is handled after `auto-mode-alist',
-only if `auto-mode-alist' (and `magic-mode-alist') says nothing about the file.
+*** New variable 'magic-fallback-mode-alist' determines major mode for a file 
by
+looking at the file contents.  It is handled after 'auto-mode-alist',
+only if 'auto-mode-alist' (and 'magic-mode-alist') says nothing about the file.
 
-*** XML or SGML major mode is selected when file starts with an `<?xml'
-or `<!DOCTYPE' declaration.
+*** XML or SGML major mode is selected when file starts with an '<?xml'
+or '<!DOCTYPE' declaration.
 
 *** An interpreter magic line (if present) takes precedence over the
 file name when setting the major mode.
 
-*** If new variable `auto-mode-case-fold' is set to a non-nil value,
+*** If new variable 'auto-mode-case-fold' is set to a non-nil value,
 Emacs will perform a second case-insensitive search through
-`auto-mode-alist' if the first case-sensitive search fails.  This
+'auto-mode-alist' if the first case-sensitive search fails.  This
 means that a file FILE.TXT is opened in text-mode, and a file
 PROG.HTML is opened in html-mode.  Note however, that independent of
 this setting, *.C files are usually recognized as C++ files.  It also
 has no effect on systems with case-insensitive file names.
 
 *** All major mode functions should now run the new normal hook
-`after-change-major-mode-hook', at their very end, after the mode
-hooks.  `run-mode-hooks' does this automatically.
+'after-change-major-mode-hook', at their very end, after the mode
+hooks.  'run-mode-hooks' does this automatically.
 
-*** Major modes can define `eldoc-documentation-function'
+*** Major modes can define 'eldoc-documentation-function'
 locally to provide ElDoc functionality by some method appropriate to
 the language.
 
-*** Use the new function `run-mode-hooks' to run the major mode's mode hook.
+*** Use the new function 'run-mode-hooks' to run the major mode's mode hook.
 
-*** The new function `run-mode-hooks' and the new macro `delay-mode-hooks'
-are used by `define-derived-mode' to make sure the mode hook for the
+*** The new function 'run-mode-hooks' and the new macro 'delay-mode-hooks'
+are used by 'define-derived-mode' to make sure the mode hook for the
 parent mode is run at the end of the child mode.
 
-*** `define-derived-mode' by default creates a new empty abbrev table.
+*** 'define-derived-mode' by default creates a new empty abbrev table.
 It does not copy abbrevs from the parent mode's abbrev table.
 
-*** If a major mode function has a non-nil `no-clone-indirect'
-property, `clone-indirect-buffer' signals an error if you use
+*** If a major mode function has a non-nil 'no-clone-indirect'
+property, 'clone-indirect-buffer' signals an error if you use
 it in that buffer.
 
 ** Minor mode changes:
 
-*** `define-minor-mode' now accepts arbitrary additional keyword arguments
-and simply passes them to `defcustom', if applicable.
+*** 'define-minor-mode' now accepts arbitrary additional keyword arguments
+and simply passes them to 'defcustom', if applicable.
 
-*** `define-globalized-minor-mode'.
+*** 'define-globalized-minor-mode'.
 
 This is a new name for what was formerly called
-`easy-mmode-define-global-mode'.  The old name remains as an alias.
+'easy-mmode-define-global-mode'.  The old name remains as an alias.
 
-*** `minor-mode-list' now holds a list of minor mode commands.
+*** 'minor-mode-list' now holds a list of minor mode commands.
 
 ** Command loop changes:
 
-*** The new function `called-interactively-p' does what many people
-have mistakenly believed `interactive-p' to do: it returns t if the
-calling function was called through `call-interactively'.
+*** The new function 'called-interactively-p' does what many people
+have mistakenly believed 'interactive-p' to do: it returns t if the
+calling function was called through 'call-interactively'.
 
 Only use this when you cannot solve the problem by adding a new
 INTERACTIVE argument to the command.
 
-*** The function `commandp' takes an additional optional argument.
+*** The function 'commandp' takes an additional optional argument.
 
-If it is non-nil, then `commandp' checks for a function that could be
-called with `call-interactively', and does not return t for keyboard
+If it is non-nil, then 'commandp' checks for a function that could be
+called with 'call-interactively', and does not return t for keyboard
 macros.
 
 *** When a command returns, the command loop moves point out from
@@ -5289,41 +5288,41 @@ covered by an image or composition property.
 This makes it generally unnecessary to mark invisible text as intangible.
 This is particularly good because the intangible property often has
 unexpected side-effects since the property applies to everything
-(including `goto-char', ...) whereas this new code is only run after
-`post-command-hook' and thus does not care about intermediate states.
+(including 'goto-char', ...) whereas this new code is only run after
+'post-command-hook' and thus does not care about intermediate states.
 
-*** If a command sets `transient-mark-mode' to `only', that
+*** If a command sets 'transient-mark-mode' to 'only', that
 enables Transient Mark mode for the following command only.
-During that following command, the value of `transient-mark-mode'
-is `identity'.  If it is still `identity' at the end of the command,
+During that following command, the value of 'transient-mark-mode'
+is 'identity'.  If it is still 'identity' at the end of the command,
 the next return to the command loop changes to nil.
 
-*** Both the variable and the function `disabled-command-hook' have
-been renamed to `disabled-command-function'.  The variable
-`disabled-command-hook' has been kept as an obsolete alias.
+*** Both the variable and the function 'disabled-command-hook' have
+been renamed to 'disabled-command-function'.  The variable
+'disabled-command-hook' has been kept as an obsolete alias.
 
-*** `emacsserver' now runs `pre-command-hook' and `post-command-hook'
+*** 'emacsserver' now runs 'pre-command-hook' and 'post-command-hook'
 when it receives a request from emacsclient.
 
-*** `current-idle-time' reports how long Emacs has been idle.
+*** 'current-idle-time' reports how long Emacs has been idle.
 
 ** Lisp file loading changes:
 
-*** `load-history' can now have elements of the form (t . FUNNAME),
+*** 'load-history' can now have elements of the form (t . FUNNAME),
 which means FUNNAME was previously defined as an autoload (before the
 current file redefined it).
 
-*** `load-history' now records (defun . FUNNAME) when a function is
+*** 'load-history' now records (defun . FUNNAME) when a function is
 defined.  For a variable, it records just the variable name.
 
-*** The function `symbol-file' can now search specifically for function,
+*** The function 'symbol-file' can now search specifically for function,
 variable or face definitions.
 
-*** `provide' and `featurep' now accept an optional second argument
-to test/provide subfeatures.  Also `provide' now checks `after-load-alist'
+*** 'provide' and 'featurep' now accept an optional second argument
+to test/provide subfeatures.  Also 'provide' now checks 'after-load-alist'
 and runs any code associated with the provided feature.
 
-*** The variable `recursive-load-depth-limit' has been deleted.
+*** The variable 'recursive-load-depth-limit' has been deleted.
 Emacs now signals an error if the same file is loaded with more
 than 3 levels of nesting.
 
@@ -5335,8 +5334,8 @@ warning and error messages have been brought into line 
with GNU standards
 for these.  As a result, you can use next-error and friends on the
 compilation output buffer.
 
-*** The new macro `with-no-warnings' suppresses all compiler warnings
-inside its body.  In terms of execution, it is equivalent to `progn'.
+*** The new macro 'with-no-warnings' suppresses all compiler warnings
+inside its body.  In terms of execution, it is equivalent to 'progn'.
 
 *** You can avoid warnings for possibly-undefined symbols with a
 simple convention that the compiler understands.  (This is mostly
@@ -5347,21 +5346,21 @@ forms:
   (if (fboundp 'foo) <then> <else>)
   (if (boundp 'foo) <then> <else)
 
-In the first case, using `foo' as a function inside the <then> form
+In the first case, using 'foo' as a function inside the <then> form
 won't produce a warning if it's not defined as a function, and in the
-second case, using `foo' as a variable won't produce a warning if it's
+second case, using 'foo' as a variable won't produce a warning if it's
 unbound.  The test must be in exactly one of the above forms (after
-macro expansion), but such tests can be nested.  Note that `when' and
-`unless' expand to `if', but `cond' doesn't.
+macro expansion), but such tests can be nested.  Note that 'when' and
+'unless' expand to 'if', but 'cond' doesn't.
 
-*** `(featurep 'xemacs)' is treated by the compiler as nil.  This
+*** '(featurep 'xemacs)' is treated by the compiler as nil.  This
 helps to avoid noisy compiler warnings in code meant to run under both
 Emacs and XEmacs and can sometimes make the result significantly more
 efficient.  Since byte code from recent versions of XEmacs won't
 generally run in Emacs and vice versa, this optimization doesn't lose
 you anything.
 
-*** The local variable `no-byte-compile' in Lisp files is now obeyed.
+*** The local variable 'no-byte-compile' in Lisp files is now obeyed.
 
 *** When a Lisp file uses CL functions at run-time, compiling the file
 now issues warnings about these calls, unless the file performs
@@ -5369,33 +5368,33 @@ now issues warnings about these calls, unless the file 
performs
 
 ** Frame operations:
 
-*** New functions `frame-current-scroll-bars' and `window-current-scroll-bars'.
+*** New functions 'frame-current-scroll-bars' and 'window-current-scroll-bars'.
 
 These functions return the current locations of the vertical and
 horizontal scroll bars in a frame or window.
 
-*** The new function `modify-all-frames-parameters' modifies parameters
+*** The new function 'modify-all-frames-parameters' modifies parameters
 for all (existing and future) frames.
 
-*** The new frame parameter `tty-color-mode' specifies the mode to use
+*** The new frame parameter 'tty-color-mode' specifies the mode to use
 for color support on character terminal frames.  Its value can be a
 number of colors to support, or a symbol.  See the Emacs Lisp
 Reference manual for more detailed documentation.
 
 *** When using non-toolkit scroll bars with the default width,
-the `scroll-bar-width' frame parameter value is nil.
+the 'scroll-bar-width' frame parameter value is nil.
 
 ** Mode line changes:
 
-*** New function `format-mode-line'.
+*** New function 'format-mode-line'.
 
 This returns the mode line or header line of the selected (or a
 specified) window as a string with or without text properties.
 
-*** The new mode-line construct `(:propertize ELT PROPS...)' can be
+*** The new mode-line construct '(:propertize ELT PROPS...)' can be
 used to add text properties to mode-line elements.
 
-*** The new `%i' and `%I' constructs for `mode-line-format' can be used
+*** The new '%i' and '%I' constructs for 'mode-line-format' can be used
 to display the size of the accessible part of the buffer on the mode
 line.
 
@@ -5409,13 +5408,13 @@ proper name "file".  In previous Emacs versions, you 
had to specify
 several versions ago.
 
 *** The dummy function keys made by easy-menu are now always lower case.
-If you specify the menu item name "Ada", for instance, it uses `ada'
+If you specify the menu item name "Ada", for instance, it uses 'ada'
 as the "key" bound by that key binding.
 
 This is relevant only if Lisp code looks for the bindings that were
 made with easy-menu.
 
-*** `easy-menu-define' now allows you to use nil for the symbol name
+*** 'easy-menu-define' now allows you to use nil for the symbol name
 if you don't need to give the menu a name.  If you install the menu
 into other keymaps right away (MAPS is non-nil), it usually doesn't
 need to have a name.
@@ -5437,62 +5436,62 @@ the time it takes to convert the format.
 3. For binary files where format conversion would be pointless and
 wasteful.
 
-*** The new variable `auto-coding-functions' lets you specify functions
+*** The new variable 'auto-coding-functions' lets you specify functions
 to examine a file being visited and deduce the proper coding system
 for it.  (If the coding system is detected incorrectly for a specific
-file, you can put a `coding:' tags to override it.)
+file, you can put a 'coding:' tags to override it.)
 
-*** The new variable `ascii-case-table' stores the case table for the
+*** The new variable 'ascii-case-table' stores the case table for the
 ascii character set.  Language environments (such as Turkish) may
 alter the case correspondences of ASCII characters.  This variable
 saves the original ASCII case table before any such changes.
 
-*** The new function `merge-coding-systems' fills in unspecified aspects
+*** The new function 'merge-coding-systems' fills in unspecified aspects
 of one coding system from another coding system.
 
-*** New coding system property `mime-text-unsuitable' indicates that
-the coding system's `mime-charset' is not suitable for MIME text
+*** New coding system property 'mime-text-unsuitable' indicates that
+the coding system's 'mime-charset' is not suitable for MIME text
 parts, e.g. utf-16.
 
-*** New function `decode-coding-inserted-region' decodes a region as if
+*** New function 'decode-coding-inserted-region' decodes a region as if
 it is read from a file without decoding.
 
-*** New CCL functions `lookup-character' and `lookup-integer' access
-hash tables defined by the Lisp function `define-translation-hash-table'.
+*** New CCL functions 'lookup-character' and 'lookup-integer' access
+hash tables defined by the Lisp function 'define-translation-hash-table'.
 
-*** New function `quail-find-key' returns a list of keys to type in the
+*** New function 'quail-find-key' returns a list of keys to type in the
 current input method to input a character.
 
-*** `set-buffer-file-coding-system' now takes an additional argument,
+*** 'set-buffer-file-coding-system' now takes an additional argument,
 NOMODIFY.  If it is non-nil, it means don't mark the buffer modified.
 
 ** Operating system access:
 
-*** The new primitive `get-internal-run-time' returns the processor
+*** The new primitive 'get-internal-run-time' returns the processor
 run time used by Emacs since start-up.
 
-*** Functions `user-uid' and `user-real-uid' now return floats if the
-user UID doesn't fit in a Lisp integer.  Function `user-full-name'
+*** Functions 'user-uid' and 'user-real-uid' now return floats if the
+user UID doesn't fit in a Lisp integer.  Function 'user-full-name'
 accepts a float as UID parameter.
 
-*** New function `locale-info' accesses locale information.
+*** New function 'locale-info' accesses locale information.
 
 *** On MS Windows, locale-coding-system is used to interact with the OS.
 The Windows specific variable w32-system-coding-system, which was
 formerly used for that purpose is now an alias for locale-coding-system.
 
-*** New function `redirect-debugging-output' can be used to redirect
+*** New function 'redirect-debugging-output' can be used to redirect
 debugging output on the stderr file handle to a file.
 
 ** GC changes:
 
-*** New variable `gc-cons-percentage' automatically grows the GC cons threshold
+*** New variable 'gc-cons-percentage' automatically grows the GC cons threshold
 as the heap size increases.
 
-*** New variables `gc-elapsed' and `gcs-done' provide extra information
+*** New variables 'gc-elapsed' and 'gcs-done' provide extra information
 on garbage collection.
 
-*** The normal hook `post-gc-hook' is run at the end of garbage collection.
+*** The normal hook 'post-gc-hook' is run at the end of garbage collection.
 
 The hook is run with GC inhibited, so use it with care.
 
@@ -5500,28 +5499,28 @@ The hook is run with GC inhibited, so use it with care.
 
 *** A number of hooks have been renamed to better follow the conventions:
 
-`find-file-hooks' to `find-file-hook',
-`find-file-not-found-hooks' to `find-file-not-found-functions',
-`write-file-hooks' to `write-file-functions',
-`write-contents-hooks' to `write-contents-functions',
-`x-lost-selection-hooks' to `x-lost-selection-functions',
-`x-sent-selection-hooks' to `x-sent-selection-functions',
-`delete-frame-hook' to `delete-frame-functions'.
+'find-file-hooks' to 'find-file-hook',
+'find-file-not-found-hooks' to 'find-file-not-found-functions',
+'write-file-hooks' to 'write-file-functions',
+'write-contents-hooks' to 'write-contents-functions',
+'x-lost-selection-hooks' to 'x-lost-selection-functions',
+'x-sent-selection-hooks' to 'x-sent-selection-functions',
+'delete-frame-hook' to 'delete-frame-functions'.
 
 In each case the old name remains as an alias for the moment.
 
-*** Variable `local-write-file-hooks' is marked obsolete.
+*** Variable 'local-write-file-hooks' is marked obsolete.
 
-Use the LOCAL arg of `add-hook'.
+Use the LOCAL arg of 'add-hook'.
 
-*** New function `x-send-client-message' sends a client message when
+*** New function 'x-send-client-message' sends a client message when
 running under X.
 
 * New Packages for Lisp Programming in Emacs 22.1
 
-** The new library button.el implements simple and fast `clickable
+** The new library button.el implements simple and fast 'clickable
 buttons' in Emacs buffers.  Buttons are much lighter-weight than the
-`widgets' implemented by widget.el, and can be used by lisp code that
+'widgets' implemented by widget.el, and can be used by lisp code that
 doesn't require the full power of widgets.  Emacs uses buttons for
 such things as help and apropos buffers.
 
@@ -5545,15 +5544,15 @@ This is how to use sql.el and master.el together: the 
variable
 sql-buffer contains the slave buffer.  It is a local variable in the
 SQL buffer.
 
-(add-hook 'sql-mode-hook
-   (function (lambda ()
-              (master-mode t)
-              (master-set-slave sql-buffer))))
-(add-hook 'sql-set-sqli-hook
-   (function (lambda ()
-              (master-set-slave sql-buffer))))
+    (add-hook 'sql-mode-hook
+       (function (lambda ()
+                   (master-mode t)
+                   (master-set-slave sql-buffer))))
+    (add-hook 'sql-set-sqli-hook
+       (function (lambda ()
+                   (master-set-slave sql-buffer))))
 
-** The new library benchmark.el does timing measurements on Lisp code.
+** The new library 'benchmark' does timing measurements on Lisp code.
 
 This includes measuring garbage collection time.
 
@@ -5562,23 +5561,23 @@ This includes measuring garbage collection time.
 This is so you can tell whether you've tested all paths in your Lisp
 code.  It works with edebug.
 
-The function `testcover-start' instruments all functions in a given
-file.  Then test your code.  The function `testcover-mark-all' adds
+The function 'testcover-start' instruments all functions in a given
+file.  Then test your code.  The function 'testcover-mark-all' adds
 overlay "splotches" to the Lisp file's buffer to show where coverage
-is lacking.  The command `testcover-next-mark' (bind it to a key!)
+is lacking.  The command 'testcover-next-mark' (bind it to a key!)
 will move point forward to the next spot that has a splotch.
 
 Normally, a red splotch indicates the form was never completely
 evaluated; a brown splotch means it always evaluated to the same
 value.  The red splotches are skipped for forms that can't possibly
-complete their evaluation, such as `error'.  The brown splotches are
+complete their evaluation, such as 'error'.  The brown splotches are
 skipped for forms that are expected to always evaluate to the same
 value, such as (setq x 14).
 
 For difficult cases, you can add do-nothing macros to your code to
-help out the test coverage tool.  The macro `noreturn' suppresses a
-red splotch.  It is an error if the argument to `noreturn' does
-return.  The macro `1value' suppresses a brown splotch for its argument.
+help out the test coverage tool.  The macro 'noreturn' suppresses a
+red splotch.  It is an error if the argument to 'noreturn' does
+return.  The macro '1value' suppresses a brown splotch for its argument.
 This macro is a no-op except during test-coverage -- then it signals
 an error if the argument actually returns differing values.
 
diff --git a/etc/NEWS.23 b/etc/NEWS.23
index da483c3e7b..ef87db79d9 100644
--- a/etc/NEWS.23
+++ b/etc/NEWS.23
@@ -11,7 +11,7 @@ This file is about changes in Emacs version 23.
 See files NEWS.22, NEWS.21, NEWS.20, NEWS.19, NEWS.18, and NEWS.1-17
 for changes in older Emacs versions.
 
-You can narrow news to a specific version by calling `view-emacs-news'
+You can narrow news to a specific version by calling 'view-emacs-news'
 with a prefix argument or by typing C-u C-h C-n.
 
 
@@ -28,12 +28,12 @@ downloaded.
 
 ** EDE
 
-*** New variable `ede-project-directories'.
+*** New variable 'ede-project-directories'.
 EDE now refuses to automatically load a project file (Project.ede)
 unless the file is in one of the directories specified by this
 variable.  This reduces the risk of inadvertently loading malicious
-project files.  The commands `M-x ede-new' and `M-x ede' now offer to
-save directories to `ede-project-directories'.
+project files.  The commands 'M-x ede-new' and 'M-x ede' now offer to
+save directories to 'ede-project-directories'.
 
 * Changes in Emacs 23.4 on non-free operating systems
 
@@ -51,10 +51,10 @@ used on x86-64 and s390x GNU/Linux architectures.
 
 * Changes in Emacs 23.3
 
-** The last-resort backup file `%backup%~' is now written to
-`user-emacs-directory', instead of the user's home directory.
+** The last-resort backup file '%backup%~' is now written to
+'user-emacs-directory', instead of the user's home directory.
 
-** If Emacs creates `user-emacs-directory', that directory's
+** If Emacs creates 'user-emacs-directory', that directory's
 permissions are now set to rwx------, ignoring the umask.
 
 
@@ -62,46 +62,46 @@ permissions are now set to rwx------, ignoring the umask.
 
 ** Calendar and diary
 
-*** The appt-add command takes an optional argument, the warning time.
-This can be used in place of the default appt-message-warning-time.
+*** The 'appt-add' command takes an optional argument, the warning time.
+This can be used in place of the default 'appt-message-warning-time'.
 
 ** Python mode
 
 *** You can allow inferior Python processes to load modules from the
-current directory by setting `python-remove-cwd-from-path' to nil.
+current directory by setting 'python-remove-cwd-from-path' to nil.
 
 ** Rmail
 
-*** The default value of `rmail-enable-mime' is now t.  Rmail decodes
+*** The default value of 'rmail-enable-mime' is now t.  Rmail decodes
 MIME contents automatically.  You can customize the variable
-`rmail-enable-mime' back to `nil' to disable this automatic MIME
+'rmail-enable-mime' back to 'nil' to disable this automatic MIME
 decoding.
 
-*** The command `rmail-mime' change the displaying of a MIME message
-between decoded presentation form and raw data if `rmail-enable-mime'
+*** The command 'rmail-mime' change the displaying of a MIME message
+between decoded presentation form and raw data if 'rmail-enable-mime'
 is non-nil.  And, with prefix argument, it change only the displaying
 of the MIME entity at point.
 
-*** The new command `rmail-mime-next-item' (bound to TAB) moves point
+*** The new command 'rmail-mime-next-item' (bound to TAB) moves point
 to the next item of MIME message.
 
-*** The new command `rmail-mime-previous-item' (bound to backtab) moves
+*** The new command 'rmail-mime-previous-item' (bound to backtab) moves
 point to the previous item of MIME message.
 
-*** The new command `rmail-mime-toggle-hidden' (RET) hide or show the
+*** The new command 'rmail-mime-toggle-hidden' (RET) hide or show the
 body of the MIME entity at point.
 
 ** VC and related modes
 
-*** New VC command `vc-log-incoming', bound to `C-x v I'.
+*** New VC command 'vc-log-incoming', bound to 'C-x v I'.
 This shows a log of changes to be received with a pull operation.
 For Git, this runs "git fetch" to make the necessary data available
 locally; this requires version 1.7 or newer.
 
-*** New VC command `vc-log-outgoing', bound to `C-x v O'.
+*** New VC command 'vc-log-outgoing', bound to 'C-x v O'.
 This shows a log of changes to be sent in the next commit.
 
-*** New VC command vc-find-conflicted-file.
+*** New VC command 'vc-find-conflicted-file'.
 
 *** The 'g' key in VC diff, log, log-incoming and log-outgoing buffers
 reruns the corresponding VC command to compute an up to date version
@@ -136,23 +136,23 @@ indentation, which can be adjusted via ad-hoc indentation 
rules.
 
 * Incompatible Lisp Changes in Emacs 23.3
 
-** posn-col-row now excludes the header line from the row count
+** 'posn-col-row' now excludes the header line from the row count
 If the frame has a header line, posn-col-row will count row numbers
 starting from the first line of text below the header line.
 
 
 * Lisp changes in Emacs 23.3
 
-** `e' and `pi' are now called `float-e' and `float-pi'.
+** 'e' and 'pi' are now called 'float-e' and 'float-pi'.
   The old names are obsolete.
 
-** The use of unintern without an obarray arg is now obsolete.
+** The use of 'unintern' without an obarray arg is now obsolete.
 
-** The function `princ-list' is now obsolete.
+** The function 'princ-list' is now obsolete.
 
 ** The yank-handler argument to kill-region and friends is now obsolete.
 
-** New function byte-to-string, like char-to-string but for bytes.
+** New function 'byte-to-string', like 'char-to-string' but for bytes.
 
 
 * Changes in Emacs 23.3 on non-free operating systems
@@ -171,12 +171,12 @@ This might not work on all platforms.
 
 *** --enable-checking[=OPTIONS] builds emacs with extra runtime checks.
 
-** `make install' now consistently ignores umask, creating a
+** 'make install' now consistently ignores umask, creating a
 world-readable install.
 
 ** Emacs compiles with Gconf support, if it is detected.
 Use the configure option --without-gconf to disable this.
-This is used by the `font-use-system-font' feature (see below).
+This is used by the 'font-use-system-font' feature (see below).
 
 * Startup Changes in Emacs 23.2
 
@@ -186,7 +186,7 @@ resource settings for the graphical widgets are still 
applied.
 On Windows, the -Q option causes Emacs to ignore Registry settings,
 but environment variables set on the Registry are still honored.
 
-*** The new variable `inhibit-x-resources' shows whether X resources
+*** The new variable 'inhibit-x-resources' shows whether X resources
 were loaded.
 
 ** New command-line option -mm (--maximized) maximizes the initial frame.
@@ -196,19 +196,19 @@ were loaded.
 ** The maximum size of buffers (and the largest fixnum) is doubled.
 On typical 32bit systems, buffers can now be up to 512MB.
 
-** The default value of `trash-directory' is now nil.
-This means that `move-file-to-trash' trashes files according to
+** The default value of 'trash-directory' is now nil.
+This means that 'move-file-to-trash' trashes files according to
 freedesktop.org specifications, the same method used by the Gnome,
 KDE, and XFCE desktops.  (This change has no effect on Windows, which
-uses `system-move-file-to-trash' for trashing.)
+uses 'system-move-file-to-trash' for trashing.)
 
 ** The pointer now becomes invisible when typing.
-Customize `make-pointer-invisible' to disable this feature.
+Customize 'make-pointer-invisible' to disable this feature.
 
 ** Font changes
 
 *** Emacs can use the system default monospaced font in Gnome.
-To enable this feature, set `font-use-system-font' to non-nil (it is
+To enable this feature, set 'font-use-system-font' to non-nil (it is
 nil by default).  If the system default changes, Emacs changes also.
 This feature requires Gconf support, which is automatically included
 at compile-time if configure detects the gconf libraries (you can
@@ -219,9 +219,9 @@ via the XSETTINGS mechanism.  This includes antialias, 
hinting,
 hintstyle, RGBA, DPI and lcdfilter changes.
 
 ** Killing a buffer with a running process now asks for confirmation.
-To remove this query, remove `process-kill-buffer-query-function' from
-`kill-buffer-query-functions', or set the appropriate process flag
-with `set-process-query-on-exit-flag'.
+To remove this query, remove 'process-kill-buffer-query-function' from
+'kill-buffer-query-functions', or set the appropriate process flag
+with 'set-process-query-on-exit-flag'.
 
 ** File-local variable changes
 
@@ -230,16 +230,16 @@ unconditionally.  The previous behavior, toggling the 
mode, was
 neither reliable nor generally desirable.
 
 *** There are new commands for adding and removing file-local variables:
-`add-file-local-variable', `delete-file-local-variable',
-`add-file-local-variable-prop-line', and
-`delete-file-local-variable-prop-line'.
+'add-file-local-variable', 'delete-file-local-variable',
+'add-file-local-variable-prop-line', and
+'delete-file-local-variable-prop-line'.
 
 *** There are new commands for adding and removing directory-local variables,
 and copying them to and from file-local variable lists:
-`add-dir-local-variable', `delete-dir-local-variable',
-`copy-dir-locals-to-file-locals',
-`copy-dir-locals-to-file-locals-prop-line' and
-`copy-file-locals-to-dir-locals'.
+'add-dir-local-variable', 'delete-dir-local-variable',
+'copy-dir-locals-to-file-locals',
+'copy-dir-locals-to-file-locals-prop-line' and
+'copy-file-locals-to-dir-locals'.
 
 ** Internationalization changes
 
@@ -249,18 +249,18 @@ This refers to the EMACS_UNIBYTE environment variable as 
well as the
 arguments.  Customizing enable-multibyte-characters and setting
 default-enable-multibyte-characters are also deprecated.
 
-*** New coding system `utf-8-hfs'.
-This is suitable for default-file-name-coding-system on Mac OS X; see
+*** New coding system 'utf-8-hfs'.
+This is suitable for 'default-file-name-coding-system' on Mac OS X; see
 international/ucs-normalize.el.
 
 ** Function arguments in *Help* buffers are now shown in upper-case.
-Customize `help-downcase-arguments' to t to show them in lower-case.
+Customize 'help-downcase-arguments' to t to show them in lower-case.
 
-** New command `async-shell-command', bound globally to `M-&'.
-This executes the command asynchronously, similar to calling `M-!' and
-manually adding an ampersand to the end of the command.  With `M-&',
+** New command 'async-shell-command', bound globally to 'M-&'.
+This executes the command asynchronously, similar to calling 'M-!' and
+manually adding an ampersand to the end of the command.  With 'M-&',
 you don't need the ampersand.  The output appears in the buffer
-`*Async Shell Command*'.
+'*Async Shell Command*'.
 
 ** When running in a new enough xterm (newer than version 242), Emacs
 asks xterm what the background color is and it sets up faces
@@ -272,95 +272,95 @@ consider the background light).
 
 ** Kill-ring and selection changes
 
-*** If `select-active-regions' is t, any active region automatically
+*** If 'select-active-regions' is t, any active region automatically
 becomes the primary selection (for interaction with other window
 applications).  If you enable this, you might want to bind
-`mouse-yank-primary' to Mouse-2.
+'mouse-yank-primary' to Mouse-2.
 
-*** When `save-interprogram-paste-before-kill' is non-nil, the kill
+*** When 'save-interprogram-paste-before-kill' is non-nil, the kill
 commands save the interprogram-paste selection into the kill ring
 before doing anything else.  This avoids losing the selection.
 
-*** When `kill-do-not-save-duplicates' is non-nil, identical
-subsequent kills are not duplicated in the `kill-ring'.
+*** When 'kill-do-not-save-duplicates' is non-nil, identical
+subsequent kills are not duplicated in the 'kill-ring'.
 
 ** Completion changes
 
-*** The new command `completion-at-point' provides mode-sensitive completion.
+*** The new command 'completion-at-point' provides mode-sensitive completion.
 
-*** tab-always-indent set to `complete' lets TAB do completion as well.
+*** 'tab-always-indent' set to 'complete' lets TAB do completion as well.
 
-*** The new completion-style `initials' is available.
+*** The new completion-style 'initials' is available.
 For instance, this can complete M-x lch to list-command-history.
 
-*** The new variable `completions-format' determines how completions
+*** The new variable 'completions-format' determines how completions
 are displayed in the *Completions* buffer.  If you set it to
-`vertical', completions are sorted vertically in columns.
+'vertical', completions are sorted vertically in columns.
 
-** The default value of `blink-matching-paren-distance' is increased.
+** The default value of 'blink-matching-paren-distance' is increased.
 
 ** M-n provides more default values in the minibuffer for commands
 that read file names.  These include the file name at point (when ffap
-is loaded without ffap-bindings), the file name on the current line
+is loaded without 'ffap-bindings'), the file name on the current line
 (in Dired buffers), and the directory names of adjacent Dired windows
 (for Dired commands that operate on several directories, such as copy,
 rename, or diff).
 
-** M-r is bound to the new `move-to-window-line-top-bottom'.
+** M-r is bound to the new 'move-to-window-line-top-bottom'.
 This moves point to the window center, top and bottom on successive
 invocations, in the same spirit as the C-l (recenter-top-bottom)
 command.
 
-** The new variable `recenter-positions' determines the default
-cycling order of C-l (`recenter-top-bottom').
+** The new variable 'recenter-positions' determines the default
+cycling order of C-l ('recenter-top-bottom').
 
 ** The abbrevs file is now a file named abbrev_defs in
-user-emacs-directory; but the old location, ~/.abbrev_defs, is used if
+'user-emacs-directory'; but the old location, ~/.abbrev_defs, is used if
 that file exists.
 
 
 * Changes in Specialized Modes and Packages in Emacs 23.2
 
-** The bookmark menu has a narrowing search via bookmark-bmenu-search.
+** The bookmark menu has a narrowing search via 'bookmark-bmenu-search'.
 
 ** Calc
 
 *** The Calc settings file is now a file named calc.el in
-user-emacs-directory; but the old location, ~/.calc.el, is used if
+'user-emacs-directory'; but the old location, ~/.calc.el, is used if
 that file exists.
 
 *** New twos-complement display.
 
-*** Graphing commands (`g f' etc.) now work on MS-Windows, if you have
+*** Graphing commands ('g f' etc.) now work on MS-Windows, if you have
 the native Windows port of Gnuplot version 3.8 or later installed.
 
 ** Calendar and diary
 
 *** Fancy diary display is now the default.
-If you prefer the simple display, customize `diary-display-function'.
+If you prefer the simple display, customize 'diary-display-function'.
 
 *** The diary's fancy display now enables view-mode.
 
-*** The command `calendar-current-date' accepts an optional argument
+*** The command 'calendar-current-date' accepts an optional argument
 giving an offset from today.
 
 ** Desktop
 
-*** The default value for `desktop-buffers-not-to-save' is nil.
+*** The default value for 'desktop-buffers-not-to-save' is nil.
 This means Desktop will try restoring all buffers, when you restart
-your Emacs session.  Also, `desktop-buffers-not-to-save' is only
+your Emacs session.  Also, 'desktop-buffers-not-to-save' is only
 effective for buffers that have no associated file.  If you want to
 exempt buffers that do correspond to files, customize the value of
-`desktop-files-not-to-save' instead.
+'desktop-files-not-to-save' instead.
 
 ** Dired
 
-*** The new variable `dired-auto-revert-buffer', if non-nil, causes
+*** The new variable 'dired-auto-revert-buffer', if non-nil, causes
 Dired buffers to be reverted automatically on revisiting them.
 
 ** DocView
 
-*** When `doc-view-continuous' is non-nil, scrolling a line
+*** When 'doc-view-continuous' is non-nil, scrolling a line
 on the page edge advances to the next/previous page.
 
 ** Elint
@@ -371,12 +371,12 @@ on the page edge advances to the next/previous page.
 and can be run in batch mode.
 
 *** Elint does a more thorough initialization, and recognizes more built-in
-functions and variables.  Customize `elint-scan-preloaded' if you want
+functions and variables.  Customize 'elint-scan-preloaded' if you want
 to sacrifice some accuracy for a faster startup.
 
 *** Elint attempts some basic understanding of featurep and (f)boundp tests.
 
-*** Customize `elint-ignored-warnings' to suppress some warnings.
+*** Customize 'elint-ignored-warnings' to suppress some warnings.
 
 ** GDB-UI
 
@@ -385,14 +385,14 @@ collections as watch expressions.  These features require 
GDB 7.0 or later.
 
 ** Grep
 
-*** A new command `zrgrep' searches recursively in gzipped files.
+*** A new command 'zrgrep' searches recursively in gzipped files.
 
 ** Info
 
-*** The new command `Info-virtual-index' bound to "I" displays a menu of
+*** The new command 'Info-virtual-index' bound to "I" displays a menu of
 matched topics found in the index.
 
-*** The new command `info-finder' replaces finder.el with a virtual Info
+*** The new command 'info-finder' replaces finder.el with a virtual Info
 manual that generates an Info file which gives the same information
 through a menu structure.
 
@@ -400,35 +400,35 @@ through a menu structure.
 
 ** Message mode is now the default mode for composing mail.
 
-The default for `mail-user-agent' is now message-user-agent, so the
-C-x m (`compose-mail') command uses Message mode instead of Mail mode.
+The default for 'mail-user-agent' is now message-user-agent, so the
+C-x m ('compose-mail') command uses Message mode instead of Mail mode.
 
 Message mode has been included in Emacs, as part of the Gnus package,
 for several years.  It provides several features that are absent in
 Mail mode, such as MIME handling.
 
-*** If the user has not customized mail-user-agent, `compose-mail'
+*** If the user has not customized mail-user-agent, 'compose-mail'
 checks for Mail mode customizations, and issues a warning if these
 customizations are found.  This alerts users who may otherwise be
 unaware that their mail configuration has changed.
 
-To disable this check, set compose-mail-user-agent-warnings to nil.
+To disable this check, set 'compose-mail-user-agent-warnings' to nil.
 
-** The default value of mail-interactive is t, since Emacs 23.1.
+** The default value of 'mail-interactive' is t, since Emacs 23.1.
 (This was not announced at the time.)  It means that when sending mail,
 Emacs will wait for the process sending mail to return.  If you
 experience delays when sending mail, you may wish to set this to nil.
 
 ** nXML mode is now the default for editing XML files.
 
-** pcomplete provides a new command `pcomplete-std-completion' which
-is similar to `pcomplete' but using the standard completion UI code.
+** pcomplete provides a new command 'pcomplete-std-completion' which
+is similar to 'pcomplete' but using the standard completion UI code.
 
 ** Shell (and other comint modes)
 
-*** M-s is no longer bound to `comint-next-matching-input'.
+*** M-s is no longer bound to 'comint-next-matching-input'.
 
-*** M-r is now bound to `comint-history-isearch-backward-regexp'.
+*** M-r is now bound to 'comint-history-isearch-backward-regexp'.
 This starts an incremental search of the comint/shell input history.
 
 *** ansi-color is now enabled by default in Shell mode.
@@ -447,22 +447,22 @@ directory not controlled by any VCS, ask the user what VC 
backend to
 use to create a repository, create a new repository and register the
 file.
 
-*** New command `vc-root-print-log', bound to `C-x v L'.
-This displays a `*vc-change-log*' buffer showing the history of the
+*** New command 'vc-root-print-log', bound to 'C-x v L'.
+This displays a '*vc-change-log*' buffer showing the history of the
 version-controlled directory tree as a whole.
 
-*** New command `vc-root-diff', bound to `C-x v D'.
-This is similar to `vc-diff', but compares the entire directory tree
+*** New command 'vc-root-diff', bound to 'C-x v D'.
+This is similar to 'vc-diff', but compares the entire directory tree
 of the current VC directory with its working revision.
 
-*** `C-x v l' and `C-x v L' do not show the full log by default.
+*** 'C-x v l' and 'C-x v L' do not show the full log by default.
 The number of entries shown can be chosen interactively with a prefix
-argument, or by customizing vc-log-show-limit.  The `*vc-change-log*'
+argument, or by customizing vc-log-show-limit.  The '*vc-change-log*'
 buffer now contains buttons at the end of the buffer, which can be
 used to increase the number of entries shown.  RCS, SCCS, and CVS do
 not support this feature.
 
-*** vc-annotate supports annotations through file copies and renames,
+*** 'vc-annotate' supports annotations through file copies and renames,
 it displays the old names for the files and it can show logs/diffs for
 the corresponding lines.  Currently only Git and Mercurial take
 advantage of this feature.
@@ -495,21 +495,21 @@ are stripped when copying text from the ChangeLog to the 
*VC-Log* buffer.
 
 ** Miscellaneous
 
-*** Interactively `multi-isearch-buffers' and `multi-isearch-buffers-regexp'
+*** Interactively 'multi-isearch-buffers' and 'multi-isearch-buffers-regexp'
 read buffer names to search, one by one, ended with RET.  With a prefix
 argument, they ask for a regexp, and search in buffers whose names match
-the specified regexp.  Interactively `multi-isearch-files' and
-`multi-isearch-files-regexp' read file names to search, one by one,
+the specified regexp.  Interactively 'multi-isearch-files' and
+'multi-isearch-files-regexp' read file names to search, one by one,
 ended with RET.  With a prefix argument, they ask for a wildcard, and
 search in file buffers whose file names match the specified wildcard.
 
 *** Autorevert Tail mode now works also for remote files.
 
-*** The new eshell built-in commands `su' and `sudo' support Tramp.
-Thus, they change `default-directory' to reflect the new user id, and
+*** The new eshell built-in commands 'su' and 'sudo' support Tramp.
+Thus, they change 'default-directory' to reflect the new user id, and
 let commands run under that user's permissions.  This works even when
-`default-directory' is already remote.  Calling the external commands
-is possible via `*su' or `*sudo', respectively.
+'default-directory' is already remote.  Calling the external commands
+is possible via '*su' or '*sudo', respectively.
 
 ** Obsolete packages
 
@@ -529,13 +529,13 @@ edit and navigate source code.  Parsers for C/C++, Java, 
Javascript,
 and several other languages are included by default, and Semantic can
 also interface with external tools such as GNU Global and GNU Idutils.
 
-To enable Semantic, use the global minor mode `semantic-mode'.
+To enable Semantic, use the global minor mode 'semantic-mode'.
 See the Semantic manual for details.
 
 *** EDE (Emacs Development Environment) is a package for managing code
 projects, including features such as automatic Makefile generation.
 
-To enable EDE, use the minor mode `global-ede-mode'.
+To enable EDE, use the minor mode 'global-ede-mode'.
 See the EDE manual for details.
 
 *** SRecode is a library for recoding Semantic tags back into source
@@ -557,8 +557,8 @@ System (CLOS).  It is used by the other CEDET packages.
 * Incompatible Lisp Changes in Emacs 23.2
 
 ** The Lisp reader turns integers that are too large/small into floats.
-For instance, on machines where `536870911' is the largest integer,
-reading `536870912' gives the floating-point object `536870912.0'.
+For instance, on machines where '536870911' is the largest integer,
+reading '536870912' gives the floating-point object '536870912.0'.
 
 This change only concerns the Lisp reader; it does not affect how
 actual integer objects overflow.
@@ -573,18 +573,18 @@ be in use:
   time-stamp-hhmm, baud-rate
 
 ** Support for generating Emacs 18 compatible bytecode (by setting
-the variable `byte-compile-compatibility') has been removed.
-
-** In image-mode.el `image-mode-maybe' is obsolete.
-Instead, you can either use `image-mode' (which displays an image file
-as the actual image initially), or `image-mode-as-text' (when you want
-to display an image file as text initially).  `image-mode-as-text' is a
-combination of a non-image mode from `auto-mode-alist' (or Fundamental
-mode) and `image-minor-mode'.  `image-minor-mode' provides a `C-c C-c'
+the variable 'byte-compile-compatibility') has been removed.
+
+** In image-mode.el 'image-mode-maybe' is obsolete.
+Instead, you can either use 'image-mode' (which displays an image file
+as the actual image initially), or 'image-mode-as-text' (when you want
+to display an image file as text initially).  'image-mode-as-text' is a
+combination of a non-image mode from 'auto-mode-alist' (or Fundamental
+mode) and 'image-minor-mode'.  'image-minor-mode' provides a 'C-c C-c'
 key binding to toggle image display.
-`image-toggle-display-text' removes image properties.
-`image-toggle-display-image' adds image properties.
-`image-toggle-display' toggles between `image-mode-as-text' and `image-mode'.
+'image-toggle-display-text' removes image properties.
+'image-toggle-display-image' adds image properties.
+'image-toggle-display' toggles between 'image-mode-as-text' and 'image-mode'.
 
 
 * Lisp changes in Emacs 23.2
@@ -592,113 +592,113 @@ key binding to toggle image display.
 ** All the default-FOO variables that hold the default value of the FOO
 variable, are now declared obsolete.
 
-** read-key is a function halfway between read-event and read-key-sequence.
+** 'read-key' is a mix between 'read-event' and 'read-key-sequence'.
 It reads a single key, but obeys input and escape sequence decoding.
 
 ** Frame parameter changes
 
-*** You can give the `fullscreen' frame parameter the value `maximized'.
+*** You can give the 'fullscreen' frame parameter the value 'maximized'.
 This maximizes the frame.
 
-*** The new frame parameter `sticky' makes Emacs frames sticky in
+*** The new frame parameter 'sticky' makes Emacs frames sticky in
 virtual desktops.
 
 ** Completion changes
 
-*** completion-base-size is obsoleted by completion-base-position.
+*** 'completion-base-size' is obsoleted by 'completion-base-position'.
 This change causes a few backward incompatibilities, mostly with
-choose-completion-string-functions where the `mini-p' argument has
-been replaced by a `base-position' argument, and where the `base-size'
+'choose-completion-string-functions' where the 'mini-p' argument has
+been replaced by a 'base-position' argument, and where the 'base-size'
 argument is now always nil.
 
-*** New function `completion-in-region' to use the standard completion
+*** New function 'completion-in-region' to use the standard completion
 facilities on a particular region of text.
 
 *** The 4th arg to all-completions (aka hide-spaces) is declared obsolete.
 
-*** completion-annotate-function specifies how to compute annotations
+*** 'completion-annotate-function' specifies how to compute annotations
 for completions displayed in *Completions*.
 
 ** Minibuffer changes
 
 *** read-file-name-predicate is obsolete.  It was used to pass the predicate
-to read-file-name-internal because read-file-name-internal abused its `pred'
+to read-file-name-internal because read-file-name-internal abused its 'pred'
 argument to pass the current directory, but this hack is not needed
 any more.
 
 ** Changes to file-manipulation functions
 
-*** `delete-directory' has an optional parameter RECURSIVE.
+*** 'delete-directory' has an optional parameter RECURSIVE.
 
-*** New function `copy-directory', which copies a directory recursively.
+*** New function 'copy-directory', which copies a directory recursively.
 
 ** called-interactively-p now takes one argument and replaces interactive-p
 which is now marked obsolete.
 
-** New function set-advertised-calling-convention makes it possible
+** New function 'set-advertised-calling-convention' makes it possible
 to obsolete arguments as well as make some arguments mandatory.
 
 ** You can control which binding is preferentially shown in menus and
-docstrings by adding a `:advertised-binding' property to the corresponding
+docstrings by adding a ':advertised-binding' property to the corresponding
 command's symbol.  That property can hold a single binding or a list
 of bindings.
 
 ** Network and process changes
 
-*** start-process-shell-command and start-file-process-shell-command
-now only take a single `command' argument.
+*** 'start-process-shell-command' and 'start-file-process-shell-command'
+now only take a single 'command' argument.
 
-*** The new variable `process-file-side-effects' should be set to nil
-if a `process-file' call does not change a remote file.  This allows
+*** The new variable 'process-file-side-effects' should be set to nil
+if a 'process-file' call does not change a remote file.  This allows
 file name handlers such as Tramp to optimizations.
 
-*** make-network-process can now also create `seqpacket' Unix sockets.
+*** 'make-network-process' can now also create 'seqpacket' Unix sockets.
 
 ** Loading changes
 
-*** eval-next-after-load is obsolete.
+*** 'eval-next-after-load' is obsolete.
 
-*** New hook `after-load-functions' run after loading an Elisp file.
+*** New hook 'after-load-functions' run after loading an Elisp file.
 
 ** Byte compilation changes
 
 *** Changing the file-names generated by byte-compilation by redefining
-the function `byte-compile-dest-file' before loading bytecomp.el is obsolete.
+the function 'byte-compile-dest-file' before loading bytecomp.el is obsolete.
 Instead, customize byte-compile-dest-file-function.
 
-*** `byte-compile-warnings' has new members, `constants' and `suspicious'.
+*** 'byte-compile-warnings' has new members, 'constants' and 'suspicious'.
 
-** New macro with-silent-modifications to tweak text properties without
+** New macro 'with-silent-modifications' to tweak text properties without
 affecting the buffer's modification state.
 
 ** Hash tables have a new printed representation that is readable.
-The feature `hashtable-print-readable' identifies this new
+The feature 'hashtable-print-readable' identifies this new
 functionality.
 
 ** New functions for performing Unicode normalization:
-ucs-normalize-NFD-region, ucs-normalize-NFD-string,
-ucs-normalize-NFC-region, ucs-normalize-NFC-string,
-ucs-normalize-NFKD-region, ucs-normalize-NFKD-string,
-ucs-normalize-NFKC-region, ucs-normalize-NFKC-string,
-ucs-normalize-HFS-NFD-region, ucs-normalize-HFS-NFD-string,
-ucs-normalize-HFS-NFC-region, ucs-normalize-HFS-NFC-string.
+'ucs-normalize-NFD-region', 'ucs-normalize-NFD-string',
+'ucs-normalize-NFC-region', 'ucs-normalize-NFC-string',
+'ucs-normalize-NFKD-region', 'ucs-normalize-NFKD-string',
+'ucs-normalize-NFKC-region', 'ucs-normalize-NFKC-string',
+'ucs-normalize-HFS-NFD-region', 'ucs-normalize-HFS-NFD-string',
+'ucs-normalize-HFS-NFC-region', 'ucs-normalize-HFS-NFC-string'.
 
 ** Face aliases can now be marked as obsolete, using the macro
-`define-obsolete-face-alias'.
+'define-obsolete-face-alias'.
 
-** New function `window-full-height-p', analogous to the full-width version.
+** New function 'window-full-height-p', analogous to the full-width version.
 
 
 * Changes in Emacs 23.2 on non-free operating systems
 
-** On MS-Windows, `display-time' now displays the system load average
+** On MS-Windows, 'display-time' now displays the system load average
 as well as the time, as it does on GNU and Unix.
 
 
 * Installation Changes in Emacs 23.1
 
 ** The default X toolkit is now Gtk+, rather than Lucid.
-The configure option `--with-gtk' has been removed.  Gtk is now the
+The configure option '--with-gtk' has been removed.  Gtk is now the
 default toolkit, but you can use --with-x-toolkit=gtk if necessary.
 
 ** New font code.
@@ -749,7 +749,7 @@ See the list at the end of etc/MACHINES for details.
 
 *** Support for Sun windows has been removed.
 
-*** The `emacstool' utility has been removed.
+*** The 'emacstool' utility has been removed.
 
 ** The following platforms will be removed in a future Emacs version:
 If you are still using Emacs on one of these platforms, please email
@@ -771,7 +771,7 @@ executable format.
 *** Platforms not supporting shared libraries (i.e., requiring the
 NO_SHARED_LIBS compilation flag).
 
-** The configure options `--with-gcc', `--without-gcc' have been removed.
+** The configure options '--with-gcc', '--without-gcc' have been removed.
 Configure will use gcc by default.  Set the CC environment variable if
 you need control over which C compiler is used.
 
@@ -782,22 +782,22 @@ or any later version.
 
 ** Emacs 23 comes with a new set of default icons.
 Various resolutions are available as etc/images/icons/hicolor/*/apps/emacs.png.
-The Emacs 22 icon is available as `emacs22.png' in the same location.
+The Emacs 22 icon is available as 'emacs22.png' in the same location.
 
 * Changes in Emacs 23.1
 
 ** Improved X Window System support
 
 *** Emacs now supports using both X displays and ttys in one session.
-With an Emacs server active (M-x server-start), `emacsclient -t'
+With an Emacs server active (M-x server-start), 'emacsclient -t'
 creates a tty frame connected to the running emacs server.  You can
-use any number of different ttys.  `emacsclient -c' creates a new X11
+use any number of different ttys.  'emacsclient -c' creates a new X11
 frame on the current $DISPLAY (or a tty frame if $DISPLAY is not set).
 There may be problems if a display exits unexpectedly and Emacs is compiled
 with Gtk+, see etc/PROBLEMS.
 
 You can test for the presence of this feature in your Lisp code by
-testing for the `multi-tty' feature.
+testing for the 'multi-tty' feature.
 
 *** Emacs starts in the background, as a daemon, when given the
 --daemon command line argument.  It disconnects from the terminal and
@@ -809,7 +809,7 @@ terminal frames using emacsclient.
 ALTERNATE_EDITOR is set to "") and emacsclient cannot connect to an
 emacs server.
 
-*** The new command close-display-connection closes a connection to a
+*** The new command 'close-display-connection' closes a connection to a
 remote display.  There are some bugs for Gtk+.  See etc/PROBLEMS.
 
 *** Emacs now supports the XEmbed specification.
@@ -819,7 +819,7 @@ 
https://specifications.freedesktop.org/xembed-spec/xembed-spec-latest.html
 for details about XEmbed.
 
 *** Emacs can now set the frame opacity.
-The opacity of a frame can be controlled by setting the `alpha' frame
+The opacity of a frame can be controlled by setting the 'alpha' frame
 parameter.  This only takes effect on a compositing window manager for
 the X Window System, such as Compiz, Beryl and Compiz Fusion, on Mac
 OS X, or on Windows 2000 and later versions of Windows.
@@ -829,7 +829,7 @@ The alpha parameter should be an integer between 0 
(transparent) and
 cons cell (ACTIVE . INACTIVE), where ACTIVE is the opacity of an
 active frame and INACTIVE is the opacity of non-active frames.
 
-The variable `frame-alpha-lower-limit' defines a lower bound for the
+The variable 'frame-alpha-lower-limit' defines a lower bound for the
 opacity; the default is 20.
 
 ** Internationalization changes
@@ -838,15 +838,15 @@ opacity; the default is 20.
 (It has about four times the code space, which should be plenty).
 
 The internal encoding used for buffers and strings is now
-Unicode-based and called `utf-8-emacs' (`emacs-internal' is an alias
+Unicode-based and called 'utf-8-emacs' ('emacs-internal' is an alias
 for this).  This encoding is backward-compatible with Unicode's UTF-8
 encoding.  The internal encoding previously used by Emacs,
-`emacs-mule', is still available for reading and writing files.
+'emacs-mule', is still available for reading and writing files.
 
-During byte-compilation, Emacs 23 uses `utf-8-emacs' to write files.
+During byte-compilation, Emacs 23 uses 'utf-8-emacs' to write files.
 As a result, byte-compiled files containing non-ASCII characters can't
 be read by earlier versions of Emacs.  Files compiled by Emacs 20, 21,
-or 22 are loaded correctly as `emacs-mule' (whether or not they
+or 22 are loaded correctly as 'emacs-mule' (whether or not they
 contain multibyte characters).  This takes somewhat more time, so it
 may be worth recompiling existing .elc files which don't need to be
 shared with older Emacsen.
@@ -864,24 +864,24 @@ Sinhala, and TaiViet.
 *** The minor modes unify-8859-on-encoding-mode and
 unify-8859-on-decoding-mode are obsolete.
 
-*** `ucs-insert' is bound to `C-x 8 RET' and in addition to hex numbers
+*** 'ucs-insert' is bound to 'C-x 8 RET' and in addition to hex numbers
 accepts numbers in hash notation (e.g. #o21430 for octal, or #10r8984 for
 decimal).  It also accepts Unicode character names with completion.
 
-*** The `cyrillic-translit' input method supports many new characters.
+*** The 'cyrillic-translit' input method supports many new characters.
 Common typographical characters available from Unicode were added to
-`cyrillic-translit': punctuation marks, accented characters, fractions,
+'cyrillic-translit': punctuation marks, accented characters, fractions,
 and others.
 
 ** Emacs now supports serial port access on GNU/Linux, Unix, and
-Windows.  The new command `serial-term' starts an interactive terminal
+Windows.  The new command 'serial-term' starts an interactive terminal
 on a serial port.  The serial port can be configured at runtime with
 the mode-line mouse menu.
 
 ** Menu Bar changes
 
 *** In the Options menu, the "Set Default Font" item applies the
-selected font to the `default' face on all frames, not just the
+selected font to the 'default' face on all frames, not just the
 current frame.  Furthermore, if Emacs is compiled with both GTK and
 Fontconfig support, the "Set Default Font" item uses the GTK font
 selection dialog instead of an Emacs pop-up menu.
@@ -904,13 +904,13 @@ mode menus have been improved to include more 
functionality.
 
 ** Mode-line changes
 
-*** The mode-line displays a `@', instead of `-', if the
+*** The mode-line displays a '@', instead of '-', if the
 default-directory for the current buffer is on a remote machine.
 
 *** The mode-line displays a mode menu when mouse-1 is clicked on a
 minor mode, in the same way as it already did for major modes.
 
-*** The `mode-line-emphasis' face is used to highlight certain
+*** The 'mode-line-emphasis' face is used to highlight certain
 mode-line information (e.g. waiting for a VC command to finish).
 
 *** The mode-line tooltips have been improved to provide more details.
@@ -919,37 +919,37 @@ mode-line information (e.g. waiting for a VC command to 
finish).
 line are now interactive: mouse-1 can be used on them to pop up a menu.
 
 ** File deletion can make use of the Recycle Bin or system Trash folder.
-Set `delete-by-moving-to-trash' non-nil to use this.  Deleted files
+Set 'delete-by-moving-to-trash' non-nil to use this.  Deleted files
 and directories will then be sent to the Recycle Bin on Windows, and
-to `trash-directory' on other systems.
+to 'trash-directory' on other systems.
 
 ** Directory-local variables can now be defined.
 By default, Emacs looks in .dir-locals.el for directory-local
-variables.  For more information, see `dir-locals-set-directory-class'
-and `dir-locals-set-class-variables'.
+variables.  For more information, see 'dir-locals-set-directory-class'
+and 'dir-locals-set-class-variables'.
 
-** Emacs can now use `auth-source' for authentication.
-`smtpmail' and `url' (Tramp and Gnus also) use `auth-source' to obtain
+** Emacs can now use 'auth-source' for authentication.
+'smtpmail' and 'url' (Tramp and Gnus also) use 'auth-source' to obtain
 login names and passwords.  The match, if found, is reported
 in *Messages* with the password blanked out.
 
-** `where-is-preferred-modifier' can specify your favorite modifier.
+** 'where-is-preferred-modifier' can specify your favorite modifier.
 
 
 * Startup Changes in Emacs 23.1
 
-** The option `inhibit-startup-screen' (with aliases to old names
-`inhibit-splash-screen' and `inhibit-startup-message') doesn't inhibit
+** The option 'inhibit-startup-screen' (with aliases to old names
+'inhibit-splash-screen' and 'inhibit-startup-message') doesn't inhibit
 display of the initial message in the *scratch* buffer.  If you don't
 want to display the initial message in the *scratch* buffer at startup,
-you can set the option `initial-scratch-message' to nil.
+you can set the option 'initial-scratch-message' to nil.
 
-** New user option `initial-buffer-choice' specifies what to display
+** New user option 'initial-buffer-choice' specifies what to display
 after starting Emacs: startup screen, *scratch* buffer, visiting a
 file or directory.
 
-** New alias `argv' for `command-line-args-left'
-This is a convenience alias, so that one can write `(pop argv)'
+** New alias 'argv' for 'command-line-args-left'
+This is a convenience alias, so that one can write '(pop argv)'
 inside of --eval command line arguments in order to access
 following arguments.
 
@@ -957,36 +957,36 @@ following arguments.
 
 ** Emacs now supports invocation by an X session manager.
 It can save a session and restore it later.  See the documentation of
-the functions `emacs-session-save' and `emacs-session-restore'.
+the functions 'emacs-session-save' and 'emacs-session-restore'.
 (Actually, this feature was introduced with Emacs 22, but it was not
 documented.)
 
 * Incompatible Editing Changes in Emacs 23.1
 
-** In Dired, `dired-flag-garbage-files' is rebound from `&' to `%&'
+** In Dired, 'dired-flag-garbage-files' is rebound from '&' to '%&'
 on the regexp command prefix map.
 
 ** In Dired-x, all command guesses for ! are now added to the default
 list accessible by M-n instead of pushing all guesses temporarily into
 the history list.
 
-** In Isearch mode, a special case of typing `C-w' at the beginning of
+** In Isearch mode, a special case of typing 'C-w' at the beginning of
 the minibuffer that toggles word search (i.e. using key sequences
-`C-s RET C-w' or `C-s M-e C-w') is obsolete.  You can use the global key
-`M-s w' to start word search, or type `M-s w' in Isearch mode to
+'C-s RET C-w' or 'C-s M-e C-w') is obsolete.  You can use the global key
+'M-s w' to start word search, or type 'M-s w' in Isearch mode to
 toggle word search.  To start nonincremental word search you can now use
-`M-s w RET' and `M-s w C-r RET' instead of `C-s RET C-w' and `C-r RET C-w'.
+'M-s w RET' and 'M-s w C-r RET' instead of 'C-s RET C-w' and 'C-r RET C-w'.
 
-** In Info, `Info-search' is unbound from `M-s' to allow using `M-s w'
+** In Info, 'Info-search' is unbound from 'M-s' to allow using 'M-s w'
 for word search as well as other search commands from the global prefix
-key `M-s'.  `Info-search' is still bound to `s', and also incremental
-search commands `C-s', `C-M-s', `C-r', `C-M-r' are available for searching
+key 'M-s'.  'Info-search' is still bound to 's', and also incremental
+search commands 'C-s', 'C-M-s', 'C-r', 'C-M-r' are available for searching
 through multiple Info nodes, together with their nonincremental versions
-`C-s RET', `C-r RET', `C-M-s RET', `C-M-r RET', `M-s w RET'.
+'C-s RET', 'C-r RET', 'C-M-s RET', 'C-M-r RET', 'M-s w RET'.
 
-** In Text mode, `center-line' and `center-paragraph' are rebound from
-`M-s' and `M-S' to global keys `M-o M-s' and `M-o M-S' on the global
-prefix map `M-o', which is intended for such formatting commands.
+** In Text mode, 'center-line' and 'center-paragraph' are rebound from
+'M-s' and 'M-S' to global keys 'M-o M-s' and 'M-o M-S' on the global
+prefix map 'M-o', which is intended for such formatting commands.
 
 ** The following input methods were removed in Emacs 22.2, but this was
 not advertised: danish-alt-postfix, esperanto-alt-postfix,
@@ -1000,13 +1000,13 @@ identical.
 
 ** The C-n and C-p line-motion commands now move by screen lines,
 taking continued lines and variable-width characters into account.
-Setting `line-move-visual' to nil reverts this to the previous
+Setting 'line-move-visual' to nil reverts this to the previous
 behavior (i.e., motion by logical lines based on buffer contents
 alone).
 
-** C-x C-c now invokes `save-buffers-kill-terminal', and C-z now
-invokes `suspend-frame'.  These changes are for compatibility with the
-new multi-tty support (see `Improved X Window System support' above).
+** C-x C-c now invokes 'save-buffers-kill-terminal', and C-z now
+invokes 'suspend-frame'.  These changes are for compatibility with the
+new multi-tty support (see 'Improved X Window System support' above).
 
 ** Mark changes
 
@@ -1027,13 +1027,13 @@ word at point.
 *** When Transient Mark mode is on, TAB now indents the region if the
 region is active.
 
-*** The variable `use-empty-active-region' controls whether an empty
+*** The variable 'use-empty-active-region' controls whether an empty
 active region in Transient Mark mode should make commands operate on
 that empty region.
 
 ** Temporarily active regions
 
-*** The new variable shift-select-mode, non-nil by default, controls
+*** The new minor mode 'shift-select-mode', non-nil by default, controls
 shift-selection.  When Shift Select mode is on, shift-translated
 motion keys (e.g. S-left and S-down) activate and extend a temporary
 region, similar to mouse-selection.
@@ -1055,8 +1055,8 @@ complete far enough and you entered RET by mistake.  In 
that case,
 Emacs puts the message "[Confirm]" in the minibuffer; type RET again
 to create the file or buffer.
 
-The new variable confirm-nonexistent-file-or-buffer determines whether
-Emacs asks for confirmation.  The default value is `after-completion'.
+The new variable 'confirm-nonexistent-file-or-buffer' determines whether
+Emacs asks for confirmation.  The default value is 'after-completion'.
 If you change it to t, Emacs always asks for confirmation; if you
 change it to nil, Emacs never asks for confirmation.
 
@@ -1070,7 +1070,7 @@ attempts to perform partial-completion.  If still no 
completion
 alternatives are found, we fall back on the Emacs 22 rules for
 performing completion.
 
-The new variable `completion-styles' can be customized to choose your
+The new variable 'completion-styles' can be customized to choose your
 favorite completion style.
 
 *** When M-n in the minibuffer reaches the end of the list of defaults,
@@ -1082,25 +1082,25 @@ searching minibuffer completion items.
 
 *** Minibuffer input of shell commands now comes with completion.
 
-*** In the `C-x d' (Dired) prompt, typing M-n gives the visited file
+*** In the 'C-x d' (Dired) prompt, typing M-n gives the visited file
 name of the current buffer.
 
 *** In the M-! (shell-command) prompt, M-n provides some default commands.
 These are guessed using the file extension of the current file, based
-on the file-handlers specified in the operating system's `mailcap'
+on the file-handlers specified in the operating system's 'mailcap'
 file.  The ! command in Dired (dired-do-shell-command) works
 similarly, using the file displayed on the current line.
 
-*** A list of regexp default values is available via M-n for `occur',
-`keep-lines', `flush-lines' and `how-many'.  This list includes the active
+*** A list of regexp default values is available via M-n for 'occur',
+'keep-lines', 'flush-lines' and 'how-many'.  This list includes the active
 region in transient-mark-mode, the word under the cursor, the last Isearch
 regexp, the last Isearch string and the last replacement regexp.
 
-*** When enable-recursive-minibuffers is non-nil, operations which use
+*** When 'enable-recursive-minibuffers' is non-nil, operations which use
 switch-to-buffer (such as C-x b and C-x C-f) do not fail any more when
 used in a minibuffer or a dedicated window.  Instead, they fallback on
 using pop-to-buffer, which will use some other window.  This change
-has no effect when enable-recursive-minibuffers is nil (the default).
+has no effect when 'enable-recursive-minibuffers' is nil (the default).
 
 *** Isearch started in the minibuffer searches in the minibuffer history.
 Reverse Isearch commands (C-r, C-M-r) search in previous minibuffer
@@ -1110,18 +1110,18 @@ element, it wraps to the last history element, and the 
forward search
 wraps to the first history element.  When the search is terminated, the
 history element containing the search string becomes the current.
 
-*** The variable read-file-name-completion-ignore-case overrides
-completion-ignore-case for file name completion.
+*** The variable 'read-file-name-completion-ignore-case' overrides
+'completion-ignore-case' for file name completion.
 
-*** The variable read-buffer-completion-ignore-case overrides
-completion-ignore-case for buffer name completion.
+*** The variable 'read-buffer-completion-ignore-case' overrides
+'completion-ignore-case' for buffer name completion.
 
-*** The new command `minibuffer-force-complete' chooses one of the
+*** The new command 'minibuffer-force-complete' chooses one of the
 possible completions, rather than stopping at the common prefix.
 
-*** If `completion-auto-help' is `lazy', Emacs shows the completions
+*** If 'completion-auto-help' is 'lazy', Emacs shows the completions
 buffer only on the second attempt to complete.  This was already
-supported in `partial-completion-mode'.
+supported in 'partial-completion-mode'.
 
 ** Face changes
 
@@ -1130,30 +1130,30 @@ size of the default face in the current buffer.  The 
face is changed
 via face remapping (see Lisp changes, below).
 
 *** New commands to change the default face size in the current buffer.
-To increase it, type `C-x C-+' or `C-x C-='.  To decrease it, type
-`C-x C--'.  To restore the default (global) face size, type `C-x C-0'.
-These work via Text Scale mode, a new minor mode.
+To increase it, type 'C-x C-+' or 'C-x C-='.  To decrease it, type
+'C-x C--'.  To restore the default (global) face size, type 'C-x C-0'.
+These work via 'text-scale-mode', a new minor mode.
 
 The final key in the above commands may be repeated without the
-leading `C-x', e.g. `C-x C-= C-= C-=' increases the face height by
+leading 'C-x', e.g. 'C-x C-= C-= C-=' increases the face height by
 three steps.  Each step scales the height of the default face by the
-value of the variable `text-scale-mode-step'.
+value of the variable 'text-scale-mode-step'.
 
-*** The commands buffer-face-mode and buffer-face-set can be used to
+*** The commands 'buffer-face-mode' and 'buffer-face-set' can be used to
 remap the default face in the current buffer.  See "Buffer Face mode",
 under New Modes and Packages.
 
 ** Primary selection changes
 
 *** You can disable kill ring commands from accessing the primary
-selection by setting `x-select-enable-primary' to nil.
+selection by setting 'x-select-enable-primary' to nil.
 
 ** Continuation lines can now be wrapped at word boundaries
 (word-wrapping).  This is controlled by the new per-buffer variable
-`word-wrap'.  Word wrapping does not take place if continuation lines
+'word-wrap'.  Word wrapping does not take place if continuation lines
 are not shown, e.g. if truncate-lines is non-nil.  The most convenient
 way to enable word-wrapping is using the new minor mode Visual Line
-mode; in addition to setting `word-wrap' to t, this rebinds some
+mode; in addition to setting 'word-wrap' to t, this rebinds some
 editing commands to work on screen lines rather than text lines.  See
 New Modes and Packages, below.
 
@@ -1163,7 +1163,7 @@ New Modes and Packages, below.
 specify a minimum window width for partial-width windows, below which
 lines are truncated.  The default has been changed to 50.
 
-*** The new command balance-windows-area balances windows both
+*** The new command 'balance-windows-area' balances windows both
 vertically and horizontally.
 
 *** pop-to-buffer now always sets input focus when the popped-to window
@@ -1171,68 +1171,68 @@ is on a different frame.
 
 ** Miscellaneous changes:
 
-*** C-l is bound to the new command recenter-top-bottom, rather than recenter.
+*** C-l is bound to the new command 'recenter-top-bottom', rather than 
recenter.
 This moves the current line to window center, top and bottom on
 successive invocations.
 
 *** scroll-preserve-screen-position also preserves the column position.
 
-*** If `yank-pop-change-selection' is t, rotating the kill ring also
+*** If 'yank-pop-change-selection' is t, rotating the kill ring also
 updates the selection or clipboard to the current yank, just as M-w
 would do so with the text it copies to the kill ring.
 
 *** C-M-% now shows replacement as it would look in the buffer, with
-`\N' and `\&' substituted according to the match.  Old behavior can be
-restored by customizing `query-replace-show-replacement'.
+'\N' and '\&' substituted according to the match.  Old behavior can be
+restored by customizing 'query-replace-show-replacement'.
 
 *** The command shell prompts for the default directory, when it is
 called with a prefix and the default directory is a remote file name.
 This is because some file name handlers (like ange-ftp) are not able to
 run processes remotely.
 
-*** The new command kill-matching-buffers kills buffers whose name
+*** The new command 'kill-matching-buffers' kills buffers whose name
 matches a regexp.
 
-*** The value of comment-style now defaults to `indent'.
+*** The value of comment-style now defaults to 'indent'.
 Therefore, comment-start markers are inserted at the current indentation
 of the region to comment, rather than the leftmost column.
 
-*** The new commands `pp-macroexpand-expression' and
-`pp-macroexpand-last-sexp' pretty-print macro expansions.
+*** The new commands 'pp-macroexpand-expression' and
+'pp-macroexpand-last-sexp' pretty-print macro expansions.
 
-*** The new command `set-file-modes' allows to set file's mode bits.
+*** The new command 'set-file-modes' allows to set file's mode bits.
 The mode bits can be specified in symbolic notation, like with GNU
-Coreutils, in addition to an octal number.  `chmod' is a new
+Coreutils, in addition to an octal number.  'chmod' is a new
 convenience alias for this function.
 
-*** `next-error-recenter' specifies how next-error should recenter the
+*** 'next-error-recenter' specifies how next-error should recenter the
 visited source file.  Its value can be a number (for example, 0 for
 top line, -1 for bottom line), or nil for no recentering.
 
 *** When typing in a password in the echo area, C-y yanks the current
 kill into the password.
 
-*** Tooltip frame parameters `font' and `color' in `tooltip-frame-parameters'
-are ignored.  Customize the `tooltip' face instead.
+*** Tooltip frame parameters 'font' and 'color' in 'tooltip-frame-parameters'
+are ignored.  Customize the 'tooltip' face instead.
 
-*** `mkdir' is a new convenience alias for `make-directory'.
+*** 'mkdir' is a new convenience alias for 'make-directory'.
 
 * New Modes and Packages in Emacs 23.1
 
 ** Auto Composition Mode is a minor mode that composes characters
 automatically when they are displayed.  It is globally on by default.
-It uses `auto-composition-function' (default `auto-compose-chars').
+It uses 'auto-composition-function' (default 'auto-compose-chars').
 
 ** Bubbles, a new game, is similar to SameGame.
 
 ** Buffer Face mode is a minor mode for remapping the default face in
-the current buffer.  The variable `buffer-face-mode-face' specifies
-the face to remap to.  The command `buffer-face-set' prompts for a
-face name, sets `buffer-face-mode-face' to it, and enables
+the current buffer.  The variable 'buffer-face-mode-face' specifies
+the face to remap to.  The command 'buffer-face-set' prompts for a
+face name, sets 'buffer-face-mode-face' to it, and enables
 buffer-face-mode.  See "Face changes", under Editing Changes, for a
 description of face remapping.
 
-** butterfly flips the desired bit on the drive platter.
+** 'butterfly' flips the desired bit on the drive platter.
 See http://xkcd.com/378/
 
 ** bug-reference.el provides clickable links to bug reports.
@@ -1267,7 +1267,7 @@ display the search results with Rmail, Gnus and VM.  Note 
that there
 is an existing Gnus back end, nnmairix.el, which should be used with
 Maildir/MH setups.
 
-** minibuffer-depth-indicate-mode shows the minibuffer depth in the prompt.
+** 'minibuffer-depth-indicate-mode' shows the minibuffer depth in the prompt.
 
 ** nXML Mode
 This is a new mode for editing XML documents.  It allows a schema to
@@ -1281,8 +1281,8 @@ any invalid parts of your document.
 attribute name or data value by using information about what is
 allowed by the schema in that context.
 
-** proced.el provides a Dired-like interface for operating on
-processes.  Proced makes an Emacs buffer containing a listing of the
+** 'proced' provides a Dired-like interface for operating on processes.
+Proced makes an Emacs buffer containing a listing of the
 current processes.  You can use the normal Emacs commands to move
 around in this buffer, and special Proced commands to operate on the
 processes listed.  It is currently only functional on GNU/Linux,
@@ -1299,7 +1299,7 @@ Manual.
 ** Visual Line mode provides support for editing by visual lines.
 It turns on word-wrapping in the current buffer, and rebinds C-a, C-e,
 and C-k to commands that operate by visual lines instead of logical
-lines.  This is a more reliable replacement for longlines-mode.
+lines.  This is a more reliable replacement for 'longlines-mode'.
 This can also be turned on using the menu bar, via
 Options -> Line Wrapping in this Buffer -> Word Wrap
 
@@ -1312,14 +1312,14 @@ interfaces according to the zeroconf specification.  It 
communicates
 with Avahi, a zeroconf implementation, via D-Bus messages on systems
 which have installed this software.
 
-** There is a new `whitespace' package.
-(The pre-existing one has been renamed to `old-whitespace'.)
+** There is a new 'whitespace' package.
+(The pre-existing one has been renamed to 'old-whitespace'.)
 Now, besides reporting bogus blanks, the whitespace package has a
 minor mode and a global minor mode to visualize blanks (TAB, (HARD)
 SPACE and NEWLINE).  The visualization is made via faces and/or display
 table.  It can also indicate lines that extend beyond a given column,
 trailing blanks, and empty lines at the start or end of a buffer.
-See `whitespace-style' for more details.  The `whitespace-action' option
+See 'whitespace-style' for more details.  The 'whitespace-action' option
 specifies what to do when a buffer is visited, killed, or written.
 
 
@@ -1327,30 +1327,30 @@ specifies what to do when a buffer is visited, killed, 
or written.
 
 ** Abbrev has been rewritten in Elisp and extended with more flexibility.
 
-*** New functions: abbrev-get, abbrev-put, abbrev-table-get, abbrev-table-put,
-abbrev-table-p, abbrev-insert, abbrev-table-menu.
+*** New functions: 'abbrev-get', 'abbrev-put', 'abbrev-table-get',
+'abbrev-table-put', 'abbrev-table-p', 'abbrev-insert', 'abbrev-table-menu'.
 
-*** Special hook `abbrev-expand-functions' obsoletes `pre-abbrev-expand-hook'.
+*** Special hook 'abbrev-expand-functions' obsoletes 'pre-abbrev-expand-hook'.
 
-*** `make-abbrev-table', `define-abbrev', `define-abbrev-table' all take
+*** 'make-abbrev-table', 'define-abbrev', 'define-abbrev-table' all take
 extra arguments for arbitrary properties.
 
-*** New variable `abbrev-minor-mode-table-alist'.
+*** New variable 'abbrev-minor-mode-table-alist'.
 
-*** `local-abbrev-table' can hold a list of abbrev-tables.
+*** 'local-abbrev-table' can hold a list of abbrev-tables.
 
 *** Abbrevs have now the following special properties:
-`:count', `:system', `:enable-function', `:case-fixed'.
+':count', ':system', ':enable-function', ':case-fixed'.
 
 *** Abbrev-tables have now the following special properties:
-`:parents', `:case-fixed', `:enable-function', `:regexp',
-`abbrev-table-modiff'.
+':parents', ':case-fixed', ':enable-function', ':regexp',
+'abbrev-table-modiff'.
 
 ** Apropos
 
-*** `apropos-library' describes the elements defined in a given library.
+*** 'apropos-library' describes the elements defined in a given library.
 
-*** Set `apropos-compact-layout' is you want a more compact (but wider) layout.
+*** Set 'apropos-compact-layout' is you want a more compact (but wider) layout.
 
 ** Archive Mode has basic support to browse Rar archives.
 Note, however, that the free version of the unrar command only handles
@@ -1358,15 +1358,15 @@ versions 1 and 2 of the Rar format.
 
 ** BibTeX mode
 
-*** New command `bibtex-initialize' (re)initializes BibTeX buffers.
+*** New command 'bibtex-initialize' (re)initializes BibTeX buffers.
 
-*** New `bibtex-entry-format' options `whitespace', `braces', and
-`string', disabled by default.
+*** New 'bibtex-entry-format' options 'whitespace', 'braces', and
+'string', disabled by default.
 
-*** New variable `bibtex-cite-matcher-alist' contains rules to
-identify cited keys in BibTeX entries, used by `bibtex-find-crossref'.
+*** New variable 'bibtex-cite-matcher-alist' contains rules to
+identify cited keys in BibTeX entries, used by 'bibtex-find-crossref'.
 
-*** Command `bibtex-url' allows multiple URLs per entry.
+*** Command 'bibtex-url' allows multiple URLs per entry.
 
 ** Bookmarks
 
@@ -1376,10 +1376,10 @@ older Emacs cannot read one saved by Emacs 23.
 
 ** Calc
 
-*** `j *' (cal-sel-mult-both-sides) has an option to expand the denominator.
+*** 'j *' (cal-sel-mult-both-sides) has an option to expand the denominator.
 
-*** `calc-embedded-word-regexp' is used for finding words in
-`calc-embedded-word' in place of delimiters.
+*** 'calc-embedded-word-regexp' is used for finding words in
+'calc-embedded-word' in place of delimiters.
 
 *** The separate Calc version number has been removed; use the Emacs
 version for reference.
@@ -1400,15 +1400,15 @@ version for reference.
 
 ** Calendar and diary
 
-*** There is a new date style, `iso', essentially year/month/day.
-The variable `european-calendar-style' is obsolete - use `calendar-date-style'.
-Similarly, the commands `american-calendar' and `european-calendar'
-should be replaced by `calendar-set-date-style'.
+*** There is a new date style, 'iso', essentially year/month/day.
+The variable 'european-calendar-style' is obsolete - use 'calendar-date-style'.
+Similarly, the commands 'american-calendar' and 'european-calendar'
+should be replaced by 'calendar-set-date-style'.
 
 *** The calendar namespace has been rationalized.
-All functions and variables now begin with a `calendar-', `diary-', or
-`holiday-' prefix.  The various calendar systems have secondary
-prefixes, eg `calendar-french-'.  The old names you are likely to use
+All functions and variables now begin with a 'calendar-', 'diary-', or
+'holiday-' prefix.  The various calendar systems have secondary
+prefixes, eg 'calendar-french-'.  The old names you are likely to use
 directly still exist, for the time being, as aliases, but please start
 using the new names.
 
@@ -1420,18 +1420,18 @@ calendar-day-header-width, and calendar-day-digit-width.
 *** Text (e.g. ISO weeks) can be displayed between the calendar months.
 See the variables calendar-intermonth-header and calendar-intermonth-text.
 
-*** The function `holiday-chinese' computes holidays on the Chinese calendar.
-It has been used to add items to the list `holiday-oriental-holidays'.
+*** The function 'holiday-chinese' computes holidays on the Chinese calendar.
+It has been used to add items to the list 'holiday-oriental-holidays'.
 
-*** `diary-remind' accepts a negative number -DAYS as a shorthand for
+*** 'diary-remind' accepts a negative number -DAYS as a shorthand for
 the list (1 2 ... DAYS).
 
 ** Change Log mode
 
-*** The new command C-c C-f (change-log-find-file) finds the file
+*** The new command C-c C-f ('change-log-find-file') finds the file
 associated with the current log entry.
 
-*** The new command C-c C-c (change-log-goto-source) goes to the
+*** The new command C-c C-c ('change-log-goto-source') goes to the
 source code associated with a log entry.
 
 ** Compile and grep modes
@@ -1440,79 +1440,79 @@ source code associated with a log entry.
 It has different colors for to show that: (a) the command is still
 running, (b) successful completion, (c) error.
 
-*** compilation-auto-jump-to-first-error tells `compile' to jump to
+*** compilation-auto-jump-to-first-error tells 'compile' to jump to
 the first error encountered during compilations.
 
-*** compilation-scroll-output accepts a new value, `first-error', which
+*** compilation-scroll-output accepts a new value, 'first-error', which
 says to stop auto scrolling at the first error that occurs.
 
-*** The `cc' alias for C++ files in `grep-file-aliases' has been
-improved.  `hh' can be used to match C++ header files and `cchh' both
+*** The 'cc' alias for C++ files in 'grep-file-aliases' has been
+improved.  'hh' can be used to match C++ header files and 'cchh' both
 C++ sources and headers.
 
 ** Copyright
 
 *** You can specify your copyright holders' names.
-Only copyright lines with holders matching `copyright-names-regexp' are
+Only copyright lines with holders matching 'copyright-names-regexp' are
 considered for update.
 
 *** Copyrights can be at the end of the buffer.
-This is controlled by `copyright-at-end-flag' (used by, e.g., change-log-mode).
+This is controlled by 'copyright-at-end-flag' (used by, e.g., change-log-mode).
 
 ** Custom
 
-*** defcustom accepts new keyword arguments, `:safe' and `:risky', which
-set a variable's `safe-local-variable' and `risky-local-variable' property.
+*** defcustom accepts new keyword arguments, ':safe' and ':risky', which
+set a variable's 'safe-local-variable' and 'risky-local-variable' property.
 
 ** Diff mode
 
-*** diff-refine-hunk highlights word-level details of changes in a diff hunk.
+*** 'diff-refine-hunk' highlights word-level details of changes in a diff hunk.
 It's used automatically as you move through hunks, see
-diff-auto-refine-mode.  It is bound to `C-c C-b'.
+'diff-auto-refine-mode'.  It is bound to 'C-c C-b'.
 
-*** diff-add-change-log-entries-other-window iterates through the diff
+*** 'diff-add-change-log-entries-other-window' iterates through the diff
 buffer and tries to create ChangeLog entries for each change.
-It is bound to `C-x 4 A'.
+It is bound to 'C-x 4 A'.
 
-*** Turning on `whitespace-mode' in a diff buffer will show trailing
+*** Turning on 'whitespace-mode' in a diff buffer will show trailing
 whitespace problems in the modified lines.
 
 ** Dired
 
-*** In Dired, C-x C-q now runs the command wdired-change-to-wdired-mode,
+*** In Dired, C-x C-q now runs the command 'wdired-change-to-wdired-mode',
 and C-x C-q in wdired-mode exits it with asking a question about
 saving changes.
 
-*** `&' runs the command `dired-do-async-shell-command' that executes
+*** '&' runs the command 'dired-do-async-shell-command' that executes
 the command asynchronously without the need to manually add ampersand
-to the end of the command.  Its output appears in the buffer `*Async Shell
+to the end of the command.  Its output appears in the buffer '*Async Shell
 Command*'.
 
-*** `M-s f C-s' and `M-s f M-C-s' run Isearch that matches only at file names.
-When a new user option `dired-isearch-filenames' is t, then even ordinary
-Isearch started with `C-s' and `C-M-s' matches only at file names in the
-Dired buffer.  When `dired-isearch-filenames' is `dwim' then activation of
+*** 'M-s f C-s' and 'M-s f M-C-s' run Isearch that matches only at file names.
+When a new user option 'dired-isearch-filenames' is t, then even ordinary
+Isearch started with 'C-s' and 'C-M-s' matches only at file names in the
+Dired buffer.  When 'dired-isearch-filenames' is 'dwim' then activation of
 file name Isearch depends on the position of point - if point is on a file
 name initially, then Isearch matches only file names, otherwise it matches
 everywhere in the Dired buffer.  You can toggle file names matching on or
-off by typing `M-s f' in Isearch mode.
+off by typing 'M-s f' in Isearch mode.
 
-*** `M-s a C-s' and `M-s a M-C-s' run multi-file Isearch on the marked files.
+*** 'M-s a C-s' and 'M-s a M-C-s' run multi-file Isearch on the marked files.
 They visit the first marked file in the sequence and display the usual Isearch
 prompt for a string or a regexp where all Isearch commands are available.
 
-*** `Q' in Dired provides two new keys for multi-file replacement.
-The upper case key `Y' replaces all remaining matches in all remaining files
-with no more questions.  The upper case key `N' stops doing replacements
+*** 'Q' in Dired provides two new keys for multi-file replacement.
+The upper case key 'Y' replaces all remaining matches in all remaining files
+with no more questions.  The upper case key 'N' stops doing replacements
 in the current file and skips to the next file.  These multi-file keys
-are available for all commands that use `tags-query-replace'
-including `dired-do-query-replace-regexp', `vc-dir-query-replace-regexp',
-`reftex-query-replace-document'.
+are available for all commands that use 'tags-query-replace'
+including 'dired-do-query-replace-regexp', 'vc-dir-query-replace-regexp',
+'reftex-query-replace-document'.
 
 ** Fortran
 
 *** The line length of fixed-form Fortran is not fixed at 72 any more.
-Customize the variable `fortran-line-length' to change it.
+Customize the variable 'fortran-line-length' to change it.
 
 *** In Fortran mode, M-; is now bound to the standard comment-dwim,
 rather than fortran-indent-comment.
@@ -1525,43 +1525,43 @@ rather than fortran-indent-comment.
 There are many new features, bug fixes and improvements; see the file
 GNUS-NEWS or the node "No Gnus" in the Gnus manual for details.
 
-*** In Emacs 23, Gnus uses Emacs' new internal coding system `utf-8-emacs' for
+*** In Emacs 23, Gnus uses Emacs' new internal coding system 'utf-8-emacs' for
 saving articles, drafts, and ~/.newsrc.eld.  These file may not be read
 correctly in Emacs 22 and below.  If you want to Gnus across different Emacs
-versions, you may set `mm-auto-save-coding-system' to `emacs-mule'.
+versions, you may set 'mm-auto-save-coding-system' to 'emacs-mule'.
 
-*** Passwords are consistently loaded through `auth-source'
-Gnus can use `auth-source' for POP and IMAP passwords.  Also see that
-`smtpmail' and `url' support `auth-source' for SMTP and HTTP/HTTPS/RSS
+*** Passwords are consistently loaded through 'auth-source'
+Gnus can use 'auth-source' for POP and IMAP passwords.  Also see that
+'smtpmail' and 'url' support 'auth-source' for SMTP and HTTP/HTTPS/RSS
 authentication respectively.
 
 ** Help mode
 
-*** New macro `with-help-window' should set up help windows better
-than `with-output-to-temp-buffer' with `print-help-return-message'.
+*** New macro 'with-help-window' should set up help windows better
+than 'with-output-to-temp-buffer' with 'print-help-return-message'.
 
-*** New option `help-window-select' permits to customize whether help
+*** New option 'help-window-select' permits to customize whether help
 window shall be automatically selected when invoking help.
 
-*** New variable `help-window-point-marker' permits one to specify a new
-position for point in help window (for example in `view-lossage').
+*** New variable 'help-window-point-marker' permits one to specify a new
+position for point in help window (for example in 'view-lossage').
 
 ** Isearch
 
-*** New command `isearch-forward-word' bound globally to `M-s w' starts
-incremental word search.  New command `isearch-toggle-word' bound to the
-same key `M-s w' in Isearch mode toggles word searching on or off
+*** New command 'isearch-forward-word' bound globally to 'M-s w' starts
+incremental word search.  New command 'isearch-toggle-word' bound to the
+same key 'M-s w' in Isearch mode toggles word searching on or off
 while Isearch is active.
 
-*** New command `isearch-highlight-regexp' bound to `M-s h r' in Isearch
-mode runs `highlight-regexp' (`hi-lock-face-buffer') with the current
-search string as its regexp argument.  The same key `M-s h r' and
-other keys on the `M-s h' prefix are bound globally to the command
-`highlight-regexp' and other hi-lock commands.
+*** New command 'isearch-highlight-regexp' bound to 'M-s h r' in Isearch
+mode runs 'highlight-regexp' ('hi-lock-face-buffer') with the current
+search string as its regexp argument.  The same key 'M-s h r' and
+other keys on the 'M-s h' prefix are bound globally to the command
+'highlight-regexp' and other hi-lock commands.
 
-*** New command `isearch-occur' bound to `M-s o' in Isearch mode
-runs `occur' with the current search string.  The same key `M-s o'
-is bound globally to the command `occur'.
+*** New command 'isearch-occur' bound to 'M-s o' in Isearch mode
+runs 'occur' with the current search string.  The same key 'M-s o'
+is bound globally to the command 'occur'.
 
 *** Isearch can now search through multiple ChangeLog files.
 When running Isearch in a ChangeLog file, if the search fails,
@@ -1570,20 +1570,20 @@ if there is one (e.g. going from ChangeLog to 
ChangeLog.12).
 This is enabled if multi-isearch-search is non-nil.
 
 *** Two new commands to start Isearch on a list of marked buffers
-for buff-menu.el and ibuffer.el are bound to the keys `M-s a C-s' and
-`M-s a M-C-s'.
+for buff-menu.el and ibuffer.el are bound to the keys 'M-s a C-s' and
+'M-s a M-C-s'.
 
 *** The part of an Isearch that failed to match is highlighted in
-`isearch-fail' face.
+'isearch-fail' face.
 
-*** `C-h C-h' in Isearch mode displays isearch-specific Help screen,
-`C-h b' displays all Isearch key bindings, `C-h k' displays the full
-documentation of the given Isearch key sequence, `C-h m' displays
+*** 'C-h C-h' in Isearch mode displays isearch-specific Help screen,
+'C-h b' displays all Isearch key bindings, 'C-h k' displays the full
+documentation of the given Isearch key sequence, 'C-h m' displays
 documentation for Isearch mode.  All the other Help commands exit
 Isearch mode and execute their global definitions.
 
 *** When started in the minibuffer, Isearch searches in the minibuffer
-history.  See `Minibuffer changes', above.
+history.  See 'Minibuffer changes', above.
 
 ** MH-E
 
@@ -1593,14 +1593,14 @@ history.  See `Minibuffer changes', above.
 *** The file etc/emacs.py now supports both Python 2 and 3, meaning
 that either version can be used as inferior Python by python.el.
 
-*** Python mode now has `pdbtrack' functionality.  When using pdb to
+*** Python mode now has 'pdbtrack' functionality.  When using pdb to
 debug a Python program, pdbtrack notices the pdb prompt and displays
 the source file and line that the program is stopped at, much the same
 way as gud-mode does for debugging C programs with gdb.
 
 ** Recentf
 
-*** The default value of `recentf-keep' prevents from checking of
+*** The default value of 'recentf-keep' prevents from checking of
 remote files, if there is no established connection to the
 corresponding remote host.
 
@@ -1631,37 +1631,37 @@ just a narrowed portion of the whole.  So you cannot 
access the whole
 of a message (or message collection) by a simple save-restriction and
 widen.  Instead, there are two buffers: the rmail-buffer, and the
 rmail-view-buffer.  The former is the buffer that you see, the latter
-is invisible.  Most of the time, the invisible `view' buffer contains
+is invisible.  Most of the time, the invisible 'view' buffer contains
 the full contents of the Rmail file, and the Rmail buffer contains a
 decoded copy of the current message (with only a subset of the
-headers).  In this state, Rmail is said to be `swapped'.
+headers).  In this state, Rmail is said to be 'swapped'.
 
 You may find the following functions useful:
 
-`rmail-get-header' and `rmail-set-header' get or set the value of a
+'rmail-get-header' and 'rmail-set-header' get or set the value of a
 message header, whether or not it is currently visible.
 
-`rmail-apply-in-message' is a general purpose function that calls a
+'rmail-apply-in-message' is a general purpose function that calls a
 function (with arguments) which you specify on the full text of a given
 message.  To further narrow to just the headers, search forward for "\n\n".
 
-*** The new command `rmail-mime' displays MIME messages.
-It is bound to `v' in Rmail buffers and summaries.  It displays plain
+*** The new command 'rmail-mime' displays MIME messages.
+It is bound to 'v' in Rmail buffers and summaries.  It displays plain
 text and multipart messages in a temporary buffer, and offers buttons
 to save attachments.
 
-*** The command `rmail-redecode-body' no longer accepts the optional arg RAW.
+*** The command 'rmail-redecode-body' no longer accepts the optional arg RAW.
 Since Rmail now holds messages in their original undecoded form in a
-separate buffer, `rmail-redecode-body' no longer encodes the original
+separate buffer, 'rmail-redecode-body' no longer encodes the original
 message, and therefore there should be no need to avoid encoding it.
 
-*** The o command is now `rmail-output'.  It is an all-purpose command
+*** The o command is now 'rmail-output'.  It is an all-purpose command
 for copying messages from Rmail and appending them to files.  It
 handles Babyl-format files as well as mbox-format files, and it
 handles both kinds properly when they are visited in Emacs.  It always
 copies the full headers of the message.
 
-*** The C-o command is now `rmail-output-as-seen'.  It uses
+*** The C-o command is now 'rmail-output-as-seen'.  It uses
 the message as displayed, appending it to an mbox file.
 
 *** The modified status of the Rmail buffer is reported in the mode-line.
@@ -1669,7 +1669,7 @@ Previously, this information was hidden.
 
 ** TeX modes
 
-*** New option latex-indent-within-escaped-parens
+*** New option 'latex-indent-within-escaped-parens'
 permits to customize indentation of LaTeX environments delimited
 by escaped parens.
 
@@ -1694,27 +1694,27 @@ in square brackets, like in "/ssh:[::1]:".
 
 *** Multihop syntax has been removed.
 The pseudo-method "multi" has been removed.  Instead, multi hops
-can be specified by the new variable `tramp-default-proxies-alist'.
+can be specified by the new variable 'tramp-default-proxies-alist'.
 
 *** More default settings.
-Default values can be set via the variables `tramp-default-user',
-`tramp-default-user-alist' and `tramp-default-host'.
+Default values can be set via the variables 'tramp-default-user',
+'tramp-default-user-alist' and 'tramp-default-host'.
 
 *** Connection information is cached.
 In order to reduce connection setup, information about used
 connections is kept persistently in a file.  The name of this file is
-defined in the variable `tramp-persistency-file-name'.
+defined in the variable 'tramp-persistency-file-name'.
 
 *** Control of remote processes.
 Running processes on a remote host can be controlled by settings in
-`tramp-remote-path' and `tramp-remote-process-environment'.
+'tramp-remote-path' and 'tramp-remote-process-environment'.
 
 *** Success of remote copy is checked.
-When the variable `file-precious-flag' is set, the success of a remote
+When the variable 'file-precious-flag' is set, the success of a remote
 file copy is checked via the file's checksum.
 
 *** Passwords can be read from an authentication file.
-Tramp uses the package `auth-source' to read passwords from a file, if
+Tramp uses the package 'auth-source' to read passwords from a file, if
 necessary.
 
 ** VC and related modes
@@ -1725,7 +1725,7 @@ version-control systems such as Subversion, GNU Arch, 
Mercurial, Git
 and Bzr.  VC will now pass a multiple-file commit to these systems as
 a single changeset.
 
-*** vc-dir is a new command that displays file names and their VC
+*** 'vc-dir' is a new command that displays file names and their VC
 status.  It allows to apply various VC operations to a file, a
 directory or a set of files/directories.
 
@@ -1733,9 +1733,9 @@ directory or a set of files/directories.
 (This was for the most part true in Emacs 22, but was not advertised).
 This is because there is an increasing variety of VC systems, and they
 do not all accept the same "common" options.  For example, a CVS diff
-command used to append the values of `vc-cvs-diff-switches',
-`vc-diff-switches', and `diff-switches'.  Now the first non-nil value
-from that sequence is used.  The special value `t' means "no switches".
+command used to append the values of 'vc-cvs-diff-switches',
+'vc-diff-switches', and 'diff-switches'.  Now the first non-nil value
+from that sequence is used.  The special value 't' means "no switches".
 
 *** Clicking on the VC mode-line entry now pops the VC menu.
 
@@ -1760,7 +1760,7 @@ active.
 
 *** Log entries can be modified using the key "e" in log-view.
 For now only CVS, RCS, SCCS and SVN support this functionality.
-This is done by the `modify-change-comment' backend function.
+This is done by the 'modify-change-comment' backend function.
 
 *** In log-view-mode, for VC systems that support changesets, you can
 see the diff for the whole changeset (not only for the current file)
@@ -1775,37 +1775,37 @@ to update it to the new VC.
 
 ** Miscellaneous
 
-*** comint-mode uses `start-file-process' now (see Lisp Changes).
-If `default-directory' is a remote file name, subprocesses are started
+*** comint-mode uses 'start-file-process' now (see Lisp Changes).
+If 'default-directory' is a remote file name, subprocesses are started
 on the corresponding remote system.
 
 *** ElDoc highlights the function argument under point
-with the face `eldoc-highlight-function-argument'.
+with the face 'eldoc-highlight-function-argument'.
 
 *** In Etags, the --members option is now the default.
 Use --no-members if you want the old default behavior of not tagging
 struct members in C, members variables in C++ and variables in PHP.
 
-*** The `gdb' command only works with the graphical interface now.
-Use `gud-gdb' if you want the (old) text command mode.
+*** The 'gdb' command only works with the graphical interface now.
+Use 'gud-gdb' if you want the (old) text command mode.
 
-*** goto-address.el provides two new minor modes, goto-address-mode and
-goto-address-prog-mode, which buttonize URLS and email addresses.
+*** 'goto-address' provides two new minor modes, 'goto-address-mode' and
+'goto-address-prog-mode', which buttonize URLS and email addresses.
 
-*** The new command `eshell/info' runs info in an eshell buffer.
+*** The new command 'eshell/info' runs info in an eshell buffer.
 
-*** The new variable `ffap-rfc-directories' specifies a list of local
-directories in which `ffap-rfc' will first search for RFCs.
+*** The new variable 'ffap-rfc-directories' specifies a list of local
+directories in which 'ffap-rfc' will first search for RFCs.
 
 *** hide-ifdef-mode allows shadowing ifdef-blocks instead of hiding them.
-See option `hide-ifdef-shadow' and function `hide-ifdef-toggle-shadowing'.
+See option 'hide-ifdef-shadow' and function 'hide-ifdef-toggle-shadowing'.
 
-*** `icomplete-prospects-height' now supersedes `icomplete-prospects-length'.
+*** 'icomplete-prospects-height' now supersedes 'icomplete-prospects-length'.
 
 *** Info displays breadcrumbs in the header of the page.
 See Info-breadcrumbs-depth to control it.
 
-*** net-utils has an `iwconfig' command, similar to the existing `ifconfig'.
+*** net-utils has an 'iwconfig' command, similar to the existing 'ifconfig'.
 It is used to configure wireless interfaces.
 
 *** The pcmpl-unix package supports hostname completion for ssh and scp.
@@ -1818,7 +1818,7 @@ smerge-auto-refine-mode.
 
 *** talk.el has been extended for multiple tty support.
 
-*** A new command `display-time-world' has been added to the Time
+*** A new command 'display-time-world' has been added to the Time
 package.  It creates a buffer with an updating time display using
 several time zones.
 
@@ -1831,16 +1831,16 @@ tex-suscript-height-minimum.
 since users found iconification of view-mode frames distracting.
 
 *** WoMan tries to add locale-specific manual page directories to the
-search path.  This can be disabled by setting `woman-locale' to nil.
+search path.  This can be disabled by setting 'woman-locale' to nil.
 
 
 * Changes in Emacs 23.1 on non-free operating systems
 
 ** Case is now considered significant in completion on MS-Windows.
-The default value of `completion-ignore-case' is now nil on
+The default value of 'completion-ignore-case' is now nil on
 MS-Windows, the same as it is for other operating systems.  The
 variable doesn't apply to reading a file name -- in that case Emacs
-heeds `read-file-name-completion-ignore-case' instead.
+heeds 'read-file-name-completion-ignore-case' instead.
 
 ** IPv6 is supported on MS-Windows.
 Emacs now supports IPv6 on Windows XP and later, and earlier versions
@@ -1855,7 +1855,7 @@ In Emacs 22 only X supported the busy cursor.
 ** Battery status is available on MS-Windows
 Emacs can now display the battery status in the mode-line when enabled with
 display-battery-mode or from the Options menu.  More verbose battery
-information is also available with the command `battery'.  In Emacs 22
+information is also available with the command 'battery'.  In Emacs 22
 battery status was supported only on GNU/Linux and Mac.
 
 ** More keys available on MS-Windows.
@@ -1886,8 +1886,8 @@ freetype library, giving access to a wider range of font 
formats.
 
 ** Variables cannot be both buffer-local and frame-local any more.
 
-** `functionp' returns nil for special forms.
-I.e., it only returns t for objects that can be passed to `funcall'.
+** 'functionp' returns nil for special forms.
+I.e., it only returns t for objects that can be passed to 'funcall'.
 
 ** The behavior of map-char-table has changed.  It may call the
 specified function with a cons (FROM . TO) as a key if characters in
@@ -1895,32 +1895,32 @@ that range have the same value.
 
 ** Process changes
 
-*** The function `dired-call-process' has been removed.
+*** The function 'dired-call-process' has been removed.
 
 *** The multibyteness of process filters is now determined by the
 coding-system used for decoding.  The functions
-`process-filter-multibyte-p' and `set-process-filter-multibyte' are
+'process-filter-multibyte-p' and 'set-process-filter-multibyte' are
 obsolete.
 
-** The variable `byte-compile-warnings' can now be a list starting with `not',
+** The variable 'byte-compile-warnings' can now be a list starting with 'not',
 meaning to disable the specified warnings.  The meaning of this list
 may therefore be the reverse of what you expect (of course, this is
-only an issue if you make use of the new `not' syntax).  Rather than
+only an issue if you make use of the new 'not' syntax).  Rather than
 checking/manipulating elements directly, use the new functions
-`byte-compile-warning-enabled-p', `byte-compile-disable-warning', and
-`byte-compile-enable-warning.'
+'byte-compile-warning-enabled-p', 'byte-compile-disable-warning', and
+'byte-compile-enable-warning'.
 
-** `mode-name' is no longer guaranteed to be a string.
-Use `(format-mode-line mode-name)' to ensure a string value.
+** 'mode-name' is no longer guaranteed to be a string.
+Use '(format-mode-line mode-name)' to ensure a string value.
 
-** The function x-font-family-list has been removed.
-Use the new function font-family-list (see Lisp Changes, below).
+** The function 'x-font-family-list' has been removed.
+Use the new function 'font-family-list' (see Lisp Changes, below).
 
 ** Internationalization changes
 
-*** The value of the function `charset-id' is now always 0.
+*** The value of the function 'charset-id' is now always 0.
 
-*** The functions `register-char-codings' and `coding-system-spec'
+*** The functions 'register-char-codings' and 'coding-system-spec'
 have been removed.
 
 *** The cpXXX coding systems are now supported automatically.
@@ -1931,23 +1931,23 @@ enable support for these coding systems, have been 
deleted.
 displaying various scripts with specific fonts, and are no longer
 needed now that OpenType font support is available:
 
-**** `devanagari' and `devan-util', and all associated devanagari-* and
+**** 'devanagari' and 'devan-util', and all associated devanagari-* and
 dev-* functions and variables (formerly used for Devanagari script).
 
-**** `kannada' and `knd-util', and all associated kannada-* and knd-*
+**** 'kannada' and 'knd-util', and all associated kannada-* and knd-*
 functions and variables (formerly used for Kannada script).
 
-**** `malayalam' and `mlm-util', and all associated malayalam-* and
+**** 'malayalam' and 'mlm-util', and all associated malayalam-* and
 mlm-* functions and variables (formerly used for Malayalam script).
 
-**** `tamil' and `tml-util, and all associated tamil-* and tml-*
+**** 'tamil' and 'tml-util', and all associated tamil-* and tml-*
 functions and variables (formerly used for Tamil script).
 
-*** The meaning of NAME argument of `set-fontset-font' is changed.
+*** The meaning of NAME argument of 'set-fontset-font' is changed.
 Previously nil is accepted as the default fontset.  Now, nil is for
 the fontset of the selected frame and t is for the default fontset.
 
-*** The meaning of FONTSET argument of `print-fontset' is changed.
+*** The meaning of FONTSET argument of 'print-fontset' is changed.
 Now, nil is for the fontset of the selected frame and t is for the
 default fontset.
 
@@ -1955,8 +1955,8 @@ default fontset.
 different buffer current, Emacs no longer kills that buffer
 automatically.  This behavior existed in previous versions of Emacs,
 but was undocumented.  To kill a buffer after write-region, give the
-variable `write-region-post-annotation-function' a buffer-local value
-of `kill-buffer'.
+variable 'write-region-post-annotation-function' a buffer-local value
+of 'kill-buffer'.
 
 ** The variable temp-file-name-pattern has been removed.
 This variable was only used by call-process-region, which now uses
@@ -1968,127 +1968,127 @@ arbitrary abbrev properties.
 
 ** end-of-defun-function is now guaranteed to work only when called
 from the start of a defun.  It must now leave point exactly at the end
-of defun, since `end-of-defun' now itself moves forward over
+of defun, since 'end-of-defun' now itself moves forward over
 whitespace after calling it.
 
 
 * Lisp Changes in Emacs 23.1
 
-** The new variable `generate-autoload-cookie' controls the magic comment
-string used by `update-file-autoloads' to find autoloaded forms.  The
-variable `generated-autoload-file' similarly controls the name of the
-file where `update-file-autoloads' writes the calls to `autoload'.
-The default values are ";;;###autoload" and `loaddefs.el',
+** The new variable 'generate-autoload-cookie' controls the magic comment
+string used by 'update-file-autoloads' to find autoloaded forms.  The
+variable 'generated-autoload-file' similarly controls the name of the
+file where 'update-file-autoloads' writes the calls to 'autoload'.
+The default values are ";;;###autoload" and 'loaddefs.el',
 respectively.
 
-** New primitives `list-system-processes' and `process-attributes'
+** New primitives 'list-system-processes' and 'process-attributes'
 let Lisp programs access the processes that are running on the local
 machine.  See the doc strings of these functions for more details.
 Not all platforms support accessing this information; on those that
 don't, these primitives will return nil.
 
-** New variable `user-emacs-directory'.
+** New variable 'user-emacs-directory'.
 Use this instead of "~/.emacs.d".
 
-** If a local hook function has a non-nil `permanent-local-hook'
-property, `kill-all-local-variables' does not remove it from the local
+** If a local hook function has a non-nil 'permanent-local-hook'
+property, 'kill-all-local-variables' does not remove it from the local
 value of the hook variable; it remains even if you change major modes.
 
-** `frame-inherited-parameters' lets new frames inherit parameters from
+** 'frame-inherited-parameters' lets new frames inherit parameters from
 the selected frame.
 
-** New keymap `input-decode-map' overrides like key-translation-map, but
+** New keymap 'input-decode-map' overrides like key-translation-map, but
 applies before function-key-map.  Also it is terminal-local contrary to
 key-translation-map.  Terminal-specific key-sequences are generally added to
 this map rather than to function-key-map now.
 
-** `ignore-errors' is now a standard macro (does not require the CL package).
+** 'ignore-errors' is now a standard macro (does not require the CL package).
 
-** `interprogram-paste-function' can now return one string or a list
+** 'interprogram-paste-function' can now return one string or a list
 of strings.  In the latter case, Emacs puts the second and following
 strings on the kill ring.
 
-** In `condition-case', a handler can specify "let the debugger run first".
-You do this by writing `debug' in the list of conditions to be handled,
+** In 'condition-case', a handler can specify "let the debugger run first".
+You do this by writing 'debug' in the list of conditions to be handled,
 like this:
 
     (condition-case nil
        (foo bar)
       ((debug error) nil))
 
-** clone-indirect-buffer now runs the clone-indirect-buffer-hook.
+** 'clone-indirect-buffer' now runs the 'clone-indirect-buffer-hook'.
 
-** `beginning-of-defun-function' now takes one argument, the count given to
-`beginning-of-defun'.  (N.B. `end-of-defun-function' doesn't take any
+** 'beginning-of-defun-function' now takes one argument, the count given to
+'beginning-of-defun'.  (N.B. 'end-of-defun-function' doesn't take any
 arguments.)
 
-** `file-remote-p' has new optional parameters IDENTIFICATION and CONNECTED.
+** 'file-remote-p' has new optional parameters IDENTIFICATION and CONNECTED.
 IDENTIFICATION specifies which part of the remote identifier has to be
 returned.  With CONNECTED passed non-nil, it is checked whether a
 remote connection has been established already.
 
-** The new macro `declare-function' suppresses compiler warnings about
+** The new macro 'declare-function' suppresses compiler warnings about
 undefined functions.
 
 ** Changes to interactive function handling
 
 *** The new interactive spec code ^ says to first call
-handle-shift-selection if shift-select-mode is non-nil, before reading
+'handle-shift-selection' if shift-select-mode is non-nil, before reading
 the command arguments.  This is used for shift-selection (see above).
 
 *** Built-in functions can now have an interactive specification that
-is not a prompt string.  If the `intspec' parameter of a `DEFUN'
-starts with a `(', the string is evaluated as a Lisp form.
+is not a prompt string.  If the 'intspec' parameter of a 'DEFUN'
+starts with a '(', the string is evaluated as a Lisp form.
 
 *** The interactive-form of a function can be added post-facto via the
-`interactive-form' symbol property.  Mostly useful to add complex
+'interactive-form' symbol property.  Mostly useful to add complex
 interactive forms to subroutines.
 
 ** Region changes
 
-*** Commands should use `use-region-p' to test whether there is
+*** Commands should use 'use-region-p' to test whether there is
 an active region that they should operate on.
 
-*** `region-active-p' returns non-nil when Transient Mark mode is
+*** 'region-active-p' returns non-nil when Transient Mark mode is
 enabled and the mark is active.  Most commands that act specially on
-the active region in Transient Mark mode should use `use-region-p'
-instead of `region-active-p', because `use-region-p' obeys the new
-user option `use-empty-active-region' (see Editing Changes, above).
+the active region in Transient Mark mode should use 'use-region-p'
+instead of 'region-active-p', because 'use-region-p' obeys the new
+user option 'use-empty-active-region' (see Editing Changes, above).
 
-*** If a command sets `transient-mark-mode' to (only . OLDVAL), that
+*** If a command sets 'transient-mark-mode' to (only . OLDVAL), that
 means to activate transient-mark-mode temporarily, until the next
 unshifted point motion command or mark deactivation.  Afterwards,
-reset transient-mark-mode to the value OLDVAL.  The values `only' and
-`identity', introduced in Emacs 22, are now deprecated.
+reset transient-mark-mode to the value OLDVAL.  The values 'only' and
+'identity', introduced in Emacs 22, are now deprecated.
 
 ** Emacs session information
 
-*** The new variables `before-init-time' and `after-init-time' record the
-value of `current-time' before and after Emacs loads the init files.
+*** The new variables 'before-init-time' and 'after-init-time' record the
+value of 'current-time' before and after Emacs loads the init files.
 
-*** The new function `emacs-uptime' returns the uptime of an Emacs instance.
+*** The new function 'emacs-uptime' returns the uptime of an Emacs instance.
 
-*** The new function `emacs-init-time' returns the duration of the
+*** The new function 'emacs-init-time' returns the duration of the
 Emacs initialization.
 
 ** Changes affecting display-buffer
 
-*** display-buffer tries to be smarter when splitting windows.
-The new option split-window-preferred-function lets you specify your own
-function to pop up new windows.  Its default value split-window-sensibly
+*** 'display-buffer' tries to be smarter when splitting windows.
+The new option 'split-window-preferred-function' lets you specify your own
+function to pop up new windows.  Its default value 'split-window-sensibly'
 can split a window either vertically or horizontally, whichever seems
 more suitable in the current configuration.  You can tune the behavior
-of split-window-sensibly by customizing split-height-threshold and the
-new option split-width-threshold.  Both options now take the value nil
-to inhibit splitting in one direction.  Setting split-width-threshold to
+of 'split-window-sensibly' by customizing 'split-height-threshold' and the
+new option 'split-width-threshold'.  Both options now take the value nil
+to inhibit splitting in one direction.  Setting 'split-width-threshold' to
 nil inhibits horizontal splitting and gets you the behavior of Emacs 22
 in this respect.  In any case, display-buffer may now split the largest
 window vertically even when it is not as wide as the containing frame.
 
-*** If pop-up-frames has the value `graphic-only', display-buffer only
+*** If 'pop-up-frames' has the value 'graphic-only', display-buffer only
 makes a separate frame on graphic displays.
 
-*** select-frame and set-frame-selected-window have a new optional
+*** 'select-frame' and 'set-frame-selected-window' have a new optional
 argument NORECORD.  If non-nil, this will avoid messing with the order
 of recently selected windows and the buffer list.
 
@@ -2096,56 +2096,56 @@ of recently selected windows and the buffer list.
 These are analogous to frame parameters, but are associated with
 individual windows.
 
-*** The new functions window-parameters, window-parameter, and
-set-window-parameter are used to query and set window parameters.
+*** The new functions 'window-parameters', 'window-parameter', and
+'set-window-parameter' are used to query and set window parameters.
 
 ** Minibuffer and completion changes
 
 *** A list of default values can be specified for the DEFAULT argument of
-functions `read-from-minibuffer', `read-string', `read-command',
-`read-variable', `read-buffer', `completing-read'.  Elements of this list
-are available for inserting into the minibuffer by typing `M-n'.
+functions 'read-from-minibuffer', 'read-string', 'read-command',
+'read-variable', 'read-buffer', 'completing-read'.  Elements of this list
+are available for inserting into the minibuffer by typing 'M-n'.
 For empty input these functions return the first element of this list.
 
-*** New function `read-regexp' uses the regexp history and some useful
+*** New function 'read-regexp' uses the regexp history and some useful
 regexp defaults (string at point, last Isearch/replacement regexp/string)
 via M-n when reading a regexp in the minibuffer.
 
 *** minibuffer-local-must-match-filename-map is now named
 minibuffer-local-filename-must-match-map.
 
-*** The `require-match' argument to `completing-read' accepts the new
-values `confirm-only' and `confirm-after-completion'.
+*** The 'require-match' argument to 'completing-read' accepts the new
+values 'confirm-only' and 'confirm-after-completion'.
 
 ** Search and replacement changes
 
 *** The regexp form \(?<num>:<regexp>\) specifies the group number explicitly.
 
-*** New function `match-substitute-replacement' returns the result of
-`replace-match' without actually using it in the buffer.
+*** New function 'match-substitute-replacement' returns the result of
+'replace-match' without actually using it in the buffer.
 
-*** The new variable `replace-search-function' determines the function
+*** The new variable 'replace-search-function' determines the function
 to use for searching in query-replace and replace-string.  The
-function it specifies is called by `perform-replace' when its 4th
+function it specifies is called by 'perform-replace' when its 4th
 argument is nil.
 
-*** The new variable `replace-re-search-function' determines the
-function to use for searching in `query-replace-regexp',
-`replace-regexp', `query-replace-regexp-eval', and
-`map-query-replace-regexp'.  The function it specifies is called by
-`perform-replace' when its 4th argument is non-nil.
+*** The new variable 'replace-re-search-function' determines the
+function to use for searching in 'query-replace-regexp',
+'replace-regexp', 'query-replace-regexp-eval', and
+'map-query-replace-regexp'.  The function it specifies is called by
+'perform-replace' when its 4th argument is non-nil.
 
-*** New keymap `search-map' bound to `M-s' provides global bindings
+*** New keymap 'search-map' bound to 'M-s' provides global bindings
 for search related commands.
 
-*** New keymap `multi-query-replace-map' contains additional keys bound
-to `automatic-all' and `exit-current' for multi-buffer interactive replacement.
+*** New keymap 'multi-query-replace-map' contains additional keys bound
+to 'automatic-all' and 'exit-current' for multi-buffer interactive replacement.
 
-*** The variable `inhibit-changing-match-data', if non-nil, prevents
+*** The variable 'inhibit-changing-match-data', if non-nil, prevents
 the search and match primitives from changing the match data.
 
-*** New functions `word-search-forward-lax' and `word-search-backward-lax'.
-These are like `word-search-forward and `word-search-backward', except
+*** New functions 'word-search-forward-lax' and 'word-search-backward-lax'.
+These are like 'word-search-forward' and 'word-search-backward', except
 that the end of the search string need not match a word boundary,
 unless it ends in whitespace.
 
@@ -2160,37 +2160,37 @@ variables defined in the current buffer.
 ** Face-remapping
 
 *** Each face can be remapped to a different face definition using the
-variable `face-remapping-alist'.  This is an alist that maps faces to
+variable 'face-remapping-alist'.  This is an alist that maps faces to
 replacement definitions (which can be face names, lists of face names,
 or attribute/value plists.  If this variable is buffer-local, the
 remapping occurs only in that buffer.
 
 *** text-scale-mode remaps the default face to a larger or smaller
 size in the current buffer.  This feature is used by the Buffer Face
-menu and the new `C-x C-+', `C-x C--', and `C-x C-0' commands (see
+menu and the new 'C-x C-+', 'C-x C--', and 'C-x C-0' commands (see
 Editing Changes, above).
 
 *** New functions:
 
-**** `face-remap-add-relative' adds a face remapping entry to the
+**** 'face-remap-add-relative' adds a face remapping entry to the
 current buffer.
 
-**** ``face-remap-remove-relative' removes a face remapping entry from
+**** 'face-remap-remove-relative' removes a face remapping entry from
 the current buffer.
 
-**** `face-remap-reset-base' restores a face to its global definition.
+**** 'face-remap-reset-base' restores a face to its global definition.
 
-**** `face-remap-set-base' sets the base remapping of a face.
+**** 'face-remap-set-base' sets the base remapping of a face.
 
 ** Process changes
 
-*** The new function `start-file-process' is similar to `start-process',
+*** The new function 'start-file-process' is similar to 'start-process',
 but obeys file handlers.  The file handler is chosen based on
-`default-directory'.  The functions `start-file-process-shell-command'
-and `process-file-shell-command' are also new; they call internally
-`start-file-process' and `process-file', respectively.
+'default-directory'.  The functions 'start-file-process-shell-command'
+and 'process-file-shell-command' are also new; they call internally
+'start-file-process' and 'process-file', respectively.
 
-*** The new function `process-lines' executes an external program and
+*** The new function 'process-lines' executes an external program and
 returns its output as a list of lines.
 
 ** Character code, representation, and charset changes.
@@ -2213,105 +2213,105 @@ each dimension is no longer limited to 94 or 96.
 **** A dynamic charset priority list is used to infer the charset of
 characters for display.
 
-*** The functions `split-char' and `make-char' now accept up to 4
+*** The functions 'split-char' and 'make-char' now accept up to 4
 positional codes instead of just 2.
 
-*** The functions `encode-char' and `decode-char' now accept any character 
sets.
+*** The functions 'encode-char' and 'decode-char' now accept any character 
sets.
 
-*** The function `define-charset' now accepts a completely different
+*** The function 'define-charset' now accepts a completely different
 form of arguments (old-style arguments still work).
 
-*** The value of the function `char-charset' depends on the current
+*** The value of the function 'char-charset' depends on the current
 priorities of charsets.
 
-*** The function get-char-code-property now accepts many Unicode base
-character properties.  They are `name', `general-category',
-`canonical-combining-class', `bidi-class', `decomposition',
-`decimal-digit-value', `digit-value', `numeric-value', `mirrored',
-`old-name', `iso-10646-comment', `uppercase', `lowercase', and
-`titlecase'.
+*** The function 'get-char-code-property' now accepts many Unicode base
+character properties.  They are 'name', 'general-category',
+'canonical-combining-class', 'bidi-class', 'decomposition',
+'decimal-digit-value', 'digit-value', 'numeric-value', 'mirrored',
+'old-name', 'iso-10646-comment', 'uppercase', 'lowercase', and
+'titlecase'.
 
-*** The functions `modify-syntax-entry' and `modify-category-entry' now
+*** The functions 'modify-syntax-entry' and 'modify-category-entry' now
 accept a cons of characters as the first argument, and modify all
 entries in that range of characters.
 
-*** Use of `translation-table-for-input' for character code unification
+*** Use of 'translation-table-for-input' for character code unification
 is now obsolete, since Emacs 23.1 and later uses Unicode as basis for
 internal representation of characters.
 
 *** New functions:
 
-**** `characterp' returns t if and only if the argument is a character.
-This replaces `char-valid-p', which is now obsolete.
+**** 'characterp' returns t if and only if the argument is a character.
+This replaces 'char-valid-p', which is now obsolete.
 
-**** `max-char' returns the maximum character code (currently #x3FFFFF).
+**** 'max-char' returns the maximum character code (currently #x3FFFFF).
 
-**** `define-charset-alias' defines an alias of a charset.
+**** 'define-charset-alias' defines an alias of a charset.
 
-**** `set-charset-priority' sets priorities of charsets.
+**** 'set-charset-priority' sets priorities of charsets.
 
-**** `charset-priority-list' returns a prioritized list of charsets.
+**** 'charset-priority-list' returns a prioritized list of charsets.
 
-**** `unibyte-string' makes a unibyte string from bytes.
+**** 'unibyte-string' makes a unibyte string from bytes.
 
-**** `define-char-code-property' defines a character code property.
+**** 'define-char-code-property' defines a character code property.
 
-**** `char-code-property-description' returns the description string of
+**** 'char-code-property-description' returns the description string of
 a character code property.
 
 *** New variables:
 
-**** `find-word-boundary-function-table' is a char-table of functions to
+**** 'find-word-boundary-function-table' is a char-table of functions to
 search for a word boundary.
 
-**** `char-script-table' is a char-table of script names.
+**** 'char-script-table' is a char-table of script names.
 
-**** `char-width-table' is a char-table of character widths.
+**** 'char-width-table' is a char-table of character widths.
 
-**** `print-charset-text-property' controls how to handle `charset' text
+**** 'print-charset-text-property' controls how to handle 'charset' text
 property on printing a string.
 
-**** `printable-chars' is a char-table of printable characters.
+**** 'printable-chars' is a char-table of printable characters.
 
 ** Code conversion changes
 
-*** The new function `define-coding-system' should be used to define a
-coding system instead of `make-coding-system' (which is now obsolete).
+*** The new function 'define-coding-system' should be used to define a
+coding system instead of 'make-coding-system' (which is now obsolete).
 
-*** The functions `encode-coding-region' and `decode-coding-region'
+*** The functions 'encode-coding-region' and 'decode-coding-region'
 have an optional 4th argument to specify where the result of
 conversion should go.
 
-*** The functions `encode-coding-string' and `decode-coding-string'
+*** The functions 'encode-coding-string' and 'decode-coding-string'
 have an optional 4th argument specifying a buffer to store the result
 of conversion.
 
-*** The new variable `inhibit-null-byte-detection' controls whether to
+*** The new variable 'inhibit-null-byte-detection' controls whether to
 consider text with null bytes as binary data.  By default, it is
-`nil', and Emacs uses `no-conversion' for any text containing null
+'nil', and Emacs uses 'no-conversion' for any text containing null
 bytes.
 
-*** The functions `set-coding-priority' and `make-coding-system' are obsolete.
+*** The functions 'set-coding-priority' and 'make-coding-system' are obsolete.
 
 *** New functions:
 
-**** `with-coding-priority' executes Lisp code using the specified
+**** 'with-coding-priority' executes Lisp code using the specified
 coding system priority order.
 
-**** `check-coding-systems-region' checks if the text in the region is
+**** 'check-coding-systems-region' checks if the text in the region is
 encodable by the specified coding systems.
 
-**** `coding-system-aliases' returns a list of aliases of a coding system.
+**** 'coding-system-aliases' returns a list of aliases of a coding system.
 
-**** `coding-system-charset-list' returns a list of charsets supported
+**** 'coding-system-charset-list' returns a list of charsets supported
 by a coding system.
 
-**** `coding-system-priority-list' returns a list of coding systems
+**** 'coding-system-priority-list' returns a list of coding systems
 ordered by their priorities.
 
-**** `set-coding-system-priority' sets priorities of coding systems.
+**** 'set-coding-system-priority' sets priorities of coding systems.
 
-**** `coding-system-from-name' returns a coding system matching with
+**** 'coding-system-from-name' returns a coding system matching with
 the argument name.
 
 ** There is a new input method, Robin, different from Quail.
@@ -2321,14 +2321,14 @@ ii) converts an existing buffer substring into another 
string
 iii) reverse conversion (each character produced by a
 robin rule can hold the original ASCII sequence as a char-code-property)
 
-*** The new function `robin-define-package' defines a Robin package.
+*** The new function 'robin-define-package' defines a Robin package.
 
-*** The new function `robin-modify-package' modifies an existing Robin package.
+*** The new function 'robin-modify-package' modifies an existing Robin package.
 
-*** The new function `robin-use-package' starts using a Robin package
+*** The new function 'robin-use-package' starts using a Robin package
 as an input method.
 
-*** The new function `string-to-unibyte' is like `string-as-unibyte'
+*** The new function 'string-to-unibyte' is like 'string-as-unibyte'
 but signals an error if STRING contains a non-ASCII, non-eight-bit
 character.
 
@@ -2342,115 +2342,115 @@ Emacs.FontBackend: x,xft
 If this resource is not set, Emacs tries to use all font backends
 available on your graphic device.
 
-*** New frame parameter `font-backend' specifies a list of
+*** New frame parameter 'font-backend' specifies a list of
 font-backends supported by the frame's graphic device.  On X, they are
-currently `x' and `xft'.
+currently 'x' and 'xft'.
 
-*** The function `set-fontset-font' now accepts a script name as the
+*** The function 'set-fontset-font' now accepts a script name as the
 second argument, and has an optional 5th argument to control how to
 set the font.
 
 *** New functions:
 
-**** `fontp' checks if the argument is a font-spec or font-entity.
+**** 'fontp' checks if the argument is a font-spec or font-entity.
 
-**** `font-spec' creates a new font-spec object.
+**** 'font-spec' creates a new font-spec object.
 
-**** `font-get' returns a font property value.
+**** 'font-get' returns a font property value.
 
-**** `font-put' sets a font property value.
+**** 'font-put' sets a font property value.
 
-**** `font-face-attributes' returns a plist of face attributes set by a font.
+**** 'font-face-attributes' returns a plist of face attributes set by a font.
 
-**** `list-fonts' returns a list of font-entities matching a font spec.
+**** 'list-fonts' returns a list of font-entities matching a font spec.
 
-**** `find-font' returns the font-entity best matching the given font spec.
+**** 'find-font' returns the font-entity best matching the given font spec.
 
-**** `font-family-list' returns a list of family names of available fonts.
+**** 'font-family-list' returns a list of family names of available fonts.
 
-**** `font-xlfd-name' returns an XLFD name of a given font spec, font
+**** 'font-xlfd-name' returns an XLFD name of a given font spec, font
 entity, or font object.
 
-**** `clear-font-cache' clears all font caches.
+**** 'clear-font-cache' clears all font caches.
 
 ** Changes related to multiple-terminal (multi-tty) support
 
-*** $TERM is now set to `dumb' for subprocesses.  If you want to know the
+*** $TERM is now set to 'dumb' for subprocesses.  If you want to know the
 $TERM inherited by Emacs you will have to look inside initial-environment.
 
-*** $DISPLAY is now dynamically inherited from the frame's `display'.
+*** $DISPLAY is now dynamically inherited from the frame's 'display'.
 
-*** The `window-system' variable is now frame-local.  The new
-`initial-window-system' variable contains the `window-system' value
-for the first frame.  `window-system' is also now a function that
+*** The 'window-system' variable is now frame-local.  The new
+'initial-window-system' variable contains the 'window-system' value
+for the first frame.  'window-system' is also now a function that
 takes a frame argument.
 
-*** The `keyboard-translate-table' variable and the terminal and
+*** The 'keyboard-translate-table' variable and the terminal and
 keyboard coding systems are now terminal-local.
 
-*** You can specify a terminal device (`tty' parameter) and a terminal
-type (`tty-type' parameter) to `make-terminal-frame'.
+*** You can specify a terminal device ('tty' parameter) and a terminal
+type ('tty-type' parameter) to 'make-terminal-frame'.
 
-*** The function `make-frame-on-display' now works during a tty
+*** The function 'make-frame-on-display' now works during a tty
 session.
 
-*** A new `terminal' data type.
-The functions `get-device-terminal', `terminal-parameters',
-`terminal-parameter', `set-terminal-parameter' use this data type.
+*** A new 'terminal' data type.
+The functions 'get-device-terminal', 'terminal-parameters',
+'terminal-parameter', 'set-terminal-parameter' use this data type.
 
-*** Function key sequences are now mapped using `local-function-key-map',
+*** Function key sequences are now mapped using 'local-function-key-map',
 a new variable.  This inherits from the global variable function-key-map,
 which is not used directly any more.
 
 *** New hooks:
 
-**** before-hack-local-variables-hook is called after setting new
-variable file-local-variables-alist, and before actually applying the
+**** 'before-hack-local-variables-hook' is called after setting new
+variable 'file-local-variables-alist', and before actually applying the
 file-local variables.
 
-**** `suspend-tty-functions' and `resume-tty-functions' are called
+**** 'suspend-tty-functions' and 'resume-tty-functions' are called
 after a tty frame has been suspended or resumed, respectively.  The
 functions are called with the terminal id of the frame being
 suspended/resumed as a parameter.
 
-**** The special hook `delete-terminal-functions' is called before
+**** The special hook 'delete-terminal-functions' is called before
 deleting a terminal.
 
 *** New functions:
 
-**** `delete-terminal'
+**** 'delete-terminal'
 
-**** `suspend-tty'
+**** 'suspend-tty'
 
-**** `resume-tty'.
+**** 'resume-tty'.
 
-*** `initial-environment' holds the environment inherited from Emacs's parent.
+*** 'initial-environment' holds the environment inherited from Emacs's parent.
 
 ** Redisplay changes
 
 *** For underlined characters, the distance between the underline and
-the baseline is controlled by a new variable, `underline-minimum-offset'.
+the baseline is controlled by a new variable, 'underline-minimum-offset'.
 
-*** You can now pass the value of the `invisible' property to
+*** You can now pass the value of the 'invisible' property to
 invisible-p to check whether it would cause the text to be invisible.
 This is convenient when checking invisibility of text with no buffer
 position (e.g. in before/after-strings).
 
-*** `clear-image-cache' can be told to flush only images of a specific file.
+*** 'clear-image-cache' can be told to flush only images of a specific file.
 
-*** `vertical-motion' can now be given a goal column.
+*** 'vertical-motion' can now be given a goal column.
 It now accepts a cons cell (COLS . LINES) in its first argument, which
 says to stop, where possible, at a pixel x-position equal to COLS
 times the default column width.
 
 *** redisplay-end-trigger-functions, set-window-redisplay-end-trigger,
-and window-redisplay-end-trigger are obsolete.  Use `jit-lock-register'
+and window-redisplay-end-trigger are obsolete.  Use 'jit-lock-register'
 instead.
 
-*** The new variables `wrap-prefix' and `line-prefix' specify display
+*** The new variables 'wrap-prefix' and 'line-prefix' specify display
 specs which are appended at display-time to every continuation line
 and non-continuation line, respectively.  In addition, Emacs
-recognizes the `wrap-prefix' and `line-prefix' text or overlay
+recognizes the 'wrap-prefix' and 'line-prefix' text or overlay
 properties; these have the same effects as the variables of the same
 name, but take precedence.
 
@@ -2458,68 +2458,68 @@ name, but take precedence.
 
 ** Miscellaneous new functions
 
-*** `apply-partially' performs a "curried" application of a function.
+*** 'apply-partially' performs a "curried" application of a function.
 
-*** `buffer-swap-text' swaps text between two buffers.  This can be
-useful for modes such as tar-mode, archive-mode, RMAIL.
+*** 'buffer-swap-text' swaps text between two buffers.  This can be
+useful for modes such as 'tar-mode', 'archive-mode', RMAIL.
 
-*** `combine-and-quote-strings' produces a single string from a list of strings
+*** 'combine-and-quote-strings' produces a single string from a list of strings
 sticking a separator string in between each pair, and quoting those
 strings that include the separator as their substring.  Useful for
 consing shell command lines from the individual arguments.
 
-*** `custom-note-var-changed' tells Custom to treat the change in a
+*** 'custom-note-var-changed' tells Custom to treat the change in a
 certain variable as having been made within Custom.
 
-*** `face-all-attributes' returns an alist describing all the basic
+*** 'face-all-attributes' returns an alist describing all the basic
 attributes of a given face.
 
-*** `format-seconds' converts a number of seconds into a readable
+*** 'format-seconds' converts a number of seconds into a readable
 string of days, hours, etc.
 
-*** `image-refresh' refreshes all images associated with a given image
+*** 'image-refresh' refreshes all images associated with a given image
 specification.
 
-*** `locate-user-emacs-file' helps packages to select the appropriate
-place to save user-specific files.  It defaults to `user-emacs-directory'
+*** 'locate-user-emacs-file' helps packages to select the appropriate
+place to save user-specific files.  It defaults to 'user-emacs-directory'
 unless the file already exists at $HOME.
 
-*** `read-color' reads a color name using the minibuffer.
+*** 'read-color' reads a color name using the minibuffer.
 
-*** `read-shell-command' does what its name says, with completion.  It
-uses the minibuffer-local-shell-command-map for that.
+*** 'read-shell-command' does what its name says, with completion.  It
+uses the 'minibuffer-local-shell-command-map' for that.
 
-*** `split-string-and-unquote' splits a string into a list of substrings
+*** 'split-string-and-unquote' splits a string into a list of substrings
 on the boundaries of a given delimiter, and unquotes the substrings that
 are quoted.  Useful for taking apart shell commands.
 
-*** The two new functions `looking-at-p' and `string-match-p' can do
-the same matching as `looking-at' and `string-match' without changing
+*** The two new functions 'looking-at-p' and 'string-match-p' can do
+the same matching as 'looking-at' and 'string-match' without changing
 the match data.
 
-*** The two new functions `make-serial-process' and
-`serial-process-configure' provide a Lisp interface to the new serial
+*** The two new functions 'make-serial-process' and
+'serial-process-configure' provide a Lisp interface to the new serial
 port support (see Emacs changes, above).
 
 ** Miscellaneous new variables
 
-*** `auto-save-include-big-deletions', if non-nil, means auto-save is
+*** 'auto-save-include-big-deletions', if non-nil, means auto-save is
 not turned off automatically after a big deletion.
 
-*** `read-circle', if nil, disables the reading of recursive Lisp
+*** 'read-circle', if nil, disables the reading of recursive Lisp
 structures using the #N= and #N# syntax.
 
-*** `this-command-keys-shift-translated' is non-nil if the key
+*** 'this-command-keys-shift-translated' is non-nil if the key
 sequence invoking the current command was found by shift-translation.
 
-*** `window-point-insertion-type' determines the insertion-type of the
+*** 'window-point-insertion-type' determines the insertion-type of the
 marker used for window-point.
 
-*** bookmark provides `bookmark-make-record-function' so special major
+*** bookmark provides 'bookmark-make-record-function' so special major
 modes like Info can teach bookmark.el how to save and restore the
 relevant data.
 
-*** `fill-forward-paragraph-function' specifies which function the
+*** 'fill-forward-paragraph-function' specifies which function the
 filling code should use to find paragraph boundaries.
 
 
@@ -2527,20 +2527,20 @@ filling code should use to find paragraph boundaries.
 
 ** The new package avl-tree.el deals with the AVL tree data structure.
 
-** The new package check-declare.el verifies the accuracy of
+** The new package 'check-declare' verifies the accuracy of
 declare-function macros (see Lisp Changes, above).
 
-** find-cmd.el can build `find' commands using lisp syntax.
+** 'find-cmd' can build 'find' commands using lisp syntax.
 
 ** The package misearch.el has been added.  It allows Isearch to search
-through multiple buffers.  A variable `multi-isearch-next-buffer-function'
+through multiple buffers.  A variable 'multi-isearch-next-buffer-function'
 defines the function to call to get the next buffer to search in the series
-of multiple buffers.  Top-level functions `multi-isearch-buffers',
-`multi-isearch-buffers-regexp', `multi-isearch-files' and
-`multi-isearch-files-regexp' accept a single argument that specifies
+of multiple buffers.  Top-level functions 'multi-isearch-buffers',
+'multi-isearch-buffers-regexp', 'multi-isearch-files' and
+'multi-isearch-files-regexp' accept a single argument that specifies
 a list of buffers/files to search for a string/regexp.
 
-** The new major mode `special-mode' is intended as a parent for
+** The new major mode 'special-mode' is intended as a parent for
 major modes such as those that set the "'mode-class 'special" property.
 
 
diff --git a/etc/NEWS.24 b/etc/NEWS.24
index 0fd4037ed0..8ef479ac0a 100644
--- a/etc/NEWS.24
+++ b/etc/NEWS.24
@@ -11,7 +11,7 @@ This file is about changes in Emacs version 24.
 See files NEWS.23, NEWS.22, NEWS.21, NEWS.20, NEWS.19, NEWS.18,
 and NEWS.1-17 for changes in older Emacs versions.
 
-You can narrow news to a specific version by calling `view-emacs-news'
+You can narrow news to a specific version by calling 'view-emacs-news'
 with a prefix argument or by typing C-u C-h C-n.
 
 
@@ -19,29 +19,29 @@ with a prefix argument or by typing C-u C-h C-n.
 
 ** This is mainly a bug-fix release, but there are some other changes.
 
-** The default value of `history-length' has increased to 100.
+** The default value of 'history-length' has increased to 100.
 
-** The variable `redisplay-dont-pause' is obsolete.
+** The variable 'redisplay-dont-pause' is obsolete.
 
 
 * Changes in Specialized Modes and Packages in Emacs 24.5
 
-** `call-process-shell-command' and `process-file-shell-command' no longer
+** 'call-process-shell-command' and 'process-file-shell-command' no longer
 take "&rest args".
 
-** The option `browse-url-firefox-startup-arguments' no longer has an effect.
+** The option 'browse-url-firefox-startup-arguments' no longer has an effect.
 
 ** ERC
 
-*** New option `erc-rename-buffers'.
+*** New option 'erc-rename-buffers'.
 
-*** New faces `erc-my-nick-prefix-face' and `erc-nick-prefix-face'.
+*** New faces 'erc-my-nick-prefix-face' and 'erc-nick-prefix-face'.
 
-*** `erc-format-@nick' displays all user modes instead of only op and voice.
+*** 'erc-format-@nick' displays all user modes instead of only op and voice.
 
 *** The display of irc commands in the current buffer has been disabled.
 
-*** `erc-version' now follows the Emacs version.
+*** 'erc-version' now follows the Emacs version.
 
 ** Obsolete packages
 
@@ -61,27 +61,27 @@ These emulations of old editors are believed to be no 
longer relevant
 ** Emacs can now be compiled with ACL (access control list) support.
 This happens by default if a suitable support library is found at
 build time, like libacl on GNU/Linux.  To prevent this, use the
-configure option `--disable-acl'.  See below for the features this provides.
+configure option '--disable-acl'.  See below for the features this provides.
 
 ** Emacs can now be compiled with file notification support.
 This happens by default if a suitable system library is found at
 build time.  To prevent this, use the configure option
-`--without-file-notification'.  See below for file-notify features.
+'--without-file-notification'.  See below for file-notify features.
 This feature is not available for the Nextstep port.
 
 ** Emacs can now be compiled with zlib support.
 This happens by default if zlib is present, which it normally is.
-To prevent this, use the configure option `--without-zlib'.
-This provides the function `zlib-decompress-region'; see below for details.
+To prevent this, use the configure option '--without-zlib'.
+This provides the function 'zlib-decompress-region'; see below for details.
 
-** The configure option `--without-compress-info' has been generalized,
-and renamed to `--without-compress-install'.  It now prevents compression
+** The configure option '--without-compress-info' has been generalized,
+and renamed to '--without-compress-install'.  It now prevents compression
 of _any_ files during installation.
 
-** The configure option `--with-crt-dir' has been removed.
+** The configure option '--with-crt-dir' has been removed.
 It is no longer needed, as the crt*.o files are no longer linked specially.
 
-** Directories passed to configure option `--enable-locallisppath' are
+** Directories passed to configure option '--enable-locallisppath' are
 no longer created during installation.
 
 ** Emacs for Nextstep (OS X, GNUstep) can be built with ImageMagick support.
@@ -90,7 +90,7 @@ This requires pkg-config to be available at build time.
 
 * Startup Changes in Emacs 24.4
 
-** When initializing `load-path', an empty element in the EMACSLOADPATH
+** When initializing 'load-path', an empty element in the EMACSLOADPATH
 environment variable (either leading, e.g., ":/foo"; trailing, e.g.,
 "/foo:"; or embedded, e.g., "/foo::/bar") is replaced with the default
 load-path (the one that would have been used if EMACSLOADPATH was unset).
@@ -100,15 +100,15 @@ including the defaults).  (In older versions of Emacs, an 
empty element
 was replaced by ".", so use an explicit "." now if that is what you want.)
 
 ** The -L option, which normally prepends its argument to load-path,
-will instead append, if the argument begins with `:' (or `;' on MS Windows;
-i.e., `path-separator').
+will instead append, if the argument begins with ':' (or ';' on MS Windows;
+i.e., 'path-separator').
 
 ** If you use either site-load.el or site-init.el to customize the dumped
-Emacs executable, any changes to `load-path' that these files make
+Emacs executable, any changes to 'load-path' that these files make
 will no longer be present after dumping.  To affect a permanent change
-to `load-path', use the `--enable-locallisppath' option of `configure'.
+to 'load-path', use the '--enable-locallisppath' option of 'configure'.
 
-** The user option `initial-buffer-choice' can now specify a function
+** The user option 'initial-buffer-choice' can now specify a function
 to set up the initial buffer.
 
 
@@ -122,7 +122,7 @@ ACLs are extended file attributes, used e.g. for 
finer-grained permissions.
 
 *** Emacs preserves the ACL entries of files when backing up.
 
-*** New functions `file-acl' and `set-file-acl' get and set file ACLs.
+*** New functions 'file-acl' and 'set-file-acl' get and set file ACLs.
 
 ** Support for menus on text-mode terminals.
 If the terminal supports a mouse, clicking on the menu bar, or on
@@ -131,14 +131,14 @@ menu defined at that position.  Likewise, clicking 
C-mouse-1, C-mouse-2, or
 C-mouse-3 on the text area will pop up the menus defined for those locations.
 
 If the text terminal does not support a mouse, you can activate the
-first menu-bar menu by typing F10, which invokes `menu-bar-open'.
+first menu-bar menu by typing F10, which invokes 'menu-bar-open'.
 
-If you want the previous behavior, where F10 invoked `tmm-menubar',
-customize the option `tty-menu-open-use-tmm' to a non-nil value.
-(Typing M-` always invokes `tmm-menubar', even if `tty-menu-open-use-tmm'
+If you want the previous behavior, where F10 invoked 'tmm-menubar',
+customize the option 'tty-menu-open-use-tmm' to a non-nil value.
+(Typing M-` always invokes 'tmm-menubar', even if 'tty-menu-open-use-tmm'
 is nil.)
 
-** New option `load-prefer-newer' affects how the `load' function chooses
+** New option 'load-prefer-newer' affects how the 'load' function chooses
 the file to load.  If this is non-nil, then when both .el and .elc
 versions of a file exist, and the caller did not explicitly specify
 which one to load, then the newer file is loaded.  The default, nil,
@@ -146,64 +146,64 @@ means to always load the .elc file.
 
 ** Multi-monitor support
 
-*** New functions `display-monitor-attributes-list' and
-`frame-monitor-attributes' can be used to obtain information about
+*** New functions 'display-monitor-attributes-list' and
+'frame-monitor-attributes' can be used to obtain information about
 each physical monitor on multi-monitor setups.
 
-*** The functions `display-pixel-width' and `display-pixel-height' now
+*** The functions 'display-pixel-width' and 'display-pixel-height' now
 behave consistently among the platforms: they return the pixel width
 or height for all physical monitors associated with the given display
 as if they were on X.  To get information for each physical
 monitor, use the new functions above.  Similar notes also apply to
-`x-display-pixel-width', `x-display-pixel-height', `display-mm-width',
-`display-mm-height', `x-display-mm-width', and `x-display-mm-height'.
+'x-display-pixel-width', 'x-display-pixel-height', 'display-mm-width',
+'display-mm-height', 'x-display-mm-width', and 'x-display-mm-height'.
 
-** New function `zlib-decompress-region', which decompresses gzip- and
+** New function 'zlib-decompress-region', which decompresses gzip- and
 zlib-format compressed data using built-in zlib support (if available).
 
-** The *Messages* buffer is created in `messages-buffer-mode',
+** The *Messages* buffer is created in 'messages-buffer-mode',
 a new major mode, with read-only status.  Any code that might create
-the *Messages* buffer should call the function `messages-buffer' to do
+the *Messages* buffer should call the function 'messages-buffer' to do
 so and set up the mode.
 
 ** The cursor stops blinking after 10 blinks (by default) on X and Nextstep.
-You can change the default by customizing `blink-cursor-blinks'.
+You can change the default by customizing 'blink-cursor-blinks'.
 
 ** In keymaps where SPC scrolls forward, S-SPC now scrolls backward.
 This affects View mode, etc.
 
-** The default value of `make-backup-file-name-function' is no longer nil.
+** The default value of 'make-backup-file-name-function' is no longer nil.
 Instead it defaults to a function that does what the nil value used to.
 
 ** Help
 
-*** The command `apropos-variable' is renamed to `apropos-user-option'.
-`apropos-user-option' shows all user options, while `apropos-variable'
+*** The command 'apropos-variable' is renamed to 'apropos-user-option'.
+'apropos-user-option' shows all user options, while 'apropos-variable'
 shows all variables.  When called with a universal prefix argument,
-the two commands swap their behaviors.  When `apropos-do-all' is
+the two commands swap their behaviors.  When 'apropos-do-all' is
 non-nil, they output the same results.
 
-*** The key `?' now describes prefix bindings, like `C-h'.
+*** The key '?' now describes prefix bindings, like 'C-h'.
 
-*** The command `describe-function' has been extended for EIEIO.
+*** The command 'describe-function' has been extended for EIEIO.
 Running it on constructors will show a full description of the
 generated class.  For generic functions, it will show all
 implementations together with links to the source.  The old commands
-`describe-class', `describe-constructor' and `describe-generic' were
+'describe-class', 'describe-constructor' and 'describe-generic' were
 removed.
 
-*** The function `quail-help' is no longer an interactive command.
-Use `C-h C-\' (`describe-input-method') instead.
+*** The function 'quail-help' is no longer an interactive command.
+Use 'C-h C-\' ('describe-input-method') instead.
 
 ** Frame and window handling
 
-*** New commands `toggle-frame-fullscreen' and `toggle-frame-maximized',
+*** New commands 'toggle-frame-fullscreen' and 'toggle-frame-maximized',
 bound to <f11> and M-<f10>, respectively.
 
-*** New hooks `focus-in-hook', `focus-out-hook'.
+*** New hooks 'focus-in-hook', 'focus-out-hook'.
 These are normal hooks run when an Emacs frame gains or loses input focus.
 
-*** The function `window-in-direction' now takes additional arguments
+*** The function 'window-in-direction' now takes additional arguments
 for specifying a reference point, wrapping the selection around frame
 borders, and specifying ways to select the minibuffer window.
 
@@ -211,116 +211,116 @@ borders, and specifying ways to select the minibuffer 
window.
 text rows or columns.  When maximizing a frame or making it fullscreen,
 remaining extra pixels are no longer given to the minibuffer, the rightmost
 fringe, or other unusable space, but are distributed among the text
-areas of the frame's windows.  If the new option `frame-resize-pixelwise'
+areas of the frame's windows.  If the new option 'frame-resize-pixelwise'
 is non-nil, all frame size changes happen pixelwise and set the
 corresponding size hints for the window manager.
 
 *** Emacs can now change window sizes in units of pixels.
 Mouse-dragging a mode line or window divider now changes the size of
-adjacent windows pixelwise.  If the new option `window-resize-pixelwise'
-is non-nil, functions like `balance-windows-area' and `fit-window-to-buffer'
+adjacent windows pixelwise.  If the new option 'window-resize-pixelwise'
+is non-nil, functions like 'balance-windows-area' and 'fit-window-to-buffer'
 resize windows pixelwise.  Most functions for changing or accessing
 window sizes now have an additional argument that allows changes to apply,
 or values to be returned, in pixels instead of lines/columns.
 
-*** The functions `window-body-height' and `window-body-width' now never
+*** The functions 'window-body-height' and 'window-body-width' now never
 count partially visible lines or columns if called with a nil PIXELWISE
 argument.
 
 *** Emacs can now draw dividers between adjacent windows.  To put
 dividers between side-by-side/vertically stacked windows customize the
-frame parameters `right-divider-width' and `bottom-divider-width' to
+frame parameters 'right-divider-width' and 'bottom-divider-width' to
 some positive integer.  You can drag dividers with the mouse (they show
 a corresponding cursor when the mouse hovers over them).  You can change
-the appearance of dividers by customizing the faces `window-divider',
-`window-divider-first-pixel', and `window-divider-last-pixel'.  The last
+the appearance of dividers by customizing the faces 'window-divider',
+'window-divider-first-pixel', and 'window-divider-last-pixel'.  The last
 two are useful to provide a 3D effect, or to better distinguish dividers
 from surrounding display objects.
 
 *** New functions to return the pixel sizes of window components, namely
-`window-scroll-bar-width', `window-mode-line-height',
-`window-header-line-height', `window-right-divider-width', and
-`window-bottom-divider-width'.
+'window-scroll-bar-width', 'window-mode-line-height',
+'window-header-line-height', 'window-right-divider-width', and
+'window-bottom-divider-width'.
 
-*** The new function `window-text-pixel-size' returns the size of the
+*** The new function 'window-text-pixel-size' returns the size of the
 text of a window's buffer in pixels.  This allows functions like
-`fit-frame-to-buffer' and `fit-window-to-buffer' to accurately fit a
+'fit-frame-to-buffer' and 'fit-window-to-buffer' to accurately fit a
 window to its buffer as it will be displayed.
 
-*** `fit-window-to-buffer' can now resize windows in both dimensions.
+*** 'fit-window-to-buffer' can now resize windows in both dimensions.
 This behavior is controlled by the new option
-`fit-window-to-buffer-horizontally'.  The new option
-`fit-frame-to-buffer' allows you to fit the window's frame to its buffer.
+'fit-window-to-buffer-horizontally'.  The new option
+'fit-frame-to-buffer' allows you to fit the window's frame to its buffer.
 
-*** `fit-frame-to-buffer' now fits frames in both dimensions.  The new
-options `fit-frame-to-buffer-margins' and `fit-frame-to-buffer-sizes'
+*** 'fit-frame-to-buffer' now fits frames in both dimensions.  The new
+options 'fit-frame-to-buffer-margins' and 'fit-frame-to-buffer-sizes'
 control the size of the frame and its position on screen.
 
 *** Temp Buffer Resize Mode can now adjust the height and width of
-windows and frames.  The new option `temp-buffer-max-width' allows you to
+windows and frames.  The new option 'temp-buffer-max-width' allows you to
 control the width of temporary buffer windows.  Moreover, if the new
-option `fit-frame-to-buffer' is non-nil and the buffer appears in the
+option 'fit-frame-to-buffer' is non-nil and the buffer appears in the
 root window of a frame, Temp Buffer Resize Mode will try to adjust the
 width and/or height of the frame.
 
-*** `split-window' is now a non-interactive function, not a command.
-As a command, it was a special case of `C-x 2' (`split-window-below'),
+*** 'split-window' is now a non-interactive function, not a command.
+As a command, it was a special case of 'C-x 2' ('split-window-below'),
 and as such superfluous.  After being reimplemented in Lisp, its
 interactive form was mistakenly retained.
 
-*** The functions `window-size' and `window-total-size' now have an
+*** The functions 'window-size' and 'window-total-size' now have an
 optional argument to return a rounded size value.
 
-*** `window-state-put' now allows you to put a window state into internal
+*** 'window-state-put' now allows you to put a window state into internal
 windows too.
 
-*** New option `scroll-bar-adjust-thumb-portion'.
+*** New option 'scroll-bar-adjust-thumb-portion'.
 Available only on X, this option allows you to control over-scrolling
 using the scroll bar (i.e., dragging the thumb down even when the end
 of the buffer is visible).
 
-*** New display actions functions for `display-buffer':
+*** New display actions functions for 'display-buffer':
 
-**** `display-buffer-at-bottom' chooses or creates a window at the
+**** 'display-buffer-at-bottom' chooses or creates a window at the
 bottom of the selected frame.
 
-**** `display-buffer-no-window' to not display the buffer in a window.
+**** 'display-buffer-no-window' to not display the buffer in a window.
 
-*** New display action alist entry `allow-no-window' to indicate the
-caller of `display-buffer' is ready to handle the case of not displaying
+*** New display action alist entry 'allow-no-window' to indicate the
+caller of 'display-buffer' is ready to handle the case of not displaying
 the buffer in a window.
 
-*** `display-buffer-in-previous-window' is now a member of
-`display-buffer-fallback-action'.
+*** 'display-buffer-in-previous-window' is now a member of
+'display-buffer-fallback-action'.
 
 ** Lisp evaluation
 
-*** `eval-defun' on an already defined defcustom calls the :set function,
+*** 'eval-defun' on an already defined defcustom calls the :set function,
 if there is one.
 
-*** The commands `eval-expression' (`M-:'), `eval-last-sexp' (`C-x C-e'),
-and `eval-print-last-sexp' (`C-j' in Lisp Interaction mode) can take a
+*** The commands 'eval-expression' ('M-:'), 'eval-last-sexp' ('C-x C-e'),
+and 'eval-print-last-sexp' ('C-j' in Lisp Interaction mode) can take a
 zero prefix argument.  This disables truncation of lists in the output,
-equivalent to setting `(eval-expression-)print-length' and
-`(eval-expression-)print-level' to nil.  Additionally, it causes integers
+equivalent to setting '(eval-expression-)print-length' and
+'(eval-expression-)print-level' to nil.  Additionally, it causes integers
 to be printed in other formats (octal, hexadecimal, and character).
 
-*** New hook `eval-expression-minibuffer-setup-hook' run by
-`eval-expression' on entering the minibuffer.
+*** New hook 'eval-expression-minibuffer-setup-hook' run by
+'eval-expression' on entering the minibuffer.
 
-** `cache-long-line-scans' is now non-nil, and renamed to `cache-long-scans',
+** 'cache-long-line-scans' is now non-nil, and renamed to 'cache-long-scans',
 because it affects caching of paragraph scanning results as well.
 There is no reason to set this to nil except for debugging purposes.
 
-** `emacs-bzr-version' has been renamed to `emacs-repository-version',
+** 'emacs-bzr-version' has been renamed to 'emacs-repository-version',
 and works for git too, if you fetch the repository notes.
 
-** The default value of `comment-use-global-state' is now t,
+** The default value of 'comment-use-global-state' is now t,
 and this variable has been marked obsolete.
 
-** `write-region-inhibit-fsync' now defaults to t in batch mode.
+** 'write-region-inhibit-fsync' now defaults to t in batch mode.
 
-** The option `set-mark-default-inactive' has been deleted.
+** The option 'set-mark-default-inactive' has been deleted.
 This unfinished feature was introduced by accident in Emacs 23.1;
 simply disabling Transient Mark mode does the same thing.
 
@@ -329,69 +329,69 @@ simply disabling Transient Mark mode does the same thing.
 
 ** Indentation
 
-*** `electric-indent-mode' is now enabled by default.
+*** 'electric-indent-mode' is now enabled by default.
 Typing RET reindents the current line and indents the new line.
-`C-j' inserts a newline but does not indent.  In some programming modes,
-additional characters are electric (eg `{').
+'C-j' inserts a newline but does not indent.  In some programming modes,
+additional characters are electric (eg '{').
 
-*** New buffer-local `electric-indent-local-mode'.
+*** New buffer-local 'electric-indent-local-mode'.
 
-*** The behavior of `C-x TAB' (`indent-rigidly') has changed.
+*** The behavior of 'C-x TAB' ('indent-rigidly') has changed.
 When invoked without a prefix argument, it now activates a transient
 mode in which typing <left>, <right>, <S-left>, and <S-right> adjusts
 the text indentation in the region.  Typing any other key resumes
 normal editing behavior.
 
-*** `tab-stop-list' is now implicitly extended to infinity by repeating
+*** 'tab-stop-list' is now implicitly extended to infinity by repeating
 the last step.  Its default value is changed to nil, which means a tab
-stop every `tab-width' columns.
+stop every 'tab-width' columns.
 
-** Uniquify is enabled by default, with `post-forward-angle-brackets' style.
+** Uniquify is enabled by default, with 'post-forward-angle-brackets' style.
 In other words, if you visit two files that have the same base name,
 then rather than creating buffers basename and basename<2>,
 Emacs uses basename<dirA> and basename<dirB>.  To change this,
-customize `uniquify-buffer-name-style'.  Set it to nil for the old behavior.
+customize 'uniquify-buffer-name-style'.  Set it to nil for the old behavior.
 
-** New command `C-x SPC' (`rectangle-mark-mode') makes a rectangular region.
+** New command 'C-x SPC' ('rectangle-mark-mode') makes a rectangular region.
 Most commands are still unaware of it, but kill/yank do work on the rectangle.
 
-** New option `visual-order-cursor-movement'.
+** New option 'visual-order-cursor-movement'.
 If this is non-nil, cursor motion with arrow keys will follow the
 visual order of characters on the screen: <left> always moves to the
 left, <right> always moves to the right, disregarding the surrounding
 bidirectional context.
 
-** New command `delete-duplicate-lines'.
+** New command 'delete-duplicate-lines'.
 This searches the region for identical lines, and removes all but one
 copy of each repeated line.  The lines need not be sorted.
 
-** New command `cycle-spacing' acts like a smarter `just-one-space'.
+** New command 'cycle-spacing' acts like a smarter 'just-one-space'.
 When called in succession, it cycles between spacing conventions:
 one space, no spaces, original spacing.
 
-** `blink-matching-paren' now only highlights the matching open-paren
-by default, instead of moving the cursor.  Set this variable to `jump' to
+** 'blink-matching-paren' now only highlights the matching open-paren
+by default, instead of moving the cursor.  Set this variable to 'jump' to
 restore the old behavior.
 
-** The new function `fill-single-char-nobreak-p' can stop fill from breaking
+** The new function 'fill-single-char-nobreak-p' can stop fill from breaking
 a line after a one-letter word, which is an error in some typographical
-conventions.  To use it, add it to the `fill-nobreak-predicate' hook.
+conventions.  To use it, add it to the 'fill-nobreak-predicate' hook.
 
 ** Registers
 
-*** All interactive commands that read a register (`copy-to-register', etc.)
-now display a temporary window after `register-preview-delay' seconds
+*** All interactive commands that read a register ('copy-to-register', etc.)
+now display a temporary window after 'register-preview-delay' seconds
 that summarizes existing registers.  To disable this, set that option to nil.
 Interactive commands that read registers and want to make use of this
-should use `register-read-with-preview' to read register names.
+should use 'register-read-with-preview' to read register names.
 
-*** New command `frameset-to-register' bound to `C-x r f', replacing
-`frame-configuration-to-register'.  It offers similar functionality,
+*** New command 'frameset-to-register' bound to 'C-x r f', replacing
+'frame-configuration-to-register'.  It offers similar functionality,
 plus enhancements like the ability to restore deleted frames.
-(`frame-configuration-to-register' still exists, but no longer has a
+('frame-configuration-to-register' still exists, but no longer has a
 key binding.)
 
-*** New command `C-x C-k x' (`kmacro-to-register') stores keyboard
+*** New command 'C-x C-k x' ('kmacro-to-register') stores keyboard
 macros in registers.
 
 
@@ -399,18 +399,18 @@ macros in registers.
 
 ** Backtrace and debugger
 
-*** New Lisp debugger command `v' (`debugger-toggle-locals') toggles the
+*** New Lisp debugger command 'v' ('debugger-toggle-locals') toggles the
 display of local variables of the current stack frame.
 
-*** The Lisp debugger's `e' command (`debugger-eval-expression') now includes
+*** The Lisp debugger's 'e' command ('debugger-eval-expression') now includes
 the lexical environment when evaluating the code in the context at point
 (and so allows you to access lexical variables).
 
-*** New minor mode `jit-lock-debug-mode' helps you debug code run via JIT Lock.
+*** New minor mode 'jit-lock-debug-mode' helps you debug code run via JIT Lock.
 
-** Battery information can now be retrieved from BSD's `apm' utility.
+** Battery information can now be retrieved from BSD's 'apm' utility.
 
-** In the Buffer Menu, `M-s a C-o' shows matches for a regexp in marked 
buffers.
+** In the Buffer Menu, 'M-s a C-o' shows matches for a regexp in marked 
buffers.
 
 ** Calc
 
@@ -420,22 +420,22 @@ Julian calendar for dates before September 14, 1752, and 
it used
 December 31, 1 BC as its day number 1; the new scheme is more
 consistent with Calendar's calendrical system and day numbering.
 
-*** The new option `calc-gregorian-switch' lets you configure if
+*** The new option 'calc-gregorian-switch' lets you configure if
 (and when) Calc switches from the Julian to the Gregorian calendar.
 
 *** Support for ISO 8601 dates.
 
 ** Calendar and Diary
 
-*** New faces `calendar-weekday-header', `calendar-weekend-header',
-and `calendar-month-header'.
+*** New faces 'calendar-weekday-header', 'calendar-weekend-header',
+and 'calendar-month-header'.
 
-*** New option `calendar-day-header-array'.
+*** New option 'calendar-day-header-array'.
 
-*** New variable `diary-from-outlook-function', used by the command
-`diary-from-outlook'.
+*** New variable 'diary-from-outlook-function', used by the command
+'diary-from-outlook'.
 
-*** The variable `calendar-font-lock-keywords' is obsolete.
+*** The variable 'calendar-font-lock-keywords' is obsolete.
 
 ** CEDET
 
@@ -443,7 +443,7 @@ and `calendar-month-header'.
 
 **** The cpp-root project now supports executing a compile command.
 It can be set through the new :compile-command slot or the
-buffer-local variable `compile-command'.
+buffer-local variable 'compile-command'.
 
 **** Better selection of include directories for the 'linux' project.
 Include directories now support out-of-tree build directories and
@@ -470,184 +470,184 @@ For example, this enables parsing of macros that open 
new namespaces.
 
 *** The current CFEngine syntax is parsed from "cf-promises -s json".
 There is a fallback syntax available if you don't have cf-promises or
-if your version doesn't support that option.  See option 
`cfengine-cf-promises'.
+if your version doesn't support that option.  See option 
'cfengine-cf-promises'.
 
 ** cl-lib
 
-*** New macro `cl-tagbody'.
+*** New macro 'cl-tagbody'.
 This executes statements while allowing for control transfer to labels.
 
 *** letf is now just an alias for cl-letf.
 
 ** CUA mode
 
-*** CUA mode now uses `delete-selection-mode' and `shift-select-mode'.
+*** CUA mode now uses 'delete-selection-mode' and 'shift-select-mode'.
 Hence, you can now enable it independently from those modes, and from
-`transient-mark-mode'.
+'transient-mark-mode'.
 
-*** `cua-highlight-region-shift-only' is now obsolete.
-You can disable `transient-mark-mode' to get the same result.
+*** 'cua-highlight-region-shift-only' is now obsolete.
+You can disable 'transient-mark-mode' to get the same result.
 
 *** CUA's rectangles can now be used without CUA by calling the command
-`cua-rectangle-mark-mode'.
+'cua-rectangle-mark-mode'.
 
 ** Delete Selection mode can now be used without Transient Mark mode.
 
 ** Desktop
 
-*** `desktop-save-mode' by default now auto-saves an existing desktop file
-after `desktop-auto-save-timeout'.  To disable this, customize that option
+*** 'desktop-save-mode' by default now auto-saves an existing desktop file
+after 'desktop-auto-save-timeout'.  To disable this, customize that option
 to nil (or zero).
 
 *** Desktop now saves and restores the frame/window configuration.
-To disable this, set `desktop-restore-frames' to nil.
-See also related options `desktop-restore-reuses-frames',
-`desktop-restore-in-current-display', and `desktop-restore-forces-onscreen'.
+To disable this, set 'desktop-restore-frames' to nil.
+See also related options 'desktop-restore-reuses-frames',
+'desktop-restore-in-current-display', and 'desktop-restore-forces-onscreen'.
 
-** New Dired minor mode `dired-hide-details-mode' toggles whether details,
+** New Dired minor mode 'dired-hide-details-mode' toggles whether details,
 such as file ownership or permissions, are visible in Dired buffers.
-See the new options `dired-hide-details-hide-symlink-targets' and
-`dired-hide-details-hide-information-lines' for customizing what to hide.
+See the new options 'dired-hide-details-hide-symlink-targets' and
+'dired-hide-details-hide-information-lines' for customizing what to hide.
 
-** You can enable ElDoc inside the `eval-expression' minibuffer with:
-  (add-hook 'eval-expression-minibuffer-setup-hook 'eldoc-mode)
+** You can enable ElDoc inside the 'eval-expression' minibuffer with:
+  (add-hook 'eval-expression-minibuffer-setup-hook #'eldoc-mode)
 The results display in the mode line.
 
 ** Electric Pair mode
 
-*** New option `electric-pair-preserve-balance', enabled by default.
+*** New option 'electric-pair-preserve-balance', enabled by default.
 If non-nil, pairing/skipping only kicks in when that help the balance
 of parentheses and quotes; i.e., the buffer should end up at least as
 balanced as before.
 
 You can further control this behavior by adjusting the predicates
-stored in `electric-pair-inhibit-predicate' and `electric-pair-skip-self'.
+stored in 'electric-pair-inhibit-predicate' and 'electric-pair-skip-self'.
 
-*** New option `electric-pair-delete-adjacent-pairs', enabled by default.
-In `electric-pair-mode', the commands `backward-delete-char' and
-`backward-delete-char-untabify' are now bound to electric variants
+*** New option 'electric-pair-delete-adjacent-pairs', enabled by default.
+In 'electric-pair-mode', the commands 'backward-delete-char' and
+'backward-delete-char-untabify' are now bound to electric variants
 that delete the closer when invoked between adjacent pairs.
 
-*** New option `electric-pair-open-newline-between-pairs', enabled by default.
-In `electric-pair-mode', inserting a newline between adjacent pairs
+*** New option 'electric-pair-open-newline-between-pairs', enabled by default.
+In 'electric-pair-mode', inserting a newline between adjacent pairs
 opens an extra newline after point, which is indented if
-`electric-indent-mode' is also set.
+'electric-indent-mode' is also set.
 
-*** New option `electric-pair-skip-whitespace', enabled by default.
+*** New option 'electric-pair-skip-whitespace', enabled by default.
 This controls if skipping over closing delimiters should jump over any
-whitespace slack.  Setting it to `chomp' makes it delete this
-whitespace.  See also the variable `electric-pair-skip-whitespace-chars'.
+whitespace slack.  Setting it to 'chomp' makes it delete this
+whitespace.  See also the variable 'electric-pair-skip-whitespace-chars'.
 
 *** New variables control the pairing in strings and comments.
-You can customize `electric-pair-text-pairs' and
-`electric-pair-text-syntax-table' to tweak pairing behavior inside
+You can customize 'electric-pair-text-pairs' and
+'electric-pair-text-syntax-table' to tweak pairing behavior inside
 strings and comments.
 
-** New EPA option `epa-mail-aliases'.
-You can set this to a list of email address aliases that `epa-mail-encrypt'
+** New EPA option 'epa-mail-aliases'.
+You can set this to a list of email address aliases that 'epa-mail-encrypt'
 should use to find keys.
 
-** New ERC option `erc-accidental-paste-threshold-seconds'.
+** New ERC option 'erc-accidental-paste-threshold-seconds'.
 If set to a number, this can be used to avoid accidentally pasting large
 amounts of data into the ERC input.
 
-** New ERT macro `skip-unless' allows skipping ERT tests.
+** New ERT macro 'skip-unless' allows skipping ERT tests.
 
 ** Eshell
 
-*** `eshell' now supports visual subcommands and options.
+*** 'eshell' now supports visual subcommands and options.
 Eshell has been able to handle "visual" commands (interactive,
 non-line oriented commands such as top that require display
 capabilities not provided by eshell) by running them in an Emacs
-terminal emulator.  See `eshell-visual-commands'.
+terminal emulator.  See 'eshell-visual-commands'.
 
 This feature has been extended to subcommands and options that make a
 usually line-oriented command a visual command.  Typical examples are
 "git log" and "git <command> --help", which display their output in a
-pager by default.  See `eshell-visual-subcommands' and `eshell-visual-options'.
+pager by default.  See 'eshell-visual-subcommands' and 'eshell-visual-options'.
 
 *** New Eshell-Tramp module.
 External su and sudo commands are now the default; the internal,
 Tramp-using variants can still be used by enabling the eshell-tramp module.
 
-** New F90 mode option `f90-smart-end-names'.
+** New F90 mode option 'f90-smart-end-names'.
 
-** New option `gnutls-verify-error', if non-nil, means that Emacs
+** New option 'gnutls-verify-error', if non-nil, means that Emacs
 should reject SSL/TLS certificates that GnuTLS determines as invalid.
 (This option defaults to nil at present, but this is expected to change
 in a future release.)
 
 ** Hi-Lock
 
-*** New global command `M-s h .' (`highlight-symbol-at-point') highlights
+*** New global command 'M-s h .' ('highlight-symbol-at-point') highlights
 the symbol near point.
 
-*** New option `hi-lock-auto-select-face'.  When non-nil, hi-lock commands
-will cycle through faces in `hi-lock-face-defaults' without prompting.
+*** New option 'hi-lock-auto-select-face'.  When non-nil, hi-lock commands
+will cycle through faces in 'hi-lock-face-defaults' without prompting.
 
 ** Icomplete is now more similar to Ido.
 
 *** Icomplete by default now applies to all forms of minibuffer completion.
-The variable `icomplete-with-completion-tables' (now a user option)
+The variable 'icomplete-with-completion-tables' (now a user option)
 controls this.  To restore the old behavior, set it back to
 '(internal-complete-buffer).
 
 *** You can navigate through and select completions using the keys
-from `icomplete-minibuffer-map'.
+from 'icomplete-minibuffer-map'.
 
 *** The string that separates potential completions is now a customizable
-option (`icomplete-separator').  The default is " | " rather than ",".
+option ('icomplete-separator').  The default is " | " rather than ",".
 
-*** New face `icomplete-first-match'; and new options
-`icomplete-hide-common-prefix' and `icomplete-show-matches-on-no-input'.
+*** New face 'icomplete-first-match'; and new options
+'icomplete-hide-common-prefix' and 'icomplete-show-matches-on-no-input'.
 
-*** The option `icomplete-show-key-bindings' has been removed.
+*** The option 'icomplete-show-key-bindings' has been removed.
 
 ** Ido
 
 *** An Ido user manual is now included.
 
-*** The option `ido-use-virtual-buffers' can now take the value `auto'.
+*** The option 'ido-use-virtual-buffers' can now take the value 'auto'.
 This means to use virtual buffers if the current ido input does not match
 an existing buffer.
 
-*** The variable `ido-decorations' can optionally have two new elements,
+*** The variable 'ido-decorations' can optionally have two new elements,
 which are the brackets to use around the sole remaining completion.
 
 ** Image mode
 
-*** New commands `n' (`image-next-file') and `p' (`image-previous-file')
+*** New commands 'n' ('image-next-file') and 'p' ('image-previous-file')
 visit the next image file and the previous image file in the same
 directory, respectively.
 
 *** New commands to show specific frames of multi-frame images.
-`f' (`image-next-frame') and `b' (`image-previous-frame') visit the
-next or previous frame.  `F' (`image-goto-frame') shows a specific frame.
+'f' ('image-next-frame') and 'b' ('image-previous-frame') visit the
+next or previous frame.  'F' ('image-goto-frame') shows a specific frame.
 
 *** New commands to speed up, slow down, or reverse animation.
-`a +' (`image-increase-speed') and `a -' (`image-decrease-speed') to
-speed up and slow down the animation.  `a r' (`image-reverse-speed')
-to reverse it and `a 0' (`image-reset-speed') to reset it.
+'a +' ('image-increase-speed') and 'a -' ('image-decrease-speed') to
+speed up and slow down the animation.  'a r' ('image-reverse-speed')
+to reverse it and 'a 0' ('image-reset-speed') to reset it.
 
-*** The command `image-mode-fit-frame' deletes other windows.
+*** The command 'image-mode-fit-frame' deletes other windows.
 When toggling, it restores the frame's previous window configuration.
 It also has an optional frame argument, which can be used by Lisp
 callers to fit the image to a frame other than the selected frame.
 
-** New Imenu option `imenu-generic-skip-comments-and-strings'.
+** New Imenu option 'imenu-generic-skip-comments-and-strings'.
 
 ** Info
 
-*** New Info face `info-index-match', used to highlight matches in index
-entries displayed by `Info-index-next', `Info-virtual-index' and
-`info-apropos'.
+*** New Info face 'info-index-match', used to highlight matches in index
+entries displayed by 'Info-index-next', 'Info-virtual-index' and
+'info-apropos'.
 
 *** The Info-edit command is obsolete.  Editing Info nodes by hand
 has not been relevant for some time.
 
 ** JS Mode
 
-*** New option `js-switch-indent-offset'.
+*** New option 'js-switch-indent-offset'.
 
 *** Better indentation of multiple-variable declarations.
 If a declaration spans several lines, variables on the following lines
@@ -674,10 +674,10 @@ are lined up to the first one.
 *** All delphi-* variables and functions have been renamed to opascal-*.
 Obsolete aliases exist for those likely to have been used externally.
 
-*** The option `delphi-newline-always-indents' has been removed.
-Use `electric-indent-mode' instead.
+*** The option 'delphi-newline-always-indents' has been removed.
+Use 'electric-indent-mode' instead.
 
-*** The TAB key runs the standard `indent-for-tab-command', not `delphi-tab'.
+*** The TAB key runs the standard 'indent-for-tab-command', not 'delphi-tab'.
 
 ** Package
 
@@ -685,43 +685,43 @@ Use `electric-indent-mode' instead.
 Maintainers of package archives should consider signing their packages
 to enhance security.
 
-**** If the user option `package-check-signature' is non-nil,
+**** If the user option 'package-check-signature' is non-nil,
 Emacs tries to check package signatures at install time.
-The value `allow-unsigned' allows installation of unsigned packages.
+The value 'allow-unsigned' allows installation of unsigned packages.
 
-**** The user option `package-unsigned-archives' lists archives where
+**** The user option 'package-unsigned-archives' lists archives where
 Emacs will not try to check signatures.
 
-*** New option `package-pinned-packages'.  This is useful if you have multiple
+*** New option 'package-pinned-packages'.  This is useful if you have multiple
 archives enabled, with more than one offering a given package that you want.
 
-*** In the `list-packages' buffer, you can use `f' (`package-menu-filter')
+*** In the 'list-packages' buffer, you can use 'f' ('package-menu-filter')
 to filter the list of packages by a keyword.
 
-*** In the `describe-package' buffer, there are now buttons listing the
+*** In the 'describe-package' buffer, there are now buttons listing the
 keywords related to the package.  Click on a button to see other packages
 related to that keyword.
 
-*** The format of `archive-contents' files, generated by package
+*** The format of 'archive-contents' files, generated by package
 repositories, has changed to allow a new (fifth) element in the data
 vectors, containing an associative list with extra properties.
-(For example, `describe-package' uses the `:url' extra property to
+(For example, 'describe-package' uses the ':url' extra property to
 display a "Homepage" header.)
 
-** In Prolog mode, `prolog-use-smie' has been removed,
+** In Prolog mode, 'prolog-use-smie' has been removed,
 along with the non-SMIE indentation code.
 
 ** Python mode
 
 *** Out of the box support for CPython, iPython and readline based shells.
-**** `python-shell-completion-module-string-code' is no longer used.
+**** 'python-shell-completion-module-string-code' is no longer used.
 
 *** Automatic shell prompt detection.  New user options:
-**** `python-shell-interpreter-interactive-arg'.
-**** `python-shell-prompt-detect-enabled'.
-**** `python-shell-prompt-detect-failure-warning'.
-**** `python-shell-prompt-input-regexps'.
-**** `python-shell-prompt-output-regexps'.
+**** 'python-shell-interpreter-interactive-arg'.
+**** 'python-shell-prompt-detect-enabled'.
+**** 'python-shell-prompt-detect-failure-warning'.
+**** 'python-shell-prompt-input-regexps'.
+**** 'python-shell-prompt-output-regexps'.
 
 *** Python shell support for remote hosts via tramp.
 
@@ -729,106 +729,106 @@ along with the non-SMIE indentation code.
 
 ** Remember
 
-*** The new command `remember-notes' creates a buffer that is saved on exit.
+*** The new command 'remember-notes' creates a buffer that is saved on exit.
 You can use it as a more permanent *scratch* buffer.
 
 *** Remember can now store notes in separate files.
-To use this, add `remember-store-in-files' to the `remember-handler-functions'
-option.  The files are saved in `remember-data-directory' using
-names specified by `remember-directory-file-name-format'.
+To use this, add 'remember-store-in-files' to the 'remember-handler-functions'
+option.  The files are saved in 'remember-data-directory' using
+names specified by 'remember-directory-file-name-format'.
 
 ** Rmail
 
-*** Customize `rmail-mbox-format' to influence some minor aspects of
+*** Customize 'rmail-mbox-format' to influence some minor aspects of
 how Rmail displays non-MIME messages.
 
-*** The `unrmail' command now converts from BABYL to mboxrd format,
-rather than mboxo.  Customize `unrmail-mbox-format' to change this.
+*** The 'unrmail' command now converts from BABYL to mboxrd format,
+rather than mboxo.  Customize 'unrmail-mbox-format' to change this.
 
 ** Ruby mode
 
 *** Improved syntax highlighting and indentation.
 
-*** New `electric-indent-mode' integration.
+*** New 'electric-indent-mode' integration.
 
-*** New option `ruby-encoding-magic-comment-style'.
+*** New option 'ruby-encoding-magic-comment-style'.
 
-*** New option `ruby-custom-encoding-magic-comment-template'.
+*** New option 'ruby-custom-encoding-magic-comment-template'.
 
-*** New option `ruby-align-to-stmt-keywords'.
+*** New option 'ruby-align-to-stmt-keywords'.
 
-*** New option `ruby-align-chained-calls'.
+*** New option 'ruby-align-chained-calls'.
 
-*** More Ruby file types have been added to `auto-mode-alist'.
+*** More Ruby file types have been added to 'auto-mode-alist'.
 
 ** Search and Replace
 
-*** New global command `M-s .' (`isearch-forward-symbol-at-point')
+*** New global command 'M-s .' ('isearch-forward-symbol-at-point')
 starts a symbol (identifier) incremental search forward with the
 symbol found near point added to the search string initially.
 
-*** `C-x 8 RET' in Isearch mode reads a character by its Unicode name
+*** 'C-x 8 RET' in Isearch mode reads a character by its Unicode name
 and adds it to the search string.
 
-*** `M-s i' in Isearch mode toggles whether search matches invisible text.
+*** 'M-s i' in Isearch mode toggles whether search matches invisible text.
 
-*** `query-replace' skips invisible text when `search-invisible' is nil,
-and opens overlays with hidden text when `search-invisible' is `open'.
+*** 'query-replace' skips invisible text when 'search-invisible' is nil,
+and opens overlays with hidden text when 'search-invisible' is 'open'.
 
 *** A negative prefix argument of replacement commands replaces backward.
-`M-- M-%' replaces a string backward, `M-- C-M-%' replaces a regexp
-backward, `M-s w words M-- M-%' replaces a sequence of words backward.
+'M-- M-%' replaces a string backward, 'M-- C-M-%' replaces a regexp
+backward, 'M-s w words M-- M-%' replaces a sequence of words backward.
 
 *** By default, prefix arguments do not now terminate Isearch mode.
-Set `isearch-allow-prefix' to nil to restore the old behavior.
+Set 'isearch-allow-prefix' to nil to restore the old behavior.
 
 *** More Isearch commands accept prefix arguments, namely
-`isearch-printing-char', `isearch-quote-char', `isearch-yank-word',
-`isearch-yank-line'.
+'isearch-printing-char', 'isearch-quote-char', 'isearch-yank-word',
+'isearch-yank-line'.
 
 *** Word search now matches whitespace at the beginning/end
 of the search string if it contains leading/trailing whitespace.
 In an incremental word search or when using a non-nil LAX argument
-of `word-search-regexp', the lax matching can also match part of
+of 'word-search-regexp', the lax matching can also match part of
 the first word (in addition to the lax matching of the last word).
 The same rules are now applied to the symbol search, with the difference
 that it matches symbols, and non-symbol characters between symbols.
 
-** New SES command `ses-rename-cell' allows assignment of names to SES cells.
+** New SES command 'ses-rename-cell' allows assignment of names to SES cells.
 
-** The shell.el option `explicit-bash-args' includes --noediting by default.
+** The shell.el option 'explicit-bash-args' includes --noediting by default.
 All non-ancient Bash versions support this option.
 
 ** Shell Script mode
 
-*** The SMIE indentation engine is now used by default - see `sh-use-smie'.
+*** The SMIE indentation engine is now used by default - see 'sh-use-smie'.
 
-*** `sh-mode' now has its own setting for `add-log-current-defun-function'.
+*** 'sh-mode' now has its own setting for 'add-log-current-defun-function'.
 
 ** SMIE
 
-*** You can customize the SMIE indentation of a mode via `smie-config'.
-The command `smie-config-guess' can help you derive the appropriate
+*** You can customize the SMIE indentation of a mode via 'smie-config'.
+The command 'smie-config-guess' can help you derive the appropriate
 indentation settings, if you provide it with an indented sample file.
-Use `smie-config-save' to save the result.
+Use 'smie-config-save' to save the result.
 
 *** You can customize the SMIE indentation of a file by adding an entry to
-the file's local variables of the form: `eval: (smie-config-local '(RULES))'.
+the file's local variables of the form: 'eval: (smie-config-local '(RULES))'.
 
-*** New commands `smie-config-show-indent' and `smie-config-set-indent'.
+*** New commands 'smie-config-show-indent' and 'smie-config-set-indent'.
 
 ** SQL mode
 
 *** Improved login monitoring and appropriate response to login failures.
-New variable `sql-login-delay' defines maximum wait time for a connection.
+New variable 'sql-login-delay' defines maximum wait time for a connection.
 
 *** Oracle support.
 SQL*Plus script placeholders are properly highlighted and identified
-in `sql-placeholders-filter'.  When starting SQL*Plus, `sql-oracle-options'
+in 'sql-placeholders-filter'.  When starting SQL*Plus, 'sql-oracle-options'
 are passed before the logon parameter, as required.  The default now
-includes `-L', to limit the number of logon attempts per invocation.
+includes '-L', to limit the number of logon attempts per invocation.
 
-** New Term mode option `term-suppress-hard-newline'.
+** New Term mode option 'term-suppress-hard-newline'.
 
 ** Todo mode has been rewritten and enhanced.
 The Todo mode user manual describes all commands and most user
@@ -861,11 +861,11 @@ or in archive files, undoing or unarchiving done items.
 
 ** Trace
 
-*** `trace-function' and `trace-function-background' no longer prompt for
+*** 'trace-function' and 'trace-function-background' no longer prompt for
 the output buffer.  Unless you use a prefix argument, they output to
-`trace-buffer'.
+'trace-buffer'.
 
-*** With a prefix argument, `trace-function' and `trace-function-background'
+*** With a prefix argument, 'trace-function' and 'trace-function-background'
 will prompt for a "context".  This is a Lisp expression, whose value at the
 time the function is entered/exited is printed along with the function's
 name and arguments.
@@ -873,13 +873,13 @@ name and arguments.
 ** Tramp
 
 *** New connection method "adb", which allows to access Android
-devices by the Android Debug Bridge.  The variable `tramp-adb-program'
+devices by the Android Debug Bridge.  The variable 'tramp-adb-program'
 can be used to adapt the path of the "adb" program, if needed.
 
-*** Handlers for `file-acl' and `set-file-acl' for remote machines
+*** Handlers for 'file-acl' and 'set-file-acl' for remote machines
 that support POSIX ACLs.
 
-*** Handlers for `file-notify-add-watch' and `file-notify-rm-watch'
+*** Handlers for 'file-notify-add-watch' and 'file-notify-rm-watch'
 for remote machines that support filesystem notifications.
 
 *** The experimental url syntax for remote file names has been removed.
@@ -887,34 +887,34 @@ for remote machines that support filesystem notifications.
 *** The connection methods "plink1", "ssh1", "ssh2", "scp1", "scp2",
 "scpc" and "rsyncc" are discontinued.  The ssh option
 "ControlMaster=auto" is set automatically in all ssh-based methods,
-when possible.  See `tramp-use-ssh-controlmaster-options'.
+when possible.  See 'tramp-use-ssh-controlmaster-options'.
 
-** New URL command `url-cookie-list' displays the current cookies,
+** New URL command 'url-cookie-list' displays the current cookies,
 and allows you to interactively remove cookies.
 
 ** VC and related modes
 
-*** In VC directory mode, `D' displays diffs between VC-controlled
+*** In VC directory mode, 'D' displays diffs between VC-controlled
 whole tree revisions.
 
-*** In VC directory mode, `L' lists the change log for the current VC
+*** In VC directory mode, 'L' lists the change log for the current VC
 controlled tree in a window.
 
-*** In VC directory mode, `I' shows a log of changes that will be
+*** In VC directory mode, 'I' shows a log of changes that will be
 received with a pull operation.
 
-*** `C-x v G' (globally) and `G' (in VC directory mode) ignores a file
+*** 'C-x v G' (globally) and 'G' (in VC directory mode) ignores a file
 under current version control system.  When called with a prefix
 argument, you can remove a file from the ignored file list.
 
 ** VHDL mode
 
-*** New options: `vhdl-actual-generic-name', `vhdl-beautify-options'.
+*** New options: 'vhdl-actual-generic-name', 'vhdl-beautify-options'.
 
-*** New commands: `vhdl-fix-statement-region', `vhdl-fix-statement-buffer'.
+*** New commands: 'vhdl-fix-statement-region', 'vhdl-fix-statement-buffer'.
 
-** The Woman commands `woman-default-faces' and `woman-monochrome-faces'
-are obsolete.  Customize the `woman-*' faces instead.
+** The Woman commands 'woman-default-faces' and 'woman-monochrome-faces'
+are obsolete.  Customize the 'woman-*' faces instead.
 
 ** More packages look for ~/.emacs.d/<foo> additionally to ~/.<foo>.
 Affected files:
@@ -939,9 +939,9 @@ Also the following files used by the now obsolete 
otodo-mode.el:
 
 ** Obsolete packages
 
-*** iswitchb.el; use icomplete-mode.
+*** iswitchb.el; use 'icomplete-mode'.
 
-*** longlines.el; use visual-line-mode.
+*** longlines.el; use 'visual-line-mode'.
 
 *** meese.el.
 
@@ -958,17 +958,17 @@ Also the following files used by the now obsolete 
otodo-mode.el:
 
 * New Modes and Packages in Emacs 24.4
 
-** New package eww.el provides a built-in web browser.
+** New package 'eww' provides a built-in web browser.
 This requires Emacs to have been compiled with libxml2 support.
 
 ** New package nadvice.el offers lighter-weight advice facilities.
 It is layered as:
 
-*** `add-function'/`remove-function', which can be used to add/remove code on
-any function-carrying place, such as process filters or `<foo>-function' hooks.
+*** 'add-function'/'remove-function', which can be used to add/remove code on
+any function-carrying place, such as process filters or '<foo>-function' hooks.
 
-*** `advice-add'/`advice-remove' to add/remove a piece of advice on a named
-function, much like `defadvice' does.
+*** 'advice-add'/'advice-remove' to add/remove a piece of advice on a named
+function, much like 'defadvice' does.
 
 ** New package frameset.el provides a set of operations to save a frameset
 (the state of all or a subset of the existing frames and windows, somewhat
@@ -979,23 +979,23 @@ restore it at some point in the future.
 notifications.  It requires that Emacs be compiled with one of the
 low-level libraries gfilenotify.c, inotify.c or w32notify.c.
 
-** New minor modes `prettify-symbols-mode' and `global-prettify-symbols-mode'
+** New minor modes 'prettify-symbols-mode' and 'global-prettify-symbols-mode'
 display specified symbols as composed characters.  E.g., in Emacs Lisp mode,
 this replaces the string "lambda" with the Greek lambda character.
 
-** New minor mode `superword-mode', which overrides the default word motion
+** New minor mode 'superword-mode', which overrides the default word motion
 commands to treat "symbol_words" as a single word, similar to what
-`subword-mode' does.
+'subword-mode' does.
 
 
 * Incompatible Lisp Changes in Emacs 24.4
 
 ** The default file coding for Emacs Lisp files is now utf-8.
-(See `file-coding-system-alist'.)  In most cases, this change is
+(See 'file-coding-system-alist'.)  In most cases, this change is
 transparent, but files that contain unusual characters without
 specifying an explicit coding system may fail to load with obscure
 errors.  You should either convert them to utf-8 or add an explicit
-`coding:' cookie.
+'coding:' cookie.
 
 ** Default process filters and sentinels are not nil any more.
 Instead they default to a function that does what the nil value used to do.
@@ -1007,57 +1007,57 @@ don't feel it's right to document them.  For now, don't 
assume in your
 code that the values of overlay priority can only be either nil or an
 integer, always test them with an appropriate predicate to be one or
 the other.  If you need to sort arbitrary overlays into priority
-order, `overlays-at' can now optionally do this.
+order, 'overlays-at' can now optionally do this.
 You should still only specify integer priorities on overlays you create.
 
-** The cars of the elements in `interpreter-mode-alist' are now
+** The cars of the elements in 'interpreter-mode-alist' are now
 treated as regexps rather than literal strings.
 
-** `overriding-terminal-local-map' no longer replaces the local keymaps.
+** 'overriding-terminal-local-map' no longer replaces the local keymaps.
 It used to disable the minor mode, major mode, and text-property keymaps,
 whereas now it simply has higher precedence.
 
-** `kill-region' has lost its `yank-handler' optional argument.
+** 'kill-region' has lost its 'yank-handler' optional argument.
 
-** `(input-pending-p)' no longer runs other timers that are ready to run.
+** '(input-pending-p)' no longer runs other timers that are ready to run.
 The new optional CHECK-TIMERS parameter allows for the prior behavior.
 
-** `defvar' and `defcustom' in a let-binding affect the "external" default.
+** 'defvar' and 'defcustom' in a let-binding affect the "external" default.
 
 ** The syntax of ?» and ?« is now punctuation instead of matched parens.
 Some languages match those as »...«, and others as «...», so it is
 better for Emacs to stay neutral by default.
 
-** `read-event' does not always decode chars in ttys any more.  As was the case
-in Emacs 22 and before, `read-event' (and `read-char') by default read raw
+** 'read-event' does not always decode chars in ttys any more.  As was the case
+in Emacs 22 and before, 'read-event' (and 'read-char') by default read raw
 bytes from the terminal.  If you want to read decoded chars instead (as was
 always the case in Emacs-23, for example), pass a non-nil
-`inherit-input-method' argument.
+'inherit-input-method' argument.
 
-** In `symbol-function', nil and "unbound" are indistinguishable.
-`symbol-function' does not signal a `void-function' error any more.
-To determine if a symbol's function definition is void, use `fboundp'.
+** In 'symbol-function', nil and "unbound" are indistinguishable.
+'symbol-function' does not signal a 'void-function' error any more.
+To determine if a symbol's function definition is void, use 'fboundp'.
 
-** `defadvice' does not honor the `freeze' flag and cannot advise
+** 'defadvice' does not honor the 'freeze' flag and cannot advise
 special-forms any more.
 
-** `dolist' no longer binds VAR while evaluating the RESULT form,
+** 'dolist' no longer binds VAR while evaluating the RESULT form,
 when lexical binding is enabled.  Previously, VAR was bound to nil,
 which often led to spurious unused-variable warnings.
 
-** The return value of `backup-buffer' has changed.
+** The return value of 'backup-buffer' has changed.
 The second argument is no longer an SELinux context, instead it is an
 alist of extended attributes as returned by the new function
-`file-extended-attributes'.  The attributes can be applied to another
-file using `set-file-extended-attributes'.
+'file-extended-attributes'.  The attributes can be applied to another
+file using 'set-file-extended-attributes'.
 
-** By default `copy-file' no longer copies file permission bits to an
+** By default 'copy-file' no longer copies file permission bits to an
 existing destination; and it sets the file permission bits of a newly
 created destination to those of the source, masked by the default file
 permissions.  To copy the file permission bits, pass t as the
-PRESERVE-PERMISSIONS argument of `copy-file'.
+PRESERVE-PERMISSIONS argument of 'copy-file'.
 
-** `visited-file-modtime' now returns -1 for nonexistent files.
+** 'visited-file-modtime' now returns -1 for nonexistent files.
 Formerly it returned a list (-1 LOW USEC PSEC), but this was ambiguous
 in the presence of files with negative time stamps.
 
@@ -1067,7 +1067,7 @@ value when looking up variables.
 
 ** In compiled Lisp files, the header no longer includes a timestamp.
 
-** The option `inhibit-local-menu-bar-menus' has been removed.
+** The option 'inhibit-local-menu-bar-menus' has been removed.
 
 
 * Lisp Changes in Emacs 24.4
@@ -1076,111 +1076,111 @@ value when looking up variables.
 and name of global variables, constants, and functions should be separated
 by two hyphens if the symbol is not meant to be used by other packages.
 
-** The second argument of `eval' can now specify a lexical environment.
+** The second argument of 'eval' can now specify a lexical environment.
 
-** New macro `define-alternatives' can be used to define generic commands.
+** New macro 'define-alternatives' can be used to define generic commands.
 Generic commands are interactive functions whose implementation can be
 selected among several alternatives, as a matter of user preference.
 
 ** Numeric comparison functions =, <, >, <=, >= can now take many arguments.
 
-** New functions `special-form-p' and `macrop'.
+** New functions 'special-form-p' and 'macrop'.
 
-** New macro `with-eval-after-load'.
-This is like the old `eval-after-load', but better behaved.
+** New macro 'with-eval-after-load'.
+This is like the old 'eval-after-load', but better behaved.
 
-** If you give a symbol a `defalias-fset-function' property, `defalias'
+** If you give a symbol a 'defalias-fset-function' property, 'defalias'
 on that symbol will use the associated value as a function to call
-in place of `fset'.
+in place of 'fset'.
 
-** New variable `enable-dir-local-variables'.
+** New variable 'enable-dir-local-variables'.
 Directory-local variables are ignored if this is nil.  This may be
 useful for modes that want to ignore directory-locals while still
 respecting file-local variables.
 
-** `read-regexp' now uses the new variable `read-regexp-defaults-function'
+** 'read-regexp' now uses the new variable 'read-regexp-defaults-function'
 as a function to call to provide default values.
 
-** New functions `group-gid' and `group-real-gid'.
+** New functions 'group-gid' and 'group-real-gid'.
 
-** New function `get-pos-property'.
+** New function 'get-pos-property'.
 
-** New hook `pre-redisplay-function'.
+** New hook 'pre-redisplay-function'.
 
-** `byte-compile-interactive-only-functions' is now obsolete.
+** 'byte-compile-interactive-only-functions' is now obsolete.
 To specify that a command should only be called interactively, give it
-a non-nil `interactive-only' property.
+a non-nil 'interactive-only' property.
 
-** New function `string-suffix-p'.
+** New function 'string-suffix-p'.
 
-** `split-string' now takes an optional argument TRIM.
+** 'split-string' now takes an optional argument TRIM.
 The value, if non-nil, is a regexp that specifies what to trim from
 the start and end of each substring.
 
-** New function `delete-consecutive-dups'.
+** New function 'delete-consecutive-dups'.
 
 ** Completion
 
-*** The separator used by `completing-read-multiple' is now a regexp.
-The default `crm-separator' has been changed to allow surrounding spaces
+*** The separator used by 'completing-read-multiple' is now a regexp.
+The default 'crm-separator' has been changed to allow surrounding spaces
 around the comma.
 
-*** New function `completion-table-with-cache' is a wrapper for
-`completion-table-dynamic' that caches the result of the last lookup.
+*** New function 'completion-table-with-cache' is a wrapper for
+'completion-table-dynamic' that caches the result of the last lookup.
 
-*** New function `completion-table-merge' to combine several
+*** New function 'completion-table-merge' to combine several
 completion tables by merging their completions.
 
-*** The `common-substring' argument of `display-completion-list',
+*** The 'common-substring' argument of 'display-completion-list',
 which has been documented as obsolete since Emacs 23.1, is now _really_
 obsolete, and no longer advertised.  Instead either call
-`completion-hilit-commonality' to add the highlighting; or use
-`completion-all-completions', which returns highlighted strings.
+'completion-hilit-commonality' to add the highlighting; or use
+'completion-all-completions', which returns highlighted strings.
 
 ** Encoding and decoding of text
 
-*** New coding-system `prefer-utf-8'.
-This is like `undecided' but prefers UTF-8 on decoding if the text to
+*** New coding-system 'prefer-utf-8'.
+This is like 'undecided' but prefers UTF-8 on decoding if the text to
 be decoded does not contain any invalid UTF-8 sequences.  On encoding,
 any non-ASCII characters are automatically encoded as UTF-8.
 
-*** New attributes of coding-systems whose type is `undecided'.
-Two new attributes, `:inhibit-null-byte-detection' and
-`:inhibit-iso-escape-detection', determine how to detect encoding of
+*** New attributes of coding-systems whose type is 'undecided'.
+Two new attributes, ':inhibit-null-byte-detection' and
+':inhibit-iso-escape-detection', determine how to detect encoding of
 text that includes null bytes and ISO-2022 escape sequences, respectively.
 Each of these attributes can be either nil, zero, or t.  If t, decoding
 text ignores null bytes and ISO-2022 sequences, respectively.  If nil,
 null bytes cause text to be decoded with no-conversion, and ISO-2022
 sequences cause Emacs to assume the text is encoded in one of the ISO-2022
 encodings, such as iso-2022-7bit.  If zero, Emacs consults the variables
-`inhibit-null-byte-detection' and `inhibit-iso-escape-detection'.
-The new attribute `:prefer-utf-8', if non-nil, causes Emacs to prefer
+'inhibit-null-byte-detection' and 'inhibit-iso-escape-detection'.
+The new attribute ':prefer-utf-8', if non-nil, causes Emacs to prefer
 UTF-8 encoding and decoding, whenever possible.
 
-These attributes are only meaningful for coding-systems of type `undecided'.
-(The type of a coding-system is determined by its `:coding-type' attribute
-and can be accessed by calling the `coding-system-type' function.)
+These attributes are only meaningful for coding-systems of type 'undecided'.
+(The type of a coding-system is determined by its ':coding-type' attribute
+and can be accessed by calling the 'coding-system-type' function.)
 
 ** Error-handling
 
-*** New function `define-error'.
+*** New function 'define-error'.
 
-*** `with-demoted-errors' takes an additional argument `format'.
+*** 'with-demoted-errors' takes an additional argument 'format'.
 
 *** Errors from timer functions are no longer silently discarded,
 but are reported as messages.  So you may see "Error running timer"
 messages from code that was failing silently till now.  Set
-`debug-on-error' non-nil to get a real error and a backtrace.
+'debug-on-error' non-nil to get a real error and a backtrace.
 
 ** Faces
 
-*** Face specs set via Custom themes now replace the `defface' spec
+*** Face specs set via Custom themes now replace the 'defface' spec
 rather than inheriting from it.  In other words, setting a face via a
 theme now behaves like setting it via Customize: you only need to
 specify the attributes that you want, you don't need to unset those
 that you don't want.
 
-*** The function `face-spec-set' is now like `setq' for face specs.
+*** The function 'face-spec-set' is now like 'setq' for face specs.
 Its third arg now accepts values specifying a face spec type (defface,
 custom, or override spec), and the relevant spec is set accordingly.
 
@@ -1188,7 +1188,7 @@ custom, or override spec), and the relevant spec is set 
accordingly.
 specifies foreground to use if background color is near the foreground
 color that would otherwise have been used.
 
-*** New function `add-face-text-property', which can be used to
+*** New function 'add-face-text-property', which can be used to
 conveniently prepend/append new face properties.
 
 *** New face characteristic (supports :underline (:style wave))
@@ -1199,76 +1199,76 @@ specifies whether or not the terminal can display a 
wavy line.
 *** Support for filesystem notifications.
 Emacs now supports notifications of filesystem changes, such as
 creation, modification, and deletion of files.  This requires the
-`glib' API, or the 'inotify' API (on GNU/Linux systems only).  On
+'glib' API, or the 'inotify' API (on GNU/Linux systems only).  On
 MS-Windows systems, this is supported for Windows XP and newer.
 
-*** The 9th element returned by `file-attributes' is now unspecified.
+*** The 9th element returned by 'file-attributes' is now unspecified.
 Formerly, it was t if the file's gid would change if file were deleted
 and recreated.  This value has been inaccurate for years on many
 platforms, and nobody seems to have noticed or cared.
 
-*** The 6th argument to `copy-file' has been renamed to
+*** The 6th argument to 'copy-file' has been renamed to
 PRESERVE-PERMISSIONS as it now handles ACL entries and the traditional
 Unix file permission bits as well as SELinux context.
 
-*** The function `file-ownership-preserved-p' now has an optional
+*** The function 'file-ownership-preserved-p' now has an optional
 argument GROUP which causes it check for file group too.  This can be
-used in place of the 9th element of `file-attributes'.
+used in place of the 9th element of 'file-attributes'.
 
-*** The function `set-visited-file-modtime' now accepts a 0 or -1 argument,
-with the same interpretation as the returned value of `visited-file-modtime'.
+*** The function 'set-visited-file-modtime' now accepts a 0 or -1 argument,
+with the same interpretation as the returned value of 'visited-file-modtime'.
 
 ** Image API
 
-*** `image-animated-p' is now `image-multi-frame-p'.
+*** 'image-animated-p' is now 'image-multi-frame-p'.
 It returns non-nil for any image that contains multiple frames,
 whether or not it specifies a frame delay.
 
-*** New variable `image-default-frame-delay' gives the frame delay for
+*** New variable 'image-default-frame-delay' gives the frame delay for
 animated images which do not specify a frame delay.
 
-*** New functions `image-current-frame' and `image-show-frame' for getting
+*** New functions 'image-current-frame' and 'image-show-frame' for getting
 and setting the current frame of a multi-frame image.
 
 ** ImageMagick
 
 *** ImageMagick images now support the :max-width and :max-height keywords.
 
-*** When using `create-image' with image data, you can pass a :format
+*** When using 'create-image' with image data, you can pass a :format
 attribute (via the property-list argument) in order to help
 ImageMagick detect the image type.  The value should be a MIME
-content-type that is found in the new variable `image-format-suffixes'.
+content-type that is found in the new variable 'image-format-suffixes'.
 
 ** Revert and Autorevert
 
 *** If Emacs is compiled with file notification support, it uses notifications
 instead of checking file time stamps.  To disable this, set the user option
-`auto-revert-use-notify' to nil.  Alternatively, you can specify a regular
+'auto-revert-use-notify' to nil.  Alternatively, you can specify a regular
 expression matching directories to be excluded from file notifications via
-`auto-revert-notify-exclude-dir-regexp'.
+'auto-revert-notify-exclude-dir-regexp'.
 
-*** The default values of `buffer-stale-function', `revert-buffer-function',
-and `revert-buffer-insert-file-contents-function' are no longer nil.
+*** The default values of 'buffer-stale-function', 'revert-buffer-function',
+and 'revert-buffer-insert-file-contents-function' are no longer nil.
 Instead they default to functions that do what the nil value used to.
 
-*** `buffer-stale-function' is now used for buffers visiting files too.
+*** 'buffer-stale-function' is now used for buffers visiting files too.
 
-*** The new user option `auto-revert-remote-files' enables reversion
+*** The new user option 'auto-revert-remote-files' enables reversion
 of remote files, if non-nil.
 
 ** Terminal
 
 *** Functions to pop up menus and dialogs now work on all terminals,
-including TTYs.  This includes `x-popup-menu', `x-popup-dialog',
-`message-box', `yes-or-no-p', etc.
+including TTYs.  This includes 'x-popup-menu', 'x-popup-dialog',
+'message-box', 'yes-or-no-p', etc.
 
-The function `display-popup-menus-p' will now return non-nil for a
+The function 'display-popup-menus-p' will now return non-nil for a
 display or frame whenever a mouse is supported on that display or frame.
 
-*** New hook `tty-setup-hook', run at the end of initializing a text terminal.
+*** New hook 'tty-setup-hook', run at the end of initializing a text terminal.
 
-*** The hook `term-setup-hook' is obsolete.  It is entirely equivalent
-to `emacs-startup-hook'.  See also the new `tty-setup-hook'.
+*** The hook 'term-setup-hook' is obsolete.  It is entirely equivalent
+to 'emacs-startup-hook'.  See also the new 'tty-setup-hook'.
 
 ** Minor internal changes to the details of lock files.
 The lock for DIR/FILE is now _always_ DIR/.#FILE.
@@ -1279,34 +1279,34 @@ On file systems that do not support symbolic links, the 
lock is now a
 regular file with contents being what would have been in the symlink.
 
 ** New bool-vector set operation functions:
-*** `bool-vector-exclusive-or'
-*** `bool-vector-union'
-*** `bool-vector-intersection'
-*** `bool-vector-set-difference'
-*** `bool-vector-not'
-*** `bool-vector-subsetp'
-*** `bool-vector-count-consecutive'
-*** `bool-vector-count-population'
+*** 'bool-vector-exclusive-or'
+*** 'bool-vector-union'
+*** 'bool-vector-intersection'
+*** 'bool-vector-set-difference'
+*** 'bool-vector-not'
+*** 'bool-vector-subsetp'
+*** 'bool-vector-count-consecutive'
+*** 'bool-vector-count-population'
 
 ** New library subr-x.el with miscellaneous small utility functions:
-*** `hash-table-keys'
-*** `hash-table-values'
-*** `string-blank-p'
-*** `string-empty-p'
-*** `string-join'
-*** `string-reverse'
-*** `string-trim-left'
-*** `string-trim-right'
-*** `string-trim'
-*** `string-remove-prefix'
-*** `string-remove-suffix'
-
-** The `time-to-seconds' alias to `float-time' is no longer marked obsolete.
-
-** The spelling of the rx.el category `chinese-two-byte' has been
+*** 'hash-table-keys'
+*** 'hash-table-values'
+*** 'string-blank-p'
+*** 'string-empty-p'
+*** 'string-join'
+*** 'string-reverse'
+*** 'string-trim-left'
+*** 'string-trim-right'
+*** 'string-trim'
+*** 'string-remove-prefix'
+*** 'string-remove-suffix'
+
+** The 'time-to-seconds' alias to 'float-time' is no longer marked obsolete.
+
+** The spelling of the rx.el category 'chinese-two-byte' has been
 corrected (the first 'e' was missing).
 
-** EIEIO namespace cleanup, obsolete-aliasing functions to use `eieio-' prefix:
+** EIEIO namespace cleanup, obsolete-aliasing functions to use 'eieio-' prefix:
 *** object-name -> eieio-object-name
 *** object-class -> eieio-object-class
 *** object-class-fast -> eieio--object-class
@@ -1326,21 +1326,21 @@ corrected (the first 'e' was missing).
 *** class-direct-superclasses -> eieio-class-parents
 
 ** Obsoleted functions
-*** `log10'
-*** `dont-compile'
-*** `lisp-complete-symbol'
-*** `field-complete'
-*** `minibuffer-completion-contents'
-*** `isearch-nonincremental-exit-minibuffer'
-*** `isearch-filter-visible'
-*** `generic-make-keywords-list'
-*** `get-upcase-table' (use `case-table-get-table' instead).
-
-** `with-wrapper-hook' is obsoleted by `add-function'.
+*** 'log10'
+*** 'dont-compile'
+*** 'lisp-complete-symbol'
+*** 'field-complete'
+*** 'minibuffer-completion-contents'
+*** 'isearch-nonincremental-exit-minibuffer'
+*** 'isearch-filter-visible'
+*** 'generic-make-keywords-list'
+*** 'get-upcase-table' (use 'case-table-get-table' instead).
+
+** 'with-wrapper-hook' is obsoleted by 'add-function'.
 The few hooks that used with-wrapper-hook are replaced as follows:
-*** `abbrev-expand-function' obsoletes `abbrev-expand-functions'.
-*** `completion-in-region-function' obsoletes `completion-in-region-functions'.
-*** `filter-buffer-substring-function' obsoletes 
`filter-buffer-substring-functions'.
+*** 'abbrev-expand-function' obsoletes 'abbrev-expand-functions'.
+*** 'completion-in-region-function' obsoletes 'completion-in-region-functions'.
+*** 'filter-buffer-substring-function' obsoletes 
'filter-buffer-substring-functions'.
 
 
 * Changes in Emacs 24.4 on Non-Free Operating Systems
@@ -1352,10 +1352,10 @@ GNUstep and Mac OS X 10.4 use the old font backend.
 
 ** Improved fullscreen support on Mac OS X 10.7 and newer, where the
 default fullscreen method is now "native" fullscreen.  To use the
-old style fullscreen, customize `ns-use-native-fullscreen' to nil.
+old style fullscreen, customize 'ns-use-native-fullscreen' to nil.
 
 ** On Mac OS X 10.7 and newer, Emacs can use sRGB colorspace, and does so
-by default.  Customize `ns-use-srgb-colorspace' to go back to the old method.
+by default.  Customize 'ns-use-srgb-colorspace' to go back to the old method.
 Note that this does not apply to images.
 
 ** The procedure for building Emacs on MS-Windows has changed.
@@ -1378,7 +1378,7 @@ need to set any variables due to this change.)
 ** Emacs on Windows 2000 and later can now access files and directories
 whose names cannot be encoded in the current system codepage.
 
-The new variable `w32-unicode-filenames' controls this feature: if it
+The new variable 'w32-unicode-filenames' controls this feature: if it
 is t, Emacs uses Unicode APIs to pass file names to system calls,
 which lifts the limitation of file names to the current locale.
 
@@ -1386,57 +1386,57 @@ which lifts the limitation of file names to the current 
locale.
 This helps to prevent losing your edits if the same file is being
 edited in another Emacs session or by another user.  See the node
 "Interlocking" in the Emacs User Manual for the details.  To disable
-file locking, customize `create-lockfiles' to nil.
+file locking, customize 'create-lockfiles' to nil.
 
 ** The "generate a backtrace on fatal error" feature now works on MS-Windows.
 The backtrace is written to the 'emacs_backtrace.txt' file in the
 directory where Emacs was running.
 
-** The `network-interface-list' and `network-interface-info' functions
+** The 'network-interface-list' and 'network-interface-info' functions
 are now available on MS-Windows.
 
-** The variable `buffer-file-type' is no longer supported.
+** The variable 'buffer-file-type' is no longer supported.
 Setting it has no effect, and %t in the mode-line format is ignored.
-Likewise, `file-name-buffer-file-type-alist' is now obsolete, and
+Likewise, 'file-name-buffer-file-type-alist' is now obsolete, and
 modifying it has no effect.
 
 
 * Installation Changes in Emacs 24.3
 
 ** The default X toolkit is now Gtk+ version 3.
-If you don't pass `--with-x-toolkit' to configure, or if you use
-`--with-x-toolkit=gtk' or `--with-x-toolkit=yes', configure will try
+If you don't pass '--with-x-toolkit' to configure, or if you use
+'--with-x-toolkit=gtk' or '--with-x-toolkit=yes', configure will try
 to build with Gtk+ version 3, and if that fails, try Gtk+ version 2.
 You can explicitly require a specific version by passing
-`--with-x-toolkit=gtk2' or `--with-x-toolkit=gtk3' to configure.
+'--with-x-toolkit=gtk2' or '--with-x-toolkit=gtk3' to configure.
 
-** New configure option `--enable-link-time-optimization', to utilize
+** New configure option '--enable-link-time-optimization', to utilize
 an appropriate feature provided by GCC since version 4.5.0.
 
-** New configure option `--without-all' to disable most of the optional
+** New configure option '--without-all' to disable most of the optional
 features (image support, etc.) that are normally enabled by default.
 
-** New configure option `--enable-gcc-warnings' (for developing/debugging
+** New configure option '--enable-gcc-warnings' (for developing/debugging
 Emacs).  If building with GCC, this enables compile-time checks that
 warn/give errors about possibly-questionable C code.  On a recent GNU
 system there should be no warnings; on older and on non-GNU systems
 the results may be useful to developers.
 
-** The configure option `--enable-use-lisp-union-type' has been
-renamed to `--enable-check-lisp-object-type', as the resulting
+** The configure option '--enable-use-lisp-union-type' has been
+renamed to '--enable-check-lisp-object-type', as the resulting
 Lisp_Object type no longer uses a union to implement the compile time
 check that this option enables.
 
-** The configure option `--disable-maintainer-mode' has been removed,
+** The configure option '--disable-maintainer-mode' has been removed,
 as it was confusingly-named and rarely useful.
 
-** The configure options `--program-prefix', `--program-suffix', and
-`--program-transform-name' apply to more than just the installed
+** The configure options '--program-prefix', '--program-suffix', and
+'--program-transform-name' apply to more than just the installed
 binaries.  Now they also affect the man pages, icons, and the
 etc/emacs.desktop file; but not the info pages, since this would break
 links between the various manuals.
 
-** You can use `NO_BIN_LINK=t make install' to prevent the installation
+** You can use 'NO_BIN_LINK=t make install' to prevent the installation
 overwriting "emacs" in the installation bin/ directory with a link
 to "emacs-VERSION".
 
@@ -1446,31 +1446,31 @@ to "emacs-VERSION".
 /usr/pkg/lib to the linker search path.  You must add them yourself if
 you want them.
 
-** The standalone scripts `rcs-checkin' and `vcdiff' have been removed
+** The standalone scripts 'rcs-checkin' and 'vcdiff' have been removed
 (from the bin and libexec directories, respectively).  The former is
 no longer relevant, the latter is replaced by lisp (in vc-sccs.el).
 
 
 * Startup Changes in Emacs 24.3
 
-** Emacs no longer searches for `leim-list.el' files beneath the standard
+** Emacs no longer searches for 'leim-list.el' files beneath the standard
 lisp/ directory.  There should not be any there anyway.  If you have
 been adding them there, put them somewhere else; e.g., site-lisp.
 
-** The `--no-site-lisp' command line option now works for Nextstep builds.
+** The '--no-site-lisp' command line option now works for Nextstep builds.
 
 
 * Changes in Emacs 24.3
 
 ** Help
 
-*** `C-h f' (`describe-function') can now perform autoloading.
+*** 'C-h f' ('describe-function') can now perform autoloading.
 When this command is called for an autoloaded function whose docstring
 contains a key substitution construct, that function's library is
 automatically loaded, so that the documentation can be shown
-correctly.  To disable this, set `help-enable-auto-load' to nil.
+correctly.  To disable this, set 'help-enable-auto-load' to nil.
 
-*** `C-h f' now reports previously-autoloaded functions as "autoloaded",
+*** 'C-h f' now reports previously-autoloaded functions as "autoloaded",
 even after their associated libraries have been loaded (and the
 autoloads have been redefined as functions).
 
@@ -1480,68 +1480,68 @@ autoloads have been redefined as functions).
 :background image specification property.
 
 *** When available, ImageMagick support is automatically enabled.
-It is no longer necessary to call `imagemagick-register-types'
+It is no longer necessary to call 'imagemagick-register-types'
 explicitly to install ImageMagick image types; that function is called
 automatically at startup, or when customizing an imagemagick- option.
 
-*** Setting `imagemagick-types-inhibit' to t now disables the use of
-ImageMagick to view images.  (You must call `imagemagick-register-types'
+*** Setting 'imagemagick-types-inhibit' to t now disables the use of
+ImageMagick to view images.  (You must call 'imagemagick-register-types'
 afterwards if you do not use customize to change this.)
 
-*** The new variable `imagemagick-enabled-types' also affects which
+*** The new variable 'imagemagick-enabled-types' also affects which
 ImageMagick types are treated as images.  The function
-`imagemagick-filter-types' returns the list of types that will be
+'imagemagick-filter-types' returns the list of types that will be
 treated as images.
 
 ** Minibuffer
 
-*** In minibuffer filename prompts, `C-M-f' and `C-M-b' now move to the
+*** In minibuffer filename prompts, 'C-M-f' and 'C-M-b' now move to the
 next and previous path separator, respectively.
 
-*** `minibuffer-electric-default-mode' can shorten "(default ...)" to "[...]"
-in minibuffer prompts.  Just set `minibuffer-eldef-shorten-default'
+*** 'minibuffer-electric-default-mode' can shorten "(default ...)" to "[...]"
+in minibuffer prompts.  Just set 'minibuffer-eldef-shorten-default'
 non-nil before enabling the mode.
 
 ** Mode line
 
-*** New option `mode-line-default-help-echo' specifies the help text
+*** New option 'mode-line-default-help-echo' specifies the help text
 (shown in a tooltip or in the echo area) for any part of the mode line
 that does not have its own specialized help text.
 
 *** You can now click mouse-3 in the coding system indicator to invoke
-`set-buffer-file-coding-system'.
+'set-buffer-file-coding-system'.
 
 ** Server and client
 
-*** emacsclient now obeys string values for `initial-buffer-choice',
+*** emacsclient now obeys string values for 'initial-buffer-choice',
 if it is told to open a new frame without specifying any file to visit
 or expression to evaluate.
 
-*** New option `server-auth-key' specifies a shared server key.
+*** New option 'server-auth-key' specifies a shared server key.
 
 ** Emacs now generates backtraces on fatal errors.
 On encountering a fatal error, Emacs now outputs a textual description
 of the fatal signal, and a short backtrace on platforms like glibc
 that support backtraces.
 
-** `C-x C-q' is now bound to the new minor mode `read-only-mode'.
-This minor mode replaces `toggle-read-only', which is now obsolete.
+** 'C-x C-q' is now bound to the new minor mode 'read-only-mode'.
+This minor mode replaces 'toggle-read-only', which is now obsolete.
 
-** Most `y-or-n' prompts now allow you to scroll the selected window.
-Typing `C-v' or `M-v' at a y-or-n prompt scrolls forward or backward
+** Most 'y-or-n' prompts now allow you to scroll the selected window.
+Typing 'C-v' or 'M-v' at a y-or-n prompt scrolls forward or backward
 respectively, without exiting from the prompt.
 
 ** In the Package Menu, newly-available packages are listed as "new",
 and sorted above the other "available" packages by default.
 
 ** If your Emacs was built from a repository checkout, the new variable
-`emacs-bzr-version' contains information about the bzr revision used.
+'emacs-bzr-version' contains information about the bzr revision used.
 
-** New option `create-lockfiles' specifies usage of lockfiles.
+** New option 'create-lockfiles' specifies usage of lockfiles.
 It defaults to t.  Changing it to nil inhibits the creation of lock
 files (use this with caution).
 
-** New option `enable-remote-dir-locals', if non-nil, allows directory-local
+** New option 'enable-remote-dir-locals', if non-nil, allows directory-local
 variables on remote hosts.
 
 ** The entry for PCL-CVS has been removed from the Tools menu.
@@ -1550,16 +1550,16 @@ The PCL-CVS commands are still available via the 
keyboard.
 ** Using "unibyte: t" in Lisp source files is obsolete.
 Use "coding: raw-text" instead.
 
-** In the buffer made by `M-x report-emacs-bug', the `C-c m' binding
-has been changed to `C-c M-i' (`report-emacs-bug-insert-to-mailer').
+** In the buffer made by 'M-x report-emacs-bug', the 'C-c m' binding
+has been changed to 'C-c M-i' ('report-emacs-bug-insert-to-mailer').
 The previous binding, introduced in Emacs 24.1, was a mistake, because
-`C-c LETTER' bindings are reserved for user customizations.
+'C-c LETTER' bindings are reserved for user customizations.
 
 ** Internationalization
 
 *** New language environment: Persian.
 
-*** New input method `vietnamese-vni'.
+*** New input method 'vietnamese-vni'.
 
 ** Nextstep (GNUstep / OS X) port
 
@@ -1576,54 +1576,54 @@ menu/toolbar.
 *** Non-regexp Isearch now performs "lax" space matching.
 Each sequence of spaces in the supplied search string may match any
 sequence of one or more whitespace characters, as specified by the
-variable `search-whitespace-regexp'.  (This variable is also used by a
+variable 'search-whitespace-regexp'.  (This variable is also used by a
 similar existing feature for regexp Isearch.)
 
-*** New Isearch command `M-s SPC' toggles lax space matching.
+*** New Isearch command 'M-s SPC' toggles lax space matching.
 This applies to both ordinary and regexp Isearch.
 
-*** New option `replace-lax-whitespace'.
-If non-nil, `query-replace' uses flexible whitespace matching too.
+*** New option 'replace-lax-whitespace'.
+If non-nil, 'query-replace' uses flexible whitespace matching too.
 The default is nil.
 
-*** Global `M-s _' starts a symbol (identifier) incremental search,
-and `M-s _' in Isearch toggles symbol search mode.
-`M-s c' in Isearch toggles search case-sensitivity.
+*** Global 'M-s _' starts a symbol (identifier) incremental search,
+and 'M-s _' in Isearch toggles symbol search mode.
+'M-s c' in Isearch toggles search case-sensitivity.
 
 ** Navigation commands
 
-*** New binding `M-g c' for `goto-char'.
+*** New binding 'M-g c' for 'goto-char'.
 
-*** New binding `M-g TAB' for `move-to-column'.
+*** New binding 'M-g TAB' for 'move-to-column'.
 
-*** `M-g TAB' (`move-to-column') prompts for a column number if called
+*** 'M-g TAB' ('move-to-column') prompts for a column number if called
 interactively with no prefix arg.  Previously, it moved to column 1.
 
-** New option `yank-handled-properties' allows processing of text
+** New option 'yank-handled-properties' allows processing of text
 properties on yanked text, in ways that are more general than just
-removing them (as is done by `yank-excluded-properties').
+removing them (as is done by 'yank-excluded-properties').
 
-** New option `delete-trailing-lines' specifies whether
+** New option 'delete-trailing-lines' specifies whether
 M-x delete-trailing-whitespace should delete trailing lines at the end
 of the buffer.  It defaults to t.
 
-** `C-u M-=' now counts lines/words/characters in the entire buffer.
+** 'C-u M-=' now counts lines/words/characters in the entire buffer.
 
-** `C-x 8 RET' is now bound to `insert-char', which is now a command.
-`ucs-insert' is now an obsolete alias for `insert-char'.
+** 'C-x 8 RET' is now bound to 'insert-char', which is now a command.
+'ucs-insert' is now an obsolete alias for 'insert-char'.
 
-** The `z' key no longer has a binding in most special modes.
-It used to be bound to `kill-this-buffer', but `z' is too easy to
+** The 'z' key no longer has a binding in most special modes.
+It used to be bound to 'kill-this-buffer', but 'z' is too easy to
 accidentally type.
 
-** New command `C-x r M-w' (`copy-rectangle-as-kill').
+** New command 'C-x r M-w' ('copy-rectangle-as-kill').
 It copies the region-rectangle as the last rectangle kill.
 
 ** Registers
 
-*** `C-x r +' is now overloaded to invoke `append-to-register'.
+*** 'C-x r +' is now overloaded to invoke 'append-to-register'.
 
-*** New option `register-separator' specifies the register containing
+*** New option 'register-separator' specifies the register containing
 the text to put between collected texts for use with
 M-x append-to-register and M-x prepend-to-register.
 
@@ -1633,58 +1633,58 @@ M-x append-to-register and M-x prepend-to-register.
 ** Common Lisp emulation (CL)
 
 *** CL's main entry is now (require 'cl-lib).
-`cl-lib' is like the old `cl' except that it uses the namespace cleanly;
+'cl-lib' is like the old 'cl' except that it uses the namespace cleanly;
 i.e., all its definitions have the "cl-" prefix (and internal definitions
 use the "cl--" prefix).
 
-If `cl' provided a feature under the name `foo', then `cl-lib'
-provides it under the name `cl-foo' instead; with the exceptions of the
-few `cl' definitions that had to use `foo*' to avoid conflicts with
-pre-existing Elisp entities.  These have been renamed to `cl-foo'
-rather than `cl-foo*'.
+If 'cl' provided a feature under the name 'foo', then 'cl-lib'
+provides it under the name 'cl-foo' instead; with the exceptions of the
+few 'cl' definitions that had to use 'foo*' to avoid conflicts with
+pre-existing Elisp entities.  These have been renamed to 'cl-foo'
+rather than 'cl-foo*'.
 
-The old `cl' is now deprecated and is mainly just a bunch of aliases that
+The old 'cl' is now deprecated and is mainly just a bunch of aliases that
 provide the old, non-prefixed names.  Some exceptions are listed below:
 
-*** `cl-flet' is not like `flet' (which is deprecated).
-Instead it obeys the behavior of Common-Lisp's `flet'.
+*** 'cl-flet' is not like 'flet' (which is deprecated).
+Instead it obeys the behavior of Common-Lisp's 'flet'.
 In particular, in cl-flet function definitions are lexically scoped,
 whereas in flet the scoping is dynamic.
 
-*** `cl-labels' is slightly different from `labels'.
-The difference is that it relies on the `lexical-binding' machinery
-(as opposed to the `lexical-let' machinery used previously) to capture
-definitions in closures, so such closures will only work if `lexical-binding'
+*** 'cl-labels' is slightly different from 'labels'.
+The difference is that it relies on the 'lexical-binding' machinery
+(as opposed to the 'lexical-let' machinery used previously) to capture
+definitions in closures, so such closures will only work if 'lexical-binding'
 is in use.
 
-*** `cl-letf' is not exactly like `letf'.
+*** 'cl-letf' is not exactly like 'letf'.
 The only difference is in details that relate to some deprecated usage
-of `symbol-function' in place forms.
+of 'symbol-function' in place forms.
 
-*** `progv' was rewritten to use the `let' machinery.
+*** 'progv' was rewritten to use the 'let' machinery.
 A side effect is that variables without corresponding values are bound
 to nil rather than being made unbound.
 
-*** The following methods of extending `setf' are obsolete
+*** The following methods of extending 'setf' are obsolete
 (use features from gv.el instead):
-`define-modify-macro' (use `gv-letplace')
-`defsetf' (use `gv-define-simple-setter' or `gv-define-setter')
-`define-setf-expander' (use `gv-define-setter' or `gv-define-expander')
-`get-setf-method' no longer exists (see "Incompatible Lisp Changes")
+'define-modify-macro' (use 'gv-letplace')
+'defsetf' (use 'gv-define-simple-setter' or 'gv-define-setter')
+'define-setf-expander' (use 'gv-define-setter' or 'gv-define-expander')
+'get-setf-method' no longer exists (see "Incompatible Lisp Changes")
 
 ** Diff mode
 
 *** Changes are now highlighted using the same color scheme as in
 modern VCSes.  Deletions are displayed in red (new faces
-`diff-refine-removed' and `smerge-refined-removed', and new definition
-of `diff-removed'), insertions in green (new faces `diff-refine-added'
-and `smerge-refined-added', and new definition of `diff-added').
+'diff-refine-removed' and 'smerge-refined-removed', and new definition
+of 'diff-removed'), insertions in green (new faces 'diff-refine-added'
+and 'smerge-refined-added', and new definition of 'diff-added').
 
-*** The variable `diff-use-changed-face' defines whether to use the
-face `diff-changed', or `diff-removed' and `diff-added' to highlight
+*** The variable 'diff-use-changed-face' defines whether to use the
+face 'diff-changed', or 'diff-removed' and 'diff-added' to highlight
 changes in context diffs.
 
-*** The new command `diff-delete-trailing-whitespace' removes trailing
+*** The new command 'diff-delete-trailing-whitespace' removes trailing
 whitespace introduced by a diff.
 
 ** Ediff now uses the same color scheme as Diff mode.
@@ -1704,22 +1704,22 @@ text based shell).
 
 *** Some user options have been removed, including:
 
-**** `python-indent-string-contents': Strings are never indented.
+**** 'python-indent-string-contents': Strings are never indented.
 
-**** `python-honour-comment-indentation':
+**** 'python-honour-comment-indentation':
 Comments are always considered as indentation markers.
 
-**** `python-continuation-offset': Indentation is automatically
+**** 'python-continuation-offset': Indentation is automatically
 calculated in a pep8 compliant way depending on the context.
 
-**** `python-shell-prompt-alist', `python-shell-continuation-prompt-alist':
+**** 'python-shell-prompt-alist', 'python-shell-continuation-prompt-alist':
 Have no direct mapping as the shell interaction is completely different.
 
-**** `python-python-command', `python-jython-command':
-Replaced by `python-shell-interpreter'.
+**** 'python-python-command', 'python-jython-command':
+Replaced by 'python-shell-interpreter'.
 
-**** `inferior-python-filter-regexp', `python-remove-cwd-from-path',
-`python-pdbtrack-minor-mode-string', `python-source-modes':
+**** 'inferior-python-filter-regexp', 'python-remove-cwd-from-path',
+'python-pdbtrack-minor-mode-string', 'python-source-modes':
 No longer relevant.
 
 *** Some commands have been replaced (old -> new):
@@ -1746,48 +1746,48 @@ and python-shell-switch-to-shell
 
 ** D-Bus
 
-*** New variables `dbus-compiled-version' and `dbus-runtime-version'.
+*** New variables 'dbus-compiled-version' and 'dbus-runtime-version'.
 
 *** The D-Bus object manager interface is implemented.
 
 *** Variables of type :(u)int32 and :(u)int64 accept floating points,
 if their value does not fit into Emacs's integer range.
 
-*** The function `dbus-call-method' is now non-blocking.
-It can be interrupted by `C-g'.  `dbus-call-method-non-blocking' is obsolete.
+*** The function 'dbus-call-method' is now non-blocking.
+It can be interrupted by 'C-g'.  'dbus-call-method-non-blocking' is obsolete.
 
 *** Signals can also be sent as unicast messages.
 
-*** The argument list of `dbus-register-signal' has been extended,
+*** The argument list of 'dbus-register-signal' has been extended,
 according to the new match rule types of D-Bus.
 
-*** `dbus-init-bus' supports private connections.
+*** 'dbus-init-bus' supports private connections.
 
-*** There is a new function `dbus-setenv'.
+*** There is a new function 'dbus-setenv'.
 
-** `desktop-path' no longer includes the "." directory.
+** 'desktop-path' no longer includes the "." directory.
 Desktop files are now located in ~/.emacs.d by default.
 
 ** Dired
 
-*** `dired-do-async-shell-command' executes each file sequentially
-if the command ends in `;' (when operating on multiple files).
+*** 'dired-do-async-shell-command' executes each file sequentially
+if the command ends in ';' (when operating on multiple files).
 Otherwise, it executes the command on each file in parallel.
 
-*** Typing `M-n' in the minibuffer of `dired-do-chmod', `dired-do-chgrp',
-`dired-do-chown', and `dired-do-touch' yanks the attributes of the
+*** Typing 'M-n' in the minibuffer of 'dired-do-chmod', 'dired-do-chgrp',
+'dired-do-chown', and 'dired-do-touch' yanks the attributes of the
 file at point.
 
-*** When the region is active, `m' (`dired-mark'), `u' (`dired-unmark'),
-`DEL' (`dired-unmark-backward'), and `d' (`dired-flag-file-deletion')
+*** When the region is active, 'm' ('dired-mark'), 'u' ('dired-unmark'),
+'DEL' ('dired-unmark-backward'), and 'd' ('dired-flag-file-deletion')
 mark/unmark/flag all files in the active region.
 
-*** The minibuffer default for `=' (`dired-diff') has changed.
+*** The minibuffer default for '=' ('dired-diff') has changed.
 It is now the backup file for the file at point, if one exists.
 In Transient Mark mode the default is the file at the active mark.
 
-*** `M-=' is no longer bound to `dired-backup-diff' in Dired buffers.
-The global binding for `M-=', `count-words-region' is in effect.
+*** 'M-=' is no longer bound to 'dired-backup-diff' in Dired buffers.
+The global binding for 'M-=', 'count-words-region' is in effect.
 
 ** ERC
 
@@ -1797,27 +1797,27 @@ receive a private message or your nickname is mentioned.
 *** ERC will look up server/channel names via auth-source and use any
 channel keys found.
 
-*** New option `erc-lurker-hide-list', similar to `erc-hide-list', but
+*** New option 'erc-lurker-hide-list', similar to 'erc-hide-list', but
 only applies to messages sent by lurkers.
 
 ** reStructuredText mode
 
-*** Keybindings (see `C-c C-h'), TAB indentation, filling and auto-filling,
+*** Keybindings (see 'C-c C-h'), TAB indentation, filling and auto-filling,
 fontification, comment handling, and customization have all been revised
 and improved.
 
-*** Support for `imenu' and `which-function-mode'.
+*** Support for 'imenu' and 'which-function-mode'.
 
 *** The reStructuredText syntax is more closely covered.
 Sphinx support has been improved.
 
-*** `rst-insert-list' inserts new list or continues existing lists.
+*** 'rst-insert-list' inserts new list or continues existing lists.
 
-*** A negative prefix argument always works for `rst-adjust'.
+*** A negative prefix argument always works for 'rst-adjust'.
 
 *** The window configuration is reset after displaying a TOC.
 
-*** The constant `rst-version' describes the rst.el package version.
+*** The constant 'rst-version' describes the rst.el package version.
 
 ** Ruby mode
 
@@ -1827,28 +1827,28 @@ steps definitions.
 
 *** Improved syntax highlighting and indentation.
 
-*** New command `ruby-toggle-block', bound to `C-c {'.
+*** New command 'ruby-toggle-block', bound to 'C-c {'.
 
 *** Some non-standard keybindings/commands have been removed:
 
-**** `ruby-electric-brace'; use `electric-indent-mode' instead.
+**** 'ruby-electric-brace'; use 'electric-indent-mode' instead.
 
-**** `ruby-mark-defun'; use `mark-defun'.
+**** 'ruby-mark-defun'; use 'mark-defun'.
 
-**** `ruby-beginning-of-defun' and `ruby-end-of-defun' are replaced by
-appropriate settings for the variables `beginning-of-defun-function'
-and `end-of-defun-function'.
+**** 'ruby-beginning-of-defun' and 'ruby-end-of-defun' are replaced by
+appropriate settings for the variables 'beginning-of-defun-function'
+and 'end-of-defun-function'.
 
-**** Non-standard keybindings for `backward-kill-word', `comment-region',
-`reindent-then-newline-and-indent' and `newline' have been removed.
+**** Non-standard keybindings for 'backward-kill-word', 'comment-region',
+'reindent-then-newline-and-indent' and 'newline' have been removed.
 
 ** Shell Script mode
 
-*** Pairing of parens/quotes uses `electric-pair-mode' instead of 
skeleton-pair.
+*** Pairing of parens/quotes uses 'electric-pair-mode' instead of 
skeleton-pair.
 
-*** `sh-electric-here-document-mode' now controls auto-insertion of here-docs.
+*** 'sh-electric-here-document-mode' now controls auto-insertion of here-docs.
 
-*** `sh-use-smie' lets you choose a new indentation and navigation code.
+*** 'sh-use-smie' lets you choose a new indentation and navigation code.
 
 ** VHDL mode
 
@@ -1863,48 +1863,48 @@ and `end-of-defun-function'.
 ** Apropos
 
 *** The faces used by Apropos are now directly customizable.
-These faces are named `apropos-symbol', `apropos-keybinding', and so on;
-see the `apropos' Custom group for details.
+These faces are named 'apropos-symbol', 'apropos-keybinding', and so on;
+see the 'apropos' Custom group for details.
 
 *** The old options whose values specified faces to use have been removed
-(i.e. `apropos-symbol-face', `apropos-keybinding-face', `apropos-label-face',
-`apropos-match-face' and `apropos-property-face'.).
+(i.e. 'apropos-symbol-face', 'apropos-keybinding-face', 'apropos-label-face',
+'apropos-match-face' and 'apropos-property-face'.).
 
 ** Buffer Menu
 
 *** This package has been rewritten to use Tabulated List mode.
 
-*** Option `Buffer-menu-buffer+size-width' is now obsolete.
-Use `Buffer-menu-name-width' and `Buffer-menu-size-width' instead.
+*** Option 'Buffer-menu-buffer+size-width' is now obsolete.
+Use 'Buffer-menu-name-width' and 'Buffer-menu-size-width' instead.
 
 ** Calc
 
 *** Algebraic simplification mode is now the default.
 To restrict to the limited simplifications given by the former
-default simplification mode, use `m I'.
+default simplification mode, use 'm I'.
 
 ** Calendar
 
 *** You can customize the header text that appears above each calendar month.
-See the variable `calendar-month-header'.
+See the variable 'calendar-month-header'.
 
-*** New LaTeX calendar style, produced by `cal-tex-cursor-week2-summary'.
+*** New LaTeX calendar style, produced by 'cal-tex-cursor-week2-summary'.
 
 *** The calendars produced by cal-html include holidays.
-Customize `cal-html-holidays' to change this.
+Customize 'cal-html-holidays' to change this.
 
 ** CEDET
 
 *** The major modes from the parser generators "Bovine" and "Wisent"
 are now properly integrated in Emacs.  The file suffixes ".by" and ".wy"
-are in `auto-mode-alist', and the corresponding manuals are included.
+are in 'auto-mode-alist', and the corresponding manuals are included.
 
 *** EDE
 
 **** Menu support for the "Configuration" feature.  This allows users to
 choose the active configuration (such as debug or install) from the menu.
 
-**** New command `ede-set' to interactively set project-local variables.
+**** New command 'ede-set' to interactively set project-local variables.
 
 **** Support for compiling, debugging, and running in "generic" projects.
 
@@ -1950,24 +1950,24 @@ mode (like Java).
 **** Support for merging tables from multiple related modes, such as
 default -> c++ -> arduino.
 
-** Compile has a new option `compilation-always-kill'.
+** Compile has a new option 'compilation-always-kill'.
 
 ** Customize
 
-*** `custom-reset-button-menu' now defaults to t.
+*** 'custom-reset-button-menu' now defaults to t.
 
-*** Non-option variables are never matched in `customize-apropos' and
-`customize-apropos-options' (i.e., the prefix argument does nothing for
+*** Non-option variables are never matched in 'customize-apropos' and
+'customize-apropos-options' (i.e., the prefix argument does nothing for
 these commands now).
 
 ** Term
 
-*** The variables `term-default-fg-color' and `term-default-bg-color'
-are now deprecated in favor of the customizable face `term'.
+*** The variables 'term-default-fg-color' and 'term-default-bg-color'
+are now deprecated in favor of the customizable face 'term'.
 
 *** You can customize how to display ANSI terminal colors and styles
-by customizing the corresponding `term-color-<COLOR>',
-`term-color-underline' and `term-color-bold' faces.
+by customizing the corresponding 'term-color-<COLOR>',
+'term-color-underline' and 'term-color-bold' faces.
 
 ** Tramp
 
@@ -1977,86 +1977,86 @@ by customizing the corresponding `term-color-<COLOR>',
 
 ** URL
 
-*** Structs made by `url-generic-parse-url' have nil `attributes' slot.
+*** Structs made by 'url-generic-parse-url' have nil 'attributes' slot.
 Previously, this slot stored semicolon-separated attribute-value pairs
 appended to some imap URLs, but this is not compatible with RFC 3986.
-So now the `filename' slot stores the entire path and query components,
-and the `attributes' slot is always nil.
+So now the 'filename' slot stores the entire path and query components,
+and the 'attributes' slot is always nil.
 
-*** New function `url-encode-url' for encoding a URI string.
-The `url-retrieve' function now uses this to encode its URL argument,
+*** New function 'url-encode-url' for encoding a URI string.
+The 'url-retrieve' function now uses this to encode its URL argument,
 in case that is not properly encoded.
 
 ** notifications.el supports now version 1.2 of the Notifications API.
-The function `notifications-get-capabilities' returns the supported
+The function 'notifications-get-capabilities' returns the supported
 server properties.
 
 ** Flymake uses fringe bitmaps to indicate errors and warnings.
-See `flymake-fringe-indicator-position', `flymake-error-bitmap' and
-`flymake-warning-bitmap'.
+See 'flymake-fringe-indicator-position', 'flymake-error-bitmap' and
+'flymake-warning-bitmap'.
 
-** The FFAP option `ffap-url-unwrap-remote' can now be a list of strings,
+** The FFAP option 'ffap-url-unwrap-remote' can now be a list of strings,
 specifying URL types that should be converted to remote file names at
 the FFAP prompt.  The default is now '("ftp").
 
-** New Ibuffer `derived-mode' filter, bound to `/ M'.
-The old binding for `/ M' (filter by used-mode) is now bound to `/ m'.
+** New Ibuffer 'derived-mode' filter, bound to '/ M'.
+The old binding for '/ M' (filter by used-mode) is now bound to '/ m'.
 
-** New option `mouse-avoidance-banish-position' specifies where the
-`banish' mouse avoidance setting moves the mouse.
+** New option 'mouse-avoidance-banish-position' specifies where the
+'banish' mouse avoidance setting moves the mouse.
 
-** In Perl mode, new option `perl-indent-parens-as-block' causes non-block
+** In Perl mode, new option 'perl-indent-parens-as-block' causes non-block
 closing brackets to be aligned with the line of the opening bracket.
 
-** In Proced mode, new command `proced-renice' renices marked processes.
+** In Proced mode, new command 'proced-renice' renices marked processes.
 
-** New option `async-shell-command-buffer' specifies the buffer to use
-for a new asynchronous `shell-command' when the default output buffer
-`*Async Shell Command*' is already in use.
+** New option 'async-shell-command-buffer' specifies the buffer to use
+for a new asynchronous 'shell-command' when the default output buffer
+'*Async Shell Command*' is already in use.
 
-** SQL mode has a new option `sql-db2-escape-newlines'.
+** SQL mode has a new option 'sql-db2-escape-newlines'.
 If non-nil, newlines sent to the command interpreter will be escaped
 by a backslash.  The default does not escape the newlines and assumes
 that the sql statement will be terminated by a semicolon.
 
-** New command `tabulated-list-sort', bound to `S' in Tabulated List mode
+** New command 'tabulated-list-sort', bound to 'S' in Tabulated List mode
 (and modes that derive from it), sorts the column at point, or the Nth
 column if a numeric prefix argument is given.
 
-** `which-func-modes' now defaults to t, so Which Function mode, when
+** 'which-func-modes' now defaults to t, so Which Function mode, when
 enabled, applies to all applicable major modes.
 
-** `winner-mode-hook' now runs when the mode is disabled, as well as when
+** 'winner-mode-hook' now runs when the mode is disabled, as well as when
 it is enabled.
 
 ** Follow mode no longer works by using advice.
-The option `follow-intercept-processes' has been removed.
+The option 'follow-intercept-processes' has been removed.
 
-** `javascript-generic-mode' is now an obsolete alias for `js-mode'.
+** 'javascript-generic-mode' is now an obsolete alias for 'js-mode'.
 
 ** Hooks renamed to avoid obsolete "-hooks" suffix:
-*** semantic-lex-reset-hooks -> semantic-lex-reset-functions
-*** semantic-change-hooks -> semantic-change-functions
-*** semantic-edits-new-change-hooks -> semantic-edits-new-change-functions
-*** semantic-edits-delete-change-hooks -> 
semantic-edits-delete-change-functions
-*** semantic-edits-reparse-change-hooks -> 
semantic-edits-reparse-change-functions
-*** semanticdb-save-database-hooks -> semanticdb-save-database-functions
-*** c-prepare-bug-report-hooks -> c-prepare-bug-report-hook
-*** rcirc-sentinel-hooks -> rcirc-sentinel-functions
-*** rcirc-receive-message-hooks -> rcirc-receive-message-functions
-*** rcirc-activity-hooks -> rcirc-activity-functions
-*** rcirc-print-hooks -> rcirc-print-functions
-*** dbus-event-error-hooks -> dbus-event-error-functions
-*** eieio-pre-method-execution-hooks -> eieio-pre-method-execution-functions
-*** checkdoc-style-hooks -> checkdoc-style-functions
-*** checkdoc-comment-style-hooks -> checkdoc-comment-style-functions
-*** archive-extract-hooks -> archive-extract-hook
-*** filesets-cache-fill-content-hooks -> filesets-cache-fill-content-hook
-*** hfy-post-html-hooks -> hfy-post-html-hook
-*** nndiary-request-create-group-hooks -> 
nndiary-request-create-group-functions
-*** nndiary-request-update-info-hooks -> nndiary-request-update-info-functions
-*** nndiary-request-accept-article-hooks -> 
nndiary-request-accept-article-functions
-*** gnus-subscribe-newsgroup-hooks -> gnus-subscribe-newsgroup-functions
+*** 'semantic-lex-reset-hooks' -> 'semantic-lex-reset-functions'
+*** 'semantic-change-hooks' -> 'semantic-change-functions'
+*** 'semantic-edits-new-change-hooks' -> 'semantic-edits-new-change-functions'
+*** 'semantic-edits-delete-change-hooks' -> 
'semantic-edits-delete-change-functions'
+*** 'semantic-edits-reparse-change-hooks' -> 
'semantic-edits-reparse-change-functions'
+*** 'semanticdb-save-database-hooks' -> 'semanticdb-save-database-functions'
+*** 'c-prepare-bug-report-hooks' -> 'c-prepare-bug-report-hook'
+*** 'rcirc-sentinel-hooks' -> 'rcirc-sentinel-functions'
+*** 'rcirc-receive-message-hooks' -> 'rcirc-receive-message-functions'
+*** 'rcirc-activity-hooks' -> 'rcirc-activity-functions'
+*** 'rcirc-print-hooks' -> 'rcirc-print-functions'
+*** 'dbus-event-error-hooks' -> 'dbus-event-error-functions'
+*** 'eieio-pre-method-execution-hooks' -> 
'eieio-pre-method-execution-functions'
+*** 'checkdoc-style-hooks' -> 'checkdoc-style-functions'
+*** 'checkdoc-comment-style-hooks' -> 'checkdoc-comment-style-functions'
+*** 'archive-extract-hooks' -> 'archive-extract-hook'
+*** 'filesets-cache-fill-content-hooks' -> 'filesets-cache-fill-content-hook'
+*** 'hfy-post-html-hooks' -> 'hfy-post-html-hook'
+*** 'nndiary-request-create-group-hooks' -> 
'nndiary-request-create-group-functions'
+*** 'nndiary-request-update-info-hooks' -> 
'nndiary-request-update-info-functions'
+*** 'nndiary-request-accept-article-hooks' -> 
'nndiary-request-accept-article-functions'
+*** 'gnus-subscribe-newsgroup-hooks' -> 'gnus-subscribe-newsgroup-functions'
 
 ** Obsolete packages
 
@@ -2074,44 +2074,44 @@ inefficiency, and not namespace-clean.
 
 * Incompatible Lisp Changes in Emacs 24.3
 
-** Docstrings starting with `*' no longer indicate user options.
-Only variables defined using `defcustom' are considered user options.
-The function `user-variable-p' is now an obsolete alias for
-`custom-variable-p'.
+** Docstrings starting with '*' no longer indicate user options.
+Only variables defined using 'defcustom' are considered user options.
+The function 'user-variable-p' is now an obsolete alias for
+'custom-variable-p'.
 
-** The return values of `defalias', `defun' and `defmacro' have changed,
-and are now undefined.  For backwards compatibility, `defun' and
-`defmacro' currently return the name of the newly defined
+** The return values of 'defalias', 'defun' and 'defmacro' have changed,
+and are now undefined.  For backwards compatibility, 'defun' and
+'defmacro' currently return the name of the newly defined
 function/macro, but this should not be relied upon.
 
-** `random' by default now returns a different random sequence in
-every Emacs run.  Use `(random S)', where S is a string, to set the
+** 'random' by default now returns a different random sequence in
+every Emacs run.  Use '(random S)', where S is a string, to set the
 random seed to a value based on S, in order to get a repeatable
 sequence in later calls.
 
-** If the NEWTEXT arg to `replace-match' contains a substring "\?",
+** If the NEWTEXT arg to 'replace-match' contains a substring "\?",
 that substring is inserted literally even if the LITERAL arg is
 non-nil, instead of causing an error to be signaled.
 
-** `select-window' now always makes the window's buffer current.
+** 'select-window' now always makes the window's buffer current.
 It does so even if the window was selected before.
 
-** The function `x-select-font' can return a font spec, instead of a
+** The function 'x-select-font' can return a font spec, instead of a
 font name as a string.  Whether it returns a font spec or a font name
 depends on the graphical library.
 
-** `face-spec-set' no longer sets frame-specific attributes when the
+** 'face-spec-set' no longer sets frame-specific attributes when the
 third argument is a frame (that usage was obsolete since Emacs 22.2).
 
-** `set-buffer-multibyte' now signals an error in narrowed buffers.
+** 'set-buffer-multibyte' now signals an error in narrowed buffers.
 
-** The CL package's `get-setf-method' function no longer exists.
+** The CL package's 'get-setf-method' function no longer exists.
 Generalized variables are now part of core Emacs Lisp, and implemented
 differently to the way cl.el used to do it.  It is not possible to
-define a compatible replacement for `get-setf-method'.  See the file
+define a compatible replacement for 'get-setf-method'.  See the file
 gv.el for internal details of the new implementation.
 
-** The arguments of `dbus-register-signal' are no longer just strings,
+** The arguments of 'dbus-register-signal' are no longer just strings,
 but keywords or keyword-string pairs.  The old argument list will
 still be supported for Emacs 24.x.
 
@@ -2120,55 +2120,55 @@ Some Lisp symbols have been renamed to correct their 
spelling,
 or to be more consistent with standard Emacs terminology.
 
 *** Renamed functions
-**** hangul-input-method-inactivate -> hangul-input-method-deactivate
-**** inactivate-input-method -> deactivate-input-method
-**** quail-inactivate -> quail-deactivate
-**** robin-inactivate -> robin-deactivate
-**** viper-inactivate-input-method -> viper-deactivate-input-method
-**** viper-inactivate-input-method-action ->
-     viper-deactivate-input-method-action
-**** ucs-input-inactivate -> ucs-input-deactivate
+**** 'hangul-input-method-inactivate' -> 'hangul-input-method-deactivate'
+**** 'inactivate-input-method' -> 'deactivate-input-method'
+**** 'quail-inactivate' -> 'quail-deactivate'
+**** 'robin-inactivate' -> 'robin-deactivate'
+**** 'viper-inactivate-input-method' -> 'viper-deactivate-input-method'
+**** 'viper-inactivate-input-method-action' ->
+     'viper-deactivate-input-method-action'
+**** 'ucs-input-inactivate' -> 'ucs-input-deactivate'
 
 *** Renamed hooks
 The old hooks are still supported for backward compatibility, but they
 are deprecated and will be removed eventually.
-**** input-method-inactivate-hook -> input-method-deactivate-hook
-**** robin-inactivate-hook -> robin-deactivate-hook
-**** quail-inactivate-hook -> quail-deactivate-hook
+**** 'input-method-inactivate-hook' -> 'input-method-deactivate-hook'
+**** 'robin-inactivate-hook' -> 'robin-deactivate-hook'
+**** 'quail-inactivate-hook' -> 'quail-deactivate-hook'
 
 *** Renamed variables
-**** follow-deactive-menu -> follow-inactive-menu
-**** inactivate-current-input-method-function ->
-     deactivate-current-input-method-function
+**** 'follow-deactive-menu' -> 'follow-inactive-menu'
+**** 'inactivate-current-input-method-function' ->
+     'deactivate-current-input-method-function'
 
 ** Some obsolete functions, variables, and faces have been removed:
-*** `last-input-char', `last-command-char', `unread-command-char'
-*** `facemenu-unlisted-faces'
-*** `rmail-decode-mime-charset'
-*** `iswitchb-read-buffer'
-*** `sc-version', `sc-submit-bug-report'
-*** `set-char-table-default'
-*** `string-to-sequence' (use `string-to-list' or `string-to-vector')
-*** `compile-internal'
-*** `modeline'
-*** `mode-line-inverse-video'
-*** `follow-mode-off-hook'
-*** `cvs-commit-buffer-require-final-newline'
-(use `log-edit-require-final-newline' instead)
-*** `cvs-changelog-full-paragraphs'
-(use `log-edit-changelog-full-paragraphs' instead)
-*** `cvs-diff-ignore-marks', `cvs-diff-buffer-name'
-*** `vc-ignore-vc-files' (use `vc-handled-backends' instead)
-*** `vc-master-templates' (use `vc-handled-backends' instead)
-*** `vc-checkout-carefully'
+*** 'last-input-char', 'last-command-char', 'unread-command-char'
+*** 'facemenu-unlisted-faces'
+*** 'rmail-decode-mime-charset'
+*** 'iswitchb-read-buffer'
+*** 'sc-version', 'sc-submit-bug-report'
+*** 'set-char-table-default'
+*** 'string-to-sequence' (use 'string-to-list' or 'string-to-vector')
+*** 'compile-internal'
+*** 'modeline'
+*** 'mode-line-inverse-video'
+*** 'follow-mode-off-hook'
+*** 'cvs-commit-buffer-require-final-newline'
+(use 'log-edit-require-final-newline' instead)
+*** 'cvs-changelog-full-paragraphs'
+(use 'log-edit-changelog-full-paragraphs' instead)
+*** 'cvs-diff-ignore-marks', 'cvs-diff-buffer-name'
+*** 'vc-ignore-vc-files' (use 'vc-handled-backends' instead)
+*** 'vc-master-templates' (use 'vc-handled-backends' instead)
+*** 'vc-checkout-carefully'
 
 
 * Lisp Changes in Emacs 24.3
 
 ** CL-style generalized variables are now in core Elisp.
-`setf' is autoloaded; `push' and `pop' accept generalized variables.
-You can define your own generalized variables using `gv-define-simple-setter',
-`gv-define-setter', etc.
+'setf' is autoloaded; 'push' and 'pop' accept generalized variables.
+You can define your own generalized variables using 'gv-define-simple-setter',
+'gv-define-setter', etc.
 
 ** Emacs tries to macroexpand interpreted (non-compiled) files during load.
 This can significantly speed up execution of non-byte-compiled code,
@@ -2183,108 +2183,108 @@ Try M-x profiler-start, do some work, and then call 
M-x profiler-report.
 When finished, use M-x profiler-stop.  The sampling rate can be based on
 CPU time or memory allocations.
 
-** `defun' also accepts a (declare DECLS) form, like `defmacro'.
-The interpretation of the DECLS is determined by `defun-declarations-alist'.
+** 'defun' also accepts a (declare DECLS) form, like 'defmacro'.
+The interpretation of the DECLS is determined by 'defun-declarations-alist'.
 
-** New macros `setq-local' and `defvar-local'.
+** New macros 'setq-local' and 'defvar-local'.
 
 ** Face underlining can now use a wave.
 
-** `read-regexp' has a new argument HISTORY; the first argument PROMPT
-of `read-regexp' accepts a string ending with a colon and space, and its
-second argument DEFAULTS can be a list of strings accessible via `M-n'
+** 'read-regexp' has a new argument HISTORY; the first argument PROMPT
+of 'read-regexp' accepts a string ending with a colon and space, and its
+second argument DEFAULTS can be a list of strings accessible via 'M-n'
 in the minibuffer ahead of other hard-coded useful regexp-related values.
-More commands use `read-regexp' now to read their regexp arguments.
+More commands use 'read-regexp' now to read their regexp arguments.
 
 ** Completion
 
-*** New function `completion-table-with-quoting' to handle completion
+*** New function 'completion-table-with-quoting' to handle completion
 in the presence of quoting, such as file completion in shell buffers.
 
-*** New function `completion-table-subvert' to use an existing completion
+*** New function 'completion-table-subvert' to use an existing completion
 table, but with a different prefix.
 
 ** Debugger
 
-*** New error type and new function `user-error'.
+*** New error type and new function 'user-error'.
 These do not trigger the debugger.
 
-*** New option `debugger-bury-or-kill', saying what to do with the
+*** New option 'debugger-bury-or-kill', saying what to do with the
 debugger buffer when exiting debug.
 
-*** Set `debug-on-message' to enter the debugger when a certain
+*** Set 'debug-on-message' to enter the debugger when a certain
 message is displayed in the echo area.  This can be useful when trying
 to work out which code is doing something.
 
-*** New var `inhibit-debugger', automatically set to prevent accidental
+*** New var 'inhibit-debugger', automatically set to prevent accidental
 recursive invocations.
 
 ** Window handling
 
-*** New command `fit-frame-to-buffer' adjusts the frame height to
+*** New command 'fit-frame-to-buffer' adjusts the frame height to
 fit the contents.
 
-*** The command `fit-window-to-buffer' can adjust the frame height
-if the new option `fit-frame-to-buffer' is non-nil.
+*** The command 'fit-window-to-buffer' can adjust the frame height
+if the new option 'fit-frame-to-buffer' is non-nil.
 
-*** New macro `with-temp-buffer-window', similar to
-`with-output-to-temp-buffer'.
+*** New macro 'with-temp-buffer-window', similar to
+'with-output-to-temp-buffer'.
 
-*** `temp-buffer-resize-mode' no longer resizes windows that have been
+*** 'temp-buffer-resize-mode' no longer resizes windows that have been
 reused.
 
-*** New option `switch-to-buffer-preserve-window-point' to restore a
+*** New option 'switch-to-buffer-preserve-window-point' to restore a
 window's point when switching buffers.
 
-*** New display action alist entries `window-height' and `window-width'
-specify the size of new windows created by `display-buffer'.
+*** New display action alist entries 'window-height' and 'window-width'
+specify the size of new windows created by 'display-buffer'.
 
-*** New display action alist entry `pop-up-frame-parameters', if
+*** New display action alist entry 'pop-up-frame-parameters', if
 non-nil, specifies frame parameters to give any newly-created frame.
 
-*** New display action alist entry `inhibit-switch-frame', if non-nil,
+*** New display action alist entry 'inhibit-switch-frame', if non-nil,
 tells display action functions to avoid changing which frame is
 selected.
 
-*** New display action alist entry `previous-window', if non-nil,
-specifies window to reuse in `display-buffer-in-previous-window'.
+*** New display action alist entry 'previous-window', if non-nil,
+specifies window to reuse in 'display-buffer-in-previous-window'.
 
-*** New display action functions `display-buffer-below-selected',
-and `display-buffer-in-previous-window'.
+*** New display action functions 'display-buffer-below-selected',
+and 'display-buffer-in-previous-window'.
 
-*** The functions `get-lru-window', `get-mru-window' and `get-largest-window'
+*** The functions 'get-lru-window', 'get-mru-window' and 'get-largest-window'
 now accept a third argument to avoid choosing the selected window.
 
-*** Additional values recognized for option `window-combination-limit'.
+*** Additional values recognized for option 'window-combination-limit'.
 
 *** The following variables are obsolete, as they can be replaced by
-appropriate entries in the `display-buffer-alist' function introduced
+appropriate entries in the 'display-buffer-alist' function introduced
 in Emacs 24.1:
-**** `dired-shrink-to-fit'
-**** `display-buffer-reuse-frames'
-**** `display-buffer-function'
-**** `special-display-buffer-names'
-**** `special-display-frame-alist'
-**** `special-display-function'
-**** `special-display-regexps'
+**** 'dired-shrink-to-fit'
+**** 'display-buffer-reuse-frames'
+**** 'display-buffer-function'
+**** 'special-display-buffer-names'
+**** 'special-display-frame-alist'
+**** 'special-display-function'
+**** 'special-display-regexps'
 
 ** Time
 
-*** `current-time-string' no longer requires that its argument's year
+*** 'current-time-string' no longer requires that its argument's year
 must be in the range 1000..9999.  It now works with any year supported
 by the underlying C implementation.
 
-*** `current-time' now returns extended-format time stamps
+*** 'current-time' now returns extended-format time stamps
 (HIGH LOW USEC PSEC), where the new PSEC slot specifies picoseconds.
 PSEC is typically a multiple of 1000 on current machines.  Other
-functions that use this format, such as `file-attributes' and
-`format-time-string', have been changed accordingly.  Old-format time
+functions that use this format, such as 'file-attributes' and
+'format-time-string', have been changed accordingly.  Old-format time
 stamps are still accepted.
 
-*** The format of timers in `timer-list' and `timer-idle-list' is now
+*** The format of timers in 'timer-list' and 'timer-idle-list' is now
 [TRIGGERED-P HI-SECS LO-SECS USECS REPEAT-DELAY FUNCTION ARGS IDLE-DELAY 
PSECS].
 The PSECS slot is new, and uses picosecond resolution.  It can be
-accessed via the new `timer--psecs' accessor.
+accessed via the new 'timer--psecs' accessor.
 
 *** Last-modified time stamps in undo lists now are of the form
 (t HI-SECS LO-SECS USECS PSECS) instead of (t HI-SECS . LO-SECS).
@@ -2293,7 +2293,7 @@ accessed via the new `timer--psecs' accessor.
 
 *** Improved security when handling persistent objects:
 
-**** `eieio-persistent-read' now features optional arguments for specifying
+**** 'eieio-persistent-read' now features optional arguments for specifying
 the class to load, as well as a flag stating whether subclasses are allowed;
 if provided, other classes will be rejected by the reader.  For
 compatibility with existing code, if the class is omitted only a
@@ -2305,74 +2305,74 @@ without evaluation of suspicious code.
 **** All slots that contain objects must have a :type.  Slots with lists
 of objects must use a new type predicate for a list of an object type.
 
-*** Support for `find-function' and similar utilities, through the addition
+*** Support for 'find-function' and similar utilities, through the addition
 of filename support to generated symbols.
 
 ** Floating point functions now always return special values like NaN,
 instead of signaling errors, if given invalid args; e.g., (log -1.0).
 Previously, they returned NaNs on some platforms but signaled errors
-on others.  The affected functions are acos, asin, tan, exp, expt,
-log, log10, sqrt, and mod.
+on others.  The affected functions are 'acos', 'asin', 'tan', 'exp', 'expt',
+'log', 'log10', 'sqrt', and 'mod'.
 
-** New fringe bitmap `exclamation-mark'.
+** New fringe bitmap 'exclamation-mark'.
 
 ** Miscellaneous changes to special forms and macros
 
-*** `defun' and `defmacro' are now macros rather than special forms.
+*** 'defun' and 'defmacro' are now macros rather than special forms.
 
-*** `kbd' is now a function rather than a macro.
+*** 'kbd' is now a function rather than a macro.
 
 ** Miscellaneous new functions
 
-*** `set-temporary-overlay-map' sets up a temporary keymap that
+*** 'set-temporary-overlay-map' sets up a temporary keymap that
 takes precedence over most other maps for a short while (normally one key).
 
-*** `autoloadp' tests if its argument is an autoloaded object.
+*** 'autoloadp' tests if its argument is an autoloaded object.
 
-*** `autoload-do-load' performs the autoloading operation.
+*** 'autoload-do-load' performs the autoloading operation.
 
-*** `buffer-narrowed-p' tests if the buffer is narrowed.
+*** 'buffer-narrowed-p' tests if the buffer is narrowed.
 
-*** `file-name-base' returns a file name sans directory and extension.
+*** 'file-name-base' returns a file name sans directory and extension.
 
-*** `function-get' fetches a function property, following aliases.
+*** 'function-get' fetches a function property, following aliases.
 
-*** `posnp' tests if an object is a `posn'.
+*** 'posnp' tests if an object is a 'posn'.
 
-*** `system-users' returns the user names on the system.
+*** 'system-users' returns the user names on the system.
 
-*** `system-groups' returns the group names on the system.
+*** 'system-groups' returns the group names on the system.
 
-*** `tty-top-frame' returns the topmost frame of a text terminal.
+*** 'tty-top-frame' returns the topmost frame of a text terminal.
 
 ** The following functions and variables are obsolete:
-*** `automount-dir-prefix' (use `directory-abbrev-alist')
-*** `buffer-has-markers-at'
-*** `macro-declaration-function' (use `macro-declarations-alist')
-*** `window-system-version' (provides no useful information)
-*** `dired-pop-to-buffer' (use `dired-mark-pop-up')
-*** `query-replace-interactive'
-*** `font-list-limit' (has had no effect since Emacs < 23)
+*** 'automount-dir-prefix' (use 'directory-abbrev-alist')
+*** 'buffer-has-markers-at'
+*** 'macro-declaration-function' (use 'macro-declarations-alist')
+*** 'window-system-version' (provides no useful information)
+*** 'dired-pop-to-buffer' (use 'dired-mark-pop-up')
+*** 'query-replace-interactive'
+*** 'font-list-limit' (has had no effect since Emacs < 23)
 
 
 * Changes in Emacs 24.3 on Non-Free Operating Systems
 
 ** Cygwin builds can use the native MS Windows user interface.
-Pass `--with-w32' to configure.  The default remains the X11 interface.
+Pass '--with-w32' to configure.  The default remains the X11 interface.
 
 ** Two new functions are available in Cygwin builds:
-`cygwin-convert-file-name-from-windows' and
-`cygwin-convert-file-name-to-windows'.  These functions allow Lisp
+'cygwin-convert-file-name-from-windows' and
+'cygwin-convert-file-name-to-windows'.  These functions allow Lisp
 code to access the Cygwin file-name mapping machinery to convert
 between Cygwin and Windows-native file and directory names.
 
 ** When invoked with the -nw switch to run on the Windows text-mode terminal,
-Emacs now supports `mouse-highlight', help-echo (in the echo area), and
-`mouse-autoselect-window'.
+Emacs now supports 'mouse-highlight', help-echo (in the echo area), and
+'mouse-autoselect-window'.
 
 ** On MS Windows Vista and later Emacs now supports symbolic links.
 
-** On MS Windows, you can pass `--without-libxml2' to configure.bat to omit
+** On MS Windows, you can pass '--without-libxml2' to configure.bat to omit
 support for libxml2, even if its presence is detected.
 
 ** On OS X, the Nextstep port requires Mac OS X 10.4 or later.
@@ -2396,23 +2396,23 @@ also depend on Gtk+.  You can disable them with 
--without-rsvg and
 ** Emacs can be compiled with GnuTLS support.
 This happens by default if a suitably recent version of the library is
 found at build time.  To prevent this, use the configure option
-`--without-gnutls'.  See below for GnuTLS features.
+'--without-gnutls'.  See below for GnuTLS features.
 
 ** Emacs can be compiled with SELinux support.
 This happens by default if a suitably recent version of the library is
 found at build time.  To prevent this, use the configure option
-`--without-selinux'.  See below for SELinux features.
+'--without-selinux'.  See below for SELinux features.
 
 ** Emacs can be compiled with ImageMagick support.
 This happens by default if a suitably recent version of the library is
 found at build time.  To prevent this, use the configure option
-`--without-imagemagick'.  See below for ImageMagick features.
+'--without-imagemagick'.  See below for ImageMagick features.
 This feature is not available for the Nextstep or MS ports.
 
 ** Emacs can be compiled with libxml2 support.
 This happens by default if a suitably recent version of the library is
 found at build time.  To prevent this, use the configure option
-`--without-xml2'.  See below for libxml2 features.
+'--without-xml2'.  See below for libxml2 features.
 
 ** By default, the installed Info and man pages are compressed.
 You can disable this by configuring --without-compress-info.
@@ -2431,9 +2431,9 @@ This is only useful for Emacs developers to debug certain 
types of bugs.
 This is not a new feature; only the configure flag is new.
 
 ** The standalone programs digest-doc and sorted-doc are removed.
-Emacs now uses Lisp commands `doc-file-to-man' and `doc-file-to-info'.
+Emacs now uses Lisp commands 'doc-file-to-man' and 'doc-file-to-info'.
 
-** The standalone program `fakemail' is removed.
+** The standalone program 'fakemail' is removed.
 If you need it, feedmail.el provides a superset of the functionality.
 
 
@@ -2443,7 +2443,7 @@ If you need it, feedmail.el provides a superset of the 
functionality.
 command line arguments, and the EMACS_UNIBYTE environment variable, no
 longer have any effect.  (They were declared obsolete in Emacs 23.)
 
-** New command line option `--no-site-lisp' removes site-lisp directories
+** New command line option '--no-site-lisp' removes site-lisp directories
 from load-path.  -Q now implies this.  This option does not affect the
 EMACSLOADPATH environment variable (and hence has no effect for
 Nextstep builds).
@@ -2453,35 +2453,35 @@ Nextstep builds).
 
 ** Completion
 
-*** Many packages now use the `completion-at-point' command,
+*** Many packages now use the 'completion-at-point' command,
 rather than implementing separate completion commands.
 
-*** `completion-at-point' now handles tags and semantic completion.
+*** 'completion-at-point' now handles tags and semantic completion.
 
 *** Completion in a non-minibuffer now tries to detect the end of completion
 and pops down the *Completions* buffer accordingly.
 
-*** New option `completion-cycle-threshold' allows completion cycling.
+*** New option 'completion-cycle-threshold' allows completion cycling.
 
-*** New option `completion-category-overrides' for overriding the
+*** New option 'completion-category-overrides' for overriding the
 default completion style in certain circumstances.
 
-*** New completion style `substring'.
+*** New completion style 'substring'.
 
-*** Completion of buffer names uses `substring' completion by default.
+*** Completion of buffer names uses 'substring' completion by default.
 
-*** The option `widget-complete-field' has been removed.
+*** The option 'widget-complete-field' has been removed.
 
 ** Mail changes
 
 *** The first time you try sending mail, Emacs asks for a mail method.
-This is implemented by a new default for `send-mail-function', which
-is `sendmail-query-once'.  This offers to use the smtpmail package, or
+This is implemented by a new default for 'send-mail-function', which
+is 'sendmail-query-once'.  This offers to use the smtpmail package, or
 to use the old defaults relying on external mail facilities
-(`sendmail-send-it' on GNU/Linux and other Unix-like systems, and
-`mailclient-send-it' on Windows).
+('sendmail-send-it' on GNU/Linux and other Unix-like systems, and
+'mailclient-send-it' on Windows).
 
-*** Typing `C-c m' in the buffer made by `M-x report-emacs-bug'
+*** Typing 'C-c m' in the buffer made by 'M-x report-emacs-bug'
 transfers the report to your desktop's preferred mail client, if there
 is one.  This uses either the "xdg-email" utility, or Mac OS's "open"
 command.
@@ -2491,7 +2491,7 @@ and Mail mode changes
 
 ** Emacs server and client changes
 
-*** New option `server-port' specifies the port for TCP Emacs servers.
+*** New option 'server-port' specifies the port for TCP Emacs servers.
 
 *** New emacsclient argument -q/--quiet suppresses some status messages.
 
@@ -2514,13 +2514,13 @@ scripts.  The display reordering is a "full 
bidirectionality" class
 implementation of the Unicode Bidirectional Algorithm (UBA).  Buffers
 with no RTL text should look exactly the same as before.
 
-**** New buffer-local variable `bidi-display-reordering'.
+**** New buffer-local variable 'bidi-display-reordering'.
 To disable display reordering in a buffer, change this to nil.
 
-**** New buffer-local variable `bidi-paragraph-direction'.
+**** New buffer-local variable 'bidi-paragraph-direction'.
 If nil (the default), Emacs determines the base direction of each
 paragraph from its text, as specified by the UBA.  Setting the value
-to `right-to-left' or `left-to-right' forces a base direction on each
+to 'right-to-left' or 'left-to-right' forces a base direction on each
 paragraph.
 
 Paragraphs with right-to-left base direction are displayed starting at
@@ -2528,18 +2528,18 @@ the right window edge.
 
 *** Enhanced support for characters with no glyphs in available fonts,
 or, on text terminals, characters that cannot be encoded by the
-terminal coding system.  The new option `glyphless-char-display-control'
+terminal coding system.  The new option 'glyphless-char-display-control'
 specifies how to display them: as a hexadecimal code in a box, a thin
 1-pixel space, an empty box, etc.
 
 *** New input methods for Farsi and Bulgarian
 (farsi-isiri-9147, farsi-transliterate-banan, bulgarian-alt-phonetic).
 
-*** `nobreak-char-display' now also highlights Unicode hyphen chars
+*** 'nobreak-char-display' now also highlights Unicode hyphen chars
 (U+2010 and U+2011).
 
 *** New Hebrew translation of the Emacs Tutorial.
-Type `C-u C-h t' to choose it in case your language setup doesn't
+Type 'C-u C-h t' to choose it in case your language setup doesn't
 automatically select it.
 
 ** An Emacs Lisp package manager is now included.
@@ -2549,36 +2549,36 @@ from a package repository at https://elpa.gnu.org.
 *** M-x list-packages shows a list of packages, which can be
 selected for installation.
 
-*** New command `describe-package', bound to `C-h P'.
+*** New command 'describe-package', bound to 'C-h P'.
 
 *** By default, all installed packages are loaded automatically when
-Emacs starts up.  To disable this, set `package-enable-at-startup' to
-nil.  To specify the packages to load, customize `package-load-list'.
+Emacs starts up.  To disable this, set 'package-enable-at-startup' to
+nil.  To specify the packages to load, customize 'package-load-list'.
 
 ** Custom theme changes
 
-*** New command `M-x customize-themes', which provides a convenient
+*** New command 'M-x customize-themes', which provides a convenient
 interface for enabling and disabling Custom themes.
 
-*** New option `custom-theme-load-path' is the load path for themes.
-Emacs no longer looks for Custom themes in `load-path'.  The default
-value of `custom-theme-load-path' says to look for themes in
-`custom-theme-directory', followed by a subdirectory of
-`data-directory' named "themes/", which contains a small selection of
+*** New option 'custom-theme-load-path' is the load path for themes.
+Emacs no longer looks for Custom themes in 'load-path'.  The default
+value of 'custom-theme-load-path' says to look for themes in
+'custom-theme-directory', followed by a subdirectory of
+'data-directory' named "themes/", which contains a small selection of
 built-in Custom themes.
 
-*** New option `custom-safe-themes' records known-safe theme files.
+*** New option 'custom-safe-themes' records known-safe theme files.
 If a theme is not in this list, Emacs queries before loading it, and
-offers to save the theme to `custom-safe-themes' automatically.  By
+offers to save the theme to 'custom-safe-themes' automatically.  By
 default, all themes included in Emacs are treated as safe.
 
 ** Improved GTK integration
 
 *** GTK scroll-bars are now placed on the right by default.
-The function `set-scroll-bar-mode' can change this.
+The function 'set-scroll-bar-mode' can change this.
 
 *** GTK tool bars can have just text, just images or images and text.
-Customize `tool-bar-style' to choose the style.  On a Gnome desktop,
+Customize 'tool-bar-style' to choose the style.  On a Gnome desktop,
 the default is taken from desktop settings.
 
 *** GTK tool bars can be placed on any edge of the frame.
@@ -2586,11 +2586,11 @@ The frame-parameter tool-bar-position controls this.  
It takes the
 values top, left, right or bottom.  The Options => Show/Hide menu has
 entries for this.
 
-*** The default colors for selected text (the `region' face) are taken
+*** The default colors for selected text (the 'region' face) are taken
 from the GTK theme when Emacs is built with GTK.
 
 *** Emacs uses GTK tooltips by default if built with GTK.
-You can disable this by changing `x-gtk-use-system-tooltips' to nil.
+You can disable this by changing 'x-gtk-use-system-tooltips' to nil.
 
 ** Graphical interface changes
 
@@ -2598,8 +2598,8 @@ You can disable this by changing 
`x-gtk-use-system-tooltips' to nil.
 Also, the first dash (which does not indicate anything) is just
 displayed as a space.
 
-*** `menu-bar-select-buffer-function' lets you choose another operation
-instead of `switch-to-buffer' when selecting an item in the Buffers menu.
+*** 'menu-bar-select-buffer-function' lets you choose another operation
+instead of 'switch-to-buffer' when selecting an item in the Buffers menu.
 
 *** Lucid menus and dialogs can display antialiased fonts if Emacs is
 built with Xft.  These fonts can be set via X resources, for example:
@@ -2607,37 +2607,37 @@ Emacs.pane.menubar.font: Courier-12
 
 ** Exiting changes
 
-*** Emacs now calls `kill-emacs' if it receives SIGTERM or SIGHUP,
+*** Emacs now calls 'kill-emacs' if it receives SIGTERM or SIGHUP,
 or if it receives a SIGINT signal in batch mode.
 
-*** `kill-emacs-hook' is now also run in batch mode.
-Third-party code which adds to `kill-emacs-hook' should check if they
+*** 'kill-emacs-hook' is now also run in batch mode.
+Third-party code which adds to 'kill-emacs-hook' should check if they
 do the right thing in batch mode.
 
 ** Scrolling changes
 
-*** New scrolling commands `scroll-up-command' and `scroll-down-command'
+*** New scrolling commands 'scroll-up-command' and 'scroll-down-command'
 (bound to C-v/[next] and M-v/[prior]) do not signal errors at top/bottom
 of buffer at first key-press (instead they move to top/bottom of buffer)
-when `scroll-error-top-bottom' is non-nil.
+when 'scroll-error-top-bottom' is non-nil.
 
-*** New option `scroll-error-top-bottom' (see above).
+*** New option 'scroll-error-top-bottom' (see above).
 
-*** New scrolling commands `scroll-up-line' and `scroll-down-line'
+*** New scrolling commands 'scroll-up-line' and 'scroll-down-line'
 scroll a line instead of full screen.
 
-*** New property `scroll-command' should be set on a command's symbol to
-define it as a scroll command affected by `scroll-preserve-screen-position'.
+*** New property 'scroll-command' should be set on a command's symbol to
+define it as a scroll command affected by 'scroll-preserve-screen-position'.
 
-*** If you customize `scroll-conservatively' to a value greater than 100,
+*** If you customize 'scroll-conservatively' to a value greater than 100,
 Emacs will never recenter point in the window when it scrolls due to
-cursor motion commands or commands that move point (e.f., `M-g M-g').
-Previously, you needed to use `most-positive-fixnum' as the value of
-`scroll-conservatively' to achieve the same effect.
+cursor motion commands or commands that move point (e.f., 'M-g M-g').
+Previously, you needed to use 'most-positive-fixnum' as the value of
+'scroll-conservatively' to achieve the same effect.
 
 *** "Aggressive" scrolling now honors the scroll margins.
-If you customize `scroll-up-aggressively' or
-`scroll-down-aggressively' and move point off the window, Emacs now
+If you customize 'scroll-up-aggressively' or
+'scroll-down-aggressively' and move point off the window, Emacs now
 scrolls the window so as to avoid positioning point inside the scroll
 margin.
 
@@ -2645,20 +2645,20 @@ margin.
 This requires Emacs to be linked with libselinux at build time.
 
 *** Emacs preserves the SELinux file context when backing up.
-Also, the function `copy-file' has an extra optional argument for
-preserving SELinux context, and the return value of `backup-buffer'
+Also, the function 'copy-file' has an extra optional argument for
+preserving SELinux context, and the return value of 'backup-buffer'
 now includes the SELinux context.
 
-*** New functions `file-selinux-context' and `set-file-selinux-context'
+*** New functions 'file-selinux-context' and 'set-file-selinux-context'
 get and set the SELinux context of a file.
 
 ** Trash changes
 
-*** `delete-by-moving-to-trash' now only affects commands that specify
+*** 'delete-by-moving-to-trash' now only affects commands that specify
 trashing.  This avoids inadvertently trashing temporary files.
 
-*** Calling `delete-file' or `delete-directory' with a prefix argument
-now forces true deletion, regardless of `delete-by-moving-to-trash'.
+*** Calling 'delete-file' or 'delete-directory' with a prefix argument
+now forces true deletion, regardless of 'delete-by-moving-to-trash'.
 
 ** File- and directory-local variable changes
 
@@ -2670,124 +2670,124 @@ subdirectories.
 *** Directory local variables can apply to some file-less buffers.
 Affected modes include dired, vc-dir, and log-edit.  For example,
 adding "(diff-mode . ((mode . whitespace)))" to .dir-locals.el will
-turn on `whitespace-mode' for *vc-diff* buffers.  Modes should call
-`hack-dir-local-variables-non-file-buffer' to support this.
+turn on 'whitespace-mode' for *vc-diff* buffers.  Modes should call
+'hack-dir-local-variables-non-file-buffer' to support this.
 
 *** Using "mode: MINOR-MODE" to enable a minor mode is deprecated.
 Instead, use "eval: (minor-mode 1)".
 
-*** The variable `inhibit-first-line-modes-regexps' has been renamed
-to `inhibit-local-variables-regexps'.  As the name suggests, it now
+*** The variable 'inhibit-first-line-modes-regexps' has been renamed
+to 'inhibit-local-variables-regexps'.  As the name suggests, it now
 applies to ALL file local variables, not just -*- lines.  The
-associated `inhibit-first-line-modes-suffixes' has been renamed in the
+associated 'inhibit-first-line-modes-suffixes' has been renamed in the
 corresponding way.
 
 ** Window changes
 
-*** The `quit-window' command now restores the last buffer displayed
+*** The 'quit-window' command now restores the last buffer displayed
 in the quitted window.
 
 *** Resizing an Emacs frame now preserves proportional window sizes,
 modulo restrictions like window minimum sizes and fixed-size windows.
 
-*** The behavior of `display-buffer' is now customizable in detail.
+*** The behavior of 'display-buffer' is now customizable in detail.
 
-**** New option `display-buffer-base-action' specifies a list of
+**** New option 'display-buffer-base-action' specifies a list of
 user-determined display "actions" (functions and optional arguments
 for choosing the displaying window).
 
 This takes precedence over the default display action, which is
-specified by `display-buffer-fallback-action'.
+specified by 'display-buffer-fallback-action'.
 
-**** New option `display-buffer-alist' maps buffer name regexps to
-display actions, taking precedence over `display-buffer-base-action'.
+**** New option 'display-buffer-alist' maps buffer name regexps to
+display actions, taking precedence over 'display-buffer-base-action'.
 
-*** New option `window-combination-limit'.
-The new option `window-combination-limit' allows to return the space
+*** New option 'window-combination-limit'.
+The new option 'window-combination-limit' allows to return the space
 obtained for resizing or creating a window more reliably to the window
 from which such space was obtained.
 
-*** New option `window-combination-resize'.
-The new option `window-combination-resize' allows to split a window that
+*** New option 'window-combination-resize'.
+The new option 'window-combination-resize' allows to split a window that
 otherwise cannot be split because it's too small by stealing space from
 other windows in the same combination.  Subsequent resizing or deletion
 of the window will resize all windows in the same combination as well.
 
-*** New option `frame-auto-hide-function' lets you choose between
+*** New option 'frame-auto-hide-function' lets you choose between
 iconifying or deleting a frame when burying a buffer in a dedicated
 frame, or quitting a window showing a buffer in a frame of its own.
 
-*** New commands `maximize-window' and `minimize-window'.
+*** New commands 'maximize-window' and 'minimize-window'.
 These maximize and minimize the size of a window within its frame.
 
-*** New commands `switch-to-prev-buffer' and `switch-to-next-buffer'.
+*** New commands 'switch-to-prev-buffer' and 'switch-to-next-buffer'.
 These functions allow to navigate through the live buffers that have
 been shown in a specific window.
 
 ** Minibuffer changes
 
-*** The inactive minibuffer has its own major mode `minibuffer-inactive-mode'.
+*** The inactive minibuffer has its own major mode 'minibuffer-inactive-mode'.
 This is handy for minibuffer-only frames, and is also used for the feature
 where mouse-1 pops up *Messages*"', which can now easily be changed.
 
-*** Minibuffers set `truncate-lines' to nil.
+*** Minibuffers set 'truncate-lines' to nil.
 If you want to change the value to something else, you could use
-for example `minibuffer-setup-hook'.
+for example 'minibuffer-setup-hook'.
 
-** `auto-mode-case-fold' is now enabled by default.
+** 'auto-mode-case-fold' is now enabled by default.
 
-** `backup-by-copying-when-mismatch' now defaults to t.
+** 'backup-by-copying-when-mismatch' now defaults to t.
 
-** New basic faces `error', `warning', `success'.
+** New basic faces 'error', 'warning', 'success'.
 These are used to highlight text indicating failure, caution or
 successful operation.
 
-** New option `list-colors-sort' defines the color sort order
-for `list-colors-display'.
+** New option 'list-colors-sort' defines the color sort order
+for 'list-colors-display'.
 
-** The variable `focus-follows-mouse' now always defaults to nil.
+** The variable 'focus-follows-mouse' now always defaults to nil.
 
 
 * Editing Changes in Emacs 24.1
 
 ** Search changes
 
-*** C-y in Isearch is now bound to `isearch-yank-kill', instead of
-`isearch-yank-line'.
+*** C-y in Isearch is now bound to 'isearch-yank-kill', instead of
+'isearch-yank-line'.
 
-*** M-y in Isearch is now bound to `isearch-yank-pop', instead of
-`isearch-yank-kill'.
+*** M-y in Isearch is now bound to 'isearch-yank-pop', instead of
+'isearch-yank-kill'.
 
-*** M-s C-e in Isearch is now bound to `isearch-yank-line'.
+*** M-s C-e in Isearch is now bound to 'isearch-yank-line'.
 
-** New commands `count-words-region' and `count-words'.
+** New commands 'count-words-region' and 'count-words'.
 
-*** M-= is bound to `count-words-region', not `count-lines-region'.
-The `count-words-region' command, when called interactively, reports
+*** M-= is bound to 'count-words-region', not 'count-lines-region'.
+The 'count-words-region' command, when called interactively, reports
 the number of lines, words, and characters in the region.  It is a
-superset of the old `count-lines-region', which is now an obsolete
+superset of the old 'count-lines-region', which is now an obsolete
 alias for it.
 
-** The command `just-one-space' (M-SPC), if given a negative argument,
+** The command 'just-one-space' (M-SPC), if given a negative argument,
 also deletes newlines around point.
 
 ** Deletion changes
 
-*** New option `delete-active-region'.
+*** New option 'delete-active-region'.
 If non-nil, [delete] and DEL delete the region if it is active and no
-prefix argument is given.  If set to `kill', those commands kill
+prefix argument is given.  If set to 'kill', those commands kill
 instead.
 
-*** New command `delete-forward-char', bound to [delete].
-This is meant for interactive use, and obeys `delete-active-region'.
-The command `delete-char' does not obey `delete-active-region'.
+*** New command 'delete-forward-char', bound to [delete].
+This is meant for interactive use, and obeys 'delete-active-region'.
+The command 'delete-char' does not obey 'delete-active-region'.
 
-*** `delete-backward-char' is now a Lisp function.
-Apart from obeying `delete-active-region', its behavior is unchanged.
+*** 'delete-backward-char' is now a Lisp function.
+Apart from obeying 'delete-active-region', its behavior is unchanged.
 However, the byte compiler now warns if it is called from Lisp; Lisp
 callers should use delete-char with a negative argument instead.
 
-*** The option `mouse-region-delete-keys' has been deleted.
+*** The option 'mouse-region-delete-keys' has been deleted.
 
 ** Selection changes.
 
@@ -2799,70 +2799,70 @@ mouse commands use the primary selection.
 In the following, we provide a list of these changes, followed by a
 list of steps to get the old behavior back if you prefer that.
 
-*** `select-active-regions' now defaults to t.
+*** 'select-active-regions' now defaults to t.
 Merely selecting text (e.g. with drag-mouse-1) no longer puts it in
 the kill ring.  The selected text is put in the primary selection, if
 the system possesses a separate primary selection facility (e.g. X).
 
-**** `select-active-regions' also accepts a new value, `only'.
+**** 'select-active-regions' also accepts a new value, 'only'.
 This means to only set the primary selection for temporarily active
 regions (usually made by mouse-dragging or shift-selection);
 "ordinary" active regions, such as those made with C-SPC followed by
 point motion, do not alter the primary selection.
 
-**** `mouse-drag-copy-region' now defaults to nil.
+**** 'mouse-drag-copy-region' now defaults to nil.
 
-*** mouse-2 is now bound to `mouse-yank-primary'.
+*** mouse-2 is now bound to 'mouse-yank-primary'.
 This pastes from the primary selection, ignoring the kill-ring.
-Previously, mouse-2 was bound to `mouse-yank-at-click'.
+Previously, mouse-2 was bound to 'mouse-yank-at-click'.
 
-*** `x-select-enable-clipboard' now defaults to t on all platforms.
+*** 'x-select-enable-clipboard' now defaults to t on all platforms.
 
-*** `x-select-enable-primary' now defaults to nil.
+*** 'x-select-enable-primary' now defaults to nil.
 Thus, commands that kill text or copy it to the kill-ring (such as
 M-w, C-w, and C-k) also use the clipboard---not the primary selection.
 
 **** The "Copy", "Cut", and "Paste" items in the "Edit" menu are now
 exactly equivalent to M-w, C-w, and C-y respectively.
 
-**** Note that on MS-Windows, `x-select-enable-clipboard' was already
+**** Note that on MS-Windows, 'x-select-enable-clipboard' was already
 non-nil by default, as Windows does not support the primary selection
 between applications.
 
 *** To return to the previous behavior, do the following:
 
-**** Change `select-active-regions' to nil.
-**** Change `mouse-drag-copy-region' to t.
-**** Change `x-select-enable-primary' to t (on X only).
-**** Change `x-select-enable-clipboard' to nil.
-**** Bind `mouse-yank-at-click' to mouse-2.
+**** Change 'select-active-regions' to nil.
+**** Change 'mouse-drag-copy-region' to t.
+**** Change 'x-select-enable-primary' to t (on X only).
+**** Change 'x-select-enable-clipboard' to nil.
+**** Bind 'mouse-yank-at-click' to mouse-2.
 
 *** Support for X cut buffers has been removed.
 
 *** X clipboard managers are now supported.
-To inhibit this, change `x-select-enable-clipboard-manager' to nil.
+To inhibit this, change 'x-select-enable-clipboard-manager' to nil.
 
-** New command `C-x r N' (`rectangle-number-lines') numbers the lines
+** New command 'C-x r N' ('rectangle-number-lines') numbers the lines
 in the current rectangle.  With a prefix argument, this prompts for a
 number to count from and for a format string.
 
-** `redisplay-dont-pause' now defaults to t.
+** 'redisplay-dont-pause' now defaults to t.
 This makes Emacs feel more responsive to editing commands that arrive
 at high rate, e.g. if you lean on some key, because stopping redisplay
 in the middle (when this variable is nil) forces more expensive
 updates later on, and Emacs appears to be unable to keep up.
 
 ** The behavior of <TAB> for active regions in Text mode has changed.
-In Text and related modes, typing <TAB> (`indent-for-tab-command')
+In Text and related modes, typing <TAB> ('indent-for-tab-command')
 when the region is active causes Emacs to indent all the lines in the
 region, aligning them with the line previous to the first line in the
 region (or with the left margin if there is no previous line).
 
-** When `occur' is called with a prefix argument, matching strings are
-collected into the `*Occur*' buffer without line numbers.  If there
-are parenthesized subexpressions in the specified regexp, `occur'
+** When 'occur' is called with a prefix argument, matching strings are
+collected into the '*Occur*' buffer without line numbers.  If there
+are parenthesized subexpressions in the specified regexp, 'occur'
 reads replacement text that may contain \\& and \\N whose convention
-follows `replace-match'.
+follows 'replace-match'.
 
 
 * Changes in Specialized Modes and Packages in Emacs 24.1
@@ -2872,19 +2872,19 @@ follows `replace-match'.
 ** BibTeX mode
 
 *** BibTeX mode now supports biblatex.
-Use the variable `bibtex-dialect' to select different BibTeX dialects.
-`bibtex-entry-field-alist' is now an obsolete alias for
-`bibtex-BibTeX-entry-alist'.
+Use the variable 'bibtex-dialect' to select different BibTeX dialects.
+'bibtex-entry-field-alist' is now an obsolete alias for
+'bibtex-BibTeX-entry-alist'.
 
-*** New command `bibtex-search-entries', bound to C-c C-a.
+*** New command 'bibtex-search-entries', bound to C-c C-a.
 
-*** New `bibtex-entry-format' option `sort-fields', disabled by default.
+*** New 'bibtex-entry-format' option 'sort-fields', disabled by default.
 
-*** New variable `bibtex-search-entry-globally'.
+*** New variable 'bibtex-search-entry-globally'.
 
 ** Browse-url
 
-*** New option `browse-url-mailto-function' specifies how to handle "mailto:"s.
+*** New option 'browse-url-mailto-function' specifies how to handle "mailto:"s.
 
 *** The default browser used by the package is now the "xdg-open" program,
 on platforms that support it.  This calls your desktop's preferred browser.
@@ -2900,32 +2900,32 @@ using TeX or LaTeX mode.
 
 *** New option to highlight selections using faces.
 
-*** `calc-histogram' has the option of using a vector to determine the bins.
+*** 'calc-histogram' has the option of using a vector to determine the bins.
 
 *** New "O" option prefix.
 
-*** Use the "O" prefix to "d r" (`calc-radix') to turn on twos-complement mode.
+*** Use the "O" prefix to "d r" ('calc-radix') to turn on twos-complement mode.
 
 ** Calendar, Diary, and Appt
 
 *** Diary entries can contain non-printing "comments".
-See the variable `diary-comment-start'.
+See the variable 'diary-comment-start'.
 
 *** Appointments can specify their individual warning times.
-See the variable `appt-warning-time-regexp'.
+See the variable 'appt-warning-time-regexp'.
 
-*** The function specified by `appt-disp-window-function' may be passed
+*** The function specified by 'appt-disp-window-function' may be passed
 lists of arguments if multiple appointments are due at similar times.
 If you are using a custom function for this, you should update it.
 
-*** New function `diary-hebrew-birthday'.
+*** New function 'diary-hebrew-birthday'.
 
-*** Elements of `calendar-day-abbrev-array' and `calendar-month-abbrev-array'
+*** Elements of 'calendar-day-abbrev-array' and 'calendar-month-abbrev-array'
 may no longer be nil, but must all be strings.
 
 *** The obsolete (since Emacs 22.1) method of enabling the appt
-package by adding `appt-make-list' to `diary-hook' has been removed.
-Use `appt-activate' instead.
+package by adding 'appt-make-list' to 'diary-hook' has been removed.
+Use 'appt-activate' instead.
 
 *** Some appt variables (obsolete since Emacs 22.1) have been removed:
 appt-issue-message (use the function appt-activate)
@@ -2941,7 +2941,7 @@ The main entry point is M-x c-guess.
 
 *** Java Mode now supports Java 5.0 (Tiger) and 6 (Mustang).
 
-*** `c-beginning-of-defun' and `c-end-of-defun' now respect nested scopes.
+*** 'c-beginning-of-defun' and 'c-end-of-defun' now respect nested scopes.
 Thus C-M-a will, by default, go to the beginning of the immediate function,
 not the top level.
 
@@ -2954,13 +2954,13 @@ parsed as a statement continuation.
 ** Compilation mode
 
 *** Compilation mode can be used without Font Lock mode.
-`compilation-parse-errors-function' is now obsolete.
+'compilation-parse-errors-function' is now obsolete.
 
-*** New variable `compilation-filter-start', which is bound while
-`compilation-filter-hook' runs.  It records the start position of the
-text inserted by `compilation-filter'.
+*** New variable 'compilation-filter-start', which is bound while
+'compilation-filter-hook' runs.  It records the start position of the
+text inserted by 'compilation-filter'.
 
-*** `compilation-error-screen-columns' and `compilation-first-column'
+*** 'compilation-error-screen-columns' and 'compilation-first-column'
 are obeyed in the editing buffer.  So programming language modes can
 set them, whereas previously only the value in the *Compilation*
 buffer was used.
@@ -2968,31 +2968,31 @@ buffer was used.
 ** Customize
 
 *** Customize buffers now contain a search field.
-The search is performed using `customize-apropos'.
-To turn off the search field, set `custom-search-field' to nil.
+The search is performed using 'customize-apropos'.
+To turn off the search field, set 'custom-search-field' to nil.
 
 *** Options in customize group buffers start out hidden if not customized.
 Use the arrow to the left of the option name to toggle visibility.
 
-*** custom-buffer-sort-alphabetically now defaults to t.
+*** 'custom-buffer-sort-alphabetically' now defaults to t.
 
 *** The color widget now has a "Choose" button, which allows you to
-choose a color via `list-colors-display'.
+choose a color via 'list-colors-display'.
 
 ** D-Bus
 
 *** It is now possible to access buses other than the default system
 or session bus.
 
-*** The `dbus-register-method' and `dbus-register-property' functions
+*** The 'dbus-register-method' and 'dbus-register-property' functions
 optionally do not register names.
 
-*** The new function `dbus-register-service' registers a known service
+*** The new function 'dbus-register-service' registers a known service
 name on a D-Bus without also registering a property or a method.
 
 ** Dired-x
 
-*** C-x C-j (`dired-jump') and C-x 4 C-j (`dired-jump-other-window'),
+*** C-x C-j ('dired-jump') and C-x 4 C-j ('dired-jump-other-window'),
 if called with a prefix argument, read a file name from the minibuffer
 instead of using the current buffer.
 
@@ -3001,18 +3001,18 @@ The standard directory local variables feature replaces 
it.
 
 ** ERC changes
 
-*** New options `erc-autojoin-timing' and `erc-autojoin-delay',
+*** New options 'erc-autojoin-timing' and 'erc-autojoin-delay',
 controlling attempts to autojoin a channel.
 
-*** New variable `erc-coding-system-precedence': If we use `undecided'
+*** New variable 'erc-coding-system-precedence': If we use 'undecided'
 as the server coding system, this variable will then be consulted.
 The default is to decode strings that can be decoded as utf-8 as
-utf-8, and do the normal `undecided' decoding for the rest.
+utf-8, and do the normal 'undecided' decoding for the rest.
 
 ** Eshell changes
 
-*** The default value of `eshell-directory-name' has changed
-to be an "eshell" directory in `user-emacs-directory'.
+*** The default value of 'eshell-directory-name' has changed
+to be an "eshell" directory in 'user-emacs-directory'.
 The old "~/.eshell/" directory is still used if it exists, though.
 
 ** gdb-mi
@@ -3023,8 +3023,8 @@ debugging of several threads.
 
 ** Image mode
 
-*** RET (`image-toggle-animation') toggles animation, if applicable.
-Animation plays once, unless the option `image-animate-loop' is non-nil.
+*** RET ('image-toggle-animation') toggles animation, if applicable.
+Animation plays once, unless the option 'image-animate-loop' is non-nil.
 
 ** Info
 
@@ -3034,9 +3034,9 @@ that buffer.  (This is handy if you have many manuals in 
many *info*
 buffers, and don't remember the name of the buffer visiting the manual
 you want to consult.)  Otherwise, it loads and displays the manual.
 
-*** `e' is now bound to `end-of-buffer' rather than to `Info-edit'.
+*** 'e' is now bound to 'end-of-buffer' rather than to 'Info-edit'.
 This is for compatibility with the stand-alone Info reader program,
-and also because `Info-edit' is a rarely used command that is disabled
+and also because 'Info-edit' is a rarely used command that is disabled
 by default.
 
 ** Mail mode changes (not Message mode)
@@ -3054,9 +3054,9 @@ See MH-E-NEWS for details.
 
 ** mpc.el: Can use pseudo tags of the form tag1|tag2 as a union of two tags.
 
-** nXML mode no longer binds C-RET to `nxml-complete'.
-Completion is now performed via `completion-at-point', bound to C-M-i
-or M-TAB.  If `nxml-bind-meta-tab-to-complete-flag' is non-nil (the
+** nXML mode no longer binds C-RET to 'nxml-complete'.
+Completion is now performed via 'completion-at-point', bound to C-M-i
+or M-TAB.  If 'nxml-bind-meta-tab-to-complete-flag' is non-nil (the
 default), this performs tag completion.
 
 ** Org mode has been updated to version 7.8.09.
@@ -3068,30 +3068,30 @@ support for more variants, including Mercury, and a lot 
more.
 
 ** Rmail
 
-*** The command `rmail-epa-decrypt' decrypts OpenPGP data
+*** The command 'rmail-epa-decrypt' decrypts OpenPGP data
 in the Rmail incoming message.
 
-*** The variable `rmail-message-filter' no longer has any effect.
+*** The variable 'rmail-message-filter' no longer has any effect.
 This change was made in Emacs 23.1 but was not advertised at the time.
-Try using `rmail-show-message-hook' instead.
+Try using 'rmail-show-message-hook' instead.
 
 ** Shell mode
 
 *** M-x shell prompts for the shell path name if the default directory
 is a remote file name and neither the environment variable $ESHELL nor
-the variable `explicit-shell-file-name' is set.
+the variable 'explicit-shell-file-name' is set.
 
-*** TAB is now bound to the standard `completion-at-point' command,
+*** TAB is now bound to the standard 'completion-at-point' command,
 which now implements the pcomplete rules for shell command completion.
 
 ** SMTPmail
 
 *** SMTPmail now uses encrypted connections (via STARTTLS) by default
 if the mail server supports them.  This uses either built-in GnuTLS
-support, or the starttls.el library.  Customize `smtpmail-stream-type'
+support, or the starttls.el library.  Customize 'smtpmail-stream-type'
 to change this.
 
-*** The variable `smtpmail-auth-credentials' has been removed.
+*** The variable 'smtpmail-auth-credentials' has been removed.
 By default, the information is now stored in the file ~/.authinfo.
 This was the default value of smtpmail-auth-credentials.  If you had
 customized smtpmail-auth-credentials to a list of user names and
@@ -3110,7 +3110,7 @@ then the equivalent line in ~/.authinfo would be
 See the auth-source manual for more information, e.g. on encrypting
 the credentials file.
 
-*** The variable `smtpmail-starttls-credentials' has been removed.
+*** The variable 'smtpmail-starttls-credentials' has been removed.
 If you had that set, you need to put
 
   machine smtp.whatever.foo port 25 key "~/.my_smtp_tls.key" cert 
"~/.my_smtp_tls.cert"
@@ -3118,36 +3118,36 @@ If you had that set, you need to put
 in your ~/.authinfo file instead.
 
 *** SMTPmail defaults to using the address in the From: header as the
-SMTP MAIL FROM envelope.  To override this, set `mail-envelope-from'
+SMTP MAIL FROM envelope.  To override this, set 'mail-envelope-from'
 to the address you wish to use instead.
 
 ** SQL mode
 
-*** New options `sql-port', `sql-connection-alist', `sql-send-terminator',
-and `sql-oracle-scan-on'.
+*** New options 'sql-port', 'sql-connection-alist', 'sql-send-terminator',
+and 'sql-oracle-scan-on'.
 
 *** New options controlling prompting for login parameters.
-Each supported product has a custom variable `sql-*-login-params',
+Each supported product has a custom variable 'sql-*-login-params',
 which is a list of the parameters to be prompted for before a
 connection is established.
 
-*** The command `sql-product-interactive' now takes a prefix argument,
+*** The command 'sql-product-interactive' now takes a prefix argument,
 which causes it to prompt for an SQL product.
 
 *** Product-specific SQL interactive commands now take prefix arguments.
-These commands (`sql-sqlite', `sql-postgres', `sql-mysql', etc.),
+These commands ('sql-sqlite', 'sql-postgres', 'sql-mysql', etc.),
 given a prefix argument, prompt for a name for the SQL interactive
-buffer.  This reduces the need for calling `sql-rename-buffer'.
+buffer.  This reduces the need for calling 'sql-rename-buffer'.
 
 *** SQL interactive modes suppress command continuation prompts, and
 replace tabs with spaces.  The first change impacts multiple line SQL
 statements entered with C-j between each line, statements yanked into
-the buffer and statements sent with `sql-send-*' functions.  The
+the buffer and statements sent with 'sql-send-*' functions.  The
 second prevents the MySQL and Postgres interpreters from listing
-object name completions when sent text via `sql-send-*' functions.
+object name completions when sent text via 'sql-send-*' functions.
 
-*** New command `sql-connect' starts a predefined SQLi session,
-using the login parameters from `sql-connection-alist'.
+*** New command 'sql-connect' starts a predefined SQLi session,
+using the login parameters from 'sql-connection-alist'.
 
 *** New "Save Connection" menu item in SQLi buffers.
 This gathers the login params specified for the SQLi session, if it
@@ -3169,53 +3169,53 @@ sql-list-all and sql-list-table.
 *** The following access methods are discontinued: "ssh1_old",
 "ssh2_old", "scp1_old", "scp2_old", "imap", "imaps" and "fish".
 
-*** The user option `remote-file-name-inhibit-cache' controls whether
+*** The user option 'remote-file-name-inhibit-cache' controls whether
 remote file attributes are cached for better performance.
 
-*** The option `ange-ftp-binary-file-name-regexp' has changed its
+*** The option 'ange-ftp-binary-file-name-regexp' has changed its
 default value to "".
 
-*** Handlers for `file-selinux-context' and `set-file-selinux-context'
+*** Handlers for 'file-selinux-context' and 'set-file-selinux-context'
 for remote machines which support SELinux.
 
-** New function `url-queue-retrieve', which behaves like url-retrieve,
-but with limits (`url-queue-parallel-processes', `url-queue-timeout') on
+** New function 'url-queue-retrieve', which behaves like 'url-retrieve',
+but with limits ('url-queue-parallel-processes', 'url-queue-timeout') on
 the degree of parallelism.
 
 ** VC and related modes
 
 *** Support for pulling on distributed version control systems.
-The command C-x v + (`vc-pull') runs a "pull" operation, if it is
+The command C-x v + ('vc-pull') runs a "pull" operation, if it is
 supported (currently with Bzr, Git, and Mercurial), to update the
 current branch and working tree.  A prefix argument means to prompt
 the user for specifics, e.g. a pull location.
 
-*** `vc-update' is now an alias for `vc-pull'.
+*** 'vc-update' is now an alias for 'vc-pull'.
 
 *** Support for merging on distributed version control systems.
-The command C-x v m (`vc-merge') now runs a "merge" operation, if it
+The command C-x v m ('vc-merge') now runs a "merge" operation, if it
 is supported (currently with Bzr, Git, and Mercurial), to merge
 changes from another branch into the current one.  It prompts for
 specifics, e.g. a merge source.
 
-*** New option `vc-revert-show-diff' controls whether `vc-revert'
+*** New option 'vc-revert-show-diff' controls whether 'vc-revert'
 shows a diff while querying the user.  It defaults to t.
 
 *** Log entries in some Log View buffers can be toggled to display a
 longer description by typing RET (log-view-toggle-entry-display).
 This is currently supported for Bzr, Git, and Mercurial (to support
-another backend, define a `log-view-expanded-log-entry-function').
-In the Log View buffers made by C-x v L (`vc-print-root-log'), you can
+another backend, define a 'log-view-expanded-log-entry-function').
+In the Log View buffers made by C-x v L ('vc-print-root-log'), you can
 use this to display the full log entry for the revision at point.
 
-*** New command `vc-ediff' allows visual comparison of two revisions
-of a file similar to `vc-diff', but using ediff backend.
+*** New command 'vc-ediff' allows visual comparison of two revisions
+of a file similar to 'vc-diff', but using ediff backend.
 
-*** The option `vc-initial-comment' was removed in Emacs 23.2, but
+*** The option 'vc-initial-comment' was removed in Emacs 23.2, but
 this was not advertised at the time.
 
-*** `vc-toggle-read-only' is an obsolete alias for `toggle-read-only'.
-Since Emacs 23, it has done the same thing as `toggle-read-only', but
+*** 'vc-toggle-read-only' is an obsolete alias for 'toggle-read-only'.
+Since Emacs 23, it has done the same thing as 'toggle-read-only', but
 this was not advertised at the time.
 
 ** Obsolete modes
@@ -3226,8 +3226,8 @@ this was not advertised at the time.
 
 *** partial-completion-mode (complete.el) is obsolete.
 You can get a comparable behavior with:
-(setq completion-styles '(partial-completion initials))
-(setq completion-pcm-complete-word-inserts-delimiters t)
+    (setq completion-styles '(partial-completion initials))
+    (setq completion-pcm-complete-word-inserts-delimiters t)
 
 *** pc-mode.el is obsolete (CUA mode is much more comprehensive).
 
@@ -3242,17 +3242,17 @@ They are superseded by shift-select-mode, enabled by 
default since 23.1.
 
 ** Miscellaneous
 
-*** The Landmark game is now invoked with `landmark', not `lm'.
+*** The Landmark game is now invoked with 'landmark', not 'lm'.
 Its functions and variables have been similarly renamed.
 
-*** In `ido-file-completion-map', C-v is no longer bound to `ido-toggle-vc'.
+*** In 'ido-file-completion-map', C-v is no longer bound to 'ido-toggle-vc'.
 (This interfered with cua-mode.)
 
 *** f90.el has some support for Fortran 2008 syntax.
 
-*** `copyright-fix-years' can optionally convert consecutive years to ranges.
+*** 'copyright-fix-years' can optionally convert consecutive years to ranges.
 
-*** New command `nato-region' converts text to NATO phonetic alphabet.
+*** New command 'nato-region' converts text to NATO phonetic alphabet.
 
 
 * New Modes and Packages in Emacs 24.1
@@ -3260,28 +3260,28 @@ Its functions and variables have been similarly renamed.
 ** Occur Edit mode applies edits made in *Occur* buffers to the
 original buffers.  It is bound to "e" in Occur mode.
 
-** New global minor mode electric-pair-mode.
+** New global minor mode 'electric-pair-mode'.
 When enabled, typing an open parenthesis automatically inserts the
 matching closing one.
 
-** New global minor mode electric-indent-mode.
+** New global minor mode 'electric-indent-mode'.
 When enabled, typing certain characters triggers reindentation.
-Major modes wishing to use this can set electric-indent-chars or
-electric-indent-functions.
+Major modes wishing to use this can set 'electric-indent-chars' or
+'electric-indent-functions'.
 
-** New global minor mode electric-layout-mode.
+** New global minor mode 'electric-layout-mode'.
 When enabled, typing certain characters automatically inserts newlines.
-Major modes wishing to use this can set electric-layout-rules.
+Major modes wishing to use this can set 'electric-layout-rules'.
 
 ** tabulated-list.el provides a generic major mode for tabulated data,
 from which other modes can be derived.
 
-** pcase.el provides the ML-style pattern matching macro `pcase'.
+** pcase.el provides the ML-style pattern matching macro 'pcase'.
 
 ** secrets.el is an implementation of the Secret Service API, an
 interface to password managers like GNOME Keyring or KDE Wallet.  The
 Secret Service API requires D-Bus for communication.  The command
-`secrets-show-secrets' offers a buffer with a visualization of the
+'secrets-show-secrets' offers a buffer with a visualization of the
 secrets.
 
 ** notifications.el provides an implementation of the Desktop
@@ -3294,7 +3294,7 @@ soap-inspect.el is an interactive inspector for SOAP WSDL 
structures.
 
 ** New emacs-lock.el package.
 The previous version has been moved to obsolete/old-emacs-lock.el.
-Now, there is a proper minor mode `emacs-lock-mode'.  Protection
+Now, there is a proper minor mode 'emacs-lock-mode'.  Protection
 against exiting Emacs and killing the buffer can be set separately.
 The mechanism for automatically turning off protection for buffers
 with dead inferior processes has been generalized.
@@ -3305,26 +3305,26 @@ with dead inferior processes has been generalized.
 ** Passing a nil argument to a minor mode function call now ENABLES
 the minor mode unconditionally.  This is so that you can write e.g.
 
- (add-hook 'text-mode-hook 'foo-mode)
+    (add-hook 'text-mode-hook #'foo-mode)
 
 to enable foo-mode in Text mode buffers, removing the need for
-`turn-on-foo-mode' style functions.  This affects all mode commands
-defined by `define-minor-mode'.  If called interactively, the mode
+'turn-on-foo-mode' style functions.  This affects all mode commands
+defined by 'define-minor-mode'.  If called interactively, the mode
 command still toggles the minor mode.
 
-** The return value of `backup-buffer' has changed.
+** The return value of 'backup-buffer' has changed.
 It is now a list of three elements, where the second element is a list
 describing the original file's SELinux context.  If Emacs or the
 system lacks SELinux support, the context list is (nil nil nil nil).
 See "Basic SELinux support" above, under "Changes in Emacs 24.1".
 
-** `char-direction-table' and the `char-direction' function were deleted.
+** 'char-direction-table' and the 'char-direction' function were deleted.
 They were buggy and inferior to the new support of bidirectional
 editing introduced in Emacs 24.  If you need the bidirectional
-properties of a character, use `get-char-code-property' with the last
-argument `bidi-class'.
+properties of a character, use 'get-char-code-property' with the last
+argument 'bidi-class'.
 
-** `copy-directory' now copies the source directory as a subdirectory
+** 'copy-directory' now copies the source directory as a subdirectory
 of the target directory, if the latter is an existing directory.  The
 new optional arg COPY-CONTENTS, if non-nil, makes the function copy
 the contents directly into a pre-existing target directory.
@@ -3348,22 +3348,22 @@ for key sequence notation: instead of [(control ,)] and 
[(control ')],
 you should write [(control ?,)] and [(control ?')], which will work in
 older Emacsen too.
 
-** The macro `eval-at-startup' was removed in Emacs 23.2, but this
-was not advertised at the time.  The function `custom-initialize-delay'
+** The macro 'eval-at-startup' was removed in Emacs 23.2, but this
+was not advertised at the time.  The function 'custom-initialize-delay'
 replaced all known uses.
 
-** `view-buffer' now treats special mode-class in the same way that
-`view-file' has since Emacs 22 (i.e. it won't enable View mode if the
+** 'view-buffer' now treats special mode-class in the same way that
+'view-file' has since Emacs 22 (i.e. it won't enable View mode if the
 major mode is special).
 
 ** Menu and tool bar changes
 
-*** During startup, Emacs no longer adds entries for `menu-bar-lines'
-and `tool-bar-lines' to `default-frame-alist' and `initial-frame-alist'.
-With these alist entries omitted, `make-frame' checks the value of the
-variable `menu-bar-mode'/`tool-bar-mode' to determine whether to create
+*** During startup, Emacs no longer adds entries for 'menu-bar-lines'
+and 'tool-bar-lines' to 'default-frame-alist' and 'initial-frame-alist'.
+With these alist entries omitted, 'make-frame' checks the value of the
+variable 'menu-bar-mode'/'tool-bar-mode' to determine whether to create
 a menu-bar or tool-bar, respectively.  If the alist entries are added,
-they override the value of `menu-bar-mode'/`tool-bar-mode'.
+they override the value of 'menu-bar-mode'/'tool-bar-mode'.
 
 *** The menu bar bindings's caches are not used any more.
 Use (where-is-internal <def> nil t) instead.
@@ -3371,82 +3371,82 @@ Use (where-is-internal <def> nil t) instead.
 ** Regions created by mouse dragging are now normal active regions,
 similar to those created by shift-selection (see Selection changes
 above).  In previous Emacs versions, these regions were delineated by
-`mouse-drag-overlay'; that variable has been removed.
+'mouse-drag-overlay'; that variable has been removed.
 
-** The fourth argument of `filter-buffer-substring' has been removed.
+** The fourth argument of 'filter-buffer-substring' has been removed.
 If you want to remove text properties from the final result, simply
 pass the result through substring-no-properties.
 
-** cl.el no longer provides `cl-19'.
+** cl.el no longer provides 'cl-19'.
 
 ** The following obsolete functions and aliases have been removed
 (the appropriate new function is given in parentheses; "not needed"
 means you can just remove all calls to the function in question):
 
-*** `comint-kill-output' (`comint-delete-output')
-*** `decompose-composite-char' (`char-to-string')
-*** `outline-visible' (`outline-invisible-p')
-*** `internal-find-face' (`facep')
-*** `internal-get-face' (`facep and check-face')
-*** `frame-update-faces' (not needed)
-*** `frame-update-face-colors' (`frame-set-background-mode')
-*** `x-frob-font-weight' and `x-frob-font-slant' (`make-face-*' functions)
-*** `x-make-font-bold' and `x-make-font-demibold' (`make-face-bold')
-*** `x-make-font-italic' and `x-make-font-oblique' (`make-face-italic')
-*** `x-make-font-bold-italic' (`make-face-bold-italic')
-*** `x-make-font-unbold' (`make-face-unbold')
-*** `x-make-font-unitalic' (`make-face-unitalic')
-*** `mldrag-drag-mode-line' (`mouse-drag-mode-line')
-*** `mldrag-drag-vertical-line' (`mouse-drag-vertical-line')
-*** `iswitchb-default-keybindings' (`iswitchb-mode')
-*** `char-bytes' (== 1)
-*** `isearch-return-char' (`isearch-printing-char')
-*** `make-local-hook' (not needed)
-*** `set-screen-height' (`set-frame-height')
-*** `set-screen-width' (`set-frame-width')
+*** 'comint-kill-output' ('comint-delete-output')
+*** 'decompose-composite-char' ('char-to-string')
+*** 'outline-visible' ('outline-invisible-p')
+*** 'internal-find-face' ('facep')
+*** 'internal-get-face' ('facep' and 'check-face')
+*** 'frame-update-faces' (not needed)
+*** 'frame-update-face-colors' ('frame-set-background-mode')
+*** 'x-frob-font-weight' and 'x-frob-font-slant' ('make-face-*' functions)
+*** 'x-make-font-bold' and 'x-make-font-demibold' ('make-face-bold')
+*** 'x-make-font-italic' and 'x-make-font-oblique' ('make-face-italic')
+*** 'x-make-font-bold-italic' ('make-face-bold-italic')
+*** 'x-make-font-unbold' ('make-face-unbold')
+*** 'x-make-font-unitalic' ('make-face-unitalic')
+*** 'mldrag-drag-mode-line' ('mouse-drag-mode-line')
+*** 'mldrag-drag-vertical-line' ('mouse-drag-vertical-line')
+*** 'iswitchb-default-keybindings' ('iswitchb-mode')
+*** 'char-bytes' (== 1)
+*** 'isearch-return-char' ('isearch-printing-char')
+*** 'make-local-hook' (not needed)
+*** 'set-screen-height' ('set-frame-height')
+*** 'set-screen-width' ('set-frame-width')
 
 ** The following obsolete variables and varaliases have been removed
 (the appropriate new variable is given in parentheses):
 
-*** `checkdoc-minor-keymap' (`checkdoc-minor-mode-map')
-*** `vc-header-alist' (`vc-BACKEND-header')
-*** `directory-sep-char' (== ?/)
-*** `font-lock-defaults-alist' (`font-lock-defaults')
-*** `e' (`float-e').
+*** 'checkdoc-minor-keymap' ('checkdoc-minor-mode-map')
+*** 'vc-header-alist' ('vc-BACKEND-header')
+*** 'directory-sep-char' (== ?/)
+*** 'font-lock-defaults-alist' ('font-lock-defaults')
+*** 'e' ('float-e').
 
 ** The following obsolete files were removed:
 sc.el, x-menu.el, rnews.el, rnewspost.el
 
 ** The format of the finder-inf.el file has changed, since the Finder
 mechanism is now based on the package system.  The variable
-`finder-package-info' is replaced by `package--builtins' and
-`finder-keywords-hash'.
+'finder-package-info' is replaced by 'package--builtins' and
+'finder-keywords-hash'.
 
-** When generating autoloads, `update-directory-autoloads' no longer
-assumes every inspected file is in your `load-path'.  It instead
-generates relative names according to the current `load-path'.
+** When generating autoloads, 'update-directory-autoloads' no longer
+assumes every inspected file is in your 'load-path'.  It instead
+generates relative names according to the current 'load-path'.
 
 
 * Lisp Changes in Emacs 24.1
 
 ** Code can now use lexical scoping by default instead of dynamic scoping.
-The `lexical-binding' variable enables lexical scoping for local
+The 'lexical-binding' variable enables lexical scoping for local
 variables.  It is typically set via a file-local variable in the first
 line of the file, in which case it applies to all the code in that
 file.
 
-*** `eval' takes a new optional argument `lexical' to choose the new lexical
+*** 'eval' takes a new optional argument 'lexical' to choose the new lexical
 binding instead of the old dynamic binding mode.
 
 *** Lexically scoped interpreted functions are represented with a new form
 of function value which looks like (closure ENV ARGS &rest BODY).
 
-*** New macro `letrec' to define recursive local functions.
+*** New macro 'letrec' to define recursive local functions.
 
-*** `defvar' and `defconst' now mark the variable as special (dynamic).
-So do `defcustom' and other forms that call `defvar' as a subroutine.
+*** 'defvar' and 'defconst' now mark the variable as special (dynamic).
+So do 'defcustom' and other forms that call 'defvar' as a subroutine.
 
-*** New function `special-variable-p' to check whether a variable is
+*** New function 'special-variable-p' to check whether a variable is
 declared as dynamically bound.
 
 *** The form ((lambda ...) ...) is deprecated.
@@ -3457,10 +3457,10 @@ their code.  See the ERT info manual for details.
 
 ** Changes for bidirectional display and editing
 
-*** New function `current-bidi-paragraph-direction'.
+*** New function 'current-bidi-paragraph-direction'.
 This returns the base direction of the paragraph at point.
 
-*** New function `bidi-string-mark-left-to-right'.
+*** New function 'bidi-string-mark-left-to-right'.
 Given a string containing characters from right-to-left scripts, this
 function returns another string which can be safely inserted into a
 buffer, such that any following text will be always displayed to the
@@ -3478,43 +3478,43 @@ Functions are provided to return the parent, siblings 
or child windows
 of any window including internal windows (windows not associated with a
 buffer) in the window tree.
 
-**** New function `window-valid-p' gives non-nil for live and internal
+**** New function 'window-valid-p' gives non-nil for live and internal
 windows.
 
 **** Window manipulation can deal with internal windows.
-Many window handling functions like `split-window', `delete-window', or
-`delete-other-windows' as well as the window resizing functions can now
+Many window handling functions like 'split-window', 'delete-window', or
+'delete-other-windows' as well as the window resizing functions can now
 act on any window including internal ones.
 
 *** window-total-height/-width vs window-body-height/-width.
-The function `window-height' has been renamed to `window-total-height'
-and `window-width' has been renamed to `window-body-width'.  The old
-names are provided as aliases.  Two new functions `window-total-width'
-and `window-body-height' are provided.
+The function 'window-height' has been renamed to 'window-total-height'
+and 'window-width' has been renamed to 'window-body-width'.  The old
+names are provided as aliases.  Two new functions 'window-total-width'
+and 'window-body-height' are provided.
 
 *** Window parameters specific to window handling functions.
 For each window you can specify a parameter to override the default
-behavior of a number of functions like `split-window', `delete-window'
-and `delete-other-windows'.  The variable `ignore-window-parameters'
+behavior of a number of functions like 'split-window', 'delete-window'
+and 'delete-other-windows'.  The variable 'ignore-window-parameters'
 allows to ignore processing such parameters.
 
-*** New semantics of third argument of `split-window'.
-The third argument of `split-window' has been renamed to SIDE and can be
+*** New semantics of third argument of 'split-window'.
+The third argument of 'split-window' has been renamed to SIDE and can be
 set to any of the values 'below, 'right, 'above, or 'left to make the
 new window appear on the corresponding side of the window that shall be
-split.  Any other value of SIDE will cause `split-window' to split the
+split.  Any other value of SIDE will cause 'split-window' to split the
 window into two side-by-side windows as before.
 
 *** Window resizing functions.
-A new standard function for resizing windows called `window-resize' has
+A new standard function for resizing windows called 'window-resize' has
 been introduced.  This and all other functions for resizing windows no
 longer delete any windows when they become too small.
 
 *** Deleting the selected window now selects the most recently selected
 live window on that frame instead.
 
-*** `adjust-window-trailing-edge' adjustments.
-`adjust-window-trailing-edge' can now deal with fixed-size windows and
+*** 'adjust-window-trailing-edge' adjustments.
+'adjust-window-trailing-edge' can now deal with fixed-size windows and
 is able to resize other windows if a window adjacent to the trailing
 edge cannot be shrunk any more.  This makes its behavior more similar to
 that of Emacs 21 without compromising, however, its inability to delete
@@ -3527,272 +3527,272 @@ shown in that window with its previous window-start 
and window-point
 positions.  This also means that the same buffer may be automatically
 shown twice even if it already appears in another window.
 
-*** `switch-to-buffer' has a new optional argument FORCE-SAME-WINDOW,
+*** 'switch-to-buffer' has a new optional argument FORCE-SAME-WINDOW,
 which if non-nil requires the buffer to be displayed in the currently
 selected window, signaling an error otherwise.  If nil, another window
 can be used, e.g. if the selected one is strongly dedicated.
 
-*** `split-window-vertically' and `split-window-horizontally' renamed
-to `split-window-below' and `split-window-right' respectively.
+*** 'split-window-vertically' and 'split-window-horizontally' renamed
+to 'split-window-below' and 'split-window-right' respectively.
 The old names are kept as aliases.
 
 *** Display actions
 
-**** The second arg to `display-buffer' and `pop-to-buffer' is now
+**** The second arg to 'display-buffer' and 'pop-to-buffer' is now
 named ACTION, and takes a display action of the same form as
-`display-buffer-base-action' (see Changes, above).  A non-nil,
+'display-buffer-base-action' (see Changes, above).  A non-nil,
 non-list value is treated specially, as the old meaning.
 
-**** New variable `display-buffer-overriding-action'.
+**** New variable 'display-buffer-overriding-action'.
 
-**** The procedure of `display-buffer' etc. to choose a window is
-determined by combining `display-buffer-overriding-action',
-`display-buffer-alist', the ACTION arg, `display-buffer-base-action',
-and `display-buffer-fallback-action'.  The second and fourth of these
+**** The procedure of 'display-buffer' etc. to choose a window is
+determined by combining 'display-buffer-overriding-action',
+'display-buffer-alist', the ACTION arg, 'display-buffer-base-action',
+and 'display-buffer-fallback-action'.  The second and fourth of these
 are user-customizable variables.
 
-See the docstring of `display-buffer' for details.
+See the docstring of 'display-buffer' for details.
 
-*** New functions `window-state-get' and `window-state-put'.
+*** New functions 'window-state-get' and 'window-state-put'.
 These functions allow to save and restore the state of an arbitrary
 frame or window as an Elisp object.
 
 ** Completion
 
-*** New variable `completion-extra-properties' used to specify extra
+*** New variable 'completion-extra-properties' used to specify extra
 properties of the current completion:
 - :annotation-function, same as the old completion-annotate-function.
 - :exit-function, function to call after completion took place.
 
-*** Functions on `completion-at-point-functions' can return any of the
-properties valid for `completion-extra-properties'.
+*** Functions on 'completion-at-point-functions' can return any of the
+properties valid for 'completion-extra-properties'.
 
-*** `completion-annotate-function' is obsolete.
+*** 'completion-annotate-function' is obsolete.
 
-*** New `metadata' method for completion tables.  The metadata thus returned
-can specify various details of the data returned by `all-completions':
-- `category' is the kind of objects returned (e.g., `buffer', `file', ...),
+*** New 'metadata' method for completion tables.  The metadata thus returned
+can specify various details of the data returned by 'all-completions':
+- 'category' is the kind of objects returned (e.g., 'buffer', 'file', ...),
   used to select a style in completion-category-overrides.
-- `annotation-function' to add annotations in *Completions*.
-- `display-sort-function' to specify how to sort entries in *Completions*.
-- `cycle-sort-function' to specify how to sort entries when cycling.
+- 'annotation-function' to add annotations in *Completions*.
+- 'display-sort-function' to specify how to sort entries in *Completions*.
+- 'cycle-sort-function' to specify how to sort entries when cycling.
 
-*** `minibuffer-local-filename-must-match-map' is not used any more.
-Instead, the bindings in `minibuffer-local-filename-completion-map'
-are combined with `minibuffer-local-must-match-map'.
+*** 'minibuffer-local-filename-must-match-map' is not used any more.
+Instead, the bindings in 'minibuffer-local-filename-completion-map'
+are combined with 'minibuffer-local-must-match-map'.
 
-*** New variable `completing-read-function' allows overriding the
-behavior of `completing-read'.
+*** New variable 'completing-read-function' allows overriding the
+behavior of 'completing-read'.
 
-** `glyphless-char-display' can now distinguish between graphical and
+** 'glyphless-char-display' can now distinguish between graphical and
 text terminal display, via a char-table entry that is a cons cell.
 
-** `pre-command-hook'/`post-command-hook' are not reset to nil on error.
+** 'pre-command-hook'/'post-command-hook' are not reset to nil on error.
 Instead, the offending function is removed.
 
 ** New hook types
 
-*** New function `run-hook-wrapped' for running an abnormal hook by
+*** New function 'run-hook-wrapped' for running an abnormal hook by
 passing the hook functions as arguments to a "wrapping" function.
-Like `run-hook-with-args-until-success', it stops at the first
+Like 'run-hook-with-args-until-success', it stops at the first
 non-nil return value.
 
-*** New macro `with-wrapper-hook' for running an abnormal hook as a
+*** New macro 'with-wrapper-hook' for running an abnormal hook as a
 set of "wrapping" filters, similar to around advice.
 (A version of this macro was actually added in Emacs 23.2 but was not
 advertised at the time.)
 
 ** Debugger changes
 
-*** New macro `condition-case-unless-debug'.
+*** New macro 'condition-case-unless-debug'.
 (This was actually added in Emacs 23.1 as condition-case-no-debug, but
 not advertised)
 
-*** The macro `with-demoted-errors'.
+*** The macro 'with-demoted-errors'.
 It was also added in Emacs 23.1, but not advertised.
 
-*** Variable `stack-trace-on-error' removed.
+*** Variable 'stack-trace-on-error' removed.
 
 *** The debugger can now "continue" from an error, which means it will
 jump to the error handler as if the debugger had not been invoked
 instead of jumping all the way to the top-level.
 
-*** Set `debug-on-event' to enter the debugger on events like SIGUSR1.
-This can be useful when `inhibit-quit' is set.
+*** Set 'debug-on-event' to enter the debugger on events like SIGUSR1.
+This can be useful when 'inhibit-quit' is set.
 
-** The new function `server-eval-at' allows evaluation of Lisp forms on
+** The new function 'server-eval-at' allows evaluation of Lisp forms on
 named Emacs server instances.
 
-** `call-process' and `call-process-region' allow a `(:file "file")' spec
+** 'call-process' and 'call-process-region' allow a '(:file "file")' spec
 to redirect STDOUT to a file.
 
-** The function `format-time-string' now supports the %N directive,
+** The function 'format-time-string' now supports the %N directive,
 for higher-resolution time stamps.
 
 ** New input reading functions
 
-*** New function `read-char-choice' reads a restricted set of
+*** New function 'read-char-choice' reads a restricted set of
 characters, discarding any inputs not inside the set.
 
-*** The command `read-color' now requires a match for a color name
+*** The command 'read-color' now requires a match for a color name
 or RGB triplet, instead of signaling an error if the user provides
 invalid input.
 
-**** `facemenu-read-color' is now an alias for `read-color'.
+**** 'facemenu-read-color' is now an alias for 'read-color'.
 
-** `image-library-alist' is renamed to `dynamic-library-alist'.
+** 'image-library-alist' is renamed to 'dynamic-library-alist'.
 The variable is now used to load all kind of supported dynamic libraries,
 not just image libraries.  The previous name is still available as an
 obsolete alias.
 
 ** Syntax parsing changes
 
-*** New variable `syntax-propertize-function'.
-This replaces `font-lock-syntactic-keywords' which is now obsolete.
+*** New variable 'syntax-propertize-function'.
+This replaces 'font-lock-syntactic-keywords' which is now obsolete.
 This allows syntax-table properties to be set independently from font-lock:
-just call syntax-propertize to make sure the text is propertized.
+just call 'syntax-propertize' to make sure the text is propertized.
 Together with this new variable come a new hook
-syntax-propertize-extend-region-functions, as well as two helper functions:
-syntax-propertize-via-font-lock to reuse old font-lock-syntactic-keywords
-as-is; and syntax-propertize-rules which provides a new way to specify
+'syntax-propertize-extend-region-functions', as well as two helper functions:
+'syntax-propertize-via-font-lock' to reuse old 'font-lock-syntactic-keywords'
+as-is; and 'syntax-propertize-rules' which provides a new way to specify
 syntactic rules.
 
 *** Syntax tables support a new "comment style c" additionally to style b.
 
-** New hook `post-self-insert-hook', run after `self-insert-command'.
+** New hook 'post-self-insert-hook', run after 'self-insert-command'.
 
 ** frame-local variables cannot be let-bound any more.
 
 ** Major and minor mode changes
 
-*** `set-auto-mode' now respects mode: local variables at the end of files,
+*** 'set-auto-mode' now respects mode: local variables at the end of files,
 as well as those in the -*- line.
 
-*** `prog-mode' is a new major mode from which programming modes
+*** 'prog-mode' is a new major mode from which programming modes
 should be derived.
 
-**** `prog-mode-hook' can be used to enable features for programming
-modes, e.g. (add-hook 'prog-mode-hook 'flyspell-prog-mode) to enable
+**** 'prog-mode-hook' can be used to enable features for programming
+modes, e.g. (add-hook 'prog-mode-hook #'flyspell-prog-mode) to enable
 on-the-fly spell checking for comments and strings.
 
-*** New hook `change-major-mode-after-body-hook', run by
-`run-mode-hooks' just before any other mode hooks.
+*** New hook 'change-major-mode-after-body-hook', run by
+'run-mode-hooks' just before any other mode hooks.
 
 *** Enabled globalized minor modes can be disabled in specific major modes.
 If the global mode is global-FOO-mode, then run (FOO-mode -1) in the
 major mode's hook, where FOO-mode toggles the mode on a per-buffer basis.
 
-*** `define-minor-mode' accepts new keywords :variable, :after-hook.
+*** 'define-minor-mode' accepts new keywords :variable, :after-hook.
 
 ** File-handling changes
 
-*** `delete-file' and `delete-directory' now accept optional arg TRASH.
-Trashing is performed if TRASH and `delete-by-moving-to-trash' are
+*** 'delete-file' and 'delete-directory' now accept optional arg TRASH.
+Trashing is performed if TRASH and 'delete-by-moving-to-trash' are
 both non-nil.  Interactively, TRASH defaults to t, unless a prefix
 argument is supplied (see Trash changes, above).
 
-*** New file predicates: `file-equal-p', `file-in-directory-p'.
+*** New file predicates: 'file-equal-p', 'file-in-directory-p'.
 
-*** New function `file-size-human-readable'.
+*** New function 'file-size-human-readable'.
 
 ** Tool-bars can display separators.
 Tool-bar separators are handled like menu separators in menu-bar maps,
-i.e. via menu entries of the form `(menu-item "--")'.
+i.e. via menu entries of the form '(menu-item "--")'.
 
 ** Image API
 
 *** Animated images support (currently animated gifs only).
 
-**** `image-animated-p' returns non-nil if an image can be animated.
+**** 'image-animated-p' returns non-nil if an image can be animated.
 
-**** `image-animate' animates a supplied image spec.
+**** 'image-animate' animates a supplied image spec.
 
-**** `image-animate-timer' returns the timer object for an image that
+**** 'image-animate-timer' returns the timer object for an image that
 is being animated.
 
-*** `image-extension-data' has been renamed to `image-metadata'.
+*** 'image-extension-data' has been renamed to 'image-metadata'.
 The old name is an obsolete alias to the new one.
 
 *** Image mode can view any image type that ImageMagick supports.
 This requires Emacs to be built with ImageMagick support.
 
-**** New function `imagemagick-types', defined if ImageMagick support
+**** New function 'imagemagick-types', defined if ImageMagick support
 is enabled, returns a list of image file extensions that your
 ImageMagick installation supports.
 
-**** New function `imagemagick-register-types' enables ImageMagick
-image types in Image mode and in `create-image' and other helper
+**** New function 'imagemagick-register-types' enables ImageMagick
+image types in Image mode and in 'create-image' and other helper
 functions.
 
-**** New option `imagemagick-types-inhibit' excludes certain
-ImageMagick image types from `imagemagick-register-types'.
+**** New option 'imagemagick-types-inhibit' excludes certain
+ImageMagick image types from 'imagemagick-register-types'.
 
 **** With ImageMagick support, there are extra Image mode commands to
-resize and rotate images: `image-transform-fit-to-height',
-`image-transform-fit-to-width', `image-transform-set-rotation', and
-`image-transform-set-scale'.
+resize and rotate images: 'image-transform-fit-to-height',
+'image-transform-fit-to-width', 'image-transform-set-rotation', and
+'image-transform-set-scale'.
 
-** `compose-mail' now accepts an optional 8th arg, RETURN-ACTION, and
+** 'compose-mail' now accepts an optional 8th arg, RETURN-ACTION, and
 passes it to the mail user agent function.  This argument specifies an
 action for returning to the caller after finishing with the mail.  For
 example, this is used by Rmail to optionally delete a mail window.
 
 ** XML and HTML parsing
 If Emacs is compiled with libxml2 support, there are two new
-functions: `libxml-parse-html-region' (which parses "real world" HTML)
-and `libxml-parse-xml-region' (which parses XML).  Both return an
+functions: 'libxml-parse-html-region' (which parses "real world" HTML)
+and 'libxml-parse-xml-region' (which parses XML).  Both return an
 Emacs Lisp parse tree.
 
 ** Networking and encryption changes
 
-*** `open-network-stream' can now be used to open an encrypted stream.
-It now accepts an optional `:type' parameter for initiating a TLS
+*** 'open-network-stream' can now be used to open an encrypted stream.
+It now accepts an optional ':type' parameter for initiating a TLS
 connection, directly or via STARTTLS.  To do STARTTLS, additional
-parameters (`:end-of-command', `:success', `:capabilities-command')
+parameters (':end-of-command', ':success', ':capabilities-command')
 must also be supplied.
 
 *** New library gnutls.el.
-The new function `gnutls-available-p' returns non-nil if Emacs is
+The new function 'gnutls-available-p' returns non-nil if Emacs is
 built with GnuTLS support.  The main entry points are
-`open-gnutls-stream' and `gnutls-negotiate'.  It's easiest to use
-these functions through `open-network-stream', because that can
+'open-gnutls-stream' and 'gnutls-negotiate'.  It's easiest to use
+these functions through 'open-network-stream', because that can
 upgrade connections through STARTTLS opportunistically or use plain
-SSL, depending on your needs.  For debugging, set `gnutls-log-level'
+SSL, depending on your needs.  For debugging, set 'gnutls-log-level'
 greater than 0.
 
-*** New primitive `secure-hash' that supports many secure hash algorithms:
+*** New primitive 'secure-hash' that supports many secure hash algorithms:
 md5, sha1, sha2, sha224, sha256, sha384, and sha512.  The lisp library
-sha1.el has been removed.  The `sha1' feature is provided by default.
+sha1.el has been removed.  The 'sha1' feature is provided by default.
 
 ** Isearch
 
-*** New hook `isearch-update-post-hook' that runs in `isearch-update'.
+*** New hook 'isearch-update-post-hook' that runs in 'isearch-update'.
 
 ** Progress reporters can now "spin".
-The MIN-VALUE and MAX-VALUE arguments of `make-progress-reporter' can
+The MIN-VALUE and MAX-VALUE arguments of 'make-progress-reporter' can
 now be nil, or omitted.  This makes a "non-numeric" reporter.  Each
-time you call `progress-reporter-update' on that progress reporter,
+time you call 'progress-reporter-update' on that progress reporter,
 with a nil or omitted VALUE argument, the reporter message is
 displayed with a "spinning bar".
 
-** New variable `revert-buffer-in-progress-p' is true while a buffer is
-being reverted, even if the buffer has a local `revert-buffer-function'.
+** New variable 'revert-buffer-in-progress-p' is true while a buffer is
+being reverted, even if the buffer has a local 'revert-buffer-function'.
 
-** New variables `delayed-warnings-list' and `delayed-warnings-hook'.
+** New variables 'delayed-warnings-list' and 'delayed-warnings-hook'.
 If delayed-warnings-list is non-nil, the command loop calls
-`delayed-warnings-hook' after `post-command-hook'.  At present, this
+'delayed-warnings-hook' after 'post-command-hook'.  At present, this
 is only used by Emacs on some platforms to display warnings during
 startup, which might otherwise not be noticed.  This uses the
-functions `display-delayed-warnings' and `collapse-delayed-warnings'.
+functions 'display-delayed-warnings' and 'collapse-delayed-warnings'.
 
-** rx.el has a new `group-n' construct for explicitly numbered groups.
+** rx.el has a new 'group-n' construct for explicitly numbered groups.
 
-** New function `make-composed-keymap' that constructs a new keymap
+** New function 'make-composed-keymap' that constructs a new keymap
 from multiple input maps.  You can use this to make a keymap that
 inherits from multiple maps, eg:
- (set-keymap-parent newmap (make-composed-keymap othermap parent))
+    (set-keymap-parent newmap (make-composed-keymap othermap parent))
 
-** New function `string-prefix-p'.
+** New function 'string-prefix-p'.
 (This was actually added in Emacs 23.2 but was not advertised at the time.)
 
 ** New reader macro ## that stands for the empty symbol.
@@ -3800,22 +3800,22 @@ This means that the empty symbol can now be read back.  
Also, #: by itself
 (when not immediately followed by a possible symbol character) stands for
 an empty uninterned symbol.
 
-** New math functions `isnan', `copysign', `frexp', `ldexp'.
+** New math functions 'isnan', 'copysign', 'frexp', 'ldexp'.
 
 ** The following functions and variables are obsolete:
 
-*** `tooltip-use-echo-area' is obsolete.
+*** 'tooltip-use-echo-area' is obsolete.
 Rather than setting this to t, disable Tooltip mode instead.
 
 *** buffer-substring-filters is obsolete.
-Use `filter-buffer-substring-functions' instead.
+Use 'filter-buffer-substring-functions' instead.
 
-*** `byte-compile-disable-print-circle' is obsolete.
+*** 'byte-compile-disable-print-circle' is obsolete.
 
-*** `deferred-action-list' and `deferred-action-function' are obsolete.
-Use `post-command-hook' instead.
+*** 'deferred-action-list' and 'deferred-action-function' are obsolete.
+Use 'post-command-hook' instead.
 
-*** `font-lock-maximum-size' is obsolete.
+*** 'font-lock-maximum-size' is obsolete.
 
 
 * Changes in Emacs 24.1 on Non-Free Operating Systems
@@ -3833,9 +3833,9 @@ and also when HOME is set to C:\ by default.
 
 *** --lib for general library linkage, works with the USER_LIBS build variable.
 
-** New make target `dist' to create binary distribution for MS Windows.
+** New make target 'dist' to create binary distribution for MS Windows.
 
-** The Lisp function `w32-default-color-map' is now obsolete.
+** The Lisp function 'w32-default-color-map' is now obsolete.
 (It is only used internally in the Emacs C code.)
 
 ** Customize ns-auto-hide-menu-bar to have the menu-bar hidden, but
diff --git a/etc/NEWS.25 b/etc/NEWS.25
index 21fcd052dc..d1e43e0538 100644
--- a/etc/NEWS.25
+++ b/etc/NEWS.25
@@ -550,8 +550,8 @@ When you invoke 'shell' interactively, the '*shell*' buffer 
will now
 display in a new window.  However, you can customize this behavior via
 the 'display-buffer-alist' variable.  For example, to get
 the old behavior -- '*shell*' buffer displays in current window -- use
-(add-to-list 'display-buffer-alist
-     '("^\\*shell\\*$" . (display-buffer-same-window))).
+    (add-to-list 'display-buffer-alist
+         '("\\`\\*shell\\*\\'" . (display-buffer-same-window))).
 
 ** EIEIO
 *** The ':protection' slot option is not obeyed any more.
@@ -1264,7 +1264,7 @@ SWITCH-BUFFER to 'completion-table-dynamic'.
 
 ** window-configurations no longer record the buffers' marks.
 
-** 'inhibit-modification-hooks' now also inhibits lock-file checks, as
+** 'inhibit-modification-hooks' now also inhibits 'lock-file' checks, as
 well as active region handling.
 
 ** 'deactivate-mark' is now buffer-local.
diff --git a/etc/NEWS.26 b/etc/NEWS.26
index a78baaea5f..50a711a0d1 100644
--- a/etc/NEWS.26
+++ b/etc/NEWS.26
@@ -736,7 +736,7 @@ keep previous behavior.
 
 ** html2text is now marked obsolete.
 
-** smerge-refine-regions can refine regions in separate buffers.
+** 'smerge-refine-regions' can refine regions in separate buffers.
 
 ** Info menu and index completion uses substring completion by default.
 This can be customized via the 'info-menu' category in
@@ -1506,7 +1506,7 @@ supported by the GnuTLS library used by Emacs.
 
 ** Emacs now supports records for user-defined types, via the new
 functions 'make-record', 'record', and 'recordp'.  Records are now
-used internally to represent cl-defstruct and defclass instances, for
+used internally to represent 'cl-defstruct' and 'defclass' instances, for
 example.
 
 If your program defines new record types, you should use
@@ -1798,11 +1798,11 @@ suitable for use in 'display-buffer-alist'.  For 
example, to avoid
 creating a new window when opening man pages when there's already one,
 use
 
-(add-to-list 'display-buffer-alist
-     '("\\`\\*Man .*\\*\\'" .
-       (display-buffer-reuse-mode-window
-        (inhibit-same-window . nil)
-        (mode . Man-mode))))
+    (add-to-list 'display-buffer-alist
+         '("\\`\\*Man .*\\*\\'" .
+           (display-buffer-reuse-mode-window
+            (inhibit-same-window . nil)
+            (mode . Man-mode))))
 
 *** New window parameter 'no-delete-other-windows' prevents that
 its window gets deleted by 'delete-other-windows'.
diff --git a/etc/NEWS.27 b/etc/NEWS.27
index 6e116533c5..f67a8c70d4 100644
--- a/etc/NEWS.27
+++ b/etc/NEWS.27
@@ -233,8 +233,8 @@ into the init file when Emacs was started.  This call can 
now safely
 be removed.  Alternatively, if you want to ensure that your init file
 is still compatible with earlier versions of Emacs, change it to:
 
-(when (< emacs-major-version 27)
-  (package-initialize))
+    (when (< emacs-major-version 27)
+      (package-initialize))
 
 However, if your init file changes the values of 'package-load-list'
 or 'package-user-dir', or sets 'package-enable-at-startup' to nil then
@@ -1761,7 +1761,7 @@ error.
 It can be used to set any buffer as the next one to be used by
 'next-error' and 'previous-error'.
 
-** nxml-mode
+** 'nxml-mode'
 
 *** The default value of 'nxml-sexp-element-flag' is now t.
 This means that pressing 'C-M-SPACE' now selects the entire tree by
@@ -2285,7 +2285,7 @@ Unqualified host name: (was none), now %q
 Login name: was %u, now %l
 User's full name: was %U, now %L
 
-Merely having '(add-hook 'before-save-hook 'time-stamp)' in your
+Merely having '(add-hook 'before-save-hook #'time-stamp)' in your
 Emacs init file does not expose you to this change.  However,
 if you set 'time-stamp-format' or 'time-stamp-pattern' with a
 file-local variable, you may need to update the value.
@@ -2400,7 +2400,7 @@ expansion to backtrace buffers produced by the Lisp 
debugger, Edebug
 and ERT.  See the node "(elisp) Backtraces" in the Elisp manual for
 documentation of the new mode and its commands.
 
-** so-long.el helps to mitigate performance problems with long lines.
+** 'so-long' helps to mitigate performance problems with long lines.
 When 'global-so-long-mode' has been enabled, visiting a file with very
 long lines will (subject to configuration) cause the user's preferred
 'so-long-action' to be automatically invoked (by default, the buffer's
@@ -2599,8 +2599,8 @@ available by scrolling with the meta modifier key.
 To get the old behavior back, customize the user option
 'mouse-wheel-scroll-amount', or add the following to your init file:
 
-(customize-set-variable 'mouse-wheel-scroll-amount
-                        '(5 ((shift) . 1) ((control) . nil)))
+    (customize-set-variable 'mouse-wheel-scroll-amount
+                            '(5 ((shift) . 1) ((control) . nil)))
 
 By default, the font size will be changed in the window that the mouse
 pointer is over.  To change this behavior, you can customize the user
diff --git a/etc/NEWS.28 b/etc/NEWS.28
index 2efa881b2f..01e8ac112f 100644
--- a/etc/NEWS.28
+++ b/etc/NEWS.28
@@ -18,6 +18,24 @@ with a prefix argument or by typing 'C-u C-h C-n'.
 
 * Installation Changes in Emacs 28.2
 
+** To install the Emacs binary in a non-standard directory, use '--bindir='.
+If you install Emacs in a way that places the Emacs executable file in
+a directory other than "${prefix}/bin", you will now need to specify
+that at configure time, if you build Emacs with native-compilation
+support.  To this end, add the '--bindir=DIRECTORY' switch to the
+command line of the 'configure' script, where DIRECTORY is the
+directory in which you will install the executable file "emacs".  This
+is required even if you place a symlink under "${prefix}/bin" that
+points to the real executable file in some other DIRECTORY.
+
+It is no longer enough to specify 'bindir=DIRECTORY' on the command
+line of the "make install" command.
+
+The reason for this new requirement is that Emacs needs to locate at
+startup the directory with its "*.eln" natively-compiled files for the
+preloaded Lisp packages, and the relative name of that directory needs
+therefore to be recorded in the executable as part of the build.
+
 
 * Startup Changes in Emacs 28.2
 
@@ -1431,7 +1449,7 @@ the entire buffer.
 
 *** 'so-long-target-modes' now includes 'fundamental-mode' by default.
 This means that 'global-so-long-mode' will also process files which were
-not recognised.  (This only has an effect if 'set-auto-mode' chooses
+not recognized.  (This only has an effect if 'set-auto-mode' chooses
 'fundamental-mode'; buffers which are simply in 'fundamental-mode' by
 default are unaffected.)
 
@@ -1659,7 +1677,7 @@ and variables.
 
 *** Lisp mode now uses 'common-lisp-indent-function'.
 To revert to the previous behavior,
-'(setq lisp-indent-function 'lisp-indent-function)' from 'lisp-mode-hook'.
+'(setq lisp-indent-function #'lisp-indent-function)' from 'lisp-mode-hook'.
 
 ** Change Logs and VC
 
@@ -1745,8 +1763,8 @@ If non-nil (the default), create registry entries for all 
messages.
 If nil, don't automatically create entries, they must be created
 manually.
 
-*** New user options to customise the summary line specs "%[" and "%]".
-Four new options introduced in customisation group
+*** New user options to customize the summary line specs "%[" and "%]".
+Four new options introduced in customization group
 'gnus-summary-format'.  These are 'gnus-sum-opening-bracket',
 'gnus-sum-closing-bracket', 'gnus-sum-opening-bracket-adopted', and
 'gnus-sum-closing-bracket-adopted'.  Their default values are "[", "]",
@@ -2084,7 +2102,7 @@ modified flag.  The default is nil, to preserve the old 
behavior.
 ** CC mode
 
 *** Added support for Doxygen documentation style.
-'doxygen' is now a valid 'c-doc-comment-style' which recognises all
+'doxygen' is now a valid 'c-doc-comment-style' which recognizes all
 comment styles supported by Doxygen (namely '///', '//!', '/** … */'
 and '/*! … */'.  'gtkdoc' remains the default for C and C++ modes; to
 use 'doxygen' by default one might evaluate:
@@ -2808,7 +2826,7 @@ different timezone causing a difference in the date.
 
 *** 'mspools-show' is now autoloaded.
 
-*** Loading dunnet.el in batch mode doesn't start the game any more.
+*** Loading 'dunnet' in batch mode doesn't start the game any more.
 Instead you need to do "emacs --batch -f dunnet" to start the game in
 batch mode.
 
@@ -3150,9 +3168,9 @@ ledit.el, lmenu.el, lucid.el and old-whitespace.el.
 'nnmail-fix-eudora-headers', 'non-iso-charset-alist',
 'nonascii-insert-offset', 'nonascii-translation-table',
 'password-read-and-add', 'pre-abbrev-expand-hook', 'princ-list',
-'print-help-return-message', 'process-filter-multibyte-p',
-'read-file-name-predicate', 'remember-buffer', 'rmail-highlight-face',
-'rmail-message-filter', 'semantic-after-idle-scheduler-reparse-hooks',
+'print-help-return-message', 'read-file-name-predicate',
+'remember-buffer', 'rmail-highlight-face', 'rmail-message-filter',
+'semantic-after-idle-scheduler-reparse-hooks',
 'semantic-after-toplevel-bovinate-hook',
 'semantic-before-idle-scheduler-reparse-hooks',
 'semantic-before-toplevel-bovination-hook',
@@ -3178,9 +3196,9 @@ ledit.el, lmenu.el, lucid.el and old-whitespace.el.
 'semantic-something-to-stream', 'semantic-tag-make-assoc-list',
 'semantic-token-type-parent', 'semantic-toplevel-bovine-cache',
 'semantic-toplevel-bovine-table', 'semanticdb-mode-hooks',
-'set-coding-priority', 'set-process-filter-multibyte',
-'shadows-compare-text-p', 'shell-dirtrack-toggle',
-'speedbar-navigating-speed', 'speedbar-update-speed', 't-mouse-mode',
+'set-coding-priority', 'shadows-compare-text-p',
+'shell-dirtrack-toggle', 'speedbar-navigating-speed',
+'speedbar-update-speed', 't-mouse-mode',
 'term-dynamic-simple-complete', 'tooltip-hook', 'tpu-have-ispell',
 'url-generate-unique-filename', 'url-temporary-directory',
 'vc-arch-command', 'vc-default-working-revision' (variable),
diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS
index 37a39131d9..3c164b1282 100644
--- a/etc/ORG-NEWS
+++ b/etc/ORG-NEWS
@@ -293,7 +293,7 @@ with width equal to the pixel-width of the buffer text 
multiplied by 0.7.
 This functionality is implemented in a new function,
 ~org-display-inline-image--width~ which contains the width
 determination logic previously in ~org-display-inline-images~ and the
-new behaviour.
+new behavior.
 
 ** New options
 *** Option ~org-hidden-keywords~ now also applies to #+SUBTITLE:
@@ -311,7 +311,7 @@ descriptions.
 *** New option ~org-id-ts-format~
 
 Earlier, IDs generated using =ts= method had a hard-coded format (i.e. 
=20200923T160237.891616=).
-The new option allows user to customise the format.
+The new option allows user to customize the format.
 Defaults are unchanged.
 
 *** New argument for ~file-desc~ babel header
@@ -503,16 +503,16 @@ heading, except return nil.
 
 *** Faces of all the heading text elements now conform to the headline face
 
-In the past, faces of todo keywords, emphasised text, tags, and
+In the past, faces of todo keywords, emphasized text, tags, and
 priority cookies inherited =default= face.  The resulting headline
 fontification was not always consistent, as discussed in 
[[msg::87h7sawubl.fsf@protesilaos.com][this bug
 report]].  Now, the relevant faces adapt to face used to fontify the
 current headline level.
 
-Users who prefer to keep the old behaviour should change their face
-customisation explicitly stating that =default= face is inherited.
+Users who prefer to keep the old behavior should change their face
+customization explicitly stating that =default= face is inherited.
 
-Example of old face customisation:
+Example of old face customization:
 
 #+begin_src emacs-lisp
 (setq org-todo-keyword-faces '(("TODO"
@@ -520,7 +520,7 @@ Example of old face customisation:
                                 :height 0.75)))
 #+end_src
 
-To preserve the old behaviour the above customisation should be
+To preserve the old behavior the above customization should be
 changed to
 
 #+begin_src emacs-lisp
@@ -543,7 +543,7 @@ The function does not allow for a third optional parameter 
anymore.
 *** LaTeX environment =#+results= are now removed
 
 If a babel src block produces a raw LaTeX environment, it will now be
-recognised as a result, and so replaced when re-evaluated.
+recognized as a result, and so replaced when re-evaluated.
 
 *** Tag completion now uses =completing-read-multiple=
 
@@ -681,7 +681,7 @@ enabled, and point is neither in a table nor on a timestamp 
or a link:
 - =C-j= (bound to the new command ~org-return-and-maybe-indent~)
   merely inserts a newline.
 
-To get the previous behaviour back, disable ~electric-indent-mode~
+To get the previous behavior back, disable ~electric-indent-mode~
 explicitly:
 
 #+begin_src emacs-lisp
@@ -1029,7 +1029,7 @@ Previously all session names had  ~org-babel-session-~ 
prepended.
 *** Forward/backward paragraph functions in line with the rest of Emacs
 
 ~org-forward-paragraph~ and ~org-backward-paragraph~, bound to
-~<C-UP>~ and ~<C-DOWN>~ functions mimic more closely behaviour of
+~<C-UP>~ and ~<C-DOWN>~ functions mimic more closely behavior of
 ~forward-paragraph~ and ~backward-paragraph~ functions when
 available.
 
diff --git a/etc/PROBLEMS b/etc/PROBLEMS
index 018efcf302..6624f747c8 100644
--- a/etc/PROBLEMS
+++ b/etc/PROBLEMS
@@ -568,12 +568,6 @@ This can happen with CVS versions 1.12.8 and 1.12.9.  
Upgrade to CVS
 
 ** Miscellaneous problems
 
-*** Editing files with very long lines is slow.
-
-For example, simply moving through a file that contains hundreds of
-thousands of characters per line is slow, and consumes a lot of CPU.
-This is a known limitation of Emacs with no solution at this time.
-
 *** Display artifacts on GUI frames on X-based systems.
 
 This is known to be caused by using double-buffering (which is enabled
@@ -729,13 +723,52 @@ time.  Possible reasons for this include:
 To work around the problem, you could use Git or some other
 free-software program, instead of ClearCase.
 
-*** ps-print commands fail to find prologue files ps-prin*.ps.
-
-This can happen if you use an old version of X-Symbol package: it
-defines compatibility functions which trick ps-print into thinking it
-runs in XEmacs, and look for the prologue files in a wrong directory.
-
-The solution is to upgrade X-Symbol to a later version.
+*** Various commands that visit files on networked filesystems fail.
+
+This could happen if the filesystem of those files is mounted in a way
+that causes the files to be accessed via a symlink.  One such example
+is the 'amd' automounter, which unmounts the filesystem after some
+period of lack of use.  Another example is Emacs running on MS-Windows
+that accesses files on remote server via symlinks whose target is a
+UNC of the form '\\server\share'.
+
+The reason for these problems is that some Emacs commands visit files
+via their truename, resolving the symlink, which causes these files'
+default-directory to also have the symlink resolved.  If the resolved
+directory has access problems, subsequent commands from that file's
+buffer could fail.  For example, the stock MS-Windows shell 'cmd.exe'
+is unable to use a UNC-form directory as the current directory, so
+'shell-command' and its callers will typically fail.  Similarly with
+using targets of symlinks which no longer mount the remote filesystem
+will fail.
+
+You can solve these problems in several ways:
+
+  - Write a 'find-file'hook' function which will change the value of
+    'default-directory' to reference the symlink instead of its
+    target.
+
+  - Set up 'directory-abbrev-alist' to automatically convert the
+    'default-directory' of such files in the same manner.
+
+  - On MS-Windows, map a drive letter to the '\\server\share'
+    directory and point your symlinks to a directory name that uses
+    the drive letter.
+
+*** On MS-Windows, visiting files in OneDrive fails.
+
+This is known to happen when OneDrive is accessed via the so-called
+"metered connections", whose use is charged by the volume of
+transferred data.  Those are typically wireless links using a modem or
+a mobile phone.  In these cases, files that are left in the cloud and
+not downloaded to the local computer can produce various failures in
+system calls that access the files or their meta-data.
+
+The solution is to disable the "metered connection" status from the
+WiFi properties (reachable from the Windows Settings menu).  This will
+cause files to be downloaded to the local computer when they are
+accessed (which could take some time, and Emacs functions accessing
+the file will wait for that), avoiding the errors.
 
 *** On systems with shared libraries you might encounter run-time errors
 from the dynamic linker telling you that it is unable to find some
@@ -1318,6 +1351,17 @@ command:
 
 ** Window-manager and toolkit-related problems
 
+*** Emacs built with GTK+ displays giant tool bar icons in some cases
+
+This is because some icon themes (such as the KDE Breeze icon theme)
+have several incorrectly sized icons, which also causes the toolbar to
+expand uncontrollably.  The fix is to switch to a different icon
+theme, or to use Emacs's own toolbar icons by placing:
+
+  (setq x-gtk-stock-map nil)
+
+in your early-init.el.
+
 *** Emacs built with GTK+ toolkit produces corrupted display on HiDPI screen
 
 This can happen if you set GDK_SCALE=2 in the environment or in your
@@ -1768,7 +1812,15 @@ This happens on the proprietary X server ASTEC-X when 
the number of
 monitors is changed after the server has started.  A workaround is to
 restart the X server after the monitor configuration has been changed.
 
-*** Touchpad gestures don't work and emit warning messages.
+*** Touchpad gestures don't work and/or emit warning messages.
+
+Support for touch gestures in Emacs requires a sufficiently new X
+server.  We currently know of only one: version 21.1.0 or later of the
+X.Org server, coupled with the xf86-input-libinput input driver.
+
+Type 'M-: (x-server-input-extension-version) RET'; if that doesn't
+return '(2 4)' (version 2.4) or later, your version of the X server
+and libraries are too old and need to be upgraded.
 
 When pinching or swiping on your touchpad, you might see a warning
 message that looks like:
@@ -2277,8 +2329,23 @@ terminals display them as 1-column glyphs.  Again, this 
causes cursor
 addressing to get out of sync and eventually messes up the display.
 
 One possible workaround for problems caused by character composition
-is to turn off 'auto-composition-mode' on Kitty terminals.
+is to turn off 'auto-composition-mode' on Kitty terminals, e.g. by
+customizing the 'auto-composition-mode' variable to have as value a
+string that the 'tty-type' function returns on those terminals.
+
+*** Display artifacts on the Alacritty text terminal
+
+This terminal is known to cause problems with Emoji sequences: when
+displaying them, the Emacs text-mode frame could show gaps and other
+visual artifacts.
+
+The solution is to disable 'auto-composition-mode' on these
+terminals, for example, like this:
+
+  (setq auto-composition-mode "alacritty")
 
+This disables 'auto-composition-mode' on frames that display on
+terminals of this type.
 
 * Runtime problems specific to individual Unix variants
 
@@ -2540,6 +2607,11 @@ Emacs so that it isn't compiled with '-O5'.
 We list bugs in current versions here.  See also the section on legacy
 systems.
 
+*** On Solaris 10 sparc, Emacs crashes during the build while saving state.
+This was observed for Emacs 28.1 on Solaris 10 32-bit sparc, with
+Oracle Developer Studio 12.6 (Sun C 5.15).  The failure was intermittent,
+and running GNU Make a second time would typically finish the build.
+
 *** On Solaris 10, Emacs crashes during the build process.
 (This applies only with './configure --with-unexec=yes', which is rare.)
 This was reported for Emacs 25.2 on i386-pc-solaris2.10 with Sun
@@ -2957,6 +3029,72 @@ please call support for your X-server and see if you can 
get a fix.
 If you do, please send it to bug-gnu-emacs@gnu.org so we can list it here.
 
 
+* Runtime problems specific to Cygwin
+
+** Fork failures in a build with native compilation
+
+To prevent fork failures, shared libraries on Cygwin need to be
+rebased occasionally, for the reasons explained here:
+
+  https://cygwin.com/cygwin-ug-net/highlights.html#ov-hi-process-problems
+
+This includes the .eln files produced by an Emacs built with native
+compilation.
+
+Rebasing is handled by Cygwin's autorebase postinstall script every
+time you run the Cygwin setup program (which you should do with no
+Cygwin processes running).  This script knows about the .eln files
+installed in the standard places (e.g.,
+/usr/lib/emacs/28.1/native-lisp), but it does not know about those in
+your user cache (e.g., /home/<username>/.emacs.d/eln-cache).  In order
+for these to be automatically rebased, you must create a file
+
+  /var/lib/rebase/userpath.d/<username>
+
+with one line for each directory containing .eln files.  If you are
+running an installed Emacs, it should suffice to list your cache
+directory.  For example, if there is an Emacs user "kbrown", then
+there should be a file
+
+  /var/lib/rebase/userpath.d/kbrown
+
+containing the single line
+
+  /home/kbrown/.emacs.d/eln-cache
+
+If you are running an Emacs that you have built but not installed,
+then you will need an additional line giving the path to the
+native-lisp subdirectory of your build directory.
+
+If more than one user will be using Emacs on your system, there should
+be a file like this for each user.
+
+Rebasing is not currently done when new .eln files are created, so
+fork failures are still possible between runs of Cygwin's setup
+program.  If you ever see a fork failure whose error message refers to
+a .eln file, you should be able to fix it temporarily by exiting emacs
+and issuing the command
+
+   find ~/.emacs.d/eln-cache -name '*.eln' | rebase -O -T -
+
+This is called an "ephemeral" rebase.  Again, if you are running an
+Emacs that has not been installed, you need to add the native-lisp
+subdirectory of your build directory to this command.  Alternatively,
+stop all Cygwin processes and run Cygwin's setup program to let the
+autorebase postinstall script run.
+
+It is hoped that the measures above will make native compilation
+usable on 64-bit Cygwin, with only an occasional minor annoyance.  In
+the 32-bit case, however, the limited address space makes frequent
+fork failures extremely likely.  It is therefore strongly recommended
+that you not build Emacs with native compilation on 32-bit Cygwin.
+Indeed, the configure script will not allow this unless you use the
+--with-cygwin32-native-compilation option.
+
+See bug#50666 (https://debbugs.gnu.org/cgi/bugreport.cgi?bug=50666)
+for further discussion.
+
+
 * Runtime problems specific to macOS
 
 ** Error message when opening Emacs on macOS
@@ -3011,6 +3149,17 @@ file; for example:
 
 * Runtime problems specific to PGTK
 
+** Giant tool bar icons are displayed in some cases
+
+This is because some icon themes (such as the KDE Breeze icon theme)
+have several incorrectly sized icons, which also causes the toolbar to
+expand uncontrollably.  The fix is to switch to a different icon
+theme, or to use Emacs's own toolbar icons by placing:
+
+  (setq x-gtk-stock-map nil)
+
+in your early-init.el.
+
 ** Some modifier keys doesn't work if Emacs is started in a systemd unit file.
 
 Environment variables may be different if there is a difference in the
@@ -3286,14 +3435,6 @@ The fix is to install a newer version of ncurses, such 
as version 4.2.
 Bootstrapping (compiling the .el files) is normally only necessary
 with development builds, since the .elc files are pre-compiled in releases.
 
-*** "No rule to make target" with Ubuntu 8.04 make 3.81-3build1
-
-Compiling the lisp files fails at random places, complaining:
-"No rule to make target '/path/to/some/lisp.elc'".
-The causes of this problem are not understood.  Using GNU make 3.81 compiled
-from source, rather than the Ubuntu version, worked.
-See <URL:https://debbugs.gnu.org/327>, <URL:https://debbugs.gnu.org/821>.
-
 ** Dumping
 
 *** Segfault during 'make'
@@ -3412,21 +3553,21 @@ as a macro.  If the definition (in both unex*.c and 
malloc.c) is wrong,
 it can cause problems like this.  You might be able to find the correct
 value in the man page for a.out(5).
 
-* 'make check' failures
-
-** emacs-module-tests fail on Ubuntu 16.04
-
-This is due to a bug in GCC that was fixed in 2015; see
-<https://lists.gnu.org/r/emacs-devel/2018-09/msg00548.html>.
-You can work around the problem by using a later version of GCC or of
-Ubuntu, or by configuring without modules.
-
 * Problems on legacy systems
 
 This section covers bugs reported on very old hardware or software.
 If you are using hardware and an operating system shipped after 2000,
 it is unlikely you will see any of these.
 
+** GNU/Linux
+
+*** Ubuntu 8.04 make 3.81-3build1: "No rule to make target"
+Compiling the lisp files fails at random places, complaining:
+"No rule to make target '/path/to/some/lisp.elc'".
+The causes of this problem are not understood.  Using GNU make 3.81 compiled
+from source, rather than the Ubuntu version, worked.
+See <URL:https://debbugs.gnu.org/327>, <URL:https://debbugs.gnu.org/821>.
+
 ** Solaris
 
 *** Problem with remote X server on Suns.
diff --git a/etc/TODO b/etc/TODO
index 2f23d410a7..772fbf7191 100644
--- a/etc/TODO
+++ b/etc/TODO
@@ -130,11 +130,6 @@ See also ESR's proposal for a BROWSER environment variable
 ** In Custom buffers, put the option that turns a mode on or off first
 This should use a heuristic of some kind?
 
-** Define recompute-arg and recompute-arg-if for fix_command to use
-See rms message of 11 Dec 05 in
-https://lists.gnu.org/r/emacs-pretest-bug/2005-12/msg00165.html,
-and the rest of that discussion.
-
 ** In Emacs Info, examples of using Customize should be clickable
 They should create Custom buffers when clicked.
 
@@ -722,8 +717,6 @@ bar.  In the mean time, it should process other messages.
 
 ** Get some major packages installed
 
-*** W3 (development version needs significant work)
-
 *** PSGML, _possibly_ ECB
 https://lists.gnu.org/r/emacs-devel/2007-05/msg01493.html Check the
 assignments file for other packages which might go in and have been
@@ -803,10 +796,10 @@ artist, ansi-color, array, calculator, cdl, cmuscheme, 
completion,
 delim-col, dirtrack, double, echistory, elide-head, easymenu, expand,
 flow-ctrl, format [format-alist], generic/generic-x [various modes],
 kermit, log-edit, makesum, midnight [other than in Kill Buffer node],
-mouse-copy [?], mouse-drag, mouse-sel, net-utils, rcompile, snmp-mode
+mouse-copy [?], mouse-drag, mouse-sel, net-utils, snmp-mode
 [?], soundex [should be interactive?], strokes [start from the web
 page], talk, thingatpt [interactive functions?], type-break, vcursor,
-xscheme, zone-mode [?], mlconvert [?], iso-cvt, feedmail [?], uce,
+xscheme, zone-mode [?], mlconvert [?], iso-cvt, feedmail [?],
 gametree, page-ext, refbib, refer, scribe, texinfo, underline,
 cmacexp, hideif, pcomplete, xml, cvs-status (should be described in
 PCL-CVS manual); other progmodes, probably in separate manual.
@@ -1715,17 +1708,8 @@ apparently loses under Solaris, at least. [fx has mostly 
done this.]
 
 (Obsolete, since gmalloc.c is nowadays only used on MS-DOS.)
 
-** Rewrite make-docfile to be clean and maintainable
-It might be better to replace with Lisp the part of make-docfile that
-produces the etc/DOC file by scanning *.el files, for example by
-reusing the code in the byte compiler or in autoload.el that already
-scans *.el files.
-https://lists.gnu.org/r/emacs-devel/2012-06/msg00037.html
-https://lists.gnu.org/r/emacs-devel/2021-05/msg00235.html
-
 ** Eliminate the etc/DOC file altogether
-As an alternative to the previous item, we could try and eliminate the
-DOC file altogether.  See
+We could try and eliminate the DOC file altogether.  See
 https://lists.gnu.org/r/emacs-devel/2021-05/msg00237.html
 
 ** Add an inferior-comint-minor-mode
@@ -1757,6 +1741,19 @@ for vc-rcs-update-changelog.
 A two-char comment-starter whose two chars are symbol constituents will
 not be noticed if it appears within a word.
 
+** Multi-pointer X does not work very well
+Emacs is reasonably usable under a multi-pointer X (MPX) environment,
+if you turn off tooltips and mouse highlight, and don't use anything
+that calls `mouse-position'.  Otherwise, tooltips are shown next to
+the wrong pointer, mouse highlight simply goes haywire, and
+`mouse-position' returns information for the wrong pointer.
+
+This could be easily fixed in principle, but I cannot find a stable
+enough environment under which the fix can be tested.
+
+The MPX code has not been tested under X toolkit or GTK+ 2.x builds
+and is not expected to work there.
+
 
 This file is part of GNU Emacs.
 
diff --git a/etc/compilation.txt b/etc/compilation.txt
index 5601ce272a..fc254dd3d7 100644
--- a/etc/compilation.txt
+++ b/etc/compilation.txt
@@ -193,6 +193,15 @@ symbol: gradle-kotlin
 e: /src/Test.kt: (34, 15): foo: bar
 w: /src/Test.kt: (34, 15): foo: bar
 
+* Gradle Android resource linking
+
+symbol: gradle-android
+
+Execution failed for task ':app:processDebugResources'.
+> A failure occurred while executing 
com.android.build.gradle.internal.res.LinkApplicationAndroidResourcesTask$TaskAction
+   > Android resource linking failed
+     
ERROR:/Users/salutis/src/AndroidSchemeExperiment/app/build/intermediates/incremental/debug/mergeDebugResources/stripped.dir/layout/item.xml:3:
 AAPT: error: '16dpw' is incompatible with attribute padding (attr) dimension.
+
 
 * IAR Systems C Compiler
 
@@ -424,7 +433,7 @@ symbol: oracle
 
 This stupid precompiler wraps lines at column 80 in the middle of a file name.
 There is no obvious way of detecting this or turning it off.  But if you
-delete the newline (probably needs M-x toggle-read-only), the file name will
+delete the newline (probably needs M-x read-only-mode), the file name will
 automatically be reparsed, so that you can then go there.
 
 Semantic error at line 528, column 5, file erosacqdb.pc:
@@ -542,7 +551,7 @@ cf90-113 f90comp: ERROR NSE, File = Hoved.f90, Line = 16, 
Column = 3
 * ShellCheck
 
 In autogen.sh line 38:
-autoconf_min=`sed -n 's/^ *AC_PREREQ(\([0-9\.]*\)).*/\1/p' configure.ac`
+autoconf_min=`sed -n 's/^ *AC_PREREQ(\[\([0-9\.]*\)]).*/\1/p' configure.ac`
 ^----------^ SC2034: autoconf_min appears unused. Verify use (or export if 
used externally).
              ^-- SC2006: Use $(...) notation instead of legacy backticked 
`...`.
 
diff --git a/etc/emacs_lldb.py b/etc/emacs_lldb.py
new file mode 100644
index 0000000000..a2329e6ea4
--- /dev/null
+++ b/etc/emacs_lldb.py
@@ -0,0 +1,254 @@
+# 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, 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/>.
+
+# Load this module in LLDB with
+#
+# (lldb) command script import emacs_lldb
+#
+# Available commands start with 'x' and can be seen with
+#
+# (lldb) help
+
+import lldb
+
+
+########################################################################
+#                              Utilities
+########################################################################
+
+# Return the name of enumerator ENUM as a string.
+def enumerator_name(enum):
+    enumerators = enum.GetType().GetEnumMembers()
+    for enum_member in enumerators:
+        if enum.GetValueAsUnsigned() == enum_member.GetValueAsUnsigned():
+            return enum_member.GetName()
+    return None
+
+# A class wrapping an SBValue for a Lisp_Object, providing convenience
+# functions.
+class Lisp_Object:
+    # Map pvec_type enumerators to corresponding C types.
+    pvec2type = {
+        "PVEC_FRAME": "struct frame",
+        "PVEC_WINDOW": "struct window",
+        "PVEC_BIGNUM": "struct Lisp_Bignum",
+        "PVEC_MARKER": "struct Lisp_Marker",
+        "PVEC_OVERLAY": "struct Lisp_Overlay",
+        "PVEC_FINALIZER": "struct Lisp_Finalizer",
+        "PVEC_SYMBOL_WITH_POS": "struct Lisp_Symbol_With_Pos",
+        "PVEC_MISC_PTR": "",
+        "PVEC_USER_PTR": "struct Lisp_User_Ptr",
+        "PVEC_PROCESS": "struct Lisp_Process",
+        "PVEC_BOOL_VECTOR": "struct Lisp_Bool_Vector",
+        "PVEC_BUFFER": "struct buffer",
+        "PVEC_HASH_TABLE": "struct Lisp_Hash_Table",
+        "PVEC_TERMINAL": "struct terminal",
+        "PVEC_WINDOW_CONFIGURATION": "struct save_window_data",
+        "PVEC_SUBR": "struct Lisp_Subr",
+        "PVEC_OTHER": "void",
+        "PVEC_XWIDGET": "void",
+        "PVEC_XWIDGET_VIEW": "void",
+        "PVEC_THREAD": "struct thread_state",
+        "PVEC_MUTEX": "Lisp_Mutex",
+        "PVEC_CONDVAR": "Lisp_CondVar",
+        "PVEC_MODULE_FUNCTION": "struct Lisp_Module_Function",
+        "PVEC_NATIVE_COMP_UNIT": "struct Lisp_Native_Comp_Unit",
+        "PVEC_SQLITE": "struct Lisp_Sqlite",
+        "PVEC_COMPILED": "struct Lisp_Vector",
+        "PVEC_CHAR_TABLE": "struct Lisp_Vector",
+        "PVEC_SUB_CHAR_TABLE": "void",
+        "PVEC_RECORD": "struct Lisp_Vector",
+        "PVEC_FONT": "struct font",
+        "PVEC_NORMAL_VECTOR": "struct Lisp_Vector"
+    }
+
+    # Object construction/initialization.
+    def __init__(self, lisp_obj):
+        self.lisp_obj = lisp_obj
+        self.frame = lisp_obj.GetFrame()
+        self.lisp_type = None
+        self.pvec_type = None
+        self.value = None
+        self.init_unsigned()
+        self.init_lisp_types()
+        self.init_values()
+
+    def init_unsigned(self):
+        if self.lisp_obj.GetNumChildren() != 0:
+            # Lisp_Object is actually a struct.
+            lisp_word = self.lisp_obj.GetValueForExpressionPath(".i")
+            self.unsigned = lisp_word.GetValueAsUnsigned()
+        else:
+            self.unsigned = self.lisp_obj.GetValueAsUnsigned()
+
+    # Initialize self.lisp_type to the C Lisp_Type enumerator of the
+    # Lisp_Object, as a string.  Initialize self.pvec_type likewise to
+    # the pvec_type enumerator if the object is a vector-like, as a
+    # string.
+    def init_lisp_types(self):
+        t = self.eval(f"(enum Lisp_Type)"
+                      f"((EMACS_INT) {self.unsigned} "
+                      f"& (1 << GCTYPEBITS) - 1)")
+        self.lisp_type = enumerator_name(t)
+        if self.lisp_type == "Lisp_Vectorlike":
+            self.pvec_type = "PVEC_NORMAL_VECTOR"
+            vector = self.get_lisp_pointer("struct Lisp_Vector")
+            size = vector.GetValueForExpressionPath("->header.size")
+            size = size.GetValueAsUnsigned()
+            pseudo = self.eval(f"{size} & PSEUDOVECTOR_FLAG")
+            if pseudo.GetValueAsUnsigned() != 0:
+                typ = self.eval(
+                    f"(enum pvec_type) (({size} "
+                    f"& More_Lisp_Bits::PVEC_TYPE_MASK) "
+                    f">> More_Lisp_Bits::PSEUDOVECTOR_AREA_BITS)")
+                self.pvec_type = enumerator_name(typ)
+
+    # Initialize self.value according to lisp_type and pvec_type.
+    def init_values(self):
+        if self.lisp_type == "Lisp_Symbol":
+            offset = self.get_lisp_pointer("char").GetValueAsUnsigned()
+            self.value = self.eval(f"(struct Lisp_Symbol *)"
+                                   f" ((char *) &lispsym + {offset})")
+        elif self.lisp_type == "Lisp_String":
+            self.value = self.get_lisp_pointer("struct Lisp_String")
+        elif self.lisp_type == "Lisp_Vectorlike":
+            c_type = Lisp_Object.pvec2type[self.pvec_type]
+            self.value = self.get_lisp_pointer(c_type)
+        elif self.lisp_type == "Lisp_Cons":
+            self.value = self.get_lisp_pointer("struct Lisp_Cons")
+        elif self.lisp_type == "Lisp_Float":
+            self.value = self.get_lisp_pointer("struct Lisp_Float")
+        elif self.lisp_type in ("Lisp_Int0", "Lisp_Int1"):
+            self.value = self.eval(f"((EMACS_INT) {self.unsigned}) "
+                                   f">> (GCTYPEBITS - 1)")
+        else:
+            assert False, "Unknown Lisp type"
+
+    # Create an SBValue for EXPR with name NAME.
+    def create_value(self, name, expr):
+        return self.lisp_obj.CreateValueFromExpression(name, expr)
+
+    # Evaluate EXPR in the context of the current frame.
+    def eval(self, expr):
+        return self.frame.EvaluateExpression(expr)
+
+    # Return an SBValue for this object denoting a pointer of type
+    # TYP*.
+    def get_lisp_pointer(self, typ):
+        return self.eval(f"({typ}*) (((EMACS_INT) "
+                         f"{self.unsigned}) & VALMASK)")
+
+    # If this is a Lisp_String, return an SBValue for its string data.
+    # Return None otherwise.
+    def get_string_data(self):
+        if self.lisp_type == "Lisp_String":
+            return self.value.GetValueForExpressionPath("->u.s.data")
+        return None
+
+    # if this is a Lisp_Symbol, return an SBBalue for its name.
+    # Return None otherwise.
+    def get_symbol_name(self):
+        if self.lisp_type == "Lisp_Symbol":
+            name = self.value.GetValueForExpressionPath("->u.s.name")
+            return Lisp_Object(name).get_string_data()
+        return None
+
+    # Return a summary string for this object.
+    def summary(self):
+        return str(self.value)
+
+
+########################################################################
+#                           LLDB Commands
+########################################################################
+
+def xbacktrace(debugger, command, ctx, result, internal_dict):
+    """Print Emacs Lisp backtrace"""
+    frame = ctx.GetFrame()
+    n = frame.EvaluateExpression(
+        "current_thread->m_specpdl_ptr - current_thread->m_specpdl")
+    for i in reversed(range(0, n.GetValueAsUnsigned())):
+        s = frame.EvaluateExpression(f"current_thread->m_specpdl[{i}]")
+        kind = enumerator_name(s.GetChildMemberWithName("kind"))
+        if kind == "SPECPDL_BACKTRACE":
+            function = Lisp_Object(s.GetValueForExpressionPath(".bt.function"))
+            if function.lisp_type == "Lisp_Symbol":
+                sym_name = function.get_symbol_name()
+                result.AppendMessage(str(sym_name))
+            elif function.lisp_type == "Lisp_Vectorlike":
+                result.AppendMessage(function.pvec_type)
+            else:
+                result.AppendMessage(function.lisp_type)
+
+def xdebug_print(debugger, command, result, internal_dict):
+    """Print Lisp_Objects using safe_debug_print()"""
+    debugger.HandleCommand(f"expr safe_debug_print({command})")
+
+
+########################################################################
+#                             Formatters
+########################################################################
+
+def type_summary_Lisp_Object(obj, internal_dict):
+    return Lisp_Object(obj).summary()
+
+
+########################################################################
+#                           Initialization
+########################################################################
+
+# Define Python FUNCTION as an LLDB command.
+def define_command (debugger, function):
+    lldb_command = function.__name__
+    python_function = __name__ + "." + function.__name__
+    interpreter = debugger.GetCommandInterpreter()
+    def define(overwrite):
+        res = lldb.SBCommandReturnObject()
+        interpreter.HandleCommand(f"command script add "
+                                  f"{overwrite} "
+                                  f"--function {python_function} "
+                                  f"{lldb_command}",
+                                  res)
+        return res.Succeeded()
+    if not define("--overwrite"):
+        define("")
+
+# Define Python FUNCTION as an LLDB type summary provider for types
+# matching REGEX.  Type summaries defined here are defined in the
+# category Emacs, and can be seen with 'type summary list -w Emacs',
+# and deleted in a similar way.
+def define_type_summary(debugger, regex, function):
+    python_function = __name__ + "." + function.__name__
+    debugger.HandleCommand(f"type summary add --expand "
+                           f"--cascade true "
+                           f"--category Emacs "
+                           f"--python-function {python_function} "
+                           + regex)
+
+# Enable a given category of type summary providers.
+def enable_type_category(debugger, category):
+    debugger.HandleCommand(f"type category enable {category}")
+
+# This function is called by LLDB to initialize the module.
+def __lldb_init_module(debugger, internal_dict):
+    define_command(debugger, xbacktrace)
+    define_command(debugger, xdebug_print)
+    define_type_summary(debugger, "Lisp_Object", type_summary_Lisp_Object)
+    enable_type_category(debugger, "Emacs")
+    print('Emacs debugging support has been installed.')
+
+# end.
diff --git a/etc/images/README b/etc/images/README
index 72da92427b..858f33e40b 100644
--- a/etc/images/README
+++ b/etc/images/README
@@ -112,7 +112,7 @@ GNOME project).  They are not part of Emacs, but are 
distributed and
 used by Emacs.  They are licensed under either the GNU LGPL v3 or the
 Creative Commons Attribution-Share Alike 3.0 United States License.
 
-To view a copy of the CC-BY-SA licence, visit
+To view a copy of the CC-BY-SA license, visit
 http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative
 Commons, 171 Second Street, Suite 300, San Francisco, California 94105, USA.
 
diff --git a/etc/publicsuffix.txt b/etc/publicsuffix.txt
index f52169116e..b5a89c65cc 100644
--- a/etc/publicsuffix.txt
+++ b/etc/publicsuffix.txt
@@ -1340,7 +1340,7 @@ tt.im
 tv.im
 
 // in : https://en.wikipedia.org/wiki/.in
-// see also: https://registry.in/Policies
+// see also: https://registry.in/policies
 // Please note, that nic.in is not an official eTLD, but used by most
 // government institutions.
 in
@@ -7130,7 +7130,7 @@ org.zw
 
 // newGTLDs
 
-// List of new gTLDs imported from 
https://www.icann.org/resources/registries/gtlds/v2/gtlds.json on 
2022-05-18T15:16:02Z
+// List of new gTLDs imported from 
https://www.icann.org/resources/registries/gtlds/v2/gtlds.json on 
2022-07-28T15:14:54Z
 // This list is auto-generated, don't edit it manually.
 // aaa : 2015-02-26 American Automobile Association, Inc.
 aaa
@@ -7687,7 +7687,7 @@ chanel
 // channel : 2014-05-08 Charleston Road Registry Inc.
 channel
 
-// charity : 2018-04-11 Binky Moon, LLC
+// charity : 2018-04-11 Public Interest Registry
 charity
 
 // chase : 2015-04-30 JPMorgan Chase Bank, National Association
@@ -7834,7 +7834,7 @@ coupon
 // coupons : 2015-03-26 Binky Moon, LLC
 coupons
 
-// courses : 2014-12-04 OPEN UNIVERSITIES AUSTRALIA PTY LTD
+// courses : 2014-12-04 Registry Services, LLC
 courses
 
 // cpa : 2019-06-10 American Institute of Certified Public Accountants
@@ -8020,7 +8020,7 @@ dvag
 // dvr : 2016-05-26 DISH Technologies L.L.C.
 dvr
 
-// earth : 2014-12-04 Interlink Co., Ltd.
+// earth : 2014-12-04 Interlink Systems Innovation Institute K.K.
 earth
 
 // eat : 2014-01-23 Charleston Road Registry Inc.
@@ -8227,7 +8227,7 @@ forsale
 // forum : 2015-04-02 Fegistry, LLC
 forum
 
-// foundation : 2013-12-05 Binky Moon, LLC
+// foundation : 2013-12-05 Public Interest Registry
 foundation
 
 // fox : 2015-09-11 FOX Registry, LLC
@@ -8326,7 +8326,7 @@ gift
 // gifts : 2014-07-03 Binky Moon, LLC
 gifts
 
-// gives : 2014-03-06 Dog Beach, LLC
+// gives : 2014-03-06 Public Interest Registry
 gives
 
 // giving : 2014-11-13 Giving Limited
@@ -8452,7 +8452,7 @@ health
 // healthcare : 2014-06-12 Binky Moon, LLC
 healthcare
 
-// help : 2014-06-26 UNR Corp.
+// help : 2014-06-26 Innovation service Limited
 help
 
 // helsinki : 2015-02-05 City of Helsinki
@@ -8779,7 +8779,7 @@ lanxess
 // lasalle : 2015-04-02 Jones Lang LaSalle Incorporated
 lasalle
 
-// lat : 2014-10-16 ECOM-LAC Federaciòn de Latinoamèrica y el Caribe para 
Internet y el Comercio Electrònico
+// lat : 2014-10-16 XYZ.COM LLC
 lat
 
 // latino : 2015-07-30 Dish DBS Corporation
@@ -8866,7 +8866,7 @@ living
 // llc : 2017-12-14 Afilias Limited
 llc
 
-// llp : 2019-08-26 UNR Corp.
+// llp : 2019-08-26 Intercap Registry Inc.
 llp
 
 // loan : 2014-11-20 dot Loan Limited
@@ -9034,7 +9034,7 @@ mobile
 // moda : 2013-11-07 Dog Beach, LLC
 moda
 
-// moe : 2013-11-13 Interlink Co., Ltd.
+// moe : 2013-11-13 Interlink Systems Innovation Institute K.K.
 moe
 
 // moi : 2014-12-18 Amazon Registry Services, Inc.
@@ -9841,7 +9841,7 @@ stream
 // studio : 2015-02-11 Dog Beach, LLC
 studio
 
-// study : 2014-12-11 OPEN UNIVERSITIES AUSTRALIA PTY LTD
+// study : 2014-12-11 Registry Services, LLC
 study
 
 // style : 2014-12-04 Binky Moon, LLC
@@ -12111,6 +12111,7 @@ kill.jp
 kilo.jp
 kuron.jp
 littlestar.jp
+lolipopmc.jp
 lolitapunk.jp
 lomo.jp
 lovepop.jp
@@ -12378,6 +12379,11 @@ moonscale.net
 // Submitted by Hannu Aronsson <haa@iki.fi>
 iki.fi
 
+// iliad italia: https://www.iliad.it
+// Submitted by Marios Makassikis <mmakassikis@freebox.fr>
+ibxos.it
+iliadboxos.it
+
 // Impertrix Solutions : <https://impertrixcdn.com>
 // Submitted by Zhixiang Zhao <csuite@impertrix.com>
 impertrixcdn.com
@@ -12458,9 +12464,11 @@ iopsys.se
 // Submitted by Matthew Hardeman <mhardeman@ipifony.com>
 ipifony.net
 
-// IServ GmbH : https://iserv.eu
-// Submitted by Kim-Alexander Brodowski <info@iserv.eu>
+// IServ GmbH : https://iserv.de
+// Submitted by Mario Hoberg <info@iserv.de>
+iservschule.de
 mein-iserv.de
+schulplattform.de
 schulserver.de
 test-iserv.de
 iserv.dev
@@ -12782,6 +12790,10 @@ hra.health
 miniserver.com
 memset.net
 
+// Messerli Informatik AG : https://www.messerli.ch/
+// Submitted by Ruben Schmidmeister <psl-maintainers@messerli.ch>
+messerli.app
+
 // MetaCentrum, CESNET z.s.p.o. : https://www.metacentrum.cz/en/
 // Submitted by Zdeněk Šustr <zdenek.sustr@cesnet.cz>
 *.cloud.metacentrum.cz
@@ -13394,9 +13406,9 @@ rocky.page
 
 // Salesforce.com, Inc. https://salesforce.com/
 // Submitted by Michael Biven <mbiven@salesforce.com>
-builder.code.com
-dev-builder.code.com
-stg-builder.code.com
+*.builder.code.com
+*.dev-builder.code.com
+*.stg-builder.code.com
 
 // Sandstorm Development Group, Inc. : https://sandcats.io/
 // Submitted by Asheesh Laroia <asheesh@sandstorm.io>
diff --git a/etc/srecode/ede-autoconf.srt b/etc/srecode/ede-autoconf.srt
index 19dc14202d..ecca7afd00 100644
--- a/etc/srecode/ede-autoconf.srt
+++ b/etc/srecode/ede-autoconf.srt
@@ -44,10 +44,10 @@ template ede-empty :project
 
 AC_INIT({{PROJECT_NAME}}, {{PROJECT_VERSION}})
 AM_INIT_AUTOMAKE([{{PROGRAM}}], 0)
-AM_CONFIG_HEADER(config.h)
+AM_CONFIG_HEADER([config.h])
 
 {{comment_prefix}} End the configure script.
-AC_OUTPUT(Makefile, [date > stamp-h] )
+AC_OUTPUT([Makefile], [date > stamp-h] )
 ----
 
 
diff --git a/etc/themes/leuven-dark-theme.el b/etc/themes/leuven-dark-theme.el
index 3fbb9d6c99..0e162c8bab 100644
--- a/etc/themes/leuven-dark-theme.el
+++ b/etc/themes/leuven-dark-theme.el
@@ -792,7 +792,7 @@ more...")
    `(org-example ((,class (:foreground "#ffff0b" :background "#38203d"))))
    `(org-footnote ((,class (:underline t :foreground "#ff7138"))))
    `(org-formula ((,class (:foreground "#0680e1"))))
-   ;; org-habit colours are thanks to zenburn
+   ;; org-habit colors are thanks to zenburn
    `(org-habit-ready-face ((t :background "#7F9F7F"))) ; ,zenburn-green
    `(org-habit-alert-face ((t :background "#E0CF9F" :foreground "#3F3F3F"))) ; 
,zenburn-yellow-1 fg ,zenburn-bg
    `(org-habit-clear-face ((t :background "#5C888B")))                       ; 
,zenburn-blue-3
diff --git a/etc/themes/manoj-dark-theme.el b/etc/themes/manoj-dark-theme.el
index c7d2d3fee5..af5576386c 100644
--- a/etc/themes/manoj-dark-theme.el
+++ b/etc/themes/manoj-dark-theme.el
@@ -380,7 +380,7 @@ jarring angry fruit salad look to reduce eye fatigue.")
                           :foreground "black" :background "grey"
                           :weight bold ))))
  '(calendar-today-face ((t (:underline t :bold t :foreground "cornsilk"))))
- '(change-log-acknowledgement-face ((t (:italic t :slant oblique :foreground 
"AntiqueWhite3"))))
+ '(change-log-acknowledgment ((t (:italic t :slant oblique :foreground 
"AntiqueWhite3"))))
  '(change-log-conditionals-face ((t (:foreground "Aquamarine"))))
  '(change-log-date-face ((t (:italic t :slant oblique :foreground 
"BurlyWood"))))
  '(change-log-email-face ((t (:foreground "Aquamarine"))))
diff --git a/etc/themes/modus-operandi-theme.el 
b/etc/themes/modus-operandi-theme.el
index 646504636f..fd7ffff98f 100644
--- a/etc/themes/modus-operandi-theme.el
+++ b/etc/themes/modus-operandi-theme.el
@@ -3,8 +3,10 @@
 ;; Copyright (C) 2019-2022  Free Software Foundation, Inc.
 
 ;; Author: Protesilaos Stavrou <info@protesilaos.com>
+;; Maintainer: Modus-Themes Development <~protesilaos/modus-themes@lists.sr.ht>
 ;; URL: https://git.sr.ht/~protesilaos/modus-themes
-;; Version: 2.4.1
+;; Mailing-List: https://lists.sr.ht/~protesilaos/modus-themes
+;; Version: 2.6.0
 ;; Package-Requires: ((emacs "27.1"))
 ;; Keywords: faces, theme, accessibility
 
diff --git a/etc/themes/modus-themes.el b/etc/themes/modus-themes.el
index f068e4a214..c4edb1efcb 100644
--- a/etc/themes/modus-themes.el
+++ b/etc/themes/modus-themes.el
@@ -3,9 +3,10 @@
 ;; Copyright (C) 2019-2022  Free Software Foundation, Inc.
 
 ;; Author: Protesilaos Stavrou <info@protesilaos.com>
+;; Maintainer: Modus-Themes Development <~protesilaos/modus-themes@lists.sr.ht>
 ;; URL: https://git.sr.ht/~protesilaos/modus-themes
-;; Mailing list: https://lists.sr.ht/~protesilaos/modus-themes
-;; Version: 2.4.1
+;; Mailing-List: https://lists.sr.ht/~protesilaos/modus-themes
+;; Version: 2.6.0
 ;; Package-Requires: ((emacs "27.1"))
 ;; Keywords: faces, theme, accessibility
 
@@ -102,19 +103,19 @@ cover the blue-cyan-magenta side of the spectrum."
   :tag "Modus Themes")
 
 (defgroup modus-themes-faces ()
-  "Faces defined my `modus-operandi' and `modus-vivendi'."
+  "Faces defined by `modus-operandi' and `modus-vivendi'."
   :group 'modus-themes
   :link '(info-link "(modus-themes) Top")
   :prefix "modus-themes-"
   :tag "Modus Themes Faces")
 
-(defvar modus-themes--version "2.5.0-dev"
+(defvar modus-themes--version "2.6.0"
   "Current version of the Modus themes.
 
-The version either is the last tagged release, such as '2.4.0',
-or an in-development version like '2.5.0-dev'.  As we use
-semantic versioning, tags of the '2.4.1' sort are not reported:
-those would count as part of '2.5.0-dev'.")
+The version either is the last tagged release, such as '1.0.0',
+or an in-development version like '1.1.0-dev'.  As we use
+semantic versioning, tags of the '1.0.1' sort are not reported:
+those would count as part of '1.1.0-dev'.")
 
 ;;;###autoload
 (defun modus-themes-version (&optional insert)
@@ -954,7 +955,7 @@ The actual styling of the face is done by 
`modus-themes-faces'."
   :group 'modus-themes-faces)
 
 (defface modus-themes-special-cold nil
-  "Combines the 'special cold' background and foreground values.
+  "Combines the special cold background and foreground values.
 This is intended for cases when a neutral gray background is not
 suitable and where a combination of more saturated colors would
 not be appropriate.
@@ -963,7 +964,7 @@ The actual styling of the face is done by 
`modus-themes-faces'."
   :group 'modus-themes-faces)
 
 (defface modus-themes-special-mild nil
-  "Combines the 'special mild' background and foreground values.
+  "Combines the special mild background and foreground values.
 This is intended for cases when a neutral gray background is not
 suitable and where a combination of more saturated colors would
 not be appropriate.
@@ -972,7 +973,7 @@ The actual styling of the face is done by 
`modus-themes-faces'."
   :group 'modus-themes-faces)
 
 (defface modus-themes-special-warm nil
-  "Combines the 'special warm' background and foreground values.
+  "Combines the special warm background and foreground values.
 This is intended for cases when a neutral gray background is not
 suitable and where a combination of more saturated colors would
 not be appropriate.
@@ -981,7 +982,7 @@ The actual styling of the face is done by 
`modus-themes-faces'."
   :group 'modus-themes-faces)
 
 (defface modus-themes-special-calm nil
-  "Combines the 'special calm' background and foreground values.
+  "Combines the special calm background and foreground values.
 This is intended for cases when a neutral gray background is not
 suitable and where a combination of more saturated colors would
 not be appropriate.
@@ -990,7 +991,7 @@ The actual styling of the face is done by 
`modus-themes-faces'."
   :group 'modus-themes-faces)
 
 (defface modus-themes-diff-added nil
-  "Combines green colors for the 'added' state in diffs.
+  "Combines green colors for the added state in diffs.
 The applied colors are contingent on the value assigned to
 `modus-themes-diffs'.
 
@@ -998,7 +999,7 @@ The actual styling of the face is done by 
`modus-themes-faces'."
   :group 'modus-themes-faces)
 
 (defface modus-themes-diff-changed nil
-  "Combines yellow colors for the 'changed' state in diffs.
+  "Combines yellow colors for the changed state in diffs.
 The applied colors are contingent on the value assigned to
 `modus-themes-diffs'.
 
@@ -1006,7 +1007,7 @@ The actual styling of the face is done by 
`modus-themes-faces'."
   :group 'modus-themes-faces)
 
 (defface modus-themes-diff-removed nil
-  "Combines red colors for the 'removed' state in diffs.
+  "Combines red colors for the removed state in diffs.
 The applied colors are contingent on the value assigned to
 `modus-themes-diffs'.
 
@@ -1014,7 +1015,7 @@ The actual styling of the face is done by 
`modus-themes-faces'."
   :group 'modus-themes-faces)
 
 (defface modus-themes-diff-refine-added nil
-  "Combines green colors for word-wise 'added' state in diffs.
+  "Combines green colors for word-wise added state in diffs.
 The applied colors are contingent on the value assigned to
 `modus-themes-diffs'.
 
@@ -1022,7 +1023,7 @@ The actual styling of the face is done by 
`modus-themes-faces'."
   :group 'modus-themes-faces)
 
 (defface modus-themes-diff-refine-changed nil
-  "Combines yellow colors for word-wise 'changed' state in diffs.
+  "Combines yellow colors for word-wise changed state in diffs.
 The applied colors are contingent on the value assigned to
 `modus-themes-diffs'.
 
@@ -1030,7 +1031,7 @@ The actual styling of the face is done by 
`modus-themes-faces'."
   :group 'modus-themes-faces)
 
 (defface modus-themes-diff-refine-removed nil
-  "Combines red colors for word-wise 'removed' state in diffs.
+  "Combines red colors for word-wise removed state in diffs.
 The applied colors are contingent on the value assigned to
 `modus-themes-diffs'.
 
@@ -1038,7 +1039,7 @@ The actual styling of the face is done by 
`modus-themes-faces'."
   :group 'modus-themes-faces)
 
 (defface modus-themes-diff-focus-added nil
-  "Combines green colors for the focused 'added' state in diffs.
+  "Combines green colors for the focused added state in diffs.
 The applied colors are contingent on the value assigned to
 `modus-themes-diffs'.
 
@@ -1046,7 +1047,7 @@ The actual styling of the face is done by 
`modus-themes-faces'."
   :group 'modus-themes-faces)
 
 (defface modus-themes-diff-focus-changed nil
-  "Combines yellow colors for the focused 'changed' state in.
+  "Combines yellow colors for the focused changed state in diffs.
 The applied colors are contingent on the value assigned to
 `modus-themes-diffs'.
 
@@ -1054,7 +1055,7 @@ The actual styling of the face is done by 
`modus-themes-faces'."
   :group 'modus-themes-faces)
 
 (defface modus-themes-diff-focus-removed nil
-  "Combines red colors for the focused 'removed' state in diffs.
+  "Combines red colors for the focused removed state in diffs.
 The applied colors are contingent on the value assigned to
 `modus-themes-diffs'.
 
@@ -1099,6 +1100,14 @@ The actual styling of the face is done by 
`modus-themes-faces'."
   "Applies a blue color and other styles for mark indicators.
 This is intended for use in modes such as Dired, Ibuffer, Proced.
 
+The actual styling of the face is done by `modus-themes-faces'."
+  :group 'modus-themes-faces)
+
+(defface modus-themes-heading-0 nil
+  "General purpose face for use as the document's title.
+The exact attributes assigned to this face are contingent on the
+values assigned to the `modus-themes-headings' variable.
+
 The actual styling of the face is done by `modus-themes-faces'."
   :group 'modus-themes-faces)
 
@@ -1459,7 +1468,7 @@ For form, see `modus-themes-operandi-colors'."
   :type '(alist :key-type symbol :value-type color)
   :set #'modus-themes--set-option
   :initialize #'custom-initialize-default
-  :link '(info-link "(modus-themes) Override colors (DIY)"))
+  :link '(info-link "(modus-themes) Override colors"))
 
 (defcustom modus-themes-vivendi-color-overrides nil
   "Override colors in the Modus Vivendi palette.
@@ -1471,7 +1480,7 @@ For form, see `modus-themes-vivendi-colors'."
   :type '(alist :key-type symbol :value-type color)
   :set #'modus-themes--set-option
   :initialize #'custom-initialize-default
-  :link '(info-link "(modus-themes) Override colors (DIY)"))
+  :link '(info-link "(modus-themes) Override colors"))
 
 ;; The byte compiler complains when a defcustom isn't a top level form
 (let* ((names (mapcar (lambda (pair)
@@ -1576,14 +1585,19 @@ speaking, is not limited to mouse usage."
 This is a helper variable intended for internal use.")
 
 (defcustom modus-themes-headings nil
-  "Heading styles with optional list of values for levels 1-8.
+  "Heading styles with optional list of values for levels 0-8.
 
 This is an alist that accepts a (key . list-of-values)
 combination.  The key is either a number, representing the
-heading's level or t, which pertains to the fallback style.  The
-list of values covers symbols that refer to properties, as
-described below.  Here is a sample, followed by a presentation of
-all available properties:
+heading's level (0-8) or t, which pertains to the fallback style.
+
+Level 0 is a special heading: it is used for what counts as a
+document title or equivalent, such as the #+title construct we
+find in Org files.  Levels 1-8 are regular headings.
+
+The list of values covers symbols that refer to properties, as
+described below.  Here is a complete sample, followed by a
+presentation of all available properties:
 
     (setq modus-themes-headings
           (quote ((1 . (background overline variable-pitch 1.5))
@@ -1668,12 +1682,12 @@ For Org users, the extent of the heading depends on the 
variable
 and `background' properties.  Depending on the version of Org,
 there may be others, such as `org-fontify-done-headline'."
   :group 'modus-themes
-  :package-version '(modus-themes . "2.3.0")
+  :package-version '(modus-themes . "2.5.0")
   :version "29.1"
   :type `(alist
           :options ,(mapcar (lambda (el)
                               (list el modus-themes--headings-choice))
-                            '(1 2 3 4 5 6 7 8 t))
+                            '(0 1 2 3 4 5 6 7 8 t))
           :key-type symbol
           :value-type ,modus-themes--headings-choice)
   :set #'modus-themes--set-option
@@ -1827,6 +1841,7 @@ value are passed as a symbol.  Those are:
   yellow, green, blue, in tinted and shaded versions.  They cover
   the full set of information provided by the `org-habit'
   consistency graph.
+
 - `simplified' is like the default except that it removes the
   dichotomy between current and future variants by applying
   uniform color-coded values.  It applies a total of four colors:
@@ -1835,15 +1850,17 @@ value are passed as a symbol.  Those are:
   the default.  The intent is to shift focus towards the
   distinction between the four states of a habit task, rather
   than each state's present/future outlook.
+
 - `traffic-light' further reduces the available colors to red,
   yellow, and green.  As in `simplified', present and future
-  variants appear uniformly, but differently from it, the 'clear'
+  variants appear uniformly, but differently from it, the CLEAR
   state is rendered in a green hue, instead of the original blue.
   This is meant to capture the use-case where a habit task being
-  \"too early\" is less important than it being \"too late\".
-  The difference between ready and clear states is attenuated by
+  too early is less important than it being too late.  The
+  difference between READY and CLEAR states is attenuated by
   painting both of them using shades of green.  This option thus
   highlights the alert and overdue states.
+
 - When `modus-themes-deuteranopia' is non-nil the exact style of
   the habit graph adapts to the needs of users with red-green
   color deficiency by substituting every instance of green with
@@ -2060,7 +2077,7 @@ active mode line.  The inactive mode lines remain 
two-dimensional
 and are toned down a bit, relative to the default style.
 
 The `moody' property optimizes the mode line for use with the
-library of the same name (hereinafter referred to as 'Moody').
+library of the same name (hereinafter referred to as Moody).
 In practice, it removes the box effect and replaces it with
 underline and overline properties.  It also tones down the
 inactive mode lines.  Despite its intended purpose, this option
@@ -3113,10 +3130,10 @@ theme's fallback text color."
 
 (defun modus-themes--paren (normalbg intensebg)
   "Conditional use of intense colors for matching parentheses.
-NORMALBG should be the special palette color 'bg-paren-match' or
+NORMALBG should be the special palette color bg-paren-match or
 something similar.  INTENSEBG must be easier to discern next to
 other backgrounds, such as the special palette color
-'bg-paren-match-intense'."
+bg-paren-match-intense."
   (let ((properties (modus-themes--list-or-warn 'modus-themes-paren-match)))
     (list :inherit
           (if (memq 'bold properties)
@@ -3197,7 +3214,7 @@ an alternative to the default value."
            ((and (memq 'alt-syntax properties)
                  (memq 'yellow-comments properties)
                  (not (memq 'green-strings properties)))
-            (or faint-yellow yellow))
+            yellow)
            ((memq 'yellow-comments properties)
             yellow)
            ((memq 'faint properties)
@@ -3222,7 +3239,7 @@ an alternative to the default value."
   "Search for `modus-themes--heading' weight in LIST."
   (catch 'found
     (dolist (elt list)
-      (when (memq elt modus-themes--heading-weights)
+      (when (memq elt modus-themes-weights)
         (throw 'found elt)))))
 
 (defun modus-themes--heading (level fg fg-alt bg bg-gray border)
@@ -3382,8 +3399,8 @@ clearly distinguishes past, present, future tasks."
 (defun modus-themes--agenda-habit (default traffic simple &optional default-d 
traffic-d simple-d)
   "Specify background values for `modus-themes-org-agenda' habits.
 DEFAULT is the original foregrounc color.  TRAFFIC is to be used
-when the 'traffic-light' style is applied, while SIMPLE
-corresponds to the 'simplified style'.
+when the traffic-light style is applied, while SIMPLE corresponds
+to the simplified style.
 
 Optional DEFAULT-D, TRAFFIC-D, SIMPLE-D are alternatives to the
 main colors, meant for dopia when `modus-themes-deuteranopia' is
@@ -3880,32 +3897,44 @@ pressed button style, else the released button."
 
 ;;;; Utilities for DIY users
 
-;;;;; List colors (a respin of M-x list-colors-display)
+;;;;; List colors (a variant of M-x list-colors-display)
 
-(defun modus-themes--list-colors-render (buffer palette)
-  "Render colors in BUFFER from PALETTE.
+(defun modus-themes--list-colors-render (buffer theme &rest _)
+  "Render colors in BUFFER from THEME.
 Routine for `modus-themes-list-colors'."
-  (with-help-window buffer
-    (with-current-buffer standard-output
-      (erase-buffer)
-      ;; We need this to properly render the first line.
-      (insert " ")
-      (dolist (cell palette)
-        (let* ((name (car cell))
-               (color (cdr cell))
-               (fg (readable-foreground-color color))
-               (pad (make-string 5 ?\s)))
-          (let ((old-point (point)))
-            (insert (format "%s %s" color pad))
-            (put-text-property old-point (point) 'face `( :foreground ,color)))
-          (let ((old-point (point)))
-            (insert (format " %s %s %s\n" color pad name))
-            (put-text-property old-point (point)
-                               'face `( :background ,color
-                                        :foreground ,fg
-                                        :extend t)))
-          ;; We need this to properly render the last line.
-          (insert " "))))))
+  (let ((palette (seq-uniq (modus-themes--palette theme)
+                           (lambda (x y)
+                             (eq (car x) (car y)))))
+        (current-buffer buffer)
+        (current-theme theme))
+    (with-help-window buffer
+      (with-current-buffer standard-output
+        (erase-buffer)
+        (when (<= (display-color-cells) 256)
+          (insert (concat "Your display terminal may not render all color 
previews!\n"
+                          "It seems to only support <= 256 colors.\n\n"))
+          (put-text-property (point-min) (point) 'face 'warning))
+        ;; We need this to properly render the first line.
+        (insert " ")
+        (dolist (cell palette)
+          (let* ((name (car cell))
+                 (color (cdr cell))
+                 (fg (readable-foreground-color color))
+                 (pad (make-string 5 ?\s)))
+            (let ((old-point (point)))
+              (insert (format "%s %s" color pad))
+              (put-text-property old-point (point) 'face `( :foreground 
,color)))
+            (let ((old-point (point)))
+              (insert (format " %s %s %s\n" color pad name))
+              (put-text-property old-point (point)
+                                 'face `( :background ,color
+                                          :foreground ,fg
+                                          :extend t)))
+            ;; We need this to properly render the last line.
+            (insert " ")))
+        (setq-local revert-buffer-function
+                    (lambda (_ignore-auto _noconfirm)
+                       (modus-themes--list-colors-render current-buffer 
current-theme)))))))
 
 (defvar modus-themes--list-colors-prompt-history '()
   "Minibuffer history for `modus-themes--list-colors-prompt'.")
@@ -3921,15 +3950,10 @@ Helper function for `modus-themes-list-colors'."
 
 (defun modus-themes-list-colors (theme)
   "Preview palette of the Modus THEME of choice."
-  (interactive
-   (list (intern (modus-themes--list-colors-prompt))))
-  (let ((palette (pcase theme
-                   ('modus-operandi modus-themes-operandi-colors)
-                   ('modus-vivendi modus-themes-vivendi-colors)
-                   (_ (user-error "`%s' is not a Modus theme" theme)))))
-    (modus-themes--list-colors-render
-     (format "*%s-list-colors*" theme)
-     palette)))
+  (interactive (list (intern (modus-themes--list-colors-prompt))))
+  (modus-themes--list-colors-render
+   (format "*%s-list-colors*" theme)
+   theme))
 
 (defun modus-themes-list-colors-current ()
   "Call `modus-themes-list-colors' for the current Modus theme."
@@ -4209,6 +4233,10 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(modus-themes-mark-symbol ((,class :inherit bold :foreground ,blue-alt)))
 ;;;;; heading levels
     ;; styles for regular headings used in Org, Markdown, Info, etc.
+    `(modus-themes-heading-0
+      ((,class ,@(modus-themes--heading
+                  0 cyan-alt-other blue-alt
+                  cyan-nuanced-bg bg-alt bg-region))))
     `(modus-themes-heading-1
       ((,class ,@(modus-themes--heading
                   1 fg-main magenta-alt-other
@@ -4265,12 +4293,8 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
       ((,class ,@(modus-themes--markup magenta-alt magenta-intense bg-alt
                                        bg-special-faint-calm))))
 ;;;;; search
-    `(modus-themes-search-success ((,class :inherit ,@(modus-themes--deuteran
-                                                       
'modus-themes-intense-blue
-                                                       
'modus-themes-intense-green))))
-    `(modus-themes-search-success-lazy ((,class :inherit 
,@(modus-themes--deuteran
-                                                            
'modus-themes-special-mild
-                                                            
'modus-themes-refine-cyan))))
+    `(modus-themes-search-success ((,class :inherit 
modus-themes-intense-yellow)))
+    `(modus-themes-search-success-lazy ((,class :inherit 
modus-themes-subtle-cyan)))
     `(modus-themes-search-success-modeline ((,class :foreground 
,@(modus-themes--deuteran
                                                                    blue-active
                                                                    
green-active))))
@@ -4330,7 +4354,8 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
                                       cyan-alt-other blue-alt-other fg-alt
                                       cyan-nuanced-bg blue-refine-bg fg-main
                                       bg-alt bg-active))))
-    `(modus-themes-reset-hard ((,class :inherit (fixed-pitch 
modus-themes-reset-soft))))
+    `(modus-themes-reset-hard ((,class :inherit (fixed-pitch 
modus-themes-reset-soft)
+                                       :family ,(face-attribute 'default 
:family))))
     `(modus-themes-reset-soft ((,class :background ,bg-main :foreground 
,fg-main
                                        :weight normal :slant normal 
:strike-through nil
                                        :box nil :underline nil :overline nil 
:extend nil)))
@@ -4350,6 +4375,7 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(comint-highlight-input ((,class :inherit bold)))
     `(comint-highlight-prompt ((,class :inherit modus-themes-prompt)))
     `(confusingly-reordered ((,class :inherit modus-themes-lang-error)))
+    `(edmacro-label ((,class :inherit bold :foreground ,cyan)))
     `(elisp-shorthand-font-lock-face ((,class :inherit 
font-lock-variable-name-face)))
     `(error ((,class :inherit bold :foreground ,red)))
     `(escape-glyph ((,class :foreground ,fg-escape-char-construct)))
@@ -4369,8 +4395,8 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(mm-command-output ((,class :foreground ,red-alt-other)))
     `(mm-uu-extract ((,class :background ,bg-dim :foreground 
,fg-special-mild)))
     `(next-error ((,class :inherit modus-themes-subtle-red :extend t)))
-    `(pgtk-im-0 ((,class :inherit modus-themes-fringe-blue :underline t)))
-    `(rectangle-preview ((,class :background ,bg-special-faint-warm 
:foreground ,fg-special-warm)))
+    `(pgtk-im-0 ((,class :inherit modus-themes-refine-cyan)))
+    `(rectangle-preview ((,class :inherit modus-themes-special-warm)))
     `(region ((,class ,@(modus-themes--region bg-region fg-main
                                               bg-hl-alt-intense 
bg-region-accent
                                               bg-region-accent-subtle))))
@@ -4477,8 +4503,8 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(anzu-match-3 ((,class :inherit modus-themes-subtle-yellow)))
     `(anzu-mode-line ((,class :inherit (bold 
modus-themes-search-success-modeline))))
     `(anzu-mode-line-no-match ((,class :inherit bold :foreground ,red-active)))
-    `(anzu-replace-highlight ((,class :inherit modus-themes-refine-yellow 
:underline t)))
-    `(anzu-replace-to ((,class :inherit (modus-themes-search-success bold))))
+    `(anzu-replace-highlight ((,class :inherit modus-themes-refine-red 
:underline t)))
+    `(anzu-replace-to ((,class :inherit modus-themes-search-success)))
 ;;;;; apropos
     `(apropos-button ((,class :foreground ,magenta-alt-other)))
     `(apropos-function-button ((,class :foreground ,magenta)))
@@ -4631,18 +4657,6 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(calibredb-mark-face ((,class :inherit modus-themes-mark-sel)))
     `(calibredb-size-face (( )))
     `(calibredb-tag-face ((,class :foreground ,magenta-alt-faint)))
-;;;;; centaur-tabs
-    `(centaur-tabs-active-bar-face ((,class :background ,blue-active)))
-    `(centaur-tabs-close-mouse-face ((,class :inherit bold :foreground 
,red-active :underline t)))
-    `(centaur-tabs-close-selected ((,class :inherit centaur-tabs-selected)))
-    `(centaur-tabs-close-unselected ((,class :inherit 
centaur-tabs-unselected)))
-    `(centaur-tabs-modified-marker-selected ((,class :inherit 
centaur-tabs-selected)))
-    `(centaur-tabs-modified-marker-unselected ((,class :inherit 
centaur-tabs-unselected)))
-    `(centaur-tabs-default ((,class :background ,bg-main)))
-    `(centaur-tabs-selected ((,class :inherit modus-themes-tab-active)))
-    `(centaur-tabs-selected-modified ((,class :inherit (italic 
centaur-tabs-selected))))
-    `(centaur-tabs-unselected ((,class :inherit modus-themes-tab-inactive)))
-    `(centaur-tabs-unselected-modified ((,class :inherit (italic 
centaur-tabs-unselected))))
 ;;;;; cfrs
     `(cfrs-border-color ((,class :background ,fg-window-divider-inner)))
 ;;;;; change-log and log-view (`vc-print-log' and `vc-print-root-log')
@@ -4737,7 +4751,7 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(company-tooltip-scrollbar-thumb ((,class :background ,fg-active)))
     `(company-tooltip-scrollbar-track ((,class :background ,bg-active)))
     `(company-tooltip-search ((,class :inherit 
(modus-themes-search-success-lazy bold))))
-    `(company-tooltip-search-selection ((,class :inherit 
(modus-themes-search-success bold) :underline t)))
+    `(company-tooltip-search-selection ((,class :inherit 
modus-themes-search-success :underline t)))
     `(company-tooltip-selection ((,class :inherit 
modus-themes-completion-selected-popup)))
 ;;;;; company-posframe
     `(company-posframe-active-backend-name ((,class :inherit bold :background 
,bg-active :foreground ,blue-active)))
@@ -4768,6 +4782,7 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(consult-narrow-indicator ((,class :foreground ,magenta-alt)))
     `(consult-preview-cursor ((,class :inherit modus-themes-intense-blue)))
     `(consult-preview-error ((,class :inherit modus-themes-intense-red)))
+    `(consult-preview-insertion ((,class :inherit modus-themes-special-warm)))
     `(consult-preview-line ((,class :background ,bg-hl-alt-intense)))
 ;;;;; corfu
     `(corfu-current ((,class :inherit modus-themes-completion-selected-popup)))
@@ -4815,11 +4830,9 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
 ;;;;; csv-mode
     `(csv-separator-face ((,class :foreground ,red-intense)))
 ;;;;; ctrlf
-    `(ctrlf-highlight-active ((,class :inherit (modus-themes-search-success 
bold))))
+    `(ctrlf-highlight-active ((,class :inherit modus-themes-search-success)))
     `(ctrlf-highlight-line ((,class :inherit modus-themes-hl-line)))
     `(ctrlf-highlight-passive ((,class :inherit 
modus-themes-search-success-lazy)))
-;;;;; cursor-flash
-    `(cursor-flash-face ((,class :inherit modus-themes-intense-blue)))
 ;;;;; custom (M-x customize)
     `(custom-button ((,class :inherit modus-themes-box-button)))
     `(custom-button-mouse ((,class :inherit (highlight custom-button))))
@@ -4852,12 +4865,6 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(dap-ui-sessions-stack-frame-face ((,class :inherit bold :foreground 
,magenta-alt)))
     `(dap-ui-sessions-terminated-active-face ((,class :inherit bold 
:foreground ,fg-alt)))
     `(dap-ui-sessions-terminated-face ((,class :inherit shadow)))
-;;;;; dashboard (emacs-dashboard)
-    `(dashboard-banner-logo-title ((,class :inherit bold :foreground 
,fg-special-cold)))
-    `(dashboard-footer ((,class :inherit bold :foreground ,fg-special-mild)))
-    `(dashboard-heading ((,class :inherit bold :foreground ,fg-special-warm)))
-    `(dashboard-navigator ((,class :foreground ,cyan-alt-other)))
-    `(dashboard-text-banner ((,class :foreground ,fg-dim)))
 ;;;;; deadgrep
     `(deadgrep-filename-face ((,class :inherit bold :foreground 
,fg-special-cold)))
     `(deadgrep-match-face ((,class :inherit modus-themes-special-calm)))
@@ -4878,13 +4885,15 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(debbugs-gnu-stale-5 ((,class :foreground ,red-alt)))
     `(debbugs-gnu-tagged ((,class :foreground ,magenta-alt)))
 ;;;;; deft
-    `(deft-filter-string-error-face ((,class :inherit 
modus-themes-refine-red)))
-    `(deft-filter-string-face ((,class :foreground ,green-intense)))
-    `(deft-header-face ((,class :inherit bold :foreground ,fg-special-warm)))
-    `(deft-separator-face ((,class :inherit shadow)))
+    `(deft-filter-string-face ((,class :inherit bold :foreground ,blue)))
+    `(deft-header-face ((,class :foreground ,fg-special-warm)))
+    `(deft-separator-face ((,class :foreground "gray50")))
     `(deft-summary-face ((,class :inherit (shadow modus-themes-slant))))
-    `(deft-time-face ((,class :foreground ,fg-special-cold)))
-    `(deft-title-face ((,class :inherit bold :foreground ,fg-main)))
+    `(deft-time-face ((,class :foreground ,cyan)))
+    `(deft-title-face ((,class :inherit bold)))
+;;;;; denote
+    `(denote-faces-date ((,class :foreground ,cyan)))
+    `(denote-faces-keywords ((,class :inherit modus-themes-bold :foreground 
,magenta-alt)))
 ;;;;; devdocs
     `(devdocs-code-block ((,class :inherit modus-themes-fixed-pitch 
:background ,bg-dim :extend t)))
 ;;;;; dictionary
@@ -4962,7 +4971,7 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(dired-git-branch-else ((,class :inherit bold :foreground ,magenta-alt)))
     `(dired-git-branch-master ((,class :inherit bold :foreground 
,magenta-alt-other)))
 ;;;;; dired-git-info
-    `(dgi-commit-message-face ((,class :foreground ,fg-special-mild)))
+    `(dgi-commit-message-face ((,class :foreground ,cyan-alt-other)))
 ;;;;; dired-narrow
     `(dired-narrow-blink ((,class :inherit (modus-themes-subtle-cyan bold))))
 ;;;;; dired-subtree
@@ -5072,11 +5081,8 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(doom-modeline-unread-number ((,class :inherit italic :foreground 
,fg-active)))
     `(doom-modeline-urgent ((,class :inherit bold :foreground ,red-active)))
     `(doom-modeline-warning ((,class :inherit bold :foreground 
,yellow-active)))
-;;;;; dynamic-ruler
-    `(dynamic-ruler-negative-face ((,class :inherit 
modus-themes-intense-neutral)))
-    `(dynamic-ruler-positive-face ((,class :inherit 
modus-themes-intense-yellow)))
 ;;;;; easy-jekyll
-    `(easy-jekyll-help-face ((,class :background ,bg-dim :foreground 
,cyan-alt-other)))
+    `(easy-jekyll-help-face ((,class :background ,bg-dim :foreground 
,blue-alt-other)))
 ;;;;; ebdb
     `(ebdb-address-default ((,class :foreground ,fg-special-calm)))
     `(ebdb-defunct ((,class :inherit shadow)))
@@ -5318,7 +5324,7 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(evil-ex-lazy-highlight ((,class :inherit 
modus-themes-search-success-lazy)))
     `(evil-ex-search ((,class :inherit modus-themes-search-success)))
     `(evil-ex-substitute-matches ((,class :inherit modus-themes-refine-yellow 
:underline t)))
-    `(evil-ex-substitute-replacement ((,class :inherit 
(modus-themes-search-success bold))))
+    `(evil-ex-substitute-replacement ((,class :inherit 
modus-themes-search-success)))
 ;;;;; evil-goggles
     `(evil-goggles-change-face ((,class :inherit modus-themes-refine-yellow)))
     `(evil-goggles-commentary-face ((,class :inherit 
(modus-themes-subtle-neutral modus-themes-slant))))
@@ -5403,13 +5409,6 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(flx-highlight-face ((,class :inherit modus-themes-completion-match-0)))
 ;;;;; freeze-it
     `(freeze-it-show ((,class :background ,bg-dim :foreground 
,fg-special-warm)))
-;;;;; frog-menu
-    `(frog-menu-action-keybinding-face ((,class :inherit 
modus-themes-key-binding)))
-    `(frog-menu-actions-face ((,class :foreground ,magenta)))
-    `(frog-menu-border ((,class :background ,bg-active)))
-    `(frog-menu-candidates-face ((,class :foreground ,fg-main)))
-    `(frog-menu-posframe-background-face ((,class :background ,bg-dim)))
-    `(frog-menu-prompt-face ((,class :foreground ,cyan)))
 ;;;;; focus
     `(focus-unfocused ((,class :foreground ,fg-unfocused)))
 ;;;;; fold-this
@@ -5466,8 +5465,8 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
                                                cyan cyan-faint
                                                blue-alt blue-alt-faint))))
     `(font-lock-warning-face ((,class :inherit modus-themes-bold
-                                      ,@(modus-themes--syntax-foreground
-                                         yellow-active yellow-alt-faint))))
+                                      ,@(modus-themes--syntax-comment
+                                         yellow red yellow-alt-faint 
red-faint))))
 ;;;;; forge
     `(forge-post-author ((,class :inherit bold :foreground ,fg-main)))
     `(forge-post-date ((,class :foreground ,fg-special-cold)))
@@ -5715,18 +5714,20 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
 ;;;;; helpful
     `(helpful-heading ((,class :inherit modus-themes-heading-1)))
 ;;;;; highlight region or ad-hoc regexp
-    `(hi-aquamarine ((,class :background ,cyan-subtle-bg :foreground 
,fg-main)))
-    `(hi-black-b ((,class :inherit bold :background ,fg-main :foreground 
,bg-main)))
-    `(hi-black-hb ((,class :inherit bold :background ,fg-alt :foreground 
,bg-main)))
-    `(hi-blue ((,class :background ,blue-subtle-bg :foreground ,fg-main)))
+    ;; HACK 2022-06-23: The :inverse-video prevents hl-line-mode from
+    ;; overriding the background.  Such an override really defeats the
+    ;; purpose of setting those highlights.
+    `(hi-aquamarine ((,class :background ,bg-main :foreground ,cyan 
:inverse-video t)))
+    `(hi-black-b ((,class :inverse-video t)))
+    `(hi-black-hb ((,class :background ,bg-main :foreground ,fg-alt 
:inverse-video t)))
+    `(hi-blue ((,class :background ,bg-main :foreground ,blue-alt 
:inverse-video t)))
     `(hi-blue-b ((,class :inherit (bold hi-blue))))
-    `(hi-green ((,class :background ,green-subtle-bg :foreground ,fg-main)))
+    `(hi-green ((,class :background ,bg-main :foreground ,green :inverse-video 
t)))
     `(hi-green-b ((,class :inherit (bold hi-green))))
-    `(hi-pink ((,class :background ,magenta-subtle-bg :foreground ,fg-main)))
-    `(hi-pink-b ((,class :inherit (bold hi-pink))))
-    `(hi-red-b ((,class :inherit bold :background ,red-intense-bg :foreground 
,fg-main)))
-    `(hi-salmon ((,class :background ,red-subtle-bg :foreground ,fg-main)))
-    `(hi-yellow ((,class :background ,yellow-subtle-bg :foreground ,fg-main)))
+    `(hi-pink ((,class :background ,bg-main :foreground ,magenta 
:inverse-video t)))
+    `(hi-red-b ((,class :inherit bold :background ,bg-main :foreground ,red 
:inverse-video t)))
+    `(hi-salmon ((,class :background ,bg-main :foreground ,red-alt-faint 
:inverse-video t)))
+    `(hi-yellow ((,class :background ,bg-main :foreground ,yellow-alt 
:inverse-video t)))
     `(highlight ((,class ,@(if modus-themes-intense-mouseovers
                                (list :background blue-intense-bg :foreground 
fg-main)
                              (list :background cyan-subtle-bg :foreground 
fg-main)))))
@@ -5740,7 +5741,7 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
 ;;;;; highlight-numbers
     `(highlight-numbers-number ((,class :foreground ,blue-alt-other)))
 ;;;;; highlight-thing
-    `(highlight-thing ((,class :background ,bg-alt :foreground ,cyan)))
+    `(highlight-thing ((,class :inherit modus-themes-special-calm)))
 ;;;;; hl-defined
     `(hdefd-functions ((,class :foreground ,blue)))
     `(hdefd-undefined ((,class :foreground ,red-alt)))
@@ -5805,6 +5806,26 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(info-title-2 ((,class :inherit modus-themes-heading-2)))
     `(info-title-3 ((,class :inherit modus-themes-heading-3)))
     `(info-title-4 ((,class :inherit modus-themes-heading-4)))
+;;;;; info+ (info-plus)
+    `(info-command-ref-item ((,class :inherit font-lock-function-name-face)))
+    `(info-constant-ref-item ((,class :inherit font-lock-constant-face)))
+    `(info-custom-delimited ((,class :inherit modus-themes-markup-verbatim)))
+    `(info-double-quoted-name ((,class :inherit font-lock-string-face)))
+    `(info-file (( )))
+    `(info-function-ref-item ((,class :inherit font-lock-function-name-face)))
+    `(info-glossary-word ((,class :inherit modus-themes-box-button)))
+    `(info-indented-text (( )))
+    `(info-isolated-backquote (( )))
+    `(info-isolated-quote (( )))
+    `(info-macro-ref-item ((,class :inherit font-lock-keyword-face)))
+    `(info-menu ((,class :inherit bold)))
+    `(info-quoted-name ((,class :inherit modus-themes-markup-verbatim)))
+    `(info-reference-item ((,class :inherit bold)))
+    `(info-special-form-ref-item ((,class :inherit warning)))
+    `(info-string ((,class :inherit font-lock-string-face)))
+    `(info-syntax-class-item ((,class :inherit modus-themes-markup-code)))
+    `(info-user-option-ref-item ((,class :inherit 
font-lock-variable-name-face)))
+    `(info-variable-ref-item ((,class :inherit font-lock-variable-name-face)))
 ;;;;; info-colors
     `(info-colors-lisp-code-block ((,class :inherit modus-themes-fixed-pitch)))
     `(info-colors-ref-item-command ((,class :inherit 
font-lock-function-name-face)))
@@ -5834,13 +5855,13 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(ioccur-regexp-face ((,class :inherit (modus-themes-intense-magenta 
bold))))
     `(ioccur-title-face ((,class :inherit modus-themes-pseudo-header 
:foreground ,fg-special-cold)))
 ;;;;; isearch, occur, and the like
-    `(isearch ((,class :inherit (modus-themes-search-success bold))))
+    `(isearch ((,class :inherit modus-themes-search-success)))
     `(isearch-fail ((,class :inherit modus-themes-refine-red)))
     `(isearch-group-1 ((,class :inherit modus-themes-refine-blue)))
     `(isearch-group-2 ((,class :inherit modus-themes-refine-magenta)))
     `(lazy-highlight ((,class :inherit modus-themes-search-success-lazy)))
     `(match ((,class :inherit modus-themes-special-calm)))
-    `(query-replace ((,class :inherit (modus-themes-intense-yellow bold))))
+    `(query-replace ((,class :inherit modus-themes-intense-red)))
 ;;;;; ivy
     `(ivy-action ((,class :inherit modus-themes-key-binding)))
     `(ivy-confirm-face ((,class :inherit success)))
@@ -5921,12 +5942,14 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(ledger-font-payee-pending-face ((,class :foreground ,yellow)))
     `(ledger-font-payee-uncleared-face ((,class :foreground ,red-alt-other)))
     `(ledger-font-xact-highlight-face ((,class :background ,bg-hl-alt)))
+;;;;; leerzeichen
+    `(leerzeichen ((,class :background ,bg-whitespace :foreground 
,fg-whitespace)))
 ;;;;; line numbers (display-line-numbers-mode and global variant)
     ;; Here we cannot inherit `modus-themes-fixed-pitch'.  We need to
     ;; fall back to `default' otherwise line numbers do not scale when
     ;; using `text-scale-adjust'.
     `(line-number
-      ((,class :inherit ,(if modus-themes-mixed-fonts 'fixed-pitch 'default)
+      ((,class :inherit ,(if modus-themes-mixed-fonts '(fixed-pitch default) 
'default)
                ,@(modus-themes--line-numbers
                   fg-alt bg-dim
                   fg-unfocused))))
@@ -6120,8 +6143,9 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(makefile-makepp-perl ((,class :background ,cyan-nuanced-bg)))
     `(makefile-space ((,class :background ,magenta-nuanced-bg)))
 ;;;;; man
-    `(Man-overstrike ((,class :inherit bold :foreground ,fg-special-calm)))
+    `(Man-overstrike ((,class :inherit bold :foreground ,magenta-alt)))
     `(Man-reverse ((,class :inherit modus-themes-subtle-magenta)))
+    `(Man-underline ((,class :foreground ,cyan-alt-other :underline t)))
 ;;;;; marginalia
     `(marginalia-archive ((,class :foreground ,cyan-alt-other)))
     `(marginalia-char ((,class :foreground ,magenta)))
@@ -6159,7 +6183,7 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(markdown-comment-face ((,class :inherit font-lock-comment-face)))
     `(markdown-footnote-marker-face ((,class :inherit bold :foreground 
,cyan-alt)))
     `(markdown-footnote-text-face ((,class :inherit modus-themes-slant 
:foreground ,fg-main)))
-    `(markdown-gfm-checkbox-face ((,class :foreground ,cyan-alt-other)))
+    `(markdown-gfm-checkbox-face ((,class :foreground ,yellow-alt-other)))
     `(markdown-header-delimiter-face ((,class :inherit modus-themes-bold 
:foreground ,fg-dim)))
     `(markdown-header-face ((t nil)))
     `(markdown-header-face-1 ((,class :inherit modus-themes-heading-1)))
@@ -6235,8 +6259,6 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(markup-title-4-face ((,class :inherit modus-themes-heading-5)))
     `(markup-title-5-face ((,class :inherit modus-themes-heading-6)))
     `(markup-verbatim-face ((,class :inherit modus-themes-fixed-pitch 
:background ,bg-alt)))
-;;;;; mct
-    `(mct-highlight-candidate ((,class :inherit 
modus-themes-completion-selected)))
 ;;;;; mentor
     `(mentor-download-message ((,class :foreground ,fg-special-warm)))
     `(mentor-download-name ((,class :foreground ,fg-special-cold)))
@@ -6336,6 +6358,7 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(mu4e-moved-face ((,class :inherit modus-themes-slant :foreground 
,yellow)))
     `(mu4e-ok-face ((,class :inherit bold :foreground ,green)))
     `(mu4e-region-code ((,class :inherit modus-themes-special-calm)))
+    `(mu4e-related-face ((,class :inherit (italic shadow))))
     `(mu4e-replied-face ((,class :foreground ,blue)))
     `(mu4e-special-header-value-face ((,class :inherit 
message-header-subject)))
     `(mu4e-system-face ((,class :inherit modus-themes-slant :foreground 
,fg-mark-del)))
@@ -6450,14 +6473,12 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(org-agenda-column-dateline ((,class :background ,bg-alt)))
     `(org-agenda-current-time ((,class :foreground ,blue-alt-other-faint)))
     `(org-agenda-date ((,class ,@(modus-themes--agenda-date cyan fg-main))))
-    `(org-agenda-date-today ((,class ,@(modus-themes--agenda-date cyan fg-main
-                                                                  nil nil
-                                                                  bg-inactive 
t t))))
-    `(org-agenda-date-weekend ((,class ,@(modus-themes--agenda-date 
cyan-alt-other-faint fg-alt
-                                                                    cyan 
fg-main))))
-    `(org-agenda-date-weekend-today ((,class ,@(modus-themes--agenda-date 
cyan-alt-other-faint fg-alt
-                                                                          cyan 
fg-main
-                                                                          
bg-inactive t t))))
+    `(org-agenda-date-today
+      ((,class ,@(modus-themes--agenda-date cyan fg-main nil nil 
bg-special-cold t t))))
+    `(org-agenda-date-weekend
+      ((,class ,@(modus-themes--agenda-date cyan-alt-other-faint fg-alt cyan 
fg-main))))
+    `(org-agenda-date-weekend-today
+      ((,class ,@(modus-themes--agenda-date cyan-alt-other-faint fg-alt cyan 
fg-main bg-special-cold t t))))
     `(org-agenda-diary ((,class :inherit org-agenda-calendar-sexp)))
     `(org-agenda-dimmed-todo-face ((,class :inherit shadow)))
     `(org-agenda-done ((,class :inherit modus-themes-grue-nuanced)))
@@ -6477,7 +6498,7 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
                                        bg-dim fg-special-cold
                                        bg-alt fg-alt))))
     `(org-block-end-line ((,class :inherit org-block-begin-line)))
-    `(org-checkbox (( )))
+    `(org-checkbox ((,class :foreground ,yellow-alt-other)))
     `(org-checkbox-statistics-done ((,class :inherit org-done)))
     `(org-checkbox-statistics-todo ((,class :inherit org-todo)))
     `(org-clock-overlay ((,class :background ,yellow-nuanced-bg :foreground 
,red-alt-faint)))
@@ -6491,7 +6512,7 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(org-dispatcher-highlight ((,class :inherit (bold 
modus-themes-mark-alt))))
     `(org-document-info ((,class :foreground ,fg-special-cold)))
     `(org-document-info-keyword ((,class :inherit (shadow 
modus-themes-fixed-pitch))))
-    `(org-document-title ((,class :inherit modus-themes-heading-1 :background 
,bg-main :overline nil :foreground ,fg-special-cold)))
+    `(org-document-title ((,class :inherit modus-themes-heading-0)))
     `(org-done ((,class :inherit modus-themes-grue)))
     `(org-drawer ((,class :inherit (shadow modus-themes-fixed-pitch))))
     `(org-ellipsis (())) ; inherits from the heading's color
@@ -6589,8 +6610,8 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(org-journal-calendar-scheduled-face ((,class :inherit modus-themes-slant 
:foreground ,red-alt-other)))
     `(org-journal-highlight ((,class :foreground ,magenta-alt)))
 ;;;;; org-noter
-    `(org-noter-no-notes-exist-face ((,class :inherit bold :foreground 
,red-active)))
-    `(org-noter-notes-exist-face ((,class :inherit bold :foreground 
,green-active)))
+    `(org-noter-no-notes-exist-face ((,class :inherit error)))
+    `(org-noter-notes-exist-face ((,class :inherit success)))
 ;;;;; org-pomodoro
     `(org-pomodoro-mode-line ((,class :foreground ,red-active)))
     `(org-pomodoro-mode-line-break ((,class :foreground ,cyan-active)))
@@ -6613,9 +6634,6 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(org-table-sticky-header-face ((,class :inherit 
modus-themes-special-cold)))
 ;;;;; org-tree-slide
     `(org-tree-slide-header-overlay-face ((,class :inherit 
org-document-title)))
-;;;;; org-treescope
-    `(org-treescope-faces--markerinternal-midday ((,class :inherit 
modus-themes-intense-blue)))
-    `(org-treescope-faces--markerinternal-range ((,class :inherit 
modus-themes-special-mild)))
 ;;;;; origami
     `(origami-fold-header-face ((,class :background ,bg-dim :foreground 
,fg-dim :box t)))
     `(origami-fold-replacement-face ((,class :background ,bg-alt :foreground 
,fg-alt)))
@@ -6632,19 +6650,19 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(outline-minor-0 (()))
 ;;;;; package (M-x list-packages)
     `(package-description ((,class :foreground ,fg-special-cold)))
-    `(package-help-section-name ((,class :inherit bold :foreground 
,magenta-alt-other)))
+    `(package-help-section-name ((,class :inherit bold :foreground ,cyan)))
     `(package-name ((,class :inherit button)))
-    `(package-status-avail-obso ((,class :inherit bold :foreground ,red)))
-    `(package-status-available ((,class :foreground ,fg-special-mild)))
+    `(package-status-available ((,class :foreground ,cyan-alt-other)))
+    `(package-status-avail-obso ((,class :inherit error)))
     `(package-status-built-in ((,class :foreground ,magenta)))
     `(package-status-dependency ((,class :foreground ,magenta-alt-other)))
     `(package-status-disabled ((,class :inherit modus-themes-subtle-red)))
     `(package-status-external ((,class :foreground ,cyan-alt-other)))
     `(package-status-held ((,class :foreground ,yellow-alt)))
-    `(package-status-incompat ((,class :inherit bold :foreground ,yellow)))
+    `(package-status-incompat ((,class :inherit warning)))
     `(package-status-installed ((,class :foreground ,fg-special-warm)))
-    `(package-status-new ((,class :inherit bold :foreground ,green)))
-    `(package-status-unsigned ((,class :inherit bold :foreground ,red-alt)))
+    `(package-status-new ((,class :inherit success)))
+    `(package-status-unsigned ((,class :inherit error)))
 ;;;;; page-break-lines
     `(page-break-lines ((,class :inherit default :foreground 
,fg-window-divider-outer)))
 ;;;;; pandoc-mode
@@ -6653,19 +6671,6 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(pandoc-directive-braces-face ((,class :foreground ,blue-alt-other)))
     `(pandoc-directive-contents-face ((,class :foreground ,cyan-alt-other)))
     `(pandoc-directive-type-face ((,class :foreground ,magenta)))
-;;;;; paradox
-    `(paradox-archive-face ((,class :foreground ,fg-special-mild)))
-    `(paradox-comment-face ((,class :inherit font-lock-comment-face)))
-    `(paradox-commit-tag-face ((,class :inherit modus-themes-refine-magenta 
:box t)))
-    `(paradox-description-face ((,class :foreground ,fg-special-cold)))
-    `(paradox-description-face-multiline ((,class :foreground 
,fg-special-cold)))
-    `(paradox-download-face ((,class :inherit modus-themes-bold :foreground 
,blue-alt-other)))
-    `(paradox-highlight-face ((,class :inherit modus-themes-bold :foreground 
,cyan-alt-other)))
-    `(paradox-homepage-button-face ((,class :foreground ,magenta-alt-other 
:underline t)))
-    `(paradox-mode-line-face ((,class :inherit bold :foreground ,cyan-active)))
-    `(paradox-name-face ((,class :foreground ,blue :underline t)))
-    `(paradox-star-face ((,class :foreground ,magenta)))
-    `(paradox-starred-face ((,class :foreground ,magenta-alt)))
 ;;;;; paren-face
     `(parenthesis ((,class :foreground ,fg-unfocused)))
 ;;;;; pass
@@ -6695,7 +6700,7 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(pomidor-work-face ((,class :inherit modus-themes-grue)))
 ;;;;; popup
     `(popup-face ((,class :background ,bg-alt :foreground ,fg-main)))
-    `(popup-isearch-match ((,class :inherit (modus-themes-search-success 
bold))))
+    `(popup-isearch-match ((,class :inherit modus-themes-search-success)))
     `(popup-menu-mouse-face ((,class :inherit highlight)))
     `(popup-menu-selection-face ((,class :inherit 
modus-themes-completion-selected-popup)))
     `(popup-scroll-bar-background-face ((,class :background ,bg-active)))
@@ -6703,12 +6708,12 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(popup-summary-face ((,class :background ,bg-active :foreground 
,fg-inactive)))
     `(popup-tip-face ((,class :inherit modus-themes-refine-yellow)))
 ;;;;; powerline
-    `(powerline-active0 ((,class :background ,blue-faint :foreground 
,bg-main)))
-    `(powerline-active1 ((,class :background ,blue-nuanced-bg :foreground 
,blue-nuanced-fg)))
-    `(powerline-active2 ((,class :background ,bg-active :foreground 
,fg-active)))
-    `(powerline-inactive0 ((,class :background ,bg-special-cold :foreground 
,fg-special-cold)))
-    `(powerline-inactive1 ((,class :background ,bg-dim :foreground 
,fg-inactive)))
-    `(powerline-inactive2 ((,class :background ,bg-inactive :foreground 
,fg-inactive)))
+    `(powerline-active0 ((,class :background ,fg-unfocused :foreground 
,bg-main)))
+    `(powerline-active1 ((,class :inherit mode-line-active)))
+    `(powerline-active2 ((,class :inherit mode-line-inactive)))
+    `(powerline-inactive0 ((,class :background ,bg-active :foreground 
,fg-alt)))
+    `(powerline-inactive1 ((,class :background ,bg-main :foreground ,fg-alt)))
+    `(powerline-inactive2 ((,class :inherit mode-line-inactive)))
 ;;;;; powerline-evil
     `(powerline-evil-base-face ((,class :background ,fg-main :foreground 
,bg-main)))
     `(powerline-evil-emacs-face ((,class :inherit 
modus-themes-active-magenta)))
@@ -6834,10 +6839,8 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
 ;;;;; selectrum
     `(selectrum-current-candidate ((,class :inherit 
modus-themes-completion-selected)))
     `(selectrum-mouse-highlight ((,class :inherit highlight)))
-    `(selectrum-quick-keys-highlight
-      ((,class :inherit modus-themes-refine-red)))
-    `(selectrum-quick-keys-match
-      ((,class :inherit (bold modus-themes-search-success))))
+    `(selectrum-quick-keys-highlight ((,class :inherit bold :background 
,bg-char-0)))
+    `(selectrum-quick-keys-match ((,class :inherit bold :background 
,bg-char-1)))
 ;;;;; selectrum-prescient
     `(selectrum-prescient-primary-highlight ((,class :inherit 
modus-themes-completion-match-0)))
     `(selectrum-prescient-secondary-highlight ((,class :inherit 
modus-themes-completion-match-1)))
@@ -6854,8 +6857,8 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(semantic-tag-boundary-face ((,class :overline ,blue-intense)))
     `(semantic-unmatched-syntax-face ((,class :underline ,fg-lang-error)))
 ;;;;; sesman
-    `(sesman-browser-button-face ((,class :foreground ,blue-alt-other 
:underline t)))
-    `(sesman-browser-highligh-face ((,class :inherit 
modus-themes-subtle-blue)))
+    `(sesman-browser-button-face ((,class :inherit button)))
+    `(sesman-browser-highligh-face ((,class :inherit highlight)))
     `(sesman-buffer-face ((,class :foreground ,magenta)))
     `(sesman-directory-face ((,class :inherit bold :foreground ,blue)))
     `(sesman-project-face ((,class :inherit bold :foreground 
,magenta-alt-other)))
@@ -6962,11 +6965,6 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(smerge-refined-changed (()))
     `(smerge-refined-removed ((,class :inherit 
modus-themes-diff-refine-removed)))
     `(smerge-upper ((,class :inherit modus-themes-diff-removed)))
-;;;;; solaire
-    `(solaire-default-face ((,class :inherit default :background ,bg-alt 
:foreground ,fg-dim)))
-    `(solaire-line-number-face ((,class :inherit solaire-default-face 
:foreground ,fg-unfocused)))
-    `(solaire-hl-line-face ((,class :background ,bg-active)))
-    `(solaire-org-hide-face ((,class :background ,bg-alt :foreground ,bg-alt)))
 ;;;;; spaceline
     `(spaceline-evil-emacs ((,class :inherit modus-themes-active-magenta)))
     `(spaceline-evil-insert ((,class :inherit modus-themes-active-green)))
@@ -6986,7 +6984,7 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(speedbar-button-face ((,class :inherit button)))
     `(speedbar-directory-face ((,class :inherit bold :foreground ,blue)))
     `(speedbar-file-face ((,class :foreground ,fg-main)))
-    `(speedbar-highlight-face ((,class :inherit modus-themes-subtle-blue)))
+    `(speedbar-highlight-face ((,class :inherit highlight)))
     `(speedbar-selected-face ((,class :inherit bold :foreground ,cyan)))
     `(speedbar-separator-face ((,class :inherit modus-themes-intense-neutral)))
     `(speedbar-tag-face ((,class :foreground ,yellow-alt-other)))
@@ -7047,14 +7045,14 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(symbol-overlay-face-8 ((,class :inherit modus-themes-refine-cyan)))
 ;;;;; syslog-mode
     `(syslog-debug ((,class :inherit bold :foreground ,cyan-alt-other)))
-    `(syslog-error ((,class :inherit bold :foreground ,red)))
+    `(syslog-error ((,class :inherit error)))
     `(syslog-file ((,class :inherit bold :foreground ,fg-special-cold)))
     `(syslog-hide ((,class :background ,bg-main :foreground ,fg-main)))
     `(syslog-hour ((,class :inherit bold :foreground ,magenta-alt-other)))
-    `(syslog-info ((,class :inherit bold :foreground ,blue-alt-other)))
+    `(syslog-info ((,class :inherit success)))
     `(syslog-ip ((,class :inherit bold :foreground ,fg-special-mild :underline 
t)))
     `(syslog-su ((,class :inherit bold :foreground ,red-alt)))
-    `(syslog-warn ((,class :inherit bold :foreground ,yellow)))
+    `(syslog-warn ((,class :inherit warning)))
 ;;;;; tab-bar-groups
     `(tab-bar-groups-tab-1 ((,class :inherit modus-themes-ui-variable-pitch 
:foreground ,blue-tab)))
     `(tab-bar-groups-tab-2 ((,class :inherit modus-themes-ui-variable-pitch 
:foreground ,red-tab)))
@@ -7427,8 +7425,9 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(writegood-weasels-face ((,class :inherit modus-themes-lang-error)))
 ;;;;; woman
     `(woman-addition ((,class :foreground ,magenta-alt-other)))
-    `(woman-bold ((,class :inherit bold :foreground ,fg-special-calm)))
-    `(woman-unknown ((,class :foreground ,cyan)))
+    `(woman-bold ((,class :inherit bold :foreground ,magenta-alt)))
+    `(woman-italic ((,class :inherit italic :foreground ,cyan)))
+    `(woman-unknown ((,class :foreground ,green-alt)))
 ;;;;; xah-elisp-mode
     `(xah-elisp-at-symbol ((,class :inherit font-lock-warning-face)))
     `(xah-elisp-cap-variable ((,class :inherit font-lock-preprocessor-face)))
@@ -7465,6 +7464,10 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
 ;;;; awesome-tray
     `(awesome-tray-mode-line-active-color ,blue)
     `(awesome-tray-mode-line-inactive-color ,bg-active)
+;;;; chart
+    `(chart-face-color-list
+      '( ,red-graph-0-bg ,green-graph-0-bg ,yellow-graph-0-bg ,blue-graph-0-bg 
,magenta-graph-0-bg ,cyan-graph-0-bg
+         ,red-graph-1-bg ,green-graph-1-bg ,yellow-graph-1-bg ,blue-graph-1-bg 
,magenta-graph-1-bg ,cyan-graph-1-bg))
 ;;;; exwm
     `(exwm-floating-border-color ,fg-window-divider-inner)
 ;;;; flymake fringe indicators
@@ -7504,29 +7507,6 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
 ;;;; pdf-tools
     `(pdf-view-midnight-colors
       '(,fg-main . ,bg-dim))
-;;;; vc-annotate (C-x v g)
-    `(vc-annotate-background nil)
-    `(vc-annotate-background-mode nil)
-    `(vc-annotate-color-map
-      '((20 . ,red)
-        (40 . ,magenta)
-        (60 . ,magenta-alt)
-        (80 . ,red-alt)
-        (100 . ,yellow)
-        (120 . ,yellow-alt)
-        (140 . ,fg-special-warm)
-        (160 . ,fg-special-mild)
-        (180 . ,green)
-        (200 . ,green-alt)
-        (220 . ,cyan-alt-other)
-        (240 . ,cyan-alt)
-        (260 . ,cyan)
-        (280 . ,fg-special-cold)
-        (300 . ,blue)
-        (320 . ,blue-alt)
-        (340 . ,blue-alt-other)
-        (360 . ,magenta-alt-other)))
-    `(vc-annotate-very-old-color nil)
 ;;;; wid-edit
     `(widget-link-prefix ,(if (memq 'all-buttons modus-themes-box-buttons)
                               " "
diff --git a/etc/themes/modus-vivendi-theme.el 
b/etc/themes/modus-vivendi-theme.el
index fe52aefc84..ba75a2527d 100644
--- a/etc/themes/modus-vivendi-theme.el
+++ b/etc/themes/modus-vivendi-theme.el
@@ -3,8 +3,10 @@
 ;; Copyright (C) 2019-2022  Free Software Foundation, Inc.
 
 ;; Author: Protesilaos Stavrou <info@protesilaos.com>
+;; Maintainer: Modus-Themes Development <~protesilaos/modus-themes@lists.sr.ht>
 ;; URL: https://git.sr.ht/~protesilaos/modus-themes
-;; Version: 2.4.1
+;; Mailing-List: https://lists.sr.ht/~protesilaos/modus-themes
+;; Version: 2.6.0
 ;; Package-Requires: ((emacs "27.1"))
 ;; Keywords: faces, theme, accessibility
 
diff --git a/etc/tutorials/TUTORIAL.nl b/etc/tutorials/TUTORIAL.nl
index 2ec3fac11b..7aaed218ff 100644
--- a/etc/tutorials/TUTORIAL.nl
+++ b/etc/tutorials/TUTORIAL.nl
@@ -1158,7 +1158,7 @@ overeenkomende commandonaam zoals find-file.
 --------------------
 
 Je kunt meer over Emacs leren door haar handleiding te lezen.  Deze is
-zowel als boek als in in Emacs beschikbaar (gebruik het Help menu of
+zowel als boek als in Emacs beschikbaar (gebruik het Help menu of
 tik C-h r).  Kijk bijvoorbeeld eens naar "completion", wat minder
 tikwerk oplevert, of "dired" wat het omgaan met bestanden
 vereenvoudigt.
diff --git a/lib-src/Makefile.in b/lib-src/Makefile.in
index 0453b93506..cf4659fc2c 100644
--- a/lib-src/Makefile.in
+++ b/lib-src/Makefile.in
@@ -210,11 +210,13 @@ HAVE_SECCOMP=@HAVE_SECCOMP@
 HAVE_LIBSECCOMP=@HAVE_LIBSECCOMP@
 LIBSECCOMP_LIBS=@LIBSECCOMP_LIBS@
 LIBSECCOMP_CFLAGS=@LIBSECCOMP_CFLAGS@
+SIZEOF_LONG=@SIZEOF_LONG@
 
 # Currently, we can only generate seccomp filter files for x86-64.
 ifeq ($(HAVE_SECCOMP),yes)
 ifeq ($(HAVE_LIBSECCOMP),yes)
 ifeq ($(shell uname -m),x86_64)
+ifeq ($(SIZEOF_LONG),8)
 # We require SECCOMP_RET_KILL_PROCESS, which is only available in
 # Linux 4.14 and later.
 ifeq ($(shell { echo 4.14; uname -r | cut -d . -f 1-2; } | \
@@ -225,6 +227,7 @@ endif
 endif
 endif
 endif
+endif
 
 ifeq ($(SECCOMP_FILTER),1)
 DONT_INSTALL += seccomp-filter$(EXEEXT)
diff --git a/lib-src/etags.c b/lib-src/etags.c
index 9a60714eca..ed8a218464 100644
--- a/lib-src/etags.c
+++ b/lib-src/etags.c
@@ -87,14 +87,6 @@ University of California, as described above. */
 
 #include <config.h>
 
-/* WIN32_NATIVE is for XEmacs.
-   MSDOS, WINDOWSNT, DOS_NT are for Emacs. */
-#ifdef WIN32_NATIVE
-# undef MSDOS
-# undef  WINDOWSNT
-# define WINDOWSNT
-#endif /* WIN32_NATIVE */
-
 #ifdef MSDOS
 # undef MSDOS
 # define MSDOS true
@@ -1431,6 +1423,16 @@ 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
+       /* 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 \"");
+       z = stpcpy (z, tagfile);
+       z = stpcpy (z, "\" \"");
+       z = stpcpy (z, tagfile);
+       stpcpy (z, "\"");
+#else
+       /* Quote 'like this', and escape the apostrophe in the file name.  */
        char *z = stpcpy (cmd, "sort -u -o '");
        char *escaped_tagfile = z;
        for (; *tagfile; *z++ = *tagfile++)
@@ -1440,6 +1442,7 @@ main (int argc, char **argv)
        z = stpcpy (z, "' '");
        z = mempcpy (z, escaped_tagfile, escaped_tagfile_len);
        strcpy (z, "'");
+#endif
        return system (cmd);
       }
   return EXIT_SUCCESS;
diff --git a/lib-src/make-docfile.c b/lib-src/make-docfile.c
index 908d73f525..b5beffce19 100644
--- a/lib-src/make-docfile.c
+++ b/lib-src/make-docfile.c
@@ -19,8 +19,8 @@ You should have received a copy of the GNU General Public 
License
 along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 
 
-/* The arguments given to this program are all the C and some Lisp source files
- of GNU Emacs.  .el and .c files are allowed.
+/* The arguments given to this program are all the C files
+ of GNU Emacs.  .c files are allowed.
  A .o file can also be specified; the .c file it was made from is used.
  This helps the makefile pass the correct list of files.
  Option -d DIR means change to DIR before looking for files.
@@ -66,7 +66,6 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #endif /* not DOS_NT */
 
 static void scan_file (char *filename);
-static void scan_lisp_file (const char *filename, const char *mode);
 static void scan_c_file (char *filename, const char *mode);
 static void scan_c_stream (FILE *infile);
 static void start_globals (void);
@@ -236,14 +235,9 @@ put_filename (char *filename)
 static void
 scan_file (char *filename)
 {
-  ptrdiff_t len = strlen (filename);
-
   if (!generate_globals)
     put_filename (filename);
-  if (len > 3 && !strcmp (filename + len - 3, ".el"))
-    scan_lisp_file (filename, "r");
-  else
-    scan_c_file (filename, "r");
+  scan_c_file (filename, "r");
 }
 
 static void
@@ -1221,352 +1215,4 @@ scan_c_stream (FILE *infile)
     fatal ("read error");
 }
 
-/* Read a file of Lisp source code.
- Looks for
-  (defun NAME ARGS DOCSTRING ...)
-  (defmacro NAME ARGS DOCSTRING ...)
-  (defsubst NAME ARGS DOCSTRING ...)
-  (autoload (quote NAME) FILE DOCSTRING ...)
-  (defvar NAME VALUE DOCSTRING)
-  (defconst NAME VALUE DOCSTRING)
-  (fset (quote NAME) (make-byte-code ... DOCSTRING ...))
-  (fset (quote NAME) #[... DOCSTRING ...])
-  (defalias (quote NAME) #[... DOCSTRING ...])
-  (custom-declare-variable (quote NAME) VALUE DOCSTRING ...)
- starting in column zero.
- (quote NAME) may appear as 'NAME as well.
-
- We also look for #@LENGTH CONTENTS^_ at the beginning of the line.
- When we find that, we save it for the following defining-form,
- and we use that instead of reading a doc string within that defining-form.
-
- For defvar, defconst, and fset we skip to the docstring with a kludgy
- formatting convention: all docstrings must appear on the same line as the
- initial open-paren (the one in column zero) and must contain a backslash
- and a newline immediately after the initial double-quote.  No newlines
- must appear between the beginning of the form and the first double-quote.
- For defun, defmacro, and autoload, we know how to skip over the
- arglist, but the doc string must still have a backslash and newline
- immediately after the double quote.
- The only source files that follow this convention are autoload-generated
- files like loaddefs.el;
- The NAME and DOCSTRING are output.
- NAME is preceded by `F' for a function or `V' for a variable.
- An entry is output only if DOCSTRING has \ newline just after the opening ".
- */
-
-static void
-skip_white (FILE *infile)
-{
-  int c;
-  do
-    c = getc (infile);
-  while (c_isspace (c));
-
-  ungetc (c, infile);
-}
-
-static void
-read_lisp_symbol (FILE *infile, char *buffer)
-{
-  int c;
-  char *fillp = buffer;
-
-  skip_white (infile);
-  while (true)
-    {
-      c = getc (infile);
-      if (c == '\\')
-       {
-         c = getc (infile);
-         if (c < 0)
-           return;
-         *fillp++ = c;
-       }
-      else if (c_isspace (c) || c == '(' || c == ')' || c < 0)
-       {
-         ungetc (c, infile);
-         *fillp = 0;
-         break;
-       }
-      else
-       *fillp++ = c;
-    }
-
-  if (! buffer[0])
-    fprintf (stderr, "## expected a symbol, got '%c'\n", c);
-
-  skip_white (infile);
-}
-
-static bool
-search_lisp_doc_at_eol (FILE *infile)
-{
-  int c = 0, c1 = 0, c2 = 0;
-
-  /* Skip until the end of line; remember two previous chars.  */
-  while (c != '\n' && c != '\r' && c != EOF)
-    {
-      c2 = c1;
-      c1 = c;
-      c = getc (infile);
-    }
-
-  /* If two previous characters were " and \,
-     this is a doc string.  Otherwise, there is none.  */
-  if (c2 != '"' || c1 != '\\')
-    {
-#ifdef DEBUG
-      fprintf (stderr, "## non-docstring found\n");
-#endif
-      ungetc (c, infile);
-      return false;
-    }
-  return true;
-}
-
-static void
-scan_lisp_file (const char *filename, const char *mode)
-{
-  FILE *infile;
-  int c;
-
-  if (generate_globals)
-    fatal ("scanning lisp file when -g specified");
-
-  infile = fopen (filename, mode);
-  if (infile == NULL)
-    {
-      perror (filename);
-      exit (EXIT_FAILURE);
-    }
-
-  c = '\n';
-  while (!feof (infile))
-    {
-      char buffer[BUFSIZ];
-      char type;
-
-      /* If not at end of line, skip till we get to one.  */
-      if (c != '\n' && c != '\r')
-       {
-         c = getc (infile);
-         continue;
-       }
-      /* Skip the line break.  */
-      while (c == '\n' || c == '\r')
-       c = getc (infile);
-
-      if (c != '(')
-       continue;
-
-      read_lisp_symbol (infile, buffer);
-
-      if (! strcmp (buffer, "defun")
-         || ! strcmp (buffer, "defmacro")
-         || ! strcmp (buffer, "defsubst"))
-       {
-         type = 'F';
-         read_lisp_symbol (infile, buffer);
-
-         /* Skip the arguments: either "nil" or a list in parens.  */
-
-         c = getc (infile);
-         if (c == 'n') /* nil */
-           {
-             if ((c = getc (infile)) != 'i'
-                 || (c = getc (infile)) != 'l')
-               {
-                 fprintf (stderr, "## unparsable arglist in %s (%s)\n",
-                          buffer, filename);
-                 continue;
-               }
-           }
-         else if (c != '(')
-           {
-             fprintf (stderr, "## unparsable arglist in %s (%s)\n",
-                      buffer, filename);
-             continue;
-           }
-         else
-           while (! (c == ')' || c < 0))
-             c = getc (infile);
-         skip_white (infile);
-
-         /* If the next three characters aren't `dquote bslash newline'
-            then we're not reading a docstring.
-          */
-         if ((c = getc (infile)) != '"'
-             || (c = getc (infile)) != '\\'
-             || ((c = getc (infile)) != '\n' && c != '\r'))
-           {
-#ifdef DEBUG
-             fprintf (stderr, "## non-docstring in %s (%s)\n",
-                      buffer, filename);
-#endif
-             continue;
-           }
-       }
-
-      else if (! strcmp (buffer, "defvar")
-              || ! strcmp (buffer, "defconst")
-              || ! strcmp (buffer, "defcustom"))
-       {
-         type = 'V';
-         read_lisp_symbol (infile, buffer);
-
-         if (!search_lisp_doc_at_eol (infile))
-           continue;
-       }
-
-      else if (! strcmp (buffer, "custom-declare-variable")
-              || ! strcmp (buffer, "defvaralias")
-              )
-       {
-         type = 'V';
-
-         c = getc (infile);
-         if (c == '\'')
-           read_lisp_symbol (infile, buffer);
-         else
-           {
-             if (c != '(')
-               {
-                 fprintf (stderr,
-                          "## unparsable name in custom-declare-variable in 
%s\n",
-                          filename);
-                 continue;
-               }
-             read_lisp_symbol (infile, buffer);
-             if (strcmp (buffer, "quote"))
-               {
-                 fprintf (stderr,
-                          "## unparsable name in custom-declare-variable in 
%s\n",
-                          filename);
-                 continue;
-               }
-             read_lisp_symbol (infile, buffer);
-             c = getc (infile);
-             if (c != ')')
-               {
-                 fprintf (stderr,
-                          "## unparsable quoted name in 
custom-declare-variable in %s\n",
-                          filename);
-                 continue;
-               }
-           }
-
-         if (!search_lisp_doc_at_eol (infile))
-           continue;
-       }
-
-      else if (! strcmp (buffer, "fset") || ! strcmp (buffer, "defalias"))
-       {
-         type = 'F';
-
-         c = getc (infile);
-         if (c == '\'')
-           read_lisp_symbol (infile, buffer);
-         else
-           {
-             if (c != '(')
-               {
-                 fprintf (stderr, "## unparsable name in fset in %s\n",
-                          filename);
-                 continue;
-               }
-             read_lisp_symbol (infile, buffer);
-             if (strcmp (buffer, "quote"))
-               {
-                 fprintf (stderr, "## unparsable name in fset in %s\n",
-                          filename);
-                 continue;
-               }
-             read_lisp_symbol (infile, buffer);
-             c = getc (infile);
-             if (c != ')')
-               {
-                 fprintf (stderr,
-                          "## unparsable quoted name in fset in %s\n",
-                          filename);
-                 continue;
-               }
-           }
-
-         if (!search_lisp_doc_at_eol (infile))
-           continue;
-       }
-
-      else if (! strcmp (buffer, "autoload"))
-       {
-         type = 'F';
-         c = getc (infile);
-         if (c == '\'')
-           read_lisp_symbol (infile, buffer);
-         else
-           {
-             if (c != '(')
-               {
-                 fprintf (stderr, "## unparsable name in autoload in %s\n",
-                          filename);
-                 continue;
-               }
-             read_lisp_symbol (infile, buffer);
-             if (strcmp (buffer, "quote"))
-               {
-                 fprintf (stderr, "## unparsable name in autoload in %s\n",
-                          filename);
-                 continue;
-               }
-             read_lisp_symbol (infile, buffer);
-             c = getc (infile);
-             if (c != ')')
-               {
-                 fprintf (stderr,
-                          "## unparsable quoted name in autoload in %s\n",
-                          filename);
-                 continue;
-               }
-           }
-         skip_white (infile);
-         c = getc (infile);
-         if (c != '\"')
-           {
-             fprintf (stderr, "## autoload of %s unparsable (%s)\n",
-                      buffer, filename);
-             continue;
-           }
-         read_c_string_or_comment (infile, 0, false, 0);
-
-         if (!search_lisp_doc_at_eol (infile))
-           continue;
-       }
-
-#ifdef DEBUG
-      else if (! strcmp (buffer, "if")
-              || ! strcmp (buffer, "byte-code"))
-       continue;
-#endif
-
-      else
-       {
-#ifdef DEBUG
-         fprintf (stderr, "## unrecognized top-level form, %s (%s)\n",
-                  buffer, filename);
-#endif
-         continue;
-       }
-
-      /* At this point, we should gobble a doc string from the input file.
-        The opening quote (and leading backslash-newline)
-        have already been read.  */
-
-      printf ("\037%c%s\n", type, buffer);
-      read_c_string_or_comment (infile, 1, false, 0);
-    }
-  if (ferror (infile) || fclose (infile) != 0)
-    fatal ("%s: read error", filename);
-}
-
-
 /* make-docfile.c ends here */
diff --git a/lib/fchmodat.c b/lib/fchmodat.c
index dc53583366..164e2c4a95 100644
--- a/lib/fchmodat.c
+++ b/lib/fchmodat.c
@@ -83,9 +83,10 @@ fchmodat (int dir, char const *file, mode_t mode, int flags)
 # if NEED_FCHMODAT_NONSYMLINK_FIX
   if (flags == AT_SYMLINK_NOFOLLOW)
     {
-      struct stat st;
+#  if HAVE_READLINKAT
+      char readlink_buf[1];
 
-#  if defined O_PATH && defined AT_EMPTY_PATH
+#   ifdef O_PATH
       /* Open a file descriptor with O_NOFOLLOW, to make sure we don't
          follow symbolic links, if /proc is mounted.  O_PATH is used to
          avoid a failure if the file is not readable.
@@ -94,49 +95,29 @@ fchmodat (int dir, char const *file, mode_t mode, int flags)
       if (fd < 0)
         return fd;
 
-      /* Up to Linux 5.3 at least, when FILE refers to a symbolic link, the
-         chmod call below will change the permissions of the symbolic link
-         - which is undesired - and on many file systems (ext4, btrfs, jfs,
-         xfs, ..., but not reiserfs) fail with error EOPNOTSUPP - which is
-         misleading.  Therefore test for a symbolic link explicitly.
-         Use fstatat because fstat does not work on O_PATH descriptors
-         before Linux 3.6.  */
-      if (fstatat (fd, "", &st, AT_EMPTY_PATH) != 0)
+      int err;
+      if (0 <= readlinkat (fd, "", readlink_buf, sizeof readlink_buf))
+        err = EOPNOTSUPP;
+      else if (errno == EINVAL)
         {
-          int stat_errno = errno;
-          close (fd);
-          errno = stat_errno;
-          return -1;
-        }
-      if (S_ISLNK (st.st_mode))
-        {
-          close (fd);
-          errno = EOPNOTSUPP;
-          return -1;
+          static char const fmt[] = "/proc/self/fd/%d";
+          char buf[sizeof fmt - sizeof "%d" + INT_BUFSIZE_BOUND (int)];
+          sprintf (buf, fmt, fd);
+          err = chmod (buf, mode) == 0 ? 0 : errno == ENOENT ? -1 : errno;
         }
+      else
+        err = errno == ENOENT ? -1 : errno;
 
-#   if defined __linux__ || defined __ANDROID__ || defined __CYGWIN__
-      static char const fmt[] = "/proc/self/fd/%d";
-      char buf[sizeof fmt - sizeof "%d" + INT_BUFSIZE_BOUND (int)];
-      sprintf (buf, fmt, fd);
-      int chmod_result = chmod (buf, mode);
-      int chmod_errno = errno;
       close (fd);
-      if (chmod_result == 0)
-        return chmod_result;
-      if (chmod_errno != ENOENT)
-        {
-          errno = chmod_errno;
-          return chmod_result;
-        }
+
+      errno = err;
+      if (0 <= err)
+        return err == 0 ? 0 : -1;
 #   endif
-      /* /proc is not mounted or would not work as in GNU/Linux.  */
 
-#  else
-      int fstatat_result = fstatat (dir, file, &st, AT_SYMLINK_NOFOLLOW);
-      if (fstatat_result != 0)
-        return fstatat_result;
-      if (S_ISLNK (st.st_mode))
+      /* O_PATH + /proc is not supported.  */
+
+      if (0 <= readlinkat (dir, file, readlink_buf, sizeof readlink_buf))
         {
           errno = EOPNOTSUPP;
           return -1;
diff --git a/lib/filevercmp.c b/lib/filevercmp.c
index d546e79054..7e54793e61 100644
--- a/lib/filevercmp.c
+++ b/lib/filevercmp.c
@@ -29,6 +29,8 @@
 /* Return the length of a prefix of S that corresponds to the suffix
    defined by this extended regular expression in the C locale:
      (\.[A-Za-z~][A-Za-z0-9~]*)*$
+   Use the longest suffix matching this regular expression,
+   except do not use all of S as a suffix if S is nonempty.
    If *LEN is -1, S is a string; set *LEN to S's length.
    Otherwise, *LEN should be nonnegative, S is a char array,
    and *LEN does not change.  */
@@ -36,20 +38,22 @@ static idx_t
 file_prefixlen (char const *s, ptrdiff_t *len)
 {
   size_t n = *len;  /* SIZE_MAX if N == -1.  */
+  idx_t prefixlen = 0;
 
-  for (idx_t i = 0; ; i++)
+  for (idx_t i = 0; ; )
     {
-      idx_t prefixlen = i;
-      while (i + 1 < n && s[i] == '.' && (c_isalpha (s[i + 1])
-                                          || s[i + 1] == '~'))
-        for (i += 2; i < n && (c_isalnum (s[i]) || s[i] == '~'); i++)
-          continue;
-
       if (*len < 0 ? !s[i] : i == n)
         {
           *len = i;
           return prefixlen;
         }
+
+      i++;
+      prefixlen = i;
+      while (i + 1 < n && s[i] == '.' && (c_isalpha (s[i + 1])
+                                          || s[i + 1] == '~'))
+        for (i += 2; i < n && (c_isalnum (s[i]) || s[i] == '~'); i++)
+          continue;
     }
 }
 
diff --git a/lib/filevercmp.h b/lib/filevercmp.h
index 5a33677671..57949760b2 100644
--- a/lib/filevercmp.h
+++ b/lib/filevercmp.h
@@ -61,7 +61,9 @@
    without them, using version sort without special priority;
    if they do not compare equal, this comparison result is used and
    the suffixes are effectively ignored.  Otherwise, the entire
-   strings are compared using version sort.
+   strings are compared using version sort.  When removing a suffix
+   from a nonempty string, remove the maximal-length suffix such that
+   the remaining string is nonempty.
 
    This function is intended to be a replacement for strverscmp.  */
 int filevercmp (char const *a, char const *b) _GL_ATTRIBUTE_PURE;
diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in
index bf0df878a5..5bb78740d6 100644
--- a/lib/gnulib.mk.in
+++ b/lib/gnulib.mk.in
@@ -35,6 +35,7 @@
 #  --macro-prefix=gl \
 #  --no-vc-files \
 #  --avoid=btowc \
+#  --avoid=chmod \
 #  --avoid=close \
 #  --avoid=crypto/af_alg \
 #  --avoid=dup \
@@ -317,6 +318,7 @@ GL_GENERATE_IEEE754_H_CONDITION = 
@GL_GENERATE_IEEE754_H_CONDITION@
 GL_GENERATE_LIMITS_H_CONDITION = @GL_GENERATE_LIMITS_H_CONDITION@
 GL_GENERATE_MINI_GMP_H_CONDITION = @GL_GENERATE_MINI_GMP_H_CONDITION@
 GL_GENERATE_STDALIGN_H_CONDITION = @GL_GENERATE_STDALIGN_H_CONDITION@
+GL_GENERATE_STDCKDINT_H_CONDITION = @GL_GENERATE_STDCKDINT_H_CONDITION@
 GL_GENERATE_STDDEF_H_CONDITION = @GL_GENERATE_STDDEF_H_CONDITION@
 GL_GENERATE_STDINT_H_CONDITION = @GL_GENERATE_STDINT_H_CONDITION@
 GL_GNULIB_ACCESS = @GL_GNULIB_ACCESS@
@@ -327,6 +329,7 @@ GL_GNULIB_CALLOC_GNU = @GL_GNULIB_CALLOC_GNU@
 GL_GNULIB_CALLOC_POSIX = @GL_GNULIB_CALLOC_POSIX@
 GL_GNULIB_CANONICALIZE_FILE_NAME = @GL_GNULIB_CANONICALIZE_FILE_NAME@
 GL_GNULIB_CHDIR = @GL_GNULIB_CHDIR@
+GL_GNULIB_CHMOD = @GL_GNULIB_CHMOD@
 GL_GNULIB_CHOWN = @GL_GNULIB_CHOWN@
 GL_GNULIB_CLOSE = @GL_GNULIB_CLOSE@
 GL_GNULIB_CLOSEDIR = @GL_GNULIB_CLOSEDIR@
@@ -1029,6 +1032,7 @@ REPLACE_ALIGNED_ALLOC = @REPLACE_ALIGNED_ALLOC@
 REPLACE_CALLOC_FOR_CALLOC_GNU = @REPLACE_CALLOC_FOR_CALLOC_GNU@
 REPLACE_CALLOC_FOR_CALLOC_POSIX = @REPLACE_CALLOC_FOR_CALLOC_POSIX@
 REPLACE_CANONICALIZE_FILE_NAME = @REPLACE_CANONICALIZE_FILE_NAME@
+REPLACE_CHMOD = @REPLACE_CHMOD@
 REPLACE_CHOWN = @REPLACE_CHOWN@
 REPLACE_CLOSE = @REPLACE_CLOSE@
 REPLACE_CLOSEDIR = @REPLACE_CLOSEDIR@
@@ -1195,9 +1199,12 @@ SETTINGS_CFLAGS = @SETTINGS_CFLAGS@
 SETTINGS_LIBS = @SETTINGS_LIBS@
 SHELL = @SHELL@
 SIG_ATOMIC_T_SUFFIX = @SIG_ATOMIC_T_SUFFIX@
+SIZEOF_LONG = @SIZEOF_LONG@
 SIZE_T_SUFFIX = @SIZE_T_SUFFIX@
+SMALL_JA_DIC = @SMALL_JA_DIC@
 SQLITE3_LIBS = @SQLITE3_LIBS@
 STDALIGN_H = @STDALIGN_H@
+STDCKDINT_H = @STDCKDINT_H@
 STDDEF_H = @STDDEF_H@
 STDINT_H = @STDINT_H@
 SUBDIR_MAKEFILES_IN = @SUBDIR_MAKEFILES_IN@
@@ -1314,6 +1321,7 @@ gl_GNULIB_ENABLED_lchmod_CONDITION = 
@gl_GNULIB_ENABLED_lchmod_CONDITION@
 gl_GNULIB_ENABLED_open_CONDITION = @gl_GNULIB_ENABLED_open_CONDITION@
 gl_GNULIB_ENABLED_rawmemchr_CONDITION = @gl_GNULIB_ENABLED_rawmemchr_CONDITION@
 gl_GNULIB_ENABLED_scratch_buffer_CONDITION = 
@gl_GNULIB_ENABLED_scratch_buffer_CONDITION@
+gl_GNULIB_ENABLED_stdckdint_CONDITION = @gl_GNULIB_ENABLED_stdckdint_CONDITION@
 gl_GNULIB_ENABLED_strtoll_CONDITION = @gl_GNULIB_ENABLED_strtoll_CONDITION@
 gl_GNULIB_ENABLED_utimens_CONDITION = @gl_GNULIB_ENABLED_utimens_CONDITION@
 gl_LIBOBJDEPS = @gl_LIBOBJDEPS@
@@ -2263,7 +2271,7 @@ endif
 ifeq (,$(OMIT_GNULIB_MODULE_intprops))
 
 
-EXTRA_DIST += intprops.h
+EXTRA_DIST += intprops-internal.h intprops.h
 
 endif
 ## end   gnulib module intprops
@@ -2868,6 +2876,31 @@ EXTRA_DIST += stdalign.in.h
 endif
 ## end   gnulib module stdalign
 
+## begin gnulib module stdckdint
+ifeq (,$(OMIT_GNULIB_MODULE_stdckdint))
+
+ifneq (,$(gl_GNULIB_ENABLED_stdckdint_CONDITION))
+BUILT_SOURCES += $(STDCKDINT_H)
+
+# We need the following in order to create <stdckdint.h> when the system
+# doesn't have one that works with the given compiler.
+ifneq (,$(GL_GENERATE_STDCKDINT_H_CONDITION))
+stdckdint.h: stdckdint.in.h $(top_builddir)/config.status
+       $(gl_V_at)$(SED_HEADER_STDOUT) \
+         $(srcdir)/stdckdint.in.h > $@-t
+       $(AM_V_at)mv $@-t $@
+else
+stdckdint.h: $(top_builddir)/config.status
+       rm -f $@
+endif
+MOSTLYCLEANFILES += stdckdint.h stdckdint.h-t
+
+endif
+EXTRA_DIST += intprops-internal.h stdckdint.in.h
+
+endif
+## end   gnulib module stdckdint
+
 ## begin gnulib module stddef
 ifeq (,$(OMIT_GNULIB_MODULE_stddef))
 
@@ -3497,6 +3530,7 @@ sys/stat.h: sys_stat.in.h $(top_builddir)/config.status 
$(CXXDEFS_H) $(ARG_NONNU
              -e 's|@''NEXT_SYS_STAT_H''@|$(NEXT_SYS_STAT_H)|g' \
              -e 's|@''WINDOWS_64_BIT_ST_SIZE''@|$(WINDOWS_64_BIT_ST_SIZE)|g' \
              -e 's|@''WINDOWS_STAT_TIMESPEC''@|$(WINDOWS_STAT_TIMESPEC)|g' \
+             -e 's/@''GNULIB_CHMOD''@/$(GL_GNULIB_CHMOD)/g' \
              -e 's/@''GNULIB_FCHMODAT''@/$(GL_GNULIB_FCHMODAT)/g' \
              -e 's/@''GNULIB_FSTAT''@/$(GL_GNULIB_FSTAT)/g' \
              -e 's/@''GNULIB_FSTATAT''@/$(GL_GNULIB_FSTATAT)/g' \
@@ -3528,6 +3562,7 @@ sys/stat.h: sys_stat.in.h $(top_builddir)/config.status 
$(CXXDEFS_H) $(ARG_NONNU
              -e 's|@''HAVE_MKNOD''@|$(HAVE_MKNOD)|g' \
              -e 's|@''HAVE_MKNODAT''@|$(HAVE_MKNODAT)|g' \
              -e 's|@''HAVE_UTIMENSAT''@|$(HAVE_UTIMENSAT)|g' \
+             -e 's|@''REPLACE_CHMOD''@|$(REPLACE_CHMOD)|g' \
              -e 's|@''REPLACE_FCHMODAT''@|$(REPLACE_FCHMODAT)|g' \
              -e 's|@''REPLACE_FSTAT''@|$(REPLACE_FSTAT)|g' \
              -e 's|@''REPLACE_FSTATAT''@|$(REPLACE_FSTATAT)|g' \
diff --git a/lib/group-member.c b/lib/group-member.c
index 480a12616a..cd43f36f4e 100644
--- a/lib/group-member.c
+++ b/lib/group-member.c
@@ -21,12 +21,11 @@
 /* Specification.  */
 #include <unistd.h>
 
+#include <stdckdint.h>
 #include <stdio.h>
 #include <sys/types.h>
 #include <stdlib.h>
 
-#include "intprops.h"
-
 /* Most processes have no more than this many groups, and for these
    processes we can avoid using malloc.  */
 enum { GROUPBUF_SIZE = 100 };
@@ -54,7 +53,7 @@ get_group_info (struct group_info *gi)
     {
       int n_group_slots = getgroups (0, NULL);
       size_t nbytes;
-      if (! INT_MULTIPLY_WRAPV (n_group_slots, sizeof *gi->group, &nbytes))
+      if (! ckd_mul (&nbytes, n_group_slots, sizeof *gi->group))
         {
           gi->group = malloc (nbytes);
           if (gi->group)
diff --git a/lib/intprops-internal.h b/lib/intprops-internal.h
new file mode 100644
index 0000000000..f6455f7855
--- /dev/null
+++ b/lib/intprops-internal.h
@@ -0,0 +1,392 @@
+/* intprops-internal.h -- properties of integer types not visible to users
+
+   Copyright (C) 2001-2022 Free Software Foundation, Inc.
+
+   This program 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 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 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/>.  */
+
+#ifndef _GL_INTPROPS_INTERNAL_H
+#define _GL_INTPROPS_INTERNAL_H
+
+#include <limits.h>
+
+/* Return a value with the common real type of E and V and the value of V.
+   Do not evaluate E.  */
+#define _GL_INT_CONVERT(e, v) ((1 ? 0 : (e)) + (v))
+
+/* Act like _GL_INT_CONVERT (E, -V) but work around a bug in IRIX 6.5 cc; see
+   <https://lists.gnu.org/r/bug-gnulib/2011-05/msg00406.html>.  */
+#define _GL_INT_NEGATE_CONVERT(e, v) ((1 ? 0 : (e)) - (v))
+
+/* The extra casts in the following macros work around compiler bugs,
+   e.g., in Cray C 5.0.3.0.  */
+
+/* True if the real type T is signed.  */
+#define _GL_TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
+
+/* Return 1 if the real expression E, after promotion, has a
+   signed or floating type.  Do not evaluate E.  */
+#define _GL_EXPR_SIGNED(e) (_GL_INT_NEGATE_CONVERT (e, 1) < 0)
+
+
+/* Minimum and maximum values for integer types and expressions.  */
+
+/* The width in bits of the integer type or expression T.
+   Do not evaluate T.  T must not be a bit-field expression.
+   Padding bits are not supported; this is checked at compile-time below.  */
+#define _GL_TYPE_WIDTH(t) (sizeof (t) * CHAR_BIT)
+
+/* The maximum and minimum values for the type of the expression E,
+   after integer promotion.  E is not evaluated.  */
+#define _GL_INT_MINIMUM(e)                                              \
+  (_GL_EXPR_SIGNED (e)                                                  \
+   ? ~ _GL_SIGNED_INT_MAXIMUM (e)                                       \
+   : _GL_INT_CONVERT (e, 0))
+#define _GL_INT_MAXIMUM(e)                                              \
+  (_GL_EXPR_SIGNED (e)                                                  \
+   ? _GL_SIGNED_INT_MAXIMUM (e)                                         \
+   : _GL_INT_NEGATE_CONVERT (e, 1))
+#define _GL_SIGNED_INT_MAXIMUM(e)                                       \
+  (((_GL_INT_CONVERT (e, 1) << (_GL_TYPE_WIDTH (+ (e)) - 2)) - 1) * 2 + 1)
+
+/* Work around OpenVMS incompatibility with C99.  */
+#if !defined LLONG_MAX && defined __INT64_MAX
+# define LLONG_MAX __INT64_MAX
+# define LLONG_MIN __INT64_MIN
+#endif
+
+/* This include file assumes that signed types are two's complement without
+   padding bits; the above macros have undefined behavior otherwise.
+   If this is a problem for you, please let us know how to fix it for your 
host.
+   This assumption is tested by the intprops-tests module.  */
+
+/* Does the __typeof__ keyword work?  This could be done by
+   'configure', but for now it's easier to do it by hand.  */
+#if (2 <= __GNUC__ \
+     || (4 <= __clang_major__) \
+     || (1210 <= __IBMC__ && defined __IBM__TYPEOF__) \
+     || (0x5110 <= __SUNPRO_C && !__STDC__))
+# define _GL_HAVE___TYPEOF__ 1
+#else
+# define _GL_HAVE___TYPEOF__ 0
+#endif
+
+/* Return 1 if the integer type or expression T might be signed.  Return 0
+   if it is definitely unsigned.  T must not be a bit-field expression.
+   This macro does not evaluate its argument, and expands to an
+   integer constant expression.  */
+#if _GL_HAVE___TYPEOF__
+# define _GL_SIGNED_TYPE_OR_EXPR(t) _GL_TYPE_SIGNED (__typeof__ (t))
+#else
+# define _GL_SIGNED_TYPE_OR_EXPR(t) 1
+#endif
+
+/* Return 1 if - A would overflow in [MIN,MAX] arithmetic.
+   A should not have side effects, and A's type should be an
+   integer with minimum value MIN and maximum MAX.  */
+#define _GL_INT_NEGATE_RANGE_OVERFLOW(a, min, max) \
+  ((min) < 0 ? (a) < - (max) : 0 < (a))
+
+/* True if __builtin_add_overflow (A, B, P) and __builtin_sub_overflow
+   (A, B, P) work when P is non-null.  */
+#ifdef __EDG__
+/* EDG-based compilers like nvc 22.1 cannot add 64-bit signed to unsigned
+   <https://bugs.gnu.org/53256>.  */
+# define _GL_HAS_BUILTIN_ADD_OVERFLOW 0
+#elif defined __has_builtin
+# define _GL_HAS_BUILTIN_ADD_OVERFLOW __has_builtin (__builtin_add_overflow)
+/* __builtin_{add,sub}_overflow exists but is not reliable in GCC 5.x and 6.x,
+   see <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98269>.  */
+#elif 7 <= __GNUC__
+# define _GL_HAS_BUILTIN_ADD_OVERFLOW 1
+#else
+# define _GL_HAS_BUILTIN_ADD_OVERFLOW 0
+#endif
+
+/* True if __builtin_mul_overflow (A, B, P) works when P is non-null.  */
+#if defined __clang_major__ && __clang_major__ < 14
+/* Work around Clang bug <https://bugs.llvm.org/show_bug.cgi?id=16404>.  */
+# define _GL_HAS_BUILTIN_MUL_OVERFLOW 0
+#else
+# define _GL_HAS_BUILTIN_MUL_OVERFLOW _GL_HAS_BUILTIN_ADD_OVERFLOW
+#endif
+
+/* True if __builtin_add_overflow_p (A, B, C) works, and similarly for
+   __builtin_sub_overflow_p and __builtin_mul_overflow_p.  */
+#ifdef __EDG__
+/* In EDG-based compilers like ICC 2021.3 and earlier,
+   __builtin_add_overflow_p etc. are not treated as integral constant
+   expressions even when all arguments are.  */
+# define _GL_HAS_BUILTIN_OVERFLOW_P 0
+#elif defined __has_builtin
+# define _GL_HAS_BUILTIN_OVERFLOW_P __has_builtin (__builtin_mul_overflow_p)
+#else
+# define _GL_HAS_BUILTIN_OVERFLOW_P (7 <= __GNUC__)
+#endif
+
+#if (!defined _GL_STDCKDINT_H && 202311 <= __STDC_VERSION__ \
+     && ! (_GL_HAS_BUILTIN_ADD_OVERFLOW && _GL_HAS_BUILTIN_MUL_OVERFLOW))
+# include <stdckdint.h>
+#endif
+
+/* Store the low-order bits of A + B, A - B, A * B, respectively, into *R.
+   Return 1 if the result overflows.  Arguments should not have side
+   effects and A, B and *R can be of any integer type other than char,
+   bool, a bit-precise integer type, or an enumeration type.  */
+#if _GL_HAS_BUILTIN_ADD_OVERFLOW
+# define _GL_INT_ADD_WRAPV(a, b, r) __builtin_add_overflow (a, b, r)
+# define _GL_INT_SUBTRACT_WRAPV(a, b, r) __builtin_sub_overflow (a, b, r)
+#elif defined ckd_add && defined ckd_sub && !defined _GL_STDCKDINT_H
+# define _GL_INT_ADD_WRAPV(a, b, r) ckd_add (r, + (a), + (b))
+# define _GL_INT_SUBTRACT_WRAPV(a, b, r) ckd_sub (r, + (a), + (b))
+#else
+# define _GL_INT_ADD_WRAPV(a, b, r) \
+   _GL_INT_OP_WRAPV (a, b, r, +, _GL_INT_ADD_RANGE_OVERFLOW)
+# define _GL_INT_SUBTRACT_WRAPV(a, b, r) \
+   _GL_INT_OP_WRAPV (a, b, r, -, _GL_INT_SUBTRACT_RANGE_OVERFLOW)
+#endif
+#if _GL_HAS_BUILTIN_MUL_OVERFLOW
+# if ((9 < __GNUC__ + (3 <= __GNUC_MINOR__) \
+       || (__GNUC__ == 8 && 4 <= __GNUC_MINOR__)) \
+      && !defined __EDG__)
+#  define _GL_INT_MULTIPLY_WRAPV(a, b, r) __builtin_mul_overflow (a, b, r)
+# else
+   /* Work around GCC bug 91450.  */
+#  define _GL_INT_MULTIPLY_WRAPV(a, b, r) \
+    ((!_GL_SIGNED_TYPE_OR_EXPR (*(r)) && _GL_EXPR_SIGNED (a) && 
_GL_EXPR_SIGNED (b) \
+      && _GL_INT_MULTIPLY_RANGE_OVERFLOW (a, b, 0, (__typeof__ (*(r))) -1)) \
+     ? ((void) __builtin_mul_overflow (a, b, r), 1) \
+     : __builtin_mul_overflow (a, b, r))
+# endif
+#elif defined ckd_mul && !defined _GL_STDCKDINT_H
+# define _GL_INT_MULTIPLY_WRAPV(a, b, r) ckd_mul (r, + (a), + (b))
+#else
+# define _GL_INT_MULTIPLY_WRAPV(a, b, r) \
+   _GL_INT_OP_WRAPV (a, b, r, *, _GL_INT_MULTIPLY_RANGE_OVERFLOW)
+#endif
+
+/* Nonzero if this compiler has GCC bug 68193 or Clang bug 25390.  See:
+   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68193
+   https://llvm.org/bugs/show_bug.cgi?id=25390
+   For now, assume all versions of GCC-like compilers generate bogus
+   warnings for _Generic.  This matters only for compilers that
+   lack relevant builtins.  */
+#if __GNUC__ || defined __clang__
+# define _GL__GENERIC_BOGUS 1
+#else
+# define _GL__GENERIC_BOGUS 0
+#endif
+
+/* Store the low-order bits of A <op> B into *R, where OP specifies
+   the operation and OVERFLOW the overflow predicate.  Return 1 if the
+   result overflows.  Arguments should not have side effects,
+   and A, B and *R can be of any integer type other than char, bool, a
+   bit-precise integer type, or an enumeration type.  */
+#if 201112 <= __STDC_VERSION__ && !_GL__GENERIC_BOGUS
+# define _GL_INT_OP_WRAPV(a, b, r, op, overflow) \
+   (_Generic \
+    (*(r), \
+     signed char: \
+       _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
+                        signed char, SCHAR_MIN, SCHAR_MAX), \
+     unsigned char: \
+       _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
+                        unsigned char, 0, UCHAR_MAX), \
+     short int: \
+       _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
+                        short int, SHRT_MIN, SHRT_MAX), \
+     unsigned short int: \
+       _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
+                        unsigned short int, 0, USHRT_MAX), \
+     int: \
+       _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
+                        int, INT_MIN, INT_MAX), \
+     unsigned int: \
+       _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
+                        unsigned int, 0, UINT_MAX), \
+     long int: \
+       _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
+                        long int, LONG_MIN, LONG_MAX), \
+     unsigned long int: \
+       _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
+                        unsigned long int, 0, ULONG_MAX), \
+     long long int: \
+       _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \
+                        long long int, LLONG_MIN, LLONG_MAX), \
+     unsigned long long int: \
+       _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \
+                        unsigned long long int, 0, ULLONG_MAX)))
+#else
+/* Store the low-order bits of A <op> B into *R, where OP specifies
+   the operation and OVERFLOW the overflow predicate.  If *R is
+   signed, its type is ST with bounds SMIN..SMAX; otherwise its type
+   is UT with bounds U..UMAX.  ST and UT are narrower than int.
+   Return 1 if the result overflows.  Arguments should not have side
+   effects, and A, B and *R can be of any integer type other than
+   char, bool, a bit-precise integer type, or an enumeration type.  */
+# if _GL_HAVE___TYPEOF__
+#  define _GL_INT_OP_WRAPV_SMALLISH(a,b,r,op,overflow,st,smin,smax,ut,umax) \
+    (_GL_TYPE_SIGNED (__typeof__ (*(r))) \
+     ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, st, smin, smax) \
+     : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, ut, 0, umax))
+# else
+#  define _GL_INT_OP_WRAPV_SMALLISH(a,b,r,op,overflow,st,smin,smax,ut,umax) \
+    (overflow (a, b, smin, smax) \
+     ? (overflow (a, b, 0, umax) \
+        ? (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a,b,op,unsigned,st), 1) \
+        : (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a,b,op,unsigned,st)) < 0) \
+     : (overflow (a, b, 0, umax) \
+        ? (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a,b,op,unsigned,st)) >= 0 \
+        : (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a,b,op,unsigned,st), 0)))
+# endif
+
+# define _GL_INT_OP_WRAPV(a, b, r, op, overflow) \
+   (sizeof *(r) == sizeof (signed char) \
+    ? _GL_INT_OP_WRAPV_SMALLISH (a, b, r, op, overflow, \
+                                 signed char, SCHAR_MIN, SCHAR_MAX, \
+                                 unsigned char, UCHAR_MAX) \
+    : sizeof *(r) == sizeof (short int) \
+    ? _GL_INT_OP_WRAPV_SMALLISH (a, b, r, op, overflow, \
+                                 short int, SHRT_MIN, SHRT_MAX, \
+                                 unsigned short int, USHRT_MAX) \
+    : sizeof *(r) == sizeof (int) \
+    ? (_GL_EXPR_SIGNED (*(r)) \
+       ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
+                          int, INT_MIN, INT_MAX) \
+       : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
+                          unsigned int, 0, UINT_MAX)) \
+    : _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow))
+# ifdef LLONG_MAX
+#  define _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow) \
+    (sizeof *(r) == sizeof (long int) \
+     ? (_GL_EXPR_SIGNED (*(r)) \
+        ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
+                           long int, LONG_MIN, LONG_MAX) \
+        : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
+                           unsigned long int, 0, ULONG_MAX)) \
+     : (_GL_EXPR_SIGNED (*(r)) \
+        ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \
+                           long long int, LLONG_MIN, LLONG_MAX) \
+        : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \
+                           unsigned long long int, 0, ULLONG_MAX)))
+# else
+#  define _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow) \
+    (_GL_EXPR_SIGNED (*(r)) \
+     ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
+                        long int, LONG_MIN, LONG_MAX) \
+     : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
+                        unsigned long int, 0, ULONG_MAX))
+# endif
+#endif
+
+/* Store the low-order bits of A <op> B into *R, where the operation
+   is given by OP.  Use the unsigned type UT for calculation to avoid
+   overflow problems.  *R's type is T, with extrema TMIN and TMAX.
+   T can be any signed integer type other than char, bool, a
+   bit-precise integer type, or an enumeration type.
+   Return 1 if the result overflows.  */
+#define _GL_INT_OP_CALC(a, b, r, op, overflow, ut, t, tmin, tmax) \
+  (overflow (a, b, tmin, tmax) \
+   ? (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 1) \
+   : (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 0))
+
+/* Return 1 if the integer expressions A - B and -A would overflow,
+   respectively.  Arguments should not have side effects,
+   and can be any signed integer type other than char, bool, a
+   bit-precise integer type, or an enumeration type.
+   These macros are tuned for their last input argument being a constant.  */
+
+#if _GL_HAS_BUILTIN_OVERFLOW_P
+# define _GL_INT_NEGATE_OVERFLOW(a) \
+   __builtin_sub_overflow_p (0, a, (__typeof__ (- (a))) 0)
+#else
+# define _GL_INT_NEGATE_OVERFLOW(a) \
+   _GL_INT_NEGATE_RANGE_OVERFLOW (a, _GL_INT_MINIMUM (a), _GL_INT_MAXIMUM (a))
+#endif
+
+/* Return the low-order bits of A <op> B, where the operation is given
+   by OP.  Use the unsigned type UT for calculation to avoid undefined
+   behavior on signed integer overflow, and convert the result to type T.
+   UT is at least as wide as T and is no narrower than unsigned int,
+   T is two's complement, and there is no padding or trap representations.
+   Assume that converting UT to T yields the low-order bits, as is
+   done in all known two's-complement C compilers.  E.g., see:
+   https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html
+
+   According to the C standard, converting UT to T yields an
+   implementation-defined result or signal for values outside T's
+   range.  However, code that works around this theoretical problem
+   runs afoul of a compiler bug in Oracle Studio 12.3 x86.  See:
+   https://lists.gnu.org/r/bug-gnulib/2017-04/msg00049.html
+   As the compiler bug is real, don't try to work around the
+   theoretical problem.  */
+
+#define _GL_INT_OP_WRAPV_VIA_UNSIGNED(a, b, op, ut, t) \
+  ((t) ((ut) (a) op (ut) (b)))
+
+/* Return true if the numeric values A + B, A - B, A * B fall outside
+   the range TMIN..TMAX.  Arguments should not have side effects
+   and can be any integer type other than char, bool,
+   a bit-precise integer type, or an enumeration type.
+   TMIN should be signed and nonpositive.
+   TMAX should be positive, and should be signed unless TMIN is zero.  */
+#define _GL_INT_ADD_RANGE_OVERFLOW(a, b, tmin, tmax) \
+  ((b) < 0 \
+   ? (((tmin) \
+       ? ((_GL_EXPR_SIGNED (_GL_INT_CONVERT (a, (tmin) - (b))) || (b) < 
(tmin)) \
+          && (a) < (tmin) - (b)) \
+       : (a) <= -1 - (b)) \
+      || ((_GL_EXPR_SIGNED (a) ? 0 <= (a) : (tmax) < (a)) && (tmax) < (a) + 
(b))) \
+   : (a) < 0 \
+   ? (((tmin) \
+       ? ((_GL_EXPR_SIGNED (_GL_INT_CONVERT (b, (tmin) - (a))) || (a) < 
(tmin)) \
+          && (b) < (tmin) - (a)) \
+       : (b) <= -1 - (a)) \
+      || ((_GL_EXPR_SIGNED (_GL_INT_CONVERT (a, b)) || (tmax) < (b)) \
+          && (tmax) < (a) + (b))) \
+   : (tmax) < (b) || (tmax) - (b) < (a))
+#define _GL_INT_SUBTRACT_RANGE_OVERFLOW(a, b, tmin, tmax) \
+  (((a) < 0) == ((b) < 0) \
+   ? ((a) < (b) \
+      ? !(tmin) || -1 - (tmin) < (b) - (a) - 1 \
+      : (tmax) < (a) - (b)) \
+   : (a) < 0 \
+   ? ((!_GL_EXPR_SIGNED (_GL_INT_CONVERT ((a) - (tmin), b)) && (a) - (tmin) < 
0) \
+      || (a) - (tmin) < (b)) \
+   : ((! (_GL_EXPR_SIGNED (_GL_INT_CONVERT (tmax, b)) \
+          && _GL_EXPR_SIGNED (_GL_INT_CONVERT ((tmax) + (b), a))) \
+       && (tmax) <= -1 - (b)) \
+      || (tmax) + (b) < (a)))
+#define _GL_INT_MULTIPLY_RANGE_OVERFLOW(a, b, tmin, tmax) \
+  ((b) < 0 \
+   ? ((a) < 0 \
+      ? (_GL_EXPR_SIGNED (_GL_INT_CONVERT (tmax, b)) \
+         ? (a) < (tmax) / (b) \
+         : ((_GL_INT_NEGATE_OVERFLOW (b) \
+             ? _GL_INT_CONVERT (b, tmax) >> (_GL_TYPE_WIDTH (+ (b)) - 1) \
+             : (tmax) / -(b)) \
+            <= -1 - (a))) \
+      : _GL_INT_NEGATE_OVERFLOW (_GL_INT_CONVERT (b, tmin)) && (b) == -1 \
+      ? (_GL_EXPR_SIGNED (a) \
+         ? 0 < (a) + (tmin) \
+         : 0 < (a) && -1 - (tmin) < (a) - 1) \
+      : (tmin) / (b) < (a)) \
+   : (b) == 0 \
+   ? 0 \
+   : ((a) < 0 \
+      ? (_GL_INT_NEGATE_OVERFLOW (_GL_INT_CONVERT (a, tmin)) && (a) == -1 \
+         ? (_GL_EXPR_SIGNED (b) ? 0 < (b) + (tmin) : -1 - (tmin) < (b) - 1) \
+         : (tmin) / (a) < (b)) \
+      : (tmax) / (b) < (a)))
+
+#endif /* _GL_INTPROPS_INTERNAL_H */
diff --git a/lib/intprops.h b/lib/intprops.h
index d4a917f72a..f182ddc1fe 100644
--- a/lib/intprops.h
+++ b/lib/intprops.h
@@ -15,19 +15,10 @@
    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/>.  */
 
-
 #ifndef _GL_INTPROPS_H
 #define _GL_INTPROPS_H
 
-#include <limits.h>
-
-/* Return a value with the common real type of E and V and the value of V.
-   Do not evaluate E.  */
-#define _GL_INT_CONVERT(e, v) ((1 ? 0 : (e)) + (v))
-
-/* Act like _GL_INT_CONVERT (E, -V) but work around a bug in IRIX 6.5 cc; see
-   <https://lists.gnu.org/r/bug-gnulib/2011-05/msg00406.html>.  */
-#define _GL_INT_NEGATE_CONVERT(e, v) ((1 ? 0 : (e)) - (v))
+#include "intprops-internal.h"
 
 /* The extra casts in the following macros work around compiler bugs,
    e.g., in Cray C 5.0.3.0.  */
@@ -37,11 +28,11 @@
 #define TYPE_IS_INTEGER(t) ((t) 1.5 == 1)
 
 /* True if the real type T is signed.  */
-#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
+#define TYPE_SIGNED(t) _GL_TYPE_SIGNED (t)
 
 /* Return 1 if the real expression E, after promotion, has a
    signed or floating type.  Do not evaluate E.  */
-#define EXPR_SIGNED(e) (_GL_INT_NEGATE_CONVERT (e, 1) < 0)
+#define EXPR_SIGNED(e) _GL_EXPR_SIGNED (e)
 
 
 /* Minimum and maximum values for integer types and expressions.  */
@@ -49,7 +40,7 @@
 /* The width in bits of the integer type or expression T.
    Do not evaluate T.  T must not be a bit-field expression.
    Padding bits are not supported; this is checked at compile-time below.  */
-#define TYPE_WIDTH(t) (sizeof (t) * CHAR_BIT)
+#define TYPE_WIDTH(t) _GL_TYPE_WIDTH (t)
 
 /* The maximum and minimum values for the integer type T.  */
 #define TYPE_MINIMUM(t) ((t) ~ TYPE_MAXIMUM (t))
@@ -58,51 +49,6 @@
         ? (t) -1                                                        \
         : ((((t) 1 << (TYPE_WIDTH (t) - 2)) - 1) * 2 + 1)))
 
-/* The maximum and minimum values for the type of the expression E,
-   after integer promotion.  E is not evaluated.  */
-#define _GL_INT_MINIMUM(e)                                              \
-  (EXPR_SIGNED (e)                                                      \
-   ? ~ _GL_SIGNED_INT_MAXIMUM (e)                                       \
-   : _GL_INT_CONVERT (e, 0))
-#define _GL_INT_MAXIMUM(e)                                              \
-  (EXPR_SIGNED (e)                                                      \
-   ? _GL_SIGNED_INT_MAXIMUM (e)                                         \
-   : _GL_INT_NEGATE_CONVERT (e, 1))
-#define _GL_SIGNED_INT_MAXIMUM(e)                                       \
-  (((_GL_INT_CONVERT (e, 1) << (TYPE_WIDTH (+ (e)) - 2)) - 1) * 2 + 1)
-
-/* Work around OpenVMS incompatibility with C99.  */
-#if !defined LLONG_MAX && defined __INT64_MAX
-# define LLONG_MAX __INT64_MAX
-# define LLONG_MIN __INT64_MIN
-#endif
-
-/* This include file assumes that signed types are two's complement without
-   padding bits; the above macros have undefined behavior otherwise.
-   If this is a problem for you, please let us know how to fix it for your 
host.
-   This assumption is tested by the intprops-tests module.  */
-
-/* Does the __typeof__ keyword work?  This could be done by
-   'configure', but for now it's easier to do it by hand.  */
-#if (2 <= __GNUC__ \
-     || (4 <= __clang_major__) \
-     || (1210 <= __IBMC__ && defined __IBM__TYPEOF__) \
-     || (0x5110 <= __SUNPRO_C && !__STDC__))
-# define _GL_HAVE___TYPEOF__ 1
-#else
-# define _GL_HAVE___TYPEOF__ 0
-#endif
-
-/* Return 1 if the integer type or expression T might be signed.  Return 0
-   if it is definitely unsigned.  T must not be a bit-field expression.
-   This macro does not evaluate its argument, and expands to an
-   integer constant expression.  */
-#if _GL_HAVE___TYPEOF__
-# define _GL_SIGNED_TYPE_OR_EXPR(t) TYPE_SIGNED (__typeof__ (t))
-#else
-# define _GL_SIGNED_TYPE_OR_EXPR(t) 1
-#endif
-
 /* Bound on length of the string representing an unsigned integer
    value representable in B bits.  log10 (2.0) < 146/485.  The
    smallest value of B where this bound is not tight is 2621.  */
@@ -129,12 +75,11 @@
 /* Range overflow checks.
 
    The INT_<op>_RANGE_OVERFLOW macros return 1 if the corresponding C
-   operators might not yield numerically correct answers due to
-   arithmetic overflow.  They do not rely on undefined or
-   implementation-defined behavior.  Their implementations are simple
-   and straightforward, but they are harder to use and may be less
-   efficient than the INT_<op>_WRAPV, INT_<op>_OK, and
-   INT_<op>_OVERFLOW macros described below.
+   operators overflow arithmetically when given the same arguments.
+   These macros do not rely on undefined or implementation-defined behavior.
+   Although their implementations are simple and straightforward,
+   they are harder to use and may be less efficient than the
+   INT_<op>_WRAPV, INT_<op>_OK, and INT_<op>_OVERFLOW macros described below.
 
    Example usage:
 
@@ -181,9 +126,7 @@
 /* Return 1 if - A would overflow in [MIN,MAX] arithmetic.
    See above for restrictions.  */
 #define INT_NEGATE_RANGE_OVERFLOW(a, min, max)          \
-  ((min) < 0                                            \
-   ? (a) < - (max)                                      \
-   : 0 < (a))
+  _GL_INT_NEGATE_RANGE_OVERFLOW (a, min, max)
 
 /* Return 1 if A * B would overflow in [MIN,MAX] arithmetic.
    See above for restrictions.  Avoid && and || as they tickle
@@ -227,43 +170,6 @@
    ? (a) < (min) >> (b)                                 \
    : (max) >> (b) < (a))
 
-/* True if __builtin_add_overflow (A, B, P) and __builtin_sub_overflow
-   (A, B, P) work when P is non-null.  */
-#ifdef __EDG__
-/* EDG-based compilers like nvc 22.1 cannot add 64-bit signed to unsigned
-   <https://bugs.gnu.org/53256>.  */
-# define _GL_HAS_BUILTIN_ADD_OVERFLOW 0
-#elif defined __has_builtin
-# define _GL_HAS_BUILTIN_ADD_OVERFLOW __has_builtin (__builtin_add_overflow)
-/* __builtin_{add,sub}_overflow exists but is not reliable in GCC 5.x and 6.x,
-   see <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98269>.  */
-#elif 7 <= __GNUC__
-# define _GL_HAS_BUILTIN_ADD_OVERFLOW 1
-#else
-# define _GL_HAS_BUILTIN_ADD_OVERFLOW 0
-#endif
-
-/* True if __builtin_mul_overflow (A, B, P) works when P is non-null.  */
-#if defined __clang_major__ && __clang_major__ < 14
-/* Work around Clang bug <https://bugs.llvm.org/show_bug.cgi?id=16404>.  */
-# define _GL_HAS_BUILTIN_MUL_OVERFLOW 0
-#else
-# define _GL_HAS_BUILTIN_MUL_OVERFLOW _GL_HAS_BUILTIN_ADD_OVERFLOW
-#endif
-
-/* True if __builtin_add_overflow_p (A, B, C) works, and similarly for
-   __builtin_sub_overflow_p and __builtin_mul_overflow_p.  */
-#ifdef __EDG__
-/* In EDG-based compilers like ICC 2021.3 and earlier,
-   __builtin_add_overflow_p etc. are not treated as integral constant
-   expressions even when all arguments are.  */
-# define _GL_HAS_BUILTIN_OVERFLOW_P 0
-#elif defined __has_builtin
-# define _GL_HAS_BUILTIN_OVERFLOW_P __has_builtin (__builtin_mul_overflow_p)
-#else
-# define _GL_HAS_BUILTIN_OVERFLOW_P (7 <= __GNUC__)
-#endif
-
 /* The _GL*_OVERFLOW macros have the same restrictions as the
    *_RANGE_OVERFLOW macros, except that they do not assume that operands
    (e.g., A and B) have the same type as MIN and MAX.  Instead, they assume
@@ -350,13 +256,18 @@
    Because the WRAPV macros convert the result, they report overflow
    in different circumstances than the OVERFLOW macros do.  For
    example, in the typical case with 16-bit 'short' and 32-bit 'int',
-   if A, B and R are all of type 'short' then INT_ADD_OVERFLOW (A, B)
+   if A, B and *R are all of type 'short' then INT_ADD_OVERFLOW (A, B)
    returns false because the addition cannot overflow after A and B
-   are converted to 'int', whereas INT_ADD_WRAPV (A, B, &R) returns
+   are converted to 'int', whereas INT_ADD_WRAPV (A, B, R) returns
    true or false depending on whether the sum fits into 'short'.
 
    These macros are tuned for their last input argument being a constant.
 
+   A, B, and *R should be integers; they need not be the same type,
+   and they need not be all signed or all unsigned.
+   However, none of the integer types should be bit-precise,
+   and *R's type should not be char, bool, or an enumeration type.
+
    Return 1 if the integer expressions A * B, A - B, -A, A * B, A / B,
    A % B, and A << B would overflow, respectively.  */
 
@@ -364,12 +275,7 @@
   _GL_BINARY_OP_OVERFLOW (a, b, _GL_ADD_OVERFLOW)
 #define INT_SUBTRACT_OVERFLOW(a, b) \
   _GL_BINARY_OP_OVERFLOW (a, b, _GL_SUBTRACT_OVERFLOW)
-#if _GL_HAS_BUILTIN_OVERFLOW_P
-# define INT_NEGATE_OVERFLOW(a) INT_SUBTRACT_OVERFLOW (0, a)
-#else
-# define INT_NEGATE_OVERFLOW(a) \
-   INT_NEGATE_RANGE_OVERFLOW (a, _GL_INT_MINIMUM (a), _GL_INT_MAXIMUM (a))
-#endif
+#define INT_NEGATE_OVERFLOW(a) _GL_INT_NEGATE_OVERFLOW (a)
 #define INT_MULTIPLY_OVERFLOW(a, b) \
   _GL_BINARY_OP_OVERFLOW (a, b, _GL_MULTIPLY_OVERFLOW)
 #define INT_DIVIDE_OVERFLOW(a, b) \
@@ -391,224 +297,9 @@
 
 /* Store the low-order bits of A + B, A - B, A * B, respectively, into *R.
    Return 1 if the result overflows.  See above for restrictions.  */
-#if _GL_HAS_BUILTIN_ADD_OVERFLOW
-# define INT_ADD_WRAPV(a, b, r) __builtin_add_overflow (a, b, r)
-# define INT_SUBTRACT_WRAPV(a, b, r) __builtin_sub_overflow (a, b, r)
-#else
-# define INT_ADD_WRAPV(a, b, r) \
-   _GL_INT_OP_WRAPV (a, b, r, +, _GL_INT_ADD_RANGE_OVERFLOW)
-# define INT_SUBTRACT_WRAPV(a, b, r) \
-   _GL_INT_OP_WRAPV (a, b, r, -, _GL_INT_SUBTRACT_RANGE_OVERFLOW)
-#endif
-#if _GL_HAS_BUILTIN_MUL_OVERFLOW
-# if ((9 < __GNUC__ + (3 <= __GNUC_MINOR__) \
-       || (__GNUC__ == 8 && 4 <= __GNUC_MINOR__)) \
-      && !defined __EDG__)
-#  define INT_MULTIPLY_WRAPV(a, b, r) __builtin_mul_overflow (a, b, r)
-# else
-   /* Work around GCC bug 91450.  */
-#  define INT_MULTIPLY_WRAPV(a, b, r) \
-    ((!_GL_SIGNED_TYPE_OR_EXPR (*(r)) && EXPR_SIGNED (a) && EXPR_SIGNED (b) \
-      && _GL_INT_MULTIPLY_RANGE_OVERFLOW (a, b, 0, (__typeof__ (*(r))) -1)) \
-     ? ((void) __builtin_mul_overflow (a, b, r), 1) \
-     : __builtin_mul_overflow (a, b, r))
-# endif
-#else
-# define INT_MULTIPLY_WRAPV(a, b, r) \
-   _GL_INT_OP_WRAPV (a, b, r, *, _GL_INT_MULTIPLY_RANGE_OVERFLOW)
-#endif
-
-/* Nonzero if this compiler has GCC bug 68193 or Clang bug 25390.  See:
-   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68193
-   https://llvm.org/bugs/show_bug.cgi?id=25390
-   For now, assume all versions of GCC-like compilers generate bogus
-   warnings for _Generic.  This matters only for compilers that
-   lack relevant builtins.  */
-#if __GNUC__ || defined __clang__
-# define _GL__GENERIC_BOGUS 1
-#else
-# define _GL__GENERIC_BOGUS 0
-#endif
-
-/* Store the low-order bits of A <op> B into *R, where OP specifies
-   the operation and OVERFLOW the overflow predicate.  Return 1 if the
-   result overflows.  See above for restrictions.  */
-#if 201112 <= __STDC_VERSION__ && !_GL__GENERIC_BOGUS
-# define _GL_INT_OP_WRAPV(a, b, r, op, overflow) \
-   (_Generic \
-    (*(r), \
-     signed char: \
-       _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
-                        signed char, SCHAR_MIN, SCHAR_MAX), \
-     unsigned char: \
-       _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
-                        unsigned char, 0, UCHAR_MAX), \
-     short int: \
-       _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
-                        short int, SHRT_MIN, SHRT_MAX), \
-     unsigned short int: \
-       _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
-                        unsigned short int, 0, USHRT_MAX), \
-     int: \
-       _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
-                        int, INT_MIN, INT_MAX), \
-     unsigned int: \
-       _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
-                        unsigned int, 0, UINT_MAX), \
-     long int: \
-       _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
-                        long int, LONG_MIN, LONG_MAX), \
-     unsigned long int: \
-       _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
-                        unsigned long int, 0, ULONG_MAX), \
-     long long int: \
-       _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \
-                        long long int, LLONG_MIN, LLONG_MAX), \
-     unsigned long long int: \
-       _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \
-                        unsigned long long int, 0, ULLONG_MAX)))
-#else
-/* Store the low-order bits of A <op> B into *R, where OP specifies
-   the operation and OVERFLOW the overflow predicate.  If *R is
-   signed, its type is ST with bounds SMIN..SMAX; otherwise its type
-   is UT with bounds U..UMAX.  ST and UT are narrower than int.
-   Return 1 if the result overflows.  See above for restrictions.  */
-# if _GL_HAVE___TYPEOF__
-#  define _GL_INT_OP_WRAPV_SMALLISH(a,b,r,op,overflow,st,smin,smax,ut,umax) \
-    (TYPE_SIGNED (__typeof__ (*(r))) \
-     ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, st, smin, smax) \
-     : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, ut, 0, umax))
-# else
-#  define _GL_INT_OP_WRAPV_SMALLISH(a,b,r,op,overflow,st,smin,smax,ut,umax) \
-    (overflow (a, b, smin, smax) \
-     ? (overflow (a, b, 0, umax) \
-        ? (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a,b,op,unsigned,st), 1) \
-        : (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a,b,op,unsigned,st)) < 0) \
-     : (overflow (a, b, 0, umax) \
-        ? (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a,b,op,unsigned,st)) >= 0 \
-        : (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a,b,op,unsigned,st), 0)))
-# endif
-
-# define _GL_INT_OP_WRAPV(a, b, r, op, overflow) \
-   (sizeof *(r) == sizeof (signed char) \
-    ? _GL_INT_OP_WRAPV_SMALLISH (a, b, r, op, overflow, \
-                                 signed char, SCHAR_MIN, SCHAR_MAX, \
-                                 unsigned char, UCHAR_MAX) \
-    : sizeof *(r) == sizeof (short int) \
-    ? _GL_INT_OP_WRAPV_SMALLISH (a, b, r, op, overflow, \
-                                 short int, SHRT_MIN, SHRT_MAX, \
-                                 unsigned short int, USHRT_MAX) \
-    : sizeof *(r) == sizeof (int) \
-    ? (EXPR_SIGNED (*(r)) \
-       ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
-                          int, INT_MIN, INT_MAX) \
-       : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
-                          unsigned int, 0, UINT_MAX)) \
-    : _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow))
-# ifdef LLONG_MAX
-#  define _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow) \
-    (sizeof *(r) == sizeof (long int) \
-     ? (EXPR_SIGNED (*(r)) \
-        ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
-                           long int, LONG_MIN, LONG_MAX) \
-        : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
-                           unsigned long int, 0, ULONG_MAX)) \
-     : (EXPR_SIGNED (*(r)) \
-        ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \
-                           long long int, LLONG_MIN, LLONG_MAX) \
-        : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \
-                           unsigned long long int, 0, ULLONG_MAX)))
-# else
-#  define _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow) \
-    (EXPR_SIGNED (*(r)) \
-     ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
-                        long int, LONG_MIN, LONG_MAX) \
-     : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
-                        unsigned long int, 0, ULONG_MAX))
-# endif
-#endif
-
-/* Store the low-order bits of A <op> B into *R, where the operation
-   is given by OP.  Use the unsigned type UT for calculation to avoid
-   overflow problems.  *R's type is T, with extrema TMIN and TMAX.
-   T must be a signed integer type.  Return 1 if the result overflows.  */
-#define _GL_INT_OP_CALC(a, b, r, op, overflow, ut, t, tmin, tmax) \
-  (overflow (a, b, tmin, tmax) \
-   ? (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 1) \
-   : (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 0))
-
-/* Return the low-order bits of A <op> B, where the operation is given
-   by OP.  Use the unsigned type UT for calculation to avoid undefined
-   behavior on signed integer overflow, and convert the result to type T.
-   UT is at least as wide as T and is no narrower than unsigned int,
-   T is two's complement, and there is no padding or trap representations.
-   Assume that converting UT to T yields the low-order bits, as is
-   done in all known two's-complement C compilers.  E.g., see:
-   https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html
-
-   According to the C standard, converting UT to T yields an
-   implementation-defined result or signal for values outside T's
-   range.  However, code that works around this theoretical problem
-   runs afoul of a compiler bug in Oracle Studio 12.3 x86.  See:
-   https://lists.gnu.org/r/bug-gnulib/2017-04/msg00049.html
-   As the compiler bug is real, don't try to work around the
-   theoretical problem.  */
-
-#define _GL_INT_OP_WRAPV_VIA_UNSIGNED(a, b, op, ut, t) \
-  ((t) ((ut) (a) op (ut) (b)))
-
-/* Return true if the numeric values A + B, A - B, A * B fall outside
-   the range TMIN..TMAX.  Arguments should be integer expressions
-   without side effects.  TMIN should be signed and nonpositive.
-   TMAX should be positive, and should be signed unless TMIN is zero.  */
-#define _GL_INT_ADD_RANGE_OVERFLOW(a, b, tmin, tmax) \
-  ((b) < 0 \
-   ? (((tmin) \
-       ? ((EXPR_SIGNED (_GL_INT_CONVERT (a, (tmin) - (b))) || (b) < (tmin)) \
-          && (a) < (tmin) - (b)) \
-       : (a) <= -1 - (b)) \
-      || ((EXPR_SIGNED (a) ? 0 <= (a) : (tmax) < (a)) && (tmax) < (a) + (b))) \
-   : (a) < 0 \
-   ? (((tmin) \
-       ? ((EXPR_SIGNED (_GL_INT_CONVERT (b, (tmin) - (a))) || (a) < (tmin)) \
-          && (b) < (tmin) - (a)) \
-       : (b) <= -1 - (a)) \
-      || ((EXPR_SIGNED (_GL_INT_CONVERT (a, b)) || (tmax) < (b)) \
-          && (tmax) < (a) + (b))) \
-   : (tmax) < (b) || (tmax) - (b) < (a))
-#define _GL_INT_SUBTRACT_RANGE_OVERFLOW(a, b, tmin, tmax) \
-  (((a) < 0) == ((b) < 0) \
-   ? ((a) < (b) \
-      ? !(tmin) || -1 - (tmin) < (b) - (a) - 1 \
-      : (tmax) < (a) - (b)) \
-   : (a) < 0 \
-   ? ((!EXPR_SIGNED (_GL_INT_CONVERT ((a) - (tmin), b)) && (a) - (tmin) < 0) \
-      || (a) - (tmin) < (b)) \
-   : ((! (EXPR_SIGNED (_GL_INT_CONVERT (tmax, b)) \
-          && EXPR_SIGNED (_GL_INT_CONVERT ((tmax) + (b), a))) \
-       && (tmax) <= -1 - (b)) \
-      || (tmax) + (b) < (a)))
-#define _GL_INT_MULTIPLY_RANGE_OVERFLOW(a, b, tmin, tmax) \
-  ((b) < 0 \
-   ? ((a) < 0 \
-      ? (EXPR_SIGNED (_GL_INT_CONVERT (tmax, b)) \
-         ? (a) < (tmax) / (b) \
-         : ((INT_NEGATE_OVERFLOW (b) \
-             ? _GL_INT_CONVERT (b, tmax) >> (TYPE_WIDTH (+ (b)) - 1) \
-             : (tmax) / -(b)) \
-            <= -1 - (a))) \
-      : INT_NEGATE_OVERFLOW (_GL_INT_CONVERT (b, tmin)) && (b) == -1 \
-      ? (EXPR_SIGNED (a) \
-         ? 0 < (a) + (tmin) \
-         : 0 < (a) && -1 - (tmin) < (a) - 1) \
-      : (tmin) / (b) < (a)) \
-   : (b) == 0 \
-   ? 0 \
-   : ((a) < 0 \
-      ? (INT_NEGATE_OVERFLOW (_GL_INT_CONVERT (a, tmin)) && (a) == -1 \
-         ? (EXPR_SIGNED (b) ? 0 < (b) + (tmin) : -1 - (tmin) < (b) - 1) \
-         : (tmin) / (a) < (b)) \
-      : (tmax) / (b) < (a)))
+#define INT_ADD_WRAPV(a, b, r) _GL_INT_ADD_WRAPV (a, b, r)
+#define INT_SUBTRACT_WRAPV(a, b, r) _GL_INT_SUBTRACT_WRAPV (a, b, r)
+#define INT_MULTIPLY_WRAPV(a, b, r) _GL_INT_MULTIPLY_WRAPV (a, b, r)
 
 /* The following macros compute A + B, A - B, and A * B, respectively.
    If no overflow occurs, they set *R to the result and return 1;
@@ -624,6 +315,8 @@
 
    A, B, and *R should be integers; they need not be the same type,
    and they need not be all signed or all unsigned.
+   However, none of the integer types should be bit-precise,
+   and *R's type should not be char, bool, or an enumeration type.
 
    These macros work correctly on all known practical hosts, and do not rely
    on undefined behavior due to signed arithmetic overflow.
@@ -635,8 +328,8 @@
 
    These macros are tuned for B being a constant.  */
 
-#define INT_ADD_OK(a, b, r) ! INT_ADD_WRAPV (a, b, r)
-#define INT_SUBTRACT_OK(a, b, r) ! INT_SUBTRACT_WRAPV (a, b, r)
-#define INT_MULTIPLY_OK(a, b, r) ! INT_MULTIPLY_WRAPV (a, b, r)
+#define INT_ADD_OK(a, b, r) (! INT_ADD_WRAPV (a, b, r))
+#define INT_SUBTRACT_OK(a, b, r) (! INT_SUBTRACT_WRAPV (a, b, r))
+#define INT_MULTIPLY_OK(a, b, r) (! INT_MULTIPLY_WRAPV (a, b, r))
 
 #endif /* _GL_INTPROPS_H */
diff --git a/lib/lchmod.c b/lib/lchmod.c
index 706dddff7b..8410a2d835 100644
--- a/lib/lchmod.c
+++ b/lib/lchmod.c
@@ -25,17 +25,9 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <stdio.h>
+#include <string.h>
 #include <unistd.h>
 
-#ifdef __osf__
-/* Write "sys/stat.h" here, not <sys/stat.h>, otherwise OSF/1 5.1 DTK cc
-   eliminates this include because of the preliminary #include <sys/stat.h>
-   above.  */
-# include "sys/stat.h"
-#else
-# include <sys/stat.h>
-#endif
-
 #include <intprops.h>
 
 /* Work like chmod, except when FILE is a symbolic link.
@@ -45,7 +37,9 @@
 int
 lchmod (char const *file, mode_t mode)
 {
-#if defined O_PATH && defined AT_EMPTY_PATH
+  char readlink_buf[1];
+
+#ifdef O_PATH
   /* Open a file descriptor with O_NOFOLLOW, to make sure we don't
      follow symbolic links, if /proc is mounted.  O_PATH is used to
      avoid a failure if the file is not readable.
@@ -54,56 +48,46 @@ lchmod (char const *file, mode_t mode)
   if (fd < 0)
     return fd;
 
-  /* Up to Linux 5.3 at least, when FILE refers to a symbolic link, the
-     chmod call below will change the permissions of the symbolic link
-     - which is undesired - and on many file systems (ext4, btrfs, jfs,
-     xfs, ..., but not reiserfs) fail with error EOPNOTSUPP - which is
-     misleading.  Therefore test for a symbolic link explicitly.
-     Use fstatat because fstat does not work on O_PATH descriptors
-     before Linux 3.6.  */
-  struct stat st;
-  if (fstatat (fd, "", &st, AT_EMPTY_PATH) != 0)
+  int err;
+  if (0 <= readlinkat (fd, "", readlink_buf, sizeof readlink_buf))
+    err = EOPNOTSUPP;
+  else if (errno == EINVAL)
     {
-      int stat_errno = errno;
-      close (fd);
-      errno = stat_errno;
-      return -1;
-    }
-  if (S_ISLNK (st.st_mode))
-    {
-      close (fd);
-      errno = EOPNOTSUPP;
-      return -1;
+      static char const fmt[] = "/proc/self/fd/%d";
+      char buf[sizeof fmt - sizeof "%d" + INT_BUFSIZE_BOUND (int)];
+      sprintf (buf, fmt, fd);
+      err = chmod (buf, mode) == 0 ? 0 : errno == ENOENT ? -1 : errno;
     }
+  else
+    err = errno == ENOENT ? -1 : errno;
 
-# if defined __linux__ || defined __ANDROID__ || defined __CYGWIN__
-  static char const fmt[] = "/proc/self/fd/%d";
-  char buf[sizeof fmt - sizeof "%d" + INT_BUFSIZE_BOUND (int)];
-  sprintf (buf, fmt, fd);
-  int chmod_result = chmod (buf, mode);
-  int chmod_errno = errno;
   close (fd);
-  if (chmod_result == 0)
-    return chmod_result;
-  if (chmod_errno != ENOENT)
+
+  errno = err;
+  if (0 <= err)
+    return err == 0 ? 0 : -1;
+#endif
+
+  size_t len = strlen (file);
+  if (len && file[len - 1] == '/')
     {
-      errno = chmod_errno;
-      return chmod_result;
+      struct stat st;
+      if (lstat (file, &st) < 0)
+        return -1;
+      if (!S_ISDIR (st.st_mode))
+        {
+          errno = ENOTDIR;
+          return -1;
+        }
     }
-# endif
-  /* /proc is not mounted or would not work as in GNU/Linux.  */
-
-#elif HAVE_LSTAT
-  struct stat st;
-  int lstat_result = lstat (file, &st);
-  if (lstat_result != 0)
-    return lstat_result;
-  if (S_ISLNK (st.st_mode))
+
+  /* O_PATH + /proc is not supported.  */
+
+  if (0 <= readlink (file, readlink_buf, sizeof readlink_buf))
     {
       errno = EOPNOTSUPP;
       return -1;
     }
-#endif
 
   /* Fall back on chmod, despite a possible race.  */
   return chmod (file, mode);
diff --git a/lib/mini-gmp.h b/lib/mini-gmp.h
index 508712d235..59c24cf511 100644
--- a/lib/mini-gmp.h
+++ b/lib/mini-gmp.h
@@ -8,7 +8,7 @@ The GNU MP Library is free software; you can redistribute it 
and/or modify
 it under the terms of either:
 
   * the GNU Lesser General Public License as published by the Free
-    Software Foundation, either version 3 of the License, or (at your
+    Software Foundation; either version 3 of the License, or (at your
     option) any later version.
 
 or
diff --git a/lib/stdckdint.in.h b/lib/stdckdint.in.h
new file mode 100644
index 0000000000..90fa62e596
--- /dev/null
+++ b/lib/stdckdint.in.h
@@ -0,0 +1,37 @@
+/* stdckdint.h -- checked integer arithmetic
+
+   Copyright 2022 Free Software Foundation, Inc.
+
+   This program 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 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 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/>.  */
+
+#ifndef _GL_STDCKDINT_H
+#define _GL_STDCKDINT_H
+
+#include "intprops-internal.h"
+
+#include <stdbool.h>
+
+/* Store into *R the low-order bits of A + B, A - B, A * B, respectively.
+   Return 1 if the result overflows, 0 otherwise.
+   A, B, and *R can have any integer type other than char, bool, a
+   bit-precise integer type, or an enumeration type.
+
+   These are like the standard macros introduced in C23, except that
+   arguments should not have side effects.  */
+
+#define ckd_add(r, a, b) ((bool) _GL_INT_ADD_WRAPV (a, b, r))
+#define ckd_sub(r, a, b) ((bool) _GL_INT_SUBTRACT_WRAPV (a, b, r))
+#define ckd_mul(r, a, b) ((bool) _GL_INT_MULTIPLY_WRAPV (a, b, r))
+
+#endif /* _GL_STDCKDINT_H */
diff --git a/lib/str-two-way.h b/lib/str-two-way.h
index 7ee344aea1..b00017c0b4 100644
--- a/lib/str-two-way.h
+++ b/lib/str-two-way.h
@@ -231,7 +231,7 @@ critical_factorization (const unsigned char *needle, size_t 
needle_len,
    most 2 * HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching.
    If AVAILABLE modifies HAYSTACK_LEN (as in strstr), then at most 3 *
    HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching.  */
-static RETURN_TYPE
+static RETURN_TYPE _GL_ATTRIBUTE_PURE
 two_way_short_needle (const unsigned char *haystack, size_t haystack_len,
                       const unsigned char *needle, size_t needle_len)
 {
@@ -325,7 +325,7 @@ two_way_short_needle (const unsigned char *haystack, size_t 
haystack_len,
    If AVAILABLE modifies HAYSTACK_LEN (as in strstr), then at most 3 *
    HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching, and
    sublinear performance is not possible.  */
-static RETURN_TYPE
+static RETURN_TYPE _GL_ATTRIBUTE_PURE
 two_way_long_needle (const unsigned char *haystack, size_t haystack_len,
                      const unsigned char *needle, size_t needle_len)
 {
diff --git a/lib/string.in.h b/lib/string.in.h
index 33160b2525..3996da9fcb 100644
--- a/lib/string.in.h
+++ b/lib/string.in.h
@@ -122,8 +122,12 @@ _GL_EXTERN_C void rpl_free (void *);
 #  undef _GL_ATTRIBUTE_DEALLOC_FREE
 #  define _GL_ATTRIBUTE_DEALLOC_FREE _GL_ATTRIBUTE_DEALLOC (rpl_free, 1)
 # else
-#  if defined _MSC_VER
-_GL_EXTERN_C void __cdecl free (void *);
+#  if defined _MSC_VER && !defined free
+_GL_EXTERN_C
+#   if defined _DLL
+     __declspec (dllimport)
+#   endif
+     void __cdecl free (void *);
 #  else
 #   if defined __cplusplus && (__GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2)
 _GL_EXTERN_C void free (void *) throw ();
@@ -133,8 +137,12 @@ _GL_EXTERN_C void free (void *);
 #  endif
 # endif
 #else
-# if defined _MSC_VER
-_GL_EXTERN_C void __cdecl free (void *);
+# if defined _MSC_VER && !defined free
+_GL_EXTERN_C
+#   if defined _DLL
+     __declspec (dllimport)
+#   endif
+     void __cdecl free (void *);
 # else
 #  if defined __cplusplus && (__GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2)
 _GL_EXTERN_C void free (void *) throw ();
diff --git a/lib/sys_stat.in.h b/lib/sys_stat.in.h
index 28ddd42f81..714c3cb189 100644
--- a/lib/sys_stat.in.h
+++ b/lib/sys_stat.in.h
@@ -391,7 +391,33 @@ struct stat
 #endif
 
 
-#if @GNULIB_MDA_CHMOD@
+#if @GNULIB_CHMOD@
+# if @REPLACE_CHMOD@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef chmod
+#   define chmod rpl_chmod
+#  endif
+_GL_FUNCDECL_RPL (chmod, int, (const char *filename, mode_t mode)
+                               _GL_ARG_NONNULL ((1)));
+_GL_CXXALIAS_RPL (chmod, int, (const char *filename, mode_t mode));
+# elif defined _WIN32 && !defined __CYGWIN__
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef chmod
+#   define chmod _chmod
+#  endif
+/* Need to cast, because in mingw the last argument is 'int mode'.  */
+_GL_CXXALIAS_MDA_CAST (chmod, int, (const char *filename, mode_t mode));
+# else
+_GL_CXXALIAS_SYS (chmod, int, (const char *filename, mode_t mode));
+# endif
+_GL_CXXALIASWARN (chmod);
+#elif defined GNULIB_POSIXCHECK
+# undef chmod
+# if HAVE_RAW_DECL_CHMOD
+_GL_WARN_ON_USE (chmod, "chmod has portability problems - "
+                 "use gnulib module chmod for portability");
+# endif
+#elif @GNULIB_MDA_CHMOD@
 /* On native Windows, map 'chmod' to '_chmod', so that -loldnames is not
    required.  In C++ with GNULIB_NAMESPACE, avoid differences between
    platforms by defining GNULIB_NAMESPACE::chmod always.  */
diff --git a/lib/tempname.c b/lib/tempname.c
index 5fc5efe031..11b4796b34 100644
--- a/lib/tempname.c
+++ b/lib/tempname.c
@@ -20,16 +20,10 @@
 # include "tempname.h"
 #endif
 
-#include <sys/types.h>
-#include <assert.h>
 #include <stdbool.h>
-
 #include <errno.h>
 
 #include <stdio.h>
-#ifndef P_tmpdir
-# define P_tmpdir "/tmp"
-#endif
 #ifndef TMP_MAX
 # define TMP_MAX 238328
 #endif
@@ -43,27 +37,23 @@
 # error report this to bug-gnulib@gnu.org
 #endif
 
-#include <stddef.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include <fcntl.h>
-#include <stdalign.h>
 #include <stdint.h>
 #include <sys/random.h>
 #include <sys/stat.h>
 #include <time.h>
 
 #if _LIBC
-# define struct_stat64 struct stat64
-# define __secure_getenv __libc_secure_getenv
+# define struct_stat64 struct __stat64_t64
 #else
 # define struct_stat64 struct stat
 # define __gen_tempname gen_tempname
 # define __mkdir mkdir
 # define __open open
-# define __lstat64(file, buf) lstat (file, buf)
-# define __stat64(file, buf) stat (file, buf)
+# define __lstat64_time64(file, buf) lstat (file, buf)
 # define __getrandom getrandom
 # define __clock_gettime64 clock_gettime
 # define __timespec64 timespec
@@ -77,94 +67,56 @@ typedef uint_fast64_t random_value;
 #define BASE_62_DIGITS 10 /* 62**10 < UINT_FAST64_MAX */
 #define BASE_62_POWER (62LL * 62 * 62 * 62 * 62 * 62 * 62 * 62 * 62 * 62)
 
+/* Return the result of mixing the entropy from R and S.
+   Assume that R and S are not particularly random,
+   and that the result should look randomish to an untrained eye.  */
+
 static random_value
-random_bits (random_value var, bool use_getrandom)
+mix_random_values (random_value r, random_value s)
 {
-  random_value r;
-  /* Without GRND_NONBLOCK it can be blocked for minutes on some systems.  */
-  if (use_getrandom && __getrandom (&r, sizeof r, GRND_NONBLOCK) == sizeof r)
-    return r;
-#if _LIBC || (defined CLOCK_MONOTONIC && HAVE_CLOCK_GETTIME)
-  /* Add entropy if getrandom did not work.  */
-  struct __timespec64 tv;
-  __clock_gettime64 (CLOCK_MONOTONIC, &tv);
-  var ^= tv.tv_nsec;
-#endif
-  return 2862933555777941757 * var + 3037000493;
+  /* As this code is used only when high-quality randomness is neither
+     available nor necessary, there is no need for fancier polynomials
+     such as those in the Linux kernel's 'random' driver.  */
+  return (2862933555777941757 * r + 3037000493) ^ s;
 }
 
-#if _LIBC
-/* Return nonzero if DIR is an existent directory.  */
-static int
-direxists (const char *dir)
-{
-  struct_stat64 buf;
-  return __stat64 (dir, &buf) == 0 && S_ISDIR (buf.st_mode);
-}
+/* Set *R to a random value.
+   Return true if *R is set to high-quality value taken from getrandom.
+   Otherwise return false, falling back to a low-quality *R that might
+   depend on S.
 
-/* Path search algorithm, for tmpnam, tmpfile, etc.  If DIR is
-   non-null and exists, uses it; otherwise uses the first of $TMPDIR,
-   P_tmpdir, /tmp that exists.  Copies into TMPL a template suitable
-   for use with mk[s]temp.  Will fail (-1) if DIR is non-null and
-   doesn't exist, none of the searched dirs exists, or there's not
-   enough space in TMPL. */
-int
-__path_search (char *tmpl, size_t tmpl_len, const char *dir, const char *pfx,
-               int try_tmpdir)
+   This function returns false only when getrandom fails.
+   On GNU systems this should happen only early in the boot process,
+   when the fallback should be good enough for programs using tempname
+   because any attacker likely has root privileges already.  */
+
+static bool
+random_bits (random_value *r, random_value s)
 {
-  const char *d;
-  size_t dlen, plen;
+  /* Without GRND_NONBLOCK it can be blocked for minutes on some systems.  */
+  if (__getrandom (r, sizeof *r, GRND_NONBLOCK) == sizeof *r)
+    return true;
 
-  if (!pfx || !pfx[0])
-    {
-      pfx = "file";
-      plen = 4;
-    }
-  else
-    {
-      plen = strlen (pfx);
-      if (plen > 5)
-        plen = 5;
-    }
+  /* If getrandom did not work, use ersatz entropy based on low-order
+     clock bits.  On GNU systems getrandom should fail only
+     early in booting, when ersatz should be good enough.
+     Do not use ASLR-based entropy, as that would leak ASLR info into
+     the resulting file name which is typically public.
 
-  if (try_tmpdir)
-    {
-      d = __secure_getenv ("TMPDIR");
-      if (d != NULL && direxists (d))
-        dir = d;
-      else if (dir != NULL && direxists (dir))
-        /* nothing */ ;
-      else
-        dir = NULL;
-    }
-  if (dir == NULL)
-    {
-      if (direxists (P_tmpdir))
-        dir = P_tmpdir;
-      else if (strcmp (P_tmpdir, "/tmp") != 0 && direxists ("/tmp"))
-        dir = "/tmp";
-      else
-        {
-          __set_errno (ENOENT);
-          return -1;
-        }
-    }
+     Of course we are in a state of sin here.  */
 
-  dlen = strlen (dir);
-  while (dlen > 1 && dir[dlen - 1] == '/')
-    dlen--;                     /* remove trailing slashes */
+  random_value v = s;
 
-  /* check we have room for "${dir}/${pfx}XXXXXX\0" */
-  if (tmpl_len < dlen + 1 + plen + 6 + 1)
-    {
-      __set_errno (EINVAL);
-      return -1;
-    }
+#if _LIBC || (defined CLOCK_REALTIME && HAVE_CLOCK_GETTIME)
+  struct __timespec64 tv;
+  __clock_gettime64 (CLOCK_REALTIME, &tv);
+  v = mix_random_values (v, tv.tv_sec);
+  v = mix_random_values (v, tv.tv_nsec);
+#endif
 
-  sprintf (tmpl, "%.*s/%.*sXXXXXX", (int) dlen, dir, (int) plen, pfx);
-  return 0;
+  *r = mix_random_values (v, clock ());
+  return false;
 }
-#endif /* _LIBC */
 
 #if _LIBC
 static int try_tempname_len (char *, int, void *, int (*) (char *, void *),
@@ -191,7 +143,7 @@ try_nocreate (char *tmpl, _GL_UNUSED void *flags)
 {
   struct_stat64 st;
 
-  if (__lstat64 (tmpl, &st) == 0 || errno == EOVERFLOW)
+  if (__lstat64_time64 (tmpl, &st) == 0 || errno == EOVERFLOW)
     __set_errno (EEXIST);
   return errno == ENOENT ? 0 : -1;
 }
@@ -213,7 +165,7 @@ static const char letters[] =
                         and return a read-write fd.  The file is mode 0600.
    __GT_DIR:            create a directory, which will be mode 0700.
 
-   We use a clever algorithm to get hard-to-predict names. */
+   */
 #ifdef _LIBC
 static
 #endif
@@ -261,25 +213,17 @@ try_tempname_len (char *tmpl, int suffixlen, void *args,
   unsigned int attempts = ATTEMPTS_MIN;
 #endif
 
-  /* A random variable.  The initial value is used only the for fallback path
-     on 'random_bits' on 'getrandom' failure.  Its initial value tries to use
-     some entropy from the ASLR and ignore possible bits from the stack
-     alignment.  */
-  random_value v = ((uintptr_t) &v) / alignof (max_align_t);
+  /* A random variable.  */
+  random_value v = 0;
 
-  /* How many random base-62 digits can currently be extracted from V.  */
+  /* A value derived from the random variable, and how many random
+     base-62 digits can currently be extracted from VDIGBUF.  */
+  random_value vdigbuf;
   int vdigits = 0;
 
-  /* Whether to consume entropy when acquiring random bits.  On the
-     first try it's worth the entropy cost with __GT_NOCREATE, which
-     is inherently insecure and can use the entropy to make it a bit
-     less secure.  On the (rare) second and later attempts it might
-     help against DoS attacks.  */
-  bool use_getrandom = tryfunc == try_nocreate;
-
-  /* Least unfair value for V.  If V is less than this, V can generate
-     BASE_62_DIGITS digits fairly.  Otherwise it might be biased.  */
-  random_value const unfair_min
+  /* Least biased value for V.  If V is less than this, V can generate
+     BASE_62_DIGITS unbiased digits.  Otherwise the digits are biased.  */
+  random_value const biased_min
     = RANDOM_VALUE_MAX - RANDOM_VALUE_MAX % BASE_62_POWER;
 
   len = strlen (tmpl);
@@ -299,18 +243,16 @@ try_tempname_len (char *tmpl, int suffixlen, void *args,
         {
           if (vdigits == 0)
             {
-              do
-                {
-                  v = random_bits (v, use_getrandom);
-                  use_getrandom = true;
-                }
-              while (unfair_min <= v);
+              /* Worry about bias only if the bits are high quality.  */
+              while (random_bits (&v, v) && biased_min <= v)
+                continue;
 
+              vdigbuf = v;
               vdigits = BASE_62_DIGITS;
             }
 
-          XXXXXX[i] = letters[v % 62];
-          v /= 62;
+          XXXXXX[i] = letters[vdigbuf % 62];
+          vdigbuf /= 62;
           vdigits--;
         }
 
diff --git a/lib/tempname.h b/lib/tempname.h
index c172820f7f..5e3c5e1550 100644
--- a/lib/tempname.h
+++ b/lib/tempname.h
@@ -48,7 +48,7 @@ extern "C" {
                         and return a read-write fd.  The file is mode 0600.
    GT_DIR:              create a directory, which will be mode 0700.
 
-   We use a clever algorithm to get hard-to-predict names. */
+   */
 extern int gen_tempname (char *tmpl, int suffixlen, int flags, int kind);
 /* Similar, except X_SUFFIX_LEN gives the number of Xs.  */
 extern int gen_tempname_len (char *tmpl, int suffixlen, int flags, int kind,
diff --git a/lib/verify.h b/lib/verify.h
index c5c63ae97c..47b6ee661b 100644
--- a/lib/verify.h
+++ b/lib/verify.h
@@ -303,13 +303,16 @@ template <int w>
 # define assume(R) ((R) ? (void) 0 : __builtin_unreachable ())
 #elif 1200 <= _MSC_VER
 # define assume(R) __assume (R)
+#elif 202311L <= __STDC_VERSION__
+# include <stddef.h>
+# define assume(R) ((R) ? (void) 0 : unreachable ())
 #elif (defined GCC_LINT || defined lint) && _GL_HAS_BUILTIN_TRAP
   /* Doing it this way helps various packages when configured with
      --enable-gcc-warnings, which compiles with -Dlint.  It's nicer
-     when 'assume' silences warnings even with older GCCs.  */
+     if 'assume' silences warnings with GCC 3.4 through GCC 4.4.7 (2012).  */
 # define assume(R) ((R) ? (void) 0 : __builtin_trap ())
 #else
-  /* Some tools grok NOTREACHED, e.g., Oracle Studio 12.6.  */
+  /* Some older tools grok NOTREACHED, e.g., Oracle Studio 12.6 (2017).  */
 # define assume(R) ((R) ? (void) 0 : /*NOTREACHED*/ (void) 0)
 #endif
 
diff --git a/lisp/ChangeLog.12 b/lisp/ChangeLog.12
index c45c8ae735..a89e515510 100644
--- a/lisp/ChangeLog.12
+++ b/lisp/ChangeLog.12
@@ -14359,7 +14359,7 @@
        * ldefs-boot.el: Likewise.
 
        * textmodes/bibtex.el (bibtex-validate-globally): Fix typo in a
-       message text: "Duplicat" => "Duplicate".
+       message text.
 
 2006-01-06  Sven Joachim  <svenjoac@gmx.de>  (tiny change)
 
diff --git a/lisp/ChangeLog.17 b/lisp/ChangeLog.17
index 6333d1dadd..cebafe18aa 100644
--- a/lisp/ChangeLog.17
+++ b/lisp/ChangeLog.17
@@ -825,7 +825,7 @@
 
 2015-03-10  Paul Eggert  <eggert@cs.ucla.edu>
 
-       Prefer "initialize" to "initialise"
+       Prefer "initialize"
        * progmodes/js.el (js-indent-first-init):
        Rename from js-indent-first-initialiser, to avoid worrying about
        American vs British spelling.  All uses changed.
diff --git a/lisp/ChangeLog.5 b/lisp/ChangeLog.5
index 4c54f148c1..b7b8b892db 100644
--- a/lisp/ChangeLog.5
+++ b/lisp/ChangeLog.5
@@ -8998,7 +8998,7 @@
 
        * startup.el (inhibit-startup-echo-area-message): Doc fix.
 
-       * avoid.el (mouse-avoidance-threshold): Renamed from ...threshhold.
+       * avoid.el (mouse-avoidance-threshold): Fix typo in name.
 
 1994-06-13  Richard Stallman  (rms@albert.gnu.ai.mit.edu)
 
@@ -9010,7 +9010,7 @@
 
        * startup.el (inhibit-startup-echo-area-message): Doc fix.
 
-       * avoid.el (mouse-avoidance-threshold): Renamed from ...threshhold.
+       * avoid.el (mouse-avoidance-threshold): Fix typo in name.
 
        * simple.el (end-of-buffer): Recenter overlay lists.
 
diff --git a/lisp/ChangeLog.9 b/lisp/ChangeLog.9
index 00c8133743..a8ebe81e7d 100644
--- a/lisp/ChangeLog.9
+++ b/lisp/ChangeLog.9
@@ -5165,7 +5165,7 @@
        * sql.el (sql-interbase): New function.
        (sql-interbase-program): New option.
        (sql-interbase-options): New option.
-       And some typos fixed: "customise" to "customize".
+       And some typos fixed: "customize".
 
 2001-03-06  Dave Love  <fx@gnu.org>
 
diff --git a/lisp/Makefile.in b/lisp/Makefile.in
index 8728467977..c73a623cce 100644
--- a/lisp/Makefile.in
+++ b/lisp/Makefile.in
@@ -67,7 +67,8 @@ AUTOGENEL = ${loaddefs} ${srcdir}/cus-load.el 
${srcdir}/finder-inf.el \
 
 # Set load-prefer-newer for the benefit of the non-bootstrappers.
 BYTE_COMPILE_FLAGS = \
-  --eval '(setq load-prefer-newer t)' $(BYTE_COMPILE_EXTRA_FLAGS)
+  --eval "(setq load-prefer-newer t byte-compile-warnings 'all)" \
+       $(BYTE_COMPILE_EXTRA_FLAGS)
 # ... but we must prefer .elc files for those in the early bootstrap.
 # A larger `max-specpdl-size' is needed for emacs-lisp/comp.el.
 compile-first: BYTE_COMPILE_FLAGS = \
@@ -122,10 +123,10 @@ SUBDIRS_FINDER = $(filter-out 
${srcdir}/leim%,${SUBDIRS_ALMOST})
 ## All subdirectories in which we might want to create subdirs.el.
 SUBDIRS_SUBDIRS = $(filter-out ${srcdir}/cedet% ${srcdir}/leim%,${SUBDIRS})
 
-# cus-load and finder-inf are not explicitly requested by anything, so
-# we add them here to make sure they get built.
+# cus-load, finder-inf and autoloads are not explicitly requested by
+# anything, so we add them here to make sure they get built.
 all: compile-main $(lisp)/cus-load.el $(lisp)/finder-inf.el generate-ja-dic \
-       org-manuals
+       org-manuals autoloads
 
 PHONY_EXTRAS =
 .PHONY: all custom-deps finder-data autoloads update-subdirs $(PHONY_EXTRAS) \
@@ -170,52 +171,42 @@ org-manuals: main-first
 
 ## Comments on loaddefs generation:
 
-# loaddefs depends on gen-lisp for two reasons:
-# 1) In ../src, the emacs target depends on loaddefs but not on eg leim-list.
-# So having leim as a dependency of loaddefs (via gen-lisp) ensures leim-list
+# loaddefs depends on gen-lisp because in ../src, the emacs target
+# depends on loaddefs, but not on, for instance, leim-list.  So having
+# leim as a dependency of loaddefs (via gen-lisp) ensures leim-list
 # gets created before the final emacs is dumped.  Having leim
-# dependencies in ../src as well would create a parallel race condition.
+# dependencies in ../src as well would create a parallel race
+# condition.
 #
-# FIXME: 2) is no longer correct, so perhaps we could add unidata to
-# gen-lisp now?
+# FIXME: Is the following true any more?
 #
-# 2) Files that are marked no-update-autoloads still get recorded in loaddefs.
-# So those files should be generated before we make autoloads, if we
-# don't want a successive make autoloads to change the output file.
-# Said changes are trivial (only comments in the "files without autoloads"
-# section), but still can be annoying.  Of course, if generated lisp files
-# do contain autoloads, it is essential they be built before make autoloads.
-# (Also, if a generated file is not written atomically, it is possible that
-# in a parallel build, make autoloads could read a partial version of it.)
-#
-# We'd really like to add "make -C ../admin/unidata all" to gen-lisp
-# because of 2) above, but it causes a race condition in parallel
-# builds because ../src also runs that rule.  Given the limitations of
-# recursive make, the only way to fix that would be to remove unidata
-# from ../src rules, but that doesn't seem possible due to the various
-# non-trivial dependencies.
-
-# We make $(lisp)/loaddefs.el a dependency of .PHONY to cause Make to
-# ignore its time stamp.  That's because the real dependencies of
-# loaddefs.el aren't known to Make, they are implemented in
-# loaddefs-generate--emacs-batch.
-
-autoloads .PHONY: $(lisp)/loaddefs.el
-$(lisp)/loaddefs.el: gen-lisp $(LOADDEFS) $(lisp)/emacs-lisp/loaddefs-gen.elc
+# We'd really like to add "make -C ../admin/unidata all" to gen-lisp,
+# but it causes a race condition in parallel builds because ../src
+# also runs that rule.  Given the limitations of recursive make, the
+# only way to fix that would be to remove unidata from ../src rules,
+# but that doesn't seem possible due to the various non-trivial
+# dependencies.
+
+# The real dependencies of loaddefs.el aren't known to Make, they are
+# implemented in loaddefs-generate--emacs-batch, so autoloads is an
+# "all" dependency.  "leim" isn't really a dependency here, but we
+# need leim-list.el at about the same time, so ensure that it's
+# generated, too.
+autoloads: $(lisp)/emacs-lisp/loaddefs-gen.elc gen-lisp
        $(AM_V_GEN)$(emacs) \
             -l $(lisp)/emacs-lisp/loaddefs-gen.elc \
            -f loaddefs-generate--emacs-batch ${SUBDIRS_ALMOST}
 
-# autoloads only runs when loaddefs.el is nonexistent, although it
-# generates a number of different files. Provide a force option to enable
-# regeneration of all these files.
+# autoloads always runs, but only updates when there's something new.
+# Provide a force option to enable regeneration of all loaddefs files.
 .PHONY: autoloads-force
 autoloads-force:
        rm -f $(lisp)/loaddefs.el
        $(MAKE) autoloads
 
 ldefs-boot.el: autoloads-force
-       cp  $(lisp)/loaddefs.el $(lisp)/ldefs-boot.el
+       sed '/^;; Local Variables:/a ;; no-byte-compile: t'\
+               < $(lisp)/loaddefs.el > $(lisp)/ldefs-boot.el
 
 # This is required by the bootstrap-emacs target in ../src/Makefile, so
 # we know that if we have an emacs executable, we also have a subdirs.el.
@@ -361,7 +352,11 @@ endif
 
 # Compile all the Elisp files that need it.  Beware: it approximates
 # 'no-byte-compile', so watch out for false-positives!
-compile-main: gen-lisp compile-clean main-first
+
+# The "autoloads" target has to run first, because it may generate new
+# loaddefs files.  But don't depend on it, because that might trigger
+# unnecessary rebuilds.
+compile-main: gen-lisp compile-clean main-first | autoloads
        @(cd $(lisp) &&                              \
        els=`echo "${SUBDIRS_REL} " | sed -e 's|/\./|/|g' -e 's|/\. | |g' -e 
's| |/*.el |g'`; \
        for el in $$els; do            \
@@ -469,7 +464,7 @@ bootstrap-clean:
        rm -f $(AUTOGENEL)
 
 distclean:
-       -rm -f ./Makefile $(lisp)/loaddefs.el
+       -rm -f ./Makefile $(lisp)/loaddefs.el $(lisp)/loaddefs.elc
 
 maintainer-clean: distclean bootstrap-clean
        rm -f TAGS
diff --git a/lisp/abbrev.el b/lisp/abbrev.el
index e875d77faa..718938df0c 100644
--- a/lisp/abbrev.el
+++ b/lisp/abbrev.el
@@ -292,8 +292,11 @@ The saved abbrevs are written to the file specified by
 
 (defun add-mode-abbrev (arg)
   "Define a mode-specific abbrev whose expansion is the last word before point.
+If there's an active region, use that as the expansion.
+
 Prefix argument ARG says how many words before point to use for the expansion;
 zero means the entire region is the expansion.
+
 A negative ARG means to undefine the specified abbrev.
 
 This command reads the abbreviation from the minibuffer.
@@ -303,7 +306,7 @@ if the abbreviation is already in the buffer, use that 
command to define
 a mode-specific abbrev by specifying its expansion in the minibuffer.
 
 Don't use this function in a Lisp program; use `define-abbrev' instead."
-  (interactive "p")
+  (interactive "P")
   (add-abbrev
    (if only-global-abbrevs
        global-abbrev-table
@@ -313,8 +316,11 @@ Don't use this function in a Lisp program; use 
`define-abbrev' instead."
 
 (defun add-global-abbrev (arg)
   "Define a global (all modes) abbrev whose expansion is last word before 
point.
+If there's an active region, use that as the expansion.
+
 Prefix argument ARG says how many words before point to use for the expansion;
 zero means the entire region is the expansion.
+
 A negative ARG means to undefine the specified abbrev.
 
 This command reads the abbreviation from the minibuffer.
@@ -324,15 +330,21 @@ if the abbreviation is already in the buffer, use that 
command to define
 a global abbrev by specifying its expansion in the minibuffer.
 
 Don't use this function in a Lisp program; use `define-abbrev' instead."
-  (interactive "p")
+  (interactive "P")
   (add-abbrev global-abbrev-table "Global" arg))
 
 (defun add-abbrev (table type arg)
-  (let ((exp (and (>= arg 0)
-                 (buffer-substring-no-properties
-                  (point)
-                  (if (= arg 0) (mark)
-                    (save-excursion (forward-word (- arg)) (point))))))
+  (let ((exp
+         (cond
+          ((or (and (null arg) (use-region-p))
+               (zerop (prefix-numeric-value arg)))
+           (buffer-substring-no-properties (region-beginning) (region-end)))
+          ((> (prefix-numeric-value arg) 0)
+          (buffer-substring-no-properties
+           (point)
+           (save-excursion
+              (forward-word (- (prefix-numeric-value arg)))
+              (point))))))
        name)
     (setq name
          (read-string (format (if exp "%s abbrev that expands into \"%s\": "
@@ -885,8 +897,8 @@ longer than the abbrev, the benefit of informing the user 
is not
 significant.  If you always want to be informed about existing
 abbrevs for the text you type, set this value to zero or less.
 This setting only applies if `abbrev-suggest' is non-nil."
-    :type 'number
-    :version "28.1")
+  :type 'natnum
+  :version "28.1")
 
 (defun abbrev--suggest-get-active-tables-including-parents ()
   "Return a list of all active abbrev tables, including parent tables."
diff --git a/lisp/align.el b/lisp/align.el
index 9364d54665..be70f8f9d4 100644
--- a/lisp/align.el
+++ b/lisp/align.el
@@ -86,10 +86,9 @@
 ;;     '((my-rule
 ;;        (regexp . "Sample")))
 ;;     :type align-rules-list-type
+;;     :risky t
 ;;     :group 'my-package)
 ;;
-;;   (put 'my-align-rules-list 'risky-local-variable t)
-;;
 ;;   (add-to-list 'align-dq-string-modes 'my-package-mode)
 ;;   (add-to-list 'align-open-comment-modes 'my-package-mode)
 ;;
@@ -319,10 +318,9 @@ The possible settings for `align-region-separate' are:
 ;         (const largest)
          (regexp :tag "Regexp defines section boundaries")
          (function :tag "Function defines section boundaries"))
+  :risky t
   :group 'align)
 
-(put 'align-region-separate 'risky-local-variable t)
-
 (defvar align-rules-list-type
   '(repeat
     (cons
@@ -699,10 +697,9 @@ The following attributes are meaningful:
            (see the documentation of that variable for possible
            values), and any separation argument passed to `align'."
   :type align-rules-list-type
+  :risky t
   :group 'align)
 
-(put 'align-rules-list 'risky-local-variable t)
-
 (defvar align-exclude-rules-list-type
   '(repeat
     (cons
@@ -770,10 +767,9 @@ The following attributes are meaningful:
   "A list describing text that should be excluded from alignment.
 See the documentation for `align-rules-list' for more info."
   :type align-exclude-rules-list-type
+  :risky t
   :group 'align)
 
-(put 'align-exclude-rules-list 'risky-local-variable t)
-
 ;;; Internal Variables:
 
 (defvar-local align-mode-rules-list nil
@@ -823,8 +819,8 @@ See the variable `align-exclude-rules-list' for more 
details.")
      (regexp   . "\\(\\s-+\\)use\\s-+entity")))
   "Alignment rules for `vhdl-mode'.  See `align-rules-list' for more info."
   :type align-rules-list-type
+  :risky t
   :group 'align)
-(put 'align-vhdl-rules-list 'risky-local-variable t)
 (make-obsolete-variable 'align-vhdl-rules-list "no longer used." "27.1")
 
 (defun align-set-vhdl-rules ()
@@ -841,8 +837,8 @@ Interactively, BEG and END are the mark/point of the 
current region.
 
 Many modes define specific alignment rules, and some of these
 rules in some modes react to the current prefix argument.  For
-instance, in `text-mode', `M-x align' will align into columns
-based on space delimiters, while `C-u - M-x align' will align
+instance, in `text-mode', \\`M-x align' will align into columns
+based on space delimiters, while \\`C-u -' \\`M-x align' will align
 into columns based on the \"$\" character.  See the
 `align-rules-list' variable definition for the specific rules.
 
diff --git a/lisp/allout.el b/lisp/allout.el
index 4624c236f5..fb922608b0 100644
--- a/lisp/allout.el
+++ b/lisp/allout.el
@@ -26,7 +26,7 @@
 ;;; Commentary:
 
 ;; Allout outline minor mode provides extensive outline formatting and
-;; and manipulation beyond standard Emacs outline mode.  Some features:
+;; manipulation beyond standard Emacs outline mode.  Some features:
 ;;
 ;;  - Classic outline-mode topic-oriented navigation and exposure adjustment
 ;;  - Topic-oriented editing including coherent topic and subtopic
@@ -394,9 +394,8 @@ else allout's special hanging-indent maintaining auto-fill 
function,
 ;;;_  = allout-use-hanging-indents
 (defcustom allout-use-hanging-indents t
   "If non-nil, topic body text auto-indent defaults to indent of the header.
-Ie, it is indented to be just past the header prefix.  This is
-relevant mostly for use with `indented-text-mode', or other situations
-where auto-fill occurs."
+I.e., it is indented to be just past the header prefix.  This is
+relevant mostly for situations where auto-fill occurs."
   :type 'boolean
   :group 'allout)
 (make-variable-buffer-local 'allout-use-hanging-indents)
@@ -733,8 +732,6 @@ Set this var to the bullet you want to use for file 
cross-references."
 (put 'allout-presentation-padding 'safe-local-variable #'integerp)
 
 ;;;_  = allout-flattened-numbering-abbreviation
-(define-obsolete-variable-alias 'allout-abbreviate-flattened-numbering
-  'allout-flattened-numbering-abbreviation "24.1")
 (defcustom allout-flattened-numbering-abbreviation nil
   "If non-nil, `allout-flatten-exposed-to-buffer' abbreviates topic
 numbers to minimal amount with some context.  Otherwise, entire
@@ -1350,11 +1347,6 @@ their settings before `allout-mode' was started."
 ;;;_   = allout-mode-hook
 (defvar allout-mode-hook nil
   "Hook run when allout mode starts.")
-;;;_   = allout-mode-deactivate-hook
-(define-obsolete-variable-alias 'allout-mode-deactivate-hook
-  'allout-mode-off-hook "24.1")
-(defvar allout-mode-deactivate-hook nil
-  "Hook run when allout mode ends.")
 ;;;_   = allout-exposure-category
 (defvar allout-exposure-category nil
   "Symbol for use as allout invisible-text overlay category.")
@@ -1707,7 +1699,7 @@ the HOT-SPOT Operation section.
 
         Misc commands:
         -------------
-M-x outlineify-sticky       Activate outline mode for current buffer,
+\\[allout-outlinify-sticky] Activate outline mode for current buffer,
                             and establish a default file-var setting
                             for `allout-layout'.
 \\[allout-mark-topic]       `allout-mark-topic'
@@ -1779,7 +1771,6 @@ hooks, by which independent code can cooperate with allout
 without changes to the allout core.  Here are key ones:
 
 `allout-mode-hook'
-`allout-mode-deactivate-hook' (deprecated)
 `allout-mode-off-hook'
 `allout-exposure-change-functions'
 `allout-structure-added-functions'
@@ -4607,7 +4598,7 @@ by pops to non-distinctive yanks.  Bug..."
         (save-match-data
           (save-excursion
             (let* ((text-start allout-recent-prefix-end)
-                   (heading-end (point-at-eol)))
+                   (heading-end (line-end-position)))
               (goto-char text-start)
               (setq file-name
                     (if (re-search-forward "\\s-\\(\\S-*\\)" heading-end t)
@@ -4883,7 +4874,7 @@ siblings, even if the target topic is already closed."
   (interactive)
   (save-excursion
     (allout-back-to-heading)
-    (if (allout-hidden-p (point-at-eol))
+    (if (allout-hidden-p (line-end-position))
         (allout-show-current-subtree)
       (allout-hide-current-subtree))))
 ;;;_   > allout-show-current-branches ()
@@ -5546,7 +5537,7 @@ environment.  Leaves point at the end of the line."
   (let ((inhibit-field-text-motion t))
     (beginning-of-line)
     (let (;(beg (point))
-          (end (point-at-eol)))
+          (end (line-end-position)))
       (save-match-data
         (while (re-search-forward "\\\\"
   ;;"\\\\\\|\\{\\|\\}\\|\\_\\|\\$\\|\\\"\\|\\&\\|\\^\\|\\-\\|\\*\\|#"
@@ -6193,19 +6184,18 @@ save.  See `allout-encrypt-unencrypted-on-saves' for 
more info."
 
 ;;;_ #9 miscellaneous
 ;;;_  : Mode:
-;;;_   > outlineify-sticky ()
-;; outlinify-sticky is correct spelling; provide this alias for sticklers:
+;;;_   > allout-outlinify-sticky ()
 ;;;###autoload
-(defalias 'outlinify-sticky #'outlineify-sticky)
+(define-obsolete-function-alias 'outlinify-sticky #'allout-outlinify-sticky 
"29.1")
 ;;;###autoload
-(defun outlineify-sticky (&optional _arg)
+(define-obsolete-function-alias 'outlineify-sticky #'allout-outlinify-sticky 
"29.1")
+;;;###autoload
+(defun allout-outlinify-sticky (&optional _arg)
   "Activate outline mode and establish file var so it is started subsequently.
 
 See `allout-layout' and customization of `allout-auto-activation'
 for details on preparing Emacs for automatic allout activation."
-
   (interactive "P")
-
   (if (allout-mode-p) (allout-mode))    ; deactivate so we can re-activate...
   (allout-mode)
 
diff --git a/lisp/ansi-color.el b/lisp/ansi-color.el
index d5db9ecfed..6f1c270c23 100644
--- a/lisp/ansi-color.el
+++ b/lisp/ansi-color.el
@@ -456,9 +456,6 @@ variable, and is meant to be used in 
`compilation-filter-hook'."
       (_
        (ansi-color-apply-on-region compilation-filter-start (point))))))
 
-(define-obsolete-function-alias 'ansi-color-unfontify-region
-  'font-lock-default-unfontify-region "24.1")
-
 ;; Working with strings
 (defvar-local ansi-color-context nil
   "Context saved between two calls to `ansi-color-apply'.
diff --git a/lisp/apropos.el b/lisp/apropos.el
index 0b84f9fa63..624c29cb41 100644
--- a/lisp/apropos.el
+++ b/lisp/apropos.el
@@ -1,7 +1,6 @@
 ;;; apropos.el --- apropos commands for users and programmers  -*- 
lexical-binding: t -*-
 
-;; Copyright (C) 1989, 1994-1995, 2001-2022 Free Software Foundation,
-;; Inc.
+;; Copyright (C) 1989-2022 Free Software Foundation, Inc.
 
 ;; Author: Joe Wells <jbw@bigbird.bu.edu>
 ;;     Daniel Pfeiffer <occitan@esperanto.org> (rewrite)
@@ -218,7 +217,7 @@ before `apropos-mode' makes it buffer-local.")
 
 (define-button-type 'apropos-symbol
   'face 'apropos-symbol
-  'help-echo "mouse-2, RET: Display more help on this symbol"
+  'help-echo "\\`mouse-2', \\`RET': Display more help on this symbol"
   'follow-link t
   'action #'apropos-symbol-button-display-help)
 
@@ -232,7 +231,7 @@ before `apropos-mode' makes it buffer-local.")
   'apropos-label "Function"
   'apropos-short-label "f"
   'face 'apropos-function-button
-  'help-echo "mouse-2, RET: Display more help on this function"
+  'help-echo "\\`mouse-2', \\`RET': Display more help on this function"
   'follow-link t
   'action (lambda (button)
            (describe-function (button-get button 'apropos-symbol))))
@@ -241,7 +240,7 @@ before `apropos-mode' makes it buffer-local.")
   'apropos-label "Macro"
   'apropos-short-label "m"
   'face 'apropos-function-button
-  'help-echo "mouse-2, RET: Display more help on this macro"
+  'help-echo "\\`mouse-2', \\`RET': Display more help on this macro"
   'follow-link t
   'action (lambda (button)
            (describe-function (button-get button 'apropos-symbol))))
@@ -250,7 +249,7 @@ before `apropos-mode' makes it buffer-local.")
   'apropos-label "Command"
   'apropos-short-label "c"
   'face 'apropos-function-button
-  'help-echo "mouse-2, RET: Display more help on this command"
+  'help-echo "\\`mouse-2', \\`RET': Display more help on this command"
   'follow-link t
   'action (lambda (button)
            (describe-function (button-get button 'apropos-symbol))))
@@ -264,7 +263,7 @@ before `apropos-mode' makes it buffer-local.")
   'apropos-label "Variable"
   'apropos-short-label "v"
   'face 'apropos-variable-button
-  'help-echo "mouse-2, RET: Display more help on this variable"
+  'help-echo "\\`mouse-2', \\`RET': Display more help on this variable"
   'follow-link t
   'action (lambda (button)
            (describe-variable (button-get button 'apropos-symbol))))
@@ -273,7 +272,7 @@ before `apropos-mode' makes it buffer-local.")
   'apropos-label "User option"
   'apropos-short-label "o"
   'face 'apropos-user-option-button
-  'help-echo "mouse-2, RET: Display more help on this user option"
+  'help-echo "\\`mouse-2', \\`RET': Display more help on this user option"
   'follow-link t
   'action (lambda (button)
            (describe-variable (button-get button 'apropos-symbol))))
@@ -282,7 +281,7 @@ before `apropos-mode' makes it buffer-local.")
   'apropos-label "Face"
   'apropos-short-label "F"
   'face 'apropos-button
-  'help-echo "mouse-2, RET: Display more help on this face"
+  'help-echo "\\`mouse-2', \\`RET': Display more help on this face"
   'follow-link t
   'action (lambda (button)
            (describe-face (button-get button 'apropos-symbol))))
@@ -291,7 +290,7 @@ before `apropos-mode' makes it buffer-local.")
   'apropos-label "Group"
   'apropos-short-label "g"
   'face 'apropos-misc-button
-  'help-echo "mouse-2, RET: Display more help on this group"
+  'help-echo "\\`mouse-2', \\`RET': Display more help on this group"
   'follow-link t
   'action (lambda (button)
            (customize-group-other-window
@@ -301,7 +300,7 @@ before `apropos-mode' makes it buffer-local.")
   'apropos-label "Widget"
   'apropos-short-label "w"
   'face 'apropos-misc-button
-  'help-echo "mouse-2, RET: Display more help on this widget"
+  'help-echo "\\`mouse-2', \\`RET': Display more help on this widget"
   'follow-link t
   'action (lambda (button)
            (widget-browse-other-window (button-get button 'apropos-symbol))))
@@ -310,13 +309,13 @@ before `apropos-mode' makes it buffer-local.")
   'apropos-label "Properties"
   'apropos-short-label "p"
   'face 'apropos-misc-button
-  'help-echo "mouse-2, RET: Display more help on this plist"
+  'help-echo "\\`mouse-2', \\`RET': Display more help on this plist"
   'follow-link t
   'action (lambda (button)
            (apropos-describe-plist (button-get button 'apropos-symbol))))
 
 (define-button-type 'apropos-library
-  'help-echo "mouse-2, RET: Display more help on this library"
+  'help-echo "\\`mouse-2', \\`RET': Display more help on this library"
   'follow-link t
   'action (lambda (button)
            (apropos-library (button-get button 'apropos-symbol))))
@@ -909,41 +908,39 @@ Returns list of symbols and documentation found."
   (apropos-parse-pattern pattern t)
   (or do-all (setq do-all apropos-do-all))
   (setq apropos-accumulator () apropos-files-scanned ())
-  (let ((standard-input (get-buffer-create " apropos-temp"))
-       (apropos-sort-by-scores apropos-documentation-sort-by-scores)
-       f v sf sv)
-    (unwind-protect
-       (with-current-buffer standard-input
-         (apropos-documentation-check-doc-file)
-         (if do-all
-             (mapatoms
-              (lambda (symbol)
-                (setq f (apropos-safe-documentation symbol)
-                      v (get symbol 'variable-documentation))
-                (if (integerp v) (setq v nil))
-                (setq f (apropos-documentation-internal f)
-                      v (apropos-documentation-internal v))
-                (setq sf (apropos-score-doc f)
-                      sv (apropos-score-doc v))
-                (if (or f v)
-                    (if (setq apropos-item
-                              (cdr (assq symbol apropos-accumulator)))
-                        (progn
-                          (if f
-                              (progn
-                                (setcar (nthcdr 1 apropos-item) f)
-                                (setcar apropos-item (+ (car apropos-item) 
sf))))
-                          (if v
-                              (progn
-                                (setcar (nthcdr 2 apropos-item) v)
-                                (setcar apropos-item (+ (car apropos-item) 
sv)))))
-                      (setq apropos-accumulator
-                            (cons (list symbol
-                                        (+ (apropos-score-symbol symbol 2) sf 
sv)
-                                        f v)
-                                  apropos-accumulator)))))))
-         (apropos-print nil "\n----------------\n" nil t))
-      (kill-buffer standard-input))))
+  (with-temp-buffer
+    (let ((standard-input (current-buffer))
+          (apropos-sort-by-scores apropos-documentation-sort-by-scores)
+          f v sf sv)
+      (apropos-documentation-check-doc-file)
+      (if do-all
+          (mapatoms
+           (lambda (symbol)
+             (setq f (apropos-safe-documentation symbol)
+                   v (get symbol 'variable-documentation))
+             (if (integerp v) (setq v nil))
+             (setq f (apropos-documentation-internal f)
+                   v (apropos-documentation-internal v))
+             (setq sf (apropos-score-doc f)
+                   sv (apropos-score-doc v))
+             (if (or f v)
+                 (if (setq apropos-item
+                           (cdr (assq symbol apropos-accumulator)))
+                     (progn
+                       (if f
+                           (progn
+                             (setcar (nthcdr 1 apropos-item) f)
+                             (setcar apropos-item (+ (car apropos-item) sf))))
+                       (if v
+                           (progn
+                             (setcar (nthcdr 2 apropos-item) v)
+                             (setcar apropos-item (+ (car apropos-item) sv)))))
+                   (setq apropos-accumulator
+                         (cons (list symbol
+                                     (+ (apropos-score-symbol symbol 2) sf sv)
+                                     f v)
+                               apropos-accumulator)))))))
+      (apropos-print nil "\n----------------\n" nil t))))
 
 
 (defun apropos-value-internal (predicate symbol function)
@@ -1334,14 +1331,14 @@ as a heading."
 
 (defun apropos-follow ()
   "Invokes any button at point, otherwise invokes the nearest label button."
-  (interactive)
+  (interactive nil apropos-mode)
   (button-activate
    (or (apropos-next-label-button (line-beginning-position))
        (error "There is nothing to follow here"))))
 
 (defun apropos-next-symbol ()
   "Move cursor down to the next symbol in an `apropos-mode' buffer."
-  (interactive)
+  (interactive nil apropos-mode)
   (forward-line)
   (while (and (not (eq (face-at-point) 'apropos-symbol))
               (< (point) (point-max)))
@@ -1349,7 +1346,7 @@ as a heading."
 
 (defun apropos-previous-symbol ()
   "Move cursor back to the last symbol in an `apropos-mode' buffer."
-  (interactive)
+  (interactive nil apropos-mode)
   (forward-line -1)
   (while (and (not (eq (face-at-point) 'apropos-symbol))
               (> (point) (point-min)))
diff --git a/lisp/arc-mode.el b/lisp/arc-mode.el
index 1c5faa1152..632ae57852 100644
--- a/lisp/arc-mode.el
+++ b/lisp/arc-mode.el
@@ -101,6 +101,7 @@
 ;;; Code:
 
 (eval-when-compile (require 'cl-lib))
+(eval-when-compile (require 'subr-x))
 
 ;; -------------------------------------------------------------------------
 ;;; Section: Configuration.
@@ -1072,22 +1073,31 @@ NEW-NAME."
     (user-error "Can't copy a list of files to a single file"))
   (save-excursion
     (dolist (file files)
-      (let ((write-to (if (file-directory-p new-name)
-                          (expand-file-name file new-name)
-                        new-name)))
+      (let* ((write-to (if (file-directory-p new-name)
+                           (expand-file-name file new-name)
+                         new-name))
+             (write-to-dir (file-name-directory write-to)))
         (when (and (file-exists-p write-to)
                    (not (yes-or-no-p (format "%s already exists; overwrite? "
                                              write-to))))
           (user-error "Not overwriting %s" write-to))
+        (unless (file-directory-p write-to-dir)
+          (make-directory write-to-dir t))
         (archive-goto-file file)
         (let* ((descr (archive-get-descr))
                (archive (buffer-file-name))
                (extractor (archive-name "extract"))
-               (ename (archive--file-desc-ext-file-name descr)))
-          (with-temp-buffer
-            (set-buffer-multibyte nil)
-            (archive--extract-file extractor archive ename)
-            (write-region (point-min) (point-max) write-to)))))))
+               (ename (archive--file-desc-ext-file-name descr))
+               ;; If the archive is remote, we have to copy it to a
+               ;; local file first to make extraction work.
+               (copy (archive-maybe-copy archive)))
+          (unwind-protect
+              (with-temp-buffer
+                (set-buffer-multibyte nil)
+                (archive--extract-file extractor copy ename)
+                (write-region (point-min) (point-max) write-to))
+            (unless (equal copy archive)
+              (delete-file copy))))))))
 
 (defun archive-extract (&optional other-window-p event)
   "In archive mode, extract this entry of the archive into its own buffer."
@@ -1317,6 +1327,8 @@ NEW-NAME."
 ;;; Section: IO stuff
 
 (defun archive-write-file-member ()
+  (unless (buffer-live-p archive-superior-buffer)
+    (error "The archive buffer no longer exists; can't save"))
   (save-excursion
     (save-restriction
       (message "Updating archive...")
diff --git a/lisp/array.el b/lisp/array.el
index 08c5ff45dd..aed93ffb65 100644
--- a/lisp/array.el
+++ b/lisp/array.el
@@ -103,7 +103,7 @@ Set them to the optional arguments A-ROW and A-COLUMN if 
those are supplied."
 
 (defun array-update-buffer-position ()
   "Set `array-buffer-line' and `array-buffer-column' to their current values."
-  (setq array-buffer-line (current-line)
+  (setq array-buffer-line (array-current-line)
        array-buffer-column (current-column)))
 
 
@@ -113,7 +113,7 @@ Set them to the optional arguments A-ROW and A-COLUMN if 
those are supplied."
 (defun array-what-position ()
   "Display the row and column in which the cursor is positioned."
   (interactive)
-  (let ((array-buffer-line (current-line))
+  (let ((array-buffer-line (array-current-line))
        (array-buffer-column (current-column)))
     (message "Array row: %s  Array column: %s"
             (prin1-to-string (array-current-row))
@@ -147,13 +147,13 @@ Set them to the optional arguments A-ROW and A-COLUMN if 
those are supplied."
 ;;; Internal movement functions.
 
 (defun array-beginning-of-field (&optional go-there)
-   "Return the column of the beginning of the current field.
+  "Return the column of the beginning of the current field.
 Optional argument GO-THERE, if non-nil, means go there too."
-   ;; Requires that array-buffer-column be current.
-   (let ((goal-column (- array-buffer-column (% array-buffer-column 
array-field-width))))
-     (if go-there
-        (move-to-column-untabify goal-column)
-       goal-column)))
+  ;; Requires that array-buffer-column be current.
+  (let ((goal-column (- array-buffer-column (% array-buffer-column 
array-field-width))))
+    (if go-there
+        (array-move-to-column-untabify goal-column)
+      goal-column)))
 
 (defun array-end-of-field (&optional go-there)
   "Return the column of the end of the current array field.
@@ -162,7 +162,7 @@ If optional argument GO-THERE is non-nil, go there too."
   (let ((goal-column (+ (- array-buffer-column (% array-buffer-column 
array-field-width))
                        array-field-width)))
     (if go-there
-       (move-to-column-untabify goal-column)
+        (array-move-to-column-untabify goal-column)
       goal-column)))
 
 (defun array-move-to-cell (a-row a-column)
@@ -174,7 +174,7 @@ Leave point at the beginning of the field and return the 
new buffer column."
        (goal-column (* array-field-width (% (1- a-column) 
array-columns-per-line))))
     (goto-char (point-min))
     (forward-line goal-line)
-    (move-to-column-untabify goal-column)))
+    (array-move-to-column-untabify goal-column)))
 
 (defun array-move-to-row (a-row)
   "Move to array row A-ROW preserving the current array column.
@@ -184,7 +184,7 @@ Leave point at the beginning of the field and return the 
new array row."
                      (% array-buffer-line array-lines-per-row)))
        (goal-column (- array-buffer-column (% array-buffer-column 
array-field-width))))
     (forward-line (- goal-line array-buffer-line))
-    (move-to-column-untabify goal-column)
+    (array-move-to-column-untabify goal-column)
     a-row))
 
 (defun array-move-to-column (a-column)
@@ -196,7 +196,7 @@ Leave point at the beginning of the field and return the 
new array column."
                      (floor (1- a-column) array-columns-per-line)))
        (goal-column (* array-field-width (% (1- a-column) 
array-columns-per-line))))
     (forward-line (- goal-line array-buffer-line))
-    (move-to-column-untabify goal-column)
+    (array-move-to-column-untabify goal-column)
     a-column))
 
 (defun array-move-one-row (sign)
@@ -214,7 +214,7 @@ If requested to move beyond the array bounds, signal an 
error."
          (t
           (progn
             (forward-line (* sign array-lines-per-row))
-            (move-to-column-untabify goal-column)
+             (array-move-to-column-untabify goal-column)
             (+ array-row sign))))))
 
 (defun array-move-one-column (sign)
@@ -233,15 +233,15 @@ If requested to move beyond the array bounds, signal an 
error."
            ;; Going backward from first column on the line.
            ((and (= sign -1) (= 1 (% array-column array-columns-per-line)))
             (forward-line -1)
-            (move-to-column-untabify
+             (array-move-to-column-untabify
              (* array-field-width (1- array-columns-per-line))))
            ;; Going forward from last column on the line.
            ((and (= sign 1) (zerop (% array-column array-columns-per-line)))
             (forward-line 1))
            ;; Somewhere in the middle of the line.
            (t
-            (move-to-column-untabify (+ (array-beginning-of-field)
-                                        (* array-field-width sign)))))
+             (array-move-to-column-untabify (+ (array-beginning-of-field)
+                                               (* array-field-width sign)))))
           (+ array-column sign)))))
 
 (defun array-normalize-cursor ()
@@ -281,15 +281,15 @@ If necessary, scroll horizontally to keep the cursor in 
view."
   "Move down one array row, staying in the current array column.
 If optional ARG is given, move down ARG array rows."
   (interactive "p")
-  (let ((array-buffer-line (current-line))
+  (let ((array-buffer-line (array-current-line))
        (array-buffer-column (current-column)))
     (if (= (abs arg) 1)
        (array-move-one-row arg)
       (array-move-to-row
-       (limit-index (+ (or (array-current-row)
-                          (error "Cursor is not in an array cell"))
-                      arg)
-                   array-max-row))))
+       (array--limit-index (+ (or (array-current-row)
+                             (error "Cursor is not in an array cell"))
+                         arg)
+                      array-max-row))))
   (array-normalize-cursor))
 
 (defun array-previous-row (&optional arg)
@@ -303,15 +303,15 @@ If optional ARG is given, move up ARG array rows."
 If optional ARG is given, move forward ARG array columns.
 If necessary, keep the cursor in the window by scrolling right or left."
   (interactive "p")
-  (let ((array-buffer-line (current-line))
+  (let ((array-buffer-line (array-current-line))
        (array-buffer-column (current-column)))
     (if (= (abs arg) 1)
        (array-move-one-column arg)
       (array-move-to-column
-       (limit-index (+ (or (array-current-column)
-                          (error "Cursor is not in an array cell"))
-                      arg)
-                   array-max-column))))
+       (array--limit-index (+ (or (array-current-column)
+                             (error "Cursor is not in an array cell"))
+                         arg)
+                      array-max-column))))
   (array-normalize-cursor))
 
 (defun array-backward-column (&optional arg)
@@ -325,8 +325,8 @@ If necessary, keep the cursor in the window by scrolling 
right or left."
   "Go to array row A-ROW and array column A-COLUMN."
   (interactive "nArray row: \nnArray column: ")
   (array-move-to-cell
-   (limit-index a-row array-max-row)
-   (limit-index a-column array-max-column))
+   (array--limit-index a-row array-max-row)
+   (array--limit-index a-column array-max-column))
   (array-normalize-cursor))
 
 
@@ -417,7 +417,7 @@ Leave point at the beginning of the field."
   "Copy the current field one array row down.
 If optional ARG is given, copy down through ARG array rows."
   (interactive "p")
-  (let* ((array-buffer-line (current-line))
+  (let* ((array-buffer-line (array-current-line))
         (array-buffer-column (current-column))
         (array-row (or (array-current-row)
                           (error "Cursor is not in a valid array cell")))
@@ -425,7 +425,7 @@ If optional ARG is given, copy down through ARG array rows."
     (if (= (abs arg) 1)
        (array-copy-once-vertically arg)
       (array-copy-to-row
-       (limit-index (+ array-row arg) array-max-row))))
+       (array--limit-index (+ array-row arg) array-max-row))))
   (array-normalize-cursor))
 
 (defun array-copy-up (&optional arg)
@@ -438,7 +438,7 @@ If optional ARG is given, copy up through ARG array rows."
   "Copy the current field one array column to the right.
 If optional ARG is given, copy through ARG array columns to the right."
   (interactive "p")
-  (let* ((array-buffer-line (current-line))
+  (let* ((array-buffer-line (array-current-line))
         (array-buffer-column (current-column))
         (array-column (or (array-current-column)
                           (error "Cursor is not in a valid array cell")))
@@ -446,7 +446,7 @@ If optional ARG is given, copy through ARG array columns to 
the right."
     (if (= (abs arg) 1)
        (array-copy-once-horizontally arg)
       (array-copy-to-column
-       (limit-index (+ array-column arg) array-max-column))))
+       (array--limit-index (+ array-column arg) array-max-column))))
   (array-normalize-cursor))
 
 (defun array-copy-backward (&optional arg)
@@ -473,7 +473,7 @@ If optional ARG is given, copy through ARG array columns to 
the right."
        (if (= (abs arg) 1)
            (array-copy-once-horizontally arg)
          (array-copy-to-column
-          (limit-index (+ array-column arg) array-max-column))))))
+           (array--limit-index (+ array-column arg) array-max-column))))))
   (message "Working...done")
   (array-move-to-row array-row)
   (array-normalize-cursor))
@@ -506,7 +506,7 @@ If optional ARG is given, copy through ARG rows down."
                             (forward-line 1)
                             (point))))
           (this-row array-row)
-          (goal-row (limit-index (+ this-row arg) array-max-row))
+           (goal-row (array--limit-index (+ this-row arg) array-max-row))
           (num (- goal-row this-row))
           (count (abs num))
           (sign (if (not (zerop count)) (/ num count))))
@@ -700,13 +700,13 @@ of `array-rows-numbered'."
               (floor (1- temp-max-column) new-columns-per-line))
              (newlines-added 0))
          (while (< newlines-removed newlines-to-be-removed)
-           (move-to-column-untabify
+            (array-move-to-column-untabify
             (* (1+ newlines-removed) old-line-length))
            (kill-line 1)
            (setq newlines-removed (1+ newlines-removed)))
          (beginning-of-line)
          (while (< newlines-added newlines-to-be-added)
-           (move-to-column-untabify (* old-field-width new-columns-per-line))
+            (array-move-to-column-untabify (* old-field-width 
new-columns-per-line))
            (newline)
            (setq newlines-added (1+ newlines-added)))
          (forward-line 1))))
@@ -735,16 +735,16 @@ of `array-rows-numbered'."
 
 ;;; Utilities.
 
-(defun limit-index (index limit)
+(defun array--limit-index (index limit)
   (cond ((< index 1) 1)
        ((> index limit) limit)
        (t index)))
 
-(defun current-line ()
+(defun array-current-line ()
   "Return the current buffer line at point.  The first line is 0."
   (count-lines (point-min) (line-beginning-position)))
 
-(defun move-to-column-untabify (column)
+(defun array-move-to-column-untabify (column)
   "Move to COLUMN on the current line, untabifying if necessary.
 Return COLUMN."
   (or (and (= column (move-to-column column))
@@ -753,10 +753,10 @@ Return COLUMN."
       (if array-respect-tabs
          (error "There is a TAB character in the way")
        (progn
-         (untabify-backward)
+          (array--untabify-backward)
          (move-to-column column)))))
 
-(defun untabify-backward ()
+(defun array--untabify-backward ()
   "Untabify the preceding TAB."
   (save-excursion
     (let ((start (point)))
@@ -885,7 +885,10 @@ Entering array mode calls the function `array-mode-hook'."
   (setq-local truncate-lines t)
   (setq overwrite-mode 'overwrite-mode-textual))
 
-
+(define-obsolete-function-alias 'limit-index #'array--limit-index "29.1")
+(define-obsolete-function-alias 'current-line #'array-current-line "29.1")
+(define-obsolete-function-alias 'move-to-column-untabify 
#'array-move-to-column-untabify "29.1")
+(define-obsolete-function-alias 'untabify-backward #'array--untabify-backward 
"29.1")
 
 (provide 'array)
 
diff --git a/lisp/auth-source.el b/lisp/auth-source.el
index fc62e36dfc..c79e5b81f7 100644
--- a/lisp/auth-source.el
+++ b/lisp/auth-source.el
@@ -164,8 +164,6 @@ Overrides `password-cache-expiry' through a let-binding."
 (defvar auth-source-creation-prompts nil
   "Default prompts for token values.  Usually let-bound.")
 
-(make-obsolete 'auth-source-hide-passwords nil "24.1")
-
 (defcustom auth-source-save-behavior 'ask
   "If set, auth-source will respect it for save behavior."
   :version "23.2" ;; No Gnus
@@ -911,10 +909,17 @@ Remove trailing \": \"."
 (defun auth-source--aget (alist key)
   (cdr (assoc key alist)))
 
+;;;###autoload
+(defun auth-source-netrc-parse-all (file)
+  "Parse FILE and return all entries."
+  (auth-source-netrc-parse :file file :allow-null t))
+
 ;; (auth-source-netrc-parse :file "~/.authinfo.gpg")
 (cl-defun auth-source-netrc-parse (&key file max host user port require
-                                   &allow-other-keys)
-  "Parse FILE and return a list of all entries in the file.
+                                        allow-null &allow-other-keys)
+  "Parse FILE and return a list of matching entries in the file.
+If ALLOW-NULL, allow nil values of HOST, USER and PORT to match.
+
 Note that the MAX parameter is used so we can exit the parse early."
   (if (listp file)
       ;; We got already parsed contents; just return it.
@@ -927,27 +932,33 @@ Note that the MAX parameter is used so we can exit the 
parse early."
                (cached (cdr-safe (assoc file auth-source-netrc-cache)))
                (cached-mtime (plist-get cached :mtime))
                (cached-secrets (plist-get cached :secret))
-               (check (lambda(alist)
+               (check (lambda (alist)
                         (and alist
-                             (auth-source-search-collection
-                              host
-                              (or
-                               (auth-source--aget alist "machine")
-                               (auth-source--aget alist "host")
-                               t))
-                             (auth-source-search-collection
-                              user
-                              (or
-                               (auth-source--aget alist "login")
-                               (auth-source--aget alist "account")
-                               (auth-source--aget alist "user")
-                               t))
-                             (auth-source-search-collection
-                              port
-                              (or
-                               (auth-source--aget alist "port")
-                               (auth-source--aget alist "protocol")
-                               t))
+                             (or
+                              (and allow-null (null host))
+                              (auth-source-search-collection
+                               host
+                               (or
+                                (auth-source--aget alist "machine")
+                                (auth-source--aget alist "host")
+                                t)))
+                             (or
+                              (and allow-null (null user))
+                              (auth-source-search-collection
+                               user
+                               (or
+                                (auth-source--aget alist "login")
+                                (auth-source--aget alist "account")
+                                (auth-source--aget alist "user")
+                                t)))
+                             (or
+                              (and allow-null (null port))
+                              (auth-source-search-collection
+                               port
+                               (or
+                                (auth-source--aget alist "port")
+                                (auth-source--aget alist "protocol")
+                                t)))
                              (or
                               ;; the required list of keys is nil, or
                               (null require)
@@ -959,7 +970,8 @@ Note that the MAX parameter is used so we can exit the 
parse early."
                result)
 
           (if (and (functionp cached-secrets)
-                   (equal cached-mtime
+                  (time-equal-p
+                         cached-mtime
                           (file-attribute-modification-time
                            (file-attributes file))))
               (progn
@@ -1606,10 +1618,13 @@ authentication tokens:
          (search-specs (auth-source-secrets-listify-pattern
                         (apply #'append (mapcar
                                       (lambda (k)
-                                        (if (or (null (plist-get spec k))
-                                                (eq t (plist-get spec k)))
-                                            nil
-                                          (list k (plist-get spec k))))
+                                        (let ((v (plist-get spec k)))
+                                          (if (or (null v)
+                                                  (eq t v))
+                                              nil
+                                            (list
+                                             k
+                                             (auth-source-ensure-strings v)))))
                                       search-keys))))
          ;; needed keys (always including host, login, port, and secret)
          (returned-keys (delete-dups (append
@@ -1624,7 +1639,7 @@ authentication tokens:
                                 (not (string-match label item)))
                     collect item)))
          ;; TODO: respect max in `secrets-search-items', not after the fact
-         (items (butlast items (- (length items) max)))
+         (items (take max items))
          ;; convert the item name to a full plist
          (items (mapcar (lambda (item)
                           (append
@@ -2082,7 +2097,7 @@ entries for git.gnus.org:
                                      search-keys)))
          (items (plstore-find store search-spec))
          (item-names (mapcar #'car items))
-         (items (butlast items (- (length items) max)))
+         (items (take max items))
          ;; convert the item to a full plist
          (items (mapcar (lambda (item)
                           (let* ((plist (copy-tree (cdr item)))
@@ -2325,89 +2340,6 @@ See `auth-source-search' for details on SPEC."
         (push item all)))
     (nreverse all)))
 
-;;; older API
-
-;; (auth-source-user-or-password '("login" "password") "imap.myhost.com" t 
"tzz")
-
-;; deprecate the old interface
-(make-obsolete 'auth-source-user-or-password
-               'auth-source-search "24.1")
-(make-obsolete 'auth-source-forget-user-or-password
-               'auth-source-forget "24.1")
-
-(defun auth-source-user-or-password
-  (mode host port &optional username create-missing delete-existing)
-  "Find MODE (string or list of strings) matching HOST and PORT.
-
-DEPRECATED in favor of `auth-source-search'!
-
-USERNAME is optional and will be used as \"login\" in a search
-across the Secret Service API (see secrets.el) if the resulting
-items don't have a username.  This means that if you search for
-username \"joe\" and it matches an item but the item doesn't have
-a :user attribute, the username \"joe\" will be returned.
-
-A non-nil DELETE-EXISTING means deleting any matching password
-entry in the respective sources.  This is useful only when
-CREATE-MISSING is non-nil as well; the intended use case is to
-remove wrong password entries.
-
-If no matching entry is found, and CREATE-MISSING is non-nil,
-the password will be retrieved interactively, and it will be
-stored in the password database which matches best (see
-`auth-sources').
-
-MODE can be \"login\" or \"password\"."
-  (auth-source-do-debug
-   "auth-source-user-or-password: DEPRECATED get %s for %s (%s) + user=%s"
-   mode host port username)
-
-  (let* ((listy (listp mode))
-         (mode (if listy mode (list mode)))
-         ;; (cname (if username
-         ;;            (format "%s %s:%s %s" mode host port username)
-         ;;          (format "%s %s:%s" mode host port)))
-         (search (list :host host :port port))
-         (search (if username (append search (list :user username)) search))
-         (search (if create-missing
-                     (append search (list :create t))
-                   search))
-         (search (if delete-existing
-                     (append search (list :delete t))
-                   search))
-         ;; (found (if (not delete-existing)
-         ;;            (gethash cname auth-source-cache)
-         ;;          (remhash cname auth-source-cache)
-         ;;          nil)))
-         (found nil))
-    (if found
-        (progn
-          (auth-source-do-debug
-           "auth-source-user-or-password: DEPRECATED cached %s=%s for %s (%s) 
+ %s"
-           mode
-           ;; don't show the password
-           (if (and (member "password" mode) t)
-               "SECRET"
-             found)
-           host port username)
-          found)                        ; return the found data
-      ;; else, if not found, search with a max of 1
-      (let ((choice (nth 0 (apply #'auth-source-search
-                                  (append '(:max 1) search)))))
-        (when choice
-          (dolist (m mode)
-            (cond
-             ((equal "password" m)
-              (push (if (plist-get choice :secret)
-                        (funcall (plist-get choice :secret))
-                      nil) found))
-             ((equal "login" m)
-              (push (plist-get choice :user) found)))))
-        (setq found (nreverse found))
-        (setq found (if listy found (car-safe found)))))
-
-    found))
-
 (defun auth-source-user-and-password (host &optional user)
   (let* ((auth-info (car
                      (if user
diff --git a/lisp/autoinsert.el b/lisp/autoinsert.el
index c12c554498..29d10bc629 100644
--- a/lisp/autoinsert.el
+++ b/lisp/autoinsert.el
@@ -67,7 +67,7 @@ Possible values:
        other   insert if possible, but mark as unmodified.
 Insertion is possible when something appropriate is found in
 `auto-insert-alist'.  When the insertion is marked as unmodified, you can
-save it with  \\[write-file] RET.
+save it with  \\[write-file] \\`RET'.
 This variable is used when the function `auto-insert' is called, e.g.
 when you do (add-hook \\='find-file-hook \\='auto-insert).
 With \\[auto-insert], this is always treated as if it were t."
@@ -76,6 +76,9 @@ With \\[auto-insert], this is always treated as if it were t."
                  (other :tag "insert if possible, mark as unmodified."
                         not-modified)))
 
+;;;###autoload
+(put 'auto-insert 'safe-local-variable #'null)
+
 (defcustom auto-insert-query 'function
   "Non-nil means ask user before auto-inserting.
 When this is `function', only ask when called non-interactively."
diff --git a/lisp/autorevert.el b/lisp/autorevert.el
index 918c0c7f19..872a896689 100644
--- a/lisp/autorevert.el
+++ b/lisp/autorevert.el
@@ -800,7 +800,7 @@ This is an internal function used by Auto-Revert Mode."
     (when revert
       (when (and auto-revert-verbose
                  (not (eq revert 'fast)))
-        (message "Reverting buffer `%s'." (buffer-name)))
+        (message "Reverting buffer `%s'" (buffer-name)))
       ;; If point (or a window point) is at the end of the buffer, we
       ;; want to keep it at the end after reverting.  This allows one
       ;; to tail a file.
diff --git a/lisp/battery.el b/lisp/battery.el
index 3cff3167a6..72b3dfdae7 100644
--- a/lisp/battery.el
+++ b/lisp/battery.el
@@ -255,14 +255,14 @@ of the following information may or may not be available:
 For instance, to play an alarm when the battery power dips below
 10%, you could use a function like the following:
 
-(defvar my-prev-battery nil)
-(defun my-battery-alarm (data)
-  (when (and my-prev-battery
-             (equal (alist-get ?L data) \"off-line\")
-             (< (string-to-number (alist-get ?p data)) 10)
-             (>= (string-to-number (alist-get ?p my-prev-battery)) 10))
-    (play-sound-file \"~/alarm.wav\" 5))
-  (setq my-prev-battery data))"
+  (defvar my-prev-battery nil)
+  (defun my-battery-alarm (data)
+    (when (and my-prev-battery
+               (equal (alist-get ?L data) \"off-line\")
+               (< (string-to-number (alist-get ?p data)) 10)
+               (>= (string-to-number (alist-get ?p my-prev-battery)) 10))
+      (play-sound-file \"~/alarm.wav\" 5))
+    (setq my-prev-battery data))"
   :version "29.1"
   :type '(repeat function))
 
@@ -369,11 +369,11 @@ The following %-sequences are provided:
        (setq driver-version (match-string 1))
        (setq bios-version (match-string 2))
        (setq tem (string-to-number (match-string 3) 16))
-       (if (not (logand tem 2))
+        (if (zerop (logand tem 2))
            (setq bios-interface "not supported")
          (setq bios-interface "enabled")
-         (cond ((logand tem 16) (setq bios-interface "disabled"))
-               ((logand tem 32) (setq bios-interface "disengaged")))
+          (cond ((/= (logand tem 16) 0) (setq bios-interface "disabled"))
+                ((/= (logand tem 32) 0) (setq bios-interface "disengaged")))
          (setq tem (string-to-number (match-string 4) 16))
          (cond ((= tem 0) (setq line-status "off-line"))
                ((= tem 1) (setq line-status "on-line"))
diff --git a/lisp/bindings.el b/lisp/bindings.el
index ed1325e326..2e32128274 100644
--- a/lisp/bindings.el
+++ b/lisp/bindings.el
@@ -1,7 +1,6 @@
 ;;; bindings.el --- define standard key bindings and some variables  -*- 
lexical-binding: t; -*-
 
-;; Copyright (C) 1985-1987, 1992-1996, 1999-2022 Free Software
-;; Foundation, Inc.
+;; Copyright (C) 1985-2022 Free Software Foundation, Inc.
 
 ;; Maintainer: emacs-devel@gnu.org
 ;; Keywords: internal
@@ -231,6 +230,7 @@ mnemonics of the following coding systems:
     (:propertize ("" (:eval (if (frame-parameter nil 'client) "@" "")))
                 help-echo ,(purecopy "emacsclient frame")))
   "Mode line construct for identifying emacsclient frames.")
+;; Autoload if this file no longer dumped.
 ;;;###autoload
 (put 'mode-line-client 'risky-local-variable t)
 
@@ -458,8 +458,8 @@ displayed in `mode-line-position', a component of the 
default
           (const :tag "\"%q\": Offsets of both top and bottom of window"
                  (6 "%q")))
   :version "26.1"
+  :risky t
   :group 'mode-line)
-(put 'mode-line-percent-position 'risky-local-variable t)
 
 (defcustom mode-line-position-line-format '(" L%l")
   "Format used to display line numbers in the mode line.
@@ -517,31 +517,31 @@ mouse-1: Display Line and Column Mode Menu")
          'help-echo "Size indication mode\n\
 mouse-1: Display Line and Column Mode Menu")))
     (line-number-mode
-     ((column-number-mode
-       (column-number-indicator-zero-based
-        (10
-         (:propertize
-          mode-line-position-column-line-format
-          display (min-width (10.0))
-          ,@mode-line-position--column-line-properties))
-        (10
-         (:propertize
-          (:eval (string-replace
-                  "%c" "%C" (car mode-line-position-column-line-format)))
-          display (min-width (10.0))
-          ,@mode-line-position--column-line-properties)))
-       (6
+     (column-number-mode
+      (column-number-indicator-zero-based
+       (10
         (:propertize
-        mode-line-position-line-format
-         display (min-width (6.0))
-         ,@mode-line-position--column-line-properties))))
+         mode-line-position-column-line-format
+         display (min-width (10.0))
+         ,@mode-line-position--column-line-properties))
+       (10
+        (:propertize
+         (:eval (string-replace
+                 "%c" "%C" (car mode-line-position-column-line-format)))
+         display (min-width (10.0))
+         ,@mode-line-position--column-line-properties)))
+      (6
+       (:propertize
+       mode-line-position-line-format
+        display (min-width (6.0))
+        ,@mode-line-position--column-line-properties)))
      (column-number-mode
       (column-number-indicator-zero-based
        (6
         (:propertize
          mode-line-position-column-format
          display (min-width (6.0))
-         (,@mode-line-position--column-line-properties)))
+         ,@mode-line-position--column-line-properties))
        (6
         (:propertize
          (:eval (string-replace
@@ -966,14 +966,13 @@ if `inhibit-field-text-motion' is non-nil."
       (backward-word n)
     (forward-word n)))
 
-(defvar narrow-map (make-sparse-keymap)
-  "Keymap for narrowing commands.")
+(defvar-keymap narrow-map
+  :doc "Keymap for narrowing commands."
+  "n" #'narrow-to-region
+  "w" #'widen
+  "g" #'goto-line-relative)
 (define-key ctl-x-map "n" narrow-map)
 
-(define-key narrow-map "n" 'narrow-to-region)
-(define-key narrow-map "w" 'widen)
-(define-key narrow-map "g" 'goto-line-relative)
-
 ;; Quitting
 (define-key global-map "\e\e\e" 'keyboard-escape-quit)
 (define-key global-map "\C-g" 'keyboard-quit)
@@ -1009,11 +1008,9 @@ if `inhibit-field-text-motion' is non-nil."
 ;; Richard said that we should not use C-x <uppercase letter> and I have
 ;; no idea whereas to bind it.  Any suggestion welcome.  -stef
 ;; (define-key ctl-x-map "U" 'undo-only)
-(defvar undo-repeat-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "u" 'undo)
-    map)
-  "Keymap to repeat undo key sequences `C-x u u'.  Used in `repeat-mode'.")
+(defvar-keymap undo-repeat-map
+  :doc "Keymap to repeat undo key sequences \\`C-x u u'.  Used in 
`repeat-mode'."
+  "u" #'undo)
 (put 'undo 'repeat-map 'undo-repeat-map)
 
 (define-key global-map '[(control ??)] 'undo-redo)
@@ -1084,8 +1081,6 @@ if `inhibit-field-text-motion' is non-nil."
 (define-key global-map "\C-y" 'yank)
 (define-key esc-map "y" 'yank-pop)
 
-;; (define-key ctl-x-map "a" 'append-to-buffer)
-
 (define-key global-map "\C-@" 'set-mark-command)
 ;; Many people are used to typing C-SPC and getting C-@.
 (define-key global-map [?\C- ] 'set-mark-command)
@@ -1104,44 +1099,41 @@ if `inhibit-field-text-motion' is non-nil."
 
 (define-key ctl-x-map "`" 'next-error)
 
-(defvar next-error-repeat-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map    "n" 'next-error)
-    (define-key map "\M-n" 'next-error)
-    (define-key map    "p" 'previous-error)
-    (define-key map "\M-p" 'previous-error)
-    map)
-  "Keymap to repeat `next-error' key sequences.  Used in `repeat-mode'.")
+(defvar-keymap next-error-repeat-map
+  :doc "Keymap to repeat `next-error' key sequences.  Used in `repeat-mode'."
+  "n"   #'next-error
+  "M-n" #'next-error
+  "p"   #'previous-error
+  "M-p" #'previous-error)
 (put 'next-error 'repeat-map 'next-error-repeat-map)
 (put 'previous-error 'repeat-map 'next-error-repeat-map)
 
-(defvar goto-map (make-sparse-keymap)
-  "Keymap for navigation commands.")
+(defvar-keymap goto-map
+  :doc "Keymap for navigation commands."
+  "c"   #'goto-char
+  "g"   #'goto-line
+  "M-g" #'goto-line
+  "n"   #'next-error
+  "M-n" #'next-error
+  "p"   #'previous-error
+  "M-p" #'previous-error
+  "TAB" #'move-to-column
+  "i"   #'imenu)
 (define-key esc-map "g" goto-map)
 
-(define-key goto-map    "c" 'goto-char)
-(define-key goto-map    "g" 'goto-line)
-(define-key goto-map "\M-g" 'goto-line)
-(define-key goto-map    "n" 'next-error)
-(define-key goto-map "\M-n" 'next-error)
-(define-key goto-map    "p" 'previous-error)
-(define-key goto-map "\M-p" 'previous-error)
-(define-key goto-map   "\t" 'move-to-column)
-(define-key goto-map    "i" 'imenu)
-
-(defvar search-map (make-sparse-keymap)
-  "Keymap for search related commands.")
+(defvar-keymap search-map
+  :doc "Keymap for search related commands."
+  "o"   #'occur
+  "M-w" #'eww-search-words
+  "h r" #'highlight-regexp
+  "h p" #'highlight-phrase
+  "h l" #'highlight-lines-matching-regexp
+  "h ." #'highlight-symbol-at-point
+  "h u" #'unhighlight-regexp
+  "h f" #'hi-lock-find-patterns
+  "h w" #'hi-lock-write-interactive-patterns)
 (define-key esc-map "s" search-map)
 
-(define-key search-map "o"    'occur)
-(define-key search-map "\M-w" 'eww-search-words)
-(define-key search-map "hr"   'highlight-regexp)
-(define-key search-map "hp"   'highlight-phrase)
-(define-key search-map "hl"   'highlight-lines-matching-regexp)
-(define-key search-map "h."   'highlight-symbol-at-point)
-(define-key search-map "hu"   'unhighlight-regexp)
-(define-key search-map "hf"   'hi-lock-find-patterns)
-(define-key search-map "hw"   'hi-lock-write-interactive-patterns)
 (put 'highlight-regexp                   :advertised-binding [?\M-s ?h ?r])
 (put 'highlight-phrase                   :advertised-binding [?\M-s ?h ?p])
 (put 'highlight-lines-matching-regexp    :advertised-binding [?\M-s ?h ?l])
@@ -1339,7 +1331,15 @@ if `inhibit-field-text-motion' is non-nil."
 ;; can use S-tab instead to access that binding.
 (define-key function-key-map [S-tab] [backtab])
 
-(define-key global-map [mouse-movement] 'ignore)
+(defun ignore-preserving-kill-region (&rest _)
+  "Like `ignore', but don't overwrite `last-event' if it's `kill-region'."
+  (declare (completion ignore))
+  (interactive)
+  (when (eq last-command 'kill-region)
+    (setq this-command 'kill-region))
+  nil)
+
+(define-key global-map [mouse-movement] #'ignore-preserving-kill-region)
 
 (define-key global-map "\C-t" 'transpose-chars)
 (define-key esc-map "t" 'transpose-words)
@@ -1367,7 +1367,7 @@ if `inhibit-field-text-motion' is non-nil."
 
 (defalias 'mode-specific-command-prefix (make-sparse-keymap))
 (defvar mode-specific-map (symbol-function 'mode-specific-command-prefix)
-  "Keymap for characters following C-c.")
+  "Keymap for characters following \\`C-c'.")
 (define-key global-map "\C-c" 'mode-specific-command-prefix)
 
 (global-set-key [M-right]  'right-word)
@@ -1423,31 +1423,29 @@ if `inhibit-field-text-motion' is non-nil."
 (define-key ctl-x-5-map "m" 'compose-mail-other-frame)
 
 
-(defvar ctl-x-r-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "c" 'clear-rectangle)
-    (define-key map "k" 'kill-rectangle)
-    (define-key map "d" 'delete-rectangle)
-    (define-key map "y" 'yank-rectangle)
-    (define-key map "o" 'open-rectangle)
-    (define-key map "t" 'string-rectangle)
-    (define-key map "N" 'rectangle-number-lines)
-    (define-key map "\M-w" 'copy-rectangle-as-kill)
-    (define-key map "\C-@" 'point-to-register)
-    (define-key map [?\C-\ ] 'point-to-register)
-    (define-key map " " 'point-to-register)
-    (define-key map "j" 'jump-to-register)
-    (define-key map "s" 'copy-to-register)
-    (define-key map "x" 'copy-to-register)
-    (define-key map "i" 'insert-register)
-    (define-key map "g" 'insert-register)
-    (define-key map "r" 'copy-rectangle-to-register)
-    (define-key map "n" 'number-to-register)
-    (define-key map "+" 'increment-register)
-    (define-key map "w" 'window-configuration-to-register)
-    (define-key map "f" 'frameset-to-register)
-    map)
-  "Keymap for subcommands of C-x r.")
+(defvar-keymap ctl-x-r-map
+  :doc "Keymap for subcommands of \\`C-x r'."
+  "c"     #'clear-rectangle
+  "k"     #'kill-rectangle
+  "d"     #'delete-rectangle
+  "y"     #'yank-rectangle
+  "o"     #'open-rectangle
+  "t"     #'string-rectangle
+  "N"     #'rectangle-number-lines
+  "M-w"   #'copy-rectangle-as-kill
+  "C-@"   #'point-to-register
+  "C-SPC" #'point-to-register
+  "SPC"   #'point-to-register
+  "j"     #'jump-to-register
+  "s"     #'copy-to-register
+  "x"     #'copy-to-register
+  "i"     #'insert-register
+  "g"     #'insert-register
+  "r"     #'copy-rectangle-to-register
+  "n"     #'number-to-register
+  "+"     #'increment-register
+  "w"     #'window-configuration-to-register
+  "f"     #'frameset-to-register)
 (define-key ctl-x-map "r" ctl-x-r-map)
 
 (define-key esc-map "q" 'fill-paragraph)
@@ -1464,12 +1462,10 @@ if `inhibit-field-text-motion' is non-nil."
 (define-key ctl-x-map "[" 'backward-page)
 (define-key ctl-x-map "]" 'forward-page)
 
-(defvar page-navigation-repeat-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "]" #'forward-page)
-    (define-key map "[" #'backward-page)
-    map)
-  "Keymap to repeat page navigation key sequences.  Used in `repeat-mode'.")
+(defvar-keymap page-navigation-repeat-map
+  :doc "Keymap to repeat page navigation key sequences.  Used in 
`repeat-mode'."
+  "]" #'forward-page
+  "[" #'backward-page)
 
 (put 'forward-page 'repeat-map 'page-navigation-repeat-map)
 (put 'backward-page 'repeat-map 'page-navigation-repeat-map)
@@ -1477,26 +1473,20 @@ if `inhibit-field-text-motion' is non-nil."
 (define-key ctl-x-map "\C-p" 'mark-page)
 (define-key ctl-x-map "l" 'count-lines-page)
 (define-key ctl-x-map "np" 'narrow-to-page)
-;; (define-key ctl-x-map "p" 'narrow-to-page)
 
-(defvar abbrev-map (make-sparse-keymap)
-  "Keymap for abbrev commands.")
+(defvar-keymap abbrev-map
+  :doc "Keymap for abbrev commands."
+  "l"   #'add-mode-abbrev
+  "C-a" #'add-mode-abbrev
+  "g"   #'add-global-abbrev
+  "+"   #'add-mode-abbrev
+  "i g" #'inverse-add-global-abbrev
+  "i l" #'inverse-add-mode-abbrev
+  "-"   #'inverse-add-global-abbrev
+  "e"   #'expand-abbrev
+  "'"   #'expand-abbrev)
 (define-key ctl-x-map "a" abbrev-map)
 
-(define-key abbrev-map "l" 'add-mode-abbrev)
-(define-key abbrev-map "\C-a" 'add-mode-abbrev)
-(define-key abbrev-map "g" 'add-global-abbrev)
-(define-key abbrev-map "+" 'add-mode-abbrev)
-(define-key abbrev-map "ig" 'inverse-add-global-abbrev)
-(define-key abbrev-map "il" 'inverse-add-mode-abbrev)
-;; (define-key abbrev-map "\C-h" 'inverse-add-global-abbrev)
-(define-key abbrev-map "-" 'inverse-add-global-abbrev)
-(define-key abbrev-map "e" 'expand-abbrev)
-(define-key abbrev-map "'" 'expand-abbrev)
-;; (define-key ctl-x-map "\C-a" 'add-mode-abbrev)
-;; (define-key ctl-x-map "+" 'add-global-abbrev)
-;; (define-key ctl-x-map "\C-h" 'inverse-add-mode-abbrev)
-;; (define-key ctl-x-map "-" 'inverse-add-global-abbrev)
 (define-key esc-map "'" 'abbrev-prefix-mark)
 (define-key ctl-x-map "'" 'expand-abbrev)
 (define-key ctl-x-map "\C-b" 'list-buffers)
@@ -1506,17 +1496,15 @@ if `inhibit-field-text-motion' is non-nil."
 
 (define-key ctl-x-map "z" 'repeat)
 
-(defvar ctl-x-x-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "f" #'font-lock-update)
-    (define-key map "g" #'revert-buffer-quick)
-    (define-key map "r" #'rename-buffer)
-    (define-key map "u" #'rename-uniquely)
-    (define-key map "n" #'clone-buffer)
-    (define-key map "i" #'insert-buffer)
-    (define-key map "t" #'toggle-truncate-lines)
-    map)
-  "Keymap for subcommands of C-x x.")
+(defvar-keymap ctl-x-x-map
+  :doc "Keymap for subcommands of \\`C-x x'."
+  "f" #'font-lock-update
+  "g" #'revert-buffer-quick
+  "r" #'rename-buffer
+  "u" #'rename-uniquely
+  "n" #'clone-buffer
+  "i" #'insert-buffer
+  "t" #'toggle-truncate-lines)
 (define-key ctl-x-map "x" ctl-x-x-map)
 
 (define-key esc-map "\C-l" 'reposition-window)
diff --git a/lisp/bookmark.el b/lisp/bookmark.el
index b0b54e52d8..8dfc16bf9f 100644
--- a/lisp/bookmark.el
+++ b/lisp/bookmark.el
@@ -35,6 +35,7 @@
 (require 'pp)
 (require 'tabulated-list)
 (require 'text-property-search)
+(require 'fringe) ; for builds --without-x
 (eval-when-compile (require 'cl-lib))
 
 ;;; Misc comments:
@@ -160,7 +161,7 @@ This includes the annotations column.")
 (defcustom bookmark-bmenu-file-column 30
   "Column at which to display filenames in a buffer listing bookmarks.
 You can toggle whether files are shown with 
\\<bookmark-bmenu-mode-map>\\[bookmark-bmenu-toggle-filenames]."
-  :type 'integer)
+  :type 'natnum)
 
 
 (defcustom bookmark-bmenu-toggle-filenames t
@@ -174,23 +175,32 @@ A non-nil value may result in truncated bookmark names."
 
 (defcustom bookmark-menu-length 70
   "Maximum length of a bookmark name displayed on a popup menu."
-  :type 'integer)
+  :type 'natnum)
 
 ;; FIXME: Is it really worth a customization option?
 (defcustom bookmark-search-delay 0.2
   "Time before `bookmark-bmenu-search' updates the display."
   :type  'number)
 
-(defcustom bookmark-set-fringe-mark t
-  "Whether to set a fringe mark at bookmarked lines."
-  :type  'boolean
-  :version "28.1")
-
-;; FIXME: No longer used.  Should be declared obsolete or removed.
-(defface bookmark-menu-heading
-  '((t (:inherit font-lock-type-face)))
-  "Face used to highlight the heading in bookmark menu buffers."
-  :version "22.1")
+(define-fringe-bitmap 'bookmark-mark
+  [#b01111110
+   #b01111110
+   #b01111110
+   #b01111110
+   #b01111110
+   #b01111110
+   #b01100110
+   #b01000010])
+
+(define-obsolete-variable-alias 'bookmark-set-fringe-mark
+  'bookmark-fringe-mark "29.1")
+
+(defcustom bookmark-fringe-mark 'bookmark-mark
+  "The fringe bitmap to mark bookmarked lines with.
+If nil, don't display a mark on the fringe."
+  :type '(choice (const nil) fringe-bitmap)
+  :set #'fringe-custom-set-bitmap
+  :version "29.1")
 
 (defface bookmark-face
   '((((class grayscale)
@@ -201,10 +211,10 @@ A non-nil value may result in truncated bookmark names."
      :foreground "LightGray")
     (((class color)
       (background light))
-     :background "White" :foreground "DarkOrange1")
+     :foreground "DarkOrange1" :distant-foreground "DarkOrange3")
     (((class color)
       (background dark))
-     :background "Black" :foreground "DarkOrange1"))
+     :foreground "DarkOrange1" :distant-foreground "Orange1"))
   "Face used to highlight current line."
   :version "28.1")
 
@@ -216,10 +226,10 @@ A non-nil value may result in truncated bookmark names."
 ;; Set up these bindings dumping time *only*;
 ;; if the user alters them, don't override the user when loading bookmark.el.
 
-;;;###autoload (define-key ctl-x-r-map "b" 'bookmark-jump)
-;;;###autoload (define-key ctl-x-r-map "m" 'bookmark-set)
-;;;###autoload (define-key ctl-x-r-map "M" 'bookmark-set-no-overwrite)
-;;;###autoload (define-key ctl-x-r-map "l" 'bookmark-bmenu-list)
+;;;###autoload (keymap-set ctl-x-r-map "b" #'bookmark-jump)
+;;;###autoload (keymap-set ctl-x-r-map "m" #'bookmark-set)
+;;;###autoload (keymap-set ctl-x-r-map "M" #'bookmark-set-no-overwrite)
+;;;###autoload (keymap-set ctl-x-r-map "l" #'bookmark-bmenu-list)
 
 ;;;###autoload
 (defvar-keymap bookmark-map
@@ -482,13 +492,10 @@ In other words, return all information but the name."
 (defvar bookmark-history nil
   "The history list for bookmark functions.")
 
-(define-fringe-bitmap 'bookmark-fringe-mark
-  "\x3c\x7e\xff\xff\xff\xff\x7e\x3c")
-
 (defun bookmark--set-fringe-mark ()
   "Apply a colorized overlay to the bookmarked location.
-See user option `bookmark-set-fringe-mark'."
-  (let ((bm (make-overlay (point-at-bol) (1+ (point-at-bol)))))
+See user option `bookmark-fringe-mark'."
+  (let ((bm (make-overlay (pos-bol) (1+ (pos-bol)))))
     (overlay-put bm 'category 'bookmark)
     (overlay-put bm 'evaporate t)
     (overlay-put bm 'before-string
@@ -499,7 +506,7 @@ See user option `bookmark-set-fringe-mark'."
 (defun bookmark--remove-fringe-mark (bm)
   "Remove a bookmark's colorized overlay.
 BM is a bookmark as returned from function `bookmark-get-bookmark'.
-See user option `bookmark-set-fringe'."
+See user option `bookmark-fringe-mark'."
   (let ((filename (cdr (assq 'filename bm)))
         (pos (cdr (assq 'position bm)))
         overlays found temp)
@@ -511,7 +518,7 @@ See user option `bookmark-set-fringe'."
             (setq overlays
                   (save-excursion
                     (goto-char pos)
-                    (overlays-in (point-at-bol) (1+ (point-at-bol)))))
+                    (overlays-in (pos-bol) (1+ (pos-bol)))))
             (while (and (not found) (setq temp (pop overlays)))
               (when (eq 'bookmark (overlay-get temp 'category))
                 (delete-overlay (setq found temp))))))))))
@@ -615,7 +622,7 @@ old one."
         ;; no prefix arg means just overwrite old bookmark.
         (let ((bm (bookmark-get-bookmark stripped-name)))
           ;; First clean up if previously location was fontified.
-          (when bookmark-set-fringe-mark
+          (when bookmark-fringe-mark
             (bookmark--remove-fringe-mark bm))
           ;; Modify using the new (NAME . ALIST) format.
           (setcdr bm alist))
@@ -931,7 +938,7 @@ still there, in order, if the topmost one is ever deleted."
            ;; Ask for an annotation buffer for this bookmark
            (when bookmark-use-annotations
              (bookmark-edit-annotation str))
-           (when bookmark-set-fringe-mark
+           (when bookmark-fringe-mark
              (bookmark--set-fringe-mark))))
     (setq bookmark-yank-point nil)
     (setq bookmark-current-buffer nil)))
@@ -966,7 +973,7 @@ it removes only the first instance of a bookmark with that 
name from
 the list of bookmarks.)"
   (interactive (list nil current-prefix-arg))
   (let ((prompt
-         (if no-overwrite "Append bookmark named" "Set bookmark named")))
+         (if no-overwrite "Add bookmark named" "Set bookmark named")))
     (bookmark-set-internal prompt name (if no-overwrite 'push 'overwrite))))
 
 ;;;###autoload
@@ -1007,7 +1014,7 @@ the list of bookmarks.)"
   "Kill from point to end of line.
 If optional arg NEWLINE-TOO is non-nil, delete the newline too.
 Does not affect the kill ring."
-  (let ((eol (line-end-position)))
+  (let ((eol (pos-eol)))
     (delete-region (point) eol)
     (when (and newline-too (= (following-char) ?\n))
       (delete-char 1))))
@@ -1027,10 +1034,13 @@ annotations."
            bookmark-name)
          (format-message
            "#  All lines which start with a `#' will be deleted.\n")
-         "#  Type C-c C-c when done.\n#\n"
+          (substitute-command-keys
+           (concat
+            "#  Type \\[bookmark-edit-annotation-confirm] when done.  Type "
+            "\\[bookmark-edit-annotation-cancel] to cancel.\n#\n"))
          "#  Author: " (user-full-name) " <" (user-login-name) "@"
          (system-name) ">\n"
-         "#  Date:    " (current-time-string) "\n"))
+          "#  Date:   " (current-time-string) "\n"))
 
 
 (defvar bookmark-edit-annotation-text-func 'bookmark-default-annotation-text
@@ -1040,7 +1050,8 @@ It takes one argument, the name of the bookmark, as a 
string.")
 (defvar-keymap bookmark-edit-annotation-mode-map
   :doc "Keymap for editing an annotation of a bookmark."
   :parent text-mode-map
-  "C-c C-c" #'bookmark-send-edited-annotation)
+  "C-c C-c" #'bookmark-edit-annotation-confirm
+  "C-c C-k" #'bookmark-edit-annotation-cancel)
 
 (defun bookmark-insert-annotation (bookmark-name-or-record)
   "Insert annotation for BOOKMARK-NAME-OR-RECORD at point."
@@ -1054,12 +1065,32 @@ It takes one argument, the name of the bookmark, as a 
string.")
 (define-derived-mode bookmark-edit-annotation-mode
   text-mode "Edit Bookmark Annotation"
   "Mode for editing the annotation of bookmarks.
-When you have finished composing, type \\[bookmark-send-edited-annotation].
+\\<bookmark-edit-annotation-mode-map>\
+When you have finished composing, type \\[bookmark-edit-annotation-confirm] \
+or \\[bookmark-edit-annotation-cancel] to cancel.
 
 \\{bookmark-edit-annotation-mode-map}")
 
+(defmacro bookmark-edit-annotation--maybe-display-list (&rest body)
+  "Display bookmark list after editing if appropriate."
+  `(let ((from-bookmark-list bookmark--annotation-from-bookmark-list)
+         (old-buffer (current-buffer)))
+     ,@body
+     (quit-window)
+     (bookmark-bmenu-surreptitiously-rebuild-list)
+     (when from-bookmark-list
+       (pop-to-buffer (get-buffer bookmark-bmenu-buffer))
+       (goto-char (point-min))
+       (bookmark-bmenu-bookmark))
+     (kill-buffer old-buffer)))
+
+(defun bookmark-edit-annotation-cancel ()
+  "Cancel the current annotation edit."
+  (interactive nil bookmark-edit-annotation-mode)
+  (bookmark-edit-annotation--maybe-display-list
+   (message "Canceled by user")))
 
-(defun bookmark-send-edited-annotation ()
+(defun bookmark-edit-annotation-confirm ()
   "Use buffer contents as annotation for a bookmark.
 Lines beginning with `#' are ignored."
   (interactive nil bookmark-edit-annotation-mode)
@@ -1071,22 +1102,14 @@ Lines beginning with `#' are ignored."
         (bookmark-kill-line t)
       (forward-line 1)))
   ;; Take no chances with text properties.
-  (let ((annotation (buffer-substring-no-properties (point-min) (point-max)))
-        (bookmark-name bookmark-annotation-name)
-        (from-bookmark-list bookmark--annotation-from-bookmark-list)
-        (old-buffer (current-buffer)))
-    (bookmark-set-annotation bookmark-name annotation)
-    (bookmark-update-last-modified bookmark-name)
-    (setq bookmark-alist-modification-count
-          (1+ bookmark-alist-modification-count))
-    (message "Annotation updated for \"%s\"" bookmark-name)
-    (quit-window)
-    (bookmark-bmenu-surreptitiously-rebuild-list)
-    (when from-bookmark-list
-      (pop-to-buffer (get-buffer bookmark-bmenu-buffer))
-      (goto-char (point-min))
-      (bookmark-bmenu-bookmark))
-    (kill-buffer old-buffer)))
+  (bookmark-edit-annotation--maybe-display-list
+   (let ((annotation (buffer-substring-no-properties (point-min) (point-max)))
+         (bookmark-name bookmark-annotation-name))
+     (bookmark-set-annotation bookmark-name annotation)
+     (bookmark-update-last-modified bookmark-name)
+     (setq bookmark-alist-modification-count
+           (1+ bookmark-alist-modification-count))
+     (message "Annotation updated for \"%s\"" bookmark-name))))
 
 
 (defun bookmark-edit-annotation (bookmark-name-or-record &optional 
from-bookmark-list)
@@ -1094,8 +1117,8 @@ Lines beginning with `#' are ignored."
 If optional argument FROM-BOOKMARK-LIST is non-nil, return to the
 bookmark list when editing is done."
   (pop-to-buffer (generate-new-buffer-name "*Bookmark Annotation Compose*"))
-  (bookmark-insert-annotation bookmark-name-or-record)
   (bookmark-edit-annotation-mode)
+  (bookmark-insert-annotation bookmark-name-or-record)
   (setq bookmark--annotation-from-bookmark-list from-bookmark-list)
   (setq bookmark-annotation-name bookmark-name-or-record))
 
@@ -1156,7 +1179,7 @@ it to the name of the bookmark currently being set, 
advancing
 (defun bookmark--watch-file-already-queried-p (new-mtime)
   ;; Don't ask repeatedly if user already said "no" to reloading a
   ;; file with this mtime:
-  (prog1 (equal new-mtime bookmark--watch-already-asked-mtime)
+  (prog1 (time-equal-p new-mtime bookmark--watch-already-asked-mtime)
     (setq bookmark--watch-already-asked-mtime new-mtime)))
 
 (defun bookmark-maybe-load-default-file ()
@@ -1169,7 +1192,7 @@ it to the name of the bookmark currently being set, 
advancing
               (let ((new-mtime (nth 5 (file-attributes
                                        (car bookmark-bookmarks-timestamp))))
                     (old-mtime (cdr bookmark-bookmarks-timestamp)))
-                (and (not (equal new-mtime old-mtime))
+               (and (not (time-equal-p new-mtime old-mtime))
                      (not (bookmark--watch-file-already-queried-p new-mtime))
                      (or (eq 'silent bookmark-watch-bookmark-file)
                          (yes-or-no-p
@@ -1197,8 +1220,8 @@ and then show any annotations for this bookmark."
     (if win (set-window-point win (point))))
   ;; FIXME: we used to only run bookmark-after-jump-hook in
   ;; `bookmark-jump' itself, but in none of the other commands.
-  (when bookmark-set-fringe-mark
-    (let ((overlays (overlays-in (point-at-bol) (1+ (point-at-bol))))
+  (when bookmark-fringe-mark
+    (let ((overlays (overlays-in (pos-bol) (1+ (pos-bol))))
           temp found)
       (while (and (not found) (setq temp (pop overlays)))
         (when (eq 'bookmark (overlay-get temp 'category))
@@ -1420,9 +1443,9 @@ name."
              (read-from-minibuffer
               "New name: "
               nil
-              (let ((now-map (copy-keymap minibuffer-local-map)))
-                (define-key now-map "\C-w" 'bookmark-yank-word)
-                now-map)
+              (define-keymap
+                :parent minibuffer-local-map
+                "C-w" #'bookmark-yank-word)
               nil
               'bookmark-history))))
     (bookmark-set-name old-name final-new-name)
@@ -2555,6 +2578,12 @@ This also runs `bookmark-exit-hook'."
 
 (run-hooks 'bookmark-load-hook)
 
+
+;;; Obsolete:
+
+(define-obsolete-function-alias 'bookmark-send-edited-annotation
+  #'bookmark-edit-annotation-confirm "29.1")
+
 (provide 'bookmark)
 
 ;;; bookmark.el ends here
diff --git a/lisp/bs.el b/lisp/bs.el
index cff19c81cb..aabc2dc558 100644
--- a/lisp/bs.el
+++ b/lisp/bs.el
@@ -1,6 +1,7 @@
 ;;; bs.el --- menu for selecting and displaying buffers -*- lexical-binding: t 
-*-
 
 ;; Copyright (C) 1998-2022 Free Software Foundation, Inc.
+
 ;; Author: Olaf Sylvester <Olaf.Sylvester@netsurf.de>
 ;; Maintainer: emacs-devel@gnu.org
 ;; Keywords: convenience
@@ -434,58 +435,61 @@ Used internally, only.")
 (defvar bs--marked-buffers nil
   "Currently marked buffers in Buffer Selection Menu.")
 
-(defvar bs-mode-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map " "       'bs-select)
-    (define-key map "f"       'bs-select)
-    (define-key map "v"       'bs-view)
-    (define-key map "!"       'bs-select-in-one-window)
-    (define-key map [mouse-2] 'bs-mouse-select)
-    (define-key map "F"       'bs-select-other-frame)
-    (let ((key ?1))
-      (while (<= key ?9)
-       (define-key map (char-to-string key) 'digit-argument)
-       (setq key (1+ key))))
-    (define-key map "-"       'negative-argument)
-    (define-key map "\e-"     'negative-argument)
-    (define-key map "o"       'bs-select-other-window)
-    (define-key map "\C-o"    'bs-tmp-select-other-window)
-    (define-key map [mouse-3] 'bs-mouse-select-other-frame)
-    (define-key map [up]      'bs-up)
-    (define-key map "n"       'bs-down)
-    (define-key map "p"       'bs-up)
-    (define-key map [down]    'bs-down)
-    (define-key map "\C-m"    'bs-select)
-    (define-key map "b"       'bs-bury-buffer)
-    (define-key map "s"       'bs-save)
-    (define-key map "S"       'bs-show-sorted)
-    (define-key map "a"       'bs-toggle-show-all)
-    (define-key map "d"       'bs-delete)
-    (define-key map "\C-d"    'bs-delete-backward)
-    (define-key map "k"       'bs-delete)
-    (define-key map "g"       'bs-refresh)
-    (define-key map "C"       'bs-set-configuration-and-refresh)
-    (define-key map "c"       'bs-select-next-configuration)
-    (define-key map "q"       'bs-kill)
-    ;; (define-key map "z"       'bs-kill)
-    (define-key map "\C-c\C-c" 'bs-kill)
-    (define-key map "\C-g"    'bs-abort)
-    (define-key map "\C-]"    'bs-abort)
-    (define-key map "%"       'bs-toggle-readonly)
-    (define-key map "~"       'bs-clear-modified)
-    (define-key map "M"       'bs-toggle-current-to-show)
-    (define-key map "+"       'bs-set-current-buffer-to-show-always)
-    ;;(define-key map "-"       'bs-set-current-buffer-to-show-never)
-    (define-key map "t"       'bs-visit-tags-table)
-    (define-key map "m"       'bs-mark-current)
-    (define-key map "u"       'bs-unmark-current)
-    (define-key map "U"       'bs-unmark-all)
-    (define-key map "\177"    'bs-unmark-previous)
-    (define-key map ">"       'scroll-right)
-    (define-key map "<"       'scroll-left)
-    (define-key map "?"       'bs-help)
-    map)
-  "Keymap of `bs-mode'.")
+(defvar-keymap bs-mode-map
+  :doc "Keymap of `bs-mode'."
+  "SPC"     #'bs-select
+  "f"       #'bs-select
+  "v"       #'bs-view
+  "!"       #'bs-select-in-one-window
+  "F"       #'bs-select-other-frame
+  "1"       #'digit-argument
+  "2"       #'digit-argument
+  "3"       #'digit-argument
+  "4"       #'digit-argument
+  "5"       #'digit-argument
+  "6"       #'digit-argument
+  "7"       #'digit-argument
+  "8"       #'digit-argument
+  "9"       #'digit-argument
+  "-"       #'negative-argument
+  "ESC -"   #'negative-argument
+  "o"       #'bs-select-other-window
+  "C-o"     #'bs-tmp-select-other-window
+  "<up>"    #'bs-up
+  "n"       #'bs-down
+  "p"       #'bs-up
+  "<down>"  #'bs-down
+  "C-m"     #'bs-select
+  "b"       #'bs-bury-buffer
+  "s"       #'bs-save
+  "S"       #'bs-show-sorted
+  "a"       #'bs-toggle-show-all
+  "d"       #'bs-delete
+  "C-d"     #'bs-delete-backward
+  "k"       #'bs-delete
+  "g"       #'bs-refresh
+  "C"       #'bs-set-configuration-and-refresh
+  "c"       #'bs-select-next-configuration
+  "q"       #'bs-kill
+  ;; "z"       #'bs-kill
+  "C-c C-c" #'bs-kill
+  "C-g"     #'bs-abort
+  "C-]"     #'bs-abort
+  "%"       #'bs-toggle-readonly
+  "~"       #'bs-clear-modified
+  "M"       #'bs-toggle-current-to-show
+  "+"       #'bs-set-current-buffer-to-show-always
+  ;; "-"       #'bs-set-current-buffer-to-show-never
+  "t"       #'bs-visit-tags-table
+  "m"       #'bs-mark-current
+  "u"       #'bs-unmark-current
+  "U"       #'bs-unmark-all
+  "DEL"     #'bs-unmark-previous
+  ">"       #'scroll-right
+  "<"       #'scroll-left
+  "?"       #'describe-mode
+  "<mouse-2>" #'bs-mouse-select
+  "<mouse-3>" #'bs-mouse-select-other-frame)
 
 ;; ----------------------------------------------------------------------
 ;; Functions
@@ -608,12 +612,12 @@ Used from `window-size-change-functions'."
 \\<bs-mode-map>
 Aside from two header lines each line describes one buffer.
 Move to a line representing the buffer you want to edit and select
-buffer by \\[bs-select] or SPC.  Abort buffer list with \\[bs-kill].
+buffer by \\[bs-select] or \\`SPC'.  Abort buffer list with \\[bs-kill].
 There are many key commands similar to `Buffer-menu-mode' for
 manipulating the buffer list and buffers.
 For faster navigation each digit key is a digit argument.
 
-\\[bs-select] or SPACE -- select current line's buffer and other marked 
buffers.
+\\[bs-select] or \\`SPC' -- select current line's buffer and other marked 
buffers.
 \\[bs-select-in-one-window] -- select current's line buffer in one \
 window, and delete other
      windows in the same frame.
@@ -651,7 +655,7 @@ apply it.
 
 \\[bs-kill] -- leave Buffer Selection Menu without a selection.
 \\[bs-refresh] -- refresh Buffer Selection Menu.
-\\[bs-help] -- display this help text."
+\\[describe-mode] -- display this help text."
   (buffer-disable-undo)
   (setq buffer-read-only t
        truncate-lines t
@@ -1117,7 +1121,8 @@ configuration."
 
 (defun bs-help ()
   "Help for `bs-show'."
-  (interactive)
+  (declare (obsolete describe-mode "29.1"))
+  (interactive nil bs-mode)
   (describe-function 'bs-mode))
 
 (defun bs-next-config-aux (start-name list)
@@ -1480,7 +1485,7 @@ manipulating the buffer list and the buffers themselves.
 User can move with [up] or [down], select a buffer
 by \\[bs-select] or [SPC]\n
 Type \\[bs-kill] to leave Buffer Selection Menu without a selection.
-Type \\[bs-help] after invocation to get help on commands available.
+Type \\[describe-mode] after invocation to get help on commands available.
 With prefix argument ARG show a different buffer list.  Function
 `bs--configuration-name-for-prefix-arg' determine accordingly
 name of buffer configuration."
diff --git a/lisp/buff-menu.el b/lisp/buff-menu.el
index 179cc5484c..539ef673f0 100644
--- a/lisp/buff-menu.el
+++ b/lisp/buff-menu.el
@@ -92,13 +92,13 @@ number."
 
 (defcustom Buffer-menu-size-width 7
   "Width of buffer size column in the Buffer Menu."
-  :type 'number
+  :type 'natnum
   :group 'Buffer-menu
   :version "24.3")
 
 (defcustom Buffer-menu-mode-width 16
   "Width of mode name column in the Buffer Menu."
-  :type 'number
+  :type 'natnum
   :group 'Buffer-menu)
 
 (defcustom Buffer-menu-use-frame-buffer-list t
diff --git a/lisp/button.el b/lisp/button.el
index 80b73033d6..21047ad554 100644
--- a/lisp/button.el
+++ b/lisp/button.el
@@ -623,12 +623,15 @@ itself will be used instead as the function argument.
 If HELP-ECHO, use that as the `help-echo' property.
 
 Also see `buttonize-region'."
-  (apply #'propertize string
-         (button--properties callback data help-echo)))
+  (let ((string
+         (apply #'propertize string
+                (button--properties callback data help-echo))))
+    ;; Add the face to the end so that it can be overridden.
+    (add-face-text-property 0 (length string) 'button t string)
+    string))
 
 (defun button--properties (callback data help-echo)
-  (list 'face 'button
-        'font-lock-face 'button
+  (list 'font-lock-face 'button
         'mouse-face 'highlight
         'help-echo help-echo
         'button t
@@ -647,7 +650,8 @@ itself will be used instead as the function argument.
 If HELP-ECHO, use that as the `help-echo' property.
 
 Also see `buttonize'."
-  (add-text-properties start end (button--properties callback data help-echo)))
+  (add-text-properties start end (button--properties callback data help-echo))
+  (add-face-text-property start end 'button t))
 
 (provide 'button)
 
diff --git a/lisp/calc/calc-embed.el b/lisp/calc/calc-embed.el
index 9a580d9602..bb427ef86e 100644
--- a/lisp/calc/calc-embed.el
+++ b/lisp/calc/calc-embed.el
@@ -335,7 +335,8 @@
          (message (concat
                     "Embedded Calc mode enabled; "
                     (if calc-embedded-quiet
-                        "Type `C-x * x'"
+                        (substitute-command-keys
+                         "Type \\`C-x * x'")
                       "Give this command again")
                     " to return to normal")))))
   (scroll-down 0)))    ; fix a bug which occurs when truncate-lines is changed.
diff --git a/lisp/calc/calc-keypd.el b/lisp/calc/calc-keypd.el
index 6144ee1c08..3db3746a8e 100644
--- a/lisp/calc/calc-keypd.el
+++ b/lisp/calc/calc-keypd.el
@@ -387,7 +387,7 @@
   (interactive)
   (unless (eq major-mode 'calc-keypad-mode)
     (error "Must be in *Calc Keypad* buffer for this command"))
-  (let* ((row (count-lines (point-min) (point-at-bol)))
+  (let* ((row (count-lines (point-min) (line-beginning-position)))
         (y (/ row 2))
         (x (/ (current-column) (if (>= y 4) 6 5)))
         radix frac inv
diff --git a/lisp/calc/calc-misc.el b/lisp/calc/calc-misc.el
index bd1635f2bf..7c75e79a26 100644
--- a/lisp/calc/calc-misc.el
+++ b/lisp/calc/calc-misc.el
@@ -61,48 +61,48 @@
 
 ;;;###autoload
 (defun calc-dispatch-help (arg)
-  "C-x* is a prefix key sequence; follow it with one of these letters:
+  "\\`C-x *' is a prefix key sequence; follow it with one of these letters:
 
 For turning Calc on and off:
-  C  calc.  Start the Calculator in a window at the bottom of the screen.
-  O  calc-other-window.  Start the Calculator but don't select its window.
-  B  calc-big-or-small.  Control whether to use the full Emacs screen for Calc.
-  Q  quick-calc.  Use the Calculator in the minibuffer.
-  K  calc-keypad.  Start the Calculator in keypad mode (X window system only).
-  E  calc-embedded.  Use the Calculator on a formula in this editing buffer.
-  J  calc-embedded-select.  Like E, but select appropriate half of => or :=.
-  W  calc-embedded-word.  Like E, but activate a single word, i.e., a number.
-  Z  calc-user-invocation.  Invoke Calc in the way you defined with `Z I' cmd.
-  X  calc-quit.  Turn Calc off.
+  \\`C'  calc.  Start the Calculator in a window at the bottom of the screen.
+  \\`O'  calc-other-window.  Start the Calculator but don't select its window.
+  \\`B'  calc-big-or-small.  Toggle using the full Emacs screen for Calc.
+  \\`Q'  quick-calc.  Use the Calculator in the minibuffer.
+  \\`K'  calc-keypad.  Start the Calculator in keypad mode (X window system 
only).
+  \\`E'  calc-embedded.  Use the Calculator on a formula in this editing 
buffer.
+  \\`J'  calc-embedded-select.  Like \\`E', but select appropriate half of => 
or :=.
+  \\`W'  calc-embedded-word.  Like \\`E', but activate a single word, i.e., a 
number.
+  \\`Z'  calc-user-invocation.  Invoke Calc in the way you defined with `Z I' 
cmd.
+  \\`X'  calc-quit.  Turn Calc off.
 
 For moving data into and out of Calc:
-  G  calc-grab-region.  Grab the region defined by mark and point into Calc.
-  R  calc-grab-rectangle.  Grab the rectangle defined by mark, point into Calc.
-  :  calc-grab-sum-down.  Grab a rectangle and sum the columns.
-  _  calc-grab-sum-across.  Grab a rectangle and sum the rows.
-  Y  calc-copy-to-buffer.  Copy a value from the stack into the editing buffer.
+  \\`G'  calc-grab-region.  Grab the region defined by mark and point into 
Calc.
+  \\`R'  calc-grab-rectangle.  Grab the rectangle defined by mark, point into 
Calc.
+  \\`:'  calc-grab-sum-down.  Grab a rectangle and sum the columns.
+  \\`_'  calc-grab-sum-across.  Grab a rectangle and sum the rows.
+  \\`Y'  calc-copy-to-buffer.  Copy a value from the stack into the editing 
buffer.
 
 For use with Embedded mode:
-  A  calc-embedded-activate.  Find and activate all :='s and =>'s in buffer.
-  D  calc-embedded-duplicate.  Make a copy of this formula and select it.
-  F  calc-embedded-new-formula.  Insert a new formula at current point.
-  N  calc-embedded-next.  Advance cursor to next known formula in buffer.
-  P  calc-embedded-previous.  Advance cursor to previous known formula.
-  U  calc-embedded-update-formula.  Re-evaluate formula at point.
-  \\=`  calc-embedded-edit.  Use calc-edit to edit formula at point.
+  \\`A'  calc-embedded-activate.  Find and activate all :='s and =>'s in 
buffer.
+  \\`D'  calc-embedded-duplicate.  Make a copy of this formula and select it.
+  \\`F'  calc-embedded-new-formula.  Insert a new formula at current point.
+  \\`N'  calc-embedded-next.  Advance cursor to next known formula in buffer.
+  \\`P'  calc-embedded-previous.  Advance cursor to previous known formula.
+  \\`U'  calc-embedded-update-formula.  Re-evaluate formula at point.
+  \\``'  calc-embedded-edit.  Use calc-edit to edit formula at point.
 
 Documentation:
-  I  calc-info.  Read the Calculator manual in the Emacs Info system.
-  T  calc-tutorial.  Run the Calculator Tutorial using the Emacs Info system.
-  S  calc-summary.  Read the Summary from the Calculator manual in Info.
+  \\`I'  calc-info.  Read the Calculator manual in the Emacs Info system.
+  \\`T'  calc-tutorial.  Run the Calculator Tutorial using the Emacs Info 
system.
+  \\`S'  calc-summary.  Read the Summary from the Calculator manual in Info.
 
 Miscellaneous:
-  L  calc-load-everything.  Load all parts of the Calculator into memory.
-  M  read-kbd-macro.  Read a region of keystroke names as a keyboard macro.
-  0  (zero) calc-reset.  Reset Calc stack and modes to default state.
+  \\`L'  calc-load-everything.  Load all parts of the Calculator into memory.
+  \\`M'  read-kbd-macro.  Read a region of keystroke names as a keyboard macro.
+  \\`0'  (zero) calc-reset.  Reset Calc stack and modes to default state.
 
-Press `*' twice (`C-x * *') to turn Calc on or off using the same
-Calc user interface as before (either C-x * C or C-x * K; initially C-x * C)."
+Press \\`*' twice (\\`C-x * *') to turn Calc on or off using the same
+Calc user interface as before (either \\`C-x * C' or \\`C-x * K'; initially 
\\`C-x * C')."
   (interactive "P")
   (calc-check-defines)
   (if calc-dispatch-help
diff --git a/lisp/calc/calc-prog.el b/lisp/calc/calc-prog.el
index dc2a086bbd..127f6340a1 100644
--- a/lisp/calc/calc-prog.el
+++ b/lisp/calc/calc-prog.el
@@ -678,7 +678,7 @@
   (or last-kbd-macro
       (error "No keyboard macro defined"))
   (setq calc-invocation-macro last-kbd-macro)
-  (message "Use `C-x * Z' to invoke this macro"))
+  (message (substitute-command-keys "Use \\`C-x * Z' to invoke this macro")))
 
 (defun calc-user-define-edit ()
   (interactive)  ; but no calc-wrapper!
@@ -1447,7 +1447,8 @@ Redefine the corresponding command."
           (let ((calc-kbd-push-level 0))
             (execute-kbd-macro (substring body 0 -2))))
        (let ((calc-kbd-push-level (1+ calc-kbd-push-level)))
-        (message "%s" "Saving modes; type Z' to restore")
+         ;; Avoid substituting the "'" character:
+         (message "%s" "Saving modes; type Z' to restore")
         (recursive-edit))))))
 
 (defun calc-kbd-pop ()
@@ -1949,7 +1950,7 @@ Redefine the corresponding command."
 
 ;; The variable math-exp-env is local to math-define-body, but is
 ;; used by math-define-exp, which is called (indirectly) by
-;; by math-define-body.
+;; math-define-body.
 (defvar math-exp-env)
 
 (defun math-define-body (body exp-env)
diff --git a/lisp/calc/calc-vec.el b/lisp/calc/calc-vec.el
index 3b8629b797..8d99f62a9b 100644
--- a/lisp/calc/calc-vec.el
+++ b/lisp/calc/calc-vec.el
@@ -647,9 +647,7 @@
 (defun calcFunc-rhead (vec)
   (if (and (Math-vectorp vec)
           (cdr vec))
-      (let ((vec (copy-sequence vec)))
-       (setcdr (nthcdr (- (length vec) 2) vec) nil)
-       vec)
+      (butlast vec)
     (calc-record-why 'vectorp vec)
     (list 'calcFunc-rhead vec)))
 
diff --git a/lisp/calc/calc-yank.el b/lisp/calc/calc-yank.el
index e0ed098b70..504ba5b40d 100644
--- a/lisp/calc/calc-yank.el
+++ b/lisp/calc/calc-yank.el
@@ -48,7 +48,7 @@
         (let ((stuff (calc-top-list n (- num n -1))))
           (calc-cursor-stack-index num)
            (unless calc-kill-line-numbering
-             (re-search-forward "\\=[0-9]+:\\s-+" (point-at-eol) t))
+             (re-search-forward "\\=[0-9]+:\\s-+" (line-end-position) t))
           (let ((first (point)))
             (calc-cursor-stack-index (- num n))
             (if (null nn)
@@ -150,7 +150,6 @@
 
 ;; This function uses calc-last-kill if possible to get an exact result,
 ;; otherwise it just parses the yanked string.
-;; Modified to use Emacs 19 extended concept of kill-ring. -- daveg 12/15/96
 ;;;###autoload
 (defun calc-yank-internal (radix thing-raw)
   "Internal common implementation for yank functions.
@@ -266,14 +265,16 @@ as well as set the contents of the Emacs register 
REGISTER to TEXT."
   "Return the CALCVAL portion of the contents of the Calc register REG,
 unless the TEXT portion doesn't match the contents of the Emacs register REG,
 in which case either return the contents of the Emacs register (if it is
-text) or nil."
+text or a number) or nil."
   (let ((cval (cdr (assq reg calc-register-alist)))
         (val (cdr (assq reg register-alist))))
-    (if (stringp val)
-        (if (and (stringp (car cval))
-                 (string= (car cval) val))
-            (cdr cval)
-          val))))
+    (cond
+     ((stringp val)
+      (if (and (stringp (car cval))
+               (string= (car cval) val))
+          (cdr cval)
+        val))
+     ((numberp val) (number-to-string val)))))
 
 (defun calc-copy-to-register (register start end &optional delete-flag)
   "Copy the lines in the region into register REGISTER.
@@ -303,10 +304,7 @@ Interactively, reads the register using 
`register-read-with-preview'."
 (defun calc-insert-register (register)
   "Insert the contents of register REGISTER.
 
-Interactively, reads the register using `register-read-with-preview'.
-
-Note that this command only works with Calc registers, and they
-have nothing to do with the Emacs-wide register mechanism."
+Interactively, reads the register using `register-read-with-preview'."
   (interactive (list (register-read-with-preview "Insert register: ")))
   (if (eq major-mode 'calc-mode)
       (let ((val (calc-get-register register)))
@@ -412,8 +410,8 @@ Interactively, reads the register using 
`register-read-with-preview'."
            (setq single t)
          (setq arg (prefix-numeric-value arg))
          (if (= arg 0)
-             (setq top (point-at-bol)
-                   bot (point-at-eol))
+              (setq top (line-beginning-position)
+                    bot (line-end-position))
            (save-excursion
              (setq top (point))
              (forward-line arg)
@@ -716,9 +714,9 @@ To cancel the edit, simply kill the *Calc Edit* buffer."
     (insert (propertize
              (concat
               (or title title "Calc Edit Mode. ")
-              (format-message "Press `C-c C-c'")
+              (substitute-command-keys "Press \\`C-c C-c'")
               (if allow-ret "" " or RET")
-              (format-message " to finish, `C-x k RET' to cancel.\n\n"))
+              (substitute-command-keys " to finish, \\`C-x k RET' to 
cancel.\n\n"))
              'font-lock-face 'italic 'read-only t 'rear-nonsticky t 
'front-sticky t))
     (setq-local calc-edit-top (point))))
 
diff --git a/lisp/calc/calc.el b/lisp/calc/calc.el
index b03dcfeb5b..6c21430b1b 100644
--- a/lisp/calc/calc.el
+++ b/lisp/calc/calc.el
@@ -412,7 +412,7 @@ and deleted by `calc-pop'."
 
 (defcustom calc-undo-length 100
   "The number of undo steps that will be preserved when Calc is quit."
-  :type 'integer)
+  :type 'natnum)
 
 (defcustom calc-highlight-selections-with-faces nil
   "If non-nil, use a separate face to indicate selected sub-formulas.
@@ -1959,12 +1959,8 @@ See calc-keypad for details."
   (or n (setq n 1))
   (or m (setq m 1))
   (calc-check-stack (+ n m -1))
-  (and (> n 0)
-       (let ((top (copy-sequence (nthcdr (+ m calc-stack-top -1)
-                                        calc-stack))))
-        (setcdr (nthcdr (1- n) top) nil)
-        (nreverse
-          (mapcar (lambda (x) (calc-get-stack-element x sel-mode)) top)))))
+  (nreverse (mapcar (lambda (x) (calc-get-stack-element x sel-mode))
+                    (take n (nthcdr (+ m calc-stack-top -1) calc-stack)))))
 
 (defun calc-top-list-n (&optional n m sel-mode)
   (mapcar #'math-check-complete
@@ -2291,9 +2287,7 @@ the United States."
              ((and (null n)
                    (eq (car-safe top) 'incomplete)
                    (> (length top) (if (eq (nth 1 top) 'intv) 3 2)))
-              (calc-pop-push-list 1 (let ((tt (copy-sequence top)))
-                                      (setcdr (nthcdr (- (length tt) 2) tt) 
nil)
-                                      (list tt))))
+              (calc-pop-push-list 1 (list (butlast top))))
              ((< nn 0)
               (if (and calc-any-selections
                        (calc-top-selected 1 (- nn)))
diff --git a/lisp/calendar/calendar.el b/lisp/calendar/calendar.el
index 9a77ae72d0..c1f176050c 100644
--- a/lisp/calendar/calendar.el
+++ b/lisp/calendar/calendar.el
@@ -211,7 +211,7 @@ If you change this variable directly (without using 
customize)
 after starting `calendar', you should call `calendar-redraw' to
 update the calendar display to reflect the change, otherwise
 movement commands will not work correctly."
-  :type 'integer
+  :type 'natnum
   ;; Change the initialize so that if you reload calendar.el, it will not
   ;; cause a redraw.
   :initialize 'custom-initialize-default
@@ -511,7 +511,7 @@ Then redraw the calendar, if necessary."
   :initialize #'custom-initialize-default
   :set (lambda (sym val)
          (calendar-set-layout-variable sym val 1))
-  :type 'integer
+  :type 'natnum
   :version "23.1")
 
 ;; FIXME calendar-month-column-width?
@@ -520,7 +520,7 @@ Then redraw the calendar, if necessary."
   :initialize #'custom-initialize-default
   :set (lambda (sym val)
          (calendar-set-layout-variable sym val 3))
-  :type 'integer
+  :type 'natnum
   :version "23.1")
 
 (defun calendar-day-header-construct (&optional width)
@@ -553,7 +553,7 @@ Must be at least one less than `calendar-column-width'."
   :initialize #'custom-initialize-default
   :set (lambda (sym val)
          (calendar-set-layout-variable sym val 2))
-  :type 'integer
+  :type 'natnum
   :version "23.1")
 
 (defcustom calendar-intermonth-header nil
@@ -565,7 +565,7 @@ See `calendar-intermonth-text'."
   :set (lambda (sym val)
          (set sym val)
          (calendar-redraw))
-  :type '(choice (const nil :tag "Nothing")
+  :type '(choice (const :value nil :tag "Nothing")
                  (string :tag "Fixed string")
                  (sexp :value
                        (propertize "WK" 'font-lock-face
@@ -597,7 +597,7 @@ See also `calendar-intermonth-header'."
   :set (lambda (sym val)
          (set sym val)
          (calendar-redraw))
-  :type '(choice (const nil :tag "Nothing")
+  :type '(choice (const :value nil :tag "Nothing")
                  (string :tag "Fixed string")
                  (sexp :value
                        (propertize
@@ -742,9 +742,9 @@ Setting this variable directly does not take effect (if the
 calendar package is already loaded).  Rather, use either
 \\[customize] or the function `calendar-set-date-style'."
   :version "23.1"
-  :type '(choice (const american :tag "Month/Day/Year")
-                 (const european :tag "Day/Month/Year")
-                 (const iso      :tag "Year/Month/Day"))
+  :type '(choice (const :value american :tag "American (Month/Day/Year)")
+                 (const :value european :tag "European (Day/Month/Year)")
+                 (const :value iso      :tag "ISO 8601 (Year/Month/Day)"))
   :initialize 'custom-initialize-default
   :set (lambda (_symbol value)
          (calendar-set-date-style value))
diff --git a/lisp/calendar/diary-lib.el b/lisp/calendar/diary-lib.el
index 48dbf33adf..98e91aaa75 100644
--- a/lisp/calendar/diary-lib.el
+++ b/lisp/calendar/diary-lib.el
@@ -100,11 +100,11 @@ are: `string', `symbol', `int', `tnil', `stringtnil'."
   :type '(repeat (list (regexp :tag "Regular expression")
                        (integer :tag "Sub-expression")
                        (symbol :tag "Attribute (e.g. :foreground)")
-                       (choice (const string :tag "A string")
-                               (const symbol :tag "A symbol")
-                               (const int :tag "An integer")
-                               (const tnil :tag "t or nil")
-                               (const stringtnil
+                       (choice (const :value string :tag "A string")
+                               (const :value symbol :tag "A symbol")
+                               (const :value int    :tag "An integer")
+                               (const :value tnil   :tag "t or nil")
+                               (const :value stringtnil
                                       :tag "A string, t, or nil"))))
   :group 'diary)
 
@@ -2465,8 +2465,8 @@ Fontify the region between BEG and END, quietly unless 
VERBOSE is non-nil."
       (setq end (line-beginning-position 2)))
   (font-lock-default-fontify-region beg end verbose))
 
-(defvar diary-fancy-overriding-map (make-sparse-keymap)
-  "Keymap overriding minor-mode maps in `diary-fancy-display-mode'.")
+(defvar-keymap diary-fancy-overriding-map
+  :doc "Keymap overriding minor-mode maps in `diary-fancy-display-mode'.")
 
 (define-derived-mode diary-fancy-display-mode special-mode
   "Diary"
diff --git a/lisp/calendar/icalendar.el b/lisp/calendar/icalendar.el
index 1a5a071e20..cf54293989 100644
--- a/lisp/calendar/icalendar.el
+++ b/lisp/calendar/icalendar.el
@@ -1144,7 +1144,8 @@ FExport diary data into iCalendar file: ")
                                      (cdr contents-n-summary))))
                       (setq result (concat result header contents alarm
                                            "\nEND:VEVENT")))
-                    (if (consp cns-cons-or-list)
+                    (if (and (consp cns-cons-or-list)
+                             (not (listp (cdr cns-cons-or-list))))
                         (list cns-cons-or-list)
                       cns-cons-or-list)))
           ;; handle errors
diff --git a/lisp/calendar/time-date.el b/lisp/calendar/time-date.el
index d19134db83..bbdcaa4db4 100644
--- a/lisp/calendar/time-date.el
+++ b/lisp/calendar/time-date.el
@@ -171,15 +171,21 @@ If DATE lacks timezone information, GMT is assumed."
              (error "Invalid date: %s" date)))))))))
 
 ;;;###autoload
-(defalias 'time-to-seconds 'float-time)
+(defalias 'time-to-seconds #'float-time)
 
 ;;;###autoload
-(defalias 'seconds-to-time 'time-convert)
+(defun seconds-to-time (seconds)
+  "Convert SECONDS to a proper time, like `current-time' would."
+  ;; FIXME: Should we (declare (obsolete time-convert "27.1")) ?
+  (time-convert seconds 'list))
 
 ;;;###autoload
 (defun days-to-time (days)
   "Convert DAYS into a time value."
-  (let ((time (time-convert (* 86400 days))))
+  ;; FIXME: We should likely just pass `t' to `time-convert'.
+  ;; All uses I could find in Emacs, GNU ELPA, and NonGNU ELPA can handle
+  ;; any valid time representation as return value.
+  (let ((time (time-convert (* 86400 days) 'list)))
     ;; Traditionally, this returned a two-element list if DAYS was an integer.
     ;; Keep that tradition if time-convert outputs timestamps in list form.
     (if (and (integerp days) (consp (cdr time)))
@@ -196,7 +202,7 @@ TIME should be either a time value or a date-time string."
   (time-subtract nil time))
 
 ;;;###autoload
-(define-obsolete-function-alias 'subtract-time 'time-subtract "26.1")
+(define-obsolete-function-alias 'subtract-time #'time-subtract "26.1")
 
 ;;;###autoload
 (defun date-to-day (date)
@@ -256,10 +262,10 @@ Returns a floating point number."
 ;;;###autoload
 (defun safe-date-to-time (date)
   "Parse a string DATE that represents a date-time and return a time value.
-If DATE is malformed, return a time value of zeros."
+If DATE is malformed, return a time value of zero."
   (condition-case ()
       (date-to-time date)
-    (error '(0 0))))
+    (error 0)))
 
 
 ;;;###autoload
@@ -590,7 +596,7 @@ TIME is modified and returned."
   time)
 
 (defun decoded-time-period (time)
-  "Interpret DECODED as a period and return its length in seconds.
+  "Interpret TIME as a period and return its length in seconds.
 For computational purposes, years are 365 days long and months
 are 30 days long."
   (+ (if (consp (decoded-time-second time))
diff --git a/lisp/calendar/timeclock.el b/lisp/calendar/timeclock.el
index 1c6a557a0d..6b6cc517a2 100644
--- a/lisp/calendar/timeclock.el
+++ b/lisp/calendar/timeclock.el
@@ -86,7 +86,7 @@
 
 (defcustom timeclock-workday (* 8 60 60)
   "The length of a work period in seconds."
-  :type 'integer)
+  :type 'natnum)
 
 (defvar timeclock--previous-workday nil)
 
@@ -1247,7 +1247,7 @@ HTML-P is non-nil, HTML markup is added."
               (time-out (vector (list t) (list t) (list t) (list t) (list t)))
               (breaks   (vector (list t) (list t) (list t) (list t) (list t)))
               (workday  (vector (list t) (list t) (list t) (list t) (list t)))
-              (lengths  (vector '(0 0) thirty-days-ago three-months-ago
+              (lengths  (vector 0 thirty-days-ago three-months-ago
                                 six-months-ago one-year-ago)))
          ;; collect statistics from complete timelog
          (dolist (day day-list)
diff --git a/lisp/cedet/cedet-global.el b/lisp/cedet/cedet-global.el
index 6a147bf430..a2d8bae36b 100644
--- a/lisp/cedet/cedet-global.el
+++ b/lisp/cedet/cedet-global.el
@@ -133,7 +133,7 @@ DIR defaults to `default-directory'."
       (goto-char (point-min))
       (when (not (eobp))
        (file-name-as-directory
-        (buffer-substring (point) (point-at-eol)))))))
+         (buffer-substring (point) (line-end-position)))))))
 
 (defun cedet-gnu-global-version-check (&optional noerror)
   "Check the version of the installed GNU Global command.
diff --git a/lisp/cedet/cedet.el b/lisp/cedet/cedet.el
index e6befb10e9..c33ac85072 100644
--- a/lisp/cedet/cedet.el
+++ b/lisp/cedet/cedet.el
@@ -25,15 +25,12 @@
 ;;; Commentary:
 
 ;;; Code:
-;;
-;; This file depends on the major components of CEDET, so that you can
-;; load them all by doing (require 'cedet).  This is mostly for
-;; compatibility with the upstream, stand-alone CEDET distribution.
 
 (declare-function inversion-find-version "inversion")
 
 (defconst cedet-version "2.0"
   "Current version of CEDET.")
+(make-obsolete-variable 'cedet-version 'emacs-version "29.1")
 
 (defconst cedet-packages
   `(
@@ -45,6 +42,7 @@
     (ede           "1.2"           nil       "ede"         )
     )
   "Table of CEDET packages to install.")
+(make-obsolete-variable 'cedet-packages 'package-built-in-p "29.1")
 
 (defvar cedet-menu-map ;(make-sparse-keymap "CEDET menu")
   (let ((map (make-sparse-keymap "CEDET menu")))
diff --git a/lisp/cedet/data-debug.el b/lisp/cedet/data-debug.el
index 0edc853edd..605dc9fa19 100644
--- a/lisp/cedet/data-debug.el
+++ b/lisp/cedet/data-debug.el
@@ -854,7 +854,6 @@ If PARENT is non-nil, it is somehow related as a parent to 
thing."
     table)
   "Syntax table used in data-debug macro buffers.")
 
-(define-obsolete-variable-alias 'data-debug-map 'data-debug-mode-map "24.1")
 (defvar data-debug-mode-map
   (let ((km (make-sparse-keymap)))
     (suppress-keymap km)
@@ -903,14 +902,14 @@ If PARENT is non-nil, it is somehow related as a parent 
to thing."
   (interactive)
   (forward-line 1)
   (beginning-of-line)
-  (skip-chars-forward "- *><[]" (point-at-eol)))
+  (skip-chars-forward "- *><[]" (line-end-position)))
 
 (defun data-debug-prev ()
   "Go to the previous line in the Ddebug buffer."
   (interactive)
   (forward-line -1)
   (beginning-of-line)
-  (skip-chars-forward "- *><[]" (point-at-eol)))
+  (skip-chars-forward "- *><[]" (line-end-position)))
 
 (defun data-debug-next-expando ()
   "Go to the next line in the Ddebug buffer.
@@ -997,7 +996,7 @@ Do nothing if already contracted."
           (data-debug-current-line-expanded-p))
       (data-debug-contract-current-line)
     (data-debug-expand-current-line))
-  (skip-chars-forward "- *><[]" (point-at-eol)))
+  (skip-chars-forward "- *><[]" (line-end-position)))
 
 (defun data-debug-expand-or-contract-mouse (event)
   "Expand or contract anything at event EVENT."
@@ -1028,11 +1027,9 @@ Do nothing if already contracted."
 (defun data-debug-edebug-expr (expr)
   "Dump out the contents of some expression EXPR in edebug with ddebug."
   (interactive
-   (list (let ((minibuffer-completing-symbol t))
-          (read-from-minibuffer "Eval: "
-                                nil read-expression-map t
-                                'read-expression-history))
-        ))
+   (list (read-from-minibuffer "Eval: "
+                               nil read-expression-map t
+                               'read-expression-history)))
   (let ((v (eval expr t)))
     (if (not v)
        (message "Expression %s is nil." expr)
@@ -1043,10 +1040,9 @@ Do nothing if already contracted."
 If the result is something simple, show it in the echo area.
 If the result is a list or vector, then use the data debugger to display it."
   (interactive
-   (list (let ((minibuffer-completing-symbol t))
-          (read-from-minibuffer "Eval: "
-                                nil read-expression-map t
-                                'read-expression-history))))
+   (list (read-from-minibuffer "Eval: "
+                               nil read-expression-map t
+                               'read-expression-history)))
 
   (let (result)
     (if (null eval-expression-debug-on-error)
diff --git a/lisp/cedet/ede.el b/lisp/cedet/ede.el
index 4ea14e33c5..e6bfd0b1e8 100644
--- a/lisp/cedet/ede.el
+++ b/lisp/cedet/ede.el
@@ -1,10 +1,10 @@
 ;;; ede.el --- Emacs Development Environment gloss  -*- lexical-binding: t; -*-
 
-;; Copyright (C) 1998-2005, 2007-2022 Free Software Foundation, Inc.
+;; Copyright (C) 1998-2022 Free Software Foundation, Inc.
 
 ;; Author: Eric M. Ludlam <zappo@gnu.org>
 ;; Keywords: project, make
-;; Version: 1.2
+;; Version: 2.0
 
 ;; This file is part of GNU Emacs.
 
@@ -39,6 +39,8 @@
 ;;
 ;;  (global-ede-mode t)
 
+;;; Code:
+
 (require 'cedet)
 (require 'cl-lib)
 (require 'eieio)
@@ -66,10 +68,11 @@
 
 (defconst ede-version "2.0"
   "Current version of the Emacs EDE.")
+(make-obsolete-variable 'ede-version 'emacs-version "29.1")
 
-;;; Code:
 (defun ede-version ()
   "Display the current running version of EDE."
+  (declare (obsolete emacs-version "29.1"))
   (interactive) (message "EDE %s" ede-version))
 
 (defgroup ede nil
diff --git a/lisp/cedet/ede/auto.el b/lisp/cedet/ede/auto.el
index 7af9987de1..7e3cac616f 100644
--- a/lisp/cedet/ede/auto.el
+++ b/lisp/cedet/ede/auto.el
@@ -234,6 +234,7 @@ type is required and the load function used.")
     (display-buffer b)
  ))
 
+;;;###autoload
 (defun ede-add-project-autoload (projauto &optional flag)
   "Add PROJAUTO, an EDE autoload definition to `ede-project-class-files'.
 Optional argument FLAG indicates how this autoload should be
diff --git a/lisp/cedet/ede/autoconf-edit.el b/lisp/cedet/ede/autoconf-edit.el
index faf50edaa1..78edea1da8 100644
--- a/lisp/cedet/ede/autoconf-edit.el
+++ b/lisp/cedet/ede/autoconf-edit.el
@@ -383,16 +383,16 @@ Optional argument BODY is the code to execute which edits 
the autoconf file."
     (beginning-of-line)
     (let* ((end-of-cmd
            (save-excursion
-             (if (re-search-forward "(" (point-at-eol) t)
+              (if (re-search-forward "(" (line-end-position) t)
                  (progn
                    (forward-char -1)
                    (forward-sexp 1)
                    (point))
                ;; Else, just return EOL.
-               (point-at-eol))))
+                (line-end-position))))
           (cnt 0))
       (save-restriction
-       (narrow-to-region (point-at-bol) end-of-cmd)
+        (narrow-to-region (line-beginning-position) end-of-cmd)
        (condition-case nil
            (progn
              (down-list 1)
@@ -417,7 +417,7 @@ INDEX starts at 1."
   (down-list 1)
   (re-search-forward ", ?" nil nil (1- index))
   (let ((end (save-excursion
-              (re-search-forward ",\\|)" (point-at-eol))
+               (re-search-forward ",\\|)" (line-end-position))
               (forward-char -1)
               (point))))
     (setq autoconf-deleted-text (buffer-substring (point) end))
diff --git a/lisp/cedet/ede/base.el b/lisp/cedet/ede/base.el
index 9d23909d62..9182fcd5ac 100644
--- a/lisp/cedet/ede/base.el
+++ b/lisp/cedet/ede/base.el
@@ -141,7 +141,7 @@ For some project types, this will be the file that stores 
the project configurat
 In other projects types, this file is merely a unique identifier to this type 
of project.")
    (rootproject ; :initarg - no initarg, don't save this slot!
     :initform nil
-    :type (or null ede-project-placeholder-child)
+    :type (or null ede-project-placeholder)
     :documentation "Pointer to our root project.")
    )
   "Placeholder object for projects not loaded into memory.
@@ -171,7 +171,7 @@ For Automake based projects, each directory is treated as a 
project.")
            :label "Local Targets"
            :group (targets)
            :documentation "List of top level targets in this project.")
-   (locate-obj :type (or null ede-locate-base-child)
+   (locate-obj :type (or null ede-locate-base)
               :documentation
               "A locate object to use as a backup to `ede-expand-filename'.")
    (tool-cache :initarg :tool-cache
@@ -204,7 +204,7 @@ This is a URL to be sent to a web site for documentation.")
                       :group name
                       :documentation
                       "A directory where web pages can be found by Emacs.
-For remote locations use a path compatible with ange-ftp or EFS.
+For remote locations use a path compatible with ange-ftp.
 You can also use TRAMP for use with rcp & scp.")
    (web-site-file :initarg :web-site-file
                  :initform ""
@@ -214,7 +214,7 @@ You can also use TRAMP for use with rcp & scp.")
                  :documentation
                   "A file which contains the website for this project.
 This file can be relative to slot `web-site-directory'.
-This can be a local file, use ange-ftp, EFS, or TRAMP.")
+This can be a local file, use ange-ftp or TRAMP.")
    (ftp-site :initarg :ftp-site
             :initform ""
             :type string
diff --git a/lisp/cedet/ede/config.el b/lisp/cedet/ede/config.el
index 529b96f2b0..8c4f52647b 100644
--- a/lisp/cedet/ede/config.el
+++ b/lisp/cedet/ede/config.el
@@ -65,7 +65,7 @@
 (defclass ede-extra-config (eieio-persistent)
   ((extension :initform ".ede")
    (file-header-line :initform ";; EDE Project Configuration")
-   (project :type ede-project-with-config-child
+   (project :type ede-project-with-config
            :documentation
            "The project this config is bound to.")
    (ignored-file :initform nil
@@ -102,7 +102,7 @@ initialize the :file slot of the persistent baseclass.")
     :documentation
     "The class of the configuration used by this project.")
    (config :initform nil
-          :type (or null ede-extra-config-child)
+          :type (or null ede-extra-config)
           :documentation
           "The configuration object for this project.")
    )
diff --git a/lisp/cedet/ede/custom.el b/lisp/cedet/ede/custom.el
index 2d4f408e96..0854c8cc47 100644
--- a/lisp/cedet/ede/custom.el
+++ b/lisp/cedet/ede/custom.el
@@ -35,7 +35,9 @@
 (require 'ede)
 (eval-when-compile (require 'eieio-custom))
 
-(defvar eieio-ede-old-variables nil
+(define-obsolete-variable-alias 'ede-eieio-old-variables
+  'eieio-ede-old-variables "29.1")
+(defvar ede-eieio-old-variables nil
   "The old variables for a project.")
 
 ;;; Customization Commands
@@ -50,7 +52,7 @@
   (let* ((ov (oref (ede-current-project) local-variables))
         (cp (ede-current-project)))
     (ede-customize cp)
-    (setq-local eieio-ede-old-variables ov)))
+    (setq-local ede-eieio-old-variables ov)))
 
 ;;;###autoload
 (defalias 'customize-project #'ede-customize-project)
@@ -178,9 +180,9 @@ OBJ is the target object to customize."
 ;; These hooks are used when finishing up a customization.
 (cl-defmethod eieio-done-customizing ((proj ede-project))
   "Call this when a user finishes customizing PROJ."
-  (let ((ov eieio-ede-old-variables)
+  (let ((ov ede-eieio-old-variables)
        (nv (oref proj local-variables)))
-    (setq eieio-ede-old-variables nil)
+    (setq ede-eieio-old-variables nil)
     (while ov
       (if (not (assoc (car (car ov)) nv))
          (save-excursion
diff --git a/lisp/cedet/ede/emacs.el b/lisp/cedet/ede/emacs.el
index 5a23f504f7..c83e687367 100644
--- a/lisp/cedet/ede/emacs.el
+++ b/lisp/cedet/ede/emacs.el
@@ -59,7 +59,7 @@ Return a tuple of ( EMACSNAME . VERSION )."
            (file-exists-p (setq configure_ac "configure.in")))
        (insert-file-contents configure_ac)
        (goto-char (point-min))
-       (re-search-forward "AC_INIT(\\(?:GNU 
\\)?[eE]macs,\\s-*\\([0-9.]+\\)\\s-*[,)]")
+       (re-search-forward "AC_INIT(\\[?\\(?:GNU 
\\)?[eE]macs]?,\\s-*\\[?\\([0-9.]+\\)]?\\s-*[,)]")
        (setq ver (match-string 1))
        )
        )
@@ -80,7 +80,6 @@ ROOTPROJ is nil, since there is only one project."
   ;; Doesn't already exist, so let's make one.
   (let* ((vertuple (ede-emacs-version dir)))
     (ede-emacs-project
-     (car vertuple)
      :name (car vertuple)
      :version (cdr vertuple)
      :directory (file-name-as-directory dir)
diff --git a/lisp/cedet/ede/files.el b/lisp/cedet/ede/files.el
index b8acb192c1..e44ddea32f 100644
--- a/lisp/cedet/ede/files.el
+++ b/lisp/cedet/ede/files.el
@@ -340,7 +340,7 @@ Optional FORCE means to ignore the hash of known 
directories."
 ;;
 ;; These utilities will identify the "toplevel" of a project.
 ;;
-;; NOTE: These two -toplevel- functions return a directory even though
+;; NOTE: This -toplevel- function returns a directory even though
 ;;       the function name implies a project.
 
 (defun ede-toplevel-project (dir)
@@ -365,8 +365,6 @@ If DIR is not part of a project, return nil."
 
      (t nil))))
 
-(defalias 'ede-toplevel-project-or-nil #'ede-toplevel-project)
-
 ;;; DIRECTORY CONVERSION STUFF
 ;;
 (cl-defmethod ede-convert-path ((this ede-project) path)
@@ -535,6 +533,7 @@ Argument DIR is the directory to trim upwards."
        nil
       fnd)))
 
+(define-obsolete-function-alias 'ede-toplevel-project-or-nil 
#'ede-toplevel-project "29.1")
 
 (provide 'ede/files)
 
diff --git a/lisp/cedet/ede/pmake.el b/lisp/cedet/ede/pmake.el
index 9a913109f0..7739115b31 100644
--- a/lisp/cedet/ede/pmake.el
+++ b/lisp/cedet/ede/pmake.el
@@ -566,7 +566,7 @@ Argument THIS is the target that should insert stuff."
            (cond ((eq (cdr sv) 'share)
                   ;; This variable may be shared between multiple targets.
                   (if (re-search-backward (concat "\\$(" (car sv) ")")
-                                          (point-at-bol) t)
+                                           (line-beginning-position) t)
                       ;; If its already in the dist target, then skip it.
                       nil
                     (setq sv (car sv))))
diff --git a/lisp/cedet/ede/proj-elisp.el b/lisp/cedet/ede/proj-elisp.el
index 7c56ca1993..594d8f1c29 100644
--- a/lisp/cedet/ede/proj-elisp.el
+++ b/lisp/cedet/ede/proj-elisp.el
@@ -272,7 +272,8 @@ is found, such as a `-version' variable, or the standard 
header."
            (let ((path (match-string 1)))
              (if (string= path "nil")
                  nil
-               (delete-region (point-at-bol) (point-at-bol 2)))))))))
+                (delete-region (line-beginning-position)
+                               (line-beginning-position 2)))))))))
 
 ;;;
 ;; Autoload generators
diff --git a/lisp/cedet/ede/project-am.el b/lisp/cedet/ede/project-am.el
index 544e39b872..de6936ad1a 100644
--- a/lisp/cedet/ede/project-am.el
+++ b/lisp/cedet/ede/project-am.el
@@ -911,7 +911,7 @@ Kill the Configure buffer if it was not already in a 
buffer."
     (goto-char (point-min))
     (when (re-search-forward (concat "^" (regexp-quote var) "\\s-*=\\s-*")
                             nil t)
-      (buffer-substring-no-properties (point) (point-at-eol)))))
+      (buffer-substring-no-properties (point) (line-end-position)))))
 
 (defun project-am-extract-package-info (dir)
   "Extract the package information for directory DIR."
diff --git a/lisp/cedet/ede/speedbar.el b/lisp/cedet/ede/speedbar.el
index f99a1d114b..f45c070539 100644
--- a/lisp/cedet/ede/speedbar.el
+++ b/lisp/cedet/ede/speedbar.el
@@ -62,7 +62,7 @@
 (defvar ede-speedbar-menu
   '([ "Compile" ede-speedbar-compile-line t]
     [ "Compile Project" ede-speedbar-compile-project
-      (ede-project-child-p (speedbar-line-token)) ]
+      (cl-typep (speedbar-line-token) 'ede-project) ]
     "---"
     [ "Edit File/Tag" speedbar-edit-line
       (not (eieio-object-p (speedbar-line-token)))]
@@ -79,7 +79,7 @@
       (eieio-object-p (speedbar-line-token)) ]
     [ "Edit Project File" ede-speedbar-edit-projectfile t]
     [ "Make Distribution" ede-speedbar-make-distribution
-      (ede-project-child-p (speedbar-line-token)) ]
+      (cl-typep (speedbar-line-token) 'ede-project) ]
     )
   "Menu part in easymenu format used in speedbar while browsing objects.")
 
@@ -175,7 +175,7 @@ Argument DIR is the directory from which to derive the list 
of objects."
     (beginning-of-line)
     (looking-at "^\\([0-9]+\\):")
     (let ((depth (string-to-number (match-string 1))))
-      (while (not (re-search-forward "[]] [^ ]" (point-at-eol) t))
+      (while (not (re-search-forward "[]] [^ ]" (line-end-position) t))
        (re-search-backward (format "^%d:" (1- depth)))
        (setq depth (1- depth)))
       (speedbar-line-token))))
diff --git a/lisp/cedet/ede/system.el b/lisp/cedet/ede/system.el
index 2da16b37d7..b4fc95c607 100644
--- a/lisp/cedet/ede/system.el
+++ b/lisp/cedet/ede/system.el
@@ -133,7 +133,7 @@ Download tramp, and use /r:machine: for names on remote 
sites w/out FTP access."
 (defun ede-vc-project-directory ()
   "Run `vc-dir' on the current project."
   (interactive)
-  (let ((top (ede-toplevel-project-or-nil default-directory)))
+  (let ((top (ede-toplevel-project default-directory)))
     (vc-dir top nil)))
 
 (provide 'ede/system)
diff --git a/lisp/cedet/pulse.el b/lisp/cedet/pulse.el
index f7af10887c..9941f2a0cb 100644
--- a/lisp/cedet/pulse.el
+++ b/lisp/cedet/pulse.el
@@ -202,7 +202,7 @@ If POINT is nil or missing, the current point is used 
instead.
 Optional argument FACE specifies the face to do the highlighting."
   (save-excursion
     (goto-char (or point (point)))
-    (let ((start (point-at-bol))
+    (let ((start (line-beginning-position))
           (end (save-excursion
                  (end-of-line)
                  (when (not (eobp))
diff --git a/lisp/cedet/semantic.el b/lisp/cedet/semantic.el
index 78002dd8ab..3166279de4 100644
--- a/lisp/cedet/semantic.el
+++ b/lisp/cedet/semantic.el
@@ -34,6 +34,8 @@
 ;; menu).  To enable it at startup, put (semantic-mode 1) in your init
 ;; file.
 
+;;; Code:
+
 (require 'cedet)
 (require 'semantic/tag)
 (require 'semantic/lex)
@@ -41,6 +43,7 @@
 
 (defvar semantic-version "2.2"
   "Current version of Semantic.")
+(make-obsolete-variable 'semantic-version 'emacs-version "29.1")
 
 (declare-function inversion-test "inversion")
 (declare-function semanticdb-load-ebrowse-caches "semantic/db-ebrowse")
@@ -73,9 +76,6 @@ introduced."
 
 (require 'semantic/fw)
 
-;;; Code:
-;;
-
 ;;; Variables and Configuration
 ;;
 (defvar-local semantic--parse-table nil
diff --git a/lisp/cedet/semantic/bovine.el b/lisp/cedet/semantic/bovine.el
index 1e52b1f850..a6cf8d89a4 100644
--- a/lisp/cedet/semantic/bovine.el
+++ b/lisp/cedet/semantic/bovine.el
@@ -143,14 +143,14 @@ list of semantic tokens found."
                         cvl nil     ;re-init the collected value list.
                         lte (car matchlist) ;Get the local matchlist entry.
                         )
-                  (if (or (byte-code-function-p (car lte))
+                  (if (or (compiled-function-p (car lte))
                           (listp (car lte)))
                       ;; In this case, we have an EMPTY match!  Make
                       ;; stuff up.
                       (setq cvl (list nil))))
 
                 (while (and lte
-                            (not (byte-code-function-p (car lte)))
+                            (not (compiled-function-p (car lte)))
                             (not (listp (car lte))))
 
                   ;; GRAMMAR SOURCE DEBUGGING!
diff --git a/lisp/cedet/semantic/bovine/c.el b/lisp/cedet/semantic/bovine/c.el
index ee1cbcad4d..d4ce20589e 100644
--- a/lisp/cedet/semantic/bovine/c.el
+++ b/lisp/cedet/semantic/bovine/c.el
@@ -437,8 +437,8 @@ I think it just returns t/nil dependent on if VAR has been 
defined."
         (progn
           (semantic-push-parser-warning
           (format "Skip %s" (buffer-substring-no-properties
-                             (point-at-bol) (point-at-eol)))
-          (point-at-bol) (point-at-eol))
+                              (line-beginning-position) (line-end-position)))
+           (line-beginning-position) (line-end-position))
           nil)
       t)))
 
@@ -501,8 +501,10 @@ code to parse."
 
        ;; The if indicates to skip this preprocessor section
        (let () ;; (pt nil)
-         (semantic-push-parser-warning (format "Skip %s" 
(buffer-substring-no-properties (point-at-bol) (point-at-eol)))
-                                       (point-at-bol) (point-at-eol))
+          (semantic-push-parser-warning (format "Skip %s" 
(buffer-substring-no-properties
+                                                           
(line-beginning-position)
+                                                           
(line-end-position)))
+                                        (line-beginning-position) 
(line-end-position))
          (beginning-of-line)
          ;; (setq pt (point))
          ;; This skips only a section of a conditional.  Once that section
diff --git a/lisp/cedet/semantic/complete.el b/lisp/cedet/semantic/complete.el
index 6a09adca32..dc270603a0 100644
--- a/lisp/cedet/semantic/complete.el
+++ b/lisp/cedet/semantic/complete.el
@@ -311,11 +311,43 @@ HISTORY is a symbol representing a variable to story the 
history in."
 (defvar semantic-complete-current-matched-tag nil
   "Variable used to pass the tags being matched to the prompt.")
 
-;; semantic-displayer-focus-abstract-child-p is part of the
-;; semantic-displayer-focus-abstract class, defined later in this
-;; file.
-(declare-function semantic-displayer-focus-abstract-child-p "semantic/complete"
-                 t t)
+
+
+;; Abstract baseclass for any displayer which supports focus
+
+(defclass semantic-displayer-abstract ()
+  ((table :type (or null semanticdb-find-result-with-nil)
+         :initform nil
+         :protection :protected
+         :documentation "List of tags this displayer is showing.")
+   (last-prefix :type string
+               :protection :protected
+               :documentation "Prefix associated with slot `table'.")
+   )
+  "Abstract displayer baseclass.
+Manages the display of some number of tags.
+Provides the basics for a displayer, including interacting with
+a collector, and tracking tables of completion to display."
+  :abstract t)
+
+(defclass semantic-displayer-focus-abstract (semantic-displayer-abstract)
+  ((focus :type number
+         :protection :protected
+         :documentation "A tag index from `table' which has focus.
+Multiple calls to the display function can choose to focus on a
+given tag, by highlighting its location.")
+   (find-file-focus
+    :allocation :class
+    :initform nil
+    :documentation
+    "Non-nil if focusing requires a tag's buffer be in memory.")
+   )
+  "Abstract displayer supporting `focus'.
+A displayer which has the ability to focus in on one tag.
+Focusing is a way of differentiating among multiple tags
+which have the same name."
+  :abstract t)
+
 
 (defun semantic-complete-current-match ()
   "Calculate a match from the current completion environment.
@@ -346,7 +378,7 @@ Return value can be:
        ((setq matchlist (semantic-collector-current-exact-match collector))
        (if (= (semanticdb-find-result-length matchlist) 1)
            (setq answer (semanticdb-find-result-nth-in-buffer matchlist 0))
-         (if (semantic-displayer-focus-abstract-child-p displayer)
+         (if (cl-typep displayer 'semantic-displayer-focus-abstract)
              ;; For focusing displayers, we can claim this is
              ;; not unique.  Multiple focuses can choose the correct
              ;; one.
@@ -1011,20 +1043,14 @@ Output must be in semanticdb Find result format."
                           (oref obj last-prefix)))
         (completionlist
          (cond ((or same-prefix-p
-                    (and last-prefix (eq (compare-strings
-                                          last-prefix 0 nil
-                                          prefix 0 (length last-prefix))
-                                         t)))
+                    (and last-prefix (string-prefix-p last-prefix prefix t)))
                 ;; We have the same prefix, or last-prefix is a
                 ;; substring of the of new prefix, in which case we are
                 ;; refining our symbol so just re-use cache.
                 (oref obj last-all-completions))
                ((and last-prefix
                      (> (length prefix) 1)
-                     (eq (compare-strings
-                          prefix 0 nil
-                          last-prefix 0 (length prefix))
-                         t))
+                     (string-prefix-p prefix last-prefix t))
                   ;; The new prefix is a substring of the old
                   ;; prefix, and it's longer than one character.
                   ;; Perform a full search to pull in additional
@@ -1307,21 +1333,6 @@ Uses semanticdb for searching all tags in the current 
project."
 ;; * semantic-displayer-scroll-request
 ;; * semantic-displayer-focus-request
 
-(defclass semantic-displayer-abstract ()
-  ((table :type (or null semanticdb-find-result-with-nil)
-         :initform nil
-         :protection :protected
-         :documentation "List of tags this displayer is showing.")
-   (last-prefix :type string
-               :protection :protected
-               :documentation "Prefix associated with slot `table'.")
-   )
-  "Abstract displayer baseclass.
-Manages the display of some number of tags.
-Provides the basics for a displayer, including interacting with
-a collector, and tracking tables of completion to display."
-  :abstract t)
-
 (define-obsolete-function-alias 'semantic-displayor-cleanup
   #'semantic-displayer-cleanup "27.1")
 (cl-defmethod semantic-displayer-cleanup ((_obj semantic-displayer-abstract))
@@ -1413,24 +1424,7 @@ to click on the items to aid in completion.")
     )
   )
 
-;;; Abstract baseclass for any displayer which supports focus
-(defclass semantic-displayer-focus-abstract (semantic-displayer-abstract)
-  ((focus :type number
-         :protection :protected
-         :documentation "A tag index from `table' which has focus.
-Multiple calls to the display function can choose to focus on a
-given tag, by highlighting its location.")
-   (find-file-focus
-    :allocation :class
-    :initform nil
-    :documentation
-    "Non-nil if focusing requires a tag's buffer be in memory.")
-   )
-  "Abstract displayer supporting `focus'.
-A displayer which has the ability to focus in on one tag.
-Focusing is a way of differentiating among multiple tags
-which have the same name."
-  :abstract t)
+;;; Methods for any displayer which supports focus
 
 (define-obsolete-function-alias 'semantic-displayor-next-action
   #'semantic-displayer-next-action "27.1")
@@ -1638,8 +1632,10 @@ This will not happen if you directly set this variable 
via `setq'."
   :set (lambda (sym var)
          (set-default sym var)
          (when (boundp 'x-max-tooltip-size)
-           (setcdr x-max-tooltip-size (max (1+ var) (cdr 
x-max-tooltip-size))))))
-
+           (if (not (consp x-max-tooltip-size))
+               (setq x-max-tooltip-size '(80 . 40)))
+           (setcdr x-max-tooltip-size
+                   (max (1+ var) (cdr x-max-tooltip-size))))))
 
 (defclass semantic-displayer-tooltip (semantic-displayer-traditional)
   ((mode :initarg :mode
diff --git a/lisp/cedet/semantic/db-file.el b/lisp/cedet/semantic/db-file.el
index d00ab47ce6..e2c9d618ba 100644
--- a/lisp/cedet/semantic/db-file.el
+++ b/lisp/cedet/semantic/db-file.el
@@ -29,7 +29,7 @@
 (require 'cedet-files)
 (require 'data-debug)
 
-(defvar semanticdb-file-version semantic-version
+(defvar semanticdb-file-version "2.2"
   "Version of semanticdb we are writing files to disk with.")
 (defvar semanticdb-file-incompatible-version "1.4"
   "Version of semanticdb we are not reverse compatible with.")
diff --git a/lisp/cedet/semantic/db-typecache.el 
b/lisp/cedet/semantic/db-typecache.el
index 38caac2292..efc1ab2c5f 100644
--- a/lisp/cedet/semantic/db-typecache.el
+++ b/lisp/cedet/semantic/db-typecache.el
@@ -362,7 +362,7 @@ a master list."
          ;; don't include ourselves in this crazy list.
          (when (and i (not (eq i table))
                     ;; @todo - This eieio fcn can be slow!  Do I need it?
-                    ;; (semanticdb-table-child-p i)
+                    ;; (cl-typep i 'semanticdb-table)
                     )
            (setq incstream
                  (semanticdb-typecache-merge-streams
diff --git a/lisp/cedet/semantic/db.el b/lisp/cedet/semantic/db.el
index 82785ec6d2..ff62f53d3c 100644
--- a/lisp/cedet/semantic/db.el
+++ b/lisp/cedet/semantic/db.el
@@ -115,11 +115,13 @@ for a new table not associated with a buffer."
   "Return a nil, meaning abstract table OBJ is not in a buffer."
   nil)
 
-(cl-defmethod semanticdb-get-buffer ((_obj semanticdb-abstract-table))
-  "Return a buffer associated with OBJ.
+(cl-defgeneric semanticdb-get-buffer (_obj)
+  "Return a buffer associated with semanticdb table OBJ.
 If the buffer is not in memory, load it with `find-file-noselect'."
   nil)
 
+;; FIXME: Should we merge `semanticdb-get-buffer' and
+;; `semantic-tag-parent-buffer'?
 ;; This generic method allows for sloppier coding.  Many
 ;; functions treat "table" as something that could be a buffer,
 ;; file name, or other.  This makes use of table more robust.
@@ -271,6 +273,9 @@ For C/C++, the C preprocessor macros can be saved here.")
    )
   "A single table of tags derived from file.")
 
+(cl-defmethod semantic-tag-parent-buffer ((parent semanticdb-table))
+  (semanticdb-get-buffer parent))       ;FIXME: η-redex!
+
 (cl-defmethod semanticdb-in-buffer-p ((obj semanticdb-table))
   "Return a buffer associated with OBJ.
 If the buffer is in memory, return that buffer."
@@ -609,7 +614,7 @@ The file associated with OBJ does not need to be in a 
buffer."
        (or (not (slot-boundp obj 'tags))
            ;; (not (oref obj tags)) -->  not needed anymore?
            (/= (or (oref obj fsize) 0) actualsize)
-           (not (equal (oref obj lastmodtime) actualmod))
+           (not (time-equal-p (oref obj lastmodtime) actualmod))
            )
        ))))
 
diff --git a/lisp/cedet/semantic/edit.el b/lisp/cedet/semantic/edit.el
index 76230d438a..4679500ed9 100644
--- a/lisp/cedet/semantic/edit.el
+++ b/lisp/cedet/semantic/edit.el
@@ -610,7 +610,7 @@ This function is for internal use by 
`semantic-edits-incremental-parser'."
                (setq last-cond "Beginning of buffer")
                 (setq parse-start
                       ;; Don't worry about parents since
-                      ;; there there would be an exact
+                      ;; there would be an exact
                       ;; match in the tag list otherwise
                       ;; and the routine would fail.
                       (point-min)
diff --git a/lisp/cedet/semantic/grammar.el b/lisp/cedet/semantic/grammar.el
index 74d4a229fa..d42022e042 100644
--- a/lisp/cedet/semantic/grammar.el
+++ b/lisp/cedet/semantic/grammar.el
@@ -252,7 +252,7 @@ That is tag names plus names defined in tag attribute 
`:rest'."
               (skip-chars-backward "\r\n\t")
               ;; If a grammar footer is found, skip it.
               (re-search-backward "^;;;\\s-+\\S-+\\s-+ends here"
-                                  (point-at-bol) t)
+                                  (line-beginning-position) t)
               (skip-chars-backward "\r\n\t")
               (point)))
            "\n"))
@@ -1123,8 +1123,6 @@ END is the limit of the search."
 ;;;; Define major mode
 ;;;;
 
-(define-obsolete-variable-alias 'semantic-grammar-syntax-table
-  'semantic-grammar-mode-syntax-table "24.1")
 (defvar semantic-grammar-mode-syntax-table
   (let ((table (make-syntax-table (standard-syntax-table))))
     (modify-syntax-entry ?\: "."     table) ;; COLON
@@ -1197,8 +1195,6 @@ END is the limit of the search."
   semantic-grammar-mode-keywords-1
   "Font Lock keywords used to highlight Semantic grammar buffers.")
 
-(define-obsolete-variable-alias 'semantic-grammar-map
-  'semantic-grammar-mode-map "24.1")
 (defvar semantic-grammar-mode-map
   (let ((km (make-sparse-keymap)))
 
diff --git a/lisp/cedet/semantic/idle.el b/lisp/cedet/semantic/idle.el
index 1afb1d841d..2d6f26919d 100644
--- a/lisp/cedet/semantic/idle.el
+++ b/lisp/cedet/semantic/idle.el
@@ -818,13 +818,13 @@ visible, then highlight it."
               (goto-char (overlay-start region))
               (when (pos-visible-in-window-p
                      (point) (get-buffer-window (current-buffer) 'visible))
-                (if (< (overlay-end region) (point-at-eol))
+                 (if (< (overlay-end region) (line-end-position))
                     (pulse-momentary-highlight-overlay
                      region semantic-idle-symbol-highlight-face)
                   ;; Not the same
                   (pulse-momentary-highlight-region
                    (overlay-start region)
-                   (point-at-eol)
+                    (line-end-position)
                    semantic-idle-symbol-highlight-face))))
             ))
          ((vectorp region)
@@ -843,8 +843,8 @@ visible, then highlight it."
                        end t)
                   ;; This is likely it, give it a try.
                   (pulse-momentary-highlight-region
-                   start (if (<= end (point-at-eol)) end
-                           (point-at-eol))
+                    start (if (<= end (line-end-position)) end
+                            (line-end-position))
                    semantic-idle-symbol-highlight-face)))
               ))))
     nil))
diff --git a/lisp/cedet/semantic/java.el b/lisp/cedet/semantic/java.el
index 9b70afd0a3..53fd4de297 100644
--- a/lisp/cedet/semantic/java.el
+++ b/lisp/cedet/semantic/java.el
@@ -37,25 +37,24 @@
 ;;; Lexical analysis
 ;;
 (defconst semantic-java-number-regexp
-  (eval-when-compile
-    (concat "\\("
-            "\\<[0-9]+[.][0-9]+\\([eE][-+]?[0-9]+\\)?[fFdD]?\\>"
-            "\\|"
-            "\\<[0-9]+[.][eE][-+]?[0-9]+[fFdD]?\\>"
-            "\\|"
-            "\\<[0-9]+[.][fFdD]\\>"
-            "\\|"
-            "\\<[0-9]+[.]"
-            "\\|"
-            "[.][0-9]+\\([eE][-+]?[0-9]+\\)?[fFdD]?\\>"
-            "\\|"
-            "\\<[0-9]+[eE][-+]?[0-9]+[fFdD]?\\>"
-            "\\|"
-            "\\<0[xX][[:xdigit:]]+[lL]?\\>"
-            "\\|"
-            "\\<[0-9]+[lLfFdD]?\\>"
-            "\\)"
-            ))
+  (concat "\\("
+          "\\<[0-9]+[.][0-9]+\\([eE][-+]?[0-9]+\\)?[fFdD]?\\>"
+          "\\|"
+          "\\<[0-9]+[.][eE][-+]?[0-9]+[fFdD]?\\>"
+          "\\|"
+          "\\<[0-9]+[.][fFdD]\\>"
+          "\\|"
+          "\\<[0-9]+[.]"
+          "\\|"
+          "[.][0-9]+\\([eE][-+]?[0-9]+\\)?[fFdD]?\\>"
+          "\\|"
+          "\\<[0-9]+[eE][-+]?[0-9]+[fFdD]?\\>"
+          "\\|"
+          "\\<0[xX][[:xdigit:]]+[lL]?\\>"
+          "\\|"
+          "\\<[0-9]+[lLfFdD]?\\>"
+          "\\)"
+          )
   "Lexer regexp to match Java number terminals.
 Following is the specification of Java number literals.
 
diff --git a/lisp/cedet/semantic/lex-spp.el b/lisp/cedet/semantic/lex-spp.el
index 57e59f4e9f..b66e5c19cb 100644
--- a/lisp/cedet/semantic/lex-spp.el
+++ b/lisp/cedet/semantic/lex-spp.el
@@ -826,7 +826,7 @@ Argument BEG and END specify the bounds of SYM in the 
buffer."
          (goto-char end)
          (setq arg-parsed
                (semantic-lex-spp-one-token-and-move-for-macro
-                ;; NOTE: This used to be (point-at-eol), but
+                 ;; NOTE: This used to be (line-end-position), but
                 ;;       that was too close for multi-line arguments
                 ;;       to a macro.  Point max may be too far if there
                 ;;       is a typo in the buffer.
@@ -1074,7 +1074,7 @@ and variable state from the current buffer."
            ))
 
        ;; Second Cheat: copy key variables regarding macro state from the
-       ;; the originating buffer we are parsing.  We need to do this every time
+       ;; originating buffer we are parsing.  We need to do this every time
        ;; since the state changes.
        (dolist (V important-vars)
          (set V (buffer-local-value V origbuff)))
diff --git a/lisp/cedet/semantic/lex.el b/lisp/cedet/semantic/lex.el
index 885ffbf5a7..75c4ee328d 100644
--- a/lisp/cedet/semantic/lex.el
+++ b/lisp/cedet/semantic/lex.el
@@ -574,25 +574,24 @@ may need to be overridden for some special languages.")
 (defvar-local semantic-lex-number-expression
   ;; This expression was written by David Ponce for Java, and copied
   ;; here for C and any other similar language.
-  (eval-when-compile
-    (concat "\\("
-            "\\<[0-9]+[.][0-9]+\\([eE][-+]?[0-9]+\\)?[fFdD]?\\>"
-            "\\|"
-            "\\<[0-9]+[.][eE][-+]?[0-9]+[fFdD]?\\>"
-            "\\|"
-            "\\<[0-9]+[.][fFdD]\\>"
-            "\\|"
-            "\\<[0-9]+[.]"
-            "\\|"
-            "[.][0-9]+\\([eE][-+]?[0-9]+\\)?[fFdD]?\\>"
-            "\\|"
-            "\\<[0-9]+[eE][-+]?[0-9]+[fFdD]?\\>"
-            "\\|"
-            "\\<0[xX][[:xdigit:]]+[lL]?\\>"
-            "\\|"
-            "\\<[0-9]+[lLfFdD]?\\>"
-            "\\)"
-            ))
+  (concat "\\("
+          "\\<[0-9]+[.][0-9]+\\([eE][-+]?[0-9]+\\)?[fFdD]?\\>"
+          "\\|"
+          "\\<[0-9]+[.][eE][-+]?[0-9]+[fFdD]?\\>"
+          "\\|"
+          "\\<[0-9]+[.][fFdD]\\>"
+          "\\|"
+          "\\<[0-9]+[.]"
+          "\\|"
+          "[.][0-9]+\\([eE][-+]?[0-9]+\\)?[fFdD]?\\>"
+          "\\|"
+          "\\<[0-9]+[eE][-+]?[0-9]+[fFdD]?\\>"
+          "\\|"
+          "\\<0[xX][[:xdigit:]]+[lL]?\\>"
+          "\\|"
+          "\\<[0-9]+[lLfFdD]?\\>"
+          "\\)"
+          )
   "Regular expression for matching a number.
 If this value is nil, no number extraction is done during lex.
 This expression tries to match C and Java like numbers.
@@ -1424,7 +1423,7 @@ Return either a paren token or a semantic list token 
depending on
        ;; to work properly.  Lets try and move over
        ;; whatever white space we matched to begin
        ;; with.
-       (skip-syntax-forward "-.'" (point-at-eol))
+        (skip-syntax-forward "-.'" (line-end-position))
       ;; We may need to back up so newlines or whitespace is generated.
       (if (bolp)
          (backward-char 1)))
diff --git a/lisp/cedet/semantic/symref.el b/lisp/cedet/semantic/symref.el
index e48cefa4ca..16bbacc428 100644
--- a/lisp/cedet/semantic/symref.el
+++ b/lisp/cedet/semantic/symref.el
@@ -555,7 +555,7 @@ deleting the buffers that were opened."
     (when (re-search-forward (if (memq searchtype '(regexp tagregexp))
                                  searchtxt
                                (regexp-quote searchtxt))
-                            (point-at-eol)
+                             (line-end-position)
                             t)
       (goto-char (match-beginning 0))
       )
diff --git a/lisp/cedet/semantic/symref/list.el 
b/lisp/cedet/semantic/symref/list.el
index 7823dad6ef..eacbb6f1f8 100644
--- a/lisp/cedet/semantic/symref/list.el
+++ b/lisp/cedet/semantic/symref/list.el
@@ -234,7 +234,7 @@ Some useful functions are found in 
`semantic-format-tag-functions'."
   "Toggle showing the contents below the current line."
   (interactive)
   (beginning-of-line)
-  (when (re-search-forward "\\[[-+]\\]" (point-at-eol) t)
+  (when (re-search-forward "\\[[-+]\\]" (line-end-position) t)
     (forward-char -1)
     (push-button)))
 
@@ -255,7 +255,7 @@ BUTTON is the button that was clicked."
          (forward-line (1- H))
          (beginning-of-line)
          (back-to-indentation)
-         (setq text (cons (buffer-substring (point) (point-at-eol)) text)))
+          (setq text (cons (buffer-substring (point) (line-end-position)) 
text)))
        (setq text (nreverse text)))
       (goto-char (button-start button))
       (forward-char 1)
@@ -409,7 +409,7 @@ cursor to the beginning of that symbol, then record a macro 
as if
     (switch-to-buffer-other-window (semantic-tag-buffer tag))
     (goto-char (point-min))
     (forward-line (1- line))
-    (when (not (re-search-forward (regexp-quote oldsym) (point-at-eol) t))
+    (when (not (re-search-forward (regexp-quote oldsym) (line-end-position) t))
       (error "Cannot find hit.  Cannot record macro"))
     (goto-char (match-beginning 0))
     ;; Cursor is now in the right location.  Start recording a macro.
@@ -479,7 +479,7 @@ Return the number of occurrences FUNCTION was operated 
upon."
              (goto-char (point-min))
              (forward-line (1- line))
              (beginning-of-line)
-             (while (re-search-forward (regexp-quote oldsym) (point-at-eol) t)
+              (while (re-search-forward (regexp-quote oldsym) 
(line-end-position) t)
                (setq count (1+ count))
                (save-excursion ;; Leave cursor after the matched name.
                  (goto-char (match-beginning 0)) ;; Go to beginning of that sym
diff --git a/lisp/cedet/semantic/tag-file.el b/lisp/cedet/semantic/tag-file.el
index 7a80bccb53..a5220f622a 100644
--- a/lisp/cedet/semantic/tag-file.el
+++ b/lisp/cedet/semantic/tag-file.el
@@ -28,8 +28,6 @@
 (require 'semantic/tag)
 
 (defvar ede-minor-mode)
-(declare-function semanticdb-table-child-p "semantic/db" t t)
-(declare-function semanticdb-get-buffer "semantic/db")
 (declare-function semantic-dependency-find-file-on-path "semantic/dep")
 (declare-function ede-toplevel "ede/base")
 
@@ -37,68 +35,66 @@
 
 ;;; Location a TAG came from.
 ;;
+
+(cl-defgeneric semantic-tag-parent-buffer (parent)
+  "Return the buffer in which a tag can be found, knowing its PARENT."
+  (cond ((and (semantic-tag-p parent) (semantic-tag-in-buffer-p parent))
+        ;; We have a parent with a buffer, then go there.
+        (semantic-tag-buffer parent))
+       ((and (semantic-tag-p parent) (semantic-tag-file-name parent))
+        ;; The parent only has a file-name, then
+        ;; find that file, and switch to that buffer.
+        (find-file-noselect (semantic-tag-file-name parent)))))
+
 ;;;###autoload
-(define-overloadable-function semantic-go-to-tag (tag &optional parent)
+(defun semantic-go-to-tag (tag &optional parent)
   "Go to the location of TAG.
 TAG may be a stripped element, in which case PARENT specifies a
 parent tag that has position information.
 PARENT can also be a `semanticdb-table' object."
-  (:override
-   (save-match-data
+  (save-match-data
+    (set-buffer
      (cond ((semantic-tag-in-buffer-p tag)
            ;; We have a linked tag, go to that buffer.
-           (set-buffer (semantic-tag-buffer tag)))
+           (semantic-tag-buffer tag))
           ((semantic-tag-file-name tag)
            ;; If it didn't have a buffer, but does have a file
            ;; name, then we need to get to that file so the tag
            ;; location is made accurate.
-           (set-buffer (find-file-noselect (semantic-tag-file-name tag))))
-          ((and parent (semantic-tag-p parent) (semantic-tag-in-buffer-p 
parent))
-           ;; The tag had nothing useful, but we have a parent with
-           ;; a buffer, then go there.
-           (set-buffer (semantic-tag-buffer parent)))
-          ((and parent (semantic-tag-p parent) (semantic-tag-file-name parent))
-           ;; Tag had nothing, and the parent only has a file-name, then
-           ;; find that file, and switch to that buffer.
-           (set-buffer (find-file-noselect (semantic-tag-file-name parent))))
-          ((and parent (featurep 'semantic/db)
-                (semanticdb-table-child-p parent))
-           (set-buffer (semanticdb-get-buffer parent)))
-          (t
-           ;; Well, just assume things are in the current buffer.
-           nil
-           )))
-   ;; We should be in the correct buffer now, try and figure out
-   ;; where the tag is.
-   (cond ((semantic-tag-with-position-p tag)
-         ;; If it's a number, go there
-         (goto-char (semantic-tag-start tag)))
-        ((semantic-tag-with-position-p parent)
-         ;; Otherwise, it's a trimmed vector, such as a parameter,
-         ;; or a structure part.  If there is a parent, we can use it
-         ;; as a bounds for searching.
-         (goto-char (semantic-tag-start parent))
-         ;; Here we make an assumption that the text returned by
-         ;; the parser and concocted by us actually exists
-         ;; in the buffer.
-         (re-search-forward (semantic-tag-name tag)
-                            (semantic-tag-end parent)
-                            t))
-        ((semantic-tag-get-attribute tag :line)
-         ;; The tag has a line number in it.  Go there.
-         (goto-char (point-min))
-         (forward-line (1- (semantic-tag-get-attribute tag :line))))
-        ((and (semantic-tag-p parent) (semantic-tag-get-attribute parent 
:line))
-         ;; The tag has a line number in it.  Go there.
-         (goto-char (point-min))
-         (forward-line (1- (semantic-tag-get-attribute parent :line)))
-         (re-search-forward (semantic-tag-name tag) nil t))
-        (t
-         ;; Take a guess that the tag has a unique name, and just
-         ;; search for it from the beginning of the buffer.
-         (goto-char (point-min))
-         (re-search-forward (semantic-tag-name tag) nil t)))
-   )
+           (find-file-noselect (semantic-tag-file-name tag)))
+          ((and parent (semantic-tag-parent-buffer parent)))
+          ;; Well, just assume things are in the current buffer.
+          (t (current-buffer)))))
+  ;; We should be in the correct buffer now, try and figure out
+  ;; where the tag is.
+  (cond ((semantic-tag-with-position-p tag)
+        ;; If it's a number, go there
+        (goto-char (semantic-tag-start tag)))
+       ((semantic-tag-with-position-p parent)
+        ;; Otherwise, it's a trimmed vector, such as a parameter,
+        ;; or a structure part.  If there is a parent, we can use it
+        ;; as a bounds for searching.
+        (goto-char (semantic-tag-start parent))
+        ;; Here we make an assumption that the text returned by
+        ;; the parser and concocted by us actually exists
+        ;; in the buffer.
+        (re-search-forward (semantic-tag-name tag)
+                           (semantic-tag-end parent)
+                           t))
+       ((semantic-tag-get-attribute tag :line)
+        ;; The tag has a line number in it.  Go there.
+        (goto-char (point-min))
+        (forward-line (1- (semantic-tag-get-attribute tag :line))))
+       ((and (semantic-tag-p parent) (semantic-tag-get-attribute parent :line))
+        ;; The tag has a line number in it.  Go there.
+        (goto-char (point-min))
+        (forward-line (1- (semantic-tag-get-attribute parent :line)))
+        (re-search-forward (semantic-tag-name tag) nil t))
+       (t
+        ;; Take a guess that the tag has a unique name, and just
+        ;; search for it from the beginning of the buffer.
+        (goto-char (point-min))
+        (re-search-forward (semantic-tag-name tag) nil t)))
   )
 
 ;;; Dependencies
diff --git a/lisp/cedet/semantic/util-modes.el 
b/lisp/cedet/semantic/util-modes.el
index fdd93c6bcf..33fed9191e 100644
--- a/lisp/cedet/semantic/util-modes.el
+++ b/lisp/cedet/semantic/util-modes.el
@@ -750,7 +750,7 @@ If there is no function, disable the header line."
                    (if noshow
                        ""
                      (if semantic-stickyfunc-show-only-functions-p ""
-                       (buffer-substring (point-at-bol) (point-at-eol))
+                        (buffer-substring (line-beginning-position) 
(line-end-position))
                        ))
                  ;; Go get the first line of this tag.
                  (goto-char (semantic-tag-start tag))
@@ -765,7 +765,7 @@ If there is no function, disable the header line."
                  ;; Without going to the tag-name we would get"void" in the
                  ;; header line which is IMHO not really useful
                  (search-forward (semantic-tag-name tag) nil t)
-                 (buffer-substring (point-at-bol) (point-at-eol))
+                  (buffer-substring (line-beginning-position) 
(line-end-position))
                  ))))
           (start 0))
       (while (string-match "%" str start)
@@ -959,7 +959,7 @@ function was called, move the overlay."
            (goto-char (semantic-tag-start tag))
            (search-forward (semantic-tag-name tag) nil t)
            (overlay-put ol 'tag tag)
-           (move-overlay ol (point-at-bol) (point-at-eol)))))))
+            (move-overlay ol (line-beginning-position) 
(line-end-position)))))))
   nil)
 
 (semantic-add-minor-mode 'semantic-highlight-func-mode
diff --git a/lisp/cedet/semantic/util.el b/lisp/cedet/semantic/util.el
index 69a7c8f59c..24f71a2dcc 100644
--- a/lisp/cedet/semantic/util.el
+++ b/lisp/cedet/semantic/util.el
@@ -77,7 +77,6 @@ If FILE is not loaded, and semanticdb is not available, find 
the file
        (with-current-buffer (find-file-noselect file)
          (semantic-fetch-tags))))))
 
-(declare-function semanticdb-abstract-table-child-p "semantic/db" (obj) t)
 (declare-function semanticdb-refresh-table "semantic/db")
 (declare-function semanticdb-get-tags "semantic/db" (arg &rest args) t)
 (declare-function semanticdb-find-results-p "semantic/db-find" (resultp))
@@ -115,8 +114,6 @@ buffer, or a filename.  If SOMETHING is nil return nil."
         (require 'semantic/db-mode)
         (semanticdb-minor-mode-p)
         (progn
-          (declare-function semanticdb-abstract-table--eieio-childp
-                            "semantic/db")
           (cl-typep something 'semanticdb-abstract-table)))
     (semanticdb-refresh-table something)
     (semanticdb-get-tags something))
diff --git a/lisp/cedet/semantic/wisent/comp.el 
b/lisp/cedet/semantic/wisent/comp.el
index ba67d25060..e24f6128a6 100644
--- a/lisp/cedet/semantic/wisent/comp.el
+++ b/lisp/cedet/semantic/wisent/comp.el
@@ -38,6 +38,7 @@
 ;;; Code:
 (require 'semantic/wisent)
 (eval-when-compile (require 'cl-lib))
+(require 'subr-x)   ; `string-pad'
 
 ;;;; -------------------
 ;;;; Misc. useful things
@@ -80,18 +81,13 @@
   `(dlet ,(wisent-context-bindings name)
      ,@body))
 
-;; Other utilities
-
 (defsubst wisent-pad-string (s n &optional left)
   "Fill string S with spaces.
 Return a new string of at least N characters.  Insert spaces on right.
 If optional LEFT is non-nil insert spaces on left."
-  (let ((i (length s)))
-    (if (< i n)
-        (if left
-            (concat (make-string (- n i) ?\ ) s)
-          (concat s (make-string (- n i) ?\ )))
-      s)))
+  (declare (obsolete string-pad "29.1"))
+  (string-pad s n nil left))
+
 
 ;;;; ------------------------
 ;;;; Environment dependencies
@@ -704,7 +700,7 @@ S must be a vector of integers."
       (setq i 1)
       (while (<= i nrules)
         (unless (aref ruseful i)
-          (wisent-log "#%s  " (wisent-pad-string (format "%d" i) 4))
+          (wisent-log "#%s  " (string-pad (format "%d" i) 4))
           (wisent-log "%s:" (wisent-tag (aref rlhs i)))
           (setq r (aref rrhs i))
           (while (natnump (aref ritem r))
@@ -2298,7 +2294,7 @@ there are any reduce/reduce conflicts."
       ;; Don't print rules disabled in `wisent-reduce-grammar-tables'.
       (when (aref ruseful i)
         (wisent-log "  %s  %s ->"
-                    (wisent-pad-string (number-to-string i) 6)
+                    (string-pad (number-to-string i) 6)
                     (wisent-tag (aref rlhs i)))
         (setq r (aref rrhs i))
         (if (> (aref ritem r) 0)
diff --git a/lisp/cedet/semantic/wisent/javascript.el 
b/lisp/cedet/semantic/wisent/javascript.el
index cc7ae1b181..492f574fce 100644
--- a/lisp/cedet/semantic/wisent/javascript.el
+++ b/lisp/cedet/semantic/wisent/javascript.el
@@ -107,7 +107,7 @@ This is currently needed for the mozrepl omniscient 
database."
          (when (looking-at "\\w\\|\\s_")
            (forward-sexp 1))
          (setq end (point))
-         (unless (re-search-backward "\\s-" (point-at-bol) t)
+          (unless (re-search-backward "\\s-" (line-beginning-position) t)
            (beginning-of-line))
          (setq tmp (buffer-substring-no-properties (point) end))
          ;; (setq symlist
diff --git a/lisp/cedet/semantic/wisent/python.el 
b/lisp/cedet/semantic/wisent/python.el
index 941efbbbef..6b2833ef44 100644
--- a/lisp/cedet/semantic/wisent/python.el
+++ b/lisp/cedet/semantic/wisent/python.el
@@ -1,6 +1,6 @@
 ;;; wisent-python.el --- Semantic support for Python  -*- lexical-binding: t; 
-*-
 
-;; Copyright (C) 2002, 2004, 2006-2022 Free Software Foundation, Inc.
+;; Copyright (C) 2002-2022 Free Software Foundation, Inc.
 
 ;; Author: Richard Kim <emacs18@gmail.com>
 ;; Created: June 2002
@@ -27,9 +27,7 @@
 
 ;;; Code:
 
-;; Try to load python support, but fail silently since it is only used
-;; for optional functionality
-(require 'python nil t)
+(require 'python)
 
 (require 'semantic/wisent)
 (require 'semantic/wisent/python-wy)
diff --git a/lisp/cedet/srecode.el b/lisp/cedet/srecode.el
index 7c054d4c10..9691f906a4 100644
--- a/lisp/cedet/srecode.el
+++ b/lisp/cedet/srecode.el
@@ -37,14 +37,16 @@
 ;;
 ;; See the srecode manual for specific details.
 
+;;; Code:
+
 (require 'eieio)
 (require 'mode-local)
 (load "srecode/loaddefs" nil 'nomessage)
 
 (defvar srecode-version "1.2"
   "Current version of the Semantic Recoder.")
+(make-obsolete-variable 'srecode-version 'emacs-version "29.1")
 
-;;; Code:
 (defgroup srecode nil
   "Semantic Recoder."
   :group 'extensions
diff --git a/lisp/cedet/srecode/compile.el b/lisp/cedet/srecode/compile.el
index 37c83be811..bed74861ca 100644
--- a/lisp/cedet/srecode/compile.el
+++ b/lisp/cedet/srecode/compile.el
@@ -38,9 +38,6 @@
 (require 'srecode/table)
 (require 'srecode/dictionary)
 
-(declare-function srecode-template-inserter-newline-child-p "srecode/insert"
-                 t t)
-
 ;;; Code:
 
 ;;; Template Class
@@ -378,8 +375,11 @@ It is hard if the previous inserter is a newline object."
   (while (and comp (stringp (car comp)))
     (setq comp (cdr comp)))
   (or (not comp)
-      (progn (require 'srecode/insert)
-            (srecode-template-inserter-newline-child-p (car comp)))))
+      (srecord-compile-inserter-newline-p (car comp))))
+
+(cl-defgeneric srecord-compile-inserter-newline-p (_obj)
+  "Non-nil if OBJ is a newline inserter object."
+  nil)
 
 (defun srecode-compile-split-code (tag str STATE
                                       &optional end-name)
diff --git a/lisp/cedet/srecode/document.el b/lisp/cedet/srecode/document.el
index 8c5f343e98..a25d1441f1 100644
--- a/lisp/cedet/srecode/document.el
+++ b/lisp/cedet/srecode/document.el
@@ -496,7 +496,7 @@ It is assumed that the comment occurs just after VAR-IN."
 
     ;; Find any existing doc strings.
     (goto-char (semantic-tag-end var-in))
-    (skip-syntax-forward "-" (point-at-eol))
+    (skip-syntax-forward "-" (line-end-position))
     (let ((lextok (semantic-doc-snarf-comment-for-tag 'lex))
          )
 
@@ -521,7 +521,7 @@ It is assumed that the comment occurs just after VAR-IN."
     (end-of-line)
     (delete-horizontal-space)
     (move-to-column comment-column t)
-    (when (< (point) (point-at-eol)) (end-of-line))
+    (when (< (point) (line-end-position)) (end-of-line))
 
     ;; Perform the insertion
     (let ((srecode-semantic-selected-tag var-in)
@@ -819,7 +819,7 @@ not account for verb parts."
   "Does TAG fit on one line with space on the end?"
   (save-excursion
     (semantic-go-to-tag tag)
-    (and (<= (semantic-tag-end tag) (point-at-eol))
+    (and (<= (semantic-tag-end tag) (line-end-position))
         (goto-char (semantic-tag-end tag))
         (< (current-column) 70))))
 
diff --git a/lisp/cedet/srecode/insert.el b/lisp/cedet/srecode/insert.el
index 8dd5d25157..db17b7f23f 100644
--- a/lisp/cedet/srecode/insert.el
+++ b/lisp/cedet/srecode/insert.el
@@ -319,6 +319,10 @@ by themselves.")
 Specify the :indent argument to enable automatic indentation when newlines
 occur in your template.")
 
+(cl-defmethod srecord-compile-inserter-newline-p
+    ((_ srecode-template-inserter-newline))
+  t)
+
 (cl-defmethod srecode-insert-method ((sti srecode-template-inserter-newline)
                                  dictionary)
   "Insert the STI inserter."
@@ -402,7 +406,7 @@ Specify the :blank argument to enable this inserter.")
            ((eq (oref sti where) 'end)
             ;; If there is whitespace after pnt, then clear it out.
             (when (looking-at "\\s-*$")
-              (delete-region (point) (point-at-eol)))
+               (delete-region (point) (line-end-position)))
             (when (not (eolp))
               (princ "\n")))
            )
diff --git a/lisp/cedet/srecode/table.el b/lisp/cedet/srecode/table.el
index 3dfbb9d58b..f77898f906 100644
--- a/lisp/cedet/srecode/table.el
+++ b/lisp/cedet/srecode/table.el
@@ -200,13 +200,13 @@ INIT are the initialization parameters for the new 
template table."
     ;; go front-to-back, the highest priority items are put
     ;; into the search table first, allowing lower priority items
     ;; to be the items found in the search table.
-    (object-sort-list mt 'modetables (lambda (a b)
-                                      (> (oref a priority)
-                                         (oref b priority))))
+    (srecode-object-sort-list mt 'modetables (lambda (a b)
+                                               (> (oref a priority)
+                                                  (oref b priority))))
     ;; Return it.
     new))
 
-(defun object-sort-list (object slot predicate)
+(defun srecode-object-sort-list (object slot predicate)
   "Sort the items in OBJECT's SLOT.
 Use PREDICATE is the same as for the `sort' function."
   (when (slot-boundp object slot)
@@ -284,6 +284,8 @@ Use PREDICATE is the same as for the `sort' function."
       (setq temp (cdr temp))))
   )
 
+(define-obsolete-function-alias 'object-sort-list
+  #'srecode-object-sort-list "29.1")
 
 (provide 'srecode/table)
 
diff --git a/lisp/chistory.el b/lisp/chistory.el
index dd0f499743..9dce60a19f 100644
--- a/lisp/chistory.el
+++ b/lisp/chistory.el
@@ -119,8 +119,6 @@ The buffer is left in Command History mode."
          (error "No command history")
        (command-history-mode)))))
 
-(define-obsolete-variable-alias 'command-history-map
-  'command-history-mode-map "24.1")
 (defvar command-history-mode-map
   (let ((map (make-sparse-keymap)))
     (set-keymap-parent map (make-composed-keymap lisp-mode-shared-map
@@ -165,11 +163,11 @@ The buffer for that command is the previous current 
buffer."
   "Examine commands from variable `command-history' in a buffer.
 The number of commands listed is controlled by `list-command-history-max'.
 The command history is filtered by `list-command-history-filter' if non-nil.
-Use \\<command-history-map>\\[command-history-repeat] to repeat the command on 
the current line.
+Use \\<command-history-mode-map>\\[command-history-repeat] to repeat the 
command on the current line.
 
 Otherwise much like Emacs-Lisp Mode except that there is no self-insertion
 and digits provide prefix arguments.  Tab does not indent.
-\\{command-history-map}
+\\{command-history-mode-map}
 
 This command always recompiles the Command History listing
 and runs the normal hook `command-history-hook'."
diff --git a/lisp/comint.el b/lisp/comint.el
index 3da61fb992..3ed04f098c 100644
--- a/lisp/comint.el
+++ b/lisp/comint.el
@@ -330,12 +330,12 @@ This variable is buffer-local in all Comint buffers."
   "The maximum size in lines for Comint buffers.
 Comint buffers are truncated from the top to be no greater than this number, if
 the function `comint-truncate-buffer' is on `comint-output-filter-functions'."
-  :type 'integer
+  :type 'natnum
   :group 'comint)
 
 (defcustom comint-input-ring-size 500
   "Size of the input history ring in `comint-mode'."
-  :type 'integer
+  :type 'natnum
   :group 'comint
   :version "23.2")
 
@@ -905,6 +905,12 @@ series of processes in the same Comint buffer.  The hook
   "Return non-nil if STR contains non-whitespace syntax."
   (not (string-match "\\`\\s *\\'" str)))
 
+(defcustom comint-delete-old-input t
+  "When non-nil, delete old input on inserting previous input with 
\\<comint-mode-map>\\[comint-insert-input]."
+  :type 'boolean
+  :group 'comint
+  :version "29.1")
+
 (defun comint-insert-input (event)
   "In a Comint buffer, set the current input to the previous input at point.
 If there is no previous input at point, run the command specified
@@ -936,10 +942,11 @@ by the global keymap (usually `mouse-yank-at-click')."
         ;; Otherwise, insert the previous input.
         (goto-char (point-max))
         ;; First delete any old unsent input at the end
-        (delete-region
-         (or (marker-position comint-accum-marker)
-             (process-mark (get-buffer-process (current-buffer))))
-         (point))
+        (when comint-delete-old-input
+          (delete-region
+           (or (marker-position comint-accum-marker)
+               (process-mark (get-buffer-process (current-buffer))))
+           (point)))
         ;; Insert the input at point
         (insert input)))))
 
@@ -1466,7 +1473,7 @@ A useful command to bind to SPC.  See 
`comint-replace-by-expanded-history'."
 
 (defcustom comint-history-isearch nil
   "Non-nil to Isearch in input history only, not in comint buffer output.
-If t, usual Isearch keys like `C-r' and `C-M-r' in comint mode search
+If t, usual Isearch keys like \\`C-r' and \\`C-M-r' in comint mode search
 in the input history.
 If `dwim', Isearch keys search in the input history only when initial
 point position is at the comint command line.  When starting Isearch
@@ -2515,8 +2522,9 @@ This function could be in the list 
`comint-output-filter-functions'."
                 (1+ comint--prompt-recursion-depth)))
            (if (> comint--prompt-recursion-depth 10)
                (message "Password prompt recursion too deep")
-             (comint-send-invisible
-              (string-trim string "[ \n\r\t\v\f\b\a]+" "\n+"))))))
+             (when (get-buffer-process (current-buffer))
+               (comint-send-invisible
+                (string-trim string "[ \n\r\t\v\f\b\a]+" "\n+")))))))
      (current-buffer))))
 
 ;; Low-level process communication
@@ -2811,7 +2819,7 @@ Interactively, if no prefix argument is given, the last 
argument is inserted.
 Repeated interactive invocations will cycle through the same argument
 from progressively earlier commands (using the value of INDEX specified
 with the first command).  Values of INDEX < 0 count from the end, so
-INDEX = -1 is the last argument.  This command is like `M-.' in
+INDEX = -1 is the last argument.  This command is like \"M-.\" in
 Bash and zsh."
   (interactive "P")
   (unless (null index)
@@ -3298,10 +3306,6 @@ Magic characters are those in 
`comint-file-name-quote-list'."
 (defun comint-completion-at-point ()
   (run-hook-with-args-until-success 'comint-dynamic-complete-functions))
 
-(define-obsolete-function-alias
-  'comint-dynamic-complete
-  'completion-at-point "24.1")
-
 (defun comint-dynamic-complete-filename ()
   "Dynamically complete the filename at point.
 Completes if after a filename.
@@ -3382,13 +3386,6 @@ See `completion-table-with-quoting' and 
`comint-unquote-function'.")
                      (goto-char (match-end 0))
                    (insert filesuffix)))))))))
 
-(defun comint-dynamic-complete-as-filename ()
-  "Dynamically complete at point as a filename.
-See `comint-dynamic-complete-filename'.  Returns t if successful."
-  (declare (obsolete comint-filename-completion "24.1"))
-  (let ((data (comint--complete-file-name-data)))
-    (completion-in-region (nth 0 data) (nth 1 data) (nth 2 data))))
-
 (defun comint-replace-by-expanded-filename ()
   "Dynamically expand and complete the filename at point.
 Replace the filename with an expanded, canonicalized and
@@ -3403,65 +3400,6 @@ filename absolute.  For expansion see `expand-file-name' 
and
       (replace-match (expand-file-name filename) t t)
       (comint-dynamic-complete-filename))))
 
-
-(defun comint-dynamic-simple-complete (stub candidates)
-  "Dynamically complete STUB from CANDIDATES list.
-This function inserts completion characters at point by
-completing STUB from the strings in CANDIDATES.  If completion is
-ambiguous, possibly show a completions listing in a separate
-buffer.
-
-Return nil if no completion was inserted.
-Return `sole' if completed with the only completion match.
-Return `shortest' if completed with the shortest match.
-Return `partial' if completed as far as possible.
-Return `listed' if a completion listing was shown.
-
-See also `comint-dynamic-complete-filename'."
-  (declare (obsolete completion-in-region "24.1"))
-  (let* ((completion-ignore-case (memq system-type '(ms-dos windows-nt 
cygwin)))
-        (minibuffer-p (window-minibuffer-p))
-        (suffix (cond ((not comint-completion-addsuffix) "")
-                      ((not (consp comint-completion-addsuffix)) " ")
-                      (t (cdr comint-completion-addsuffix))))
-        (completions (all-completions stub candidates)))
-    (cond ((null completions)
-          (if minibuffer-p
-              (minibuffer-message "No completions of %s" stub)
-            (message "No completions of %s" stub))
-          nil)
-         ((= 1 (length completions))   ; Gotcha!
-          (let ((completion (car completions)))
-            (if (string-equal completion stub)
-                (unless minibuffer-p
-                  (message "Sole completion"))
-              (insert (substring completion (length stub)))
-              (unless minibuffer-p
-                (message "Completed")))
-            (insert suffix)
-            'sole))
-         (t                            ; There's no unique completion.
-          (let ((completion (try-completion stub candidates)))
-            ;; Insert the longest substring.
-            (insert (substring completion (length stub)))
-            (cond ((and comint-completion-recexact comint-completion-addsuffix
-                        (string-equal stub completion)
-                        (member completion completions))
-                   ;; It's not unique, but user wants shortest match.
-                   (insert suffix)
-                   (unless minibuffer-p
-                     (message "Completed shortest"))
-                   'shortest)
-                  ((or comint-completion-autolist
-                       (string-equal stub completion))
-                   ;; It's not unique, list possible completions.
-                   (comint-dynamic-list-completions completions stub)
-                   'listed)
-                  (t
-                   (unless minibuffer-p
-                     (message "Partially completed"))
-                   'partial)))))))
-
 (defun comint-dynamic-list-filename-completions ()
   "Display a list of possible completions for the filename at point."
   (interactive)
diff --git a/lisp/completion.el b/lisp/completion.el
index fb700954b0..2e486b6a50 100644
--- a/lisp/completion.el
+++ b/lisp/completion.el
@@ -926,10 +926,6 @@ Each symbol is bound to a single completion entry.")
   "Return a completion entry."
   (list string 0 nil current-completion-source))
 
-;; Obsolete
-;;(defmacro cmpl-prefix-entry-symbol (completion-entry)
-;;  (list 'car (list 'cdr completion-entry)))
-
 
 
 ;;-----------------------------------------------
diff --git a/lisp/composite.el b/lisp/composite.el
index d7ac75708c..6fcf637584 100644
--- a/lisp/composite.el
+++ b/lisp/composite.el
@@ -474,6 +474,25 @@ after a sequence of character events."
     (aset gstring (1- len) nil))
   gstring)
 
+(defun lgstring-glyph-boundary (gstring startpos endpos)
+  "Return buffer position at or after ENDPOS where grapheme from GSTRING ends.
+STARTPOS is the position where the grapheme cluster starts; it is returned
+by `find-composition'."
+  (let ((nglyphs (lgstring-glyph-len gstring))
+        (idx 0)
+        glyph found)
+    (while (and (not found) (< idx nglyphs))
+      (setq glyph (lgstring-glyph gstring idx))
+      (cond
+       ((or (null glyph)
+            (= (+ startpos (lglyph-from glyph)) endpos))
+        (setq found endpos))
+       ((>= (+ startpos (lglyph-to glyph)) endpos)
+        (setq found (+ startpos (lglyph-to glyph) 1)))
+       (t
+        (setq idx (1+ idx)))))
+    (or found endpos)))
+
 (defun compose-glyph-string (gstring from to)
   (let ((glyph (lgstring-glyph gstring from))
        from-pos to-pos)
diff --git a/lisp/cus-dep.el b/lisp/cus-dep.el
index 47d2cac3be..bb07a0694a 100644
--- a/lisp/cus-dep.el
+++ b/lisp/cus-dep.el
@@ -37,7 +37,7 @@
 ldefs-boot\\|cus-load\\|finder-inf\\|esh-groups\\|subdirs\\)\\.el$\\)"
   "Regexp matching file names not to scan for `custom-make-dependencies'.")
 
-(require 'autoload)
+(require 'loaddefs-gen)
 
 ;; Hack workaround for bug#14384.
 ;; Define defcustom-mh as an alias for defcustom, etc.
diff --git a/lisp/cus-edit.el b/lisp/cus-edit.el
index 6dff9ec97a..d3768766be 100644
--- a/lisp/cus-edit.el
+++ b/lisp/cus-edit.el
@@ -139,6 +139,7 @@
 
 (require 'cus-face)
 (require 'wid-edit)
+(require 'icons)
 
 (defvar custom-versions-load-alist)    ; from cus-load
 (defvar recentf-exclude)               ; from recentf.el
@@ -1075,6 +1076,7 @@ plain variables.  This means that `setopt' will execute 
any
   (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)))
+  (put variable 'custom-check-value (list value))
   (funcall (or (get variable 'custom-set) #'set-default) variable value))
 
 ;;;###autoload
@@ -2583,7 +2585,13 @@ If INITIAL-STRING is non-nil, use that rather than 
\"Parent groups:\"."
 Normally just return the docstring.  But if VARIABLE automatically
 becomes buffer local when set, append a message to that effect.
 Also append any obsolescence information."
-  (format "%s%s%s" (documentation-property variable 'variable-documentation t)
+  (format "%s%s%s"
+          (with-temp-buffer
+            (insert
+             (or (documentation-property variable 'variable-documentation t)
+                 ""))
+            (untabify (point-min) (point-max))
+            (buffer-string))
          (if (and (local-variable-if-set-p variable)
                   (or (not (local-variable-p variable))
                       (with-temp-buffer
@@ -4278,6 +4286,30 @@ restoring it to the state of a face that has never been 
customized."
     (widget-put widget :args args)
     widget))
 
+;;; The `fringe-bitmap' Widget.
+
+(defvar widget-fringe-bitmap-prompt-value-history nil
+  "History of input to `widget-fringe-bitmap-prompt-value'.")
+
+;; In no-X builds, fringe.el isn't preloaded.
+(autoload 'fringe-bitmap-p "fringe")
+
+(define-widget 'fringe-bitmap 'symbol
+  "A Lisp fringe bitmap name."
+  :format "%v"
+  :tag "Fringe bitmap"
+  :match (lambda (_widget value) (fringe-bitmap-p value))
+  :completions (apply-partially #'completion-table-with-predicate
+                                obarray #'fringe-bitmap-p 'strict)
+  :prompt-match 'fringe-bitmap-p
+  :prompt-history 'widget-face-prompt-value-history
+  :validate (lambda (widget)
+             (unless (fringe-bitmap-p (widget-value widget))
+               (widget-put widget
+                           :error (format "Invalid fringe bitmap: %S"
+                                          (widget-value widget)))
+               widget)))
+
 ;;; The `custom-group-link' Widget.
 
 (define-widget 'custom-group-link 'link
@@ -4842,7 +4874,8 @@ if only the first line of the docstring is shown."))
             (print-escape-control-characters t))
         (atomic-change-group
          (custom-save-variables)
-         (custom-save-faces)))
+         (custom-save-faces)
+          (custom-save-icons)))
       (let ((file-precious-flag t))
        (save-buffer))
       (if old-buffer
@@ -5283,6 +5316,294 @@ if that value is non-nil."
 
 (put 'Custom-mode 'mode-class 'special)
 
+;; Icons.
+
+(define-widget 'custom-icon 'custom
+  "A widget for displaying an icon.
+The following properties have special meanings for this widget:
+
+:hidden-states should be a list of widget states for which the
+  widget's initial contents are to be hidden.
+
+:custom-form should be a symbol describing how to display and
+  edit the variable---either `edit' (using edit widgets),
+  `lisp' (as a Lisp sexp), or `mismatch' (should not happen);
+  if nil, use the return value of `custom-variable-default-form'.
+
+:shown-value, if non-nil, should be a list whose `car' is the
+  variable value to display in place of the current value.
+
+:custom-style describes the widget interface style; nil is the
+  default style, while `simple' means a simpler interface that
+  inhibits the magic custom-state widget."
+  :format "%v"
+  :help-echo "Alter or reset this icon."
+  :documentation-property #'icon-documentation
+  :custom-category 'option
+  :custom-state nil
+  :custom-form nil
+  :value-create 'custom-icon-value-create
+  :hidden-states '(standard)
+  :custom-set 'custom-icon-set
+  :custom-reset-current 'custom-redraw
+  :custom-reset-saved 'custom-variable-reset-saved)
+
+(defun custom-icon-value-create (widget)
+  "Here is where you edit the icon's specification."
+  (custom-load-widget widget)
+  (unless (widget-get widget :custom-form)
+    (widget-put widget :custom-form custom-variable-default-form))
+  (let* ((buttons (widget-get widget :buttons))
+        (children (widget-get widget :children))
+        (form (widget-get widget :custom-form))
+        (symbol (widget-get widget :value))
+        (tag (widget-get widget :tag))
+        (type '(repeat
+                 (list (choice (const :tag "Images" image)
+                               (const :tag "Colorful Emojis" emoji)
+                               (const :tag "Monochrome Symbols" symbol)
+                               (const :tag "Text Only" text))
+                       (repeat string)
+                       plist)))
+        (prefix (widget-get widget :custom-prefix))
+        (last (widget-get widget :custom-last))
+        (style (widget-get widget :custom-style))
+        (value (let ((shown-value (widget-get widget :shown-value)))
+                 (cond (shown-value
+                        (car shown-value))
+                       (t (icon-complete-spec symbol nil t)))))
+        (state (or (widget-get widget :custom-state)
+                   (if (memq (custom-icon-state symbol value)
+                             (widget-get widget :hidden-states))
+                       'hidden))))
+
+    ;; Transform the spec into something that agrees with the type.
+    (setq value
+          (mapcar
+           (lambda (elem)
+             (list (car elem)
+                   (icon-spec-values elem)
+                   (icon-spec-keywords elem)))
+           value))
+
+    ;; Now we can create the child widget.
+    (cond ((eq custom-buffer-style 'tree)
+          (insert prefix (if last " `--- " " |--- "))
+          (push (widget-create-child-and-convert
+                 widget 'custom-browse-variable-tag)
+                buttons)
+          (insert " " tag "\n")
+          (widget-put widget :buttons buttons))
+         ((eq state 'hidden)
+          ;; Indicate hidden value.
+          (push (widget-create-child-and-convert
+                 widget 'custom-visibility
+                 :help-echo "Show the value of this option."
+                 :on-glyph "down"
+                 :on "Hide"
+                 :off-glyph "right"
+                 :off "Show Value"
+                 :action 'custom-toggle-hide-icon
+                 nil)
+                buttons)
+          (insert " ")
+          (push (widget-create-child-and-convert
+                 widget 'item
+                 :format "%{%t%} "
+                 :sample-face 'custom-variable-tag
+                 :tag tag
+                 :parent widget)
+                buttons))
+         (t
+          ;; Edit mode.
+          (push (widget-create-child-and-convert
+                 widget 'custom-visibility
+                 :help-echo "Hide or show this option."
+                 :on "Hide"
+                 :off "Show"
+                 :on-glyph "down"
+                 :off-glyph "right"
+                 :action 'custom-toggle-hide-icon
+                 t)
+                buttons)
+          (insert " ")
+          (let* ((format (widget-get type :format))
+                  tag-format)
+             (unless (string-match ":\\s-?" format)
+              (error "Bad format"))
+            (setq tag-format (substring format 0 (match-end 0)))
+            (push (widget-create-child-and-convert
+                   widget 'item
+                   :format tag-format
+                   :action 'custom-tag-action
+                   :help-echo "Change specs of this face."
+                   :mouse-down-action 'custom-tag-mouse-down-action
+                   :button-face 'custom-variable-button
+                   :sample-face 'custom-variable-tag
+                   :tag tag)
+                  buttons)
+            (push (widget-create-child-and-convert
+                   widget type
+                   :value value)
+                  children))))
+    (unless (eq custom-buffer-style 'tree)
+      (unless (eq (preceding-char) ?\n)
+       (widget-insert "\n"))
+      ;; Create the magic button.
+      (unless (eq style 'simple)
+       (let ((magic (widget-create-child-and-convert
+                     widget 'custom-magic nil)))
+         (widget-put widget :custom-magic magic)
+         (push magic buttons)))
+      (widget-put widget :buttons buttons)
+      ;; Insert documentation.
+      (widget-put widget :documentation-indent 3)
+      (unless (and (eq style 'simple)
+                  (eq state 'hidden))
+       (widget-add-documentation-string-button
+        widget :visibility-widget 'custom-visibility))
+
+      ;; Update the rest of the properties.
+      (widget-put widget :custom-form form)
+      (widget-put widget :children children)
+      ;; Now update the state.
+      (if (eq state 'hidden)
+         (widget-put widget :custom-state state)
+       (custom-icon-state-set widget))
+      ;; See also.
+      (unless (eq state 'hidden)
+       (when (eq (widget-get widget :custom-level) 1)
+         (custom-add-parent-links widget))
+       (custom-add-see-also widget)))))
+
+(defun custom-toggle-hide-icon (visibility-widget &rest _ignore)
+  "Toggle the visibility of a `custom-icon' parent widget.
+By default, this signals an error if the parent has unsaved
+changes."
+  (let ((widget (widget-get visibility-widget :parent)))
+    (unless (eq (widget-type widget) 'custom-icon)
+      (error "Invalid widget type"))
+    (custom-load-widget widget)
+    (let ((state (widget-get widget :custom-state)))
+      (if (eq state 'hidden)
+         (widget-put widget :custom-state 'unknown)
+       ;; In normal interface, widget can't be hidden if modified.
+       (when (memq state '(invalid modified set))
+         (error "There are unsaved changes"))
+       (widget-put widget :custom-state 'hidden))
+      (custom-redraw widget)
+      (widget-setup))))
+
+(defun custom--icons-widget-value (widget)
+  ;; Transform back to the real format.
+  (mapcar
+   (lambda (elem)
+     (cons (nth 0 elem)
+           (append (nth 1 elem) (nth 2 elem))))
+   (widget-value widget)))
+
+(defun custom-icon-set (widget)
+  "Set the current spec for the icon being edited by WIDGET."
+  (let* ((state (widget-get widget :custom-state))
+        (child (car (widget-get widget :children)))
+        (symbol (widget-value widget))
+        val)
+    (when (eq state 'hidden)
+      (user-error "Cannot update hidden icon"))
+
+    (setq val (custom--icons-widget-value child))
+    (unless (equal val (icon-complete-spec symbol))
+      (custom-variable-backup-value widget))
+    (custom-push-theme 'theme-icon symbol 'user 'set val)
+    (custom-redraw-magic widget)))
+
+;;;###autoload
+(defun customize-icon (icon)
+  "Customize ICON."
+  (interactive
+   (let* ((v (symbol-at-point))
+         (default (and (iconp v) (symbol-name v)))
+         val)
+     (setq val (completing-read (format-prompt "Customize icon" default)
+                               obarray 'iconp t nil nil default))
+     (list (if (equal val "")
+              (if (symbolp v) v nil)
+            (intern val)))))
+  (unless icon
+    (error "No icon specified"))
+  (custom-buffer-create (list (list icon 'custom-icon))
+                       (format "*Customize Icon: %s*"
+                               (custom-unlispify-tag-name icon))))
+
+(defun custom-icon-state-set (widget &optional state)
+  "Set the state of WIDGET to STATE."
+  (let ((value (custom--icons-widget-value
+                (car (widget-get widget :children)))))
+    (widget-put
+     widget :custom-state
+     (or state
+         (custom-icon-state (widget-value widget) value)))))
+
+;;; FIXME -- more work is needed here.  We don't properly
+;;; differentiate between `saved' and `set'.
+(defun custom-icon-state (symbol value)
+  "Return the state of customize icon SYMBOL for VALUE.
+Possible return values are `standard', `saved', `set', `themed',
+and `changed'."
+  (cond
+   ((equal (icon-complete-spec symbol t t) value)
+    'standard)
+   ((equal (icon-complete-spec symbol nil t) value)
+    (if (eq (caar (get symbol 'theme-icon)) 'user)
+        'set
+      'themed))
+   (t 'changed)))
+
+(defun custom-theme-set-icons (theme &rest specs)
+  "Apply a list of icon specs associated with THEME.
+THEME should be a symbol, and SPECS are icon name/spec pairs.
+See `define-icon' for details."
+  (custom-check-theme theme)
+  (pcase-dolist (`(,icon ,spec) specs)
+    (custom-push-theme 'theme-icon icon theme 'set spec)))
+
+;;;###autoload
+(defun custom-set-icons (&rest args)
+  "Install user customizations of icon specs specified in ARGS.
+These settings are registered as theme `user'.
+The arguments should each be a list of the form:
+
+  (SYMBOL EXP)
+
+This stores EXP (without evaluating it) as the saved spec for SYMBOL."
+  (apply #'custom-theme-set-icons 'user args))
+
+;;;###autoload
+(defun custom-save-icons ()
+  "Save all customized icons in `custom-file'."
+  (let ((values nil))
+    (mapatoms
+     (lambda (symbol)
+       (let ((value (car-safe (get symbol 'theme-icon))))
+        (when (eq (car value) 'user)
+           (push (list symbol (cadr value)) values)))))
+    (save-excursion
+      (custom-save-delete 'custom-set-icons)
+      (when values
+        (ensure-empty-lines)
+        (insert "(custom-set-icons
+ ;; custom-set-icons was added by Custom.
+ ;; If you edit it by hand, you could mess it up, so be careful.
+ ;; Your init file should contain only one such instance.
+ ;; If there is more than one, they won't work right.\n")
+        (dolist (value (sort values (lambda (s1 s2)
+                                      (string< (car s1) (car s2)))))
+         (unless (bolp)
+           (insert "\n"))
+          (insert "  '")
+          (prin1 value (current-buffer)))
+        (insert ")\n")))))
+
 (provide 'cus-edit)
 
 ;;; cus-edit.el ends here
diff --git a/lisp/cus-face.el b/lisp/cus-face.el
index 80d0aaa0d5..73a33f064c 100644
--- a/lisp/cus-face.el
+++ b/lisp/cus-face.el
@@ -83,9 +83,9 @@
 
     (:height
      (choice :tag "Height"
-            :help-echo "Face's font height."
+             :help-echo "Face's font size."
             :value 1.0                 ; default
-            (integer :tag "Height in 1/10 pt")
+             (integer :tag "Font size in 1/10 pt")
             (number :tag "Scale" 1.0)))
 
     (:weight
diff --git a/lisp/cus-start.el b/lisp/cus-start.el
index d8c4b48035..0e1cb4589d 100644
--- a/lisp/cus-start.el
+++ b/lisp/cus-start.el
@@ -398,6 +398,7 @@ Leaving \"Default\" unchecked is equivalent with specifying 
a default of
             ;;                         (const :tag " current dir" nil)
             ;;                         (directory :format "%v"))))
             (load-prefer-newer lisp boolean "24.4")
+             (record-all-keys keyboard boolean)
             ;; minibuf.c
             (minibuffer-follows-selected-frame
               minibuffer (choice (const :tag "Always" t)
@@ -833,6 +834,10 @@ since it could result in memory overflow and make Emacs 
crash."
              (x-scroll-event-delta-factor mouse float "29.1")
              (x-gtk-use-native-input keyboard boolean "29.1")
              (x-dnd-disable-motif-drag dnd boolean "29.1")
+             (x-auto-preserve-selections x
+                                         (choice (const :tag "Always preserve 
selections" t)
+                                                 (repeat symbol))
+                                         "29.1")
             ;; xselect.c
             (x-select-enable-clipboard-manager killing boolean "24.1")
             ;; xsettings.c
@@ -873,6 +878,8 @@ since it could result in memory overflow and make Emacs 
crash."
                            (equal "x-scroll-event-delta-factor"
                                   (symbol-name symbol))
                            (equal "x-dnd-disable-motif-drag"
+                                  (symbol-name symbol))
+                           (equal "x-auto-preserve-selections"
                                   (symbol-name symbol)))
                       (featurep 'x))
                      ((string-match "\\`x-" (symbol-name symbol))
diff --git a/lisp/custom.el b/lisp/custom.el
index 2b7621229d..96dfb37d86 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -90,6 +90,20 @@ The value is either the symbol's current value
  (as obtained using the `:get' function), if any,
 or the value in the symbol's `saved-value' property if any,
 or (last of all) the value of EXP."
+  ;; If this value has been set with `setopt' (for instance in
+  ;; ~/.emacs), we didn't necessarily know the type of the user option
+  ;; then.  So check now, and issue a warning if it's wrong.
+  (let ((value (get symbol 'custom-check-value)))
+    (when value
+      (let ((type (get symbol 'custom-type)))
+        (when (and type
+                   (boundp symbol)
+                   (eq (car value) (symbol-value symbol))
+                   ;; Check that the type is correct.
+                   (not (widget-apply (widget-convert type)
+                                      :match (car value))))
+          (warn "Value `%S' for `%s' does not match type %s"
+                value symbol type)))))
   (funcall (or (get symbol 'custom-set) #'set-default-toplevel-value)
            symbol
            (condition-case nil
@@ -896,7 +910,7 @@ symbol `set', then VALUE is the value to use.  If it is the 
symbol
 `reset', then SYMBOL will be removed from THEME (VALUE is ignored).
 
 See `custom-known-themes' for a list of known themes."
-  (unless (memq prop '(theme-value theme-face))
+  (unless (memq prop '(theme-value theme-face theme-icon))
     (error "Unknown theme property"))
   (let* ((old (get symbol prop))
         (setting (assq theme old))  ; '(theme value)
@@ -1678,6 +1692,7 @@ Each of the arguments ARGS has this form:
     (VARIABLE IGNORED)
 
 This means reset VARIABLE.  (The argument IGNORED is ignored)."
+  (declare (obsolete nil "29.1"))
     (apply #'custom-theme-reset-variables 'user args))
 
 (defun custom-add-choice (variable choice)
diff --git a/lisp/descr-text.el b/lisp/descr-text.el
index 0f01ad676a..7fad031add 100644
--- a/lisp/descr-text.el
+++ b/lisp/descr-text.el
@@ -655,7 +655,9 @@ The character information includes:
               ("file code"
                ,@(if multibyte-p
                      (let* ((coding buffer-file-coding-system)
-                            (encoded (encode-coding-char char coding charset)))
+                            (encoded
+                             (and coding
+                                  (encode-coding-char char coding charset))))
                        (if encoded
                            (list (encoded-string-description encoded coding)
                                  (format "(encoded by coding system %S)"
@@ -701,6 +703,7 @@ The character information includes:
                                                   (looking-at-p "[ \t]+$")))
                              'trailing-whitespace)
                             ((and nobreak-char-display char
+                                  (> char 127)
                                   (eq (get-char-code-property char 
'general-category) 'Zs))
                              'nobreak-space)
                             ((and nobreak-char-display char
diff --git a/lisp/desktop.el b/lisp/desktop.el
index 947f7cff5c..ef73bc596d 100644
--- a/lisp/desktop.el
+++ b/lisp/desktop.el
@@ -481,7 +481,7 @@ If value is t, all buffers are restored immediately."
 (defcustom desktop-lazy-idle-delay 5
   "Idle delay before starting to create buffers.
 See `desktop-restore-eager'."
-  :type 'integer
+  :type 'natnum
   :group 'desktop
   :version "22.1")
 
@@ -701,7 +701,7 @@ DIRNAME omitted or nil means use `desktop-dirname'."
                                           -4))))
           ;; We should err on the safe side here: if any of the
           ;; executables is something like "emacs-nox" or "emacs-42.1"
-          ;; or "gemacs" or "xemacs", let's recognize them as well.
+          ;; or "gemacs", let's recognize them as well.
           (and (string-match-p "emacs" proc-cmd)
                (string-match-p "emacs" my-cmd))))))
 
@@ -791,7 +791,10 @@ if different)."
 
 ;; ----------------------------------------------------------------------------
 (unless noninteractive
-  (add-hook 'kill-emacs-query-functions #'desktop-kill))
+  (add-hook 'kill-emacs-query-functions #'desktop-kill)
+  ;; Certain things should be done even if
+  ;; `kill-emacs-query-functions' are not called.
+  (add-hook 'kill-emacs-hook #'desktop--on-kill))
 
 (defun desktop-kill ()
   "If `desktop-save-mode' is non-nil, do what `desktop-save' says to do.
@@ -818,12 +821,15 @@ is nil, ask the user where to save the desktop."
       (file-error
        (unless (yes-or-no-p "Error while saving the desktop.  Ignore? ")
         (signal (car err) (cdr err))))))
+  (desktop--on-kill)
+  t)
+
+(defun desktop--on-kill ()
   ;; If we own it, we don't anymore.
   (when (eq (emacs-pid) (desktop-owner))
     ;; Allow exiting Emacs even if we can't delete the desktop file.
     (ignore-error 'file-error
-      (desktop-release-lock)))
-  t)
+      (desktop-release-lock))))
 
 ;; ----------------------------------------------------------------------------
 (defun desktop-list* (&rest args)
diff --git a/lisp/dired-aux.el b/lisp/dired-aux.el
index d16aee0fa8..06f0b86fc4 100644
--- a/lisp/dired-aux.el
+++ b/lisp/dired-aux.el
@@ -760,7 +760,7 @@ with a prefix argument."
 
 (defvar dired-aux-files)
 
-(defun minibuffer-default-add-dired-shell-commands ()
+(defun dired-minibuffer-default-add-shell-commands ()
   "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."
@@ -780,20 +780,16 @@ which is replaced by the value returned by 
`dired-mark-prompt',
 with ARG and FILES as its arguments.  FILES should be a list of
 file names.  The result is used as the prompt.
 
-This normally reads using `read-shell-command', but if the
-`dired-x' package is loaded, use `dired-guess-shell-command' to
-offer a smarter default choice of shell command."
+Use `dired-guess-shell-command' to offer a smarter default choice
+of shell command."
   (minibuffer-with-setup-hook
       (lambda ()
        (setq-local dired-aux-files files)
        (setq-local minibuffer-default-add-function
-                   #'minibuffer-default-add-dired-shell-commands))
+                    #'dired-minibuffer-default-add-shell-commands))
     (setq prompt (format prompt (dired-mark-prompt arg files)))
-    (if (functionp 'dired-guess-shell-command)
-       (dired-mark-pop-up nil 'shell files
-                          'dired-guess-shell-command prompt files)
-      (dired-mark-pop-up nil 'shell files
-                        'read-shell-command prompt nil nil))))
+    (dired-mark-pop-up nil 'shell files
+                       'dired-guess-shell-command prompt files)))
 
 ;;;###autoload
 (defcustom dired-confirm-shell-command t
@@ -1056,18 +1052,278 @@ Return the result of `process-file' - zero for 
success."
         (dir default-directory))
     (with-current-buffer (get-buffer-create out-buffer)
       (erase-buffer)
-      (let* ((default-directory dir)
-             (res (process-file
-                   shell-file-name
-                   nil
-                   t
-                   nil
-                   shell-command-switch
-                   cmd)))
-        (dired-uncache dir)
-        (unless (zerop res)
-          (pop-to-buffer out-buffer))
-        res))))
+      (let ((default-directory dir) res)
+        (with-connection-local-variables
+         (setq res (process-file
+                    shell-file-name
+                    nil
+                    t
+                    nil
+                    shell-command-switch
+                    cmd))
+         (dired-uncache dir)
+         (unless (zerop res)
+           (pop-to-buffer out-buffer))
+         res)))))
+
+
+;;; Guess shell command
+
+;; * `dired-guess-shell-command' provides smarter defaults for
+;;    `dired-read-shell-command'.
+;;
+;; * `dired-guess-shell-command' calls `dired-guess-default' with list of
+;;    marked files.
+;;
+;; * Parse `dired-guess-shell-alist-user' and
+;;   `dired-guess-shell-alist-default' (in that order) for the first REGEXP
+;;   that matches the first file in the file list.
+;;
+;; * If the REGEXP matches all the entries of the file list then evaluate
+;;   COMMAND, which is either a string or a Lisp expression returning a
+;;   string.  COMMAND may be a list of commands.
+;;
+;; * Return this command to `dired-guess-shell-command' which prompts user
+;;   with it.  The list of commands is put into the list of default values.
+;;   If a command is used successfully then it is stored permanently in
+;;   `dired-shell-command-history'.
+
+;; Guess what shell command to apply to a file.
+(defvar dired-shell-command-history nil
+  "History list for commands that read dired-shell commands.")
+
+;; Default list of shell commands.
+
+;; NOTE: Use `gunzip -c' instead of `zcat' on `.gz' files.  Some do not
+;; install GNU zip's version of zcat.
+
+(autoload 'Man-support-local-filenames "man")
+(autoload 'vc-responsible-backend "vc")
+
+(defvar dired-guess-shell-alist-default
+  (list
+   (list "\\.tar\\'"
+         '(if dired-guess-shell-gnutar
+              (concat dired-guess-shell-gnutar " xvf")
+            "tar xvf")
+         ;; Extract files into a separate subdirectory
+         '(if dired-guess-shell-gnutar
+              (concat "mkdir " (file-name-sans-extension file)
+                      "; " dired-guess-shell-gnutar " -C "
+                      (file-name-sans-extension file) " -xvf")
+            (concat "mkdir " (file-name-sans-extension file)
+                    "; tar -C " (file-name-sans-extension file) " -xvf"))
+         ;; List archive contents.
+         '(if dired-guess-shell-gnutar
+              (concat dired-guess-shell-gnutar " tvf")
+            "tar tvf"))
+
+   ;; REGEXPS for compressed archives must come before the .Z rule to
+   ;; be recognized:
+   (list "\\.tar\\.Z\\'"
+         ;; Untar it.
+         '(if dired-guess-shell-gnutar
+              (concat dired-guess-shell-gnutar " zxvf")
+            (concat "zcat * | tar xvf -"))
+         ;; Optional conversion to gzip format.
+         '(concat "znew" (if dired-guess-shell-gzip-quiet " -q")
+                  " " dired-guess-shell-znew-switches))
+
+   ;; gzip'ed archives
+   (list "\\.t\\(ar\\.\\)?gz\\'"
+         '(if dired-guess-shell-gnutar
+              (concat dired-guess-shell-gnutar " zxvf")
+            (concat "gunzip -qc * | tar xvf -"))
+         ;; Extract files into a separate subdirectory
+         '(if dired-guess-shell-gnutar
+              (concat "mkdir " (file-name-sans-extension file)
+                      "; " dired-guess-shell-gnutar " -C "
+                      (file-name-sans-extension file) " -zxvf")
+            (concat "mkdir " (file-name-sans-extension file)
+                    "; gunzip -qc * | tar -C "
+                    (file-name-sans-extension file) " -xvf -"))
+         ;; Optional decompression.
+         '(concat "gunzip" (if dired-guess-shell-gzip-quiet " -q" ""))
+         ;; List archive contents.
+         '(if dired-guess-shell-gnutar
+              (concat dired-guess-shell-gnutar " ztvf")
+            (concat "gunzip -qc * | tar tvf -")))
+
+   ;; bzip2'ed archives
+   (list "\\.t\\(ar\\.bz2\\|bz\\)\\'"
+         "bunzip2 -c * | tar xvf -"
+         ;; Extract files into a separate subdirectory
+         '(concat "mkdir " (file-name-sans-extension file)
+                  "; bunzip2 -c * | tar -C "
+                  (file-name-sans-extension file) " -xvf -")
+         ;; Optional decompression.
+         "bunzip2")
+
+   ;; xz'ed archives
+   (list "\\.t\\(ar\\.\\)?xz\\'"
+         "unxz -c * | tar xvf -"
+         ;; Extract files into a separate subdirectory
+         '(concat "mkdir " (file-name-sans-extension file)
+                  "; unxz -c * | tar -C "
+                  (file-name-sans-extension file) " -xvf -")
+         ;; Optional decompression.
+         "unxz")
+
+   '("\\.shar\\.Z\\'" "zcat * | unshar")
+   '("\\.shar\\.g?z\\'" "gunzip -qc * | unshar")
+
+   '("\\.e?ps\\'" "ghostview" "xloadimage" "lpr")
+   (list "\\.e?ps\\.g?z\\'" "gunzip -qc * | ghostview -"
+         ;; Optional decompression.
+         '(concat "gunzip" (if dired-guess-shell-gzip-quiet " -q")))
+   (list "\\.e?ps\\.Z\\'" "zcat * | ghostview -"
+         ;; Optional conversion to gzip format.
+         '(concat "znew" (if dired-guess-shell-gzip-quiet " -q")
+                  " " dired-guess-shell-znew-switches))
+
+   (list "\\.patch\\'"
+         '(if (eq (ignore-errors (vc-responsible-backend default-directory)) 
'Git)
+              "cat * | git apply"
+            "cat * | patch"))
+   (list "\\.patch\\.g?z\\'" "gunzip -qc * | patch"
+         ;; Optional decompression.
+         '(concat "gunzip" (if dired-guess-shell-gzip-quiet " -q")))
+   (list "\\.patch\\.Z\\'" "zcat * | patch"
+         ;; Optional conversion to gzip format.
+         '(concat "znew" (if dired-guess-shell-gzip-quiet " -q")
+                  " " dired-guess-shell-znew-switches))
+
+   ;; The following four extensions are useful with dired-man ("N" key)
+   ;; FIXME "man ./" does not work with dired-do-shell-command,
+   ;; because there seems to be no way for us to modify the filename,
+   ;; only the command.  Hmph.  `dired-man' works though.
+   (list "\\.\\(?:[0-9]\\|man\\)\\'"
+         '(let ((loc (Man-support-local-filenames)))
+            (cond ((eq loc 'man-db) "man -l")
+                  ((eq loc 'man) "man ./")
+                  (t
+                   "cat * | tbl | nroff -man -h | col -b"))))
+   (list "\\.\\(?:[0-9]\\|man\\)\\.g?z\\'"
+         '(let ((loc (Man-support-local-filenames)))
+            (cond ((eq loc 'man-db)
+                   "man -l")
+                  ((eq loc 'man)
+                   "man ./")
+                  (t "gunzip -qc * | tbl | nroff -man -h | col -b")))
+         ;; Optional decompression.
+         '(concat "gunzip" (if dired-guess-shell-gzip-quiet " -q")))
+   (list "\\.[0-9]\\.Z\\'"
+         '(let ((loc (Man-support-local-filenames)))
+            (cond ((eq loc 'man-db) "man -l")
+                  ((eq loc 'man) "man ./")
+                  (t "zcat * | tbl | nroff -man -h | col -b")))
+         ;; Optional conversion to gzip format.
+         '(concat "znew" (if dired-guess-shell-gzip-quiet " -q")
+                  " " dired-guess-shell-znew-switches))
+   '("\\.pod\\'" "perldoc" "pod2man * | nroff -man")
+
+   '("\\.dvi\\'" "xdvi" "dvips")       ; preview and printing
+   '("\\.au\\'" "play")                        ; play Sun audiofiles
+   '("\\.mpe?g\\'\\|\\.avi\\'" "xine -p")
+   '("\\.ogg\\'" "ogg123")
+   '("\\.mp3\\'" "mpg123")
+   '("\\.wav\\'" "play")
+   '("\\.uu\\'" "uudecode")            ; for uudecoded files
+   '("\\.hqx\\'" "mcvert")
+   '("\\.sh\\'" "sh")                  ; execute shell scripts
+   '("\\.xbm\\'" "bitmap")             ; view X11 bitmaps
+   '("\\.gp\\'" "gnuplot")
+   '("\\.p[bgpn]m\\'" "xloadimage")
+   '("\\.gif\\'" "xloadimage")         ; view gif pictures
+   '("\\.tif\\'" "xloadimage")
+   '("\\.png\\'" "display")            ; xloadimage 4.1 doesn't grok PNG
+   '("\\.jpe?g\\'" "xloadimage")
+   '("\\.fig\\'" "xfig")               ; edit fig pictures
+   '("\\.out\\'" "xgraph")             ; for plotting purposes.
+   '("\\.tex\\'" "latex" "tex")
+   '("\\.texi\\(nfo\\)?\\'" "makeinfo" "texi2dvi")
+   '("\\.pdf\\'" "xpdf")
+   '("\\.doc\\'" "antiword" "strings")
+   '("\\.rpm\\'" "rpm -qilp" "rpm -ivh")
+   '("\\.dia\\'" "dia")
+   '("\\.mgp\\'" "mgp")
+
+   ;; Some other popular archivers.
+   (list "\\.zip\\'" "unzip" "unzip -l"
+         ;; Extract files into a separate subdirectory
+         '(concat "unzip" (if dired-guess-shell-gzip-quiet " -q")
+                  " -d " (file-name-sans-extension file)))
+   '("\\.zoo\\'" "zoo x//")
+   '("\\.lzh\\'" "lharc x")
+   '("\\.arc\\'" "arc x")
+   '("\\.shar\\'" "unshar")
+   '("\\.rar\\'" "unrar x")
+   '("\\.7z\\'" "7z x")
+
+   ;; Compression.
+   (list "\\.g?z\\'" '(concat "gunzip" (if dired-guess-shell-gzip-quiet " 
-q")))
+   (list "\\.dz\\'" "dictunzip")
+   (list "\\.bz2\\'" "bunzip2")
+   (list "\\.xz\\'" "unxz")
+   (list "\\.Z\\'" "uncompress"
+         ;; Optional conversion to gzip format.
+         '(concat "znew" (if dired-guess-shell-gzip-quiet " -q")
+                  " " dired-guess-shell-znew-switches))
+
+   '("\\.sign?\\'" "gpg --verify"))
+  "Default alist used for shell command guessing.
+See `dired-guess-shell-alist-user'.")
+
+(defun dired-guess-default (files)
+  "Return a shell command, or a list of commands, appropriate for FILES.
+See `dired-guess-shell-alist-user'."
+  (let* ((case-fold-search dired-guess-shell-case-fold-search)
+         (programs
+          (delete-dups
+           (mapcar
+            (lambda (command)
+              (eval command `((file . ,(car files)))))
+            (seq-reduce
+             #'append
+             (mapcar #'cdr
+                     (seq-filter (lambda (elem)
+                                   (seq-every-p
+                                    (lambda (file)
+                                      (string-match-p (car elem) file))
+                                    files))
+                                 (append dired-guess-shell-alist-user
+                                         dired-guess-shell-alist-default)))
+             nil)))))
+    (if (length= programs 1)
+        (car programs)
+      programs)))
+
+;;;###autoload
+(defun dired-guess-shell-command (prompt files)
+  "Ask user with PROMPT for a shell command, guessing a default from FILES."
+  (let ((default (dired-guess-default files))
+        default-list val)
+    (if (null default)
+        ;; Nothing to guess
+        (read-shell-command prompt nil 'dired-shell-command-history)
+      (setq prompt (replace-regexp-in-string ": $" " " prompt))
+      (if (listp default)
+          ;; More than one guess
+          (setq default-list default
+                default (car default)
+                prompt (concat
+                        prompt
+                        (format "{%d guesses} " (length default-list))))
+        ;; Just one guess
+        (setq default-list (list default)))
+      ;; Put the first guess in the prompt but not in the initial value.
+      (setq prompt (concat prompt (format "[%s]: " default)))
+      ;; All guesses can be retrieved with M-n
+      (setq val (read-shell-command prompt nil
+                                    'dired-shell-command-history
+                                    default-list))
+      ;; If we got a return, then return default.
+      (if (equal val "") default val))))
 
 
 ;;; Commands that delete or redisplay part of the dired buffer
@@ -1095,45 +1351,46 @@ With a prefix argument, kill that many lines starting 
with the current line.
     (dired-move-to-filename)))
 
 ;;;###autoload
-(defun dired-do-kill-lines (&optional arg fmt)
-  "Kill all marked lines (not the files).
-With a prefix argument, kill that many lines starting with the current line.
-\(A negative argument kills backward.)
+(defun dired-do-kill-lines (&optional arg fmt init-count)
+  "Remove all marked lines, or the next ARG lines.
+The files or directories on those lines are _not_ deleted.  Only the
+Dired listing is affected.  To restore the removals, use `\\[revert-buffer]'.
 
-If you use this command with a prefix argument to kill the line
-for a file that is a directory, which you have inserted in the
-Dired buffer as a subdirectory, then it deletes that subdirectory
-from the buffer as well.
+With a numeric prefix arg, remove that many lines going forward,
+starting with the current line.  (A negative prefix arg removes lines
+going backward.)
 
-To kill an entire subdirectory \(without killing its line in the
-parent directory), go to its directory header line and use this
-command with a prefix argument (the value does not matter).
+If you use a prefix arg to remove the line for a subdir whose listing
+you have inserted into the Dired buffer, then that subdir listing is
+also removed.
 
-To undo the killing, the undo command can be used as normally.
+To remove a subdir listing _without_ removing the subdir's line in its
+parent listing, go to the header line of the subdir listing and use
+this command with any prefix arg.
 
-This function returns the number of killed lines.
+When called from Lisp, non-nil INIT-COUNT is added to the number of
+lines removed by this invocation, for the reporting message.
 
-FMT is a format string used for messaging the user about the
-killed lines, and defaults to \"Killed %d line%s.\" if not
-present.  A FMT of \"\" will suppress the messaging."
+A FMT of \"\" will suppress the messaging."
+  ;; Returns count of killed lines.
   (interactive "P")
   (if arg
       (if (dired-get-subdir)
-         (dired-kill-subdir)
-       (dired-kill-line arg))
+          (dired-kill-subdir)
+        (dired-kill-line arg))
     (save-excursion
       (goto-char (point-min))
-      (let (buffer-read-only
-           (count 0)
-           (regexp (dired-marker-regexp)))
-       (while (and (not (eobp))
-                   (re-search-forward regexp nil t))
-         (setq count (1+ count))
-         (delete-region (line-beginning-position)
-                        (progn (forward-line 1) (point))))
-       (or (equal "" fmt)
-           (message (or fmt "Killed %d line%s.") count (dired-plural-s count)))
-       count))))
+      (let ((count (or init-count  0))
+            (regexp (dired-marker-regexp))
+            (inhibit-read-only t))
+        (while (and (not (eobp))
+                    (re-search-forward regexp nil t))
+          (setq count (1+ count))
+          (delete-region (line-beginning-position)
+                         (progn (forward-line 1) (point))))
+        (unless (equal "" fmt)
+          (message (or fmt "Killed %d line%s.") count (dired-plural-s count)))
+        count))))
 
 
 ;;; Compression
@@ -1935,7 +2192,7 @@ unless OK-IF-ALREADY-EXISTS is non-nil."
     (while blist
       (with-current-buffer (car blist)
        (if (and buffer-file-name
-                 (dired-in-this-tree-p buffer-file-name expanded-from-dir))
+                (dired-in-this-tree-p buffer-file-name expanded-from-dir))
            (let ((modflag (buffer-modified-p))
                  (to-file (replace-regexp-in-string
                            (concat "^" (regexp-quote from-dir))
@@ -2519,6 +2776,73 @@ Also see `dired-do-revert-buffer'."
   (dired-do-create-files 'symlink #'make-symbolic-link
                          "Symlink" arg dired-keep-marker-symlink))
 
+;;;###autoload
+(defun dired-do-relsymlink (&optional arg)
+  "Relative symlink all marked (or next ARG) files into a directory.
+Otherwise make a relative symbolic link to the current file.
+This creates relative symbolic links like
+
+    foo -> ../bar/foo
+
+not absolute ones like
+
+    foo -> /ugly/file/name/that/may/change/any/day/bar/foo
+
+For absolute symlinks, use \\[dired-do-symlink]."
+  (interactive "P")
+  (dired-do-create-files 'relsymlink #'dired-make-relative-symlink
+                         "RelSymLink" arg dired-keep-marker-relsymlink))
+
+(defun dired-make-relative-symlink (file1 file2 &optional ok-if-already-exists)
+  "Make a symbolic link (pointing to FILE1) in FILE2.
+The link is relative (if possible), for example
+
+    \"/vol/tex/bin/foo\" \"/vol/local/bin/foo\"
+
+results in
+
+    \"../../tex/bin/foo\" \"/vol/local/bin/foo\""
+  (interactive "FRelSymLink: \nFRelSymLink %s: \np")
+  (let (name1 name2 len1 len2 (index 0) sub)
+    (setq file1 (expand-file-name file1)
+          file2 (expand-file-name file2)
+          len1 (length file1)
+          len2 (length file2))
+    ;; Find common initial file name components:
+    (let (next)
+      (while (and (setq next (string-search "/" file1 index))
+                  (< (setq next (1+ next)) (min len1 len2))
+                  ;; For the comparison, both substrings must end in
+                  ;; `/', so NEXT is *one plus* the result of the
+                  ;; string-search.
+                  ;; E.g., consider the case of linking "/tmp/a/abc"
+                  ;; to "/tmp/abc" erroneously giving "/tmp/a" instead
+                  ;; of "/tmp/" as common initial component
+                  (string-equal (substring file1 0 next)
+                                (substring file2 0 next)))
+        (setq index next))
+      (setq name2 file2
+            sub (substring file1 0 index)
+            name1 (substring file1 index)))
+    (if (string-equal sub "/")
+        ;; No common initial file name found
+        (setq name1 file1)
+      ;; Else they have a common parent directory
+      (let ((tem (substring file2 index))
+            (start 0)
+            (count 0))
+        ;; Count number of slashes we must compensate for ...
+        (while (setq start (string-search "/" tem start))
+          (setq count (1+ count)
+                start (1+ start)))
+        ;; ... and prepend a "../" for each slash found:
+        (dotimes (_ count)
+          (setq name1 (concat "../" name1)))))
+    (make-symbolic-link
+     (directory-file-name name1)        ; must not link to foo/
+                                        ; (trailing slash!)
+     name2 ok-if-already-exists)))
+
 ;;;###autoload
 (defun dired-do-hardlink (&optional arg)
   "Add names (hard links) current file or all marked (or next ARG) files.
@@ -2679,6 +3003,16 @@ See function `dired-do-rename-regexp' for more info."
    #'make-symbolic-link
    "SymLink" arg regexp newname whole-name dired-keep-marker-symlink))
 
+;;;###autoload
+(defun dired-do-relsymlink-regexp (regexp newname &optional arg whole-name)
+  "RelSymlink all marked files containing REGEXP to NEWNAME.
+See functions `dired-do-rename-regexp' and `dired-do-relsymlink'
+for more info."
+  (interactive (dired-mark-read-regexp "RelSymLink"))
+  (dired-do-create-files-regexp
+   #'dired-make-relative-symlink
+   "RelSymLink" arg regexp newname whole-name dired-keep-marker-relsymlink))
+
 
 ;;; Change case of file names
 
@@ -2816,7 +3150,7 @@ This function takes some pains to conform to `ls -lR' 
output."
       (setq switches (string-replace "R" "" switches))
       (dolist (cur-ass dired-subdir-alist)
        (let ((cur-dir (car cur-ass)))
-         (and (file-in-directory-p cur-dir dirname)
+         (and (dired-in-this-tree-p cur-dir dirname)
               (let ((cur-cons (assoc-string cur-dir dired-switches-alist)))
                 (if cur-cons
                     (setcdr cur-cons switches)
@@ -2828,7 +3162,7 @@ This function takes some pains to conform to `ls -lR' 
output."
 (defun dired-insert-subdir-validate (dirname &optional switches)
   ;; Check that it is valid to insert DIRNAME with SWITCHES.
   ;; Signal an error if invalid (e.g. user typed `i' on `..').
-  (or (file-in-directory-p dirname (expand-file-name default-directory))
+  (or (dired-in-this-tree-p dirname (expand-file-name default-directory))
       (error  "%s: Not in this directory tree" dirname))
   (let ((real-switches (or switches dired-subdir-switches)))
     (when real-switches
@@ -2979,7 +3313,7 @@ Optional third arg LIMIT (>= 1) is a limit to the length 
of the
 resulting list.
 Thus, if SEP is a regexp that only matches itself,
 
-   (mapconcat #'identity (dired-split SEP STRING) SEP)
+   (mapconcat #\\='identity (dired-split SEP STRING) SEP)
 
 is always equal to STRING."
   (declare (obsolete split-string "29.1"))
@@ -3021,18 +3355,20 @@ When called interactively and not on a subdir line, go 
to this subdir's line."
 
 ;;;###autoload
 (defun dired-goto-subdir (dir)
-  "Go to end of header line of DIR in this dired buffer.
+  "Go to end of header line of inserted directory DIR in this Dired buffer.
+When called interactively, prompt for the inserted subdirectory
+to go to.
+
 Return value of point on success, otherwise return nil.
 The next char is \\n."
   (interactive
    (prog1                              ; let push-mark display its message
        (list (expand-file-name
-             (completing-read "Goto in situ directory: " ; prompt
-                              dired-subdir-alist ; table
-                              nil      ; predicate
-                              t        ; require-match
-                              (dired-current-directory))))
-     (push-mark)))
+              (completing-read "Goto inserted directory: "
+                               dired-subdir-alist nil t
+                               (dired-current-directory))))
+     (push-mark))
+   dired-mode)
   (setq dir (file-name-as-directory dir))
   (let ((elt (assoc dir dired-subdir-alist)))
     (and elt
@@ -3208,7 +3544,8 @@ Intended to be added to `isearch-mode-hook'."
 The returned function narrows the search to match the search string
 only as part of a file name enclosed by the text property `dired-filename'.
 It's intended to override the default search function."
-  (isearch-search-fun-in-text-property 'dired-filename (funcall orig-fun)))
+  (isearch-search-fun-in-text-property
+   (funcall orig-fun) '(dired-filename dired-symlink-filename)))
 
 ;;;###autoload
 (defun dired-isearch-filenames ()
@@ -3448,6 +3785,9 @@ in the Dired buffer."
         (setq model (vc-checkout-model backend only-files-list))))
     (list backend files only-files-list state model)))
 
+(define-obsolete-function-alias 'minibuffer-default-add-dired-shell-commands
+  #'dired-minibuffer-default-add-shell-commands "29.1")
+
 
 (provide 'dired-aux)
 
diff --git a/lisp/dired-x.el b/lisp/dired-x.el
index 56036b6c16..cf1ef37694 100644
--- a/lisp/dired-x.el
+++ b/lisp/dired-x.el
@@ -1,7 +1,6 @@
 ;;; dired-x.el --- extra Dired functionality  -*- lexical-binding:t -*-
 
-;; Copyright (C) 1993-1994, 1997, 2001-2022 Free Software Foundation,
-;; Inc.
+;; Copyright (C) 1993-2022 Free Software Foundation, Inc.
 
 ;; Author: Sebastian Kremer <sk@thp.uni-koeln.de>
 ;;     Lawrence R. Dodd <dodd@roebling.poly.edu>
@@ -51,11 +50,6 @@
   "Extended directory editing (dired-x)."
   :group 'dired)
 
-(defgroup dired-keys nil
-  "Dired keys customizations."
-  :prefix "dired-"
-  :group 'dired-x)
-
 (defcustom dired-bind-vm nil
   "Non-nil means \"V\" runs `dired-vm', otherwise \"V\" runs `dired-rmail'.
 RMAIL files in the old Babyl format (used before Emacs 23.1)
@@ -63,34 +57,16 @@ contain \"-*- rmail -*-\" at the top, so `dired-find-file'
 will run `rmail' on these files.  New RMAIL files use the standard
 mbox format, and so cannot be distinguished in this way."
   :type 'boolean
-  :group 'dired-keys)
+  :group 'dired-x)
 
 (defvar dired-bind-jump t)
 (make-obsolete-variable 'dired-bind-jump "not used." "28.1")
 
-(defcustom dired-bind-man t
-  "Non-nil means bind `dired-man' to \"N\" in Dired, otherwise do not.
-Setting this variable directly after dired-x is loaded has no effect -
-use \\[customize]."
-  :type 'boolean
-  :set (lambda (sym val)
-         (if (set sym val)
-             (define-key dired-mode-map "N" 'dired-man)
-           (if (eq 'dired-man (lookup-key dired-mode-map "N"))
-               (define-key dired-mode-map "N" nil))))
-  :group 'dired-keys)
-
-(defcustom dired-bind-info t
-  "Non-nil means bind `dired-info' to \"I\" in Dired, otherwise do not.
-Setting this variable directly after dired-x is loaded has no effect -
-use \\[customize]."
-  :type 'boolean
-  :set (lambda (sym val)
-         (if (set sym val)
-             (define-key dired-mode-map "I" 'dired-info)
-           (if (eq 'dired-info (lookup-key dired-mode-map "I"))
-               (define-key dired-mode-map "I" nil))))
-  :group 'dired-keys)
+(defvar dired-bind-man t)
+(make-obsolete-variable 'dired-bind-man "not used." "29.1")
+
+(defvar dired-bind-info t)
+(make-obsolete-variable 'dired-bind-info "not used." "29.1")
 
 (defcustom dired-vm-read-only-folders nil
   "If non-nil, \\[dired-vm] will visit all folders read-only.
@@ -101,11 +77,12 @@ files not writable by you are visited read-only."
                 (other :tag "non-writable only" if-file-read-only))
   :group 'dired-x)
 
-(defcustom dired-omit-size-limit 30000
+(defcustom dired-omit-size-limit 100000
   "Maximum size for the \"omitting\" feature.
 If nil, there is no maximum size."
   :type '(choice (const :tag "no maximum" nil) integer)
-  :group 'dired-x)
+  :group 'dired-x
+  :version "29.1")
 
 (defcustom dired-omit-case-fold 'filesystem
   "Determine whether \"omitting\" patterns are case-sensitive.
@@ -125,14 +102,49 @@ folding to be used on case-insensitive filesystems only."
       (file-name-case-insensitive-p dir)
     dired-omit-case-fold))
 
+(defcustom dired-omit-lines nil
+  "Regexp matching lines to be omitted by `dired-omit-mode'.
+The value can also be a variable whose value is such a regexp.
+The value can also be nil, which means do no line matching.
+
+Some predefined regexp variables for Dired, which you can use as the
+option value:
+
+* `dired-re-inode-size'
+* `dired-re-mark'
+* `dired-re-maybe-mark'
+* `dired-re-dir'
+* `dired-re-sym'
+* `dired-re-exe'
+* `dired-re-perms'
+* `dired-re-dot'
+* `dired-re-no-dot'"
+  :type `(choice
+          (const :tag "Do not match lines to omit" nil)
+          (regexp
+           :tag "Regexp to match lines to omit (default omits executables)"
+           :value ,dired-re-exe)
+          (restricted-sexp
+           :tag "Variable with regexp value (default: `dired-re-exe')"
+           :match-alternatives
+           ((lambda (obj) (and (symbolp obj) (boundp obj))))
+           :value dired-re-exe))
+  :group 'dired-x)
+
 ;;;###autoload
 (define-minor-mode dired-omit-mode
   "Toggle omission of uninteresting files in Dired (Dired-Omit mode).
+With prefix argument ARG, enable Dired-Omit mode if ARG is positive,
+and disable it otherwise.
+
+If called from Lisp, enable the mode if ARG is omitted or nil.
 
-Dired-Omit mode is a buffer-local minor mode.  When enabled in a
-Dired buffer, Dired does not list files whose filenames match
-regexp `dired-omit-files', nor files ending with extensions in
-`dired-omit-extensions'.
+Dired-Omit mode is a buffer-local minor mode.
+
+When enabled in a Dired buffer, Dired does not list files whose
+filenames match regexp `dired-omit-files', files ending with
+extensions in `dired-omit-extensions', or files listed on lines
+matching `dired-omit-lines'.
 
 To enable omitting in every Dired buffer, you can put this in
 your init file:
@@ -141,10 +153,16 @@ your init file:
 
 See Info node `(dired-x) Omitting Variables' for more information."
   :group 'dired-x
-  (if dired-omit-mode
-      ;; This will mention how many lines were omitted:
-      (let ((dired-omit-size-limit nil)) (dired-omit-expunge))
-    (revert-buffer)))
+  (if (not dired-omit-mode)
+      (revert-buffer)
+    (let ((dired-omit-size-limit  nil)
+          (file-count 0))
+      ;; Omit by file-name match, then omit by line match.
+      ;; Use count of file-name match as INIT-COUNT for line match.
+      ;; Return total count.  (Return value is not used anywhere, so far).
+      (setq file-count (dired-omit-expunge))
+      (when dired-omit-lines
+        (dired-omit-expunge dired-omit-lines 'LINEP file-count)))))
 
 (put 'dired-omit-mode 'safe-local-variable 'booleanp)
 
@@ -178,46 +196,6 @@ toggle between those two."
   :type 'boolean
   :group 'dired-x)
 
-(defcustom dired-guess-shell-gnutar
-  (catch 'found
-    (dolist (exe '("tar" "gtar"))
-      (if (with-temp-buffer
-            (ignore-errors (call-process exe nil t nil "--version"))
-            (and (re-search-backward "GNU tar" nil t) t))
-          (throw 'found exe))))
-  "If non-nil, name of GNU tar executable.
-\(E.g., \"tar\" or \"gtar\").  The `z' switch will be used with it for
-compressed or gzip'ed tar files.  If you don't have GNU tar, set this
-to nil: a pipe using `zcat' or `gunzip -c' will be used."
-  ;; Changed from system-type test to testing --version output.
-  ;; Maybe test --help for -z instead?
-  :version "24.1"
-  :type '(choice (const :tag "Not GNU tar" nil)
-                (string :tag "Command name"))
-  :group 'dired-x)
-
-(defcustom dired-guess-shell-gzip-quiet t
-  "Non-nil says pass -q to gzip overriding verbose GZIP environment."
-  :type 'boolean
-  :group 'dired-x)
-
-(defcustom dired-guess-shell-znew-switches nil
-  "If non-nil, then string of switches passed to `znew', example: \"-K\"."
-  :type '(choice (const :tag "None" nil)
-                (string :tag "Switches"))
-  :group 'dired-x)
-
-(defcustom dired-clean-up-buffers-too t
-  "Non-nil means offer to kill buffers visiting files and dirs deleted in 
Dired."
-  :type 'boolean
-  :group 'dired-x)
-
-(defcustom dired-clean-confirm-killing-deleted-buffers t
-  "If nil, don't ask whether to kill buffers visiting deleted files."
-  :version "26.1"
-  :type 'boolean
-  :group 'dired-x)
-
 
 ;;; Key bindings
 
@@ -226,15 +204,10 @@ to nil: a pipe using `zcat' or `gunzip -c' will be used."
   (define-key dired-mode-map "*O" 'dired-mark-omitted)
   (define-key dired-mode-map "*." 'dired-mark-extension))
 
-(when (keymapp (lookup-key dired-mode-map "%"))
-  (define-key dired-mode-map "%Y" 'dired-do-relsymlink-regexp))
-
 (define-key dired-mode-map "\C-x\M-o" 'dired-omit-mode)
 (define-key dired-mode-map "\M-(" 'dired-mark-sexp)
 (define-key dired-mode-map "\M-!" 'dired-smart-shell-command)
-(define-key dired-mode-map "\M-G" 'dired-goto-subdir)
 (define-key dired-mode-map "F" 'dired-do-find-marked-files)
-(define-key dired-mode-map "Y"  'dired-do-relsymlink)
 (define-key dired-mode-map "V" 'dired-do-run-mail)
 
 
@@ -245,12 +218,6 @@ to nil: a pipe using `zcat' or `gunzip -c' will be used."
                       ["Find Files" dired-do-find-marked-files
                        :help "Find current or marked files"]
                       "Shell Command...")
-  (easy-menu-add-item menu '("Operate")
-                      ["Relative Symlink to..." dired-do-relsymlink
-                       :visible (fboundp 'make-symbolic-link)
-                       :help "Make relative symbolic links for current or \
-marked files"]
-                      "Hardlink to...")
   (easy-menu-add-item menu '("Mark")
                       ["Flag Extension..." dired-flag-extension
                        :help "Flag files with a certain extension for 
deletion"]
@@ -264,12 +231,6 @@ marked files"]
                        :help "Mark files matching `dired-omit-files' \
 and `dired-omit-extensions'"]
                       "Unmark All")
-  (easy-menu-add-item menu '("Regexp")
-                      ["Relative Symlink..." dired-do-relsymlink-regexp
-                       :visible (fboundp 'make-symbolic-link)
-                       :help "Make relative symbolic links for files \
-matching regexp"]
-                      "Hardlink...")
   (easy-menu-add-item menu '("Immediate")
                       ["Omit Mode" dired-omit-mode
                        :style toggle :selected dired-omit-mode
@@ -287,8 +248,6 @@ files"]
   "Automatically put on `dired-mode-hook' to get extra Dired features:
 \\<dired-mode-map>
   \\[dired-do-run-mail]\t-- run mail on folder (see `dired-bind-vm')
-  \\[dired-info]\t-- run info on file
-  \\[dired-man]\t-- run man on file
   \\[dired-do-find-marked-files]\t-- visit all marked files simultaneously
   \\[dired-omit-mode]\t-- toggle omitting of files
   \\[dired-mark-sexp]\t-- mark by Lisp expression
@@ -297,10 +256,8 @@ To see the options you can set, use \\[customize-group] 
RET dired-x RET.
 See also the functions:
   `dired-flag-extension'
   `dired-virtual'
-  `dired-man'
   `dired-vm'
   `dired-rmail'
-  `dired-info'
   `dired-do-find-marked-files'"
   (interactive)
   ;; These must be done in each new dired buffer.
@@ -486,45 +443,61 @@ variables `dired-omit-mode' and `dired-omit-files'."
   :type '(repeat string)
   :group 'dired-x)
 
-(defun dired-omit-expunge (&optional regexp)
-  "Erases all unmarked files matching REGEXP.
-Does nothing if global variable `dired-omit-mode' is nil, or if called
-  non-interactively and buffer is bigger than `dired-omit-size-limit'.
-If REGEXP is nil or not specified, uses `dired-omit-files', and also omits
-  filenames ending in `dired-omit-extensions'.
-If REGEXP is the empty string, this function is a no-op.
-
-This functions works by temporarily binding `dired-marker-char' to
-`dired-omit-marker-char' and calling `dired-do-kill-lines'."
-  (interactive "sOmit files (regexp): ")
+(defun dired-omit-expunge (&optional regexp linep init-count)
+  "Erase all unmarked files whose names match REGEXP.
+With a prefix arg (non-nil LINEP when called from Lisp), match REGEXP
+against the whole line.  Otherwise, match it against the file name.
+
+If REGEXP is nil, use `dired-omit-files', and also omit file names
+ending in `dired-omit-extensions'.
+
+Do nothing if REGEXP is the empty string, `dired-omit-mode' is nil, or
+if called from Lisp and buffer is bigger than `dired-omit-size-limit'.
+
+Optional arg INIT-COUNT is an initial count tha'is added to the number
+of lines omitted by this invocation of `dired-omit-expunge', in the
+status message."
+  (interactive "sOmit files (regexp): \nP")
+  ;; Bind `dired-marker-char' to `dired-omit-marker-char',
+  ;; then call `dired-do-kill-lines'.
   (if (and dired-omit-mode
            (or (called-interactively-p 'interactive)
                (not dired-omit-size-limit)
                (< (buffer-size) dired-omit-size-limit)
-              (progn
-                (when dired-omit-verbose
-                  (message "Not omitting: directory larger than %d characters."
-                           dired-omit-size-limit))
-                (setq dired-omit-mode nil)
-                nil)))
+               (progn
+                 (when dired-omit-verbose
+                   (message "Not omitting: directory larger than %d 
characters."
+                            dired-omit-size-limit))
+                 (setq dired-omit-mode nil)
+                 nil)))
       (let ((omit-re (or regexp (dired-omit-regexp)))
             (old-modified-p (buffer-modified-p))
-            count)
-        (or (string= omit-re "")
-            (let ((dired-marker-char dired-omit-marker-char))
-              (when dired-omit-verbose (message "Omitting..."))
-              (if (dired-mark-unmarked-files omit-re nil nil dired-omit-localp
-                                             (dired-omit-case-fold-p (if 
(stringp dired-directory)
-                                                                         
dired-directory
-                                                                       (car 
dired-directory))))
-                  (progn
-                    (setq count (dired-do-kill-lines
-                                nil
-                                (if dired-omit-verbose "Omitted %d line%s." 
"")))
-                    (force-mode-line-update))
-                (when dired-omit-verbose (message "(Nothing to omit)")))))
-        ;; Try to preserve modified state of buffer.  So `%*' doesn't appear
-        ;; in mode-line of omitted buffers.
+            (count (or init-count 0)))
+        (unless (string= omit-re "")
+          (let ((dired-marker-char dired-omit-marker-char))
+            (when dired-omit-verbose (message "Omitting..."))
+            (if (not (if linep
+                         (dired-mark-if
+                          (and (= (following-char) ?\s) ; Not already marked
+                               (string-match-p
+                                omit-re (buffer-substring
+                                         (line-beginning-position)
+                                         (line-end-position))))
+                          nil)
+                       (dired-mark-unmarked-files
+                        omit-re nil nil dired-omit-localp
+                        (dired-omit-case-fold-p (if (stringp dired-directory)
+                                                    dired-directory
+                                                  (car dired-directory))))))
+                (when dired-omit-verbose (message "(Nothing to omit)"))
+              (setq count  (+ count
+                              (dired-do-kill-lines
+                               nil
+                               (if dired-omit-verbose "Omitted %d line%s" "")
+                               init-count)))
+              (force-mode-line-update))))
+        ;; Try to preserve modified state, so `%*' doesn't appear in
+        ;; `mode-line'.
         (set-buffer-modified-p (and old-modified-p
                                     (save-excursion
                                       (goto-char (point-min))
@@ -725,391 +698,6 @@ Also useful for `auto-mode-alist' like this:
     (shell-command command output-buffer error-buffer)))
 
 
-;;; Guess shell command
-
-;; Brief Description:
-;;
-;; * `dired-do-shell-command' is bound to `!' by dired.el.
-;;
-;; * `dired-guess-shell-command' provides smarter defaults for
-;;    dired-aux.el's `dired-read-shell-command'.
-;;
-;; * `dired-guess-shell-command' calls `dired-guess-default' with list of
-;;    marked files.
-;;
-;; * Parse `dired-guess-shell-alist-user' and
-;;   `dired-guess-shell-alist-default' (in that order) for the first REGEXP
-;;   that matches the first file in the file list.
-;;
-;; * If the REGEXP matches all the entries of the file list then evaluate
-;;   COMMAND, which is either a string or a Lisp expression returning a
-;;   string.  COMMAND may be a list of commands.
-;;
-;; * Return this command to `dired-guess-shell-command' which prompts user
-;;   with it.  The list of commands is put into the list of default values.
-;;   If a command is used successfully then it is stored permanently in
-;;   `dired-shell-command-history'.
-
-;; Guess what shell command to apply to a file.
-(defvar dired-shell-command-history nil
-  "History list for commands that read dired-shell commands.")
-
-;; Default list of shell commands.
-
-;; NOTE: Use `gunzip -c' instead of `zcat' on `.gz' files.  Some do not
-;; install GNU zip's version of zcat.
-
-(autoload 'Man-support-local-filenames "man")
-(autoload 'vc-responsible-backend "vc")
-
-(defvar dired-guess-shell-alist-default
-  (list
-   (list "\\.tar\\'"
-        '(if dired-guess-shell-gnutar
-             (concat dired-guess-shell-gnutar " xvf")
-           "tar xvf")
-        ;; Extract files into a separate subdirectory
-        '(if dired-guess-shell-gnutar
-             (concat "mkdir " (file-name-sans-extension file)
-                     "; " dired-guess-shell-gnutar " -C "
-                     (file-name-sans-extension file) " -xvf")
-           (concat "mkdir " (file-name-sans-extension file)
-                   "; tar -C " (file-name-sans-extension file) " -xvf"))
-        ;; List archive contents.
-        '(if dired-guess-shell-gnutar
-             (concat dired-guess-shell-gnutar " tvf")
-           "tar tvf"))
-
-   ;; REGEXPS for compressed archives must come before the .Z rule to
-   ;; be recognized:
-   (list "\\.tar\\.Z\\'"
-        ;; Untar it.
-        '(if dired-guess-shell-gnutar
-             (concat dired-guess-shell-gnutar " zxvf")
-           (concat "zcat * | tar xvf -"))
-        ;; Optional conversion to gzip format.
-        '(concat "znew" (if dired-guess-shell-gzip-quiet " -q")
-                 " " dired-guess-shell-znew-switches))
-
-   ;; gzip'ed archives
-   (list "\\.t\\(ar\\.\\)?gz\\'"
-        '(if dired-guess-shell-gnutar
-             (concat dired-guess-shell-gnutar " zxvf")
-           (concat "gunzip -qc * | tar xvf -"))
-        ;; Extract files into a separate subdirectory
-        '(if dired-guess-shell-gnutar
-             (concat "mkdir " (file-name-sans-extension file)
-                     "; " dired-guess-shell-gnutar " -C "
-                     (file-name-sans-extension file) " -zxvf")
-           (concat "mkdir " (file-name-sans-extension file)
-                   "; gunzip -qc * | tar -C "
-                   (file-name-sans-extension file) " -xvf -"))
-        ;; Optional decompression.
-        '(concat "gunzip" (if dired-guess-shell-gzip-quiet " -q" ""))
-        ;; List archive contents.
-        '(if dired-guess-shell-gnutar
-             (concat dired-guess-shell-gnutar " ztvf")
-           (concat "gunzip -qc * | tar tvf -")))
-
-   ;; bzip2'ed archives
-   (list "\\.t\\(ar\\.bz2\\|bz\\)\\'"
-        "bunzip2 -c * | tar xvf -"
-        ;; Extract files into a separate subdirectory
-        '(concat "mkdir " (file-name-sans-extension file)
-                 "; bunzip2 -c * | tar -C "
-                 (file-name-sans-extension file) " -xvf -")
-        ;; Optional decompression.
-        "bunzip2")
-
-   ;; xz'ed archives
-   (list "\\.t\\(ar\\.\\)?xz\\'"
-        "unxz -c * | tar xvf -"
-        ;; Extract files into a separate subdirectory
-        '(concat "mkdir " (file-name-sans-extension file)
-                 "; unxz -c * | tar -C "
-                 (file-name-sans-extension file) " -xvf -")
-        ;; Optional decompression.
-        "unxz")
-
-   '("\\.shar\\.Z\\'" "zcat * | unshar")
-   '("\\.shar\\.g?z\\'" "gunzip -qc * | unshar")
-
-   '("\\.e?ps\\'" "ghostview" "xloadimage" "lpr")
-   (list "\\.e?ps\\.g?z\\'" "gunzip -qc * | ghostview -"
-        ;; Optional decompression.
-        '(concat "gunzip" (if dired-guess-shell-gzip-quiet " -q")))
-   (list "\\.e?ps\\.Z\\'" "zcat * | ghostview -"
-        ;; Optional conversion to gzip format.
-        '(concat "znew" (if dired-guess-shell-gzip-quiet " -q")
-                 " " dired-guess-shell-znew-switches))
-
-   (list "\\.patch\\'"
-         '(if (eq (ignore-errors (vc-responsible-backend default-directory)) 
'Git)
-              "cat * | git apply"
-            "cat * | patch"))
-   (list "\\.patch\\.g?z\\'" "gunzip -qc * | patch"
-        ;; Optional decompression.
-        '(concat "gunzip" (if dired-guess-shell-gzip-quiet " -q")))
-   (list "\\.patch\\.Z\\'" "zcat * | patch"
-        ;; Optional conversion to gzip format.
-        '(concat "znew" (if dired-guess-shell-gzip-quiet " -q")
-                 " " dired-guess-shell-znew-switches))
-
-   ;; The following four extensions are useful with dired-man ("N" key)
-   ;; FIXME "man ./" does not work with dired-do-shell-command,
-   ;; because there seems to be no way for us to modify the filename,
-   ;; only the command.  Hmph.  `dired-man' works though.
-   (list "\\.\\(?:[0-9]\\|man\\)\\'"
-         '(let ((loc (Man-support-local-filenames)))
-            (cond ((eq loc 'man-db) "man -l")
-                  ((eq loc 'man) "man ./")
-                  (t
-                   "cat * | tbl | nroff -man -h | col -b"))))
-   (list "\\.\\(?:[0-9]\\|man\\)\\.g?z\\'"
-         '(let ((loc (Man-support-local-filenames)))
-            (cond ((eq loc 'man-db)
-                   "man -l")
-                  ((eq loc 'man)
-                   "man ./")
-                  (t "gunzip -qc * | tbl | nroff -man -h | col -b")))
-        ;; Optional decompression.
-        '(concat "gunzip" (if dired-guess-shell-gzip-quiet " -q")))
-   (list "\\.[0-9]\\.Z\\'"
-         '(let ((loc (Man-support-local-filenames)))
-            (cond ((eq loc 'man-db) "man -l")
-                  ((eq loc 'man) "man ./")
-                  (t "zcat * | tbl | nroff -man -h | col -b")))
-        ;; Optional conversion to gzip format.
-        '(concat "znew" (if dired-guess-shell-gzip-quiet " -q")
-                 " " dired-guess-shell-znew-switches))
-   '("\\.pod\\'" "perldoc" "pod2man * | nroff -man")
-
-   '("\\.dvi\\'" "xdvi" "dvips")       ; preview and printing
-   '("\\.au\\'" "play")                        ; play Sun audiofiles
-   '("\\.mpe?g\\'\\|\\.avi\\'" "xine -p")
-   '("\\.ogg\\'" "ogg123")
-   '("\\.mp3\\'" "mpg123")
-   '("\\.wav\\'" "play")
-   '("\\.uu\\'" "uudecode")            ; for uudecoded files
-   '("\\.hqx\\'" "mcvert")
-   '("\\.sh\\'" "sh")                  ; execute shell scripts
-   '("\\.xbm\\'" "bitmap")             ; view X11 bitmaps
-   '("\\.gp\\'" "gnuplot")
-   '("\\.p[bgpn]m\\'" "xloadimage")
-   '("\\.gif\\'" "xloadimage")         ; view gif pictures
-   '("\\.tif\\'" "xloadimage")
-   '("\\.png\\'" "display")            ; xloadimage 4.1 doesn't grok PNG
-   '("\\.jpe?g\\'" "xloadimage")
-   '("\\.fig\\'" "xfig")               ; edit fig pictures
-   '("\\.out\\'" "xgraph")             ; for plotting purposes.
-   '("\\.tex\\'" "latex" "tex")
-   '("\\.texi\\(nfo\\)?\\'" "makeinfo" "texi2dvi")
-   '("\\.pdf\\'" "xpdf")
-   '("\\.doc\\'" "antiword" "strings")
-   '("\\.rpm\\'" "rpm -qilp" "rpm -ivh")
-   '("\\.dia\\'" "dia")
-   '("\\.mgp\\'" "mgp")
-
-   ;; Some other popular archivers.
-   (list "\\.zip\\'" "unzip" "unzip -l"
-        ;; Extract files into a separate subdirectory
-        '(concat "unzip" (if dired-guess-shell-gzip-quiet " -q")
-                 " -d " (file-name-sans-extension file)))
-   '("\\.zoo\\'" "zoo x//")
-   '("\\.lzh\\'" "lharc x")
-   '("\\.arc\\'" "arc x")
-   '("\\.shar\\'" "unshar")
-   '("\\.rar\\'" "unrar x")
-   '("\\.7z\\'" "7z x")
-
-   ;; Compression.
-   (list "\\.g?z\\'" '(concat "gunzip" (if dired-guess-shell-gzip-quiet " 
-q")))
-   (list "\\.dz\\'" "dictunzip")
-   (list "\\.bz2\\'" "bunzip2")
-   (list "\\.xz\\'" "unxz")
-   (list "\\.Z\\'" "uncompress"
-        ;; Optional conversion to gzip format.
-        '(concat "znew" (if dired-guess-shell-gzip-quiet " -q")
-                 " " dired-guess-shell-znew-switches))
-
-   '("\\.sign?\\'" "gpg --verify"))
-
-  "Default alist used for shell command guessing.
-See `dired-guess-shell-alist-user'.")
-
-(defcustom dired-guess-shell-alist-user nil
-  "User-defined alist of rules for suggested commands.
-These rules take precedence over the predefined rules in the variable
-`dired-guess-shell-alist-default' (to which they are prepended).
-
-Each element of this list looks like
-
-    (REGEXP COMMAND...)
-
-COMMAND will be used if REGEXP matches the file to be processed.
-If several files are to be processed, REGEXP has to match all the
-files.
-
-Each COMMAND can either be a string or a Lisp expression that evaluates
-to a string.  If this expression needs to consult the name of the file for
-which the shell commands are being requested, it can access that file name
-as the variable `file'.
-
-If several COMMANDs are given, the first one will be the default
-and the rest will be added temporarily to the history and can be retrieved
-with `previous-history-element' 
(\\<minibuffer-mode-map>\\[previous-history-element]).
-
-The variable `dired-guess-shell-case-fold-search' controls whether
-REGEXP is matched case-sensitively."
-  :group 'dired-x
-  :type '(alist :key-type regexp :value-type (repeat sexp)))
-
-(defcustom dired-guess-shell-case-fold-search t
-  "If non-nil, `dired-guess-shell-alist-default' and
-`dired-guess-shell-alist-user' are matched case-insensitively."
-  :group 'dired-x
-  :type 'boolean)
-
-(defun dired-guess-default (files)
-  "Return a shell command, or a list of commands, appropriate for FILES.
-See `dired-guess-shell-alist-user'."
-  (let* ((case-fold-search dired-guess-shell-case-fold-search)
-         (programs
-          (delete-dups
-           (mapcar
-            (lambda (command)
-              (eval command `((file . ,(car files)))))
-            (seq-reduce
-             #'append
-             (mapcar #'cdr
-                     (seq-filter (lambda (elem)
-                                   (seq-every-p
-                                    (lambda (file)
-                                      (string-match-p (car elem) file))
-                                    files))
-                                 (append dired-guess-shell-alist-user
-                                         dired-guess-shell-alist-default)))
-             nil)))))
-    (if (length= programs 1)
-        (car programs)
-      programs)))
-
-(defun dired-guess-shell-command (prompt files)
-  "Ask user with PROMPT for a shell command, guessing a default from FILES."
-  (let ((default (dired-guess-default files))
-        default-list val)
-    (if (null default)
-        ;; Nothing to guess
-        (read-shell-command prompt nil 'dired-shell-command-history)
-      (setq prompt (replace-regexp-in-string ": $" " " prompt))
-      (if (listp default)
-          ;; More than one guess
-          (setq default-list default
-                default (car default)
-                prompt (concat
-                        prompt
-                        (format "{%d guesses} " (length default-list))))
-        ;; Just one guess
-        (setq default-list (list default)))
-      ;; Put the first guess in the prompt but not in the initial value.
-      (setq prompt (concat prompt (format "[%s]: " default)))
-      ;; All guesses can be retrieved with M-n
-      (setq val (read-shell-command prompt nil
-                                    'dired-shell-command-history
-                                    default-list))
-      ;; If we got a return, then return default.
-      (if (equal val "") default val))))
-
-
-;;; Relative symbolic links
-
-(declare-function make-symbolic-link "fileio.c")
-
-(defvar dired-keep-marker-relsymlink ?S
-  "See variable `dired-keep-marker-move'.")
-
-(defun dired-make-relative-symlink (file1 file2 &optional ok-if-already-exists)
-  "Make a symbolic link (pointing to FILE1) in FILE2.
-The link is relative (if possible), for example
-
-    \"/vol/tex/bin/foo\" \"/vol/local/bin/foo\"
-
-results in
-
-    \"../../tex/bin/foo\" \"/vol/local/bin/foo\""
-  (interactive "FRelSymLink: \nFRelSymLink %s: \np")
-  (let (name1 name2 len1 len2 (index 0) sub)
-    (setq file1 (expand-file-name file1)
-          file2 (expand-file-name file2)
-          len1 (length file1)
-          len2 (length file2))
-    ;; Find common initial file name components:
-    (let (next)
-      (while (and (setq next (string-search "/" file1 index))
-                  (< (setq next (1+ next)) (min len1 len2))
-                  ;; For the comparison, both substrings must end in
-                  ;; `/', so NEXT is *one plus* the result of the
-                  ;; string-search.
-                  ;; E.g., consider the case of linking "/tmp/a/abc"
-                  ;; to "/tmp/abc" erroneously giving "/tmp/a" instead
-                  ;; of "/tmp/" as common initial component
-                  (string-equal (substring file1 0 next)
-                                (substring file2 0 next)))
-        (setq index next))
-      (setq name2 file2
-            sub (substring file1 0 index)
-            name1 (substring file1 index)))
-    (if (string-equal sub "/")
-        ;; No common initial file name found
-        (setq name1 file1)
-      ;; Else they have a common parent directory
-      (let ((tem (substring file2 index))
-            (start 0)
-            (count 0))
-        ;; Count number of slashes we must compensate for ...
-        (while (setq start (string-search "/" tem start))
-          (setq count (1+ count)
-                start (1+ start)))
-        ;; ... and prepend a "../" for each slash found:
-        (dotimes (_ count)
-          (setq name1 (concat "../" name1)))))
-    (make-symbolic-link
-     (directory-file-name name1)        ; must not link to foo/
-                                        ; (trailing slash!)
-     name2 ok-if-already-exists)))
-
-(autoload 'dired-do-create-files "dired-aux")
-
-;;;###autoload
-(defun dired-do-relsymlink (&optional arg)
-  "Relative symlink all marked (or next ARG) files into a directory.
-Otherwise make a relative symbolic link to the current file.
-This creates relative symbolic links like
-
-    foo -> ../bar/foo
-
-not absolute ones like
-
-    foo -> /ugly/file/name/that/may/change/any/day/bar/foo
-
-For absolute symlinks, use \\[dired-do-symlink]."
-  (interactive "P")
-  (dired-do-create-files 'relsymlink #'dired-make-relative-symlink
-                         "RelSymLink" arg dired-keep-marker-relsymlink))
-
-(autoload 'dired-mark-read-regexp "dired-aux")
-(autoload 'dired-do-create-files-regexp "dired-aux")
-
-(defun dired-do-relsymlink-regexp (regexp newname &optional arg whole-name)
-  "RelSymlink all marked files containing REGEXP to NEWNAME.
-See functions `dired-do-rename-regexp' and `dired-do-relsymlink'
-for more info."
-  (interactive (dired-mark-read-regexp "RelSymLink"))
-  (dired-do-create-files-regexp
-   #'dired-make-relative-symlink
-   "RelSymLink" arg regexp newname whole-name dired-keep-marker-relsymlink))
-
-
 ;;; Visit all marked files simultaneously
 
 ;; Brief Description:
@@ -1181,31 +769,6 @@ NOSELECT the files are merely found but not selected."
 
 ;;; Miscellaneous commands
 
-;; Run man on files.
-
-(declare-function Man-getpage-in-background "man" (topic))
-
-(defvar manual-program) ; from man.el
-
-(defun dired-man ()
-  "Run `man' on this file."
-  ;; Used also to say: "Display old buffer if buffer name matches filename."
-  ;; but I have no idea what that means.
-  (interactive)
-  (require 'man)
-  (let* ((file (dired-get-filename))
-         (manual-program (string-replace "*" "%s"
-                          (dired-guess-shell-command
-                           "Man command: " (list file)))))
-    (Man-getpage-in-background file)))
-
-;; Run Info on files.
-
-(defun dired-info ()
-  "Run `info' on this file."
-  (interactive)
-  (info (dired-get-filename)))
-
 ;; Run mail on mail folders.
 
 (declare-function vm-visit-folder "ext:vm" (folder &optional read-only))
@@ -1249,14 +812,6 @@ otherwise."
 
 ;;; Miscellaneous internal functions
 
-;; This should be a builtin
-(defun dired-buffer-more-recently-used-p (buffer1 buffer2)
-  "Return t if BUFFER1 is more recently used than BUFFER2.
-Considers buffers closer to the car of `buffer-list' to be more recent."
-  (and (not (equal buffer1 buffer2))
-       (memq buffer1 (buffer-list))
-       (not (memq buffer1 (memq buffer2 (buffer-list))))))
-
 ;; Needed if ls -lh is supported and also for GNU ls -ls.
 (defun dired-x--string-to-number (str)
   "Like `string-to-number' but recognize a trailing unit prefix.
@@ -1458,12 +1013,13 @@ Binding direction based on `dired-x-hands-off-my-keys'."
   (interactive)
   (if (called-interactively-p 'interactive)
       (setq dired-x-hands-off-my-keys
-            (not (y-or-n-p "Bind dired-x-find-file over find-file? "))))
+            (not (y-or-n-p (format-message
+                            "Bind `dired-x-find-file' over `find-file'?")))))
   (unless dired-x-hands-off-my-keys
-    (define-key (current-global-map) [remap find-file]
-      'dired-x-find-file)
-    (define-key (current-global-map) [remap find-file-other-window]
-      'dired-x-find-file-other-window)))
+    (keymap-set (current-global-map) "<remap> <find-file>"
+                #'dired-x-find-file)
+    (keymap-set (current-global-map) "<remap> <find-file-other-window>"
+                #'dired-x-find-file-other-window)))
 
 ;; Now call it so binding is correct.  This could go in the :initialize
 ;; slot, but then dired-x-bind-find-file has to be defined before the
@@ -1531,13 +1087,8 @@ If `current-prefix-arg' is non-nil, uses name at point 
as guess."
                         nil (file-name-nondirectory guess)))
     (read-file-name prompt default-directory)))
 
-(define-obsolete-function-alias 'read-filename-at-point
-  'dired-x-read-filename-at-point "24.1") ; is this even needed?
-
-
-;;; Epilog
-
-(define-obsolete-function-alias 'dired-x-submit-report 'report-emacs-bug 
"24.1")
+(define-obsolete-function-alias 'dired-man #'dired-do-man "29.1")
+(define-obsolete-function-alias 'dired-info #'dired-do-info "29.1")
 
 
 ;; As Barry Warsaw would say: "This might be useful..."
diff --git a/lisp/dired.el b/lisp/dired.el
index 55e150e9e0..fa06c8fd44 100644
--- a/lisp/dired.el
+++ b/lisp/dired.el
@@ -40,9 +40,6 @@
 (require 'dired-loaddefs nil t)
 (require 'dnd)
 
-(declare-function dired-buffer-more-recently-used-p
-                 "dired-x" (buffer1 buffer2))
-
 
 ;;; Customizable variables
 
@@ -56,6 +53,11 @@
   :prefix "dired-"
   :group 'dired)
 
+(defgroup dired-guess nil
+  "Guess shell command in Dired."
+  :prefix "dired-"
+  :group 'dired)
+
 ;;;###autoload
 (defcustom dired-listing-switches (purecopy "-al")
   "Switches passed to `ls' for Dired.  MUST contain the `l' option.
@@ -106,10 +108,10 @@ If `dired-maybe-use-globstar' is non-nil, then 
`dired-insert-directory'
 checks this alist to enable globstar in the shell subprocess.")
 
 (defcustom dired-chown-program
-  (purecopy (cond ((executable-find "chown") "chown")
-                  ((file-executable-p "/usr/sbin/chown") "/usr/sbin/chown")
-                  ((file-executable-p "/etc/chown") "/etc/chown")
-                  (t "chown")))
+  (cond ((executable-find "chown") "chown")
+        ((file-executable-p "/usr/sbin/chown") "/usr/sbin/chown")
+        ((file-executable-p "/etc/chown") "/etc/chown")
+        (t "chown"))
   "Name of chown command (usually `chown')."
   :group 'dired
   :type 'file)
@@ -164,7 +166,7 @@ always set this variable to t."
   :type 'boolean
   :group 'dired-mark)
 
-(defcustom dired-trivial-filenames (purecopy "\\`\\.\\.?\\'\\|\\`\\.?#")
+(defcustom dired-trivial-filenames "\\`\\.\\.?\\'\\|\\`\\.?#"
   "Regexp of files to skip when finding first file of a directory.
 A value of nil means move to the subdir line.
 A value of t means move to first file."
@@ -210,6 +212,11 @@ If a character, new links are unconditionally marked with 
that character."
                 (character :tag "Mark"))
   :group 'dired-mark)
 
+(defvar dired-keep-marker-relsymlink ?S
+  "Controls marking of newly made relative symbolic links.
+If t, they are marked if and as the files linked to were marked.
+If a character, new links are unconditionally marked with that character.")
+
 (defcustom dired-free-space 'first
   "Whether and how to display the amount of free disk space in Dired buffers.
 If nil, don't display.
@@ -417,6 +424,72 @@ is anywhere on its Dired line, except the beginning of the 
line."
   :type 'boolean
   :version "28.1")
 
+(defcustom dired-guess-shell-case-fold-search t
+  "If non-nil, `dired-guess-shell-alist-default' and
+`dired-guess-shell-alist-user' are matched case-insensitively."
+  :group 'dired-guess
+  :type 'boolean
+  :version "29.1")
+
+(defcustom dired-guess-shell-alist-user nil
+  "User-defined alist of rules for suggested commands.
+These rules take precedence over the predefined rules in the variable
+`dired-guess-shell-alist-default' (to which they are prepended).
+
+Each element of this list looks like
+
+    (REGEXP COMMAND...)
+
+COMMAND will be used if REGEXP matches the file to be processed.
+If several files are to be processed, REGEXP has to match all the
+files.
+
+Each COMMAND can either be a string or a Lisp expression that evaluates
+to a string.  If this expression needs to consult the name of the file for
+which the shell commands are being requested, it can access that file name
+as the variable `file'.
+
+If several COMMANDs are given, the first one will be the default
+and the rest will be added temporarily to the history and can be retrieved
+with `previous-history-element' 
(\\<minibuffer-mode-map>\\[previous-history-element]).
+
+The variable `dired-guess-shell-case-fold-search' controls whether
+REGEXP is matched case-sensitively."
+  :group 'dired-guess
+  :type '(alist :key-type regexp :value-type (repeat sexp))
+  :version "29.1")
+
+(defcustom dired-guess-shell-gnutar
+  (catch 'found
+    (dolist (exe '("tar" "gtar"))
+      (if (with-temp-buffer
+            (ignore-errors (call-process exe nil t nil "--version"))
+            (and (re-search-backward "GNU tar" nil t) t))
+          (throw 'found exe))))
+  "If non-nil, name of GNU tar executable.
+\(E.g., \"tar\" or \"gtar\").  The `z' switch will be used with it for
+compressed or gzip'ed tar files.  If you don't have GNU tar, set this
+to nil: a pipe using `zcat' or `gunzip -c' will be used."
+  ;; Changed from system-type test to testing --version output.
+  ;; Maybe test --help for -z instead?
+  :group 'dired-guess
+  :type '(choice (const :tag "Not GNU tar" nil)
+                 (string :tag "Command name"))
+  :version "29.1")
+
+(defcustom dired-guess-shell-gzip-quiet t
+  "Non-nil says pass -q to gzip overriding verbose GZIP environment."
+  :group 'dired-guess
+  :type 'boolean
+  :version "29.1")
+
+(defcustom dired-guess-shell-znew-switches nil
+  "If non-nil, then string of switches passed to `znew', example: \"-K\"."
+  :group 'dired-guess
+  :type '(choice (const :tag "None" nil)
+                 (string :tag "Switches"))
+  :version "29.1")
+
 
 ;;; Internal variables
 
@@ -713,7 +786,7 @@ Subexpression 2 must end right before the \\n.")
                nil
                '(1 'dired-broken-symlink)
                '(2 dired-symlink-face)
-               '(3 'dired-broken-symlink)))
+               '(3 '(face dired-broken-symlink dired-symlink-filename t))))
    ;;
    ;; Symbolic link to a directory.
    (list dired-re-sym
@@ -725,7 +798,7 @@ Subexpression 2 must end right before the \\n.")
                '(dired-move-to-filename)
                nil
                '(1 dired-symlink-face)
-               '(2 dired-directory-face)))
+               '(2 '(face dired-directory-face dired-symlink-filename t))))
    ;;
    ;; Symbolic link to a non-directory.
    (list dired-re-sym
@@ -739,7 +812,7 @@ Subexpression 2 must end right before the \\n.")
                '(dired-move-to-filename)
                nil
                '(1 dired-symlink-face)
-               '(2 'default)))
+               '(2 '(face default dired-symlink-filename t))))
    ;;
    ;; Sockets, pipes, block devices, char devices.
    (list dired-re-special
@@ -773,19 +846,20 @@ of the region if `dired-mark-region' is non-nil.  
Otherwise, operate
 on the whole buffer.
 
 Return value is the number of files marked, or nil if none were marked."
-  `(let ((inhibit-read-only t) count
+  `(let ((msg ,msg)
+         (inhibit-read-only t) count
          (use-region-p (dired-mark--region-use-p))
          (beg (dired-mark--region-beginning))
          (end (dired-mark--region-end)))
     (save-excursion
       (setq count 0)
-      (when ,msg
+      (when msg
        (message "%s %ss%s%s..."
                 (cond ((eq dired-marker-char ?\s) "Unmarking")
                       ((eq dired-del-marker dired-marker-char)
                        "Flagging")
                       (t "Marking"))
-                ,msg
+                msg
                 (if (eq dired-del-marker dired-marker-char)
                     " for deletion"
                   "")
@@ -800,9 +874,9 @@ Return value is the number of files marked, or nil if none 
were marked."
             (insert dired-marker-char)
             (setq count (1+ count))))
         (forward-line 1))
-      (when ,msg (message "%s %s%s %s%s%s"
+      (when msg (message "%s %s%s %s%s%s"
                         count
-                        ,msg
+                        msg
                         (dired-plural-s count)
                         (if (eq dired-marker-char ?\s) "un" "")
                         (if (eq dired-marker-char dired-del-marker)
@@ -1138,7 +1212,8 @@ If DIRNAME is already in a Dired buffer, that buffer is 
used without refresh."
             (modtime (visited-file-modtime)))
         (or (eq modtime 0)
             (not (eq (file-attribute-type attributes) t))
-            (equal (file-attribute-modification-time attributes) modtime)))))
+            (time-equal-p (file-attribute-modification-time attributes)
+                          modtime)))))
 
 (defvar auto-revert-remote-files)
 
@@ -1187,13 +1262,13 @@ The return value is the target column for the file 
names."
     (dired-goto-next-file)
     ;; Use point difference instead of `current-column', because
     ;; the former works when `dired-hide-details-mode' is enabled.
-    (let* ((first (- (point) (point-at-bol)))
+    (let* ((first (- (point) (line-beginning-position)))
            (target first))
       (while (and (not (eobp))
                   (progn
                     (forward-line)
                     (dired-move-to-filename)))
-        (when-let* ((distance (- (point) (point-at-bol)))
+        (when-let* ((distance (- (point) (line-beginning-position)))
                     (higher (> distance target)))
           (setq target distance)))
       (and (/= first target) target))))
@@ -1209,7 +1284,7 @@ The return value is the target column for the file names."
         (while (dired-move-to-filename)
           ;; Use point difference instead of `current-column', because
           ;; the former works when `dired-hide-details-mode' is enabled.
-          (let ((distance (- target (- (point) (point-at-bol))))
+          (let ((distance (- target (- (point) (line-beginning-position))))
                 (inhibit-read-only t))
             (unless (zerop distance)
               (re-search-backward regexp nil t)
@@ -2079,8 +2154,10 @@ Do so according to the former subdir alist 
OLD-SUBDIR-ALIST."
   "D"       #'dired-do-delete
   "G"       #'dired-do-chgrp
   "H"       #'dired-do-hardlink
+  "I"       #'dired-do-info
   "L"       #'dired-do-load
   "M"       #'dired-do-chmod
+  "N"       #'dired-do-man
   "O"       #'dired-do-chown
   "P"       #'dired-do-print
   "Q"       #'dired-do-find-regexp-and-replace
@@ -2088,6 +2165,7 @@ Do so according to the former subdir alist 
OLD-SUBDIR-ALIST."
   "S"       #'dired-do-symlink
   "T"       #'dired-do-touch
   "X"       #'dired-do-shell-command
+  "Y"       #'dired-do-relsymlink
   "Z"       #'dired-do-compress
   "c"       #'dired-do-compress-to
   "!"       #'dired-do-shell-command
@@ -2117,6 +2195,7 @@ Do so according to the former subdir alist 
OLD-SUBDIR-ALIST."
   "% H"     #'dired-do-hardlink-regexp
   "% R"     #'dired-do-rename-regexp
   "% S"     #'dired-do-symlink-regexp
+  "% Y"     #'dired-do-relsymlink-regexp
   "% &"     #'dired-flag-garbage-files
   ;; Commands for marking and unmarking.
   "* *"     #'dired-mark-executables
@@ -2168,6 +2247,7 @@ Do so according to the former subdir alist 
OLD-SUBDIR-ALIST."
   "S-SPC"   #'dired-previous-line
   "<remap> <next-line>"        #'dired-next-line
   "<remap> <previous-line>"    #'dired-previous-line
+  "M-G"    #'dired-goto-subdir
   ;; hiding
   "$"       #'dired-hide-subdir
   "M-$"     #'dired-hide-all
@@ -2294,6 +2374,9 @@ Do so according to the former subdir alist 
OLD-SUBDIR-ALIST."
     ["Symlink..." dired-do-symlink-regexp
      :visible (fboundp 'make-symbolic-link)
      :help "Make symbolic links for files matching regexp"]
+    ["Relative Symlink..." dired-do-relsymlink-regexp
+     :visible (fboundp 'make-symbolic-link)
+     :help "Make relative symbolic links for files matching regexp"]
     ["Hardlink..." dired-do-hardlink-regexp
      :help "Make hard links for files matching regexp"]
     ["Upcase" dired-upcase
@@ -2363,6 +2446,9 @@ Do so according to the former subdir alist 
OLD-SUBDIR-ALIST."
     ["Symlink to..." dired-do-symlink
      :visible (fboundp 'make-symbolic-link)
      :help "Make symbolic links for current or marked files"]
+    ["Relative Symlink to..." dired-do-relsymlink
+     :visible (fboundp 'make-symbolic-link)
+     :help "Make relative symbolic links for current or marked files"]
     ["Hardlink to..." dired-do-hardlink
      :help "Make hard links for current or marked files"]
     ["Print..." dired-do-print
@@ -2467,7 +2553,7 @@ Type \\[dired-do-copy] to Copy files.
 Type \\[dired-sort-toggle-or-edit] to toggle Sorting by name/date or change 
the `ls' switches.
 Type \\[revert-buffer] to read all currently expanded directories aGain.
   This retains all marks and hides subdirs again that were hidden before.
-Use `SPC' and `DEL' to move down and up by lines.
+Use \\`SPC' and \\`DEL' to move down and up by lines.
 
 If Dired ever gets confused, you can either type \\[revert-buffer] \
 to read the
@@ -2951,10 +3037,11 @@ See options: `dired-hide-details-hide-symlink-targets' 
and
   ;; approximate ("anywhere on the line is fine").
   ;; FIXME: This also removes other invisible properties!
   (save-excursion
-    (remove-list-of-text-properties
-     (progn (goto-char start) (line-end-position))
-     (progn (goto-char end) (line-end-position))
-     '(invisible))))
+    (let ((inhibit-read-only t))
+      (remove-list-of-text-properties
+       (progn (goto-char start) (line-end-position))
+       (progn (goto-char end) (line-end-position))
+       '(invisible)))))
 
 ;;; Functions for finding the file name in a dired buffer line
 
@@ -3059,7 +3146,11 @@ If EOL, it should be an position to use instead of
 
 (defun dired-copy-filename-as-kill (&optional arg)
   "Copy names of marked (or next ARG) files into the kill ring.
-The names are separated by a space.
+If there are several names, they will be separated by a space,
+and file names that have spaces or quote characters in them will
+be quoted (with double quotes).  (When there's a single file, no
+quoting is done.)
+
 With a zero prefix arg, use the absolute file name of each marked file.
 With \\[universal-argument], use the file name relative to the Dired buffer's
 `default-directory'.  (This still may contain slashes if in a subdirectory.)
@@ -3069,19 +3160,26 @@ prefix arg and marked files are ignored in this case.
 
 You can then feed the file name(s) to other commands with \\[yank]."
   (interactive "P")
-  (let ((string
-         (or (dired-get-subdir)
-             (mapconcat #'identity
-                        (if arg
-                            (cond ((zerop (prefix-numeric-value arg))
-                                   (dired-get-marked-files))
-                                  ((consp arg)
-                                   (dired-get-marked-files t))
-                                  (t
-                                   (dired-get-marked-files
-                                   'no-dir (prefix-numeric-value arg))))
-                          (dired-get-marked-files 'no-dir))
-                        " "))))
+  (let* ((files
+          (or (ensure-list (dired-get-subdir))
+              (if arg
+                  (cond ((zerop (prefix-numeric-value arg))
+                         (dired-get-marked-files))
+                        ((consp arg)
+                         (dired-get-marked-files t))
+                        (t
+                         (dired-get-marked-files
+                         'no-dir (prefix-numeric-value arg))))
+                (dired-get-marked-files 'no-dir))))
+         (string
+          (if (length= files 1)
+              (car files)
+            (mapconcat (lambda (file)
+                         (if (string-match-p "[ \"']" file)
+                             (format "%S" file)
+                           file))
+                       files
+                       " "))))
     (unless (string= string "")
       (if (eq last-command 'kill-region)
           (kill-append string nil)
@@ -3490,6 +3588,14 @@ is the directory where the file on this line resides."
        (point-max)
       (point))))
 
+;; This should be a builtin
+(defun dired-buffer-more-recently-used-p (buffer1 buffer2)
+  "Return t if BUFFER1 is more recently used than BUFFER2.
+Considers buffers closer to the car of `buffer-list' to be more recent."
+  (and (not (equal buffer1 buffer2))
+       (memq buffer1 (buffer-list))
+       (not (memq buffer1 (memq buffer2 (buffer-list))))))
+
 
 ;;; Deleting files
 
@@ -3690,13 +3796,21 @@ See `dired-delete-file' in case you wish that."
   (dired-remove-entry file)
   (dired-clean-up-after-deletion file))
 
-(defvar dired-clean-up-buffers-too)
-(defvar dired-clean-confirm-killing-deleted-buffers)
+(defcustom dired-clean-up-buffers-too t
+  "Non-nil means offer to kill buffers visiting files and dirs deleted in 
Dired."
+  :type 'boolean
+  :group 'dired)
+
+(defcustom dired-clean-confirm-killing-deleted-buffers t
+  "If nil, don't ask whether to kill buffers visiting deleted files."
+  :type 'boolean
+  :group 'dired
+  :version "26.1")
 
 (defun dired-clean-up-after-deletion (fn)
   "Clean up after a deleted file or directory FN.
-Removes any expanded subdirectory of deleted directory.  If
-`dired-x' is loaded and `dired-clean-up-buffers-too' is non-nil,
+Removes any expanded subdirectory of deleted directory.
+If `dired-clean-up-buffers-too' is non-nil,
 kill any buffers visiting those files, prompting for
 confirmation.  To disable the confirmation, see
 `dired-clean-confirm-killing-deleted-buffers'."
@@ -4795,6 +4909,38 @@ Interactively with prefix argument, read FILE-NAME."
              (read-file-name "Jump to Dired file: "))))
   (dired-jump t file-name))
 
+(defvar-keymap dired-jump-map
+  :doc "Keymap to repeat `dired-jump'.  Used in `repeat-mode'."
+  "j"   #'dired-jump
+  "C-j" #'dired-jump)
+(put 'dired-jump 'repeat-map 'dired-jump-map)
+
+
+;;; Miscellaneous commands
+
+(declare-function Man-getpage-in-background "man" (topic))
+(defvar manual-program) ; from man.el
+
+(defun dired-do-man ()
+  "In Dired, run `man' on this file."
+  (interactive nil dired-mode)
+  (require 'man)
+  (let* ((file (dired-get-file-for-visit))
+         (manual-program (string-replace "*" "%s"
+                                         (dired-guess-shell-command
+                                          "Man command: " (list file)))))
+    (Man-getpage-in-background file)))
+
+(defun dired-do-info ()
+  "In Dired, run `info' on this file."
+  (interactive nil dired-mode)
+  (info (dired-get-file-for-visit)))
+
+(defun dired-do-eww ()
+  "In Dired, visit file in EWW."
+  (interactive nil dired-mode)
+  (eww-open-file (dired-get-file-for-visit)))
+
 (provide 'dired)
 
 (run-hooks 'dired-load-hook)           ; for your customizations
diff --git a/lisp/dirtrack.el b/lisp/dirtrack.el
index da60840f8b..4f092f95e0 100644
--- a/lisp/dirtrack.el
+++ b/lisp/dirtrack.el
@@ -26,13 +26,14 @@
 ;; Shell directory tracking by watching the prompt.
 ;;
 ;; This is yet another attempt at a directory-tracking package for
-;; Emacs shell-mode.  However, this package makes one strong assumption:
-;; that you can customize your shell's prompt to contain the
-;; current working directory.  Most shells do support this, including
-;; almost every type of Bourne and C shell on Unix, the native shells on
-;; Windows95 (COMMAND.COM) and Windows NT (CMD.EXE), and most 3rd party
-;; Windows shells.  If you cannot do this, or do not wish to, this package
-;; will be useless to you.
+;; Emacs shell-mode.  However, this package makes one strong
+;; assumption: that you can customize your shell's prompt to contain
+;; the current working directory.  Most shells do support this,
+;; including almost every type of Bourne and C shell on Unix, the
+;; native shells on Windows 9X (COMMAND.COM) and modern MS-Windows
+;; systems (cmd.exe), and most 3rd party MS-Windows shells.  If you
+;; cannot do this, or do not wish to, this package will be useless to
+;; you.
 ;;
 ;; Installation:
 ;;
@@ -63,7 +64,7 @@
 ;;
 ;; Examples:
 ;;
-;; 1) On Windows NT, my prompt is set to emacs$S$P$G.
+;; 1) On MS-Windows, my prompt is set to emacs$S$P$G.
 ;; 'dirtrack-list' is set to (list "^emacs \\([a-zA-Z]:.*\\)>" 1)
 ;;
 ;; 2) On Solaris running bash, my prompt is set like this:
@@ -92,7 +93,7 @@
 ;; A final note:
 ;;
 ;;   I run LOTS of shell buffers through Emacs, sometimes as different users
-;;   (eg, when logged in as myself, I'll run a root shell in the same Emacs).
+;;   (e.g., when logged in as myself, I'll run a root shell in the same Emacs).
 ;;   If you do this, and the shell prompt contains a ~, Emacs will interpret
 ;;   this relative to the user which owns the Emacs process, not the user
 ;;   who owns the shell buffer.  This may cause dirtrack to behave strangely
@@ -100,7 +101,7 @@
 ;;   with a ~ in it).
 ;;
 ;;   The same behavior can occur if you use dirtrack with remote filesystems
-;;   (using telnet, rlogin, etc) as Emacs will be checking the local
+;;   (using telnet, ssh, etc.) as Emacs will be checking the local
 ;;   filesystem, not the remote one.  This problem is not specific to dirtrack,
 ;;   but also affects file completion, etc.
 
diff --git a/lisp/dnd.el b/lisp/dnd.el
index 9d72a4b595..70852885a8 100644
--- a/lisp/dnd.el
+++ b/lisp/dnd.el
@@ -106,6 +106,18 @@ program."
   :version "29.1"
   :group 'dnd)
 
+(defcustom dnd-direct-save-remote-files 'x
+  "Whether or not to perform a direct save of remote files.
+This is compatible with less programs, but means dropped files
+will be saved with their actual file names, and not a temporary
+file name provided by TRAMP.
+
+This defaults to `x', which means only to drop that way on X
+Windows."
+  :type '(choice (const :tag "Only use direct save on X Windows" x)
+                 (const :tag "Use direct save everywhere" t)
+                 (const :tag "Don't use direct save")))
+
 ;; Functions
 
 (defun dnd-handle-movement (posn)
@@ -315,7 +327,7 @@ in that list instead."
   "Begin dragging TEXT from FRAME.
 Initate a drag-and-drop operation allowing the user to drag text
 from Emacs to another program (the drop target), then block until
-the drop is completed or is cancelled.
+the drop is completed or is canceled.
 
 If the drop completed, return the action that the drop target
 actually performed, which can be one of the following symbols:
@@ -329,14 +341,14 @@ actually performed, which can be one of the following 
symbols:
   - `private', which means the drop target chose to perform an
     unspecified action.
 
-Return nil if the drop was cancelled.
+Return nil if the drop was canceled.
 
 TEXT is a string containing text that will be inserted by the
 program where the drop happened.  FRAME is the frame where the
 mouse is currently held down, or nil, which stands for the
 current frame.  ACTION is one of the symbols `copy' or `move',
 where `copy' means that the text should be inserted by the drop
-target, and `move' means the the same as `copy', but in addition
+target, and `move' means the same as `copy', but in addition
 the caller might have to delete TEXT from its source after this
 function returns.  If ALLOW-SAME-FRAME is nil, ignore any drops
 on FRAME itself.
@@ -371,7 +383,7 @@ currently being held down.  It should only be called upon a
   "Begin dragging FILE from FRAME.
 Initate a drag-and-drop operation allowing the user to drag a file
 from Emacs to another program (the drop target), then block until
-the drop happens or is cancelled.
+the drop happens or is canceled.
 
 Return the action that the drop target actually performed, which
 can be one of the following symbols:
@@ -387,7 +399,7 @@ can be one of the following symbols:
   - `private', which means the drop target chose to perform an
     unspecified action.
 
-Return nil if the drop was cancelled.
+Return nil if the drop was canceled.
 
 FILE is the file name that will be sent to the program where the
 drop happened.  If it is a remote file, Emacs will make a
@@ -409,48 +421,58 @@ currently being held down.  It should only be called upon 
a
   (dnd-remove-last-dragged-remote-file)
   (unless action
     (setq action 'copy))
-  (let ((original-file file))
-    (when (file-remote-p file)
-      (if (eq action 'link)
-          (error "Cannot create symbolic link to remote file")
-        (setq file (file-local-copy file))
-        (setq dnd-last-dragged-remote-file file)
-        (add-hook 'kill-emacs-hook
-                  #'dnd-remove-last-dragged-remote-file)))
-    (gui-set-selection 'XdndSelection
-                       (propertize (expand-file-name file) 'text/uri-list
-                                   (concat "file://"
-                                           (expand-file-name file))))
-    (let ((return-value
-           (x-begin-drag '(;; Xdnd types used by GTK, Qt, and most other
-                           ;; modern programs that expect filenames to
-                           ;; be supplied as URIs.
-                           "text/uri-list" "text/x-xdnd-username"
-                           ;; Traditional X selection targets used by
-                           ;; programs supporting the Motif
-                           ;; drag-and-drop protocols.  Also used by NS
-                           ;; and Haiku.
-                           "FILE_NAME" "FILE" "HOST_NAME"
-                           ;; ToolTalk filename.  Mostly used by CDE
-                           ;; programs.
-                           "_DT_NETFILE")
-                         (cl-ecase action
-                           ('copy 'XdndActionCopy)
-                           ('move 'XdndActionMove)
-                           ('link 'XdndActionLink))
-                         frame nil allow-same-frame)))
-      (cond
-       ((eq return-value 'XdndActionCopy) 'copy)
-       ((eq return-value 'XdndActionMove)
-        (prog1 'move
-          ;; If original-file is a remote file, delete it from the
-          ;; remote as well.
-          (when (file-remote-p original-file)
-            (ignore-errors
-              (delete-file original-file)))))
-       ((eq return-value 'XdndActionLink) 'link)
-       ((not return-value) nil)
-       (t 'private)))))
+  (if (and (or (and (eq dnd-direct-save-remote-files 'x)
+                    (eq (framep (or frame
+                                    (selected-frame)))
+                        'x))
+               (and dnd-direct-save-remote-files
+                    (not (eq dnd-direct-save-remote-files 'x))))
+           (eq action 'copy)
+           (file-remote-p file))
+      (dnd-direct-save file (file-name-nondirectory file)
+                       frame allow-same-frame)
+    (let ((original-file file))
+      (when (file-remote-p file)
+        (if (eq action 'link)
+            (error "Cannot create symbolic link to remote file")
+          (setq file (file-local-copy file))
+          (setq dnd-last-dragged-remote-file file)
+          (add-hook 'kill-emacs-hook
+                    #'dnd-remove-last-dragged-remote-file)))
+      (gui-set-selection 'XdndSelection
+                         (propertize (expand-file-name file) 'text/uri-list
+                                     (concat "file://"
+                                             (expand-file-name file))))
+      (let ((return-value
+             (x-begin-drag '(;; Xdnd types used by GTK, Qt, and most other
+                             ;; modern programs that expect filenames to
+                             ;; be supplied as URIs.
+                             "text/uri-list" "text/x-xdnd-username"
+                             ;; Traditional X selection targets used by
+                             ;; programs supporting the Motif
+                             ;; drag-and-drop protocols.  Also used by NS
+                             ;; and Haiku.
+                             "FILE_NAME" "FILE" "HOST_NAME"
+                             ;; ToolTalk filename.  Mostly used by CDE
+                             ;; programs.
+                             "_DT_NETFILE")
+                           (cl-ecase action
+                             ('copy 'XdndActionCopy)
+                             ('move 'XdndActionMove)
+                             ('link 'XdndActionLink))
+                           frame nil allow-same-frame)))
+        (cond
+         ((eq return-value 'XdndActionCopy) 'copy)
+         ((eq return-value 'XdndActionMove)
+          (prog1 'move
+            ;; If original-file is a remote file, delete it from the
+            ;; remote as well.
+            (when (file-remote-p original-file)
+              (ignore-errors
+                (delete-file original-file)))))
+         ((eq return-value 'XdndActionLink) 'link)
+         ((not return-value) nil)
+         (t 'private))))))
 
 (defun dnd-begin-drag-files (files &optional frame action allow-same-frame)
   "Begin dragging FILES from FRAME.
@@ -477,6 +499,9 @@ FILES will be dragged."
           (error (message "Failed to download file: %s" error)
                  (setcar tem nil))))
       (setq tem (cdr tem)))
+    (when dnd-last-dragged-remote-file
+      (add-hook 'kill-emacs-hook
+                #'dnd-remove-last-dragged-remote-file))
     ;; Remove any files that failed to download from a remote host.
     (setq new-files (delq nil new-files))
     (unless new-files
@@ -520,6 +545,27 @@ FILES will be dragged."
        ((not return-value) nil)
        (t 'private)))))
 
+(declare-function x-dnd-do-direct-save "x-dnd.el")
+
+(defun dnd-direct-save (file name &optional frame allow-same-frame)
+  "Drag FILE from FRAME, but do not treat it as an actual file.
+Instead, ask the target window to insert the file with NAME.
+File managers will create a file in the displayed directory with
+the contents of FILE and the name NAME, while text editors will
+insert the contents of FILE in a new document named
+NAME.
+
+ALLOW-SAME-FRAME means the same as in `dnd-begin-file-drag'.
+Return `copy' if the drop was successful, else nil."
+  (setq file (expand-file-name file))
+  (cond ((eq window-system 'x)
+         (when (x-dnd-do-direct-save file name frame
+                                     allow-same-frame)
+           'copy))
+        ;; Avoid infinite recursion.
+        (t (let ((dnd-direct-save-remote-files nil))
+             (dnd-begin-file-drag file frame nil allow-same-frame)))))
+
 (provide 'dnd)
 
 ;;; dnd.el ends here
diff --git a/lisp/doc-view.el b/lisp/doc-view.el
index 9d27347360..29da3b4297 100644
--- a/lisp/doc-view.el
+++ b/lisp/doc-view.el
@@ -144,6 +144,7 @@
 (require 'dired)
 (require 'image-mode)
 (require 'jka-compr)
+(require 'filenotify)
 (eval-when-compile (require 'subr-x))
 
 ;;;; Customization Options
@@ -224,19 +225,51 @@ are available (see Info node `(emacs)Document View')"
 (defcustom doc-view-resolution 100
   "Dots per inch resolution used to render the documents.
 Higher values result in larger images."
-  :type 'number)
-
-(defcustom doc-view-mutool-user-stylesheet nil
-  "User stylesheet to use when converting EPUB documents to PDF."
-  :type '(choice (const nil)
-                 (file :must-match t))
-  :version "29.1")
+  :type 'natnum)
 
 (defvar doc-view-doc-type nil
   "The type of document in the current buffer.
 Can be `dvi', `pdf', `ps', `djvu', `odf', `epub', `cbz', `fb2',
 `xps' or `oxps'.")
 
+(defvar doc-view--epub-stylesheet-watcher nil
+  "File watcher for `doc-view-epub-user-stylesheet'.")
+
+(defun doc-view--epub-reconvert (&optional _event)
+  "Reconvert all epub buffers.
+
+EVENT is unused, but necessary to work with the filenotify API."
+  (dolist (x (buffer-list))
+    (with-current-buffer x
+      (when (eq doc-view-doc-type 'epub)
+        (doc-view-reconvert-doc)))))
+
+(defun doc-view-custom-set-epub-user-stylesheet (option-name new-value)
+  "Setter for `doc-view-epub-user-stylesheet'.
+
+Reconverts existing epub buffers when the file used as a user
+stylesheet is switched, or its contents modified."
+  (set-default option-name new-value)
+  (file-notify-rm-watch doc-view--epub-stylesheet-watcher)
+  (doc-view--epub-reconvert)
+  (setq doc-view--epub-stylesheet-watcher
+         (when new-value
+           (file-notify-add-watch new-value '(change) 
#'doc-view--epub-reconvert))))
+
+(defcustom doc-view-epub-user-stylesheet nil
+  "User stylesheet to use when converting EPUB documents to PDF."
+  :type '(choice (const nil)
+                 (file :must-match t))
+  :version "29.1"
+  :set #'doc-view-custom-set-epub-user-stylesheet)
+
+(defvar-local doc-view--current-cache-dir nil
+  "Only used internally.")
+
+(defun doc-view-custom-set-epub-font-size (option-name new-value)
+  (set-default option-name new-value)
+  (doc-view--epub-reconvert))
+
 ;; FIXME: The doc-view-current-* definitions below are macros because they
 ;; map to accessors which we want to use via `setf' as well!
 (defmacro doc-view-current-page (&optional win)
@@ -249,15 +282,6 @@ Can be `dvi', `pdf', `ps', `djvu', `odf', `epub', `cbz', 
`fb2',
 (defvar-local doc-view--current-cache-dir nil
   "Only used internally.")
 
-(defun doc-view-custom-set-epub-font-size (option-name new-value)
-  (set-default option-name new-value)
-  (dolist (x (buffer-list))
-    (with-current-buffer x
-      (when (eq doc-view-doc-type 'epub)
-        (delete-directory doc-view--current-cache-dir t)
-        (doc-view-initiate-display)
-        (doc-view-goto-page (doc-view-current-page))))))
-
 (defcustom doc-view-epub-font-size nil
   "Font size in points for EPUB layout."
   :type '(choice (const nil) integer)
@@ -277,7 +301,7 @@ scaling."
 Has only an effect if `doc-view-scale-internally' is non-nil and support for
 scaling is compiled into Emacs."
   :version "24.1"
-  :type 'number)
+  :type 'natnum)
 
 (defcustom doc-view-dvipdfm-program "dvipdfm"
   "Program to convert DVI files to PDF.
@@ -354,7 +378,8 @@ After such a refresh newly converted pages will be 
available for
 viewing.  If set to nil there won't be any refreshes and the
 pages won't be displayed before conversion of the whole document
 has finished."
-  :type 'integer)
+  :type '(choice natnum
+                 (const :value nil :tag "No refreshes")))
 
 (defcustom doc-view-continuous nil
   "In Continuous mode reaching the page edge advances to next/previous page.
@@ -433,62 +458,60 @@ Typically \"page-%s.png\".")
 
 ;;;; DocView Keymaps
 
-(defvar doc-view-mode-map
-  (let ((map (make-sparse-keymap)))
-    (set-keymap-parent map image-mode-map)
-    ;; Navigation in the document
-    (define-key map (kbd "n")         'doc-view-next-page)
-    (define-key map (kbd "p")         'doc-view-previous-page)
-    (define-key map (kbd "<next>")    'forward-page)
-    (define-key map (kbd "<prior>")   'backward-page)
-    (define-key map [remap forward-page]  'doc-view-next-page)
-    (define-key map [remap backward-page] 'doc-view-previous-page)
-    (define-key map (kbd "SPC")       'doc-view-scroll-up-or-next-page)
-    (define-key map (kbd "S-SPC")     'doc-view-scroll-down-or-previous-page)
-    (define-key map (kbd "DEL")       'doc-view-scroll-down-or-previous-page)
-    (define-key map (kbd "C-n")       'doc-view-next-line-or-next-page)
-    (define-key map (kbd "<down>")    'doc-view-next-line-or-next-page)
-    (define-key map (kbd "C-p")       'doc-view-previous-line-or-previous-page)
-    (define-key map (kbd "<up>")      'doc-view-previous-line-or-previous-page)
-    (define-key map (kbd "M-<")       'doc-view-first-page)
-    (define-key map (kbd "M->")       'doc-view-last-page)
-    (define-key map [remap goto-line] 'doc-view-goto-page)
-    (define-key map (kbd "RET")       'image-next-line)
-    ;; Zoom in/out.
-    (define-key map "+"               'doc-view-enlarge)
-    (define-key map "="               'doc-view-enlarge)
-    (define-key map "-"               'doc-view-shrink)
-    (define-key map "0"               'doc-view-scale-reset)
-    (define-key map [remap text-scale-adjust] 'doc-view-scale-adjust)
-    ;; Fit the image to the window
-    (define-key map "W"               'doc-view-fit-width-to-window)
-    (define-key map "H"               'doc-view-fit-height-to-window)
-    (define-key map "P"               'doc-view-fit-page-to-window)
-    (define-key map "F"               'doc-view-fit-window-to-page) ;F = frame
-    ;; Killing the buffer (and the process)
-    (define-key map (kbd "k")         'image-kill-buffer)
-    (define-key map (kbd "K")         'doc-view-kill-proc)
-    ;; Slicing the image
-    (define-key map (kbd "c s")       'doc-view-set-slice)
-    (define-key map (kbd "c m")       'doc-view-set-slice-using-mouse)
-    (define-key map (kbd "c b")       'doc-view-set-slice-from-bounding-box)
-    (define-key map (kbd "c r")       'doc-view-reset-slice)
-    ;; Centering the image
-    (define-key map (kbd "c h")       'doc-view-center-page-horizontally)
-    (define-key map (kbd "c v")       'doc-view-center-page-vertically)
-    ;; Searching
-    (define-key map (kbd "C-s")       'doc-view-search)
-    (define-key map (kbd "<find>")    'doc-view-search)
-    (define-key map (kbd "C-r")       'doc-view-search-backward)
-    ;; Show the tooltip
-    (define-key map (kbd "C-t")       'doc-view-show-tooltip)
-    ;; Toggle between text and image display or editing
-    (define-key map (kbd "C-c C-c")   'doc-view-toggle-display)
-    ;; Open a new buffer with doc's text contents
-    (define-key map (kbd "C-c C-t")   'doc-view-open-text)
-    (define-key map (kbd "r")         'revert-buffer)
-    map)
-  "Keymap used by `doc-view-mode' when displaying a doc as a set of images.")
+(defvar-keymap doc-view-mode-map
+  :doc "Keymap used by `doc-view-mode' when displaying a doc as a set of 
images."
+  :parent image-mode-map
+  ;; Navigation in the document
+  "n"       #'doc-view-next-page
+  "p"       #'doc-view-previous-page
+  "<next>"  #'forward-page
+  "<prior>" #'backward-page
+  "<remap> <forward-page>"  #'doc-view-next-page
+  "<remap> <backward-page>" #'doc-view-previous-page
+  "SPC"     #'doc-view-scroll-up-or-next-page
+  "S-SPC"   #'doc-view-scroll-down-or-previous-page
+  "DEL"     #'doc-view-scroll-down-or-previous-page
+  "C-n"     #'doc-view-next-line-or-next-page
+  "<down>"  #'doc-view-next-line-or-next-page
+  "C-p"     #'doc-view-previous-line-or-previous-page
+  "<up>"    #'doc-view-previous-line-or-previous-page
+  "M-<"     #'doc-view-first-page
+  "M->"     #'doc-view-last-page
+  "<remap> <goto-line>" #'doc-view-goto-page
+  "RET"     #'image-next-line
+  ;; Zoom in/out.
+  "+"       #'doc-view-enlarge
+  "="       #'doc-view-enlarge
+  "-"       #'doc-view-shrink
+  "0"       #'doc-view-scale-reset
+  "<remap> <text-scale-adjust>" #'doc-view-scale-adjust
+  ;; Fit the image to the window
+  "W"       #'doc-view-fit-width-to-window
+  "H"       #'doc-view-fit-height-to-window
+  "P"       #'doc-view-fit-page-to-window
+  "F"       #'doc-view-fit-window-to-page ;F = frame
+  ;; Killing the buffer (and the process)
+  "k"       #'image-kill-buffer
+  "K"       #'doc-view-kill-proc
+  ;; Slicing the image
+  "c s"     #'doc-view-set-slice
+  "c m"     #'doc-view-set-slice-using-mouse
+  "c b"     #'doc-view-set-slice-from-bounding-box
+  "c r"     #'doc-view-reset-slice
+  ;; Centering the image
+  "c h"     #'doc-view-center-page-horizontally
+  "c v"     #'doc-view-center-page-vertically
+  ;; Searching
+  "C-s"     #'doc-view-search
+  "<find>"  #'doc-view-search
+  "C-r"     #'doc-view-search-backward
+  ;; Show the tooltip
+  "C-t"     #'doc-view-show-tooltip
+  ;; Toggle between text and image display or editing
+  "C-c C-c" #'doc-view-toggle-display
+  ;; Open a new buffer with doc's text contents
+  "C-c C-t" #'doc-view-open-text
+  "r"       #'revert-buffer)
 
 (define-obsolete-function-alias 'doc-view-revert-buffer #'revert-buffer "27.1")
 (defvar revert-buffer-preserve-modes)
@@ -592,12 +615,10 @@ Typically \"page-%s.png\".")
      :help                      "Jump to the previous match or initiate a new 
search"]
     ))
 
-(defvar doc-view-minor-mode-map
-  (let ((map (make-sparse-keymap)))
-    ;; Toggle between text and image display or editing
-    (define-key map (kbd "C-c C-c") 'doc-view-toggle-display)
-    map)
-  "Keymap used by `doc-view-minor-mode'.")
+(defvar-keymap doc-view-minor-mode-map
+  :doc "Keymap used by `doc-view-minor-mode'."
+  ;; Toggle between text and image display or editing
+  "C-c C-c" #'doc-view-toggle-display)
 
 (easy-menu-define doc-view-minor-mode-menu doc-view-minor-mode-map
   "Menu for Doc View minor mode."
@@ -1178,12 +1199,12 @@ The test is performed using `doc-view-pdfdraw-program'."
       (when doc-view-epub-font-size
         (setq options (append options
                               (list (format "-S%s" doc-view-epub-font-size)))))
-      (when doc-view-mutool-user-stylesheet
+      (when doc-view-epub-user-stylesheet
         (setq options
               (append options
                       (list (format "-U%s"
                                     (expand-file-name
-                                     doc-view-mutool-user-stylesheet)))))))
+                                     doc-view-epub-user-stylesheet)))))))
     (doc-view-start-process
      "pdf->png" doc-view-pdfdraw-program
      `(,@(doc-view-pdfdraw-program-subcommand)
@@ -2153,12 +2174,11 @@ See the command `doc-view-mode' for more information on 
this mode."
 
 ;;;; Presentation mode
 
-(defvar doc-view-presentation-mode-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "\e" 'doc-view-presentation-exit)
-    (define-key map "q" 'doc-view-presentation-exit)
-    ;; (define-key map "C" 'doc-view-convert-all-pages)
-    map))
+(defvar-keymap doc-view-presentation-mode-map
+  "ESC"  #'doc-view-presentation-exit
+  "q"    #'doc-view-presentation-exit
+  ;; "C" #'doc-view-convert-all-pages
+  )
 
 (defvar-local doc-view-presentation--src-data nil)
 
@@ -2260,7 +2280,7 @@ See the command `doc-view-mode' for more information on 
this mode."
     (add-hook 'bookmark-after-jump-hook show-fn-sym)
     (bookmark-default-handler bmk)))
 
-(put 'doc-view-bookmark-jump 'bookmark-handler-type "Docview")
+(put 'doc-view-bookmark-jump 'bookmark-handler-type "DocView")
 
 ;; Obsolete.
 
diff --git a/lisp/dos-fns.el b/lisp/dos-fns.el
index ea54eea603..edbe9e494f 100644
--- a/lisp/dos-fns.el
+++ b/lisp/dos-fns.el
@@ -231,9 +231,6 @@ returned unaltered."
 
 (add-hook 'before-init-hook 'dos-reevaluate-defcustoms)
 
-(define-obsolete-variable-alias
-  'register-name-alist 'dos-register-name-alist "24.1")
-
 (defvar dos-register-name-alist
   '((ax . 0) (bx . 1) (cx . 2) (dx . 3) (si . 4) (di . 5)
     (cflag . 6) (flags . 7)
@@ -243,8 +240,6 @@ returned unaltered."
 (defun dos-make-register ()
   (make-vector 8 0))
 
-(define-obsolete-function-alias 'make-register 'dos-make-register "24.1")
-
 (defun dos-register-value (regs name)
   (let ((where (cdr (assoc name dos-register-name-alist))))
     (cond ((consp where)
@@ -256,8 +251,6 @@ returned unaltered."
           (aref regs where))
          (t nil))))
 
-(define-obsolete-function-alias 'register-value 'dos-register-value "24.1")
-
 (defun dos-set-register-value (regs name value)
   (and (numberp value)
        (>= value 0)
@@ -274,9 +267,6 @@ returned unaltered."
                (aset regs where (logand value 65535))))))
   regs)
 
-(define-obsolete-function-alias
-  'set-register-value 'dos-set-register-value "24.1")
-
 (defsubst dos-intdos (regs)
   "Issue the DOS Int 21h with registers REGS.
 
@@ -284,8 +274,6 @@ REGS should be a vector produced by `dos-make-register'
 and `dos-set-register-value', which see."
   (int86 33 regs))
 
-(define-obsolete-function-alias 'intdos 'dos-intdos "24.1")
-
 ;; Backward compatibility for obsolescent functions which
 ;; set screen size.
 
@@ -294,8 +282,6 @@ and `dos-set-register-value', which see."
   (interactive)
   (set-frame-size (selected-frame) 80 25))
 
-(define-obsolete-function-alias 'mode25 'dos-mode25 "24.1")
-
 (defun dos-mode4350 ()
   "Change the number of rows to 43 or 50.
 Emacs always tries to set the screen height to 50 rows first.
@@ -307,8 +293,6 @@ that your video hardware might not support 50-line mode."
       nil  ; the original built-in function returned nil
     (set-frame-size (selected-frame) 80 43)))
 
-(define-obsolete-function-alias 'mode4350 'dos-mode4350 "24.1")
-
 (provide 'dos-fns)
 
 ;;; dos-fns.el ends here
diff --git a/lisp/ecomplete.el b/lisp/ecomplete.el
index d5f3fc7756..aa415a3e9e 100644
--- a/lisp/ecomplete.el
+++ b/lisp/ecomplete.el
@@ -199,7 +199,7 @@ matches."
     (goto-char (point-min))
     (forward-line line)
     (save-restriction
-      (narrow-to-region (point) (point-at-eol))
+      (narrow-to-region (point) (line-end-position))
       (while (not (eobp))
        ;; Put the 'region face on any characters on this line that
        ;; aren't already highlighted.
diff --git a/lisp/edmacro.el b/lisp/edmacro.el
index 26f3ae02ab..26a5d2347f 100644
--- a/lisp/edmacro.el
+++ b/lisp/edmacro.el
@@ -62,6 +62,7 @@
 ;;; Code:
 
 (require 'cl-lib)
+(require 'seq)
 (require 'kmacro)
 
 ;;; The user-level commands for editing macros.
@@ -72,11 +73,35 @@ Default nil means to write characters above \\177 in octal 
notation."
   :type 'boolean
   :group 'kmacro)
 
-(defvar edmacro-mode-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "\C-c\C-c" #'edmacro-finish-edit)
-    (define-key map "\C-c\C-q" #'edmacro-insert-key)
-    map))
+(defvar-keymap edmacro-mode-map
+  "C-c C-c" #'edmacro-finish-edit
+  "C-c C-q" #'edmacro-insert-key)
+
+(defface edmacro-label
+  '((default :inherit bold)
+    (((class color) (background dark)) :foreground "light blue")
+    (((min-colors 88) (class color) (background light)) :foreground "DarkBlue")
+    (((class color) (background light)) :foreground "blue")
+    (t :inherit bold))
+  "Face used for labels in `edit-kbd-macro'."
+  :version "29.1"
+  :group 'kmacro)
+
+(defvar edmacro-mode-font-lock-keywords
+  `((,(rx bol (group (or "Command" "Key" "Macro") ":")) 0 'edmacro-label)
+    (,(rx bol
+          (group ";; Keyboard Macro Editor.  Press ")
+          (group (*? any))
+          (group  " to finish; press "))
+     (1 'font-lock-comment-face)
+     (2 'help-key-binding)
+     (3 'font-lock-comment-face)
+     (,(rx (group (*? any))
+           (group " to cancel" (* any)))
+      nil nil
+      (1 'help-key-binding)
+      (2 'font-lock-comment-face)))
+    (,(rx (one-or-more ";") (zero-or-more any)) 0 'font-lock-comment-face)))
 
 (defvar edmacro-store-hook)
 (defvar edmacro-finish-hook)
@@ -86,7 +111,7 @@ Default nil means to write characters above \\177 in octal 
notation."
 (defun edit-kbd-macro (keys &optional prefix finish-hook store-hook)
   "Edit a keyboard macro.
 At the prompt, type any key sequence which is bound to a keyboard macro.
-Or, type `\\[kmacro-end-and-call-macro]' or RET to edit the last
+Or, type `\\[kmacro-end-and-call-macro]' or \\`RET' to edit the last
 keyboard macro, `\\[view-lossage]' to edit the last 300
 keystrokes as a keyboard macro, or `\\[execute-extended-command]'
 to edit a macro by its command name.
@@ -153,9 +178,18 @@ With a prefix argument, format the macro in a more concise 
way."
         (setq-local edmacro-original-buffer oldbuf)
         (setq-local edmacro-finish-hook finish-hook)
         (setq-local edmacro-store-hook store-hook)
+        (setq-local font-lock-defaults
+                    '(edmacro-mode-font-lock-keywords nil nil nil nil))
+        (setq font-lock-multiline nil)
        (erase-buffer)
-       (insert ";; Keyboard Macro Editor.  Press C-c C-c to finish; "
-               "press C-x k RET to cancel.\n")
+        (insert (substitute-command-keys
+                 (concat
+                  ;; When editing this, make sure to update
+                  ;; `edmacro-mode-font-lock-keywords' to match.
+                  ";; Keyboard Macro Editor.  Press \\[edmacro-finish-edit] "
+                  "to finish; press \\[kill-buffer] \\`RET' to cancel.\n")
+                 ;; Use 'no-face argument to not conflict with font-lock.
+                 'no-face))
        (insert ";; Original keys: " fmt "\n")
        (unless store-hook
          (insert "\nCommand: " (if cmd (symbol-name cmd) "none") "\n")
@@ -217,11 +251,12 @@ If VERBOSE is `1', put everything on one line.  If 
VERBOSE is omitted
 or nil, use a compact 80-column format."
   (and macro (symbolp macro) (setq macro (symbol-function macro)))
   (edmacro-format-keys (or macro last-kbd-macro) verbose))
+
 
 ;;; Commands for *Edit Macro* buffer.
 
 (defun edmacro-finish-edit ()
-  (interactive)
+  (interactive nil edmacro-mode)
   (unless (eq major-mode 'edmacro-mode)
     (error
      "This command is valid only in buffers created by `edit-kbd-macro'"))
@@ -332,7 +367,7 @@ or nil, use a compact 80-column format."
 
 (defun edmacro-insert-key (key)
   "Insert the written name of a KEY in the buffer."
-  (interactive "kKey to insert: ")
+  (interactive "kKey to insert: " edmacro-mode)
   (if (bolp)
       (insert (edmacro-format-keys key t) "\n")
     (insert (edmacro-format-keys key) " ")))
@@ -340,7 +375,7 @@ or nil, use a compact 80-column format."
 (defun edmacro-mode ()
   "\\<edmacro-mode-map>Keyboard Macro Editing mode.  Press \
 \\[edmacro-finish-edit] to save and exit.
-To abort the edit, just kill this buffer with \\[kill-buffer] RET.
+To abort the edit, just kill this buffer with \\[kill-buffer] \\`RET'.
 
 Press \\[edmacro-insert-key] to insert the name of any key by typing the key.
 
@@ -412,6 +447,7 @@ doubt, use whitespace."
   (interactive)
   (error "This mode can be enabled only by `edit-kbd-macro'"))
 (put 'edmacro-mode 'mode-class 'special)
+
 
 ;;; Formatting a keyboard macro as human-readable text.
 
@@ -530,8 +566,8 @@ doubt, use whitespace."
                               ((integerp ch)
                                (concat
                                 (cl-loop for pf across "ACHMsS"
-                                         for bit in '(?\A-\^@ ?\C-\^@ ?\H-\^@
-                                                              ?\M-\^@ ?\s-\^@ 
?\S-\^@)
+                                         for bit in '( ?\A-\0 ?\C-\0 ?\H-\0
+                                                       ?\M-\0 ?\s-\0 ?\S-\0)
                                          when (/= (logand ch bit) 0)
                                          concat (format "%c-" pf))
                                 (let ((ch2 (logand ch (1- (ash 1 18)))))
@@ -590,7 +626,7 @@ The string represents the same events; Meta is indicated by 
bit 7.
 This function assumes that the events can be stored in a string."
   (setq seq (copy-sequence seq))
   (cl-loop for i below (length seq) do
-           (when (logand (aref seq i) 128)
+           (when (/= (logand (aref seq i) 128) 0)
              (setf (aref seq i) (logand (aref seq i) 127))))
   seq)
 
@@ -603,12 +639,8 @@ This function assumes that the events can be stored in a 
string."
 (defun edmacro-fix-menu-commands (macro &optional noerror)
   (if (vectorp macro)
       (let (result)
-        ;; Not preloaded in without-x builds.
+        ;; Not preloaded in a --without-x build.
         (require 'mwheel)
-        (defvar mouse-wheel-down-event)
-        (defvar mouse-wheel-left-event)
-        (defvar mouse-wheel-right-event)
-        (defvar mouse-wheel-up-event)
        ;; Make a list of the elements.
        (setq macro (append macro nil))
        (dolist (ev macro)
@@ -635,6 +667,7 @@ This function assumes that the events can be stored in a 
string."
        ;; Reverse them again and make them back into a vector.
        (vconcat (nreverse result)))
     macro))
+
 
 ;;; Parsing a human-readable keyboard macro.
 
diff --git a/lisp/elec-pair.el b/lisp/elec-pair.el
index 231dcdeb98..e4d6461505 100644
--- a/lisp/elec-pair.el
+++ b/lisp/elec-pair.el
@@ -188,6 +188,30 @@ be considered.")
    ;; I also find it often preferable not to pair next to a word.
    (eq (char-syntax (following-char)) ?w)))
 
+(defmacro electric-pair--with-syntax (string-or-comment &rest body)
+  "Run BODY with appropriate syntax table active.
+STRING-OR-COMMENT is the start position of the string/comment
+in which we are, if applicable.
+Uses the text-mode syntax table if within a string or a comment."
+  (declare (debug t) (indent 1))
+  `(electric-pair--with-syntax-1 ,string-or-comment (lambda () ,@body)))
+
+(defun electric-pair--with-syntax-1 (string-or-comment body-fun)
+  (if (not string-or-comment)
+      (funcall body-fun)
+    ;; Here we assume that the `syntax-ppss' cache has already been filled
+    ;; past `string-or-comment' with data corresponding to the "normal" syntax
+    ;; (this should be the case because STRING-OR-COMMENT was returned
+    ;; in the `nth 8' of `syntax-ppss').
+    ;; Maybe we should narrow-to-region so that `syntax-ppss' uses the narrow
+    ;; cache?
+    (syntax-ppss-flush-cache string-or-comment)
+    (let ((syntax-propertize-function nil))
+       (unwind-protect
+           (with-syntax-table electric-pair-text-syntax-table
+             (funcall body-fun))
+         (syntax-ppss-flush-cache string-or-comment)))))
+
 (defun electric-pair-syntax-info (command-event)
   "Calculate a list (SYNTAX PAIR UNCONDITIONAL STRING-OR-COMMENT-START).
 
@@ -202,13 +226,11 @@ inside a comment or string."
          (post-string-or-comment (nth 8 (syntax-ppss (point))))
          (string-or-comment (and post-string-or-comment
                                  pre-string-or-comment))
-         (table (if string-or-comment
-                    electric-pair-text-syntax-table
-                  (syntax-table)))
-         (table-syntax-and-pair (with-syntax-table table
-                                  (list (char-syntax command-event)
-                                        (or (matching-paren command-event)
-                                            command-event))))
+         (table-syntax-and-pair
+          (electric-pair--with-syntax string-or-comment
+            (list (char-syntax command-event)
+                  (or (matching-paren command-event)
+                      command-event))))
          (fallback (if string-or-comment
                        (append electric-pair-text-pairs
                                electric-pair-pairs)
@@ -237,22 +259,6 @@ inside a comment or string."
         (electric-layout-allow-duplicate-newlines t))
     (self-insert-command 1)))
 
-(cl-defmacro electric-pair--with-uncached-syntax ((table &optional start) 
&rest body)
-  "Like `with-syntax-table', but flush the `syntax-ppss' cache afterwards.
-Use this instead of (with-syntax-table TABLE BODY) when BODY
-contains code which may update the `syntax-ppss' cache.  This
-includes calling `parse-partial-sexp' and any sexp-based movement
-functions when `parse-sexp-lookup-properties' is non-nil.  The
-cache is flushed from position START, defaulting to point."
-  (declare (debug ((form &optional form) body)) (indent 1))
-  (let ((start-var (make-symbol "start")))
-    `(let ((syntax-propertize-function #'ignore)
-           (,start-var ,(or start '(point))))
-       (unwind-protect
-           (with-syntax-table ,table
-             ,@body)
-         (syntax-ppss-flush-cache ,start-var)))))
-
 (defun electric-pair--syntax-ppss (&optional pos where)
   "Like `syntax-ppss', but sometimes fallback to `parse-partial-sexp'.
 
@@ -271,8 +277,7 @@ when to fallback to `parse-partial-sexp'."
                               (skip-syntax-forward " >!")
                               (point)))))
     (if s-or-c-start
-        (electric-pair--with-uncached-syntax (electric-pair-text-syntax-table
-                                              s-or-c-start)
+        (electric-pair--with-syntax s-or-c-start
           (parse-partial-sexp s-or-c-start pos))
       ;; HACK! cc-mode apparently has some `syntax-ppss' bugs
       (if (memq major-mode '(c-mode c++ mode))
@@ -290,7 +295,8 @@ when to fallback to `parse-partial-sexp'."
 (defun electric-pair--balance-info (direction string-or-comment)
   "Examine lists forward or backward according to DIRECTION's sign.
 
-STRING-OR-COMMENT is info suitable for running `parse-partial-sexp'.
+STRING-OR-COMMENT is the position of the start of the comment/string
+in which we are, if applicable.
 
 Return a cons of two descriptions (MATCHED-P . PAIR) for the
 innermost and outermost lists that enclose point.  The outermost
@@ -301,9 +307,6 @@ If the outermost list is matched, don't rely on its PAIR.
 If point is not enclosed by any lists, return ((t) . (t))."
   (let* (innermost
          outermost
-         (table (if string-or-comment
-                    electric-pair-text-syntax-table
-                  (syntax-table)))
          (at-top-level-or-equivalent-fn
           ;; called when `scan-sexps' ran perfectly, when it found
           ;; a parenthesis pointing in the direction of travel.
@@ -325,11 +328,11 @@ If point is not enclosed by any lists, return ((t) . 
(t))."
                       (cond ((< direction 0)
                              (condition-case nil
                                  (eq (char-after pos)
-                                     (electric-pair--with-uncached-syntax
-                                      (table)
-                                      (matching-paren
-                                       (char-before
-                                        (scan-sexps (point) 1)))))
+                                     (electric-pair--with-syntax
+                                         string-or-comment
+                                       (matching-paren
+                                        (char-before
+                                         (scan-sexps (point) 1)))))
                                (scan-error nil)))
                             (t
                              ;; In this case, no need to use
@@ -343,7 +346,8 @@ If point is not enclosed by any lists, return ((t) . (t))."
                                     (opener (char-after start)))
                                (and start
                                     (eq (char-before pos)
-                                        (or (with-syntax-table table
+                                        (or (electric-pair--with-syntax
+                                                string-or-comment
                                               (matching-paren opener))
                                             opener))))))))
                    (actual-pair (if (> direction 0)
@@ -356,7 +360,7 @@ If point is not enclosed by any lists, return ((t) . (t))."
     (save-excursion
       (while (not outermost)
         (condition-case err
-            (electric-pair--with-uncached-syntax (table)
+            (electric-pair--with-syntax string-or-comment
               (scan-sexps (point) (if (> direction 0)
                                       (point-max)
                                     (- (point-max))))
@@ -498,13 +502,13 @@ The decision is taken by order of preference:
   corresponding delimiter for C;
 
 * According to C alone, by looking C up in the tables
-  `electric-pair-paris' or `electric-pair-text-pairs' (which
+  `electric-pair-pairs' or `electric-pair-text-pairs' (which
   see);
 
 * According to C's syntax and the syntactic state of the buffer
   (both as defined by the major mode's syntax table).  This is
-  done by looking up up the variables
-  `electric-pair-inhibit-predicate', `electric-pair-skip-self'
+  done by looking up the variables
+ `electric-pair-inhibit-predicate', `electric-pair-skip-self'
   and `electric-pair-skip-whitespace' (which see)."
   (let* ((pos (and electric-pair-mode (electric--after-char-pos)))
          (skip-whitespace-info))
@@ -575,7 +579,7 @@ The decision is taken by order of preference:
          (save-excursion (electric-pair--insert pair))))))))
 
 (defun electric-pair-open-newline-between-pairs-psif ()
-  "Honour `electric-pair-open-newline-between-pairs'.
+  "Honor `electric-pair-open-newline-between-pairs'.
 Member of `post-self-insert-hook' if `electric-pair-mode' is on."
   (when (and (if (functionp electric-pair-open-newline-between-pairs)
                  (funcall electric-pair-open-newline-between-pairs)
@@ -662,7 +666,8 @@ To toggle the mode in a single buffer, use 
`electric-pair-local-mode'."
 ;;;###autoload
 (define-minor-mode electric-pair-local-mode
   "Toggle `electric-pair-mode' only in this buffer."
-  :variable (buffer-local-value 'electric-pair-mode (current-buffer))
+  :variable ( electric-pair-mode .
+              (lambda (val) (setq-local electric-pair-mode val)))
   (cond
    ((eq electric-pair-mode (default-value 'electric-pair-mode))
     (kill-local-variable 'electric-pair-mode))
diff --git a/lisp/electric.el b/lisp/electric.el
index 0cf3a299cf..bd7ea527ba 100644
--- a/lisp/electric.el
+++ b/lisp/electric.el
@@ -340,7 +340,8 @@ use `electric-indent-local-mode'."
 ;;;###autoload
 (define-minor-mode electric-indent-local-mode
   "Toggle `electric-indent-mode' only in this buffer."
-  :variable (buffer-local-value 'electric-indent-mode (current-buffer))
+  :variable ( electric-indent-mode .
+              (lambda (val) (setq-local electric-indent-mode val)))
   (cond
    ((eq electric-indent-mode (default-value 'electric-indent-mode))
     (kill-local-variable 'electric-indent-mode))
@@ -484,7 +485,8 @@ The variable `electric-layout-rules' says when and how to 
insert newlines."
 ;;;###autoload
 (define-minor-mode electric-layout-local-mode
   "Toggle `electric-layout-mode' only in this buffer."
-  :variable (buffer-local-value 'electric-layout-mode (current-buffer))
+  :variable ( electric-layout-mode .
+              (lambda (val) (setq-local electric-layout-mode val)))
   (cond
    ((eq electric-layout-mode (default-value 'electric-layout-mode))
     (kill-local-variable 'electric-layout-mode))
@@ -540,6 +542,16 @@ closing double quote otherwise."
   :version "26.1"
   :type 'boolean :safe #'booleanp :group 'electricity)
 
+(defcustom electric-quote-replace-consecutive t
+  "Non-nil means to replace a pair of single quotes with a double quote.
+Two single quotes are replaced by the corresponding double quote
+when the second quote of the pair is entered (i.e. by typing ` or
+') by default.  If nil, the single quotes are not altered."
+  :version "29.1"
+  :type 'boolean
+  :safe #'booleanp
+  :group 'electricity)
+
 (defvar electric-quote-inhibit-functions ()
   "List of functions that should inhibit electric quoting.
 When the variable `electric-quote-mode' is non-nil, Emacs will
@@ -592,7 +604,9 @@ This requotes when a quoting key is typed."
                               (memq (char-syntax (char-before))
                                     '(?\s ?\())))
                         (setq backtick ?\')))
-               (cond ((search-backward (string q< backtick) (- (point) 2) t)
+               (cond ((and electric-quote-replace-consecutive
+                           (search-backward
+                            (string q< backtick) (- (point) 2) t))
                       (replace-match (string q<<))
                       (when (and electric-pair-mode
                                  (eq (cdr-safe
@@ -606,7 +620,8 @@ This requotes when a quoting key is typed."
                      ((search-backward "\"" (1- (point)) t)
                       (replace-match (string q<<))
                       (setq last-command-event q<<)))
-             (cond ((search-backward (string q> ?') (- (point) 2) t)
+             (cond ((and electric-quote-replace-consecutive
+                         (search-backward (string q> ?') (- (point) 2) t))
                     (replace-match (string q>>))
                     (setq last-command-event q>>))
                    ((search-backward "'" (1- (point)) t)
@@ -627,7 +642,7 @@ and text paragraphs, and these are selectively controlled 
with
 `electric-quote-paragraph'.
 
 Customize `electric-quote-chars' to use characters other than the
-ones listed here.
+ones listed here.  Also see `electric-quote-replace-consecutive'.
 
 This is a global minor mode.  To toggle the mode in a single buffer,
 use `electric-quote-local-mode'."
@@ -648,7 +663,8 @@ use `electric-quote-local-mode'."
 ;;;###autoload
 (define-minor-mode electric-quote-local-mode
   "Toggle `electric-quote-mode' only in this buffer."
-  :variable (buffer-local-value 'electric-quote-mode (current-buffer))
+  :variable ( electric-quote-mode .
+              (lambda (val) (setq-local electric-quote-mode val)))
   (cond
    ((eq electric-quote-mode (default-value 'electric-quote-mode))
     (kill-local-variable 'electric-quote-mode))
diff --git a/lisp/emacs-lisp/advice.el b/lisp/emacs-lisp/advice.el
index 86a42b208e..d383650f4e 100644
--- a/lisp/emacs-lisp/advice.el
+++ b/lisp/emacs-lisp/advice.el
@@ -1,6 +1,6 @@
 ;;; advice.el --- An overloading mechanism for Emacs Lisp functions  -*- 
lexical-binding: t -*-
 
-;; Copyright (C) 1993-1994, 2000-2022 Free Software Foundation, Inc.
+;; Copyright (C) 1993-2022 Free Software Foundation, Inc.
 
 ;; Author: Hans Chalupsky <hans@cs.buffalo.edu>
 ;; Maintainer: emacs-devel@gnu.org
@@ -23,12 +23,6 @@
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
-;; LCD Archive Entry:
-;; advice|Hans Chalupsky|hans@cs.buffalo.edu|
-;; Overloading mechanism for Emacs Lisp functions|
-;; 1994/08/05 03:42:04|2.14|~/packages/advice.el.Z|
-
-
 ;;; Commentary:
 
 ;; Advice is documented in the Emacs Lisp Manual.
@@ -1060,9 +1054,9 @@
 ;;   (print "Let's clean up now!"))
 ;; foo
 ;;
-;; Now `foo's advice is byte-compiled:
+;; Now `foo's advice is compiled:
 ;;
-;; (byte-code-function-p 'ad-Advice-foo)
+;; (compiled-function-p 'ad-Advice-foo)
 ;; t
 ;;
 ;; (foo 3)
@@ -1304,7 +1298,7 @@
 ;; constructed during preactivation was used, even though we did not specify
 ;; the `compile' flag:
 ;;
-;; (byte-code-function-p 'ad-Advice-fum)
+;; (compiled-function-p 'ad-Advice-fum)
 ;; t
 ;;
 ;; (fum 2)
@@ -1335,7 +1329,7 @@
 ;;
 ;; A new uncompiled advised definition got constructed:
 ;;
-;; (byte-code-function-p 'ad-Advice-fum)
+;; (compiled-function-p 'ad-Advice-fum)
 ;; nil
 ;;
 ;; (fum 2)
@@ -1586,8 +1580,6 @@
   :link '(custom-manual "(elisp)Advising Functions")
   :group 'lisp)
 
-(defconst ad-version "2.14")
-
 ;;;###autoload
 (defcustom ad-redefinition-action 'warn
   "Defines what to do with redefinitions during Advice de/activation.
@@ -2124,9 +2116,9 @@ the cache-id will clear the cache."
 
 (defsubst ad-compiled-p (definition)
   "Return non-nil if DEFINITION is a compiled byte-code object."
-  (or (byte-code-function-p definition)
-       (and (macrop definition)
-            (byte-code-function-p (ad-lambdafy definition)))))
+  (or (compiled-function-p definition)
+      (and (macrop definition)
+           (compiled-function-p (ad-lambdafy definition)))))
 
 (defsubst ad-compiled-code (compiled-definition)
   "Return the byte-code object of a COMPILED-DEFINITION."
@@ -3256,6 +3248,9 @@ Use only in REAL emergencies."
     (message "Oops! Left over advised function %S" function)
     (ad-pop-advised-function function)))
 
+(defconst ad-version "2.14")
+(make-obsolete-variable 'ad-version 'emacs-version "29.1")
+
 (provide 'advice)
 
 ;;; advice.el ends here
diff --git a/lisp/emacs-lisp/autoload.el b/lisp/emacs-lisp/autoload.el
deleted file mode 100644
index eed88b6faf..0000000000
--- a/lisp/emacs-lisp/autoload.el
+++ /dev/null
@@ -1,915 +0,0 @@
-;;; autoload.el --- maintain autoloads in loaddefs.el  -*- lexical-binding: t 
-*-
-
-;; Copyright (C) 1991-1997, 2001-2022 Free Software Foundation, Inc.
-
-;; Author: Roland McGrath <roland@gnu.org>
-;; Keywords: maint
-;; Package: emacs
-
-;; 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 code helps GNU Emacs maintainers keep the loaddefs.el file up to
-;; date.  It interprets magic cookies of the form ";;;###autoload" in
-;; Lisp source files in various useful ways.  To learn more, read the
-;; source; if you're going to use this, you'd better be able to.
-
-;; The functions in this file have been largely superseded by
-;; loaddefs-gen.el.
-
-;;; Code:
-
-(require 'lisp-mode)                   ;for `doc-string-elt' properties.
-(require 'lisp-mnt)
-(require 'cl-lib)
-(require 'loaddefs-gen)
-
-;; This feels like it should be a defconst, but MH-E sets it to
-;; ";;;###mh-autoload" for the autoloads that are to go into mh-loaddefs.el.
-(defvar generate-autoload-cookie ";;;###autoload"
-  "Magic comment indicating the following form should be autoloaded.
-Used by \\[update-file-autoloads].  This string should be
-meaningless to Lisp (e.g., a comment).
-
-This string is used:
-
-\;;;###autoload
-\(defun function-to-be-autoloaded () ...)
-
-If this string appears alone on a line, the following form will be
-read and an autoload made for it.  If there is further text on the line,
-that text will be copied verbatim to `generated-autoload-file'.")
-
-(defvar autoload-excludes nil
-  "If non-nil, list of absolute file names not to scan for autoloads.")
-
-(defconst generate-autoload-section-header "\f\n;;;### "
-  "String that marks the form at the start of a new file's autoload section.")
-
-(defconst generate-autoload-section-trailer "\n;;;***\n"
-  "String which indicates the end of the section of autoloads for a file.")
-
-(defconst generate-autoload-section-continuation ";;;;;; "
-  "String to add on each continuation of the section header form.")
-
-;; In some ways it would be nicer to use a value that is recognizably
-;; not a time-value, eg t, but that can cause issues if an older Emacs
-;; that does not expect non-time-values loads the file.
-(defconst autoload--non-timestamp '(0 0 0 0)
-  "Value to insert when `autoload-timestamps' is nil.")
-
-(defvar autoload-timestamps nil                ; experimental, see bug#22213
-  "Non-nil means insert a timestamp for each input file into the output.
-We use these in incremental updates of the output file to decide
-if we need to rescan an input file.  If you set this to nil,
-then we use the timestamp of the output file instead.  As a result:
- - for fixed inputs, the output will be the same every time
- - incremental updates of the output file might not be correct if:
-   i) the timestamp of the output file cannot be trusted (at least
-     relative to that of the input files)
-   ii) any of the input files can be modified during the time it takes
-      to create the output
-   iii) only a subset of the input files are scanned
-   These issues are unlikely to happen in practice, and would arguably
-   represent bugs in the build system.  Item iii) will happen if you
-   use a command like `update-file-autoloads', though, since it only
-   checks a single input file.")
-
-(defvar autoload-modified-buffers)      ;Dynamically scoped var.
-
-(defalias 'make-autoload #'loaddefs-generate--make-autoload)
-
-;; Forms which have doc-strings which should be printed specially.
-;; A doc-string-elt property of ELT says that (nth ELT FORM) is
-;; the doc-string in FORM.
-;; Those properties are now set in lisp-mode.el.
-
-(defun autoload-find-generated-file (file)
-  "Visit the autoload file for the current buffer, and return its buffer."
-  (let ((enable-local-variables :safe)
-        (enable-local-eval nil)
-        (find-file-hook nil)
-        (delay-mode-hooks t))
-    ;; We used to use `raw-text' to read this file, but this causes
-    ;; problems when the file contains non-ASCII characters.
-    (with-current-buffer (find-file-noselect
-                          (autoload-ensure-file-writeable file))
-      (if (zerop (buffer-size)) (insert (autoload-rubric file nil t)))
-      (current-buffer))))
-
-(defun autoload-generated-file (outfile)
-  "Return OUTFILE as an absolute name.
-If `generated-autoload-file' is bound locally in the current
-buffer, that is used instead, and it is expanded using the
-default directory; otherwise, `source-directory'/lisp is used."
-  (expand-file-name (if (local-variable-p 'generated-autoload-file)
-                        generated-autoload-file
-                      outfile)
-                    ;; File-local settings of generated-autoload-file should
-                    ;; be interpreted relative to the file's location,
-                    ;; of course.
-                    (if (not (local-variable-p 'generated-autoload-file))
-                        (expand-file-name "lisp" source-directory))))
-
-(defun autoload-read-section-header ()
-  "Read a section header form.
-Since continuation lines have been marked as comments,
-we must copy the text of the form and remove those comment
-markers before we call `read'."
-  (save-match-data
-    (let ((beginning (point))
-         string)
-      (forward-line 1)
-      (while (looking-at generate-autoload-section-continuation)
-       (forward-line 1))
-      (setq string (buffer-substring beginning (point)))
-      (with-current-buffer (get-buffer-create " *autoload*")
-       (erase-buffer)
-       (insert string)
-       (goto-char (point-min))
-       (while (search-forward generate-autoload-section-continuation nil t)
-         (replace-match " "))
-       (goto-char (point-min))
-       (read (current-buffer))))))
-
-(defvar autoload-print-form-outbuf nil
-  "Buffer which gets the output of `autoload-print-form'.")
-
-(defun autoload-print-form (form)
-  "Print FORM such that `make-docfile' will find the docstrings.
-The variable `autoload-print-form-outbuf' specifies the buffer to
-put the output in."
-  (cond
-   ;; If the form is a sequence, recurse.
-   ((eq (car form) 'progn) (mapcar #'autoload-print-form (cdr form)))
-   ;; Symbols at the toplevel are meaningless.
-   ((symbolp form) nil)
-   (t
-    (let ((doc-string-elt (function-get (car-safe form) 'doc-string-elt))
-         (outbuf autoload-print-form-outbuf))
-      (if (and (numberp doc-string-elt) (stringp (nth doc-string-elt form)))
-         ;; We need to hack the printing because the
-         ;; doc-string must be printed specially for
-         ;; make-docfile (sigh).
-         (let* ((p (nthcdr (1- doc-string-elt) form))
-                (elt (cdr p)))
-           (setcdr p nil)
-           (princ "\n(" outbuf)
-           (let ((print-escape-newlines t)
-                 (print-escape-control-characters t)
-                  (print-quoted t)
-                 (print-escape-nonascii t))
-             (dolist (elt form)
-               (prin1 elt outbuf)
-               (princ " " outbuf)))
-           (princ "\"\\\n" outbuf)
-           (let ((begin (with-current-buffer outbuf (point))))
-             (princ (substring (prin1-to-string (car elt)) 1)
-                    outbuf)
-             ;; Insert a backslash before each ( that
-             ;; appears at the beginning of a line in
-             ;; the doc string.
-             (with-current-buffer outbuf
-               (save-excursion
-                 (while (re-search-backward "\n[[(]" begin t)
-                   (forward-char 1)
-                   (insert "\\"))))
-             (if (null (cdr elt))
-                 (princ ")" outbuf)
-               (princ " " outbuf)
-               (princ (substring (prin1-to-string (cdr elt)) 1)
-                      outbuf))
-             (terpri outbuf)))
-       (let ((print-escape-newlines t)
-             (print-escape-control-characters t)
-              (print-quoted t)
-             (print-escape-nonascii t))
-         (print form outbuf)))))))
-
-(defalias 'autoload-rubric #'loaddefs-generate--rubric)
-
-(defvar autoload-ensure-writable nil
-  "Non-nil means `autoload-find-generated-file' makes existing file writable.")
-;; Just in case someone tries to get you to overwrite a file that you
-;; don't want to.
-;;;###autoload
-(put 'autoload-ensure-writable 'risky-local-variable t)
-
-(defun autoload-ensure-file-writeable (file)
-  ;; Probably pointless, but replaces the old AUTOGEN_VCS in lisp/Makefile,
-  ;; which was designed to handle CVSREAD=1 and equivalent.
-  (and autoload-ensure-writable
-       (let ((modes (file-modes file)))
-        (if (and modes (zerop (logand modes #o0200)))
-             ;; Ignore any errors here, and let subsequent attempts
-             ;; to write the file raise any real error.
-             (ignore-errors (set-file-modes file (logior modes #o0200))))))
-  file)
-
-(defun autoload-insert-section-header (outbuf autoloads load-name file time)
-  "Insert into buffer OUTBUF the section-header line for FILE.
-The header line lists the file name, its \"load name\", its autoloads,
-and the time the FILE was last updated (the time is inserted only
-if `autoload-timestamps' is non-nil, otherwise a fixed fake time is inserted)."
-  ;; (cl-assert ;Make sure we don't insert it in the middle of another section.
-  ;;  (save-excursion
-  ;;    (or (not (re-search-backward
-  ;;              (concat "\\("
-  ;;                      (regexp-quote generate-autoload-section-header)
-  ;;                      "\\)\\|\\("
-  ;;                      (regexp-quote generate-autoload-section-trailer)
-  ;;                      "\\)")
-  ;;              nil t))
-  ;;        (match-end 2))))
-  (insert generate-autoload-section-header)
-  (prin1 `(autoloads ,autoloads ,load-name ,file ,time)
-        outbuf)
-  (terpri outbuf)
-  ;; Break that line at spaces, to avoid very long lines.
-  ;; Make each sub-line into a comment.
-  (with-current-buffer outbuf
-    (save-excursion
-      (forward-line -1)
-      (while (not (eolp))
-       (move-to-column 64)
-       (skip-chars-forward "^ \n")
-       (or (eolp)
-           (insert "\n" generate-autoload-section-continuation))))))
-
-(defun autoload-find-file (file)
-  "Fetch FILE and put it in a temp buffer.  Return the buffer."
-  ;; It is faster to avoid visiting the file.
-  (setq file (expand-file-name file))
-  (with-current-buffer (get-buffer-create " *autoload-file*")
-    (kill-all-local-variables)
-    (erase-buffer)
-    (setq buffer-undo-list t
-          buffer-read-only nil)
-    (delay-mode-hooks (emacs-lisp-mode))
-    (setq default-directory (file-name-directory file))
-    (insert-file-contents file nil)
-    (let ((enable-local-variables :safe)
-         (enable-local-eval nil))
-      (hack-local-variables))
-    (current-buffer)))
-
-(defalias 'autoload-insert-section-header
-  #'loaddefs-generate--insert-section-header)
-
-(defvar no-update-autoloads nil
-  "File local variable to prevent scanning this file for autoload cookies.")
-
-(defalias 'autoload-file-load-name #'loaddefs-generate--file-load-name)
-
-(defun generate-file-autoloads (file)
-  "Insert at point a loaddefs autoload section for FILE.
-Autoloads are generated for defuns and defmacros in FILE
-marked by `generate-autoload-cookie' (which see).
-If FILE is being visited in a buffer, the contents of the buffer
-are used.
-Return non-nil in the case where no autoloads were added at point."
-  (interactive "fGenerate autoloads for file: ")
-  (let ((autoload-modified-buffers nil))
-    (autoload-generate-file-autoloads file (current-buffer) buffer-file-name)
-    autoload-modified-buffers))
-
-(defconst autoload-def-prefixes-max-entries 5
-  "Target length of the list of definition prefixes per file.
-If set too small, the prefixes will be too generic (i.e. they'll use little
-memory, we'll end up looking in too many files when we need a particular
-prefix), and if set too large, they will be too specific (i.e. they will
-cost more memory use).")
-
-(defconst autoload-def-prefixes-max-length 12
-  "Target size of definition prefixes.
-Don't try to split prefixes that are already longer than that.")
-
-(defalias 'autoload--make-defs-autoload #'loaddefs-generate--make-prefixes)
-
-(defun autoload--setup-output (otherbuf outbuf absfile load-name output-file)
-  (let ((outbuf
-         (or (if otherbuf
-                 ;; A file-local setting of
-                 ;; autoload-generated-file says we
-                 ;; should ignore OUTBUF.
-                 nil
-               outbuf)
-             (autoload-find-destination absfile load-name output-file)
-             ;; The file has autoload cookies, but they're
-             ;; already up-to-date. If OUTFILE is nil, the
-             ;; entries are in the expected OUTBUF,
-             ;; otherwise they're elsewhere.
-             (throw 'done otherbuf))))
-    (with-current-buffer outbuf
-      (point-marker))))
-
-(defun autoload--print-cookie-text (output-start load-name file)
-  (let ((standard-output (marker-buffer output-start)))
-     (search-forward generate-autoload-cookie)
-     (skip-chars-forward " \t")
-     (if (eolp)
-         (condition-case-unless-debug err
-             ;; Read the next form and make an autoload.
-             (let* ((form (prog1 (read (current-buffer))
-                            (or (bolp) (forward-line 1))))
-                    (autoload (make-autoload form load-name)))
-               (if autoload
-                   nil
-                 (setq autoload form))
-               (let ((autoload-print-form-outbuf
-                      standard-output))
-                 (autoload-print-form autoload)))
-           (error
-            (message "Autoload cookie error in %s:%s %S"
-                     file (count-lines (point-min) (point)) err)))
-
-       ;; Copy the rest of the line to the output.
-       (princ (buffer-substring
-               (progn
-                 ;; Back up over whitespace, to preserve it.
-                 (skip-chars-backward " \f\t")
-                 (if (= (char-after (1+ (point))) ? )
-                     ;; Eat one space.
-                     (forward-char 1))
-                 (point))
-              (progn (forward-line 1) (point)))))))
-
-(defvar autoload-builtin-package-versions nil)
-
-(defun autoload-generate-file-autoloads (file &optional outbuf outfile)
-  "Insert an autoload section for FILE in the appropriate buffer.
-Autoloads are generated for defuns and defmacros in FILE
-marked by `generate-autoload-cookie' (which see).
-
-If FILE is being visited in a buffer, the contents of the buffer are used.
-OUTBUF is the buffer in which the autoload statements should be inserted.
-
-If OUTBUF is nil, the output will go to OUTFILE, unless there's a
-buffer-local setting of `generated-autoload-file' in FILE.
-
-Return non-nil if and only if FILE adds no autoloads to OUTFILE
-\(or OUTBUF if OUTFILE is nil).  The actual return value is
-FILE's modification time."
-  ;; Include the file name in any error messages
-  (condition-case err
-      (let (load-name
-            (print-length nil)
-            (print-level nil)
-            (float-output-format nil)
-            (visited (get-file-buffer file))
-            (otherbuf nil)
-            (absfile (expand-file-name file))
-          (defs '())
-            ;; nil until we found a cookie.
-            output-start)
-        (when
-            (catch 'done
-              (with-current-buffer (or visited
-                                       ;; It is faster to avoid visiting the 
file.
-                                       (autoload-find-file file))
-                ;; Obey the no-update-autoloads file local variable.
-                (unless no-update-autoloads
-                  (or noninteractive (message "Generating autoloads for %s..." 
file))
-                  (setq load-name
-                        (if (stringp generated-autoload-load-name)
-                            generated-autoload-load-name
-                          (autoload-file-load-name absfile outfile)))
-                  ;; FIXME? Comparing file-names for equality with just equal
-                  ;; is fragile, eg if one has an automounter prefix and one
-                  ;; does not, but both refer to the same physical file.
-                  (when (and outfile
-                             (not outbuf)
-                             (not
-                              (if (memq system-type '(ms-dos windows-nt))
-                                  (equal (downcase outfile)
-                                         (downcase (autoload-generated-file
-                                                    outfile)))
-                                (equal outfile (autoload-generated-file
-                                                outfile)))))
-                    (setq otherbuf t))
-                  (save-excursion
-                    (save-restriction
-                      (widen)
-                      (when autoload-builtin-package-versions
-                        (let ((version (lm-header "version"))
-                              package)
-                          (and version
-                               (setq version (ignore-errors (version-to-list 
version)))
-                               (setq package (or (lm-header "package")
-                                                 (file-name-sans-extension
-                                                  (file-name-nondirectory 
file))))
-                               (setq output-start (autoload--setup-output
-                                                   otherbuf outbuf absfile
-                                                   load-name outfile))
-                               (let ((standard-output (marker-buffer 
output-start))
-                                     (print-quoted t))
-                                 (princ `(push (purecopy
-                                                ',(cons (intern package) 
version))
-                                               package--builtin-versions))
-                                 (princ "\n")))))
-
-                      ;; Do not insert autoload entries for excluded files.
-                      (unless (member absfile autoload-excludes)
-                        (goto-char (point-min))
-                        (while (not (eobp))
-                          (skip-chars-forward " \t\n\f")
-                          (cond
-                           ((looking-at (regexp-quote 
generate-autoload-cookie))
-                            ;; If not done yet, figure out where to insert 
this text.
-                            (unless output-start
-                              (setq output-start (autoload--setup-output
-                                                  otherbuf outbuf absfile
-                                                  load-name outfile)))
-                            (autoload--print-cookie-text output-start 
load-name file))
-                           ((= (following-char) ?\;)
-                            ;; Don't read the comment.
-                            (forward-line 1))
-                           (t
-                  ;; Avoid (defvar <foo>) by requiring a trailing space.
-                  ;; Also, ignore this prefix business
-                  ;; for ;;;###tramp-autoload and friends.
-                  (when (and (equal generate-autoload-cookie ";;;###autoload")
-                             (looking-at "(\\(def[^ ]+\\) ['(]*\\([^' 
()\"\n]+\\)[\n \t]")
-                             (not (member
-                                   (match-string 1)
-                                   autoload-ignored-definitions)))
-                    (push (match-string-no-properties 2) defs))
-                            (forward-sexp 1)
-                            (forward-line 1)))))))
-
-          (when (and autoload-compute-prefixes defs)
-            ;; This output needs to always go in the main loaddefs.el,
-            ;; regardless of generated-autoload-file.
-            ;; FIXME: the files that don't have autoload cookies but
-            ;; do have definitions end up listed twice in loaddefs.el:
-            ;; once for their register-definition-prefixes and once in
-            ;; the list of "files without any autoloads".
-            (let ((form (autoload--make-defs-autoload defs load-name)))
-              (cond
-               ((null form))             ;All defs obey the default rule, yay!
-               ((not otherbuf)
-                (unless output-start
-                  (setq output-start (autoload--setup-output
-                                      nil outbuf absfile load-name outfile)))
-                (let ((autoload-print-form-outbuf
-                       (marker-buffer output-start)))
-                  (autoload-print-form form)))
-               (t
-                (let* ((other-output-start
-                        ;; To force the output to go to the main loaddefs.el
-                        ;; rather than to generated-autoload-file,
-                        ;; there are two cases: if outbuf is non-nil,
-                        ;; then passing otherbuf=nil is enough, but if
-                        ;; outbuf is nil, that won't cut it, so we
-                        ;; locally bind generated-autoload-file.
-                        (autoload--setup-output nil outbuf absfile load-name
-                                                outfile))
-                       (autoload-print-form-outbuf
-                        (marker-buffer other-output-start)))
-                  (autoload-print-form form)
-                  (with-current-buffer (marker-buffer other-output-start)
-                    (save-excursion
-                      ;; Insert the section-header line which lists
-                      ;; the file name and which functions are in it, etc.
-                      (goto-char other-output-start)
-                      (let ((relfile (file-relative-name absfile)))
-                        (autoload-insert-section-header
-                         (marker-buffer other-output-start)
-                         "actual autoloads are elsewhere" load-name relfile
-                        (if autoload-timestamps
-                            (file-attribute-modification-time
-                             (file-attributes absfile))
-                          autoload--non-timestamp))
-                        (insert ";;; Generated autoloads from " relfile "\n")))
-                    (insert generate-autoload-section-trailer)))))))
-
-                  (when output-start
-                    (let ((secondary-autoloads-file-buf
-                           (if otherbuf (current-buffer))))
-                      (with-current-buffer (marker-buffer output-start)
-                        (cl-assert (> (point) output-start))
-                        (save-excursion
-                          ;; Insert the section-header line which lists the 
file name
-                          ;; and which functions are in it, etc.
-                          (goto-char output-start)
-                          (let ((relfile (file-relative-name absfile)))
-                            (autoload-insert-section-header
-                             (marker-buffer output-start)
-                             () load-name relfile
-                             (if secondary-autoloads-file-buf
-                                 ;; MD5 checksums are much better because they 
do not
-                                 ;; change unless the file changes (so they'll 
be
-                                 ;; equal on two different systems and will 
change
-                                 ;; less often than time-stamps, thus leading 
to fewer
-                                 ;; unneeded changes causing spurious 
conflicts), but
-                                 ;; using time-stamps is a very useful 
optimization,
-                                 ;; so we use time-stamps for the main 
autoloads file
-                                 ;; (loaddefs.el) where we have special ways to
-                                 ;; circumvent the "random change problem", 
and MD5
-                                 ;; checksum in secondary autoload files where 
we do
-                                 ;; not need the time-stamp optimization 
because it is
-                                 ;; already provided by the primary autoloads 
file.
-                                 (md5 secondary-autoloads-file-buf
-                                      ;; We'd really want to just use
-                                      ;; `emacs-internal' instead.
-                                      nil nil 'emacs-mule-unix)
-                               (if autoload-timestamps
-                                   (file-attribute-modification-time
-                                   (file-attributes relfile))
-                                 autoload--non-timestamp)))
-                            (insert ";;; Generated autoloads from " relfile 
"\n")))
-                        (insert generate-autoload-section-trailer))))
-                  (or noninteractive
-                      (message "Generating autoloads for %s...done" file)))
-                (or visited
-                    ;; We created this buffer, so we should kill it.
-                    (kill-buffer (current-buffer))))
-              (or (not output-start)
-                  ;; If the entries were added to some other buffer, then the 
file
-                  ;; doesn't add entries to OUTFILE.
-                  otherbuf))
-          (file-attribute-modification-time (file-attributes absfile))))
-    (error
-     ;; Probably unbalanced parens in forward-sexp. In that case, the
-     ;; condition is scan-error, and the signal data includes point
-     ;; where the error was found; we'd like to convert that to
-     ;; line:col, but line-number-at-pos gets the wrong line in batch
-     ;; mode for some reason.
-     ;;
-     ;; At least this gets the file name in the error message; the
-     ;; developer can use goto-char to get to the error position.
-     (error "%s:0:0: error: %s: %s" file (car err) (cdr err)))
-    ))
-
-;; For parallel builds, to stop another process reading a half-written file.
-(defun autoload--save-buffer ()
-  "Save current buffer to its file, atomically."
-  ;; Similar to byte-compile-file.
-  (let* ((version-control 'never)
-         (tempfile (make-temp-file buffer-file-name))
-        (default-modes (default-file-modes))
-        (temp-modes (logand default-modes #o600))
-        (desired-modes (logand default-modes
-                               (or (file-modes buffer-file-name) #o666)))
-         (kill-emacs-hook
-          (cons (lambda () (ignore-errors (delete-file tempfile)))
-                kill-emacs-hook)))
-    (unless (= temp-modes desired-modes)
-      (set-file-modes tempfile desired-modes 'nofollow))
-    (write-region (point-min) (point-max) tempfile nil 1)
-    (backup-buffer)
-    (rename-file tempfile buffer-file-name t))
-  (set-buffer-modified-p nil)
-  (set-visited-file-modtime)
-  (or noninteractive (message "Wrote %s" buffer-file-name)))
-
-(defun autoload-save-buffers ()
-  (while autoload-modified-buffers
-    (with-current-buffer (pop autoload-modified-buffers)
-      (autoload--save-buffer))))
-
-;; FIXME This command should be deprecated.
-;; See https://debbugs.gnu.org/22213#41
-;;;###autoload
-(defun update-file-autoloads (file &optional save-after outfile)
-  "Update the autoloads for FILE.
-If prefix arg SAVE-AFTER is non-nil, save the buffer too.
-
-If FILE binds `generated-autoload-file' as a file-local variable,
-autoloads are written into that file.  Otherwise, the autoloads
-file is determined by OUTFILE.  If called interactively, prompt
-for OUTFILE; if called from Lisp with OUTFILE nil, use the
-existing value of `generated-autoload-file'.
-
-Return FILE if there was no autoload cookie in it, else nil."
-  (interactive (list (read-file-name "Update autoloads for file: ")
-                    current-prefix-arg
-                    (read-file-name "Write autoload definitions to file: ")))
-  (setq outfile (or outfile generated-autoload-file))
-  (let* ((autoload-modified-buffers nil)
-        ;; We need this only if the output file handles more than one input.
-        ;; See https://debbugs.gnu.org/22213#38 and subsequent.
-        (autoload-timestamps t)
-         (no-autoloads (autoload-generate-file-autoloads
-                        file nil
-                        (if (local-variable-p 'generated-autoload-file)
-                            generated-autoload-file
-                          outfile))))
-    (if autoload-modified-buffers
-        (if save-after (autoload-save-buffers))
-      (if (called-interactively-p 'interactive)
-          (message "Autoload section for %s is up to date." file)))
-    (if no-autoloads file)))
-
-(defun autoload-find-destination (file load-name output-file)
-  "Find the destination point of the current buffer's autoloads.
-FILE is the file name of the current buffer.
-LOAD-NAME is the name as it appears in the output.
-Returns a buffer whose point is placed at the requested location.
-Returns nil if the file's autoloads are up-to-date, otherwise
-removes any prior now out-of-date autoload entries."
-  (catch 'up-to-date
-    (let* ((buf (current-buffer))
-           (existing-buffer (if buffer-file-name buf))
-           (output-file (autoload-generated-file output-file))
-           (output-time (if (file-exists-p output-file)
-                            (file-attribute-modification-time
-                            (file-attributes output-file))))
-           (found nil))
-      (with-current-buffer (autoload-find-generated-file output-file)
-        ;; This is to make generated-autoload-file have Unix EOLs, so
-        ;; that it is portable to all platforms.
-        (or (eq 0 (coding-system-eol-type buffer-file-coding-system))
-           (set-buffer-file-coding-system 'unix))
-        (or (> (buffer-size) 0)
-            (error "Autoloads file %s lacks boilerplate" buffer-file-name))
-        (or (file-writable-p buffer-file-name)
-            (error "Autoloads file %s is not writable" buffer-file-name))
-        (widen)
-        (goto-char (point-min))
-        ;; Look for the section for LOAD-NAME.
-        (while (and (not found)
-                    (search-forward generate-autoload-section-header nil t))
-          (let ((form (autoload-read-section-header)))
-            (cond ((string= (nth 2 form) load-name)
-                   ;; We found the section for this file.
-                   ;; Check if it is up to date.
-                   (let ((begin (match-beginning 0))
-                         (last-time (nth 4 form))
-                         (file-time (file-attribute-modification-time
-                                    (file-attributes file))))
-                     (if (and (or (null existing-buffer)
-                                  (not (buffer-modified-p existing-buffer)))
-                              (cond
-                               ;; FIXME? Arguably we should throw a
-                               ;; user error, or some kind of warning,
-                               ;; if we were called from update-file-autoloads,
-                               ;; which can update only a single input file.
-                               ;; It's not appropriate to use the output
-                               ;; file modtime in such a case,
-                               ;; if there are multiple input files
-                               ;; contributing to the output.
-                               ((and output-time
-                                    (member last-time
-                                            (list t autoload--non-timestamp)))
-                                (not (time-less-p output-time file-time)))
-                               ;; last-time is the time-stamp (specifying
-                               ;; the last time we looked at the file) and
-                               ;; the file hasn't been changed since.
-                               ((listp last-time)
-                                (not (time-less-p last-time file-time)))
-                               ;; last-time is an MD5 checksum instead.
-                               ((stringp last-time)
-                                (equal last-time
-                                      (md5 buf nil nil 'emacs-mule)))))
-                         (throw 'up-to-date nil)
-                       (autoload-remove-section begin)
-                       (setq found t))))
-                  ((string< load-name (nth 2 form))
-                   ;; We've come to a section alphabetically later than
-                   ;; LOAD-NAME.  We assume the file is in order and so
-                   ;; there must be no section for LOAD-NAME.  We will
-                   ;; insert one before the section here.
-                   (goto-char (match-beginning 0))
-                   (setq found t)))))
-        (or found
-            (progn
-              ;; No later sections in the file.  Put before the last page.
-              (goto-char (point-max))
-              (search-backward "\f" nil t)))
-        (unless (memq (current-buffer) autoload-modified-buffers)
-          (push (current-buffer) autoload-modified-buffers))
-        (current-buffer)))))
-
-(defun autoload-remove-section (begin)
-  (goto-char begin)
-  (search-forward generate-autoload-section-trailer)
-  (delete-region begin (point)))
-
-;;;###autoload
-(defun update-directory-autoloads (&rest dirs)
-  "Update autoload definitions for Lisp files in the directories DIRS.
-In an interactive call, you must give one argument, the name of a
-single directory.  In a call from Lisp, you can supply multiple
-directories as separate arguments, but this usage is discouraged.
-
-The function does NOT recursively descend into subdirectories of the
-directory or directories specified.
-
-In an interactive call, prompt for a default output file for the
-autoload definitions.  When called from Lisp, use the existing
-value of `generated-autoload-file'.  If any Lisp file binds
-`generated-autoload-file' as a file-local variable, write its
-autoloads into the specified file instead."
-  (declare (obsolete make-directory-autoloads "28.1"))
-  (interactive "DUpdate autoloads from directory: ")
-  (make-directory-autoloads
-   dirs
-   (if (called-interactively-p 'interactive)
-       (read-file-name "Write autoload definitions to file: ")
-     generated-autoload-file)))
-
-;;;###autoload
-(defun make-directory-autoloads (dir output-file)
-  "Update autoload definitions for Lisp files in the directories DIRS.
-DIR can be either a single directory or a list of
-directories.  (The latter usage is discouraged.)
-
-The autoloads will be written to OUTPUT-FILE.  If any Lisp file
-binds `generated-autoload-file' as a file-local variable, write
-its autoloads into the specified file instead.
-
-The function does NOT recursively descend into subdirectories of the
-directory or directories specified."
-  (interactive "DUpdate autoloads from directory: \nFWrite to file: ")
-  (let* ((files-re (let ((tmp nil))
-                    (dolist (suf (get-load-suffixes))
-                       ;; We don't use module-file-suffix below because
-                       ;; we don't want to depend on whether Emacs was
-                       ;; built with or without modules support, nor
-                       ;; what is the suffix for the underlying OS.
-                      (unless (string-match "\\.\\(elc\\|so\\|dll\\)" suf)
-                         (push suf tmp)))
-                     (concat "\\`[^=.].*" (regexp-opt tmp t) "\\'")))
-        (files (apply #'nconc
-                      (mapcar (lambda (d)
-                                (directory-files (expand-file-name d)
-                                                  t files-re))
-                              (if (consp dir) dir (list dir)))))
-         (done ())                      ;Files processed; to remove duplicates.
-         (changed nil)                  ;Non-nil if some change occurred.
-        (last-time)
-         ;; Files with no autoload cookies or whose autoloads go to other
-         ;; files because of file-local autoload-generated-file settings.
-        (no-autoloads nil)
-         ;; Ensure that we don't do odd things when putting the doc
-         ;; strings into the autoloads file.
-         (left-margin 0)
-         (autoload-modified-buffers nil)
-        (output-time
-         (and (file-exists-p output-file)
-              (file-attribute-modification-time
-                (file-attributes output-file)))))
-
-    (with-current-buffer (autoload-find-generated-file output-file)
-      (save-excursion
-       ;; Canonicalize file names and remove the autoload file itself.
-       (setq files (delete (file-relative-name buffer-file-name)
-                           (mapcar #'file-relative-name files)))
-
-       (goto-char (point-min))
-       (while (search-forward generate-autoload-section-header nil t)
-         (let* ((form (autoload-read-section-header))
-                (file (nth 3 form)))
-           (cond ((and (consp file) (stringp (car file)))
-                  ;; This is a list of files that have no autoload cookies.
-                  ;; There shouldn't be more than one such entry.
-                  ;; Remove the obsolete section.
-                  (autoload-remove-section (match-beginning 0))
-                  (setq last-time (nth 4 form))
-                  (if (member last-time (list t autoload--non-timestamp))
-                      (setq last-time output-time))
-                  (dolist (file file)
-                    (let ((file-time (file-attribute-modification-time
-                                      (file-attributes file))))
-                      (when (and file-time
-                                 (not (time-less-p last-time file-time)))
-                        ;; file unchanged
-                        (push file no-autoloads)
-                        (setq files (delete file files))))))
-                 ((not (stringp file)))
-                 ((or (not (file-exists-p file))
-                       ;; Remove duplicates as well, just in case.
-                       (member file done))
-                   ;; Remove the obsolete section.
-                   (setq changed t)
-                  (autoload-remove-section (match-beginning 0)))
-                 ((not (time-less-p (let ((oldtime (nth 4 form)))
-                                      (if (member oldtime
-                                                  (list
-                                                   t autoload--non-timestamp))
-                                          output-time
-                                        oldtime))
-                                     (file-attribute-modification-time
-                                     (file-attributes file))))
-                  ;; File hasn't changed.
-                  nil)
-                 (t
-                   (setq changed t)
-                   (autoload-remove-section (match-beginning 0))
-                   (if (autoload-generate-file-autoloads
-                        ;; Passing `current-buffer' makes it insert at point.
-                        file (current-buffer) buffer-file-name)
-                       (push file no-autoloads))))
-            (push file done)
-           (setq files (delete file files)))))
-      ;; Elements remaining in FILES have no existing autoload sections yet.
-      (let ((no-autoloads-time (or last-time '(0 0 0 0)))
-            (progress (make-progress-reporter
-                       (byte-compile-info
-                        (concat "Scraping files for "
-                                (file-relative-name output-file)))
-                       0 (length files) nil 10))
-            (file-count 0)
-            file-time)
-       (dolist (file files)
-          (progress-reporter-update progress (setq file-count (1+ file-count)))
-         (cond
-          ;; Passing nil as second argument forces
-          ;; autoload-generate-file-autoloads to look for the right
-          ;; spot where to insert each autoloads section.
-          ((setq file-time
-                 (autoload-generate-file-autoloads file nil buffer-file-name))
-           (push file no-autoloads)
-           (if (time-less-p no-autoloads-time file-time)
-               (setq no-autoloads-time file-time)))
-           (t (setq changed t))))
-        (progress-reporter-done progress)
-
-       (when no-autoloads
-         ;; Sort them for better readability.
-         (setq no-autoloads (sort no-autoloads 'string<))
-         ;; Add the `no-autoloads' section.
-         (goto-char (point-max))
-         (search-backward "\f" nil t)
-         (autoload-insert-section-header
-          (current-buffer) nil nil
-           ;; Filter out the other loaddefs files, because it makes
-           ;; the list unstable (and leads to spurious changes in
-           ;; ldefs-boot.el) since the loaddef files can be created in
-           ;; any order.
-           (seq-filter (lambda (file)
-                         (not (string-match-p "[/-]loaddefs.el" file)))
-                       no-autoloads)
-           (if autoload-timestamps
-              no-autoloads-time
-            autoload--non-timestamp))
-         (insert generate-autoload-section-trailer)))
-
-      ;; Don't modify the file if its content has not been changed, so `make'
-      ;; dependencies don't trigger unnecessarily.
-      (if (not changed)
-          (set-buffer-modified-p nil)
-        (autoload--save-buffer))
-
-      ;; In case autoload entries were added to other files because of
-      ;; file-local autoload-generated-file settings.
-      (autoload-save-buffers))))
-
-(defun batch-update-autoloads--summary (strings)
-  (let ((message ""))
-    (while strings
-      (when (> (length (concat message " " (car strings))) 64)
-        (byte-compile-info (concat message " ...") t "SCRAPE")
-        (setq message ""))
-      (setq message (if (zerop (length message))
-                        (car strings)
-                      (concat message " " (car strings))))
-      (setq strings (cdr strings)))
-    (when (> (length message) 0)
-      (byte-compile-info message t "SCRAPE"))))
-
-;;;###autoload
-(defun batch-update-autoloads ()
-  "Update loaddefs.el autoloads in batch mode.
-Calls `update-directory-autoloads' on the command line arguments.
-Definitions are written to `generated-autoload-file' (which
-should be non-nil)."
-  ;; For use during the Emacs build process only.
-  ;; Exclude those files that are preloaded on ALL platforms.
-  ;; These are the ones in loadup.el where "(load" is at the start
-  ;; of the line (crude, but it works).
-  (unless autoload-excludes
-    (let ((default-directory (file-name-directory generated-autoload-file))
-         file)
-      (when (file-readable-p "loadup.el")
-       (with-temp-buffer
-         (insert-file-contents "loadup.el")
-         (while (re-search-forward "^(load \"\\([^\"]+\\)\"" nil t)
-           (setq file (match-string 1))
-           (or (string-match "\\.el\\'" file)
-               (setq file (format "%s.el" file)))
-           (or (string-match "\\`site-" file)
-               (push (expand-file-name file) autoload-excludes)))))))
-  (let ((args command-line-args-left))
-    (batch-update-autoloads--summary args)
-    (setq command-line-args-left nil)
-    (make-directory-autoloads args generated-autoload-file)))
-
-(provide 'autoload)
-
-;;; autoload.el ends here
diff --git a/lisp/emacs-lisp/backtrace.el b/lisp/emacs-lisp/backtrace.el
index 3231877a30..70473770d1 100644
--- a/lisp/emacs-lisp/backtrace.el
+++ b/lisp/emacs-lisp/backtrace.el
@@ -58,7 +58,8 @@ Backtrace mode will attempt to abbreviate printing of 
backtrace
 frames by setting `print-level' and `print-length' to make them
 shorter than this, but success is not guaranteed.  If set to nil
 or zero, backtrace mode will not abbreviate the forms it prints."
-  :type 'integer
+  :type '(choice natnum
+                 (const :value nil :tag "Don't abbreviate"))
   :group 'backtrace
   :version "27.1")
 
@@ -199,63 +200,63 @@ functions returns non-nil.  When adding a function to 
this hook,
 you should also set the :source-available flag for the backtrace
 frames where the source code location is known.")
 
-(defvar backtrace-mode-map
-  (let ((map (copy-keymap special-mode-map)))
-    (set-keymap-parent map button-buffer-map)
-    (define-key map "n" 'backtrace-forward-frame)
-    (define-key map "p" 'backtrace-backward-frame)
-    (define-key map "v" 'backtrace-toggle-locals)
-    (define-key map "#" 'backtrace-toggle-print-circle)
-    (define-key map ":" 'backtrace-toggle-print-gensym)
-    (define-key map "s" 'backtrace-goto-source)
-    (define-key map "\C-m" 'backtrace-help-follow-symbol)
-    (define-key map "+" 'backtrace-multi-line)
-    (define-key map "-" 'backtrace-single-line)
-    (define-key map "." 'backtrace-expand-ellipses)
-    (define-key map [follow-link] 'mouse-face)
-    (define-key map [mouse-2] 'mouse-select-window)
-    (easy-menu-define nil map ""
-      '("Backtrace"
-        ["Next Frame" backtrace-forward-frame
-         :help "Move cursor forwards to the start of a backtrace frame"]
-        ["Previous Frame" backtrace-backward-frame
-         :help "Move cursor backwards to the start of a backtrace frame"]
-        "--"
-        ["Show Variables" backtrace-toggle-locals
-         :style toggle
-         :active (backtrace-get-index)
-         :selected (plist-get (backtrace-get-view) :show-locals)
-         :help "Show or hide the local variables for the frame at point"]
-        ["Show Circular Structures" backtrace-toggle-print-circle
-         :style toggle
-         :active (backtrace-get-index)
-         :selected (plist-get (backtrace-get-view) :print-circle)
-         :help
-         "Condense or expand shared or circular structures in the frame at 
point"]
-        ["Show Uninterned Symbols" backtrace-toggle-print-gensym
-         :style toggle
-         :active (backtrace-get-index)
-         :selected (plist-get (backtrace-get-view) :print-gensym)
-         :help
-         "Toggle unique printing of uninterned symbols in the frame at point"]
-        ["Expand \"...\"s" backtrace-expand-ellipses
-         :help "Expand all the abbreviated forms in the current frame"]
-        ["Show on Multiple Lines" backtrace-multi-line
-         :help "Use line breaks and indentation to make a form more readable"]
-        ["Show on Single Line" backtrace-single-line]
-        "--"
-        ["Go to Source" backtrace-goto-source
-         :active (and (backtrace-get-index)
-                      (plist-get (backtrace-frame-flags
-                                  (nth (backtrace-get-index) backtrace-frames))
-                                 :source-available))
-         :help "Show the source code for the current frame"]
-        ["Help for Symbol" backtrace-help-follow-symbol
-         :help "Show help for symbol at point"]
-        ["Describe Backtrace Mode" describe-mode
-         :help "Display documentation for backtrace-mode"]))
-    map)
-  "Local keymap for `backtrace-mode' buffers.")
+(defvar-keymap backtrace-mode-map
+  :doc "Local keymap for `backtrace-mode' buffers."
+  :parent (make-composed-keymap special-mode-map
+                                button-buffer-map)
+  "n"   #'backtrace-forward-frame
+  "p"   #'backtrace-backward-frame
+  "v"   #'backtrace-toggle-locals
+  "#"   #'backtrace-toggle-print-circle
+  ":"   #'backtrace-toggle-print-gensym
+  "s"   #'backtrace-goto-source
+  "RET" #'backtrace-help-follow-symbol
+  "+"   #'backtrace-multi-line
+  "-"   #'backtrace-single-line
+  "."   #'backtrace-expand-ellipses
+  "<follow-link>" 'mouse-face
+  "<mouse-2>"     #'mouse-select-window
+
+  :menu
+  '("Backtrace"
+    ["Next Frame" backtrace-forward-frame
+     :help "Move cursor forwards to the start of a backtrace frame"]
+    ["Previous Frame" backtrace-backward-frame
+     :help "Move cursor backwards to the start of a backtrace frame"]
+    "--"
+    ["Show Variables" backtrace-toggle-locals
+     :style toggle
+     :active (backtrace-get-index)
+     :selected (plist-get (backtrace-get-view) :show-locals)
+     :help "Show or hide the local variables for the frame at point"]
+    ["Show Circular Structures" backtrace-toggle-print-circle
+     :style toggle
+     :active (backtrace-get-index)
+     :selected (plist-get (backtrace-get-view) :print-circle)
+     :help
+     "Condense or expand shared or circular structures in the frame at point"]
+    ["Show Uninterned Symbols" backtrace-toggle-print-gensym
+     :style toggle
+     :active (backtrace-get-index)
+     :selected (plist-get (backtrace-get-view) :print-gensym)
+     :help
+     "Toggle unique printing of uninterned symbols in the frame at point"]
+    ["Expand \"...\"s" backtrace-expand-ellipses
+     :help "Expand all the abbreviated forms in the current frame"]
+    ["Show on Multiple Lines" backtrace-multi-line
+     :help "Use line breaks and indentation to make a form more readable"]
+    ["Show on Single Line" backtrace-single-line]
+    "--"
+    ["Go to Source" backtrace-goto-source
+     :active (and (backtrace-get-index)
+                  (plist-get (backtrace-frame-flags
+                              (nth (backtrace-get-index) backtrace-frames))
+                             :source-available))
+     :help "Show the source code for the current frame"]
+    ["Help for Symbol" backtrace-help-follow-symbol
+     :help "Show help for symbol at point"]
+    ["Describe Backtrace Mode" describe-mode
+     :help "Display documentation for backtrace-mode"]))
 
 (defconst backtrace--flags-width 2
   "Width in characters of the flags for a backtrace frame.")
@@ -590,7 +591,7 @@ content of the sexp."
          (begin (previous-single-property-change end 'backtrace-form
                                                  nil (point-min))))
     (unless tag
-      (when (or (= end (point-max)) (> end (point-at-eol)))
+      (when (or (= end (point-max)) (> end (line-end-position)))
         (user-error "No form here to reformat"))
       (goto-char end)
       (setq pos end
diff --git a/lisp/emacs-lisp/bindat.el b/lisp/emacs-lisp/bindat.el
index 9ba89a5e3f..0ecac3d52a 100644
--- a/lisp/emacs-lisp/bindat.el
+++ b/lisp/emacs-lisp/bindat.el
@@ -440,17 +440,26 @@ e.g. corresponding to STRUCT.FIELD1[INDEX2].FIELD3..."
       (aset bindat-raw (+ bindat-idx i) (aref v i)))
     (setq bindat-idx (+ bindat-idx len))))
 
-(defun bindat--pack-strz (v)
+(defun bindat--pack-strz (len v)
   (let* ((v (string-to-unibyte v))
-         (len (length v)))
-    (dotimes (i len)
-      (when (= (aref v i) 0)
-        ;; Alternatively we could pretend that this was the end of
-        ;; the string and stop packing, but then bindat-length would
-        ;; need to scan the input string looking for a null byte.
-        (error "Null byte encountered in input strz string"))
-      (aset bindat-raw (+ bindat-idx i) (aref v i)))
-    (setq bindat-idx (+ bindat-idx len 1))))
+         (vlen (length v)))
+    ;; Explicitly write a null terminator (if there's room) in case
+    ;; the user provided a pre-allocated string to `bindat-pack' that
+    ;; wasn't already zeroed.
+    (when (or (null len) (< vlen len))
+      (aset bindat-raw (+ bindat-idx vlen) 0))
+    (if len
+        ;; When len is specified, behave the same as the str type
+        ;; (except for the null terminator possibly written above).
+        (bindat--pack-str len v)
+      (dotimes (i vlen)
+        (when (= (aref v i) 0)
+          ;; Alternatively we could pretend that this was the end of
+          ;; the string and stop packing, but then bindat-length would
+          ;; need to scan the input string looking for a null byte.
+          (error "Null byte encountered in input strz string"))
+        (aset bindat-raw (+ bindat-idx i) (aref v i)))
+      (setq bindat-idx (+ bindat-idx vlen 1)))))
 
 (defun bindat--pack-bits (len v)
   (let ((bnum (1- (* 8 len))) j m)
@@ -479,7 +488,8 @@ e.g. corresponding to STRUCT.FIELD1[INDEX2].FIELD3..."
    ('u24r (bindat--pack-u24r v))
    ('u32r (bindat--pack-u32r v))
    ('bits (bindat--pack-bits len v))
-   ((or 'str 'strz) (bindat--pack-str len v))
+   ('str (bindat--pack-str len v))
+   ('strz (bindat--pack-strz len v))
    ('vec
     (let ((l (length v)) (vlen 1))
       (if (consp vectype)
@@ -696,18 +706,7 @@ is the name of a variable that will hold the value we need 
to pack.")
                             ((numberp len) len)
                             ;; General expression support.
                             (t `(or ,len (1+ (length ,val)))))))
-    (`(pack . ,args)
-     ;; When len is specified, behave the same as the str type since we don't
-     ;; actually add the terminating zero anyway (because we rely on the fact
-     ;; that `bindat-raw' was presumably initialized with all-zeroes before we
-     ;; started).
-     (cond ; Same optimizations as 'length above.
-      ((null len) `(bindat--pack-strz . ,args))
-      ((numberp len) `(bindat--pack-str ,len . ,args))
-      (t (macroexp-let2 nil len len
-           `(if ,len
-                (bindat--pack-str ,len . ,args)
-              (bindat--pack-strz . ,args))))))))
+    (`(pack . ,args) `(bindat--pack-strz ,len . ,args))))
 
 (cl-defmethod bindat--type (op (_ (eql 'bits))  len)
   (bindat--pcase op
diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el
index fc49e88f8e..27b0d33d3e 100644
--- a/lisp/emacs-lisp/byte-opt.el
+++ b/lisp/emacs-lisp/byte-opt.el
@@ -171,7 +171,7 @@ Earlier variables shadow later ones with the same name.")
        (if (eq fn localfn)
            ;; From the same file => same mode.
            (macroexp--unfold-lambda `(,fn ,@(cdr form)))
-         ;; Since we are called from inside the optimiser, we need to make
+         ;; Since we are called from inside the optimizer, we need to make
          ;; sure not to propagate lexvar values.
          (let ((byte-optimize--lexvars nil)
                ;; Silence all compilation warnings: the useful ones should
@@ -204,7 +204,7 @@ Same format as `byte-optimize--lexvars', with shared 
structure and contents.")
 This indicates the loop discovery phase.")
 
 (defvar byte-optimize--dynamic-vars nil
-  "List of variables declared as dynamic during optimisation.")
+  "List of variables declared as dynamic during optimization.")
 
 (defvar byte-optimize--aliased-vars nil
   "List of variables which may be aliased by other lexical variables.
@@ -315,7 +315,7 @@ for speeding up processing.")
       (`(cond . ,clauses)
        ;; FIXME: The condition in the first clause is always executed, and
        ;; clause bodies are mutually exclusive -- use this for improved
-       ;; optimisation (see comment about `if' below).
+       ;; optimization (see comment about `if' below).
        (cons fn
              (mapcar (lambda (clause)
                        (if (consp clause)
@@ -364,9 +364,9 @@ for speeding up processing.")
        ;; FIXME: We have to traverse the expressions in left-to-right
        ;; order (because that is the order of evaluation and variable
        ;; mutations must be found prior to their use), but doing so we miss
-       ;; some optimisation opportunities:
+       ;; some optimization opportunities:
        ;; consider (and A B) in a for-effect context, where B => nil.
-       ;; Then A could be optimised in a for-effect context too.
+       ;; Then A could be optimized in a for-effect context too.
        (let ((tail exps)
              (args nil))
          (while tail
@@ -380,19 +380,19 @@ for speeding up processing.")
        ;; FIXME: If the loop condition is statically nil after substitution
        ;; of surrounding variables then we can eliminate the whole loop,
        ;; even if those variables are mutated inside the loop.
-       ;; We currently don't perform this important optimisation.
+       ;; We currently don't perform this important optimization.
        (let* ((byte-optimize--vars-outside-loop byte-optimize--lexvars)
               (condition-body
                (if byte-optimize--inhibit-outside-loop-constprop
                    ;; We are already inside the discovery phase of an outer
                    ;; loop so there is no need for traversing this loop twice.
                    (cons exp exps)
-                 ;; Discovery phase: run optimisation without substitution
+                 ;; Discovery phase: run optimization without substitution
                  ;; of variables bound outside this loop.
                  (let ((byte-optimize--inhibit-outside-loop-constprop t))
                    (cons (byte-optimize-form exp nil)
                          (byte-optimize-body exps t)))))
-              ;; Optimise again, this time with constprop enabled (unless
+              ;; Optimize again, this time with constprop enabled (unless
               ;; we are in discovery of an outer loop),
               ;; as mutated variables have been marked as non-substitutable.
               (condition (byte-optimize-form (car condition-body) nil))
@@ -406,7 +406,7 @@ for speeding up processing.")
       (`(function . ,_)
        ;; This forms is compiled as constant or by breaking out
        ;; all the subexpressions and compiling them separately.
-       form)
+       (and (not for-effect) form))
 
       (`(condition-case ,var ,exp . ,clauses)
        `(,fn ,var          ;Not evaluated.
@@ -422,15 +422,13 @@ for speeding up processing.")
                               (byte-optimize-body (cdr clause) for-effect))))
                     clauses)))
 
-      (`(unwind-protect ,exp :fun-body ,f)
-       ;; The unwinding part of an unwind-protect is compiled (and thus
-       ;; optimized) as a top-level form, but run the optimizer for it here
-       ;; anyway for lexical variable usage and substitution.  But the
-       ;; protected part has the same for-effect status as the
-       ;; unwind-protect itself.  (The unwinding part is always for effect,
-       ;; but that isn't handled properly yet.)
-       (let ((bodyform (byte-optimize-form exp for-effect)))
-         `(,fn ,bodyform :fun-body ,(byte-optimize-form f nil))))
+      ;; `unwind-protect' is a special form which here takes the shape
+      ;; (unwind-protect EXPR :fun-body UNWIND-FUN).
+      ;; We can treat it as if it were a plain function at this point,
+      ;; although there are specific optimizations possible.
+      ;; In particular, the return value of UNWIND-FUN is never used
+      ;; so its body should really be compiled for-effect, but we
+      ;; don't do that right now.
 
       (`(catch ,tag . ,exps)
        `(,fn ,(byte-optimize-form tag nil)
@@ -438,13 +436,15 @@ for speeding up processing.")
 
       ;; Needed as long as we run byte-optimize-form after cconv.
       (`(internal-make-closure . ,_)
+       (and (not for-effect)
+            (progn
        ;; Look up free vars and mark them to be kept, so that they
-       ;; won't be optimised away.
+       ;; won't be optimized away.
        (dolist (var (caddr form))
          (let ((lexvar (assq var byte-optimize--lexvars)))
            (when lexvar
              (setcar (cdr lexvar) t))))
-       form)
+              form)))
 
       (`((lambda . ,_) . ,_)
        (let ((newform (macroexp--unfold-lambda form)))
@@ -513,7 +513,7 @@ for speeding up processing.")
 
 (defun byte-optimize-one-form (form &optional for-effect)
   "The source-level pass of the optimizer."
-  ;; Make optimiser aware of lexical arguments.
+  ;; Make optimizer aware of lexical arguments.
   (let ((byte-optimize--lexvars
          (mapcar (lambda (v) (list (car v) t))
                  byte-compile--lexical-environment)))
@@ -525,7 +525,7 @@ for speeding up processing.")
         ;; First, optimize all sub-forms of this one.
         (setq form (byte-optimize-form-code-walker form for-effect))
 
-        ;; If a form-specific optimiser is available, run it and start over
+        ;; If a form-specific optimizer is available, run it and start over
         ;; until a fixpoint has been reached.
         (and (consp form)
              (symbolp (car form))
@@ -722,35 +722,108 @@ for speeding up processing.")
 ;; something not EQ to its argument if and ONLY if it has made a change.
 ;; This implies that you cannot simply destructively modify the list;
 ;; you must return something not EQ to it if you make an optimization.
-;;
-;; It is now safe to optimize code such that it introduces new bindings.
 
-(defsubst byte-compile-trueconstp (form)
+(defsubst byte-opt--bool-value-form (form)
+  "The form in FORM that yields its boolean value, possibly FORM itself."
+  (while (let ((head (car-safe form)))
+           (cond ((memq head '( progn inline save-excursion save-restriction
+                                save-current-buffer))
+                  (setq form (car (last (cdr form))))
+                  t)
+                 ((memq head '(let let*))
+                  (setq form (car (last (cddr form))))
+                  t)
+                 ((memq head '( prog1 unwind-protect copy-sequence identity
+                                reverse nreverse sort))
+                  (setq form (nth 1 form))
+                  t)
+                 ((memq head '(mapc setq setcar setcdr puthash))
+                  (setq form (nth 2 form))
+                  t)
+                 ((memq head '(aset put function-put))
+                  (setq form (nth 3 form))
+                  t))))
+  form)
+
+(defun byte-compile-trueconstp (form)
   "Return non-nil if FORM always evaluates to a non-nil value."
-  (while (eq (car-safe form) 'progn)
-    (setq form (car (last (cdr form)))))
+  (setq form (byte-opt--bool-value-form form))
   (cond ((consp form)
-         (pcase (car form)
-           ('quote (cadr form))
-           ;; Can't use recursion in a defsubst.
-           ;; (`progn (byte-compile-trueconstp (car (last (cdr form)))))
-           ))
+         (let ((head (car form)))
+           ;; FIXME: Lots of other expressions are statically non-nil.
+           (cond ((memq head '(quote function)) (cadr form))
+                 ((eq head 'list) (cdr form))
+                 ((memq head
+                        ;; FIXME: Replace this list with a function property?
+                        '( length safe-length cons lambda
+                           string unibyte-string make-string concat
+                           format format-message
+                           substring substring-no-properties string-replace
+                           replace-regexp-in-string symbol-name make-symbol
+                           compare-strings string-distance
+                           mapconcat
+                           vector make-vector vconcat make-record record
+                           regexp-quote regexp-opt
+                           buffer-string buffer-substring
+                           buffer-substring-no-properties
+                           current-buffer buffer-size get-buffer-create
+                           point point-min point-max buffer-end count-lines
+                           following-char preceding-char get-byte max-char
+                           region-beginning region-end
+                           line-beginning-position line-end-position
+                           pos-bol pos-eol
+                           + - * / % 1+ 1- min max abs mod expt logb
+                           logand logior logxor lognot ash logcount
+                           floor ceiling round truncate
+                           sqrt sin cos tan asin acos atan exp log copysign
+                           ffloor fceiling fround ftruncate float
+                           ldexp frexp
+                           number-to-string string-to-number
+                           int-to-string char-to-string
+                           prin1-to-string read-from-string
+                           byte-to-string string-to-vector string-to-char
+                           capitalize upcase downcase
+                           propertize
+                           string-as-multibyte string-as-unibyte
+                           string-to-multibyte string-to-unibyte
+                           string-make-multibyte string-make-unibyte
+                           string-width char-width
+                           make-hash-table hash-table-count
+                           unibyte-char-to-multibyte multibyte-char-to-unibyte
+                           sxhash sxhash-equal sxhash-eq sxhash-eql
+                           sxhash-equal-including-properties
+                           make-marker copy-marker point-marker mark-marker
+                           kbd key-description
+                           always))
+                  t)
+                 ((eq head 'if)
+                  (and (byte-compile-trueconstp (nth 2 form))
+                       (byte-compile-trueconstp (car (last (cdddr form))))))
+                 ((memq head '(not null))
+                  (byte-compile-nilconstp (cadr form)))
+                 ((eq head 'or)
+                  (and (cdr form)
+                       (byte-compile-trueconstp (car (last (cdr form)))))))))
         ((not (symbolp form)))
         ((eq form t))
         ((keywordp form))))
 
-(defsubst byte-compile-nilconstp (form)
+(defun byte-compile-nilconstp (form)
   "Return non-nil if FORM always evaluates to a nil value."
-  (while (eq (car-safe form) 'progn)
-    (setq form (car (last (cdr form)))))
-  (cond ((consp form)
-         (pcase (car form)
-           ('quote (null (cadr form)))
-           ;; Can't use recursion in a defsubst.
-           ;; (`progn (byte-compile-nilconstp (car (last (cdr form)))))
-           ))
-        ((not (symbolp form)) nil)
-        ((null form))))
+  (setq form (byte-opt--bool-value-form form))
+  (or (not form)   ; assume (quote nil) always being normalised to nil
+      (and (consp form)
+           (let ((head (car form)))
+             ;; FIXME: There are many other expressions that are statically 
nil.
+             (cond ((memq head '(while ignore)) t)
+                   ((eq head 'if)
+                    (and (byte-compile-nilconstp (nth 2 form))
+                         (byte-compile-nilconstp (car (last (cdddr form))))))
+                   ((memq head '(not null))
+                    (byte-compile-trueconstp (cadr form)))
+                   ((eq head 'and)
+                    (and (cdr form)
+                         (byte-compile-nilconstp (car (last (cdr 
form)))))))))))
 
 ;; If the function is being called with constant integer args,
 ;; evaluate as much as possible at compile-time.  This optimizer
@@ -921,7 +994,7 @@ for speeding up processing.")
 (defun byte-optimize--fixnump (o)
   "Return whether O is guaranteed to be a fixnum in all Emacsen.
 See Info node `(elisp) Integer Basics'."
-  (and (fixnump o) (<= -536870912 o 536870911)))
+  (and (integerp o) (<= -536870912 o 536870911)))
 
 (defun byte-optimize-equal (form)
   ;; Replace `equal' or `eql' with `eq' if at least one arg is a
@@ -1077,35 +1150,91 @@ See Info node `(elisp) Integer Basics'."
     (nth 1 form)))
 
 (defun byte-optimize-and (form)
-  ;; Simplify if less than 2 args.
-  ;; if there is a literal nil in the args to `and', throw it and following
-  ;; forms away, and surround the `and' with (progn ... nil).
-  (cond ((null (cdr form)))
-       ((memq nil form)
-        (list 'progn
-              (byte-optimize-and
-               (prog1 (setq form (copy-sequence form))
-                 (while (nth 1 form)
-                   (setq form (cdr form)))
-                 (setcdr form nil)))
-              nil))
-       ((null (cdr (cdr form)))
-        (nth 1 form))
-       ((byte-optimize-constant-args form))))
+  (let ((seq nil)
+        (new-args nil)
+        (nil-result nil)
+        (args (cdr form)))
+    (while
+        (and args
+             (let ((arg (car args)))
+               (cond
+                (seq                    ; previous arg was always-true
+                 (push arg seq)
+                 (unless (and (cdr args) (byte-compile-trueconstp arg))
+                   (push `(progn . ,(nreverse seq)) new-args)
+                   (setq seq nil))
+                 t)
+                ((and (cdr args) (byte-compile-trueconstp arg))
+                 ;; Always-true arg: evaluate unconditionally.
+                 (push arg seq)
+                 t)
+                ((and arg (not (byte-compile-nilconstp arg)))
+                 (push arg new-args)
+                 t)
+                (t
+                 ;; Throw away the remaining args; this one is always false.
+                 (setq nil-result t)
+                 (when arg
+                   (push arg new-args))  ; keep possible side-effects
+                 nil))))
+      (setq args (cdr args)))
+
+    (setq new-args (nreverse new-args))
+    (if (equal new-args (cdr form))
+        ;; Input is unchanged: keep original form, and don't represent
+        ;; a nil result explicitly because that would lead to infinite
+        ;; growth when the optimiser is iterated.
+        (setq nil-result nil)
+      (setq form (cons (car form) new-args)))
+
+    (let ((new-form
+           (pcase form
+             ;; (and (progn ... X) ...) -> (progn ... (and X ...))
+             (`(,head (progn . ,forms) . ,rest)
+              `(progn ,@(butlast forms) (,head ,(car (last forms)) . ,rest)))
+             (`(,_) t)                   ; (and) -> t
+             (`(,_ ,arg) arg)            ; (and X) -> X
+             (_ (byte-optimize-constant-args form)))))
+      (if nil-result
+          `(progn ,new-form nil)
+        new-form))))
 
 (defun byte-optimize-or (form)
-  ;; Throw away nil's, and simplify if less than 2 args.
-  ;; If there is a literal non-nil constant in the args to `or', throw away all
-  ;; following forms.
-  (setq form (remq nil form))
-  (let ((rest form))
-    (while (cdr (setq rest (cdr rest)))
-      (if (byte-compile-trueconstp (car rest))
-         (setq form (copy-sequence form)
-               rest (setcdr (memq (car rest) form) nil))))
-    (if (cdr (cdr form))
-       (byte-optimize-constant-args form)
-      (nth 1 form))))
+  (let ((seq nil)
+        (new-args nil)
+        (args (remq nil (cdr form))))   ; Discard nil arguments.
+    (while
+        (and args
+             (let ((arg (car args)))
+               (cond
+                (seq                    ; previous arg was always-false
+                 (push arg seq)
+                 (unless (and (cdr args) (byte-compile-nilconstp arg))
+                   (push `(progn . ,(nreverse seq)) new-args)
+                   (setq seq nil))
+                 t)
+                ((and (cdr args) (byte-compile-nilconstp arg))
+                 ;; Always-false arg: evaluate unconditionally.
+                 (push arg seq)
+                 t)
+                (t
+                 (push arg new-args)
+                 ;; If this arg is always true, throw away the remaining args.
+                 (not (byte-compile-trueconstp arg))))))
+      (setq args (cdr args)))
+
+    (setq new-args (nreverse new-args))
+    ;; Keep original form unless the arguments changed.
+    (unless (equal new-args (cdr form))
+      (setq form (cons (car form) new-args)))
+
+    (pcase form
+      ;; (or (progn ... X) ...) -> (progn ... (or X ...))
+      (`(,head (progn . ,forms) . ,rest)
+       `(progn ,@(butlast forms) (,head ,(car (last forms)) . ,rest)))
+      (`(,_) nil)                       ; (or) -> nil
+      (`(,_ ,arg) arg)                  ; (or X) -> X
+      (_ (byte-optimize-constant-args form)))))
 
 (defun byte-optimize-cond (form)
   ;; if any clauses have a literal nil as their test, throw them away.
@@ -1142,55 +1271,79 @@ See Info node `(elisp) Integer Basics'."
          (and clauses form)))
     form))
 
+(defsubst byte-opt--negate (form)
+  "Negate FORM, avoiding double negation if already negated."
+  (if (and (consp form) (memq (car form) '(not null)))
+      (cadr form)
+    `(not ,form)))
+
 (defun byte-optimize-if (form)
-  ;; (if (progn <insts> <test>) <rest>) ==> (progn <insts> (if <test> <rest>))
-  ;; (if <true-constant> <then> <else...>) ==> <then>
-  ;; (if <false-constant> <then> <else...>) ==> (progn <else...>)
-  ;; (if <test> nil <else...>) ==> (if (not <test>) (progn <else...>))
-  ;; (if <test> <then> nil) ==> (if <test> <then>)
-  (let ((clause (nth 1 form)))
-    (cond ((and (eq (car-safe clause) 'progn)
-                (proper-list-p clause))
-           (if (null (cddr clause))
-               ;; A trivial `progn'.
-               (byte-optimize-if `(,(car form) ,(cadr clause) ,@(nthcdr 2 
form)))
-             (nconc (butlast clause)
-                    (list
-                     (byte-optimize-if
-                      `(,(car form) ,(car (last clause)) ,@(nthcdr 2 
form)))))))
-          ((byte-compile-trueconstp clause)
-          `(progn ,clause ,(nth 2 form)))
-         ((byte-compile-nilconstp clause)
-           `(progn ,clause ,@(nthcdr 3 form)))
-         ((nth 2 form)
-          (if (equal '(nil) (nthcdr 3 form))
-              (list (car form) clause (nth 2 form))
-            form))
-         ((or (nth 3 form) (nthcdr 4 form))
-          (list (car form)
-                ;; Don't make a double negative;
-                ;; instead, take away the one that is there.
-                (if (and (consp clause) (memq (car clause) '(not null))
-                         (= (length clause) 2)) ; (not xxxx) or (not (xxxx))
-                    (nth 1 clause)
-                  (list 'not clause))
-                (if (nthcdr 4 form)
-                    (cons 'progn (nthcdr 3 form))
-                  (nth 3 form))))
-         (t
-          (list 'progn clause nil)))))
+  (let ((condition (nth 1 form))
+        (then (nth 2 form))
+        (else (nthcdr 3 form)))
+    (cond
+     ;; (if (progn ... X) ...) -> (progn ... (if X ...))
+     ((eq (car-safe condition) 'progn)
+      (nconc (butlast condition)
+             (list
+              (byte-optimize-if
+               `(,(car form) ,(car (last condition)) ,@(nthcdr 2 form))))))
+     ;; (if TRUE THEN ...) -> (progn TRUE THEN)
+     ((byte-compile-trueconstp condition)
+      `(progn ,condition ,then))
+     ;; (if FALSE THEN ELSE...) -> (progn FALSE ELSE...)
+     ((byte-compile-nilconstp condition)
+      (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))))
+      `(not ,(byte-opt--negate condition)))
+     ;; (if VAR VAR X...) -> (or VAR (progn X...))
+     ((and (symbolp condition) (eq condition then))
+      `(or ,then ,(if (cdr else)
+                      `(progn . ,else)
+                    (car else))))
+     ;; (if X THEN nil) -> (if X THEN)
+     (then
+      (if (equal else '(nil))
+         (list (car form) condition then)
+       form))
+     ;; (if X nil ELSE...) -> (if (not X) (progn ELSE...))
+     ((or (car else) (cdr else))
+      (list (car form) (byte-opt--negate condition)
+           (if (cdr else)
+               `(progn . ,else)
+             (car else))))
+     ;; (if X nil nil) -> (progn X nil)
+     (t
+      (list 'progn condition nil)))))
 
 (defun byte-optimize-while (form)
-  (when (< (length form) 2)
-    (byte-compile-warn-x form "too few arguments for `while'"))
-  (if (nth 1 form)
-      form))
+  (let ((condition (nth 1 form)))
+    (if (byte-compile-nilconstp condition)
+        condition
+      form)))
+
+(defun byte-optimize-not (form)
+  (and (= (length form) 2)
+       (let ((arg (nth 1 form)))
+         (cond ((null arg) t)
+               ((macroexp-const-p arg) nil)
+               ((byte-compile-nilconstp arg) `(progn ,arg t))
+               ((byte-compile-trueconstp arg) `(progn ,arg nil))
+               (t form)))))
 
 (put 'and   'byte-optimizer #'byte-optimize-and)
 (put 'or    'byte-optimizer #'byte-optimize-or)
 (put 'cond  'byte-optimizer #'byte-optimize-cond)
 (put 'if    'byte-optimizer #'byte-optimize-if)
 (put 'while 'byte-optimizer #'byte-optimize-while)
+(put 'not   'byte-optimizer #'byte-optimize-not)
+(put 'null  'byte-optimizer #'byte-optimize-not)
 
 ;; byte-compile-negation-optimizer lives in bytecomp.el
 (put '/= 'byte-optimizer #'byte-compile-negation-optimizer)
@@ -1207,25 +1360,26 @@ See Info node `(elisp) Integer Basics'."
       form)))
 
 (defun byte-optimize-apply (form)
-  ;; If the last arg is a literal constant, turn this into a funcall.
-  ;; The funcall optimizer can then transform (funcall 'foo ...) -> (foo ...).
-  (if (= (length form) 2)
-      ;; single-argument `apply' is not worth optimizing (bug#40968)
-      form
-    (let ((fn (nth 1 form))
-         (last (nth (1- (length form)) form))) ; I think this really is fastest
-      (or (if (or (null last)
-                 (eq (car-safe last) 'quote))
-             (if (listp (nth 1 last))
-                 (let ((butlast (nreverse (cdr (reverse (cdr (cdr form)))))))
-                   (nconc (list 'funcall fn) butlast
-                          (mapcar (lambda (x) (list 'quote x)) (nth 1 last))))
+  (let ((len (length form)))
+    (if (>= len 2)
+        (let ((fn (nth 1 form))
+             (last (nth (1- len) form)))
+          (cond
+           ;; (apply F ... '(X Y ...)) -> (funcall F ... 'X 'Y ...)
+           ((or (null last)
+                (eq (car-safe last) 'quote))
+            (let ((last-value (nth 1 last)))
+             (if (listp last-value)
+                  `(funcall ,fn ,@(butlast (cddr form))
+                            ,@(mapcar (lambda (x) (list 'quote x)) last-value))
                (byte-compile-warn-x
-                 last
-                "last arg to apply can't be a literal atom: `%s'"
-                last)
-               nil))
-         form))))
+                 last "last arg to apply can't be a literal atom: `%s'" last)
+               nil)))
+           ;; (apply F ... (list X Y ...)) -> (funcall F ... X Y ...)
+           ((eq (car-safe last) 'list)
+            `(funcall ,fn ,@(butlast (cddr form)) ,@(cdr last)))
+           (t form)))
+      form)))
 
 (put 'funcall 'byte-optimizer #'byte-optimize-funcall)
 (put 'apply   'byte-optimizer #'byte-optimize-apply)
@@ -1281,15 +1435,99 @@ See Info node `(elisp) Integer Basics'."
 
 (put 'cons 'byte-optimizer #'byte-optimize-cons)
 (defun byte-optimize-cons (form)
-  ;; (cons X nil) => (list X)
-  (if (and (= (safe-length form) 3)
-           (null (nth 2 form)))
-      `(list ,(nth 1 form))
-    form))
+  (let ((tail (nth 2 form)))
+    (cond
+     ;; (cons X nil) => (list X)
+     ((null tail) `(list ,(nth 1 form)))
+     ;; (cons X (list YS...)) -> (list X YS...)
+     ((and (consp tail) (eq (car tail) 'list))
+      `(,(car tail) ,(nth 1 form) . ,(cdr tail)))
+     (t form))))
+
+(put 'list 'byte-optimizer #'byte-optimize-list)
+(defun byte-optimize-list (form)
+  ;; (list) -> nil
+  (and (cdr form) form))
+
+(put 'append 'byte-optimizer #'byte-optimize-append)
+(defun byte-optimize-append (form)
+  ;; There is (probably) too much code relying on `append' to return a
+  ;; new list for us to do full constant-folding; these transformations
+  ;; preserve the allocation semantics.
+  (and (cdr form)                       ; (append) -> nil
+       (named-let loop ((args (cdr form)) (newargs nil))
+         (let ((arg (car args))
+               (prev (car newargs)))
+           (cond
+            ;; Flatten nested `append' forms.
+            ((and (consp arg) (eq (car arg) 'append))
+             (loop (append (cdr arg) (cdr args)) newargs))
+
+            ;; Merge consecutive `list' forms.
+            ((and (consp arg) (eq (car arg) 'list)
+                  newargs (consp prev) (eq (car prev) 'list))
+             (loop (cons (cons (car prev) (append (cdr prev) (cdr arg)))
+                         (cdr args))
+                   (cdr newargs)))
+
+            ;; non-terminal arg
+            ((cdr args)
+             (cond
+              ((macroexp-const-p arg)
+               ;; constant arg
+               (let ((val (eval arg)))
+                 (cond
+                  ;; Elide empty arguments (nil, empty string, etc).
+                  ((zerop (length val))
+                   (loop (cdr args) newargs))
+                  ;; Merge consecutive constants.
+                  ((and newargs (macroexp-const-p prev))
+                   (loop (cdr args)
+                         (cons
+                          (list 'quote
+                                (append (eval prev) val nil))
+                          (cdr newargs))))
+                  (t (loop (cdr args) (cons arg newargs))))))
+
+              ;; (list CONSTANTS...) -> '(CONSTANTS...)
+              ((and (consp arg) (eq (car arg) 'list)
+                    (not (memq nil (mapcar #'macroexp-const-p (cdr arg)))))
+               (loop (cons (list 'quote (eval arg)) (cdr args)) newargs))
+
+              (t (loop (cdr args) (cons arg newargs)))))
+
+            ;; At this point, `arg' is the last (tail) argument.
+
+            ;; (append X) -> X
+            ((null newargs) arg)
+
+            ;; (append (list Xs...) nil) -> (list Xs...)
+            ((and (null arg)
+                  newargs (null (cdr newargs))
+                  (consp prev) (eq (car prev) 'list))
+             prev)
+
+            ;; (append '(X) Y)     -> (cons 'X Y)
+            ;; (append (list X) Y) -> (cons X Y)
+            ((and newargs (null (cdr newargs))
+                  (consp prev)
+                  (cond ((eq (car prev) 'quote)
+                         (and (consp (cadr prev))
+                              (= (length (cadr prev)) 1)))
+                        ((eq (car prev) 'list)
+                         (= (length (cdr prev)) 1))))
+             (list 'cons (if (eq (car prev) 'quote)
+                             (macroexp-quote (caadr prev))
+                           (cadr prev))
+                   arg))
+
+            (t
+             (let ((new-form (cons 'append (nreverse (cons arg newargs)))))
+               (if (equal new-form form)
+                   form
+                 new-form))))))))
 
 ;; Fixme: delete-char -> delete-region (byte-coded)
-;; optimize string-as-unibyte, string-as-multibyte, string-make-unibyte,
-;; string-make-multibyte for constant args.
 
 (put 'set 'byte-optimizer #'byte-optimize-set)
 (defun byte-optimize-set (form)
@@ -1354,28 +1592,27 @@ See Info node `(elisp) Integer Basics'."
         keymap-parent
          lax-plist-get ldexp
          length length< length> length=
-         line-beginning-position line-end-position
+         line-beginning-position line-end-position pos-bol pos-eol
         local-variable-if-set-p local-variable-p locale-info
         log log10 logand logb logcount logior lognot logxor lsh
         make-byte-code make-list make-string make-symbol mark marker-buffer max
          match-beginning match-end
         member memq memql min minibuffer-selected-window minibuffer-window
         mod multibyte-char-to-unibyte next-window nth nthcdr number-to-string
-        parse-colon-path plist-get plist-member
+        parse-colon-path
         prefix-numeric-value previous-window prin1-to-string propertize
         degrees-to-radians
         radians-to-degrees rassq rassoc read-from-string regexp-opt
          regexp-quote region-beginning region-end reverse round
         sin sqrt string string< string= string-equal string-lessp
-         string> string-greaterp string-empty-p
-         string-prefix-p string-suffix-p string-blank-p
+         string> string-greaterp string-empty-p string-blank-p
          string-search string-to-char
         string-to-number string-to-syntax substring
         sxhash sxhash-equal sxhash-eq sxhash-eql
         symbol-function symbol-name symbol-plist symbol-value 
string-make-unibyte
         string-make-multibyte string-as-multibyte string-as-unibyte
         string-to-multibyte
-        tan time-convert truncate
+        take tan time-convert truncate
         unibyte-char-to-multibyte upcase user-full-name
         user-login-name user-original-login-name custom-variable-p
         vconcat
@@ -1388,7 +1625,7 @@ See Info node `(elisp) Integer Basics'."
         window-next-buffers window-next-sibling window-new-normal
         window-new-total window-normal-size window-parameter window-parameters
         window-parent window-pixel-edges window-point window-prev-buffers
-        window-prev-sibling window-redisplay-end-trigger window-scroll-bars
+         window-prev-sibling window-scroll-bars
         window-start window-text-height window-top-child window-top-line
         window-total-height window-total-width window-use-time window-vscroll
         window-width zerop))
@@ -1416,7 +1653,7 @@ See Info node `(elisp) Integer Basics'."
         natnump nlistp not null number-or-marker-p numberp
         one-window-p overlayp
         point point-marker point-min point-max preceding-char primary-charset
-        processp
+        processp proper-list-p
         recent-keys recursion-depth
         safe-length selected-frame selected-window sequencep
         standard-case-table standard-syntax-table stringp subrp symbolp
@@ -1461,7 +1698,7 @@ See Info node `(elisp) Integer Basics'."
          floor ceiling round truncate
          ffloor fceiling fround ftruncate
          string= string-equal string< string-lessp string> string-greaterp
-         string-empty-p string-blank-p string-prefix-p string-suffix-p
+         string-empty-p string-blank-p
          string-search
          consp atom listp nlistp proper-list-p
          sequencep arrayp vectorp stringp bool-vector-p hash-table-p
@@ -1476,14 +1713,14 @@ See Info node `(elisp) Integer Basics'."
          ;; arguments.  This is pure enough for the purposes of
          ;; constant folding, but not necessarily for all kinds of
          ;; code motion.
-         car cdr car-safe cdr-safe nth nthcdr last
+         car cdr car-safe cdr-safe nth nthcdr last take
          equal
          length safe-length
          memq memql member
          ;; `assoc' and `assoc-default' are excluded since they are
          ;; impure if the test function is (consider `string-match').
          assq rassq rassoc
-         plist-get lax-plist-get plist-member
+         lax-plist-get
          aref elt
          base64-decode-string base64-encode-string base64url-encode-string
          bool-vector-subsetp
@@ -1664,10 +1901,10 @@ See Info node `(elisp) Integer Basics'."
     byte-goto-if-not-nil-else-pop))
 
 (defconst byte-after-unbind-ops
-   '(byte-constant byte-dup
+   '(byte-constant byte-dup byte-stack-ref byte-stack-set byte-discard
      byte-symbolp byte-consp byte-stringp byte-listp byte-numberp byte-integerp
      byte-eq byte-not
-     byte-cons byte-list1 byte-list2   ; byte-list3 byte-list4
+     byte-cons byte-list1 byte-list2 byte-list3 byte-list4 byte-listN
      byte-interactive-p)
    ;; How about other side-effect-free-ops?  Is it safe to move an
    ;; error invocation (such as from nth) out of an unwind-protect?
@@ -1679,7 +1916,8 @@ See Info node `(elisp) Integer Basics'."
 (defconst byte-compile-side-effect-and-error-free-ops
   '(byte-constant byte-dup byte-symbolp byte-consp byte-stringp byte-listp
     byte-integerp byte-numberp byte-eq byte-equal byte-not byte-car-safe
-    byte-cdr-safe byte-cons byte-list1 byte-list2 byte-point byte-point-max
+    byte-cdr-safe byte-cons byte-list1 byte-list2 byte-list3 byte-list4
+    byte-listN byte-point byte-point-max
     byte-point-min byte-following-char byte-preceding-char
     byte-current-column byte-eolp byte-eobp byte-bolp byte-bobp
     byte-current-buffer byte-stack-ref))
@@ -2030,13 +2268,15 @@ If FOR-EFFECT is non-nil, the return value is assumed 
to be of no importance."
          (setcar (cdr rest) lap0)
          (setq keep-going t))
         ;;
-        ;; varbind-X unbind-N         -->  discard unbind-(N-1)
-        ;; save-excursion unbind-N    -->  unbind-(N-1)
-        ;; save-restriction unbind-N  -->  unbind-(N-1)
+        ;; varbind-X unbind-N            -->  discard unbind-(N-1)
+        ;; save-excursion unbind-N       -->  unbind-(N-1)
+        ;; save-restriction unbind-N     -->  unbind-(N-1)
+        ;; save-current-buffer unbind-N  -->  unbind-(N-1)
         ;;
         ((and (eq 'byte-unbind (car lap1))
               (memq (car lap0) '(byte-varbind byte-save-excursion
-                                 byte-save-restriction))
+                                 byte-save-restriction
+                                  byte-save-current-buffer))
               (< 0 (cdr lap1)))
          (if (zerop (setcdr lap1 (1- (cdr lap1))))
              (delq lap1 rest))
@@ -2060,9 +2300,9 @@ If FOR-EFFECT is non-nil, the return value is assumed to 
be of no importance."
         ((and (memq (car lap0) byte-goto-ops)
               (memq (car (setq tmp (nth 1 (memq (cdr lap0) lap))))
                     '(byte-goto byte-return)))
-         (cond ((and (not (eq tmp lap0))
-                     (or (eq (car lap0) 'byte-goto)
-                         (eq (car tmp) 'byte-goto)))
+         (cond ((and (or (eq (car lap0) 'byte-goto)
+                         (eq (car tmp) 'byte-goto))
+                      (not (eq (cdr tmp) (cdr lap0))))
                 (byte-compile-log-lap "  %s [%s]\t-->\t%s"
                                       (car lap0) tmp tmp)
                 (if (eq (car tmp) 'byte-return)
@@ -2392,8 +2632,7 @@ If FOR-EFFECT is non-nil, the return value is assumed to 
be of no importance."
 ;; itself, compile some of its most used recursive functions (at load time).
 ;;
 (eval-when-compile
- (or (byte-code-function-p (symbol-function 'byte-optimize-form))
-     (subr-native-elisp-p (symbol-function 'byte-optimize-form))
+ (or (compiled-function-p (symbol-function 'byte-optimize-form))
      (assq 'byte-code (symbol-function 'byte-optimize-form))
      (let ((byte-optimize nil)
           (byte-compile-warnings nil))
diff --git a/lisp/emacs-lisp/byte-run.el b/lisp/emacs-lisp/byte-run.el
index 92c2699c6e..9a56ba0f7a 100644
--- a/lisp/emacs-lisp/byte-run.el
+++ b/lisp/emacs-lisp/byte-run.el
@@ -166,7 +166,7 @@ The return value of this function is not used."
 (defalias 'byte-run--set-obsolete
   #'(lambda (f _args new-name when)
       (list 'make-obsolete
-            (list 'quote f) (list 'quote new-name) (list 'quote when))))
+            (list 'quote f) (list 'quote new-name) when)))
 
 (defalias 'byte-run--set-interactive-only
   #'(lambda (f _args instead)
@@ -210,12 +210,16 @@ The return value of this function is not used."
 (defalias 'byte-run--set-doc-string
   #'(lambda (f _args pos)
       (list 'function-put (list 'quote f)
-            ''doc-string-elt (list 'quote pos))))
+            ''doc-string-elt (if (numberp pos)
+                                 pos
+                               (list 'quote pos)))))
 
 (defalias 'byte-run--set-indent
   #'(lambda (f _args val)
       (list 'function-put (list 'quote f)
-            ''lisp-indent-function (list 'quote val))))
+            ''lisp-indent-function (if (numberp val)
+                                       val
+                                     (list 'quote val)))))
 
 (defalias 'byte-run--set-speed
   #'(lambda (f _args val)
@@ -232,6 +236,20 @@ The return value of this function is not used."
       (list 'function-put (list 'quote f)
             ''command-modes (list 'quote val))))
 
+(defalias 'byte-run--set-interactive-args
+  #'(lambda (f args &rest val)
+      (setq args (remove '&optional (remove '&rest args)))
+      (list 'function-put (list 'quote f)
+            ''interactive-args
+            (list
+             'quote
+             (mapcar
+              (lambda (elem)
+                (cons
+                 (seq-position args (car elem))
+                 (cadr elem)))
+              val)))))
+
 ;; Add any new entries to info node `(elisp)Declare Form'.
 (defvar defun-declarations-alist
   (list
@@ -251,7 +269,8 @@ If `error-free', drop calls even if 
`byte-compile-delete-errors' is nil.")
    (list 'indent #'byte-run--set-indent)
    (list 'speed #'byte-run--set-speed)
    (list 'completion #'byte-run--set-completion)
-   (list 'modes #'byte-run--set-modes))
+   (list 'modes #'byte-run--set-modes)
+   (list 'interactive-args #'byte-run--set-interactive-args))
   "List associating function properties to their macro expansion.
 Each element of the list takes the form (PROP FUN) where FUN is
 a function.  For each (PROP . VALUES) in a function's declaration,
@@ -272,6 +291,75 @@ This is used by `declare'.")
       (list 'function-put (list 'quote name)
            ''no-font-lock-keyword (list 'quote val))))
 
+(defalias 'byte-run--parse-body
+  #'(lambda (body allow-interactive)
+      "Decompose BODY into (DOCSTRING DECLARE INTERACTIVE BODY-REST WARNINGS)."
+      (let* ((top body)
+             (docstring nil)
+             (declare-form nil)
+             (interactive-form nil)
+             (warnings nil)
+             (warn #'(lambda (msg form)
+                       (push (macroexp-warn-and-return msg nil nil t form)
+                             warnings))))
+        (while
+            (and body
+                 (let* ((form (car body))
+                        (head (car-safe form)))
+                   (cond
+                    ((or (and (stringp form) (cdr body))
+                         (eq head :documentation))
+                     (cond
+                      (docstring (funcall warn "More than one doc string" top))
+                      (declare-form
+                       (funcall warn "Doc string after `declare'" 
declare-form))
+                      (interactive-form
+                       (funcall warn "Doc string after `interactive'"
+                                interactive-form))
+                      (t (setq docstring form)))
+                     t)
+                    ((eq head 'declare)
+                     (cond
+                      (declare-form
+                       (funcall warn "More than one `declare' form" form))
+                      (interactive-form
+                       (funcall warn "`declare' after `interactive'" form))
+                      (t (setq declare-form form)))
+                     t)
+                    ((eq head 'interactive)
+                     (cond
+                      ((not allow-interactive)
+                       (funcall warn "No `interactive' form allowed here" 
form))
+                      (interactive-form
+                       (funcall warn "More than one `interactive' form" form))
+                      (t (setq interactive-form form)))
+                     t))))
+          (setq body (cdr body)))
+        (list docstring declare-form interactive-form body warnings))))
+
+(defalias 'byte-run--parse-declarations
+  #'(lambda (name arglist clauses construct declarations-alist)
+      (let* ((cl-decls nil)
+             (actions
+              (mapcar
+               #'(lambda (x)
+                   (let ((f (cdr (assq (car x) declarations-alist))))
+                     (cond
+                      (f (apply (car f) name arglist (cdr x)))
+                      ;; Yuck!!
+                      ((and (featurep 'cl)
+                            (memq (car x)  ;C.f. cl--do-proclaim.
+                                  '(special inline notinline optimize warn)))
+                       (push (list 'declare x) cl-decls)
+                       nil)
+                      (t
+                       (macroexp-warn-and-return
+                        (format-message "Unknown %s property `%S'"
+                                        construct (car x))
+                        nil nil nil (car x))))))
+               clauses)))
+        (cons actions cl-decls))))
+
 (defvar macro-declarations-alist
   (cons
    (list 'debug #'byte-run--set-debug)
@@ -289,7 +377,7 @@ This is used by `declare'.")
 (defalias 'defmacro
   (cons
    'macro
-   #'(lambda (name arglist &optional docstring &rest body)
+   #'(lambda (name arglist &rest body)
        "Define NAME as a macro.
 When the macro is called, as in (NAME ARGS...),
 the function (lambda ARGLIST BODY...) is applied to
@@ -300,116 +388,73 @@ DECLS is a list of elements of the form (PROP . VALUES). 
 These are
 interpreted according to `macro-declarations-alist'.
 The return value is undefined.
 
-\(fn NAME ARGLIST &optional DOCSTRING DECL &rest BODY)"
-       ;; We can't just have `decl' as an &optional argument, because we need
-       ;; to distinguish
-       ;;    (defmacro foo (arg) (bar) nil)
-       ;; from
-       ;;    (defmacro foo (arg) (bar)).
-       (let ((decls (cond
-                    ((eq (car-safe docstring) 'declare)
-                     (prog1 (cdr docstring) (setq docstring nil)))
-                    ((and (stringp docstring)
-                          (eq (car-safe (car body)) 'declare))
-                     (prog1 (cdr (car body)) (setq body (cdr body)))))))
-        (if docstring (setq body (cons docstring body))
-          (if (null body) (setq body '(nil))))
-        ;; Can't use backquote because it's not defined yet!
-        (let* ((fun (list 'function (cons 'lambda (cons arglist body))))
-               (def (list 'defalias
-                          (list 'quote name)
-                          (list 'cons ''macro fun)))
-               (declarations
-                (mapcar
-                 #'(lambda (x)
-                     (let ((f (cdr (assq (car x) macro-declarations-alist))))
-                       (if f (apply (car f) name arglist (cdr x))
-                          (macroexp-warn-and-return
-                          (format-message
-                           "Unknown macro property %S in %S"
-                           (car x) name)
-                          nil nil nil (car x)))))
-                 decls)))
-          ;; Refresh font-lock if this is a new macro, or it is an
-          ;; existing macro whose 'no-font-lock-keyword declaration
-          ;; has changed.
-          (if (and
-               ;; If lisp-mode hasn't been loaded, there's no reason
-               ;; to flush.
-               (fboundp 'lisp--el-font-lock-flush-elisp-buffers)
-               (or (not (fboundp name)) ;; new macro
-                   (and (fboundp name)  ;; existing macro
-                        (member `(function-put ',name 'no-font-lock-keyword
-                                               ',(get name 
'no-font-lock-keyword))
-                                declarations))))
-              (lisp--el-font-lock-flush-elisp-buffers))
-          (if declarations
-              (cons 'prog1 (cons def declarations))
+\(fn NAME ARGLIST [DOCSTRING] [DECL] BODY...)"
+       (let* ((parse (byte-run--parse-body body nil))
+              (docstring (nth 0 parse))
+              (declare-form (nth 1 parse))
+              (body (nth 3 parse))
+              (warnings (nth 4 parse))
+              (declarations
+               (and declare-form (byte-run--parse-declarations
+                                  name arglist (cdr declare-form) 'macro
+                                  macro-declarations-alist))))
+         (setq body (nconc warnings body))
+         (setq body (nconc (cdr declarations) body))
+         (if docstring
+             (setq body (cons docstring body)))
+         (if (null body)
+             (setq body '(nil)))
+         (let* ((fun (list 'function (cons 'lambda (cons arglist body))))
+               (def (list 'defalias
+                          (list 'quote name)
+                          (list 'cons ''macro fun))))
+           (if declarations
+              (cons 'prog1 (cons def (car declarations)))
             def))))))
 
 ;; Now that we defined defmacro we can use it!
-(defmacro defun (name arglist &optional docstring &rest body)
+(defmacro defun (name arglist &rest body)
   "Define NAME as a function.
-The definition is (lambda ARGLIST [DOCSTRING] BODY...).
-See also the function `interactive'.
+The definition is (lambda ARGLIST [DOCSTRING] [INTERACTIVE] BODY...).
 DECL is a declaration, optional, of the form (declare DECLS...) where
 DECLS is a list of elements of the form (PROP . VALUES).  These are
 interpreted according to `defun-declarations-alist'.
+INTERACTIVE is an optional `interactive' specification.
 The return value is undefined.
 
-\(fn NAME ARGLIST &optional DOCSTRING DECL &rest BODY)"
-  ;; We can't just have `decl' as an &optional argument, because we need
-  ;; to distinguish
-  ;;    (defun foo (arg) (toto) nil)
-  ;; from
-  ;;    (defun foo (arg) (toto)).
+\(fn NAME ARGLIST [DOCSTRING] [DECL] [INTERACTIVE] BODY...)"
   (declare (doc-string 3) (indent 2))
   (or name (error "Cannot define '%s' as a function" name))
   (if (null
        (and (listp arglist)
             (null (delq t (mapcar #'symbolp arglist)))))
       (error "Malformed arglist: %s" arglist))
-  (let ((decls (cond
-                ((eq (car-safe docstring) 'declare)
-                 (prog1 (cdr docstring) (setq docstring nil)))
-                ((and (stringp docstring)
-                     (eq (car-safe (car body)) 'declare))
-                 (prog1 (cdr (car body)) (setq body (cdr body)))))))
-    (if docstring (setq body (cons docstring body))
-      (if (null body) (setq body '(nil))))
-    (let ((declarations
-           (mapcar
-            #'(lambda (x)
-                (let ((f (cdr (assq (car x) defun-declarations-alist))))
-                  (cond
-                   (f (apply (car f) name arglist (cdr x)))
-                   ;; Yuck!!
-                   ((and (featurep 'cl)
-                         (memq (car x)  ;C.f. cl-do-proclaim.
-                               '(special inline notinline optimize warn)))
-                    (push (list 'declare x)
-                          (if (stringp docstring)
-                              (if (eq (car-safe (cadr body)) 'interactive)
-                                  (cddr body)
-                                (cdr body))
-                            (if (eq (car-safe (car body)) 'interactive)
-                                (cdr body)
-                              body)))
-                    nil)
-                   (t
-                    (macroexp-warn-and-return
-                     (format-message "Unknown defun property `%S' in %S"
-                                     (car x) name)
-                     nil nil nil (car x))))))
-            decls))
-          (def (list 'defalias
+  (let* ((parse (byte-run--parse-body body t))
+         (docstring (nth 0 parse))
+         (declare-form (nth 1 parse))
+         (interactive-form (nth 2 parse))
+         (body (nth 3 parse))
+         (warnings (nth 4 parse))
+         (declarations
+          (and declare-form (byte-run--parse-declarations
+                             name arglist (cdr declare-form) 'defun
+                             defun-declarations-alist))))
+    (setq body (nconc warnings body))
+    (setq body (nconc (cdr declarations) body))
+    (if interactive-form
+        (setq body (cons interactive-form body)))
+    (if docstring
+        (setq body (cons docstring body)))
+    (if (null body)
+        (setq body '(nil)))
+    (let ((def (list 'defalias
                      (list 'quote name)
                      (list 'function
                            (cons 'lambda
                                  (cons arglist body))))))
       (if declarations
-          (cons 'prog1 (cons def declarations))
-          def))))
+          (cons 'prog1 (cons def (car declarations)))
+        def))))
 
 
 ;; Redefined in byte-opt.el.
@@ -523,7 +568,6 @@ ACCESS-TYPE if non-nil should specify the kind of access 
that will trigger
        (purecopy (list current-name access-type when)))
   obsolete-name)
 
-
 (defmacro define-obsolete-variable-alias ( obsolete-name current-name when
                                            &optional docstring)
   "Make OBSOLETE-NAME a variable alias for CURRENT-NAME and mark it obsolete.
@@ -642,7 +686,7 @@ 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' can be used."
+the symbol list.  For `suspicious', only `set-buffer' and `lsh' 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 d28ec0be16..a16486dc31 100644
--- a/lisp/emacs-lisp/bytecomp.el
+++ b/lisp/emacs-lisp/bytecomp.el
@@ -244,11 +244,6 @@ the functions you loaded will not be able to run.")
 (make-obsolete-variable 'byte-compile-dynamic "not worthwhile any more." 
"27.1")
 ;;;###autoload(put 'byte-compile-dynamic 'safe-local-variable 'booleanp)
 
-(defvar byte-compile-disable-print-circle nil
-  "If non-nil, disable `print-circle' on printing a byte-compiled code.")
-(make-obsolete-variable 'byte-compile-disable-print-circle nil "24.1")
-;;;###autoload(put 'byte-compile-disable-print-circle 'safe-local-variable 
'booleanp)
-
 (defcustom byte-compile-dynamic-docstrings t
   "If non-nil, compile doc strings for lazy access.
 We bury the doc strings of functions and variables inside comments in
@@ -299,10 +294,10 @@ The information is logged to `byte-compile-log-buffer'."
   '(redefine callargs free-vars unresolved
              obsolete noruntime interactive-only
              make-local mapcar constants suspicious lexical lexical-dynamic
-             docstrings not-unused)
+             docstrings docstrings-non-ascii-quotes not-unused)
   "The list of warning types used when `byte-compile-warnings' is t.")
 (defcustom byte-compile-warnings t
-  "List of warnings that the byte-compiler should issue (t for all).
+  "List of warnings that the byte-compiler should issue (t for almost all).
 
 Elements of the list may be:
 
@@ -327,15 +322,28 @@ Elements of the list may be:
               `byte-compile-docstring-max-column' or
               `fill-column' characters, whichever is bigger) or
               have other stylistic issues.
+  docstrings-non-ascii-quotes docstrings that have non-ASCII quotes.
+                              This depends on the `docstrings' warning type.
   suspicious  constructs that usually don't do what the coder wanted.
 
 If the list begins with `not', then the remaining elements specify warnings to
-suppress.  For example, (not mapcar) will suppress warnings about mapcar."
+suppress.  For example, (not mapcar) will suppress warnings about mapcar.
+
+The t value means \"all non experimental warning types\", and
+excludes the types in `byte-compile--emacs-build-warning-types'.
+A value of `all' really means all."
   :type `(choice (const :tag "All" t)
                 (set :menu-tag "Some"
                       ,@(mapcar (lambda (x) `(const ,x))
                                 byte-compile-warning-types))))
 
+(defconst byte-compile--emacs-build-warning-types
+  '(docstrings-non-ascii-quotes)
+  "List of warning types that are only enabled during Emacs builds.
+This is typically either warning types that are being phased in
+(but shouldn't be enabled for packages yet), or that are only relevant
+for the Emacs build itself.")
+
 (defvar byte-compile--suppressed-warnings nil
   "Dynamically bound by `with-suppressed-warnings' to suppress warnings.")
 
@@ -354,10 +362,15 @@ suppress.  For example, (not mapcar) will suppress 
warnings about mapcar."
                  (memq symbol (cdr elem)))
         (setq suppress t)))
     (and (not suppress)
-         (or (eq byte-compile-warnings t)
-             (if (eq (car byte-compile-warnings) 'not)
-                 (not (memq warning byte-compile-warnings))
-               (memq warning byte-compile-warnings))))))
+         ;; During an Emacs build, we want all warnings.
+         (or (eq byte-compile-warnings 'all)
+             ;; If t, we want almost all the warnings, but not the
+             ;; ones that are Emacs build specific.
+             (and (not (memq warning byte-compile--emacs-build-warning-types))
+                  (or (eq byte-compile-warnings t)
+                      (if (eq (car byte-compile-warnings) 'not)
+                          (not (memq warning byte-compile-warnings))
+                        (memq warning byte-compile-warnings))))))))
 
 ;;;###autoload
 (defun byte-compile-disable-warning (warning)
@@ -663,10 +676,13 @@ Each element is (INDEX . VALUE)")
     (put 'byte-stack+-info 'tmp-compile-time-value nil)))
 
 
-;; These opcodes are special in that they pack their argument into the
-;; opcode word.
-;;
+;; The following opcodes (1-47) use the 3 lowest bits for an immediate
+;; argument.
+
 (byte-defop   0  1 byte-stack-ref "for stack reference")
+;; Code 0 is actually unused but reserved as invalid code for detecting
+;; corrupted bytecode.  Codes 1-7 are stack-ref.
+
 (byte-defop   8  1 byte-varref "for variable reference")
 (byte-defop  16 -1 byte-varset "for setting a variable")
 (byte-defop  24 -1 byte-varbind        "for binding a variable")
@@ -674,11 +690,9 @@ Each element is (INDEX . VALUE)")
 (byte-defop  40  0 byte-unbind "for unbinding special bindings")
 ;; codes 8-47 are consumed by the preceding opcodes
 
-;; New (in Emacs-24.4) bytecodes for more efficient handling of non-local exits
-;; (especially useful in lexical-binding code).
 (byte-defop  48  0 byte-pophandler)
-(byte-defop  50 -1 byte-pushcatch)
 (byte-defop  49 -1 byte-pushconditioncase)
+(byte-defop  50 -1 byte-pushcatch)
 
 ;; unused: 51-55
 
@@ -701,9 +715,9 @@ Each element is (INDEX . VALUE)")
 (byte-defop  72 -1 byte-aref)
 (byte-defop  73 -2 byte-aset)
 (byte-defop  74  0 byte-symbol-value)
-(byte-defop  75  0 byte-symbol-function) ; this was commented out
+(byte-defop  75  0 byte-symbol-function)
 (byte-defop  76 -1 byte-set)
-(byte-defop  77 -1 byte-fset) ; this was commented out
+(byte-defop  77 -1 byte-fset)
 (byte-defop  78 -1 byte-get)
 (byte-defop  79 -2 byte-substring)
 (byte-defop  80 -1 byte-concat2)
@@ -721,8 +735,9 @@ Each element is (INDEX . VALUE)")
 (byte-defop  92 -1 byte-plus)
 (byte-defop  93 -1 byte-max)
 (byte-defop  94 -1 byte-min)
-(byte-defop  95 -1 byte-mult) ; v19 only
+(byte-defop  95 -1 byte-mult)
 (byte-defop  96  1 byte-point)
+(byte-defop  97  0 byte-save-current-buffer-OBSOLETE) ; unused since v20
 (byte-defop  98  0 byte-goto-char)
 (byte-defop  99  0 byte-insert)
 (byte-defop 100  1 byte-point-max)
@@ -744,7 +759,6 @@ Each element is (INDEX . VALUE)")
 (byte-defop 115  0 byte-set-mark-OBSOLETE)
 (byte-defop 116  1 byte-interactive-p-OBSOLETE)
 
-;; These ops are new to v19
 (byte-defop 117  0 byte-forward-char)
 (byte-defop 118  0 byte-forward-word)
 (byte-defop 119 -1 byte-skip-chars-forward)
@@ -801,7 +815,6 @@ the unwind-action")
 
 ;; unused: 146
 
-;; these ops are new to v19
 (byte-defop 147 -2 byte-set-marker)
 (byte-defop 148  0 byte-match-beginning)
 (byte-defop 149  0 byte-match-end)
@@ -833,6 +846,8 @@ the unwind-action")
 (byte-defop 178 -1 byte-stack-set)     ; Stack offset in following one byte.
 (byte-defop 179 -1 byte-stack-set2)    ; Stack offset in following two bytes.
 
+;; unused: 180-181
+
 ;; If (following one byte & 0x80) == 0
 ;;    discard (following one byte & 0x7F) stack entries
 ;; else
@@ -848,10 +863,11 @@ the unwind-action")
  "to take a hash table and a value from the stack, and jump to
 the address the value maps to, if any.")
 
-;; unused: 182-191
+;; unused: 184-191
 
 (byte-defop 192  1 byte-constant       "for reference to a constant")
-;; codes 193-255 are consumed by byte-constant.
+;; Codes 193-255 are consumed by `byte-constant', which uses the 6
+;; lowest bits for an immediate argument.
 (defconst byte-constant-limit 64
   "Exclusive maximum index usable in the `byte-constant' opcode.")
 
@@ -1104,10 +1120,8 @@ message buffer `default-directory'."
   :type '(repeat (choice (const :tag "Default" nil)
                         (string :tag "Directory"))))
 
-(defvar emacs-lisp-compilation-mode-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "g" 'emacs-lisp-compilation-recompile)
-    map))
+(defvar-keymap emacs-lisp-compilation-mode-map
+  "g" #'emacs-lisp-compilation-recompile)
 
 (defvar emacs-lisp-compilation--current-file nil)
 
@@ -1147,7 +1161,7 @@ message buffer `default-directory'."
 
 ;; Log something that isn't a warning.
 (defun byte-compile-log-1 (string)
-  (with-current-buffer byte-compile-log-buffer
+  (with-current-buffer (get-buffer-create byte-compile-log-buffer)
     (let ((inhibit-read-only t))
       (goto-char (point-max))
       (byte-compile-warning-prefix nil nil)
@@ -1156,18 +1170,6 @@ message buffer `default-directory'."
            (t
             (insert (format "%s\n" string)))))))
 
-;; copied from gnus-util.el
-(defsubst byte-compile-delete-first (elt list)
-  (if (eq (car list) elt)
-      (cdr list)
-    (let ((total list))
-      (while (and (cdr list)
-                 (not (eq (cadr list) elt)))
-       (setq list (cdr list)))
-      (when (cdr list)
-       (setcdr list (cddr list)))
-      total)))
-
 (defvar byte-compile-last-warned-form nil)
 (defvar byte-compile-last-logged-file nil)
 (defvar byte-compile-root-dir nil
@@ -1228,13 +1230,13 @@ Order is by depth-first search."
                                      load-file-name dir)))
                     (t "")))
          (offset (byte-compile--warning-source-offset))
-        (pos (if (and byte-compile-current-file
-                       (or offset (not symbols-with-pos-enabled)))
+        (pos (if (and byte-compile-current-file offset)
                  (with-current-buffer byte-compile-current-buffer
                     (let (new-l new-c)
                       (save-excursion
                         (goto-char offset)
-                        (setq new-l (1+ (count-lines (point-min) 
(point-at-bol)))
+                        (setq new-l (1+ (count-lines (point-min)
+                                                     
(line-beginning-position)))
                               new-c (1+ (current-column)))
                         (format "%d:%d:" new-l new-c))))
                ""))
@@ -1354,16 +1356,23 @@ FORMAT and ARGS are as in `byte-compile-warn'."
   (let ((byte-compile-form-stack (cons arg byte-compile-form-stack)))
     (apply #'byte-compile-warn format args)))
 
-(defun byte-compile-warn-obsolete (symbol)
-  "Warn that SYMBOL (a variable or function) is obsolete."
+;;;###autoload
+(defun byte-compile-warn-obsolete (symbol type)
+  "Warn that SYMBOL (a variable, function or generalized variable) is obsolete.
+TYPE is a string that say which one of these three types it is."
   (when (byte-compile-warning-enabled-p 'obsolete symbol)
-    (let* ((funcp (get symbol 'byte-obsolete-info))
-           (msg (macroexp--obsolete-warning
-                 symbol
-                 (or funcp (get symbol 'byte-obsolete-variable))
-                 (if funcp "function" "variable"))))
-      (unless (and funcp (memq symbol byte-compile-not-obsolete-funcs))
-       (byte-compile-warn-x symbol "%s" msg)))))
+    (byte-compile-warn-x
+     symbol "%s"
+     (macroexp--obsolete-warning
+      symbol
+      (pcase type
+        ("function"
+         (get symbol 'byte-obsolete-info))
+        ("variable"
+         (get symbol 'byte-obsolete-variable))
+        ("generalized variable"
+         (get symbol 'byte-obsolete-generalized-variable)))
+      type))))
 
 (defun byte-compile-report-error (error-info &optional fill)
   "Report Lisp error in compilation.
@@ -1394,7 +1403,7 @@ when printing the error message."
                      (or (symbolp (symbol-function fn))
                          (consp (symbol-function fn))
                          (and (not macro-p)
-                              (byte-code-function-p (symbol-function fn)))))
+                              (compiled-function-p (symbol-function fn)))))
            (setq fn (symbol-function fn)))
           (let ((advertised (gethash (if (and (symbolp fn) (fboundp fn))
                                          ;; Could be a subr.
@@ -1406,7 +1415,7 @@ when printing the error message."
               (if macro-p
                   `(macro lambda ,advertised)
                 `(lambda ,advertised)))
-             ((and (not macro-p) (byte-code-function-p fn)) fn)
+             ((and (not macro-p) (compiled-function-p fn)) fn)
              ((not (consp fn)) nil)
              ((eq 'macro (car fn)) (cdr fn))
              (macro-p nil)
@@ -1467,8 +1476,8 @@ when printing the error message."
 
 (defun byte-compile-function-warn (f nargs def)
   (when (and (get f 'byte-obsolete-info)
-             (byte-compile-warning-enabled-p 'obsolete f))
-    (byte-compile-warn-obsolete f))
+             (not (memq f byte-compile-not-obsolete-funcs)))
+    (byte-compile-warn-obsolete f "function"))
 
   ;; Check to see if the function will be available at runtime
   ;; and/or remember its arity if it's unknown.
@@ -1721,8 +1730,8 @@ The byte-compiler will emit a warning for documentation 
strings
 containing lines wider than this.  If `fill-column' has a larger
 value, it will override this variable."
   :group 'bytecomp
-  :type 'integer
-  :safe #'integerp
+  :type 'natnum
+  :safe #'natnump
   :version "28.1")
 
 (define-obsolete-function-alias 'byte-compile-docstring-length-warn
@@ -1739,7 +1748,8 @@ It is too wide if it has any lines longer than the 
largest of
       (pcase (car form)
         ((or 'autoload 'custom-declare-variable 'defalias
              'defconst 'define-abbrev-table
-             'defvar 'defvaralias)
+             'defvar 'defvaralias
+             'custom-declare-face)
          (setq kind (nth 0 form))
          (setq name (nth 1 form))
          (setq docs (nth 3 form)))
@@ -1758,10 +1768,17 @@ It is too wide if it has any lines longer than the 
largest of
            kind name col))
         ;; There's a "naked" ' character before a symbol/list, so it
         ;; should probably be quoted with \=.
-        (when (string-match-p "\\( \"\\|[ \t]\\|^\\)'[a-z(]" docs)
+        (when (string-match-p "\\( [\"#]\\|[ \t]\\|^\\)'[a-z(]" docs)
           (byte-compile-warn-x
            name "%s%sdocstring has wrong usage of unescaped single quotes (use 
\\= or different quoting)"
-           kind name)))))
+           kind name))
+        ;; There's a "Unicode quote" in the string -- it should probably
+        ;; be an ASCII one instead.
+        (when (byte-compile-warning-enabled-p 'docstrings-non-ascii-quotes)
+          (when (string-match-p "\\( \"\\|[ \t]\\|^\\)[‘’]" docs)
+            (byte-compile-warn-x
+             name "%s%sdocstring has wrong usage of \"fancy\" single quotation 
marks"
+             kind name))))))
   form)
 
 ;; If we have compiled any calls to functions which are not known to be
@@ -2064,10 +2081,12 @@ If compilation is needed, this functions returns the 
result of
 The output file's name is generated by passing FILENAME to the
 function `byte-compile-dest-file' (which see).
 The value is non-nil if there were no errors, nil if errors.
+If the file sets the file variable `no-byte-compile', it is not
+compiled, any existing output file is removed, and the return
+value is `no-byte-compile'.
 
 See also `emacs-lisp-byte-compile-and-load'."
   (declare (advertised-calling-convention (filename) "28.1"))
-;;  (interactive "fByte compile file: \nP")
   (interactive
    (let ((file buffer-file-name)
         (file-dir nil))
@@ -2393,8 +2412,8 @@ Call from the source buffer."
 
 (defun byte-compile-output-file-form (form)
   ;; Write the given form to the output buffer, being careful of docstrings
-  ;; in defvar, defvaralias, defconst, autoload and
-  ;; custom-declare-variable because make-docfile is so amazingly stupid.
+  ;; (for `byte-compile-dynamic-docstrings') in defvar, defvaralias,
+  ;; defconst, autoload, and custom-declare-variable.
   ;; defalias calls are output directly by byte-compile-file-form-defmumble;
   ;; it does not pay to first build the defalias in defmumble and then parse
   ;; it here.
@@ -2408,8 +2427,7 @@ Call from the source buffer."
         (print-level nil)
         (print-quoted t)
         (print-gensym t)
-        (print-circle                   ; Handle circular data structures.
-         (not byte-compile-disable-print-circle)))
+        (print-circle t))               ; Handle circular data structures.
     (if (and (memq (car-safe form) '(defvar defvaralias defconst
                                       autoload custom-declare-variable))
              (stringp (nth 3 form)))
@@ -2441,21 +2459,9 @@ list that represents a doc string reference.
       (let (position
             (print-symbols-bare t))     ; Possibly redundant binding.
         ;; Insert the doc string, and make it a comment with #@LENGTH.
-        (and (>= (nth 1 info) 0)
-             dynamic-docstrings
-             (progn
-               ;; Make the doc string start at beginning of line
-               ;; for make-docfile's sake.
-               (insert "\n")
-               (setq position
-                     (byte-compile-output-as-comment
-                      (nth (nth 1 info) form) nil))
-               ;; If the doc string starts with * (a user variable),
-               ;; negate POSITION.
-               (if (and (stringp (nth (nth 1 info) form))
-                        (> (length (nth (nth 1 info) form)) 0)
-                        (eq (aref (nth (nth 1 info) form) 0) ?*))
-                   (setq position (- position)))))
+        (when (and (>= (nth 1 info) 0) dynamic-docstrings)
+          (setq position (byte-compile-output-as-comment
+                          (nth (nth 1 info) form) nil)))
 
         (let ((print-continuous-numbering t)
               print-number-table
@@ -2467,8 +2473,7 @@ list that represents a doc string reference.
               (print-level nil)
               (print-quoted t)
               (print-gensym t)
-              (print-circle             ; Handle circular data structures.
-               (not byte-compile-disable-print-circle)))
+              (print-circle t))         ; Handle circular data structures.
           (if preface
               (progn
                 ;; FIXME: We don't handle uninterned names correctly.
@@ -2521,13 +2526,12 @@ list that represents a doc string reference.
 (defun byte-compile-keep-pending (form &optional handler)
   (if (memq byte-optimize '(t source))
       (setq form (byte-optimize-one-form form t)))
+  ;; To avoid consing up monstrously large forms at load time, we split
+  ;; the output regularly.
+  (when (nthcdr 300 byte-compile-output)
+    (byte-compile-flush-pending))
   (if handler
       (let ((byte-compile--for-effect t))
-       ;; To avoid consing up monstrously large forms at load time, we split
-       ;; the output regularly.
-       (and (memq (car-safe form) '(fset defalias))
-            (nthcdr 300 byte-compile-output)
-            (byte-compile-flush-pending))
        (funcall handler form)
        (if byte-compile--for-effect
            (byte-compile-discard)))
@@ -2584,8 +2588,8 @@ list that represents a doc string reference.
          (t
           (byte-compile-keep-pending form)))))
 
-;; Functions and variables with doc strings must be output separately,
-;; so make-docfile can recognize them.  Most other things can be output
+;; Functions and variables with doc strings must be output specially,
+;; for `byte-compile-dynamic-docstrings'.  Most other things can be output
 ;; as byte-code.
 
 (put 'autoload 'byte-hunk-handler 'byte-compile-file-form-autoload)
@@ -2682,11 +2686,10 @@ list that represents a doc string reference.
   (byte-compile-keep-pending form))
 
 (put 'custom-declare-variable 'byte-hunk-handler
-     'byte-compile-file-form-custom-declare-variable)
-(defun byte-compile-file-form-custom-declare-variable (form)
-  (when (byte-compile-warning-enabled-p 'callargs)
-    (byte-compile-nogroup-warn form))
-  (byte-compile-file-form-defvar-function form))
+     'byte-compile-file-form-defvar-function)
+
+(put 'custom-declare-face 'byte-hunk-handler
+     'byte-compile-docstring-style-warn)
 
 (put 'require 'byte-hunk-handler 'byte-compile-file-form-require)
 (defun byte-compile-file-form-require (form)
@@ -2951,11 +2954,11 @@ If FORM is a lambda or a macro, byte-compile it as a 
function."
          (setq fun (cdr fun)))
       (prog1
           (cond
-           ;; Up until Emacs-24.1, byte-compile silently did nothing when 
asked to
-           ;; compile something invalid.  So let's tune down the complaint 
from an
-           ;; error to a simple message for the known case where signaling an 
error
-           ;; causes problems.
-           ((byte-code-function-p fun)
+           ;; Up until Emacs-24.1, byte-compile silently did nothing
+           ;; when asked to compile something invalid.  So let's tone
+           ;; down the complaint from an error to a simple message for
+           ;; the known case where signaling an error causes problems.
+           ((compiled-function-p fun)
             (message "Function %s is already compiled"
                      (if (symbolp form) form "provided"))
             fun)
@@ -3532,7 +3535,7 @@ lambda-expression."
     (byte-compile-out-tag endtag)))
 
 (defun byte-compile-unfold-bcf (form)
-  "Inline call to byte-code-functions."
+  "Inline call to byte-code function."
   (let* ((byte-compile-bound-variables byte-compile-bound-variables)
          (fun (car form))
          (fargs (aref fun 0))
@@ -3609,7 +3612,7 @@ lambda-expression."
                   ('set (not (eq access-type 'reference)))
                   ('get (eq access-type 'reference))
                   (_ t))))
-        (byte-compile-warn-obsolete var))))
+        (byte-compile-warn-obsolete var "variable"))))
 
 (defsubst byte-compile-dynamic-variable-op (base-op var)
   (let ((tmp (assq var byte-compile-variables)))
@@ -3753,7 +3756,6 @@ If it is nil, then the handler is 
\"byte-compile-SYMBOL.\""
 (put 'byte-insertN 'byte-opcode-invert 'insert)
 
 (byte-defop-compiler point             0)
-;;(byte-defop-compiler mark            0) ;; obsolete
 (byte-defop-compiler point-max         0)
 (byte-defop-compiler point-min         0)
 (byte-defop-compiler following-char    0)
@@ -3764,8 +3766,6 @@ If it is nil, then the handler is 
\"byte-compile-SYMBOL.\""
 (byte-defop-compiler bolp              0)
 (byte-defop-compiler bobp              0)
 (byte-defop-compiler current-buffer    0)
-;;(byte-defop-compiler read-char       0) ;; obsolete
-;; (byte-defop-compiler interactive-p  0) ;; Obsolete.
 (byte-defop-compiler widen             0)
 (byte-defop-compiler end-of-line    0-1)
 (byte-defop-compiler forward-char   0-1)
@@ -3786,7 +3786,6 @@ If it is nil, then the handler is 
\"byte-compile-SYMBOL.\""
 (byte-defop-compiler goto-char         1)
 (byte-defop-compiler char-after                0-1)
 (byte-defop-compiler set-buffer                1)
-;;(byte-defop-compiler set-mark                1) ;; obsolete
 (byte-defop-compiler forward-word      0-1)
 (byte-defop-compiler char-syntax       1)
 (byte-defop-compiler nreverse          1)
@@ -3839,7 +3838,6 @@ If it is nil, then the handler is 
\"byte-compile-SYMBOL.\""
 (byte-defop-compiler (+ byte-plus)     byte-compile-variadic-numeric)
 (byte-defop-compiler (* byte-mult)     byte-compile-variadic-numeric)
 
-;;####(byte-defop-compiler move-to-column      1)
 (byte-defop-compiler-1 interactive byte-compile-noop)
 
 
@@ -4223,7 +4221,7 @@ This function is never called when `lexical-binding' is 
nil."
 (byte-defop-compiler-1 quote)
 
 (defun byte-compile-setq (form)
-  (cl-assert (= (length form) 3))       ; normalised in macroexp
+  (cl-assert (= (length form) 3))       ; normalized in macroexp
   (let ((var (nth 1 form))
         (expr (nth 2 form)))
     (byte-compile-form expr)
@@ -4794,8 +4792,6 @@ binding slots have been popped."
 (byte-defop-compiler-1 save-excursion)
 (byte-defop-compiler-1 save-current-buffer)
 (byte-defop-compiler-1 save-restriction)
-;; (byte-defop-compiler-1 save-window-excursion)      ;Obsolete: now a macro.
-;; (byte-defop-compiler-1 with-output-to-temp-buffer) ;Obsolete: now a macro.
 
 (defun byte-compile-catch (form)
   (byte-compile-form (car (cdr form)))
@@ -4992,7 +4988,7 @@ binding slots have been popped."
   ;;
   ;; FIXME: we also use this hunk-handler to implement the function's
   ;; dynamic docstring feature (via byte-compile-file-form-defmumble).
-  ;; We should actually implement it (more elegantly) in
+  ;; We should probably actually implement it (more elegantly) in
   ;; byte-compile-lambda so it applies to all lambdas.  We did it here
   ;; so the resulting .elc format was recognizable by make-docfile,
   ;; but since then we stopped using DOC for the docstrings of
@@ -5266,11 +5262,13 @@ invoked interactively."
                ((not (consp f))
                 "<malformed function>")
                ((eq 'macro (car f))
-                (if (or (byte-code-function-p (cdr f))
+                (if (or (compiled-function-p (cdr f))
+                        ;; FIXME: Can this still happen?
                         (assq 'byte-code (cdr (cdr (cdr f)))))
                     " <compiled macro>"
                   " <macro>"))
                ((assq 'byte-code (cdr (cdr f)))
+                ;; FIXME: Can this still happen?
                 "<compiled lambda>")
                ((eq 'lambda (car f))
                 "<function>")
@@ -5519,9 +5517,7 @@ and corresponding effects."
 ;; itself, compile some of its most used recursive functions (at load time).
 ;;
 (eval-when-compile
-  (or (byte-code-function-p (symbol-function 'byte-compile-form))
-      (subr-native-elisp-p (symbol-function 'byte-compile-form))
-      (assq 'byte-code (symbol-function 'byte-compile-form))
+  (or (compiled-function-p (symbol-function 'byte-compile-form))
       (let ((byte-optimize nil)                ; do it fast
            (byte-compile-warnings nil))
        (mapc (lambda (x)
diff --git a/lisp/emacs-lisp/cconv.el b/lisp/emacs-lisp/cconv.el
index eca1123899..7f95fa94fa 100644
--- a/lisp/emacs-lisp/cconv.el
+++ b/lisp/emacs-lisp/cconv.el
@@ -267,8 +267,7 @@ Returns a form where all lambdas don't have any free 
variables."
 
 (define-inline cconv--var-classification (binder form)
   (inline-quote
-   (alist-get (cons ,binder ,form) cconv-var-classification
-              nil nil #'equal)))
+   (cdr (assoc (cons ,binder ,form) cconv-var-classification))))
 
 (defun cconv--convert-funcbody (funargs funcbody env parentform)
   "Run `cconv-convert' on FUNCBODY, the forms of a lambda expression.
diff --git a/lisp/emacs-lisp/chart.el b/lisp/emacs-lisp/chart.el
index 29fbcce773..9ff893b75b 100644
--- a/lisp/emacs-lisp/chart.el
+++ b/lisp/emacs-lisp/chart.el
@@ -63,8 +63,7 @@
 (eval-when-compile (require 'cl-generic))
 
 ;;; Code:
-(define-obsolete-variable-alias 'chart-map 'chart-mode-map "24.1")
-(defvar chart-mode-map (make-sparse-keymap) "Keymap used in chart mode.")
+(defvar-keymap chart-mode-map :doc "Keymap used in chart mode.")
 
 (defvar-local chart-local-object nil
   "Local variable containing the locally displayed chart object.")
@@ -113,7 +112,7 @@ too much in text characters anyways.")
        (set-face-foreground nf "black")
        (if (and chart-face-use-pixmaps pl)
            (condition-case nil
-               (set-face-background-pixmap nf (car pl))
+               (set-face-stipple nf (car pl))
              (error (message "Cannot set background pixmap %s" (car pl)))))
        (push nf faces)
        (setq cl (cdr cl)
@@ -527,9 +526,9 @@ cons cells of the form (NAME . NUM).  See `sort' for more 
details."
 (defun chart-zap-chars (n)
   "Zap up to N chars without deleting EOLs."
   (if (not (eobp))
-      (if (< n (- (point-at-eol) (point)))
+      (if (< n (- (line-end-position) (point)))
          (delete-char n)
-       (delete-region (point) (point-at-eol)))))
+        (delete-region (point) (line-end-position)))))
 
 (defun chart-display-label (label dir zone start end &optional face)
   "Display LABEL in direction DIR in column/row ZONE between START and END.
diff --git a/lisp/emacs-lisp/checkdoc.el b/lisp/emacs-lisp/checkdoc.el
index 5700afbb03..a5ab3a50ff 100644
--- a/lisp/emacs-lisp/checkdoc.el
+++ b/lisp/emacs-lisp/checkdoc.el
@@ -1,6 +1,6 @@
 ;;; checkdoc.el --- check documentation strings for style requirements  -*- 
lexical-binding:t -*-
 
-;; Copyright (C) 1997-1998, 2001-2022 Free Software Foundation, Inc.
+;; Copyright (C) 1997-2022 Free Software Foundation, Inc.
 
 ;; Author: Eric M. Ludlam <zappo@gnu.org>
 ;; Old-Version: 0.6.2
@@ -165,7 +165,7 @@
 (require 'cl-lib)
 (require 'help-mode) ;; for help-xref-info-regexp
 (require 'thingatpt) ;; for handy thing-at-point-looking-at
-(require 'lisp-mode) ;; for lisp-mode-symbol-regexp
+(require 'lisp-mode) ;; for lisp-mode-symbol regexp
 (eval-when-compile (require 'dired))     ;; for dired-map-over-marks
 (require 'lisp-mnt)
 
@@ -248,7 +248,7 @@ with these words enabled."
 ;;;###autoload(put 'checkdoc-spellcheck-documentation-flag 
'safe-local-variable #'booleanp)
 
 (defvar checkdoc-ispell-lisp-words
-  '("alist" "emacs" "etags" "keymap" "paren" "regexp" "sexp" "xemacs")
+  '("alist" "emacs" "etags" "keymap" "paren" "regexp" "sexp")
   "List of words that are correct when spell-checking Lisp documentation.")
 ;;;###autoload(put 'checkdoc-ispell-list-words 'safe-local-variable 
#'checkdoc-list-of-strings-p)
 
@@ -1279,38 +1279,30 @@ TEXT, START, END and UNFIXABLE conform to
 ;;; Minor Mode specification
 ;;
 
-(defvar checkdoc-minor-mode-map
-  (let ((map (make-sparse-keymap))
-       (pmap (make-sparse-keymap)))
-    ;; Override some bindings
-    (define-key map "\C-\M-x" #'checkdoc-eval-defun)
-    (define-key map "\C-x`"   #'checkdoc-continue)
-    (define-key map [menu-bar emacs-lisp eval-buffer]
-      #'checkdoc-eval-current-buffer)
-    ;; Add some new bindings under C-c ?
-    (define-key pmap "x" #'checkdoc-defun)
-    (define-key pmap "X" #'checkdoc-ispell-defun)
-    (define-key pmap "`" #'checkdoc-continue)
-    (define-key pmap "~" #'checkdoc-ispell-continue)
-    (define-key pmap "s" #'checkdoc-start)
-    (define-key pmap "S" #'checkdoc-ispell-start)
-    (define-key pmap "d" #'checkdoc)
-    (define-key pmap "D" #'checkdoc-ispell)
-    (define-key pmap "b" #'checkdoc-current-buffer)
-    (define-key pmap "B" #'checkdoc-ispell-current-buffer)
-    (define-key pmap "e" #'checkdoc-eval-current-buffer)
-    (define-key pmap "m" #'checkdoc-message-text)
-    (define-key pmap "M" #'checkdoc-ispell-message-text)
-    (define-key pmap "c" #'checkdoc-comments)
-    (define-key pmap "C" #'checkdoc-ispell-comments)
-    (define-key pmap " " #'checkdoc-rogue-spaces)
-
-    ;; bind our submap into map
-    (define-key map "\C-c?" pmap)
-    map)
-  "Keymap used to override evaluation key-bindings for documentation 
checking.")
-
-;; Add in a menubar with easy-menu
+(defvar-keymap checkdoc-minor-mode-map
+  :doc "Keymap used to override evaluation key-bindings for documentation 
checking."
+  ;; Override some bindings
+  "C-M-x"     #'checkdoc-eval-defun
+  "C-x `"     #'checkdoc-continue
+  "<menu-bar> <emacs-lisp> <eval-buffer>"  #'checkdoc-eval-current-buffer
+
+  ;; Add some new bindings under C-c ?
+  "C-c ? x"   #'checkdoc-defun
+  "C-c ? X"   #'checkdoc-ispell-defun
+  "C-c ? `"   #'checkdoc-continue
+  "C-c ? ~"   #'checkdoc-ispell-continue
+  "C-c ? s"   #'checkdoc-start
+  "C-c ? S"   #'checkdoc-ispell-start
+  "C-c ? d"   #'checkdoc
+  "C-c ? D"   #'checkdoc-ispell
+  "C-c ? b"   #'checkdoc-current-buffer
+  "C-c ? B"   #'checkdoc-ispell-current-buffer
+  "C-c ? e"   #'checkdoc-eval-current-buffer
+  "C-c ? m"   #'checkdoc-message-text
+  "C-c ? M"   #'checkdoc-ispell-message-text
+  "C-c ? c"   #'checkdoc-comments
+  "C-c ? C"   #'checkdoc-ispell-comments
+  "C-c ? SPC" #'checkdoc-rogue-spaces)
 
 (easy-menu-define nil checkdoc-minor-mode-map
   "Checkdoc Minor Mode Menu."
@@ -1365,23 +1357,6 @@ checking of documentation strings.
                               checkdoc-common-verbs-wrong-voice "\\|")
                    "\\)\\>"))))
 
-;; Profiler says this is not yet faster than just calling assoc
-;;(defun checkdoc-word-in-alist-vector (word vector)
-;;  "Check to see if WORD is in the car of an element of VECTOR.
-;;VECTOR must be sorted.  The CDR should be a replacement.  Since the
-;;word list is getting bigger, it is time for a quick bisecting search."
-;;  (let ((max (length vector)) (min 0) i
-;;     (found nil) (fw nil))
-;;    (setq i (/ max 2))
-;;    (while (and (not found) (/= min max))
-;;      (setq fw (car (aref vector i)))
-;;      (cond ((string= word fw) (setq found (cdr (aref vector i))))
-;;         ((string< word fw) (setq max i))
-;;         (t (setq min i)))
-;;      (setq i (/ (+ max min) 2))
-;;      )
-;;    found))
-
 ;;; Checking engines
 ;;
 (defun checkdoc-this-string-valid (&optional take-notes)
@@ -2007,6 +1982,7 @@ from the comment."
     (let ((defun (looking-at
                   
"(\\(?:cl-\\)?def\\(un\\|macro\\|subst\\|advice\\|generic\\|method\\)"))
          (is-advice (looking-at "(defadvice"))
+          (defun-depth (ppss-depth (syntax-ppss)))
          (lst nil)
          (ret nil)
          (oo (make-vector 3 0)))       ;substitute obarray for `read'
@@ -2022,11 +1998,17 @@ from the comment."
        (setq ret (cons nil ret))
        ;; Interactive
        (save-excursion
-         (setq ret (cons
-                    (re-search-forward "^\\s-*(interactive"
-                                       (save-excursion (end-of-defun) (point))
-                                       t)
-                    ret)))
+          (push (and (re-search-forward "^\\s-*(interactive"
+                                       (save-excursion
+                                          (end-of-defun)
+                                          (point))
+                                       t)
+                     ;; Disregard `interactive' from other parts of
+                     ;; the function.
+                     (= (ppss-depth (syntax-ppss))
+                        (+ defun-depth 2))
+                     (point))
+                ret))
        (skip-chars-forward " \t\n")
        (let ((bss (buffer-substring (point) (save-excursion (forward-sexp 1)
                                                             (point))))
@@ -2250,7 +2232,6 @@ nil."
        (progn
           (ispell-set-spellchecker-params)    ; Initialize variables and dict 
alists.
           (ispell-accept-buffer-local-defs)   ; Use the correct dictionary.
-         ;; This code copied in part from ispell.el Emacs 19.34
          (dolist (w checkdoc-ispell-lisp-words)
            (process-send-string ispell-process (concat "@" w "\n"))))
       (error (setq checkdoc-spellcheck-documentation-flag nil)))))
@@ -2361,8 +2342,6 @@ News agents may remove it"
 
 ;;; Comment checking engine
 ;;
-(defvar generate-autoload-cookie)
-
 (defun checkdoc-file-comments-engine ()
   "Return a message list if this file does not match the Emacs standard.
 This checks for style only, such as the first line, Commentary:,
@@ -2597,13 +2576,13 @@ The correct format is \"Foo\" or \"some-symbol: Foo\".  
See also
     (unless (let ((case-fold-search nil))
               (looking-at (rx (or upper-case "%s"))))
       ;; A defined Lisp symbol is always okay.
-      (unless (and (looking-at (rx (group (regexp lisp-mode-symbol-regexp))))
+      (unless (and (looking-at (rx (group lisp-mode-symbol)))
                    (or (fboundp (intern (match-string 1)))
                        (boundp (intern (match-string 1)))))
         ;; Other Lisp symbols are sometimes okay.
         (rx-let ((c (? "\\\n")))        ; `c' is for a continued line
           (let ((case-fold-search nil)
-                (some-symbol (rx (regexp lisp-mode-symbol-regexp)
+                (some-symbol (rx lisp-mode-symbol
                                  c ":" c (+ (any " \t\n"))))
                 (lowercase-str (rx c (group (any "a-z") (+ wordchar)))))
             (if (looking-at some-symbol)
@@ -2628,7 +2607,7 @@ a space as a style error."
          (checkdoc-autofix-ask-replace
           (match-beginning 0) (match-end 0)
           (format-message
-           "`y-or-n-p' argument should end with \"? \".  Fix?")
+           "`y-or-n-p' argument should end with \"?\".  Fix?")
           "?\"" t))
         nil
       (checkdoc-create-error
@@ -2863,8 +2842,6 @@ function called to create the messages."
 
 (custom-add-option 'emacs-lisp-mode-hook 'checkdoc-minor-mode)
 
-;; Obsolete
-
 (define-obsolete-function-alias 'checkdoc-run-hooks
   #'run-hook-with-args-until-success "28.1")
 (defvar checkdoc-version "0.6.2"
diff --git a/lisp/emacs-lisp/cl-extra.el b/lisp/emacs-lisp/cl-extra.el
index 8e38df43c8..607810ee14 100644
--- a/lisp/emacs-lisp/cl-extra.el
+++ b/lisp/emacs-lisp/cl-extra.el
@@ -71,8 +71,7 @@ numbers of different types (float vs. integer), and also 
compares
 strings case-insensitively."
   (cond ((eq x y) t)
        ((stringp x)
-        (and (stringp y) (= (length x) (length y))
-              (eq (compare-strings x nil nil y nil nil t) t)))
+        (and (stringp y) (string-equal-ignore-case x y)))
        ((numberp x)
         (and (numberp y) (= x y)))
        ((consp x)
diff --git a/lisp/emacs-lisp/cl-generic.el b/lisp/emacs-lisp/cl-generic.el
index 200af057cd..0560ddda26 100644
--- a/lisp/emacs-lisp/cl-generic.el
+++ b/lisp/emacs-lisp/cl-generic.el
@@ -659,13 +659,35 @@ The set of acceptable TYPEs (also called 
\"specializers\") is defined
   ;; which it depends needs to be usable before cl-generic is loaded,
   ;; which imposes a significant burden on the bootstrap.
   (if (consp (lambda (x) (+ x 1)))
-      (lambda (exp) (eval exp t)) #'byte-compile))
+      (lambda (exp) (eval exp t))
+    ;; But do byte-compile the dispatchers once bootstrap is passed:
+    ;; the performance difference is substantial (like a 5x speedup on
+    ;; the `eieio' elisp-benchmark)).
+    ;; To avoid loading the byte-compiler during the final preload,
+    ;; see `cl--generic-prefill-dispatchers'.
+    #'byte-compile))
 
 (defun cl--generic-get-dispatcher (dispatch)
   (with-memoization
       ;; We need `copy-sequence` here because this `dispatch' object might be
       ;; modified by side-effect in `cl-generic-define-method' (bug#46722).
       (gethash (copy-sequence dispatch) cl--generic-dispatchers)
+
+    (when (and purify-flag ;FIXME: Is this a reliable test of the final dump?
+               (eq cl--generic-compiler #'byte-compile))
+      ;; We don't want to preload the byte-compiler!!
+      (error
+       "Missing cl-generic dispatcher in the prefilled cache!
+Missing for: %S
+You might need to add: %S"
+       (mapcar (lambda (x) (if (cl--generic-generalizer-p x)
+                          (cl--generic-generalizer-name x)
+                        x))
+               dispatch)
+       `(cl--generic-prefill-dispatchers
+         ,@(delq nil (mapcar #'cl--generic-prefill-generalizer-sample
+                             dispatch)))))
+
     ;; (message "cl--generic-get-dispatcher (%S)" dispatch)
     (let* ((dispatch-arg (car dispatch))
            (generalizers (cdr dispatch))
@@ -708,9 +730,6 @@ The set of acceptable TYPEs (also called \"specializers\") 
is defined
       (funcall
        cl--generic-compiler
        `(lambda (generic dispatches-left methods)
-          ;; FIXME: We should find a way to expand `with-memoize' once
-          ;; and forall so we don't need `subr-x' when we get here.
-          (eval-when-compile (require 'subr-x))
           (let ((method-cache (make-hash-table :test #'eql)))
             (lambda (,@fixedargs &rest args)
               (let ,bindings
@@ -933,6 +952,20 @@ those methods.")
   (if (eq specializer t) (list cl--generic-t-generalizer)
     (error "Unknown specializer %S" specializer)))
 
+(defun cl--generic-prefill-generalizer-sample (x)
+  "Return an example specializer."
+  (if (not (cl--generic-generalizer-p x))
+      x
+    (pcase (cl--generic-generalizer-name x)
+      ('cl--generic-t-generalizer nil)
+      ('cl--generic-head-generalizer '(head 'x))
+      ('cl--generic-eql-generalizer '(eql 'x))
+      ('cl--generic-struct-generalizer 'cl--generic)
+      ('cl--generic-typeof-generalizer 'integer)
+      ('cl--generic-derived-generalizer '(derived-mode c-mode))
+      ('cl--generic-oclosure-generalizer 'oclosure)
+      (_ x))))
+
 (eval-when-compile
   ;; This macro is brittle and only really important in order to be
   ;; able to preload cl-generic without also preloading the byte-compiler,
@@ -1330,6 +1363,7 @@ See the full list and their hierarchy in 
`cl--typeof-types'."
    (cl-call-next-method)))
 
 (cl--generic-prefill-dispatchers 0 integer)
+(cl--generic-prefill-dispatchers 1 integer)
 (cl--generic-prefill-dispatchers 0 cl--generic-generalizer integer)
 
 ;;; Dispatch on major mode.
@@ -1378,7 +1412,7 @@ Used internally for the (major-mode MODE) context 
specializers."
          (when (cl-typep class 'oclosure--class)
            (oclosure--class-allparents class)))))
 
-(cl-generic-define-generalizer cl-generic--oclosure-generalizer
+(cl-generic-define-generalizer cl--generic-oclosure-generalizer
   ;; Give slightly higher priority than the struct specializer, so that
   ;; for a generic function with methods dispatching structs and on OClosures,
   ;; we first try `oclosure-type' before `type-of' since `type-of' will return
@@ -1395,7 +1429,7 @@ Used internally for the (major-mode MODE) context 
specializers."
      ;; take place without requiring cl-lib.
      (let ((class (cl--find-class type)))
        (and (cl-typep class 'oclosure--class)
-            (list cl-generic--oclosure-generalizer))))
+            (list cl--generic-oclosure-generalizer))))
    (cl-call-next-method)))
 
 (cl--generic-prefill-dispatchers 0 oclosure)
diff --git a/lisp/emacs-lisp/cl-indent.el b/lisp/emacs-lisp/cl-indent.el
index 213eecf88d..fe7e4506d7 100644
--- a/lisp/emacs-lisp/cl-indent.el
+++ b/lisp/emacs-lisp/cl-indent.el
@@ -378,10 +378,9 @@ instead."
                                          function)
                            (setq tentative-defun t))
                           ((string-match
-                             (eval-when-compile
-                              (concat "\\`\\("
-                                      (regexp-opt '("with" "without" "do"))
-                                      "\\)-"))
+                             (concat "\\`\\("
+                                     (regexp-opt '("with" "without" "do"))
+                                     "\\)-")
                              function)
                            (setq method '(&lambda &body))))))
                   ;; backwards compatibility.  Bletch.
diff --git a/lisp/emacs-lisp/cl-lib.el b/lisp/emacs-lisp/cl-lib.el
index 3f40ab0760..a54fa21fa9 100644
--- a/lisp/emacs-lisp/cl-lib.el
+++ b/lisp/emacs-lisp/cl-lib.el
@@ -372,8 +372,8 @@ SEQ, this is like `mapcar'.  With several, it is like the 
Common Lisp
 (cl--defalias 'cl-second 'cadr)
 (cl--defalias 'cl-rest 'cdr)
 
-(cl--defalias 'cl-third 'cl-caddr "Return the third element of the list X.")
-(cl--defalias 'cl-fourth 'cl-cadddr "Return the fourth element of the list X.")
+(cl--defalias 'cl-third #'caddr "Return the third element of the list X.")
+(cl--defalias 'cl-fourth #'cadddr "Return the fourth element of the list X.")
 
 (defsubst cl-fifth (x)
   "Return the fifth element of the list X."
diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el
index 10043ba280..80ca43c902 100644
--- a/lisp/emacs-lisp/cl-macs.el
+++ b/lisp/emacs-lisp/cl-macs.el
@@ -527,7 +527,7 @@ its argument list allows full Common Lisp conventions."
   (while (and (eq (car args) '&aux) (pop args))
     (while (and args (not (memq (car args) cl--lambda-list-keywords)))
       (if (consp (car args))
-          (if (and cl--bind-enquote (cl-cadar args))
+          (if (and cl--bind-enquote (cadar args))
               (cl--do-arglist (caar args)
                               `',(cadr (pop args)))
             (cl--do-arglist (caar args) (cadr (pop args))))
@@ -612,7 +612,7 @@ its argument list allows full Common Lisp conventions."
                              (if (eq ?_ (aref name 0))
                                  (setq name (substring name 1)))
                              (intern (format ":%s" name)))))
-                  (varg (if (consp (car arg)) (cl-cadar arg) (car arg)))
+                   (varg (if (consp (car arg)) (cadar arg) (car arg)))
                   (def (if (cdr arg) (cadr arg)
                           ;; The ordering between those two or clauses is
                           ;; irrelevant, since in practice only one of the two
@@ -1339,7 +1339,7 @@ For more details, see Info node `(cl)Loop Facility'.
                      (temp-idx
                        (if (eq (car cl--loop-args) 'using)
                            (if (and (= (length (cadr cl--loop-args)) 2)
-                                    (eq (cl-caadr cl--loop-args) 'index))
+                                    (eq (caadr cl--loop-args) 'index))
                                (cadr (cl--pop2 cl--loop-args))
                              (error "Bad `using' clause"))
                          (make-symbol "--cl-idx--"))))
@@ -1370,8 +1370,8 @@ For more details, see Info node `(cl)Loop Facility'.
                       (other
                         (if (eq (car cl--loop-args) 'using)
                             (if (and (= (length (cadr cl--loop-args)) 2)
-                                     (memq (cl-caadr cl--loop-args) hash-types)
-                                     (not (eq (cl-caadr cl--loop-args) word)))
+                                     (memq (caadr cl--loop-args) hash-types)
+                                     (not (eq (caadr cl--loop-args) word)))
                                 (cadr (cl--pop2 cl--loop-args))
                               (error "Bad `using' clause"))
                           (make-symbol "--cl-var--"))))
@@ -1433,8 +1433,8 @@ For more details, see Info node `(cl)Loop Facility'.
                      (other
                        (if (eq (car cl--loop-args) 'using)
                            (if (and (= (length (cadr cl--loop-args)) 2)
-                                    (memq (cl-caadr cl--loop-args) key-types)
-                                    (not (eq (cl-caadr cl--loop-args) word)))
+                                    (memq (caadr cl--loop-args) key-types)
+                                    (not (eq (caadr cl--loop-args) word)))
                                (cadr (cl--pop2 cl--loop-args))
                              (error "Bad `using' clause"))
                          (make-symbol "--cl-var--"))))
@@ -1656,7 +1656,7 @@ If BODY is `setq', then use SPECS for assignments rather 
than for bindings."
   (let ((temps nil) (new nil))
     (when par
       (let ((p specs))
-        (while (and p (or (symbolp (car-safe (car p))) (null (cl-cadar p))))
+        (while (and p (or (symbolp (car-safe (car p))) (null (cadar p))))
           (setq p (cdr p)))
         (when p
           (setq par nil)
@@ -1731,7 +1731,7 @@ such that COMBO is equivalent to (and . CLAUSES)."
              (setq clauses (cons (nconc (butlast (car clauses))
                                         (if (eq (car-safe (cadr clauses))
                                                 'progn)
-                                            (cl-cdadr clauses)
+                                             (cdadr clauses)
                                           (list (cadr clauses))))
                                  (cddr clauses)))
             ;; A final (progn ,@A t) is moved outside of the `and'.
@@ -2559,12 +2559,13 @@ values.  For compatibility, (cl-values A B C) is a 
synonym for (list A B C).
       (push x macro-declarations-alist)
       (push x defun-declarations-alist)))
 
+;;;###cl-autoload
 (defun cl--optimize (f _args &rest qualities)
   "Serve `cl-optimize' in function declarations.
 Example:
-(defun foo (x)
-  (declare (cl-optimize (speed 3) (safety 0)))
-  x)"
+  (defun foo (x)
+    (declare (cl-optimize (speed 3) (safety 0)))
+    x)"
   ;; FIXME this should make use of `cl--declare-stack' but I suspect
   ;; this mechanism should be reviewed first.
   (cl-loop for (qly val) in qualities
@@ -2612,7 +2613,7 @@ Example:
        ((and (eq (car-safe spec) 'warn) (boundp 'byte-compile-warnings))
         (while (setq spec (cdr spec))
           (if (consp (car spec))
-              (if (eq (cl-cadar spec) 0)
+               (if (eq (cadar spec) 0)
                    (byte-compile-disable-warning (caar spec))
                  (byte-compile-enable-warning (caar spec)))))))
   nil)
@@ -3092,9 +3093,9 @@ To see the documentation for a defined struct type, use
                             (t `(and (consp cl-x)
                                     (memq (nth ,pos cl-x) ,tag-symbol))))))
          pred-check (and pred-form (> safety 0)
-                         (if (and (eq (cl-caadr pred-form) 'vectorp)
+                          (if (and (eq (caadr pred-form) 'vectorp)
                                   (= safety 1))
-                             (cons 'and (cl-cdddr pred-form))
+                              (cons 'and (cdddr pred-form))
                             `(,predicate cl-x))))
     (when pred-form
       (push `(,defsym ,predicate (cl-x)
@@ -3335,10 +3336,12 @@ the form NAME which is a shorthand for (NAME NAME)."
               :around #'cl--pcase-mutually-exclusive-p))
 
 
+;;;###cl-autoload
 (defun cl-struct-sequence-type (struct-type)
   "Return the sequence used to build STRUCT-TYPE.
-STRUCT-TYPE is a symbol naming a struct type.  Return `record',
-`vector', or `list' if STRUCT-TYPE is a struct type, nil otherwise."
+STRUCT-TYPE is a symbol naming a struct type.  Return values are
+either `vector', `list' or nil (and the latter indicates a
+`record' struct type."
   (declare (side-effect-free t) (pure t))
   (cl--struct-class-type (cl--struct-get-class struct-type)))
 
@@ -3373,6 +3376,7 @@ slots skipped by :initial-offset may appear in the list."
 
 (define-error 'cl-struct-unknown-slot "struct has no slot")
 
+;;;###cl-autoload
 (defun cl-struct-slot-offset (struct-type slot-name)
   "Return the offset of slot SLOT-NAME in STRUCT-TYPE.
 The returned zero-based slot index is relative to the start of
@@ -3407,7 +3411,7 @@ Of course, we really can't know that for sure, so it's 
just a heuristic."
                  (character    . natnump)
                  (char-table   . char-table-p)
                  (command      . commandp)
-                 (compiled-function . byte-code-function-p)
+                 (compiled-function . compiled-function-p)
                  (hash-table   . hash-table-p)
                  (cons         . consp)
                  (fixnum       . fixnump)
diff --git a/lisp/emacs-lisp/cl-preloaded.el b/lisp/emacs-lisp/cl-preloaded.el
index 627bfc8516..dbe20f9202 100644
--- a/lisp/emacs-lisp/cl-preloaded.el
+++ b/lisp/emacs-lisp/cl-preloaded.el
@@ -149,7 +149,7 @@ supertypes from the most specific to least specific.")
   (while (recordp parent)
     (add-to-list (cl--struct-class-children-sym parent) tag)
     ;; Only register ourselves as a child of the leftmost parent since structs
-    ;; can only only have one parent.
+    ;; can only have one parent.
     (setq parent (car (cl--struct-class-parents parent)))))
 
 ;;;###autoload
diff --git a/lisp/emacs-lisp/cl-seq.el b/lisp/emacs-lisp/cl-seq.el
index 64ae05bf2a..60e204eaf5 100644
--- a/lisp/emacs-lisp/cl-seq.el
+++ b/lisp/emacs-lisp/cl-seq.el
@@ -139,6 +139,10 @@ only case where FUNCTION is called with fewer than two 
arguments.
 If SEQ contains exactly one element and no :INITIAL-VALUE is
 specified, then return that element and FUNCTION is not called.
 
+If :FROM-END is non-nil, the reduction occurs from the back of
+the SEQ moving forward, and the order of arguments to the
+FUNCTION is also reversed.
+
 \n(fn FUNCTION SEQ [KEYWORD VALUE]...)"
   (cl--parsing-keywords (:from-end (:start 0) :end :initial-value :key) ()
     (or (listp cl-seq) (setq cl-seq (append cl-seq nil)))
diff --git a/lisp/emacs-lisp/comp-cstr.el b/lisp/emacs-lisp/comp-cstr.el
index 6451e34c42..8cff06a383 100644
--- a/lisp/emacs-lisp/comp-cstr.el
+++ b/lisp/emacs-lisp/comp-cstr.el
@@ -37,16 +37,12 @@
 
 (require 'cl-lib)
 
-(defconst comp--typeof-types (mapcar (lambda (x)
-                                       (append x '(t)))
-                                     cl--typeof-types)
+(defconst comp--typeof-builtin-types (mapcar (lambda (x)
+                                               (append x '(t)))
+                                             cl--typeof-types)
   ;; TODO can we just add t in `cl--typeof-types'?
   "Like `cl--typeof-types' but with t as common supertype.")
 
-(defconst comp--all-builtin-types
-  (append cl--all-builtin-types '(t))
-  "Likewise like `cl--all-builtin-types' but with t as common supertype.")
-
 (cl-defstruct (comp-cstr (:constructor comp-type-to-cstr
                                        (type &aux
                                             (null (eq type 'null))
@@ -234,7 +230,7 @@ Return them as multiple value."
   (cl-loop
    named outer
    with found = nil
-   for l in comp--typeof-types
+   for l in comp--typeof-builtin-types
    do (cl-loop
        for x in l
        for i from (length l) downto 0
@@ -277,7 +273,7 @@ Return them as multiple value."
                (cl-loop
                 with types = (apply #'append typesets)
                 with res = '()
-                for lane in comp--typeof-types
+                for lane in comp--typeof-builtin-types
                 do (cl-loop
                     with last = nil
                     for x in lane
diff --git a/lisp/emacs-lisp/comp.el b/lisp/emacs-lisp/comp.el
index 53803b3818..e10443588e 100644
--- a/lisp/emacs-lisp/comp.el
+++ b/lisp/emacs-lisp/comp.el
@@ -45,7 +45,9 @@
 
 (defcustom native-comp-speed 2
   "Optimization level for native compilation, a number between -1 and 3.
- -1 functions are kept in bytecode form and no native compilation is performed.
+ -1 functions are kept in bytecode form and no native compilation is performed
+    (but *.eln files are still produced, and include the compiled code in
+    bytecode form).
   0 native compilation is performed with no optimizations.
   1 light optimizations.
   2 max optimization level fully adherent to the language semantic.
@@ -63,7 +65,7 @@ This is intended for debugging the compiler itself.
   2 emit debug symbols and dump pseudo C code.
   3 emit debug symbols and dump: pseudo C code, GCC intermediate
   passes and libgccjit log file."
-  :type 'integer
+  :type 'natnum
   :safe #'natnump
   :version "28.1")
 
@@ -74,7 +76,7 @@ This is intended for debugging the compiler itself.
   1 final LIMPLE is logged.
   2 LAP, final LIMPLE, and some pass info are logged.
   3 max verbosity."
-  :type 'integer
+  :type 'natnum
   :risky t
   :version "28.1")
 
@@ -111,7 +113,7 @@ during bootstrap."
   "Default number of subprocesses used for async native compilation.
 Value of zero means to use half the number of the CPU's execution units,
 or one if there's just one execution unit."
-  :type 'integer
+  :type 'natnum
   :risky t
   :version "28.1")
 
@@ -302,7 +304,7 @@ Useful to hook into pass checkers.")
     (bool-vector-subsetp (function (bool-vector bool-vector) boolean))
     (boundp (function (symbol) boolean))
     (buffer-end (function ((or number marker)) integer))
-    (buffer-file-name (function (&optional buffer) string))
+    (buffer-file-name (function (&optional buffer) (or string null)))
     (buffer-list (function (&optional frame) list))
     (buffer-local-variables (function (&optional buffer) list))
     (buffer-modified-p (function (&optional buffer) boolean))
@@ -319,8 +321,8 @@ Useful to hook into pass checkers.")
     (cdr (function (list) t))
     (cdr-safe (function (t) t))
     (ceiling (function (number &optional number) integer))
-    (char-after (function (&optional (or marker integer)) fixnum))
-    (char-before (function (&optional (or marker integer)) fixnum))
+    (char-after (function (&optional (or marker integer)) (or fixnum null)))
+    (char-before (function (&optional (or marker integer)) (or fixnum null)))
     (char-equal (function (integer integer) boolean))
     (char-or-string-p (function (t) boolean))
     (char-to-string (function (fixnum) string))
@@ -342,14 +344,21 @@ Useful to hook into pass checkers.")
     (current-buffer (function () buffer))
     (current-global-map (function () cons))
     (current-indentation (function () integer))
-    (current-local-map (function () cons))
-    (current-minor-mode-maps (function () cons))
+    (current-local-map (function () (or cons null)))
+    (current-minor-mode-maps (function () (or cons null)))
     (current-time (function () cons))
-    (current-time-string (function (&optional string boolean) string))
-    (current-time-zone (function (&optional string boolean) cons))
+    (current-time-string (function (&optional (or number list)
+                                              (or symbol string cons integer))
+                                   string))
+    (current-time-zone (function (&optional (or number list)
+                                            (or symbol string cons integer))
+                                 cons))
     (custom-variable-p (function (symbol) boolean))
     (decode-char (function (cons t) (or fixnum null)))
-    (decode-time (function (&optional string symbol symbol) cons))
+    (decode-time (function (&optional (or number list)
+                                      (or symbol string cons integer)
+                                      symbol)
+                           cons))
     (default-boundp (function (symbol) boolean))
     (default-value (function (symbol) t))
     (degrees-to-radians (function (number) float))
@@ -381,12 +390,14 @@ Useful to hook into pass checkers.")
     (file-writable-p (function (string) boolean))
     (fixnump (function (t) boolean))
     (float (function (number) float))
-    (float-time (function (&optional cons) float))
+    (float-time (function (&optional (or number list)) float))
     (floatp (function (t) boolean))
     (floor (function (number &optional number) integer))
     (following-char (function () fixnum))
     (format (function (string &rest t) string))
-    (format-time-string (function (string &optional cons symbol) string))
+    (format-time-string (function (string &optional (or number list)
+                                          (or symbol string cons integer))
+                                  string))
     (frame-first-window (function ((or frame window)) window))
     (frame-root-window (function (&optional (or frame window)) window))
     (frame-selected-window (function (&optional (or frame window)) window))
@@ -398,8 +409,8 @@ Useful to hook into pass checkers.")
     (get-buffer (function ((or buffer string)) (or buffer null)))
     (get-buffer-window (function (&optional (or buffer string) (or symbol 
(integer 0 0))) (or null window)))
     (get-file-buffer (function (string) (or null buffer)))
-    (get-largest-window (function (&optional t t t) window))
-    (get-lru-window (function (&optional t t t) window))
+    (get-largest-window (function (&optional t t t) (or window null)))
+    (get-lru-window (function (&optional t t t) (or window null)))
     (getenv (function (string &optional frame) (or null string)))
     (gethash (function (t hash-table &optional t) t))
     (hash-table-count (function (hash-table) integer))
@@ -448,7 +459,7 @@ Useful to hook into pass checkers.")
     (make-symbol (function (string) symbol))
     (mark (function (&optional t) (or integer null)))
     (mark-marker (function () marker))
-    (marker-buffer (function (marker) buffer))
+    (marker-buffer (function (marker) (or buffer null)))
     (markerp (function (t) boolean))
     (max (function ((or number marker) &rest (or number marker)) number))
     (max-char (function () fixnum))
@@ -457,7 +468,7 @@ Useful to hook into pass checkers.")
     (memq (function (t list) list))
     (memql (function (t list) list))
     (min (function ((or number marker) &rest (or number marker)) number))
-    (minibuffer-selected-window (function () window))
+    (minibuffer-selected-window (function () (or window null)))
     (minibuffer-window (function (&optional frame) window))
     (mod (function ((or number marker) (or number marker)) (or (integer 0 *) 
(float 0 *))))
     (mouse-movement-p (function (t) boolean))
@@ -475,8 +486,8 @@ Useful to hook into pass checkers.")
     (one-window-p (function (&optional t t) boolean))
     (overlayp (function (t) boolean))
     (parse-colon-path (function (string) cons))
-    (plist-get (function (list t) t))
-    (plist-member (function (list t) list))
+    (plist-get (function (list t &optional t) t))
+    (plist-member (function (list t &optional t) list))
     (point (function () integer))
     (point-marker (function () marker))
     (point-max (function () integer))
@@ -485,7 +496,7 @@ Useful to hook into pass checkers.")
     (previous-window (function (&optional window t t) window))
     (prin1-to-string (function (t &optional t t) string))
     (processp (function (t) boolean))
-    (proper-list-p (function (t) integer))
+    (proper-list-p (function (t) boolean))
     (propertize (function (string &rest t) string))
     (radians-to-degrees (function (number) float))
     (rassoc (function (t list) list))
@@ -518,7 +529,7 @@ Useful to hook into pass checkers.")
     (string-to-char (function (string) fixnum))
     (string-to-multibyte (function (string) string))
     (string-to-number (function (string &optional integer) number))
-    (string-to-syntax (function (string) cons))
+    (string-to-syntax (function (string) (or cons null)))
     (string< (function ((or string symbol) (or string symbol)) boolean))
     (string= (function ((or string symbol) (or string symbol)) boolean))
     (stringp (function (t) boolean))
@@ -540,7 +551,8 @@ Useful to hook into pass checkers.")
     (this-command-keys-vector (function () vector))
     (this-single-command-keys (function () vector))
     (this-single-command-raw-keys (function () vector))
-    (time-convert (function (t &optional (or boolean integer)) cons))
+    (time-convert (function ((or number list) &optional (or symbol integer))
+                            (or cons number)))
     (truncate (function (number &optional number) integer))
     (type-of (function (t) symbol))
     (unibyte-char-to-multibyte (function (fixnum) fixnum)) ;; byte is fixnum
@@ -3693,7 +3705,7 @@ Prepare every function for final compilation and drive 
the C back-end."
                                 (file-name-base output) "-")
                         nil ".el")))
        (with-temp-file temp-file
-          (insert ";; -*-coding: nil; -*-\n")
+          (insert ";; -*-coding: utf-8-emacs-unix; -*-\n")
           (mapc (lambda (e)
                   (insert (prin1-to-string e)))
                 expr))
@@ -4288,6 +4300,32 @@ of (commands) to run simultaneously."
   (let ((load (not (not load))))
     (native--compile-async files recursively load selector)))
 
+(defun native-compile-prune-cache ()
+  "Remove .eln files that aren't applicable to the current Emacs invocation."
+  (interactive)
+  (unless (featurep 'native-compile)
+    (user-error "This Emacs isn't built with native-compile support"))
+  (dolist (dir native-comp-eln-load-path)
+    ;; If a directory is non absolute it is assumed to be relative to
+    ;; `invocation-directory'.
+    (setq dir (expand-file-name dir invocation-directory))
+    (when (file-exists-p dir)
+      (dolist (subdir (directory-files dir t))
+        (when (and (file-directory-p subdir)
+                   (file-writable-p subdir)
+                   (not (equal (file-name-nondirectory
+                                (directory-file-name subdir))
+                               comp-native-version-dir)))
+          (message "Deleting %s..." subdir)
+          ;; We're being overly cautious here -- there shouldn't be
+          ;; anything but .eln files in these directories.
+          (dolist (eln (directory-files subdir t "\\.eln\\(\\.tmp\\)?\\'"))
+            (when (file-writable-p eln)
+              (delete-file eln)))
+          (when (directory-empty-p subdir)
+            (delete-directory subdir))))))
+  (message "Cache cleared"))
+
 (provide 'comp)
 
 ;; LocalWords: limplified limplified limplification limplify Limple LIMPLE 
libgccjit elc eln
diff --git a/lisp/emacs-lisp/crm.el b/lisp/emacs-lisp/crm.el
index 8a5c3d3730..6d4b29b552 100644
--- a/lisp/emacs-lisp/crm.el
+++ b/lisp/emacs-lisp/crm.el
@@ -77,38 +77,29 @@
 
 ;;; Code:
 
-;; FIXME I don't see that this needs to exist as a separate variable.
-;; crm-separator should suffice.
-(defconst crm-default-separator "[ \t]*,[ \t]*"
-  "Default value of `crm-separator'.")
+(define-obsolete-variable-alias 'crm-default-separator 'crm-separator "29.1")
 
-(defvar crm-separator crm-default-separator
+(defvar crm-separator "[ \t]*,[ \t]*"
   "Separator regexp used for separating strings in `completing-read-multiple'.
-It should be a regexp that does not match the list of completion candidates.
-The default value is `crm-default-separator'.")
-
-(defvar crm-local-completion-map
-  (let ((map (make-sparse-keymap)))
-    (set-keymap-parent map minibuffer-local-completion-map)
-    (define-key map [remap minibuffer-complete] #'crm-complete)
-    (define-key map [remap minibuffer-complete-word] #'crm-complete-word)
-    (define-key map [remap minibuffer-completion-help] #'crm-completion-help)
-    map)
-  "Local keymap for minibuffer multiple input with completion.
-Analog of `minibuffer-local-completion-map'.")
-
-(defvar crm-local-must-match-map
-  (let ((map (make-sparse-keymap)))
-    ;; We'd want to have multiple inheritance here.
-    (set-keymap-parent map minibuffer-local-must-match-map)
-    (define-key map [remap minibuffer-complete] #'crm-complete)
-    (define-key map [remap minibuffer-complete-word] #'crm-complete-word)
-    (define-key map [remap minibuffer-completion-help] #'crm-completion-help)
-    (define-key map [remap minibuffer-complete-and-exit]
-      #'crm-complete-and-exit)
-    map)
-  "Local keymap for minibuffer multiple input with exact match completion.
-Analog of `minibuffer-local-must-match-map' for crm.")
+It should be a regexp that does not match the list of completion candidates.")
+
+(defvar-keymap crm-local-completion-map
+  :doc "Local keymap for minibuffer multiple input with completion.
+Analog of `minibuffer-local-completion-map'."
+  :parent minibuffer-local-completion-map
+  "<remap> <minibuffer-complete>"        #'crm-complete
+  "<remap> <minibuffer-complete-word>"   #'crm-complete-word
+  "<remap> <minibuffer-completion-help>" #'crm-completion-help)
+
+(defvar-keymap crm-local-must-match-map
+  :doc "Local keymap for minibuffer multiple input with exact match completion.
+Analog of `minibuffer-local-must-match-map' for crm."
+  ;; We'd want to have multiple inheritance here.
+  :parent minibuffer-local-must-match-map
+  "<remap> <minibuffer-complete>"          #'crm-complete
+  "<remap> <minibuffer-complete-word>"     #'crm-complete-word
+  "<remap> <minibuffer-completion-help>"   #'crm-completion-help
+  "<remap> <minibuffer-complete-and-exit>" #'crm-complete-and-exit)
 
 (defvar crm-completion-table nil
   "An alist whose elements' cars are strings, or an obarray.
diff --git a/lisp/emacs-lisp/debug-early.el b/lisp/emacs-lisp/debug-early.el
index 4f1f4b8155..a301c73017 100644
--- a/lisp/emacs-lisp/debug-early.el
+++ b/lisp/emacs-lisp/debug-early.el
@@ -45,7 +45,13 @@ of the build process."
       (let ((print-escape-newlines t)
             (print-escape-control-characters t)
             (print-escape-nonascii t)
-            (prin1 (if (fboundp 'cl-prin1) #'cl-prin1 #'prin1)))
+            (prin1 (if (and (fboundp 'cl-prin1)
+                            ;; If we're being called while
+                            ;; bootstrapping, we won't be able to load
+                            ;; cl-print.
+                            (require 'cl-print nil t))
+                       #'cl-prin1
+                     #'prin1)))
         (mapbacktrace
          #'(lambda (evald func args _flags)
              (let ((args args))
diff --git a/lisp/emacs-lisp/debug.el b/lisp/emacs-lisp/debug.el
index c4929eb2b0..460057b3af 100644
--- a/lisp/emacs-lisp/debug.el
+++ b/lisp/emacs-lisp/debug.el
@@ -560,52 +560,53 @@ The environment used is the one when entering the 
activation frame at point."
   'backtrace-toggle-locals "28.1")
 
 
-(defvar debugger-mode-map
-  (let ((map (make-keymap)))
-    (set-keymap-parent map backtrace-mode-map)
-    (define-key map "b" 'debugger-frame)
-    (define-key map "c" 'debugger-continue)
-    (define-key map "j" 'debugger-jump)
-    (define-key map "r" 'debugger-return-value)
-    (define-key map "u" 'debugger-frame-clear)
-    (define-key map "d" 'debugger-step-through)
-    (define-key map "l" 'debugger-list-functions)
-    (define-key map "q" 'debugger-quit)
-    (define-key map "e" 'debugger-eval-expression)
-    (define-key map "R" 'debugger-record-expression)
-    (define-key map [mouse-2] 'push-button)
-    (easy-menu-define nil map ""
-      '("Debugger"
-        ["Step through" debugger-step-through
-         :help "Proceed, stepping through subexpressions of this expression"]
-        ["Continue" debugger-continue
-         :help "Continue, evaluating this expression without stopping"]
-        ["Jump" debugger-jump
-         :help "Continue to exit from this frame, with all debug-on-entry 
suspended"]
-        ["Eval Expression..." debugger-eval-expression
-         :help "Eval an expression, in an environment like that outside the 
debugger"]
-        ["Display and Record Expression" debugger-record-expression
-         :help "Display a variable's value and record it in 
`*Backtrace-record*' buffer"]
-        ["Return value..." debugger-return-value
-         :help "Continue, specifying value to return."]
-        "--"
-        ["Debug frame" debugger-frame
-         :help "Request entry to debugger when this frame exits"]
-        ["Cancel debug frame" debugger-frame-clear
-         :help "Do not enter debugger when this frame exits"]
-        ["List debug on entry functions" debugger-list-functions
-         :help "Display a list of all the functions now set to debug on entry"]
-        "--"
-        ["Next Line" next-line
-         :help "Move cursor down"]
-        ["Help for Symbol" backtrace-help-follow-symbol
-         :help "Show help for symbol at point"]
-        ["Describe Debugger Mode" describe-mode
-         :help "Display documentation for debugger-mode"]
-        "--"
-        ["Quit" debugger-quit
-         :help "Quit debugging and return to top level"]))
-    map))
+(defvar-keymap debugger-mode-map
+  :full t
+  :parent backtrace-mode-map
+  "b" #'debugger-frame
+  "c" #'debugger-continue
+  "j" #'debugger-jump
+  "r" #'debugger-return-value
+  "u" #'debugger-frame-clear
+  "d" #'debugger-step-through
+  "l" #'debugger-list-functions
+  "q" #'debugger-quit
+  "e" #'debugger-eval-expression
+  "R" #'debugger-record-expression
+
+  "<mouse-2>" #'push-button
+
+  :menu
+  '("Debugger"
+    ["Step through" debugger-step-through
+     :help "Proceed, stepping through subexpressions of this expression"]
+    ["Continue" debugger-continue
+     :help "Continue, evaluating this expression without stopping"]
+    ["Jump" debugger-jump
+     :help "Continue to exit from this frame, with all debug-on-entry 
suspended"]
+    ["Eval Expression..." debugger-eval-expression
+     :help "Eval an expression, in an environment like that outside the 
debugger"]
+    ["Display and Record Expression" debugger-record-expression
+     :help "Display a variable's value and record it in `*Backtrace-record*' 
buffer"]
+    ["Return value..." debugger-return-value
+     :help "Continue, specifying value to return."]
+    "--"
+    ["Debug frame" debugger-frame
+     :help "Request entry to debugger when this frame exits"]
+    ["Cancel debug frame" debugger-frame-clear
+     :help "Do not enter debugger when this frame exits"]
+    ["List debug on entry functions" debugger-list-functions
+     :help "Display a list of all the functions now set to debug on entry"]
+    "--"
+    ["Next Line" next-line
+     :help "Move cursor down"]
+    ["Help for Symbol" backtrace-help-follow-symbol
+     :help "Show help for symbol at point"]
+    ["Describe Debugger Mode" describe-mode
+     :help "Display documentation for debugger-mode"]
+    "--"
+    ["Quit" debugger-quit
+     :help "Quit debugging and return to top level"]))
 
 (put 'debugger-mode 'mode-class 'special)
 
diff --git a/lisp/emacs-lisp/derived.el b/lisp/emacs-lisp/derived.el
index 8912eb10cc..260fc3bf47 100644
--- a/lisp/emacs-lisp/derived.el
+++ b/lisp/emacs-lisp/derived.el
@@ -1,10 +1,9 @@
 ;;; derived.el --- allow inheritance of major modes  -*- lexical-binding: t; 
-*-
 ;; (formerly mode-clone.el)
 
-;; Copyright (C) 1993-1994, 1999, 2001-2022 Free Software Foundation,
-;; Inc.
+;; Copyright (C) 1993-2022 Free Software Foundation, Inc.
 
-;; Author: David Megginson (dmeggins@aix1.uottawa.ca)
+;; Author: David Megginson <dmeggins@aix1.uottawa.ca>
 ;; Maintainer: emacs-devel@gnu.org
 ;; Keywords: extensions
 ;; Package: emacs
diff --git a/lisp/emacs-lisp/easy-mmode.el b/lisp/emacs-lisp/easy-mmode.el
index 54cac11616..c3a4e9fc7a 100644
--- a/lisp/emacs-lisp/easy-mmode.el
+++ b/lisp/emacs-lisp/easy-mmode.el
@@ -408,7 +408,7 @@ or call the function `%s'."))))
 No problems result if this variable is not bound.
 `add-hook' automatically binds it.  (This is true for all hook variables.)"
                        modefun)))
-       ;; Allow using using `M-x customize-variable' on the hook.
+       ;; Allow using `M-x customize-variable' on the hook.
        (put ',hook 'custom-type 'hook)
        (put ',hook 'standard-value (list nil))
 
@@ -576,7 +576,7 @@ and nil means \"don't use\".  There's an implicit nil at 
the end of the
 list."
                       mode)
              :type '(repeat sexp)
-             :group ,group))
+             ,@group))
 
        ;; Autoloading define-globalized-minor-mode autoloads everything
        ;; up-to-here.
diff --git a/lisp/emacs-lisp/easymenu.el b/lisp/emacs-lisp/easymenu.el
index 43ce1872f9..41e3a197af 100644
--- a/lisp/emacs-lisp/easymenu.el
+++ b/lisp/emacs-lisp/easymenu.el
@@ -492,25 +492,11 @@ To implement dynamic menus, either call this from
 `menu-bar-update-hook' or use a menu filter."
   (easy-menu-add-item map path (easy-menu-create-menu name items) before))
 
-(defalias 'easy-menu-remove #'ignore
-  "Remove MENU from the current menu bar.
-Contrary to XEmacs, this is a nop on Emacs since menus are automatically
-\(de)activated when the corresponding keymap is (de)activated.
-
-\(fn MENU)")
+(defalias 'easy-menu-remove #'ignore)
 (make-obsolete 'easy-menu-remove "this was always a no-op in Emacs \
 and can be safely removed." "28.1")
 
-(defalias 'easy-menu-add #'ignore
-  "Add the menu to the menubar.
-On Emacs this is a nop, because menus are already automatically
-activated when the corresponding keymap is activated.  On XEmacs
-this is needed to actually add the menu to the current menubar.
-
-You should call this once the menu and keybindings are set up
-completely and menu filter functions can be expected to work.
-
-\(fn MENU &optional MAP)")
+(defalias 'easy-menu-add #'ignore)
 (make-obsolete 'easy-menu-add "this was always a no-op in Emacs \
 and can be safely removed." "28.1")
 
diff --git a/lisp/emacs-lisp/edebug.el b/lisp/emacs-lisp/edebug.el
index 9dc5a1315e..9de8999fdf 100644
--- a/lisp/emacs-lisp/edebug.el
+++ b/lisp/emacs-lisp/edebug.el
@@ -675,7 +675,7 @@ Maybe clear the markers and delete the symbol's edebug 
property?"
             (or (and (eq (aref edebug-read-syntax-table (following-char))
                          'symbol)
                      (not (= (following-char) ?\;)))
-                (memq (following-char) '(?\, ?\.)))))
+                (eq (following-char) ?.))))
       'symbol
     (aref edebug-read-syntax-table (following-char))))
 
@@ -864,7 +864,7 @@ marker.  The needed data will then come from property
 
 (defun edebug-read-special (stream)
   "Read from STREAM a Lisp object beginning with #.
-Turn #'thing into (function thing) and handle the read syntax for
+Turn #\\='thing into (function thing) and handle the read syntax for
 circular objects.  Let `read' read everything else."
   (catch 'return
     (forward-char 1)
@@ -2861,7 +2861,6 @@ See `edebug-behavior-alist' for implementations.")
              (this-command this-command)
              (current-prefix-arg nil)
 
-             ;; More for Emacs 19
              (last-input-event nil)
              (last-command-event nil)
              (last-event-frame nil)
@@ -3707,46 +3706,64 @@ Return the result of the last expression."
 (defalias 'edebug-format #'format-message)
 (defalias 'edebug-message #'message)
 
-(defun edebug-eval-expression (expr)
+(defun edebug-eval-expression (expr &optional pp)
   "Evaluate an expression in the outside environment.
 If interactive, prompt for the expression.
-Print result in minibuffer."
-  (interactive (list (read--expression "Eval: ")))
+
+Print result in minibuffer by default, but if PP is non-nil open
+a new window and pretty-print the result there.  (Interactively,
+this is the prefix key.)"
+  (interactive (list (read--expression "Edebug eval: ")
+                     current-prefix-arg))
   (let* ((errored nil)
-         (result
+         (value
           (edebug-outside-excursion
-           (let ((result (if debug-allow-recursive-debug
-                             (edebug-eval expr)
-                           (condition-case err
-                               (edebug-eval expr)
-                             (error
-                              (setq errored
-                                    (format "%s: %s"
-                                           (get (car err) 'error-message)
-                                           (car (cdr err)))))))))
-             (unless errored
-               (values--store-value result)
-               (concat (edebug-safe-prin1-to-string result)
-                       (eval-expression-print-format result)))))))
-    (if errored
-        (message "Error: %s" errored)
-      (princ result))))
-
-(defun edebug-eval-last-sexp (&optional no-truncate)
-  "Evaluate sexp before point in the outside environment.
-Print value in minibuffer.
+           (if debug-allow-recursive-debug
+               (edebug-eval expr)
+             (condition-case err
+                 (edebug-eval expr)
+               (error
+                (setq errored
+                      (format "%s: %s"
+                             (get (car err) 'error-message)
+                             (car (cdr err)))))))))
+         (result
+          (unless errored
+            (values--store-value value)
+            (concat (edebug-safe-prin1-to-string value)
+                    (eval-expression-print-format value)))))
+    (cond
+     (errored
+      (message "Error: %s" errored))
+     (pp
+      (save-selected-window
+        (pop-to-buffer "*Edebug Results*")
+        (erase-buffer)
+        (pp value (current-buffer))
+        (goto-char (point-min))
+        (lisp-data-mode)))
+     (t
+      (princ result)))))
 
-If NO-TRUNCATE is non-nil (or interactively with a prefix
-argument of zero), show the full length of the expression, not
-limited by `edebug-print-length' or `edebug-print-level'."
+(defun edebug-eval-last-sexp (&optional display-type)
+  "Evaluate sexp before point in the outside environment.
+If DISPLAY-TYPE is `pretty-print' (interactively, a non-zero
+prefix argument), pretty-print the value in a separate buffer.
+Otherwise, print the value in minibuffer.  If DISPLAY-TYPE is any
+other non-nil value (or interactively with a prefix argument of
+zero), show the full length of the expression, not limited by
+`edebug-print-length' or `edebug-print-level'."
   (interactive
    (list (and current-prefix-arg
-              (zerop (prefix-numeric-value current-prefix-arg)))))
-  (if no-truncate
-      (let ((edebug-print-length nil)
-            (edebug-print-level nil))
-        (edebug-eval-expression (edebug-last-sexp)))
-    (edebug-eval-expression (edebug-last-sexp))))
+              (if (zerop (prefix-numeric-value current-prefix-arg))
+                  'no-truncate
+                'pretty-print))))
+  (if (or (null display-type)
+          (eq display-type 'pretty-print))
+      (edebug-eval-expression (edebug-last-sexp) display-type)
+    (let ((edebug-print-length nil)
+          (edebug-print-level nil))
+      (edebug-eval-expression (edebug-last-sexp)))))
 
 (defun edebug-eval-print-last-sexp (&optional no-truncate)
   "Evaluate sexp before point in outside environment; insert value.
@@ -3791,74 +3808,72 @@ be installed in `emacs-lisp-mode-map'.")
   ;; The following isn't a GUD binding.
   (define-key emacs-lisp-mode-map "\C-x\C-a\C-m" 'edebug-set-initial-mode))
 
-(defvar edebug-mode-map
-  (let ((map (copy-keymap emacs-lisp-mode-map)))
-    ;; control
-    (define-key map " " 'edebug-step-mode)
-    (define-key map "n" 'edebug-next-mode)
-    (define-key map "g" 'edebug-go-mode)
-    (define-key map "G" 'edebug-Go-nonstop-mode)
-    (define-key map "t" 'edebug-trace-mode)
-    (define-key map "T" 'edebug-Trace-fast-mode)
-    (define-key map "c" 'edebug-continue-mode)
-    (define-key map "C" 'edebug-Continue-fast-mode)
-
-    ;;(define-key map "f" 'edebug-forward) not implemented
-    (define-key map "f" 'edebug-forward-sexp)
-    (define-key map "h" 'edebug-goto-here)
-
-    (define-key map "I" 'edebug-instrument-callee)
-    (define-key map "i" 'edebug-step-in)
-    (define-key map "o" 'edebug-step-out)
-
-    ;; quitting and stopping
-    (define-key map "q" 'top-level)
-    (define-key map "Q" 'edebug-top-level-nonstop)
-    (define-key map "a" 'abort-recursive-edit)
-    (define-key map "S" 'edebug-stop)
-
-    ;; breakpoints
-    (define-key map "b" 'edebug-set-breakpoint)
-    (define-key map "u" 'edebug-unset-breakpoint)
-    (define-key map "U" 'edebug-unset-breakpoints)
-    (define-key map "B" 'edebug-next-breakpoint)
-    (define-key map "x" 'edebug-set-conditional-breakpoint)
-    (define-key map "X" 'edebug-set-global-break-condition)
-    (define-key map "D" 'edebug-toggle-disable-breakpoint)
-
-    ;; evaluation
-    (define-key map "r" 'edebug-previous-result)
-    (define-key map "e" 'edebug-eval-expression)
-    (define-key map "\C-x\C-e" 'edebug-eval-last-sexp)
-    (define-key map "E" 'edebug-visit-eval-list)
-
-    ;; views
-    (define-key map "w" 'edebug-where)
-    (define-key map "v" 'edebug-view-outside) ;; maybe obsolete??
-    (define-key map "p" 'edebug-bounce-point)
-    (define-key map "P" 'edebug-view-outside) ;; same as v
-    (define-key map "W" 'edebug-toggle-save-windows)
-
-    ;; misc
-    (define-key map "?" 'edebug-help)
-    (define-key map "d" 'edebug-pop-to-backtrace)
-
-    (define-key map "-" 'negative-argument)
-
-    ;; statistics
-    (define-key map "=" 'edebug-temp-display-freq-count)
-
-    ;; GUD bindings
-    (define-key map "\C-c\C-s" 'edebug-step-mode)
-    (define-key map "\C-c\C-n" 'edebug-next-mode)
-    (define-key map "\C-c\C-c" 'edebug-go-mode)
-
-    (define-key map "\C-x " 'edebug-set-breakpoint)
-    (define-key map "\C-c\C-d" 'edebug-unset-breakpoint)
-    (define-key map "\C-c\C-t"
-      (lambda () (interactive) (edebug-set-breakpoint t)))
-    (define-key map "\C-c\C-l" 'edebug-where)
-    map))
+(defvar-keymap edebug-mode-map
+  :parent emacs-lisp-mode-map
+  ;; control
+  "SPC"     #'edebug-step-mode
+  "n"       #'edebug-next-mode
+  "g"       #'edebug-go-mode
+  "G"       #'edebug-Go-nonstop-mode
+  "t"       #'edebug-trace-mode
+  "T"       #'edebug-Trace-fast-mode
+  "c"       #'edebug-continue-mode
+  "C"       #'edebug-Continue-fast-mode
+
+  ;;"f"       #'edebug-forward ; not implemented
+  "f"       #'edebug-forward-sexp
+  "h"       #'edebug-goto-here
+
+  "I"       #'edebug-instrument-callee
+  "i"       #'edebug-step-in
+  "o"       #'edebug-step-out
+
+  ;; quitting and stopping
+  "q"       #'top-level
+  "Q"       #'edebug-top-level-nonstop
+  "a"       #'abort-recursive-edit
+  "S"       #'edebug-stop
+
+  ;; breakpoints
+  "b"       #'edebug-set-breakpoint
+  "u"       #'edebug-unset-breakpoint
+  "U"       #'edebug-unset-breakpoints
+  "B"       #'edebug-next-breakpoint
+  "x"       #'edebug-set-conditional-breakpoint
+  "X"       #'edebug-set-global-break-condition
+  "D"       #'edebug-toggle-disable-breakpoint
+
+  ;; evaluation
+  "r"       #'edebug-previous-result
+  "e"       #'edebug-eval-expression
+  "C-x C-e" #'edebug-eval-last-sexp
+  "E"       #'edebug-visit-eval-list
+
+  ;; views
+  "w"       #'edebug-where
+  "v"       #'edebug-view-outside        ; maybe obsolete??
+  "p"       #'edebug-bounce-point
+  "P"       #'edebug-view-outside        ; same as v
+  "W"       #'edebug-toggle-save-windows
+
+  ;; misc
+  "?"       #'edebug-help
+  "d"       #'edebug-pop-to-backtrace
+
+  "-"       #'negative-argument
+
+  ;; statistics
+  "="       #'edebug-temp-display-freq-count
+
+  ;; GUD bindings
+  "C-c C-s" #'edebug-step-mode
+  "C-c C-n" #'edebug-next-mode
+  "C-c C-c" #'edebug-go-mode
+
+  "C-x SPC" #'edebug-set-breakpoint
+  "C-c C-d" #'edebug-unset-breakpoint
+  "C-c C-t" (lambda () (interactive) (edebug-set-breakpoint t))
+  "C-c C-l" #'edebug-where)
 
 ;; Autoloading these global bindings doesn't make sense because
 ;; they cannot be used anyway unless Edebug is already loaded and active.
@@ -3873,38 +3888,35 @@ be installed in `emacs-lisp-mode-map'.")
 
 (define-obsolete-variable-alias 'global-edebug-map
   'edebug-global-map "28.1")
-(defvar edebug-global-map
-  (let ((map (make-sparse-keymap)))
-
-    (define-key map " " 'edebug-step-mode)
-    (define-key map "g" 'edebug-go-mode)
-    (define-key map "G" 'edebug-Go-nonstop-mode)
-    (define-key map "t" 'edebug-trace-mode)
-    (define-key map "T" 'edebug-Trace-fast-mode)
-    (define-key map "c" 'edebug-continue-mode)
-    (define-key map "C" 'edebug-Continue-fast-mode)
-
-    ;; breakpoints
-    (define-key map "b" 'edebug-set-breakpoint)
-    (define-key map "u" 'edebug-unset-breakpoint)
-    (define-key map "U" 'edebug-unset-breakpoints)
-    (define-key map "x" 'edebug-set-conditional-breakpoint)
-    (define-key map "X" 'edebug-set-global-break-condition)
-    (define-key map "D" 'edebug-toggle-disable-breakpoint)
-
-    ;; views
-    (define-key map "w" 'edebug-where)
-    (define-key map "W" 'edebug-toggle-save-windows)
-
-    ;; quitting
-    (define-key map "q" 'top-level)
-    (define-key map "Q" 'edebug-top-level-nonstop)
-    (define-key map "a" 'abort-recursive-edit)
-
-    ;; statistics
-    (define-key map "=" 'edebug-display-freq-count)
-    map)
-  "Global map of edebug commands, available from any buffer.")
+(defvar-keymap edebug-global-map
+  :doc "Global map of edebug commands, available from any buffer."
+  "SPC" #'edebug-step-mode
+  "g"   #'edebug-go-mode
+  "G"   #'edebug-Go-nonstop-mode
+  "t"   #'edebug-trace-mode
+  "T"   #'edebug-Trace-fast-mode
+  "c"   #'edebug-continue-mode
+  "C"   #'edebug-Continue-fast-mode
+
+  ;; breakpoints
+  "b"   #'edebug-set-breakpoint
+  "u"   #'edebug-unset-breakpoint
+  "U"   #'edebug-unset-breakpoints
+  "x"   #'edebug-set-conditional-breakpoint
+  "X"   #'edebug-set-global-break-condition
+  "D"   #'edebug-toggle-disable-breakpoint
+
+  ;; views
+  "w"   #'edebug-where
+  "W"   #'edebug-toggle-save-windows
+
+  ;; quitting
+  "q"   #'top-level
+  "Q"   #'edebug-top-level-nonstop
+  "a"   #'abort-recursive-edit
+
+  ;; statistics
+  "="   #'edebug-display-freq-count)
 
 (when edebug-global-prefix
   (global-unset-key edebug-global-prefix)
@@ -4075,16 +4087,14 @@ May only be called from within 
`edebug--recursive-edit'."
 
 
 
-(defvar edebug-eval-mode-map
-  (let ((map (make-sparse-keymap)))
-    (set-keymap-parent map lisp-interaction-mode-map)
-    (define-key map "\C-c\C-w" 'edebug-where)
-    (define-key map "\C-c\C-d" 'edebug-delete-eval-item)
-    (define-key map "\C-c\C-u" 'edebug-update-eval-list)
-    (define-key map "\C-x\C-e" 'edebug-eval-last-sexp)
-    (define-key map "\C-j" 'edebug-eval-print-last-sexp)
-    map)
-  "Keymap for Edebug Eval mode.  Superset of Lisp Interaction mode.")
+(defvar-keymap edebug-eval-mode-map
+  :doc "Keymap for Edebug Eval mode.  Superset of Lisp Interaction mode."
+  :parent lisp-interaction-mode-map
+  "C-c C-w" #'edebug-where
+  "C-c C-d" #'edebug-delete-eval-item
+  "C-c C-u" #'edebug-update-eval-list
+  "C-x C-e" #'edebug-eval-last-sexp
+  "C-j"     #'edebug-eval-print-last-sexp)
 
 (put 'edebug-eval-mode 'mode-class 'special)
 
diff --git a/lisp/emacs-lisp/eieio-base.el b/lisp/emacs-lisp/eieio-base.el
index 4c702deaa9..ef02216411 100644
--- a/lisp/emacs-lisp/eieio-base.el
+++ b/lisp/emacs-lisp/eieio-base.el
@@ -281,32 +281,26 @@ being pedantic."
   (unless class
     (warn "`eieio-persistent-read' called without specifying a class"))
   (when class (cl-check-type class class))
-  (let ((ret nil)
-       (buffstr nil))
-    (unwind-protect
-       (progn
-         (with-current-buffer (get-buffer-create " *tmp eieio read*")
-           (insert-file-contents filename nil nil nil t)
-           (goto-char (point-min))
-           (setq buffstr (buffer-string)))
-         ;; Do the read in the buffer the read was initialized from
-         ;; so that any initialize-instance calls that depend on
-         ;; the current buffer will work.
-         (setq ret (read buffstr))
-         (when (not (child-of-class-p (car ret) 'eieio-persistent))
-           (error
-             "Invalid object: %s is not a subclass of `eieio-persistent'"
-             (car ret)))
-         (when (and class
-                    (not (or (eq (car ret) class) ; same class
-                             (and allow-subclass  ; subclass
-                                  (child-of-class-p (car ret) class)))))
-           (error
-             "Invalid object: %s is not an object of class %s nor a subclass"
-             (car ret) class))
-          (setq ret (eieio-persistent-make-instance (car ret) (cdr ret)))
-         (oset ret file filename))
-      (kill-buffer " *tmp eieio read*"))
+  (let* ((buffstr (with-temp-buffer
+                    (insert-file-contents filename)
+                    (buffer-string)))
+         ;; Do the read in the buffer the read was initialized from
+         ;; so that any initialize-instance calls that depend on
+         ;; the current buffer will work.
+         (ret (read buffstr)))
+    (when (not (child-of-class-p (car ret) 'eieio-persistent))
+      (error
+       "Invalid object: %s is not a subclass of `eieio-persistent'"
+       (car ret)))
+    (when (and class
+              (not (or (eq (car ret) class) ; same class
+                       (and allow-subclass  ; subclass
+                            (child-of-class-p (car ret) class)))))
+      (error
+       "Invalid object: %s is not an object of class %s nor a subclass"
+       (car ret) class))
+    (setq ret (eieio-persistent-make-instance (car ret) (cdr ret)))
+    (oset ret file filename)
     ret))
 
 (cl-defgeneric eieio-persistent-make-instance (objclass inputlist)
diff --git a/lisp/emacs-lisp/eieio-core.el b/lisp/emacs-lisp/eieio-core.el
index d9864e6965..5e7b5cbfb2 100644
--- a/lisp/emacs-lisp/eieio-core.el
+++ b/lisp/emacs-lisp/eieio-core.el
@@ -24,15 +24,14 @@
 ;;; Commentary:
 ;;
 ;; The "core" part of EIEIO is the implementation for the object
-;; system (such as eieio-defclass, or eieio-defmethod) but not the
-;; base classes for the object system, which are defined in EIEIO.
+;; system (such as eieio-defclass-internal, or cl-defmethod) but not
+;; the base classes for the object system, which are defined in EIEIO.
 ;;
 ;; See the commentary for eieio.el for more about EIEIO itself.
 
 ;;; Code:
 
 (require 'cl-lib)
-(require 'eieio-loaddefs nil t)
 
 ;;;
 ;; A few functions that are better in the official EIEIO src, but
diff --git a/lisp/emacs-lisp/eieio-custom.el b/lisp/emacs-lisp/eieio-custom.el
index ebb6f2cd8c..0bec3bb0d5 100644
--- a/lisp/emacs-lisp/eieio-custom.el
+++ b/lisp/emacs-lisp/eieio-custom.el
@@ -329,11 +329,9 @@ Argument OBJ is the object that has been customized."
 Optional argument GROUP is the sub-group of slots to display."
   (eieio-customize-object obj group))
 
-(defvar eieio-custom-mode-map
-  (let ((map (make-sparse-keymap)))
-    (set-keymap-parent map widget-keymap)
-    map)
-  "Keymap for EIEIO Custom mode.")
+(defvar-keymap eieio-custom-mode-map
+  :doc "Keymap for EIEIO Custom mode."
+  :parent widget-keymap)
 
 (define-derived-mode eieio-custom-mode fundamental-mode "EIEIO Custom"
   "Major mode for customizing EIEIO objects.
@@ -469,8 +467,4 @@ Return the symbol for the group, or nil."
 
 (provide 'eieio-custom)
 
-;; Local variables:
-;; generated-autoload-file: "eieio-loaddefs.el"
-;; End:
-
 ;;; eieio-custom.el ends here
diff --git a/lisp/emacs-lisp/eieio-opt.el b/lisp/emacs-lisp/eieio-opt.el
index 72108f807f..5f67263f17 100644
--- a/lisp/emacs-lisp/eieio-opt.el
+++ b/lisp/emacs-lisp/eieio-opt.el
@@ -348,8 +348,4 @@ INDENT is the current indentation level."
 
 (provide 'eieio-opt)
 
-;; Local variables:
-;; generated-autoload-file: "eieio-loaddefs.el"
-;; End:
-
 ;;; eieio-opt.el ends here
diff --git a/lisp/emacs-lisp/eieio.el b/lisp/emacs-lisp/eieio.el
index 565eaf2d73..984166b593 100644
--- a/lisp/emacs-lisp/eieio.el
+++ b/lisp/emacs-lisp/eieio.el
@@ -689,6 +689,7 @@ This class is not stored in the `parent' slot of a class 
vector."
 (define-obsolete-function-alias 'standard-class
   #'eieio-default-superclass "26.1")
 
+;;;###autoload
 (cl-defgeneric make-instance (class &rest initargs)
   "Make a new instance of CLASS based on INITARGS.
 For example:
diff --git a/lisp/emacs-lisp/eldoc.el b/lisp/emacs-lisp/eldoc.el
index 0b8078579c..6fd89a690d 100644
--- a/lisp/emacs-lisp/eldoc.el
+++ b/lisp/emacs-lisp/eldoc.el
@@ -5,7 +5,7 @@
 ;; Author: Noah Friedman <friedman@splode.com>
 ;; Keywords: extensions
 ;; Created: 1995-10-06
-;; Version: 1.12.0
+;; Version: 1.13.0
 ;; Package-Requires: ((emacs "26.3"))
 
 ;; This is a GNU ELPA :core package.  Avoid functionality that is not
@@ -381,7 +381,6 @@ Also store it in `eldoc-last-message' and return that 
value."
 (defun eldoc-display-message-no-interference-p ()
   "Return nil if displaying a message would cause interference."
   (not (or executing-kbd-macro
-           (bound-and-true-p edebug-active)
            ;; The following configuration shows "Matches..." in the
            ;; echo area when point is after a closing bracket, which
            ;; conflicts with eldoc.
@@ -491,9 +490,9 @@ If INTERACTIVE, display it.  Else, return said buffer."
       (setq-local eldoc--doc-buffer-docs docs)
       (let ((inhibit-read-only t)
             (things-reported-on))
-        (erase-buffer) (setq buffer-read-only t)
+        (special-mode)
+        (erase-buffer)
         (setq-local nobreak-char-display nil)
-        (local-set-key "q" 'quit-window)
         (cl-loop for (docs . rest) on docs
                  for (this-doc . plist) = docs
                  for thing = (plist-get plist :thing)
@@ -551,12 +550,13 @@ Helper for `eldoc-display-in-echo-area'."
 (defun eldoc--echo-area-prefer-doc-buffer-p (truncatedp)
   "Tell if display in the echo area should be skipped.
 Helper for `eldoc-display-in-echo-area'.  If TRUNCATEDP the
-documentation to potentially appear in the echo are is truncated."
+documentation to potentially appear in the echo area is
+known to be truncated."
   (and (or (eq eldoc-echo-area-prefer-doc-buffer t)
            (and truncatedp
                 (eq eldoc-echo-area-prefer-doc-buffer
                     'maybe)))
-       (get-buffer-window eldoc--doc-buffer 'visible)))
+       (get-buffer-window eldoc--doc-buffer t)))
 
 (defun eldoc-display-in-echo-area (docs _interactive)
   "Display DOCS in echo area.
@@ -629,8 +629,7 @@ Honor `eldoc-echo-area-use-multiline-p' and
   "Display DOCS in a dedicated buffer.
 If INTERACTIVE is t, also display the buffer."
   (eldoc--format-doc-buffer docs)
-  (when interactive
-    (eldoc-doc-buffer)))
+  (when interactive (eldoc-doc-buffer t)))
 
 (defun eldoc-documentation-default ()
   "Show first doc string for item at point.
@@ -812,7 +811,7 @@ function passes responsibility to the functions in
 Other third-party values of `eldoc-documentation-strategy' should
 not use `eldoc--make-callback'.  They must find some alternate
 way to produce callbacks to feed to
-`eldoc-documentation-functions' and should endeavour to display
+`eldoc-documentation-functions' and should endeavor to display
 the docstrings eventually produced, using
 `eldoc-display-functions'."
   (let* (;; How many callbacks have been created by the strategy
diff --git a/lisp/emacs-lisp/elp.el b/lisp/emacs-lisp/elp.el
index 385ddb3f41..cbf38e7dd8 100644
--- a/lisp/emacs-lisp/elp.el
+++ b/lisp/emacs-lisp/elp.el
@@ -111,7 +111,7 @@
 ;; provide the functionality or interface that I wanted, so I wrote
 ;; this.
 
-;; Unlike previous profilers, elp uses Emacs 19's built-in function
+;; Unlike previous profilers, elp uses the built-in function
 ;; current-time to return interval times.  This obviates the need for
 ;; both an external C program and Emacs processes to communicate with
 ;; such a program, and thus simplifies the package as a whole.
@@ -472,13 +472,11 @@ original definition, use \\[elp-restore-function] or 
\\[elp-restore-all]."
        (insert atstr))
       (insert "\n"))))
 
-(defvar elp-results-symname-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map [mouse-2] 'elp-results-jump-to-definition)
-    (define-key map [follow-link] 'mouse-face)
-    (define-key map "\C-m" 'elp-results-jump-to-definition)
-    map)
-  "Keymap used on the function name column." )
+(defvar-keymap elp-results-symname-map
+  :doc "Keymap used on the function name column."
+  "<mouse-2>"     #'elp-results-jump-to-definition
+  "<follow-link>" 'mouse-face
+  "RET"           #'elp-results-jump-to-definition)
 
 (defun elp-results-jump-to-definition (&optional event)
   "Jump to the definition of the function at point."
diff --git a/lisp/emacs-lisp/ert-x.el b/lisp/emacs-lisp/ert-x.el
index de18adff5b..4436d0a4b1 100644
--- a/lisp/emacs-lisp/ert-x.el
+++ b/lisp/emacs-lisp/ert-x.el
@@ -158,9 +158,6 @@ test for `called-interactively' in the command will fail."
     (run-hooks 'pre-command-hook)
     (setq return-value (apply (car command) (cdr command)))
     (run-hooks 'post-command-hook)
-    (and (boundp 'deferred-action-list)
-         deferred-action-list
-         (run-hooks 'deferred-action-function))
     (setq real-last-command (car command)
           last-command this-command)
     (when (boundp 'last-repeatable-command)
@@ -491,9 +488,13 @@ The same keyword arguments are supported as in
   (string-match "Apple \\(LLVM\\|[Cc]lang\\)\\|Xcode\\.app"
                 (shell-command-to-string "gcc --version")))
 
-
-(defvar tramp-methods)
 (defvar tramp-default-host-alist)
+(defvar tramp-methods)
+(defvar tramp-remote-path)
+
+;; This should happen on hydra only.
+(when (and (featurep 'tramp) (getenv "EMACS_HYDRA_CI"))
+  (add-to-list 'tramp-remote-path 'tramp-own-remote-path))
 
 ;; If this defconst is used in a test file, `tramp' shall be loaded
 ;; prior `ert-x'.  There is no default value on w32 systems, which
diff --git a/lisp/emacs-lisp/ert.el b/lisp/emacs-lisp/ert.el
index 82722add42..047b0069bb 100644
--- a/lisp/emacs-lisp/ert.el
+++ b/lisp/emacs-lisp/ert.el
@@ -1,6 +1,6 @@
 ;;; ert.el --- Emacs Lisp Regression Testing  -*- lexical-binding: t -*-
 
-;; Copyright (C) 2007-2008, 2010-2022 Free Software Foundation, Inc.
+;; Copyright (C) 2007-2022 Free Software Foundation, Inc.
 
 ;; Author: Christian Ohler <ohler@gnu.org>
 ;; Keywords: lisp, tools
@@ -46,14 +46,10 @@
 ;; processing further, this is useful for checking the test
 ;; environment (like availability of features, external binaries, etc).
 ;;
-;; See ERT's info manual as well as the docstrings for more details.
-;; To compile the manual, run `makeinfo ert.texinfo' in the ERT
-;; directory, then C-u M-x info ert.info in Emacs to view it.
-;;
-;; To see some examples of tests written in ERT, see its self-tests in
-;; ert-tests.el.  Some of these are tricky due to the bootstrapping
-;; problem of writing tests for a testing tool, others test simple
-;; functions and are straightforward.
+;; See ERT's Info manual `(ert) Top' as well as the docstrings for
+;; more details.  To see some examples of tests written in ERT, see
+;; the test suite distributed with the Emacs source distribution (in
+;; the "test" directory).
 
 ;;; Code:
 
@@ -1696,7 +1692,7 @@ test packages depend on each other, it might be helpful.")
                          (string-match-p "^Running 0 tests" logfile-contents))
                   (insert (format "  <testsuite id=\"%s\" name=\"%s\" 
tests=\"1\" errors=\"1\" failures=\"0\" skipped=\"0\" time=\"0\" 
timestamp=\"%s\">\n"
                                   id test-report
-                                  (ert--format-time-iso8601 (current-time))))
+                                 (ert--format-time-iso8601 nil)))
                   (insert (format "    <testcase name=\"Test report missing 
%s\" status=\"error\" time=\"0\">\n"
                                   (file-name-nondirectory test-report)))
                   (insert (format "      <error message=\"Test report missing 
%s\" type=\"error\">\n"
@@ -1817,8 +1813,7 @@ Ran \\([0-9]+\\) tests, \\([0-9]+\\) results as expected\
     (unless (or (null tests) (zerop high))
       (message "\nLONG-RUNNING TESTS")
       (message "------------------")
-      (setq tests (sort tests (lambda (x y) (> (car x) (car y)))))
-      (when (< high (length tests)) (setcdr (nthcdr (1- high) tests) nil))
+      (setq tests (ntake high (sort tests (lambda (x y) (> (car x) (car y))))))
       (message "%s" (mapconcat #'cdr tests "\n")))
     ;; More details on hydra and emba, where the logs are harder to get to.
     (when (and (or (getenv "EMACS_HYDRA_CI") (getenv "EMACS_EMBA_CI"))
@@ -2884,8 +2879,14 @@ To be used in the ERT results buffer."
   nil)
 
 (defun ert-test-erts-file (file &optional transform)
-  "Parse FILE as a file containing before/after parts.
-TRANSFORM will be called to get from before to after."
+  "Parse FILE as a file containing before/after parts (an erts file).
+
+This function puts the \"before\" section of an .erts file into a
+temporary buffer, calls the TRANSFORM function, and then compares
+the result with the \"after\" section.
+
+See Info node `(ert) erts files' for more information on how to
+write erts files."
   (with-temp-buffer
     (insert-file-contents file)
     (let ((gen-specs (list (cons 'dummy t)
diff --git a/lisp/emacs-lisp/find-func.el b/lisp/emacs-lisp/find-func.el
index ac84b50b5f..486d5d0861 100644
--- a/lisp/emacs-lisp/find-func.el
+++ b/lisp/emacs-lisp/find-func.el
@@ -800,7 +800,10 @@ See `find-function-on-key'."
   (define-key ctl-x-5-map "K" 'find-function-on-key-other-frame)
   (define-key ctl-x-map "V" 'find-variable)
   (define-key ctl-x-4-map "V" 'find-variable-other-window)
-  (define-key ctl-x-5-map "V" 'find-variable-other-frame))
+  (define-key ctl-x-5-map "V" 'find-variable-other-frame)
+  (define-key ctl-x-map "L" 'find-library)
+  (define-key ctl-x-4-map "L" 'find-library-other-window)
+  (define-key ctl-x-5-map "L" 'find-library-other-frame))
 
 (provide 'find-func)
 
diff --git a/lisp/emacs-lisp/gv.el b/lisp/emacs-lisp/gv.el
index 7cfa1f2dad..eaab6439ad 100644
--- a/lisp/emacs-lisp/gv.el
+++ b/lisp/emacs-lisp/gv.el
@@ -92,6 +92,9 @@ DO must return an Elisp expression."
    (t
     (let* ((head (car place))
            (gf (function-get head 'gv-expander 'autoload)))
+      (when (and (symbolp head)
+                 (get head 'byte-obsolete-generalized-variable))
+        (byte-compile-warn-obsolete head "generalized variable"))
       (if gf (apply gf do (cdr place))
         (let ((me (macroexpand-1 place
                                  ;; (append macroexpand-all-environment
@@ -166,6 +169,18 @@ arguments as NAME.  DO is a function as defined in 
`gv-get'."
         ;; (`(expand ,expander) `(gv-define-expand ,name ,expander))
         (_ (message "Unknown %s declaration %S" symbol handler) nil))))
 
+(defun make-obsolete-generalized-variable (obsolete-name current-name when)
+  "Make byte-compiler warn that generalized variable OBSOLETE-NAME is obsolete.
+The warning will say that CURRENT-NAME should be used instead.
+
+If CURRENT-NAME is a string, that is the `use instead' message.
+
+WHEN should be a string indicating when the variable was first
+made obsolete, for example a date or a release number."
+  (put obsolete-name 'byte-obsolete-generalized-variable
+       (purecopy (list current-name when)))
+  obsolete-name)
+
 ;; Additions for `declare'.  We specify the values as named aliases so
 ;; that `describe-variable' prints something useful; cf. Bug#40491.
 
@@ -392,6 +407,7 @@ The return value is the last VAL in the list.
 (gv-define-setter buffer-local-value (val var buf)
   (macroexp-let2 nil v val
     `(with-current-buffer ,buf (set (make-local-variable ,var) ,v))))
+(make-obsolete-generalized-variable 'buffer-local-value nil "29.1")
 
 (gv-define-expander alist-get
   (lambda (do key alist &optional default remove testfn)
@@ -602,7 +618,7 @@ This is like the `*' operator of the C language.
 REF must have been previously obtained with `gv-ref'."
   (funcall (car ref)))
 ;; Don't use `declare' because it seems to introduce circularity problems:
-;; Warning: Eager macro-expansion skipped due to cycle:
+;; Eager macro-expansion skipped due to cycle:
 ;;  … => (load "gv.el") => (macroexpand-all (defsubst gv-deref …)) => 
(macroexpand (defun …)) => (load "gv.el")
 (gv-define-setter gv-deref (v ref) `(funcall (cdr ,ref) ,v))
 
@@ -618,71 +634,160 @@ REF must have been previously obtained with `gv-ref'."
 
 ;; Some Emacs-related place types.
 (gv-define-simple-setter buffer-file-name set-visited-file-name t)
+(make-obsolete-generalized-variable
+ 'buffer-file-name 'set-visited-file-name "29.1")
+
 (gv-define-setter buffer-modified-p (flag &optional buf)
   (macroexp-let2 nil buffer `(or ,buf (current-buffer))
     `(with-current-buffer ,buffer
        (set-buffer-modified-p ,flag))))
+(make-obsolete-generalized-variable
+ 'buffer-modified-p 'set-buffer-modified-p "29.1")
+
 (gv-define-simple-setter buffer-name rename-buffer t)
+(make-obsolete-generalized-variable 'buffer-name 'rename-buffer "29.1")
+
 (gv-define-setter buffer-string (store)
   `(insert (prog1 ,store (erase-buffer))))
+(make-obsolete-generalized-variable 'buffer-string nil "29.1")
+
 (gv-define-simple-setter buffer-substring cl--set-buffer-substring)
+(make-obsolete-generalized-variable 'buffer-substring nil "29.1")
+
 (gv-define-simple-setter current-buffer set-buffer)
+(make-obsolete-generalized-variable 'current-buffer 'set-buffer "29.1")
+
 (gv-define-simple-setter current-column move-to-column t)
+(make-obsolete-generalized-variable 'current-column 'move-to-column "29.1")
+
 (gv-define-simple-setter current-global-map use-global-map t)
+(make-obsolete-generalized-variable 'current-global-map 'use-global-map "29.1")
+
 (gv-define-setter current-input-mode (store)
   `(progn (apply #'set-input-mode ,store) ,store))
+(make-obsolete-generalized-variable 'current-input-mode nil "29.1")
+
 (gv-define-simple-setter current-local-map use-local-map t)
+(make-obsolete-generalized-variable 'current-local-map 'use-local-map "29.1")
+
 (gv-define-simple-setter current-window-configuration
                          set-window-configuration t)
+(make-obsolete-generalized-variable
+ 'current-window-configuration 'set-window-configuration "29.1")
+
 (gv-define-simple-setter default-file-modes set-default-file-modes t)
+(make-obsolete-generalized-variable
+ 'default-file-modes 'set-default-file-modes "29.1")
+
 (gv-define-simple-setter documentation-property put)
+(make-obsolete-generalized-variable 'documentation-property 'put "29.1")
+
 (gv-define-setter face-background (x f &optional s)
   `(set-face-background ,f ,x ,s))
 (gv-define-setter face-background-pixmap (x f &optional s)
-  `(set-face-background-pixmap ,f ,x ,s))
+  `(set-face-stipple ,f ,x ,s))
+(make-obsolete-generalized-variable 'face-background-pixmap 'face-stipple 
"29.1")
+(gv-define-setter face-stipple (x f &optional s)
+  `(set-face-stipple ,f ,x ,s))
 (gv-define-setter face-font (x f &optional s) `(set-face-font ,f ,x ,s))
 (gv-define-setter face-foreground (x f &optional s)
   `(set-face-foreground ,f ,x ,s))
 (gv-define-setter face-underline-p (x f &optional s)
   `(set-face-underline ,f ,x ,s))
 (gv-define-simple-setter file-modes set-file-modes t)
+
 (gv-define-setter frame-height (x &optional frame)
   `(set-frame-height (or ,frame (selected-frame)) ,x))
+(make-obsolete-generalized-variable 'frame-height 'set-frame-height "29.1")
+
 (gv-define-simple-setter frame-parameters modify-frame-parameters t)
 (gv-define-simple-setter frame-visible-p cl--set-frame-visible-p)
+(make-obsolete-generalized-variable 'frame-visible-p nil "29.1")
+
 (gv-define-setter frame-width (x &optional frame)
   `(set-frame-width (or ,frame (selected-frame)) ,x))
+(make-obsolete-generalized-variable 'frame-width 'set-frame-width "29.1")
+
 (gv-define-simple-setter getenv setenv t)
 (gv-define-simple-setter get-register set-register)
+
 (gv-define-simple-setter global-key-binding global-set-key)
+(make-obsolete-generalized-variable 'global-key-binding 'global-set-key "29.1")
+
 (gv-define-simple-setter local-key-binding local-set-key)
+(make-obsolete-generalized-variable 'local-key-binding 'local-set-key "29.1")
+
 (gv-define-simple-setter mark set-mark t)
+(make-obsolete-generalized-variable 'mark 'set-mark "29.1")
+
 (gv-define-simple-setter mark-marker set-mark t)
+(make-obsolete-generalized-variable 'mark-marker 'set-mark "29.1")
+
 (gv-define-simple-setter marker-position set-marker t)
+(make-obsolete-generalized-variable 'marker-position 'set-marker "29.1")
+
 (gv-define-setter mouse-position (store scr)
   `(set-mouse-position ,scr (car ,store) (cadr ,store)
                        (cddr ,store)))
+(make-obsolete-generalized-variable 'mouse-position 'set-mouse-position "29.1")
+
 (gv-define-simple-setter point goto-char)
+(make-obsolete-generalized-variable 'point 'goto-char "29.1")
+
 (gv-define-simple-setter point-marker goto-char t)
+(make-obsolete-generalized-variable 'point-marker 'goto-char "29.1")
+
 (gv-define-setter point-max (store)
   `(progn (narrow-to-region (point-min) ,store) ,store))
+(make-obsolete-generalized-variable 'point-max 'narrow-to-region "29.1")
+
 (gv-define-setter point-min (store)
   `(progn (narrow-to-region ,store (point-max)) ,store))
+(make-obsolete-generalized-variable 'point-min 'narrow-to-region "29.1")
+
 (gv-define-setter read-mouse-position (store scr)
   `(set-mouse-position ,scr (car ,store) (cdr ,store)))
+(make-obsolete-generalized-variable
+ 'read-mouse-position 'set-mouse-position "29.1")
+
 (gv-define-simple-setter screen-height set-screen-height t)
+(make-obsolete-generalized-variable 'screen-height 'set-screen-height "29.1")
+
 (gv-define-simple-setter screen-width set-screen-width t)
+(make-obsolete-generalized-variable 'screen-width 'set-screen-width "29.1")
+
 (gv-define-simple-setter selected-window select-window)
+(make-obsolete-generalized-variable 'selected-window 'select-window "29.1")
+
 (gv-define-simple-setter selected-screen select-screen)
+(make-obsolete-generalized-variable 'selected-screen 'select-screen "29.1")
+
 (gv-define-simple-setter selected-frame select-frame)
+(make-obsolete-generalized-variable 'selected-frame 'select-frame "29.1")
+
 (gv-define-simple-setter standard-case-table set-standard-case-table)
+(make-obsolete-generalized-variable
+ 'standard-case-table 'set-standard-case-table "29.1")
+
 (gv-define-simple-setter syntax-table set-syntax-table)
+(make-obsolete-generalized-variable 'syntax-table 'set-syntax-table "29.1")
+
 (gv-define-simple-setter visited-file-modtime set-visited-file-modtime t)
+(make-obsolete-generalized-variable
+ 'visited-file-modtime 'set-visited-file-modtime "29.1")
+
 (gv-define-setter window-height (store)
   `(progn (enlarge-window (- ,store (window-height))) ,store))
+(make-obsolete-generalized-variable 'window-height 'enlarge-window "29.1")
+
 (gv-define-setter window-width (store)
   `(progn (enlarge-window (- ,store (window-width)) t) ,store))
+(make-obsolete-generalized-variable 'window-width 'enlarge-window "29.1")
+
 (gv-define-simple-setter x-get-secondary-selection x-own-secondary-selection t)
+(make-obsolete-generalized-variable
+ 'x-get-secondary-selection 'x-own-secondary-selection "29.1")
+
 
 ;; More complex setf-methods.
 
diff --git a/lisp/emacs-lisp/helper.el b/lisp/emacs-lisp/helper.el
index 930dbfe6c4..10bb297325 100644
--- a/lisp/emacs-lisp/helper.el
+++ b/lisp/emacs-lisp/helper.el
@@ -1,6 +1,6 @@
 ;;; helper.el --- utility help package supporting help in electric modes  -*- 
lexical-binding: t; -*-
 
-;; Copyright (C) 1985, 2001-2022 Free Software Foundation, Inc.
+;; Copyright (C) 1985-2022 Free Software Foundation, Inc.
 
 ;; Author: K. Shane Hartman
 ;; Maintainer: emacs-devel@gnu.org
@@ -39,19 +39,16 @@
 ;; keymap either.
 
 
-(defvar Helper-help-map
-  (let ((map (make-sparse-keymap)))
-  ;(fillarray map 'undefined)
-  (define-key map "m" 'Helper-describe-mode)
-  (define-key map "b" 'Helper-describe-bindings)
-  (define-key map "c" 'Helper-describe-key-briefly)
-  (define-key map "k" 'Helper-describe-key)
-  ;(define-key map "f" 'Helper-describe-function)
-  ;(define-key map "v" 'Helper-describe-variable)
-  (define-key map "?" 'Helper-help-options)
-  (define-key map (char-to-string help-char) 'Helper-help-options)
-  (fset 'Helper-help-map map)
-  map))
+(defvar-keymap Helper-help-map
+  "m" #'Helper-describe-mode
+  "b" #'Helper-describe-bindings
+  "c" #'Helper-describe-key-briefly
+  "k" #'Helper-describe-key
+  ;;"f" #'Helper-describe-function
+  ;;"v" #'Helper-describe-variable
+  "?" #'Helper-help-options
+  (key-description (char-to-string help-char)) #'Helper-help-options)
+(fset 'Helper-help-map Helper-help-map)
 
 (defun Helper-help-scroller ()
   (let ((blurb (or (and (boundp 'Helper-return-blurb)
@@ -68,26 +65,30 @@
          (setq state (+ (* 2 (if (pos-visible-in-window-p (point-max)) 1 0))
                         (if (pos-visible-in-window-p (point-min)) 1 0)))
          (message
-           (nth state
-                '("Space forward, Delete back. Other keys %s"
-                  "Space scrolls forward. Other keys %s"
-                  "Delete scrolls back. Other keys %s"
-                  "Type anything to %s"))
+            (nth state
+                 (mapcar
+                  #'substitute-command-keys
+                  '("\\`SPC' forward, \\`DEL' back.  Other keys %s"
+                    "\\`SPC' scrolls forward.  Other keys %s"
+                    "\\`DEL' scrolls back.  Other keys %s"
+                    "Type anything to %s")))
            blurb)
          (setq continue (read-event))
          (cond ((and (memq continue '(?\s ?\C-v)) (< state 2))
                 (scroll-up))
-               ((= continue ?\C-l)
+                ((eq continue ?\C-l)
                 (recenter))
-               ((and (= continue ?\177) (zerop (% state 2)))
+                ((and (or (eq continue 'backspace)
+                          (eq continue ?\177))
+                      (zerop (% state 2)))
                 (scroll-down))
                (t (setq continue nil))))))))
 
 (defun Helper-help-options ()
   "Describe help options."
   (interactive)
-  (message "c (key briefly), m (mode), k (key), b (bindings)")
-  ;(message "c (key briefly), m (mode), k (key), v (variable), f (function)")
+  (message (substitute-command-keys
+            "\\`c' (key briefly), \\`m' (mode), \\`k' (key), \\`b' 
(bindings)"))
   (sit-for 4))
 
 (defun Helper-describe-key-briefly (key)
@@ -130,7 +131,6 @@
 (defun Helper-describe-bindings ()
   "Describe local key bindings of current mode."
   (interactive)
-  (message "Making binding list...")
   (save-window-excursion (describe-bindings))
   (Helper-help-scroller))
 
@@ -140,7 +140,8 @@
   (interactive)
   (let ((continue t) c)
     (while continue
-      (message "Help (Type ? for further options)")
+      (message (substitute-command-keys
+                "Help (Type \\`?' for further options)"))
       (setq c (read-key-sequence nil))
       (setq c (lookup-key Helper-help-map c))
       (cond ((eq c 'Helper-help-options)
diff --git a/lisp/emacs-lisp/icons.el b/lisp/emacs-lisp/icons.el
new file mode 100644
index 0000000000..93749a3451
--- /dev/null
+++ b/lisp/emacs-lisp/icons.el
@@ -0,0 +1,267 @@
+;;; icons.el --- Handling icons  -*- lexical-binding:t -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+
+;; Author: Lars Ingebrigtsen <larsi@gnus.org>
+;; Keywords: icons buttons
+
+;; 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 'cl-lib)
+
+(defface icon
+  '((t :underline nil))
+  "Face for buttons."
+  :version "29.1"
+  :group 'customize)
+
+(defface icon-button
+  '((((type x w32 ns haiku pgtk) (class color))
+     :inherit icon
+     :box (:line-width (3 . -1) :color "#404040" :style flat-button)
+     :background "#808080"
+     :foreground "black"))
+  "Face for buttons."
+  :version "29.1"
+  :group 'customize)
+
+(defcustom icon-preference '(image emoji symbol text)
+  "List of icon types to use, in order of preference.
+Emacs will choose the icon of the highest preference possible
+on the current display, and \"degrade\" gracefully to an icon
+type that's available."
+  :version "29.1"
+  :group 'customize
+  :type '(repeat (choice (const :tag "Images" image)
+                         (const :tag "Colorful Emojis" emoji)
+                         (const :tag "Monochrome Symbols" symbol)
+                         (const :tag "Text Only" text))))
+
+(defmacro define-icon (name parent specification documentation &rest keywords)
+  "Define an icon identified by NAME.
+If non-nil, inherit the specification from PARENT.  Entries from
+SPECIFICATION will override inherited specifications.
+
+SPECIFICATION is an alist of entries where the first element is
+the type, and the rest are icons of that type.  Valid types are
+`image', `emoji', `symbol' and `text'.
+
+KEYWORDS specify additional information.  Valid keywords are:
+
+`:version': The first Emacs version to include this icon; this is
+mandatory.
+
+`:group': The customization group the icon belongs in; this is
+inferred if not present.
+
+`:help-echo': Informational text that explains what happens if
+the icon is used as a button and you click it."
+  (declare (indent 2))
+  (unless (symbolp name)
+    (error "NAME must be a symbol: %S" name))
+  (unless (plist-get keywords :version)
+    (error "There must be a :version keyword in `define-icon'"))
+  `(icons--register ',name ',parent ,specification ,documentation
+                    ',keywords))
+
+(defun icons--register (name parent spec doc keywords)
+  (put name 'icon--properties (list parent spec doc keywords))
+  (custom-add-to-group
+   (or (plist-get keywords :group)
+       (custom-current-group))
+   name 'custom-icon))
+
+(defun icon-spec-keywords (spec)
+  (seq-drop-while (lambda (e) (not (keywordp e))) (cdr spec)))
+
+(defun icon-spec-values (spec)
+  (seq-take-while (lambda (e) (not (keywordp e))) (cdr spec)))
+
+(defun iconp (object)
+  "Return nil if OBJECT is not an icon.
+If OBJECT is an icon, return the icon properties."
+  (get object 'icon--properties))
+
+(defun icon-documentation (icon)
+  "Return the documentation for ICON."
+  (let ((props (iconp icon)))
+    (unless props
+      (user-error "%s is not a valid icon" icon))
+    (nth 2 props)))
+
+(defun icons--spec (icon)
+  (nth 1 (iconp icon)))
+
+(defun icons--copy-spec (spec)
+  (mapcar #'copy-sequence spec))
+
+(defun icon-complete-spec (icon &optional inhibit-theme inhibit-inheritance)
+  "Return the merged spec for ICON."
+  (pcase-let ((`(,parent ,spec _ _) (iconp icon)))
+    ;; We destructively modify `spec' when merging, so copy it.
+    (setq spec (icons--copy-spec spec))
+    ;; Let the Customize theme override.
+    (unless inhibit-theme
+      (when-let ((theme-spec (cadr (car (get icon 'theme-icon)))))
+        (setq spec (icons--merge-spec (icons--copy-spec theme-spec) spec))))
+    ;; Inherit from the parent spec (recursively).
+    (unless inhibit-inheritance
+      (while parent
+        (let ((parent-props (get parent 'icon--properties)))
+          (when parent-props
+            (setq spec (icons--merge-spec spec (cadr parent-props))))
+          (setq parent (car parent-props)))))
+    spec))
+
+(defun icon-string (name)
+  "Return a string suitable for display in the current buffer for icon NAME."
+  (let ((props (iconp name)))
+    (unless props
+      (user-error "%s is not a valid icon" name))
+    (pcase-let ((`(_ ,spec _ ,keywords) props))
+      (setq spec (icon-complete-spec name))
+      ;; We now have a full spec, so check the intersection of what
+      ;; the user wants and what this Emacs is capable of showing.
+      (let ((icon-string
+             (catch 'found
+               (dolist (type icon-preference)
+                 (let* ((type-spec (assq type spec))
+                        ;; Find the keywords at the end of the section
+                        ;; (if any).
+                        (type-keywords (icon-spec-keywords type-spec)))
+                   ;; Go through all the variations in this section
+                   ;; and return the first one we can display.
+                   (dolist (icon (icon-spec-values type-spec))
+                     (when-let ((result
+                                 (icons--create type icon type-keywords)))
+                       (throw 'found
+                              (if-let ((face (plist-get type-keywords :face)))
+                                  (propertize result 'face face)
+                                result)))))))))
+        (unless icon-string
+          (error "Couldn't find any way to display the %s icon" name))
+        (when-let ((help (plist-get keywords :help-echo)))
+          (setq icon-string (propertize icon-string 'help-echo help)))
+        (propertize icon-string 'rear-nonsticky t)))))
+
+(defun icon-elements (name)
+  "Return the elements of icon NAME.
+The elements are represented as a plist where the keys are
+`string', `face' and `display'.  The `image' element is only
+present if the icon is represented by an image."
+  (let ((string (icon-string name)))
+    (list 'face (get-text-property 0 'face string)
+          'image (get-text-property 0 'display string)
+          'string (substring-no-properties string))))
+
+(defun icons--merge-spec (merged parent-spec)
+  (dolist (elem parent-spec)
+    (let ((current (assq (car elem) merged)))
+      (if (not current)
+          ;; Just add the entry.
+          (push elem merged)
+        ;; See if there are any keywords to inherit.
+        (let ((parent-keywords (icon-spec-keywords elem))
+              (current-keywords (icon-spec-keywords current)))
+          (while parent-keywords
+            (unless (plist-get (car parent-keywords) current-keywords)
+              (nconc current (take 2 parent-keywords))
+              (setq parent-keywords (cddr parent-keywords))))))))
+  merged)
+
+(cl-defmethod icons--create ((_type (eql 'image)) icon keywords)
+  (let ((file (if (file-name-absolute-p icon)
+                  icon
+                (and (fboundp 'image-search-load-path)
+                     (image-search-load-path icon)))))
+    (and (display-images-p)
+         (fboundp 'image-supported-file-p)
+         (image-supported-file-p file)
+         (propertize
+          " " 'display
+          (if-let ((height (plist-get keywords :height)))
+              (create-image file
+                            nil nil
+                            :height (if (eq height 'line)
+                                        (window-default-line-height)
+                                      height)
+                            :scale 1)
+            (create-image file))))))
+
+(cl-defmethod icons--create ((_type (eql 'emoji)) icon _keywords)
+  (when-let ((font (and (display-multi-font-p)
+                        ;; FIXME: This is not enough for ensuring
+                        ;; display of color Emoji.
+                        (car (internal-char-font nil ?🟠)))))
+    (and (font-has-char-p font (aref icon 0))
+         icon)))
+
+(cl-defmethod icons--create ((_type (eql 'symbol)) icon _keywords)
+  (and (cl-every #'char-displayable-p icon)
+       icon))
+
+(cl-defmethod icons--create ((_type (eql 'text)) icon _keywords)
+  icon)
+
+(define-icon button nil
+  '((image :face icon-button)
+    (emoji "🔵" :face icon)
+    (symbol "●" :face icon-button)
+    (text "button" :face icon-button))
+  "Base icon for buttons."
+  :version "29.1")
+
+;;;###autoload
+(defun describe-icon (icon)
+  "Pop to a buffer to describe ICON."
+  (interactive
+   (list (intern (completing-read "Describe icon: " obarray 'iconp t))))
+  (let ((help-buffer-under-preparation t))
+    (help-setup-xref (list #'describe-icon icon)
+                    (called-interactively-p 'interactive))
+    (with-help-window (help-buffer)
+      (with-current-buffer standard-output
+        (insert "Icon: " (symbol-name icon) "\n\n")
+        (insert "Documentation:\n"
+                (substitute-command-keys (icon-documentation icon)))
+        (ensure-empty-lines)
+        (let ((spec (icon-complete-spec icon))
+              (plain (icon-complete-spec icon t t)))
+          (insert "Specification including inheritance and theming:\n")
+          (icons--describe-spec spec)
+          (unless (equal spec plain)
+            (insert "\nSpecification not including inheritance and theming:\n")
+            (icons--describe-spec plain)))))))
+
+(defun icons--describe-spec (spec)
+  (dolist (elem spec)
+    (let ((type (car elem))
+          (values (icon-spec-values elem))
+          (keywords (icon-spec-keywords elem)))
+      (when (or values keywords)
+        (insert (format "\nType: %s\n" type))
+        (dolist (value values)
+          (insert (format "  %s\n" value)))
+        (while keywords
+          (insert (format "    %s: %s\n" (pop keywords) (pop keywords))))))))
+
+(provide 'icons)
+
+;;; icons.el ends here
diff --git a/lisp/emacs-lisp/lisp-mode.el b/lisp/emacs-lisp/lisp-mode.el
index aaec13d1af..c906ee6e31 100644
--- a/lisp/emacs-lisp/lisp-mode.el
+++ b/lisp/emacs-lisp/lisp-mode.el
@@ -89,78 +89,78 @@
     table)
   "Syntax table used in `lisp-mode'.")
 
+(rx-define lisp-mode-symbol (+ (| (syntax word)
+                                  (syntax symbol)
+                                  (: "\\" nonl))))
+
 (eval-and-compile
-  (defconst lisp-mode-symbol-regexp "\\(?:\\sw\\|\\s_\\|\\\\.\\)+"))
+  (defconst lisp-mode-symbol-regexp (rx lisp-mode-symbol)))
 
 (defvar lisp-imenu-generic-expression
   (list
    (list nil
         (purecopy (concat "^\\s-*("
-                          (eval-when-compile
-                            (regexp-opt
-                             '("defun" "defmacro"
-                                ;; Elisp.
-                                "defun*" "defsubst" "define-inline"
-                               "define-advice" "defadvice" "define-skeleton"
-                               "define-compilation-mode" "define-minor-mode"
-                               "define-global-minor-mode"
-                               "define-globalized-minor-mode"
-                               "define-derived-mode" "define-generic-mode"
-                               "ert-deftest"
-                               "cl-defun" "cl-defsubst" "cl-defmacro"
-                               "cl-define-compiler-macro" "cl-defgeneric"
-                               "cl-defmethod"
-                                ;; CL.
-                               "define-compiler-macro" "define-modify-macro"
-                               "defsetf" "define-setf-expander"
-                               "define-method-combination"
-                                ;; CLOS and EIEIO
-                               "defgeneric" "defmethod")
-                              t))
-                          "\\s-+\\(" lisp-mode-symbol-regexp "\\)"))
+                          (regexp-opt
+                           '("defun" "defmacro"
+                              ;; Elisp.
+                              "defun*" "defsubst" "define-inline"
+                             "define-advice" "defadvice" "define-skeleton"
+                             "define-compilation-mode" "define-minor-mode"
+                             "define-global-minor-mode"
+                             "define-globalized-minor-mode"
+                             "define-derived-mode" "define-generic-mode"
+                             "ert-deftest"
+                             "cl-defun" "cl-defsubst" "cl-defmacro"
+                             "cl-define-compiler-macro" "cl-defgeneric"
+                             "cl-defmethod"
+                              ;; CL.
+                             "define-compiler-macro" "define-modify-macro"
+                             "defsetf" "define-setf-expander"
+                             "define-method-combination"
+                              ;; CLOS and EIEIO
+                             "defgeneric" "defmethod")
+                            t)
+                          "\\s-+\\(" (rx lisp-mode-symbol) "\\)"))
         2)
    ;; Like the previous, but uses a quoted symbol as the name.
    (list nil
         (purecopy (concat "^\\s-*("
-                          (eval-when-compile
-                            (regexp-opt
-                             '("defalias" "define-obsolete-function-alias")
-                              t))
-                          "\\s-+'\\(" lisp-mode-symbol-regexp "\\)"))
+                          (regexp-opt
+                           '("defalias" "define-obsolete-function-alias")
+                            t)
+                          "\\s-+'\\(" (rx lisp-mode-symbol) "\\)"))
         2)
    (list (purecopy "Variables")
         (purecopy (concat "^\\s-*("
-                          (eval-when-compile
-                            (regexp-opt
-                             '(;; Elisp
-                                "defconst" "defcustom"
-                                ;; CL
-                                "defconstant"
-                               "defparameter" "define-symbol-macro")
-                              t))
-                          "\\s-+\\(" lisp-mode-symbol-regexp "\\)"))
+                          (regexp-opt
+                           '(;; Elisp
+                              "defconst" "defcustom"
+                              ;; CL
+                              "defconstant"
+                             "defparameter" "define-symbol-macro")
+                            t)
+                          "\\s-+\\(" (rx lisp-mode-symbol) "\\)"))
         2)
    ;; For `defvar'/`defvar-local', we ignore (defvar FOO) constructs.
    (list (purecopy "Variables")
         (purecopy (concat "^\\s-*(defvar\\(?:-local\\)?\\s-+\\("
-                           lisp-mode-symbol-regexp "\\)"
+                           (rx lisp-mode-symbol) "\\)"
                           "[[:space:]\n]+[^)]"))
         1)
    (list (purecopy "Types")
         (purecopy (concat "^\\s-*("
-                          (eval-when-compile
-                            (regexp-opt
-                             '(;; Elisp
-                                "defgroup" "deftheme"
-                                "define-widget" "define-error"
-                               "defface" "cl-deftype" "cl-defstruct"
-                                ;; CL
-                                "deftype" "defstruct"
-                               "define-condition" "defpackage"
-                                ;; CLOS and EIEIO
-                                "defclass")
-                              t))
-                          "\\s-+'?\\(" lisp-mode-symbol-regexp "\\)"))
+                          (regexp-opt
+                           '(;; Elisp
+                              "defgroup" "deftheme"
+                              "define-widget" "define-error"
+                             "defface" "cl-deftype" "cl-defstruct"
+                              ;; CL
+                              "deftype" "defstruct"
+                             "define-condition" "defpackage"
+                              ;; CLOS and EIEIO
+                              "defclass")
+                            t)
+                          "\\s-+'?\\(" (rx lisp-mode-symbol) "\\)"))
         2))
 
   "Imenu generic expression for Lisp mode.  See `imenu-generic-expression'.")
@@ -269,8 +269,7 @@ to a package-local <package>-loaddefs.el file.")
   ;; FIXME: Move to elisp-mode.el.
   (catch 'found
     (while (re-search-forward
-            (eval-when-compile
-              (concat "(\\(" lisp-mode-symbol-regexp "\\)\\_>"))
+            (concat "(\\(" (rx lisp-mode-symbol) "\\)\\_>")
             limit t)
       (let ((sym (intern-soft (match-string 1))))
        (when (and (or (special-form-p sym) (macrop sym))
@@ -419,8 +418,8 @@ This will generate compile-time constants from BINDINGS."
                   ;; Any whitespace and defined object.
                   "[ \t']*"
                   "\\(([ \t']*\\)?" ;; An opening paren.
-                  "\\(\\(setf\\)[ \t]+" lisp-mode-symbol-regexp
-                  "\\|" lisp-mode-symbol-regexp "\\)?")
+                  "\\(\\(setf\\)[ \t]+" (rx lisp-mode-symbol)
+                  "\\|" (rx lisp-mode-symbol) "\\)?")
           (1 font-lock-keyword-face)
           (3 (let ((type (get (intern-soft (match-string 1)) 
'lisp-define-type)))
                (cond ((eq type 'var) font-lock-variable-name-face)
@@ -446,8 +445,8 @@ This will generate compile-time constants from BINDINGS."
                   ;; Any whitespace and defined object.
                   "[ \t']*"
                   "\\(([ \t']*\\)?" ;; An opening paren.
-                  "\\(\\(setf\\)[ \t]+" lisp-mode-symbol-regexp
-                  "\\|" lisp-mode-symbol-regexp "\\)?")
+                  "\\(\\(setf\\)[ \t]+" (rx lisp-mode-symbol)
+                  "\\|" (rx lisp-mode-symbol) "\\)?")
           (1 font-lock-keyword-face)
           (3 (let ((type (get (intern-soft (match-string 1)) 
'lisp-define-type)))
                (cond ((eq type 'var) font-lock-variable-name-face)
@@ -473,26 +472,34 @@ This will generate compile-time constants from BINDINGS."
          (lisp--el-match-keyword . 1)
          ;; Exit/Feature symbols as constants.
          (,(concat "(\\(catch\\|throw\\|featurep\\|provide\\|require\\)\\_>"
-                   "[ \t']*\\(" lisp-mode-symbol-regexp "\\)?")
+                   "[ \t']*\\(" (rx lisp-mode-symbol) "\\)?")
            (1 font-lock-keyword-face)
            (2 font-lock-constant-face nil t))
-         ;; Words inside \\[] tend to be for `substitute-command-keys'.
-         (,(concat "\\\\\\\\\\[\\(" lisp-mode-symbol-regexp "\\)\\]")
+         ;; Words inside \\[], \\<>, \\{} or \\`' tend to be for
+         ;; `substitute-command-keys'.
+         (,(rx "\\\\" (or (seq "[" (group-n 1 lisp-mode-symbol) "]")
+                          (seq "`" (group-n 1
+                                     ;; allow multiple words, e.g. "C-x a"
+                                     lisp-mode-symbol (* " " lisp-mode-symbol))
+                               "'")))
           (1 font-lock-constant-face prepend))
+         (,(rx "\\\\" (or (seq "<" (group-n 1 lisp-mode-symbol) ">")
+                          (seq "{" (group-n 1 lisp-mode-symbol) "}")))
+          (1 font-lock-variable-name-face prepend))
          ;; Ineffective backslashes (typically in need of doubling).
          ("\\(\\\\\\)\\([^\"\\]\\)"
           (1 (elisp--font-lock-backslash) prepend))
          ;; Words inside ‘’, '' and `' tend to be symbol names.
-         (,(concat "[`‘']\\(" lisp-mode-symbol-regexp "\\)['’]")
+         (,(concat "[`‘']\\(" (rx lisp-mode-symbol) "\\)['’]")
           (1 font-lock-constant-face prepend))
          ;; \\= tends to be an escape in doc strings.
-         ("\\\\\\\\="
+         (,(rx "\\\\=")
           (0 font-lock-builtin-face prepend))
          ;; Constant values.
-         (,(concat "\\_<:" lisp-mode-symbol-regexp "\\_>")
+         (,(concat "\\_<:" (rx lisp-mode-symbol) "\\_>")
           (0 font-lock-builtin-face))
          ;; ELisp and CLisp `&' keywords as types.
-         (,(concat "\\_<&" lisp-mode-symbol-regexp "\\_>")
+         (,(concat "\\_<&" (rx lisp-mode-symbol) "\\_>")
           . font-lock-type-face)
          ;; ELisp regexp grouping constructs
          (,(lambda (bound)
@@ -529,30 +536,30 @@ This will generate compile-time constants from BINDINGS."
          (,(concat "(" cl-kws-re "\\_>") . 1)
          ;; Exit/Feature symbols as constants.
          (,(concat "(\\(catch\\|throw\\|provide\\|require\\)\\_>"
-                   "[ \t']*\\(" lisp-mode-symbol-regexp "\\)?")
+                   "[ \t']*\\(" (rx lisp-mode-symbol) "\\)?")
            (1 font-lock-keyword-face)
            (2 font-lock-constant-face nil t))
          ;; Erroneous structures.
          (,(concat "(" cl-errs-re "\\_>")
            (1 font-lock-warning-face))
          ;; Words inside ‘’ and `' tend to be symbol names.
-         (,(concat "[`‘]\\(" lisp-mode-symbol-regexp "\\)['’]")
+         (,(concat "[`‘]\\(" (rx lisp-mode-symbol) "\\)['’]")
           (1 font-lock-constant-face prepend))
          ;; Uninterned symbols, e.g., (defpackage #:my-package ...)
          ;; must come before keywords below to have effect
-         (,(concat "#:" lisp-mode-symbol-regexp "") 0 font-lock-builtin-face)
+         (,(concat "#:" (rx lisp-mode-symbol) "") 0 font-lock-builtin-face)
          ;; Constant values.
-         (,(concat "\\_<:" lisp-mode-symbol-regexp "\\_>")
+         (,(concat "\\_<:" (rx lisp-mode-symbol) "\\_>")
           (0 font-lock-builtin-face))
          ;; ELisp and CLisp `&' keywords as types.
-         (,(concat "\\_<&" lisp-mode-symbol-regexp "\\_>")
+         (,(concat "\\_<&" (rx lisp-mode-symbol) "\\_>")
           . font-lock-type-face)
          ;; This is too general -- rms.
          ;; A user complained that he has functions whose names start with `do'
          ;; and that they get the wrong color.
          ;; That user has violated the 
https://www.cliki.net/Naming+conventions:
          ;; CL (but not EL!) `with-' (context) and `do-' (iteration)
-         (,(concat "(\\(\\(do-\\|with-\\)" lisp-mode-symbol-regexp "\\)")
+         (,(concat "(\\(\\(do-\\|with-\\)" (rx lisp-mode-symbol) "\\)")
            (1 font-lock-keyword-face))
          (lisp--match-hidden-arg
           (0 '(face font-lock-warning-face
@@ -579,16 +586,15 @@ This will generate compile-time constants from BINDINGS."
   "Gaudy highlighting from Emacs Lisp mode used in Backtrace mode.")
 
 (defun lisp-string-in-doc-position-p (listbeg startpos)
-   "Return non-nil if a doc string may occur at STARTPOS inside a list.
+  "Return non-nil if a doc string may occur at STARTPOS inside a list.
 LISTBEG is the position of the start of the innermost list
 containing STARTPOS."
   (let* ((firstsym (and listbeg
                         (save-excursion
                           (goto-char listbeg)
                           (and (looking-at
-                                (eval-when-compile
-                                  (concat "([ \t\n]*\\("
-                                          lisp-mode-symbol-regexp "\\)")))
+                                (concat "([ \t\n]*\\("
+                                        (rx lisp-mode-symbol) "\\)"))
                                (match-string 1)))))
          (docelt (and firstsym
                       (function-get (intern-soft firstsym)
@@ -747,17 +753,16 @@ font-lock keywords will not be case sensitive."
                                        (progn (forward-sexp 1)
                                               (point)))))))
 
-(defvar lisp-mode-shared-map
-  (let ((map (make-sparse-keymap)))
-    (set-keymap-parent map prog-mode-map)
-    (define-key map "\e\C-q" 'indent-sexp)
-    (define-key map "\177" 'backward-delete-char-untabify)
-    ;; This gets in the way when viewing a Lisp file in view-mode.  As
-    ;; long as [backspace] is mapped into DEL via the
-    ;; function-key-map, this should remain disabled!!
-    ;;;(define-key map [backspace] 'backward-delete-char-untabify)
-    map)
-  "Keymap for commands shared by all sorts of Lisp modes.")
+(defvar-keymap lisp-mode-shared-map
+  :doc "Keymap for commands shared by all sorts of Lisp modes."
+  :parent prog-mode-map
+  "C-M-q" #'indent-sexp
+  "DEL"   #'backward-delete-char-untabify
+  ;; This gets in the way when viewing a Lisp file in view-mode.  As
+  ;; long as [backspace] is mapped into DEL via the
+  ;; function-key-map, this should remain disabled!!
+  ;;;"<backspace>" #'backward-delete-char-untabify
+  )
 
 (defcustom lisp-mode-hook nil
   "Hook run when entering Lisp mode."
@@ -773,14 +778,12 @@ font-lock keywords will not be case sensitive."
 
 ;;; Generic Lisp mode.
 
-(defvar lisp-mode-map
-  (let ((map (make-sparse-keymap)))
-    (set-keymap-parent map lisp-mode-shared-map)
-    (define-key map "\e\C-x" 'lisp-eval-defun)
-    (define-key map "\C-c\C-z" 'run-lisp)
-    map)
-  "Keymap for ordinary Lisp mode.
-All commands in `lisp-mode-shared-map' are inherited by this map.")
+(defvar-keymap lisp-mode-map
+  :doc "Keymap for ordinary Lisp mode.
+All commands in `lisp-mode-shared-map' are inherited by this map."
+  :parent lisp-mode-shared-map
+  "C-M-x"   #'lisp-eval-defun
+  "C-c C-z" #'run-lisp)
 
 (easy-menu-define lisp-mode-menu lisp-mode-map
   "Menu for ordinary Lisp mode."
@@ -835,9 +838,8 @@ or to switch back to an existing one."
 (defcustom lisp-indent-offset nil
   "If non-nil, indent second line of expressions that many more columns."
   :group 'lisp
-  :type '(choice (const nil) integer))
-(put 'lisp-indent-offset 'safe-local-variable
-     (lambda (x) (or (null x) (integerp x))))
+  :type '(choice (const nil) integer)
+  :safe (lambda (x) (or (null x) (integerp x))))
 
 (defcustom lisp-indent-function 'lisp-indent-function
   "A function to be called by `calculate-lisp-indent'.
@@ -1249,8 +1251,8 @@ Lisp function does not specify a special indentation."
 (defcustom lisp-body-indent 2
   "Number of columns to indent the second line of a `(def...)' form."
   :group 'lisp
-  :type 'integer)
-(put 'lisp-body-indent 'safe-local-variable 'integerp)
+  :type 'integer
+  :safe #'integerp)
 
 (defun lisp-indent-specform (count state indent-point normal-indent)
   (let ((containing-form-start (elt state 1))
@@ -1411,9 +1413,8 @@ Any non-integer value means do not use a different value 
of
 `fill-column' when filling docstrings."
   :type '(choice (integer)
                  (const :tag "Use the current `fill-column'" t))
+  :safe (lambda (x) (or (eq x t) (integerp x)))
   :group 'lisp)
-(put 'emacs-lisp-docstring-fill-column 'safe-local-variable
-     (lambda (x) (or (eq x t) (integerp x))))
 
 (defun lisp-fill-paragraph (&optional justify)
   "Like \\[fill-paragraph], but handle Emacs Lisp comments and docstrings.
@@ -1426,6 +1427,9 @@ and initial semicolons."
       ;; a comment: Point is on a program line; we are interested
       ;; particularly in docstring lines.
       ;;
+      ;; FIXME: The below bindings are probably mostly irrelevant
+      ;; since we're now narrowing to a region before filling.
+      ;;
       ;; We bind `paragraph-start' and `paragraph-separate' temporarily.  They
       ;; are buffer-local, but we avoid changing them so that they can be set
       ;; to make `forward-paragraph' and friends do something the user wants.
@@ -1462,7 +1466,10 @@ and initial semicolons."
                              emacs-lisp-docstring-fill-column
                            fill-column)))
         (let ((ppss (syntax-ppss))
-              (start (point)))
+              (start (point))
+              ;; Avoid recursion if we're being called directly with
+              ;; `M-x lisp-fill-paragraph' in an `emacs-lisp-mode' buffer.
+              (fill-paragraph-function t))
           (save-excursion
             (save-restriction
               ;; If we're not inside a string, then do very basic
@@ -1481,10 +1488,19 @@ and initial semicolons."
                           (progn
                             (forward-sexp 1)
                             t))
-                    (narrow-to-region (ppss-comment-or-string-start ppss)
-                                      (point))))
+                    (narrow-to-region (1+ (ppss-comment-or-string-start ppss))
+                                      (1- (point)))))
                 ;; Move back to where we were.
                 (goto-char start)
+                ;; We should fill the first line of a string
+                ;; separately (since it's usually a doc string).
+                (if (= (line-number-at-pos) 1)
+                    (narrow-to-region (line-beginning-position)
+                                      (line-beginning-position 2))
+                  (save-excursion
+                    (goto-char (point-min))
+                    (forward-line 1)
+                    (narrow-to-region (point) (point-max))))
                (fill-paragraph justify)))))))
   ;; Never return nil.
   t)
diff --git a/lisp/emacs-lisp/lisp.el b/lisp/emacs-lisp/lisp.el
index 641ce0d5c0..acae1a0b0a 100644
--- a/lisp/emacs-lisp/lisp.el
+++ b/lisp/emacs-lisp/lisp.el
@@ -507,6 +507,11 @@ It is called with no argument, right after calling 
`beginning-of-defun-raw'.
 So the function can assume that point is at the beginning of the defun body.
 It should move point to the first position after the defun.")
 
+(defvar end-of-defun-moves-to-eol t
+  "Whether `end-of-defun' moves to eol before doing anything else.
+Set this to nil if this movement adversely affects the buffer's
+major mode's decisions about context.")
+
 (defun buffer-end (arg)
   "Return the \"far end\" position of the buffer, in direction ARG.
 If ARG is positive, that's the end of the buffer.
@@ -538,7 +543,9 @@ report errors as appropriate for this kind of usage."
         (push-mark))
     (if (or (null arg) (= arg 0)) (setq arg 1))
     (let ((pos (point))
-          (beg (progn (end-of-line 1) (beginning-of-defun-raw 1) (point)))
+          (beg (progn (when end-of-defun-moves-to-eol
+                        (end-of-line 1))
+                      (beginning-of-defun-raw 1) (point)))
          (skip (lambda ()
                  ;; When comparing point against pos, we want to consider that
                  ;; if point was right after the end of the function, it's
@@ -943,14 +950,7 @@ character."
 (defun field-complete (table &optional predicate)
   (declare (obsolete completion-in-region "24.4"))
   (let ((minibuffer-completion-table table)
-        (minibuffer-completion-predicate predicate)
-        ;; This made sense for lisp-complete-symbol, but for
-        ;; field-complete, this is out of place.  --Stef
-        ;; (completion-annotate-function
-        ;;  (unless (eq predicate 'fboundp)
-        ;;    (lambda (str)
-        ;;      (if (fboundp (intern-soft str)) " <f>"))))
-        )
+        (minibuffer-completion-predicate predicate))
     (call-interactively 'minibuffer-complete)))
 
 (defun lisp-complete-symbol (&optional _predicate)
diff --git a/lisp/emacs-lisp/loaddefs-gen.el b/lisp/emacs-lisp/loaddefs-gen.el
index 95666ddb2a..e13b92bab8 100644
--- a/lisp/emacs-lisp/loaddefs-gen.el
+++ b/lisp/emacs-lisp/loaddefs-gen.el
@@ -50,17 +50,27 @@ prefix, that will not be registered.  But all other 
prefixes will
 be included.")
 (put 'autoload-compute-prefixes 'safe-local-variable #'booleanp)
 
+(defvar no-update-autoloads nil
+  "File local variable to prevent scanning this file for autoload cookies.")
+
 (defvar autoload-ignored-definitions
   '("define-obsolete-function-alias"
     "define-obsolete-variable-alias"
-    "define-category" "define-key"
+    "define-category"
+    "define-key" "define-key-after" "define-keymap"
     "defgroup" "defface" "defadvice"
     "def-edebug-spec"
     ;; Hmm... this is getting ugly:
     "define-widget"
     "define-erc-module"
     "define-erc-response-handler"
-    "defun-rcirc-command")
+    "defun-rcirc-command"
+    "define-short-documentation-group"
+    "def-edebug-elem-spec"
+    "defvar-mode-local"
+    "defcustom-mode-local-semantic-dependency-system-include-path"
+    "define-ibuffer-column"
+    "define-ibuffer-sorter")
   "List of strings naming definitions to ignore for prefixes.
 More specifically those definitions will not be considered for the
 `register-definition-prefixes' call.")
@@ -117,6 +127,15 @@ scanning for autoloads and will be in the `load-path'."
         (substring name 0 (match-beginning 0))
       name)))
 
+(defun loaddefs-generate--shorten-autoload (form)
+  "Remove optional nil elements from an `autoload' form."
+  (take (max (- (length form)
+                (seq-position (reverse form) nil
+                              (lambda (e1 e2)
+                                (not (eq e1 e2)))))
+             3)
+        form))
+
 (defun loaddefs-generate--make-autoload (form file &optional expansion)
   "Turn FORM into an autoload or defvar for source file FILE.
 Returns nil if FORM is not a special autoload form (i.e. a function definition
@@ -155,8 +174,8 @@ expression, in which case we want to handle forms 
differently."
         ;; Add the usage form at the end where describe-function-1
         ;; can recover it.
         (when (consp args) (setq doc (help-add-fundoc-usage doc args)))
-        ;; (message "autoload of %S" (nth 1 form))
-        `(autoload ,(nth 1 form) ,file ,doc ,interactive ,type)))
+        (loaddefs-generate--shorten-autoload
+         `(autoload ,(nth 1 form) ,file ,doc ,interactive ,type))))
 
      ((and expansion (memq car '(progn prog1)))
       (let ((end (memq :autoload-end form)))
@@ -174,7 +193,8 @@ expression, in which case we want to handle forms 
differently."
                        define-globalized-minor-mode defun defmacro
                       easy-mmode-define-minor-mode define-minor-mode
                        define-inline cl-defun cl-defmacro cl-defgeneric
-                       cl-defstruct pcase-defmacro))
+                       cl-defstruct pcase-defmacro iter-defun cl-iter-defun
+                       transient-define-prefix))
            (macrop car)
           (setq expand (let ((load-true-file-name file)
                               (load-file-name file))
@@ -209,22 +229,23 @@ expression, in which case we want to handle forms 
differently."
         ;; can recover it.
        (when (listp args) (setq doc (help-add-fundoc-usage doc args)))
         ;; `define-generic-mode' quotes the name, so take care of that
-        `(autoload ,(if (listp name) name (list 'quote name))
-           ,file ,doc
-           ,(or (and (memq car '(define-skeleton define-derived-mode
-                                  define-generic-mode
-                                  easy-mmode-define-global-mode
-                                  define-global-minor-mode
-                                  define-globalized-minor-mode
-                                  easy-mmode-define-minor-mode
-                                  define-minor-mode))
-                     t)
-                (and (eq (car-safe (car body)) 'interactive)
-                     ;; List of modes or just t.
-                     (or (if (nthcdr 1 (car body))
-                             (list 'quote (nthcdr 1 (car body)))
-                           t))))
-           ,(if macrop ''macro nil))))
+        (loaddefs-generate--shorten-autoload
+         `(autoload ,(if (listp name) name (list 'quote name))
+            ,file ,doc
+            ,(or (and (memq car '(define-skeleton define-derived-mode
+                                   define-generic-mode
+                                   easy-mmode-define-global-mode
+                                   define-global-minor-mode
+                                   define-globalized-minor-mode
+                                   easy-mmode-define-minor-mode
+                                   define-minor-mode))
+                      t)
+                 (and (eq (car-safe (car body)) 'interactive)
+                      ;; List of modes or just t.
+                      (or (if (nthcdr 1 (car body))
+                              (list 'quote (nthcdr 1 (car body)))
+                            t))))
+            ,(if macrop ''macro nil)))))
 
      ;; For defclass forms, use `eieio-defclass-autoload'.
      ((eq car 'defclass)
@@ -329,9 +350,9 @@ expression, in which case we want to handle forms 
differently."
                                                     'string<))))))
 
 (defun loaddefs-generate--parse-file (file main-outfile &optional package-data)
-  "Examing FILE for ;;;###autoload statements.
+  "Examining FILE for ;;;###autoload statements.
 MAIN-OUTFILE is the main loaddefs file these statements are
-destined for, but this can be overriden by the buffer-local
+destined for, but this can be overridden by the buffer-local
 setting of `generated-autoload-file' in FILE, and
 by ;;;###foo-autoload statements.
 
@@ -366,7 +387,11 @@ don't include."
 
       ;; We always return the package version (even for pre-dumped
       ;; files).
-      (when package-data
+      (if (not package-data)
+          ;; We have to switch `emacs-lisp-mode' when scanning
+          ;; loaddefs for packages so that `syntax-ppss' later gives
+          ;; correct results.
+          (emacs-lisp-mode)
         (let ((version (lm-header "version"))
               package)
           (when (and version
@@ -442,7 +467,7 @@ don't include."
   (let ((prefs nil))
     ;; Avoid (defvar <foo>) by requiring a trailing space.
     (while (re-search-forward
-            "^(\\(def[^ ]+\\) ['(]*\\([^' ()\"\n]+\\)[\n \t]" nil t)
+            "^(\\(def[^ \t\n]+\\)[ \t\n]+['(]*\\([^' ()\"\n]+\\)[\n \t]" nil t)
       (unless (member (match-string 1) autoload-ignored-definitions)
         (let ((name (match-string-no-properties 2)))
           (when (save-excursion
@@ -454,7 +479,7 @@ don't include."
             (push name prefs)))))
     (loaddefs-generate--make-prefixes prefs load-name)))
 
-(defun loaddefs-generate--rubric (file &optional type feature)
+(defun loaddefs-generate--rubric (file &optional type feature compile)
   "Return a string giving the appropriate autoload rubric for FILE.
 TYPE (default \"autoloads\") is a string stating the type of
 information contained in FILE.  TYPE \"package\" acts like the default,
@@ -462,7 +487,9 @@ but adds an extra line to the output to modify `load-path'.
 
 If FEATURE is non-nil, FILE will provide a feature.  FEATURE may
 be a string naming the feature, otherwise it will be based on
-FILE's name."
+FILE's name.
+
+If COMPILE, don't include a \"don't compile\" cookie."
   (let ((lp (and (equal type "package") (setq type "autoloads"))))
     (with-temp-buffer
       (generate-lisp-file-heading
@@ -476,30 +503,10 @@ FILE's name."
       (insert "\n;;; End of scraped data\n\n")
       (generate-lisp-file-trailer
        file :provide (and (stringp feature) feature)
+       :compile compile
        :inhibit-provide (not feature))
       (buffer-string))))
 
-(defun loaddefs-generate--insert-section-header (outbuf autoloads
-                                                        load-name file time)
-  "Insert into buffer OUTBUF the section-header line for FILE.
-The header line lists the file name, its \"load name\", its autoloads,
-and the time the FILE was last updated (the time is inserted only
-if `autoload-timestamps' is non-nil, otherwise a fixed fake time is inserted)."
-  (insert "\f\n;;;### ")
-  (prin1 `(autoloads ,autoloads ,load-name ,file ,time)
-        outbuf)
-  (terpri outbuf)
-  ;; Break that line at spaces, to avoid very long lines.
-  ;; Make each sub-line into a comment.
-  (with-current-buffer outbuf
-    (save-excursion
-      (forward-line -1)
-      (while (not (eolp))
-       (move-to-column 64)
-       (skip-chars-forward "^ \n")
-       (or (eolp)
-           (insert "\n" ";;;;;; "))))))
-
 ;;;###autoload
 (defun loaddefs-generate (dir output-file &optional excluded-files
                               extra-data include-package-version
@@ -512,15 +519,21 @@ binds `generated-autoload-file' as a file-local variable, 
write
 its autoloads into the specified file instead.
 
 The function does NOT recursively descend into subdirectories of the
-directory or directories specified.
+directory or directories specified by DIRS.
 
-If EXTRA-DATA, include this string at the start of the generated
-file.  This will also force generation of OUTPUT-FILE even if
-there are no autoloads to put into the file.
+Optional argument EXCLUDED-FILES, if non-nil, should be a list of
+files, such as preloaded files, whose autoloads should not be written
+to OUTPUT-FILE.
 
-If INCLUDE-PACKAGE-VERSION, include package version data.
+If EXTRA-DATA is non-nil, it should be a string; include that string
+at the beginning of the generated file.  This will also force the
+generation of OUTPUT-FILE even if there are no autoloads to put into
+that file.
 
-If GENERATE-FULL, don't update, but regenerate all the loaddefs files."
+If INCLUDE-PACKAGE-VERSION is non-nil, include package version data.
+
+If GENERATE-FULL is non-nil, regenerate all the loaddefs files anew,
+instead of just updating them with the new/changed autoloads."
   (let* ((files-re (let ((tmp nil))
                     (dolist (suf (get-load-suffixes))
                        ;; We don't use module-file-suffix below because
@@ -538,6 +551,11 @@ If GENERATE-FULL, don't update, but regenerate all the 
loaddefs files."
          (updating (and (file-exists-p output-file) (not generate-full)))
          (defs nil))
 
+    ;; Allow the excluded files to be relative.
+    (setq excluded-files
+          (mapcar (lambda (file) (expand-file-name file dir))
+                  excluded-files))
+
     ;; Collect all the autoload data.
     (let ((progress (make-progress-reporter
                      (byte-compile-info
@@ -552,16 +570,15 @@ If GENERATE-FULL, don't update, but regenerate all the 
loaddefs files."
                   (time-less-p output-time
                                (file-attribute-modification-time
                                 (file-attributes file))))
-          (setq defs (nconc
-                     (loaddefs-generate--parse-file
-                       file output-file
-                       ;; We only want the package name from the
-                       ;; excluded files.
-                       (and include-package-version
-                            (if (member (expand-file-name file) excluded-files)
-                                'only
-                              t)))
-                      defs))))
+          ;; If we're scanning for package versions, we want to look
+          ;; at the file even if it's excluded.
+          (let* ((excluded (member (expand-file-name file dir) excluded-files))
+                 (package-data
+                  (and include-package-version (if excluded 'only t))))
+            (when (or package-data (not excluded))
+              (setq defs (nconc (loaddefs-generate--parse-file
+                                 file output-file package-data)
+                                defs))))))
       (progress-reporter-done progress))
 
     ;; If we have no autoloads data, but we have EXTRA-DATA, then
@@ -576,15 +593,18 @@ If GENERATE-FULL, don't update, but regenerate all the 
loaddefs files."
       ;; We have some data, so generate the loaddef files.  First
       ;; group per output file.
       (dolist (fdefs (seq-group-by #'car defs))
-        (let ((loaddefs-file (car fdefs)))
+        (let ((loaddefs-file (car fdefs))
+              hash)
           (with-temp-buffer
             (if (and updating (file-exists-p loaddefs-file))
                 (insert-file-contents loaddefs-file)
-              (insert (loaddefs-generate--rubric loaddefs-file nil t))
+              (insert (loaddefs-generate--rubric
+                       loaddefs-file nil t include-package-version))
               (search-backward "\f")
               (when extra-data
                 (insert extra-data)
                 (ensure-empty-lines 1)))
+            (setq hash (buffer-hash))
             ;; Then group by source file (and sort alphabetically).
             (dolist (section (sort (seq-group-by #'cadr (cdr fdefs))
                                    (lambda (e1 e2)
@@ -621,21 +641,27 @@ If GENERATE-FULL, don't update, but regenerate all the 
loaddefs files."
                     (loaddefs-generate--print-form def))
                   (unless (bolp)
                     (insert "\n")))))
-            (write-region (point-min) (point-max) loaddefs-file nil 'silent)
-            (byte-compile-info (file-relative-name loaddefs-file 
lisp-directory)
-                               t "GEN")))))))
+            ;; Only write the file if we actually made a change.
+            (unless (equal (buffer-hash) hash)
+              (write-region (point-min) (point-max) loaddefs-file nil 'silent)
+              (byte-compile-info
+               (file-relative-name loaddefs-file (car (ensure-list dir)))
+               t "GEN"))))))))
 
 (defun loaddefs-generate--print-form (def)
-  "Print DEF in the way make-docfile.c expects it."
+  "Print DEF in a format that makes sense for version control."
   (if (or (not (consp def))
           (not (symbolp (car def)))
+          (memq (car def) '( make-obsolete
+                             define-obsolete-function-alias))
           (not (stringp (nth 3 def))))
       (prin1 def (current-buffer) t)
-    ;; The salient point here is that we have to have the doc string
-    ;; that starts with a backslash and a newline, and there mustn't
-    ;; be any newlines before that.  So -- typically
-    ;; (defvar foo 'value "\
-    ;; Doc string" ...).
+    ;; We want to print, for instance, `defvar' values while escaping
+    ;; control characters (so that we don't end up with lines with
+    ;; trailing tab characters and the like), but we don't want to do
+    ;; this for doc strings, because then the doc strings would be on
+    ;; one single line, which would lead to more VC churn.  So --
+    ;; typically (defvar foo 'value "\ Doc string" ...).
     (insert "(")
     (dotimes (_ 3)
       (prin1 (pop def) (current-buffer)
@@ -649,7 +675,9 @@ If GENERATE-FULL, don't update, but regenerate all the 
loaddefs files."
         (insert "\\\n")))
     (while def
       (insert " ")
-      (prin1 (pop def) (current-buffer) t))
+      (prin1 (pop def) (current-buffer)
+             '(t (escape-newlines . t)
+                 (escape-control-characters . t))))
     (insert ")")))
 
 (defun loaddefs-generate--excluded-files ()
diff --git a/lisp/emacs-lisp/macroexp.el b/lisp/emacs-lisp/macroexp.el
index bae303c213..c3ba1b36d4 100644
--- a/lisp/emacs-lisp/macroexp.el
+++ b/lisp/emacs-lisp/macroexp.el
@@ -187,13 +187,15 @@ It should normally be a symbol with position and it 
defaults to FORM."
                msg))
     form)))
 
-(defun macroexp--obsolete-warning (fun obsolescence-data type)
+(defun macroexp--obsolete-warning (fun obsolescence-data type &optional key)
   (let ((instead (car obsolescence-data))
         (asof (nth 2 obsolescence-data)))
     (format-message
      "`%s' is an obsolete %s%s%s" fun type
      (if asof (concat " (as of " asof ")") "")
      (cond ((stringp instead) (concat "; " (substitute-command-keys instead)))
+           ((and instead key)
+            (format-message "; use `%s' (%s) instead." instead key))
            (instead (format-message "; use `%s' instead." instead))
            (t ".")))))
 
@@ -369,6 +371,11 @@ Assumes the caller has bound 
`macroexpand-all-environment'."
                    (macroexp--all-forms body))
                  (cdr form))
                 form)))
+            (`(while)
+             (macroexp-warn-and-return
+              "missing `while' condition"
+              `(signal 'wrong-number-of-arguments '(while 0))
+              nil 'compile-only form))
             (`(setq ,(and var (pred symbolp)
                           (pred (not booleanp)) (pred (not keywordp)))
                     ,expr)
@@ -378,7 +385,7 @@ Assumes the caller has bound `macroexpand-all-environment'."
                    form
                  `(,fn ,var ,new-expr))))
             (`(setq . ,args)
-             ;; Normalise to a sequence of (setq SYM EXPR).
+             ;; Normalize to a sequence of (setq SYM EXPR).
              ;; Malformed code is translated to code that signals an error
              ;; at run time.
              (let ((nargs (length args)))
@@ -796,8 +803,8 @@ test of free variables in the following ways:
         (if (eq (car-safe (car bt)) 'macroexpand-all) (setq bt (cdr bt)))
         (if macroexp--debug-eager
             (debug 'eager-macroexp-cycle)
-          (message "Warning: Eager macro-expansion skipped due to cycle:\n  %s"
-                   (mapconcat #'prin1-to-string (nreverse bt) " => ")))
+          (error "Eager macro-expansion skipped due to cycle:\n  %s"
+                 (mapconcat #'prin1-to-string (nreverse bt) " => ")))
         (push 'skip macroexp--pending-eager-loads)
         form))
      (t
@@ -811,7 +818,7 @@ test of free variables in the following ways:
          ;; Hopefully this shouldn't happen thanks to the cycle detection,
          ;; but in case it does happen, let's catch the error and give the
          ;; code a chance to macro-expand later.
-         (message "Eager macro-expansion failure: %S" err)
+         (error "Eager macro-expansion failure: %S" err)
          form))))))
 
 ;; ¡¡¡ Big Ugly Hack !!!
@@ -823,7 +830,7 @@ test of free variables in the following ways:
 (eval-when-compile
   (add-hook 'emacs-startup-hook
             (lambda ()
-              (and (not (byte-code-function-p
+              (and (not (compiled-function-p
                          (symbol-function 'macroexpand-all)))
                    (locate-library "macroexp.elc")
                    (load "macroexp.elc")))))
diff --git a/lisp/emacs-lisp/nadvice.el b/lisp/emacs-lisp/nadvice.el
index 00c9e5438b..a9a20ab5ab 100644
--- a/lisp/emacs-lisp/nadvice.el
+++ b/lisp/emacs-lisp/nadvice.el
@@ -167,31 +167,31 @@ DOC is a string where \"FUNCTION\" and \"OLDFUN\" are 
expected.")
 
 (defun advice--interactive-form (function)
   "Like `interactive-form' but tries to avoid autoloading functions."
-  (when (commandp function)
-    (if (not (and (symbolp function) (autoloadp (indirect-function function))))
-        (interactive-form function)
+  (if (not (and (symbolp function) (autoloadp (indirect-function function))))
+      (interactive-form function)
+    (when (commandp function)
       `(interactive (advice-eval-interactive-spec
                      (cadr (interactive-form ',function)))))))
 
-(defun advice--make-interactive-form (function main)
+(defun advice--make-interactive-form (iff ifm)
   ;; TODO: make it so that interactive spec can be a constant which
   ;; dynamically checks the advice--car/cdr to do its job.
   ;; For that, advice-eval-interactive-spec needs to be more faithful.
-  (let* ((iff (advice--interactive-form function))
-         (ifm (advice--interactive-form main))
-         (fspec (cadr iff)))
+  (let* ((fspec (cadr iff)))
     (when (eq 'function (car-safe fspec)) ;; Macroexpanded lambda?
-      (setq fspec (nth 1 fspec)))
+      (setq fspec (eval fspec t)))
     (if (functionp fspec)
         `(funcall ',fspec ',(cadr ifm))
       (cadr (or iff ifm)))))
 
 
 (cl-defmethod oclosure-interactive-form ((ad advice) &optional _)
-  (let ((car (advice--car ad))
-        (cdr (advice--cdr ad)))
-    (when (or (commandp car) (commandp cdr))
-      `(interactive ,(advice--make-interactive-form car cdr)))))
+  (let* ((car (advice--car ad))
+         (cdr (advice--cdr ad))
+         (ifa (advice--interactive-form car))
+         (ifd (advice--interactive-form cdr)))
+    (when (or ifa ifd)
+      `(interactive ,(advice--make-interactive-form ifa ifd)))))
 
 (cl-defmethod cl-print-object ((object advice) stream)
   (cl-assert (advice--p object))
@@ -313,7 +313,7 @@ different, but `function-equal' will hopefully ignore those 
differences.")
 (defmacro add-function (how place function &optional props)
   ;; TODO:
   ;; - maybe let `how' specify some kind of predicate and use it
-  ;;   to implement things like mode-local or eieio-defmethod.
+  ;;   to implement things like mode-local or cl-defmethod.
   ;;   Of course, that only makes sense if the predicates of all advices can
   ;;   be combined and made more efficient.
   ;; :before is like a normal add-hook on a normal hook.
@@ -352,7 +352,7 @@ is also interactive.  There are 3 cases:
   (declare
    ;;(indent 2)
    (debug (form [&or symbolp ("local" form) ("var" sexp) gv-place]
-           form &optional form)))
+                form &optional form)))
   `(advice--add-function ,how (gv-ref ,(advice--normalize-place place))
                          ,function ,props))
 
diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
index 9aaeb052d0..ed23ee5f22 100644
--- a/lisp/emacs-lisp/package.el
+++ b/lisp/emacs-lisp/package.el
@@ -301,6 +301,7 @@ packages in `package-directory-list'."
   :type 'directory
   :initialize #'custom-initialize-delay
   :risky t
+  :group 'applications
   :version "24.1")
 
 ;;;###autoload
@@ -319,6 +320,7 @@ These directories contain packages intended for 
system-wide; in
 contrast, `package-user-dir' contains packages for personal use."
   :type '(repeat directory)
   :initialize #'custom-initialize-delay
+  :group 'applications
   :risky t
   :version "24.1")
 
@@ -355,10 +357,10 @@ More specifically the value can be:
 
 This also applies to the \"archive-contents\" file that lists the
 contents of the archive."
-  :type '(choice (const nil :tag "Never")
-                 (const allow-unsigned :tag "Allow unsigned")
-                 (const t :tag "Check always")
-                 (const all :tag "Check all signatures"))
+  :type '(choice (const :value nil            :tag "Never")
+                 (const :value allow-unsigned :tag "Allow unsigned")
+                 (const :value t              :tag "Check always")
+                 (const :value all            :tag "Check all signatures"))
   :risky t
   :version "27.1")
 
@@ -418,22 +420,22 @@ synchronously."
 
 (defcustom package-name-column-width 30
   "Column width for the Package name in the package menu."
-  :type 'number
+  :type 'natnum
   :version "28.1")
 
 (defcustom package-version-column-width 14
   "Column width for the Package version in the package menu."
-  :type 'number
+  :type 'natnum
   :version "28.1")
 
 (defcustom package-status-column-width 12
   "Column width for the Package status in the package menu."
-  :type 'number
+  :type 'natnum
   :version "28.1")
 
 (defcustom package-archive-column-width 8
   "Column width for the Package archive in the package menu."
-  :type 'number
+  :type 'natnum
   :version "28.1")
 
 
@@ -627,6 +629,7 @@ called via `package-activate-all'.  To change which 
packages are
 loaded and/or activated, customize `package-load-list'.")
 (put 'package-alist 'risky-local-variable t)
 
+;;;###autoload
 (defvar package-activated-list nil
   ;; FIXME: This should implicitly include all builtin packages.
   "List of the names of currently activated packages.")
@@ -720,8 +723,7 @@ REQUIREMENTS is a list of dependencies on other packages.
  where OTHER-VERSION is a string.
 
 EXTRA-PROPERTIES is currently unused."
-  (declare (indent defun))
-  ;; FIXME: Placeholder!  Should we keep it?
+  (declare (obsolete nil "29.1") (indent defun))
   (error "Don't call me!"))
 
 
@@ -786,10 +788,14 @@ byte-compilation of the new package to fail."
   (with-demoted-errors "Error in package--load-files-for-activation: %s"
     (let* (result
            (dir (package-desc-dir pkg-desc))
-           (load-path-sans-dir
-            (cl-remove-if (apply-partially #'string= dir)
-                          (or (bound-and-true-p find-function-source-path)
-                              load-path)))
+           ;; A previous implementation would skip `dir' itself.
+           ;; However, in normal use reloading from the same directory
+           ;; never happens anyway, while in certain cases external to
+           ;; Emacs a package in the same directory not necessary
+           ;; stays byte-identical, e.g.  during development.  Just
+           ;; don't special-case `dir'.
+           (effective-path (or (bound-and-true-p find-library-source-path)
+                               load-path))
            (files (directory-files-recursively dir "\\`[^\\.].*\\.el\\'"))
            (history (mapcar #'file-truename
                             (cl-remove-if-not #'stringp
@@ -797,8 +803,19 @@ byte-compilation of the new package to fail."
       (dolist (file files)
         (when-let ((library (package--library-stem
                              (file-relative-name file dir)))
-                   (canonical (locate-library library nil load-path-sans-dir))
-                   (found (member (file-truename canonical) history))
+                   (canonical (locate-library library nil effective-path))
+                   (truename (file-truename canonical))
+                   ;; Normally, all files in a package are compiled by
+                   ;; now, but don't assume that.  E.g. different
+                   ;; versions can add or remove `no-byte-compile'.
+                   (altname (if (string-suffix-p ".el" truename)
+                                (replace-regexp-in-string
+                                 "\\.el\\'" ".elc" truename t)
+                              (replace-regexp-in-string
+                               "\\.elc\\'" ".el" truename t)))
+                   (found (or (member truename history)
+                              (and (not (string= altname truename))
+                                   (member altname history))))
                    (recent-index (length found)))
           (unless (equal (file-name-base library)
                          (format "%s-autoloads" (package-desc-name pkg-desc)))
@@ -1007,7 +1024,9 @@ untar into a directory named DIR; otherwise, signal an 
error."
   (unless (file-exists-p file)
     (require 'autoload)
     (let ((coding-system-for-write 'utf-8-emacs-unix))
-      (write-region (autoload-rubric file "package" nil) nil file nil 
'silent)))
+      (with-suppressed-warnings ((obsolete autoload-rubric))
+        (write-region (autoload-rubric file "package" nil)
+                      nil file nil 'silent))))
   file)
 
 (defvar autoload-timestamps)
@@ -1311,7 +1330,7 @@ errors signaled by ERROR-FORM or by BODY).
 
 (cl-defun package--with-response-buffer-1 (url body &key async file 
error-function noerror &allow-other-keys)
   (if (string-match-p "\\`https?:" url)
-        (let ((url (concat url file)))
+        (let ((url (url-expand-file-name file url)))
           (if async
               (package--unless-error #'ignore
                 (url-retrieve
@@ -1646,6 +1665,7 @@ The variable `package-load-list' controls which packages 
to load."
       (require 'package)
       (package--activate-all)))))
 
+;;;###autoload
 (defun package--activate-all ()
   (dolist (elt (package--alist))
     (condition-case err
@@ -2067,7 +2087,10 @@ If PACKAGE is a `package-desc' object, MIN-VERSION is 
ignored."
          package-activated-list)
     ;; We used the quickstart: make it possible to use package-installed-p
     ;; even before package is fully initialized.
-    (memq package package-activated-list))
+    (or
+     (memq package package-activated-list)
+     ;; Also check built-in packages.
+     (package-built-in-p package min-version)))
    (t
     (or
      (let ((pkg-descs (cdr (assq package (package--alist)))))
@@ -2422,6 +2445,35 @@ object."
    'force 'nosave)
   (package-install pkg 'dont-select))
 
+;;;###autoload
+(defun package-recompile (pkg)
+  "Byte-compile package PKG again.
+PKG should be either a symbol, the package name, or a `package-desc'
+object."
+  (interactive (list (intern (completing-read
+                              "Recompile package: "
+                              (mapcar #'symbol-name
+                                      (mapcar #'car package-alist))))))
+  (let ((pkg-desc (if (package-desc-p pkg)
+                      pkg
+                    (cadr (assq pkg package-alist)))))
+    ;; Delete the old .elc files to ensure that we don't inadvertently
+    ;; load them (in case they contain byte code/macros that are now
+    ;; invalid).
+    (dolist (elc (directory-files-recursively
+                  (package-desc-dir pkg-desc) "\\.elc\\'"))
+      (delete-file elc))
+    (package--compile pkg-desc)))
+
+;;;###autoload
+(defun package-recompile-all ()
+  "Byte-compile all installed packages.
+This is meant to be used only in the case the byte-compiled files
+are invalid due to changed byte-code, macros or the like."
+  (interactive)
+  (pcase-dolist (`(_ ,pkg-desc) package-alist)
+    (package-recompile pkg-desc)))
+
 ;;;###autoload
 (defun package-autoremove ()
   "Remove packages that are no longer needed.
@@ -3478,7 +3530,7 @@ If optional arg BUTTON is non-nil, describe its 
associated package."
         (let ((place (cdr desc))
               (out (copy-sequence (car desc))))
           (add-text-properties place (1+ place)
-                               '(face (bold font-lock-warning-face))
+                               '(face help-key-binding)
                                out)
           out))
     (package--prettify-quick-help-key (cons desc 0))))
@@ -3491,9 +3543,6 @@ The full list of keys can be viewed with 
\\[describe-mode]."
   (message (mapconcat #'package--prettify-quick-help-key
                       package--quick-help-keys "\n")))
 
-(define-obsolete-function-alias
-  'package-menu-view-commentary 'package-menu-describe-package "24.1")
-
 (defun package-menu-get-status ()
   "Return status text of package at point in Package Menu."
   (package--ensure-package-menu-mode)
@@ -4246,6 +4295,7 @@ activations need to be changed, such as when 
`package-load-list' is modified."
   (locate-user-emacs-file "package-quickstart.el")
   "Location of the file used to speed up activation of packages at startup."
   :type 'file
+  :group 'applications
   :initialize #'custom-initialize-delay
   :version "27.1")
 
diff --git a/lisp/emacs-lisp/pcase.el b/lisp/emacs-lisp/pcase.el
index 07443dabfe..10bd4bc688 100644
--- a/lisp/emacs-lisp/pcase.el
+++ b/lisp/emacs-lisp/pcase.el
@@ -607,31 +607,38 @@ recording whether the var has been referenced by earlier 
parts of the match."
     (symbolp . vectorp)
     (symbolp . stringp)
     (symbolp . byte-code-function-p)
+    (symbolp . compiled-function-p)
     (symbolp . recordp)
     (integerp . consp)
     (integerp . arrayp)
     (integerp . vectorp)
     (integerp . stringp)
     (integerp . byte-code-function-p)
+    (integerp . compiled-function-p)
     (integerp . recordp)
     (numberp . consp)
     (numberp . arrayp)
     (numberp . vectorp)
     (numberp . stringp)
     (numberp . byte-code-function-p)
+    (numberp . compiled-function-p)
     (numberp . recordp)
     (consp . arrayp)
     (consp . atom)
     (consp . vectorp)
     (consp . stringp)
     (consp . byte-code-function-p)
+    (consp . compiled-function-p)
     (consp . recordp)
     (arrayp . byte-code-function-p)
+    (arrayp . compiled-function-p)
     (vectorp . byte-code-function-p)
+    (vectorp . compiled-function-p)
     (vectorp . recordp)
     (stringp . vectorp)
     (stringp . recordp)
-    (stringp . byte-code-function-p)))
+    (stringp . byte-code-function-p)
+    (stringp . compiled-function-p)))
 
 (defun pcase--mutually-exclusive-p (pred1 pred2)
   (or (member (cons pred1 pred2)
@@ -771,8 +778,8 @@ A and B can be one of:
                    ((consp (cadr pat)) #'consp)
                    ((stringp (cadr pat)) #'stringp)
                    ((vectorp (cadr pat)) #'vectorp)
-                   ((byte-code-function-p (cadr pat))
-                    #'byte-code-function-p))))
+                   ((compiled-function-p (cadr pat))
+                    #'compiled-function-p))))
         (pcase--mutually-exclusive-p (cadr upat) otherpred))
       '(:pcase--fail . nil))
      ;; Since we turn (or 'a 'b 'c) into (pred (pcase--flip (memq '(a b c))))
diff --git a/lisp/emacs-lisp/re-builder.el b/lisp/emacs-lisp/re-builder.el
index 24770fac67..e6e8bb202d 100644
--- a/lisp/emacs-lisp/re-builder.el
+++ b/lisp/emacs-lisp/re-builder.el
@@ -216,19 +216,17 @@ Except for Lisp syntax this is the same as `reb-regexp'.")
   "Buffer to use for the RE Builder.")
 
 ;; Define the local "\C-c" keymap
-(defvar reb-mode-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "\C-c\C-c" 'reb-toggle-case)
-    (define-key map "\C-c\C-q" 'reb-quit)
-    (define-key map "\C-c\C-w" 'reb-copy)
-    (define-key map "\C-c\C-s" 'reb-next-match)
-    (define-key map "\C-c\C-r" 'reb-prev-match)
-    (define-key map "\C-c\C-i" 'reb-change-syntax)
-    (define-key map "\C-c\C-e" 'reb-enter-subexp-mode)
-    (define-key map "\C-c\C-b" 'reb-change-target-buffer)
-    (define-key map "\C-c\C-u" 'reb-force-update)
-    map)
-  "Keymap used by the RE Builder.")
+(defvar-keymap reb-mode-map
+  :doc "Keymap used by the RE Builder."
+  "C-c C-c" #'reb-toggle-case
+  "C-c C-q" #'reb-quit
+  "C-c C-w" #'reb-copy
+  "C-c C-s" #'reb-next-match
+  "C-c C-r" #'reb-prev-match
+  "C-c C-i" #'reb-change-syntax
+  "C-c C-e" #'reb-enter-subexp-mode
+  "C-c C-b" #'reb-change-target-buffer
+  "C-c C-u" #'reb-force-update)
 
 (easy-menu-define reb-mode-menu reb-mode-map
   "Menu for the RE Builder."
@@ -263,12 +261,10 @@ Except for Lisp syntax this is the same as `reb-regexp'.")
   (setq-local blink-matching-paren nil)
   (reb-mode-common))
 
-(defvar reb-lisp-mode-map
-  (let ((map (make-sparse-keymap)))
-    ;; Use the same "\C-c" keymap as `reb-mode' and use font-locking from
-    ;; `emacs-lisp-mode'
-    (define-key map "\C-c" (lookup-key reb-mode-map "\C-c"))
-    map))
+(defvar-keymap reb-lisp-mode-map
+  ;; Use the same "\C-c" keymap as `reb-mode' and use font-locking from
+  ;; `emacs-lisp-mode'
+  "C-c" (keymap-lookup reb-mode-map "C-c"))
 
 (define-derived-mode reb-lisp-mode
   emacs-lisp-mode "RE Builder Lisp"
@@ -278,16 +274,22 @@ Except for Lisp syntax this is the same as `reb-regexp'.")
     (require 'rx))                      ; require rx anyway
   (reb-mode-common))
 
-(defvar reb-subexp-mode-map
-  (let ((m (make-keymap)))
-    (suppress-keymap m)
-    ;; Again share the "\C-c" keymap for the commands
-    (define-key m "\C-c" (lookup-key reb-mode-map "\C-c"))
-    (define-key m "q" 'reb-quit-subexp-mode)
-    (dotimes (digit 10)
-      (define-key m (int-to-string digit) 'reb-display-subexp))
-    m)
-  "Keymap used by the RE Builder for the subexpression mode.")
+(defvar-keymap reb-subexp-mode-map
+  :doc "Keymap used by the RE Builder for the subexpression mode."
+  :full t :suppress t
+  ;; Again share the "\C-c" keymap for the commands
+  "C-c" (keymap-lookup reb-mode-map "C-c")
+  "q" #'reb-quit-subexp-mode
+  "0" #'reb-display-subexp
+  "1" #'reb-display-subexp
+  "2" #'reb-display-subexp
+  "3" #'reb-display-subexp
+  "4" #'reb-display-subexp
+  "5" #'reb-display-subexp
+  "6" #'reb-display-subexp
+  "7" #'reb-display-subexp
+  "8" #'reb-display-subexp
+  "9" #'reb-display-subexp)
 
 (defun reb-mode-common ()
   "Setup functions common to functions `reb-mode' and `reb-lisp-mode'."
@@ -495,7 +497,8 @@ Optional argument SYNTAX must be specified if called 
non-interactively."
        (setq reb-re-syntax syntax)
        (when buffer
           (with-current-buffer buffer
-            (reb-initialize-buffer))))
+            (reb-initialize-buffer))
+          (message "Switched syntax to `%s'" reb-re-syntax)))
     (error "Invalid syntax: %s" syntax)))
 
 
@@ -735,8 +738,7 @@ If SUBEXP is non-nil mark only the corresponding 
sub-expressions."
           (let ((face (get-text-property (1- (point)) 'face)))
             (when (or (and (listp face)
                            (memq 'font-lock-string-face face))
-                      (eq 'font-lock-string-face face)
-                      t)
+                      (eq 'font-lock-string-face face))
               (throw 'found t))))))))
 
 (defface reb-regexp-grouping-backslash
@@ -817,7 +819,6 @@ If SUBEXP is non-nil mark only the corresponding 
sub-expressions."
 
 (defun reb-restart-font-lock ()
   "Restart `font-lock-mode' to fit current regexp format."
-  (message "reb-restart-font-lock re-re-syntax=%s" reb-re-syntax)
   (with-current-buffer (get-buffer reb-buffer)
     (let ((font-lock-is-on font-lock-mode))
       (font-lock-mode -1)
diff --git a/lisp/emacs-lisp/regi.el b/lisp/emacs-lisp/regi.el
index 0099d157e4..a7d61ed51c 100644
--- a/lisp/emacs-lisp/regi.el
+++ b/lisp/emacs-lisp/regi.el
@@ -5,7 +5,6 @@
 ;; Author: 1993 Barry A. Warsaw, Century Computing, Inc. <bwarsaw@cen.com>
 ;; Created:       24-Feb-1993
 ;; Old-Version:   1.8
-;; Last Modified: 1993/06/01 21:33:00
 ;; Keywords:      extensions, matching
 
 ;; This file is part of GNU Emacs.
diff --git a/lisp/emacs-lisp/ring.el b/lisp/emacs-lisp/ring.el
index 2b2039f9d1..e8b92a532f 100644
--- a/lisp/emacs-lisp/ring.el
+++ b/lisp/emacs-lisp/ring.el
@@ -42,6 +42,8 @@
 
 ;;; Code:
 
+(eval-when-compile (require 'cl-lib))
+
 ;;; User Functions:
 
 ;;;###autoload
@@ -51,6 +53,8 @@
        (consp (cdr x)) (integerp (cadr x))
        (vectorp (cddr x))))
 
+(cl-deftype ring () '(satisfies ring-p))
+
 ;;;###autoload
 (defun make-ring (size)
   "Make a ring that can contain SIZE elements."
diff --git a/lisp/emacs-lisp/rmc.el b/lisp/emacs-lisp/rmc.el
index 195035e6be..dae6590b9b 100644
--- a/lisp/emacs-lisp/rmc.el
+++ b/lisp/emacs-lisp/rmc.el
@@ -23,8 +23,6 @@
 
 ;;; Code:
 
-(require 'seq)
-
 (defun rmc--add-key-description (elem)
   (let* ((char (car elem))
          (name (cadr elem))
@@ -125,7 +123,8 @@
     buf))
 
 ;;;###autoload
-(defun read-multiple-choice (prompt choices &optional help-string show-help)
+(defun read-multiple-choice (prompt choices &optional help-string show-help
+                                    long-form)
   "Ask user to select an entry from CHOICES, promting with PROMPT.
 This function allows to ask the user a multiple-choice question.
 
@@ -163,12 +162,21 @@ dialogs.  Otherwise, the function will always use 
text-mode dialogs.
 
 The return value is the matching entry from the CHOICES list.
 
+If LONG-FORM, do a `completing-read' over the NAME elements in
+CHOICES instead.
+
 Usage example:
 
 \(read-multiple-choice \"Continue connecting?\"
                       \\='((?a \"always\")
                         (?s \"session only\")
                         (?n \"no\")))"
+  (if long-form
+      (read-multiple-choice--long-answers prompt choices)
+    (read-multiple-choice--short-answers
+     prompt choices help-string show-help)))
+
+(defun read-multiple-choice--short-answers (prompt choices help-string 
show-help)
   (let* ((prompt-choices
           (if show-help choices (append choices '((?? "?")))))
          (altered-names (mapcar #'rmc--add-key-description prompt-choices))
@@ -244,6 +252,17 @@ Usage example:
       (kill-buffer buf))
     (assq tchar choices)))
 
+(defun read-multiple-choice--long-answers (prompt choices)
+  (let ((answer
+         (completing-read
+          (concat prompt " ("
+                  (mapconcat #'identity (mapcar #'cadr choices) "/")
+                  ") ")
+          (mapcar #'cadr choices) nil t)))
+    (seq-find (lambda (elem)
+                (equal (cadr elem) answer))
+              choices)))
+
 (provide 'rmc)
 
 ;;; rmc.el ends here
diff --git a/lisp/emacs-lisp/rx.el b/lisp/emacs-lisp/rx.el
index aa2486b47e..ec51146484 100644
--- a/lisp/emacs-lisp/rx.el
+++ b/lisp/emacs-lisp/rx.el
@@ -1110,6 +1110,15 @@ can expand to any number of values."
   (append rx--builtin-forms rx--builtin-symbols)
   "List of built-in rx names.  These cannot be redefined by the user.")
 
+;; Declare Lisp indentation rules for constructs that take 1 or 2
+;; parameters before a body of RX forms.
+;; (`>=' and `=' are omitted because they are more likely to be used
+;; as Lisp functions than RX constructs; `repeat' is a `defcustom' type.)
+(put 'group-n 'lisp-indent-function 1)
+(put 'submatch-n 'lisp-indent-function 1)
+(put '** 'lisp-indent-function 2)
+
+
 (defun rx--translate (item)
   "Translate the rx-expression ITEM.  Return (REGEXP . PRECEDENCE)."
   (cond
@@ -1442,6 +1451,12 @@ following constructs:
                    REF can be a number, as usual, or a name
                    introduced by a previous (let REF ...)
                    construct."
+  (rx--pcase-expand regexps))
+
+;; Autoloaded because it's referred to by the pcase rx macro above,
+;; whose body ends up in loaddefs.el.
+;;;###autoload
+(defun rx--pcase-expand (regexps)
   (let* ((rx--pcase-vars nil)
          (regexp (rx--to-expr (rx--pcase-transform (cons 'seq regexps)))))
     `(and (pred stringp)
diff --git a/lisp/emacs-lisp/seq.el b/lisp/emacs-lisp/seq.el
index 133d3c9e11..b6f0f66e5b 100644
--- a/lisp/emacs-lisp/seq.el
+++ b/lisp/emacs-lisp/seq.el
@@ -59,8 +59,8 @@
 (eval-when-compile (require 'cl-generic))
 
 ;; We used to use some sequence functions from cl-lib, but this
-;; dependency was swapped around so that it will be easier to make
-;; seq.el preloaded in the future.  See also Bug#39761#26.
+;; dependency was swapped around so that it's easier to make seq.el
+;; preloaded.  See also Bug#39761#26.
 
 (defmacro seq-doseq (spec &rest body)
   "Loop over a sequence.
@@ -168,21 +168,25 @@ if positive or too small if negative)."
    ((or (stringp sequence) (vectorp sequence)) (substring sequence start end))
    ((listp sequence)
     (let (len
-          (errtext (format "Bad bounding indices: %s, %s" start end)))
+          (orig-start start)
+          (orig-end end))
       (and end (< end 0) (setq end (+ end (setq len (length sequence)))))
       (if (< start 0) (setq start (+ start (or len (setq len (length 
sequence))))))
       (unless (>= start 0)
-        (error "%s" errtext))
+        (error "Start index out of bounds: %s" orig-start))
       (when (> start 0)
         (setq sequence (nthcdr (1- start) sequence))
-        (or sequence (error "%s" errtext))
+        (unless sequence
+          (error "Start index out of bounds: %s" orig-start))
         (setq sequence (cdr sequence)))
       (if end
-          (let ((res nil))
-            (while (and (>= (setq end (1- end)) start) sequence)
-              (push (pop sequence) res))
-            (or (= (1+ end) start) (error "%s" errtext))
-            (nreverse res))
+          (let ((n (- end start)))
+            (when (or (< n 0)
+                      (if len
+                          (> end len)
+                        (and (> n 0) (null (nthcdr (1- n) sequence)))))
+              (error "End index out of bounds: %s" orig-end))
+            (take n sequence))
         (copy-sequence sequence))))
    (t (error "Unsupported sequence: %s" sequence))))
 
@@ -451,6 +455,33 @@ TESTFN is used to compare elements, or `equal' if TESTFN 
is nil."
         (setq result (cons elt result))))
     (nreverse result)))
 
+(cl-defmethod seq-uniq ((sequence list) &optional testfn)
+  (let ((result nil))
+    (if (not testfn)
+        ;; Fast path.  If the list is long, use a hash table to speed
+        ;; things up even more.
+        (let ((l (length sequence)))
+          (if (> l 100)
+              (let ((hash (make-hash-table :test #'equal :size l)))
+                (while sequence
+                  (unless (gethash (car sequence) hash)
+                    (setf (gethash (car sequence) hash) t)
+                    (push (car sequence) result))
+                  (setq sequence (cdr sequence))))
+            ;; Short list.
+            (while sequence
+              (unless (member (car sequence) result)
+                (push (car sequence) result))
+              (pop sequence))))
+      ;; Slower path.
+      (while sequence
+        (unless (seq-find (lambda (elem)
+                            (funcall testfn elem (car sequence)))
+                          result)
+          (push (car sequence) result))
+        (pop sequence)))
+    (nreverse result)))
+
 (cl-defgeneric seq-mapcat (function sequence &optional type)
   "Concatenate the result of applying FUNCTION to each element of SEQUENCE.
 The result is a sequence of type TYPE, or a list if TYPE is nil."
@@ -587,11 +618,13 @@ Signal an error if SEQUENCE is empty."
 
 (cl-defmethod seq-take ((list list) n)
   "Optimized implementation of `seq-take' for lists."
-  (let ((result '()))
-    (while (and list (> n 0))
-      (setq n (1- n))
-      (push (pop list) result))
-    (nreverse result)))
+  (if (eval-when-compile (fboundp 'take))
+      (take n list)
+    (let ((result '()))
+      (while (and list (> n 0))
+        (setq n (1- n))
+        (push (pop list) result))
+      (nreverse result))))
 
 (cl-defmethod seq-drop-while (pred (list list))
   "Optimized implementation of `seq-drop-while' for lists."
@@ -632,5 +665,20 @@ Signal an error if SEQUENCE is empty."
   ;; we automatically highlight macros.
   (add-hook 'emacs-lisp-mode-hook #'seq--activate-font-lock-keywords))
 
+(defun seq-split (sequence length)
+  "Split SEQUENCE into a list of sub-sequences of at most LENGTH.
+All the sub-sequences will be of LENGTH, except the last one,
+which may be shorter."
+  (when (< length 1)
+    (error "Sub-sequence length must be larger than zero"))
+  (let ((result nil)
+        (seq-length (length sequence))
+        (start 0))
+    (while (< start seq-length)
+      (push (seq-subseq sequence start
+                        (setq start (min seq-length (+ start length))))
+            result))
+    (nreverse result)))
+
 (provide 'seq)
 ;;; seq.el ends here
diff --git a/lisp/emacs-lisp/shadow.el b/lisp/emacs-lisp/shadow.el
index 2343a9b589..da32e4564f 100644
--- a/lisp/emacs-lisp/shadow.el
+++ b/lisp/emacs-lisp/shadow.el
@@ -128,11 +128,8 @@ See the documentation for `list-load-path-shadows' for 
further information."
 
             (if (setq orig-dir
                       (assoc file files
-                             (when dir-case-insensitive
-                               (lambda (f1 f2)
-                                 (eq (compare-strings f1 nil nil
-                                                      f2 nil nil t)
-                                     t)))))
+                             (and dir-case-insensitive
+                                  #'string-equal-ignore-case)))
                ;; This file was seen before, we have a shadowing.
                ;; Report it unless the files are identical.
                 (let ((base1 (concat (cdr orig-dir) "/" (car orig-dir)))
diff --git a/lisp/emacs-lisp/shortdoc.el b/lisp/emacs-lisp/shortdoc.el
index a1256ce1b8..990dabe351 100644
--- a/lisp/emacs-lisp/shortdoc.el
+++ b/lisp/emacs-lisp/shortdoc.el
@@ -41,10 +41,12 @@
   '((t :inherit variable-pitch))
   "Face used for a section.")
 
-(defvar shortdoc--groups nil)
+;;;###autoload
+(progn
+  (defvar shortdoc--groups nil)
 
-(defmacro define-short-documentation-group (group &rest functions)
-  "Add GROUP to the list of defined documentation groups.
+  (defmacro define-short-documentation-group (group &rest functions)
+    "Add GROUP to the list of defined documentation groups.
 FUNCTIONS is a list of elements on the form:
 
   (FUNC
@@ -88,8 +90,7 @@ string will be `read' and evaluated.
 
   (FUNC
    :no-eval EXAMPLE-FORM
-   :result RESULT-FORM   ;Use `:result-string' if value is in string form
-   )
+   :result RESULT-FORM)   ;Use `:result-string' if value is in string form
 
 Using `:no-value' is the same as using `:no-eval'.
 
@@ -102,17 +103,16 @@ execution of the documented form depends on some 
conditions.
 
   (FUNC
    :no-eval EXAMPLE-FORM
-   :eg-result RESULT-FORM ;Use `:eg-result-string' if value is in string form
-   )
+   :eg-result RESULT-FORM) ;Use `:eg-result-string' if value is in string form
 
 A FUNC form can have any number of `:no-eval' (or `:no-value'),
 `:no-eval*', `:result', `:result-string', `:eg-result' and
 `:eg-result-string' properties."
-  (declare (indent defun))
-  `(progn
-     (setq shortdoc--groups (delq (assq ',group shortdoc--groups)
-                                  shortdoc--groups))
-     (push (cons ',group ',functions) shortdoc--groups)))
+    (declare (indent defun))
+    `(progn
+       (setq shortdoc--groups (delq (assq ',group shortdoc--groups)
+                                    shortdoc--groups))
+       (push (cons ',group ',functions) shortdoc--groups))))
 
 (define-short-documentation-group alist
   "Alist Basics"
@@ -243,6 +243,8 @@ A FUNC form can have any number of `:no-eval' (or 
`:no-value'),
   "Predicates for Strings"
   (string-equal
    :eval (string-equal "foo" "foo"))
+  (string-equal-ignore-case
+   :eval (string-equal-ignore-case "foo" "FOO"))
   (eq
    :eval (eq "foo" "foo"))
   (eql
@@ -353,6 +355,13 @@ A FUNC form can have any number of `:no-eval' (or 
`:no-value'),
   (abbreviate-file-name
    :no-eval (abbreviate-file-name "/home/some-user")
    :eg-result "~some-user")
+  (file-parent-directory
+   :eval (file-parent-directory "/foo/bar")
+   :eval (file-parent-directory "~")
+   :eval (file-parent-directory "/tmp/")
+   :eval (file-parent-directory "foo/bar")
+   :eval (file-parent-directory "foo")
+   :eval (file-parent-directory "/"))
   "Quoted File Names"
   (file-name-quote
    :args (name)
@@ -494,7 +503,7 @@ A FUNC form can have any number of `:no-eval' (or 
`:no-value'),
   (set-file-modes
    :no-value "(set-file-modes \"/tmp/foo\" #o644)")
   (set-file-times
-   :no-value (set-file-times "/tmp/foo" (current-time)))
+   :no-value (set-file-times "/tmp/foo"))
   "File Modes"
   (set-default-file-modes
    :no-value "(set-default-file-modes #o755)")
@@ -588,6 +597,10 @@ A FUNC form can have any number of `:no-eval' (or 
`:no-value'),
    :eval (nth 1 '(one two three)))
   (nthcdr
    :eval (nthcdr 1 '(one two three)))
+  (take
+   :eval (take 3 '(one two three four)))
+  (ntake
+   :eval (ntake 3 (list 'one 'two 'three 'four)))
   (elt
    :eval (elt '(one two three) 1))
   (car-safe
@@ -691,11 +704,6 @@ A FUNC form can have any number of `:no-eval' (or 
`:no-value'),
   (plist-put
    :no-eval (setq plist (plist-put plist 'd 4))
    :eq-result (a 1 b 2 c 3 d 4))
-  (lax-plist-get
-   :eval (lax-plist-get '("a" 1 "b" 2 "c" 3) "b"))
-  (lax-plist-put
-   :no-eval (setq plist (lax-plist-put plist "d" 4))
-   :eq-result '("a" 1 "b" 2 "c" 3 "d" 4))
   (plist-member
    :eval (plist-member '(a 1 b 2 c 3) 'b))
   "Data About Lists"
@@ -894,6 +902,8 @@ A FUNC form can have any number of `:no-eval' (or 
`:no-value'),
    :eval (seq-subseq '(a b c d e) 2 4))
   (seq-take
    :eval (seq-take '(a b c d e) 3))
+  (seq-split
+   :eval (seq-split [0 1 2 3 5] 2))
   (seq-take-while
    :eval (seq-take-while #'cl-evenp [2 4 9 6 5]))
   (seq-uniq
@@ -931,12 +941,24 @@ A FUNC form can have any number of `:no-eval' (or 
`:no-value'),
    :eval (point-min))
   (point-max
    :eval (point-max))
+  (pos-bol
+   :eval (pos-bol))
+  (pos-eol
+   :eval (pos-eol))
+  (bolp
+   :eval (bolp))
+  (eolp
+   :eval (eolp))
   (line-beginning-position
    :eval (line-beginning-position))
   (line-end-position
    :eval (line-end-position))
   (buffer-size
    :eval (buffer-size))
+  (bobp
+   :eval (bobp))
+  (eobp
+   :eval (eobp))
   "Moving Around"
   (goto-char
    :no-eval (goto-char (point-max))
@@ -962,8 +984,13 @@ A FUNC form can have any number of `:no-eval' (or 
`:no-value'),
   (following-char
    :no-eval (following-char)
    :eg-result 67)
+  (preceding-char
+   :no-eval (preceding-char)
+   :eg-result 38)
   (char-after
    :eval (char-after 45))
+  (char-before
+   :eval (char-before 13))
   (get-byte
    :no-eval (get-byte 45)
    :eg-result-string "#xff")
@@ -972,6 +999,8 @@ A FUNC form can have any number of `:no-eval' (or 
`:no-value'),
    :no-value (delete-region (point-min) (point-max)))
   (erase-buffer
    :no-value (erase-buffer))
+  (delete-line
+   :no-value (delete-line))
   (insert
    :no-value (insert "This string will be inserted in the buffer\n"))
   (subst-char-in-region
@@ -1175,9 +1204,6 @@ A FUNC form can have any number of `:no-eval' (or 
`:no-value'),
   (ash
    :eval (ash 1 4)
    :eval (ash 16 -1))
-  (lsh
-   :eval (lsh 1 4)
-   :eval (lsh 16 -1))
   (logand
    :no-eval "(logand #b10 #b111)"
    :result-string "#b10")
@@ -1363,15 +1389,15 @@ If SAME-WINDOW, don't pop to a new window."
          'action (lambda (_)
                    (describe-function function))
          'follow-link t
-         'help-echo (purecopy "mouse-1, RET: describe function"))
+         'help-echo "mouse-1, RET: describe function")
       (insert-text-button
        (symbol-name function)
        'face 'button
        'action (lambda (_)
                  (info-lookup-symbol function 'emacs-lisp-mode))
        'follow-link t
-       'help-echo (purecopy "mouse-1, RET: show \
-function's documentation in the Info manual")))
+       'help-echo "mouse-1, RET: show \
+function's documentation in the Info manual"))
     (setq arglist-start (point))
     (insert ")\n")
     ;; Doc string.
diff --git a/lisp/emacs-lisp/shorthands.el b/lisp/emacs-lisp/shorthands.el
index a9e4343715..ffd3856db6 100644
--- a/lisp/emacs-lisp/shorthands.el
+++ b/lisp/emacs-lisp/shorthands.el
@@ -61,8 +61,7 @@
 (defun shorthands-font-lock-shorthands (limit)
   (when read-symbol-shorthands
     (while (re-search-forward
-            (eval-when-compile
-              (concat "\\_<\\(" lisp-mode-symbol-regexp "\\)\\_>"))
+            (concat "\\_<\\(" (rx lisp-mode-symbol) "\\)\\_>")
             limit t)
       (let* ((existing (get-text-property (match-beginning 1) 'face))
              (probe (and (not (memq existing '(font-lock-comment-face
diff --git a/lisp/emacs-lisp/subr-x.el b/lisp/emacs-lisp/subr-x.el
index 9cd793d05c..bd7c3c82f9 100644
--- a/lisp/emacs-lisp/subr-x.el
+++ b/lisp/emacs-lisp/subr-x.el
@@ -87,15 +87,15 @@ threading."
 
 (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))
+  (let ((keys nil))
+    (maphash (lambda (k _) (push k keys)) hash-table)
+    keys))
 
 (defsubst hash-table-values (hash-table)
   "Return a list of values in HASH-TABLE."
-  (cl-loop for v being the hash-values of hash-table collect v))
-
-(defsubst string-empty-p (string)
-  "Check whether STRING is empty."
-  (string= string ""))
+  (let ((values nil))
+    (maphash (lambda (_ v) (push v values)) hash-table)
+    values))
 
 (defsubst string-join (strings &optional separator)
   "Join all STRINGS using SEPARATOR.
@@ -107,13 +107,18 @@ characters; nil stands for the empty string."
 
 ;;;###autoload
 (defun string-truncate-left (string length)
-  "Truncate STRING to LENGTH, replacing initial surplus with \"...\"."
+  "If STRING is longer than LENGTH, return a truncated version.
+When truncating, \"...\" is always prepended to the string, so
+the resulting string may be longer than the original if LENGTH is
+3 or smaller."
   (let ((strlen (length string)))
     (if (<= strlen length)
        string
       (setq length (max 0 (- length 3)))
-      (concat "..." (substring string (max 0 (- strlen 1 length)))))))
+      (concat "..." (substring string (min (1- strlen)
+                                           (max 0 (- strlen length))))))))
 
+;;;###autoload
 (defsubst string-blank-p (string)
   "Check whether STRING is either empty or only whitespace.
 The following characters count as whitespace here: space, tab, newline and
@@ -167,9 +172,13 @@ non-nil, return the last LENGTH characters instead.
 If CODING-SYSTEM is non-nil, STRING will be encoded before
 limiting, and LENGTH is interpreted as the number of bytes to
 limit the string to.  The result will be a unibyte string that is
-shorter than LENGTH, but will not contain \"partial\" characters,
-even if CODING-SYSTEM encodes characters with several bytes per
-character.
+shorter than LENGTH, but will not contain \"partial\"
+characters (or glyphs), even if CODING-SYSTEM encodes characters
+with several bytes per character.  If the coding system specifies
+prefix like the byte order mark (aka \"BOM\") or a shift-in sequence,
+their bytes will be normally counted as part of LENGTH.  This is
+the case, for instance, with `utf-16'.  If this isn't desired, use a
+coding system that doesn't specify a BOM, like `utf-16le' or `utf-16be'.
 
 When shortening strings for display purposes,
 `truncate-string-to-width' is almost always a better alternative
@@ -177,34 +186,55 @@ than this function."
   (unless (natnump length)
     (signal 'wrong-type-argument (list 'natnump length)))
   (if coding-system
-      (let ((result nil)
-            (result-length 0)
-            (index (if end (1- (length string)) 0)))
-        ;; FIXME: This implementation, which uses encode-coding-char
-        ;; to encode the string one character at a time, is in general
-        ;; incorrect: coding-systems that produce prefix or suffix
-        ;; bytes, such as ISO-2022-based or UTF-8/16 with BOM, will
-        ;; produce those bytes for each character, instead of just
-        ;; once for the entire string.  encode-coding-char attempts to
-        ;; remove those extra bytes at least in some situations, but
-        ;; it cannot do that in all cases.  And in any case, producing
-        ;; what is supposed to be a UTF-16 or ISO-2022-CN encoded
-        ;; string which lacks the BOM bytes at the beginning and the
-        ;; charset designation sequences at the head and tail of the
-        ;; result will definitely surprise the callers in some cases.
-        (while (let ((encoded (encode-coding-char
-                               (aref string index) coding-system)))
-                 (and (<= (+ (length encoded) result-length) length)
-                      (progn
-                        (push encoded result)
-                        (cl-incf result-length (length encoded))
-                        (setq index (if end (1- index)
-                                      (1+ index))))
-                      (if end (> index -1)
-                        (< index (length string)))))
-          ;; No body.
-          )
-        (apply #'concat (if end result (nreverse result))))
+      ;; The previous implementation here tried to encode char by
+      ;; char, and then adding up the length of the encoded octets,
+      ;; but that's not reliably in the presence of BOM marks and
+      ;; ISO-2022-CN which may add charset designations at the
+      ;; start/end of each encoded char (which we don't want).  So
+      ;; iterate (with a binary search) instead to find the desired
+      ;; length.
+      (let* ((glyphs (string-glyph-split string))
+             (nglyphs (length glyphs))
+             (too-long (1+ nglyphs))
+             (stop (max (/ nglyphs 2) 1))
+             (gap stop)
+             candidate encoded found candidate-stop)
+        ;; We're returning the end of the string.
+        (when end
+          (setq glyphs (nreverse glyphs)))
+        (while (and (not found)
+                    (< stop too-long))
+          (setq encoded
+                (encode-coding-string (string-join (seq-take glyphs stop))
+                                      coding-system))
+          (cond
+           ((= (length encoded) length)
+            (setq found encoded
+                  candidate-stop stop))
+           ;; Too long; try shortening.
+           ((> (length encoded) length)
+            (setq too-long stop
+                  stop (max (- stop gap) 1)))
+           ;; Too short; try lengthening.
+           (t
+            (setq candidate encoded
+                  candidate-stop stop)
+            (setq stop
+                  (if (>= stop nglyphs)
+                      too-long
+                    (min (+ stop gap) nglyphs)))))
+          (setq gap (max (/ gap 2) 1)))
+        (cond
+         ((not (or found candidate))
+          "")
+         ;; We're returning the end, so redo the encoding.
+         (end
+          (encode-coding-string
+           (string-join (nreverse (seq-take glyphs candidate-stop)))
+           coding-system))
+         (t
+          (or found candidate))))
+    ;; Char-based version.
     (cond
      ((<= (length string) length) string)
      (end (substring string (- (length string) length)))
@@ -224,13 +254,9 @@ the string."
   (unless (natnump length)
     (signal 'wrong-type-argument (list 'natnump length)))
   (let ((pad-length (- length (length string))))
-    (if (< pad-length 0)
-        string
-      (concat (and start
-                   (make-string pad-length (or padding ?\s)))
-              string
-              (and (not start)
-                   (make-string pad-length (or padding ?\s)))))))
+    (cond ((<= pad-length 0) string)
+          (start (concat (make-string pad-length (or padding ?\s)) string))
+          (t (concat string (make-string pad-length (or padding ?\s)))))))
 
 (defun string-chop-newline (string)
   "Remove the final newline (if any) from STRING."
@@ -265,6 +291,7 @@ it makes no sense to convert it to a string using
                (set-buffer source-buffer)
                (replace-buffer-contents tmp-buffer max-secs max-costs)))))))))
 
+;;;###autoload
 (defmacro named-let (name bindings &rest body)
   "Looping construct taken from Scheme.
 Like `let', bind variables in BINDINGS and then evaluate BODY,
@@ -286,19 +313,6 @@ as the new values of the bound variables in the recursive 
invocation."
       (cl-labels ((,name ,fargs . ,body)) #',name)
       . ,aargs)))
 
-(defmacro with-memoization (place &rest code)
-  "Return the value of CODE and stash it in PLACE.
-If PLACE's value is non-nil, then don't bother evaluating CODE
-and return the value found in PLACE instead."
-  (declare (indent 1) (debug (gv-place body)))
-  (gv-letplace (getter setter) place
-    `(or ,getter
-         ,(macroexp-let2 nil val (macroexp-progn code)
-            `(progn
-               ,(funcall setter val)
-               ,val)))))
-
-
 ;;;###autoload
 (defun string-pixel-width (string)
   "Return the width of STRING in pixels."
@@ -453,6 +467,18 @@ be marked unmodified, effectively ignoring those changes."
                         (equal ,hash (buffer-hash)))
                (restore-buffer-modified-p nil))))))))
 
+(defun emacs-etc--hide-local-variables ()
+  "Hide local variables.
+Used by `emacs-authors-mode' and `emacs-news-mode'."
+  (narrow-to-region (point-min)
+                    (save-excursion
+                      (goto-char (point-max))
+                      ;; Obfuscate to avoid this being interpreted
+                      ;; as a local variable section itself.
+                      (if (re-search-backward "^Local\sVariables:$" nil t)
+                          (progn (forward-line -1) (point))
+                        (point-max)))))
+
 (provide 'subr-x)
 
 ;;; subr-x.el ends here
diff --git a/lisp/emacs-lisp/syntax.el b/lisp/emacs-lisp/syntax.el
index a4d7beade1..e1be301583 100644
--- a/lisp/emacs-lisp/syntax.el
+++ b/lisp/emacs-lisp/syntax.el
@@ -124,15 +124,49 @@ When the last position scanned holds the first character 
of a
 otherwise nil.  That construct can be a two character comment
 delimiter or an Escaped or Char-quoted character."))
 
-(defun syntax-propertize-wholelines (start end)
-  "Extend the region delimited by START and END to whole lines.
+(defvar syntax-wholeline-max 10000
+  "Maximum line length for syntax operations.
+If lines are longer than that, syntax operations will treat them as chunks
+of this size.  Misfontification may then occur.
+This is a tradeoff between correctly applying the syntax rules,
+and avoiding major slowdown on pathologically long lines.")
+
+(defun syntax--lbp (&optional arg)
+  "Like `line-beginning-position' but obeying `syntax-wholeline-max'."
+  (let ((pos (point))
+        (res (line-beginning-position arg)))
+    (cond
+     ((< (abs (- pos res)) syntax-wholeline-max) res)
+     ;; For lines that are too long, round to the nearest multiple of
+     ;; `syntax-wholeline-max'.  We use rounding rather than just
+     ;; (min res (+ pos syntax-wholeline-max)) so that repeated calls
+     ;; to `syntax-propertize-wholelines' don't keep growing the bounds,
+     ;; i.e. it really behaves like additional line-breaks.
+     ((< res pos)
+      (let ((max syntax-wholeline-max))
+        (max (point-min) (* max (truncate pos max)))))
+     (t
+      (let ((max syntax-wholeline-max))
+        (min (point-max) (* max (ceiling pos max))))))))
+
+(defun syntax-propertize-wholelines (beg end)
+  "Extend the region delimited by BEG and END to whole lines.
 This function is useful for
 `syntax-propertize-extend-region-functions';
 see Info node `(elisp) Syntax Properties'."
-  (goto-char start)
-  (cons (line-beginning-position)
-        (progn (goto-char end)
-               (if (bolp) (point) (line-beginning-position 2)))))
+  ;; This let-binding was taken from
+  ;; `font-lock-extend-region-wholelines' where it was used to avoid
+  ;; inf-looping (Bug#21615) but for some reason it was not applied
+  ;; here in syntax.el and was used only for the "beg" side.
+  (let ((inhibit-field-text-motion t))
+    (let ((new-beg (progn (goto-char beg)
+                          (if (bolp) beg
+                            (syntax--lbp))))
+          (new-end (progn (goto-char end)
+                          (if (bolp) end
+                            (syntax--lbp 2)))))
+      (unless (and (eql beg new-beg) (eql end new-end))
+        (cons new-beg new-end)))))
 
 (defun syntax-propertize-multiline (beg end)
   "Let `syntax-propertize' pay attention to the syntax-multiline property."
@@ -345,10 +379,16 @@ END) suitable for `syntax-propertize-function'."
 (defvar-local syntax-ppss-table nil
   "Syntax-table to use during `syntax-ppss', if any.")
 
-(defvar-local syntax-propertize--inhibit-flush nil
-  "If non-nil, `syntax-ppss-flush-cache' only flushes the ppss cache.
-Otherwise it flushes both the ppss cache and the properties
-set by `syntax-propertize'")
+(defun syntax-propertize--in-process-p ()
+  "Non-nil if we're inside `syntax-propertize'.
+This is used to avoid infinite recursion as well as to handle cases where
+`syntax-ppss' is called when the final `syntax-table' properties have not
+yet been setup, in which case we may end up putting invalid info into the 
cache.
+It's also used so that `syntax-ppss-flush-cache' can be used from within
+`syntax-propertize' without ruining the `syntax-table' already set."
+  (eq syntax-propertize--done most-positive-fixnum))
+
+(defvar-local syntax-ppss--updated-cache nil)
 
 (defun syntax-propertize (pos)
   "Ensure that syntax-table properties are set until POS (a buffer point)."
@@ -370,21 +410,24 @@ set by `syntax-propertize'")
         (with-silent-modifications
           (with-syntax-table (or syntax-ppss-table (syntax-table))
             (make-local-variable 'syntax-propertize--done) ;Just in case!
+            ;; Make sure we let-bind it only buffer-locally.
+            (make-local-variable 'syntax-ppss--updated-cache)
             (let* ((start (max (min syntax-propertize--done (point-max))
                                (point-min)))
                    (end (max pos
                              (min (point-max)
                                   (+ start syntax-propertize-chunk-size))))
                    (first t)
-                   (repeat t))
+                   (repeat t)
+                   (syntax-ppss--updated-cache nil))
               (while repeat
                 (setq repeat nil)
                 (run-hook-wrapped
                  'syntax-propertize-extend-region-functions
                  (lambda (f)
-                   (let ((new (funcall f start end))
-                         ;; Avoid recursion!
-                         (syntax-propertize--done most-positive-fixnum))
+                   ;; Bind `syntax-propertize--done' to avoid recursion!
+                   (let* ((syntax-propertize--done most-positive-fixnum)
+                          (new (funcall f start end)))
                      (if (or (null new)
                              (and (>= (car new) start) (<= (cdr new) end)))
                          nil
@@ -399,20 +442,26 @@ set by `syntax-propertize'")
               ;; Flush ppss cache between the original value of `start' and 
that
               ;; set above by syntax-propertize-extend-region-functions.
               (syntax-ppss-flush-cache start)
-              ;; Move the limit before calling the function, so the function
-              ;; can use syntax-ppss.
+              ;; Move the limit before calling the function, so it's
+              ;; done in case of errors.
               (setq syntax-propertize--done end)
               ;; (message "syntax-propertizing from %s to %s" start end)
               (remove-text-properties start end
                                       '(syntax-table nil syntax-multiline nil))
-              ;; Make sure we only let-bind it buffer-locally.
-              (make-local-variable 'syntax-propertize--inhibit-flush)
-              ;; Let-bind `syntax-propertize--done' to avoid infinite 
recursion!
-              (let ((syntax-propertize--done most-positive-fixnum)
-                    ;; Let `syntax-propertize-function' call
-                    ;; `syntax-ppss-flush-cache' without worries.
-                    (syntax-propertize--inhibit-flush t))
-                (funcall syntax-propertize-function start end)))))))))
+              ;; Bind `syntax-propertize--done' to avoid recursion!
+              (let ((syntax-propertize--done most-positive-fixnum))
+                (funcall syntax-propertize-function start end)
+                (when syntax-ppss--updated-cache
+                  ;; `syntax-ppss' was called and updated the cache while we
+                  ;; were propertizing so we need to flush the part of the
+                  ;; cache that may have been rendered out-of-date by the new
+                  ;; properties.
+                  ;; We used to require syntax-propertize-functions to do that
+                  ;; manually when applicable, but nowadays the `syntax-ppss'
+                  ;; cache can be updated by too many functions, so the author
+                  ;; of the syntax-propertize-function may not be aware it
+                  ;; can happen.
+                  (syntax-ppss-flush-cache start))))))))))
 
 ;;; Link syntax-propertize with syntax.c.
 
@@ -487,10 +536,10 @@ These are valid when the buffer has no restriction.")
 
 (define-obsolete-function-alias 'syntax-ppss-after-change-function
   #'syntax-ppss-flush-cache "27.1")
-(defun syntax-ppss-flush-cache (beg &rest ignored)
+(defun syntax-ppss-flush-cache (beg &rest _ignored)
   "Flush the cache of `syntax-ppss' starting at position BEG."
   ;; Set syntax-propertize to refontify anything past beg.
-  (unless syntax-propertize--inhibit-flush
+  (unless (syntax-propertize--in-process-p)
     (setq syntax-propertize--done (min beg syntax-propertize--done)))
   ;; Flush invalid cache entries.
   (dolist (cell (list syntax-ppss-wide syntax-ppss-narrow))
@@ -517,10 +566,16 @@ These are valid when the buffer has no restriction.")
        (setcdr cell cache)))
     ))
 
-;;; FIXME: Explain this variable.  Currently only its last (5th) slot is used.
-;;; Perhaps the other slots should be removed?
+;; FIXME: Explain this variable.  Currently only its last (5th) slot is used.
+;; Perhaps the other slots should be removed?
+;; This variable is only used when `syntax-begin-function' is used and
+;; will hence be removed together with `syntax-begin-function'.
 (defvar syntax-ppss-stats
-  [(0 . 0) (0 . 0) (0 . 0) (0 . 0) (0 . 0) (2 . 2500)])
+  [(0 . 0) (0 . 0) (0 . 0) (0 . 0) (0 . 0) (2 . 2500)]
+  "Statistics about which case is more/less frequent in `syntax-ppss'.
+The 5th slot drives the heuristic to use `syntax-begin-function'.
+The rest is only useful if you're interested in tweaking the algorithm.")
+
 (defun syntax-ppss-stats ()
   (mapcar (lambda (x)
            (condition-case nil
@@ -658,6 +713,7 @@ running the hook."
               ;; populate the cache so we won't need to do it again soon.
               (t
                (syntax-ppss--update-stats 3 pt-min pos)
+                (setq syntax-ppss--updated-cache t)
 
                ;; If `pt-min' is too far, add a few intermediate entries.
                (while (> (- pos pt-min) (* 2 syntax-ppss-max-span))
@@ -692,6 +748,7 @@ running the hook."
                        (push pair ppss-cache)
                      (setcar ppss-cache pair)))))))))
 
+          (setq syntax-ppss--updated-cache t)
          (setq ppss-last (cons pos ppss))
           (setcar cell ppss-last)
           (setcdr cell ppss-cache)
diff --git a/lisp/emacs-lisp/tabulated-list.el 
b/lisp/emacs-lisp/tabulated-list.el
index 7d815a3ced..c01f3fd4fe 100644
--- a/lisp/emacs-lisp/tabulated-list.el
+++ b/lisp/emacs-lisp/tabulated-list.el
@@ -216,33 +216,28 @@ If ADVANCE is non-nil, move forward by one line 
afterwards."
       (while (re-search-forward re nil 'noerror)
         (tabulated-list-put-tag empty)))))
 
-(defvar tabulated-list-mode-map
-  (let ((map (make-sparse-keymap)))
-    (set-keymap-parent map (make-composed-keymap
-                            button-buffer-map
-                            special-mode-map))
-    (define-key map "n" 'next-line)
-    (define-key map "p" 'previous-line)
-    (define-key map (kbd "M-<left>") 'tabulated-list-previous-column)
-    (define-key map (kbd "M-<right>") 'tabulated-list-next-column)
-    (define-key map "S" 'tabulated-list-sort)
-    (define-key map "}" 'tabulated-list-widen-current-column)
-    (define-key map "{" 'tabulated-list-narrow-current-column)
-    (define-key map [follow-link] 'mouse-face)
-    (define-key map [mouse-2] 'mouse-select-window)
-    map)
-  "Local keymap for `tabulated-list-mode' buffers.")
-
-(defvar tabulated-list-sort-button-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map [header-line mouse-1] 'tabulated-list-col-sort)
-    (define-key map [header-line mouse-2] 'tabulated-list-col-sort)
-    (define-key map [mouse-1] 'tabulated-list-col-sort)
-    (define-key map [mouse-2] 'tabulated-list-col-sort)
-    (define-key map "\C-m" 'tabulated-list-sort)
-    (define-key map [follow-link] 'mouse-face)
-    map)
-  "Local keymap for `tabulated-list-mode' sort buttons.")
+(defvar-keymap tabulated-list-mode-map
+  :doc "Local keymap for `tabulated-list-mode' buffers."
+  :parent (make-composed-keymap button-buffer-map
+                                special-mode-map)
+  "n"             #'next-line
+  "p"             #'previous-line
+  "M-<left>"      #'tabulated-list-previous-column
+  "M-<right>"     #'tabulated-list-next-column
+  "S"             #'tabulated-list-sort
+  "}"             #'tabulated-list-widen-current-column
+  "{"             #'tabulated-list-narrow-current-column
+  "<follow-link>" 'mouse-face
+  "<mouse-2>"     #'mouse-select-window)
+
+(defvar-keymap tabulated-list-sort-button-map
+  :doc "Local keymap for `tabulated-list-mode' sort buttons."
+  "<header-line> <mouse-1>" #'tabulated-list-col-sort
+  "<header-line> <mouse-2>" #'tabulated-list-col-sort
+  "<mouse-1>"               #'tabulated-list-col-sort
+  "<mouse-2>"               #'tabulated-list-col-sort
+  "RET"                     #'tabulated-list-sort
+  "<follow-link>"           'mouse-face)
 
 (defun tabulated-list-make-glyphless-char-display-table ()
   "Make the `glyphless-char-display' table used for text-mode frames.
@@ -470,7 +465,7 @@ changing `tabulated-list-sort-key'."
       (let* ((elt (car entries))
              (tabulated-list--near-rows
               (list
-               (or (tabulated-list-get-entry (point-at-bol 0)) (cadr elt))
+               (or (tabulated-list-get-entry (pos-bol 0)) (cadr elt))
                (cadr elt)
                (or (cadr (cadr entries)) (cadr elt))))
              (id (car elt)))
@@ -524,7 +519,7 @@ of column descriptors."
        (insert (make-string x ?\s)))
     (let ((tabulated-list--near-rows ; Bind it if not bound yet (Bug#25506).
            (or (bound-and-true-p tabulated-list--near-rows)
-               (list (or (tabulated-list-get-entry (point-at-bol 0))
+               (list (or (tabulated-list-get-entry (pos-bol 0))
                          cols)
                      cols))))
       (dotimes (n ncols)
@@ -616,7 +611,7 @@ This function only changes the buffer contents; it does not 
alter
         (cols (tabulated-list-get-entry))
         (inhibit-read-only t))
     (when cols
-      (delete-region (line-beginning-position) (1+ (line-end-position)))
+      (delete-region (pos-bol) (1+ (pos-eol)))
       (list id cols))))
 
 (defun tabulated-list-set-col (col desc &optional change-entry-data)
@@ -630,8 +625,8 @@ by setting the appropriate slot of the vector originally 
used to
 print this entry.  If `tabulated-list-entries' has a list value,
 this is the vector stored within it."
   (let* ((opoint (point))
-        (eol    (line-end-position))
-        (pos    (line-beginning-position))
+         (eol    (pos-eol))
+         (pos    (pos-bol))
         (id     (tabulated-list-get-id pos))
         (entry  (tabulated-list-get-entry pos))
         (prop 'tabulated-list-column-name)
@@ -656,9 +651,9 @@ this is the vector stored within it."
       (goto-char pos)
       (let ((tabulated-list--near-rows
              (list
-              (tabulated-list-get-entry (point-at-bol 0))
+              (tabulated-list-get-entry (pos-bol 0))
               entry
-              (or (tabulated-list-get-entry (point-at-bol 2)) entry))))
+              (or (tabulated-list-get-entry (pos-bol 2)) entry))))
         (tabulated-list-print-col col desc (current-column)))
       (if change-entry-data
          (aset entry col desc))
@@ -790,7 +785,7 @@ If ARG is provided, move that many columns."
     (let ((prev (or (previous-single-property-change
                      (point) 'tabulated-list-column-name)
                     1)))
-      (unless (< prev (line-beginning-position))
+      (unless (< prev (pos-bol))
         (goto-char prev)))))
 
 ;;; The mode definition:
diff --git a/lisp/emacs-lisp/testcover.el b/lisp/emacs-lisp/testcover.el
index 33628d8f47..cd2e388ce4 100644
--- a/lisp/emacs-lisp/testcover.el
+++ b/lisp/emacs-lisp/testcover.el
@@ -65,7 +65,6 @@
 
 (eval-when-compile (require 'cl-lib))
 (require 'edebug)
-(provide 'testcover)
 
 
 ;;;==========================================================================
@@ -677,4 +676,6 @@ The list is 1valued if all of its constituent elements are 
also 1valued."
     (testcover-analyze-coverage (cadr form)))
    (t (testcover-analyze-coverage-backquote form))))
 
+(provide 'testcover)
+
 ;;; testcover.el ends here
diff --git a/lisp/emacs-lisp/timer-list.el b/lisp/emacs-lisp/timer-list.el
index aef18d0ba2..d48698234f 100644
--- a/lisp/emacs-lisp/timer-list.el
+++ b/lisp/emacs-lisp/timer-list.el
@@ -81,13 +81,12 @@
 ;; doing.  Kids, don't try this at home!
 ;;;###autoload (put 'list-timers 'disabled "Beware: manually canceling timers 
can ruin your Emacs session.")
 
-(defvar timer-list-mode-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "c" 'timer-list-cancel)
-    (easy-menu-define nil map ""
-      '("Timers"
-       ["Cancel" timer-list-cancel t]))
-    map))
+(defvar-keymap timer-list-mode-map
+  "c" #'timer-list-cancel
+  :menu
+  '("Timers"
+    ["Cancel" timer-list-cancel t]
+    ["Quit" quit-window]))
 
 (define-derived-mode timer-list-mode tabulated-list-mode "Timer-List"
   "Mode for listing and controlling timers."
diff --git a/lisp/emacs-lisp/timer.el b/lisp/emacs-lisp/timer.el
index fd29abf40a..b25a040a96 100644
--- a/lisp/emacs-lisp/timer.el
+++ b/lisp/emacs-lisp/timer.el
@@ -122,7 +122,7 @@ of SECS seconds since the epoch.  SECS may be a fraction."
       (setq ticks (ash ticks 1))
       (setq hz (ash hz 1)))
     (let ((more-ticks (+ ticks trunc-s-ticks)))
-      (time-convert (cons (- more-ticks (% more-ticks trunc-s-ticks)) hz)))))
+      (time-convert (cons (- more-ticks (% more-ticks trunc-s-ticks)) hz) t))))
 
 (defun timer-relative-time (time secs &optional usecs psecs)
   "Advance TIME by SECS seconds.
@@ -159,32 +159,42 @@ SECS may be a fraction."
   timer)
 
 (defun timer--activate (timer &optional triggered-p reuse-cell idle)
-  (if (and (timerp timer)
-          (integerp (timer--high-seconds timer))
-          (integerp (timer--low-seconds timer))
-          (integerp (timer--usecs timer))
-          (integerp (timer--psecs timer))
-          (timer--function timer))
-      (let ((timers (if idle timer-idle-list timer-list))
-           last)
-       ;; Skip all timers to trigger before the new one.
-       (while (and timers (timer--time-less-p (car timers) timer))
-         (setq last timers
-               timers (cdr timers)))
-       (if reuse-cell
-           (progn
-             (setcar reuse-cell timer)
-             (setcdr reuse-cell timers))
-         (setq reuse-cell (cons timer timers)))
-       ;; Insert new timer after last which possibly means in front of queue.
-        (setf (cond (last (cdr last))
-                    (idle timer-idle-list)
-                    (t    timer-list))
-              reuse-cell)
-       (setf (timer--triggered timer) triggered-p)
-       (setf (timer--idle-delay timer) idle)
-       nil)
-    (error "Invalid or uninitialized timer")))
+  (let ((timers (if idle timer-idle-list timer-list))
+       last)
+    (cond
+     ((not (and (timerp timer)
+               (integerp (timer--high-seconds timer))
+               (integerp (timer--low-seconds timer))
+               (integerp (timer--usecs timer))
+               (integerp (timer--psecs timer))
+               (timer--function timer)))
+      (error "Invalid or uninitialized timer"))
+     ;; FIXME: This is not reliable because `idle-delay' is only set late,
+     ;; by `timer-activate-when-idle' :-(
+     ;;((not (eq (not idle)
+     ;;          (not (timer--idle-delay timer))))
+     ;; (error "idle arg %S out of sync with idle-delay field of timer: %S"
+     ;;        idle timer))
+     ((memq timer timers)
+      (error "Timer already activated"))
+     (t
+      ;; Skip all timers to trigger before the new one.
+      (while (and timers (timer--time-less-p (car timers) timer))
+       (setq last timers
+             timers (cdr timers)))
+      (if reuse-cell
+         (progn
+           (setcar reuse-cell timer)
+           (setcdr reuse-cell timers))
+       (setq reuse-cell (cons timer timers)))
+      ;; Insert new timer after last which possibly means in front of queue.
+      (setf (cond (last (cdr last))
+                  (idle timer-idle-list)
+                  (t    timer-list))
+            reuse-cell)
+      (setf (timer--triggered timer) triggered-p)
+      (setf (timer--idle-delay timer) idle)
+      nil))))
 
 (defun timer-activate (timer &optional triggered-p reuse-cell)
   "Insert TIMER into `timer-list'.
@@ -216,7 +226,7 @@ the time of the current timer.  That's because the activated
 timer will fire right away."
   (timer--activate timer (not dont-wait) reuse-cell 'idle))
 
-(defalias 'disable-timeout 'cancel-timer)
+(defalias 'disable-timeout #'cancel-timer)
 
 (defun cancel-timer (timer)
   "Remove TIMER from the list of active timers."
@@ -430,7 +440,7 @@ The action is to call FUNCTION with arguments ARGS.
 
 This function returns a timer object which you can use in `cancel-timer'."
   (interactive "sRun after delay (seconds): \nNRepeat interval: \naFunction: ")
-  (apply 'run-at-time secs repeat function args))
+  (apply #'run-at-time secs repeat function args))
 
 (defun add-timeout (secs function object &optional repeat)
   "Add a timer to run SECS seconds from now, to call FUNCTION on OBJECT.
@@ -457,7 +467,7 @@ This function returns a timer object which you can use in 
`cancel-timer'."
   (interactive
    (list (read-from-minibuffer "Run after idle (seconds): " nil nil t)
         (y-or-n-p "Repeat each time Emacs is idle? ")
-        (intern (completing-read "Function: " obarray 'fboundp t))))
+        (intern (completing-read "Function: " obarray #'fboundp t))))
   (let ((timer (timer-create)))
     (timer-set-function timer function args)
     (timer-set-idle-time timer secs repeat)
diff --git a/lisp/emacs-lisp/trace.el b/lisp/emacs-lisp/trace.el
index 165f5c7bfe..aea12f146d 100644
--- a/lisp/emacs-lisp/trace.el
+++ b/lisp/emacs-lisp/trace.el
@@ -1,6 +1,6 @@
 ;;; trace.el --- tracing facility for Emacs Lisp functions  -*- 
lexical-binding: t -*-
 
-;; Copyright (C) 1993, 1998, 2000-2022 Free Software Foundation, Inc.
+;; Copyright (C) 1993-2022 Free Software Foundation, Inc.
 
 ;; Author: Hans Chalupsky <hans@cs.buffalo.edu>
 ;; Maintainer: emacs-devel@gnu.org
@@ -22,12 +22,6 @@
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
-;; LCD Archive Entry:
-;; trace|Hans Chalupsky|hans@cs.buffalo.edu|
-;; Tracing facility for Emacs Lisp functions|
-;; 1993/05/18 00:41:16|2.0|~/packages/trace.el.Z|
-
-
 ;;; Commentary:
 
 ;; Introduction:
@@ -273,12 +267,11 @@ If `current-prefix-arg' is non-nil, also read a buffer 
and a \"context\"
                               (if default (symbol-name default)))))
    (when current-prefix-arg
      (list
-      (read-buffer (format-prompt "Output to buffer" trace-buffer))
+      (read-buffer "Output to buffer" trace-buffer)
       (let ((exp
-             (let ((minibuffer-completing-symbol t))
-               (read-from-minibuffer "Context expression: "
-                                     nil read-expression-map t
-                                     'read-expression-history))))
+             (read-from-minibuffer "Context expression: "
+                                   nil read-expression-map t
+                                   'read-expression-history)))
         (lambda ()
           (let ((print-circle t)
                 (print-escape-newlines t))
diff --git a/lisp/emacs-lisp/warnings.el b/lisp/emacs-lisp/warnings.el
index 23e20c3b10..3a966957ec 100644
--- a/lisp/emacs-lisp/warnings.el
+++ b/lisp/emacs-lisp/warnings.el
@@ -27,6 +27,8 @@
 
 ;;; Code:
 
+(require 'icons)
+
 (defgroup warnings nil
   "Log and display warnings."
   :version "22.1"
@@ -201,20 +203,28 @@ SUPPRESS-LIST is the list of kinds of warnings to 
suppress."
     ;; we return t.
     some-match))
 
-(define-button-type 'warning-suppress-warning
-  'action #'warning-suppress-action
-  'help-echo "mouse-2, RET: Don't display this warning automatically")
-(defun warning-suppress-action (button)
-  (customize-save-variable 'warning-suppress-types
-                           (cons (list (button-get button 'warning-type))
-                                 warning-suppress-types)))
-(define-button-type 'warning-suppress-log-warning
-  'action #'warning-suppress-log-action
-  'help-echo "mouse-2, RET: Don't log this warning")
-(defun warning-suppress-log-action (button)
-  (customize-save-variable 'warning-suppress-log-types
-                           (cons (list (button-get button 'warning-type))
-                                 warning-suppress-types)))
+(define-icon warnings-suppress button
+  '((emoji "⛔")
+    (symbol " ■ ")
+    (text " stop "))
+  "Suppress warnings."
+  :version "29.1"
+  :help-echo "Click to suppress this warning type")
+
+(defun warnings-suppress (type)
+  (pcase (car
+          (read-multiple-choice
+           (format "Suppress `%s' warnings? " type)
+           `((?y ,(format "yes, ignore `%s' warnings completely" type))
+             (?n "no, just disable showing them")
+             (?q "quit and do nothing"))))
+    (?y
+     (customize-save-variable 'warning-suppress-log-types
+                              (cons (list type) warning-suppress-log-types)))
+    (?n
+     (customize-save-variable 'warning-suppress-types
+                              (cons (list type) warning-suppress-types)))
+    (_ (message "Exiting"))))
 
 ;;;###autoload
 (defun display-warning (type message &optional level buffer-name)
@@ -289,23 +299,18 @@ entirely by setting `warning-suppress-types' or
              (unless (bolp)
                (funcall newline))
              (setq start (point))
+              ;; Don't output the button when doing batch compilation
+              ;; and similar.
+              (unless (or noninteractive (eq type 'bytecomp))
+                (insert (buttonize (icon-string 'warnings-suppress)
+                                   #'warnings-suppress type)
+                        " "))
              (if warning-prefix-function
                  (setq level-info (funcall warning-prefix-function
                                            level level-info)))
              (insert (format (nth 1 level-info)
                              (format warning-type-format typename))
                      message)
-              ;; Don't output the buttons when doing batch compilation
-              ;; and similar.
-              (unless (or noninteractive (eq type 'bytecomp))
-                (insert " ")
-                (insert-button "Disable showing"
-                               'type 'warning-suppress-warning
-                               'warning-type type)
-                (insert " ")
-                (insert-button "Disable logging"
-                               'type 'warning-suppress-log-warning
-                               'warning-type type))
               (funcall newline)
              (when (and warning-fill-prefix
                          (not (string-search "\n" message))
diff --git a/lisp/emacs-lock.el b/lisp/emacs-lock.el
index 3d2eda99a9..1818e22a92 100644
--- a/lisp/emacs-lock.el
+++ b/lisp/emacs-lock.el
@@ -88,9 +88,6 @@ The functions get one argument, the first locked buffer 
found."
   :group 'emacs-lock
   :version "24.3")
 
-(define-obsolete-variable-alias 'emacs-lock-from-exiting
-  'emacs-lock-mode "24.1")
-
 (defvar-local emacs-lock-mode nil
   "If non-nil, the current buffer is locked.
 It can be one of the following values:
@@ -247,14 +244,6 @@ some major modes from being locked under some 
circumstances."
     ;; continue standard unloading
     nil))
 
-;;; Compatibility
-
-(defun toggle-emacs-lock ()
-  "Toggle `emacs-lock-from-exiting' for the current buffer."
-  (declare (obsolete emacs-lock-mode "24.1"))
-  (interactive)
-  (call-interactively 'emacs-lock-mode))
-
 (provide 'emacs-lock)
 
 ;;; emacs-lock.el ends here
diff --git a/lisp/emulation/cua-base.el b/lisp/emulation/cua-base.el
index 162d1bb641..297f7aba64 100644
--- a/lisp/emulation/cua-base.el
+++ b/lisp/emulation/cua-base.el
@@ -1144,15 +1144,15 @@ If ARG is the atom `-', scroll upward by nearly full 
screen."
            '(self-insert-command))
       def nil))
 
-(defvar cua-global-keymap (make-sparse-keymap)
-  "Global keymap for `cua-mode'; users may add to this keymap.")
-
-(defvar cua--cua-keys-keymap (make-sparse-keymap))
-(defvar cua--prefix-override-keymap (make-sparse-keymap))
-(defvar cua--prefix-repeat-keymap (make-sparse-keymap))
-(defvar cua--global-mark-keymap (make-sparse-keymap)) ; Initialized when 
cua-gmrk.el is loaded
-(defvar cua--rectangle-keymap (make-sparse-keymap))   ; Initialized when 
cua-rect.el is loaded
-(defvar cua--region-keymap (make-sparse-keymap))
+(defvar-keymap cua-global-keymap
+  :doc "Global keymap for `cua-mode'; users may add to this keymap.")
+
+(defvar-keymap cua--cua-keys-keymap)
+(defvar-keymap cua--prefix-override-keymap)
+(defvar-keymap cua--prefix-repeat-keymap)
+(defvar-keymap cua--global-mark-keymap) ; Initialized when cua-gmrk.el is 
loaded
+(defvar-keymap cua--rectangle-keymap)   ; Initialized when cua-rect.el is 
loaded
+(defvar-keymap cua--region-keymap)
 
 (defvar cua--ena-cua-keys-keymap nil)
 (defvar cua--ena-prefix-override-keymap nil)
diff --git a/lisp/emulation/edt.el b/lisp/emulation/edt.el
index 3f8113dea3..cd0e8d60cc 100644
--- a/lisp/emulation/edt.el
+++ b/lisp/emulation/edt.el
@@ -647,7 +647,7 @@ Argument NUM is the number of lines to move."
           (bottom (save-excursion (move-to-window-line bottom-margin) (point)))
           (far (save-excursion
                  (goto-char bottom)
-                 (point-at-bol (1- height)))))
+                 (line-beginning-position (1- height)))))
      (ignore top far)
      ,@body))
 
diff --git a/lisp/emulation/viper-cmd.el b/lisp/emulation/viper-cmd.el
index ddb49609d4..26793989d0 100644
--- a/lisp/emulation/viper-cmd.el
+++ b/lisp/emulation/viper-cmd.el
@@ -3266,8 +3266,8 @@ controlled by the sign of prefix numeric value."
        (if (and (eolp) (not (bolp))) (forward-char -1))
        (if (not (looking-at "[][(){}]"))
            (setq anchor-point (point)))
-       (setq beg-lim (point-at-bol)
-             end-lim (point-at-eol))
+        (setq beg-lim (line-beginning-position)
+              end-lim (line-end-position))
        (cond ((re-search-forward "[][(){}]" end-lim t)
               (backward-char) )
              ((re-search-backward "[][(){}]" beg-lim t))
@@ -4390,7 +4390,7 @@ One can use \\=`\\=` and \\='\\=' to temporarily jump 1 
step back."
              (delete-char -1)
              (setq p (point))
              (setq indent nil)))
-       (setq bol (point-at-bol))
+        (setq bol (line-beginning-position))
        (if (re-search-backward "[^ \t]" bol 1) (forward-char))
        (delete-region (point) p)
        (if indent
@@ -4474,7 +4474,7 @@ One can use \\=`\\=` and \\='\\=' to temporarily jump 1 
step back."
                       (goto-char pos)
                       (beginning-of-line)
                       (if (re-search-backward "[^ \t]" nil t)
-                          (setq s (point-at-bol)))
+                           (setq s (line-beginning-position)))
                       (goto-char pos)
                       (forward-line 1)
                       (if (re-search-forward "[^ \t]" nil t)
diff --git a/lisp/emulation/viper-ex.el b/lisp/emulation/viper-ex.el
index d1bf5e38d5..ec7b1e4cac 100644
--- a/lisp/emulation/viper-ex.el
+++ b/lisp/emulation/viper-ex.el
@@ -1547,7 +1547,7 @@ reversed."
     (if skip-rest
        ()
       ;; setup buffer
-      (if (setq wind (viper-get-visible-buffer-window buf))
+      (if (setq wind (get-buffer-window buf 'visible))
          ()
        (setq wind (get-lru-window 'visible))
        (set-window-buffer wind buf))
diff --git a/lisp/emulation/viper-init.el b/lisp/emulation/viper-init.el
index 5430cd700b..7296041ae8 100644
--- a/lisp/emulation/viper-init.el
+++ b/lisp/emulation/viper-init.el
@@ -71,7 +71,7 @@ In all likelihood, you don't need to bother with this 
setting."
 (defun viper-has-face-support-p ()
   (cond ((viper-window-display-p))
        (viper-force-faces)
-        ((x-display-color-p))
+        ((display-color-p))
        (t (memq window-system '(pc)))))
 
 
@@ -867,8 +867,8 @@ Should be set in `viper-custom-file-name'."
 (defvar-local viper-minibuffer-overlay nil)
 (put 'viper-minibuffer-overlay 'permanent-local t)
 
-;; Hook, specific to Viper, which is run just *before* exiting the minibuffer.
-;; This is needed because beginning with Emacs 19.26, the standard
+;; Hook, specific to Viper, which is run just *before* exiting the
+;; minibuffer.  This is needed because, the standard
 ;; `minibuffer-exit-hook' is run *after* exiting the minibuffer
 (defvar viper-minibuffer-exit-hook nil)
 
diff --git a/lisp/emulation/viper-keym.el b/lisp/emulation/viper-keym.el
index ca175c140c..ed97880559 100644
--- a/lisp/emulation/viper-keym.el
+++ b/lisp/emulation/viper-keym.el
@@ -79,9 +79,9 @@ If nil, C-h gets the usual Vi bindings."
 
 ;; Keymaps for vital things like \e and C-z.
 ;; Not for users
-(defvar viper-vi-intercept-map (make-sparse-keymap))
-(defvar viper-insert-intercept-map (make-sparse-keymap))
-(defvar viper-emacs-intercept-map (make-sparse-keymap))
+(defvar-keymap viper-vi-intercept-map)
+(defvar-keymap viper-insert-intercept-map)
+(defvar-keymap viper-emacs-intercept-map)
 
 (defvar-local viper-vi-local-user-map (make-sparse-keymap)
   "Keymap for user-defined local bindings.
@@ -91,60 +91,62 @@ For instance, in letter-mode, one may want to bind ZZ to
 to `save-buffers-kill-emacs' then post article, etc.")
 (put 'viper-vi-local-user-map 'permanent-local t)
 
-(defvar viper-vi-global-user-map (make-sparse-keymap)
-  "Keymap for user-defined global bindings.
+(defvar-keymap viper-vi-global-user-map
+  :doc "Keymap for user-defined global bindings.
 These bindings are seen in all Viper buffers.")
 
-(defvar viper-vi-basic-map (make-keymap)
-  "This is the main keymap in effect in Viper's Vi state.
-This map is global, shared by all buffers.")
+(defvar-keymap viper-vi-basic-map
+  :doc "This is the main keymap in effect in Viper's Vi state.
+This map is global, shared by all buffers."
+  :full t)
 
-(defvar  viper-vi-kbd-map (make-sparse-keymap)
-  "This keymap keeps keyboard macros defined via the :map command.")
+(defvar-keymap viper-vi-kbd-map
+  :doc "This keymap keeps keyboard macros defined via the :map command.")
 
-(defvar viper-vi-diehard-map (make-sparse-keymap)
-  "This keymap is in use when the user asks Viper to simulate Vi very closely.
-This happens when viper-expert-level is 1 or 2.  See viper-set-expert-level.")
+(defvar-keymap viper-vi-diehard-map
+  :doc "This keymap is in use when the user asks Viper to simulate Vi very 
closely.
+This happens when `viper-expert-level' is 1 or 2.  See 
`viper-set-expert-level'.")
 
 
 (defvar-local viper-insert-local-user-map (make-sparse-keymap)
   "Auxiliary map for per-buffer user-defined keybindings in Insert state.")
 (put 'viper-insert-local-user-map 'permanent-local t)
 
-(defvar viper-insert-global-user-map (make-sparse-keymap)
-  "Auxiliary map for global user-defined bindings in Insert state.")
+(defvar-keymap viper-insert-global-user-map
+  :doc "Auxiliary map for global user-defined bindings in Insert state.")
 
-(defvar viper-insert-basic-map (make-sparse-keymap)
-  "The basic insert-mode keymap.")
+(defvar-keymap viper-insert-basic-map
+  :doc "The basic insert-mode keymap.")
 
-(defvar viper-insert-diehard-map (make-keymap)
-  "Map used when user wants vi-style keys in insert mode.
+(defvar-keymap viper-insert-diehard-map
+  :doc "Map used when user wants vi-style keys in insert mode.
 Most of the Emacs keys are suppressed.  This map overshadows
-viper-insert-basic-map.  Not recommended, except for novice users.")
+`viper-insert-basic-map'.  Not recommended, except for novice users."
+  :full t)
 
-(defvar  viper-insert-kbd-map  (make-sparse-keymap)
-  "This keymap keeps VI-style kbd macros for insert mode.")
+(defvar-keymap viper-insert-kbd-map
+  :doc "This keymap keeps VI-style kbd macros for insert mode.")
 
-(defvar viper-replace-map (make-sparse-keymap)
-  "Map used in Viper's replace state.")
+(defvar-keymap viper-replace-map
+  :doc "Map used in Viper's replace state.")
 
-(defvar viper-emacs-global-user-map (make-sparse-keymap)
-  "Auxiliary map for global user-defined bindings in Emacs state.")
+(defvar-keymap viper-emacs-global-user-map
+  :doc "Auxiliary map for global user-defined bindings in Emacs state.")
 
-(defvar  viper-emacs-kbd-map  (make-sparse-keymap)
-  "This keymap keeps Vi-style kbd macros for Emacs mode.")
+(defvar-keymap viper-emacs-kbd-map
+  :doc "This keymap keeps Vi-style kbd macros for Emacs mode.")
 
 (defvar-local viper-emacs-local-user-map  (make-sparse-keymap)
   "Auxiliary map for local user-defined bindings in Emacs state.")
 (put 'viper-emacs-local-user-map 'permanent-local t)
 
 ;; This keymap should stay empty
-(defvar viper-empty-keymap (make-sparse-keymap))
+(defvar-keymap viper-empty-keymap)
 
 ;; This was the main Vi mode in old versions of VIP which may have been
 ;; extensively used by VIP users.  We declare it as a global var and, after
 ;; viper-custom-file-name is loaded, we add this keymap to viper-vi-basic-map.
-(defvar viper-mode-map (make-sparse-keymap))
+(defvar-keymap viper-mode-map)
 
 ;; Some important keys used in viper
 (defcustom viper-toggle-key [(control ?z)]  ; "\C-z"
@@ -442,41 +444,41 @@ In insert mode, this key also functions as Meta."
 ;;; Minibuffer keymap
 
 
-(defvar viper-minibuffer-map (make-sparse-keymap)
-  "Keymap used to modify keys when Minibuffer is in Insert state.")
+(defvar-keymap viper-minibuffer-map
+  :doc "Keymap used to modify keys when Minibuffer is in Insert state.")
 
 (define-key viper-minibuffer-map "\C-m" 'viper-exit-minibuffer)
 (define-key viper-minibuffer-map "\C-j" 'viper-exit-minibuffer)
 
 ;; Map used to read Ex-style commands.
-(defvar viper-ex-cmd-map (make-sparse-keymap))
+(defvar-keymap viper-ex-cmd-map)
 (define-key viper-ex-cmd-map " "  'ex-cmd-read-exit)
 (define-key viper-ex-cmd-map "\t" 'ex-cmd-complete)
 
 ;; Keymap for reading file names in Ex-style commands.
-(defvar ex-read-filename-map (make-sparse-keymap))
+(defvar-keymap ex-read-filename-map)
 (define-key ex-read-filename-map " " 'viper-complete-filename-or-exit)
 (define-key ex-read-filename-map "!" 'viper-handle-!)
 
 ;; Some other maps
-(defvar viper-slash-and-colon-map (make-sparse-keymap)
-  "This map redefines `/' and `:' to behave as in Vi.
+(defvar-keymap viper-slash-and-colon-map
+  :doc "This map redefines \\`/' and \\`:' to behave as in Vi.
 Useful in some modes, such as Gnus, MH, etc.")
 (define-key viper-slash-and-colon-map ":" 'viper-ex)
 (define-key viper-slash-and-colon-map "/" 'viper-search-forward)
 
-(defvar viper-comint-mode-modifier-map (make-sparse-keymap)
-  "This map modifies comint mode.")
+(defvar-keymap viper-comint-mode-modifier-map
+  :doc "This map modifies comint mode.")
 (define-key viper-comint-mode-modifier-map "\C-m" 'viper-exec-key-in-emacs)
 (define-key viper-comint-mode-modifier-map "\C-d" 'viper-exec-key-in-emacs)
 
-(defvar viper-dired-modifier-map (make-sparse-keymap)
-  "This map modifies Dired behavior.")
+(defvar-keymap viper-dired-modifier-map
+  :doc "This map modifies Dired behavior.")
 (define-key viper-dired-modifier-map ":" 'viper-ex)
 (define-key viper-dired-modifier-map "/" 'viper-search-forward)
 
-(defvar viper-gnus-modifier-map (make-sparse-keymap)
-  "This map modifies Gnus behavior.")
+(defvar-keymap viper-gnus-modifier-map
+  :doc "This map modifies Gnus behavior.")
 (define-key viper-gnus-modifier-map ":" 'viper-ex)
 
 
diff --git a/lisp/emulation/viper-macs.el b/lisp/emulation/viper-macs.el
index c4eb183ce4..06130afa7d 100644
--- a/lisp/emulation/viper-macs.el
+++ b/lisp/emulation/viper-macs.el
@@ -105,7 +105,8 @@ a key is a symbol, e.g., `a', `\\1', `f2', etc., or a list, 
e.g.,
         #'viper-end-mapping-kbd-macro)
       (define-key viper-emacs-intercept-map "\C-x)"
         #'viper-end-mapping-kbd-macro)
-      (message "Mapping %S in %s state.  Type macro definition followed by 
`C-x )'"
+      (message (substitute-command-keys "Mapping %S in %s state.  \
+Type macro definition followed by \\[kmacro-end-macro]")
               (viper-display-macro macro-name)
               (if ins "Insert" "Vi")))
     ))
@@ -886,8 +887,9 @@ mistakes in macro names to be passed to this function is to 
use
   (if (get-register reg)
       (if (y-or-n-p "Register contains data.  Overwrite? ")
          ()
-       (error
-        "Macro not saved in register.  Can still be invoked via `C-x e'")))
+        (error
+         (substitute-command-keys
+          "Macro not saved in register.  Can still be invoked via 
\\[kmacro-end-and-call-macro]"))))
   (set-register reg last-kbd-macro))
 
 (defun viper-register-macro (count)
diff --git a/lisp/emulation/viper-util.el b/lisp/emulation/viper-util.el
index 6d23ae9a0f..46dbd7f24d 100644
--- a/lisp/emulation/viper-util.el
+++ b/lisp/emulation/viper-util.el
@@ -1,6 +1,6 @@
 ;;; viper-util.el --- Utilities used by viper.el  -*- lexical-binding:t -*-
 
-;; Copyright (C) 1994-1997, 1999-2022 Free Software Foundation, Inc.
+;; Copyright (C) 1994-2022 Free Software Foundation, Inc.
 
 ;; Author: Michael Kifer <kifer@cs.stonybrook.edu>
 ;; Package: viper
@@ -57,7 +57,7 @@
 (define-obsolete-function-alias 'viper-int-to-char #'identity "27.1")
 (define-obsolete-function-alias 'viper-get-face #'facep "27.1")
 (define-obsolete-function-alias 'viper-color-defined-p
-  #'x-color-defined-p "27.1")
+  #'color-defined-p "27.1")
 (define-obsolete-function-alias 'viper-iconify
   #'iconify-or-deiconify-frame "27.1")
 
@@ -71,7 +71,7 @@
         (= char char1))
        (t nil)))
 
-(define-obsolete-function-alias 'viper-color-display-p #'x-display-color-p 
"29.1")
+(define-obsolete-function-alias 'viper-color-display-p #'display-color-p 
"29.1")
 
 (defun viper-get-cursor-color (&optional _frame)
   (cdr (assoc 'cursor-color (frame-parameters))))
@@ -89,8 +89,8 @@ Otherwise return the normal value."
 
 ;; cursor colors
 (defun viper-change-cursor-color (new-color &optional frame)
-  (if (and (viper-window-display-p) (x-display-color-p)
-          (stringp new-color) (x-color-defined-p new-color)
+  (if (and (viper-window-display-p) (display-color-p)
+           (stringp new-color) (color-defined-p new-color)
           (not (string= new-color (viper-get-cursor-color))))
       (modify-frame-parameters
        (or frame (selected-frame))
@@ -121,9 +121,9 @@ Otherwise return the normal value."
 
 ;; By default, saves current frame cursor color before changing viper state
 (defun viper-save-cursor-color (before-which-mode)
-  (if (and (viper-window-display-p) (x-display-color-p))
+  (if (and (viper-window-display-p) (display-color-p))
       (let ((color (viper-get-cursor-color)))
-       (if (and (stringp color) (x-color-defined-p color)
+        (if (and (stringp color) (color-defined-p color)
                 ;; there is something fishy in that the color is not saved if
                 ;; it is the same as frames default cursor color. need to be
                 ;; checked.
@@ -175,35 +175,23 @@ Otherwise return the normal value."
 
 
 ;; Check the current version against the major and minor version numbers
-;; using op: cur-vers op major.minor If emacs-major-version or
-;; emacs-minor-version are not defined, we assume that the current version
-;; is hopelessly outdated.  We assume that emacs-major-version and
-;; emacs-minor-version are defined.  Otherwise, for Emacs/XEmacs 19, if the
-;; current minor version is < 10 (xemacs) or < 23 (emacs) the return value
-;; will be nil (when op is =, >, or >=) and t (when op is <, <=), which may be
-;; incorrect.  However, this gives correct result in our cases, since we are
-;; testing for sufficiently high Emacs versions.
-(defun viper-check-version (op major minor &optional type-of-emacs)
+;; using op: cur-vers op major.minor
+(defun viper-check-version (op major minor &optional _type-of-emacs)
   (declare (obsolete nil "28.1"))
-  (if (and (boundp 'emacs-major-version) (boundp 'emacs-minor-version))
-      (and (cond ((eq type-of-emacs 'xemacs) (featurep 'xemacs))
-                ((eq type-of-emacs 'emacs) (featurep 'emacs))
-                (t t))
-          (cond ((eq op '=) (and (= emacs-minor-version minor)
-                                 (= emacs-major-version major)))
-                ((memq op '(> >= < <=))
-                 (and (or (funcall op emacs-major-version major)
-                          (= emacs-major-version major))
-                      (if (= emacs-major-version major)
-                          (funcall op emacs-minor-version minor)
-                        t)))
-                (t
-                 (error "%S: Invalid op in viper-check-version" op))))
-    (cond ((memq op '(= > >=)) nil)
-         ((memq op '(< <=)) t))))
+  (cond ((eq op '=) (and (= emacs-minor-version minor)
+                         (= emacs-major-version major)))
+        ((memq op '(> >= < <=))
+         (and (or (funcall op emacs-major-version major)
+                  (= emacs-major-version major))
+              (if (= emacs-major-version major)
+                  (funcall op emacs-minor-version minor)
+                t)))
+        (t
+         (error "%S: Invalid op in viper-check-version" op))))
 
 
 (defun viper-get-visible-buffer-window (wind)
+  (declare (obsolete "use `(get-buffer-window wind 'visible)'." "29.1"))
   (get-buffer-window wind 'visible))
 
 ;; Return line position.
@@ -1005,6 +993,7 @@ Otherwise return the normal value."
          (t (prin1-to-string event-seq)))))
 
 (defun viper-key-press-events-to-chars (events)
+  (declare (obsolete nil "29.1"))
   (mapconcat #'char-to-string events ""))
 
 
@@ -1031,7 +1020,6 @@ Otherwise return the normal value."
         (string-to-char (symbol-name key)))
        ((and (listp key)
              (eq (car key) 'control)
-             (symbol-name (nth 1 key))
              (= 1 (length (symbol-name (nth 1 key)))))
         (read (format "?\\C-%s" (symbol-name (nth 1 key)))))
        (t key)))
diff --git a/lisp/emulation/viper.el b/lisp/emulation/viper.el
index b1c361145c..d1c8b5ff2d 100644
--- a/lisp/emulation/viper.el
+++ b/lisp/emulation/viper.el
@@ -7,7 +7,7 @@
 
 ;; Author: Michael Kifer <kifer@cs.stonybrook.edu>
 ;; Keywords: emulations
-;; Version: 3.14.1
+;; Version: 3.14.2
 
 ;; Yoni Rabkin <yoni@rabkins.net> contacted the maintainer of this
 ;; file on 20/3/2008, and the maintainer agreed that when a bug is
@@ -379,7 +379,7 @@ widget."
     flora-mode
     sql-mode
 
-    text-mode indented-text-mode
+    text-mode
     tex-mode latex-mode bibtex-mode
     ps-mode
 
@@ -559,10 +559,10 @@ and improving upon much of it.
    2. Vi exit functions (e.g., :wq, ZZ) work on INDIVIDUAL files -- they
       do not cause Emacs to quit, except at user level 1 (for a novice).
    3. ^X^C EXITS EMACS.
-   4. Viper supports multiple undo: `u' will undo.  Typing `.' will repeat
-      undo.  Another `u' changes direction.
+   4. Viper supports multiple undo: \\`u' will undo.  Typing \\`.' will repeat
+      undo.  Another \\`u' changes direction.
 
-   6. Emacs Meta key is `C-\\' (in all modes) or `\\ ESC' (in Vi command mode).
+   6. Emacs Meta key is \\`C-\\' (in all modes) or \\`\\ ESC' (in Vi command 
mode).
       On a window system, the best way is to use the Meta-key on your keyboard.
    7. Try \\[keyboard-quit] and \\[abort-recursive-edit] repeatedly,if
       something funny happens.  This would abort the current editing command.
@@ -573,12 +573,12 @@ For more information on Viper:
    b. Print Viper manual, found in ./etc/viper.dvi
    c. Print the Quick Reference, found in ./etc/viperCard.dvi
 
-To submit a bug report or to contact the author, type :submitReport in Vi
+To submit a bug report or to contact the author, type \\`:submitReport' in Vi
 command mode.  To shoo Viper away and return to pure Emacs (horror!), type:
 
    \\[viper-go-away]
 
-This startup message appears whenever you load Viper, unless you type `y' now."
+This startup message appears whenever you load Viper, unless you type \\`y' 
now."
                      ))
                    (goto-char (point-min))
                    (if (y-or-n-p "Inhibit Viper startup message? ")
@@ -605,7 +605,7 @@ This startup message appears whenever you load Viper, 
unless you type `y' now."
 
 ;; Apply a little heuristic to invoke vi state on major-modes
 ;; that are not listed in viper-vi-state-mode-list
-(defun this-major-mode-requires-vi-state (mode)
+(defun viper-this-major-mode-requires-vi-state (mode)
   (let ((major-mode mode))
     (cond ((apply #'derived-mode-p viper-vi-state-mode-list) t)
           ((apply #'derived-mode-p viper-emacs-state-mode-list) nil)
@@ -634,7 +634,7 @@ This startup message appears whenever you load Viper, 
unless you type `y' now."
         (remove-hook symbol #'viper-minibuffer-post-command-hook)
         (remove-hook symbol #'viper-minibuffer-setup-sentinel)
         (remove-hook symbol #'viper-major-mode-change-sentinel)
-        (remove-hook symbol #'set-viper-state-in-major-mode)
+         (remove-hook symbol #'viper-set-state-in-major-mode)
         (remove-hook symbol #'viper-post-command-sentinel)
         )))
 
@@ -786,12 +786,12 @@ It also can't undo some Viper settings."
 (defvar viper-new-major-mode-buffer-list nil)
 
 ;; set appropriate Viper state in buffers that changed major mode
-(defun set-viper-state-in-major-mode ()
+(defun viper-set-state-in-major-mode ()
   (mapc
    (lambda (buf)
      (if (viper-buffer-live-p buf)
         (with-current-buffer buf
-          (cond ((and (this-major-mode-requires-vi-state major-mode)
+           (cond ((and (viper-this-major-mode-requires-vi-state major-mode)
                       (eq viper-current-state 'emacs-state))
                  (viper-mode))
                 ((cl-member-if #'derived-mode-p viper-emacs-state-mode-list)
@@ -810,7 +810,7 @@ It also can't undo some Viper settings."
   ;; clear the list of bufs that changed major mode
   (setq viper-new-major-mode-buffer-list nil)
   ;; change the global value of hook
-  (remove-hook 'viper-post-command-hooks #'set-viper-state-in-major-mode))
+  (remove-hook 'viper-post-command-hooks #'viper-set-state-in-major-mode))
 
 ;; sets up post-command-hook to turn viper-mode, if the current mode is
 ;; fundamental
@@ -820,7 +820,7 @@ It also can't undo some Viper settings."
        (setq viper-new-major-mode-buffer-list
              (cons (current-buffer) viper-new-major-mode-buffer-list))))
   ;; change the global value of hook
-  (add-hook 'viper-post-command-hooks #'set-viper-state-in-major-mode t))
+  (add-hook 'viper-post-command-hooks #'viper-set-state-in-major-mode t))
 
 
 ;;; Handling of tty's ESC event
@@ -891,7 +891,7 @@ Two differences:
   (viper-setup-ESC-to-escape t)
 
   (add-hook 'change-major-mode-hook #'viper-major-mode-change-sentinel)
-  (add-hook 'find-file-hook #'set-viper-state-in-major-mode)
+  (add-hook 'find-file-hook #'viper-set-state-in-major-mode)
 
   ;; keep this because many modes we don't know about use this hook
   (defvar text-mode-hook)
@@ -1242,12 +1242,15 @@ These two lines must come in the order given."))
   (when (eq viper-current-state 'emacs-state)
     (viper-change-state-to-emacs))
 
-  (if (this-major-mode-requires-vi-state major-mode)
+  (if (viper-this-major-mode-requires-vi-state major-mode)
       (viper-mode))
 
-  (add-function :after initial-major-mode #'set-viper-state-in-major-mode))
-
+  (add-function :after initial-major-mode #'viper-set-state-in-major-mode))
 
+(define-obsolete-function-alias 'set-viper-state-in-major-mode
+  #'viper-set-state-in-major-mode "29.1")
+(define-obsolete-function-alias 'this-major-mode-requires-vi-state
+  #'viper-this-major-mode-requires-vi-state "29.1")
 
 (run-hooks 'viper-load-hook) ; the last chance to change something
 
diff --git a/lisp/env.el b/lisp/env.el
index a630bf120f..5cdedbfb99 100644
--- a/lisp/env.el
+++ b/lisp/env.el
@@ -1,6 +1,6 @@
 ;;; env.el --- functions to manipulate environment variables  -*- 
lexical-binding:t -*-
 
-;; Copyright (C) 1991, 1994, 2000-2022 Free Software Foundation, Inc.
+;; Copyright (C) 1991-2022 Free Software Foundation, Inc.
 
 ;; Maintainer: emacs-devel@gnu.org
 ;; Keywords: processes, unix
@@ -225,7 +225,7 @@ VARIABLES is a list of variable settings of the form (VAR 
VALUE),
 where VAR is the name of the variable (a string) and VALUE
 is its value (also a string).
 
-The previous values will be be restored upon exit."
+The previous values will be restored upon exit."
   (declare (indent 1) (debug (sexp body)))
   (unless (consp variables)
     (error "Invalid VARIABLES: %s" variables))
diff --git a/lisp/epa-ks.el b/lisp/epa-ks.el
index f41429f773..7c60b659f0 100644
--- a/lisp/epa-ks.el
+++ b/lisp/epa-ks.el
@@ -295,13 +295,11 @@ enough, since keyservers have strict timeout settings."
                :created
                (and  (match-string 4)
                      (not (string-empty-p (match-string 4)))
-                    (time-convert
-                      (string-to-number (match-string 4))))
+                    (time-convert (string-to-number (match-string 4)) t))
                :expires
                (and (match-string 5)
                     (not (string-empty-p (match-string 5)))
-                   (time-convert
-                     (string-to-number (match-string 5))))
+                   (time-convert (string-to-number (match-string 5)) t))
                :flags
                (mapcar (lambda (flag)
                          (cdr (assq flag '((?r revoked)
diff --git a/lisp/epa-mail.el b/lisp/epa-mail.el
index 6170dcb611..bb34ca72d6 100644
--- a/lisp/epa-mail.el
+++ b/lisp/epa-mail.el
@@ -30,21 +30,19 @@
 
 ;;; Local Mode
 
-(defvar epa-mail-mode-map
-  (let ((keymap (make-sparse-keymap)))
-    (define-key keymap "\C-c\C-ed" 'epa-mail-decrypt)
-    (define-key keymap "\C-c\C-ev" 'epa-mail-verify)
-    (define-key keymap "\C-c\C-es" 'epa-mail-sign)
-    (define-key keymap "\C-c\C-ee" 'epa-mail-encrypt)
-    (define-key keymap "\C-c\C-ei" 'epa-mail-import-keys)
-    (define-key keymap "\C-c\C-eo" 'epa-insert-keys)
-    (define-key keymap "\C-c\C-e\C-d" 'epa-mail-decrypt)
-    (define-key keymap "\C-c\C-e\C-v" 'epa-mail-verify)
-    (define-key keymap "\C-c\C-e\C-s" 'epa-mail-sign)
-    (define-key keymap "\C-c\C-e\C-e" 'epa-mail-encrypt)
-    (define-key keymap "\C-c\C-e\C-i" 'epa-mail-import-keys)
-    (define-key keymap "\C-c\C-e\C-o" 'epa-insert-keys)
-    keymap))
+(defvar-keymap epa-mail-mode-map
+  "C-c C-e d"   #'epa-mail-decrypt
+  "C-c C-e v"   #'epa-mail-verify
+  "C-c C-e s"   #'epa-mail-sign
+  "C-c C-e e"   #'epa-mail-encrypt
+  "C-c C-e i"   #'epa-mail-import-keys
+  "C-c C-e o"   #'epa-insert-keys
+  "C-c C-e C-d" #'epa-mail-decrypt
+  "C-c C-e C-v" #'epa-mail-verify
+  "C-c C-e C-s" #'epa-mail-sign
+  "C-c C-e C-e" #'epa-mail-encrypt
+  "C-c C-e C-i" #'epa-mail-import-keys
+  "C-c C-e C-o" #'epa-insert-keys)
 
 (defvar epa-mail-mode-hook nil)
 (defvar epa-mail-mode-on-hook nil)
diff --git a/lisp/epa.el b/lisp/epa.el
index 742c37d085..63bc0941d6 100644
--- a/lisp/epa.el
+++ b/lisp/epa.el
@@ -417,7 +417,7 @@ q  trust status questionable.  -  trust status unspecified.
                                             'epa-key))
                (setq keys (cons key keys))))
          (nreverse keys)))
-      (let ((key (get-text-property (point-at-bol) 'epa-key)))
+      (let ((key (get-text-property (line-beginning-position) 'epa-key)))
        (if key
            (list key)))))
 
diff --git a/lisp/epg-config.el b/lisp/epg-config.el
index 28003eaf71..6501434e03 100644
--- a/lisp/epg-config.el
+++ b/lisp/epg-config.el
@@ -246,9 +246,9 @@ version requirement is met."
       (goto-char (match-end 0))
       (backward-char)
       (forward-sexp)
-      (skip-syntax-forward "-" (point-at-eol))
+      (skip-syntax-forward "-" (line-end-position))
       (list (cons 'program program)
-            (cons 'version (buffer-substring (point) (point-at-eol)))))))
+            (cons 'version (buffer-substring (point) (line-end-position)))))))
 
 ;;;###autoload
 (defun epg-configuration ()
diff --git a/lisp/epg.el b/lisp/epg.el
index c5d946cb76..c3c26badbb 100644
--- a/lisp/epg.el
+++ b/lisp/epg.el
@@ -606,7 +606,7 @@ callback data (if any)."
         process
         terminal-name
         agent-file
-        (agent-mtime '(0 0 0 0)))
+        (agent-mtime 0))
     ;; Set GPG_TTY and TERM for pinentry-curses.  Note that we can't
     ;; use `terminal-name' here to get the real pty name for the child
     ;; process, though /dev/fd/0" is not portable.
@@ -633,7 +633,7 @@ callback data (if any)."
       (setq agent-file (match-string 1 agent-info)
            agent-mtime (or (file-attribute-modification-time
                             (file-attributes agent-file))
-                           '(0 0 0 0))))
+                           0)))
     (if epg-debug
        (save-excursion
          (unless epg-debug-buffer
diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el
index 1252a5b4fa..df9efe4b0c 100644
--- a/lisp/erc/erc-backend.el
+++ b/lisp/erc/erc-backend.el
@@ -102,7 +102,6 @@
 ;; There's a fairly strong mutual dependency between erc.el and erc-backend.el.
 ;; Luckily, erc.el does not need erc-backend.el for macroexpansion whereas the
 ;; reverse is true:
-(provide 'erc-backend)
 (require 'erc)
 
 ;;;; Variables and options
@@ -124,6 +123,14 @@
   "Nickname on the current server.
 Use `erc-current-nick' to access this.")
 
+(defvar-local erc-session-user-full-name nil
+  "Real name used for the current session.
+Sent as the last argument to the USER command.")
+
+(defvar-local erc-session-username nil
+  "Username used for the current session.
+Sent as the first argument of the USER command.")
+
 ;;; Server attributes
 
 (defvar-local erc-server-process nil
@@ -178,21 +185,27 @@ SILENCE=10 - supports the SILENCE command, maximum 
allowed number of entries
 TOPICLEN=160 - maximum allowed topic length
 WALLCHOPS - supports sending messages to all operators in a channel")
 
+(defvar-local erc--isupport-params nil
+  "Hash map of \"ISUPPORT\" params.
+Keys are symbols.  Values are lists of zero or more strings with hex
+escapes removed.")
+
 ;;; Server and connection state
 
 (defvar erc-server-ping-timer-alist nil
   "Mapping of server buffers to their specific ping timer.")
 
 (defvar-local erc-server-connected nil
-  "Non-nil if the current buffer has been used by ERC to establish
-an IRC connection.
-
-If you wish to determine whether an IRC connection is currently
-active, use the `erc-server-process-alive' function instead.")
+  "Non-nil if the current buffer belongs to an active IRC connection.
+To determine whether an underlying transport is connected, use the
+function `erc-server-process-alive' instead.")
 
 (defvar-local erc-server-reconnect-count 0
   "Number of times we have failed to reconnect to the current server.")
 
+(defvar-local erc--server-last-reconnect-count 0
+  "Snapshot of reconnect count when the connection was established.")
+
 (defvar-local erc-server-quitting nil
   "Non-nil if the user requests a quit.")
 
@@ -217,7 +230,7 @@ current IRC process is still alive.")
 (defvar-local erc-server-lines-sent nil
   "Line counter.")
 
-(defvar-local erc-server-last-peers '(nil . nil)
+(defvar-local erc-server-last-peers nil
   "Last peers used, both sender and receiver.
 Those are used for /MSG destination shortcuts.")
 
@@ -535,6 +548,7 @@ TLS (see `erc-session-client-certificate' for more 
details)."
       (error "Connection attempt failed"))
     ;; Misc server variables
     (with-current-buffer buffer
+      (setq erc-server-filter-data nil)
       (setq erc-server-process process)
       (setq erc-server-quitting nil)
       (setq erc-server-reconnecting nil
@@ -548,7 +562,7 @@ TLS (see `erc-session-client-certificate' for more 
details)."
         (setq erc-server-last-received-time time))
       (setq erc-server-lines-sent 0)
       ;; last peers (sender and receiver)
-      (setq erc-server-last-peers '(nil . nil)))
+      (setq erc-server-last-peers (cons nil nil)))
     ;; we do our own encoding and decoding
     (when (fboundp 'set-process-coding-system)
       (set-process-coding-system process 'raw-text))
@@ -584,7 +598,13 @@ Make sure you are in an ERC buffer when running this."
       (let ((erc-server-connect-function (or erc-session-connector
                                              #'erc-open-network-stream)))
         (erc-open erc-session-server erc-session-port erc-server-current-nick
-                  erc-session-user-full-name t erc-session-password)))))
+                  erc-session-user-full-name t erc-session-password
+                  nil nil nil erc-session-client-certificate
+                  erc-session-username
+                  (erc-networks--id-given erc-networks--id))
+        (unless (with-suppressed-warnings ((obsolete erc-reuse-buffers))
+                  erc-reuse-buffers)
+          (cl-assert (not (eq buffer (current-buffer)))))))))
 
 (defun erc-server-delayed-reconnect (buffer)
   (if (buffer-live-p buffer)
@@ -695,6 +715,39 @@ Conditionally try to reconnect and take appropriate 
action."
       ;; unexpected disconnect
       (erc-process-sentinel-2 event buffer))))
 
+(defun erc--unhide-prompt ()
+  (remove-hook 'pre-command-hook #'erc--unhide-prompt-on-self-insert t)
+  (when (and (marker-position erc-insert-marker)
+             (marker-position erc-input-marker))
+    (with-silent-modifications
+      (remove-text-properties erc-insert-marker erc-input-marker
+                              '(display nil)))))
+
+(defun erc--unhide-prompt-on-self-insert ()
+  (when (and (eq this-command #'self-insert-command)
+             (or (eobp) (= (point) erc-input-marker)))
+    (erc--unhide-prompt)))
+
+(defun erc--hide-prompt (proc)
+  (erc-with-all-buffers-of-server
+      proc nil ; sorta wish this was indent 2
+      (when (and erc-hide-prompt
+                 (or (eq erc-hide-prompt t)
+                     ;; FIXME use `erc--target' after bug#48598
+                     (memq (if (erc-default-target)
+                               (if (erc-channel-p (car erc-default-recipients))
+                                   'channel
+                                 'query)
+                             'server)
+                           erc-hide-prompt))
+                 (marker-position erc-insert-marker)
+                 (marker-position erc-input-marker)
+                 (get-text-property erc-insert-marker 'erc-prompt))
+        (with-silent-modifications
+          (add-text-properties erc-insert-marker (1- erc-input-marker)
+                               `(display ,erc-prompt-hidden)))
+        (add-hook 'pre-command-hook #'erc--unhide-prompt-on-self-insert 0 t))))
+
 (defun erc-process-sentinel (cproc event)
   "Sentinel function for ERC process."
   (let ((buf (process-buffer cproc)))
@@ -717,11 +770,8 @@ Conditionally try to reconnect and take appropriate 
action."
           (dolist (buf (erc-buffer-filter (lambda () (boundp 
'erc-channel-users)) cproc))
             (with-current-buffer buf
               (setq erc-channel-users (make-hash-table :test 'equal))))
-          ;; Remove the prompt
-          (goto-char (or (marker-position erc-input-marker) (point-max)))
-          (forward-line 0)
-          (erc-remove-text-properties-region (point) (point-max))
-          (delete-region (point) (point-max))
+          ;; Hide the prompt
+          (erc--hide-prompt cproc)
           ;; Decide what to do with the buffer
           ;; Restart if disconnected
           (erc-process-sentinel-1 event buf))))))
@@ -772,11 +822,12 @@ Use DISPLAY-FN to show the results."
         (erc-split-line text)))
 
 ;; From Circe, with modifications
-(defun erc-server-send (string &optional forcep target)
+(defun erc-server-send (string &optional force target)
   "Send STRING to the current server.
-If FORCEP is non-nil, no flood protection is done - the string is
-sent directly.  This might cause the messages to arrive in a wrong
-order.
+When FORCE is non-nil, bypass flood protection so that STRING is
+sent directly without modifying the queue.  When FORCE is the
+symbol `no-penalty', exempt this round from accumulating a
+timeout penalty.
 
 If TARGET is specified, look up encoding information for that
 channel in `erc-encoding-coding-alist' or
@@ -792,11 +843,11 @@ protection algorithm."
     (if (erc-server-process-alive)
         (erc-with-server-buffer
           (let ((str (concat string "\r\n")))
-            (if forcep
+            (if force
                 (progn
-                  (setq erc-server-flood-last-message
-                        (+ erc-server-flood-penalty
-                           erc-server-flood-last-message))
+                  (unless (eq force 'no-penalty)
+                    (cl-incf erc-server-flood-last-message
+                             erc-server-flood-penalty))
                   (erc-log-irc-protocol str 'outbound)
                   (condition-case nil
                       (progn
@@ -888,21 +939,20 @@ be used.  If the target is \".\", the last person you've 
sent a message
 to will be used."
   (cond
    ((string-match "^\\s-*\\(\\S-+\\) ?\\(.*\\)" line)
-    (let ((tgt (match-string 1 line))
-          (s (match-string 2 line)))
+    (let* ((tgt (match-string 1 line))
+           (s (match-string 2 line))
+           (server-buffer (erc-server-buffer))
+           (peers (buffer-local-value 'erc-server-last-peers server-buffer)))
       (erc-log (format "cmd: MSG(%s): [%s] %s" message-command tgt s))
       (cond
        ((string= tgt ",")
-        (if (car erc-server-last-peers)
-            (setq tgt (car erc-server-last-peers))
-          (setq tgt nil)))
+        (setq tgt (car peers)))
        ((string= tgt ".")
-        (if (cdr erc-server-last-peers)
-            (setq tgt (cdr erc-server-last-peers))
-          (setq tgt nil))))
+        (setq tgt (cdr peers))))
       (cond
        (tgt
-        (setcdr erc-server-last-peers tgt)
+        (with-current-buffer server-buffer
+          (setq erc-server-last-peers (cons (car peers) tgt)))
         (erc-server-send (format "%s %s :%s" message-command tgt s)
                          force))
        (t
@@ -961,21 +1011,15 @@ PROCs `process-buffer' is `current-buffer' when this 
function is called."
     (save-match-data
       (let* ((tag-list (when (eq (aref string 0) ?@)
                          (substring string 1
-                                    (if (>= emacs-major-version 28)
-                                        (string-search " " string)
-                                      (string-match " " string)))))
+                                    (string-search " " string))))
              (msg (make-erc-response :unparsed string :tags (when tag-list
                                                               (erc-parse-tags
                                                                tag-list))))
              (string (if tag-list
-                         (substring string (+ 1 (if (>= emacs-major-version 28)
-                                                    (string-search " " string)
-                                                  (string-match " " string))))
+                         (substring string (+ 1 (string-search " " string)))
                        string))
              (posn (if (eq (aref string 0) ?:)
-                       (if (>= emacs-major-version 28)
-                           (string-search " " string)
-                         (string-match " " string))
+                       (string-search " " string)
                      0)))
 
         (setf (erc-response.sender msg)
@@ -985,9 +1029,7 @@ PROCs `process-buffer' is `current-buffer' when this 
function is called."
 
         (setf (erc-response.command msg)
               (let* ((bposn (string-match "[^ \n]" string posn))
-                     (eposn (if (>= emacs-major-version 28)
-                                (string-search " " string bposn)
-                              (string-match " " string bposn))))
+                     (eposn (string-search " " string bposn)))
                 (setq posn (and eposn
                                 (string-match "[^ \n]" string eposn)))
                 (substring string bposn eposn)))
@@ -995,9 +1037,7 @@ PROCs `process-buffer' is `current-buffer' when this 
function is called."
         (while (and posn
                     (not (eq (aref string posn) ?:)))
           (push (let* ((bposn posn)
-                       (eposn (if (>= emacs-major-version 28)
-                                  (string-search " " string bposn)
-                                (string-match " " string bposn))))
+                       (eposn (string-search " " string bposn)))
                   (setq posn (and eposn
                                   (string-match "[^ \n]" string eposn)))
                   (substring string bposn eposn))
@@ -1283,14 +1323,11 @@ add things to `%s' instead."
         (let* ((str (cond
                      ;; If I have joined a channel
                      ((erc-current-nick-p nick)
-                      (setq buffer (erc-open erc-session-server 
erc-session-port
-                                             nick erc-session-user-full-name
-                                             nil nil
-                                             (list chnl) chnl
-                                             erc-server-process))
-                      (when buffer
+                      (when (setq buffer (erc--open-target chnl))
                         (set-buffer buffer)
-                        (erc-add-default-channel chnl)
+                        (with-suppressed-warnings
+                            ((obsolete erc-add-default-channel))
+                          (erc-add-default-channel chnl))
                         (erc-server-send (format "MODE %s" chnl)))
                       (erc-with-buffer (chnl proc)
                         (erc-channel-begin-receiving-names))
@@ -1327,7 +1364,8 @@ add things to `%s' instead."
         (erc-with-buffer
             (buffer)
           (erc-remove-channel-users))
-        (erc-delete-default-channel ch buffer)
+        (with-suppressed-warnings ((obsolete erc-delete-default-channel))
+          (erc-delete-default-channel ch buffer))
         (erc-update-mode-line buffer))
        ((string= nick (erc-current-nick))
         (erc-display-message
@@ -1375,19 +1413,27 @@ add things to `%s' instead."
       ;; sent to the correct nick. also add to bufs, since the user will want
       ;; to see the nick change in the query, and if it's a newly begun query,
       ;; erc-channel-users won't contain it
-      (erc-buffer-filter
-       (lambda ()
-         (when (equal (erc-default-target) nick)
-           (setq erc-default-recipients
-                 (cons nn (cdr erc-default-recipients)))
-           (rename-buffer nn t)         ; bug#12002
-           (erc-update-mode-line)
-           (cl-pushnew (current-buffer) bufs))))
+      ;;
+      ;; Possibly still relevant: bug#12002
+      (when-let ((buf (erc-get-buffer nick erc-server-process))
+                 (tgt (erc--target-from-string nn)))
+        (with-current-buffer buf
+          (setq erc-default-recipients (cons nn (cdr erc-default-recipients))
+                erc--target tgt))
+        (with-current-buffer (erc-get-buffer-create erc-session-server
+                                                    erc-session-port nil tgt
+                                                    (erc-networks--id-given
+                                                     erc-networks--id))
+          ;; Current buffer is among bufs
+          (erc-update-mode-line)))
       (erc-update-user-nick nick nn host nil nil login)
       (cond
        ((string= nick (erc-current-nick))
         (cl-pushnew (erc-server-buffer) bufs)
         (erc-set-current-nick nn)
+        ;; Rename session, possibly rename server buf and all targets
+        (when (erc-network)
+          (erc-networks--id-reload erc-networks--id proc parsed))
         (erc-update-mode-line)
         (setq erc-nick-change-attempt-count 0)
         (setq erc-default-nicks (if (consp erc-nick) erc-nick (list erc-nick)))
@@ -1416,7 +1462,8 @@ add things to `%s' instead."
         (erc-with-buffer
             (buffer)
           (erc-remove-channel-users))
-        (erc-delete-default-channel chnl buffer)
+        (with-suppressed-warnings ((obsolete erc-delete-default-channel))
+          (erc-delete-default-channel chnl buffer))
         (erc-update-mode-line buffer)
         (when erc-kill-buffer-on-part
           (kill-buffer buffer))))))
@@ -1426,7 +1473,7 @@ add things to `%s' instead."
   (let ((pinger (car (erc-response.command-args parsed))))
     (erc-log (format "PING: %s" pinger))
     ;; ping response to the server MUST be forced, or you can lose big
-    (erc-server-send (format "PONG :%s" pinger) t)
+    (erc-server-send (format "PONG :%s" pinger) 'no-penalty)
     (when erc-verbose-server-ping
       (erc-display-message
        parsed 'error proc
@@ -1467,8 +1514,18 @@ add things to `%s' instead."
              fnick)
         (setf (erc-response.contents parsed) msg)
         (setq buffer (erc-get-buffer (if privp nick tgt) proc))
+        ;; Even worth checking for empty target here? (invalid anyway)
+        (unless (or buffer noticep (string-empty-p tgt) (eq ?$ (aref tgt 0))
+                    (erc-is-message-ctcp-and-not-action-p msg))
+          (if privp
+              (when erc-auto-query
+                (let ((erc-join-buffer erc-auto-query))
+                  (setq buffer (erc--open-target nick))))
+            ;; A channel buffer has been killed but is still joined
+            (setq buffer (erc--open-target tgt))))
         (when buffer
           (with-current-buffer buffer
+            (when privp (erc--unhide-prompt))
             ;; update the chat partner info.  Add to the list if private
             ;; message.  We will accumulate private identities indefinitely
             ;; at this point.
@@ -1484,7 +1541,7 @@ add things to `%s' instead."
                     (erc-process-ctcp-reply proc parsed nick login host
                                             (match-string 1 msg)))))
          (t
-          (setcar erc-server-last-peers nick)
+          (setq erc-server-last-peers (cons nick (cdr erc-server-last-peers)))
           (setq s (erc-format-privmessage
                    (or fnick nick) msg
                    ;; If buffer is a query buffer,
@@ -1501,13 +1558,7 @@ add things to `%s' instead."
                                     s parsed buffer nick)
                 (run-hook-with-args-until-success
                  'erc-echo-notice-hook s parsed buffer nick))
-            (erc-display-message parsed nil buffer s)))
-        (when (string= cmd "PRIVMSG")
-          (erc-auto-query proc parsed))))))
-
-;; FIXME: need clean way of specifying extra hooks in
-;; define-erc-response-handler.
-(add-hook 'erc-server-PRIVMSG-functions #'erc-auto-query)
+            (erc-display-message parsed nil buffer s)))))))
 
 (define-erc-response-handler (QUIT)
   "Another user has quit IRC." nil
@@ -1580,6 +1631,68 @@ Then display the welcome message."
      ?U (nth 3 (erc-response.command-args parsed))
      ?C (nth 4 (erc-response.command-args parsed)))))
 
+(defun erc--parse-isupport-value (value)
+  "Return list of unescaped components from an \"ISUPPORT\" VALUE."
+  ;; https://tools.ietf.org/html/draft-brocklesby-irc-isupport-03#section-2
+  ;;
+  ;; > The server SHOULD send "X", not "X="; this is the normalized form.
+  ;;
+  ;; Note: for now, assume the server will only send non-empty values,
+  ;; possibly with printable ASCII escapes.  Though in practice, the
+  ;; only two escapes we're likely to see are backslash and space,
+  ;; meaning the pattern is too liberal.
+  (let (case-fold-search)
+    (mapcar
+     (lambda (v)
+       (let ((start 0)
+             m
+             c)
+         (while (and (< start (length v))
+                     (string-match "[\\]x[0-9A-F][0-9A-F]" v start))
+           (setq m (substring v (+ 2 (match-beginning 0)) (match-end 0))
+                 c (string-to-number m 16))
+           (if (<= ?\  c ?~)
+               (setq v (concat (substring v 0 (match-beginning 0))
+                               (string c)
+                               (substring v (match-end 0)))
+                     start (- (match-end 0) 3))
+             (setq start (match-end 0))))
+         v))
+     (if (string-search "," value)
+         (split-string value ",")
+       (list value)))))
+
+(defmacro erc--with-memoization (table &rest forms)
+  "Adapter to be migrated to erc-compat."
+  (declare (indent defun))
+  `(cond
+    ((fboundp 'with-memoization)
+     (with-memoization ,table ,@forms)) ; 29.1
+    ((fboundp 'cl--generic-with-memoization)
+     (cl--generic-with-memoization ,table ,@forms))
+    (t ,@forms)))
+
+(defun erc--get-isupport-entry (key &optional single)
+  "Return an item for \"ISUPPORT\" token KEY, a symbol.
+When a lookup fails return nil.  Otherwise return a list whose
+CAR is KEY and whose CDR is zero or more strings.  With SINGLE,
+just return the first value, if any.  The latter is potentially
+ambiguous and only useful for tokens supporting a single
+primitive value."
+  (if-let* ((table (or erc--isupport-params
+                       (erc-with-server-buffer erc--isupport-params)))
+            (value (erc--with-memoization (gethash key table)
+                     (when-let ((v (assoc (symbol-name key)
+                                          erc-server-parameters)))
+                       (if (cdr v)
+                           (erc--parse-isupport-value (cdr v))
+                         '--empty--)))))
+      (pcase value
+        ('--empty-- (unless single (list key)))
+        (`(,head . ,_) (if single head (cons key value))))
+    (when table
+      (remhash key table))))
+
 (define-erc-response-handler (005)
   "Set the variable `erc-server-parameters' and display the received message.
 
@@ -1591,21 +1704,25 @@ certain commands are accepted and more.  See 
documentation for
 
 A server may send more than one 005 message."
   nil
-  (let ((line (mapconcat #'identity
-                         (setf (erc-response.command-args parsed)
-                               (cdr (erc-response.command-args parsed)))
-                         " ")))
-    (while (erc-response.command-args parsed)
-      (let ((section (pop (erc-response.command-args parsed))))
-        ;; fill erc-server-parameters
-        (when (string-match "^\\([A-Z]+\\)=\\(.*\\)$\\|^\\([A-Z]+\\)$"
+  (unless erc--isupport-params
+    (setq erc--isupport-params (make-hash-table)))
+  (let* ((args (cdr (erc-response.command-args parsed)))
+         (line (string-join args " ")))
+    (while args
+      (let ((section (pop args))
+            key
+            value
+            negated)
+        (when (string-match "^\\([A-Z]+\\)=\\(.*\\)$\\|^\\(-\\)?\\([A-Z]+\\)$"
                             section)
-          (add-to-list 'erc-server-parameters
-                       `(,(or (match-string 1 section)
-                              (match-string 3 section))
-                         .
-                         ,(match-string 2 section))))))
-    (erc-display-message parsed 'notice proc line)))
+          (setq key (or (match-string 1 section) (match-string 4 section))
+                value (match-string 2 section)
+                negated (and (match-string 3 section) '-))
+          (setf (alist-get key erc-server-parameters '- 'remove #'equal)
+                (or value negated))
+          (remhash (intern key) erc--isupport-params))))
+    (erc-display-message parsed 'notice proc line)
+    nil))
 
 (define-erc-response-handler (221)
   "Display the current user modes." nil
diff --git a/lisp/erc/erc-button.el b/lisp/erc/erc-button.el
index aeada705c4..bccf0e6f1f 100644
--- a/lisp/erc/erc-button.el
+++ b/lisp/erc/erc-button.el
@@ -71,7 +71,7 @@
   "Face used for highlighting buttons in ERC buffers.
 
 A button is a piece of text that you can activate by pressing
-`RET' or `mouse-2' above it.  See also `erc-button-keymap'."
+\\`RET' or `mouse-2' above it.  See also `erc-button-keymap'."
   :type 'face
   :group 'erc-faces)
 
diff --git a/lisp/erc/erc-capab.el b/lisp/erc/erc-capab.el
index 8d0f40af99..c590b45fd2 100644
--- a/lisp/erc/erc-capab.el
+++ b/lisp/erc/erc-capab.el
@@ -137,7 +137,7 @@ These arguments are sent to this function when called as a 
hook in
              ;; could possibly check for '("IRCD" . "dancer") in
              ;; `erc-server-parameters' instead of looking for a specific name
              ;; in `erc-server-version'
-             (assoc "CAPAB" erc-server-parameters))
+             (erc--get-isupport-entry 'CAPAB))
     (erc-log "Sending CAPAB IDENTIFY-MSG and IDENTIFY-CTCP")
     (erc-server-send "CAPAB IDENTIFY-MSG")
     (erc-server-send "CAPAB IDENTIFY-CTCP")
diff --git a/lisp/erc/erc-compat.el b/lisp/erc/erc-compat.el
index 16cfb15a5a..8a00e711ac 100644
--- a/lisp/erc/erc-compat.el
+++ b/lisp/erc/erc-compat.el
@@ -25,8 +25,14 @@
 
 ;; This mostly defines stuff that cannot be worked around easily.
 
+;; ERC depends on the `compat' library from GNU ELPA for supporting
+;; older versions of Emacs.  See this discussion for additional info:
+;; https://lists.gnu.org/archive/html/emacs-devel/2022-07/msg00512.html
+
 ;;; Code:
 
+(require 'compat nil 'noerror)
+
 ;;;###autoload(autoload 'erc-define-minor-mode "erc-compat")
 (define-obsolete-function-alias 'erc-define-minor-mode
   #'define-minor-mode "28.1")
diff --git a/lisp/erc/erc-dcc.el b/lisp/erc/erc-dcc.el
index ff486b2d4e..dd70bfb7b7 100644
--- a/lisp/erc/erc-dcc.el
+++ b/lisp/erc/erc-dcc.el
@@ -191,9 +191,7 @@ compared with `erc-nick-equal-p' which is IRC 
case-insensitive."
                   test (cadr (plist-member elt prop)))
             ;; if the property exists and is equal, we continue, else, try the
             ;; next element of the list
-            (or (and (eq prop :nick) (if (>= emacs-major-version 28)
-                                         (string-search "!" val)
-                                       (string-match "!" val))
+            (or (and (eq prop :nick) (string-search "!" val)
                      test (string-equal test val))
                 (and (eq prop :nick)
                      test val
@@ -359,10 +357,7 @@ Returns the newly created subprocess, or nil."
                                         :server t))
             (when (processp process)
               (when (fboundp 'set-process-coding-system)
-                (set-process-coding-system process 'binary 'binary))
-              (when (fboundp 'set-process-filter-multibyte)
-                (with-no-warnings       ; obsolete since 23.1
-                  (set-process-filter-multibyte process nil)))))
+                (set-process-coding-system process 'binary 'binary))))
         (file-error
          (unless (and (string= "Cannot bind server socket" (nth 1 err))
                       (string= "address already in use" (downcase (nth 2 
err))))
@@ -391,7 +386,7 @@ the accepted connection."
 (defcustom erc-dcc-get-default-directory nil
   "Default directory for incoming DCC file transfers.
 If this is nil, then the current value of `default-directory' is used."
-  :type '(choice (const nil :tag "Default directory") directory))
+  :type '(choice (const :value nil :tag "Default directory") directory))
 
 ;;;###autoload
 (defun erc-cmd-DCC (cmd &rest args)
@@ -659,13 +654,7 @@ that subcommand."
 
 (define-inline erc-dcc-unquote-filename (filename)
   (inline-quote
-   (if (>= emacs-major-version 28)
-       (string-replace
-        "\\\\" "\\"
-        (string-replace "\\\"" "\"" ,filename))
-     (replace-regexp-in-string
-      "\\\\\\\\" "\\"
-      (replace-regexp-in-string "\\\\\"" "\"" ,filename t t) t t))))
+   (string-replace "\\\\" "\\" (string-replace "\\\"" "\"" ,filename))))
 
 (defun erc-dcc-handle-ctcp-send (proc query nick login host to)
   "This is called if a CTCP DCC SEND subcommand is sent to the client.
@@ -987,7 +976,7 @@ The contents of the BUFFER will then be erased."
 
 ;; If people really need this, we can convert it into a proper option.
 
-(defvar erc-dcc--X-send-final-turbo-ack nil
+(defvar erc-dcc--send-final-turbo-ack nil
   "Workaround for maverick turbo senders that only require a final ACK.
 The only known culprit is WeeChat, with its xfer.network.fast_send
 option, which is on by default.  Leaving this set to nil and calling
@@ -1032,7 +1021,7 @@ rather than every 1024 byte block, but nobody seems to 
care."
        ;; Some senders want us to hang up.  Only observed w. TSEND.
        ((and (plist-get erc-dcc-entry-data :turbo)
              (= received-bytes (plist-get erc-dcc-entry-data :size)))
-        (when erc-dcc--X-send-final-turbo-ack
+        (when erc-dcc--send-final-turbo-ack
           (process-send-string proc (erc-pack-int received-bytes)))
         (delete-process proc))
        ((not (or (plist-get erc-dcc-entry-data :turbo)
@@ -1182,18 +1171,18 @@ other client."
          (proc (plist-get entry :peer))
          (parent-proc (plist-get entry :parent)))
     (erc-setup-buffer buffer)
-    ;; buffer is now the current buffer.
-    (erc-dcc-chat-mode)
-    (setq erc-server-process parent-proc)
-    (setq erc-dcc-from nick)
-    (setq erc-dcc-entry-data entry)
-    (setq erc-dcc-unprocessed-output "")
-    (setq erc-insert-marker (point-max-marker))
-    (setq erc-input-marker (make-marker))
-    (erc-display-prompt buffer (point-max))
-    (set-process-buffer proc buffer)
-    (add-hook 'kill-buffer-hook #'erc-dcc-chat-buffer-killed nil t)
-    (run-hook-with-args 'erc-dcc-chat-connect-hook proc)
+    (with-current-buffer buffer
+      (erc-dcc-chat-mode)
+      (setq erc-server-process parent-proc
+            erc-dcc-from nick
+            erc-dcc-entry-data entry
+            erc-dcc-unprocessed-output ""
+            erc-insert-marker (point-max-marker)
+            erc-input-marker (make-marker))
+      (erc-display-prompt buffer (point-max))
+      (set-process-buffer proc buffer)
+      (add-hook 'kill-buffer-hook #'erc-dcc-chat-buffer-killed nil t)
+      (run-hook-with-args 'erc-dcc-chat-connect-hook proc))
     buffer))
 
 (defun erc-dcc-chat-accept (entry parent-proc)
diff --git a/lisp/erc/erc-join.el b/lisp/erc/erc-join.el
index b9788c192b..b4044548e8 100644
--- a/lisp/erc/erc-join.el
+++ b/lisp/erc/erc-join.el
@@ -33,8 +33,6 @@
 ;;; Code:
 
 (require 'erc)
-(require 'auth-source)
-(require 'erc-networks)
 
 (defgroup erc-autojoin nil
   "Enable autojoining."
@@ -57,11 +55,16 @@
 Every element in the alist has the form (SERVER . CHANNELS).
 SERVER is a regexp matching the server, and channels is the list
 of channels to join.  SERVER can also be a symbol, in which case
-it is matched against the value of `erc-network' instead of
+it's matched against a non-nil `:id' passed to `erc' or `erc-tls'
+when connecting or the value of the current `erc-network' instead of
 `erc-server-announced-name' or `erc-session-server' (this can be
 useful when connecting to an IRC proxy that relays several
 networks under the same server).
 
+Note that for historical reasons, this option is mutated at runtime,
+which is regrettable but here to stay.  Please double check the value
+before saving it to a `custom-file'.
+
 If the channel(s) require channel keys for joining, the passwords
 are found via auth-source.  For instance, if you use ~/.authinfo
 as your auth-source backend, then put something like the
@@ -123,33 +126,32 @@ This is called from a timer set up by 
`erc-autojoin-channels'."
       (erc-autojoin-channels server nick))))
 
 (defun erc-autojoin-server-match (candidate)
-  "Match the current network or server against CANDIDATE.
-This should be a key from `erc-autojoin-channels-alist'."
-  (or (eq candidate (erc-network))
-      (and (stringp candidate)
-          (string-match-p candidate
-                           (or erc-server-announced-name
-                              erc-session-server)))))
+  "Match the current network ID or server against CANDIDATE.
+CANDIDATE is a key from `erc-autojoin-channels-alist'.  Return the
+matching entity, either a string or a non-nil symbol (in the case of a
+network or a network ID).  Return nil on failure."
+  (if (symbolp candidate)
+      (eq (or (erc-networks--id-given erc-networks--id) (erc-network))
+          candidate)
+    (when (stringp candidate)
+      (string-match-p candidate (or erc-server-announced-name
+                                    erc-session-server)))))
+
+(defun erc-autojoin--join ()
+  ;; This is called in the server buffer
+  (pcase-dolist (`(,name . ,channels) erc-autojoin-channels-alist)
+    (when-let ((match (erc-autojoin-server-match name)))
+      (dolist (chan channels)
+        (let ((buf (erc-get-buffer chan erc-server-process)))
+          (unless (and buf (with-current-buffer buf
+                             (erc--current-buffer-joined-p)))
+            (erc-server-join-channel nil chan)))))))
 
 (defun erc-autojoin-after-ident (_network _nick)
   "Autojoin channels in `erc-autojoin-channels-alist'.
 This function is run from `erc-nickserv-identified-hook'."
-  (if erc--autojoin-timer
-      (setq erc--autojoin-timer
-           (cancel-timer erc--autojoin-timer)))
   (when (eq erc-autojoin-timing 'ident)
-    (let ((server (or erc-session-server erc-server-announced-name))
-         (joined (mapcar (lambda (buf)
-                           (with-current-buffer buf (erc-default-target)))
-                         (erc-channel-list erc-server-process))))
-      ;; We may already be in these channels, e.g. because the
-      ;; autojoin timer went off.
-      (dolist (l erc-autojoin-channels-alist)
-       (when (erc-autojoin-server-match (car l))
-         (dolist (chan (cdr l))
-           (unless (erc-member-ignore-case chan joined)
-             (erc-server-join-channel server chan)))))))
-  nil)
+    (erc-autojoin--join)))
 
 (defun erc-autojoin-channels (server nick)
   "Autojoin channels in `erc-autojoin-channels-alist'."
@@ -162,24 +164,7 @@ This function is run from `erc-nickserv-identified-hook'."
                              #'erc-autojoin-channels-delayed
                              server nick (current-buffer))))
     ;; `erc-autojoin-timing' is `connect':
-    (let ((server (or erc-session-server erc-server-announced-name)))
-      (dolist (l erc-autojoin-channels-alist)
-        (when (erc-autojoin-server-match (car l))
-         (dolist (chan (cdr l))
-           (let ((buffer
-                   (car (erc-buffer-filter
-                         (lambda ()
-                           (let ((current (erc-default-target)))
-                             (and (stringp current)
-                                  (erc-autojoin-server-match (car l))
-                                  (string-equal (erc-downcase chan)
-                                                (erc-downcase current)))))))))
-             (when (or (not buffer)
-                       (not (with-current-buffer buffer
-                              (erc-server-process-alive))))
-               (erc-server-join-channel server chan))))))))
-  ;; Return nil to avoid stomping on any other hook funcs.
-  nil)
+    (erc-autojoin--join)))
 
 (defun erc-autojoin-current-server ()
   "Compute the current server for lookup in `erc-autojoin-channels-alist'.
@@ -190,24 +175,29 @@ Respects `erc-autojoin-domain-only'."
        (match-string 1 server)
       server)))
 
+(defun erc-autojoin--mutate (proc parsed remove)
+  (when-let* ((nick (car (erc-parse-user (erc-response.sender parsed))))
+              ((erc-current-nick-p nick))
+              (chnl (car (erc-response.command-args parsed)))
+              (elem (or (and (erc--valid-local-channel-p chnl)
+                             (regexp-quote erc-server-announced-name))
+                        (erc-networks--id-given erc-networks--id)
+                        (erc-network)
+                        (with-current-buffer (process-buffer proc)
+                          (erc-autojoin-current-server))))
+              (test (if (symbolp elem) #'eq #'equal)))
+    (if remove
+        (let ((cs (delete chnl (assoc-default elem erc-autojoin-channels-alist
+                                              test))))
+          (setf (alist-get elem erc-autojoin-channels-alist nil (null cs) test)
+                cs))
+      (cl-pushnew chnl
+                  (alist-get elem erc-autojoin-channels-alist nil nil test)
+                  :test #'equal))))
+
 (defun erc-autojoin-add (proc parsed)
   "Add the channel being joined to `erc-autojoin-channels-alist'."
-  (let* ((chnl (erc-response.contents parsed))
-        (nick (car (erc-parse-user (erc-response.sender parsed))))
-        (server (with-current-buffer (process-buffer proc)
-                  (erc-autojoin-current-server))))
-    (when (erc-current-nick-p nick)
-      (let ((elem (or (assoc (erc-network) erc-autojoin-channels-alist)
-                     (assoc server erc-autojoin-channels-alist))))
-       (if elem
-           (unless (member chnl (cdr elem))
-             (setcdr elem (cons chnl (cdr elem))))
-         ;; This always keys on server, not network -- user can
-         ;; override by simply adding a network to
-         ;; `erc-autojoin-channels-alist'
-         (setq erc-autojoin-channels-alist
-               (cons (list server chnl)
-                     erc-autojoin-channels-alist))))))
+  (erc-autojoin--mutate proc parsed nil)
   ;; We must return nil to tell ERC to continue running the other
   ;; functions.
   nil)
@@ -216,18 +206,7 @@ Respects `erc-autojoin-domain-only'."
 
 (defun erc-autojoin-remove (proc parsed)
   "Remove the channel being left from `erc-autojoin-channels-alist'."
-  (let* ((chnl (car (erc-response.command-args parsed)))
-        (nick (car (erc-parse-user (erc-response.sender parsed))))
-        (server (with-current-buffer (process-buffer proc)
-                  (erc-autojoin-current-server))))
-    (when (erc-current-nick-p nick)
-      (let ((elem (or (assoc (erc-network) erc-autojoin-channels-alist)
-                     (assoc server erc-autojoin-channels-alist))))
-       (when elem
-         (setcdr elem (delete chnl (cdr elem)))
-         (unless (cdr elem)
-           (setq erc-autojoin-channels-alist
-                 (delete elem erc-autojoin-channels-alist)))))))
+  (erc-autojoin--mutate proc parsed 'remove)
   ;; We must return nil to tell ERC to continue running the other
   ;; functions.
   nil)
diff --git a/lisp/erc/erc-networks.el b/lisp/erc/erc-networks.el
index 553697ae84..c54b12fcb0 100644
--- a/lisp/erc/erc-networks.el
+++ b/lisp/erc/erc-networks.el
@@ -731,6 +731,466 @@ MATCHER is used to find a corresponding network to a 
server while
 (defvar-local erc-network nil
   "The name of the network you are connected to (a symbol).")
 
+
+;;;; Identifying session context
+
+;; This section is concerned with identifying and managing the
+;; relationship between an IRC connection and its unique identity on a
+;; given network (as seen by that network's nick-granting system).
+;; This relationship is quasi-permanent and transcends IRC connections
+;; and Emacs sessions.  As of mid 2022, only nicknames matter, and
+;; whether a user is authenticated does not directly impact network
+;; identity from a client's perspective.  However, ERC must be
+;; equipped to adapt should this ever change.  And while a connection
+;; is normally associated with exactly one nick, some networks (or
+;; intermediaries) may allow multiple clients to control the same nick
+;; by combining instance activity into a single logical client.  ERC
+;; must be limber enough to handle such situations.
+
+(defvar-local erc-networks--id nil
+  "Server-local instance of its namesake struct.
+Also shared among all target buffers for a given connection.  See
+\\[describe-symbol] `erc-networks--id' for more.")
+
+(cl-defstruct erc-networks--id
+  "Persistent identifying info for a network presence.
+
+Here, \"presence\" refers to some local state representing a
+client's existence on a network.  Some clients refer to this as a
+\"context\" or a \"net-id\".  The management of this state
+involves tracking associated buffers and what they're displaying.
+Since a presence can outlast physical connections and survive
+changes in back-end transports (and even outlive Emacs sessions),
+its identity must be resilient.
+
+Essential to this notion of an enduring existence on a network is
+ensuring recovery from the loss of a server buffer.  Thus, any
+useful identifier must be shared among server and target buffers
+to allow for reassociation.  Beyond that, it must ideally be
+derivable from the same set of connection parameters.  See the
+constructor `erc-networks--id-create' for more info."
+  (ts nil :type float :read-only t :documentation "Creation timestamp.")
+  (symbol nil :type symbol :documentation "ID as a symbol."))
+
+(cl-defstruct (erc-networks--id-fixed
+               (:include erc-networks--id)
+               (:constructor erc-networks--id-fixed-create
+                             (given &aux (ts (float-time)) (symbol given)))))
+
+(cl-defstruct (erc-networks--id-qualifying
+               (:include erc-networks--id)
+               (:constructor erc-networks--id-qualifying-create
+                             (&aux
+                              (ts (float-time))
+                              (parts (erc-networks--id-qualifying-init-parts))
+                              (symbol (erc-networks--id-qualifying-init-symbol
+                                       parts))
+                              (len 1))))
+  "A session context composed of hierarchical connection parameters.
+Two identifiers are considered equivalent when their non-empty
+`parts' slots compare equal.  Related identifiers share a common
+prefix of `parts' taken from connection parameters (given or
+discovered).  An identifier's unique `symbol', intended for
+display purposes, is created by concatenating the shortest common
+prefix among its relatives.  For example, related presences [b a
+r d o] and [b a z a r] would have symbols b/a/r and b/a/z
+respectively.  The separator is given by `erc-networks--id-sep'."
+  (parts nil :type sequence ; a vector of atoms
+         :documentation "Sequence of identifying components.")
+  (len 0 :type integer
+       :documentation "Length of active `parts' interval."))
+
+;; For now, please use this instead of `erc-networks--id-fixed-p'.
+(cl-defgeneric erc-networks--id-given (net-id)
+  "Return the preassigned identifier for a network presence, if any.
+This may have originated from an `:id' arg to entry-point commands
+`erc-tls' or `erc'.")
+
+(cl-defmethod erc-networks--id-given ((_ erc-networks--id))
+  nil)
+
+(cl-defmethod erc-networks--id-given ((nid erc-networks--id-fixed))
+  (erc-networks--id-symbol nid))
+
+(cl-generic-define-context-rewriter erc-obsolete-var (var spec)
+  `((with-suppressed-warnings ((obsolete ,var)) ,var) ,spec))
+
+;; As a catch-all, derive the symbol from the unquoted printed repr.
+(cl-defgeneric erc-networks--id-create (id)
+  "Invoke an appropriate constructor for an `erc-networks--id' object."
+  (erc-networks--id-fixed-create (intern (format "%s" id))))
+
+;; When a given ID is a symbol, trust it unequivocally.
+(cl-defmethod erc-networks--id-create ((id symbol))
+  (erc-networks--id-fixed-create id))
+
+;; Otherwise, use an adaptive name derived from network params.
+(cl-defmethod erc-networks--id-create ((_ null))
+  (erc-networks--id-qualifying-create))
+
+;; But honor an explicitly set `erc-rename-buffers' (compat).
+(cl-defmethod erc-networks--id-create
+  ((_ null) &context (erc-obsolete-var erc-rename-buffers null))
+  (erc-networks--id-fixed-create (intern (buffer-name))))
+
+;; But honor an explicitly set `erc-reuse-buffers' (compat).
+(cl-defmethod erc-networks--id-create
+  ((_ null) &context (erc-obsolete-var erc-reuse-buffers null))
+  (erc-networks--id-fixed-create (intern (buffer-name))))
+
+(cl-defmethod erc-networks--id-create
+  ((_ symbol) &context (erc-obsolete-var erc-reuse-buffers null))
+  (erc-networks--id-fixed-create (intern (buffer-name))))
+
+(cl-defgeneric erc-networks--id-on-connect (net-id)
+  "Update NET-ID `erc-networks--id' after connection params known.
+This is typically during or just after MOTD.")
+
+(cl-defmethod erc-networks--id-on-connect ((_ erc-networks--id))
+  nil)
+
+(cl-defmethod erc-networks--id-on-connect ((id erc-networks--id-qualifying))
+  (erc-networks--id-qualifying-update id (erc-networks--id-qualifying-create)))
+
+(cl-defgeneric erc-networks--id-equal-p (self other)
+  "Return non-nil when two network identities exhibit underlying equality.
+SELF and OTHER are `erc-networks--id' struct instances.  This
+should normally be used only for ID recovery or merging, after
+which no two identities should be `equal' (timestamps aside) that
+aren't also `eq'.")
+
+(cl-defmethod erc-networks--id-equal-p ((self erc-networks--id)
+                                        (other erc-networks--id))
+  (eq self other))
+
+(cl-defmethod erc-networks--id-equal-p ((a erc-networks--id-fixed)
+                                        (b erc-networks--id-fixed))
+  (or (eq a b) (eq (erc-networks--id-symbol a) (erc-networks--id-symbol b))))
+
+(cl-defmethod erc-networks--id-equal-p ((a erc-networks--id-qualifying)
+                                        (b erc-networks--id-qualifying))
+  (or (eq a b) (equal (erc-networks--id-qualifying-parts a)
+                      (erc-networks--id-qualifying-parts b))))
+
+;; ERASE-ME: if some future extension were to come along offering
+;; additional members, e.g., [Libera.Chat "bob" laptop], it'd likely
+;; be cleaner to create a new struct type descending from
+;; `erc-networks--id-qualifying' than to convert this function into a
+;; generic.  However, the latter would be simpler because it'd just
+;; require something like &context (erc-v3-device erc-v3--device-t).
+
+(defun erc-networks--id-qualifying-init-parts ()
+  "Return opaque list of atoms to serve as canonical identifier."
+  (when-let ((network (erc-network))
+             (nick (erc-current-nick)))
+    (vector network (erc-downcase nick))))
+
+(defvar erc-networks--id-sep "/"
+  "Separator for joining `erc-networks--id-qualifying-parts' into a net ID.")
+
+(defun erc-networks--id-qualifying-init-symbol (elts &optional len)
+  "Return symbol appropriate for network context identified by ELTS.
+Use leading interval of length LEN as contributing components.
+Combine them with string separator `erc-networks--id-sep'."
+  (when elts
+    (unless len
+      (setq len 1))
+    (intern (mapconcat (lambda (s) (prin1-to-string s t))
+                       (seq-subseq elts 0 len)
+                       erc-networks--id-sep))))
+
+(defun erc-networks--id-qualifying-grow-id (nid)
+  "Grow NID by one component or return nil when at capacity."
+  (unless (= (length (erc-networks--id-qualifying-parts nid))
+             (erc-networks--id-qualifying-len nid))
+    (setf (erc-networks--id-symbol nid)
+          (erc-networks--id-qualifying-init-symbol
+           (erc-networks--id-qualifying-parts nid)
+           (cl-incf (erc-networks--id-qualifying-len nid))))))
+
+(defun erc-networks--id-qualifying-reset-id (nid)
+  "Restore NID to its initial state."
+  (setf (erc-networks--id-qualifying-len nid) 1
+        (erc-networks--id-symbol nid)
+        (erc-networks--id-qualifying-init-symbol
+         (erc-networks--id-qualifying-parts nid))))
+
+(defun erc-networks--id-qualifying-prefix-length (nid-a nid-b)
+  "Return length of common initial prefix of NID-A and NID-B.
+Return nil when no such sequence exists (instead of zero)."
+  (when-let* ((a (erc-networks--id-qualifying-parts nid-a))
+              (b (erc-networks--id-qualifying-parts nid-b))
+              (n (min (length a) (length b)))
+              ((> n 0))
+              ((equal (elt a 0) (elt b 0)))
+              (i 1))
+    (while (and (< i n)
+                (equal (elt a i)
+                       (elt b i)))
+      (cl-incf i))
+    i))
+
+(defun erc-networks--id-qualifying-update (dest source &rest overrides)
+  "Update DEST from SOURCE in place.
+Copy slots into DEST from SOURCE and recompute ID.  Both SOURCE
+and DEST must be `erc-networks--id' objects.  OVERRIDES is an
+optional plist of SLOT VAL pairs."
+  (setf (erc-networks--id-qualifying-parts dest)
+        (or (plist-get overrides :parts)
+            (erc-networks--id-qualifying-parts source))
+        (erc-networks--id-qualifying-len dest)
+        (or (plist-get overrides :len)
+            (erc-networks--id-qualifying-len source))
+        (erc-networks--id-symbol dest)
+        (or (plist-get overrides :symbol)
+            (erc-networks--id-qualifying-init-symbol
+             (erc-networks--id-qualifying-parts dest)
+             (erc-networks--id-qualifying-len dest)))))
+
+(cl-defgeneric erc-networks--id-reload (_nid &optional _proc _parsed)
+  "Handle an update to the current network identity.
+If provided, PROC should be the current `erc-server-process' and
+PARSED the current `erc-response'.  NID is an `erc-networks--id'
+object."
+  nil)
+
+(cl-defmethod erc-networks--id-reload ((nid erc-networks--id-qualifying)
+                                       &optional proc parsed)
+  "Refresh identity after an `erc-networks--id-qualifying-parts'update."
+  (erc-networks--id-qualifying-update nid (erc-networks--id-qualifying-create)
+                                      :len
+                                      (erc-networks--id-qualifying-len nid))
+  (erc-networks--rename-server-buffer (or proc erc-server-process) parsed)
+  (erc-networks--shrink-ids-and-buffer-names-any)
+  (erc-with-all-buffers-of-server
+      erc-server-process #'erc--default-target
+      (when-let* ((new-name (erc-networks--reconcile-buffer-names erc--target
+                                                                  nid))
+                  ((not (equal (buffer-name) new-name))))
+        (rename-buffer new-name 'unique))))
+
+(cl-defgeneric erc-networks--id-ensure-comparable (self other)
+  "Take measures to ensure two net identities are in comparable states.")
+
+(cl-defmethod erc-networks--id-ensure-comparable ((_ erc-networks--id)
+                                                  (_ erc-networks--id))
+  nil)
+
+(cl-defmethod erc-networks--id-ensure-comparable
+  ((nid erc-networks--id-qualifying) (other erc-networks--id-qualifying))
+  "Grow NID along with that of the current buffer.
+Rename the current buffer if its NID has grown."
+  (when-let ((n (erc-networks--id-qualifying-prefix-length other nid)))
+    (while (and (<= (erc-networks--id-qualifying-len nid) n)
+                (erc-networks--id-qualifying-grow-id nid)))
+    ;; Grow and rename a visited buffer and all its targets
+    (when (and (> (erc-networks--id-qualifying-len nid)
+                  (erc-networks--id-qualifying-len other))
+               (erc-networks--id-qualifying-grow-id other))
+      ;; Rename NID's buffers using current ID
+      (erc-buffer-filter (lambda ()
+                           (when (eq erc-networks--id other)
+                             (erc-networks--maybe-update-buffer-name)))))))
+
+(defun erc-networks--id-sort-buffers (buffers)
+  "Return a list of target BUFFERS, newest to oldest."
+  (sort buffers
+        (lambda (a b)
+          (> (with-current-buffer a (erc-networks--id-ts erc-networks--id))
+             (with-current-buffer b (erc-networks--id-ts erc-networks--id))))))
+
+
+;;;; Buffer association
+
+(cl-defgeneric erc-networks--shrink-ids-and-buffer-names ()
+  nil) ; concrete default implementation for non-eliding IDs
+
+(defun erc-networks--refresh-buffer-names (identity &optional omit)
+  "Ensure all colliding buffers for network IDENTITY have suffixes.
+Then rename current buffer appropriately.  Don't consider buffer OMIT
+when determining collisions."
+  (if (erc-networks--examine-targets identity erc--target
+        #'ignore
+        (lambda ()
+          (unless (or (not omit) (eq (current-buffer) omit))
+            (erc-networks--ensure-unique-target-buffer-name)
+            t)))
+      (erc-networks--ensure-unique-target-buffer-name)
+    (rename-buffer (erc--target-string erc--target) 'unique)))
+
+;; This currently doesn't equalize related identities that may have
+;; become mismatched because that shouldn't happen after a connection
+;; is up (other than for a brief moment while renicking or similar,
+;; when states are inconsistent).
+(defun erc-networks--shrink-ids-and-buffer-names-any (&rest omit)
+  (let (grown)
+    ;; Gather all grown identities.
+    (erc-buffer-filter
+     (lambda ()
+       (when (and erc-networks--id
+                  (erc-networks--id-qualifying-p erc-networks--id)
+                  (not (memq (current-buffer) omit))
+                  (not (memq erc-networks--id grown))
+                  (> (erc-networks--id-qualifying-len erc-networks--id) 1))
+         (push erc-networks--id grown))))
+    ;; Check for other identities with shared prefix.  If none exists,
+    ;; and an identity is overlong, shrink it.
+    (dolist (nid grown)
+      (let ((skip (not (null omit))))
+        (catch 'found
+          (if (cdr grown)
+              (dolist (other grown)
+                (unless (eq nid other)
+                  (setq skip nil)
+                  (when (erc-networks--id-qualifying-prefix-length nid other)
+                    (throw 'found (setq skip t)))))
+            (setq skip nil)))
+        (unless (or skip (< (erc-networks--id-qualifying-len nid) 2))
+          (erc-networks--id-qualifying-reset-id nid)
+          (erc-buffer-filter
+           (lambda ()
+             (when (and (eq erc-networks--id nid)
+                        (not (memq (current-buffer) omit)))
+               (if erc--target
+                   (erc-networks--refresh-buffer-names nid omit)
+                 (erc-networks--maybe-update-buffer-name))))))))))
+
+(cl-defmethod erc-networks--shrink-ids-and-buffer-names
+  (&context (erc-networks--id erc-networks--id-qualifying))
+  (erc-networks--shrink-ids-and-buffer-names-any (current-buffer)))
+
+(defun erc-networks-rename-surviving-target-buffer ()
+  "Maybe drop qualifying suffix from fellow target-buffer's name.
+But only do so when there's a single survivor with a target
+matching that of the dying buffer."
+  (when-let*
+      (((with-suppressed-warnings ((obsolete erc-reuse-buffers))
+          erc-reuse-buffers))
+       (target erc--target)
+       ;; Buffer name includes ID suffix
+       ((not (string= (erc--target-symbol target) ; string= t "t" -> t
+                      (erc-downcase (buffer-name)))))
+       (buf (current-buffer))
+       ;; All buffers, not just those belonging to same process
+       (others (erc-buffer-filter
+                (lambda ()
+                  (and-let* ((erc--target)
+                             ((not (eq buf (current-buffer))))
+                             ((eq (erc--target-symbol target)
+                                  (erc--target-symbol erc--target))))))))
+       ((not (cdr others))))
+    (with-current-buffer (car others)
+      (rename-buffer (erc--target-string target)))))
+
+(defun erc-networks-shrink-ids-and-buffer-names ()
+  "Recompute network IDs and buffer names, ignoring the current buffer.
+Only do so when an IRC connection's context supports qualified
+naming.  Do not discriminate based on whether a buffer's
+connection is active."
+  (erc-networks--shrink-ids-and-buffer-names))
+
+(defun erc-networks--examine-targets (identity target on-dupe on-collision)
+  "Visit all ERC target buffers with the same TARGET.
+Call ON-DUPE when a buffer's identity belongs to a network
+IDENTITY or \"should\" after reconciliation.  Call ON-COLLISION
+otherwise.  Neither function should accept any args. Expect
+TARGET to be an `erc--target' object."
+  (declare (indent 2))
+  (let ((announced erc-server-announced-name))
+    (erc-buffer-filter
+     (lambda ()
+       (when (and erc--target (eq (erc--target-symbol erc--target)
+                                  (erc--target-symbol target)))
+         (let ((oursp (if (erc--target-channel-local-p target)
+                          (equal announced erc-server-announced-name)
+                        (erc-networks--id-equal-p identity erc-networks--id))))
+           (funcall (if oursp on-dupe on-collision))))))))
+
+(defconst erc-networks--qualified-sep "@"
+  "Separator used for naming a target buffer.")
+
+(defun erc-networks--construct-target-buffer-name (target)
+  "Return TARGET@suffix."
+  (concat (erc--target-string target)
+          (if (with-suppressed-warnings ((obsolete erc-reuse-buffers))
+                erc-reuse-buffers)
+              erc-networks--qualified-sep "/")
+          (cond
+           ((not (with-suppressed-warnings ((obsolete erc-reuse-buffers))
+                   erc-reuse-buffers))
+            (cadr (split-string
+                   (symbol-name (erc-networks--id-symbol erc-networks--id))
+                   "/")))
+           ((erc--target-channel-local-p target) erc-server-announced-name)
+           (t (symbol-name (erc-networks--id-symbol erc-networks--id))))))
+
+(defun erc-networks--ensure-unique-target-buffer-name ()
+  (when-let* ((new-name (erc-networks--construct-target-buffer-name
+                         erc--target))
+              ((not (equal (buffer-name) new-name))))
+    (rename-buffer new-name 'unique)))
+
+(defun erc-networks--ensure-unique-server-buffer-name ()
+  (when-let* ((new-name (symbol-name (erc-networks--id-symbol
+                                      erc-networks--id)))
+              ((not (equal (buffer-name) new-name))))
+    (rename-buffer new-name 'unique)))
+
+(defun erc-networks--maybe-update-buffer-name ()
+  "Update current buffer name to reflect display ID if necessary."
+  (if erc--target
+      (erc-networks--ensure-unique-target-buffer-name)
+    (erc-networks--ensure-unique-server-buffer-name)))
+
+(defun erc-networks--reconcile-buffer-names (target nid)
+  "Reserve preferred buffer name for TARGET and network identifier.
+Expect TARGET to be an `erc--target' instance.  Guarantee that at
+most one existing buffer has the same `erc-networks--id' and a
+case-mapped target, i.e., `erc--target-symbol'.  If other buffers
+with equivalent targets exist, rename them to TARGET@their-NID
+and return TARGET@our-NID.  Otherwise return TARGET as a string.
+When multiple buffers for TARGET exist for the current NID,
+rename them with <n> suffixes going from newest to oldest."
+  (let* (existing ; Former selves or unexpected dupes (for now allow > 1)
+         ;; Renamed ERC buffers on other networks matching target
+         (namesakes (erc-networks--examine-targets nid target
+                      (lambda () (push (current-buffer) existing) nil)
+                      ;; Append network ID as TARGET@NID,
+                      ;; possibly qualifying to achieve uniqueness.
+                      (lambda ()
+                        (unless (erc--target-channel-local-p erc--target)
+                          (erc-networks--id-ensure-comparable
+                           nid erc-networks--id))
+                        (erc-networks--ensure-unique-target-buffer-name)
+                        t)))
+         ;; Must follow ^ because NID may have been modified
+         (name (if (or namesakes (not (with-suppressed-warnings
+                                          ((obsolete erc-reuse-buffers))
+                                        erc-reuse-buffers)))
+                   (erc-networks--construct-target-buffer-name target)
+                 (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)))
+    (unless (with-suppressed-warnings ((obsolete erc-reuse-buffers))
+              erc-reuse-buffers)
+      (when (string-suffix-p ">" name)
+        (setq name (substring name 0 -3))))
+    (dolist (ex (erc-networks--id-sort-buffers existing))
+      (with-current-buffer ex
+        (rename-buffer name 'unique)))
+    (when placeholder (kill-buffer placeholder))
+    name))
+
+
 ;; Functions:
 
 ;;;###autoload
@@ -739,6 +1199,7 @@ MATCHER is used to find a corresponding network to a 
server while
 Use the server parameter NETWORK if provided, otherwise parse the
 server name and search for a match in `erc-networks-alist'."
   ;; The server made it easy for us and told us the name of the NETWORK
+  (declare (obsolete "maybe see `erc-networks--determine'" "29.1"))
   (let ((network-name (cdr (assoc "NETWORK" erc-server-parameters))))
     (if network-name
        (intern network-name)
@@ -753,7 +1214,7 @@ server name and search for a match in 
`erc-networks-alist'."
 
 (defun erc-network ()
   "Return the value of `erc-network' for the current server."
-  (erc-with-server-buffer erc-network))
+  (or erc-network (erc-with-server-buffer erc-network)))
 
 (defun erc-network-name ()
   "Return the name of the current network as a string."
@@ -761,23 +1222,242 @@ server name and search for a match in 
`erc-networks-alist'."
 
 (defun erc-set-network-name (_proc _parsed)
   "Set `erc-network' to the value returned by `erc-determine-network'."
+  (declare (obsolete "maybe see `erc-networks--set-name'" "29.1"))
   (unless erc-server-connected
-    (setq erc-network (erc-determine-network)))
+    (setq erc-network (with-suppressed-warnings
+                          ((obsolete erc-determine-network))
+                        (erc-determine-network))))
+  nil)
+
+(defconst erc-networks--name-missing-sentinel (gensym "Unknown ")
+  "Value to cover rare case of a literal NETWORK=nil.")
+
+(defun erc-networks--determine ()
+  "Return the name of the network as a symbol.
+Search `erc-networks-alist' for a known entity matching
+`erc-server-announced-name'.  If that fails, use the display name
+given by the `RPL_ISUPPORT' NETWORK parameter."
+  (or (cl-loop for (name matcher) in erc-networks-alist
+               when (and matcher (string-match (concat matcher "\\'")
+                                               erc-server-announced-name))
+               return name)
+      (and-let* ((vanity (erc--get-isupport-entry 'NETWORK 'single))
+                 ((intern vanity))))
+      erc-networks--name-missing-sentinel))
+
+(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."
+  ;; 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
+      ;; 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-network-alist'.")))
+        (erc-display-error-notice parsed m)
+        (erc-error "Failed to determine network"))) ; beep
+    (setq erc-network name))
+  nil)
+
+;; This lives here in this file because all the other "on connect"
+;; MOTD stuff ended up here (but perhaps that needs to change).
+
+(defun erc-networks--ensure-announced (_ parsed)
+  "Set a fallback `erc-server-announced-name' if still unset.
+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.")
+    (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)))
   nil)
 
 (defun erc-unset-network-name (_nick _ip _reason)
   "Set `erc-network' to nil."
+  (declare (obsolete "`erc-network' is now effectively read-only" "29.1"))
   (setq erc-network nil)
   nil)
 
+;; TODO add note in Commentary saying that this module is considered a
+;; core module and that it's as much about buffer naming and network
+;; identity as anything else.
+
+(defun erc-networks--insert-transplanted-content (content)
+  (let ((inhibit-read-only t)
+        (buffer-undo-list t))
+    (save-excursion
+      (save-restriction
+        (widen)
+        (goto-char (point-min))
+        (insert-before-markers content)))))
+
+;; This should run whenever a network identity is updated.
+
+(defun erc-networks--reclaim-orphaned-target-buffers (new-proc nid announced)
+  "Visit disowned buffers for same NID and associate with NEW-PROC.
+ANNOUNCED is the server's reported host name."
+  (erc-buffer-filter
+   (lambda ()
+     (when (and erc--target
+                (not erc-server-connected)
+                (erc-networks--id-equal-p erc-networks--id nid)
+                (or (not (erc--target-channel-local-p erc--target))
+                    (string= erc-server-announced-name announced)))
+       ;; If a target buffer exists for the current process, kill this
+       ;; stale one after transplanting its content; else reinstate.
+       (if-let ((existing (erc-get-buffer
+                           (erc--target-string erc--target) new-proc)))
+           (progn
+             (widen)
+             (let ((content (buffer-substring (point-min)
+                                              erc-insert-marker)))
+               (kill-buffer) ; allow target-buf renaming hook to run
+               (with-current-buffer existing
+                 (erc-networks--ensure-unique-target-buffer-name)
+                 (erc-networks--insert-transplanted-content content))))
+         (setq erc-server-process new-proc
+               erc-server-connected t
+               erc-networks--id nid))))))
+
+(defun erc-networks--copy-over-server-buffer-contents (existing name)
+  "Kill off existing server buffer after copying its contents.
+Must be called from the replacement buffer."
+  ;; ERC expects `erc-open' to be idempotent when setting up local
+  ;; vars and other context properties for a new identity.  Thus, it's
+  ;; unlikely we'll have to copy anything else over besides text.  And
+  ;; no reconciling of user tables, etc. happens during a normal
+  ;; reconnect, so we should be fine just sticking to text. (Right?)
+  (let ((text (with-current-buffer existing
+                ;; This `erc-networks--id' should be
+                ;; `erc-networks--id-equal-p' to caller's network
+                ;; identity and older if not eq.
+                ;;
+                ;; `erc-server-process' should be set but dead
+                ;; and eq `get-buffer-process' unless latter nil
+                (delete-process erc-server-process)
+                (buffer-substring (point-min) erc-insert-marker)))
+        erc-kill-server-hook
+        erc-kill-buffer-hook)
+    (erc-networks--insert-transplanted-content text)
+    (kill-buffer name)))
+
+;; This stands alone for testing purposes
+
+(defun erc-networks--update-server-identity ()
+  "Maybe grow or replace the current network identity.
+If a dupe is found, adopt its identity by overwriting ours.
+Otherwise, take steps to ensure it can effectively be compared to
+ours, now and into the future.  Note that target buffers are
+considered as well because server buffers are often killed."
+  (let* ((identity erc-networks--id)
+         (buffer (current-buffer))
+         (f (lambda ()
+              (unless (or (eq (current-buffer) buffer)
+                          (eq erc-networks--id identity))
+                (if (erc-networks--id-equal-p identity erc-networks--id)
+                    (throw 'buffer erc-networks--id)
+                  (erc-networks--id-ensure-comparable identity
+                                                      erc-networks--id)
+                  nil))))
+         (found (catch 'buffer (erc-buffer-filter f))))
+    (when found
+      (setq erc-networks--id found))))
+
+;; These steps should only run when initializing a newly connected
+;; server buffer, whereas `erc-networks--rename-server-buffer' can run
+;; mid-session, after an identity's core components have changed.
+
+(defun erc-networks--init-identity (_proc _parsed)
+  "Update identity with real network name."
+  ;; Initialize identity for real now that we know the network
+  (cl-assert erc-network)
+  (unless (erc-networks--id-symbol erc-networks--id) ; unless just reconnected
+    (erc-networks--id-on-connect erc-networks--id))
+  ;; Find duplicate identities or other conflicting ones and act
+  ;; accordingly.
+  (erc-networks--update-server-identity)
+  ;;
+  nil)
+
+(defun erc-networks--rename-server-buffer (new-proc &optional _parsed)
+  "Rename a server buffer based on its network identity.
+Assume that the current buffer is a server buffer, either one
+with a newly established connection whose identity has just been
+fully fleshed out, or an existing one whose identity has just
+been updated.  Either way, assume the current identity is ready
+to serve as a canonical identifier.
+
+When a server buffer already exists with the chosen name, copy
+over its contents and kill it.  However, when its process is
+still alive, kill off the current buffer.  This can happen, for
+example, after a perceived loss in network connectivity turns out
+to be a false alarm.  If `erc-reuse-buffers' is nil, let
+`generate-new-buffer-name' do the actual renaming."
+  (cl-assert (eq new-proc erc-server-process))
+  (cl-assert (erc-networks--id-symbol erc-networks--id))
+  ;; Always look for targets to reassociate because original server
+  ;; buffer may have been deleted.
+  (erc-networks--reclaim-orphaned-target-buffers new-proc erc-networks--id
+                                                 erc-server-announced-name)
+  (let* ((name (symbol-name (erc-networks--id-symbol erc-networks--id)))
+         ;; When this ends up being the current buffer, either we have
+         ;; a "given" ID or the buffer was reused on reconnecting.
+         (existing (get-buffer name)))
+    (cond ((or (not existing)
+               (erc-networks--id-given erc-networks--id)
+               (eq existing (current-buffer)))
+           (rename-buffer name))
+          ;; Abort on accidental reconnect or failure to pass :id param for
+          ;; avoidable collisions.
+          ((erc-server-process-alive existing)
+           (kill-local-variable 'erc-network)
+           (delete-process new-proc)
+           (erc-display-error-notice nil (format "Buffer %s still connected"
+                                                 name))
+           (erc-set-active-buffer existing))
+          ;; Copy over old buffer's contents and kill it
+          ((with-suppressed-warnings ((obsolete erc-reuse-buffers))
+             erc-reuse-buffers)
+           (erc-networks--copy-over-server-buffer-contents existing name)
+           (rename-buffer name))
+          (t (rename-buffer (generate-new-buffer-name name)))))
+  nil)
+
+;; Soju v0.4.0 only sends ISUPPORT on upstream reconnect, so this
+;; doesn't apply.  ZNC 1.8.2, however, still sends the entire burst.
+(defconst erc-networks--bouncer-targets '(*status bouncerserv)
+  "Case-mapped symbols matching known bouncer service-bot targets.")
+
+(defun erc-networks-on-MOTD-end (proc parsed)
+  "Call on-connect functions with server PROC and PARSED message.
+This must run before `erc-server-connected' is set."
+  (when erc-server-connected
+    (unless (erc-buffer-filter (lambda ()
+                                 (and erc--target
+                                      (memq (erc--target-symbol erc--target)
+                                            erc-networks--bouncer-targets)))
+                               proc)
+      (let ((m (concat "Unexpected state detected. Please report via "
+                       (substitute-command-keys "\\[erc-bug]") ".")))
+        (erc-display-error-notice parsed m))))
+
+  ;; For now, retain compatibility with erc-server-NNN-functions.
+  (or (erc-networks--ensure-announced proc parsed)
+      (erc-networks--set-name proc parsed)
+      (erc-networks--init-identity proc parsed)
+      (erc-networks--rename-server-buffer proc parsed)))
+
 (define-erc-module networks nil
   "Provide data about IRC networks."
-  ((add-hook 'erc-server-375-functions #'erc-set-network-name)
-   (add-hook 'erc-server-422-functions #'erc-set-network-name)
-   (add-hook 'erc-disconnected-hook #'erc-unset-network-name))
-  ((remove-hook 'erc-server-375-functions #'erc-set-network-name)
-   (remove-hook 'erc-server-422-functions #'erc-set-network-name)
-   (remove-hook 'erc-disconnected-hook #'erc-unset-network-name)))
+  ((add-hook 'erc-server-376-functions #'erc-networks-on-MOTD-end)
+   (add-hook 'erc-server-422-functions #'erc-networks-on-MOTD-end))
+  ((remove-hook 'erc-server-376-functions #'erc-networks-on-MOTD-end)
+   (remove-hook 'erc-server-422-functions #'erc-networks-on-MOTD-end)))
 
 (defun erc-ports-list (ports)
   "Return a list of PORTS.
@@ -867,6 +1547,3 @@ VALUE is the options value.")
 (provide 'erc-networks)
 
 ;;; erc-networks.el ends here
-;;
-;; Local Variables:
-;; End:
diff --git a/lisp/erc/erc-services.el b/lisp/erc/erc-services.el
index cc5d5701e4..fe9cb5b5f1 100644
--- a/lisp/erc/erc-services.el
+++ b/lisp/erc/erc-services.el
@@ -174,6 +174,18 @@ function `erc-nickserv-get-password'."
   :version "28.1"
   :type 'boolean)
 
+(defcustom erc-auth-source-services-function #'erc-auth-source-search
+  "Function to retrieve NickServ password from auth-source.
+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."
+  :package-version '(ERC . "5.4.1") ; FIXME update when publishing to ELPA
+  :type '(choice (const erc-auth-source-search)
+                 (const nil)
+                 function))
+
 (defcustom erc-nickserv-passwords nil
   "Passwords used when identifying to NickServ automatically.
 `erc-prompt-for-nickserv-password' must be nil for these
@@ -202,7 +214,7 @@ Example of use:
                        (const QuakeNet)
                        (const Rizon)
                        (const SlashNET)
-                       (symbol :tag "Network name"))
+                        (symbol :tag "Network name or session ID"))
                (repeat :tag "Nickname and password"
                        (cons :tag "Identity"
                              (string :tag "Nick")
@@ -431,31 +443,20 @@ As soon as some source returns a password, the sequence of
 lookups stops and this function returns it (or returns nil if it
 is empty).  Otherwise, no corresponding password was found, and
 it returns nil."
-  (let (network server port)
-    ;; Fill in local vars, switching to the server buffer once only
-    (erc-with-server-buffer
-     (setq network erc-network
-           server erc-session-server
-           port erc-session-port))
-    (let ((ret
-           (or
-            (when erc-nickserv-passwords
-              (cdr (assoc nick
-                          (cl-second (assoc network
-                                            erc-nickserv-passwords)))))
-            (when erc-use-auth-source-for-nickserv-password
-              (auth-source-pick-first-password
-               :require '(:secret)
-               :host server
-               ;; Ensure a string for :port
-               :port (format "%s" port)
-               :user nick))
-            (when erc-prompt-for-nickserv-password
-              (read-passwd
-               (format "NickServ password for %s on %s (RET to cancel): "
-                       nick network))))))
-      (when (and ret (not (string= ret "")))
-        ret))))
+  (when-let*
+      ((nid (erc-networks--id-symbol erc-networks--id))
+       (ret (or (when erc-nickserv-passwords
+                  (assoc-default nick
+                                 (cadr (assq nid erc-nickserv-passwords))))
+                (when (and erc-use-auth-source-for-nickserv-password
+                           erc-auth-source-services-function)
+                  (funcall erc-auth-source-services-function :user nick))
+                (when erc-prompt-for-nickserv-password
+                  (read-passwd
+                   (format "NickServ password for %s on %s (RET to cancel): "
+                           nick nid)))))
+       ((not (string-empty-p ret))))
+    ret))
 
 (defvar erc-auto-discard-away)
 
diff --git a/lisp/erc/erc-speedbar.el b/lisp/erc/erc-speedbar.el
index 5b06c21612..0c32f1e51f 100644
--- a/lisp/erc/erc-speedbar.el
+++ b/lisp/erc/erc-speedbar.el
@@ -31,8 +31,7 @@
 ;; * Write intelligent update function:
 ;;   update-channel, update-nick, remove-nick-from-channel, ...
 ;; * Use indicator-strings for op/voice
-;; * Extract/convert face notes field from bbdb if available and show
-;;   it using sb-image.el
+;; * Extract/convert face notes field from bbdb if available
 ;;
 ;;; Code:
 
@@ -139,9 +138,7 @@ This will add a speedbar major display mode."
        t))))
 
 (defun erc-speedbar-expand-server (text server indent)
-  (cond ((if (>= emacs-major-version 28)
-             (string-search "+" text)
-           (string-match "\\+" text))
+  (cond ((string-search "+" text)
         (speedbar-change-expand-button-char ?-)
         (if (speedbar-with-writable
               (save-excursion
@@ -150,9 +147,7 @@ This will add a speedbar major display mode."
             (speedbar-change-expand-button-char ?-)
           (speedbar-change-expand-button-char ??)))
        (;; we have to contract this node
-         (if (>= emacs-major-version 28)
-             (string-search "-" text)
-           (string-match "-" text))
+         (string-search "-" text)
         (speedbar-change-expand-button-char ?+)
         (speedbar-delete-subblock indent))
        (t (error "Ooops... not sure what to do")))
@@ -189,9 +184,7 @@ This will add a speedbar major display mode."
   "For the line matching TEXT, in CHANNEL, expand or contract a line.
 INDENT is the current indentation level."
   (cond
-   ((if (>= emacs-major-version 28)
-        (string-search "+" text)
-      (string-match "\\+" text))
+   ((string-search "+" text)
     (speedbar-change-expand-button-char ?-)
     (speedbar-with-writable
      (save-excursion
@@ -240,9 +233,7 @@ INDENT is the current indentation level."
             (speedbar-with-writable
              (dolist (entry names)
                (erc-speedbar-insert-user entry ?+ (1+ indent))))))))))
-   ((if (>= emacs-major-version 28)
-        (string-search "-" text)
-      (string-match "-" text))
+   ((string-search "-" text)
     (speedbar-change-expand-button-char ?+)
     (speedbar-delete-subblock indent))
    (t (error "Ooops... not sure what to do")))
@@ -293,9 +284,7 @@ The update is only done when the channel is actually 
expanded already."
        (erc-speedbar-expand-channel "+" buffer 1)))))
 
 (defun erc-speedbar-expand-user (text token indent)
-  (cond ((if (>= emacs-major-version 28)
-             (string-search "+" text)
-           (string-match "\\+" text))
+  (cond ((string-search "+" text)
         (speedbar-change-expand-button-char ?-)
         (speedbar-with-writable
           (save-excursion
@@ -318,9 +307,7 @@ The update is only done when the channel is actually 
expanded already."
                  nil nil nil nil
                  info nil nil nil
                  (1+ indent)))))))
-       ((if (>= emacs-major-version 28)
-             (string-search "-" text)
-           (string-match "-" text))
+       ((string-search "-" text)
         (speedbar-change-expand-button-char ?+)
         (speedbar-delete-subblock indent))
        (t (error "Ooops... not sure what to do")))
@@ -356,7 +343,7 @@ The INDENT level is ignored."
   "Return the text for the item on the current line."
   (beginning-of-line)
   (when (re-search-forward "[]>] " nil t)
-    (buffer-substring-no-properties (point) (point-at-eol))))
+    (buffer-substring-no-properties (point) (line-end-position))))
 
 (defun erc-speedbar-item-info ()
   "Display information about the current buffer on the current line."
diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el
index cdab3241c1..c167cd2393 100644
--- a/lisp/erc/erc-stamp.el
+++ b/lisp/erc/erc-stamp.el
@@ -303,7 +303,7 @@ printed just after each line's text (no alignment)."
       ;; to the next line before inserting a stamp.  It allows for
       ;; some margin of error if what is displayed on the line differs
       ;; from the number of characters on the line.
-      (setq col (+ col (ceiling (/ (- col (- (point) (point-at-bol))) 1.6))))
+      (setq col (+ col (ceiling (/ (- col (- (point) 
(line-beginning-position))) 1.6))))
       (if (< col pos)
          (erc-insert-aligned string pos)
        (newline)
diff --git a/lisp/erc/erc-track.el b/lisp/erc/erc-track.el
index 9118d7b994..ef9a8c243e 100644
--- a/lisp/erc/erc-track.el
+++ b/lisp/erc/erc-track.el
@@ -46,7 +46,7 @@
 
 (defcustom erc-track-enable-keybindings 'ask
   "Whether to enable the ERC track keybindings, namely:
-`C-c C-SPC' and `C-c C-@', which both do the same thing.
+\\`C-c C-SPC' and \\`C-c C-@', which both do the same thing.
 
 The default is to check to see whether these keys are used
 already: if not, then enable the ERC track minor mode, which
@@ -353,8 +353,6 @@ of `erc-track-shorten-start' characters."
      (> (length s) erc-track-shorten-cutoff))
    erc-track-shorten-start))
 
-(defvar erc-default-recipients)
-
 (defun erc-all-buffer-names ()
   "Return all channel or query buffer names.
 Note that we cannot use `erc-channel-list' with a nil argument,
@@ -455,12 +453,12 @@ START is the minimum length of the name used."
 ;; Play nice with other IRC clients (and Emacs development rules) by
 ;; making this a minor mode
 
-(defvar erc-track-minor-mode-map (make-sparse-keymap)
-  "Keymap for rcirc track minor mode.")
-
-(define-key erc-track-minor-mode-map (kbd "C-c C-@") #'erc-track-switch-buffer)
-(define-key erc-track-minor-mode-map (kbd "C-c C-SPC")
-  #'erc-track-switch-buffer)
+(defvar erc-track-minor-mode-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map (kbd "C-c C-@")   #'erc-track-switch-buffer)
+    (define-key map (kbd "C-c C-SPC") #'erc-track-switch-buffer)
+    map)
+  "Keymap for ERC track minor mode.")
 
 ;;;###autoload
 (define-minor-mode erc-track-minor-mode
diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el
index ff482d4933..151d75e7ce 100644
--- a/lisp/erc/erc.el
+++ b/lisp/erc/erc.el
@@ -2,7 +2,7 @@
 
 ;; Copyright (C) 1997-2022 Free Software Foundation, Inc.
 
-;; Author: Alexander L. Belikoff (alexander@belikoff.net)
+;; Author: Alexander L. Belikoff <alexander@belikoff.net>
 ;; Maintainer: Amin Bandali <bandali@gnu.org>, F. Jason Park <jp@neverwas.me>
 ;; Contributors: Sergey Berezin (sergey.berezin@cs.cmu.edu),
 ;;               Mario Lang (mlang@delysid.org),
@@ -13,7 +13,7 @@
 ;;               Michael Olson (mwolson@gnu.org)
 ;;               Kelvin White (kwhite@gnu.org)
 ;; Version: 5.4.1
-;; Package-Requires: ((emacs "27.1"))
+;; Package-Requires: ((emacs "27.1") (compat "28.1.2.0"))
 ;; Keywords: IRC, chat, client, Internet
 ;; URL: https://www.gnu.org/software/emacs/erc.html
 
@@ -69,6 +69,8 @@
 (require 'iso8601)
 (eval-when-compile (require 'subr-x))
 
+(require 'erc-compat)
+
 (defconst erc-version "5.4.1"
   "This version of ERC.")
 
@@ -130,7 +132,29 @@
   "Running scripts at startup and with /LOAD."
   :group 'erc)
 
-(require 'erc-backend)
+;; Defined in erc-backend
+(defvar erc--server-last-reconnect-count)
+(defvar erc--server-reconnecting)
+(defvar erc-channel-members-changed-hook)
+(defvar erc-network)
+(defvar erc-networks--id)
+(defvar erc-server-367-functions)
+(defvar erc-server-announced-name)
+(defvar erc-server-connect-function)
+(defvar erc-server-connected)
+(defvar erc-server-current-nick)
+(defvar erc-server-lag)
+(defvar erc-server-last-sent-time)
+(defvar erc-server-process)
+(defvar erc-server-quitting)
+(defvar erc-server-reconnect-count)
+(defvar erc-server-reconnecting)
+(defvar erc-session-client-certificate)
+(defvar erc-session-connector)
+(defvar erc-session-port)
+(defvar erc-session-server)
+(defvar erc-session-user-full-name)
+(defvar erc-session-username)
 
 ;; tunable connection and authentication parameters
 
@@ -190,16 +214,30 @@ parameters and authentication."
   :set (lambda (sym val)
          (set sym (if (functionp val) (funcall val) val))))
 
-(defcustom erc-rename-buffers nil
+(defcustom erc-rename-buffers t
   "Non-nil means rename buffers with network name, if available."
   :version "24.5"
   :group 'erc
   :type 'boolean)
 
+;; For the sake of compatibility, an ID will be created on the user's
+;; behalf when `erc-rename-buffers' is nil and one wasn't provided.
+;; The name will simply be that of the buffer, usually SERVER:PORT.
+;; This violates the policy of treating provided IDs as gospel, but
+;; it'll have to do for now.
+
+(make-obsolete-variable 'erc-rename-buffers
+                        "old behavior when t now permanent" "29.1")
+
 (defvar erc-password nil
-  "Password to use when authenticating to an IRC server.
-It is not strictly necessary to provide this, since ERC will
-prompt you for it.")
+  "Password to use when authenticating to an IRC server interactively.
+
+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'.")
+
+(make-obsolete-variable 'erc-password "use auth-source instead" "29.1")
 
 (defcustom erc-user-mode "+i"
   ;; +i "Invisible".  Hides user from global /who and /names.
@@ -210,7 +248,7 @@ prompt you for it.")
 
 
 (defcustom erc-prompt-for-password t
-  "Asks before using the default password, or whether to enter a new one."
+  "Ask for a server password when invoking `erc-tls' interactively."
   :group 'erc
   :type 'boolean)
 
@@ -224,13 +262,49 @@ prompt you for it.")
   :group 'erc
   :type 'boolean)
 
-(defcustom erc-hide-prompt nil
-  "If non-nil, do not display the prompt for commands.
+(defcustom erc-inhibit-multiline-input nil
+  "When non-nil, conditionally disallow input consisting of multiple lines.
+Issue an error when the number of input lines submitted for
+sending exceeds this value.  The value t means disallow more
+than 1 line of input."
+  :package-version '(ERC . "5.4.1") ; FIXME match to next release
+  :group 'erc
+  :type '(choice integer boolean))
+
+(defcustom erc-ask-about-multiline-input nil
+  "Whether to ask to ignore `erc-inhibit-multiline-input' when tripped."
+  :package-version '(ERC . "5.4.1") ; FIXME match to next release
+  :group 'erc
+  :type 'boolean)
 
-\(A command is any input starting with a `/').
+(defcustom erc-prompt-hidden ">"
+  "Text to show in lieu of the prompt when hidden."
+  :package-version '(ERC . "5.4.1") ; FIXME increment on next ELPA release
+  :group 'erc-display
+  :type 'string)
 
-See also the variables `erc-prompt' and `erc-command-indicator'."
+(defcustom erc-hide-prompt t
+  "If non-nil, hide input prompt upon disconnecting.
+To unhide, type something in the input area.  Once revealed, a
+prompt remains unhidden until the next disconnection.  Channel
+prompts are unhidden upon rejoining.  See
+`erc-unhide-query-prompt' for behavior concerning query prompts."
+  :package-version '(ERC . "5.4.1") ; FIXME increment on next ELPA release
+  :group 'erc-display
+  :type '(choice (const :tag "Always hide prompt" t)
+                 (set (const server)
+                      (const query)
+                      (const channel))))
+
+(defcustom erc-unhide-query-prompt nil
+  "When non-nil, always reveal query prompts upon reconnecting.
+Otherwise, prompts in a connection's query buffers remain hidden
+until the user types in the input area or a new message arrives
+from the target."
+  :package-version '(ERC . "5.4.1") ; FIXME increment on next ELPA release
   :group 'erc-display
+  ;; Extensions may one day offer a way to discover whether a target
+  ;; is online.  When that happens, this can be expanded accordingly.
   :type 'boolean)
 
 ;; tunable GUI stuff
@@ -352,18 +426,30 @@ 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")))
+
 (defun erc-downcase (string)
-  "Convert STRING to IRC standard conforming downcase."
-  (let ((s (downcase string))
-        (c '((?\[ . ?\{)
-             (?\] . ?\})
-             (?\\ . ?\|)
-             (?~  . ?^))))
-    (save-match-data
-      (while (string-match "[]\\[~]" s)
-        (aset s (match-beginning 0)
-              (cdr (assq (aref s (match-beginning 0)) c)))))
-    s))
+  "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)))))
 
 (defmacro erc-with-server-buffer (&rest body)
   "Execute BODY in the current ERC server buffer.
@@ -1054,6 +1140,29 @@ The struct has three slots:
   :type 'hook
   :version "27.1")
 
+;; This is being auditioned for possible exporting (as a custom hook
+;; option).  Likewise for (public versions of) `erc--input-split' and
+;; `erc--discard-trailing-multiline-nulls'.  If unneeded, we'll just
+;; run the latter on the input after `erc-pre-send-functions', and
+;; remove this hook and the struct completely.  IOW, if you need this,
+;; please say so.
+
+(defvar erc--pre-send-split-functions '(erc--discard-trailing-multiline-nulls)
+  "Special hook for modifying individual lines in multiline prompt input.
+The functions are called with one argument, an `erc--input-split'
+struct, which they can optionally modify.
+
+The struct has five slots:
+
+  `string': the input string delivered by `erc-pre-send-functions'
+  `insertp': whether to insert the lines into the buffer
+  `sendp': whether the lines should be sent to the IRC server
+  `lines': a list of lines to be sent, each one a `string'
+  `cmdp': whether to interpret input as a command, like /ignore
+
+The `string' field is effectively read-only.  When `cmdp' is
+non-nil, all but the first line will be discarded.")
+
 (defvar erc-insert-this t
   "Insert the text into the target buffer or not.
 Functions on `erc-insert-pre-hook' can set this variable to nil
@@ -1338,6 +1447,45 @@ if ARG is omitted or nil.
        (put ',enable  'definition-name ',name)
        (put ',disable 'definition-name ',name))))
 
+;; The rationale for favoring inheritance here (nicer dispatch) is
+;; kinda flimsy since there aren't yet any actual methods.
+
+(cl-defstruct erc--target
+  (string "" :type string :documentation "Received name of target.")
+  (symbol nil :type symbol :documentation "Case-mapped name as symbol."))
+
+;; These should probably take on a `joined' field to track joinedness,
+;; which should be toggled by `erc-server-JOIN', `erc-server-PART',
+;; etc.  Functions like `erc--current-buffer-joined-p' (bug#48598) may
+;; find it useful.
+
+(cl-defstruct (erc--target-channel (:include erc--target)))
+
+(cl-defstruct (erc--target-channel-local (:include erc--target-channel)))
+
+;; At some point, it may make sense to add a query type with an
+;; account field, which may help support reassociation across
+;; reconnects and nick changes (likely requires v3 extensions).
+
+(defun erc--target-from-string (string)
+  "Construct an `erc--target' variant from STRING."
+  (funcall (if (erc-channel-p string)
+               (if (erc--valid-local-channel-p string)
+                   #'make-erc--target-channel-local
+                 #'make-erc--target-channel)
+             #'make-erc--target)
+           :string string :symbol (intern (erc-downcase string))))
+
+(defvar-local erc--target nil
+  "Info about a buffer's target, if any.")
+
+;; Temporary internal getter to ease transition to `erc--target'
+;; everywhere.  Will be replaced by updated `erc-default-target'.
+(defun erc--default-target ()
+  "Return target string or nil."
+  (when erc--target
+    (erc--target-string erc--target)))
+
 (defun erc-once-with-server-event (event f)
   "Run function F the next time EVENT occurs in the `current-buffer'.
 
@@ -1488,6 +1636,7 @@ Defaults to the server buffer."
   (setq-local paragraph-start
               (concat "\\(" (regexp-quote (erc-prompt)) "\\)"))
   (setq-local completion-ignore-case t)
+  (add-hook 'kill-buffer-hook #'erc-kill-buffer-function nil t)
   (add-hook 'completion-at-point-functions #'erc-complete-word-at-point nil t))
 
 ;; activation
@@ -1521,6 +1670,22 @@ The available choices are:
                  (const :tag "Use current buffer" buffer)
                  (const :tag "Use current buffer" t)))
 
+(defcustom erc-reconnect-display nil
+  "How (and whether) to display a channel buffer upon reconnecting.
+
+This only affects automatic reconnections and is ignored when
+issuing a /reconnect command or reinvoking `erc-tls' with the
+same args (assuming success, of course).  See `erc-join-buffer'
+for a description of possible values."
+  :package-version '(ERC . "5.4.1") ; FIXME increment upon publishing to ELPA
+  :group 'erc-buffers
+  :type '(choice (const :tag "Use value of `erc-join-buffer'" nil)
+                 (const :tag "Split window and select" window)
+                 (const :tag "Split window, don't select" window-noselect)
+                 (const :tag "New frame" frame)
+                 (const :tag "Bury in new buffer" bury)
+                 (const :tag "Use current buffer" buffer)))
+
 (defcustom erc-frame-alist nil
   "Alist of frame parameters for creating erc frames.
 A value of nil means to use `default-frame-alist'."
@@ -1552,6 +1717,14 @@ effect when `erc-join-buffer' is set to `frame'."
            (erc-channel-p (erc-default-target))))
         (t nil)))
 
+;; For the sake of compatibility, a historical quirk concerning this
+;; option, when nil, has been preserved: all buffers are suffixed with
+;; the original dialed host name, which is usually something like
+;; irc.libera.chat.  Collisions are handled by adding a uniquifying
+;; numeric suffix of the form <N>.  Note that channel reassociation
+;; behavior involving this option (when nil) was inverted in 28.1 (ERC
+;; 5.4 and 5.4.1).  This was regrettable and has since been undone.
+
 (defcustom erc-reuse-buffers t
   "If nil, create new buffers on joining a channel/query.
 If non-nil, a new buffer will only be created when you join
@@ -1561,6 +1734,9 @@ the existing buffers will be reused."
   :group 'erc-buffers
   :type 'boolean)
 
+(make-obsolete-variable 'erc-reuse-buffers
+                        "old behavior when t now permanent" "29.1")
+
 (defun erc-normalize-port (port)
   "Normalize the port specification PORT to integer form.
 PORT may be an integer, a string or a symbol.  If it is a string or a
@@ -1596,55 +1772,61 @@ symbol, it may have these values:
   "Check whether ports A and B are equal."
   (= (erc-normalize-port a) (erc-normalize-port b)))
 
-(defun erc-generate-new-buffer-name (server port target)
-  "Create a new buffer name based on the arguments."
-  (when (numberp port) (setq port (number-to-string port)))
-  (let* ((buf-name (or target
-                       (let ((name (concat server ":" port)))
-                         (when (> (length name) 1)
-                           name))
-                       ;; This fallback should in fact never happen.
-                       "*erc-server-buffer*"))
-         (full-buf-name (concat buf-name "/" server))
-         (dup-buf-name (buffer-name (car (erc-channel-list nil))))
-         buffer-name)
-    ;; Reuse existing buffers, but not if the buffer is a connected server
-    ;; buffer and not if its associated with a different server than the
-    ;; current ERC buffer.
-    ;; If buf-name is taken by a different connection (or by something !erc)
-    ;; then see if "buf-name/server" meets the same criteria.
-    (if (and dup-buf-name (string-match-p (concat buf-name "/") dup-buf-name))
-        (setq buffer-name full-buf-name) ; ERC buffer with full name already 
exists.
-      (dolist (candidate (list buf-name full-buf-name))
-        (if (and (not buffer-name)
-                 erc-reuse-buffers
-                 (or (not (get-buffer candidate))
-                     ;; Looking for a server buffer, so there's no target.
-                     (and (not target)
-                          (with-current-buffer (get-buffer candidate)
-                            (and (erc-server-buffer-p)
-                                 (not (erc-server-process-alive)))))
-                     ;; Channel buffer; check that it's from the right server.
-                     (and target
-                          (with-current-buffer (get-buffer candidate)
-                            (and (string= erc-session-server server)
-                                 (erc-port-equal erc-session-port port))))))
-            (setq buffer-name candidate)
-          (when (and (not buffer-name) (get-buffer buf-name) erc-reuse-buffers)
-            ;; A new buffer will be created with the name buf-name/server, 
rename
-            ;; the existing name-duplicated buffer with the same format as 
well.
-            (with-current-buffer (get-buffer buf-name)
-              (when (derived-mode-p 'erc-mode) ; ensure it's an erc buffer
-                (rename-buffer
-                 (concat buf-name "/" (or erc-session-server 
erc-server-announced-name)))))))))
-    ;; If buffer-name is unset, neither candidate worked out for us,
-    ;; fallback to the old <N> uniquification method:
-    (or buffer-name (generate-new-buffer-name full-buf-name))))
-
-(defun erc-get-buffer-create (server port target)
+(defun erc-generate-new-buffer-name (server port target &optional tgt-info id)
+  "Determine the name of an ERC buffer.
+When TGT-INFO is nil, assume this is a server buffer.  If ID is non-nil,
+return ID as a string unless a buffer already exists with a live server
+process, in which case signal an error.  When ID is nil, return a
+temporary name based on SERVER and PORT to be replaced with the network
+name when discovered (see `erc-networks--rename-server-buffer').  Allow
+either SERVER or PORT (but not both) to be nil to accommodate oddball
+`erc-server-connect-function's.
+
+When TGT-INFO is non-nil, expect its string field to match the redundant
+param TARGET (retained for compatibility).  Whenever possibly, prefer
+returning TGT-INFO's string unmodified.  But when a case-insensitive
+collision prevents that, return target@ID when ID is non-nil or
+target@network otherwise after renaming the conflicting buffer in the
+same manner."
+  (when target ; compat
+    (setq tgt-info (erc--target-from-string target)))
+  (if tgt-info
+      (let* ((esid (erc-networks--id-symbol erc-networks--id))
+             (name (if esid
+                       (erc-networks--reconcile-buffer-names tgt-info
+                                                             erc-networks--id)
+                     (erc--target-string tgt-info))))
+        (if (and esid (with-suppressed-warnings ((obsolete erc-reuse-buffers))
+                        erc-reuse-buffers))
+            name
+          (generate-new-buffer-name name)))
+    (if (and (with-suppressed-warnings ((obsolete erc-reuse-buffers))
+               erc-reuse-buffers)
+             id)
+        (progn
+          (when-let* ((buf (get-buffer (symbol-name id)))
+                      ((erc-server-process-alive buf)))
+            (user-error  "Session with ID %S already exists" id))
+          (symbol-name id))
+      (generate-new-buffer-name (if (and server port)
+                                    (if (with-suppressed-warnings
+                                            ((obsolete erc-reuse-buffers))
+                                          erc-reuse-buffers)
+                                        (format "%s:%s" server port)
+                                      (format "%s:%s/%s" server port server))
+                                  (or server port))))))
+
+(defun erc-get-buffer-create (server port target &optional tgt-info id)
   "Create a new buffer based on the arguments."
-  (get-buffer-create (erc-generate-new-buffer-name server port target)))
-
+  (when target ; compat
+    (setq tgt-info (erc--target-from-string target)))
+  (if (and erc--server-reconnecting
+           (not tgt-info)
+           (with-suppressed-warnings ((obsolete erc-reuse-buffers))
+             erc-reuse-buffers))
+      (current-buffer)
+    (get-buffer-create
+     (erc-generate-new-buffer-name server port nil tgt-info id))))
 
 (defun erc-member-ignore-case (string list)
   "Return non-nil if STRING is a member of LIST.
@@ -1799,12 +1981,24 @@ all channel buffers on all servers."
 
 ;; Some local variables
 
+;; TODO eventually deprecate this variable
+;;
+;; In the ancient, pre-CVS days (prior to June 2001), this list may
+;; have been used for supporting the changing of a buffer's target on
+;; the fly (mid-session).  Such usage, which allowed cons cells like
+;; (QUERY . bob) to serve as the list's head, was either never fully
+;; integrated or was partially clobbered prior to the introduction of
+;; version control.  But vestiges remain (see `erc-dcc-chat-mode').
+;; And despite appearances, no evidence has emerged that ERC ever
+;; supported one-to-many target buffers.  If such a thing was aspired
+;; to, it was never realized.
+;;
+;; New library code should use the `erc--target' struct instead.
+;; Third-party code can continue to use this until a getter for
+;; `erc--target' (or whatever replaces it) is exported.
 (defvar-local erc-default-recipients nil
   "List of default recipients of the current buffer.")
 
-(defvar-local erc-session-user-full-name nil
-  "Full name of the user on the current server.")
-
 (defvar-local erc-channel-user-limit nil
   "Limit of users per channel.")
 
@@ -1945,7 +2139,10 @@ removed from the list will be disabled."
 
 (defun erc-setup-buffer (buffer)
   "Consults `erc-join-buffer' to find out how to display `BUFFER'."
-  (pcase erc-join-buffer
+  (pcase (if (zerop (erc-with-server-buffer
+                      erc--server-last-reconnect-count))
+             erc-join-buffer
+           (or erc-reconnect-display erc-join-buffer))
     ('window
      (if (active-minibuffer-window)
          (display-buffer buffer)
@@ -1971,8 +2168,8 @@ removed from the list will be disabled."
 
 (defun erc-open (&optional server port nick full-name
                            connect passwd tgt-list channel process
-                           client-certificate)
-  "Connect to SERVER on PORT as NICK with FULL-NAME.
+                           client-certificate user id)
+  "Connect to SERVER on PORT as NICK with USER and FULL-NAME.
 
 If CONNECT is non-nil, connect to the server.  Otherwise assume
 already connected and just create a separate buffer for the new
@@ -1988,15 +2185,17 @@ of the client certificate itself to use when connecting 
over TLS,
 or t, which means that `auth-source' will be queried for the
 private key and the certificate.
 
+When non-nil, ID should be a symbol for identifying the connection.
+
 Returns the buffer for the given server or channel."
-  (let ((server-announced-name (when (and (boundp 'erc-session-server)
-                                          (string= server erc-session-server))
-                                 erc-server-announced-name))
-        (connected-p (unless connect erc-server-connected))
-        (buffer (erc-get-buffer-create server port channel))
-        (old-buffer (current-buffer))
-        old-point
-        continued-session)
+  (let* ((target (and channel (erc--target-from-string channel)))
+         (buffer (erc-get-buffer-create server port nil target id))
+         (old-buffer (current-buffer))
+         old-point
+         (continued-session (and erc--server-reconnecting
+                                 (with-suppressed-warnings
+                                     ((obsolete erc-reuse-buffers))
+                                   erc-reuse-buffers))))
     (when connect (run-hook-with-args 'erc-before-connect server port nick))
     (erc-update-modules)
     (set-buffer buffer)
@@ -2004,8 +2203,9 @@ Returns the buffer for the given server or channel."
     (let ((old-recon-count erc-server-reconnect-count))
       (erc-mode)
       (setq erc-server-reconnect-count old-recon-count))
-    (setq erc-server-announced-name server-announced-name)
-    (setq erc-server-connected connected-p)
+    (when (setq erc-server-connected (not connect))
+      (setq erc-server-announced-name
+            (buffer-local-value 'erc-server-announced-name old-buffer)))
     ;; connection parameters
     (setq erc-server-process process)
     (setq erc-insert-marker (make-marker))
@@ -2014,7 +2214,7 @@ Returns the buffer for the given server or channel."
     ;; (the buffer may have existed)
     (goto-char (point-max))
     (forward-line 0)
-    (when (get-text-property (point) 'erc-prompt)
+    (when (or continued-session (get-text-property (point) 'erc-prompt))
       (setq continued-session t)
       (set-marker erc-input-marker
                   (or (next-single-property-change (point) 'erc-prompt)
@@ -2025,6 +2225,9 @@ Returns the buffer for the given server or channel."
     (set-marker erc-insert-marker (point))
     ;; stack of default recipients
     (setq erc-default-recipients tgt-list)
+    (when target
+      (setq erc--target target
+            erc-network (erc-network)))
     (setq erc-server-current-nick nil)
     ;; Initialize erc-server-users and erc-channel-users
     (if connect
@@ -2036,8 +2239,6 @@ Returns the buffer for the given server or channel."
         (setq erc-server-users nil)
         (setq erc-channel-users
               (make-hash-table :test 'equal))))
-    ;; clear last incomplete line read
-    (setq erc-server-filter-data nil)
     (setq erc-channel-topic "")
     ;; limit on the number of users on the channel (mode +l)
     (setq erc-channel-user-limit nil)
@@ -2054,17 +2255,12 @@ Returns the buffer for the given server or channel."
     (setq erc-logged-in nil)
     ;; The local copy of `erc-nick' - the list of nicks to choose
     (setq erc-default-nicks (if (consp erc-nick) erc-nick (list erc-nick)))
-    ;; password stuff
-    (setq erc-session-password
-          (or passwd
-              (auth-source-pick-first-password
-               :host server
-               :user nick
-               ;; secrets.el wouldn’t accept a number
-               :port (if (numberp port) (number-to-string port) port)
-               :require '(:secret))))
     ;; client certificate (only useful if connecting over TLS)
     (setq erc-session-client-certificate client-certificate)
+    (setq erc-networks--id (if connect
+                               (erc-networks--id-create id)
+                             (buffer-local-value 'erc-networks--id
+                                                 old-buffer)))
     ;; debug output buffer
     (setq erc-dbuf
           (when erc-log-p
@@ -2074,12 +2270,13 @@ Returns the buffer for the given server or channel."
       (goto-char (point-max))
       (insert "\n"))
     (if continued-session
-        (goto-char old-point)
+        (progn (goto-char old-point)
+               (erc--unhide-prompt))
       (set-marker erc-insert-marker (point))
       (erc-display-prompt)
       (goto-char (point-max)))
 
-    (erc-determine-parameters server port nick full-name)
+    (erc-determine-parameters server port nick full-name user passwd)
 
     ;; Saving log file on exit
     (run-hook-with-args 'erc-connect-pre-hook buffer)
@@ -2177,11 +2374,9 @@ parameters SERVER and NICK."
     (setq server user-input)
 
     (setq passwd (if erc-prompt-for-password
-                     (if (and erc-password
-                              (y-or-n-p "Use the default password? "))
-                         erc-password
-                       (read-passwd "Password: "))
-                   erc-password))
+                     (read-passwd "Server password: ")
+                   (with-suppressed-warnings ((obsolete erc-password))
+                     erc-password)))
     (when (and passwd (string= "" passwd))
       (setq passwd nil))
 
@@ -2200,8 +2395,10 @@ parameters SERVER and NICK."
 (cl-defun erc (&key (server (erc-compute-server))
                     (port   (erc-compute-port))
                     (nick   (erc-compute-nick))
+                    (user   (erc-compute-user))
                     password
-                    (full-name (erc-compute-full-name)))
+                    (full-name (erc-compute-full-name))
+                    id)
   "ERC is a powerful, modular, and extensible IRC client.
 This function is the main entry point for ERC.
 
@@ -2211,8 +2408,10 @@ 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))
+   id
 
 That is, if called with
 
@@ -2220,9 +2419,13 @@ That is, if called with
 
 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."
+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."
   (interactive (erc-select-read-args))
-  (erc-open server port nick full-name t password))
+  (erc-open server port nick full-name t password nil nil nil nil user id))
 
 ;;;###autoload
 (defalias 'erc-select #'erc)
@@ -2232,9 +2435,11 @@ for the values of the other parameters."
 (cl-defun erc-tls (&key (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)
+                        client-certificate
+                        id)
   "ERC is a powerful, modular, and extensible IRC client.
 This function is the main entry point for ERC over TLS.
 
@@ -2248,6 +2453,7 @@ Non-interactively, it takes the keyword arguments
    password
    (full-name (erc-compute-full-name))
    client-certificate
+   id
 
 That is, if called with
 
@@ -2270,12 +2476,18 @@ Example usage:
     (erc-tls :server \"irc.libera.chat\" :port 6697
              :client-certificate
              \\='(\"/home/bandali/my-cert.key\"
-               \"/home/bandali/my-cert.crt\"))"
+               \"/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."
   (interactive (let ((erc-default-port erc-default-port-tls))
                 (erc-select-read-args)))
   (let ((erc-server-connect-function 'erc-open-tls-stream))
     (erc-open server port nick full-name t password
-              nil nil nil client-certificate)))
+              nil nil nil client-certificate user id)))
 
 (defun erc-open-tls-stream (name buffer host port &rest parameters)
   "Open an TLS stream to an IRC server.
@@ -2331,8 +2543,6 @@ but you won't see it.
 WARNING: Do not set this variable directly!  Instead, use the
 function `erc-toggle-debug-irc-protocol' to toggle its value.")
 
-(declare-function erc-network-name "erc-networks" ())
-
 (defun erc-log-irc-protocol (string &optional outbound)
   "Append STRING to the buffer *erc-protocol*.
 
@@ -2342,15 +2552,20 @@ The buffer is created if it doesn't exist.
 
 If OUTBOUND is non-nil, STRING is being sent to the IRC server and
 appears in face `erc-input-face' in the buffer.  Lines must already
-contain CRLF endings.  Peer is identified by the most precise label
-available at run time, starting with the network name, followed by the
-announced host name, and falling back to the dialed <server>:<port>."
+contain CRLF endings.  A peer is identified by the most precise label
+available, starting with the session ID followed by the server-reported
+hostname, and falling back to the dialed <server>:<port> pair.
+
+When capturing logs for multiple peers and sorting them into buckets,
+such inconsistent labeling may pose a problem until the MOTD is
+received.  Setting a fixed `erc-networks--id' can serve as a
+workaround."
   (when erc-debug-irc-protocol
-    (let ((esid (or (and (fboundp 'erc-network)
-                         (erc-network)
-                         (erc-network-name))
-                    erc-server-announced-name
-                    (format "%s:%s" erc-session-server erc-session-port)))
+    (let ((esid (if-let ((erc-networks--id)
+                         (esid (erc-networks--id-symbol erc-networks--id)))
+                    (symbol-name esid)
+                  (or erc-server-announced-name
+                      (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))))
       (with-current-buffer (get-buffer-create "*erc-protocol*")
@@ -2751,7 +2966,7 @@ returns non-nil."
   (let* ((command (erc-response.command parsed))
          (sender (car (erc-parse-user (erc-response.sender parsed))))
          (channel (car (erc-response.command-args parsed)))
-         (network (or (and (fboundp 'erc-network-name) (erc-network-name))
+         (network (or (and (erc-network) (erc-network-name))
                      (erc-shorten-server-name
                       (or erc-server-announced-name
                           erc-session-server))))
@@ -2817,6 +3032,8 @@ for special purposes (see erc-dcc.el).")
 
 (defun erc-send-input-line (target line &optional force)
   "Send LINE to TARGET."
+  (when (string= line "\n")
+    (setq line " \n"))
   (erc-message "PRIVMSG" (concat target " " line) force))
 
 (defun erc-get-arglist (fun)
@@ -3174,18 +3391,137 @@ For a list of user commands (/join /part, ...):
 (defalias 'erc-cmd-H #'erc-cmd-HELP)
 (put 'erc-cmd-HELP 'process-not-needed t)
 
+(defcustom erc-auth-source-server-function #'erc-auth-source-search
+  "Function to query auth-source for a server password.
+Called with a subset of keyword parameters known to
+`auth-source-search' and relevant to an opening \"PASS\" command,
+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."
+  :package-version '(ERC . "5.4.1") ; FIXME update when publishing to ELPA
+  :group 'erc
+  :type '(choice (const erc-auth-source-search)
+                 (const nil)
+                 function))
+
+(defcustom erc-auth-source-join-function #'erc-auth-source-search
+  "Function to query auth-source on joining a channel.
+Called with a subset of keyword arguments known to
+`auth-source-search' and relevant to joining a password-protected
+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'."
+  :package-version '(ERC . "5.4.1") ; FIXME update when publishing to ELPA
+  :group 'erc
+  :type '(choice (const erc-auth-source-search)
+                 (const nil)
+                 function))
+
+(defun erc--auth-source-determine-params-defaults ()
+  (let* ((net (and-let* ((esid (erc-networks--id-symbol erc-networks--id))
+                         ((symbol-name esid)))))
+         (localp (and erc--target (erc--target-channel-local-p erc--target)))
+         (hosts (if localp
+                    (list erc-server-announced-name erc-session-server net)
+                  (list net erc-server-announced-name erc-session-server)))
+         (ports (list (cl-typecase erc-session-port
+                        (integer (number-to-string erc-session-port))
+                        (string (and (string= erc-session-port "irc")
+                                     erc-session-port)) ; or nil
+                        (t erc-session-port))
+                      "irc")))
+    (list (cons :host (delq nil hosts))
+          (cons :port (delq nil ports))
+          (cons :require '(:secret)))))
+
+(defun erc--auth-source-determine-params-merge (&rest plist)
+  "Return a plist of merged keyword args to pass to `auth-source-search'.
+Combine items in PLIST with others derived from the current connection
+context, but prioritize the former.  For keys not present in PLIST,
+favor a network ID over an announced server unless `erc--target' is a
+local channel.  And treat the dialed server address as a fallback for
+the announced name in both cases."
+  (let ((defaults (erc--auth-source-determine-params-defaults)))
+    `(,@(cl-loop for (key value) on plist by #'cddr
+                 for default = (assq key defaults)
+                 do (when default (setq defaults (delq default defaults)))
+                 append `(,key ,(delete-dups
+                                 `(,@(if (consp value) value (list value))
+                                   ,@(cdr default)))))
+      ,@(cl-loop for (k . v) in defaults append (list k v)))))
+
+(defun erc--auth-source-search (&rest defaults)
+  "Ask auth-source for a secret and return it if found.
+Use DEFAULTS as keyword arguments for querying auth-source and as a
+guide for narrowing results.  Return a string if found or nil otherwise.
+The ordering of DEFAULTS influences how results are filtered, as does
+the ordering of the members of any individual composite values.  If
+necessary, the former takes priority.  For example, if DEFAULTS were to
+contain
+
+  :host (\"foo\" \"bar\") :port (\"123\" \"456\")
+
+the secret from an auth-source entry of host foo and port 456 would be
+chosen over another of host bar and port 123.  However, if DEFAULTS
+looked like
+
+  :port (\"123\" \"456\") :host (\"foo\" \"bar\")
+
+the opposite would be true.  In both cases, two entries with the same
+host but different ports would result in the one with port 123 getting
+the nod.  Much the same would happen for entries sharing only a port:
+the one with host foo would win."
+  (when-let*
+      ((priority (map-keys defaults))
+       (test (lambda (a b)
+               (catch 'done
+                 (dolist (key priority)
+                   (let* ((d (plist-get defaults key))
+                          (defval (if (listp d) d (list d)))
+                          ;; featurep 'seq via auth-source > json > map
+                          (p (seq-position defval (plist-get a key)))
+                          (q (seq-position defval (plist-get b key))))
+                     (unless (eql p q)
+                       (throw 'done (when p (or (not q) (< p q))))))))))
+       (plist (copy-sequence defaults)))
+    (unless (plist-get plist :max)
+      (setq plist (plist-put plist :max 5000))) ; `auth-source-netrc-parse'
+    (unless (plist-get defaults :require)
+      (setq plist (plist-put plist :require '(:secret))))
+    (when-let* ((sorted (sort (apply #'auth-source-search plist) test))
+                (secret (plist-get (car sorted) :secret)))
+      (if (functionp secret) (funcall secret) secret))))
+
+(defun erc-auth-source-search (&rest plist)
+  "Call `auth-source-search', possibly with keyword params in PLIST."
+  ;; These exist as separate helpers in case folks should find them
+  ;; useful.  If that's you, please request that they be exported.
+  (apply #'erc--auth-source-search
+         (apply #'erc--auth-source-determine-params-merge plist)))
+
 (defun erc-server-join-channel (server channel &optional secret)
-  (let ((password
-         (or secret
-             (auth-source-pick-first-password
-             :host server
-             :port "irc"
-             :user channel))))
-    (erc-log (format "cmd: JOIN: %s" channel))
-    (erc-server-send (concat "JOIN " channel
-                            (if password
-                                (concat " " password)
-                              "")))))
+  "Join CHANNEL, optionally with SECRET.
+Without SECRET, consult auth-source, possibly passing SERVER as the
+`:host' query parameter."
+  (unless (or secret (not erc-auth-source-join-function))
+    (unless server
+      (when (and erc-server-announced-name
+                 (erc--valid-local-channel-p channel))
+        (setq server erc-server-announced-name)))
+    (setq secret (apply erc-auth-source-join-function
+                        `(,@(and server (list :host server)) :user ,channel))))
+  (erc-log (format "cmd: JOIN: %s" channel))
+  (erc-server-send (concat "JOIN " channel (and secret (concat " " secret)))))
+
+(defun erc--valid-local-channel-p (channel)
+  "Non-nil when channel is server-local on a network that allows them."
+  (and-let* (((eq ?& (aref channel 0)))
+             (chan-types (erc--get-isupport-entry 'CHANTYPES 'single))
+             ((string-search "&" chan-types)))))
 
 (defun erc-cmd-JOIN (channel &optional key)
   "Join the channel given in CHANNEL, optionally with KEY.
@@ -3199,18 +3535,12 @@ were most recently invited.  See also `invitation'."
       (setq chnl (erc-ensure-channel-name channel)))
     (when chnl
       ;; Prevent double joining of same channel on same server.
-      (let* ((joined-channels
-              (mapcar (lambda (chanbuf)
-                        (with-current-buffer chanbuf (erc-default-target)))
-                      (erc-channel-list erc-server-process)))
-             (server (with-current-buffer (process-buffer erc-server-process)
-                      (or erc-session-server erc-server-announced-name)))
-             (chnl-name (car (erc-member-ignore-case chnl joined-channels))))
-        (if chnl-name
-            (switch-to-buffer (if (get-buffer chnl-name)
-                                  chnl-name
-                                (concat chnl-name "/" server)))
-         (erc-server-join-channel server chnl key)))))
+      (if-let* ((existing (erc-get-buffer chnl erc-server-process))
+                ((with-current-buffer existing
+                   (erc-get-channel-user (erc-current-nick)))))
+          (switch-to-buffer existing)
+        (setq erc--server-last-reconnect-count 0)
+        (erc-server-join-channel nil chnl key))))
   t)
 
 (defalias 'erc-cmd-CHANNEL #'erc-cmd-JOIN)
@@ -3512,8 +3842,8 @@ The rest of LINE is the message to send."
 (defun erc-cmd-NICK (nick)
   "Change current nickname to NICK."
   (erc-log (format "cmd: NICK: %s (erc-bad-nick: %S)" nick erc-bad-nick))
-  (let ((nicklen (cdr (assoc "NICKLEN" (erc-with-server-buffer
-                                         erc-server-parameters)))))
+  (let ((nicklen (erc-with-server-buffer
+                   (erc--get-isupport-entry 'NICKLEN 'single))))
     (and nicklen (> (length nick) (string-to-number nicklen))
          (erc-display-message
           nil 'notice 'active 'nick-too-long
@@ -3601,13 +3931,14 @@ on the value of `erc-query-display'."
   ;; `kill-buffer'?  If it makes sense, re-add it.  -- SK @ 2021-11-11
   (interactive
    (list (read-string "Start a query with: ")))
-  (let ((session-buffer (erc-server-buffer))
-        (erc-join-buffer erc-query-display))
-    (if user
-        (erc-query user session-buffer)
+  (unless user
       ;; currently broken, evil hack to display help anyway
                                         ;(erc-delete-query))))
-      (signal 'wrong-number-of-arguments ""))))
+    (signal 'wrong-number-of-arguments ""))
+  (let ((erc-join-buffer erc-query-display))
+    (erc-with-server-buffer
+     (erc--open-target user))))
+
 (defalias 'erc-cmd-Q #'erc-cmd-QUERY)
 
 (defun erc-quit/part-reason-default ()
@@ -3735,12 +4066,16 @@ the message given by REASON."
       (setq erc--server-reconnecting t)
       (setq erc-server-reconnect-count 0)
       (setq process (get-buffer-process (erc-server-buffer)))
-      (if process
-          (delete-process process)
-        (erc-server-reconnect))
-      (with-suppressed-warnings ((obsolete erc-server-reconnecting))
-        (setq erc-server-reconnecting nil))
-      (setq erc--server-reconnecting nil)))
+      (when process
+        (delete-process process))
+      (erc-server-reconnect)
+      (with-suppressed-warnings ((obsolete erc-server-reconnecting)
+                                 ((obsolete erc-reuse-buffers)))
+        (if erc-reuse-buffers
+            (progn (cl-assert (not erc--server-reconnecting))
+                   (cl-assert (not erc-server-reconnecting)))
+          (setq erc--server-reconnecting nil
+                erc-server-reconnecting nil)))))
   t)
 (put 'erc-cmd-RECONNECT 'process-not-needed t)
 
@@ -4231,8 +4566,6 @@ This places `point' just after the prompt, or at the 
beginning of the line."
 (defun erc-complete-word-at-point ()
   (run-hook-with-args-until-success 'erc-complete-functions))
 
-(define-obsolete-function-alias 'erc-complete-word #'completion-at-point 
"24.1")
-
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;
 ;;                        IRC SERVER INPUT HANDLING
@@ -4279,27 +4612,30 @@ See `erc-default-server-hook'."
   (nconc erc-server-vectors (list parsed))
   nil)
 
-(defun erc-query (target server)
-  "Open a query buffer on TARGET, using SERVER.
+(defun erc--open-target (target)
+  "Open an ERC buffer on TARGET."
+  (erc-open erc-session-server
+            erc-session-port
+            (erc-current-nick)
+            erc-session-user-full-name
+            nil
+            nil
+            (list target)
+            target
+            erc-server-process
+            nil
+            erc-session-username
+            (erc-networks--id-given erc-networks--id)))
+
+(defun erc-query (target server-buffer)
+  "Open a query buffer on TARGET using SERVER-BUFFER.
 To change how this query window is displayed, use `let' to bind
 `erc-join-buffer' before calling this."
-  (unless (and server
-               (buffer-live-p server)
-               (set-buffer server))
+  (declare (obsolete "bind `erc-cmd-query' and call `erc-cmd-QUERY'" "29.1"))
+  (unless (buffer-live-p server-buffer)
     (error "Couldn't switch to server buffer"))
-  (let ((buf (erc-open erc-session-server
-                       erc-session-port
-                       (erc-current-nick)
-                       erc-session-user-full-name
-                       nil
-                       nil
-                       (list target)
-                       target
-                       erc-server-process)))
-    (unless buf
-      (error "Couldn't open query window"))
-    (erc-update-mode-line)
-    buf))
+  (with-current-buffer server-buffer
+    (erc--open-target target)))
 
 (defcustom erc-auto-query 'window-noselect
   "If non-nil, create a query buffer each time you receive a private message.
@@ -4318,6 +4654,10 @@ a new window, but not to select it.  See the 
documentation for
                  (const :tag "Use current buffer" buffer)
                  (const :tag "Use current buffer" t)))
 
+;; FIXME either retire this or put it to use after determining how
+;; it's meant to work.  Clearly, the doc string does not describe
+;; current behavior.  It's currently only used by the obsolete
+;; function `erc-auto-query'.
 (defcustom erc-query-on-unjoined-chan-privmsg t
   "If non-nil create query buffer on receiving any PRIVMSG at all.
 This includes PRIVMSGs directed to channels.  If you are using an IRC
@@ -4378,9 +4718,8 @@ See also `erc-display-error-notice'."
        (format "Nickname %s is %s, try another." nick reason))
     (setq erc-nick-change-attempt-count (+ erc-nick-change-attempt-count 1))
     (let ((newnick (nth 1 erc-default-nicks))
-          (nicklen (cdr (assoc "NICKLEN"
-                               (erc-with-server-buffer
-                                 erc-server-parameters)))))
+          (nicklen (erc-with-server-buffer
+                     (erc--get-isupport-entry 'NICKLEN 'single))))
       (setq erc-bad-nick t)
       ;; try to use a different nick
       (if erc-default-nicks
@@ -4441,6 +4780,8 @@ and as second argument the event parsed as a vector."
              (erc-cmd-QUERY query))
            nil))))
 
+(make-obsolete 'erc-auto-query "try erc-cmd-QUERY instead" "29.1")
+
 (defun erc-is-message-ctcp-p (message)
   "Check if MESSAGE is a CTCP message or not."
   (string-match "^\C-a\\([^\C-a]*\\)\C-a?$" message))
@@ -4697,11 +5038,19 @@ Set user modes and run `erc-after-connect' hook."
             (nick (car (erc-response.command-args parsed)))
             (buffer (process-buffer proc)))
         (setq erc-server-connected t)
-       (setq erc-server-reconnect-count 0)
+        (setq erc--server-last-reconnect-count erc-server-reconnect-count
+              erc-server-reconnect-count 0)
         (erc-update-mode-line)
         (erc-set-initial-user-mode nick buffer)
         (erc-server-setup-periodical-ping buffer)
-        (run-hook-with-args 'erc-after-connect server nick)))))
+        (run-hook-with-args 'erc-after-connect server nick))))
+
+  (when erc-unhide-query-prompt
+    (erc-with-all-buffers-of-server proc
+      nil ; FIXME use `erc--target' after bug#48598
+      (when (and (erc-default-target)
+                 (not (erc-channel-p (car erc-default-recipients))))
+        (erc--unhide-prompt)))))
 
 (defun erc-set-initial-user-mode (nick buffer)
   "If `erc-user-mode' is non-nil for NICK, set the user modes.
@@ -4983,8 +5332,7 @@ See also `erc-channel-begin-receiving-names'."
 (defun erc-parse-prefix ()
   "Return an alist of valid prefix character types and their representations.
 Example: (operator) o => @, (voiced) v => +."
-  (let ((str (or (cdr (assoc "PREFIX" (erc-with-server-buffer
-                                        erc-server-parameters)))
+  (let ((str (or (erc-with-server-buffer (erc--get-isupport-entry 'PREFIX t))
                  ;; provide a sane default
                  "(qaohv)~&@%+"))
         types chars)
@@ -5524,7 +5872,7 @@ Specifically, return the position of `erc-insert-marker'."
   (point-max))
 
 (defvar erc-last-input-time 0
-  "Time of last call to `erc-send-current-line'.
+  "Time of last successful call to `erc-send-current-line'.
 If that function has never been called, the value is 0.")
 
 (defcustom erc-accidental-paste-threshold-seconds 0.2
@@ -5540,6 +5888,68 @@ submitted line to be intentional."
   :version "26.1"
   :type '(choice number (other :tag "disabled" nil)))
 
+(defvar erc--input-line-delim-regexp (rx (| (: (? ?\r) ?\n) ?\r)))
+
+(defun erc--blank-in-multiline-input-p (lines)
+  "Detect whether LINES contains a blank line.
+When `erc-send-whitespace-lines' is in effect, return nil if
+LINES is multiline or the first line is non-empty.  When
+`erc-send-whitespace-lines' is nil, return non-nil when any line
+is empty or consists of one or more spaces, tabs, or form-feeds."
+  (catch 'return
+    (let ((multilinep (cdr lines)))
+      (dolist (line lines)
+        (when (if erc-send-whitespace-lines
+                  (and (string-empty-p line) (not multilinep))
+                (string-match (rx bot (* (in " \t\f")) eot) line))
+          (throw 'return t))))))
+
+(defun erc--check-prompt-input-for-excess-lines (_ lines)
+  "Return non-nil when trying to send too many LINES."
+  (when erc-inhibit-multiline-input
+    ;; Assume `erc--discard-trailing-multiline-nulls' is set to run
+    (let ((reversed (seq-drop-while #'string-empty-p (reverse lines)))
+          (max (if (eq erc-inhibit-multiline-input t)
+                   2
+                 erc-inhibit-multiline-input))
+          (seen 0)
+          msg)
+      (while (and (pop reversed) (< (cl-incf seen) max)))
+      (when (= seen max)
+        (setq msg (format "(exceeded by %d)" (1+ (length reversed))))
+        (unless (and erc-ask-about-multiline-input
+                     (y-or-n-p (concat "Send input " msg "?")))
+          (concat "Too many lines " msg))))))
+
+(defun erc--check-prompt-input-for-multiline-blanks (_ lines)
+  "Return non-nil when multiline prompt input has blank LINES."
+  (when (erc--blank-in-multiline-input-p lines)
+    (if erc-warn-about-blank-lines
+        "Blank line - ignoring..."
+      'invalid)))
+
+(defun erc--check-prompt-input-for-point-in-bounds (_ _)
+  "Return non-nil when point is before prompt."
+  (when (< (point) (erc-beg-of-input-line))
+    "Point is not in the input area"))
+
+(defun erc--check-prompt-input-for-running-process (string _)
+  "Return non-nil unless in an active ERC server buffer."
+  (unless (or (erc-server-buffer-live-p)
+              (erc-command-no-process-p string))
+    "ERC: No process running"))
+
+(defvar erc--check-prompt-input-functions
+  '(erc--check-prompt-input-for-point-in-bounds
+    erc--check-prompt-input-for-multiline-blanks
+    erc--check-prompt-input-for-running-process
+    erc--check-prompt-input-for-excess-lines)
+  "Validators for user input typed at prompt.
+Called with latest input string submitted by user and the list of
+lines produced by splitting it.  If any member function returns
+non-nil, processing is abandoned and input is left untouched.
+When the returned value is a string, pass it to `erc-error'.")
+
 (defun erc-send-current-line ()
   "Parse current line and send it to IRC."
   (interactive)
@@ -5553,20 +5963,21 @@ submitted line to be intentional."
                      (eolp))
             (expand-abbrev))
           (widen)
-          (if (< (point) (erc-beg-of-input-line))
-              (erc-error "Point is not in the input area")
+          (if-let* ((str (erc-user-input))
+                    (msg (run-hook-with-args-until-success
+                          'erc--check-prompt-input-functions str
+                          (split-string str erc--input-line-delim-regexp))))
+              (when (stringp msg)
+                (erc-error msg))
             (let ((inhibit-read-only t)
-                  (str (erc-user-input))
                   (old-buf (current-buffer)))
-              (if (and (not (erc-server-buffer-live-p))
-                       (not (erc-command-no-process-p str)))
-                  (erc-error "ERC: No process running")
+              (progn ; unprogn this during next major surgery
                 (erc-set-active-buffer (current-buffer))
                 ;; Kill the input and the prompt
                 (delete-region (erc-beg-of-input-line)
                                (erc-end-of-input-line))
                 (unwind-protect
-                    (erc-send-input str)
+                    (erc-send-input str 'skip-ws-chk)
                   ;; Fix the buffer if the command didn't kill it
                   (when (buffer-live-p old-buf)
                     (with-current-buffer old-buf
@@ -5581,8 +5992,8 @@ submitted line to be intentional."
                           (set-buffer-modified-p buffer-modified))))))
 
                 ;; Only when last hook has been run...
-                (run-hook-with-args 'erc-send-completed-hook str))))
-          (setq erc-last-input-time now))
+                (run-hook-with-args 'erc-send-completed-hook str)))
+            (setq erc-last-input-time now)))
       (switch-to-buffer "*ERC Accidental Paste Overflow*")
       (lwarn 'erc :warning
              "You seem to have accidentally pasted some text!"))))
@@ -5599,21 +6010,31 @@ submitted line to be intentional."
 (cl-defstruct erc-input
   string insertp sendp)
 
-(defun erc-send-input (input)
+(cl-defstruct (erc--input-split (:include erc-input))
+  lines cmdp)
+
+(defun erc--discard-trailing-multiline-nulls (state)
+  "Ensure last line of STATE's string is non-null.
+But only when `erc-send-whitespace-lines' is non-nil.  STATE is
+an `erc--input-split' object."
+  (when (and erc-send-whitespace-lines (erc--input-split-lines state))
+    (let ((reversed (nreverse (erc--input-split-lines state))))
+      (when (string-empty-p (car reversed))
+        (pop reversed)
+        (setf (erc--input-split-cmdp state) nil))
+      (nreverse (seq-drop-while #'string-empty-p reversed)))))
+
+(defun erc-send-input (input &optional skip-ws-chk)
   "Treat INPUT as typed in by the user.
 It is assumed that the input and the prompt is already deleted.
 Return non-nil only if we actually send anything."
   ;; Handle different kinds of inputs
-  (cond
-   ;; Ignore empty input
-   ((if erc-send-whitespace-lines
-        (string= input "")
-      (string-match "\\`[ \t\r\f\n]*\\'" input))
-    (when erc-warn-about-blank-lines
-      (message "Blank line - ignoring...")
-      (beep))
-    nil)
-   (t
+  (if (and (not skip-ws-chk)
+           (erc--check-prompt-input-for-multiline-blanks
+            input (split-string input erc--input-line-delim-regexp)))
+      (when erc-warn-about-blank-lines
+        (message "Blank line - ignoring...") ; compat
+        (beep))
     ;; This dynamic variable is used by `erc-send-pre-hook'.  It's
     ;; obsolete, and when it's finally removed, this binding should
     ;; also be removed.
@@ -5633,48 +6054,28 @@ Return non-nil only if we actually send anything."
                                  :insertp erc-insert-this
                                  :sendp erc-send-this))
       (run-hook-with-args 'erc-pre-send-functions state)
+      (setq state (make-erc--input-split
+                   :string (erc-input-string state)
+                   :insertp (erc-input-insertp state)
+                   :sendp (erc-input-sendp state)
+                   :lines (split-string (erc-input-string state)
+                                        erc--input-line-delim-regexp)
+                   :cmdp (string-match erc-command-regexp
+                                       (erc-input-string state))))
+      (run-hook-with-args 'erc--pre-send-split-functions state)
       (when (and (erc-input-sendp state)
-                erc-send-this)
-       (let ((string (erc-input-string state)))
-          (if (or (if (>= emacs-major-version 28)
-                      (string-search "\n" string)
-                    (string-match "\n" string))
-                  (not (string-match erc-command-regexp string)))
-              (mapc
-               (lambda (line)
-                (mapc
-                  (lambda (line)
-                    ;; Insert what has to be inserted for this.
-                   (when (erc-input-insertp state)
-                      (erc-display-msg line))
-                    (erc-process-input-line (concat line "\n")
-                                            (null erc-flood-protect) t))
-                  (or (and erc-flood-protect (erc-split-line line))
-                      (list line))))
-               (split-string string "\n"))
-            (erc-process-input-line (concat string "\n") t nil))
-          t))))))
-
-;; (defun erc-display-command (line)
-;;   (when erc-insert-this
-;;     (let ((insert-position (point)))
-;;       (unless erc-hide-prompt
-;;         (erc-display-prompt nil nil (erc-command-indicator)
-;;                             (and (erc-command-indicator)
-;;                                  'erc-command-indicator-face)))
-;;       (let ((beg (point)))
-;;         (insert line)
-;;         (erc-put-text-property beg (point)
-;;                                'font-lock-face 'erc-command-indicator-face)
-;;         (insert "\n"))
-;;       (when (processp erc-server-process)
-;;         (set-marker (process-mark erc-server-process) (point)))
-;;       (set-marker erc-insert-marker (point))
-;;       (save-excursion
-;;         (save-restriction
-;;           (narrow-to-region insert-position (point))
-;;           (run-hooks 'erc-send-modify-hook)
-;;           (run-hooks 'erc-send-post-hook))))))
+                 erc-send-this)
+        (let ((lines (erc--input-split-lines state)))
+          (if (and (erc--input-split-cmdp state) (not (cdr lines)))
+              (erc-process-input-line (concat (car lines) "\n") t nil)
+            (dolist (line lines)
+              (dolist (line (or (and erc-flood-protect (erc-split-line line))
+                                (list line)))
+                (when (erc-input-insertp state)
+                  (erc-display-msg line))
+                (erc-process-input-line (concat line "\n")
+                                        (null erc-flood-protect) t))))
+          t)))))
 
 (defun erc-display-msg (line)
   "Display LINE as a message of the user to the current target at point."
@@ -5766,6 +6167,27 @@ See also `erc-downcase'."
 
 ;; default target handling
 
+(defun erc--current-buffer-joined-p ()
+  "Return whether the current target buffer is joined."
+  ;; This may be a reliable means of detecting subscription status,
+  ;; but it's also roundabout and awkward.  Perhaps it's worth
+  ;; discussing adding a joined slot to `erc--target' for this.
+  (cl-assert erc--target)
+  (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
+;;
+;;   (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
 (defun erc-default-target ()
   "Return the current default target (as a character string) or nil if none."
   (let ((tgt (car erc-default-recipients)))
@@ -5776,12 +6198,14 @@ See also `erc-downcase'."
 
 (defun erc-add-default-channel (channel)
   "Add CHANNEL to the default channel list."
+  (declare (obsolete "use `erc-cmd-JOIN' or similar instead" "29.1"))
   (let ((chl (downcase channel)))
     (setq erc-default-recipients
           (cons chl erc-default-recipients))))
 
 (defun erc-delete-default-channel (channel &optional buffer)
   "Delete CHANNEL from the default channel list."
+  (declare (obsolete "use `erc-cmd-PART' or similar instead" "29.1"))
   (with-current-buffer (if (and buffer
                                 (bufferp buffer))
                            buffer
@@ -5793,6 +6217,7 @@ See also `erc-downcase'."
   "Add QUERY'd NICKNAME to the default channel list.
 
 The previous default target of QUERY type gets removed."
+  (declare (obsolete "use `erc-cmd-QUERY' or similar instead" "29.1"))
   (let ((d1 (car erc-default-recipients))
         (d2 (cdr erc-default-recipients))
         (qt (cons 'QUERY (downcase nickname))))
@@ -5803,7 +6228,7 @@ The previous default target of QUERY type gets removed."
 
 (defun erc-delete-query ()
   "Delete the topmost target if it is a QUERY."
-
+  (declare (obsolete "use one query buffer per target instead" "29.1"))
   (let ((d1 (car erc-default-recipients))
         (d2 (cdr erc-default-recipients)))
     (if (and (listp d1)
@@ -6131,20 +6556,20 @@ user input."
                    erc-session-server
                    erc-session-user-full-name))
   (if erc-session-password
-      (erc-server-send (format "PASS %s" erc-session-password))
+      (erc-server-send (concat "PASS :" erc-session-password))
     (message "Logging in without password"))
   (erc-server-send (format "NICK %s" (erc-current-nick)))
   (erc-server-send
    (format "USER %s %s %s :%s"
            ;; hacked - S.B.
-           (if erc-anonymous-login erc-email-userid (user-login-name))
+           erc-session-username
            "0" "*"
            erc-session-user-full-name))
   (erc-update-mode-line))
 
 ;; connection properties' heuristics
 
-(defun erc-determine-parameters (&optional server port nick name)
+(defun erc-determine-parameters (&optional server port nick name user passwd)
   "Determine the connection and authentication parameters.
 Sets the buffer local variables:
 
@@ -6152,11 +6577,15 @@ Sets the buffer local variables:
 - `erc-session-server'
 - `erc-session-port'
 - `erc-session-user-full-name'
+- `erc-session-username'
+- `erc-session-password'
 - `erc-server-current-nick'"
   (setq erc-session-connector erc-server-connect-function
         erc-session-server (erc-compute-server server)
         erc-session-port (or port erc-default-port)
-        erc-session-user-full-name (erc-compute-full-name name))
+        erc-session-user-full-name (erc-compute-full-name name)
+        erc-session-username (erc-compute-user user)
+        erc-session-password (erc--compute-server-password passwd nick))
   (erc-set-current-nick (erc-compute-nick nick)))
 
 (defun erc-compute-server (&optional server)
@@ -6174,6 +6603,10 @@ non-nil value is found.
       (getenv "IRCSERVER")
       erc-default-server))
 
+(defun erc-compute-user (&optional user)
+  "Return a suitable value for the session user name."
+  (or user (if erc-anonymous-login erc-email-userid (user-login-name))))
+
 (defun erc-compute-nick (&optional nick)
   "Return user's IRC nick.
 
@@ -6189,6 +6622,12 @@ non-nil value is found.
       (getenv "IRCNICK")
       (user-login-name)))
 
+(defun erc--compute-server-password (password nick)
+  "Maybe provide a PASSWORD argument for the IRC \"PASS\" command.
+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
+                    (funcall erc-auth-source-server-function :user nick))))
 
 (defun erc-compute-full-name (&optional full-name)
   "Return user's full name.
@@ -6473,30 +6912,19 @@ This should be a string with substitution variables 
recognized by
 
 (defun erc-format-network ()
   "Return the name of the network we are currently on."
-  (let ((network (and (fboundp 'erc-network-name) (erc-network-name))))
-    (if (and network (symbolp network))
-        (symbol-name network)
-      "")))
+  (erc-network-name))
 
 (defun erc-format-target-and/or-network ()
   "Return the network or the current target and network combined.
 If the name of the network is not available, then use the
 shortened server name instead."
-  (let ((network-name (or (and (fboundp 'erc-network-name) (erc-network-name))
-                          (erc-shorten-server-name
-                           (or erc-server-announced-name
-                               erc-session-server)))))
-    (when (and network-name (symbolp network-name))
-      (setq network-name (symbol-name network-name)))
-    (cond ((erc-default-target)
-           (concat (erc-string-no-properties (erc-default-target))
-                   "@" network-name))
-          ((and network-name
-                (not (get-buffer network-name)))
-           (when erc-rename-buffers
-            (rename-buffer network-name))
-           network-name)
-          (t (buffer-name (current-buffer))))))
+  (if-let ((erc--target)
+           (name (if-let ((esid (erc-networks--id-symbol erc-networks--id)))
+                     (symbol-name esid)
+                   (erc-shorten-server-name (or erc-server-announced-name
+                                                erc-session-server)))))
+      (concat (erc--target-string erc--target) "@" name)
+    (buffer-name)))
 
 (defun erc-format-away-status ()
   "Return a formatted `erc-mode-line-away-status-format' if `erc-away' is 
non-nil."
@@ -6577,21 +7005,12 @@ shortened server name instead."
                                   (fill-region (point-min) (point-max))
                                   (buffer-string))))
                  (setq header-line-format
-                       (if (>= emacs-major-version 28)
-                           (string-replace
-                            "%"
-                            "%%"
-                            (if face
-                                (propertize header 'help-echo help-echo
-                                            'face face)
-                              (propertize header 'help-echo help-echo)))
-                         (replace-regexp-in-string
-                          "%"
-                          "%%"
-                          (if face
-                              (propertize header 'help-echo help-echo
-                                          'face face)
-                            (propertize header 'help-echo help-echo)))))))
+                       (string-replace
+                        "%"
+                        "%%"
+                        (if face
+                            (propertize header 'help-echo help-echo 'face face)
+                          (propertize header 'help-echo help-echo))))))
               (t (setq header-line-format
                        (if face
                            (propertize header 'face face)
@@ -6876,9 +7295,7 @@ functions."
               nick user host channel
               (if (not (string= reason ""))
                   (format ": %s"
-                          (if (>= emacs-major-version 28)
-                              (string-replace "%" "%%" reason)
-                            (replace-regexp-in-string "%" "%%" reason)))
+                          (string-replace "%" "%%" reason))
                 "")))))
 
 
@@ -6913,23 +7330,29 @@ See also `format-spec'."
 
 ;;; Various hook functions
 
-;; FIXME: Don't set the hook globally!
-(add-hook 'kill-buffer-hook #'erc-kill-buffer-function)
-
-(defcustom erc-kill-server-hook '(erc-kill-server)
-  "Invoked whenever a server buffer is killed via `kill-buffer'."
+(defcustom erc-kill-server-hook '(erc-kill-server
+                                  erc-networks-shrink-ids-and-buffer-names)
+  "Invoked whenever a live server buffer is killed via `kill-buffer'."
+  :package-version '(ERC . "5.4.1") ; FIXME increment upon publishing to ELPA
   :group 'erc-hooks
   :type 'hook)
 
-(defcustom erc-kill-channel-hook '(erc-kill-channel)
+(defcustom erc-kill-channel-hook
+  '(erc-kill-channel
+    erc-networks-shrink-ids-and-buffer-names
+    erc-networks-rename-surviving-target-buffer)
   "Invoked whenever a channel-buffer is killed via `kill-buffer'."
+  :package-version '(ERC . "5.4.1") ; FIXME increment upon publishing to ELPA
   :group 'erc-hooks
   :type 'hook)
 
-(defcustom erc-kill-buffer-hook nil
-  "Hook run whenever a non-server or channel buffer is killed.
+(defcustom erc-kill-buffer-hook
+  '(erc-networks-shrink-ids-and-buffer-names
+    erc-networks-rename-surviving-target-buffer)
+  "Hook run whenever a query buffer is killed.
 
 See also `kill-buffer'."
+  :package-version '(ERC . "5.4.1") ; FIXME increment upon publishing to ELPA
   :group 'erc-hooks
   :type 'hook)
 
@@ -7002,6 +7425,7 @@ This function should be on `erc-kill-channel-hook'."
 ;; Teach url.el how to open irc:// URLs with ERC.
 ;; To activate, customize `url-irc-function' to `url-irc-erc'.
 
+;; FIXME change user to nick, and use API to find server buffer
 ;;;###autoload
 (defun erc-handle-irc-url (host port channel user password)
   "Use ERC to IRC on HOST:PORT in CHANNEL as USER with PASSWORD.
@@ -7023,9 +7447,12 @@ Otherwise, connect to HOST:PORT as USER and /join 
CHANNEL."
 
 (provide 'erc)
 
+(require 'erc-backend)
+
 ;; Deprecated. We might eventually stop requiring the goodies automatically.
 ;; IMPORTANT: This require must appear _after_ the above (provide 'erc) to
 ;; avoid a recursive require error when byte-compiling the entire package.
 (require 'erc-goodies)
+(require 'erc-networks)
 
 ;;; erc.el ends here
diff --git a/lisp/eshell/em-alias.el b/lisp/eshell/em-alias.el
index 5d3aaf7c81..9ad218d598 100644
--- a/lisp/eshell/em-alias.el
+++ b/lisp/eshell/em-alias.el
@@ -206,7 +206,7 @@ file named by `eshell-aliases-file'.")
       (let ((eshell-current-handles
             (eshell-create-handles eshell-aliases-file 'overwrite)))
        (eshell/alias)
-       (eshell-close-handles 0))))
+       (eshell-close-handles 0 'nil))))
 
 (defsubst eshell-lookup-alias (name)
   "Check whether NAME is aliased.  Return the alias if there is one."
diff --git a/lisp/eshell/em-cmpl.el b/lisp/eshell/em-cmpl.el
index f4c1302629..822cc94149 100644
--- a/lisp/eshell/em-cmpl.el
+++ b/lisp/eshell/em-cmpl.el
@@ -158,14 +158,6 @@ to writing a completion function."
   (eshell-cmpl--custom-variable-docstring 'pcomplete-autolist)
   :type (get 'pcomplete-autolist 'custom-type))
 
-(defcustom eshell-cmpl-suffix-list (list ?/ ?:)
-  (eshell-cmpl--custom-variable-docstring 'pcomplete-suffix-list)
-  :type (get 'pcomplete-suffix-list 'custom-type)
-  :group 'pcomplete)
-;; Only labeled obsolete in 26.1, but all it does it set
-;; pcomplete-suffix-list, which is itself obsolete since 24.1.
-(make-obsolete-variable 'eshell-cmpl-suffix-list nil "24.1")
-
 (defcustom eshell-cmpl-recexact nil
   (eshell-cmpl--custom-variable-docstring 'pcomplete-recexact)
   :type (get 'pcomplete-recexact 'custom-type))
@@ -262,9 +254,6 @@ to writing a completion function."
               eshell-cmpl-ignore-case)
   (setq-local pcomplete-autolist
               eshell-cmpl-autolist)
-  (if (boundp 'pcomplete-suffix-list)
-      (setq-local pcomplete-suffix-list
-                  eshell-cmpl-suffix-list))
   (setq-local pcomplete-recexact
               eshell-cmpl-recexact)
   (setq-local pcomplete-man-function
diff --git a/lisp/eshell/em-dirs.el b/lisp/eshell/em-dirs.el
index 5396044d8c..00880b9f28 100644
--- a/lisp/eshell/em-dirs.el
+++ b/lisp/eshell/em-dirs.el
@@ -168,9 +168,6 @@ Thus, this does not include the current directory.")
 (defvar eshell-last-dir-ring nil
   "The last directory that Eshell was in.")
 
-(defconst eshell-inside-emacs (format "%s,eshell" emacs-version)
-  "Value for the `INSIDE_EMACS' environment variable.")
-
 ;;; Functions:
 
 (defun eshell-dirs-initialize ()    ;Called from `eshell-mode' via intern-soft!
@@ -178,24 +175,26 @@ Thus, this does not include the current directory.")
   (setq-local eshell-variable-aliases-list
        (append
         eshell-variable-aliases-list
-         `(("-" ,(lambda (indices)
-                  (if (not indices)
-                      (unless (ring-empty-p eshell-last-dir-ring)
-                        (expand-file-name
-                         (ring-ref eshell-last-dir-ring 0)))
-                    (expand-file-name
-                     (eshell-apply-indices eshell-last-dir-ring indices)))))
-          ("+" "PWD")
-          ("PWD" ,(lambda (_indices)
-                    (expand-file-name (eshell/pwd)))
-            t)
-          ("OLDPWD" ,(lambda (_indices)
-                       (unless (ring-empty-p eshell-last-dir-ring)
-                         (expand-file-name
-                          (ring-ref eshell-last-dir-ring 0))))
-            t)
-           ("INSIDE_EMACS" eshell-inside-emacs
-            t))))
+         `(("-" ,(lambda (indices quoted)
+                   (if (not indices)
+                       (unless (ring-empty-p eshell-last-dir-ring)
+                         (expand-file-name
+                          (ring-ref eshell-last-dir-ring 0)))
+                     ;; Apply the first index, expand the file name,
+                     ;; and then apply the rest of the indices.
+                     (eshell-apply-indices
+                      (expand-file-name
+                       (eshell-apply-indices eshell-last-dir-ring
+                                             (list (car indices)) quoted))
+                      (cdr indices) quoted))))
+           ("+" "PWD")
+           ("PWD" ,(lambda () (expand-file-name (eshell/pwd)))
+            t t)
+           ("OLDPWD" ,(lambda ()
+                       (unless (ring-empty-p eshell-last-dir-ring)
+                         (expand-file-name
+                          (ring-ref eshell-last-dir-ring 0))))
+            t t))))
 
   (when eshell-cd-on-directory
     (setq-local eshell-interpreter-alist
diff --git a/lisp/eshell/em-extpipe.el b/lisp/eshell/em-extpipe.el
index 3db1dea595..7d81f27a18 100644
--- a/lisp/eshell/em-extpipe.el
+++ b/lisp/eshell/em-extpipe.el
@@ -49,7 +49,7 @@
   (add-hook 'eshell-pre-rewrite-command-hook
             #'eshell-rewrite-external-pipeline -20 t))
 
-(defmacro em-extpipe--or-with-catch (&rest disjuncts)
+(defmacro eshell-extpipe--or-with-catch (&rest disjuncts)
   "Evaluate DISJUNCTS like `or' but catch `eshell-incomplete'.
 
 If `eshell-incomplete' is thrown during the evaluation of a
@@ -118,7 +118,7 @@ as though it were Eshell syntax."
                        (if (re-search-forward pat next t)
                            (throw 'found (match-beginning 1))
                          (goto-char next)
-                         (while (em-extpipe--or-with-catch
+                         (while (eshell-extpipe--or-with-catch
                                  (eshell-parse-lisp-argument)
                                  (eshell-parse-backslash)
                                  (eshell-parse-double-quote)
diff --git a/lisp/eshell/em-glob.el b/lisp/eshell/em-glob.el
index 52531ff893..58b7a83c09 100644
--- a/lisp/eshell/em-glob.el
+++ b/lisp/eshell/em-glob.el
@@ -183,6 +183,10 @@ interpretation."
 (defvar eshell-glob-matches)
 (defvar message-shown)
 
+(defvar eshell-glob-recursive-alist
+  '(("**/" . recurse)
+    ("***/" . recurse-symlink)))
+
 (defun eshell-glob-regexp (pattern)
   "Convert glob-pattern PATTERN to a regular expression.
 The basic syntax is:
@@ -232,6 +236,81 @@ resulting regular expression."
            (regexp-quote (substring pattern matched-in-pattern))
            "\\'")))
 
+(defun eshell-glob-convert-1 (glob &optional last)
+  "Convert a GLOB matching a single element of a file name to regexps.
+If LAST is non-nil, this glob is the last element of a file name.
+
+The result is a pair of regexps, the first for file names to
+include, and the second for ones to exclude."
+  (let ((len (length glob)) (index 1) (incl glob) excl)
+    ;; We can't use `directory-file-name' because it strips away text
+    ;; properties in the string.
+    (let ((last (1- (length incl))))
+      (when (eq (aref incl last) ?/)
+        (setq incl (substring incl 0 last))))
+    ;; Split the glob if it contains a negation like x~y.
+    (while (and (eq incl glob)
+                (setq index (string-search "~" glob index)))
+      (if (or (get-text-property index 'escaped glob)
+              (or (= (1+ index) len)))
+          (setq index (1+ index))
+        (setq incl (substring glob 0 index)
+              excl (substring glob (1+ index)))))
+    (setq incl (eshell-glob-regexp incl)
+          excl (and excl (eshell-glob-regexp excl)))
+    ;; Exclude dot files if requested.
+    (if (or eshell-glob-include-dot-files
+            (eq (aref glob 0) ?.))
+        (unless (or eshell-glob-include-dot-dot
+                    (not last))
+          (setq excl (if excl
+                         (concat "\\(\\`\\.\\.?\\'\\|" excl "\\)")
+                       "\\`\\.\\.?\\'")))
+      (setq excl (if excl
+                     (concat "\\(\\`\\.\\|" excl "\\)")
+                   "\\`\\.")))
+    (cons incl excl)))
+
+(defun eshell-glob-convert (glob)
+  "Convert an Eshell glob-pattern GLOB to regexps.
+The result is a list of three elements:
+
+1. The base directory to search in.
+
+2. A list containing elements of the following forms:
+
+   * Regexp pairs as generated by `eshell-glob-convert-1'.
+
+   * `recurse', indicating that searches should recurse into
+     subdirectories.
+
+   * `recurse-symlink', like `recurse', but also following
+     symlinks.
+
+3. A boolean indicating whether to match directories only."
+  (let ((globs (eshell-split-path glob))
+        (isdir (eq (aref glob (1- (length glob))) ?/))
+        start-dir result last-saw-recursion)
+    (if (and (cdr globs)
+             (file-name-absolute-p (car globs)))
+        (setq start-dir (car globs)
+              globs (cdr globs))
+      (setq start-dir "."))
+    (while globs
+      (if-let ((recurse (cdr (assoc (car globs)
+                                    eshell-glob-recursive-alist))))
+          (if last-saw-recursion
+              (setcar result recurse)
+            (push recurse result)
+            (setq last-saw-recursion t))
+        (push (eshell-glob-convert-1 (car globs) (null (cdr globs)))
+              result)
+        (setq last-saw-recursion nil))
+      (setq globs (cdr globs)))
+    (list (file-name-as-directory start-dir)
+          (nreverse result)
+          isdir)))
+
 (defun eshell-extended-glob (glob)
   "Return a list of files matched by GLOB.
 If no files match, signal an error (if `eshell-error-if-no-glob'
@@ -247,14 +326,10 @@ syntax.  Things that are not supported are:
 
 Mainly they are not supported because file matching is done with Emacs
 regular expressions, and these cannot support the above constructs."
-  (let ((paths (eshell-split-path glob))
+  (let ((globs (eshell-glob-convert glob))
         eshell-glob-matches message-shown)
     (unwind-protect
-       (if (and (cdr paths)
-                (file-name-absolute-p (car paths)))
-           (eshell-glob-entries (file-name-as-directory (car paths))
-                                (cdr paths))
-         (eshell-glob-entries (file-name-as-directory ".") paths))
+        (apply #'eshell-glob-entries globs)
       (if message-shown
          (message nil)))
     (or (and eshell-glob-matches (sort eshell-glob-matches #'string<))
@@ -263,94 +338,60 @@ regular expressions, and these cannot support the above 
constructs."
          glob))))
 
 ;; FIXME does this really need to abuse eshell-glob-matches, message-shown?
-(defun eshell-glob-entries (path globs &optional recurse-p)
-  "Glob the entries in PATH, possibly recursing if RECURSE-P is non-nil."
+(defun eshell-glob-entries (path globs only-dirs)
+  "Match the entries in PATH against GLOBS.
+GLOBS is a list of globs as converted by `eshell-glob-convert',
+which see.
+
+If ONLY-DIRS is non-nil, only match directories; otherwise, match
+directories and files."
   (let* ((entries (ignore-errors
-                   (file-name-all-completions "" path)))
-        (case-fold-search eshell-glob-case-insensitive)
-        (glob (car globs))
-        (len (length glob))
-        dirs rdirs
-        incl excl
-        name isdir pathname)
-    (while (cond
-           ((and (= len 3) (equal glob "**/"))
-            (setq recurse-p 2
-                  globs (cdr globs)
-                  glob (car globs)
-                  len (length glob)))
-           ((and (= len 4) (equal glob "***/"))
-            (setq recurse-p 3
-                  globs (cdr globs)
-                  glob (car globs)
-                  len (length glob)))))
-    (if (and recurse-p (not glob))
-       (error "`**/' cannot end a globbing pattern"))
-    (let ((index 1))
-      (setq incl glob)
-      (while (and (eq incl glob)
-                 (setq index (string-search "~" glob index)))
-       (if (or (get-text-property index 'escaped glob)
-               (or (= (1+ index) len)))
-           (setq index (1+ index))
-         (setq incl (substring glob 0 index)
-               excl (substring glob (1+ index))))))
-    ;; can't use `directory-file-name' because it strips away text
-    ;; properties in the string
-    (let ((len (1- (length incl))))
-      (if (eq (aref incl len) ?/)
-         (setq incl (substring incl 0 len)))
-      (when excl
-       (setq len (1- (length excl)))
-       (if (eq (aref excl len) ?/)
-           (setq excl (substring excl 0 len)))))
-    (setq incl (eshell-glob-regexp incl)
-         excl (and excl (eshell-glob-regexp excl)))
-    (if (or eshell-glob-include-dot-files
-           (eq (aref glob 0) ?.))
-       (unless (or eshell-glob-include-dot-dot
-                   (cdr globs))
-         (setq excl (if excl
-                        (concat "\\(\\`\\.\\.?\\'\\|" excl "\\)")
-                      "\\`\\.\\.?\\'")))
-      (setq excl (if excl
-                    (concat "\\(\\`\\.\\|" excl "\\)")
-                  "\\`\\.")))
+                    (file-name-all-completions "" path)))
+         (case-fold-search eshell-glob-case-insensitive)
+         glob glob-remainder recurse-p)
+    (if (rassq (car globs) eshell-glob-recursive-alist)
+        (setq recurse-p (car globs)
+              glob (or (cadr globs)
+                       (eshell-glob-convert-1 "*" t))
+              glob-remainder (cddr globs))
+      (setq glob (car globs)
+            glob-remainder (cdr globs)))
     (when (and recurse-p eshell-glob-show-progress)
       (message "Building file list...%d so far: %s"
-              (length eshell-glob-matches) path)
+               (length eshell-glob-matches) path)
       (setq message-shown t))
-    (if (equal path "./") (setq path ""))
-    (while entries
-      (setq name (car entries)
-           len (length name)
-           isdir (eq (aref name (1- len)) ?/))
-      (if (let ((fname (directory-file-name name)))
-           (and (not (and excl (string-match excl fname)))
-                (string-match incl fname)))
-         (if (cdr globs)
-             (if isdir
-                 (setq dirs (cons (concat path name) dirs)))
-           (setq eshell-glob-matches
-                 (cons (concat path name) eshell-glob-matches))))
-      (if (and recurse-p isdir
-              (or (> len 3)
-                  (not (or (and (= len 2) (equal name "./"))
-                           (and (= len 3) (equal name "../")))))
-              (setq pathname (concat path name))
-              (not (and (= recurse-p 2)
-                        (file-symlink-p
-                         (directory-file-name pathname)))))
-         (setq rdirs (cons pathname rdirs)))
-      (setq entries (cdr entries)))
-    (setq dirs (nreverse dirs)
-         rdirs (nreverse rdirs))
-    (while dirs
-      (eshell-glob-entries (car dirs) (cdr globs))
-      (setq dirs (cdr dirs)))
-    (while rdirs
-      (eshell-glob-entries (car rdirs) globs recurse-p)
-      (setq rdirs (cdr rdirs)))))
+    (when (equal path "./") (setq path ""))
+    (let ((incl (car glob))
+          (excl (cdr glob))
+          dirs rdirs)
+      (dolist (name entries)
+        (let* ((len (length name))
+               (isdir (eq (aref name (1- len)) ?/))
+               pathname)
+          (when (let ((fname (directory-file-name name)))
+                  (and (not (and excl (string-match excl fname)))
+                       (string-match incl fname)))
+            (if glob-remainder
+                (when isdir
+                  (push (concat path name) dirs))
+              (when (or (not only-dirs)
+                        (and isdir
+                             (not (and (eq recurse-p 'recurse)
+                                       (file-symlink-p
+                                        (directory-file-name
+                                         (concat path name)))))))
+                (push (concat path name) eshell-glob-matches))))
+          (when (and recurse-p isdir
+                     (not (member name '("./" "../")))
+                     (setq pathname (concat path name))
+                     (not (and (eq recurse-p 'recurse)
+                               (file-symlink-p
+                                (directory-file-name pathname)))))
+            (push pathname rdirs))))
+      (dolist (dir (nreverse dirs))
+        (eshell-glob-entries dir glob-remainder only-dirs))
+      (dolist (rdir (nreverse rdirs))
+        (eshell-glob-entries rdir globs only-dirs)))))
 
 (provide 'em-glob)
 
diff --git a/lisp/eshell/em-hist.el b/lisp/eshell/em-hist.el
index 1877749c5c..1db239b9f7 100644
--- a/lisp/eshell/em-hist.el
+++ b/lisp/eshell/em-hist.el
@@ -55,7 +55,6 @@
 ;;; Code:
 
 (eval-when-compile (require 'cl-lib))
-(eval-when-compile (require 'subr-x)) ; `string-blank-p'
 
 (require 'ring)
 (require 'esh-opt)
diff --git a/lisp/eshell/em-pred.el b/lisp/eshell/em-pred.el
index d73976d346..b4ef154f8c 100644
--- a/lisp/eshell/em-pred.el
+++ b/lisp/eshell/em-pred.el
@@ -233,6 +233,8 @@ Each element is of the form (OPEN . CLOSE), where OPEN and 
CLOSE
 are characters representing the opening and closing delimiter,
 respectively.")
 
+(defvar eshell-error-if-no-glob)        ; Defined in em-glob.el.
+
 (defvar-keymap eshell-pred-mode-map
   "C-c M-q" #'eshell-display-predicate-help
   "C-c M-m" #'eshell-display-modifier-help)
@@ -263,14 +265,19 @@ respectively.")
            #'eshell-parse-arg-modifier t t)
   (eshell-pred-mode))
 
-(defun eshell-apply-modifiers (lst predicates modifiers)
-  "Apply to list LST a series of PREDICATES and MODIFIERS."
+(defun eshell-apply-modifiers (lst predicates modifiers string-desc)
+  "Apply to list LST a series of PREDICATES and MODIFIERS.
+STRING-DESC is the original string defining these predicates and
+modifiers."
   (let (stringified)
     (if (stringp lst)
        (setq lst (list lst)
              stringified t))
     (when (listp lst)
-      (setq lst (eshell-winnow-list lst nil predicates))
+      (when lst
+        (setq lst (or (eshell-winnow-list lst nil predicates)
+                      (when eshell-error-if-no-glob
+                        (error "No matches found: (%s)" string-desc)))))
       (while modifiers
        (setq lst (funcall (car modifiers) lst)
              modifiers (cdr modifiers)))
@@ -290,7 +297,8 @@ This function is specially for adding onto 
`eshell-parse-argument-hook'."
        (when (eshell-arg-delimiter (1+ end))
          (save-restriction
            (narrow-to-region (point) end)
-           (let* ((modifiers (eshell-parse-modifiers))
+           (let* ((modifier-string (buffer-string))
+                   (modifiers (eshell-parse-modifiers))
                   (preds (car modifiers))
                   (mods (cdr modifiers)))
              (if (or preds mods)
@@ -302,7 +310,7 @@ This function is specially for adding onto 
`eshell-parse-argument-hook'."
                         (list
                          (lambda (lst)
                            (eshell-apply-modifiers
-                            lst preds mods))))))))
+                            lst preds mods modifier-string))))))))
          (goto-char (1+ end))
          (eshell-finish-arg))))))
 
diff --git a/lisp/eshell/em-term.el b/lisp/eshell/em-term.el
index d150c07b03..a4fa699aa9 100644
--- a/lisp/eshell/em-term.el
+++ b/lisp/eshell/em-term.el
@@ -56,7 +56,7 @@ which commands are considered visual in nature."
   :type 'hook)
 
 (defcustom eshell-visual-commands
-  '("vi"                                ; what is going on??
+  '("vi" "vim"                          ; what is going on??
     "screen" "tmux" "top" "htop"        ; ok, a valid program...
     "less" "more"                       ; M-x view-file
     "lynx" "links" "ncftp"              ; eww, ange-ftp
@@ -67,7 +67,7 @@ Commands listed here are run in a term buffer.
 
 See also `eshell-visual-subcommands' and `eshell-visual-options'."
   :type '(repeat string)
-  :version "27.1")
+  :version "29.1")
 
 (defcustom eshell-visual-subcommands
   nil
@@ -186,8 +186,10 @@ allowed."
            (set-process-sentinel proc #'eshell-term-sentinel)
          (error "Failed to invoke visual command")))
       (term-char-mode)
-      (if eshell-escape-control-x
-         (term-set-escape-char ?\C-x))))
+      (when eshell-escape-control-x
+        ;; Don't drop existing escape char.
+        (let (term-escape-char)
+          (term-set-escape-char ?\C-x)))))
   nil)
 
 ;; Process sentinels receive two arguments.
diff --git a/lisp/eshell/em-unix.el b/lisp/eshell/em-unix.el
index 3967817b0e..40b83010f9 100644
--- a/lisp/eshell/em-unix.el
+++ b/lisp/eshell/em-unix.el
@@ -755,26 +755,21 @@ external command."
                                      (eshell-stringify-list
                                       (flatten-tree args)))
                              " "))
-            (cmd (format "%s -nH %s"
-                         (pcase command
-                           ("egrep" "grep -E")
-                           ("fgrep" "grep -F")
-                           (x x))
-                         args))
+            (cmd (format "%s -n %s" command args))
             compilation-scroll-output)
        (grep cmd)))))
 
 (defun eshell/grep (&rest args)
   "Use Emacs grep facility instead of calling external grep."
-  (eshell-grep "grep" args t))
+  (eshell-grep "grep" (append '("-H") args) t))
 
 (defun eshell/egrep (&rest args)
   "Use Emacs grep facility instead of calling external grep -E."
-  (eshell-grep "egrep" args t))
+  (eshell-grep "grep" (append '("-EH") args) t))
 
 (defun eshell/fgrep (&rest args)
   "Use Emacs grep facility instead of calling external grep -F."
-  (eshell-grep "fgrep" args t))
+  (eshell-grep "grep" (append '("-FH") args) t))
 
 (defun eshell/agrep (&rest args)
   "Use Emacs grep facility instead of calling external agrep."
@@ -968,7 +963,7 @@ Show wall-clock time elapsed during execution of COMMAND.")
   (if eshell-diff-window-config
       (set-window-configuration eshell-diff-window-config)))
 
-(defun nil-blank-string (string)
+(defun eshell-nil-blank-string (string)
   "Return STRING, or nil if STRING contains only blank characters."
   (cond
     ((string-match "[^[:blank:]]" string) string)
@@ -999,7 +994,7 @@ Show wall-clock time elapsed during execution of COMMAND.")
            (condition-case nil
                (diff-no-select
                 old new
-                (nil-blank-string (eshell-flatten-and-stringify args)))
+                 (eshell-nil-blank-string (eshell-flatten-and-stringify args)))
              (error
               (throw 'eshell-replace-command
                      (eshell-parse-command "*diff" orig-args))))
@@ -1049,6 +1044,8 @@ Show wall-clock time elapsed during execution of 
COMMAND.")
 
 (put 'eshell/occur 'eshell-no-numeric-conversions t)
 
+(define-obsolete-function-alias 'nil-blank-string #'eshell-nil-blank-string 
"29.1")
+
 (provide 'em-unix)
 
 ;; Local Variables:
diff --git a/lisp/eshell/esh-arg.el b/lisp/eshell/esh-arg.el
index 459487f435..8e44a88459 100644
--- a/lisp/eshell/esh-arg.el
+++ b/lisp/eshell/esh-arg.el
@@ -186,7 +186,7 @@ If QUOTED is nil, the resulting value(s) may be converted to
 numbers (see `eshell-concat-1').
 
 If each argument in REST is a non-list value, the result will be
-a single value, as if (mapconcat #'eshell-stringify REST) had been
+a single value, as if (mapconcat #\\='eshell-stringify REST) had been
 called, possibly converted to a number.
 
 If there is at least one (non-nil) list argument, the result will
diff --git a/lisp/eshell/esh-cmd.el b/lisp/eshell/esh-cmd.el
index 775e4c1057..2f77f3f497 100644
--- a/lisp/eshell/esh-cmd.el
+++ b/lisp/eshell/esh-cmd.el
@@ -133,6 +133,10 @@ There are several different kinds of commands, however."
 Such arguments will be passed to `read', and then evaluated."
   :type 'regexp)
 
+(defcustom eshell-lisp-form-nil-is-failure t
+  "If non-nil, Lisp forms like (COMMAND ARGS) treat a nil result as failure."
+  :type 'boolean)
+
 (defcustom eshell-pre-command-hook nil
   "A hook run before each interactive command is invoked."
   :type 'hook)
@@ -541,9 +545,7 @@ implemented via rewriting, rather than as a function."
                ,(eshell-invokify-arg body t)))
             (setcar for-items (cadr for-items))
             (setcdr for-items (cddr for-items)))
-           (eshell-close-handles
-            eshell-last-command-status
-            (list 'quote eshell-last-command-result))))))
+           (eshell-close-handles)))))
 
 (defun eshell-structure-basic-command (func names keyword test body
                                            &optional else)
@@ -551,10 +553,11 @@ implemented via rewriting, rather than as a function."
 The first of NAMES should be the positive form, and the second the
 negative.  It's not likely that users should ever need to call this
 function."
-  ;; If the test form begins with `eshell-convert', it means
-  ;; something data-wise will be returned, and we should let
-  ;; that determine the truth of the statement.
-  (unless (eq (car test) 'eshell-convert)
+  ;; If the test form begins with `eshell-convert' or
+  ;; `eshell-escape-arg', it means something data-wise will be
+  ;; returned, and we should let that determine the truth of the
+  ;; statement.
+  (unless (memq (car test) '(eshell-convert eshell-escape-arg))
     (setq test
          `(progn ,test
                   (eshell-exit-success-p))))
@@ -574,9 +577,7 @@ function."
   `(let ((eshell-command-body '(nil))
          (eshell-test-body '(nil)))
      (,func ,test ,body ,else)
-     (eshell-close-handles
-        eshell-last-command-status
-        (list 'quote eshell-last-command-result))))
+     (eshell-close-handles)))
 
 (defun eshell-rewrite-while-command (terms)
   "Rewrite a `while' command into its equivalent Eshell command form.
@@ -606,7 +607,7 @@ must be implemented via rewriting, rather than as a 
function."
                                t))
        (if (= (length terms) 4)
           `(eshell-protect
-             ,(eshell-invokify-arg (car (last terms)))) t))))
+             ,(eshell-invokify-arg (car (last terms)) t))))))
 
 (defvar eshell-last-command-result)     ;Defined in esh-io.el.
 
@@ -1121,7 +1122,7 @@ be finished later after the completion of an asynchronous 
subprocess."
          (setcar eshell-test-body nil))
        (unless (car eshell-test-body)
           (setcar eshell-test-body (copy-tree (car args))))
-       (while (cadr (eshell-do-eval (car eshell-test-body)))
+       (while (cadr (eshell-do-eval (car eshell-test-body) synchronous-p))
          (setcar eshell-command-body
                   (if (cddr args)
                       `(progn ,@(copy-tree (cdr args)))
@@ -1141,7 +1142,8 @@ be finished later after the completion of an asynchronous 
subprocess."
             (setcar eshell-test-body (copy-tree (car args))))
          (setcar eshell-command-body
                   (copy-tree
-                   (if (cadr (eshell-do-eval (car eshell-test-body)))
+                   (if (cadr (eshell-do-eval (car eshell-test-body)
+                                             synchronous-p))
                        (cadr args)
                      (car (cddr args)))))
          (eshell-do-eval (car eshell-command-body) synchronous-p))
@@ -1415,43 +1417,53 @@ via `eshell-errorn'."
 (defun eshell-lisp-command (object &optional args)
   "Insert Lisp OBJECT, using ARGS if a function."
   (catch 'eshell-external               ; deferred to an external command
+    (setq eshell-last-command-status 0
+          eshell-last-arguments args)
     (let* ((eshell-ensure-newline-p (eshell-interactive-output-p))
+           (command-form-p (functionp object))
            (result
-            (if (functionp object)
-                (progn
-                  (setq eshell-last-arguments args
-                        eshell-last-command-name
+            (if command-form-p
+                (let ((numeric (not (get object
+                                         'eshell-no-numeric-conversions)))
+                      (fname-args (get object 'eshell-filename-arguments)))
+                  (when (or numeric fname-args)
+                    (while args
+                      (let ((arg (car args)))
+                        (cond
+                         ((and numeric (stringp arg) (> (length arg) 0)
+                               (text-property-any 0 (length arg)
+                                                  'number t arg))
+                          ;; If any of the arguments are flagged as
+                          ;; numbers waiting for conversion, convert
+                          ;; them now.
+                          (setcar args (string-to-number arg)))
+                         ((and fname-args (stringp arg)
+                               (string-equal arg "~"))
+                          ;; If any of the arguments match "~",
+                          ;; prepend "./" to treat it as a regular
+                          ;; file name.
+                          (setcar args (concat "./" arg)))))
+                      (setq args (cdr args))))
+                  (setq eshell-last-command-name
                         (concat "#<function " (symbol-name object) ">"))
-                  (let ((numeric (not (get object
-                                           'eshell-no-numeric-conversions)))
-                        (fname-args (get object 'eshell-filename-arguments)))
-                    (when (or numeric fname-args)
-                      (while args
-                        (let ((arg (car args)))
-                          (cond ((and numeric (stringp arg) (> (length arg) 0)
-                                      (text-property-any 0 (length arg)
-                                                         'number t arg))
-                                 ;; If any of the arguments are
-                                 ;; flagged as numbers waiting for
-                                 ;; conversion, convert them now.
-                                 (setcar args (string-to-number arg)))
-                                ((and fname-args (stringp arg)
-                                      (string-equal arg "~"))
-                                 ;; If any of the arguments match "~",
-                                 ;; prepend "./" to treat it as a
-                                 ;; regular file name.
-                                 (setcar args (concat "./" arg)))))
-                        (setq args (cdr args)))))
                   (eshell-apply object eshell-last-arguments))
-              (setq eshell-last-arguments args
-                    eshell-last-command-name "#<Lisp object>")
+              (setq eshell-last-command-name "#<Lisp object>")
               (eshell-eval object))))
       (if (and eshell-ensure-newline-p
               (save-excursion
                 (goto-char eshell-last-output-end)
                 (not (bolp))))
          (eshell-print "\n"))
-      (eshell-close-handles 0 (list 'quote result)))))
+      (eshell-close-handles
+       ;; If `eshell-lisp-form-nil-is-failure' is non-nil, Lisp forms
+       ;; that succeeded but have a nil result should have an exit
+       ;; status of 2.
+       (when (and eshell-lisp-form-nil-is-failure
+                  (not command-form-p)
+                  (= eshell-last-command-status 0)
+                  (not result))
+         2)
+       (list 'quote result)))))
 
 (defalias 'eshell-lisp-command* #'eshell-lisp-command)
 
diff --git a/lisp/eshell/esh-io.el b/lisp/eshell/esh-io.el
index 3644c1a18b..e5977c9580 100644
--- a/lisp/eshell/esh-io.el
+++ b/lisp/eshell/esh-io.el
@@ -254,6 +254,30 @@ a nil value of mode defaults to `insert'."
       (setq idx (1+ idx))))
   handles)
 
+(defun eshell-close-handles (&optional exit-code result handles)
+  "Close all of the current HANDLES, taking refcounts into account.
+If HANDLES is nil, use `eshell-current-handles'.
+
+EXIT-CODE is the process exit code (zero, if the command
+completed successfully).  If nil, then use the exit code already
+set in `eshell-last-command-status'.
+
+RESULT is the quoted value of the last command.  If nil, then use
+the value already set in `eshell-last-command-result'."
+  (when exit-code
+    (setq eshell-last-command-status exit-code))
+  (when result
+    (cl-assert (eq (car result) 'quote))
+    (setq eshell-last-command-result (cadr result)))
+  (let ((handles (or handles eshell-current-handles)))
+    (dotimes (idx eshell-number-of-handles)
+      (when-let ((handle (aref handles idx)))
+        (setcdr handle (1- (cdr handle)))
+       (when (= (cdr handle) 0)
+          (dolist (target (ensure-list (car (aref handles idx))))
+            (eshell-close-target target (= eshell-last-command-status 0)))
+          (setcar handle nil))))))
+
 (defun eshell-close-target (target status)
   "Close an output TARGET, passing STATUS as the result.
 STATUS should be non-nil on successful termination of the output."
@@ -276,8 +300,23 @@ STATUS should be non-nil on successful termination of the 
output."
    ;; If we're redirecting to a process (via a pipe, or process
    ;; redirection), send it EOF so that it knows we're finished.
    ((eshell-processp target)
-    (if (eq (process-status target) 'run)
-       (process-send-eof target)))
+    ;; According to POSIX.1-2017, section 11.1.9, when communicating
+    ;; via terminal, sending EOF causes all bytes waiting to be read
+    ;; to be sent to the process immediately.  Thus, if there are any
+    ;; bytes waiting, we need to send EOF twice: once to flush the
+    ;; buffer, and a second time to cause the next read() to return a
+    ;; size of 0, indicating end-of-file to the reading process.
+    ;; However, some platforms (e.g. Solaris) actually require sending
+    ;; a *third* EOF.  Since sending extra EOFs while the process is
+    ;; running are a no-op, we'll just send the maximum we'd ever
+    ;; need.  See bug#56025 for further details.
+    (let ((i 0)
+          ;; Only call `process-send-eof' once if communicating via a
+          ;; pipe (in truth, this just closes the pipe).
+          (max-attempts (if (process-tty-name target 'stdin) 3 1)))
+      (while (and (<= (cl-incf i) max-attempts)
+                  (eq (process-status target) 'run))
+        (process-send-eof target))))
 
    ;; A plain function redirection needs no additional arguments
    ;; passed.
@@ -290,32 +329,6 @@ STATUS should be non-nil on successful termination of the 
output."
    ((consp target)
     (apply (car target) status (cdr target)))))
 
-(defun eshell-close-handles (exit-code &optional result handles)
-  "Close all of the current handles, taking refcounts into account.
-EXIT-CODE is the process exit code; mainly, it is zero, if the command
-completed successfully.  RESULT is the quoted value of the last
-command.  If nil, then the meta variables for keeping track of the
-last execution result should not be changed."
-  (let ((idx 0))
-    (cl-assert (or (not result) (eq (car result) 'quote)))
-    (setq eshell-last-command-status exit-code
-         eshell-last-command-result (cadr result))
-    (while (< idx eshell-number-of-handles)
-      (let ((handles (or handles eshell-current-handles)))
-       (when (aref handles idx)
-         (setcdr (aref handles idx)
-                 (1- (cdr (aref handles idx))))
-         (when (= (cdr (aref handles idx)) 0)
-           (let ((target (car (aref handles idx))))
-             (if (not (listp target))
-                 (eshell-close-target target (= exit-code 0))
-               (while target
-                 (eshell-close-target (car target) (= exit-code 0))
-                 (setq target (cdr target)))))
-           (setcar (aref handles idx) nil))))
-      (setq idx (1+ idx)))
-    nil))
-
 (defun eshell-kill-append (string)
   "Call `kill-append' with STRING, if it is indeed a string."
   (if (stringp string)
@@ -488,7 +501,7 @@ Returns what was actually sent, or nil if nothing was sent."
     (condition-case nil
         (process-send-string target object)
       ;; If `process-send-string' raises an error, treat it as a broken pipe.
-      (error (signal 'eshell-pipe-broken target))))
+      (error (signal 'eshell-pipe-broken (list target)))))
 
    ((consp target)
     (apply (car target) object (cdr target))))
diff --git a/lisp/eshell/esh-mode.el b/lisp/eshell/esh-mode.el
index 59c8f8034f..ecbcf88b97 100644
--- a/lisp/eshell/esh-mode.el
+++ b/lisp/eshell/esh-mode.el
@@ -146,7 +146,7 @@ See variable `eshell-scroll-to-bottom-on-output' and 
function
 Eshell buffers are truncated from the top to be no greater than this
 number, if the function `eshell-truncate-buffer' is on
 `eshell-output-filter-functions'."
-  :type 'integer)
+  :type 'natnum)
 
 (defcustom eshell-output-filter-functions
   '(eshell-postoutput-scroll-to-bottom
@@ -301,7 +301,8 @@ and the hook `eshell-exit-hook'."
   "Emacs shell interactive mode."
   (setq-local eshell-mode t)
 
-  (when eshell-status-in-mode-line
+  (when (and eshell-status-in-mode-line
+             (listp mode-line-format))
     (make-local-variable 'eshell-command-running-string)
     (let ((fmt (copy-sequence mode-line-format)))
       (setq-local mode-line-format fmt))
@@ -361,7 +362,11 @@ and the hook `eshell-exit-hook'."
       (unless module-shortname
        (error "Invalid Eshell module name: %s" module-fullname))
       (unless (featurep (intern module-shortname))
-       (load module-shortname))))
+        (condition-case nil
+            (load module-shortname)
+          (error (lwarn 'eshell :error
+                        "Unable to load module `%s' (defined in 
`eshell-modules-list')"
+                        module-fullname))))))
 
   (unless (file-exists-p eshell-directory-name)
     (eshell-make-private-directory eshell-directory-name t))
@@ -1034,5 +1039,7 @@ This function could be in the list 
`eshell-output-filter-functions'."
   (let ((default-directory (bookmark-prop-get bookmark 'location)))
     (eshell)))
 
+(put 'eshell-bookmark-jump 'bookmark-handler-type "Eshell")
+
 (provide 'esh-mode)
 ;;; esh-mode.el ends here
diff --git a/lisp/eshell/esh-proc.el b/lisp/eshell/esh-proc.el
index 70426ccaf2..c367b5cd64 100644
--- a/lisp/eshell/esh-proc.el
+++ b/lisp/eshell/esh-proc.el
@@ -250,30 +250,6 @@ The prompt will be set to PROMPT."
   "A marker that tracks the beginning of output of the last subprocess.
 Used only on systems which do not support async subprocesses.")
 
-(defvar eshell-needs-pipe
-  '("bc"
-    ;; xclip.el (in GNU ELPA) calls all of these with
-    ;; `process-connection-type' set to nil.
-    "pbpaste" "putclip" "xclip" "xsel" "wl-copy")
-  "List of commands which need `process-connection-type' to be nil.
-Currently only affects commands in pipelines, and not those at
-the front.  If an element contains a directory part it must match
-the full name of a command, otherwise just the nondirectory part must match.")
-
-(defun eshell-needs-pipe-p (command)
-  "Return non-nil if COMMAND needs `process-connection-type' to be nil.
-See `eshell-needs-pipe'."
-  (and (bound-and-true-p eshell-in-pipeline-p)
-       (not (eq eshell-in-pipeline-p 'first))
-       ;; FIXME should this return non-nil for anything that is
-       ;; neither 'first nor 'last?  See bug#1388 discussion.
-       (catch 'found
-        (dolist (exe eshell-needs-pipe)
-          (if (string-equal exe (if (string-search "/" exe)
-                                    command
-                                  (file-name-nondirectory command)))
-              (throw 'found t))))))
-
 (defun eshell-gather-process-output (command args)
   "Gather the output from COMMAND + ARGS."
   (require 'esh-var)
@@ -290,31 +266,36 @@ See `eshell-needs-pipe'."
     (cond
      ((fboundp 'make-process)
       (setq proc
-           (let ((process-connection-type
-                  (unless (eshell-needs-pipe-p command)
-                    process-connection-type))
-                 (command (file-local-name (expand-file-name command))))
-             (apply #'start-file-process
-                    (file-name-nondirectory command) nil command args)))
+            (let ((command (file-local-name (expand-file-name command)))
+                  (conn-type (pcase (bound-and-true-p eshell-in-pipeline-p)
+                               ('first '(nil . pipe))
+                               ('last  '(pipe . nil))
+                               ('t     'pipe)
+                               ('nil   nil))))
+              (make-process
+               :name (file-name-nondirectory command)
+               :buffer (current-buffer)
+               :command (cons command args)
+               :filter (if (eshell-interactive-output-p)
+                           #'eshell-output-filter
+                         #'eshell-insertion-filter)
+               :sentinel #'eshell-sentinel
+               :connection-type conn-type
+               :file-handler t)))
       (eshell-record-process-object proc)
-      (set-process-buffer proc (current-buffer))
-      (set-process-filter proc (if (eshell-interactive-output-p)
-                                  #'eshell-output-filter
-                                 #'eshell-insertion-filter))
-      (set-process-sentinel proc #'eshell-sentinel)
       (run-hook-with-args 'eshell-exec-hook proc)
       (when (fboundp 'process-coding-system)
        (let ((coding-systems (process-coding-system proc)))
          (setq decoding (car coding-systems)
                encoding (cdr coding-systems)))
-       ;; If start-process decided to use some coding system for
+       ;; If `make-process' decided to use some coding system for
        ;; decoding data sent from the process and the coding system
        ;; doesn't specify EOL conversion, we had better convert CRLF
        ;; to LF.
        (if (vectorp (coding-system-eol-type decoding))
            (setq decoding (coding-system-change-eol-conversion decoding 'dos)
                  changed t))
-       ;; Even if start-process left the coding system for encoding
+       ;; Even if `make-process' left the coding system for encoding
        ;; data sent from the process undecided, we had better use the
        ;; same one as what we use for decoding.  But, we should
        ;; suppress EOL conversion.
@@ -365,7 +346,9 @@ See `eshell-needs-pipe'."
         (defvar eshell-last-output-end)         ;Defined in esh-mode.el.
        (eshell-update-markers eshell-last-output-end)
        ;; Simulate the effect of eshell-sentinel.
-       (eshell-close-handles (if (numberp exit-status) exit-status -1))
+       (eshell-close-handles
+         (if (numberp exit-status) exit-status -1)
+         (list 'quote (and (numberp exit-status) (= exit-status 0))))
        (eshell-kill-process-function command exit-status)
        (or (bound-and-true-p eshell-in-pipeline-p)
            (setq eshell-last-sync-output-start nil))
@@ -417,40 +400,36 @@ PROC is the process that's exiting.  STRING is the exit 
message."
   (when (buffer-live-p (process-buffer proc))
     (with-current-buffer (process-buffer proc)
       (unwind-protect
-          (let ((entry (assq proc eshell-process-list)))
-;          (if (not entry)
-;              (error "Sentinel called for unowned process `%s'"
-;                     (process-name proc))
-           (when entry
-             (unwind-protect
-                 (progn
-                   (unless (string= string "run")
-                      ;; Write the exit message if the status is
-                      ;; abnormal and the process is already writing
-                      ;; to the terminal.
-                      (when (and (eq proc (eshell-tail-process))
-                                 (not (string-match "^\\(finished\\|exited\\)"
-                                                    string)))
-                        (funcall (process-filter proc) proc string))
-                      (let ((handles (nth 1 entry))
-                            (str (prog1 (nth 3 entry)
-                                   (setf (nth 3 entry) nil)))
-                            (status (process-exit-status proc)))
-                        ;; If we're in the middle of handling output
-                        ;; from this process then schedule the EOF for
-                        ;; later.
-                        (letrec ((finish-io
-                                  (lambda ()
-                                    (if (nth 4 entry)
-                                        (run-at-time 0 nil finish-io)
-                                      (when str
-                                        (ignore-error 'eshell-pipe-broken
-                                          (eshell-output-object
-                                           str nil handles)))
-                                      (eshell-close-handles
-                                       status 'nil handles)))))
-                          (funcall finish-io)))))
-               (eshell-remove-process-entry entry))))
+          (when-let ((entry (assq proc eshell-process-list)))
+           (unwind-protect
+               (unless (string= string "run")
+                  ;; Write the exit message if the status is
+                  ;; abnormal and the process is already writing
+                  ;; to the terminal.
+                  (when (and (eq proc (eshell-tail-process))
+                             (not (string-match "^\\(finished\\|exited\\)"
+                                                string)))
+                    (funcall (process-filter proc) proc string))
+                  (let ((handles (nth 1 entry))
+                        (str (prog1 (nth 3 entry)
+                               (setf (nth 3 entry) nil)))
+                        (status (process-exit-status proc)))
+                    ;; If we're in the middle of handling output
+                    ;; from this process then schedule the EOF for
+                    ;; later.
+                    (letrec ((finish-io
+                              (lambda ()
+                                (if (nth 4 entry)
+                                    (run-at-time 0 nil finish-io)
+                                  (when str
+                                    (ignore-error 'eshell-pipe-broken
+                                      (eshell-output-object
+                                       str nil handles)))
+                                  (eshell-close-handles
+                                   status (list 'quote (= status 0))
+                                   handles)))))
+                      (funcall finish-io))))
+             (eshell-remove-process-entry entry)))
        (eshell-kill-process-function proc string)))))
 
 (defun eshell-process-interact (func &optional all query)
diff --git a/lisp/eshell/esh-util.el b/lisp/eshell/esh-util.el
index b5a423f023..9258ca5e40 100644
--- a/lisp/eshell/esh-util.el
+++ b/lisp/eshell/esh-util.el
@@ -301,16 +301,6 @@ Prepend remote identification of `default-directory', if 
any."
       (setq text (replace-match " " t t text)))
     text))
 
-(defmacro eshell-for (for-var for-list &rest forms)
-  "Iterate through a list."
-  (declare (obsolete dolist "24.1"))
-  (declare (indent 2))
-  `(let ((list-iter ,for-list))
-     (while list-iter
-       (let ((,for-var (car list-iter)))
-        ,@forms)
-       (setq list-iter (cdr list-iter)))))
-
 (define-obsolete-function-alias 'eshell-flatten-list #'flatten-tree "27.1")
 
 (defun eshell-stringify (object)
@@ -549,7 +539,7 @@ list."
 (autoload 'parse-time-string "parse-time")
 
 (eval-when-compile
-  (require 'ange-ftp nil t))           ; ange-ftp-parse-filename
+  (require 'ange-ftp))         ; ange-ftp-parse-filename
 
 (defvar tramp-file-name-structure)
 (declare-function ange-ftp-ls "ange-ftp"
diff --git a/lisp/eshell/esh-var.el b/lisp/eshell/esh-var.el
index 17add9b668..a9df172e88 100644
--- a/lisp/eshell/esh-var.el
+++ b/lisp/eshell/esh-var.el
@@ -113,6 +113,9 @@
 (require 'pcomplete)
 (require 'ring)
 
+(defconst eshell-inside-emacs (format "%s,eshell" emacs-version)
+  "Value for the `INSIDE_EMACS' environment variable.")
+
 (defgroup eshell-var nil
   "Variable interpolation is introduced whenever the `$' character
 appears unquoted in any argument (except when that argument is
@@ -149,61 +152,69 @@ if they are quoted with a backslash."
 
 (defcustom eshell-variable-aliases-list
   `(;; for eshell.el
-    ("COLUMNS" ,(lambda (_indices) (window-body-width nil 'remap)) t)
-    ("LINES" ,(lambda (_indices) (window-body-height nil 'remap)) t)
+    ("COLUMNS" ,(lambda () (window-body-width nil 'remap)) t t)
+    ("LINES" ,(lambda () (window-body-height nil 'remap)) t t)
+    ("INSIDE_EMACS" eshell-inside-emacs t)
 
     ;; for eshell-cmd.el
-    ("_" ,(lambda (indices)
+    ("_" ,(lambda (indices quoted)
            (if (not indices)
                (car (last eshell-last-arguments))
              (eshell-apply-indices eshell-last-arguments
-                                   indices))))
+                                   indices quoted))))
     ("?" eshell-last-command-status)
     ("$" eshell-last-command-result)
+
+    ;; for em-alias.el and em-script.el
     ("0" eshell-command-name)
-    ("1" ,(lambda (_indices) (nth 0 eshell-command-arguments)))
-    ("2" ,(lambda (_indices) (nth 1 eshell-command-arguments)))
-    ("3" ,(lambda (_indices) (nth 2 eshell-command-arguments)))
-    ("4" ,(lambda (_indices) (nth 3 eshell-command-arguments)))
-    ("5" ,(lambda (_indices) (nth 4 eshell-command-arguments)))
-    ("6" ,(lambda (_indices) (nth 5 eshell-command-arguments)))
-    ("7" ,(lambda (_indices) (nth 6 eshell-command-arguments)))
-    ("8" ,(lambda (_indices) (nth 7 eshell-command-arguments)))
-    ("9" ,(lambda (_indices) (nth 8 eshell-command-arguments)))
-    ("*" ,(lambda (indices)
-           (if (not indices)
-               eshell-command-arguments
-             (eshell-apply-indices eshell-command-arguments
-                                   indices)))))
+    ("1" ,(lambda () (nth 0 eshell-command-arguments)) nil t)
+    ("2" ,(lambda () (nth 1 eshell-command-arguments)) nil t)
+    ("3" ,(lambda () (nth 2 eshell-command-arguments)) nil t)
+    ("4" ,(lambda () (nth 3 eshell-command-arguments)) nil t)
+    ("5" ,(lambda () (nth 4 eshell-command-arguments)) nil t)
+    ("6" ,(lambda () (nth 5 eshell-command-arguments)) nil t)
+    ("7" ,(lambda () (nth 6 eshell-command-arguments)) nil t)
+    ("8" ,(lambda () (nth 7 eshell-command-arguments)) nil t)
+    ("9" ,(lambda () (nth 8 eshell-command-arguments)) nil t)
+    ("*" eshell-command-arguments))
   "This list provides aliasing for variable references.
-Each member defines the name of a variable, and a Lisp value used to
+Each member is of the following form:
+
+  (NAME VALUE [COPY-TO-ENVIRONMENT] [SIMPLE-FUNCTION])
+
+NAME defines the name of the variable, VALUE is a Lisp value used to
 compute the string value that will be returned when the variable is
 accessed via the syntax `$NAME'.
 
-If the value is a function, call that function with two arguments: the
-list of the indices that was used in the reference, and whether the
-user is requesting the length of the ultimate element.  For example, a
-reference of `$NAME[10][20]' would result in the function for alias
-`NAME' being called (assuming it were aliased to a function), and the
-arguments passed to this function would be the list `(10 20)', and
+If VALUE is a function, its behavior depends on the value of
+SIMPLE-FUNCTION.  If SIMPLE-FUNCTION is nil, call VALUE with two
+arguments: the list of the indices that were used in the reference,
+and either t or nil depending on whether or not the variable was
+quoted with double quotes.  For example, if `NAME' were aliased
+to a function, a reference of `$NAME[10][20]' would result in that
+function being called with the arguments `((\"10\") (\"20\"))' and
 nil.
+If SIMPLE-FUNCTION is non-nil, call the function with no arguments
+and then pass its return value to `eshell-apply-indices'.
 
-If the value is a string, return the value for the variable with that
+If VALUE is a string, return the value for the variable with that
 name in the current environment.  If no variable with that name exists
 in the environment, but if a symbol with that same name exists and has
-a value bound to it, return its value instead.  You can prioritize
-symbol values over environment values by setting
-`eshell-prefer-lisp-variables' to t.
+a value bound to it, return that symbol's value instead.  You can
+prefer symbol values over environment values by setting the value
+of `eshell-prefer-lisp-variables' to t.
 
-If the value is a symbol, return the value bound to it.
+If VALUE is a symbol, return the value bound to it.
 
-If the value has any other type, signal an error.
+If VALUE has any other type, signal an error.
 
-Additionally, each member may specify if it should be copied to the
-environment of created subprocesses."
+Additionally, if COPY-TO-ENVIRONMENT is non-nil, the alias should be
+copied (a.k.a. \"exported\") to the environment of created subprocesses."
   :type '(repeat (list string sexp
                       (choice (const :tag "Copy to environment" t)
-                               (const :tag "Use only in Eshell" nil))))
+                               (const :tag "Use only in Eshell" nil))
+                       (choice (const :tag "Call without argument" t)
+                               (const :tag "Call with 2 arguments" nil))))
   :risky t)
 
 (defvar-keymap eshell-var-mode-map
@@ -479,8 +490,11 @@ Possible variable references are:
                            ;; by `eshell-do-eval', which requires very
                            ;; particular forms in order to work
                            ;; properly.  See bug#54190.
-                           (list (function (lambda ()
-                                   (delete-file ,temp))))))
+                           (list (function
+                                  (lambda ()
+                                    (delete-file ,temp)
+                                    (when-let ((buffer (get-file-buffer 
,temp)))
+                                      (kill-buffer buffer)))))))
                    (eshell-apply-indices ,temp indices 
,eshell-current-quoted)))
             (goto-char (1+ end)))))))
    ((eq (char-after) ?\()
@@ -545,27 +559,35 @@ For example, \"[0 1][2]\" becomes:
   "Get the value for the variable NAME.
 INDICES is a list of index-lists (see `eshell-parse-indices').
 If QUOTED is non-nil, this was invoked inside double-quotes."
-  (let* ((alias (assoc name eshell-variable-aliases-list))
-        (var (if alias
-                 (cadr alias)
-               name)))
-    (if (and alias (functionp var))
-       (funcall var indices)
-      (eshell-apply-indices
-       (cond
-       ((stringp var)
-        (let ((sym (intern-soft var)))
-          (if (and sym (boundp sym)
-                   (or eshell-prefer-lisp-variables
-                       (memq sym eshell--local-vars) ; bug#15372
-                       (not (getenv var))))
-              (symbol-value sym)
-            (getenv var))))
-       ((symbolp var)
-        (symbol-value var))
-       (t
-        (error "Unknown variable `%s'" (eshell-stringify var))))
-       indices quoted))))
+  (if-let ((alias (assoc name eshell-variable-aliases-list)))
+      (let ((target (nth 1 alias)))
+        (cond
+         ((functionp target)
+          (if (nth 3 alias)
+              (eshell-apply-indices (funcall target) indices quoted)
+            (condition-case nil
+               (funcall target indices quoted)
+              (wrong-number-of-arguments
+               (display-warning
+                :warning (concat "Function for `eshell-variable-aliases-list' "
+                                 "entry should accept two arguments: INDICES "
+                                 "and QUOTED.'"))
+               (funcall target indices)))))
+         ((symbolp target)
+          (eshell-apply-indices (symbol-value target) indices quoted))
+         (t
+          (eshell-get-variable target indices quoted))))
+    (unless (stringp name)
+      (error "Unknown variable `%s'" (eshell-stringify name)))
+    (eshell-apply-indices
+     (let ((sym (intern-soft name)))
+       (if (and sym (boundp sym)
+               (or eshell-prefer-lisp-variables
+                   (memq sym eshell--local-vars) ; bug#15372
+                   (not (getenv name))))
+          (symbol-value sym)
+        (getenv name)))
+     indices quoted)))
 
 (defun eshell-apply-indices (value indices &optional quoted)
   "Apply to VALUE all of the given INDICES, returning the sub-result.
diff --git a/lisp/ezimage.el b/lisp/ezimage.el
index 9e5a08e682..ad98c45336 100644
--- a/lisp/ezimage.el
+++ b/lisp/ezimage.el
@@ -182,11 +182,6 @@ Optional argument STRING is a string upon which to add 
text properties."
   (when ezimage-use-images
     (let* ((bt (buffer-substring start (+ length start)))
           (a (assoc bt ezimage-expand-image-button-alist)))
-      ;; Regular images (created with `insert-image' are intangible
-      ;; which (I suppose) make them more compatible with XEmacs 21.
-      ;; Unfortunately, there is a giant pile of code dependent on the
-      ;; underlying text.  This means if we leave it tangible, then I
-      ;; don't have to change said giant piles of code.
       (if (and a (symbol-value (cdr a)))
          (ezimage-insert-over-text (symbol-value (cdr a))
                                    start
diff --git a/lisp/face-remap.el b/lisp/face-remap.el
index 50306a5e8a..432385587b 100644
--- a/lisp/face-remap.el
+++ b/lisp/face-remap.el
@@ -230,7 +230,8 @@ not to inherit from the global definition of FACE at all."
 
 (defcustom text-scale-mode-step 1.2
   "Scale factor used by `text-scale-mode'.
-Each positive or negative step scales the default face height by this amount."
+Each positive or negative step scales the size of the `default'
+face's font by this amount."
   :group 'display
   :type 'number
   :version "23.1")
@@ -335,7 +336,7 @@ the same amount)."
 
 ;;;###autoload
 (defun text-scale-increase (inc)
-  "Increase the height of the default face in the current buffer by INC steps.
+  "Increase the font size of the default face in current buffer by INC steps.
 If the new height is other than the default, `text-scale-mode' is enabled.
 
 Each step scales the height of the default face by the variable
@@ -347,14 +348,14 @@ will remove any scaling currently active."
          (new-value (if (= inc 0) 0 (+ current-value inc))))
     (if (or (> new-value (text-scale-max-amount))
             (< new-value (text-scale-min-amount)))
-        (user-error "Cannot %s the default face height more than it already is"
+        (user-error "Cannot %s the font size any further"
                     (if (> inc 0) "increase" "decrease")))
     (setq text-scale-mode-amount new-value))
   (text-scale-mode (if (zerop text-scale-mode-amount) -1 1)))
 
 ;;;###autoload
 (defun text-scale-decrease (dec)
-  "Decrease the height of the default face in the current buffer by DEC steps.
+  "Decrease the font size of the default face in the current buffer by DEC 
steps.
 See `text-scale-increase' for more details."
   (interactive "p")
   (text-scale-increase (- dec)))
@@ -365,19 +366,18 @@ See `text-scale-increase' for more details."
 ;;;###autoload (define-key ctl-x-map [(control ?0)] 'text-scale-adjust)
 ;;;###autoload
 (defun text-scale-adjust (inc)
-  "Adjust the height of the default face by INC.
-
+  "Adjust the font size in the current buffer by INC steps.
 INC may be passed as a numeric prefix argument.
 
 The actual adjustment made depends on the final component of the
 keybinding used to invoke the command, with all modifiers removed:
 
-   +, =   Increase the height of the default face by one step
-   -      Decrease the height of the default face by one step
-   0      Reset the height of the default face to the global default
+   \\`+', \\`='   Increase font size in current buffer by one step
+   \\`-'      Decrease font size in current buffer by one step
+   \\`0'      Reset the font size to the global default
 
 After adjusting, continue to read input events and further adjust
-the face height as long as the input event read
+the font size as long as the input event read
 \(with all modifiers removed) is one of the above characters.
 
 Each step scales the height of the default face by the variable
@@ -389,7 +389,14 @@ This command is a special-purpose wrapper around the
 `text-scale-increase' command which makes repetition convenient
 even when it is bound in a non-top-level keymap.  For binding in
 a top-level keymap, `text-scale-increase' or
-`text-scale-decrease' may be more appropriate."
+`text-scale-decrease' may be more appropriate.
+
+Most faces are affected by these font size changes, but not faces
+that have an explicit `:height' setting.  The two exceptions to
+this are the `default' and `header-line' faces: they will both be
+scaled even if they have an explicit `:height' setting.
+
+See also the related command `global-text-scale-adjust'."
   (interactive "p")
   (let ((ev last-command-event)
        (echo-keystrokes nil))
@@ -401,19 +408,15 @@ a top-level keymap, `text-scale-increase' or
               (?0 0)
               (_ inc))))
       (text-scale-increase step)
-      ;; (unless (zerop step)
-      (message "Use +,-,0 for further adjustment")
       (set-transient-map
        (let ((map (make-sparse-keymap)))
          (dolist (mods '(() (control)))
-           (dolist (key '(?- ?+ ?= ?0)) ;; = is often unshifted +.
+           (dolist (key '(?+ ?= ?- ?0)) ;; = is often unshifted +.
              (define-key map (vector (append mods (list key)))
                (lambda () (interactive) (text-scale-adjust (abs inc))))))
          map)
-       nil
-       ;; Clear the prompt after exiting.
-       (lambda ()
-         (message ""))))))
+       nil nil
+       "Use %k for further adjustment"))))
 
 (defvar-local text-scale--pinch-start-scale 0
   "The text scale at the start of a pinch sequence.")
@@ -440,6 +443,83 @@ a top-level keymap, `text-scale-increase' or
        (+ text-scale--pinch-start-scale
           (round (log scale text-scale-mode-step)))))))
 
+(defcustom global-text-scale-adjust-resizes-frames nil
+  "Whether `global-text-scale-adjust' resizes the frames."
+  :type '(choice (const :tag "Off" nil)
+                 (const :tag "On" t))
+  :group 'display
+  :version "29.1")
+
+(defcustom global-text-scale-adjust-limits '(10 . 500)
+  "Min/max values for `global-text-scale-adjust'.
+This is a cons cell where the `car' has the minimum font size and
+the `cdr' has the maximum font size, in units of 1/10 pt."
+  :version "29.1"
+  :group 'display
+  :type '(cons (integer :tag "Min")
+               (integer :tag "Max")))
+
+(defvar global-text-scale-adjust--default-height nil)
+
+;;;###autoload (define-key ctl-x-map [(control meta ?+)] 
'global-text-scale-adjust)
+;;;###autoload (define-key ctl-x-map [(control meta ?=)] 
'global-text-scale-adjust)
+;;;###autoload (define-key ctl-x-map [(control meta ?-)] 
'global-text-scale-adjust)
+;;;###autoload (define-key ctl-x-map [(control meta ?0)] 
'global-text-scale-adjust)
+;;;###autoload
+(defun global-text-scale-adjust (increment)
+  "Globally adjust the font size by INCREMENT.
+
+Interactively, INCREMENT may be passed as a numeric prefix argument.
+
+The adjustment made depends on the final component of the key binding
+used to invoke the command, with all modifiers removed:
+
+   \\`+', \\`='   Globally increase the height of the default face
+   \\`-'      Globally decrease the height of the default face
+   \\`0'      Globally reset the height of the default face
+
+After adjusting, further adjust the font size as long as the key,
+with all modifiers removed, is one of the above characters.
+
+Buffer-local face adjustments have higher priority than global
+face adjustments.
+
+The variable `global-text-scale-adjust-resizes-frames' controls
+whether the frames are resized to keep the same number of lines
+and characters per line when the font size is adjusted.
+
+See also the related command `text-scale-adjust'."
+  (interactive "p")
+  (when (display-graphic-p)
+    (unless global-text-scale-adjust--default-height
+      (setq global-text-scale-adjust--default-height
+            (face-attribute 'default :height)))
+    (let* ((key (event-basic-type last-command-event))
+           (echo-keystrokes nil)
+           (cur (face-attribute 'default :height))
+           (inc
+            (pcase key
+              (?- (* (- increment) 5))
+              (?0 (- global-text-scale-adjust--default-height cur))
+              (_ (* increment 5))))
+           (new (+ cur inc)))
+      (when (< (car global-text-scale-adjust-limits)
+               new
+               (cdr global-text-scale-adjust-limits))
+        (let ((frame-inhibit-implied-resize
+               (not global-text-scale-adjust-resizes-frames)))
+          (set-face-attribute 'default nil :height new)))
+      (when (characterp key)
+        (set-transient-map
+         (let ((map (make-sparse-keymap)))
+           (dolist (mod '(() (control meta)))
+             (dolist (key '(?+ ?= ?- ?0))
+               (define-key map (vector (append mod (list key)))
+                 'global-text-scale-adjust)))
+           map)
+       nil nil
+       "Use %k for further adjustment")))))
+
 
 ;; ----------------------------------------------------------------
 ;; buffer-face-mode
diff --git a/lisp/faces.el b/lisp/faces.el
index d92569e7cd..336078b040 100644
--- a/lisp/faces.el
+++ b/lisp/faces.el
@@ -1,6 +1,6 @@
 ;;; faces.el --- Lisp faces -*- lexical-binding: t -*-
 
-;; Copyright (C) 1992-1996, 1998-2022 Free Software Foundation, Inc.
+;; Copyright (C) 1992-2022 Free Software Foundation, Inc.
 
 ;; Maintainer: emacs-devel@gnu.org
 ;; Keywords: internal
@@ -583,9 +583,6 @@ with the `default' face (which is always completely 
specified)."
                               nil))
 
 
-(defalias 'face-background-pixmap 'face-stipple)
-
-
 (defun face-underline-p (face &optional frame inherit)
  "Return non-nil if FACE specifies a non-nil underlining.
 If the optional argument FRAME is given, report on face FACE in that frame.
@@ -657,8 +654,8 @@ If FACE is a face-alias, get the documentation for the 
target face."
   (put face 'face-documentation (purecopy string)))
 
 
-(defalias 'face-doc-string 'face-documentation)
-(defalias 'set-face-doc-string 'set-face-documentation)
+(define-obsolete-function-alias 'face-doc-string #'face-documentation "29.1")
+(define-obsolete-function-alias 'set-face-doc-string #'set-face-documentation 
"29.1")
 
 
 
@@ -709,14 +706,14 @@ a.k.a. `regular'), `semi-expanded' (a.k.a. 
`demi-expanded'),
 
 `:height'
 
-VALUE specifies the relative or absolute height of the font.  An
-absolute height is an integer, and specifies font height in units
-of 1/10 pt.  A relative height is either a floating point number,
-which specifies a scaling factor for the underlying face height;
-or a function that takes a single argument (the underlying face
-height) and returns the new height.  Note that for the `default'
-face, you must specify an absolute height (since there is nothing
-for it to be relative to).
+VALUE specifies the relative or absolute font size (height of the
+font).  An absolute height is an integer, and specifies font height in
+units of 1/10 pt.  A relative height is either a floating point
+number, which specifies a scaling factor for the underlying face
+height; or a function that takes a single argument (the underlying
+face height) and returns the new height.  Note that for the `default'
+face, you must specify an absolute height (since there is nothing for
+it to be relative to).
 
 `:weight'
 
@@ -1053,9 +1050,6 @@ Use `set-face-attribute' to \"unspecify\" underlining."
   (set-face-attribute face frame :extend extend-p))
 
 
-(defalias 'set-face-background-pixmap 'set-face-stipple)
-
-
 (defun invert-face (face &optional frame)
   "Swap the foreground and background colors of FACE.
 If FRAME is omitted or nil, it means change face on all frames.
@@ -1883,7 +1877,7 @@ This value was determined experimentally.")
   "Whether RGB is more readable against white than black.
 RGB is a 3-element list (R G B), each component in the range [0,1].
 This predicate can be used both for determining a suitable (black or white)
-contrast colour with RGB as background and as foreground."
+contrast color with RGB as background and as foreground."
   (unless (<= 0 (apply #'min rgb) (apply #'max rgb) 1)
     (error "RGB components %S not in [0,1]" rgb))
   ;; Compute the relative luminance after gamma-correcting (assuming sRGB),
@@ -2037,7 +2031,7 @@ as backgrounds."
             (setq color (background-color-at-point))))
       (when (and convert-to-RGB
                 (not (string-equal color "")))
-       (let ((components (x-color-values color)))
+        (let ((components (color-values color)))
          (unless (string-match-p 
"^#\\(?:[[:xdigit:]][[:xdigit:]][[:xdigit:]]\\)+$" color)
            (setq color (format "#%04X%04X%04X"
                                (logand 65535 (nth 0 components))
@@ -2046,18 +2040,29 @@ as backgrounds."
     (when msg (message "Color: `%s'" color))
     color))
 
-(defun face-at-point (&optional thing multiple)
-  "Return the face of the character after point.
-If it has more than one face, return the first one.
-If THING is non-nil try first to get a face name from the buffer.
-IF MULTIPLE is non-nil, return a list of all faces.
-Return nil if there is no face."
+(defun face-at-point (&optional text multiple)
+  "Return a face name from point in the current buffer.
+This function is meant to be used as a conveniency function for
+providing defaults when prompting the user for a face name.
+
+If TEXT is non-nil, return the text at point if it names an
+existing face.
+
+Otherwise, look at the faces in effect at point as text
+properties or overlay properties, and return one of these face
+names.
+
+IF MULTIPLE is non-nil, return a list of faces.
+
+Return nil if there is no face at point.
+
+This function is not meant for handling faces programatically; to
+do that, use `get-text-property' and `get-char-property'."
   (let (faces)
-    (if thing
-        ;; Try to get a face name from the buffer.
-        (let ((face (intern-soft (thing-at-point 'symbol))))
-          (if (facep face)
-              (push face faces))))
+    (when text
+      ;; Try to get a face name from the buffer.
+      (when-let ((face (thing-at-point 'face)))
+        (push face faces)))
     ;; Add the named faces that the `read-face-name' or `face' property uses.
     (let ((faceprop (or (get-char-property (point) 'read-face-name)
                         (get-char-property (point) 'face))))
@@ -2496,18 +2501,9 @@ default."
   "Basic face for highlighting."
   :group 'basic-faces)
 
-;; Region face: under NS, default to the system-defined selection
-;; color (optimized for the fixed white background of other apps),
-;; if background is light.
 (defface region
   '((((class color) (min-colors 88) (background dark))
      :background "blue3" :extend t)
-    (((class color) (min-colors 88) (background light) (type gtk))
-     :distant-foreground "gtk_selection_fg_color"
-     :background "gtk_selection_bg_color" :extend t)
-    (((class color) (min-colors 88) (background light) (type ns))
-     :distant-foreground "ns_selection_fg_color"
-     :background "ns_selection_bg_color" :extend t)
     (((class color) (min-colors 88) (background light))
      :background "lightgoldenrod2" :extend t)
     (((class color) (min-colors 16) (background dark))
@@ -2982,7 +2978,7 @@ bindings.  See also the face `tooltip'."
   :group 'help)
 
 (defface glyphless-char
-  '((((type tty)) :inherit underline)
+  '((((type tty)) :inherit escape-glyph :underline t)
     (((type pc)) :inherit escape-glyph)
     (t :height 0.6))
   "Face for displaying non-graphic characters (e.g. U+202A (LRE)).
@@ -3177,6 +3173,9 @@ also the same size as FACE on FRAME, or fail."
   :group 'display)
 (make-obsolete-variable 'font-list-limit nil "24.3")
 
+(define-obsolete-function-alias 'face-background-pixmap #'face-stipple "29.1")
+(define-obsolete-function-alias 'set-face-background-pixmap #'set-face-stipple 
"29.1")
+
 (provide 'faces)
 
 ;;; faces.el ends here
diff --git a/lisp/ffap.el b/lisp/ffap.el
index ae86e55490..88b4bce9fd 100644
--- a/lisp/ffap.el
+++ b/lisp/ffap.el
@@ -1,6 +1,6 @@
 ;;; ffap.el --- find file (or url) at point  -*- lexical-binding: t -*-
 
-;; Copyright (C) 1995-1997, 2000-2022 Free Software Foundation, Inc.
+;; Copyright (C) 1995-2022 Free Software Foundation, Inc.
 
 ;; Author: Michelangelo Grigni <mic@mathcs.emory.edu>
 ;; Maintainer: emacs-devel@gnu.org
@@ -24,14 +24,14 @@
 
 
 ;;; Commentary:
-;;
-;; Command find-file-at-point replaces find-file.  With a prefix, it
-;; behaves exactly like find-file.  Without a prefix, it first tries
-;; to guess a default file or URL from the text around the point
+
+;; Command `find-file-at-point' replaces `find-file'.  With a prefix,
+;; it behaves exactly like find-file.  Without a prefix, it first
+;; tries to guess a default file or URL from the text around the point
 ;; (`ffap-require-prefix' swaps these behaviors).  This is useful for
 ;; following references in situations such as mail or news buffers,
 ;; README's, MANIFEST's, and so on.  Submit bugs or suggestions with
-;; M-x report-emacs-bug.
+;; `M-x report-emacs-bug'.
 ;;
 ;; For the default installation, add this line to your init file:
 ;;
@@ -68,44 +68,38 @@
 ;; If you do not like these bindings, modify the variable
 ;; `ffap-bindings', or write your own.
 ;;
-;; If you use ange-ftp, browse-url, complete, efs, or w3, it is best
-;; to load or autoload them before ffap.  If you use ff-paths, load it
-;; afterwards.  Try apropos {C-h a ffap RET} to get a list of the many
-;; option variables.  In particular, if ffap is slow, try these:
+;; If you use ange-ftp, it is best to load or autoload it before ffap.
+;; If you use ff-paths, load it afterwards.  Try apropos `C-h a ffap
+;; RET' to get a list of the many option variables.  In particular, if
+;; ffap is slow, try these:
 ;;
 ;; (setq ffap-alist nil)                ; faster, dumber prompting
-;; (setq ffap-machine-p-known 'accept)  ; no pinging
 ;; (setq ffap-url-regexp nil)           ; disable URL features in ffap
 ;; (setq ffap-shell-prompt-regexp nil)  ; disable shell prompt stripping
 ;; (setq ffap-gopher-regexp nil)        ; disable gopher bookmark matching
 ;;
-;; ffap uses `browse-url' (if found, else `w3-fetch') to fetch URLs.
-;; For a hairier `ffap-url-fetcher', try ffap-url.el (same ftp site).
+;; ffap uses `browse-url' to fetch URLs.
 ;; Also, you can add `ffap-menu-rescan' to various hooks to fontify
 ;; the file and URL references within a buffer.
 
 
+;;; Code:
+
 ;;; Change Log:
-;;
-;; The History and Contributors moved to ffap.LOG (same ftp site),
-;; which also has some old examples and commentary from ffap 1.5.
+;; The History and Contributors moved to ffap.LOG, which also has some
+;; old examples and commentary from ffap 1.5.
 
-
 ;;; Todo list:
 ;; * let "/dir/file#key" jump to key (tag or regexp) in /dir/file
 ;; * find file of symbol if TAGS is loaded (like above)
 ;; * break long menus into multiple panes (like imenu?)
 ;; * notice node in "(dired)Virtual Dired" (quotes, parentheses, whitespace)
 ;; * notice "machine.dom blah blah blah dir/file" (how?)
-;; * as w3 becomes standard, rewrite to rely more on its functions
 ;; * regexp options for ffap-string-at-point, like font-lock (MCOOK)
-;; * v19: could replace `ffap-locate-file' with a quieter `locate-library'
+;; * could replace `ffap-locate-file' with a quieter `locate-library'
 ;; * handle "$(VAR)" in Makefiles
 ;; * use the font-lock machinery
 
-
-;;; Code:
-
 (eval-when-compile (require 'cl-lib))
 (require 'url-parse)
 (require 'thingatpt)
@@ -115,9 +109,6 @@
   :group 'matching
   :group 'convenience)
 
-;; The code is organized in pages, separated by formfeed characters.
-;; See the next two pages for standard customization ideas.
-
 
 ;;; User Variables:
 
@@ -174,7 +165,7 @@ well-formed, such as \"user@host\" or \"<user@host>\"."
 (defcustom ffap-ftp-default-user "anonymous"
   "User name in FTP file names generated by `ffap-host-to-filename'.
 Note this name may be omitted if it equals the default
-\(either `efs-default-user' or `ange-ftp-default-user')."
+(`ange-ftp-default-user')."
   :type 'string
   :group 'ffap)
 
@@ -191,7 +182,7 @@ Note this name may be omitted if it equals the default
    "\\("
    "news\\(post\\)?:\\|mailto:\\|file:" ; no host ok
    "\\|"
-   "\\(ftp\\|https?\\|telnet\\|gopher\\|www\\|wais\\)://" ; needs host
+   "\\(ftp\\|https?\\|telnet\\|gopher\\|gemini\\|www\\|wais\\)://" ; needs host
    "\\)")
   "Regexp matching the beginning of a URI, for ffap.
 If the value is nil, disable URL-matching features in ffap.")
@@ -246,14 +237,12 @@ it passes it on to `dired'."
   :group 'ffap)
 
 (defcustom ffap-newfile-prompt nil
-  ;; Suggestion from RHOGEE, 11 Jul 1994.  Disabled, I think this is
-  ;; better handled by `find-file-not-found-functions'.
   "Whether `find-file-at-point' prompts about a nonexistent file."
   :type 'boolean
   :group 'ffap)
+(make-obsolete-variable 'ffap-newfile-prompt 'find-file-not-found-functions 
"29.1")
 
 (defcustom ffap-require-prefix nil
-  ;; Suggestion from RHOGEE, 20 Oct 1994.
   "If set, reverses the prefix argument to `find-file-at-point'.
 This is nil so neophytes notice ffap.  Experts may prefer to disable
 ffap most of the time."
@@ -261,21 +250,20 @@ ffap most of the time."
   :group 'ffap)
 
 ;;;###autoload
-(defcustom ffap-file-finder 'find-file
+(defcustom ffap-file-finder #'find-file
   "The command called by `find-file-at-point' to find a file."
   :type 'function
   :group 'ffap
   :risky t)
 
-(defcustom ffap-directory-finder 'dired
+(defcustom ffap-directory-finder #'dired
   "The command called by `dired-at-point' to find a directory."
   :type 'function
   :group 'ffap
   :risky t)
 
-(defcustom ffap-url-fetcher 'browse-url
-  "A function of one argument, called by ffap to fetch an URL.
-For a fancy alternative, get `ffap-url.el'."
+(defcustom ffap-url-fetcher #'browse-url
+  "A function of one argument, called by ffap to fetch an URL."
   :type '(choice (const browse-url)
                 function)
   :group 'ffap
@@ -314,10 +302,6 @@ disable ffap most of the time."
 
 
 ;;; Find Next Thing in buffer (`ffap-next'):
-;;
-;; Original ffap-next-url (URLs only) from RPECK 30 Mar 1995.  Since
-;; then, broke it up into ffap-next-guess (noninteractive) and
-;; ffap-next (a command).  It now work on files as well as url's.
 
 (defvar ffap-next-guess nil
   "Last value returned by `ffap-next-guess'.")
@@ -377,6 +361,12 @@ Actual search is done by the function `ffap-next-guess'."
 
 ;;; Machines (`ffap-machine-p'):
 
+(defun ffap-accept-or-reject-p (symbol)
+  "Return non-nil if SYMBOL is `accept' or `reject'.
+Otherwise, return nil.  This is intended for use as the
+predicate in the `:safe' property of user options."
+  (memq symbol '(accept reject)))
+
 ;; I cannot decide a "best" strategy here, so these are variables.  In
 ;; particular, if `Pinging...' is broken or takes too long on your
 ;; machine, try setting these all to accept or reject.
@@ -385,16 +375,21 @@ Actual search is done by the function `ffap-next-guess'."
 Value should be a symbol, one of `ping', `accept', and `reject'."
   :type '(choice (const ping)
                 (const accept)
-                (const reject))
+                 (const reject))
+  :safe #'ffap-accept-or-reject-p
   :group 'ffap)
-(defcustom ffap-machine-p-known 'ping  ; `accept' for higher speed
+
+(defcustom ffap-machine-p-known 'accept
   "What `ffap-machine-p' does with hostnames that have a known domain.
 Value should be a symbol, one of `ping', `accept', and `reject'.
 See `mail-extr.el' for the known domains."
   :type '(choice (const ping)
                 (const accept)
-                (const reject))
-  :group 'ffap)
+                 (const reject))
+  :safe #'ffap-accept-or-reject-p
+  :group 'ffap
+  :version "29.1")
+
 (defcustom ffap-machine-p-unknown 'reject
   "What `ffap-machine-p' does with hostnames that have an unknown domain.
 Value should be a symbol, one of `ping', `accept', and `reject'.
@@ -402,6 +397,7 @@ See `mail-extr.el' for the known domains."
   :type '(choice (const ping)
                 (const accept)
                 (const reject))
+  :safe #'ffap-accept-or-reject-p
   :group 'ffap)
 
 (defun ffap-what-domain (domain)
@@ -422,13 +418,6 @@ Returned values:
  t       means that HOST answered.
 `accept' means the relevant variable told us to accept.
 \"mesg\"   means HOST exists, but does not respond for some reason."
-  ;; Try some (Emory local):
-  ;; (ffap-machine-p "ftp" nil nil 'ping)
-  ;; (ffap-machine-p "nonesuch" nil nil 'ping)
-  ;; (ffap-machine-p "ftp.mathcs.emory.edu" nil nil 'ping)
-  ;; (ffap-machine-p "mathcs" 5678 nil 'ping)
-  ;; (ffap-machine-p "foo.bonk" nil nil 'ping)
-  ;; (ffap-machine-p "foo.bonk.com" nil nil 'ping)
   (if (or (string-match "[^-[:alnum:].]" host) ; Invalid chars (?)
          (not (string-match "[^0-9]" host))) ; 1: a number? 2: quick reject
       nil
@@ -484,16 +473,13 @@ Returned values:
 
 (defun ffap-replace-file-component (fullname name)
   "In remote FULLNAME, replace path with NAME.  May return nil."
-  ;; Use efs if loaded, but do not load it otherwise.
-  (if (fboundp 'efs-replace-path-component)
-      (funcall 'efs-replace-path-component fullname name)
-    (and (stringp fullname)
-        (stringp name)
-        (concat (file-remote-p fullname) name))))
-;; (ffap-replace-file-component "/who@foo.com:/whatever" "/new")
+  (and (stringp fullname)
+       (stringp name)
+       (concat (file-remote-p fullname) name)))
 
 (defun ffap-file-suffix (file)
   "Return trailing `.foo' suffix of FILE, or nil if none."
+  (declare (obsolete file-name-extension "29.1"))
   (let ((pos (string-match "\\.[^./]*\\'" file)))
     (and pos (substring file pos nil))))
 
@@ -517,7 +503,7 @@ The optional NOMODIFY argument suppresses the extra search."
    ;; three reasons to suppress search:
    (nomodify nil)
    ((not (rassq 'jka-compr-handler file-name-handler-alist)) nil)
-   ((member (ffap-file-suffix file) ffap-compression-suffixes) nil)
+   ((member (file-name-extension file t) ffap-compression-suffixes) nil)
    (t                                  ; ok, do the search
     (let ((list ffap-compression-suffixes) try ret)
       (while list
@@ -528,9 +514,6 @@ The optional NOMODIFY argument suppresses the extra search."
 
 (defun ffap-file-remote-p (filename)
   "If FILENAME looks remote, return it (maybe slightly improved)."
-  ;; (ffap-file-remote-p "/user@foo.bar.com:/pub")
-  ;; (ffap-file-remote-p "/cssun.mathcs.emory.edu://dir")
-  ;; (ffap-file-remote-p "/ffap.el:80")
   (or (and ffap-ftp-regexp
           (string-match ffap-ftp-regexp filename)
           ;; Convert "/host.com://dir" to "/host:/dir", to handle a dying
@@ -544,6 +527,7 @@ The optional NOMODIFY argument suppresses the extra search."
           (string-match ffap-rfs-regexp filename)
           filename)))
 
+;;;###autoload
 (defun ffap-machine-at-point ()
   "Return machine name at point if it exists, or nil."
   (let ((mach (ffap-string-at-point 'machine)))
@@ -556,9 +540,8 @@ Looks at `ffap-ftp-default-user', returns \"\" for 
\"localhost\"."
       ""
     (let ((user ffap-ftp-default-user))
       ;; Avoid including the user if it is same as default:
-      (if (or (equal user (ffap-symbol-value 'ange-ftp-default-user))
-             (equal user (ffap-symbol-value 'efs-default-user)))
-         (setq user nil))
+      (when (equal user (ffap-symbol-value 'ange-ftp-default-user))
+        (setq user nil))
       (concat "/" user (and user "@") host ":"))))
 
 (defun ffap-fixup-machine (mach)
@@ -571,7 +554,7 @@ Looks at `ffap-ftp-default-user', returns \"\" for 
\"localhost\"."
    ;; www.ncsa.uiuc.edu
    ((and (string-match "\\`w\\(ww\\|eb\\)[-.]" mach))
     (concat "http://"; mach "/"))
-   ;; More cases?  Maybe "telnet:" for archie?
+   ;; More cases?
    (ffap-ftp-regexp (ffap-host-to-filename mach))
    ))
 
@@ -631,18 +614,6 @@ Looks at `ffap-ftp-default-user', returns \"\" for 
\"localhost\"."
 
 
 ;;; File Name Handling:
-;;
-;; The upcoming ffap-alist actions need various utilities to prepare
-;; and search directories.  Too many features here.
-
-;; (defun ffap-last (l) (while (cdr l) (setq l (cdr l))) l)
-;; (defun ffap-splice (func inlist)
-;;  "Equivalent to (apply 'nconc (mapcar FUNC INLIST)), but less consing."
-;;  (let* ((head (cons 17 nil)) (last head))
-;;    (while inlist
-;;      (setcdr last (funcall func (car inlist)))
-;;      (setq last (ffap-last last) inlist (cdr inlist)))
-;;    (cdr head)))
 
 (defun ffap-list-env (env &optional empty)
   "Return a list of strings parsed from environment variable ENV.
@@ -757,8 +728,7 @@ This uses `ffap-file-exists-string', which may try adding 
suffixes from
 ;;
 ;; These search actions depend on the major-mode or regexps matching
 ;; the current name.  The little functions and their variables are
-;; deferred to the next section, at some loss of "code locality".  A
-;; good example of featuritis.  Trim this list for speed.
+;; deferred to the next section, at some loss of "code locality".
 
 (defvar ffap-alist
   '(
@@ -769,19 +739,18 @@ This uses `ffap-file-exists-string', which may try adding 
suffixes from
     ("\\.elc?\\'" . ffap-el)           ; simple.el, simple.elc
     (emacs-lisp-mode . ffap-el-mode)   ; rmail, gnus, simple, custom
     ;; (lisp-interaction-mode . ffap-el-mode) ; maybe
-    (finder-mode . ffap-el-mode)       ; type {C-h p} and try it
+    (finder-mode . ffap-el-mode)       ; type `C-h p' and try it
     (help-mode . ffap-el-mode)         ; maybe useful
     (c++-mode . ffap-c++-mode)         ; search ffap-c++-path
     (cc-mode . ffap-c-mode)            ; same
     ("\\.\\([chCH]\\|cc\\|hh\\)\\'" . ffap-c-mode) ; stdio.h
-    (fortran-mode . ffap-fortran-mode) ; FORTRAN requested by MDB
+    (fortran-mode . ffap-fortran-mode)
     ("\\.[fF]\\'" . ffap-fortran-mode)
     (tex-mode . ffap-tex-mode)         ; search ffap-tex-path
     (latex-mode . ffap-latex-mode)     ; similar
     ("\\.\\(tex\\|sty\\|doc\\|cls\\)\\'" . ffap-tex)
     ("\\.bib\\'" . ffap-bib)           ; search ffap-bib-path
     ("\\`\\." . ffap-home)             ; .emacs, .bashrc, .profile
-    ("\\`~/" . ffap-lcd)               ; |~/misc/ffap.el.Z|
     ;; This used to have a blank, but ffap-string-at-point doesn't
     ;; handle blanks.
     ;; https://lists.gnu.org/r/emacs-devel/2008-01/msg01058.html
@@ -979,7 +948,7 @@ out of NAME."
                (save-excursion
                  (re-search-backward (regexp-opt
                                       (mapcar 'car preferred-suffix-rules))
-                                     (point-at-bol)
+                                     (line-beginning-position)
                                      t))
              (push (cons "" (cdr (assoc (match-string 0) ; i.e. 
"(TeX-current-macro)"
                                         preferred-suffix-rules)))
@@ -993,7 +962,7 @@ out of NAME."
                                           (concat (car rule) name (cdr rule)))
                                         guess-rules)))
              (when (< (point-min) (point-max))
-               (buffer-substring (goto-char (point-min)) (point-at-eol))))))))
+               (buffer-substring (goto-char (point-min)) 
(line-end-position))))))))
 
 (defun ffap-tex (name)
   (ffap-tex-init)
@@ -1027,9 +996,8 @@ out of NAME."
                    (match-beginning 1) (match-end 1)))))
           try))))
 
-;; Maybe a "Lisp Code Directory" reference:
 (defun ffap-lcd (name)
-  ;; FIXME: Is this still in use?
+  (declare (obsolete nil "29.1"))
   (and
    (or
     ;; lisp-dir-apropos output buffer:
@@ -1098,8 +1066,7 @@ Function `ffap-string-at-point' uses the data fields as 
follows:
 The arguments CHARS, BEG and END are handled as described in
 `skip-chars-forward'.")
 
-(defvar ffap-string-at-point nil
-  ;; Added at suggestion of RHOGEE (for ff-paths), 7/24/95.
+(defvar ffap-string-at-point nil            ; for ff-paths
   "Last string returned by the function `ffap-string-at-point'.")
 
 (defcustom ffap-file-name-with-spaces nil
@@ -1326,29 +1293,25 @@ Assumes the buffer has not changed."
       ;; Older: (apply 'copy-region-as-kill ffap-string-at-point-region)
       (message "Copied to kill ring: %s"  str))))
 
-;; External.
-(declare-function w3-view-this-url "ext:w3" (&optional no-show))
-
+;;;###autoload
 (defun ffap-url-at-point ()
   "Return URL from around point if it exists, or nil.
 
 Sets the variable `ffap-string-at-point-region' to the bounds of URL, if any."
   (when ffap-url-regexp
-    (or (and (eq major-mode 'w3-mode) ; In a w3 buffer button?
-            (w3-view-this-url t))
-       (let ((thing-at-point-beginning-of-url-regexp ffap-url-regexp)
-             (thing-at-point-default-mail-uri-scheme ffap-foo-at-bar-prefix)
-              val)
-         (setq val (thing-at-point-url-at-point ffap-lax-url
-                                                 (if (use-region-p)
-                                                     (cons (region-beginning)
-                                                           (region-end)))))
-          (if val
-              (let ((bounds (thing-at-point-bounds-of-url-at-point
-                             ffap-lax-url)))
-                (setq ffap-string-at-point-region
-                      (list (car bounds) (cdr bounds)))))
-          val))))
+    (let ((thing-at-point-beginning-of-url-regexp ffap-url-regexp)
+          (thing-at-point-default-mail-uri-scheme ffap-foo-at-bar-prefix)
+          val)
+      (setq val (thing-at-point-url-at-point ffap-lax-url
+                                             (if (use-region-p)
+                                                 (cons (region-beginning)
+                                                       (region-end)))))
+      (if val
+          (let ((bounds (thing-at-point-bounds-of-url-at-point
+                         ffap-lax-url)))
+            (setq ffap-string-at-point-region
+                  (list (car bounds) (cdr bounds)))))
+      val)))
 
 (defvar ffap-gopher-regexp
   "\\<\\(Type\\|Name\\|Path\\|Host\\|Port\\) *= *"
@@ -1489,12 +1452,7 @@ which may actually result in an URL rather than a 
filename."
                   ((and (eq major-mode 'internal-ange-ftp-mode)
                         (string-match "^\\*ftp \\(.*\\)@\\(.*\\)\\*$"
                                       (buffer-name)))
-                   (concat "/" (substring (buffer-name) 5 -1) ":"))
-                  ;; This is too often a bad idea:
-                  ;;((and (eq major-mode 'w3-mode)
-                  ;;      (stringp url-current-server))
-                  ;; (host-to-ange-path url-current-server))
-                  )))
+                    (concat "/" (substring (buffer-name) 5 -1) ":")))))
            (and remote-dir
                 (or
                  (and (string-match "\\`\\(/?~?ftp\\)/" name)
@@ -1560,12 +1518,6 @@ which may actually result in an URL rather than a 
filename."
       ;; during the completing-read call).
       (setq file-name-handler-alist (delq elem file-name-handler-alist)))))
 
-;; The rest of this page is just to work with package complete.el.
-;; This code assumes that you load ffap.el after complete.el.
-;;
-;; We must inform complete about whether our completion function
-;; will do filename style completion.
-
 
 ;;; Highlighting (`ffap-highlight'):
 
@@ -1641,7 +1593,7 @@ Uses the face `ffap' if it is defined, or else 
`highlight'."
 If `ffap-url-regexp' is not nil, the FILENAME may also be an URL.
 With a prefix, this command behaves exactly like `ffap-file-finder'.
 If `ffap-require-prefix' is set, the prefix meaning is reversed.
-See also the variables `ffap-dired-wildcards', `ffap-newfile-prompt',
+See also the variables `ffap-dired-wildcards',
 `ffap-url-unwrap-local', `ffap-url-unwrap-remote',
 `ffap-file-name-with-spaces', and the functions `ffap-file-at-point'
 and `ffap-url-at-point'."
@@ -1672,14 +1624,14 @@ and `ffap-url-at-point'."
            (file-exists-p filename)
            (y-or-n-p "File does not exist, create buffer? "))
        (find-file
-        ;; expand-file-name fixes "~/~/.emacs" bug sent by CHUCKR.
+         ;; expand-file-name fixes "~/~/.emacs" bug
         (expand-file-name filename)))
        ;; User does not want to find a non-existent file:
        ((signal 'file-missing (list "Opening file buffer"
                                    "No such file or directory"
                                    filename)))))))
 
-;; Shortcut: allow {M-x ffap} rather than {M-x find-file-at-point}.
+;; Shortcut: allow `M-x ffap' rather than `M-x find-file-at-point'.
 ;;;###autoload
 (defalias 'ffap 'find-file-at-point)
 
@@ -1822,7 +1774,7 @@ Applies `ffap-menu-text-plist' text properties at all 
matches."
 
 ;;; Mouse Support (`ffap-at-mouse'):
 ;;
-;; See the suggested binding in ffap-bindings (near eof).
+;; See the suggested binding in `ffap-bindings' (near eof).
 
 (defvar ffap-at-mouse-fallback nil     ; ffap-menu? too time-consuming
   "Command invoked by `ffap-at-mouse' if nothing found at click, or nil.
@@ -1868,7 +1820,7 @@ Return value:
 ;;; ffap-other-*, ffap-read-only-*, ffap-alternate-* commands:
 
 ;; There could be a real `ffap-noselect' function, but we would need
-;; at least two new user variables, and there is no w3-fetch-noselect.
+;; at least two new user variables.
 ;; So instead, we just fake it with a slow save-window-excursion.
 
 (defun ffap-other-window (filename)
@@ -1883,7 +1835,7 @@ Only intended for interactive use."
   "Like `ffap', but put buffer in another frame.
 Only intended for interactive use."
   (interactive (list (ffap-prompter nil " other frame")))
-  ;; Extra code works around dedicated windows (noted by JENS, 7/96):
+  ;; Extra code works around dedicated windows:
   (let* ((win (selected-window))
         (wdp (window-dedicated-p win))
         value)
@@ -2110,7 +2062,7 @@ Only intended for interactive use."
   "Like `dired-at-point', but put buffer in another frame.
 Only intended for interactive use."
   (interactive)
-  ;; Extra code works around dedicated windows (noted by JENS, 7/96):
+  ;; Extra code works around dedicated windows:
   (let* ((win (selected-window))
         (wdp (window-dedicated-p win))
         value)
diff --git a/lisp/files-x.el b/lisp/files-x.el
index 4db6fbd22c..da1e44e250 100644
--- a/lisp/files-x.el
+++ b/lisp/files-x.el
@@ -81,8 +81,7 @@ Intended to be used in the `interactive' spec of
     (let ((default (format "%S"
                            (cond ((eq variable 'unibyte) t)
                                  ((boundp variable)
-                                  (symbol-value variable)))))
-          (minibuffer-completing-symbol t))
+                                  (symbol-value variable))))))
       (read-from-minibuffer (format "Add %s with value: " variable)
                             nil read-expression-map t
                             'set-variable-value-history
@@ -502,24 +501,26 @@ from the MODE alist ignoring the input argument VALUE."
                       ((and (symbolp (car b)) (stringp (car a))) nil)
                       (t (string< (car a) (car b)))))))
              (current-buffer))
+      (when (eobp) (insert "\n"))
       (goto-char (point-min))
       (indent-sexp))))
 
 (defun dir-locals-to-string (variables)
   "Output alists of VARIABLES to string in dotted pair notation syntax."
-  (format "(%s)" (mapconcat
-                  (lambda (mode-variables)
-                    (format "(%S . %s)"
-                            (car mode-variables)
-                            (format "(%s)" (mapconcat
-                                            (lambda (variable-value)
-                                              (format "(%S . %s)"
-                                                      (car variable-value)
-                                                      (string-trim-right
-                                                       (pp-to-string
-                                                        (cdr 
variable-value)))))
-                                            (cdr mode-variables) "\n"))))
-                  variables "\n")))
+  (format "(%s)"
+          (mapconcat
+           (lambda (mode-variables)
+             (format "(%S . %s)"
+                     (car mode-variables)
+                     (format "(%s)" (mapconcat
+                                     (lambda (variable-value)
+                                       (format "(%S . %s)"
+                                               (car variable-value)
+                                               (string-trim-right
+                                                (pp-to-string
+                                                 (cdr variable-value)))))
+                                     (cdr mode-variables) "\n"))))
+           variables "\n")))
 
 ;;;###autoload
 (defun add-dir-local-variable (mode variable value)
diff --git a/lisp/files.el b/lisp/files.el
index a804f0088e..740e09055b 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -304,19 +304,17 @@ When nil, make them for files that have some already.
 The value `never' means do not make them."
   :type '(choice (const :tag "Never" never)
                 (const :tag "If existing" nil)
-                (other :tag "Always" t))
+                 (other :tag "Always" t))
+  :safe #'version-control-safe-local-p
   :group 'backup)
 
 (defun version-control-safe-local-p (x)
   "Return whether X is safe as local value for `version-control'."
   (or (booleanp x) (equal x 'never)))
 
-(put 'version-control 'safe-local-variable
-     #'version-control-safe-local-p)
-
 (defcustom dired-kept-versions 2
   "When cleaning directory, number of versions to keep."
-  :type 'integer
+  :type 'natnum
   :group 'backup
   :group 'dired)
 
@@ -330,16 +328,16 @@ If nil, ask confirmation.  Any other value prevents any 
trimming."
 
 (defcustom kept-old-versions 2
   "Number of oldest versions to keep when a new numbered backup is made."
-  :type 'integer
+  :type 'natnum
+  :safe #'natnump
   :group 'backup)
-(put 'kept-old-versions 'safe-local-variable 'integerp)
 
 (defcustom kept-new-versions 2
   "Number of newest versions to keep when a new numbered backup is made.
 Includes the new backup.  Must be greater than 0."
-  :type 'integer
+  :type 'natnum
+  :safe #'natnump
   :group 'backup)
-(put 'kept-new-versions 'safe-local-variable 'integerp)
 
 (defcustom require-final-newline nil
   "Whether to add a newline automatically at the end of the file.
@@ -398,19 +396,24 @@ add a final newline, whenever you save a file that really 
needs one."
      ;; transformed to "/2" on DOS/Windows.
      ,(concat temporary-file-directory "\\2") t))
   "Transforms to apply to buffer file name before making auto-save file name.
+
 Each transform is a list (REGEXP REPLACEMENT UNIQUIFY):
+
 REGEXP is a regular expression to match against the file name.
 If it matches, `replace-match' is used to replace the
 matching part with REPLACEMENT.
-If the optional element UNIQUIFY is non-nil, the auto-save file name is
-constructed by taking the directory part of the replaced file-name,
-concatenated with the buffer file name with all directory separators
-changed to `!' to prevent clashes.  This will not work
-correctly if your filesystem truncates the resulting name.
-If UNIQUIFY is one of the members of `secure-hash-algorithms',
-Emacs constructs the nondirectory part of the auto-save file name
-by applying that `secure-hash' to the buffer file name.  This
-avoids any risk of excessively long file names.
+
+If the optional element UNIQUIFY is nil, Emacs does not check for
+file name clashes, so using that is not recommended.  If UNIQUIFY
+is one of the members of `secure-hash-algorithms', Emacs
+constructs the nondirectory part of the auto-save file name by
+applying that `secure-hash' to the buffer file name.  This avoids
+any risk of excessively long file names.  Finally, if UNIQUIFY is
+any other value the auto-save file name is constructed by taking
+the directory part of the replaced file-name, concatenated with
+the buffer file name with all directory separators changed to `!'
+to prevent clashes.  This will not work correctly if your
+filesystem truncates the resulting name.
 
 All the transforms in the list are tried, in the order they are listed.
 When one transform applies, its result is final;
@@ -423,8 +426,13 @@ editing a remote file.
 On MS-DOS filesystems without long names this variable is always
 ignored."
   :group 'auto-save
-  :type '(repeat (list (regexp :tag "Regexp") (string :tag "Replacement")
-                                          (boolean :tag "Uniquify")))
+  :type `(repeat (list (regexp :tag "Regexp")
+                       (string :tag "Replacement")
+                       (choice
+                       (const :tag "Uniquify" t)
+                        ,@(mapcar (lambda (algo)
+                                    (list 'const algo))
+                                  (secure-hash-algorithms)))))
   :initialize 'custom-initialize-delay
   :version "21.1")
 
@@ -443,18 +451,60 @@ idle for `auto-save-visited-interval' seconds."
          (when auto-save--timer
            (timer-set-idle-time auto-save--timer value :repeat))))
 
+(defcustom auto-save-visited-predicate nil
+  "Predicate function for `auto-save-visited-mode'.
+
+If non-nil, the value should be a function of no arguments; it
+will be called once in each file-visiting buffer when the time
+comes to auto-save.  A buffer will be saved only if the predicate
+function returns a non-nil value.
+
+For example, you could add this to your Init file to only save
+files that are both in Org mode and in a particular directory:
+
+    (setq auto-save-visited-predicate
+          (lambda () (and (eq major-mode \\='org-mode)
+                          (string-match \"^/home/skangas/org/\"
+                                        buffer-file-name))))
+
+If the value of this variable is not a function, it is ignored.
+This is the same as having a predicate that always returns
+non-nil."
+  :group 'auto-save
+  :type '(choice :tag "Function:"
+                 (const :tag "No extra predicate" :value nil)
+                 (function :tag "Predicate function" :value always))
+  :risky t
+  :version "29.1")
+
+(defcustom remote-file-name-inhibit-auto-save-visited nil
+  "When nil, `auto-save-visited-mode' will auto-save remote files.
+Any other value means that it will not."
+  :group 'auto-save
+  :type 'boolean
+  :version "29.1")
+
 (define-minor-mode auto-save-visited-mode
-  "Toggle automatic saving to file-visiting buffers on or off.
+  "Toggle automatic saving of file-visiting buffers to their files.
+
+When this mode is enabled, file-visiting buffers are automatically
+saved to their files.  This is in contrast to `auto-save-mode', which
+auto-saves those buffers to a separate file, leaving the original
+file intact.  See Info node `Saving' for details of the save process.
 
-Unlike `auto-save-mode', this mode will auto-save buffer contents
-to the visited files directly and will also run all save-related
-hooks.  See Info node `Saving' for details of the save process.
+The user option `auto-save-visited-interval' controls how often to
+auto-save a buffer into its visited file.
+
+You can use `auto-save-visited-predicate' to control which
+buffers are saved.
 
 You can also set the buffer-local value of the variable
 `auto-save-visited-mode' to nil.  A buffer where the buffer-local
 value of this variable is nil is ignored for the purpose of
 `auto-save-visited-mode', even if `auto-save-visited-mode' is
-enabled."
+enabled.
+
+For more details, see Info node `(emacs) Auto Save Files'."
   :group 'auto-save
   :global t
   (when auto-save--timer (cancel-timer auto-save--timer))
@@ -467,7 +517,11 @@ enabled."
              (and buffer-file-name
                   auto-save-visited-mode
                   (not (and buffer-auto-save-file-name
-                            auto-save-visited-file-name))))))))
+                            auto-save-visited-file-name))
+                  (or (not (file-remote-p buffer-file-name))
+                      (not remote-file-name-inhibit-auto-save-visited))
+                  (or (not (functionp auto-save-visited-predicate))
+                      (funcall auto-save-visited-predicate))))))))
 
 ;; The 'set' part is so we don't get a warning for using this variable
 ;; above, while still catching code that _sets_ the variable to get
@@ -533,8 +587,6 @@ location of point in the current buffer."
 
 ;;;It is not useful to make this a local variable.
 ;;;(put 'find-file-not-found-functions 'permanent-local t)
-(define-obsolete-variable-alias 'find-file-not-found-hooks
-    'find-file-not-found-functions "22.1")
 (defvar find-file-not-found-functions nil
   "List of functions to be called for `find-file' on nonexistent file.
 These functions are called as soon as the error is detected.
@@ -799,15 +851,20 @@ resulting list of directory names.  For an empty path 
element (i.e.,
 a leading or trailing separator, or two adjacent separators), return
 nil (meaning `default-directory') as the associated list element."
   (when (stringp search-path)
-    (let ((spath (substitute-env-vars search-path)))
+    (let ((spath (substitute-env-vars search-path))
+          (double-slash-special-p
+           (memq system-type '(windows-nt cygwin ms-dos))))
       (mapcar (lambda (f)
                 (if (equal "" f) nil
                   (let ((dir (file-name-as-directory f)))
                     ;; Previous implementation used `substitute-in-file-name'
-                    ;; which collapse multiple "/" in front.  Do the same for
-                    ;; backward compatibility.
-                    (if (string-match "\\`/+" dir)
-                        (substring dir (1- (match-end 0))) dir))))
+                    ;; which collapses multiple "/" in front, while
+                    ;; preserving double slash where it matters.  Do
+                    ;; the same for backward compatibility.
+                    (if (string-match "\\`//+" dir)
+                        (substring dir (- (match-end 0)
+                                          (if double-slash-special-p 2 1)))
+                      dir))))
               (split-string spath path-separator)))))
 
 (defun cd-absolute (dir)
@@ -1115,10 +1172,17 @@ directory if it does not exist."
             (if (file-directory-p user-emacs-directory)
                 (or (file-accessible-directory-p user-emacs-directory)
                     (setq errtype "access"))
-              (with-file-modes ?\700
-                (condition-case nil
-                    (make-directory user-emacs-directory t)
-                  (error (setq errtype "create")))))
+               ;; We don't want to create HOME if it doesn't exist.
+               (if (and (not (file-exists-p "~"))
+                        (string-prefix-p
+                         (expand-file-name "~")
+                         (expand-file-name user-emacs-directory)))
+                   (setq errtype "create")
+                 ;; Create `user-emacs-directory'.
+                (with-file-modes ?\700
+                  (condition-case nil
+                      (make-directory user-emacs-directory t)
+                    (error (setq errtype "create"))))))
             (when (and errtype
                        user-emacs-directory-warning
                        (not (get 'user-emacs-directory-warning 'this-session)))
@@ -1223,28 +1287,17 @@ Tip: You can use this expansion of remote identifier 
components
 ;; It's not clear what the best file for this to be in is, but given
 ;; it uses custom-initialize-delay, it is easier if it is preloaded
 ;; rather than autoloaded.
-(defcustom remote-shell-program
-  ;; This used to try various hard-coded places for remsh, rsh, and
-  ;; rcmd, trying to guess based on location whether "rsh" was
-  ;; "restricted shell" or "remote shell", but I don't see the point
-  ;; in this day and age.  Almost everyone will use ssh, and have
-  ;; whatever command they want to use in PATH.
-  (purecopy
-   (let ((list '("ssh" "remsh" "rcmd" "rsh")))
-     (while (and list
-                (not (executable-find (car list)))
-                (setq list (cdr list))))
-     (or (car list) "ssh")))
-  "Program to use to execute commands on a remote host (e.g. ssh or rsh)."
-  :version "24.3"                      ; ssh rather than rsh, etc
+(defcustom remote-shell-program (or (executable-find "ssh") "ssh")
+  "Program to use to execute commands on a remote host (i.e. ssh)."
+  :version "29.1"
   :initialize 'custom-initialize-delay
   :group 'environment
   :type 'file)
 
 (defcustom remote-file-name-inhibit-cache 10
   "Whether to use the remote file-name cache for read access.
-When nil, never expire cached values (caution)
-When t, never use the cache (safe, but may be slow)
+When nil, never expire cached values (caution).
+When t, never use the cache (safe, but may be slow).
 A number means use cached values for that amount of seconds since caching.
 
 The attributes of remote files are cached for better performance.
@@ -1388,7 +1441,7 @@ containing it, until no links are left at any level.
            ;; If these are equal, we have the (or a) root directory.
            (or (string= dir dirfile)
                (and (file-name-case-insensitive-p dir)
-                    (eq (compare-strings dir 0 nil dirfile 0 nil t) t))
+                    (string-equal-ignore-case dir dirfile))
                ;; If this is the same dir we last got the truename for,
                ;; save time--don't recalculate.
                (if (assoc dir (car prev-dirs))
@@ -2912,7 +2965,7 @@ 
ARC\\|ZIP\\|LZH\\|LHA\\|ZOO\\|[JEW]AR\\|XPI\\|RAR\\|CBR\\|7Z\\|SQUASHFS\\)\\'" .
      ("\\.js[mx]?\\'" . javascript-mode)
      ;; https://en.wikipedia.org/wiki/.har
      ("\\.har\\'" . javascript-mode)
-     ("\\.json\\'" . javascript-mode)
+     ("\\.json\\'" . js-json-mode)
      ("\\.[ds]?va?h?\\'" . verilog-mode)
      ("\\.by\\'" . bovine-grammar-mode)
      ("\\.wy\\'" . wisent-grammar-mode)
@@ -3111,9 +3164,6 @@ major mode MODE.
 
 See also `auto-mode-alist'.")
 
-(define-obsolete-variable-alias 'inhibit-first-line-modes-regexps
-  'inhibit-file-local-variables-regexps "24.1")
-
 ;; TODO really this should be a list of modes (eg tar-mode), not regexps,
 ;; because we are duplicating info from auto-mode-alist.
 ;; TODO many elements of this list are also in auto-coding-alist.
@@ -3134,9 +3184,6 @@ member files with their own local variable sections, 
which are
 not appropriate for the containing file.
 The function `inhibit-local-variables-p' uses this.")
 
-(define-obsolete-variable-alias 'inhibit-first-line-modes-suffixes
-  'inhibit-local-variables-suffixes "24.1")
-
 (defvar inhibit-local-variables-suffixes nil
   "List of regexps matching suffixes to remove from file names.
 The function `inhibit-local-variables-p' uses this: when checking
@@ -3816,10 +3863,8 @@ DIR-NAME is the name of the associated directory.  
Otherwise it is nil."
        (cond ((memq var ignored-local-variables)
               ;; Ignore any variable in `ignored-local-variables'.
               nil)
-              ((seq-some (lambda (elem)
-                           (and (eq (car elem) var)
-                                (eq (cdr elem) val)))
-                         ignored-local-variable-values)
+              ;; Ignore variables with the specified values.
+              ((member elt ignored-local-variable-values)
                nil)
              ;; Obey `enable-local-eval'.
              ((eq var 'eval)
@@ -4414,7 +4459,8 @@ This function returns either:
                   ;; The entry MTIME should match the most recent
                   ;; MTIME among matching files.
                   (and cached-files
-                      (equal (nth 2 dir-elt)
+                      (time-equal-p
+                             (nth 2 dir-elt)
                              (let ((latest 0))
                                (dolist (f cached-files latest)
                                  (let ((f-time
@@ -4817,6 +4863,26 @@ Interactively, confirmation is required unless you 
supply a prefix argument."
     ;; It's likely that the VC status at the new location is different from
     ;; the one at the old location.
     (vc-refresh-state)))
+
+(defun rename-visited-file (new-location)
+  "Rename the file visited by the current buffer to NEW-LOCATION.
+This command also sets the visited file name.  If the buffer
+isn't visiting any file, that's all it does.
+
+Interactively, this prompts for NEW-LOCATION."
+  (interactive
+   (list (if buffer-file-name
+             (read-file-name "Rename visited file to: ")
+           (read-file-name "Set visited file name: "
+                           default-directory
+                           (expand-file-name
+                            (file-name-nondirectory (buffer-name))
+                            default-directory)))))
+  (when (and buffer-file-name
+             (file-exists-p buffer-file-name))
+    (rename-file buffer-file-name new-location))
+  (set-visited-file-name new-location nil t))
+
 
 (defun file-extended-attributes (filename)
   "Return an alist of extended attributes of file FILENAME.
@@ -5065,14 +5131,16 @@ extension, the value is \"\"."
             "")))))
 
 (defun file-name-with-extension (filename extension)
-  "Set the EXTENSION of a FILENAME.
+  "Return FILENAME modified to have the specified EXTENSION.
 The extension (in a file name) is the part that begins with the last \".\".
+This function removes any existing extension from FILENAME, and then
+appends EXTENSION to it.
 
-Trims a leading dot from the EXTENSION so that either \"foo\" or
-\".foo\" can be given.
+EXTENSION may include the leading dot; if it doesn't, this function
+will provide it.
 
-Errors if the FILENAME or EXTENSION are empty, or if the given
-FILENAME has the format of a directory.
+It is an error if FILENAME or EXTENSION is empty, or if FILENAME
+is in the form of a directory name according to `directory-name-p'.
 
 See also `file-name-sans-extension'."
   (let ((extn (string-trim-left extension "[.]")))
@@ -5118,6 +5186,24 @@ On most systems, this will be true:
           (setq filename nil))))
     components))
 
+(defun file-parent-directory (filename)
+  "Return the directory name of the parent directory of FILENAME.
+If FILENAME is at the root of the filesystem, return nil.
+If FILENAME is relative, it is interpreted to be relative
+to `default-directory', and the result will also be relative."
+  (let* ((expanded-filename (expand-file-name filename))
+         (parent (file-name-directory (directory-file-name 
expanded-filename))))
+    (cond
+     ;; filename is at top-level, therefore no parent
+     ((or (null parent)
+          (file-equal-p parent expanded-filename))
+      nil)
+     ;; filename is relative, return relative parent
+     ((not (file-name-absolute-p filename))
+      (file-relative-name parent))
+     (t
+      parent))))
+
 (defcustom make-backup-file-name-function
   #'make-backup-file-name--default-function
   "A function that `make-backup-file-name' uses to create backup file names.
@@ -5387,21 +5473,17 @@ on a DOS/Windows machine, it returns FILENAME in 
expanded form."
             ;; Test for different drive letters
             (not (eq t (compare-strings filename 0 2 directory 0 2 fold-case)))
             ;; Test for UNCs on different servers
-            (not (eq t (compare-strings
-                        (progn
-                          (if (string-match "\\`//\\([^:/]+\\)/" filename)
-                              (match-string 1 filename)
-                            ;; Windows file names cannot have ? in
-                            ;; them, so use that to detect when
-                            ;; neither FILENAME nor DIRECTORY is a
-                            ;; UNC.
-                            "?"))
-                        0 nil
-                        (progn
-                          (if (string-match "\\`//\\([^:/]+\\)/" directory)
-                              (match-string 1 directory)
-                            "?"))
-                        0 nil t)))))
+            (not (string-equal-ignore-case
+                  (if (string-match "\\`//\\([^:/]+\\)/" filename)
+                      (match-string 1 filename)
+                    ;; Windows file names cannot have ? in
+                    ;; them, so use that to detect when
+                    ;; neither FILENAME nor DIRECTORY is a
+                    ;; UNC.
+                    "?")
+                  (if (string-match "\\`//\\([^:/]+\\)/" directory)
+                      (match-string 1 directory)
+                    "?")))))
           ;; Test for different remote file system identification
           (not (equal fremote dremote)))
          filename
@@ -6550,9 +6632,14 @@ preserve markers and overlays, at the price of being 
slower."
   ;; interface, but leaving the programmatic interface the same.
   (interactive (list (not current-prefix-arg)))
   (let ((revert-buffer-in-progress-p t)
-        (revert-buffer-preserve-modes preserve-modes))
+        (revert-buffer-preserve-modes preserve-modes)
+        (state (and (boundp 'read-only-mode--state)
+                    (list read-only-mode--state))))
     (funcall (or revert-buffer-function #'revert-buffer--default)
-             ignore-auto noconfirm)))
+             ignore-auto noconfirm)
+    (when state
+      (setq buffer-read-only (car state))
+      (setq-local read-only-mode--state (car state)))))
 
 (defun revert-buffer--default (ignore-auto noconfirm)
   "Default function for `revert-buffer'.
@@ -7928,7 +8015,7 @@ If RESTART, restart Emacs after killing the current Emacs 
process."
                       ("Close Without Saving" . no-save)
                       ("Save All" . save-all)
                       ("Cancel" . cancel)))
-            ('cancel (user-error "Exit cancelled"))
+            ('cancel (user-error "Exit canceled"))
             ('save-all (save-some-buffers t)))
         (save-some-buffers arg t)))
   (let ((confirm confirm-kill-emacs))
@@ -8166,6 +8253,7 @@ arguments as the running Emacs)."
         (_
          (apply operation arguments))))))
 
+;;;###autoload
 (defsubst file-name-quoted-p (name &optional top)
   "Whether NAME is quoted with prefix \"/:\".
 If NAME is a remote file name and TOP is nil, check the local part of NAME."
@@ -8265,7 +8353,7 @@ such as `?d' for a directory, or `?l' for a symbolic link 
and will override
 the leading `-' char."
   (string
    (or filetype
-       (pcase (lsh mode -12)
+       (pcase (ash mode -12)
          ;; POSIX specifies that the file type is included in st_mode
          ;; and provides names for the file types but values only for
          ;; the permissions (e.g., S_IWOTH=2).
diff --git a/lisp/filesets.el b/lisp/filesets.el
index 83a914d58c..4831bf167d 100644
--- a/lisp/filesets.el
+++ b/lisp/filesets.el
@@ -146,29 +146,16 @@ is loaded before user customizations.  Thus, if (require 
\\='filesets)
 precedes the `custom-set-variables' command or, for XEmacs, if init.el
 is loaded before custom.el, set this variable to t.")
 
-
-;;; utils
 (defun filesets-filter-list (lst cond-fn)
   "Remove all elements not conforming to COND-FN from list LST.
 COND-FN takes one argument: the current element."
-;  (cl-remove 'dummy lst :test (lambda (dummy elt)
-;                            (not (funcall cond-fn elt)))))
-  (let ((rv nil))
-    (dolist (elt lst)
-      (when (funcall cond-fn elt)
-       (push elt rv)))
-    (nreverse rv)))
+  (declare (obsolete seq-filter "29.1"))
+  (seq-filter cond-fn lst))
 
 (defun filesets-ormap (fsom-pred lst)
   "Return the tail of LST for the head of which FSOM-PRED is non-nil."
-  (let ((fsom-lst lst)
-       (fsom-rv nil))
-    (while (and fsom-lst
-               (null fsom-rv))
-      (if (funcall fsom-pred (car fsom-lst))
-         (setq fsom-rv fsom-lst)
-       (setq fsom-lst (cdr fsom-lst))))
-    fsom-rv))
+  (declare (obsolete seq-drop-while "29.1"))
+  (seq-drop-while (lambda (x) (not (funcall fsom-pred x))) lst))
 
 (define-obsolete-function-alias 'filesets-some #'cl-some "28.1")
 (define-obsolete-function-alias 'filesets-member #'cl-member "28.1")
@@ -208,7 +195,7 @@ COND-FN takes one argument: the current element."
 (defun filesets-reset-fileset (&optional fileset no-cache)
   "Reset the cached values for one or all filesets."
   (setq filesets-submenus (if fileset
-                              (lax-plist-put filesets-submenus fileset nil)
+                              (plist-put filesets-submenus fileset nil #'equal)
                             nil))
   (setq filesets-has-changed-flag t)
   (setq filesets-update-cache-file-flag (or filesets-update-cache-file-flag
@@ -257,13 +244,13 @@ SYM to VAL and return t.  If INIT-FLAG is non-nil, set 
with
       (setq filesets-menu-use-cached-flag nil)
     (when (default-boundp 'filesets-data)
       (let ((modified-filesets
-            (filesets-filter-list val
-                                  (lambda (x)
-                                    (let ((name (car x))
-                                          (data (cdr x)))
-                                      (let ((elt (assoc name filesets-data)))
-                                        (or (not elt)
-                                            (not (equal data (cdr elt))))))))))
+             (seq-filter (lambda (x)
+                           (let ((name (car x))
+                                 (data (cdr x)))
+                             (let ((elt (assoc name filesets-data)))
+                               (or (not elt)
+                                   (not (equal data (cdr elt)))))))
+                         val)))
        (dolist (x modified-filesets)
          (filesets-reset-fileset (car x))))))
   (filesets-set-default sym val))
@@ -326,8 +313,8 @@ See `easy-menu-add-item' for documentation."
 Set this to \"\", to disable caching of menus.
 Don't forget to check out `filesets-menu-ensure-use-cached'."
   :set #'filesets-set-default
-  :type 'file)
-(put 'filesets-menu-cache-file 'risky-local-variable t)
+  :type 'file
+  :risky t)
 
 (defcustom filesets-menu-cache-contents
   '(filesets-be-docile-flag
@@ -414,12 +401,12 @@ time to time or if the fileset cache causes troubles."
 Set this value to 0 to turn menu splitting off.  BTW, parts of submenus
 will not be rewrapped if their length exceeds this value."
   :set #'filesets-set-default
-  :type 'integer)
+  :type 'natnum)
 
 (defcustom filesets-max-entry-length 50
   "Truncate names of split submenus to this length."
   :set #'filesets-set-default
-  :type 'integer)
+  :type 'natnum)
 
 (defcustom filesets-browse-dir-function #'dired
   "A function or command used for browsing directories.
@@ -518,7 +505,7 @@ i.e. how deep the menu should be.  Try something like
 and it should become clear what this option is about.  In any case,
 including directory trees to the menu can take a lot of memory."
   :set #'filesets-set-default
-  :type 'integer)
+  :type 'natnum)
 
 (defcustom filesets-commands
   '(("Isearch"
@@ -546,6 +533,7 @@ function that returns one) to be run on a filesets' files.
 The argument <file-name> or <<file-name>> (quoted) will be replaced with
 the filename."
   :set #'filesets-set-default+
+  :risky t
   :type '(repeat :tag "Commands"
                 (list :tag "Definition" :value ("")
                       (string "Name")
@@ -561,8 +549,7 @@ the filename."
                                       (string :tag "Quoted File Name"
                                               :value "<<file-name>>")
                                       (function :tag "Function"
-                                                :value nil))))))
-(put 'filesets-commands 'risky-local-variable t)
+                                                 :value nil))))))
 
 (defcustom filesets-external-viewers
   (let
@@ -651,6 +638,7 @@ In order to view pdf or rtf files in an Emacs buffer, you 
could use these:
                        (and (filesets-which-command-p \"rtf2htm\")
                             (filesets-which-command-p \"w3m\"))))))"
   :set #'filesets-set-default
+  :risky t
   :type '(repeat :tag "Viewer"
                 (list :tag "Definition"
                       :value ("^.+\\.suffix$" "")
@@ -707,7 +695,6 @@ In order to view pdf or rtf files in an Emacs buffer, you 
could use these:
                                      (const  :format ""
                                              :value :capture-output)
                                      (boolean :tag "Boolean")))))))
-(put 'filesets-external-viewers 'risky-local-variable t)
 
 (defcustom filesets-ingroup-patterns
   '(("^.+\\.tex$" t
@@ -848,6 +835,7 @@ With duplicates removed, it would be:
     M + A - X
         B"
   :set #'filesets-set-default
+  :risky t
   :type '(repeat
          :tag "Include"
          (list
@@ -894,7 +882,6 @@ With duplicates removed, it would be:
                                  :value (:preprocess)
                                  (const :format "" :value :preprocess)
                                  (function :tag "Function"))))))))
-(put 'filesets-ingroup-patterns 'risky-local-variable t)
 
 (defcustom filesets-data nil
   "Fileset definitions.
@@ -965,6 +952,7 @@ is used.
 Before using :ingroup, make sure that the file type is already
 defined in `filesets-ingroup-patterns'."
   :set #'filesets-data-set-default
+  :risky t
   :type '(repeat
          (cons :tag "Fileset"
                (string :tag "Name" :value "")
@@ -1021,24 +1009,23 @@ defined in `filesets-ingroup-patterns'."
                               :value (:open)
                               (const :format "" :value :open)
                               (function :tag "Function")))))))
-(put 'filesets-data 'risky-local-variable t)
 
 
 (defcustom filesets-query-user-limit 15
   "Query the user before opening a fileset with that many files."
   :set #'filesets-set-default
-  :type 'integer)
+  :type 'natnum)
 
 
 (defun filesets-filter-dir-names (lst &optional negative)
   "Remove non-directory names from a list of strings.
 If NEGATIVE is non-nil, remove all directory names."
-  (filesets-filter-list lst
-                       (lambda (x)
-                         (and (not (string-match-p "^\\.+/$" x))
-                              (if negative
-                                  (not (string-match-p "[:/\\]$" x))
-                                (string-match-p "[:/\\]$" x))))))
+  (seq-filter (lambda (x)
+                (and (not (string-match-p "^\\.+/$" x))
+                     (if negative
+                         (not (string-match-p "[:/\\]$" x))
+                       (string-match-p "[:/\\]$" x))))
+              lst))
 
 (defun filesets-conditional-sort (lst &optional access-fn)
   "Return a sorted copy of LST, LST being a list of strings.
@@ -1683,9 +1670,9 @@ Assume MODE (see `filesets-entry-mode'), if provided."
                        (filesets-directory-files dir patt ':files t))
                    ;; (message "Filesets: malformed entry: %s" entry)))))))
                     (error "Filesets: malformed entry: %s" entry)))))))
-    (filesets-filter-list fl
-                         (lambda (file)
-                           (not (filesets-filetype-property file event))))))
+    (seq-filter (lambda (file)
+                  (not (filesets-filetype-property file event)))
+                fl)))
 
 (defun filesets-files-under (level depth entry dir patt &optional relativep)
   "Files under DIR that match PATT.
@@ -1999,7 +1986,7 @@ LOOKUP-NAME is used as lookup name for retrieving fileset 
specific settings."
 
 (defun filesets-ingroup-cache-get (master)
   "Access to `filesets-ingroup-cache'."
-  (lax-plist-get filesets-ingroup-cache master))
+  (plist-get filesets-ingroup-cache master #'equal))
 
 (defun filesets-ingroup-cache-put (master file)
   "Access to `filesets-ingroup-cache'."
@@ -2008,7 +1995,7 @@ LOOKUP-NAME is used as lookup name for retrieving fileset 
specific settings."
                      (cons file (filesets-ingroup-cache-get emaster))
                    nil)))
     (setq filesets-ingroup-cache
-         (lax-plist-put filesets-ingroup-cache emaster this))))
+         (plist-put filesets-ingroup-cache emaster this #'equal))))
 
 (defun filesets-ingroup-collect-files (fs &optional remdupl-flag master depth)
   "Helper function for `filesets-ingroup-collect'.  Collect file names."
@@ -2305,12 +2292,12 @@ bottom up, set `filesets-submenus' to nil, first.)"
        ((null data))
       (let* ((this    (car data))
             (name    (filesets-data-get-name this))
-            (cached  (lax-plist-get filesets-submenus name))
+            (cached  (plist-get filesets-submenus name #'equal))
             (submenu (or cached
                          (filesets-build-submenu count name this))))
        (unless cached
          (setq filesets-submenus
-               (lax-plist-put filesets-submenus name submenu)))
+               (plist-put filesets-submenus name submenu #'equal)))
        (unless (filesets-entry-get-dormant-flag this)
          (setq filesets-menu-cache
                (append filesets-menu-cache (list submenu))))))
@@ -2499,8 +2486,4 @@ Set up hooks, load the cache file -- if existing -- and 
build the menu."
 
 (provide 'filesets)
 
-;; Local Variables:
-;; sentence-end-double-space:t
-;; End:
-
 ;;; filesets.el ends here
diff --git a/lisp/find-dired.el b/lisp/find-dired.el
index 61e626080e..be3d106912 100644
--- a/lisp/find-dired.el
+++ b/lisp/find-dired.el
@@ -1,7 +1,6 @@
 ;;; find-dired.el --- run a `find' command and dired the output  -*- 
lexical-binding: t -*-
 
-;; Copyright (C) 1992, 1994-1995, 2000-2022 Free Software Foundation,
-;; Inc.
+;; Copyright (C) 1992-2022 Free Software Foundation, Inc.
 
 ;; Author: Roland McGrath <roland@gnu.org>,
 ;;        Sebastian Kremer <sk@thp.uni-koeln.de>
@@ -154,6 +153,9 @@ output of `find' (one file per line) when this function is 
called."
 ;; History of find-args values entered in the minibuffer.
 (defvar find-args-history nil)
 
+(defvar find-command-history nil
+  "History of commands passed interactively to `find-dired-with-command'.")
+
 (defvar dired-sort-inhibit)
 
 ;;;###autoload
@@ -167,10 +169,47 @@ except that the car of the variable `find-ls-option' 
specifies what to
 use in place of \"-ls\" as the final argument.
 
 Collect output in the \"*Find*\" buffer.  To kill the job before
-it finishes, type \\[kill-find]."
+it finishes, type \\[kill-find].
+
+For more information on how to write valid find expressions for
+ARGS, see Info node `(find) Finding Files'.  If you are not
+using GNU findutils (on macOS and *BSD systems), see instead the
+man page for \"find\"."
   (interactive (list (read-directory-name "Run find in directory: " nil "" t)
                     (read-string "Run find (with args): " find-args
                                  '(find-args-history . 1))))
+  (setq find-args args                ; save for next interactive call
+       args (concat find-program " . "
+                    (if (string= args "")
+                        ""
+                      (concat
+                       (shell-quote-argument "(")
+                       " " args " "
+                       (shell-quote-argument ")")
+                       " "))
+                    (find-dired--escaped-ls-option)))
+  (find-dired-with-command dir args))
+
+;;;###autoload
+(defun find-dired-with-command (dir command)
+  "Run `find' and go into Dired mode on a buffer of the output.
+The user-supplied COMMAND is run after changing into DIR and should look like
+
+    find . GLOBALARGS \\( ARGS \\) -ls
+
+The car of the variable `find-ls-option' specifies what to
+use in place of \"-ls\" as the starting input.
+
+Collect output in the \"*Find*\" buffer.  To kill the job before
+it finishes, type \\[kill-find]."
+  (interactive
+   (list (read-directory-name "Run find in directory: " nil "" t)
+        (read-string "Run find command: "
+                      (cons (concat find-program
+                                    " . \\(  \\) "
+                                    (find-dired--escaped-ls-option))
+                            (+ 1 (length find-program) (length " . \\( ")))
+                     find-command-history)))
   (let ((dired-buffers dired-buffers))
     ;; Expand DIR ("" means default-directory), and make sure it has a
     ;; trailing slash.
@@ -199,25 +238,14 @@ it finishes, type \\[kill-find]."
     (kill-all-local-variables)
     (setq buffer-read-only nil)
     (erase-buffer)
-    (setq default-directory dir
-         find-args args              ; save for next interactive call
-         args (concat find-program " . "
-                      (if (string= args "")
-                          ""
-                        (concat
-                         (shell-quote-argument "(")
-                         " " args " "
-                         (shell-quote-argument ")")
-                         " "))
-                      (if (string-match "\\`\\(.*\\) {} \\(\\\\;\\|\\+\\)\\'"
-                                        (car find-ls-option))
-                          (format "%s %s %s"
-                                  (match-string 1 (car find-ls-option))
-                                  (shell-quote-argument "{}")
-                                  find-exec-terminator)
-                        (car find-ls-option))))
+    (setq default-directory dir)
     ;; Start the find process.
-    (shell-command (concat args "&") (current-buffer))
+    (shell-command (concat command "&") (current-buffer))
+    (let ((proc (get-buffer-process (current-buffer))))
+      ;; Initialize the process marker; it is used by the filter.
+      (move-marker (process-mark proc) (point) (current-buffer))
+      (set-process-filter proc #'find-dired-filter)
+      (set-process-sentinel proc #'find-dired-sentinel))
     (dired-mode dir (cdr find-ls-option))
     (let ((map (make-sparse-keymap)))
       (set-keymap-parent map (current-local-map))
@@ -226,7 +254,7 @@ it finishes, type \\[kill-find]."
     (setq-local dired-sort-inhibit t)
     (setq-local revert-buffer-function
                 (lambda (_ignore-auto _noconfirm)
-                  (find-dired dir find-args)))
+                  (find-dired-with-command dir command)))
     ;; Set subdir-alist so that Tree Dired will work:
     (if (fboundp 'dired-simple-subdir-alist)
        ;; will work even with nested dired format (dired-nstd.el,v 1.15
@@ -246,16 +274,21 @@ it finishes, type \\[kill-find]."
     ;; Make second line a ``find'' line in analogy to the ``total'' or
     ;; ``wildcard'' line.
     (let ((point (point)))
-      (insert "  " args "\n")
+      (insert "  " command "\n")
       (dired-insert-set-properties point (point)))
     (setq buffer-read-only t)
-    (let ((proc (get-buffer-process (current-buffer))))
-      (set-process-filter proc #'find-dired-filter)
-      (set-process-sentinel proc #'find-dired-sentinel)
-      ;; Initialize the process marker; it is used by the filter.
-      (move-marker (process-mark proc) (point) (current-buffer)))
     (setq mode-line-process '(":%s"))))
 
+(defun find-dired--escaped-ls-option ()
+  "Return the car of `find-ls-option' escaped for a shell command."
+  (if (string-match "\\`\\(.*\\) {} \\(\\\\;\\|\\+\\)\\'"
+                   (car find-ls-option))
+      (format "%s %s %s"
+             (match-string 1 (car find-ls-option))
+             (shell-quote-argument "{}")
+             find-exec-terminator)
+    (car find-ls-option)))
+
 (defun kill-find ()
   "Kill the `find' process running in the current buffer."
   (interactive)
@@ -286,7 +319,7 @@ See `find-name-arg' to customize the arguments."
 ;; Date: 10 May 91 17:50:00 GMT
 ;; Organization: University of Waterloo
 
-(defalias 'lookfor-dired 'find-grep-dired)
+(define-obsolete-function-alias 'lookfor-dired #'find-grep-dired "29.1")
 ;;;###autoload
 (defun find-grep-dired (dir regexp)
   "Find files in DIR that contain matches for REGEXP and start Dired on output.
@@ -385,10 +418,10 @@ specifies what to use in place of \"-ls\" as the final 
argument."
   "Sort entries in *Find* buffer by file name lexicographically."
   (sort-subr nil 'forward-line 'end-of-line
              (lambda ()
-               (buffer-substring-no-properties
-                (next-single-property-change
-                 (point) 'dired-filename)
-                (line-end-position)))))
+               (when-let ((start
+                           (next-single-property-change
+                            (point) 'dired-filename)))
+               (buffer-substring-no-properties start (line-end-position))))))
 
 
 (provide 'find-dired)
diff --git a/lisp/find-file.el b/lisp/find-file.el
index 809592413d..614ff420f2 100644
--- a/lisp/find-file.el
+++ b/lisp/find-file.el
@@ -189,8 +189,19 @@ filename that EXTRACT returned."
 (defcustom ff-other-file-alist 'cc-other-file-alist
   "Alist of extensions to find given the current file's extension.
 
-This list should contain the most used extensions before the others,
-since the search algorithm searches sequentially through each
+The value could be an alist or a symbol whose value is an alist.
+Each element of the alist has the form
+
+   (REGEXP (EXTENSION...))
+or
+   (REGEXP FUNCTION)
+
+where REGEXP is the regular expression matching a file's extension,
+EXTENSIONs is the list of literal file-name extensions to search for,
+and FUNCTION is a function of one argument, the current file's name,
+that returns the list of extensions to search for.
+The list of extensions should contain the most used extensions before the
+others, since the search algorithm searches sequentially through each
 directory specified in `ff-search-directories'.  If a file is not found,
 a new one is created with the first matching extension (`.cc' yields `.hh').
 This alist should be set by the major mode."
diff --git a/lisp/find-lisp.el b/lisp/find-lisp.el
index 0a712c0b81..e825d9cba0 100644
--- a/lisp/find-lisp.el
+++ b/lisp/find-lisp.el
@@ -281,7 +281,7 @@ It is a function which takes two arguments, the directory 
and its parent."
   (set-buffer buffer)
   (insert find-lisp-line-indent
          (find-lisp-format file (file-attributes file 'string) (list "")
-                         (current-time))))
+                           nil)))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Lifted from ls-lisp. We don't want to require it, because that
diff --git a/lisp/finder.el b/lisp/finder.el
index 73072c0cd4..08d20963b4 100644
--- a/lisp/finder.el
+++ b/lisp/finder.el
@@ -77,6 +77,7 @@ Each element has the form (KEYWORD . DESCRIPTION).")
 
 (defvar-keymap finder-mode-map
   :doc "Keymap used in `finder-mode'."
+  :parent special-mode-map
   "SPC"           #'finder-select
   "f"             #'finder-select
   "<follow-link>" 'mouse-face
@@ -420,15 +421,14 @@ FILE should be in a form suitable for passing to 
`locate-library'."
   (interactive)
   (finder-list-keywords))
 
-(define-derived-mode finder-mode nil "Finder"
+(define-derived-mode finder-mode special-mode "Finder"
   "Major mode for browsing package documentation.
 \\<finder-mode-map>
 \\[finder-select]      more help for the item on the current line
-\\[finder-exit]        exit Finder mode and kill the Finder buffer."
-  :syntax-table finder-mode-syntax-table
+\\[finder-exit]        exit Finder mode and kill the Finder buffer.
+
+\\{finder-mode-map}"
   :interactive nil
-  (setq buffer-read-only t
-       buffer-undo-list t)
   (setq-local finder-headmark nil))
 
 (defun finder-summary ()
@@ -436,9 +436,9 @@ FILE should be in a form suitable for passing to 
`locate-library'."
   (interactive nil finder-mode)
   (message "%s"
    (substitute-command-keys
-    "\\<finder-mode-map>\\[finder-select] = select, \
-\\[finder-mouse-select] = select, \\[finder-list-keywords] = to \
-finder directory, \\[finder-exit] = quit, \\[finder-summary] = help")))
+    "\\<finder-mode-map>\\[finder-select] select, \
+\\[finder-mouse-select] select, \\[finder-list-keywords] go to \
+finder directory, \\[finder-exit] quit, \\[finder-summary] help")))
 
 (defun finder-exit ()
   "Exit Finder mode.
diff --git a/lisp/font-core.el b/lisp/font-core.el
index 2b75309ff3..f70c42bb03 100644
--- a/lisp/font-core.el
+++ b/lisp/font-core.el
@@ -65,7 +65,9 @@ Other variables include that for syntactic keyword 
fontification,
 `font-lock-syntactic-keywords' and those for buffer-specialized fontification
 functions, `font-lock-fontify-buffer-function',
 `font-lock-unfontify-buffer-function', `font-lock-fontify-region-function',
-`font-lock-unfontify-region-function', and `font-lock-inhibit-thing-lock'.")
+`font-lock-unfontify-region-function'.")
+;; Autoload if this file no longer dumped.
+;;;###autoload
 (put 'font-lock-defaults 'risky-local-variable t)
 
 (defvar font-lock-function 'font-lock-default-function
@@ -105,8 +107,7 @@ example, put in your ~/.emacs:
 Where major modes support different levels of fontification, you
 can use the variable `font-lock-maximum-decoration' to specify
 which level you generally prefer.  When you turn Font Lock mode
-on/off the buffer is fontified/defontified, though fontification
-occurs only if the buffer is less than `font-lock-maximum-size'.
+on/off the buffer is fontified/defontified.
 
 To add your own highlighting for some major mode, and modify the
 highlighting selected automatically via the variable
diff --git a/lisp/font-lock.el b/lisp/font-lock.el
index 488874a175..b6f4150964 100644
--- a/lisp/font-lock.el
+++ b/lisp/font-lock.el
@@ -47,9 +47,9 @@
 ;;
 ;; Fontification for a particular mode may be available in a number of levels
 ;; of decoration.  The higher the level, the more decoration, but the more time
-;; it takes to fontify.  See the variable `font-lock-maximum-decoration', and
-;; also the variable `font-lock-maximum-size'.  Support modes for Font Lock
-;; mode can be used to speed up Font Lock mode.  See `font-lock-support-mode'.
+;; it takes to fontify.  See the variable `font-lock-maximum-decoration'.
+;; Support modes for Font Lock mode can be used to speed up Font Lock
+;; mode.  See `font-lock-support-mode'.
 
 ;;;; How Font Lock mode fontifies:
 
@@ -228,32 +228,6 @@
 
 ;; User variables.
 
-(defcustom font-lock-maximum-size 256000
-  "Maximum buffer size for unsupported buffer fontification.
-When `font-lock-support-mode' is nil, only buffers smaller than
-this are fontified.  This variable has no effect if a Font Lock
-support mode (usually `jit-lock-mode') is enabled.
-
-If nil, means size is irrelevant.
-If a list, each element should be a cons pair of the form (MAJOR-MODE . SIZE),
-where MAJOR-MODE is a symbol or t (meaning the default).  For example:
- ((c-mode . 256000) (c++-mode . 256000) (rmail-mode . 1048576))
-means that the maximum size is 250K for buffers in C or C++ modes, one megabyte
-for buffers in Rmail mode, and size is irrelevant otherwise."
-  :type '(choice (const :tag "none" nil)
-                (integer :tag "size")
-                (repeat :menu-tag "mode specific" :tag "mode specific"
-                        :value ((t . nil))
-                        (cons :tag "Instance"
-                              (radio :tag "Mode"
-                                     (const :tag "all" t)
-                                     (symbol :tag "name"))
-                              (radio :tag "Size"
-                                     (const :tag "none" nil)
-                                     (integer :tag "size")))))
-  :group 'font-lock)
-(make-obsolete-variable 'font-lock-maximum-size nil "24.1")
-
 (defcustom font-lock-maximum-decoration t
   "Maximum decoration level for fontification.
 If nil, use the default decoration (typically the minimum available).
@@ -372,9 +346,6 @@ If a number, only buffers greater than this size have 
fontification messages."
 (defvar font-lock-type-face            'font-lock-type-face
   "Face name to use for type and class names.")
 
-(define-obsolete-variable-alias
-  'font-lock-reference-face 'font-lock-constant-face "20.3")
-
 (defvar font-lock-constant-face                'font-lock-constant-face
   "Face name to use for constant and label names.")
 
@@ -516,8 +487,7 @@ of the line, i.e., cause the MATCHER search to span lines.
 These regular expressions can match text which spans lines,
 although it is better to avoid it if possible since updating them
 while editing text is slower, and it is not guaranteed to be
-always correct when using support modes like jit-lock or
-lazy-lock.
+always correct.
 
 This variable is set by major modes via the variable
 `font-lock-defaults'.  Be careful when composing regexps for this
@@ -649,11 +619,8 @@ fontified.")
 It should take two args, the beginning and end of the region.
 This is normally set via `font-lock-defaults'.")
 
-(defvar font-lock-inhibit-thing-lock nil
-  "List of Font Lock mode related modes that should not be turned on.
-Currently, valid mode names are `fast-lock-mode', `jit-lock-mode' and
-`lazy-lock-mode'.  This is normally set via `font-lock-defaults'.")
-(make-obsolete-variable 'font-lock-inhibit-thing-lock nil "25.1")
+(defvar font-lock-inhibit-thing-lock nil)
+(make-obsolete-variable 'font-lock-inhibit-thing-lock "it does nothing." 
"25.1")
 
 (defvar-local font-lock-multiline nil
   "Whether font-lock should cater to multiline keywords.
@@ -668,7 +635,6 @@ Major/minor modes can set this variable if they know which 
option applies.")
 
 (eval-when-compile
   ;;
-  ;; Borrowed from lazy-lock.el.
   ;; We use this to preserve or protect things when modifying text properties.
   (defmacro save-buffer-state (&rest body)
     "Bind variables according to VARLIST and eval BODY restoring buffer state."
@@ -695,15 +661,9 @@ be enabled."
   ;; The first fontification after turning the mode on.  This must
   ;;  only be called after the mode hooks have been run.
   (when (and font-lock-mode
-            (font-lock-specified-p t))
-    (let ((max-size (font-lock-value-in-major-mode font-lock-maximum-size)))
-      (cond (font-lock-fontified
-            nil)
-           ((or (null max-size) (> max-size (buffer-size)))
-             (with-no-warnings (font-lock-fontify-buffer)))
-           (font-lock-verbose
-            (message "Fontifying %s...buffer size greater than 
font-lock-maximum-size"
-                     (buffer-name)))))))
+             (font-lock-specified-p t)
+             (not font-lock-fontified))
+    (with-no-warnings (font-lock-fontify-buffer))))
 
 (defun font-lock-mode-internal (arg)
   ;; Turn on Font Lock mode.
@@ -913,65 +873,17 @@ happens, so the major mode can be corrected."
 
 ;;; Font Lock Support mode.
 
-;; This is the code used to interface font-lock.el with any of its add-on
-;; packages, and provide the user interface.  Packages that have their own
-;; local buffer fontification functions (see below) may have to call
-;; `font-lock-after-fontify-buffer' and/or `font-lock-after-unfontify-buffer'
-;; themselves.
-
-(defcustom font-lock-support-mode 'jit-lock-mode
+(defvar font-lock-support-mode #'jit-lock-mode
   "Support mode for Font Lock mode.
-Support modes speed up Font Lock mode by being choosy about when fontification
-occurs.  The default support mode, Just-in-time Lock mode (symbol
-`jit-lock-mode'), is recommended.
-
-Other, older support modes are Fast Lock mode (symbol `fast-lock-mode') and
-Lazy Lock mode (symbol `lazy-lock-mode').  See those modes for more info.
-However, they are no longer recommended, as Just-in-time Lock mode is better.
-
 If nil, means support for Font Lock mode is never performed.
-If a symbol, use that support mode.
-If a list, each element should be of the form (MAJOR-MODE . SUPPORT-MODE),
-where MAJOR-MODE is a symbol or t (meaning the default).  For example:
- ((c-mode . fast-lock-mode) (c++-mode . fast-lock-mode) (t . lazy-lock-mode))
-means that Fast Lock mode is used to support Font Lock mode for buffers in C or
-C++ modes, and Lazy Lock mode is used to support Font Lock mode otherwise.
-
-The value of this variable is used when Font Lock mode is turned on."
-  :type '(choice (const :tag "none" nil)
-                (const :tag "fast lock" fast-lock-mode)
-                (const :tag "lazy lock" lazy-lock-mode)
-                (const :tag "jit lock" jit-lock-mode)
-                (repeat :menu-tag "mode specific" :tag "mode specific"
-                        :value ((t . jit-lock-mode))
-                        (cons :tag "Instance"
-                              (radio :tag "Mode"
-                                     (const :tag "all" t)
-                                     (symbol :tag "name"))
-                              (radio :tag "Support"
-                                     (const :tag "none" nil)
-                                     (const :tag "fast lock" fast-lock-mode)
-                                     (const :tag "lazy lock" lazy-lock-mode)
-                                     (const :tag "JIT lock" jit-lock-mode)))
-                        ))
-  :version "21.1"
-  :group 'font-lock)
+This can be useful for debugging.
 
-(defvar fast-lock-mode)
-(defvar lazy-lock-mode)
-(defvar jit-lock-mode)
+The value of this variable is used when Font Lock mode is turned on.")
 
-(declare-function fast-lock-after-fontify-buffer "fast-lock")
-(declare-function fast-lock-after-unfontify-buffer "fast-lock")
-(declare-function fast-lock-mode "fast-lock")
-(declare-function lazy-lock-after-fontify-buffer "lazy-lock")
-(declare-function lazy-lock-after-unfontify-buffer "lazy-lock")
-(declare-function lazy-lock-mode "lazy-lock")
+(defvar jit-lock-mode)
 
 (defun font-lock-turn-on-thing-lock ()
   (pcase (font-lock-value-in-major-mode font-lock-support-mode)
-    ('fast-lock-mode (fast-lock-mode t))
-    ('lazy-lock-mode (lazy-lock-mode t))
     ('jit-lock-mode
      ;; Prepare for jit-lock
      (remove-hook 'after-change-functions
@@ -994,39 +906,11 @@ The value of this variable is used when Font Lock mode is 
turned on."
                nil t))))
 
 (defun font-lock-turn-off-thing-lock ()
-  (cond ((bound-and-true-p fast-lock-mode)
-        (fast-lock-mode -1))
-       ((bound-and-true-p jit-lock-mode)
+  (cond ((bound-and-true-p jit-lock-mode)
         (jit-lock-unregister 'font-lock-fontify-region)
         ;; Reset local vars to the non-jit-lock case.
-        (kill-local-variable 'font-lock-fontify-buffer-function))
-       ((bound-and-true-p lazy-lock-mode)
-        (lazy-lock-mode -1))))
-
-(defun font-lock-after-fontify-buffer ()
-  (cond ((bound-and-true-p fast-lock-mode)
-        (fast-lock-after-fontify-buffer))
-       ;; Useless now that jit-lock intercepts font-lock-fontify-buffer.  -sm
-       ;; (jit-lock-mode
-       ;;  (jit-lock-after-fontify-buffer))
-       ((bound-and-true-p lazy-lock-mode)
-        (lazy-lock-after-fontify-buffer))))
-
-(defun font-lock-after-unfontify-buffer ()
-  (cond ((bound-and-true-p fast-lock-mode)
-        (fast-lock-after-unfontify-buffer))
-       ;; Useless as well.  It's only called when:
-       ;; - turning off font-lock: it does not matter if we leave spurious
-       ;;   `fontified' text props around since jit-lock-mode is also off.
-       ;; - font-lock-default-fontify-buffer fails: this is not run
-       ;;   any more anyway.   -sm
-       ;;
-       ;; (jit-lock-mode
-       ;;  (jit-lock-after-unfontify-buffer))
-       ((bound-and-true-p lazy-lock-mode)
-        (lazy-lock-after-unfontify-buffer))))
-
-;; End of Font Lock Support mode.
+         (kill-local-variable 'font-lock-fontify-buffer-function))))
+
 
 ;;; Fontification functions.
 
@@ -1192,7 +1076,6 @@ Lock mode."
            (save-excursion
              (save-match-data
                (font-lock-fontify-region (point-min) (point-max) verbose)
-               (font-lock-after-fontify-buffer)
                (setq font-lock-fontified t)))
          ;; We don't restore the old fontification, so it's best to unfontify.
          (quit (font-lock-unfontify-buffer)))))))
@@ -1203,7 +1086,6 @@ Lock mode."
   (save-restriction
     (widen)
     (font-lock-unfontify-region (point-min) (point-max))
-    (font-lock-after-unfontify-buffer)
     (setq font-lock-fontified nil)))
 
 (defvar font-lock-dont-widen nil
@@ -1245,28 +1127,26 @@ Put first the functions more likely to cause a change 
and cheaper to compute.")
       (setq font-lock-beg (or (previous-single-property-change
                                font-lock-beg 'font-lock-multiline)
                               (point-min))))
-    ;;
-    (when (get-text-property font-lock-end 'font-lock-multiline)
-      (setq changed t)
-      (setq font-lock-end (or (text-property-any font-lock-end (point-max)
-                                                 'font-lock-multiline nil)
-                              (point-max))))
+    ;; If `font-lock-multiline' starts at `font-lock-end', do not
+    ;; extend the region.
+    (let ((before-end (max (point-min) (1- font-lock-end)))
+          (new-end nil))
+      (when (get-text-property before-end 'font-lock-multiline)
+        (setq new-end (or (text-property-any before-end (point-max)
+                                             'font-lock-multiline nil)
+                          (point-max)))
+        (when (/= new-end font-lock-end)
+          (setq changed t)
+          (setq font-lock-end new-end))))
     changed))
 
 (defun font-lock-extend-region-wholelines ()
   "Move fontification boundaries to beginning of lines."
-  (let ((changed nil))
-    (goto-char font-lock-beg)
-    (unless (bolp)
-      (setq changed t font-lock-beg
-            (let ((inhibit-field-text-motion t))
-              (line-beginning-position))))
-    (goto-char font-lock-end)
-    (unless (bolp)
-      (unless (eq font-lock-end
-                  (setq font-lock-end (line-beginning-position 2)))
-        (setq changed t)))
-    changed))
+  (let ((new (syntax-propertize-wholelines font-lock-beg font-lock-end)))
+    (when new
+      (setq font-lock-beg (car new))
+      (setq font-lock-end (cdr new))
+      t)))
 
 (defun font-lock-default-fontify-region (beg end loudly)
   "Fontify the text between BEG and END.
@@ -1560,7 +1440,7 @@ see `font-lock-syntactic-keywords'."
        (or (nth 3 highlight)
            (error "No match %d in highlight %S" match highlight))
       (when (and (consp value) (not (numberp (car value))))
-       (setq value (eval value)))
+       (setq value (eval value t)))
       (when (stringp value) (setq value (string-to-syntax value)))
       ;; Flush the syntax-cache.  I believe this is not necessary for
       ;; font-lock's use of syntax-ppss, but I'm not 100% sure and it can
@@ -1584,7 +1464,7 @@ KEYWORDS should be of the form MATCH-ANCHORED, see 
`font-lock-keywords',
 LIMIT can be modified by the value of its PRE-MATCH-FORM."
   (let ((matcher (nth 0 keywords)) (lowdarks (nthcdr 3 keywords)) highlights
        ;; Evaluate PRE-MATCH-FORM.
-       (pre-match-value (eval (nth 1 keywords))))
+       (pre-match-value (eval (nth 1 keywords) t)))
     ;; Set LIMIT to value of PRE-MATCH-FORM or the end of line.
     (if (and (numberp pre-match-value) (> pre-match-value (point)))
        (setq limit pre-match-value)
@@ -1600,7 +1480,7 @@ LIMIT can be modified by the value of its PRE-MATCH-FORM."
          (font-lock-apply-syntactic-highlight (car highlights))
          (setq highlights (cdr highlights)))))
     ;; Evaluate POST-MATCH-FORM.
-    (eval (nth 2 keywords))))
+    (eval (nth 2 keywords) t)))
 
 (defun font-lock-fontify-syntactic-keywords-region (start end)
   "Fontify according to `font-lock-syntactic-keywords' between START and END.
@@ -1692,7 +1572,7 @@ START should be at the beginning of a line."
                                         font-lock-comment-delimiter-face)))
                (if (looking-back (or font-lock-comment-end-skip
                                      comment-end-skip)
-                                 (point-at-bol) t)
+                                  (line-beginning-position) t)
                    (put-text-property (match-beginning 0) (point) 'face
                                       font-lock-comment-delimiter-face))))
            (< (point) end))
@@ -1713,7 +1593,7 @@ HIGHLIGHT should be of the form MATCH-HIGHLIGHT, see 
`font-lock-keywords'."
        ;; No match but we might not signal an error.
        (or (nth 3 highlight)
            (error "No match %d in highlight %S" match highlight))
-      (let ((val (eval (nth 1 highlight))))
+      (let ((val (eval (nth 1 highlight) t)))
        (when (eq (car-safe val) 'face)
          (add-text-properties start end (cddr val))
          (setq val (cadr val)))
@@ -1748,7 +1628,7 @@ LIMIT can be modified by the value of its PRE-MATCH-FORM."
   (let ((matcher (nth 0 keywords)) (lowdarks (nthcdr 3 keywords)) highlights
        (lead-start (match-beginning 0))
        ;; Evaluate PRE-MATCH-FORM.
-       (pre-match-value (eval (nth 1 keywords))))
+       (pre-match-value (eval (nth 1 keywords) t)))
     ;; Set LIMIT to value of PRE-MATCH-FORM or the end of line.
     (if (not (and (numberp pre-match-value) (> pre-match-value (point))))
        (setq limit (line-end-position))
@@ -1773,7 +1653,7 @@ LIMIT can be modified by the value of its PRE-MATCH-FORM."
          (font-lock-apply-highlight (car highlights))
          (setq highlights (cdr highlights)))))
     ;; Evaluate POST-MATCH-FORM.
-    (eval (nth 2 keywords))))
+    (eval (nth 2 keywords) t)))
 
 (defun font-lock-fontify-keywords-region (start end &optional loudly)
   "Fontify according to `font-lock-keywords' between START and END.
@@ -1879,7 +1759,7 @@ If SYNTACTIC-KEYWORDS is non-nil, it means these keywords 
are used for
   (cond ((or (functionp keyword) (nlistp keyword)) ; MATCHER
         (list keyword '(0 font-lock-keyword-face)))
        ((eq (car keyword) 'eval)               ; (eval . FORM)
-        (font-lock-compile-keyword (eval (cdr keyword))))
+        (font-lock-compile-keyword (eval (cdr keyword) t)))
        ((eq (car-safe (cdr keyword)) 'quote)   ; (MATCHER . 'FORM)
         ;; If FORM is a FACENAME then quote it.  Otherwise ignore the quote.
         (if (symbolp (nth 2 keyword))
@@ -1900,7 +1780,7 @@ If SYNTACTIC-KEYWORDS is non-nil, it means these keywords 
are used for
       keywords
     (font-lock-eval-keywords (if (fboundp keywords)
                                 (funcall keywords)
-                              (eval keywords)))))
+                              (eval keywords t)))))
 
 (defun font-lock-value-in-major-mode (values)
   "If VALUES is a list, use `major-mode' as a key and return the `assq' value.
@@ -2224,7 +2104,7 @@ as the constructs of Haddock, Javadoc and similar 
systems."
 ;;;;;###autoload
 ;;(progn
 ;;  ;; Make the Font Lock menu.
-;;  (defvar font-lock-menu (make-sparse-keymap "Syntax Highlighting"))
+;;  (defvar-keymap font-lock-menu :name "Syntax Highlighting")
 ;;  ;; Add the menu items in reverse order.
 ;;  (define-key font-lock-menu [fontify-less]
 ;;    '("Less In Current Buffer" . font-lock-fontify-less))
@@ -2363,7 +2243,7 @@ This function could be MATCHER in a MATCH-ANCHORED 
`font-lock-keywords' item."
 ;; e.g. assembler code and GNU linker script in Linux kernel.
 ;; `cpp-font-lock-keywords' is handy for modes for the files.
 ;;
-;; Here we cannot use `regexp-opt' because because regex-opt is not preloaded
+;; Here we cannot use `regexp-opt' because regex-opt is not preloaded
 ;; while font-lock.el is preloaded to emacs. So values pre-calculated with
 ;; regexp-opt are used here.
 
@@ -2429,6 +2309,10 @@ This should be an integer.  Used in 
`cpp-font-lock-keywords'.")
 for C preprocessor directives.  This definition is for the other modes
 in which C preprocessor directives are used, e.g. `asm-mode' and
 `ld-script-mode'.")
+
+(define-obsolete-function-alias 'font-lock-after-fontify-buffer #'ignore 
"29.1")
+(define-obsolete-function-alias 'font-lock-after-unfontify-buffer #'ignore 
"29.1")
+
 
 (provide 'font-lock)
 
diff --git a/lisp/format.el b/lisp/format.el
index 6c7524891e..2c368b8f9c 100644
--- a/lisp/format.el
+++ b/lisp/format.el
@@ -139,6 +139,7 @@ MODE-FN, if specified, is called when visiting a file with 
that format.
 
 PRESERVE, if non-nil, means that `format-write-file' should not remove
           this format from `buffer-file-format'.")
+;; Autoload if this file no longer dumped.
 ;;;###autoload
 (put 'format-alist 'risky-local-variable t)
 
diff --git a/lisp/frame.el b/lisp/frame.el
index 27f99fb7d2..9476cb0ec4 100644
--- a/lisp/frame.el
+++ b/lisp/frame.el
@@ -2149,6 +2149,17 @@ frame's display)."
 (defalias 'display-multi-frame-p #'display-graphic-p)
 (defalias 'display-multi-font-p #'display-graphic-p)
 
+(defcustom tty-select-active-regions nil
+  "If non-nil, update PRIMARY window-system selection on text-mode frames.
+On a text-mode terminal that supports setSelection command, if
+this variable is non-nil, Emacs will set the PRIMARY selection
+from the active region, according to `select-active-regions'.
+This is currently supported only on xterm."
+  :group 'frames
+  :group 'killing
+  :version "29.1"
+  :type 'boolean)
+
 (defun display-selections-p (&optional display)
   "Return non-nil if DISPLAY supports selections.
 A selection is a way to transfer text or other data between programs
@@ -2164,6 +2175,9 @@ frame's display)."
        (not (null dos-windows-version))))
      ((memq frame-type '(x w32 ns pgtk))
       t)
+     ((and tty-select-active-regions
+           (terminal-parameter nil 'xterm--set-selection))
+      t)
      (t
       nil))))
 
@@ -2827,7 +2841,7 @@ Values smaller than 0.2 sec are treated as 0.2 sec."
   "How many times to blink before using a solid cursor on NS, X, and 
MS-Windows.
 Use 0 or negative value to blink forever."
   :version "24.4"
-  :type 'integer
+  :type 'natnum
   :group 'cursor)
 
 (defvar blink-cursor-blinks-done 1
diff --git a/lisp/fringe.el b/lisp/fringe.el
index 657a73772d..0c88501298 100644
--- a/lisp/fringe.el
+++ b/lisp/fringe.el
@@ -46,6 +46,7 @@
   (let ((bitmaps '(question-mark exclamation-mark
                   left-arrow right-arrow up-arrow down-arrow
                   left-curly-arrow right-curly-arrow
+                  large-circle
                   left-triangle right-triangle
                   top-left-angle top-right-angle
                   bottom-left-angle bottom-right-angle
@@ -324,6 +325,17 @@ If BITMAP already exists, the existing definition is 
replaced."
     ;; The real implementation is in src/fringe.c.
     ))
 
+(defun fringe-custom-set-bitmap (symbol value)
+  "Set SYMBOL to a fringe bitmap VALUE.
+This sets the `fringe' property on SYMBOL to match that of VALUE,
+and then force all windows to be updated on the next redisplay.
+You should use this for the :set parameter for customization
+options to pick a fringe bitmap."
+  (prog1
+      (set symbol value)
+    (put symbol 'fringe (get value 'fringe))
+    (force-window-update)))
+
 (provide 'fringe)
 
 ;;; fringe.el ends here
diff --git a/lisp/gnus/ChangeLog.3 b/lisp/gnus/ChangeLog.3
index c75f5354ca..c33c76f68d 100644
--- a/lisp/gnus/ChangeLog.3
+++ b/lisp/gnus/ChangeLog.3
@@ -7385,7 +7385,7 @@
 2011-01-02  Lars Magne Ingebrigtsen  <larsi@gnus.org>
 
        * gnus-sum.el (gnus-select-newsgroup): Don't propagate marks to
-       backends after sanitising on entry, because this never makes sense:
+       backends after sanitizing on entry, because this never makes sense:
        If the articles have gone missing, then the data no longer exists on
        the backend, and if they haven't, then Gnus is wrong, and shouldn't
        overwrite anything anyway.
@@ -21361,7 +21361,7 @@
        to get all the groups a message ID is in.
 
        * spam-stat.el (spam-stat-split-fancy-spam-threshold)
-       (spam-stat-split-fancy): Change "threshhold" to "threshold".
+       (spam-stat-split-fancy): Fix typo for "threshold".
        (spam-stat-score-buffer-user-functions): Add :number custom type.
 
 2005-04-06  Katsumi Yamaoka  <yamaoka@jpl.org>
diff --git a/lisp/gnus/deuglify.el b/lisp/gnus/deuglify.el
index 732c6062b8..41fc2d83ac 100644
--- a/lisp/gnus/deuglify.el
+++ b/lisp/gnus/deuglify.el
@@ -223,6 +223,7 @@
 
 (defconst gnus-outlook-deuglify-version "1.5 Gnus version"
   "Version of gnus-outlook-deuglify.")
+(make-obsolete-variable 'gnus-outlook-deuglify-version 'emacs-version "29.1")
 
 ;;; User Customizable Variables:
 
diff --git a/lisp/gnus/gnus-agent.el b/lisp/gnus/gnus-agent.el
index e4704b35c8..e1c7bcb467 100644
--- a/lisp/gnus/gnus-agent.el
+++ b/lisp/gnus/gnus-agent.el
@@ -1681,7 +1681,7 @@ and that there are no duplicates."
              (gnus-message 1
                            "Overview buffer contains garbage `%s'."
                            (buffer-substring
-                            p (point-at-eol))))
+                             p (line-end-position))))
             ((= cur prev-num)
              (or backed-up
                   (setq backed-up (gnus-agent-backup-overview-buffer)))
@@ -2687,7 +2687,7 @@ The following commands are available:
     (gnus-category-position-point)))
 
 (defun gnus-category-name ()
-  (or (intern (get-text-property (point-at-bol) 'gnus-category))
+  (or (intern (get-text-property (line-beginning-position) 'gnus-category))
       (error "No category on the current line")))
 
 (defun gnus-category-read ()
@@ -3363,7 +3363,7 @@ missing NOV entry.  Run gnus-agent-regenerate-group to 
restore it.")))
 
                     (cl-incf nov-entries-deleted)
 
-                    (let* ((from (point-at-bol))
+                     (let* ((from (line-beginning-position))
                            (to (progn (forward-line 1) (point)))
                            (freed (- to from)))
                       (cl-incf bytes-freed freed)
diff --git a/lisp/gnus/gnus-art.el b/lisp/gnus/gnus-art.el
index 59c3bbc76e..83ba72c091 100644
--- a/lisp/gnus/gnus-art.el
+++ b/lisp/gnus/gnus-art.el
@@ -268,7 +268,7 @@ This can also be a list of the above values."
 (defcustom gnus-hidden-properties
   ;; We use to have `intangible' here as well, but Emacs's command loop moves
   ;; point out of invisible text anyway, so `intangible' is clearly not
-  ;; needed there.  And XEmacs doesn't handle `intangible' anyway.
+  ;; needed there.
   '(invisible t)
   "Property list to use for hiding text."
   :type 'plist
@@ -743,7 +743,7 @@ Each element is a regular expression."
   "Face used for highlighting buttons in the article buffer.
 
 An article button is a piece of text that you can activate by pressing
-`RET' or `mouse-2' above it."
+\\`RET' or `mouse-2' above it."
   :type 'face
   :group 'gnus-article-buttons)
 
@@ -1091,9 +1091,9 @@ positive (negative), move point forward (backwards) this 
many
 parts.  When nil, redisplay article."
   :version "23.1" ;; No Gnus
   :group 'gnus-article-mime
-  :type '(choice (const nil :tag "Redisplay article.")
-                (const 1 :tag "Next part.")
-                (const 0 :tag "Current part.")
+  :type '(choice (const :value nil :tag "Redisplay article")
+                 (const :value 1   :tag "Next part")
+                 (const :value 0   :tag "Current part")
                 integer))
 
 ;;;
@@ -1930,7 +1930,7 @@ always hide."
              (while (re-search-forward "^[^: \t]+:[ \t]*\n[^ \t]" nil t)
                (forward-line -1)
                (gnus-article-hide-text-type
-                (point-at-bol)
+                 (line-beginning-position)
                 (progn
                   (end-of-line)
                   (if (re-search-forward "^[^ \t]" nil t)
@@ -1939,8 +1939,8 @@ always hide."
                 'boring-headers)))
             ;; Hide boring Newsgroups header.
             ((eq elem 'newsgroups)
-             (when (gnus-string-equal
-                    (gnus-fetch-field "newsgroups")
+             (when (string-equal-ignore-case
+                    (or (gnus-fetch-field "newsgroups") "")
                     (gnus-group-real-name
                      (if (boundp 'gnus-newsgroup-name)
                          gnus-newsgroup-name
@@ -1954,7 +1954,7 @@ always hide."
                          gnus-newsgroup-name ""))))
                (when (and to to-address
                           (ignore-errors
-                            (gnus-string-equal
+                            (string-equal-ignore-case
                              ;; only one address in To
                              (nth 1 (mail-extract-address-components to))
                              to-address)))
@@ -1967,7 +1967,7 @@ always hide."
                          gnus-newsgroup-name ""))))
                (when (and to to-list
                           (ignore-errors
-                            (gnus-string-equal
+                            (string-equal-ignore-case
                              ;; only one address in To
                              (nth 1 (mail-extract-address-components to))
                              to-list)))
@@ -1980,15 +1980,15 @@ always hide."
                          gnus-newsgroup-name ""))))
                (when (and cc to-list
                           (ignore-errors
-                            (gnus-string-equal
+                            (string-equal-ignore-case
                              ;; only one address in Cc
                              (nth 1 (mail-extract-address-components cc))
                              to-list)))
                  (gnus-article-hide-header "cc"))))
             ((eq elem 'followup-to)
-             (when (gnus-string-equal
-                    (message-fetch-field "followup-to")
-                    (message-fetch-field "newsgroups"))
+             (when (string-equal-ignore-case
+                    (or (message-fetch-field "followup-to") "")
+                    (or (message-fetch-field "newsgroups") ""))
                (gnus-article-hide-header "followup-to")))
             ((eq elem 'reply-to)
              (if (gnus-group-find-parameter
@@ -2060,7 +2060,7 @@ always hide."
     (goto-char (point-min))
     (when (re-search-forward (concat "^" header ":") nil t)
       (gnus-article-hide-text-type
-       (point-at-bol)
+       (line-beginning-position)
        (progn
         (end-of-line)
         (if (re-search-forward "^[^ \t]" nil t)
@@ -2081,7 +2081,7 @@ always hide."
        (article-narrow-to-head)
        (while (not (eobp))
          (cond
-          ((< (setq column (- (point-at-eol) (point)))
+           ((< (setq column (- (line-end-position) (point)))
               gnus-article-normalized-header-length)
            (end-of-line)
            (insert (make-string
@@ -2092,7 +2092,7 @@ always hide."
             (progn
               (forward-char gnus-article-normalized-header-length)
               (point))
-            (point-at-eol)
+             (line-end-position)
             'invisible t))
           (t
            ;; Do nothing.
@@ -2389,7 +2389,7 @@ fill width."
            (end-of-line)
            (when (>= (current-column) width)
              (narrow-to-region (min (1+ (point)) (point-max))
-                               (point-at-bol))
+                                (line-beginning-position))
               (let ((goback (point-marker))
                    (fill-column width))
                 (fill-paragraph nil)
@@ -2446,7 +2446,7 @@ fill width."
         (while (and (not (bobp))
                     (looking-at "^[ \t]*$")
                     (not (gnus-annotation-in-region-p
-                          (point) (point-at-eol))))
+                           (point) (line-end-position))))
           (forward-line -1))
         (forward-line 1)
         (point))))))
@@ -3583,9 +3583,10 @@ possible values."
                                              'original-date)
                      bface (get-text-property (match-beginning 0) 'face)
                      eface (get-text-property (match-end 0) 'face))
-               (delete-region (point-at-bol) (progn
-                                               (gnus-article-forward-header)
-                                               (point)))))
+                (delete-region (line-beginning-position)
+                               (progn
+                                 (gnus-article-forward-header)
+                                 (point)))))
            (when (and (not date)
                       visible-date)
              (setq date visible-date))
@@ -4388,8 +4389,8 @@ If variable `gnus-use-long-file-name' is non-nil, it is
                (message-narrow-to-head)
                (goto-char (point-max))
                (forward-line -1)
-               (setq bface (get-text-property (point-at-bol) 'face)
-                     eface (get-text-property (1- (point-at-eol)) 'face))
+                (setq bface (get-text-property (line-beginning-position) 'face)
+                      eface (get-text-property (1- (line-end-position)) 'face))
                (message-remove-header "X-Gnus-PGP-Verify")
                (if (re-search-forward "^X-PGP-Sig:" nil t)
                    (forward-line)
@@ -5925,7 +5926,7 @@ all parts."
            ;; Go to the displayed subpart, assuming this is
            ;; multipart/alternative.
            (setq part start
-                 end (point-at-eol))
+                  end (line-end-position))
            (while (and (not handle)
                        part
                        (< part end)
@@ -6825,9 +6826,9 @@ not have a face in `gnus-article-boring-faces'."
   "Read article specified by message-id around point."
   (interactive nil gnus-article-mode)
   (save-excursion
-    (re-search-backward "[ \t]\\|^" (point-at-bol) t)
-    (re-search-forward "<?news:<?\\|<" (point-at-eol) t)
-    (if (re-search-forward "[^@ ]+@[^ \t>]+" (point-at-eol) t)
+    (re-search-backward "[ \t]\\|^" (line-beginning-position) t)
+    (re-search-forward "<?news:<?\\|<" (line-end-position) t)
+    (if (re-search-forward "[^@ ]+@[^ \t>]+" (line-end-position) t)
        (let ((msg-id (concat "<" (match-string 0) ">")))
          (set-buffer gnus-summary-buffer)
          (gnus-summary-refer-article msg-id))
@@ -8180,7 +8181,7 @@ url is put as the `gnus-button-url' overlay property on 
the button."
                     (goto-char start)
                     (string-match
                      "\\(?:\"\\|\\(<\\)\\)[\t ]*\\(?:url[\t ]*:[\t ]*\\)?\\'"
-                     (buffer-substring (point-at-bol) start)))
+                      (buffer-substring (line-beginning-position) start)))
                   (progn
                     (setq url (list (buffer-substring start end))
                           delim (if (match-beginning 1) ">" "\""))
@@ -8470,8 +8471,6 @@ url is put as the `gnus-button-url' overlay property on 
the button."
       (when comma
        (dotimes (_ (with-temp-buffer
                      (insert comma)
-                     ;; Note: the XEmacs version of `how-many' takes
-                     ;; no optional argument.
                      (goto-char (point-min))
                      (how-many ",")))
          (Info-index-next 1)))
diff --git a/lisp/gnus/gnus-bookmark.el b/lisp/gnus/gnus-bookmark.el
index 4f5b9bd342..18732218c9 100644
--- a/lisp/gnus/gnus-bookmark.el
+++ b/lisp/gnus/gnus-bookmark.el
@@ -509,7 +509,7 @@ Optional argument SHOW means show them unconditionally."
             (let ((bmrk (gnus-bookmark-bmenu-bookmark)))
               (setq gnus-bookmark-bmenu-hidden-bookmarks
                     (cons bmrk gnus-bookmark-bmenu-hidden-bookmarks))
-             (let ((start (point-at-eol)))
+              (let ((start (line-end-position)))
                (move-to-column gnus-bookmark-bmenu-file-column t)
                ;; Strip off `mouse-face' from the white spaces region.
                (if (display-mouse-p)
@@ -543,7 +543,7 @@ Optional argument SHOW means show them unconditionally."
   "Kill from point to end of line.
 If optional arg NEWLINE-TOO is non-nil, delete the newline too.
 Does not affect the kill ring."
-  (delete-region (point) (point-at-eol))
+  (delete-region (point) (line-end-position))
   (if (and newline-too (looking-at "\n"))
       (delete-char 1)))
 
diff --git a/lisp/gnus/gnus-cache.el b/lisp/gnus/gnus-cache.el
index ee20ba3c7f..449b73163f 100644
--- a/lisp/gnus/gnus-cache.el
+++ b/lisp/gnus/gnus-cache.el
@@ -552,7 +552,7 @@ Returns the list of articles removed."
       (set-buffer cache-buf)
       (if (search-forward (concat "\n" (int-to-string (car cached)) "\t")
                          nil t)
-         (setq beg (point-at-bol)
+          (setq beg (line-beginning-position)
                end (progn (end-of-line) (point)))
        (setq beg nil))
       (set-buffer nntp-server-buffer)
diff --git a/lisp/gnus/gnus-cite.el b/lisp/gnus/gnus-cite.el
index 3ba2bbd6fe..b4d7661d74 100644
--- a/lisp/gnus/gnus-cite.el
+++ b/lisp/gnus/gnus-cite.el
@@ -371,7 +371,7 @@ Lines matching `gnus-cite-attribution-suffix' and perhaps
        (goto-char (point-min))
        (forward-line (1- number))
        (when (re-search-forward gnus-cite-attribution-suffix
-                                (point-at-eol)
+                                 (line-end-position)
                                 t)
          (gnus-article-add-button (match-beginning 1) (match-end 1)
                                   'gnus-cite-toggle prefix))
@@ -756,7 +756,7 @@ See also the documentation for 
`gnus-article-highlight-citation'."
       ;; Each line.
       (setq begin (point)
            guess-limit (progn (skip-chars-forward "^> \t\r\n") (point))
-           end (point-at-bol 2)
+            end (line-beginning-position 2)
            start end)
       (goto-char begin)
       ;; Ignore standard Supercite attribution prefix.
@@ -1105,8 +1105,8 @@ Returns nil if there is no such line before LIMIT, t 
otherwise."
                                       "[\t [:alnum:]]+")))
                       gnus-message-max-citation-depth))
          (mlist (make-list (* (1+ gnus-message-max-citation-depth) 2) nil))
-         (start (point-at-bol))
-         (end (point-at-eol)))
+          (start (line-beginning-position))
+          (end (line-end-position)))
       (setcar mlist start)
       (setcar (cdr mlist) end)
       (setcar (nthcdr (* cdepth 2) mlist) start)
diff --git a/lisp/gnus/gnus-cus.el b/lisp/gnus/gnus-cus.el
index f8714a95d4..ddd939794d 100644
--- a/lisp/gnus/gnus-cus.el
+++ b/lisp/gnus/gnus-cus.el
@@ -273,7 +273,7 @@ DOC is a documentation string for the parameter.")
        gnus-agent-cat-predicate)
       (agent-score
        (choice :tag "Score File" :value nil
-               (const file :tag "Use group's score files")
+               (const :value file :tag "Use group's score files")
                (repeat (list (string :format "%v" :tag "File name"))))
        "Which score files to use when using score to select articles to fetch.
 
diff --git a/lisp/gnus/gnus-demon.el b/lisp/gnus/gnus-demon.el
index d9da8529eb..f6cfd727f7 100644
--- a/lisp/gnus/gnus-demon.el
+++ b/lisp/gnus/gnus-demon.el
@@ -222,7 +222,7 @@ minutes, the connection is closed."
 
 (defun gnus-demon-nntp-close-connection ()
   (save-window-excursion
-    (when (time-less-p '(0 300) (time-since nntp-last-command-time))
+    (when (time-less-p 300 (time-since nntp-last-command-time))
       (nntp-close-server))))
 
 (defun gnus-demon-add-scanmail ()
diff --git a/lisp/gnus/gnus-diary.el b/lisp/gnus/gnus-diary.el
index cd2b53064b..3c57d7b112 100644
--- a/lisp/gnus/gnus-diary.el
+++ b/lisp/gnus/gnus-diary.el
@@ -65,8 +65,9 @@ There are currently two built-in format functions:
                 (const  :tag "french"  gnus-diary-delay-format-french)
                 (symbol :tag "other")))
 
-(defconst gnus-diary-version nndiary-version
+(defconst gnus-diary-version "0.2-b14"
   "Current Diary back end version.")
+(make-obsolete-variable 'gnus-diary-version 'emacs-version "29.1")
 
 
 ;; Compatibility functions ==================================================
@@ -326,7 +327,7 @@ If ARG (or prefix) is non-nil, force prompting for all 
fields."
           (when (re-search-forward (concat "^" header ":") nil t)
             (unless (eq (char-after) ? )
               (insert " "))
-            (setq value (buffer-substring (point) (point-at-eol)))
+             (setq value (buffer-substring (point) (line-end-position)))
             (and (string-match "[ \t]*\\([^ \t]+\\)[ \t]*" value)
                  (setq value (match-string 1 value)))
             (condition-case ()
@@ -377,8 +378,9 @@ If ARG (or prefix) is non-nil, force prompting for all 
fields."
 
 (defun gnus-diary-version ()
   "Current Diary back end version."
+  (declare (obsolete emacs-version "29.1"))
   (interactive)
-  (message "NNDiary version %s" nndiary-version))
+  (message "NNDiary version %s" gnus-diary-version))
 
 (provide 'gnus-diary)
 
diff --git a/lisp/gnus/gnus-draft.el b/lisp/gnus/gnus-draft.el
index 56d498cc4d..e38deefe2a 100644
--- a/lisp/gnus/gnus-draft.el
+++ b/lisp/gnus/gnus-draft.el
@@ -150,7 +150,7 @@ Obeys the standard process/prefix convention."
             (concat "^" (regexp-quote gnus-agent-target-move-group-header)
                     ":") nil t)
        (skip-syntax-forward "-")
-       (setq move-to (buffer-substring (point) (point-at-eol)))
+        (setq move-to (buffer-substring (point) (line-end-position)))
        (message-remove-header gnus-agent-target-move-group-header))
       (goto-char (point-min))
       (when (re-search-forward
diff --git a/lisp/gnus/gnus-eform.el b/lisp/gnus/gnus-eform.el
index 300532de28..96f515119d 100644
--- a/lisp/gnus/gnus-eform.el
+++ b/lisp/gnus/gnus-eform.el
@@ -92,7 +92,7 @@ The optional LAYOUT overrides the `edit-form' window layout."
       (insert ";;; ")
       (forward-line 1))
     (insert (substitute-command-keys
-            ";; Type `C-c C-c' after you've finished editing.\n"))
+             ";; Type \\`C-c C-c' after you've finished editing.\n"))
     (insert "\n")
     (let ((p (point)))
       (gnus-pp form)
diff --git a/lisp/gnus/gnus-group.el b/lisp/gnus/gnus-group.el
index 04d19e29a3..fcad601d0c 100644
--- a/lisp/gnus/gnus-group.el
+++ b/lisp/gnus/gnus-group.el
@@ -1204,7 +1204,7 @@ case interactively), the level will be updated by this 
command."
   (gnus-group-setup-buffer)
   (gnus-update-format-specifications nil 'group 'group-mode)
   (let ((case-fold-search nil)
-       (props (text-properties-at (point-at-bol)))
+        (props (text-properties-at (line-beginning-position)))
        (empty (= (point-min) (point-max)))
        (group (gnus-group-group-name))
        number)
@@ -1724,24 +1724,24 @@ already.  If INFO-UNCHANGED is non-nil, dribble buffer 
is not updated."
 
 (defun gnus-group-group-name ()
   "Get the name of the newsgroup on the current line."
-  (let ((group (get-text-property (point-at-bol) 'gnus-group)))
+  (let ((group (get-text-property (line-beginning-position) 'gnus-group)))
     (cond ((stringp group) group)
           (group (symbol-name group)))))
 
 (defun gnus-group-group-level ()
   "Get the level of the newsgroup on the current line."
-  (get-text-property (point-at-bol) 'gnus-level))
+  (get-text-property (line-beginning-position) 'gnus-level))
 
 (defun gnus-group-group-indentation ()
   "Get the indentation of the newsgroup on the current line."
-  (or (get-text-property (point-at-bol) 'gnus-indentation)
+  (or (get-text-property (line-beginning-position) 'gnus-indentation)
       (and gnus-group-indentation-function
           (funcall gnus-group-indentation-function))
       ""))
 
 (defun gnus-group-group-unread ()
   "Get the number of unread articles of the newsgroup on the current line."
-  (get-text-property (point-at-bol) 'gnus-unread))
+  (get-text-property (line-beginning-position) 'gnus-unread))
 
 (defun gnus-group-new-mail (group)
   (if (nnmail-new-mail-p group)
@@ -2095,14 +2095,14 @@ be permanent."
                                (looking-at "[][\C-@-*,/;-@\\^`{-\C-?]")))
                       (prog1 t
                         (skip-chars-backward "^][\C-@-\t\v-*,/;-@\\^`{-\C-?"
-                                             (point-at-bol))))
+                                              (line-beginning-position))))
                  (and (looking-at "[][\C-@-\t\v-*,/;-@\\^`{-\C-?]*$")
                       (prog1 t
                         (skip-chars-backward "][\C-@-\t\v-*,/;-@\\^`{-\C-?")
                         (skip-chars-backward "^][\C-@-\t\v-*,/;-@\\^`{-\C-?"
-                                             (point-at-bol))))
+                                              (line-beginning-position))))
                  (string-match "\\`[][\C-@-\t\v-*,/;-@\\^`{-\C-?]*\\'"
-                               (buffer-substring (point-at-bol) (point))))
+                                (buffer-substring (line-beginning-position) 
(point))))
              (when (looking-at regexp)
                (match-string 1))
            (let (group distance)
@@ -2111,7 +2111,7 @@ be permanent."
                      distance (- (match-beginning 1) (match-beginning 0))))
              (skip-chars-backward "][\C-@-\t\v-*,/;-@\\^`{-\C-?")
              (skip-chars-backward "^][\C-@-\t\v-*,/;-@\\^`{-\C-?"
-                                  (point-at-bol))
+                                   (line-beginning-position))
              (if (looking-at regexp)
                  (if (and group (<= distance (- start (match-end 0))))
                      group
@@ -3948,10 +3948,10 @@ The killed newsgroups can be yanked by using 
\\[gnus-group-yank-group]."
           (count-lines
            (progn
              (goto-char begin)
-             (point-at-bol))
+              (line-beginning-position))
            (progn
              (goto-char end)
-             (point-at-bol))))))
+              (line-beginning-position))))))
     (goto-char begin)
     (beginning-of-line)                        ;Important when LINES < 1
     (gnus-group-kill-group lines)))
@@ -4532,9 +4532,11 @@ and the second element is the address."
                      ;; FIXME? gnus-secondary-servers is obsolete,
                      ;; and it is not obvious that there is anything
                      ;; sensible to use instead in this particular case.
-                     (if (boundp 'gnus-secondary-servers)
-                         gnus-secondary-servers
-                       (cdr gnus-select-method))))
+                      ;; (if (boundp 'gnus-secondary-servers)
+                      ;;     gnus-secondary-servers
+                      ;;   (cdr gnus-select-method))
+                      nil
+                      ))
             ;; We got a server name.
             how)))
    gnus-group-mode)
diff --git a/lisp/gnus/gnus-int.el b/lisp/gnus/gnus-int.el
index f00f2a0d04..a85510ba91 100644
--- a/lisp/gnus/gnus-int.el
+++ b/lisp/gnus/gnus-int.el
@@ -114,10 +114,7 @@ If CONFIRM is non-nil, the user will be asked for an NNTP 
server."
        ;; Read server name with completion.
        (setq gnus-nntp-server
              (gnus-completing-read "NNTP server"
-                                    (cons gnus-nntp-server
-                                         (if (boundp 'gnus-secondary-servers)
-                                             gnus-secondary-servers))
-                                    nil gnus-nntp-server)))
+                                    nil nil gnus-nntp-server)))
 
       (when (and gnus-nntp-server
                 (stringp gnus-nntp-server)
diff --git a/lisp/gnus/gnus-logic.el b/lisp/gnus/gnus-logic.el
index 3fb2ed3c62..c1b559ba6f 100644
--- a/lisp/gnus/gnus-logic.el
+++ b/lisp/gnus/gnus-logic.el
@@ -224,8 +224,8 @@
           (goto-char (point-min))
           (prog1
               (funcall search-func match nil t)
-            (widen)))
-        (when handles (mm-destroy-parts handles))))))
+            (widen)
+            (when handles (mm-destroy-parts handles))))))))
 
 (provide 'gnus-logic)
 
diff --git a/lisp/gnus/gnus-msg.el b/lisp/gnus/gnus-msg.el
index 17a87134be..3fc5ce2408 100644
--- a/lisp/gnus/gnus-msg.el
+++ b/lisp/gnus/gnus-msg.el
@@ -52,24 +52,6 @@ method to use when posting."
                 (const current)
                 (sexp :tag "Methods" ,gnus-select-method)))
 
-(defcustom gnus-outgoing-message-group nil
-  "All outgoing messages will be put in this group.
-If you want to store all your outgoing mail and articles in the group
-\"nnml:archive\", you set this variable to that value.  This variable
-can also be a list of group names.
-
-If you want to have greater control over what group to put each
-message in, you can set this variable to a function that checks the
-current newsgroup name and then returns a suitable group name (or list
-of names)."
-  :group 'gnus-message
-  :type '(choice (const nil)
-                (function)
-                (string :tag "Group")
-                (repeat :tag "List of groups" (string :tag "Group"))))
-
-(make-obsolete-variable 'gnus-outgoing-message-group 
'gnus-message-archive-group "24.1")
-
 (defcustom gnus-mailing-list-groups nil
   "If non-nil a regexp matching groups that are really mailing lists.
 This is useful when you're reading a mailing list that has been
@@ -215,30 +197,6 @@ use this option with care."
  :parameter-document       "\
 List of charsets that are permitted to be unencoded.")
 
-(defcustom gnus-debug-files
-  '("gnus.el" "gnus-sum.el" "gnus-group.el"
-    "gnus-art.el" "gnus-start.el" "gnus-async.el"
-    "gnus-msg.el" "gnus-score.el" "gnus-win.el" "gnus-topic.el"
-    "gnus-agent.el" "gnus-cache.el" "gnus-srvr.el"
-    "mm-util.el" "mm-decode.el" "nnmail.el" "message.el")
-  "Files whose variables will be reported in `gnus-bug'."
-  :version "22.1"
-  :group 'gnus-message
-  :type '(repeat file))
-
-(make-obsolete-variable 'gnus-debug-files "it is no longer used." "24.1")
-
-(defcustom gnus-debug-exclude-variables
-  '(mm-mime-mule-charset-alist
-    nnmail-split-fancy message-minibuffer-local-map)
-  "Variables that should not be reported in `gnus-bug'."
-  :version "22.1"
-  :group 'gnus-message
-  :type '(repeat variable))
-
-(make-obsolete-variable
- 'gnus-debug-exclude-variables "it is no longer used." "24.1")
-
 (defcustom gnus-discouraged-post-methods
   '(nndraft nnml nnimap nnmaildir nnmh nnfolder nndir)
   "A list of back ends that are not used in \"real\" newsgroups.
@@ -1665,7 +1623,7 @@ this is a reply."
 (defun gnus-inews-insert-gcc (&optional group)
   "Insert the Gcc to say where the article is to be archived."
   (let* ((group (or group gnus-newsgroup-name))
-         (var (or gnus-outgoing-message-group gnus-message-archive-group))
+         (var gnus-message-archive-group)
         (gcc-self-val
          (and group (not (gnus-virtual-group-p group))
               (gnus-group-find-parameter group 'gcc-self t)))
diff --git a/lisp/gnus/gnus-picon.el b/lisp/gnus/gnus-picon.el
index d0edf2cba8..012ac9d556 100644
--- a/lisp/gnus/gnus-picon.el
+++ b/lisp/gnus/gnus-picon.el
@@ -220,13 +220,13 @@ replacement is added."
                                                   (error 0)))
                                               spec)))
                  (when (> len 0)
-                   (goto-char (point-at-eol))
+                    (goto-char (line-end-position))
                    (insert (propertize
                             " " 'display
                             (cons 'space
                                   (list :align-to (- (window-width) 1 len))))))
-                 (goto-char (point-at-eol))
-                 (setq point (point-at-eol))
+                  (goto-char (line-end-position))
+                  (setq point (line-end-position))
                  (dolist (image spec)
                    (unless (stringp image)
                      (goto-char point)
diff --git a/lisp/gnus/gnus-range.el b/lisp/gnus/gnus-range.el
index 23a71bda20..2b9d7fac1d 100644
--- a/lisp/gnus/gnus-range.el
+++ b/lisp/gnus/gnus-range.el
@@ -36,10 +36,10 @@
   (car list))
 (make-obsolete 'gnus-last-element "use `car' of `last' instead." "27.1")
 
-(define-obsolete-function-alias 'gnus-copy-sequence 'copy-tree "27.1")
+(define-obsolete-function-alias 'gnus-copy-sequence #'copy-tree "27.1")
 
-;;; We could be using `seq-difference' here, but it's much slower
-;;; on these data sets.  See bug#50877.
+;; We could be using `seq-difference' here, but it's much slower
+;; on these data sets.  See bug#50877.
 (defun gnus-set-difference (list1 list2)
   "Return a list of elements of LIST1 that do not appear in LIST2."
   (let ((hash2 (make-hash-table :test 'eq))
@@ -163,7 +163,7 @@ LIST1 and LIST2 have to be sorted over <."
   #'range-intersection "29.1")
 
 ;;;###autoload
-(defalias 'gnus-set-sorted-intersection 'gnus-sorted-nintersection)
+(defalias 'gnus-set-sorted-intersection #'gnus-sorted-nintersection)
 
 ;;;###autoload
 (defun gnus-sorted-nintersection (list1 list2)
@@ -241,7 +241,7 @@ ranges."
       (range-compress-list numbers)
     (range-denormalize (range-compress-list numbers))))
 
-(defalias 'gnus-uncompress-sequence 'gnus-uncompress-range)
+(defalias 'gnus-uncompress-sequence #'gnus-uncompress-range)
 (define-obsolete-function-alias 'gnus-uncompress-range
   #'range-uncompress "29.1")
 
@@ -256,7 +256,7 @@ ranges."
 (define-obsolete-function-alias 'gnus-list-range-intersection
   #'range-list-intersection "29.1")
 
-(defalias 'gnus-inverse-list-range-intersection 'gnus-list-range-difference)
+(defalias 'gnus-inverse-list-range-intersection #'range-list-difference)
 
 (define-obsolete-function-alias 'gnus-list-range-difference
   #'range-list-difference "29.1")
diff --git a/lisp/gnus/gnus-registry.el b/lisp/gnus/gnus-registry.el
index 8cefb09b66..ceeb184854 100644
--- a/lisp/gnus/gnus-registry.el
+++ b/lisp/gnus/gnus-registry.el
@@ -1004,9 +1004,6 @@ Uses `gnus-registry-marks' to find what shortcuts to 
install."
                nil
                (cons "Registry Marks" gnus-registry-misc-menus)))))
 
-(define-obsolete-function-alias 'gnus-registry-user-format-function-M
-  #'gnus-registry-article-marks-to-chars "24.1")
-
 ;; use like this:
 ;; (defalias 'gnus-user-format-function-M 
#'gnus-registry-article-marks-to-chars)
 (defun gnus-registry-article-marks-to-chars (headers)
diff --git a/lisp/gnus/gnus-salt.el b/lisp/gnus/gnus-salt.el
index 3189655c8a..6b7958dcb9 100644
--- a/lisp/gnus/gnus-salt.el
+++ b/lisp/gnus/gnus-salt.el
@@ -133,9 +133,7 @@ It accepts the same format specs that 
`gnus-summary-line-format' does."
 (defun gnus-pick-start-reading (&optional catch-up)
   "Start reading the picked articles.
 If given a prefix, mark all unpicked articles as read."
-  (interactive "P")
-  (declare (completion (lambda (s b)
-                        (completion-minor-mode-active-p s b 'gnus-pick-mode))))
+  (interactive "P" gnus-pick-mode)
   (if gnus-newsgroup-processable
       (progn
        (gnus-summary-limit-to-articles nil)
@@ -688,7 +686,7 @@ it in the environment specified by BINDINGS."
        (unless (zerop level)
          (gnus-tree-indent level)
          (insert (cadr gnus-tree-parent-child-edges))
-         (setq col (- (setq beg (point)) (point-at-bol) 1))
+          (setq col (- (setq beg (point)) (line-beginning-position) 1))
          ;; Draw "|" lines upwards.
          (while (progn
                   (forward-line -1)
@@ -712,7 +710,7 @@ it in the environment specified by BINDINGS."
 
 (defsubst gnus-tree-indent-vertical ()
   (let ((len (- (* (1+ gnus-tree-node-length) gnus-tmp-indent)
-               (- (point) (point-at-bol)))))
+                (- (point) (line-beginning-position)))))
     (when (> len 0)
       (insert (make-string len ? )))))
 
diff --git a/lisp/gnus/gnus-score.el b/lisp/gnus/gnus-score.el
index c852986ae6..5f49c28007 100644
--- a/lisp/gnus/gnus-score.el
+++ b/lisp/gnus/gnus-score.el
@@ -1168,9 +1168,9 @@ If FORMAT, also format the current score file."
         (reg " -> +")
         (file (save-excursion
                 (end-of-line)
-                (if (and (re-search-backward reg (point-at-bol) t)
-                         (re-search-forward  reg (point-at-eol) t))
-                    (buffer-substring (point) (point-at-eol))
+                 (if (and (re-search-backward reg (line-beginning-position) t)
+                          (re-search-forward  reg (line-end-position) t))
+                     (buffer-substring (point) (line-end-position))
                   nil))))
     (if (or (not file)
            (string-match "\\<\\(non-file rule\\|A file\\)\\>" file)
@@ -1999,7 +1999,7 @@ score in `gnus-newsgroup-scored' by SCORE."
            (goto-char (point-min))
            (if (= dmt ?e)
                (while (funcall search-func match nil t)
-                 (and (= (point-at-bol)
+                  (and (= (line-beginning-position)
                          (match-beginning 0))
                       (= (progn (end-of-line) (point))
                          (match-end 0))
@@ -2170,7 +2170,7 @@ score in `gnus-newsgroup-scored' by SCORE."
                        (funcall search-func match nil t))
              ;; Is it really exact?
              (and (eolp)
-                  (= (point-at-bol) (match-beginning 0))
+                   (= (line-beginning-position) (match-beginning 0))
                   ;; Yup.
                   (progn
                     (setq found (setq arts (get-text-property
@@ -2260,7 +2260,7 @@ score in `gnus-newsgroup-scored' by SCORE."
          (goto-char (point-min))
          (while (and (not (eobp))
                      (search-forward match nil t))
-           (when (and (= (point-at-bol) (match-beginning 0))
+            (when (and (= (line-beginning-position) (match-beginning 0))
                       (eolp))
              (setq found (setq arts (get-text-property (point) 'articles)))
              (if trace
@@ -2344,7 +2344,7 @@ score in `gnus-newsgroup-scored' by SCORE."
               hashtb))
        (puthash
         word
-        (append (get-text-property (point-at-eol) 'articles) val)
+         (append (get-text-property (line-end-position) 'articles) val)
         hashtb)))
     ;; Make all the ignorable words ignored.
     (let ((ignored (append gnus-ignored-adaptive-words
diff --git a/lisp/gnus/gnus-search.el b/lisp/gnus/gnus-search.el
index 369df81d9b..327dba95c0 100644
--- a/lisp/gnus/gnus-search.el
+++ b/lisp/gnus/gnus-search.el
@@ -565,7 +565,7 @@ returning the one at the supplied position."
                      (buffer-substring
                       (point)
                       (progn
-                        (re-search-forward ":" (point-at-eol) t)
+                         (re-search-forward ":" (line-end-position) t)
                         (1- (point))))))
                (value (gnus-search-query-return-string
                        (when (looking-at-p "[\"/]") t))))
@@ -1672,43 +1672,6 @@ Namazu provides a little more information, for instance 
a score."
       (format "date:%s.." (notmuch-date (cdr expr))))
      (t (ignore-errors (cl-call-next-method))))))
 
-(cl-defmethod gnus-search-run-search :around ((engine gnus-search-notmuch)
-                                             server query groups)
-  "Handle notmuch's thread-search routine."
-  ;; Notmuch allows for searching threads, but only using its own
-  ;; thread ids.  That means a thread search is a \"double-bounce\":
-  ;; once to find the relevant thread ids, and again to find the
-  ;; actual messages.  This method performs the first \"bounce\".
-  (if (alist-get 'thread query)
-      (with-slots (program proc-buffer) engine
-       (let* ((qstring
-               (gnus-search-make-query-string engine query))
-              (cp-list (gnus-search-indexed-search-command
-                        engine qstring query groups))
-              thread-ids proc)
-         (with-current-buffer proc-buffer
-           (erase-buffer)
-           (setq proc (apply #'start-process (format "search-%s" server)
-                             proc-buffer program cp-list))
-           (while (process-live-p proc)
-             (accept-process-output proc))
-            (goto-char (point-min))
-           (while (re-search-forward
-                    "^thread:\\([^[:space:]\n]+\\)"
-                    (point-max) t)
-             (cl-pushnew (match-string 1) thread-ids :test #'equal)))
-         (cl-call-next-method
-          engine server
-          ;; If we found threads, completely replace the query with
-          ;; our new thread-based one.
-           (if thread-ids
-               `((query . ,(mapconcat (lambda (thrd)
-                                        (concat "thread:" thrd))
-                                      thread-ids " or ")))
-             query)
-          nil)))
-    (cl-call-next-method engine server query groups)))
-
 (cl-defmethod gnus-search-indexed-search-command ((engine gnus-search-notmuch)
                                                  (qstring string)
                                                  query &optional _groups)
@@ -1721,13 +1684,14 @@ Namazu provides a little more information, for instance 
a score."
       (append
        (list (format "--config=%s" config-file)
              "search"
-             (if thread
-                 "--output=threads"
-             "--output=files"))
+             "--output=files")
        (unless thread '("--duplicate=1"))
        (when limit (list (format "--limit=%d" limit)))
        switches
-       (list qstring)))))
+       (list (if thread
+                 (format "thread:\"{%s}\""
+                         (string-replace "\"" "\"\"" qstring))
+               qstring))))))
 
 ;;; Mairix interface
 
diff --git a/lisp/gnus/gnus-srvr.el b/lisp/gnus/gnus-srvr.el
index a520bfcd8b..e659a648e1 100644
--- a/lisp/gnus/gnus-srvr.el
+++ b/lisp/gnus/gnus-srvr.el
@@ -339,13 +339,13 @@ The following commands are available:
   (gnus-server-position-point))
 
 (defun gnus-server-server-name ()
-  (let ((server (get-text-property (point-at-bol) 'gnus-server)))
+  (let ((server (get-text-property (line-beginning-position) 'gnus-server)))
     (and server (symbol-name server))))
 
 (defun gnus-server-named-server ()
   "Return a server name that matches one of the names returned by
 `gnus-method-to-server'."
-  (let ((server (get-text-property (point-at-bol) 'gnus-named-server)))
+  (let ((server (get-text-property (line-beginning-position) 
'gnus-named-server)))
     (and server (symbol-name server))))
 
 (defalias 'gnus-server-position-point 'gnus-goto-colon)
@@ -699,7 +699,6 @@ claim them."
   "n" #'gnus-browse-next-group
   "p" #'gnus-browse-prev-group
   "DEL" #'gnus-browse-prev-group
-  "<delete>" #'gnus-browse-prev-group
   "N" #'gnus-browse-next-group
   "P" #'gnus-browse-prev-group
   "M-n" #'gnus-browse-next-group
@@ -950,7 +949,7 @@ how new groups will be entered into the group buffer."
   (save-excursion
     (beginning-of-line)
     (let ((name (get-text-property (point) 'gnus-group)))
-      (when (re-search-forward ": \\(.*\\)$" (point-at-eol) t)
+      (when (re-search-forward ": \\(.*\\)$" (line-end-position) t)
        (concat (gnus-method-to-server-name gnus-browse-current-method) ":"
                (or name
                    (match-string-no-properties 1)))))))
diff --git a/lisp/gnus/gnus-start.el b/lisp/gnus/gnus-start.el
index 7b5721fafb..7700e6bd43 100644
--- a/lisp/gnus/gnus-start.el
+++ b/lisp/gnus/gnus-start.el
@@ -855,7 +855,7 @@ If REGEXP is given, lines that match it will be deleted."
            (unless (bolp) (forward-line 1))
            (setq end (point))
            (goto-char (match-beginning 0))
-           (delete-region (point-at-bol) end))))
+            (delete-region (line-beginning-position) end))))
       (goto-char (point-max))
       ;; Make sure that each dribble entry is a single line, so that
       ;; the "remove" code above works.
@@ -2173,7 +2173,7 @@ The info element is shared with the same element of
           (unless ignore-errors
             (gnus-message 3 "Warning - invalid active: %s"
                           (buffer-substring
-                           (point-at-bol) (point-at-eol))))))
+                            (line-beginning-position) (line-end-position))))))
        (forward-line 1)))))
 
 (defun gnus-groups-to-gnus-format (method &optional hashtb real-active)
@@ -2527,10 +2527,10 @@ The form should return either t or nil."
              ;; don't give a damn, frankly, my dear.
              (concat gnus-newsrc-options
                      (buffer-substring
-                      (point-at-bol)
+                       (line-beginning-position)
                       ;; Options may continue on the next line.
                       (or (and (re-search-forward "^[^ \t]" nil 'move)
-                               (point-at-bol))
+                                (line-beginning-position))
                           (point)))))
        (forward-line -1))
        (group
@@ -2592,8 +2592,8 @@ The form should return either t or nil."
                ;; The line was buggy.
                (setq group nil)
                (gnus-error 3.1 "Mangled line: %s"
-                           (buffer-substring (point-at-bol)
-                                             (point-at-eol))))
+                            (buffer-substring (line-beginning-position)
+                                              (line-end-position))))
              nil))
          ;; Skip past ", ".  Spaces are invalid in these ranges, but
          ;; we allow them, because it's a common mistake to put a
@@ -2702,9 +2702,9 @@ The form should return either t or nil."
       (while (re-search-forward "[ \t]-n" nil t)
        (setq eol
              (or (save-excursion
-                   (and (re-search-forward "[ \t]-n" (point-at-eol) t)
+                    (and (re-search-forward "[ \t]-n" (line-end-position) t)
                         (- (point) 2)))
-                 (point-at-eol)))
+                  (line-end-position)))
        ;; Search for all "words"...
        (while (re-search-forward "[^ \t,\n]+" eol t)
          (if (eq (char-after (match-beginning 0)) ?!)
diff --git a/lisp/gnus/gnus-sum.el b/lisp/gnus/gnus-sum.el
index a4f98c9157..dde60caee7 100644
--- a/lisp/gnus/gnus-sum.el
+++ b/lisp/gnus/gnus-sum.el
@@ -97,7 +97,7 @@ See `gnus-group-goto-unread'."
   :type 'boolean)
 
 (defcustom gnus-summary-stop-at-end-of-message nil
-  "If non-nil, don't select the next message when using `SPC'."
+  "If non-nil, don't select the next message when using \\`SPC'."
   :link '(custom-manual "(gnus)Group Maneuvering")
   :group 'gnus-summary-maneuvering
   :version "24.1"
@@ -264,8 +264,8 @@ This variable will only be used if the value of
 (defcustom gnus-summary-goto-unread nil
   "If t, many commands will go to the next unread article.
 This applies to marking commands as well as other commands that
-\"naturally\" select the next article, like, for instance, `SPC' at
-the end of an article.
+\"naturally\" select the next article, like, for instance, \\`SPC'
+at the end of an article.
 
 If nil, the marking commands do NOT go to the next unread article
 \(they go to the next article instead).  If `never', commands that
@@ -1958,8 +1958,6 @@ increase the score of each group you read."
   "C-M-b" #'gnus-summary-prev-thread
   "M-<down>" #'gnus-summary-next-thread
   "M-<up>" #'gnus-summary-prev-thread
-  "C-M-u" #'gnus-summary-up-thread
-  "C-M-d" #'gnus-summary-down-thread
   "&" #'gnus-summary-execute-command
   "c" #'gnus-summary-catchup-and-exit
   "C-w" #'gnus-summary-mark-region-as-read
@@ -3385,7 +3383,7 @@ marks of articles."
     (let (config)
       (goto-char (point-min))
       (while (not (eobp))
-        (when (eq (get-char-property (point-at-eol) 'invisible) 'gnus-sum)
+        (when (eq (get-char-property (line-end-position) 'invisible) 'gnus-sum)
           (push (save-excursion (forward-line 0) (point)) config))
         (forward-line 1))
       config)))
@@ -4507,7 +4505,7 @@ Returns HEADER if it was entered in the DEPENDENCIES.  
Returns nil otherwise."
   (let (header)
     ;; overview: [num subject from date id refs chars lines misc]
     (unwind-protect
-       (narrow-to-region (point) (point-at-eol))
+        (narrow-to-region (point) (line-end-position))
       (unless (eobp)
        (forward-char))
       (setq header (nnheader-parse-nov number))
@@ -4663,7 +4661,7 @@ If LINE, insert the rebuilt thread starting on line LINE."
        (setq thread (list (car (gnus-id-to-thread id))))
       ;; Get the thread this article is part of.
       (setq thread (gnus-remove-thread id)))
-    (setq old-pos (point-at-bol))
+    (setq old-pos (line-beginning-position))
     (setq current (save-excursion
                    (and (re-search-backward "[\r\n]" nil t)
                         (gnus-summary-article-number))))
@@ -4847,9 +4845,9 @@ If LINE, insert the rebuilt thread starting on line LINE."
       (gnus-summary-show-thread)
       (gnus-data-remove
        number
-       (- (point-at-bol)
+       (- (line-beginning-position)
          (prog1
-             (1+ (point-at-eol))
+              (1+ (line-end-position))
            (gnus-delete-line)))))))
 
 (defun gnus-sort-threads-recursive (threads func)
@@ -6470,7 +6468,7 @@ This is meant to be called in 
`gnus-article-internal-prepare-hook'."
                           (looking-at "Xref:"))
                      (search-forward "\nXref:" nil t))
              (goto-char (1+ (match-end 0)))
-             (setq xref (buffer-substring (point) (point-at-eol)))
+              (setq xref (buffer-substring (point) (line-end-position)))
              (setf (mail-header-xref headers) xref)))))))
 
 (defun gnus-summary-insert-subject (id &optional old-header use-old-header)
@@ -6501,9 +6499,9 @@ too, instead of trying to fetch new headers."
          (goto-char (gnus-data-pos d))
          (gnus-data-remove
           number
-          (- (point-at-bol)
+           (- (line-beginning-position)
              (prog1
-                 (1+ (point-at-eol))
+                  (1+ (line-end-position))
                (gnus-delete-line))))))
       ;; Remove list identifiers from subject.
       (let ((gnus-newsgroup-headers (list header)))
@@ -11221,7 +11219,7 @@ If NO-EXPIRE, auto-expiry will be inhibited."
 (defun gnus-summary-update-mark (mark type)
   (let ((forward (cdr (assq type gnus-summary-mark-positions)))
        (inhibit-read-only t))
-    (re-search-backward "[\n\r]" (point-at-bol) 'move-to-limit)
+    (re-search-backward "[\n\r]" (line-beginning-position) 'move-to-limit)
     (when forward
       (when (looking-at "\r")
        (cl-incf forward))
@@ -11758,7 +11756,7 @@ If ARG is positive number, turn showing conversation 
threads on."
 Returns nil if no thread was there to be shown."
   (interactive nil gnus-summary-mode)
   (let* ((orig (point))
-        (end (point-at-eol))
+         (end (line-end-position))
          (end (or (gnus-summary--inv end) (gnus-summary--inv (1- end))))
         ;; Leave point at bol
         (beg (progn (beginning-of-line) (if (bobp) (point) (1- (point)))))
@@ -12677,8 +12675,8 @@ If REVERSE, save parts that do not match TYPE."
   ;; Added by Per Abrahamsen <amanda@iesd.auc.dk>.
   (when gnus-summary-selected-face
     (save-excursion
-      (let* ((beg (point-at-bol))
-            (end (point-at-eol))
+      (let* ((beg (line-beginning-position))
+             (end (line-end-position))
             ;; Fix by Mike Dugan <dugan@bucrf16.bu.edu>.
             (from (if (get-text-property beg 'mouse-face)
                       beg
@@ -12734,7 +12732,7 @@ If REVERSE, save parts that do not match TYPE."
   (with-no-warnings                   ;See docstring of gnus-summary-highlight.
     (defvar score) (defvar default) (defvar default-high) (defvar default-low)
     (defvar mark) (defvar uncached))
-  (let* ((beg (point-at-bol))
+  (let* ((beg (line-beginning-position))
         (article (or (gnus-summary-article-number) gnus-current-article))
         (score (or (cdr (assq article
                               gnus-newsgroup-scored))
@@ -12750,7 +12748,7 @@ If REVERSE, save parts that do not match TYPE."
     (let ((face (funcall (gnus-summary-highlight-line-0))))
       (unless (eq face (gnus-get-text-property-excluding-characters-with-faces 
beg 'face))
        (gnus-put-text-property-excluding-characters-with-faces
-        beg (1+ (point-at-eol)) 'face
+         beg (1+ (line-end-position)) 'face
         (setq face (if (boundp face) (symbol-value face) face)))
        (when gnus-summary-highlight-line-function
          (funcall gnus-summary-highlight-line-function article face))))))
@@ -12897,7 +12895,7 @@ treated as multipart/mixed."
     (insert "Mime-Version: 1.0\n")
     (widen)
     (when (search-forward "\n--" nil t)
-      (let ((separator (buffer-substring (point) (point-at-eol))))
+      (let ((separator (buffer-substring (point) (line-end-position))))
        (message-narrow-to-head)
        (message-remove-header "Content-Type")
        (goto-char (point-max))
@@ -12929,7 +12927,7 @@ treated as multipart/mixed."
     (expirable gnus-expirable-mark "e"))
   "An alist of names/marks/keystrokes.")
 
-(defvar gnus-summary-generic-mark-map (make-sparse-keymap))
+(defvar-keymap gnus-summary-generic-mark-map)
 (defvar gnus-summary-mark-map)
 
 (defun gnus-summary-make-all-marking-commands ()
diff --git a/lisp/gnus/gnus-topic.el b/lisp/gnus/gnus-topic.el
index fa942bee8e..13263dddc9 100644
--- a/lisp/gnus/gnus-topic.el
+++ b/lisp/gnus/gnus-topic.el
@@ -107,15 +107,15 @@ should return non-nil if the topic is to be displayed."
 
 (defun gnus-group-topic-name ()
   "The name of the topic on the current line."
-  (get-text-property (point-at-bol) 'gnus-topic))
+  (get-text-property (line-beginning-position) 'gnus-topic))
 
 (defun gnus-group-topic-level ()
   "The level of the topic on the current line."
-  (get-text-property (point-at-bol) 'gnus-topic-level))
+  (get-text-property (line-beginning-position) 'gnus-topic-level))
 
 (defun gnus-group-topic-unread ()
   "The number of unread articles in topic on the current line."
-  (get-text-property (point-at-bol) 'gnus-topic-unread))
+  (get-text-property (line-beginning-position) 'gnus-topic-unread))
 
 (defun gnus-topic-unread (topic)
   "Return the number of unread articles in TOPIC."
@@ -128,7 +128,7 @@ should return non-nil if the topic is to be displayed."
 
 (defun gnus-topic-visible-p ()
   "Return non-nil if the current topic is visible."
-  (get-text-property (point-at-bol) 'gnus-topic-visible))
+  (get-text-property (line-beginning-position) 'gnus-topic-visible))
 
 (defun gnus-topic-articles-in-topic (entries)
   (let ((total 0)
@@ -188,7 +188,7 @@ If TOPIC, start with that topic."
 
 (defun gnus-group-active-topic-p ()
   "Say whether the current topic comes from the active topics."
-  (get-text-property (point-at-bol) 'gnus-active))
+  (get-text-property (line-beginning-position) 'gnus-active))
 
 (defun gnus-topic-find-groups (topic &optional level all lowest recursive)
   "Return entries for all visible groups in TOPIC.
diff --git a/lisp/gnus/gnus-util.el b/lisp/gnus/gnus-util.el
index 218a4d242b..fe556b155a 100644
--- a/lisp/gnus/gnus-util.el
+++ b/lisp/gnus/gnus-util.el
@@ -40,17 +40,14 @@
 
 (defcustom gnus-completing-read-function 'gnus-emacs-completing-read
   "Function use to do completing read."
-  :version "24.1"
+  :version "29.1"
   :group 'gnus-meta
   :type '(radio (function-item
                  :doc "Use Emacs standard `completing-read' function."
                  gnus-emacs-completing-read)
                (function-item
                 :doc "Use `ido-completing-read' function."
-                gnus-ido-completing-read)
-               (function-item
-                :doc "Use iswitchb based completing-read function."
-                gnus-iswitchb-completing-read)))
+                 gnus-ido-completing-read)))
 
 (defcustom gnus-completion-styles
   (append (when (and (assq 'substring completion-styles-alist)
@@ -121,7 +118,7 @@ This is a compatibility function for different Emacsen."
 
 ;; Delete the current line (and the next N lines).
 (defmacro gnus-delete-line (&optional n)
-  `(delete-region (point-at-bol)
+  `(delete-region (line-beginning-position)
                  (progn (forward-line ,(or n 1)) (point))))
 
 (defun gnus-extract-address-components (from)
@@ -181,7 +178,7 @@ is slower."
 
 (defun gnus-goto-colon ()
   (move-beginning-of-line 1)
-  (let ((eol (point-at-eol)))
+  (let ((eol (line-end-position)))
     (goto-char (or (text-property-any (point) eol 'gnus-position t)
                   (search-forward ":" eol t)
                   (point)))))
@@ -383,7 +380,7 @@ Cache the result as a text property stored in DATE."
   ;; Either return the cached value...
   `(let ((d ,date))
      (if (equal "" d)
-        '(0 0)
+        0
        (or (get-text-property 0 'gnus-time d)
           ;; or compute the value...
           (let ((time (safe-date-to-time d)))
@@ -750,15 +747,6 @@ nil.  See also `gnus-bind-print-variables'."
   (when (file-exists-p file)
     (delete-file file)))
 
-(defun gnus-delete-duplicates (list)
-  "Remove duplicate entries from LIST."
-  (let ((result nil))
-    (while list
-      (unless (member (car list) result)
-       (push (car list) result))
-      (pop list))
-    (nreverse result)))
-
 (defun gnus-delete-directory (directory)
   "Delete files in DIRECTORY.  Subdirectories remain.
 If there's no subdirectory, delete DIRECTORY as well."
@@ -1078,6 +1066,7 @@ ARG is passed to the first function."
 ;; (`string-equal' uses symbol print names.)
 (defun gnus-string-equal (x y)
   "Like `string-equal', except it compares case-insensitively."
+  (declare (obsolete string-equal-ignore-case "29.1"))
   (and (= (length x) (length y))
        (or (string-equal x y)
           (string-equal (downcase x) (downcase y)))))
@@ -1133,14 +1122,11 @@ sure of changing the value of `foo'."
 If you find some problem with the directory separator character, try
 \"[/\\\\]\" for some systems.")
 
-(defun gnus-url-unhex (x)
-  (if (> x ?9)
-      (if (>= x ?a)
-         (+ 10 (- x ?a))
-       (+ 10 (- x ?A)))
-    (- x ?0)))
+(autoload 'url-unhex "url-util")
+(define-obsolete-function-alias 'gnus-url-unhex #'url-unhex "29.1")
 
-;; Fixme: Do it like QP.
+;; FIXME: Make obsolete in favor of `url-unhex-string', which is
+;;        identical except for the call to `char-to-string'.
 (defun gnus-url-unhex-string (str &optional allow-newlines)
   "Remove %XX, embedded spaces, etc in a url.
 If optional second argument ALLOW-NEWLINES is non-nil, then allow the
@@ -1150,9 +1136,9 @@ forbidden in URL encoding."
        (case-fold-search t))
     (while (string-match "%[0-9a-f][0-9a-f]" str)
       (let* ((start (match-beginning 0))
-            (ch1 (gnus-url-unhex (elt str (+ start 1))))
+             (ch1 (url-unhex (elt str (+ start 1))))
             (code (+ (* 16 ch1)
-                     (gnus-url-unhex (elt str (+ start 2))))))
+                      (url-unhex (elt str (+ start 2))))))
        (setq tmp (concat
                   tmp (substring str 0 start)
                   (cond
@@ -1213,6 +1199,7 @@ SPEC is a predicate specifier that contains stuff like 
`or', `and',
 (defun gnus-iswitchb-completing-read (prompt collection &optional require-match
                                             initial-input history def)
   "`iswitchb' based completing-read function."
+  (declare (obsolete nil "29.1"))
   ;; Make sure iswitchb is loaded before we let-bind its variables.
   ;; If it is loaded inside the let, variables can become unbound afterwards.
   (require 'iswitchb)
@@ -1253,7 +1240,7 @@ SPEC is a predicate specifier that contains stuff like 
`or', `and',
        contents value)
     (if (or (null (setq value (symbol-value variable)))
            (not (equal (car value) file))
-           (not (equal (nth 1 value) time)))
+           (not (time-equal-p (nth 1 value) time)))
        (progn
          (setq contents (funcall function file))
          (set variable (list file time contents))
@@ -1387,8 +1374,7 @@ sequence, this is like `mapcar'.  With several, it is 
like the Common Lisp
                          system-configuration)
                         ((memq 'type lst)
                          (symbol-name system-type))
-                        (t nil)))
-        ) ;; codename
+                         (t nil))))
     (cond
      ((not (memq 'emacs lst))
       nil)
@@ -1553,6 +1539,8 @@ lists of strings."
 ;; gnus-util.
 (autoload 'gnus-output-to-rmail "gnus-rmail")
 
+(define-obsolete-function-alias 'gnus-delete-duplicates #'seq-uniq "29.1")
+
 (provide 'gnus-util)
 
 ;;; gnus-util.el ends here
diff --git a/lisp/gnus/gnus-uu.el b/lisp/gnus/gnus-uu.el
index 6990d8ee77..9cafc78ab8 100644
--- a/lisp/gnus/gnus-uu.el
+++ b/lisp/gnus/gnus-uu.el
@@ -260,9 +260,10 @@ Default is t."
   "Non-nil means that files will be viewed with metamail.
 The gnus-uu viewing functions will be ignored and gnus-uu will try
 to guess at a content-type based on file name suffixes.  Default
-it nil."
+is nil."
   :group 'gnus-extract
   :type 'boolean)
+(make-obsolete-variable 'gnus-uu-view-with-metamail "don't use it." "29.1")
 
 (defcustom gnus-uu-unmark-articles-not-decoded nil
   "If non-nil, gnus-uu will mark unsuccessfully decoded articles as unread.
@@ -543,11 +544,11 @@ didn't work, and overwrite existing files.  Otherwise, 
ask each time."
                    "Various"))))
        (goto-char (point-min))
        (when (re-search-forward "^Subject: ")
-         (delete-region (point) (point-at-eol))
+          (delete-region (point) (line-end-position))
          (insert subject))
        (goto-char (point-min))
        (when (re-search-forward "^From:")
-         (delete-region (point) (point-at-eol))
+          (delete-region (point) (line-end-position))
          (insert " " from))
        (let ((message-forward-decoded-p t))
          (message-forward post t))))
@@ -1762,7 +1763,7 @@ Gnus might fail to display all of it.")
            (unless (looking-at (concat gnus-uu-begin-string "\\|"
                                        gnus-uu-end-string))
              (when (not found)
-               (setq length (- (point-at-eol) (point-at-bol))))
+                (setq length (- (line-end-position) 
(line-beginning-position))))
              (setq found t)
              (beginning-of-line)
              (setq beg (point))
@@ -2067,7 +2068,7 @@ If no file has been included, the user will be asked for 
a file."
     (goto-char (point-min))
     (re-search-forward
      (concat "^" (regexp-quote mail-header-separator) "$") nil t)
-    (setq header (buffer-substring (point-min) (point-at-bol)))
+    (setq header (buffer-substring (point-min) (line-beginning-position)))
 
     (goto-char (point-min))
     (when gnus-uu-post-separate-description
diff --git a/lisp/gnus/gnus.el b/lisp/gnus/gnus.el
index f60c11f985..0afd873a5d 100644
--- a/lisp/gnus/gnus.el
+++ b/lisp/gnus/gnus.el
@@ -1110,14 +1110,6 @@ that case, just return a fully prefixed name of the 
group --
                 sexp
                 string))
 
-(defcustom gnus-secondary-servers nil
-  "List of NNTP servers that the user can choose between interactively.
-To make Gnus query you for a server, you have to give `gnus' a
-non-numeric prefix - `\\[universal-argument] \\[gnus]', in short."
-  :group 'gnus-server
-  :type '(repeat string))
-(make-obsolete-variable 'gnus-secondary-servers 'gnus-select-method "24.1")
-
 (defcustom gnus-secondary-select-methods nil
   "A list of secondary methods that will be used for reading news.
 This is a list where each element is a complete select method (see
@@ -1130,16 +1122,6 @@ you could set this variable:
   :group 'gnus-server
   :type '(repeat gnus-select-method))
 
-(defcustom gnus-local-domain nil
-  "Local domain name without a host name.
-The DOMAINNAME environment variable is used instead if it is defined.
-If the function `system-name' returns the full Internet name, there is
-no need to set this variable."
-  :group 'gnus-message
-  :type '(choice (const :tag "default" nil)
-                string))
-(make-obsolete-variable 'gnus-local-domain nil "24.1")
-
 ;; Customization variables
 
 (defcustom gnus-refer-article-method 'current
@@ -2254,21 +2236,18 @@ Disabling the agent may result in noticeable loss of 
performance."
   "Which information should be exposed in the User-Agent header.
 
 Can be a list of symbols or a string.  Valid symbols are `gnus'
-\(show Gnus version) and `emacs' \(show Emacs version).  In
-addition to the Emacs version, you can add `codename' \(show
-\(S)XEmacs codename) or either `config' \(show system
-configuration) or `type' \(show system type).  If you set it to
-a string, be sure to use a valid format, see RFC 2616."
-
+(show Gnus version) and `emacs' (show Emacs version).  In
+addition to the Emacs version, you can add `config' (show system
+configuration) or `type' (show system type).  If you set it to a
+string, be sure to use a valid format, see RFC 2616."
   :version "22.1"
   :group 'gnus-message
   :type '(choice (list (set :inline t
-                           (const gnus  :tag "Gnus version")
-                           (const emacs :tag "Emacs version")
+                            (const :value gnus  :tag "Gnus version")
+                            (const :value emacs :tag "Emacs version")
                            (choice :tag "system"
-                                   (const type   :tag "system type")
-                                   (const config :tag "system configuration"))
-                           (const codename :tag "Emacs codename")))
+                                    (const :value type   :tag "system type")
+                                    (const :value config :tag "system 
configuration"))))
                 (string)))
 
 ;; Convert old (< 2005-01-10) symbol type values:
@@ -2316,11 +2295,6 @@ automatically cache the article in the agent cache."
 (defvar gnus-server-method-cache nil)
 (defvar gnus-extended-servers nil)
 
-;; The carpal mode has been removed, but define the variable for
-;; backwards compatibility.
-(defvar gnus-carpal nil)
-(make-obsolete-variable 'gnus-carpal nil "24.1")
-
 (defvar gnus-agent-fetching nil
   "Whether Gnus agent is in fetching mode.")
 
@@ -4192,8 +4166,7 @@ prompt the user for the name of an NNTP server to use."
   ;; file.
   (unless (string-match "^Gnus" gnus-version)
     (load "gnus-load" nil t))
-  (unless (or (byte-code-function-p (symbol-function 'gnus))
-             (subr-native-elisp-p (symbol-function 'gnus)))
+  (unless (compiled-function-p (symbol-function 'gnus))
     (message "You should compile Gnus")
     (sit-for 2))
   (let ((gnus-action-message-log (list nil)))
diff --git a/lisp/gnus/message.el b/lisp/gnus/message.el
index 6973d8a86b..49a04f601f 100644
--- a/lisp/gnus/message.el
+++ b/lisp/gnus/message.el
@@ -1411,7 +1411,7 @@ text and it replaces `self-insert-command' with the other 
command, e.g.
       (file-name-as-directory (expand-file-name "drafts" message-directory))
     "~/")
   "Directory where Message auto-saves buffers if Gnus isn't running.
-If nil, Message won't auto-save."
+If nil, Message won't auto-save, whether or not Gnus is running."
   :group 'message-buffers
   :link '(custom-manual "(message)Various Message Variables")
   :type '(choice directory (const :tag "Don't auto-save" nil)))
@@ -1468,11 +1468,11 @@ candidates:
       (memq feature message-shoot-gnksa-feet)))
 
 (defcustom message-hidden-headers '("^References:" "^Face:" "^X-Face:"
-                                   "^X-Draft-From:")
+                                   "^X-Draft-From:" "^In-Reply-To:")
   "Regexp of headers to be hidden when composing new messages.
 This can also be a list of regexps to match headers.  Or a list
 starting with `not' and followed by regexps."
-  :version "22.1"
+  :version "29.1"
   :group 'message
   :link '(custom-manual "(message)Message Headers")
   :type '(choice
@@ -2081,11 +2081,13 @@ You must have the \"hashcash\" binary installed, see 
`hashcash-path'."
 
 (defsubst message-delete-line (&optional n)
   "Delete the current line (and the next N lines)."
+  (declare (obsolete delete-line "29.1"))
   (delete-region (progn (beginning-of-line) (point))
                 (progn (forward-line (or n 1)) (point))))
 
 (defun message-mark-active-p ()
   "Non-nil means the mark and region are currently active in this buffer."
+  (declare (obsolete mark-active "29.1"))
   mark-active)
 
 (defun message-unquote-tokens (elems)
@@ -2183,7 +2185,7 @@ see `message-narrow-to-headers-or-head'."
    (progn
      (forward-line 1)
      (if (re-search-forward "^[^ \n\t]" nil t)
-        (point-at-bol)
+         (line-beginning-position)
        (point-max))))
   (goto-char (point-min)))
 
@@ -2384,7 +2386,7 @@ Leading \"Re: \" is not stripped by this function.  Use 
the function
                    (setq old-subject
                          (message-strip-subject-re old-subject))
                    (message-goto-subject)
-                   (message-delete-line)
+                   (delete-line)
                    (insert (concat "Subject: "
                                    new-subject
                                    " (was: "
@@ -2499,12 +2501,12 @@ been made to before the user asked for a Crosspost."
     (while (re-search-backward
            (concat "^" (regexp-quote message-cross-post-note) ".*")
            head t)
-      (message-delete-line))
+      (delete-line))
     (message-goto-signature)
     (while (re-search-backward
            (concat "^" (regexp-quote message-followup-to-note) ".*")
            head t)
-      (message-delete-line))
+      (delete-line))
     ;; insert new note
     (if (message-goto-signature)
        (re-search-backward message-signature-separator))
@@ -2576,7 +2578,7 @@ With prefix-argument just set Follow-Up, don't 
cross-post."
    (cond (cc-content
          (save-excursion
            (message-goto-to)
-           (message-delete-line)
+           (delete-line)
            (insert (concat "To: " cc-content "\n"))
            (save-restriction
              (message-narrow-to-headers)
@@ -2731,20 +2733,17 @@ Point is left at the beginning of the narrowed-to 
region."
   (interactive nil message-mode)
   (save-excursion
     (save-restriction
-      (let ((max (1+ (length message-header-format-alist)))
-           rank)
+      (let ((max (1+ (length message-header-format-alist))))
        (message-narrow-to-headers)
        (while (re-search-forward "^[^ \n]+:" nil t)
          (put-text-property
           (match-beginning 0) (1+ (match-beginning 0))
           'message-rank
-          (if (setq rank (length (memq (assq (intern (buffer-substring
-                                                      (match-beginning 0)
-                                                      (1- (match-end 0))))
-                                             message-header-format-alist)
-                                       message-header-format-alist)))
-              (- max rank)
-            (1+ max)))))
+           (- max (length
+                   (memq (assq (intern (buffer-substring
+                                       (match-beginning 0) (1- (match-end 0))))
+                              message-header-format-alist)
+                        message-header-format-alist))))))
       (message-sort-headers-1))))
 
 (defun message-kill-address ()
@@ -2953,12 +2952,12 @@ Consider adding this function to 
`message-header-setup-hook'"
     ["Fill Yanked Message" message-fill-yanked-message t]
     ["Insert Signature" message-insert-signature t]
     ["Caesar (rot13) Message" message-caesar-buffer-body t]
-    ["Caesar (rot13) Region" message-caesar-region (message-mark-active-p)]
+    ["Caesar (rot13) Region" message-caesar-region mark-active]
     ["Elide Region" message-elide-region
-     :active (message-mark-active-p)
+     :active mark-active
      :help "Replace text in region with an ellipsis"]
     ["Delete Outside Region" message-delete-not-region
-     :active (message-mark-active-p)
+     :active mark-active
      :help "Delete all quoted text outside region"]
     ["Kill To Signature" message-kill-to-signature t]
     ["Newline and Reformat" message-newline-and-reformat t]
@@ -2966,7 +2965,7 @@ Consider adding this function to 
`message-header-setup-hook'"
     ["Spellcheck" ispell-message :help "Spellcheck this message"]
     "----"
     ["Insert Region Marked" message-mark-inserted-region
-     :active (message-mark-active-p) :help "Mark region with enclosing tags"]
+     :active mark-active :help "Mark region with enclosing tags"]
     ["Insert File Marked..." message-mark-insert-file
      :help "Insert file at point marked with enclosing tags"]
     ["Attach File..." mml-attach-file t]
@@ -3665,7 +3664,7 @@ Message buffers and is not meant to be called directly."
   (save-excursion
     (save-restriction
       (widen)
-      (let ((bound (+ (point-at-eol) 1)) case-fold-search)
+      (let ((bound (+ (line-end-position) 1)) case-fold-search)
         (goto-char (point-min))
         (not (search-forward (concat "\n" mail-header-separator "\n")
                              bound t))))))
@@ -3929,18 +3928,16 @@ However, if `message-yank-prefix' is non-nil, insert 
that prefix on each line."
        (if all-removed
            (goto-char start)
          (forward-line 1))))
-    ;; Delete blank lines at the start of the buffer.
-    (while (and (point-min)
-               (eolp)
-               (not (eobp)))
-      (message-delete-line))
+    ;; Delete blank lines at the start of the cited text.
+    (while (and (eolp) (not (eobp)))
+      (delete-line))
     ;; Delete blank lines at the end of the buffer.
     (goto-char (point-max))
     (unless (eq (preceding-char) ?\n)
       (insert "\n"))
     (while (and (zerop (forward-line -1))
                (looking-at "$"))
-      (message-delete-line)))
+      (delete-line)))
   ;; Do the indentation.
   (if (null message-yank-prefix)
       (indent-rigidly start (or end (mark t)) message-indentation-spaces)
@@ -4180,8 +4177,7 @@ See `message-citation-line-format'."
                  (setq fname (car names)
                        lname (string-join (cdr names) " ")))
                 ((> count 3)
-                 (setq fname (string-join (butlast names (- count 2))
-                                          " ")
+                 (setq fname (string-join (take 2 names) " ")
                        lname (string-join (nthcdr 2 names) " "))))
           (when (string-match "\\(.*\\),\\'" fname)
             (let ((newlname (match-string 1 fname)))
@@ -5145,9 +5141,9 @@ to find out how to use this."
       (let ((headers message-mh-deletable-headers))
        (while headers
          (goto-char (point-min))
-         (and (re-search-forward
-               (concat "^" (symbol-name (car headers)) ": *") nil t)
-              (message-delete-line))
+         (when (re-search-forward
+                (concat "^" (symbol-name (car headers)) ": *") nil t)
+           (delete-line))
          (pop headers))))
     (run-hooks 'message-send-mail-hook)
     ;; Pass it on to mh.
@@ -5674,11 +5670,11 @@ Otherwise, generate and save a value for 
`canlock-password' first."
        (goto-char (point-max))
        (if (not (re-search-backward message-signature-separator nil t))
           t
-        (setq sig-start (1+ (point-at-eol)))
+         (setq sig-start (1+ (line-end-position)))
         (setq sig-end
               (if (re-search-forward
                    "<#/?\\(multipart\\|part\\|external\\|mml\\)" nil t)
-                  (- (point-at-bol) 1)
+                   (- (line-beginning-position) 1)
                 (point-max)))
         (if (>= (count-lines sig-start sig-end) 5)
             (if (message-gnksa-enable-p 'signature)
@@ -6279,7 +6275,7 @@ Headers already prepared in the buffer are not modified."
          (and (re-search-forward
                (concat "^" (symbol-name (car headers)) ": *") nil t)
               (get-text-property (1+ (match-beginning 0)) 'message-deletable)
-              (message-delete-line))
+              (delete-line))
          (pop headers)))
       ;; Go through all the required headers and see if they are in the
       ;; articles already.  If they are not, or are empty, they are
@@ -6364,7 +6360,7 @@ Headers already prepared in the buffer are not modified."
                      (forward-line -1)))
                ;; The value of this header was empty, so we clear
                ;; totally and insert the new value.
-               (delete-region (point) (point-at-eol))
+                (delete-region (point) (line-end-position))
                ;; If the header is optional, and the header was
                ;; empty, we can't insert it anyway.
                (unless optionalp
@@ -6498,7 +6494,7 @@ If the current line has `message-yank-prefix', insert it 
on the new line."
     ;; Tapdance around looong Message-IDs.
     (forward-line -1)
     (when (looking-at "[ \t]*$")
-      (message-delete-line))
+      (delete-line))
     (goto-char begin)
     (search-forward ":" nil t)
     (when (looking-at "\n[ \t]+")
@@ -6619,10 +6615,10 @@ beginning of a folded header)."
                 (or (eq (char-after) ?\s) (eq (char-after) ?\t)))
       (beginning-of-line 0)))
   (when (or (eq (char-after) ?\s) (eq (char-after) ?\t)
-            (search-forward ":" (point-at-eol) t))
+            (search-forward ":" (line-end-position) t))
     ;; We are a bit more lacks than the RFC and allow any positive number of 
WSP
     ;; characters.
-    (skip-chars-forward " \t" (point-at-eol))
+    (skip-chars-forward " \t" (line-end-position))
     (point)))
 
 (defun message-beginning-of-line (&optional n)
@@ -6881,13 +6877,14 @@ are not included."
     (or (bolp) (insert ?\n)))
   (insert (concat mail-header-separator "\n"))
   (forward-line -1)
-  ;; If a crash happens while replying, the auto-save file would *not* have a
-  ;; `References:' header if `message-generate-headers-first' was nil.
-  ;; Therefore, always generate it first.
+  ;; If a crash happens while replying, the auto-save file would *not*
+  ;; have a `References:' header if `message-generate-headers-first'
+  ;; was nil.  Therefore, always generate it first.  (And why not
+  ;; include the `In-Reply-To' header as well.)
   (let ((message-generate-headers-first
          (if (eq message-generate-headers-first t)
              t
-           (append message-generate-headers-first '(References)))))
+           (append message-generate-headers-first '(References In-Reply-To)))))
     (when (message-news-p)
       (when message-default-news-headers
         (insert message-default-news-headers)
@@ -8644,7 +8641,7 @@ From headers in the original article."
 (autoload 'ecomplete-display-matches "ecomplete")
 
 (defun message--in-tocc-p ()
-  (and (memq (char-after (point-at-bol)) '(?C ?T ?\t ? ))
+  (and (memq (char-after (line-beginning-position)) '(?C ?T ?\t ? ))
        (message-point-in-header-p)
        (save-excursion
         (beginning-of-line)
diff --git a/lisp/gnus/mm-decode.el b/lisp/gnus/mm-decode.el
index 7256e5a2f7..5268f192c6 100644
--- a/lisp/gnus/mm-decode.el
+++ b/lisp/gnus/mm-decode.el
@@ -117,8 +117,8 @@
   (cond ((fboundp 'libxml-parse-html-region) 'shr)
        ((executable-find "w3m") 'gnus-w3m)
        ((executable-find "links") 'links)
-       ((executable-find "lynx") 'lynx)
-       ((locate-library "html2text") 'html2text))
+        ((executable-find "lynx") 'lynx)
+        (t 'shr))
   "Render of HTML contents.
 It is one of defined renderer types, or a rendering function.
 The defined renderer types are:
@@ -127,16 +127,14 @@ The defined renderer types are:
 `w3m': use emacs-w3m;
 `w3m-standalone': use plain w3m;
 `links': use links;
-`lynx': use lynx;
-`html2text': use html2text."
-  :version "27.1"
+`lynx': use lynx."
+  :version "29.1"
   :type '(choice (const shr)
                  (const gnus-w3m)
                  (const w3m :tag "emacs-w3m")
                 (const w3m-standalone :tag "standalone w3m" )
                 (const links)
                 (const lynx)
-                (const html2text)
                 (function))
   :group 'mime-display)
 
@@ -193,7 +191,11 @@ before the external MIME handler is invoked."
   `(("image/p?jpeg"
      mm-inline-image
      ,(lambda (handle)
-       (mm-valid-and-fit-image-p 'jpeg handle)))
+        (mm-valid-and-fit-image-p 'jpeg handle)))
+    ("image/webp"
+     mm-inline-image
+     ,(lambda (handle)
+       (mm-valid-and-fit-image-p 'webp handle)))
     ("image/png"
      mm-inline-image
      ,(lambda (handle)
diff --git a/lisp/gnus/mm-util.el b/lisp/gnus/mm-util.el
index 727e3abfff..48cca45cb9 100644
--- a/lisp/gnus/mm-util.el
+++ b/lisp/gnus/mm-util.el
@@ -673,7 +673,6 @@ If INHIBIT is non-nil, inhibit 
`mm-inhibit-file-name-handlers'."
           inhibit-file-name-handlers)))
     (write-region start end filename append visit lockname)))
 
-(defalias 'mm-make-temp-file 'make-temp-file)
 (define-obsolete-function-alias 'mm-make-temp-file 'make-temp-file "26.1")
 
 (defvar mm-image-load-path-cache nil)
diff --git a/lisp/gnus/mm-view.el b/lisp/gnus/mm-view.el
index 57ce36a944..5cfde5a864 100644
--- a/lisp/gnus/mm-view.el
+++ b/lisp/gnus/mm-view.el
@@ -86,7 +86,7 @@ This is only used if `mm-inline-large-images' is set to
 (defun mm-inline-image (handle)
   (let ((b (point-marker))
        (inhibit-read-only t))
-    (put-image
+    (insert-image
      (let ((image (mm-get-image handle)))
        (if (eq mm-inline-large-images 'resize)
            (gnus-rescale-image
@@ -98,7 +98,7 @@ This is only used if `mm-inline-large-images' is set to
                    (truncate (* mm-inline-large-images-proportion
                                 (- (nth 3 edges) (nth 1 edges)))))))
          image))
-     b)
+     " ")
     (insert "\n")
     (mm-handle-set-undisplayer
      handle
diff --git a/lisp/gnus/mml.el b/lisp/gnus/mml.el
index 093e582ea7..e8291cfe6f 100644
--- a/lisp/gnus/mml.el
+++ b/lisp/gnus/mml.el
@@ -35,7 +35,6 @@
 (declare-function gnus-setup-posting-charset "gnus-msg" (group))
 (autoload 'gnus-completing-read "gnus-util")
 (autoload 'message-fetch-field "message")
-(autoload 'message-mark-active-p "message")
 (autoload 'message-info "message")
 (autoload 'fill-flowed-encode "flow-fill")
 (autoload 'message-posting-charset "message")
@@ -980,13 +979,10 @@ type detected."
          (symbol-name type) value))))))
 
 (defvar ange-ftp-name-format)
-(defvar efs-path-regexp)
 
 (defun mml-parse-file-name (path)
-  (if (if (boundp 'efs-path-regexp)
-         (string-match efs-path-regexp path)
-       (if (boundp 'ange-ftp-name-format)
-           (string-match (car ange-ftp-name-format) path)))
+  (if (and (boundp 'ange-ftp-name-format)
+           (string-match (car ange-ftp-name-format) path))
       (list (match-string 1 path) (match-string 2 path)
            (substring path (1+ (match-end 2))))
     path))
@@ -1239,7 +1235,7 @@ If HANDLES is non-nil, use it instead reparsing the 
buffer."
     ;;
     ;;["Narrow" mml-narrow-to-part t]
     ["Quote MML in region" mml-quote-region
-     :active (message-mark-active-p)
+     :active mark-active
      :help "Quote MML tags in region"]
     ["Validate MML" mml-validate t]
     ["Preview" mml-preview t]
@@ -1517,7 +1513,7 @@ BUFFER is the name of the buffer to attach.  See
 
 (defun mml-attach-external (file &optional type description)
   "Attach an external file into the buffer.
-FILE is an ange-ftp/efs specification of the part location.
+FILE is an ange-ftp specification of the part location.
 TYPE is the MIME type to use."
   (interactive
    (let* ((file (mml-minibuffer-read-file "Attach external file: "))
diff --git a/lisp/gnus/mml2015.el b/lisp/gnus/mml2015.el
index a373b7999e..bf9e975f74 100644
--- a/lisp/gnus/mml2015.el
+++ b/lisp/gnus/mml2015.el
@@ -45,7 +45,7 @@
 ;; could be removed.
 (defvar mml2015-use 'epg
   "The package used for PGP/MIME.
-Valid packages include `epg', `pgg' and `mailcrypt'.")
+Valid packages include `epg', and `mailcrypt'.")
 
 ;; Something is not RFC2015.
 (defvar mml2015-function-alist
diff --git a/lisp/gnus/nnagent.el b/lisp/gnus/nnagent.el
index 60140a4641..d7e32e4580 100644
--- a/lisp/gnus/nnagent.el
+++ b/lisp/gnus/nnagent.el
@@ -35,6 +35,7 @@
 
 
 (defconst nnagent-version "nnagent 1.0")
+(make-obsolete-variable 'nnagent-version 'emacs-version "29.1")
 
 (defvoo nnagent-directory nil
   "Internal variable."
diff --git a/lisp/gnus/nnbabyl.el b/lisp/gnus/nnbabyl.el
index ff0dea8ecd..1a699d0e70 100644
--- a/lisp/gnus/nnbabyl.el
+++ b/lisp/gnus/nnbabyl.el
@@ -55,6 +55,7 @@
 
 (defconst nnbabyl-version "nnbabyl 1.0"
   "nnbabyl version.")
+(make-obsolete-variable 'nnbabyl-version 'emacs-version "29.1")
 
 (defvoo nnbabyl-mbox-buffer nil)
 (defvoo nnbabyl-current-group nil)
@@ -306,7 +307,7 @@
        (while (re-search-forward
               "^X-Gnus-Newsgroup:"
               (save-excursion (search-forward "\n\n" nil t) (point)) t)
-        (delete-region (point-at-bol) (progn (forward-line 1) (point))))
+         (delete-region (line-beginning-position) (progn (forward-line 1) 
(point))))
        (setq result (eval accept-form t))
        (kill-buffer (current-buffer))
        result)
@@ -423,7 +424,7 @@
 (defun nnbabyl-delete-mail (&optional force leave-delim)
   ;; Delete the current X-Gnus-Newsgroup line.
   (unless force
-    (delete-region (point-at-bol) (progn (forward-line 1) (point))))
+    (delete-region (line-beginning-position) (progn (forward-line 1) (point))))
   ;; Beginning of the article.
   (save-excursion
     (save-restriction
@@ -629,7 +630,8 @@
       (while (re-search-forward "^X-Gnus-Newsgroup: \\([^ ]+\\) "  nil t)
        (if (gethash (setq id (match-string 1)) idents)
            (progn
-             (delete-region (point-at-bol) (progn (forward-line 1) (point)))
+              (delete-region (line-beginning-position)
+                             (progn (forward-line 1) (point)))
              (nnheader-message 7 "Moving %s..." id)
              (nnbabyl-save-mail
               (nnmail-article-group 'nnbabyl-active-number)))
diff --git a/lisp/gnus/nndiary.el b/lisp/gnus/nndiary.el
index bd60c43f59..27204b3618 100644
--- a/lisp/gnus/nndiary.el
+++ b/lisp/gnus/nndiary.el
@@ -234,9 +234,11 @@ all.  This may very well take some time.")
 
 (defconst nndiary-version "0.2-b14"
   "Current Diary back end version.")
+(make-obsolete-variable 'nndiary-version 'emacs-version "29.1")
 
 (defun nndiary-version ()
   "Current Diary back end version."
+  (declare (obsolete emacs-version "29.1"))
   (interactive)
   (message "NNDiary version %s" nndiary-version))
 
@@ -860,7 +862,7 @@ all.  This may very well take some time.")
                  (search-forward id nil t)) ; We find the ID.
        ;; And the id is in the fourth field.
        (if (not (and (search-backward "\t" nil t 4)
-                     (not (search-backward"\t" (point-at-bol) t))))
+                      (not (search-backward"\t" (line-beginning-position) t))))
            (forward-line 1)
          (beginning-of-line)
          (setq found t)
diff --git a/lisp/gnus/nndir.el b/lisp/gnus/nndir.el
index 2ca25534ce..75a6ace107 100644
--- a/lisp/gnus/nndir.el
+++ b/lisp/gnus/nndir.el
@@ -48,6 +48,7 @@
 
 (defvoo nndir-status-string "" nil nnmh-status-string)
 (defconst nndir-version "nndir 1.0")
+(make-obsolete-variable 'nndir-version 'emacs-version "29.1")
 
 
 
diff --git a/lisp/gnus/nndoc.el b/lisp/gnus/nndoc.el
index 19ccce47b5..cdff7c9acc 100644
--- a/lisp/gnus/nndoc.el
+++ b/lisp/gnus/nndoc.el
@@ -218,6 +218,7 @@ from the document.")
 
 (defconst nndoc-version "nndoc 1.0"
   "nndoc version.")
+(make-obsolete-variable 'nndoc-version 'emacs-version "29.1")
 
 
 
diff --git a/lisp/gnus/nndraft.el b/lisp/gnus/nndraft.el
index fa88b8a87e..f21e4faf55 100644
--- a/lisp/gnus/nndraft.el
+++ b/lisp/gnus/nndraft.el
@@ -56,6 +56,7 @@ are generated if and only if they are also in 
`message-draft-headers'."
 (defvoo nndraft-current-directory nil nil nnmh-current-directory)
 
 (defconst nndraft-version "nndraft 1.0")
+(make-obsolete-variable 'nndraft-version 'emacs-version "29.1")
 (defvoo nndraft-status-string "" nil nnmh-status-string)
 
 
diff --git a/lisp/gnus/nneething.el b/lisp/gnus/nneething.el
index 829d912cb2..ff72842a2e 100644
--- a/lisp/gnus/nneething.el
+++ b/lisp/gnus/nneething.el
@@ -57,6 +57,7 @@ included.")
 
 (defconst nneething-version "nneething 1.0"
   "nneething version.")
+(make-obsolete-variable 'nneething-version 'emacs-version "29.1")
 
 (defvoo nneething-current-directory nil
   "Current news group directory.")
@@ -245,7 +246,8 @@ included.")
        (while map
          (if (and (member (cadr (car map)) files)
                  ;; We also remove files that have changed mod times.
-                  (equal (file-attribute-modification-time (file-attributes
+                  (time-equal-p
+                         (file-attribute-modification-time (file-attributes
                                  (nneething-file-name (cadr (car map)))))
                          (cadr (cdar map))))
              (progn
diff --git a/lisp/gnus/nnfolder.el b/lisp/gnus/nnfolder.el
index 5dc8e5c30d..c47a398c4c 100644
--- a/lisp/gnus/nnfolder.el
+++ b/lisp/gnus/nnfolder.el
@@ -91,6 +91,7 @@ message, a huge time saver for large mailboxes.")
 
 (defconst nnfolder-version "nnfolder 2.0"
   "nnfolder version.")
+(make-obsolete-variable 'nnfolder-version 'emacs-version "29.1")
 
 (defconst nnfolder-article-marker "X-Gnus-Article-Number: "
   "String used to demarcate what the article number for a message is.")
@@ -178,7 +179,7 @@ all.  This may very well take some time.")
                        (goto-char (match-end 0))
                        (setq num (string-to-number
                                   (buffer-substring
-                                   (point) (point-at-eol))))
+                                    (point) (line-end-position))))
                        (goto-char start)
                        (< num article)))
                      ;; Check that we are before an article with a
@@ -188,7 +189,7 @@ all.  This may very well take some time.")
                      (progn
                        (setq num (string-to-number
                                   (buffer-substring
-                                   (point) (point-at-eol))))
+                                    (point) (line-end-position))))
                        (> num article))
                      ;; Discard any article numbers before the one we're
                      ;; now looking at.
@@ -258,7 +259,7 @@ all.  This may very well take some time.")
                  (if (search-forward (concat "\n" nnfolder-article-marker)
                                      nil t)
                      (string-to-number (buffer-substring
-                                     (point) (point-at-eol)))
+                                         (point) (line-end-position)))
                    -1))))))))
 
 (deffoo nnfolder-request-group (group &optional server dont-check _info)
@@ -860,7 +861,8 @@ deleted.  Point is left where the deleted region was."
                    (nnheader-find-file-noselect file t)))))
     (mm-enable-multibyte) ;; Use multibyte buffer for future copying.
     (buffer-disable-undo)
-    (if (equal (cadr (assoc group nnfolder-scantime-alist))
+    (if (time-equal-p
+              (cadr (assoc group nnfolder-scantime-alist))
               (file-attribute-modification-time (file-attributes file)))
        ;; This looks up-to-date, so we don't do any scanning.
        (if (file-exists-p file)
diff --git a/lisp/gnus/nnheader.el b/lisp/gnus/nnheader.el
index c1c5f00ff7..b91798b8a0 100644
--- a/lisp/gnus/nnheader.el
+++ b/lisp/gnus/nnheader.el
@@ -188,7 +188,7 @@ on your system, you could say something like:
 
 (defsubst nnheader-header-value ()
   (skip-chars-forward " \t")
-  (buffer-substring (point) (point-at-eol)))
+  (buffer-substring (point) (line-end-position)))
 
 (autoload 'ietf-drums-unfold-fws "ietf-drums")
 
@@ -397,7 +397,7 @@ leaving the original buffer untouched."
 (autoload 'gnus-extract-message-id-from-in-reply-to "gnus-sum")
 
 (defun nnheader-parse-nov (&optional number)
-  (let ((eol (point-at-eol))
+  (let ((eol (line-end-position))
        references in-reply-to x header)
       (setq header
            (make-full-mail-header
@@ -632,7 +632,7 @@ the line could be found."
       ;; This is invalid, but not all articles have Message-IDs.
       ()
     (mail-position-on-field "References")
-    (let ((begin (point-at-bol))
+    (let ((begin (line-beginning-position))
          (fill-column 78)
          (fill-prefix "\t"))
       (when references
@@ -918,15 +918,11 @@ first.  Otherwise, find the newest one, though it may 
take a time."
       (car (sort results #'file-newer-than-file-p)))))
 
 (defvar ange-ftp-path-format)
-(defvar efs-path-regexp)
 (defun nnheader-re-read-dir (path)
   "Re-read directory PATH if PATH is on a remote system."
-  (if (and (fboundp 'efs-re-read-dir) (boundp 'efs-path-regexp))
-      (when (string-match efs-path-regexp path)
-       (efs-re-read-dir path))
-    (when (and (fboundp 'ange-ftp-re-read-dir) (boundp 'ange-ftp-path-format))
-      (when (string-match (car ange-ftp-path-format) path)
-       (ange-ftp-re-read-dir path)))))
+  (when (and (fboundp 'ange-ftp-reread-dir) (boundp 'ange-ftp-path-format))
+    (when (string-match (car ange-ftp-path-format) path)
+      (ange-ftp-reread-dir path))))
 
 (defun nnheader-insert-file-contents (filename &optional visit beg end replace)
   "Like `insert-file-contents', q.v., but only reads in the file.
@@ -1059,7 +1055,7 @@ See `find-file-noselect' for the arguments."
                                     (or ,end (point-max)))
                '(buffer-string)))))
 
-(defvar nnheader-last-message-time '(0 0))
+(defvar nnheader-last-message-time 0)
 (defun nnheader-message-maybe (&rest args)
   (let ((now (current-time)))
     (when (time-less-p 1 (time-subtract now nnheader-last-message-time))
diff --git a/lisp/gnus/nnimap.el b/lisp/gnus/nnimap.el
index afd5418912..73cd183a02 100644
--- a/lisp/gnus/nnimap.el
+++ b/lisp/gnus/nnimap.el
@@ -34,7 +34,6 @@
 (require 'gnus-util)
 (require 'gnus)
 (require 'nnoo)
-(require 'netrc)
 (require 'utf7)
 (require 'nnmail)
 
@@ -95,9 +94,6 @@ Uses the same syntax as `nnmail-split-methods'.")
 (defvoo nnimap-unsplittable-articles '(%Deleted %Seen)
   "Articles with the flags in the list will not be considered when splitting.")
 
-(make-obsolete-variable 'nnimap-split-rule "see `nnimap-split-methods'."
-                        "24.1")
-
 (defvoo nnimap-authenticator nil
   "How nnimap authenticate itself to the server.
 Possible choices are nil (use default methods), `anonymous',
@@ -233,18 +229,28 @@ during splitting, which may be slow."
          params)
     (format "%s" (nreverse params))))
 
+(defvar nnimap--max-retrieve-headers 200)
+
 (deffoo nnimap-retrieve-headers (articles &optional group server _fetch-old)
   (with-current-buffer nntp-server-buffer
     (erase-buffer)
     (when (nnimap-change-group group server)
       (with-current-buffer (nnimap-buffer)
        (erase-buffer)
-       (nnimap-wait-for-response
-        (nnimap-send-command
-         "UID FETCH %s %s"
-         (nnimap-article-ranges (gnus-compress-sequence articles))
-         (nnimap-header-parameters))
-        t)
+        ;; If we have a lot of ranges, split them up to avoid
+        ;; generating too-long lines.  (The limit is 8192 octects,
+        ;; and this should guarantee that it's (much) shorter than
+        ;; that.)  We don't stream the requests, since the server
+        ;; may respond to the requests out-of-order:
+        ;; https://datatracker.ietf.org/doc/html/rfc3501#section-5.5
+        (dolist (ranges (seq-split (gnus-compress-sequence articles t)
+                                   nnimap--max-retrieve-headers))
+          (nnimap-wait-for-response
+          (nnimap-send-command
+           "UID FETCH %s %s"
+           (nnimap-article-ranges ranges)
+           (nnimap-header-parameters))
+           t))
        (unless (process-live-p (get-buffer-process (current-buffer)))
          (error "IMAP server %S closed connection" nnimap-address))
        (nnimap-transform-headers)
@@ -549,7 +555,7 @@ during splitting, which may be slow."
                                ;; Look for the credentials based on
                                ;; the virtual server name and the address
                                (nnimap-credentials
-                               (gnus-delete-duplicates
+                                (seq-uniq
                                 (list server nnimap-address))
                                 ports
                                 nnimap-user))))
diff --git a/lisp/gnus/nnmail.el b/lisp/gnus/nnmail.el
index bde0de9892..afa14448fc 100644
--- a/lisp/gnus/nnmail.el
+++ b/lisp/gnus/nnmail.el
@@ -661,7 +661,7 @@ nn*-request-list should have been called before calling 
this function."
     (while (not (eobp))
       (condition-case nil
          (progn
-           (narrow-to-region (point) (point-at-eol))
+            (narrow-to-region (point) (line-end-position))
            (setq group (read buffer)
                  group
                  (cond ((symbolp group)
@@ -1116,7 +1116,7 @@ FUNC will be called with the group name to determine the 
article number."
        (while (not (eobp))
          (unless (< (move-to-column nnmail-split-header-length-limit)
                     nnmail-split-header-length-limit)
-           (delete-region (point) (point-at-eol)))
+            (delete-region (point) (line-end-position)))
          (forward-line 1))
        ;; Allow washing.
        (goto-char (point-min))
@@ -1650,7 +1650,7 @@ See the documentation for the variable 
`nnmail-split-fancy' for details."
        (skip-chars-forward "^\n\r\t")
        (unless (looking-at "[\r\n]")
          (forward-char 1)
-         (buffer-substring (point) (point-at-eol)))))))
+          (buffer-substring (point) (line-end-position)))))))
 
 ;; Function for nnmail-split-fancy: look up all references in the
 ;; cache and if a match is found, return that group.
diff --git a/lisp/gnus/nnmaildir.el b/lisp/gnus/nnmaildir.el
index 30f473b129..4d1ecbf864 100644
--- a/lisp/gnus/nnmaildir.el
+++ b/lisp/gnus/nnmaildir.el
@@ -62,6 +62,7 @@
   (require 'subr-x))
 
 (defconst nnmaildir-version "Gnus")
+(make-obsolete-variable 'nnmaildir-version 'emacs-version "29.1")
 
 (defconst nnmaildir-flag-mark-mapping
   '((?F . tick)
@@ -99,7 +100,7 @@ SUFFIX should start with \":2,\"."
   (let* ((flags (substring suffix 3))
         (flags-as-list (append flags nil))
         (new-flags
-         (concat (gnus-delete-duplicates
+          (concat (seq-uniq
                   ;; maildir flags must be sorted
                   (sort (cons flag flags-as-list) #'<)))))
     (concat ":2," new-flags)))
@@ -463,7 +464,7 @@ This variable is set by `nnmaildir-request-article'.")
        ;; usable: if the message has been edited or if nnmail-extra-headers
        ;; has been augmented since this data was parsed from the message,
        ;; then we have to reparse.  Otherwise it's up-to-date.
-       (when (and nov (equal mtime (nnmaildir--nov-get-mtime nov)))
+       (when (and nov (time-equal-p mtime (nnmaildir--nov-get-mtime nov)))
          ;; The timestamp matches.  Now check nnmail-extra-headers.
          (setq old-extra (nnmaildir--nov-get-extra nov))
          (when (equal nnmaildir--extra old-extra) ;; common case
@@ -799,7 +800,7 @@ This variable is set by `nnmaildir-request-article'.")
          isnew
          (throw 'return t))
       (setq nattr (file-attribute-modification-time nattr))
-      (if (equal nattr (nnmaildir--grp-new group))
+      (if (time-equal-p nattr (nnmaildir--grp-new group))
          (setq nattr nil))
       (if read-only (setq dir (and (or isnew nattr) ndir))
        (when (or isnew nattr)
@@ -811,7 +812,7 @@ This variable is set by `nnmaildir-request-article'.")
                 (rename-file x (concat cdir (nnmaildir--ensure-suffix file)))))
          (setf (nnmaildir--grp-new group) nattr))
        (setq cattr (file-attribute-modification-time (file-attributes cdir)))
-       (if (equal cattr (nnmaildir--grp-cur group))
+       (if (time-equal-p cattr (nnmaildir--grp-cur group))
            (setq cattr nil))
        (setq dir (and (or isnew cattr) cdir)))
       (unless dir (throw 'return t))
@@ -899,7 +900,7 @@ This variable is set by `nnmaildir-request-article'.")
             (remhash scan-group groups))
         (setq x (file-attribute-modification-time (file-attributes srv-dir))
               scan-group (null scan-group))
-        (if (equal x (nnmaildir--srv-mtime nnmaildir--cur-server))
+        (if (time-equal-p x (nnmaildir--srv-mtime nnmaildir--cur-server))
             (when scan-group
               (maphash (lambda (group-name _group)
                          (nnmaildir--scan group-name t groups
@@ -1015,7 +1016,7 @@ This variable is set by `nnmaildir-request-article'.")
            dir (nnmaildir--nndir dir)
            dir (nnmaildir--marks-dir dir)
             ls (nnmaildir--group-ls nnmaildir--cur-server pgname)
-           all-marks (gnus-delete-duplicates
+            all-marks (seq-uniq
                       ;; get mark names from mark dirs and from flag
                       ;; mappings
                       (append
@@ -1049,7 +1050,7 @@ This variable is set by `nnmaildir-request-article'.")
                   (t
                    markdir-mtime))))
          (puthash mark mtime new-mmth)
-         (when (equal mtime (gethash mark old-mmth))
+         (when (time-equal-p mtime (gethash mark old-mmth))
            (setq ranges (assq mark old-marks))
            (if ranges (setq ranges (cdr ranges)))
            (throw 'got-ranges nil))
@@ -1697,7 +1698,7 @@ This variable is set by `nnmaildir-request-article'.")
             pgname (nnmaildir--pgname nnmaildir--cur-server gname)
             ls (nnmaildir--group-ls nnmaildir--cur-server pgname)
            all-marks (funcall ls marksdir nil "\\`[^.]" 'nosort)
-           all-marks (gnus-delete-duplicates
+            all-marks (seq-uniq
                       ;; get mark names from mark dirs and from flag
                       ;; mappings
                       (append
@@ -1785,9 +1786,4 @@ This variable is set by `nnmaildir-request-article'.")
 
 (provide 'nnmaildir)
 
-;; Local Variables:
-;; indent-tabs-mode: t
-;; fill-column: 77
-;; End:
-
 ;;; nnmaildir.el ends here
diff --git a/lisp/gnus/nnmairix.el b/lisp/gnus/nnmairix.el
index 8c811b0c6c..b1eee2d530 100644
--- a/lisp/gnus/nnmairix.el
+++ b/lisp/gnus/nnmairix.el
@@ -574,7 +574,7 @@ Other back ends might or might not work.")
                              (gnus-group-get-parameter qualgroup 'folder)))
                (progn
                  (replace-match cur)
-                 (delete-region cpoint (point-at-bol))
+                  (delete-region cpoint (line-beginning-position))
                  (forward-line)
                  (setq cpoint (point)))
              (forward-line)))
diff --git a/lisp/gnus/nnmbox.el b/lisp/gnus/nnmbox.el
index 96ecc34e15..5735c97805 100644
--- a/lisp/gnus/nnmbox.el
+++ b/lisp/gnus/nnmbox.el
@@ -52,6 +52,7 @@
 
 (defconst nnmbox-version "nnmbox 1.0"
   "nnmbox version.")
+(make-obsolete-variable 'nnmbox-version 'emacs-version "29.1")
 
 (defvoo nnmbox-current-group nil
   "Current nnmbox news group directory.")
diff --git a/lisp/gnus/nnmh.el b/lisp/gnus/nnmh.el
index 5d016267bc..bced527d03 100644
--- a/lisp/gnus/nnmh.el
+++ b/lisp/gnus/nnmh.el
@@ -55,6 +55,7 @@ as unread by Gnus.")
 
 (defconst nnmh-version "nnmh 1.0"
   "nnmh version.")
+(make-obsolete-variable 'nnmh-version 'emacs-version "29.1")
 
 (defvoo nnmh-current-directory nil
   "Current news group directory.")
@@ -539,7 +540,7 @@ as unread by Gnus.")
     (let ((arts articles)
          art)
       (while (setq art (pop arts))
-       (when (not (equal
+       (when (not (time-equal-p
                    (file-attribute-modification-time
                     (file-attributes (concat dir (int-to-string (car art)))))
                    (cdr art)))
@@ -547,14 +548,17 @@ as unread by Gnus.")
          (push (car art) new))))
     ;; Go through all the new articles and add them, and their
     ;; time-stamps, to the list.
+    ;; Use list format for timestamps, so Emacs <27 can read .nnmh-articles.
     (setq articles
          (nconc articles
                 (mapcar
                  (lambda (art)
                    (cons art
-                         (file-attribute-modification-time
-                          (file-attributes
-                           (concat dir (int-to-string art))))))
+                         (when-let ((modtime
+                                     (file-attribute-modification-time
+                                      (file-attributes
+                                       (concat dir (int-to-string art))))))
+                           (time-convert modtime 'list))))
                  new)))
     ;; Make Gnus mark all new articles as unread.
     (when new
diff --git a/lisp/gnus/nnml.el b/lisp/gnus/nnml.el
index 7fe2b516cc..40e4b9ea82 100644
--- a/lisp/gnus/nnml.el
+++ b/lisp/gnus/nnml.el
@@ -89,6 +89,7 @@ non-nil.")
 
 (defconst nnml-version "nnml 1.0"
   "nnml version.")
+(make-obsolete-variable 'nnml-version 'emacs-version "29.1")
 
 (defvoo nnml-nov-file-name ".overview")
 
@@ -600,7 +601,7 @@ non-nil.")
                  (search-forward id nil t)) ; We find the ID.
        ;; And the id is in the fourth field.
        (if (not (and (search-backward "\t" nil t 4)
-                     (not (search-backward "\t" (point-at-bol) t))))
+                      (not (search-backward "\t" (line-beginning-position) 
t))))
            (forward-line 1)
          (beginning-of-line)
          (setq found t)
@@ -754,7 +755,7 @@ article number.  This function is called narrowed to an 
article."
     (nnheader-insert-nov headers)))
 
 (defsubst nnml-header-value ()
-  (buffer-substring (match-end 0) (point-at-eol)))
+  (buffer-substring (match-end 0) (line-end-position)))
 
 (defun nnml-parse-head (chars &optional number)
   "Parse the head of the current buffer."
@@ -1060,7 +1061,7 @@ Use the nov database for the current group if available."
                                        (regexp-quote
                                         (concat group ":" old-number-string))
                                        "\\>")
-                               (point-at-eol) t))
+                                (line-end-position) t))
                      (replace-match
                       (concat group ":" new-number-string)))
                    ;; Save to the new file:
@@ -1108,7 +1109,7 @@ Use the nov database for the current group if available."
                                     (regexp-quote
                                      (concat group ":" old-number-string))
                                     "\\>")
-                            (point-at-eol) t)
+                             (line-end-position) t)
                        (replace-match
                         (concat "\\1" group ":" new-number-string))))))
                ;; 4/ Possibly remove the article from the backlog:
diff --git a/lisp/gnus/nnrss.el b/lisp/gnus/nnrss.el
index f740af3b6d..99e7b2a6f3 100644
--- a/lisp/gnus/nnrss.el
+++ b/lisp/gnus/nnrss.el
@@ -71,6 +71,7 @@ this variable to the list of fields to be ignored.")
 (defvoo nnrss-status-string "")
 
 (defconst nnrss-version "nnrss 1.0")
+(make-obsolete-variable 'nnrss-version 'emacs-version "29.1")
 
 (defvar nnrss-group-alist '()
   "List of RSS addresses.")
@@ -325,7 +326,7 @@ for decoding when the cdr that the data specify is not 
available.")
               (nnmail-expired-article-p
                group
                (if (listp (setq days (nth 1 e))) days
-                 (days-to-time (- days (time-to-days '(0 0)))))
+                 (days-to-time (- days (time-to-days 0))))
                force))
          (setq nnrss-group-data (delq e nnrss-group-data)
                changed t)
@@ -453,8 +454,8 @@ which RSS 2.0 allows."
   (let (case-fold-search vector year month day time zone given)
     (cond ((null date))                        ; do nothing for this case
          ;; if the date is just digits (unix time stamp):
-         ((string-match "^[0-9]+$" date)
-          (setq given (time-convert (string-to-number date))))
+         ((string-match "\\`[0-9]+\\'" date)
+          (setq given (time-convert (string-to-number date) t)))
          ;; RFC 822
          ((string-match " [0-9]+ " date)
           (setq vector (timezone-parse-date date)
diff --git a/lisp/gnus/nnspool.el b/lisp/gnus/nnspool.el
index 39b89abb88..e5eb4b8160 100644
--- a/lisp/gnus/nnspool.el
+++ b/lisp/gnus/nnspool.el
@@ -114,6 +114,7 @@ there.")
 
 (defconst nnspool-version "nnspool 2.0"
   "Version numbers of this version of NNSPOOL.")
+(make-obsolete-variable 'nnspool-version 'emacs-version "29.1")
 
 (defvoo nnspool-current-directory nil
   "Current news group directory.")
diff --git a/lisp/gnus/nntp.el b/lisp/gnus/nntp.el
index f047c83293..6dea405d02 100644
--- a/lisp/gnus/nntp.el
+++ b/lisp/gnus/nntp.el
@@ -217,25 +217,6 @@ then use this hook to rsh to the remote machine and start 
a proxy NNTP
 server there that you can connect to.  See also
 `nntp-open-connection-function'")
 
-(defcustom nntp-authinfo-file "~/.authinfo"
-  ".netrc-like file that holds nntp authinfo passwords."
-  :type
-  '(choice file
-          (repeat :tag "Entries"
-                  :menu-tag "Inline"
-                  (list :format "%v"
-                        :value ("" ("login" . "") ("password" . ""))
-                        (string :tag "Host")
-                        (checklist :inline t
-                                   (cons :format "%v"
-                                         (const :format "" "login")
-                                         (string :format "Login: %v"))
-                                   (cons :format "%v"
-                                         (const :format "" "password")
-                                         (string :format "Password: %v")))))))
-
-(make-obsolete 'nntp-authinfo-file nil "24.1")
-
 
 
 (defvoo nntp-connection-timeout nil
@@ -278,6 +259,7 @@ update their active files often, this can help.")
 (defvoo nntp-connection-alist nil)
 (defvoo nntp-status-string "")
 (defconst nntp-version "nntp 5.0")
+(make-obsolete-variable 'nntp-version 'emacs-version "29.1")
 (defvoo nntp-inhibit-erase nil)
 (defvoo nntp-inhibit-output nil)
 
@@ -498,7 +480,7 @@ retried once before actually displaying the error report."
              (goto-char pos)
              (if (looking-at (regexp-quote command))
                  (delete-region pos (progn (forward-line 1)
-                                           (point-at-bol)))))))
+                                            (line-beginning-position)))))))
       (nnheader-report 'nntp "Couldn't open connection to %s."
                       nntp-address))))
 
@@ -521,7 +503,7 @@ retried once before actually displaying the error report."
              (goto-char pos)
              (if (looking-at (regexp-quote command))
                  (delete-region pos (progn (forward-line 1)
-                                           (point-at-bol)))))))
+                                            (line-beginning-position)))))))
       (nnheader-report 'nntp "Couldn't open connection to %s."
                       nntp-address))))
 
@@ -546,7 +528,8 @@ retried once before actually displaying the error report."
            (with-current-buffer buffer
              (goto-char pos)
              (if (looking-at (regexp-quote command))
-                 (delete-region pos (progn (forward-line 1) (point-at-bol))))
+                  (delete-region pos (progn (forward-line 1)
+                                            (line-beginning-position))))
              )))
       (nnheader-report 'nntp "Couldn't open connection to %s."
                       nntp-address))))
@@ -1152,11 +1135,6 @@ It will make innd servers spawn an nnrpd process to 
allow actual article
 reading."
   (nntp-send-command "^.*\n" "MODE READER"))
 
-(declare-function netrc-parse "netrc" (&optional file))
-(declare-function netrc-machine "netrc"
-                 (list machine &optional port defaultport))
-(declare-function netrc-get "netrc" (alist type))
-
 (defun nntp-send-authinfo (&optional send-if-force)
   "Send the AUTHINFO to the nntp server.
 It will look in the \"~/.authinfo\" file for matching entries.  If
@@ -1165,30 +1143,16 @@ and a password.
 
 If SEND-IF-FORCE, only send authinfo to the server if the
 .authinfo file has the FORCE token."
-  (require 'netrc)
-  (let* ((list (netrc-parse nntp-authinfo-file))
-        (alist (netrc-machine list nntp-address "nntp"))
-         (auth-info
+  (let* ((auth-info
           (nth 0 (auth-source-search
                  :max 1
                  :host (list nntp-address (nnoo-current-server 'nntp))
                  :port `("119" "nntp" ,(format "%s" nntp-port-number)
                          "563" "nntps" "snews"))))
          (auth-user (plist-get auth-info :user))
-         (auth-force (plist-get auth-info :force))
-         (auth-passwd (auth-info-password auth-info))
-        (force (or (netrc-get alist "force")
-                    nntp-authinfo-force
-                    auth-force))
-        (user (or
-               ;; this is preferred to netrc-*
-               auth-user
-               (netrc-get alist "login")
-               nntp-authinfo-user))
-        (passwd (or
-                 ;; this is preferred to netrc-*
-                 auth-passwd
-                 (netrc-get alist "password"))))
+         (passwd (auth-info-password auth-info))
+        (force (or nntp-authinfo-force (plist-get auth-info :force)))
+        (user (or auth-user nntp-authinfo-user)))
     (when (or (not send-if-force)
              force)
       (unless user
diff --git a/lisp/gnus/nnvirtual.el b/lisp/gnus/nnvirtual.el
index ae4265de7f..e150cbf2b4 100644
--- a/lisp/gnus/nnvirtual.el
+++ b/lisp/gnus/nnvirtual.el
@@ -57,6 +57,7 @@ component group will show up when you enter the virtual 
group.")
 
 
 (defconst nnvirtual-version "nnvirtual 1.1")
+(make-obsolete-variable 'nnvirtual-version 'emacs-version "29.1")
 
 (defvoo nnvirtual-current-group nil)
 
@@ -386,7 +387,7 @@ lines have the correct component server prefix."
   (looking-at
    "[^\t]*\t[^\t]*\t[^\t]*\t[^\t]*\t[^\t]*\t[^\t]*\t[^\t]*\t")
   (goto-char (match-end 0))
-  (unless (search-forward "\t" (point-at-eol) 'move)
+  (unless (search-forward "\t" (line-end-position) 'move)
     (insert "\t"))
 
   ;; Remove any spaces at the beginning of the Xref field.
@@ -402,8 +403,8 @@ lines have the correct component server prefix."
   ;; component server prefix.
   (save-restriction
     (narrow-to-region (point)
-                     (or (search-forward "\t" (point-at-eol) t)
-                         (point-at-eol)))
+                      (or (search-forward "\t" (line-end-position) t)
+                          (line-end-position)))
     (goto-char (point-min))
     (when (re-search-forward "Xref: *[^\n:0-9 ]+ *" nil t)
       (replace-match "" t t))
diff --git a/lisp/gnus/smime.el b/lisp/gnus/smime.el
index 87b5551d31..fd2791f5c5 100644
--- a/lisp/gnus/smime.el
+++ b/lisp/gnus/smime.el
@@ -519,7 +519,7 @@ A string or a list of strings is returned."
     (goto-char b)
     (let (res)
       (while (< (point) e)
-       (let ((str (buffer-substring (point) (point-at-eol))))
+        (let ((str (buffer-substring (point) (line-end-position))))
          (unless (string= "" str)
            (push str res)))
        (forward-line))
diff --git a/lisp/gnus/spam-report.el b/lisp/gnus/spam-report.el
index 334204768b..014b8254fa 100644
--- a/lisp/gnus/spam-report.el
+++ b/lisp/gnus/spam-report.el
@@ -291,7 +291,7 @@ symbol `ask', query before flushing the queue file."
     (goto-char (point-min))
     (while (and (not (eobp))
                (re-search-forward
-                "http://\\([^/]+\\)\\(/.*\\) *$" (point-at-eol) t))
+                 "http://\\([^/]+\\)\\(/.*\\) *$" (line-end-position) t))
       (let ((spam-report-gmane-wait
             (zerop (% (line-number-at-pos) spam-report-gmane-max-requests))))
        (gnus-message 6 "Reporting %s%s..."
diff --git a/lisp/gnus/spam-stat.el b/lisp/gnus/spam-stat.el
index b0d258d67a..5763ac14bb 100644
--- a/lisp/gnus/spam-stat.el
+++ b/lisp/gnus/spam-stat.el
@@ -189,7 +189,7 @@ When using `spam-stat-process-spam-directory' or
 been touched in this many days will be considered.  Without
 this filter, re-training spam-stat with several thousand messages
 will start to take a very long time."
-  :type 'number)
+  :type 'integer)
 
 (defvar spam-stat-last-saved-at nil
   "Time stamp of last change of spam-stat-file on this run")
@@ -422,7 +422,8 @@ spam-stat (spam-stat-to-hash-table '(" spam-stat-ngood 
spam-stat-nbad))
     (cond (spam-stat-dirty (message "Spam stat not loaded: spam-stat-dirty t"))
           ((or (not (boundp 'spam-stat-last-saved-at))
                (null spam-stat-last-saved-at)
-               (not (equal spam-stat-last-saved-at
+              (not (time-equal-p
+                          spam-stat-last-saved-at
                            (file-attribute-modification-time
                            (file-attributes spam-stat-file)))))
            (progn
diff --git a/lisp/gnus/spam.el b/lisp/gnus/spam.el
index 5af29c0a24..e0d90e5547 100644
--- a/lisp/gnus/spam.el
+++ b/lisp/gnus/spam.el
@@ -43,14 +43,12 @@
 (require 'gnus-uu)                      ; because of key prefix issues
 ;;; for the definitions of group content classification and spam processors
 (require 'gnus)
+(require 'dig)
 
 (eval-when-compile
   (require 'cl-lib)
   (require 'hashcash))
 
-;; autoload query-dig
-(autoload 'query-dig "dig")
-
 ;; autoload spam-report
 (autoload 'spam-report-gmane "spam-report")
 (autoload 'spam-report-gmane-spam "spam-report")
@@ -2008,7 +2006,7 @@ See the Info node `(gnus)Fancy Mail Splitting' for more 
details."
             (unless matches
               (let ((query-string (concat ip "." server)))
                 (if spam-use-dig
-                    (let ((query-result (query-dig query-string)))
+                    (let ((query-result (dig-query query-string)))
                       (when query-result
                         (gnus-message 6 "(DIG): positive blackhole check `%s'"
                                       query-result)
@@ -2134,7 +2132,7 @@ See `spam-ifile-database'."
         ;; check the return now (we're back in the temp buffer)
         (goto-char (point-min))
         (if (not (eobp))
-            (setq category (buffer-substring (point) (point-at-eol))))
+            (setq category (buffer-substring (point) (line-end-position))))
         (when (not (zerop (length category))) ; we need a category here
           (if spam-ifile-all-categories
               (setq return category)
@@ -2323,7 +2321,7 @@ With a non-nil REMOVE, remove the ADDRESSES."
       (with-temp-buffer
         (insert-file-contents file)
         (while (not (eobp))
-          (setq address (buffer-substring (point) (point-at-eol)))
+          (setq address (buffer-substring (point) (line-end-position)))
           (forward-line 1)
           ;; insert the e-mail address if detected, otherwise the raw data
           (unless (zerop (length address))
diff --git a/lisp/help-fns.el b/lisp/help-fns.el
index 61fc8037df..1ccf9bb428 100644
--- a/lisp/help-fns.el
+++ b/lisp/help-fns.el
@@ -135,6 +135,11 @@ with the current prefix.  The files are chosen according to
 
 (defcustom help-enable-variable-value-editing nil
   "If non-nil, allow editing values in *Help* buffers.
+
+To edit the value of a variable, use \\[describe-variable] to
+display a \"*Help*\" buffer, move point after the text
+\"Its value is\" and type \\`e'.
+
 Values that aren't readable by the Emacs Lisp reader can't be
 edited even if this option is enabled."
   :type 'boolean
@@ -261,13 +266,9 @@ handling of autoloaded functions."
              (current-buffer)))
         (help-buffer-under-preparation t))
 
-    (help-setup-xref
-     (list (lambda (function buffer)
-             (let ((describe-function-orig-buffer
-                    (if (buffer-live-p buffer) buffer)))
-               (describe-function function)))
-           function describe-function-orig-buffer)
-     (called-interactively-p 'interactive))
+    (help-setup-xref (list #'describe-function--helper
+                           function describe-function-orig-buffer)
+                     (called-interactively-p 'interactive))
 
     (save-excursion
       (with-help-window (help-buffer)
@@ -617,7 +618,7 @@ the C sources, too."
   (pcase-dolist (`(,type . ,handler)
                  (list (cons "compiler macro"
                              (function-get function 'compiler-macro))
-                       (cons "`byte-compile' property"
+                       (cons (substitute-command-keys "`byte-compile' 
property")
                              (function-get function 'byte-compile))
                        (cons "byte-code optimizer"
                              (function-get function 'byte-optimizer))))
@@ -720,19 +721,22 @@ the C sources, too."
   ;; Ignore lambda constructs, keyboard macros, etc.
   (let* ((obsolete (and (symbolp function)
                        (get function 'byte-obsolete-info)))
-         (use (car obsolete)))
+         (use (car obsolete))
+         (start (point)))
     (when obsolete
-      (insert "  This "
+      (insert "This "
              (if (eq (car-safe (symbol-function function)) 'macro)
                  "macro"
                "function")
              " is obsolete")
       (when (nth 2 obsolete)
         (insert (format " since %s" (nth 2 obsolete))))
-      (insert (cond ((stringp use) (concat ";\n  " use))
-                    (use (format-message ";\n  use `%s' instead." use))
+      (insert (cond ((stringp use) (concat "; " use))
+                    (use (format-message "; use `%s' instead." use))
                     (t "."))
-              "\n"))))
+              "\n")
+      (fill-region-as-paragraph start (point))
+      (ensure-empty-lines))))
 
 (add-hook 'help-fns-describe-function-functions
           #'help-fns--globalized-minor-mode)
@@ -783,15 +787,40 @@ the C sources, too."
              (function-get function 'disabled))
     (insert "  This function is disabled.\n")))
 
+(defun help-fns--first-release-regexp (symbol)
+  (let* ((name (symbol-name symbol))
+         (quoted (regexp-quote name)))
+    ;; We used to use just (concat "\\_<" (regexp-quote name) "\\_>"),
+    ;; which had the advantage of adapting to the various notational
+    ;; conventions we've used over the years in etc/NEWS*, but it was also
+    ;; leading to many false positives.  So we use a more restrictive regexp
+    ;; now (which can still lead to false positives, e.g. because we don't
+    ;; distinguish between occurrences of the same symbol for
+    ;; different purposes, such as function name, var name, face name,
+    ;; property name, ...).
+    (concat
+     ;; The main "canonical" occurrence of symbols is within '...'.
+     "'" quoted "'"
+     ;; Commands can also occur as `M-x blabla'.
+     "\\|M-x[ \t\n]+" quoted "\\_>"
+     ;; Other times we do '<key>' (<cmdname>).
+     "\\|(" quoted ")"
+     ;; Finally other times we just include sample code, which we will
+     ;; only recognize if it's indented by at least 2 spaces and start with
+     ;; an open paren.
+     "\\|^\\(?:  \\|\t\\)[ \t]*(\\(.*[( ']\\)?" quoted "\\_>")
+    ))
+
+
 (defun help-fns--first-release (symbol)
   "Return the likely first release that defined SYMBOL, or nil."
   ;; Code below relies on the etc/NEWS* files.
   ;; FIXME: Maybe we should also use the */ChangeLog* files when available.
   ;; FIXME: Maybe we should also look for announcements of the addition
   ;; of the *packages* in which the function is defined.
-  (let* ((name (symbol-name symbol))
-         (re (concat "\\_<" (regexp-quote name) "\\_>"))
+  (let* ((re (help-fns--first-release-regexp symbol))
          (news (directory-files data-directory t "\\`NEWS\\(\\'\\|\\.\\)"))
+         (case-fold-search nil)
          (place nil)
          (first nil))
     (with-temp-buffer
@@ -808,10 +837,11 @@ the C sources, too."
                 ;; Almost all entries are of the form "* ... in Emacs NN.MM."
                 ;; but there are also a few in the form "* Emacs NN.MM is a bug
                 ;; fix release ...".
-                (if (not (re-search-backward "^\\* .* Emacs \\([0-9.]+[0-9]\\)"
-                                             nil t))
-                    (message "Ref found in non-versioned section in %S"
-                             (file-name-nondirectory f))
+                (if (not (re-search-backward
+                          "^\\* \\(?:.* \\)?Emacs \\([0-9.]+[0-9]\\)"
+                          nil t))
+                    (message "Ref to %S found in non-versioned section in %S"
+                             symbol (file-name-nondirectory f))
                   (let ((version (match-string 1)))
                     (when (or (null first) (version< version first))
                       (setq place (list f pos))
@@ -819,6 +849,48 @@ the C sources, too."
     (when first
       (make-text-button first nil 'type 'help-news 'help-args place))))
 
+;; (defun help-fns--check-first-releases ()
+;;   "Compare the old liberal regexp to the new more restrictive one."
+;;   (interactive)
+;;   (let* ((quoted nil)
+;;          (rx-fun (lambda (orig-fun symbol)
+;;                    (if quoted
+;;                        (funcall orig-fun symbol)
+;;                      (format "\\_<%s\\_>"
+;;                              (regexp-quote (symbol-name symbol))))))
+;;          (count
+;;           (let ((count 0))
+;;             (obarray-map (lambda (sym)
+;;                            (when (or (fboundp sym) (boundp sym))
+;;                              (cl-incf count)))
+;;                          obarray)
+;;             count))
+;;          (p (make-progress-reporter "Check first releases..." 0 count)))
+;;     (with-current-buffer (get-buffer-create "*Check-first-release*")
+;;       (unwind-protect
+;;           (progn
+;;             (advice-add 'help-fns--first-release-regexp :around rx-fun)
+;;             (erase-buffer)
+;;             (setq count 0)
+;;             (obarray-map
+;;              (lambda (sym)
+;;                (when (or (fboundp sym) (boundp sym))
+;;                  (cl-incf count)
+;;                  (progress-reporter-update p count)
+;;                  (let ((vt (progn (setq quoted t)
+;;                                   (help-fns--first-release sym)))
+;;                        (vnil (progn (setq quoted nil)
+;;                                     (help-fns--first-release sym))))
+;;                    (when (and vnil (not (equal vt vnil)))
+;;                      (insert (symbol-name sym)
+;;                              "\nnot-quoted: " (or vnil "nil")
+;;                              "\nquoted:     " (or vt "nil")
+;;                              "\n\n")))))
+;;              obarray)
+;;             (progress-reporter-done p))
+;;         (advice-remove 'help-fns--first-release-regexp rx-fun))
+;;       (display-buffer (current-buffer)))))
+
 (add-hook 'help-fns-describe-function-functions
           #'help-fns--mention-first-release)
 (add-hook 'help-fns-describe-variable-functions
@@ -860,7 +932,7 @@ the C sources, too."
                       (shortdoc-display-group group object
                                               help-window-keep-selected))
             'follow-link t
-            'help-echo (purecopy "mouse-1, RET: show documentation group")))
+            'help-echo "mouse-1, RET: show documentation group"))
          groups)
         (insert (if (= (length groups) 1)
                     " group.\n"
@@ -933,9 +1005,9 @@ Returns a list of the form (REAL-FUNCTION DEF ALIASED 
REAL-DEF)."
                 (help-fns--analyze-function function))
                (file-name (find-lisp-object-file-name
                            function (if aliased 'defun def)))
-               (beg (if (and (or (byte-code-function-p def)
+               (beg (if (and (or (functionp def)
                                  (keymapp def)
-                                 (memq (car-safe def) '(macro lambda closure)))
+                                 (eq (car-safe def) 'macro))
                              (stringp file-name)
                              (help-fns--autoloaded-p function))
                         (concat
@@ -954,7 +1026,7 @@ Returns a list of the form (REAL-FUNCTION DEF ALIASED 
REAL-DEF)."
                 (aliased
                  (format-message "an alias for `%s'" real-def))
                  ((subr-native-elisp-p def)
-                  (concat beg "native compiled Lisp function"))
+                  (concat beg "native-compiled Lisp function"))
                 ((subrp def)
                  (concat beg (if (eq 'unevalled (cdr (subr-arity def)))
                                  "special form"
@@ -968,12 +1040,12 @@ Returns a list of the form (REAL-FUNCTION DEF ALIASED 
REAL-DEF)."
                            (t "Lisp function"))))
                 ((or (eq (car-safe def) 'macro)
                      ;; For advised macros, def is a lambda
-                     ;; expression or a byte-code-function-p, so we
+                     ;; expression or a compiled-function-p, so we
                      ;; need to check macros before functions.
                      (macrop function))
                  (concat beg "Lisp macro"))
                 ((byte-code-function-p def)
-                 (concat beg "compiled Lisp function"))
+                 (concat beg "byte-compiled Lisp function"))
                  ((module-function-p def)
                   (concat beg "module function"))
                 ((eq (car-safe def) 'lambda)
@@ -1039,6 +1111,8 @@ Returns a list of the form (REAL-FUNCTION DEF ALIASED 
REAL-DEF)."
          nil t)
         (ensure-empty-lines))))
 
+  (help-fns--obsolete function)
+
   (pcase-let* ((`(,real-function ,def ,_aliased ,real-def)
                 (help-fns--analyze-function function))
                (doc-raw (condition-case nil
@@ -1077,11 +1151,21 @@ Returns a list of the form (REAL-FUNCTION DEF ALIASED 
REAL-DEF)."
         (set-buffer-file-coding-system 'utf-8)))))
 
 ;; Add defaults to `help-fns-describe-function-functions'.
-(add-hook 'help-fns-describe-function-functions #'help-fns--obsolete)
 (add-hook 'help-fns-describe-function-functions #'help-fns--interactive-only)
 (add-hook 'help-fns-describe-function-functions #'help-fns--parent-mode)
 (add-hook 'help-fns-describe-function-functions #'help-fns--compiler-macro 100)
 
+(defun help-fns--generalized-variable (function)
+  (when (and (get function 'gv-expander)
+             ;; Don't mention obsolete generalized variables.
+             (not (get function 'byte-obsolete-generalized-variable)))
+    (insert (format-message "  `%s' is also a " function)
+            (buttonize "generalized variable"
+                       (lambda (_) (info "(elisp)Generalized Variables")))
+            ".\n")))
+(add-hook 'help-fns-describe-function-functions
+          #'help-fns--generalized-variable)
+
 
 ;; Variables
 
@@ -1234,10 +1318,11 @@ it is displayed along with the global value."
                    (terpri)
                     (let ((buf (current-buffer)))
                       (with-temp-buffer
-                        (lisp-mode-variables nil)
+                        (lisp-data-mode)
                         (set-syntax-table emacs-lisp-mode-syntax-table)
                         (insert print-rep)
                         (pp-buffer)
+                        (font-lock-ensure)
                         (let ((pp-buffer (current-buffer)))
                           (with-current-buffer buf
                             (insert-buffer-substring pp-buffer)))))
@@ -1332,6 +1417,7 @@ it is displayed along with the global value."
                              alias 'variable-documentation))))
 
              (with-current-buffer standard-output
+                (help-fns--var-obsolete variable)
                (insert (or doc "Not documented as a variable.")))
 
               ;; Output the indented administrative bits.
@@ -1352,9 +1438,6 @@ it is displayed along with the global value."
 
 (defun help-fns--editable-variable (start end variable value buffer)
   (when (and (readablep value)
-             (or (not (symbolp value))
-                 (and (not (and (symbolp value) (boundp value)))
-                      (not (and (symbolp value) (fboundp value)))))
              help-enable-variable-value-editing)
     (add-text-properties
      start end
@@ -1362,6 +1445,7 @@ it is displayed along with the global value."
            'help-fns--edit-variable (list variable value buffer
                                           (current-buffer))
            'keymap (define-keymap
+                     :parent button-map
                      "e" #'help-fns-edit-variable)))))
 
 (defvar help-fns--edit-variable)
@@ -1369,8 +1453,8 @@ it is displayed along with the global value."
 (put 'help-fns-edit-variable 'disabled t)
 (defun help-fns-edit-variable ()
   "Edit the variable under point."
-  (interactive)
   (declare (completion ignore))
+  (interactive)
   (let ((var (get-text-property (point) 'help-fns--edit-variable)))
     (unless var
       (error "No variable under point"))
@@ -1378,19 +1462,22 @@ it is displayed along with the global value."
     (prin1 (nth 1 var) (current-buffer))
     (pp-buffer)
     (goto-char (point-min))
-    (insert (format ";; Edit the `%s' variable.\n" (nth 0 var))
-            ";; C-c C-c to update the value and exit.\n\n")
     (help-fns--edit-value-mode)
+    (insert (format ";; Edit the `%s' variable.\n" (nth 0 var))
+            (substitute-command-keys
+             ";; `\\[help-fns-edit-mode-done]' to update the value and exit; \
+`\\[help-fns-edit-mode-cancel]' to cancel.\n\n"))
     (setq-local help-fns--edit-variable var)))
 
 (defvar-keymap help-fns--edit-value-mode-map
-  "C-c C-c" #'help-fns-edit-mode-done)
+  "C-c C-c" #'help-fns-edit-mode-done
+  "C-c C-k" #'help-fns-edit-mode-cancel)
 
 (define-derived-mode help-fns--edit-value-mode emacs-lisp-mode "Elisp"
   :interactive nil)
 
 (defun help-fns-edit-mode-done (&optional kill)
-  "Update the value of the variable and kill the buffer.
+  "Update the value of the variable being edited and kill the edit buffer.
 If KILL (the prefix), don't update the value, but just kill the
 current buffer."
   (interactive "P" help-fns--edit-value-mode)
@@ -1410,6 +1497,12 @@ current buffer."
       (with-current-buffer help-buffer
         (revert-buffer)))))
 
+(defun help-fns-edit-mode-cancel ()
+  "Kill the edit buffer and cancel editing of the value.
+This cancels value editing without updating the value."
+  (interactive nil help-fns--edit-value-mode)
+  (help-fns-edit-mode-done t))
+
 (defun help-fns--run-describe-functions (functions &rest args)
   (with-current-buffer standard-output
     (unless (bolp)
@@ -1452,8 +1545,8 @@ current buffer."
     (when safe-var
       (princ "  This variable is safe as a file local variable ")
       (princ "if its value\n  satisfies the predicate ")
-      (princ (if (byte-code-function-p safe-var)
-                "which is a byte-compiled expression.\n"
+      (princ (if (compiled-function-p safe-var)
+                "which is a compiled expression.\n"
               (format-message "`%s'.\n" safe-var))))))
 
 (add-hook 'help-fns-describe-variable-functions #'help-fns--var-risky)
@@ -1526,19 +1619,21 @@ variable.\n")))
       (princ watchpoints)
       (terpri))))
 
-(add-hook 'help-fns-describe-variable-functions #'help-fns--var-obsolete)
 (defun help-fns--var-obsolete (variable)
   (let* ((obsolete (get variable 'byte-obsolete-variable))
-        (use (car obsolete)))
+        (use (car obsolete))
+         (start (point)))
     (when obsolete
-      (princ "  This variable is obsolete")
+      (insert "This variable is obsolete")
       (if (nth 2 obsolete)
-          (princ (format " since %s" (nth 2 obsolete))))
-      (princ (cond ((stringp use) (concat ";\n  " use))
-                  (use (format-message ";\n  use `%s' instead."
-                                        (car obsolete)))
-                  (t ".")))
-      (terpri))))
+          (insert (format " since %s" (nth 2 obsolete))))
+      (insert (cond ((stringp use) (concat "; " use))
+                   (use (format-message "; use `%s' instead."
+                                         (car obsolete)))
+                   (t "."))
+              "\n")
+      (fill-region-as-paragraph start (point))
+      (ensure-empty-lines))))
 
 (add-hook 'help-fns-describe-variable-functions #'help-fns--var-alias)
 (defun help-fns--var-alias (variable)
@@ -1771,8 +1866,10 @@ current buffer and the selected frame, respectively."
                                (when (funcall testfn symbol)
                                  ;; Don't record the current entry in the 
stack.
                                  (setq help-xref-stack-item nil)
-                                 (cons name
-                                       (funcall descfn symbol buffer frame))))
+                                 (let ((help-xref-stack nil)
+                                       (help-xref-forward-stack nil))
+                                   (funcall descfn symbol buffer frame))
+                                 (cons name (buffer-string))))
                              describe-symbol-backends))))
              (single (null (cdr docs))))
         (while (cdr docs)
@@ -1793,6 +1890,8 @@ current buffer and the selected frame, respectively."
           ;; Don't record the `describe-variable' item in the stack.
           (setq help-xref-stack-item nil)
           (help-setup-xref (list #'describe-symbol symbol) nil))
+        (goto-char (point-max))
+        (help-xref--navigation-buttons)
         (goto-char (point-min))))))
 
 ;;;###autoload
@@ -2103,6 +2202,8 @@ documentation for the major and minor modes of that 
buffer."
        (when (and (commandp sym)
                   ;; Ignore aliases.
                   (not (symbolp (symbol-function sym)))
+                  ;; Ignore obsolete commands.
+                  (not (get sym 'byte-obsolete-info))
                   ;; Ignore everything bound.
                   (not (where-is-internal sym nil t))
                   (apply #'derived-mode-p (command-modes sym)))
diff --git a/lisp/help-mode.el b/lisp/help-mode.el
index a50524253b..f49d20270c 100644
--- a/lisp/help-mode.el
+++ b/lisp/help-mode.el
@@ -31,25 +31,23 @@
 
 (require 'cl-lib)
 
-(defvar help-mode-map
-  (let ((map (make-sparse-keymap)))
-    (set-keymap-parent map (make-composed-keymap button-buffer-map
-                                                 special-mode-map))
-    (define-key map "n" 'help-goto-next-page)
-    (define-key map "p" 'help-goto-previous-page)
-    (define-key map "l" 'help-go-back)
-    (define-key map "r" 'help-go-forward)
-    (define-key map "\C-c\C-b" 'help-go-back)
-    (define-key map "\C-c\C-f" 'help-go-forward)
-    (define-key map [XF86Back] 'help-go-back)
-    (define-key map [XF86Forward] 'help-go-forward)
-    (define-key map "\C-c\C-c" 'help-follow-symbol)
-    (define-key map "s" 'help-view-source)
-    (define-key map "I" 'help-goto-lispref-info)
-    (define-key map "i" 'help-goto-info)
-    (define-key map "c" 'help-customize)
-    map)
-  "Keymap for Help mode.")
+(defvar-keymap help-mode-map
+  :doc "Keymap for Help mode."
+  :parent (make-composed-keymap button-buffer-map
+                                special-mode-map)
+  "n"             #'help-goto-next-page
+  "p"             #'help-goto-previous-page
+  "l"             #'help-go-back
+  "r"             #'help-go-forward
+  "C-c C-b"       #'help-go-back
+  "C-c C-f"       #'help-go-forward
+  "<XF86Back>"    #'help-go-back
+  "<XF86Forward>" #'help-go-forward
+  "C-c C-c"       #'help-follow-symbol
+  "s"             #'help-view-source
+  "I"             #'help-goto-lispref-info
+  "i"             #'help-goto-info
+  "c"             #'help-customize)
 
 (easy-menu-define help-mode-menu help-mode-map
   "Menu for Help mode."
@@ -386,8 +384,8 @@ The format is (FUNCTION ARGS...).")
   'help-function
   (lambda (file pos)
     (if help-window-keep-selected
-        (view-buffer (find-file-noselect file))
-      (view-buffer-other-window (find-file-noselect file)))
+        (view-file file)
+      (view-file-other-window file))
     (goto-char pos))
   'help-echo (purecopy "mouse-2, RET: show corresponding NEWS announcement"))
 
@@ -410,7 +408,7 @@ Commands:
 \\{help-mode-map}"
   (setq-local revert-buffer-function
               #'help-mode-revert-buffer)
-  (add-hook 'context-menu-functions 'help-mode-context-menu 5 t)
+  (add-hook 'context-menu-functions #'help-mode-context-menu 5 t)
   (setq-local tool-bar-map
               help-mode-tool-bar-map)
   (setq-local help-mode--current-data nil)
@@ -543,6 +541,12 @@ Each element has the form (NAME TESTFUN DESCFUN) where:
     and a frame), inserts the description of that symbol in the current buffer
     and returns that text as well.")
 
+(defcustom help-clean-buttons nil
+  "If non-nil, remove quotes around link buttons."
+  :version "29.1"
+  :type 'boolean
+  :group 'help)
+
 ;;;###autoload
 (defun help-make-xrefs (&optional buffer)
   "Parse and hyperlink documentation cross-references in the given BUFFER.
@@ -669,34 +673,52 @@ that."
           (while (and (not (bobp)) (bolp))
             (delete-char -1))
           (insert "\n")
-          (when (or help-xref-stack help-xref-forward-stack)
-            (insert "\n"))
-          ;; Make a back-reference in this buffer if appropriate.
-          (when help-xref-stack
-            (help-insert-xref-button help-back-label 'help-back
-                                     (current-buffer)))
-          ;; Make a forward-reference in this buffer if appropriate.
-          (when help-xref-forward-stack
-            (when help-xref-stack
-              (insert "\t"))
-            (help-insert-xref-button help-forward-label 'help-forward
-                                     (current-buffer)))
-          (when (or help-xref-stack help-xref-forward-stack)
-            (insert "\n")))
+          (help-xref--navigation-buttons))
         (set-buffer-modified-p old-modified)))))
 
+(defun help-xref--navigation-buttons ()
+  (let ((inhibit-read-only t))
+    (when (or help-xref-stack help-xref-forward-stack)
+      (ensure-empty-lines 1))
+    ;; Make a back-reference in this buffer if appropriate.
+    (when help-xref-stack
+      (help-insert-xref-button help-back-label 'help-back
+                               (current-buffer)))
+    ;; Make a forward-reference in this buffer if appropriate.
+    (when help-xref-forward-stack
+      (when help-xref-stack
+        (insert "\t"))
+      (help-insert-xref-button help-forward-label 'help-forward
+                               (current-buffer)))
+    (unless (bolp)
+      (insert "\n"))))
+
 ;;;###autoload
 (defun help-xref-button (match-number type &rest args)
   "Make a hyperlink for cross-reference text previously matched.
 MATCH-NUMBER is the subexpression of interest in the last matched
 regexp.  TYPE is the type of button to use.  Any remaining arguments are
 passed to the button's help-function when it is invoked.
-See `help-make-xrefs'."
+See `help-make-xrefs'.
+
+This function removes quotes surrounding the match if the
+variable `help-clean-buttons' is non-nil."
   ;; Don't mung properties we've added specially in some instances.
-  (unless (button-at (match-beginning match-number))
-    (make-text-button (match-beginning match-number)
-                     (match-end match-number)
-                     'type type 'help-args args)))
+  (let ((beg (match-beginning match-number))
+        (end (match-end match-number)))
+    (unless (button-at beg)
+      (make-text-button beg end 'type type 'help-args args)
+      (when (and help-clean-buttons
+                 (> beg (point-min))
+                 (save-excursion
+                   (goto-char (1- beg))
+                   (looking-at "['`‘]"))
+                 (< end (point-max))
+                 (save-excursion
+                   (goto-char end)
+                   (looking-at "['’]")))
+        (delete-region end (1+ end))
+        (delete-region (1- beg) beg)))))
 
 ;;;###autoload
 (defun help-insert-xref-button (string type &rest args)
@@ -740,7 +762,7 @@ See `help-make-xrefs'."
 ;; Additional functions for (re-)creating types of help buffers.
 
 ;;;###autoload
-(define-obsolete-function-alias 'help-xref-interned 'describe-symbol "25.1")
+(define-obsolete-function-alias 'help-xref-interned #'describe-symbol "25.1")
 
 
 ;; Navigation/hyperlinking with xrefs
@@ -810,7 +832,7 @@ The help buffers are divided into \"pages\" by the ^L 
character."
 
 (defun help-goto-previous-page ()
   "Go to the previous page (if any) in the current buffer.
-(If not at the start of a page, go to the start of the current page.)
+\(If not at the start of a page, go to the start of the current page.)
 
 The help buffers are divided into \"pages\" by the ^L character."
   (interactive nil help-mode)
diff --git a/lisp/help.el b/lisp/help.el
index 766bae0845..15ab3192ad 100644
--- a/lisp/help.el
+++ b/lisp/help.el
@@ -566,13 +566,16 @@ To record all your input, use `open-dribble-file'."
 ;; Key bindings
 
 (defun help--key-description-fontified (keys &optional prefix)
-  "Like `key-description' but add face for \"*Help*\" buffers."
-  ;; We add both the `font-lock-face' and `face' properties here, as this
-  ;; seems to be the only way to get this to work reliably in any
-  ;; buffer.
-  (propertize (key-description keys prefix)
-              'font-lock-face 'help-key-binding
-              'face 'help-key-binding))
+  "Like `key-description' but add face for \"*Help*\" buffers.
+KEYS is the return value of `(where-is-internal \\='foo-cmd nil t)'.
+Return nil if KEYS is nil."
+  (when keys
+    ;; We add both the `font-lock-face' and `face' properties here, as this
+    ;; seems to be the only way to get this to work reliably in any
+    ;; buffer.
+    (propertize (key-description keys prefix)
+                'font-lock-face 'help-key-binding
+                'face 'help-key-binding)))
 
 (defcustom describe-bindings-outline t
   "Non-nil enables outlines in the output buffer of `describe-bindings'."
@@ -606,7 +609,6 @@ or a buffer name."
           (setq-local outline-level (lambda () 1))
           (setq-local outline-minor-mode-cycle t
                       outline-minor-mode-highlight t)
-          (setq-local outline-minor-mode-use-buttons t)
           (outline-minor-mode 1)
           (save-excursion
             (goto-char (point-min))
@@ -903,6 +905,21 @@ Describe the following key, mouse click, or menu item: "
         (setq yank-menu (copy-sequence saved-yank-menu))
         (fset 'yank-menu (cons 'keymap yank-menu))))))
 
+;; Defined in help-fns.el.
+(defvar describe-function-orig-buffer)
+
+;; These two are named functions because lambda-functions cannot be
+;; serialized in a native-compilation build, which breaks bookmark
+;; support in help-mode.el.
+(defun describe-key--helper (key-list buf)
+  (describe-key key-list
+                (if (buffer-live-p buf) buf)))
+
+(defun describe-function--helper (func buf)
+  (let ((describe-function-orig-buffer
+         (if (buffer-live-p buf) buf)))
+    (describe-function func)))
+
 (defun describe-key (&optional key-list buffer up-event)
   "Display documentation of the function invoked by KEY-LIST.
 KEY-LIST can be any kind of a key sequence; it can include keyboard events,
@@ -933,6 +950,7 @@ current buffer."
     (setq buffer nil))
   (let* ((help-buffer-under-preparation t)
          (buf (or buffer (current-buffer)))
+         (describe-function-orig-buffer buf)
          (on-link
           (mapcar (lambda (kr)
                     (let ((raw (cdr kr)))
@@ -955,10 +973,7 @@ current buffer."
                          `(,seq ,brief-desc ,defn ,locus)))
                      key-list))
            2)))
-    (help-setup-xref (list (lambda (key-list buf)
-                             (describe-key key-list
-                                           (if (buffer-live-p buf) buf)))
-                           key-list buf)
+    (help-setup-xref (list #'describe-key--helper key-list buf)
                     (called-interactively-p 'interactive))
     (if (and (<= (length info-list) 1)
              (help--binding-undefined-p (nth 2 (car info-list))))
@@ -966,16 +981,16 @@ current buffer."
       (with-help-window (help-buffer)
         (when (> (length info-list) 1)
           ;; FIXME: Make this into clickable hyperlinks.
-          (princ "There were several key-sequences:\n\n")
-          (princ (mapconcat (lambda (info)
-                              (pcase-let ((`(,_seq ,brief-desc ,_defn ,_locus)
-                                           info))
-                                (concat "  " brief-desc)))
-                            info-list
-                            "\n"))
+          (insert "There were several key-sequences:\n\n")
+          (insert (mapconcat (lambda (info)
+                               (pcase-let ((`(,_seq ,brief-desc ,_defn ,_locus)
+                                            info))
+                                 (concat "  " brief-desc)))
+                             info-list
+                             "\n"))
           (when (delq nil on-link)
-            (princ "\n\nThose are influenced by `mouse-1-click-follows-link'"))
-          (princ "\n\nThey're all described below."))
+            (insert "\n\nThose are influenced by 
`mouse-1-click-follows-link'"))
+          (insert "\n\nThey're all described below."))
         (pcase-dolist (`(,_seq ,brief-desc ,defn ,locus)
                        info-list)
           (when defn
@@ -983,18 +998,19 @@ current buffer."
               (with-current-buffer standard-output
                 (insert "\n\n" (make-separator-line) "\n")))
 
-            (princ brief-desc)
+            (insert brief-desc)
             (when locus
-              (princ (format " (found in %s)" locus)))
-            (princ ", which is ")
+              (insert (format " (found in %s)" locus)))
+            (insert ", which is ")
            (describe-function-1 defn)))))))
 
 (defun search-forward-help-for-help ()
   "Search forward in the help-for-help window.
-This command is meant to be used after issuing the `C-h C-h' command."
+This command is meant to be used after issuing the \\[help-for-help] command."
   (interactive)
   (unless (get-buffer help-for-help-buffer-name)
-    (error "No %s buffer; use `C-h C-h' first" help-for-help-buffer-name))
+    (error (substitute-command-keys "No %s buffer; use \\[help-for-help] 
first")
+           help-for-help-buffer-name))
   ;; Move cursor to the "help window".
   (pop-to-buffer help-for-help-buffer-name)
   ;; Do incremental search forward.
@@ -1161,25 +1177,25 @@ Otherwise, return a new string."
                 (delete-char 2)
                 (ignore-errors
                   (forward-char 1)))
+               ;; 1C. \`f' is replaced with a fontified f.
                ((and (= (following-char) ?`)
                      (save-excursion
                        (prog1 (search-forward "'" nil t)
-                         (setq end-point (- (point) 2)))))
-                (goto-char orig-point)
-                (delete-char 2)
-                (goto-char (1- end-point))
-                (delete-char 1)
-                ;; (backward-char 1)
-                (let ((k (buffer-substring-no-properties orig-point (point))))
-                  (cond ((= (length k) 0)
-                         (error "Empty key sequence in substitution"))
-                        ((and (not (string-match-p "\\`M-x " k))
-                              (not (key-valid-p k)))
-                         (error "Invalid key sequence in substitution: `%s'" 
k))))
-                (add-text-properties orig-point (point)
-                                     '( face help-key-binding
-                                        font-lock-face help-key-binding)))
-               ;; 1C. \[foo] is replaced with the keybinding.
+                         (setq end-point (1- (point))))))
+                (let ((k (buffer-substring-no-properties (+ orig-point 2)
+                                                         end-point)))
+                  (when (or (key-valid-p k)
+                            (string-match-p "\\`mouse-[1-9]" k)
+                            (string-match-p "\\`M-x " k))
+                    (goto-char orig-point)
+                    (delete-char 2)
+                    (goto-char (- end-point 2)) ; nb. take deletion into 
account
+                    (delete-char 1)
+                    (unless no-face
+                      (add-text-properties orig-point (point)
+                                           '( face help-key-binding
+                                              font-lock-face 
help-key-binding))))))
+               ;; 1D. \[foo] is replaced with the keybinding.
                ((and (= (following-char) ?\[)
                      (save-excursion
                        (prog1 (search-forward "]" nil t)
@@ -1189,14 +1205,6 @@ Otherwise, return a new string."
                 (let* ((fun (intern (buffer-substring (point) (1- end-point))))
                        (key (with-current-buffer orig-buf
                               (where-is-internal fun keymap t))))
-                  ;; If this a command remap, we need to follow it.
-                  (when (and (vectorp key)
-                             (> (length key) 1)
-                             (eq (aref key 0) 'remap)
-                             (symbolp (aref key 1)))
-                    (setq fun (aref key 1))
-                    (setq key (with-current-buffer orig-buf
-                                (where-is-internal fun keymap t))))
                   (if (not key)
                       ;; Function is not on any key.
                       (let ((op (point)))
@@ -1223,7 +1231,7 @@ Otherwise, return a new string."
                                  (help-mode--add-function-link key fun)
                                key)
                            key)))))))
-               ;; 1D. \{foo} is replaced with a summary of the keymap
+               ;; 1E. \{foo} is replaced with a summary of the keymap
                ;;            (symbol-value foo).
                ;;     \<foo> just sets the keymap used for \[cmd].
                ((and (or (and (= (following-char) ?{)
@@ -1318,18 +1326,17 @@ If BUFFER, lookup keys while in that buffer.  This only 
affects
 things like :filters for menu bindings."
   (let* ((amaps (accessible-keymaps startmap prefix))
          (orig-maps (if no-menu
-                        (progn
-                          ;; Delete from MAPS each element that is for
-                          ;; the menu bar.
-                          (let* ((tail amaps)
-                                 result)
-                            (while tail
-                              (let ((elem (car tail)))
-                                (when (not (and (>= (length (car elem)) 1)
-                                                (eq (elt (car elem) 0) 
'menu-bar)))
-                                  (setq result (append result (list elem)))))
-                              (setq tail (cdr tail)))
-                            result))
+                        ;; Delete from MAPS each element that is for
+                        ;; the menu bar.
+                        (let* ((tail amaps)
+                               result)
+                          (while tail
+                            (let ((elem (car tail)))
+                              (when (not (and (>= (length (car elem)) 1)
+                                              (eq (elt (car elem) 0) 
'menu-bar)))
+                                (setq result (append result (list elem)))))
+                            (setq tail (cdr tail)))
+                          result)
                       amaps))
          (maps orig-maps)
          (print-title (or maps always-title))
@@ -1443,8 +1450,7 @@ prefix keys PREFIX (a string or vector).
 TRANSL, PARTIAL, SHADOW, NOMENU, MENTION-SHADOW and BUFFER are as
 in `describe-map-tree'."
   ;; Converted from describe_map in keymap.c.
-  (let* ((suppress (and partial 'suppress-keymap))
-         (map (keymap-canonicalize map))
+  (let* ((map (keymap-canonicalize map))
          (tail map)
          (first t)
          done vect)
@@ -1475,7 +1481,7 @@ in `describe-map-tree'."
                     ;; commands.
                     (setq definition (keymap--get-keyelt (cdr (car tail)) nil))
                     (or (not (symbolp definition))
-                        (null (get definition suppress)))
+                        (not (get definition (when partial 'suppress-keymap))))
                     ;; Don't show a command that isn't really
                     ;; visible because a local definition of the
                     ;; same key shadows it.
@@ -1508,7 +1514,7 @@ in `describe-map-tree'."
                  (push (cons tail prefix) help--keymaps-seen)))))
       (setq tail (cdr tail)))
     ;; If we found some sparse map events, sort them.
-    (let ((vect (sort vect 'help--describe-map-compare))
+    (let ((vect (sort vect #'help--describe-map-compare))
           (columns ())
           line-start key-end column)
       ;; Now output them in sorted order.
@@ -1996,8 +2002,10 @@ The `temp-buffer-window-setup-hook' hook is called."
             (prog1
                 (funcall callback)
               (run-hooks 'temp-buffer-window-setup-hook)))
-        (help-window-setup (temp-buffer-window-show (current-buffer)))
-        (help-make-xrefs (current-buffer))))))
+        (help-make-xrefs (current-buffer))
+        ;; This must be done after the buffer has been completely
+        ;; generated, since `temp-buffer-resize-mode' may be enabled.
+        (help-window-setup (temp-buffer-window-show (current-buffer)))))))
 
 ;; Called from C, on encountering `help-char' when reading a char.
 ;; Don't print to *Help*; that would clobber Help history.
diff --git a/lisp/hex-util.el b/lisp/hex-util.el
index 0858e46ec5..101c8be7b4 100644
--- a/lisp/hex-util.el
+++ b/lisp/hex-util.el
@@ -41,8 +41,8 @@
         (dst (make-string (/ len 2) 0))
         (idx 0)(pos 0))
     (while (< pos len)
-      ;; logior and lsh are not byte-coded.
-      ;; (aset dst idx (logior (lsh (hex-char-to-num (aref string pos)) 4)
+      ;; logior and ash are not byte-coded.
+      ;; (aset dst idx (logior (ash (hex-char-to-num (aref string pos)) 4)
       ;;                           (hex-char-to-num (aref string (1+ pos)))))
       (aset dst idx (+ (* (hex-char-to-num (aref string pos)) 16)
                       (hex-char-to-num (aref string (1+ pos)))))
@@ -56,8 +56,8 @@
         (dst (make-string (* len 2) 0))
         (idx 0)(pos 0))
     (while (< pos len)
-      ;; logand and lsh are not byte-coded.
-      ;; (aset dst idx (num-to-hex-char (logand (lsh (aref string pos) -4) 
15)))
+      ;; logand and ash are not byte-coded.
+      ;; (aset dst idx (num-to-hex-char (logand (ash (aref string pos) -4) 
15)))
       (aset dst idx (num-to-hex-char (/ (aref string pos) 16)))
       (setq idx (1+ idx))
       ;; (aset dst idx (num-to-hex-char (logand (aref string pos) 15)))
diff --git a/lisp/hi-lock.el b/lisp/hi-lock.el
index 0934eef8ed..a45e74eca2 100644
--- a/lisp/hi-lock.el
+++ b/lisp/hi-lock.el
@@ -69,12 +69,12 @@
 ;;    You might also want to bind the hi-lock commands to more
 ;;    finger-friendly sequences:
 
-;;    (define-key hi-lock-map "\C-z\C-h" 'highlight-lines-matching-regexp)
-;;    (define-key hi-lock-map "\C-zi" 'hi-lock-find-patterns)
-;;    (define-key hi-lock-map "\C-zh" 'highlight-regexp)
-;;    (define-key hi-lock-map "\C-zp" 'highlight-phrase)
-;;    (define-key hi-lock-map "\C-zr" 'unhighlight-regexp)
-;;    (define-key hi-lock-map "\C-zb" 'hi-lock-write-interactive-patterns))
+;;    (keymap-set hi-lock-map "C-z C-h" 'highlight-lines-matching-regexp)
+;;    (keymap-set hi-lock-map "C-z i" 'hi-lock-find-patterns)
+;;    (keymap-set hi-lock-map "C-z h" 'highlight-regexp)
+;;    (keymap-set hi-lock-map "C-z p" 'highlight-phrase)
+;;    (keymap-set hi-lock-map "C-z r" 'unhighlight-regexp)
+;;    (keymap-set hi-lock-map "C-z b" 'hi-lock-write-interactive-patterns))
 
 ;;    See the documentation for hi-lock-mode `C-h f hi-lock-mode' for
 ;;    additional instructions.
@@ -97,7 +97,7 @@
 When a file is visited and hi-lock mode is on, patterns starting
 up to this limit are added to font-lock's patterns.  See documentation
 of functions `hi-lock-mode' and `hi-lock-find-patterns'."
-  :type 'integer
+  :type 'natnum
   :group 'hi-lock)
 
 (defcustom hi-lock-highlight-range 2000000
@@ -107,7 +107,7 @@ such as the buffer created by `list-colors-display'.  In 
those buffers
 hi-lock patterns will only be applied over a range of
 `hi-lock-highlight-range' characters.  If font-lock is active then
 highlighting will be applied throughout the buffer."
-  :type 'integer
+  :type 'natnum
   :group 'hi-lock)
 
 (defcustom hi-lock-exclude-modes
@@ -128,11 +128,10 @@ patterns."
                  (const :tag "Ask about file patterns" ask)
                  (function :tag "Function to check file patterns"))
   :group 'hi-lock
+  ;; It can have a function value.
+  :risky t
   :version "22.1")
 
-;; It can have a function value.
-(put 'hi-lock-file-patterns-policy 'risky-local-variable t)
-
 (defcustom hi-lock-auto-select-face nil
   "When nil, highlighting commands prompt for the face to use.
 When non-nil, highlighting command determine the faces to use
@@ -276,17 +275,16 @@ a library is being loaded.")
     ["Patterns from Buffer" hi-lock-find-patterns
      :help "Use patterns (if any) near top of buffer."]))
 
-(defvar hi-lock-map
-  (let ((map (make-sparse-keymap "Hi Lock")))
-    (define-key map "\C-xwi" 'hi-lock-find-patterns)
-    (define-key map "\C-xwl" 'highlight-lines-matching-regexp)
-    (define-key map "\C-xwp" 'highlight-phrase)
-    (define-key map "\C-xwh" 'highlight-regexp)
-    (define-key map "\C-xw." 'highlight-symbol-at-point)
-    (define-key map "\C-xwr" 'unhighlight-regexp)
-    (define-key map "\C-xwb" 'hi-lock-write-interactive-patterns)
-    map)
-  "Key map for hi-lock.")
+(defvar-keymap hi-lock-map
+  :doc "Keymap for `hi-lock-mode'."
+  :name "Hi Lock"
+  "C-x w i" #'hi-lock-find-patterns
+  "C-x w l" #'highlight-lines-matching-regexp
+  "C-x w p" #'highlight-phrase
+  "C-x w h" #'highlight-regexp
+  "C-x w ." #'highlight-symbol-at-point
+  "C-x w r" #'unhighlight-regexp
+  "C-x w b" #'hi-lock-write-interactive-patterns)
 
 ;; Visible Functions
 
diff --git a/lisp/htmlfontify.el b/lisp/htmlfontify.el
index dbcc152c15..bf7446f151 100644
--- a/lisp/htmlfontify.el
+++ b/lisp/htmlfontify.el
@@ -81,11 +81,9 @@
 (eval-when-compile (require 'cl-lib))
 (require 'cus-edit)
 
-(defconst htmlfontify-version 0.21)
-
 (defconst hfy-meta-tags
-  (format "<meta name=\"generator\" content=\"emacs %s; htmlfontify %0.2f\" />"
-          emacs-version htmlfontify-version)
+  (format "<meta name=\"generator\" content=\"emacs %s; htmlfontify\" />"
+          emacs-version)
   "The generator meta tag for this version of htmlfontify.")
 
 (defconst htmlfontify-manual "Htmlfontify Manual"
@@ -2392,13 +2390,14 @@ You may also want to set `hfy-page-header' and 
`hfy-page-footer'."
   (let ((file (hfy-initfile)))
     (load file 'NOERROR nil nil) ))
 
-;; Obsolete.
-
 (defun hfy-interq (set-a set-b)
   "Return the intersection (using `eq') of two lists SET-A and SET-B."
   (declare (obsolete seq-intersection "28.1"))
   (nreverse (seq-intersection set-a set-b #'eq)))
 
+(defconst htmlfontify-version 0.21)
+(make-obsolete-variable 'htmlfontify-version 'emacs-version "29.1")
+
 (define-obsolete-function-alias 'hfy-prop-invisible-p #'invisible-p "29.1")
 
 (provide 'htmlfontify)
diff --git a/lisp/ibuf-ext.el b/lisp/ibuf-ext.el
index 30b494f573..6b5cccec51 100644
--- a/lisp/ibuf-ext.el
+++ b/lisp/ibuf-ext.el
@@ -48,30 +48,12 @@
 ;;; Utility functions
 (defun ibuffer-remove-alist (key alist)
   "Remove all entries in ALIST that have a key equal to KEY."
-  (while (ibuffer-awhen (assoc key alist)
-           (setq alist (remove it alist)) it))
-  alist)
-
-;; borrowed from Gnus
-(defun ibuffer-remove-duplicates (list)
-  "Return a copy of LIST with duplicate elements removed."
-  (let ((new nil)
-       (tail list))
-    (while tail
-      (or (member (car tail) new)
-         (setq new (cons (car tail) new)))
-      (setq tail (cdr tail)))
-    (nreverse new)))
-
-(defun ibuffer-split-list (ibuffer-split-list-fn ibuffer-split-list-elts)
-  (let ((hip-crowd nil)
-       (lamers nil))
-    (dolist (ibuffer-split-list-elt ibuffer-split-list-elts)
-      (if (funcall ibuffer-split-list-fn ibuffer-split-list-elt)
-         (push ibuffer-split-list-elt hip-crowd)
-       (push ibuffer-split-list-elt lamers)))
-    ;; Too bad Emacs Lisp doesn't have multiple values.
-    (list (nreverse hip-crowd) (nreverse lamers))))
+  (assoc-delete-all key (copy-sequence alist)))
+
+(defun ibuffer-split-list (fn elts)
+  (declare (obsolete seq-group-by "29.1"))
+  (let ((res (seq-group-by fn elts)))
+    (list (cdr (assq t res)) (cdr (assq nil res)))))
 
 (defcustom ibuffer-never-show-predicates nil
   "A list of predicates (a regexp or function) for buffers not to display.
@@ -769,11 +751,12 @@ specification, with the same structure as an element of 
the list
          (i 0))
       (dolist (filtergroup filter-group-alist)
        (let ((filterset (cdr filtergroup)))
-         (cl-destructuring-bind (hip-crowd lamers)
-             (ibuffer-split-list (lambda (bufmark)
-                                   (ibuffer-included-in-filters-p (car bufmark)
-                                                                  filterset))
-                                 bmarklist)
+          (let* ((res (seq-group-by (lambda (bufmark)
+                                      (ibuffer-included-in-filters-p (car 
bufmark)
+                                                                     
filterset))
+                                    bmarklist))
+                 (hip-crowd (cdr (assq t res)))
+                 (lamers (cdr (assq nil res))))
            (aset vec i hip-crowd)
            (cl-incf i)
            (setq bmarklist lamers))))
@@ -803,7 +786,7 @@ specification, with the same structure as an element of the 
list
         (mapcar (lambda (mode)
                   (cons (format "%s" mode) `((mode . ,mode))))
                 (let ((modes
-                       (ibuffer-remove-duplicates
+                       (seq-uniq
                         (mapcar (lambda (buf)
                                  (buffer-local-value 'major-mode buf))
                                 (buffer-list)))))
@@ -880,7 +863,7 @@ specification, with the same structure as an element of the 
list
   "Move point to the filter group whose name is NAME."
   (interactive
    (list (ibuffer-read-filter-group-name "Jump to filter group: ")))
-  (ibuffer-aif (assoc name (ibuffer-current-filter-groups-with-position))
+  (if-let ((it (assoc name (ibuffer-current-filter-groups-with-position))))
       (goto-char (cdr it))
     (error "No filter group with name %s" name)))
 
@@ -891,7 +874,7 @@ The group will be added to 
`ibuffer-filter-group-kill-ring'."
   (interactive (list (ibuffer-read-filter-group-name "Kill filter group: " t)))
   (when (equal name "Default")
     (error "Can't kill default filter group"))
-  (ibuffer-aif (assoc name ibuffer-filter-groups)
+  (if-let ((it (assoc name ibuffer-filter-groups)))
       (progn
        (push (copy-tree it) ibuffer-filter-group-kill-ring)
        (setq ibuffer-filter-groups (ibuffer-remove-alist
@@ -906,13 +889,12 @@ The group will be added to 
`ibuffer-filter-group-kill-ring'."
   "Kill the filter group at point.
 See also `ibuffer-kill-filter-group'."
   (interactive "P\np")
-  (ibuffer-aif (save-excursion
-                (ibuffer-forward-line 0)
-                (get-text-property (point) 'ibuffer-filter-group-name))
-      (progn
-       (ibuffer-kill-filter-group it))
-      (funcall (if interactive-p #'call-interactively #'funcall)
-              #'kill-line arg)))
+  (if-let ((it (save-excursion
+                 (ibuffer-forward-line 0)
+                 (get-text-property (point) 'ibuffer-filter-group-name))))
+      (ibuffer-kill-filter-group it)
+    (funcall (if interactive-p #'call-interactively #'funcall)
+             #'kill-line arg)))
 
 (defun ibuffer-insert-filter-group-before (newgroup group)
   (let* ((found nil)
@@ -968,7 +950,7 @@ prompt for NAME, and use the current filters."
      (list
       (read-from-minibuffer "Save current filter groups as: ")
       ibuffer-filter-groups)))
-  (ibuffer-aif (assoc name ibuffer-saved-filter-groups)
+  (if-let ((it (assoc name ibuffer-saved-filter-groups)))
       (setcdr it groups)
     (push (cons name groups) ibuffer-saved-filter-groups))
   (ibuffer-maybe-save-stuff))
@@ -1140,7 +1122,7 @@ Interactively, prompt for NAME, and use the current 
filters."
      (list
       (read-from-minibuffer "Save current filters as: ")
       ibuffer-filtering-qualifiers)))
-  (ibuffer-aif (assoc name ibuffer-saved-filters)
+  (if-let ((it (assoc name ibuffer-saved-filters)))
       (setcdr it filters)
     (push (cons name filters) ibuffer-saved-filters))
   (ibuffer-maybe-save-stuff))
@@ -1211,7 +1193,9 @@ Interactively, prompt for NAME, and use the current 
filters."
      (let ((type (assq (car qualifier) ibuffer-filtering-alist)))
        (unless qualifier
          (error "Ibuffer: Bad qualifier %s" qualifier))
-       (concat " [" (cadr type) ": " (format "%s]" (cdr qualifier)))))))
+       (if (cdr qualifier)
+           (format " [%s: %s]" (cadr type) (cdr qualifier))
+         (format " [%s]" (cadr type)))))))
 
 (defun ibuffer-list-buffer-modes (&optional include-parents)
   "Create a completion table of buffer modes currently in use.
@@ -1315,7 +1299,7 @@ For example, for a buffer associated with file 
'/a/b/c.d', this
 matches against '/a/b/c.d'."
   (:description "full file name"
    :reader (read-from-minibuffer "Filter by full file name (regexp): "))
-  (ibuffer-awhen (with-current-buffer buf (ibuffer-buffer-file-name))
+  (when-let ((it (with-current-buffer buf (ibuffer-buffer-file-name))))
     (string-match qualifier it)))
 
 ;;;###autoload (autoload 'ibuffer-filter-by-basename "ibuf-ext")
@@ -1327,7 +1311,7 @@ matches against `c.d'."
   (:description "file basename"
    :reader (read-from-minibuffer
             "Filter by file name, without directory part (regex): "))
-  (ibuffer-awhen (with-current-buffer buf (ibuffer-buffer-file-name))
+  (when-let ((it (with-current-buffer buf (ibuffer-buffer-file-name))))
     (string-match qualifier (file-name-nondirectory it))))
 
 ;;;###autoload (autoload 'ibuffer-filter-by-file-extension "ibuf-ext")
@@ -1340,7 +1324,7 @@ pattern.  For example, for a buffer associated with file
   (:description "filename extension"
    :reader (read-from-minibuffer
             "Filter by filename extension without separator (regex): "))
-  (ibuffer-awhen (with-current-buffer buf (ibuffer-buffer-file-name))
+  (when-let ((it (with-current-buffer buf (ibuffer-buffer-file-name))))
     (string-match qualifier (or (file-name-extension it) ""))))
 
 ;;;###autoload (autoload 'ibuffer-filter-by-directory "ibuf-ext")
@@ -1350,11 +1334,11 @@ pattern.  For example, for a buffer associated with file
 For a buffer associated with file '/a/b/c.d', this matches
 against '/a/b'.  For a buffer not associated with a file, this
 matches against the value of `default-directory' in that buffer."
-  (:description "directory name"
-   :reader (read-from-minibuffer "Filter by directory name (regex): "))
-  (ibuffer-aif (with-current-buffer buf (ibuffer-buffer-file-name))
-      (let ((dirname (file-name-directory it)))
-        (when dirname (string-match qualifier dirname)))
+  ( :description "directory name"
+    :reader (read-from-minibuffer "Filter by directory name (regex): "))
+  (if-let ((it (with-current-buffer buf (ibuffer-buffer-file-name))))
+      (when-let ((dirname (file-name-directory it)))
+        (string-match qualifier dirname))
     (when default-directory (string-match qualifier default-directory))))
 
 ;;;###autoload (autoload 'ibuffer-filter-by-size-gt  "ibuf-ext")
@@ -1988,6 +1972,8 @@ defaults to one."
        (push buf ibuffer-do-occur-bufs)))
     (occur-1 regexp nlines ibuffer-do-occur-bufs)))
 
+(define-obsolete-function-alias 'ibuffer-remove-duplicates #'seq-uniq "29.1")
+
 (provide 'ibuf-ext)
 
 ;; Local Variables:
diff --git a/lisp/ibuf-macs.el b/lisp/ibuf-macs.el
index 5d2dd47945..acffb74ead 100644
--- a/lisp/ibuf-macs.el
+++ b/lisp/ibuf-macs.el
@@ -35,7 +35,7 @@
 If TEST returns non-nil, bind `it' to the value, and evaluate
 TRUE-BODY.  Otherwise, evaluate forms in FALSE-BODY as if in `progn'.
 Compare with `if'."
-  (declare (indent 2))
+  (declare (obsolete if-let "29.1") (indent 2))
   (let ((sym (make-symbol "ibuffer-aif-sym")))
     `(let ((,sym ,test))
        (if ,sym
@@ -47,10 +47,9 @@ Compare with `if'."
 (defmacro ibuffer-awhen (test &rest body)
   "Evaluate BODY if TEST returns non-nil.
 During evaluation of body, bind `it' to the value returned by TEST."
-  (declare (indent 1))
-  `(ibuffer-aif ,test
-       (progn ,@body)
-     nil))
+  (declare (indent 1) (obsolete when-let "29.1"))
+  `(when-let ((it ,test))
+     ,@body))
 
 (defmacro ibuffer-save-marks (&rest body)
   "Save the marked status of the buffers and execute BODY; restore marks."
@@ -321,10 +320,15 @@ bound to the current value of the filter.
          (when (cdr qualifier) ; Compose individual filters with `or'.
            (setq ,filter `(or ,@(mapcar (lambda (m) (cons ',name m)) 
qualifier))))))
        (if (null (ibuffer-push-filter ,filter))
-           (message ,(format "Filter by %s already applied:  %%s" description)
-                ,qualifier-str)
-         (message ,(format "Filter by %s added:  %%s" description)
-              ,qualifier-str)
+           (if ,qualifier-str
+               (message ,(format "Filter by %s already applied:  %%s"
+                                 description)
+                        ,qualifier-str)
+             (message ,(format "Filter by %s already applied" description)))
+         (if ,qualifier-str
+             (message ,(format "Filter by %s added:  %%s" description)
+                      ,qualifier-str)
+           (message ,(format "Filter by %s added" description)))
          (ibuffer-update nil t))))
        (push (list ',name ,description
            (lambda (buf qualifier)
diff --git a/lisp/ibuffer.el b/lisp/ibuffer.el
index 7cfa428e9b..5cb4fe2a7a 100644
--- a/lisp/ibuffer.el
+++ b/lisp/ibuffer.el
@@ -34,7 +34,7 @@
 ;; you might be interested in replacing the default `list-buffers' key
 ;; binding by adding the following to your init file:
 ;;
-;;     (global-set-key (kbd "C-x C-b") 'ibuffer)
+;;     (keymap-global-set "C-x C-b" 'ibuffer)
 ;;
 ;; See also the various customization options, not least the
 ;; documentation for `ibuffer-formats'.
@@ -364,173 +364,169 @@ directory, like `default-directory'."
                       (regexp :tag "From")
                        (regexp :tag "To"))))
 
-(defvar ibuffer--filter-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map (kbd "RET") 'ibuffer-filter-by-mode)
-    (define-key map (kbd "SPC") 'ibuffer-filter-chosen-by-completion)
-    (define-key map (kbd "m") 'ibuffer-filter-by-used-mode)
-    (define-key map (kbd "M") 'ibuffer-filter-by-derived-mode)
-    (define-key map (kbd "n") 'ibuffer-filter-by-name)
-    (define-key map (kbd "E") 'ibuffer-filter-by-process)
-    (define-key map (kbd "*") 'ibuffer-filter-by-starred-name)
-    (define-key map (kbd "f") 'ibuffer-filter-by-filename)
-    (define-key map (kbd "F") 'ibuffer-filter-by-directory)
-    (define-key map (kbd "b") 'ibuffer-filter-by-basename)
-    (define-key map (kbd ".") 'ibuffer-filter-by-file-extension)
-    (define-key map (kbd "<") 'ibuffer-filter-by-size-lt)
-    (define-key map (kbd ">") 'ibuffer-filter-by-size-gt)
-    (define-key map (kbd "i") 'ibuffer-filter-by-modified)
-    (define-key map (kbd "v") 'ibuffer-filter-by-visiting-file)
-    (define-key map (kbd "c") 'ibuffer-filter-by-content)
-    (define-key map (kbd "e") 'ibuffer-filter-by-predicate)
-
-    (define-key map (kbd "r") 'ibuffer-switch-to-saved-filters)
-    (define-key map (kbd "a") 'ibuffer-add-saved-filters)
-    (define-key map (kbd "x") 'ibuffer-delete-saved-filters)
-    (define-key map (kbd "d") 'ibuffer-decompose-filter)
-    (define-key map (kbd "s") 'ibuffer-save-filters)
-    (define-key map (kbd "p") 'ibuffer-pop-filter)
-    (define-key map (kbd "<up>") 'ibuffer-pop-filter)
-    (define-key map (kbd "!") 'ibuffer-negate-filter)
-    (define-key map (kbd "t") 'ibuffer-exchange-filters)
-    (define-key map (kbd "TAB") 'ibuffer-exchange-filters)
-    (define-key map (kbd "o") 'ibuffer-or-filter)
-    (define-key map (kbd "|") 'ibuffer-or-filter)
-    (define-key map (kbd "&") 'ibuffer-and-filter)
-    (define-key map (kbd "g") 'ibuffer-filters-to-filter-group)
-    (define-key map (kbd "P") 'ibuffer-pop-filter-group)
-    (define-key map (kbd "S-<up>") 'ibuffer-pop-filter-group)
-    (define-key map (kbd "D") 'ibuffer-decompose-filter-group)
-    (define-key map (kbd "/") 'ibuffer-filter-disable)
-
-    (define-key map (kbd "S") 'ibuffer-save-filter-groups)
-    (define-key map (kbd "R") 'ibuffer-switch-to-saved-filter-groups)
-    (define-key map (kbd "X") 'ibuffer-delete-saved-filter-groups)
-    (define-key map (kbd "\\") 'ibuffer-clear-filter-groups)
-    map))
-
-(defvar ibuffer-mode-map
-  (let ((map (make-keymap)))
-    (define-key map (kbd "0") 'digit-argument)
-    (define-key map (kbd "1") 'digit-argument)
-    (define-key map (kbd "2") 'digit-argument)
-    (define-key map (kbd "3") 'digit-argument)
-    (define-key map (kbd "4") 'digit-argument)
-    (define-key map (kbd "5") 'digit-argument)
-    (define-key map (kbd "6") 'digit-argument)
-    (define-key map (kbd "7") 'digit-argument)
-    (define-key map (kbd "8") 'digit-argument)
-    (define-key map (kbd "9") 'digit-argument)
-
-    (define-key map (kbd "m") 'ibuffer-mark-forward)
-    (define-key map (kbd "t") 'ibuffer-toggle-marks)
-    (define-key map (kbd "u") 'ibuffer-unmark-forward)
-    (define-key map (kbd "=") 'ibuffer-diff-with-file)
-    (define-key map (kbd "j") 'ibuffer-jump-to-buffer)
-    (define-key map (kbd "M-g") 'ibuffer-jump-to-buffer)
-    (define-key map (kbd "M-s a C-s") 'ibuffer-do-isearch)
-    (define-key map (kbd "M-s a M-C-s") 'ibuffer-do-isearch-regexp)
-    (define-key map (kbd "M-s a C-o") 'ibuffer-do-occur)
-    (define-key map (kbd "DEL") 'ibuffer-unmark-backward)
-    (define-key map (kbd "M-DEL") 'ibuffer-unmark-all)
-    (define-key map (kbd "* *") 'ibuffer-unmark-all)
-    (define-key map (kbd "* c") 'ibuffer-change-marks)
-    (define-key map (kbd "U") 'ibuffer-unmark-all-marks)
-    (define-key map (kbd "* M") 'ibuffer-mark-by-mode)
-    (define-key map (kbd "* m") 'ibuffer-mark-modified-buffers)
-    (define-key map (kbd "* u") 'ibuffer-mark-unsaved-buffers)
-    (define-key map (kbd "* s") 'ibuffer-mark-special-buffers)
-    (define-key map (kbd "* r") 'ibuffer-mark-read-only-buffers)
-    (define-key map (kbd "* /") 'ibuffer-mark-dired-buffers)
-    (define-key map (kbd "* e") 'ibuffer-mark-dissociated-buffers)
-    (define-key map (kbd "* h") 'ibuffer-mark-help-buffers)
-    (define-key map (kbd "* z") 'ibuffer-mark-compressed-file-buffers)
-    (define-key map (kbd ".") 'ibuffer-mark-old-buffers)
-
-    (define-key map (kbd "d") 'ibuffer-mark-for-delete)
-    (define-key map (kbd "C-d") 'ibuffer-mark-for-delete-backwards)
-    (define-key map (kbd "k") 'ibuffer-mark-for-delete)
-    (define-key map (kbd "x") 'ibuffer-do-kill-on-deletion-marks)
-
-    ;; immediate operations
-    (define-key map (kbd "n") 'ibuffer-forward-line)
-    (define-key map (kbd "SPC") 'forward-line)
-    (define-key map (kbd "p") 'ibuffer-backward-line)
-    (define-key map (kbd "M-}") 'ibuffer-forward-next-marked)
-    (define-key map (kbd "M-{") 'ibuffer-backwards-next-marked)
-    (define-key map (kbd "l") 'ibuffer-redisplay)
-    (define-key map (kbd "g") 'ibuffer-update)
-    (define-key map "`" 'ibuffer-switch-format)
-    (define-key map "-" 'ibuffer-add-to-tmp-hide)
-    (define-key map "+" 'ibuffer-add-to-tmp-show)
-    (define-key map "b" 'ibuffer-bury-buffer)
-    (define-key map (kbd ",") 'ibuffer-toggle-sorting-mode)
-    (define-key map (kbd "s i") 'ibuffer-invert-sorting)
-    (define-key map (kbd "s a") 'ibuffer-do-sort-by-alphabetic)
-    (define-key map (kbd "s v") 'ibuffer-do-sort-by-recency)
-    (define-key map (kbd "s s") 'ibuffer-do-sort-by-size)
-    (define-key map (kbd "s f") 'ibuffer-do-sort-by-filename/process)
-    (define-key map (kbd "s m") 'ibuffer-do-sort-by-major-mode)
-
-    (define-key map (kbd "M-n") 'ibuffer-forward-filter-group)
-    (define-key map "\t" 'ibuffer-forward-filter-group)
-    (define-key map (kbd "M-p") 'ibuffer-backward-filter-group)
-    (define-key map [backtab] 'ibuffer-backward-filter-group)
-    (define-key map (kbd "M-j") 'ibuffer-jump-to-filter-group)
-    (define-key map (kbd "C-k") 'ibuffer-kill-line)
-    (define-key map (kbd "C-y") 'ibuffer-yank)
-
-    (define-key map (kbd "% n") 'ibuffer-mark-by-name-regexp)
-    (define-key map (kbd "% m") 'ibuffer-mark-by-mode-regexp)
-    (define-key map (kbd "% f") 'ibuffer-mark-by-file-name-regexp)
-    (define-key map (kbd "% g") 'ibuffer-mark-by-content-regexp)
-    (define-key map (kbd "% L") 'ibuffer-mark-by-locked)
-
-    (define-key map (kbd "C-t") 'ibuffer-visit-tags-table)
-
-    (define-key map (kbd "|") 'ibuffer-do-shell-command-pipe)
-    (define-key map (kbd "!") 'ibuffer-do-shell-command-file)
-    (define-key map (kbd "~") 'ibuffer-do-toggle-modified)
-    ;; marked operations
-    (define-key map (kbd "A") 'ibuffer-do-view)
-    (define-key map (kbd "D") 'ibuffer-do-delete)
-    (define-key map (kbd "E") 'ibuffer-do-eval)
-    (define-key map (kbd "F") 'ibuffer-do-shell-command-file)
-    (define-key map (kbd "I") 'ibuffer-do-query-replace-regexp)
-    (define-key map (kbd "H") 'ibuffer-do-view-other-frame)
-    (define-key map (kbd "N") 'ibuffer-do-shell-command-pipe-replace)
-    (define-key map (kbd "M") 'ibuffer-do-toggle-modified)
-    (define-key map (kbd "O") 'ibuffer-do-occur)
-    (define-key map (kbd "P") 'ibuffer-do-print)
-    (define-key map (kbd "Q") 'ibuffer-do-query-replace)
-    (define-key map (kbd "R") 'ibuffer-do-rename-uniquely)
-    (define-key map (kbd "S") 'ibuffer-do-save)
-    (define-key map (kbd "T") 'ibuffer-do-toggle-read-only)
-    (define-key map (kbd "L") 'ibuffer-do-toggle-lock)
-    (define-key map (kbd "r") 'ibuffer-do-replace-regexp)
-    (define-key map (kbd "V") 'ibuffer-do-revert)
-    (define-key map (kbd "W") 'ibuffer-do-view-and-eval)
-    (define-key map (kbd "X") 'ibuffer-do-shell-command-pipe)
-
-    (define-key map (kbd "k") 'ibuffer-do-kill-lines)
-    (define-key map (kbd "w") 'ibuffer-copy-filename-as-kill)
-    (define-key map (kbd "B") 'ibuffer-copy-buffername-as-kill)
-
-    (define-key map (kbd "RET") 'ibuffer-visit-buffer)
-    (define-key map (kbd "e") 'ibuffer-visit-buffer)
-    (define-key map (kbd "f") 'ibuffer-visit-buffer)
-    (define-key map (kbd "C-x C-f") 'ibuffer-find-file)
-    (define-key map (kbd "o") 'ibuffer-visit-buffer-other-window)
-    (define-key map (kbd "C-o") 'ibuffer-visit-buffer-other-window-noselect)
-    (define-key map (kbd "M-o") 'ibuffer-visit-buffer-1-window)
-    (define-key map (kbd "v") 'ibuffer-do-view)
-    (define-key map (kbd "C-x v") 'ibuffer-do-view-horizontally)
-    (define-key map (kbd "C-c C-a") 'ibuffer-auto-mode)
-    (define-key map (kbd "C-x 4 RET") 'ibuffer-visit-buffer-other-window)
-    (define-key map (kbd "C-x 5 RET") 'ibuffer-visit-buffer-other-frame)
-
-    (define-key map (kbd "/") ibuffer--filter-map)
-    map))
+(defvar-keymap ibuffer--filter-map
+  "RET"    #'ibuffer-filter-by-mode
+  "SPC"    #'ibuffer-filter-chosen-by-completion
+  "m"      #'ibuffer-filter-by-used-mode
+  "M"      #'ibuffer-filter-by-derived-mode
+  "n"      #'ibuffer-filter-by-name
+  "E"      #'ibuffer-filter-by-process
+  "*"      #'ibuffer-filter-by-starred-name
+  "f"      #'ibuffer-filter-by-filename
+  "F"      #'ibuffer-filter-by-directory
+  "b"      #'ibuffer-filter-by-basename
+  "."      #'ibuffer-filter-by-file-extension
+  "<"      #'ibuffer-filter-by-size-lt
+  ">"      #'ibuffer-filter-by-size-gt
+  "i"      #'ibuffer-filter-by-modified
+  "v"      #'ibuffer-filter-by-visiting-file
+  "c"      #'ibuffer-filter-by-content
+  "e"      #'ibuffer-filter-by-predicate
+
+  "r"      #'ibuffer-switch-to-saved-filters
+  "a"      #'ibuffer-add-saved-filters
+  "x"      #'ibuffer-delete-saved-filters
+  "d"      #'ibuffer-decompose-filter
+  "s"      #'ibuffer-save-filters
+  "p"      #'ibuffer-pop-filter
+  "<up>"   #'ibuffer-pop-filter
+  "!"      #'ibuffer-negate-filter
+  "t"      #'ibuffer-exchange-filters
+  "TAB"    #'ibuffer-exchange-filters
+  "o"      #'ibuffer-or-filter
+  "|"      #'ibuffer-or-filter
+  "&"      #'ibuffer-and-filter
+  "g"      #'ibuffer-filters-to-filter-group
+  "P"      #'ibuffer-pop-filter-group
+  "S-<up>" #'ibuffer-pop-filter-group
+  "D"      #'ibuffer-decompose-filter-group
+  "/"      #'ibuffer-filter-disable
+
+  "S"      #'ibuffer-save-filter-groups
+  "R"      #'ibuffer-switch-to-saved-filter-groups
+  "X"      #'ibuffer-delete-saved-filter-groups
+  "\\"     #'ibuffer-clear-filter-groups)
+
+(defvar-keymap ibuffer-mode-map
+  :full t
+  "0"           #'digit-argument
+  "1"           #'digit-argument
+  "2"           #'digit-argument
+  "3"           #'digit-argument
+  "4"           #'digit-argument
+  "5"           #'digit-argument
+  "6"           #'digit-argument
+  "7"           #'digit-argument
+  "8"           #'digit-argument
+  "9"           #'digit-argument
+
+  "m"           #'ibuffer-mark-forward
+  "t"           #'ibuffer-toggle-marks
+  "u"           #'ibuffer-unmark-forward
+  "="           #'ibuffer-diff-with-file
+  "j"           #'ibuffer-jump-to-buffer
+  "M-g"         #'ibuffer-jump-to-buffer
+  "M-s a C-s"   #'ibuffer-do-isearch
+  "M-s a C-M-s" #'ibuffer-do-isearch-regexp
+  "M-s a C-o"   #'ibuffer-do-occur
+  "DEL"         #'ibuffer-unmark-backward
+  "M-DEL"       #'ibuffer-unmark-all
+  "* *"         #'ibuffer-unmark-all
+  "* c"         #'ibuffer-change-marks
+  "U"           #'ibuffer-unmark-all-marks
+  "* M"         #'ibuffer-mark-by-mode
+  "* m"         #'ibuffer-mark-modified-buffers
+  "* u"         #'ibuffer-mark-unsaved-buffers
+  "* s"         #'ibuffer-mark-special-buffers
+  "* r"         #'ibuffer-mark-read-only-buffers
+  "* /"         #'ibuffer-mark-dired-buffers
+  "* e"         #'ibuffer-mark-dissociated-buffers
+  "* h"         #'ibuffer-mark-help-buffers
+  "* z"         #'ibuffer-mark-compressed-file-buffers
+  "."           #'ibuffer-mark-old-buffers
+
+  "d"           #'ibuffer-mark-for-delete
+  "C-d"         #'ibuffer-mark-for-delete-backwards
+  "x"           #'ibuffer-do-kill-on-deletion-marks
+
+  ;; immediate operations
+  "n"           #'ibuffer-forward-line
+  "SPC"         #'forward-line
+  "p"           #'ibuffer-backward-line
+  "M-}"         #'ibuffer-forward-next-marked
+  "M-{"         #'ibuffer-backwards-next-marked
+  "l"           #'ibuffer-redisplay
+  "g"           #'ibuffer-update
+  "`"           #'ibuffer-switch-format
+  "-"           #'ibuffer-add-to-tmp-hide
+  "+"           #'ibuffer-add-to-tmp-show
+  "b"           #'ibuffer-bury-buffer
+  ","           #'ibuffer-toggle-sorting-mode
+  "s i"         #'ibuffer-invert-sorting
+  "s a"         #'ibuffer-do-sort-by-alphabetic
+  "s v"         #'ibuffer-do-sort-by-recency
+  "s s"         #'ibuffer-do-sort-by-size
+  "s f"         #'ibuffer-do-sort-by-filename/process
+  "s m"         #'ibuffer-do-sort-by-major-mode
+
+  "M-n"         #'ibuffer-forward-filter-group
+  "TAB"         #'ibuffer-forward-filter-group
+  "M-p"         #'ibuffer-backward-filter-group
+  "<backtab>"   #'ibuffer-backward-filter-group
+  "M-j"         #'ibuffer-jump-to-filter-group
+  "C-k"         #'ibuffer-kill-line
+  "C-y"         #'ibuffer-yank
+
+  "% n"         #'ibuffer-mark-by-name-regexp
+  "% m"         #'ibuffer-mark-by-mode-regexp
+  "% f"         #'ibuffer-mark-by-file-name-regexp
+  "% g"         #'ibuffer-mark-by-content-regexp
+  "% L"         #'ibuffer-mark-by-locked
+
+  "C-t"         #'ibuffer-visit-tags-table
+
+  "|"           #'ibuffer-do-shell-command-pipe
+  "!"           #'ibuffer-do-shell-command-file
+  "~"           #'ibuffer-do-toggle-modified
+  ;; marked operations
+  "A"           #'ibuffer-do-view
+  "D"           #'ibuffer-do-delete
+  "E"           #'ibuffer-do-eval
+  "F"           #'ibuffer-do-shell-command-file
+  "I"           #'ibuffer-do-query-replace-regexp
+  "H"           #'ibuffer-do-view-other-frame
+  "N"           #'ibuffer-do-shell-command-pipe-replace
+  "M"           #'ibuffer-do-toggle-modified
+  "O"           #'ibuffer-do-occur
+  "P"           #'ibuffer-do-print
+  "Q"           #'ibuffer-do-query-replace
+  "R"           #'ibuffer-do-rename-uniquely
+  "S"           #'ibuffer-do-save
+  "T"           #'ibuffer-do-toggle-read-only
+  "L"           #'ibuffer-do-toggle-lock
+  "r"           #'ibuffer-do-replace-regexp
+  "V"           #'ibuffer-do-revert
+  "W"           #'ibuffer-do-view-and-eval
+  "X"           #'ibuffer-do-shell-command-pipe
+
+  "k"           #'ibuffer-do-kill-lines
+  "w"           #'ibuffer-copy-filename-as-kill
+  "B"           #'ibuffer-copy-buffername-as-kill
+
+  "RET"         #'ibuffer-visit-buffer
+  "e"           #'ibuffer-visit-buffer
+  "f"           #'ibuffer-visit-buffer
+  "C-x C-f"     #'ibuffer-find-file
+  "o"           #'ibuffer-visit-buffer-other-window
+  "C-o"         #'ibuffer-visit-buffer-other-window-noselect
+  "M-o"         #'ibuffer-visit-buffer-1-window
+  "v"           #'ibuffer-do-view
+  "C-x v"       #'ibuffer-do-view-horizontally
+  "C-c C-a"     #'ibuffer-auto-mode
+  "C-x 4 RET"   #'ibuffer-visit-buffer-other-window
+  "C-x 5 RET"   #'ibuffer-visit-buffer-other-frame
+
+  "/"           ibuffer--filter-map)
 
 (defun ibuffer-mode--groups-menu-definition (&optional is-popup)
   "Build the `ibuffer' \"Filter\" menu.  Internal."
@@ -758,46 +754,32 @@ directory, like `default-directory'."
     ["Diff with file" ibuffer-diff-with-file
      :help "View the differences between this buffer and its file"]))
 
-(defvar ibuffer-name-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map [(mouse-1)] 'ibuffer-mouse-toggle-mark)
-    (define-key map [(mouse-2)] 'ibuffer-mouse-visit-buffer)
-    (define-key map [down-mouse-3] 'ibuffer-mouse-popup-menu)
-    map))
-
-(defvar ibuffer-filename/process-header-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map [(mouse-1)] 'ibuffer-do-sort-by-filename/process)
-    map))
-
-(defvar ibuffer-mode-name-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map [(mouse-2)] 'ibuffer-mouse-filter-by-mode)
-    (define-key map (kbd "RET") 'ibuffer-interactive-filter-by-mode)
-    map))
-
-(defvar ibuffer-name-header-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map [(mouse-1)] 'ibuffer-do-sort-by-alphabetic)
-    map))
-
-(defvar ibuffer-size-header-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map [(mouse-1)] 'ibuffer-do-sort-by-size)
-    map))
-
-(defvar ibuffer-mode-header-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map [(mouse-1)] 'ibuffer-do-sort-by-major-mode)
-    map))
-
-(defvar ibuffer-mode-filter-group-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map [(mouse-1)] 'ibuffer-mouse-toggle-mark)
-    (define-key map [(mouse-2)] 'ibuffer-mouse-toggle-filter-group)
-    (define-key map (kbd "RET") 'ibuffer-toggle-filter-group)
-    (define-key map [down-mouse-3] 'ibuffer-mouse-popup-menu)
-    map))
+(defvar-keymap ibuffer-name-map
+  "<mouse-1>"      #'ibuffer-mouse-toggle-mark
+  "<mouse-2>"      #'ibuffer-mouse-visit-buffer
+  "<down-mouse-3>" #'ibuffer-mouse-popup-menu)
+
+(defvar-keymap ibuffer-filename/process-header-map
+  "<mouse-1>"      #'ibuffer-do-sort-by-filename/process)
+
+(defvar-keymap ibuffer-mode-name-map
+  "<mouse-2>"      #'ibuffer-mouse-filter-by-mode
+  "RET"            #'ibuffer-interactive-filter-by-mode)
+
+(defvar-keymap ibuffer-name-header-map
+  "<mouse-1>"      #'ibuffer-do-sort-by-alphabetic)
+
+(defvar-keymap ibuffer-size-header-map
+  "<mouse-1>"      #'ibuffer-do-sort-by-size)
+
+(defvar-keymap ibuffer-mode-header-map
+  "<mouse-1>"      #'ibuffer-do-sort-by-major-mode)
+
+(defvar-keymap ibuffer-mode-filter-group-map
+  "<mouse-1>"      #'ibuffer-mouse-toggle-mark
+  "<mouse-2>"      #'ibuffer-mouse-toggle-filter-group
+  "RET"            #'ibuffer-toggle-filter-group
+  "<down-mouse-3>" #'ibuffer-mouse-popup-menu)
 
 (defvar ibuffer-did-modification nil)
 
@@ -850,7 +832,7 @@ width and the longest string in LIST."
       (let ((pt (save-excursion
                  (mouse-set-point event)
                  (point))))
-       (ibuffer-aif (get-text-property (point) 'ibuffer-filter-group-name)
+        (if-let ((it (get-text-property (point) 'ibuffer-filter-group-name)))
            (ibuffer-toggle-marks it)
          (goto-char pt)
          (let ((mark (ibuffer-current-mark)))
@@ -1281,8 +1263,8 @@ become unmarked.
 If point is on a group name, then this function operates on that
 group."
   (interactive)
-  (ibuffer-aif (get-text-property (point) 'ibuffer-filter-group-name)
-      (setq group it))
+  (when-let ((it (get-text-property (point) 'ibuffer-filter-group-name)))
+    (setq group it))
   (let ((count
         (ibuffer-map-lines
          (lambda (_buf mark)
@@ -1354,7 +1336,7 @@ If point is on a group name, this function operates on 
that group."
   (when (and movement (< movement 0))
     (setq arg (- arg)))
   (ibuffer-forward-line 0)
-  (ibuffer-aif (get-text-property (point) 'ibuffer-filter-group-name)
+  (if-let ((it (get-text-property (point) 'ibuffer-filter-group-name)))
       (progn
        (require 'ibuf-ext)
        (ibuffer-mark-on-buffer #'identity mark it))
@@ -1558,7 +1540,7 @@ If point is on a group name, this function operates on 
that group."
                    ;; `ibuffer-inline-columns' alist and insert it
                    ;; into our generated code.  Otherwise, we just
                    ;; generate a call to the column function.
-                   (ibuffer-aif (assq sym ibuffer-inline-columns)
+                    (if-let ((it (assq sym ibuffer-inline-columns)))
                        (nth 1 it)
                      `(or (,sym buffer mark) "")))
                   ;; You're not expected to understand this.  Hell, I
@@ -1755,7 +1737,7 @@ If point is on a group name, this function operates on 
that group."
        (cond ((zerop total) "No processes")
             ((= 1 total) "1 process")
             (t (format "%d processes" total))))))
-  (ibuffer-aif (get-buffer-process buffer)
+  (if-let ((it (get-buffer-process buffer)))
       (format "(%s %s)" it (process-status it))
     ""))
 
@@ -1890,8 +1872,8 @@ the buffer object itself and the current mark symbol."
            (let ((result
                   (if (buffer-live-p (ibuffer-current-buffer))
                       (when (or (null group)
-                                (ibuffer-aif (get-text-property (point) 
'ibuffer-filter-group)
-                                    (equal group it)))
+                                 (when-let ((it (get-text-property (point) 
'ibuffer-filter-group)))
+                                   (equal group it)))
                         (save-excursion
                           (funcall function
                                    (ibuffer-current-buffer)
@@ -2350,7 +2332,18 @@ FORMATS is the value to use for `ibuffer-formats'.
              (run-hooks 'ibuffer-hook))
          (setq buffer-read-only t))
        (unless ibuffer-expert
-         (message "Commands: m, u, t, RET, g, k, S, D, Q; q to quit; h for 
help"))))))
+          (message (substitute-command-keys
+                    (concat "Commands: \\[ibuffer-mark-forward], "
+                            "\\[ibuffer-unmark-forward], "
+                            "\\[ibuffer-toggle-marks], "
+                            "\\[ibuffer-visit-buffer], "
+                            "\\[ibuffer-update], "
+                            "\\[ibuffer-do-kill-lines], "
+                            "\\[ibuffer-do-save], "
+                            "\\[ibuffer-do-delete], "
+                            "\\[ibuffer-do-query-replace]; "
+                            "\\[quit-window] to quit; "
+                            "\\[describe-mode] for help"))))))))
 
 ;;;###autoload
 (defun ibuffer-jump (&optional other-window)
diff --git a/lisp/icomplete.el b/lisp/icomplete.el
index be7f6831cc..b1fcf9ae71 100644
--- a/lisp/icomplete.el
+++ b/lisp/icomplete.el
@@ -81,7 +81,7 @@ selection process starts again from the user's $HOME.")
 This means to show completions even when the current minibuffer contents
 is the same as was the initial input after minibuffer activation.
 This also means that if you traverse the list of completions with
-commands like `C-.' and just hit RET without typing any
+commands like \\`C-.' and just hit \\`RET' without typing any
 characters, the match under point will be chosen instead of the
 default."
   :type 'boolean
@@ -370,7 +370,7 @@ require user confirmation."
 (defun icomplete-fido-exit (force)
   "Attempt to exit minibuffer immediately with current input.
 Unless FORCE is non-nil (interactively with a prefix argument),
-honour a non-nil REQUIRE-MATCH argument to `completing-read' by
+honor a non-nil REQUIRE-MATCH argument to `completing-read' by
 trying to complete as much as possible and disallowing the exit
 if that doesn't produce a completion match."
   (interactive "P")
@@ -595,7 +595,7 @@ Usually run by inclusion in `minibuffer-setup-hook'."
                           ;; select it -- again, as desired.
                           ;;
                           ;; FIXME: it's arguable that this second
-                          ;; behaviour should be a property of the
+                          ;; behavior should be a property of the
                           ;; completion table and not the completion
                           ;; frontend such as we have done
                           ;; here. However, it seems generically
@@ -840,13 +840,13 @@ by `group-function''s second \"transformation\" protocol."
                                           while (listp r)
                                           count 1))
            repeat total-space
-           for neighbour = nil
+           for neighbor = nil
            if (and preds (> space-above 0)) do
-           (push (setq neighbour (pop preds)) scroll-above)
+           (push (setq neighbor (pop preds)) scroll-above)
            (cl-decf space-above)
            else if (consp succs) collect
-           (setq neighbour (pop succs)) into scroll-below-aux
-           while neighbour
+           (setq neighbor (pop succs)) into scroll-below-aux
+           while neighbor
            finally (setq scroll-below scroll-below-aux))
   ;; Halfway there...
   (let* ((selected (propertize (car comps) 'icomplete-selected t))
diff --git a/lisp/ido.el b/lisp/ido.el
index f970fce1ed..520513b1d2 100644
--- a/lisp/ido.el
+++ b/lisp/ido.el
@@ -554,7 +554,7 @@ See `ido-last-directory-list' and 
`ido-save-directory-list-file'."
   "Maximum number of working directories to record.
 This is the list of directories where files have most recently been opened.
 See `ido-work-directory-list' and `ido-save-directory-list-file'."
-  :type 'integer)
+  :type 'natnum)
 
 (defcustom ido-work-directory-list-ignore-regexps nil
   "List of regexps matching directories which should not be recorded.
@@ -3205,12 +3205,18 @@ instead removed from the current item list."
 ;; File list sorting
 
 (defun ido-file-lessp (a b)
-  ;; Simple compare two file names.
+  "Simple compare two file names."
+  (when ido-case-fold
+    (setq a (downcase a)
+          b (downcase b)))
   (string-lessp (ido-no-final-slash a) (ido-no-final-slash b)))
 
 
 (defun ido-file-extension-lessp (a b)
-  ;; Compare file names according to ido-file-extensions-order list.
+  "Compare file names according to ido-file-extensions-order list."
+  (when ido-case-fold
+    (setq a (downcase a)
+          b (downcase b)))
   (let ((n (compare-strings a 0 nil b 0 nil nil))
        lessp p)
     (if (eq n t)
@@ -3960,7 +3966,7 @@ If `ido-change-word-sub' cannot be found in WORD, return 
nil."
     (if (and (eq last-command this-command) temp-buf)
        ;; scroll buffer
        (let (win (buf (current-buffer)))
-         (display-buffer temp-buf nil nil)
+         (display-buffer temp-buf)
          (set-buffer temp-buf)
          (setq win (get-buffer-window temp-buf))
          (if (pos-visible-in-window-p (point-max) win)
@@ -3975,7 +3981,10 @@ If `ido-change-word-sub' cannot be found in WORD, return 
nil."
          (set-buffer buf))
       (setq display-it t))
     (if (and ido-completion-buffer display-it)
-       (with-output-to-temp-buffer ido-completion-buffer
+       (with-temp-buffer-window ido-completion-buffer
+            '((display-buffer-reuse-window display-buffer-at-bottom)
+              (window-height . fit-window-to-buffer))
+            nil
          (let* ((comps
                  (cond
                   (ido-directory-too-big
diff --git a/lisp/iimage.el b/lisp/iimage.el
index 8a765d5e5d..baeb4bb6a7 100644
--- a/lisp/iimage.el
+++ b/lisp/iimage.el
@@ -87,9 +87,6 @@ Examples of image filename patterns to match:
   (iimage-mode-buffer t)
   (recenter-top-bottom arg))
 
-;;;###autoload
-(define-obsolete-function-alias 'turn-on-iimage-mode 'iimage-mode "24.1")
-
 (defun turn-off-iimage-mode ()
   "Unconditionally turn off iimage mode."
   (interactive)
diff --git a/lisp/image-dired.el b/lisp/image-dired.el
index 30bf5ee108..9f12354111 100644
--- a/lisp/image-dired.el
+++ b/lisp/image-dired.el
@@ -913,7 +913,7 @@ Otherwise, delete overlays."
   (interactive)
   (setq image-dired-dired-disp-props
         (not image-dired-dired-disp-props))
-  (message "Dired display properties %s."
+  (message "Dired display properties %s"
            (if image-dired-dired-disp-props
                "on"
              "off")))
@@ -1464,7 +1464,7 @@ Should be called from commands in 
`image-dired-thumbnail-mode'."
   `(let ((file-name (image-dired-original-file-name))
          (dired-buf (image-dired-associated-dired-buffer)))
      (if (not (and dired-buf file-name))
-         (message "No image, or image with correct properties, at point.")
+         (message "No image, or image with correct properties, at point")
        (with-current-buffer dired-buf
          (when (dired-goto-file file-name)
            ,@body
@@ -1978,8 +1978,8 @@ based on `image-mode'."
         (cur-win (selected-window)))
     (when buf
       (kill-buffer buf))
-    (when-let ((buf (find-file-other-window file)))
-      (display-buffer buf)
+    (when-let ((buf (find-file-noselect file nil t)))
+      (pop-to-buffer buf)
       (rename-buffer image-dired-display-image-buffer)
       (image-dired-display-image-mode)
       (select-window cur-win))))
@@ -2106,7 +2106,7 @@ default value at the prompt."
               (image-dired-set-exif-data file "ImageDescription"
                                    (read-string "Value of ImageDescription: "
                                                old-value)))
-          (message "Successfully wrote ImageDescription tag.")
+          (message "Successfully wrote ImageDescription tag")
         (error "Could not write ImageDescription tag")))))
 
 (defun image-dired-set-exif-data (file tag-name tag-value)
@@ -2295,7 +2295,7 @@ matching tag will be marked in the Dired buffer."
        (when (search-forward-regexp (format "\\s %s$" curr-file) nil t)
          (setq hits (+ hits 1))
          (dired-mark 1))))
-    (message "%d files with matching tag marked." hits)))
+    (message "%d files with matching tag marked" hits)))
 
 
 
@@ -2728,14 +2728,14 @@ the operation by activating the Cancel button.\n\n")
                  (lambda (&rest _ignore)
                    (image-dired-save-information-from-widgets)
                    (bury-buffer)
-                   (message "Done."))
+                   (message "Done"))
                  "Save")
     (widget-insert " ")
     (widget-create 'push-button
                    :notify
                    (lambda (&rest _ignore)
                      (bury-buffer)
-                     (message "Operation canceled."))
+                     (message "Operation canceled"))
                    "Cancel")
     (widget-insert "\n")
     (use-local-map widget-keymap)
@@ -2795,7 +2795,7 @@ tags to their respective image file.  Internal function 
used by
     ;; (bookmark-prop-get bookmark 'image-dired-file)
     (goto-char (point-min))))
 
-(put 'image-dired-bookmark-jump 'bookmark-handler-type "Image")
+(put 'image-dired-bookmark-jump 'bookmark-handler-type "Image-Dired")
 
 ;;; Obsolete
 
@@ -2973,7 +2973,7 @@ Dired."
   (let ((file-name (image-dired-original-file-name))
         (dired-buf (image-dired-associated-dired-buffer)))
     (if (not (and dired-buf file-name))
-        (message "No image, or image with correct properties, at point.")
+        (message "No image, or image with correct properties, at point")
     (with-current-buffer dired-buf
         (message "%s" file-name)
         (when (dired-goto-file file-name)
diff --git a/lisp/image-mode.el b/lisp/image-mode.el
index ea5d7ff0f3..9485f1e006 100644
--- a/lisp/image-mode.el
+++ b/lisp/image-mode.el
@@ -23,10 +23,14 @@
 
 ;;; Commentary:
 
-;; Defines a major mode for visiting image files
-;; that allows conversion between viewing the text of the file,
-;; hex of the file and viewing the file as an image.  Viewing the image
-;; works by putting a `display' text-property on the
+;; Defines `image-mode', a major mode for visiting image files.  Displaying
+;; images only works if Emacs was built with support for displaying
+;; such images.  See Info node `(emacs) Image Mode' for more
+;; information.
+;;
+;; There is support for switching between viewing the text of the
+;; file, the hex of the file and viewing the file as an image.
+;; Viewing the image works by putting a `display' text-property on the
 ;; image data, with the image-data still present underneath; if the
 ;; resulting buffer file is saved to another name it will correctly save
 ;; the image data to the new file.
@@ -238,7 +242,7 @@ image."
 (defun image-forward-hscroll (&optional n)
   "Scroll image in current window to the left by N character widths.
 Stop if the right edge of the image is reached."
-  (interactive "p")
+  (interactive "p" image-mode)
   (cond ((= n 0) nil)
        ((< n 0)
         (image-set-window-hscroll (max 0 (+ (window-hscroll) n))))
@@ -253,13 +257,13 @@ Stop if the right edge of the image is reached."
 (defun image-backward-hscroll (&optional n)
   "Scroll image in current window to the right by N character widths.
 Stop if the left edge of the image is reached."
-  (interactive "p")
+  (interactive "p" image-mode)
   (image-forward-hscroll (- n)))
 
 (defun image-next-line (n)
   "Scroll image in current window upward by N lines.
 Stop if the bottom edge of the image is reached."
-  (interactive "p")
+  (interactive "p" image-mode)
   ;; Convert N to pixels.
   (setq n (* n (frame-char-height)))
   (cond ((= n 0) nil)
@@ -276,7 +280,7 @@ Stop if the bottom edge of the image is reached."
 (defun image-previous-line (&optional n)
   "Scroll image in current window downward by N lines.
 Stop if the top edge of the image is reached."
-  (interactive "p")
+  (interactive "p" image-mode)
   (image-next-line (- n)))
 
 (defun image-scroll-up (&optional n)
@@ -286,7 +290,7 @@ Stop if the bottom edge of the image is reached.
 Interactively, giving this command a numerical prefix will scroll
 up by that many lines (and down by that many lines if the number
 is negative).  Without a prefix, scroll up by a full screen.
-If given a `C-u -' prefix, scroll a full page down instead.
+If given a \\`C-u -' prefix, scroll a full page down instead.
 
 If N is omitted or nil, scroll upward by a near full screen.
 A near full screen is `next-screen-context-lines' less than a full screen.
@@ -294,7 +298,7 @@ A negative N means scroll downward.
 
 If N is the atom `-', scroll downward by nearly full screen.
 When calling from a program, supply as argument a number, nil, or `-'."
-  (interactive "P")
+  (interactive "P" image-mode)
   (cond ((null n)
         (let* ((edges (window-inside-edges))
                (win-height (- (nth 3 edges) (nth 1 edges))))
@@ -314,7 +318,7 @@ Stop if the top edge of the image is reached.
 Interactively, giving this command a numerical prefix will scroll
 down by that many lines (and up by that many lines if the number
 is negative).  Without a prefix, scroll down by a full screen.
-If given a `C-u -' prefix, scroll a full page up instead.
+If given a \\`C-u -' prefix, scroll a full page up instead.
 
 If N is omitted or nil, scroll downward by a near full screen.
 A near full screen is `next-screen-context-lines' less than a full screen.
@@ -322,7 +326,7 @@ A negative N means scroll upward.
 
 If N is the atom `-', scroll upward by nearly full screen.
 When calling from a program, supply as argument a number, nil, or `-'."
-  (interactive "P")
+  (interactive "P" image-mode)
   (cond ((null n)
         (let* ((edges (window-inside-edges))
                (win-height (- (nth 3 edges) (nth 1 edges))))
@@ -343,7 +347,7 @@ A near full screen is 2 columns less than a full screen.
 Negative ARG means scroll rightward.
 If ARG is the atom `-', scroll rightward by nearly full screen.
 When calling from a program, supply as argument a number, nil, or `-'."
-  (interactive "P")
+  (interactive "P" image-mode)
   (cond ((null n)
         (let* ((edges (window-inside-edges))
                (win-width (- (nth 2 edges) (nth 0 edges))))
@@ -364,7 +368,7 @@ A near full screen is 2 less than a full screen.
 Negative ARG means scroll leftward.
 If ARG is the atom `-', scroll leftward by nearly full screen.
 When calling from a program, supply as argument a number, nil, or `-'."
-  (interactive "P")
+  (interactive "P" image-mode)
   (cond ((null n)
         (let* ((edges (window-inside-edges))
                (win-width (- (nth 2 edges) (nth 0 edges))))
@@ -381,7 +385,7 @@ When calling from a program, supply as argument a number, 
nil, or `-'."
   "Scroll horizontally to the left edge of the image in the current window.
 With argument ARG not nil or 1, move forward ARG - 1 lines first,
 stopping if the top or bottom edge of the image is reached."
-  (interactive "p")
+  (interactive "p" image-mode)
   (and arg
        (/= (setq arg (prefix-numeric-value arg)) 1)
        (image-next-line (- arg 1)))
@@ -391,7 +395,7 @@ stopping if the top or bottom edge of the image is reached."
   "Scroll horizontally to the right edge of the image in the current window.
 With argument ARG not nil or 1, move forward ARG - 1 lines first,
 stopping if the top or bottom edge of the image is reached."
-  (interactive "p")
+  (interactive "p" image-mode)
   (and arg
        (/= (setq arg (prefix-numeric-value arg)) 1)
        (image-next-line (- arg 1)))
@@ -403,13 +407,13 @@ stopping if the top or bottom edge of the image is 
reached."
 
 (defun image-bob ()
   "Scroll to the top-left corner of the image in the current window."
-  (interactive)
+  (interactive nil image-mode)
   (image-set-window-hscroll 0)
   (image-set-window-vscroll 0))
 
 (defun image-eob ()
   "Scroll to the bottom-right corner of the image in the current window."
-  (interactive)
+  (interactive nil image-mode)
   (let* ((image (image-get-display-property))
         (edges (window-inside-edges))
         (pixel-edges (window-edges nil t t))
@@ -431,7 +435,7 @@ If called interactively, or if TOGGLE is non-nil, toggle 
between
 fitting FRAME to the current image and restoring the size and
 window configuration prior to the last `image-mode-fit-frame'
 call."
-  (interactive (list nil t))
+  (interactive (list nil t) image-mode)
   (let* ((buffer (current-buffer))
         (saved (frame-parameter frame 'image-mode-saved-params))
         (window-configuration (current-window-configuration frame))
@@ -476,156 +480,156 @@ image as text, when opening such images in 
`image-mode'."
 (defvar-local image-multi-frame nil
   "Non-nil if image for the current Image mode buffer has multiple frames.")
 
-(defvar image-mode-map
-  (let ((map (make-sparse-keymap)))
-
-    ;; Toggling keys
-    (define-key map "\C-c\C-c" 'image-toggle-display)
-    (define-key map "\C-c\C-x" 'image-toggle-hex-display)
-
-    ;; Transformation keys
-    (define-key map "sf" 'image-mode-fit-frame)
-    (define-key map "sw" 'image-transform-fit-to-window)
-    (define-key map "sh" 'image-transform-fit-to-height)
-    (define-key map "si" 'image-transform-fit-to-width)
-    (define-key map "sb" 'image-transform-fit-both)
-    (define-key map "ss" 'image-transform-set-scale)
-    (define-key map "sr" 'image-transform-set-rotation)
-    (define-key map "sm" 'image-transform-set-smoothing)
-    (define-key map "so" 'image-transform-original)
-    (define-key map "s0" 'image-transform-reset)
-
-    ;; Multi-frame keys
-    (define-key map (kbd "RET") 'image-toggle-animation)
-    (define-key map "F" 'image-goto-frame)
-    (define-key map "f" 'image-next-frame)
-    (define-key map "b" 'image-previous-frame)
-    (define-key map "a+" 'image-increase-speed)
-    (define-key map "a-" 'image-decrease-speed)
-    (define-key map "a0" 'image-reset-speed)
-    (define-key map "ar" 'image-reverse-speed)
-
-    ;; File keys
-    (define-key map "n" 'image-next-file)
-    (define-key map "p" 'image-previous-file)
-    (define-key map "w" 'image-mode-copy-file-name-as-kill)
-    (define-key map "m" 'image-mode-mark-file)
-    (define-key map "u" 'image-mode-unmark-file)
-
-    ;; Scrolling keys
-    (define-key map (kbd "SPC")   'image-scroll-up)
-    (define-key map (kbd "S-SPC") 'image-scroll-down)
-    (define-key map (kbd "DEL")   'image-scroll-down)
-    (define-key map [remap forward-char] 'image-forward-hscroll)
-    (define-key map [remap backward-char] 'image-backward-hscroll)
-    (define-key map [remap right-char] 'image-forward-hscroll)
-    (define-key map [remap left-char] 'image-backward-hscroll)
-    (define-key map [remap previous-line] 'image-previous-line)
-    (define-key map [remap next-line] 'image-next-line)
-    (define-key map [remap scroll-up] 'image-scroll-up)
-    (define-key map [remap scroll-down] 'image-scroll-down)
-    (define-key map [remap scroll-up-command] 'image-scroll-up)
-    (define-key map [remap scroll-down-command] 'image-scroll-down)
-    (define-key map [remap scroll-left] 'image-scroll-left)
-    (define-key map [remap scroll-right] 'image-scroll-right)
-    (define-key map [remap move-beginning-of-line] 'image-bol)
-    (define-key map [remap move-end-of-line] 'image-eol)
-    (define-key map [remap beginning-of-buffer] 'image-bob)
-    (define-key map [remap end-of-buffer] 'image-eob)
-
-    (easy-menu-define image-mode-menu map "Menu for Image mode."
-      '("Image"
-       ["Show as Text" image-toggle-display :active t
-        :help "Show image as text"]
+(defvar-keymap image-mode-map
+  :doc "Mode keymap for `image-mode'."
+  :parent (make-composed-keymap image-map special-mode-map)
+
+  ;; Toggling keys
+  "C-c C-c" #'image-toggle-display
+  "C-c C-x" #'image-toggle-hex-display
+
+  ;; Transformation keys
+  "s f"     #'image-mode-fit-frame
+  "s w"     #'image-transform-fit-to-window
+  "s h"     #'image-transform-fit-to-height
+  "s i"     #'image-transform-fit-to-width
+  "s b"     #'image-transform-fit-both
+  "s p"     #'image-transform-set-percent
+  "s s"     #'image-transform-set-scale
+  "s r"     #'image-transform-set-rotation
+  "s m"     #'image-transform-set-smoothing
+  "s o"     #'image-transform-original
+  "s 0"     #'image-transform-reset
+
+  ;; Multi-frame keys
+  "RET"     #'image-toggle-animation
+  "F"       #'image-goto-frame
+  "f"       #'image-next-frame
+  "b"       #'image-previous-frame
+  "a +"     #'image-increase-speed
+  "a -"     #'image-decrease-speed
+  "a 0"     #'image-reset-speed
+  "a r"     #'image-reverse-speed
+
+  ;; File keys
+  "n"       #'image-next-file
+  "p"       #'image-previous-file
+  "w"       #'image-mode-copy-file-name-as-kill
+  "m"       #'image-mode-mark-file
+  "u"       #'image-mode-unmark-file
+
+  ;; Scrolling keys
+  "SPC"     #'image-scroll-up
+  "S-SPC"   #'image-scroll-down
+  "DEL"     #'image-scroll-down
+
+  ;; Remapped
+  "<remap> <forward-char>"           #'image-forward-hscroll
+  "<remap> <backward-char>"          #'image-backward-hscroll
+  "<remap> <right-char>"             #'image-forward-hscroll
+  "<remap> <left-char>"              #'image-backward-hscroll
+  "<remap> <previous-line>"          #'image-previous-line
+  "<remap> <next-line>"              #'image-next-line
+  "<remap> <scroll-up>"              #'image-scroll-up
+  "<remap> <scroll-down>"            #'image-scroll-down
+  "<remap> <scroll-up-command>"      #'image-scroll-up
+  "<remap> <scroll-down-command>"    #'image-scroll-down
+  "<remap> <scroll-left>"            #'image-scroll-left
+  "<remap> <scroll-right>"           #'image-scroll-right
+  "<remap> <move-beginning-of-line>" #'image-bol
+  "<remap> <move-end-of-line>"       #'image-eol
+  "<remap> <beginning-of-buffer>"    #'image-bob
+  "<remap> <end-of-buffer>"          #'image-eob)
+
+(easy-menu-define image-mode-menu image-mode-map
+  "Menu for Image mode."
+  '("Image"
+    ["Show as Text" image-toggle-display :active t
+     :help "Show image as text"]
     ["Show as Hex" image-toggle-hex-display :active t
      :help "Show image as hex"]
-       "--"
-       ["Fit Frame to Image" image-mode-fit-frame :active t
-        :help "Resize frame to match image"]
-        ["Fit Image to Window" image-transform-fit-to-window
-         :help "Resize image to match the window height and width"]
-        ["Fit Image to Window (Scale down only)" image-transform-fit-both
-         :help "Scale image down to match the window height and width"]
-       ["Zoom In" image-increase-size
-        :help "Enlarge the image"]
-       ["Zoom Out" image-decrease-size
-        :help "Shrink the image"]
-       ["Set Scale..." image-transform-set-scale
-        :help "Resize image by specified scale factor"]
-       ["Rotate Clockwise" image-rotate
-        :help "Rotate the image"]
-       ["Set Rotation..." image-transform-set-rotation
-        :help "Set rotation angle of the image"]
-        ["Set Smoothing..." image-transform-set-smoothing
-        :help "Toggle smoothing"]
-       ["Original Size" image-transform-original
-        :help "Reset image to actual size"]
-       ["Reset to Default Size" image-transform-reset
-        :help "Reset all image transformations to initial size"]
-       "--"
-       ["Show Thumbnails"
-        (lambda ()
-          (interactive)
-          (image-dired default-directory))
-        :active default-directory
-        :help "Show thumbnails for all images in this directory"]
-       ["Previous Image" image-previous-file :active buffer-file-name
-         :help "Move to previous image in this directory"]
-       ["Next Image" image-next-file :active buffer-file-name
-         :help "Move to next image in this directory"]
-       ["Copy File Name" image-mode-copy-file-name-as-kill
-         :active buffer-file-name
-         :help "Copy the current file name to the kill ring"]
-       "--"
-       ["Animate Image" image-toggle-animation :style toggle
-        :selected (let ((image (image-get-display-property)))
-                    (and image (image-animate-timer image)))
-        :active image-multi-frame
-         :help "Toggle image animation"]
-       ["Loop Animation"
-        (lambda () (interactive)
-          (setq image-animate-loop (not image-animate-loop))
-          ;; FIXME this is a hacky way to make it affect a currently
-          ;; animating image.
-          (when (let ((image (image-get-display-property)))
-                  (and image (image-animate-timer image)))
-            (image-toggle-animation)
-            (image-toggle-animation)))
-        :style toggle :selected image-animate-loop
-        :active image-multi-frame
-        :help "Animate images once, or forever?"]
-       ["Reverse Animation" image-reverse-speed
-        :style toggle :selected (let ((image (image-get-display-property)))
-                                  (and image (<
-                                              (image-animate-get-speed image)
-                                              0)))
-        :active image-multi-frame
-        :help "Reverse direction of this image's animation?"]
-       ["Speed Up Animation" image-increase-speed
-        :active image-multi-frame
-        :help "Speed up this image's animation"]
-       ["Slow Down Animation" image-decrease-speed
-        :active image-multi-frame
-        :help "Slow down this image's animation"]
-       ["Reset Animation Speed" image-reset-speed
-        :active image-multi-frame
-        :help "Reset the speed of this image's animation"]
-       ["Previous Frame" image-previous-frame :active image-multi-frame
-        :help "Show the previous frame of this image"]
-       ["Next Frame" image-next-frame :active image-multi-frame
-        :help "Show the next frame of this image"]
-       ["Goto Frame..." image-goto-frame :active image-multi-frame
-        :help "Show a specific frame of this image"]
-       ))
-    (make-composed-keymap (list map image-map) special-mode-map))
-  "Mode keymap for `image-mode'.")
-
-(defvar image-minor-mode-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "\C-c\C-c" 'image-toggle-display)
-    (define-key map "\C-c\C-x" 'image-toggle-hex-display)
-    map)
-  "Mode keymap for `image-minor-mode'.")
+    "--"
+    ["Fit Frame to Image" image-mode-fit-frame :active t
+     :help "Resize frame to match image"]
+    ["Fit Image to Window" image-transform-fit-to-window
+     :help "Resize image to match the window height and width"]
+    ["Fit Image to Window (Scale down only)" image-transform-fit-both
+     :help "Scale image down to match the window height and width"]
+    ["Zoom In" image-increase-size
+     :help "Enlarge the image"]
+    ["Zoom Out" image-decrease-size
+     :help "Shrink the image"]
+    ["Set Scale..." image-transform-set-scale
+     :help "Resize image by specified scale factor"]
+    ["Rotate Clockwise" image-rotate
+     :help "Rotate the image"]
+    ["Set Rotation..." image-transform-set-rotation
+     :help "Set rotation angle of the image"]
+    ["Set Smoothing..." image-transform-set-smoothing
+     :help "Toggle smoothing"]
+    ["Original Size" image-transform-original
+     :help "Reset image to actual size"]
+    ["Reset to Default Size" image-transform-reset
+     :help "Reset all image transformations to initial size"]
+    "--"
+    ["Show Thumbnails"
+     (lambda ()
+       (interactive)
+       (image-dired default-directory))
+     :active default-directory
+     :help "Show thumbnails for all images in this directory"]
+    ["Previous Image" image-previous-file :active buffer-file-name
+     :help "Move to previous image in this directory"]
+    ["Next Image" image-next-file :active buffer-file-name
+     :help "Move to next image in this directory"]
+    ["Copy File Name" image-mode-copy-file-name-as-kill
+     :active buffer-file-name
+     :help "Copy the current file name to the kill ring"]
+    "--"
+    ["Animate Image" image-toggle-animation :style toggle
+     :selected (let ((image (image-get-display-property)))
+                 (and image (image-animate-timer image)))
+     :active image-multi-frame
+     :help "Toggle image animation"]
+    ["Loop Animation"
+     (lambda () (interactive)
+       (setq image-animate-loop (not image-animate-loop))
+       ;; FIXME this is a hacky way to make it affect a currently
+       ;; animating image.
+       (when (let ((image (image-get-display-property)))
+               (and image (image-animate-timer image)))
+         (image-toggle-animation)
+         (image-toggle-animation)))
+     :style toggle :selected image-animate-loop
+     :active image-multi-frame
+     :help "Animate images once, or forever?"]
+    ["Reverse Animation" image-reverse-speed
+     :style toggle :selected (let ((image (image-get-display-property)))
+                               (and image (<
+                                           (image-animate-get-speed image)
+                                           0)))
+     :active image-multi-frame
+     :help "Reverse direction of this image's animation?"]
+    ["Speed Up Animation" image-increase-speed
+     :active image-multi-frame
+     :help "Speed up this image's animation"]
+    ["Slow Down Animation" image-decrease-speed
+     :active image-multi-frame
+     :help "Slow down this image's animation"]
+    ["Reset Animation Speed" image-reset-speed
+     :active image-multi-frame
+     :help "Reset the speed of this image's animation"]
+    ["Previous Frame" image-previous-frame :active image-multi-frame
+     :help "Show the previous frame of this image"]
+    ["Next Frame" image-next-frame :active image-multi-frame
+     :help "Show the next frame of this image"]
+    ["Goto Frame..." image-goto-frame :active image-multi-frame
+     :help "Show a specific frame of this image"]))
+
+(defvar-keymap image-minor-mode-map
+  :doc "Mode keymap for `image-minor-mode'."
+  "C-c C-c" #'image-toggle-display
+  "C-c C-x" #'image-toggle-hex-display)
 
 (defvar bookmark-make-record-function)
 
@@ -750,9 +754,9 @@ Key bindings:
 (define-minor-mode image-minor-mode
   "Toggle Image minor mode in this buffer.
 
-Image minor mode provides the key \\<image-mode-map>\\[image-toggle-display],
-to switch back to `image-mode' and display an image file as the
-actual image."
+Image minor mode provides the key \\<image-mode-map>\\[image-toggle-display], \
+to switch back to
+`image-mode' and display an image file as the actual image."
   :lighter (:eval (if image-type (format " Image[%s]" image-type) " Image"))
   :group 'image
   :version "22.1"
@@ -769,18 +773,17 @@ displays an image file as text."
     (major-mode-restore '(image-mode image-mode-as-text))
     ;; Restore `image-type' after `kill-all-local-variables' in `normal-mode'.
     (setq image-type previous-image-type)
-    ;; Enable image minor mode with `C-c C-c'.
-    (image-minor-mode 1)
     (unless (image-get-display-property)
       ;; Show the image file as text.
       (image-toggle-display-text))))
 
 (defun image-mode-as-hex ()
-  "Set a non-image mode as major mode in combination with image minor mode.
+  "Set `hexl-mode' as major mode in combination with image minor mode.
 A non-mage major mode found from `auto-mode-alist' or fundamental mode
 displays an image file as hex.  `image-minor-mode' provides the key
-\\<image-mode-map>\\[image-toggle-hex-display] to switch back to `image-mode'
-to display an image file as the actual image.
+\\<image-mode-map>\\[image-toggle-hex-display] to switch back to `image-mode' \
+to display an image file as
+the actual image.
 
 You can use `image-mode-as-hex' in `auto-mode-alist' when you want to
 display an image file as hex initially.
@@ -789,13 +792,11 @@ See commands `image-mode' and `image-minor-mode' for more 
information
 on these modes."
   (interactive)
   (image-mode-to-text)
-  ;; Turn on hexl-mode
   (hexl-mode)
+  (image-minor-mode 1)
   (message (substitute-command-keys
-            "Type \\[image-toggle-hex-display] or \
-\\[image-toggle-display] to view the image as %s")
-           (if (image-get-display-property)
-               "hex" "an image or text")))
+            "Type \\[image-toggle-display] or \
+\\[image-toggle-hex-display] to view the image as an image")))
 
 (defun image-mode-as-text ()
   "Set a non-image mode as major mode in combination with image minor mode.
@@ -811,6 +812,7 @@ See commands `image-mode' and `image-minor-mode' for more 
information
 on these modes."
   (interactive)
   (image-mode-to-text)
+  (image-minor-mode 1)
   (message (substitute-command-keys
             "Type \\[image-toggle-display] to view the image as %s")
            (if (image-get-display-property)
@@ -986,14 +988,17 @@ was inserted."
                  (memq (intern (upcase (file-name-extension filename)) obarray)
                        imagemagick-types-inhibit)))))
 
+(declare-function hexl-mode-exit "hexl" (&optional arg))
+
 (defun image-toggle-hex-display ()
   "Toggle between image and hex display."
   (interactive)
-  (if (image-get-display-property)
-      (image-mode-as-hex)
-    (if (eq major-mode 'fundamental-mode)
-        (image-mode-as-hex)
-      (image-mode))))
+  (cond ((or (image-get-display-property) ; in `image-mode'
+             (eq major-mode 'fundamental-mode))
+         (image-mode-as-hex))
+        ((eq major-mode 'hexl-mode)
+         (hexl-mode-exit))
+        (t (error "That command is invalid here"))))
 
 (defun image-toggle-display ()
   "Toggle between image and text display.
@@ -1002,15 +1007,15 @@ If the current buffer is displaying an image file as an 
image,
 call `image-mode-as-text' to switch to text or hex display.
 Otherwise, display the image by calling `image-mode'."
   (interactive)
-  (if (image-get-display-property)
-      (image-mode-as-text)
-    (if (eq major-mode 'hexl-mode)
-        (image-mode-as-text)
-      (image-mode))))
+  (cond ((image-get-display-property) ; in `image-mode'
+         (image-mode-as-text))
+        ((eq major-mode 'hexl-mode)
+         (hexl-mode-exit))
+        ((image-mode))))
 
 (defun image-kill-buffer ()
   "Kill the current buffer."
-  (interactive)
+  (interactive nil image-mode)
   (kill-buffer (current-buffer)))
 
 (defun image-after-revert-hook ()
@@ -1191,7 +1196,7 @@ current one, in cyclic alphabetical order.
 
 This command visits the specified file via `find-alternate-file',
 replacing the current Image mode buffer."
-  (interactive "p")
+  (interactive "p" image-mode)
   (unless (derived-mode-p 'image-mode)
     (error "The buffer is not in Image mode"))
   (unless buffer-file-name
@@ -1223,7 +1228,7 @@ tar mode buffers."
       (when (buffer-live-p archive-superior-buffer)
         (push (cons 'archive archive-superior-buffer) buffers)))
      (t
-      ;; Find a dired buffer.
+      ;; Find a Dired buffer.
       (dolist (buffer (buffer-list))
         (with-current-buffer buffer
           (when (and (derived-mode-p 'dired-mode)
@@ -1232,7 +1237,7 @@ tar mode buffers."
                     (equal (file-truename dir)
                            (file-truename default-directory)))
             (push (cons 'dired (current-buffer)) buffers))))
-      ;; If we can't find any buffers to navigate in, we open a dired
+      ;; If we can't find any buffers to navigate in, we open a Dired
       ;; buffer.
       (unless buffers
         (push (cons 'dired (find-file-noselect dir)) buffers)
@@ -1244,14 +1249,14 @@ tar mode buffers."
 
 (defun image-mode--next-file (file n)
   "Go to the next image file in the parent buffer of FILE.
-This is typically a dired buffer, but may also be a tar/archive buffer.
+This is typically a Dired buffer, but may also be a tar/archive buffer.
 Return the next image file from that buffer.
 If N is negative, go to the previous file."
   (let ((regexp (image-file-name-regexp))
         (buffers (image-mode--directory-buffers file))
         next)
     (dolist (buffer buffers)
-      ;; We do this traversal for all the dired buffers open on this
+      ;; We do this traversal for all the Dired buffers open on this
       ;; directory.  There probably is just one, but we want to move
       ;; point in all of them.
       (save-window-excursion
@@ -1288,36 +1293,36 @@ current one, in cyclic alphabetical order.
 
 This command visits the specified file via `find-alternate-file',
 replacing the current Image mode buffer."
-  (interactive "p")
+  (interactive "p" image-mode)
   (image-next-file (- n)))
 
 (defun image-mode-copy-file-name-as-kill ()
   "Push the currently visited file name onto the kill ring."
-  (interactive)
+  (interactive nil image-mode)
   (unless buffer-file-name
     (error "The current buffer doesn't visit a file"))
   (kill-new buffer-file-name)
   (message "Copied %s" buffer-file-name))
 
 (defun image-mode-mark-file ()
-  "Mark the current file in the appropriate dired buffer(s).
-Any dired buffer that's opened to the current file's directory
+  "Mark the current file in the appropriate Dired buffer(s).
+Any Dired buffer that's opened to the current file's directory
 will have the line where the image appears (if any) marked.
 
 If no such buffer exists, it will be opened."
-  (interactive)
+  (interactive nil image-mode)
   (unless buffer-file-name
     (error "Current buffer is not visiting a file"))
   (image-mode--mark-file buffer-file-name #'dired-mark "marked"))
 
 (defun image-mode-unmark-file ()
-  "Unmark the current file in the appropriate dired buffer(s).
-Any dired buffer that's opened to the current file's directory
+  "Unmark the current file in the appropriate Dired buffer(s).
+Any Dired buffer that's opened to the current file's directory
 will remove the mark from the line where the image appears (if
 any).
 
 If no such buffer exists, it will be opened."
-  (interactive)
+  (interactive nil image-mode)
   (unless buffer-file-name
     (error "Current buffer is not visiting a file"))
   (image-mode--mark-file buffer-file-name #'dired-unmark "unmarked"))
@@ -1384,26 +1389,6 @@ If no such buffer exists, it will be opened."
       (image-toggle-display))))
 
 
-;; Not yet implemented.
-;; (defvar image-transform-minor-mode-map
-;;   (let ((map (make-sparse-keymap)))
-;;     ;; (define-key map  [(control ?+)] 'image-scale-in)
-;;     ;; (define-key map  [(control ?-)] 'image-scale-out)
-;;     ;; (define-key map  [(control ?=)] 'image-scale-none)
-;;     ;; (define-key map "c f h" 'image-scale-fit-height)
-;;     ;; (define-key map "c ]" 'image-rotate-right)
-;;     map)
-;;   "Minor mode keymap `image-transform-mode'.")
-;;
-;; (define-minor-mode image-transform-mode
-;;   "Minor mode for scaling and rotating images.
-;; With a prefix argument ARG, enable the mode if ARG is positive,
-;; and disable it otherwise.  If called from Lisp, enable the mode
-;; if ARG is omitted or nil.  This minor mode requires Emacs to have
-;; been compiled with ImageMagick support."
-;;   nil "image-transform" image-transform-minor-mode-map)
-
-
 (defsubst image-transform-width (width height)
   "Return the bounding box width of a rotated WIDTH x HEIGHT rectangle.
 The rotation angle is the value of `image-transform-rotation' in degrees."
@@ -1551,61 +1536,73 @@ return value is suitable for appending to an image 
spec."
             (list :transform-smoothing
                   (string= image--transform-smoothing "smooth")))))))
 
+(defun image-transform-set-percent (scale)
+  "Prompt for a percentage, and resize the current image to that size.
+The percentage is in relation to the original size of the image."
+  (interactive (list (read-number "Scale (% of original): " 100
+                                  'read-number-history))
+               image-mode)
+  (unless (cl-plusp scale)
+    (error "Not a positive number: %s" scale))
+  (setq image-transform-resize (/ scale 100.0))
+  (image-toggle-display-image))
+
 (defun image-transform-set-scale (scale)
   "Prompt for a number, and resize the current image by that amount."
-  (interactive "nScale: ")
+  (interactive "nScale: " image-mode)
   (setq image-transform-resize scale)
   (image-toggle-display-image))
 
 (defun image-transform-fit-to-height ()
   "Fit the current image to the height of the current window."
-  (interactive)
-  (declare (obsolete nil "29.1"))
+  (declare (obsolete image-transform-fit-to-window "29.1"))
+  (interactive nil image-mode)
   (setq image-transform-resize 'fit-height)
   (image-toggle-display-image))
 
 (defun image-transform-fit-to-width ()
   "Fit the current image to the width of the current window."
-  (declare (obsolete nil "29.1"))
-  (interactive)
+  (declare (obsolete image-transform-fit-to-window "29.1"))
+  (interactive nil image-mode)
   (setq image-transform-resize 'fit-width)
   (image-toggle-display-image))
 
 (defun image-transform-fit-both ()
   "Scale the current image down to fit in the current window."
-  (interactive)
+  (interactive nil image-mode)
   (setq image-transform-resize t)
   (image-toggle-display-image))
 
 (defun image-transform-fit-to-window ()
   "Fit the current image to the height and width of the current window."
-  (interactive)
+  (interactive nil image-mode)
   (setq image-transform-resize 'fit-window)
   (image-toggle-display-image))
 
 (defun image-transform-set-rotation (rotation)
   "Prompt for an angle ROTATION, and rotate the image by that amount.
 ROTATION should be in degrees."
-  (interactive "nRotation angle (in degrees): ")
+  (interactive "nRotation angle (in degrees): " image-mode)
   (setq image-transform-rotation (float (mod rotation 360)))
   (image-toggle-display-image))
 
 (defun image-transform-set-smoothing (smoothing)
   (interactive (list (completing-read "Smoothing: "
-                                      '("none" "smooth") nil t)))
+                                      '("none" "smooth") nil t))
+               image-mode)
   (setq image--transform-smoothing smoothing)
   (image-toggle-display-image))
 
 (defun image-transform-original ()
   "Display the current image with the original (actual) size and rotation."
-  (interactive)
+  (interactive nil image-mode)
   (setq image-transform-resize nil
        image-transform-scale 1)
   (image-toggle-display-image))
 
 (defun image-transform-reset ()
   "Display the current image with the default (initial) size and rotation."
-  (interactive)
+  (interactive nil image-mode)
   (setq image-transform-resize image-auto-resize
        image-transform-rotation 0.0
        image-transform-scale 1
diff --git a/lisp/image.el b/lisp/image.el
index 1b684d5c57..9311125450 100644
--- a/lisp/image.el
+++ b/lisp/image.el
@@ -32,7 +32,8 @@
   :group 'multimedia)
 
 (declare-function image-flush "image.c" (spec &optional frame))
-(defalias 'image-refresh 'image-flush)
+(declare-function clear-image-cache "image.c"
+                  (&optional filter animation-cache))
 
 (defconst image-type-header-regexps
   `(("\\`/[\t\n\r ]*\\*.*XPM.\\*/" . xpm)
@@ -177,6 +178,8 @@ or \"ffmpeg\") is installed."
   "+" #'image-increase-size
   "r" #'image-rotate
   "o" #'image-save
+  "h" #'image-flip-horizontally
+  "v" #'image-flip-vertically
   "C-<wheel-down>" #'image-mouse-decrease-size
   "C-<mouse-5>"    #'image-mouse-decrease-size
   "C-<wheel-up>"   #'image-mouse-increase-size
@@ -444,15 +447,6 @@ type if we can't otherwise guess it."
     (error "Invalid image type `%s'" type))
   type)
 
-
-(if (fboundp 'image-metadata)           ; eg not --without-x
-    (define-obsolete-function-alias 'image-extension-data
-      'image-metadata "24.1"))
-
-(define-obsolete-variable-alias
-    'image-library-alist
-    'dynamic-library-alist "24.1")
-
 ;;;###autoload
 (defun image-type-available-p (type)
   "Return t if image type TYPE is available.
@@ -620,7 +614,7 @@ means display it in the right marginal area."
       (put-text-property 0 (length string) 'display prop string)
       (overlay-put overlay 'put-image t)
       (overlay-put overlay 'before-string string)
-      (overlay-put overlay 'map image-map)
+      (overlay-put overlay 'keymap image-map)
       overlay)))
 
 
@@ -764,13 +758,15 @@ SPECS is a list of image specifications.
 
 Each image specification in SPECS is a property list.  The contents of
 a specification are image type dependent.  All specifications must at
-least contain the properties `:type TYPE' and either `:file FILE' or
-`:data DATA', where TYPE is a symbol specifying the image type,
-e.g. `xbm', FILE is the file to load the image from, and DATA is a
-string containing the actual image data.  The specification whose TYPE
-is supported, and FILE exists, is used to construct the image
-specification to be returned.  Return nil if no specification is
-satisfied.
+least contain either the property `:file FILE' or `:data DATA',
+where FILE is the file to load the image from, and DATA is a string
+containing the actual image data.  If the property `:type TYPE' is
+omitted or nil, try to determine the image type from its first few
+bytes of image data.  If that doesn't work, and the property `:file
+FILE' provide a file name, use its file extension as image type.
+If `:type TYPE' is provided, it must match the actual type
+determined for FILE or DATA by `create-image'.  Return nil if no
+specification is satisfied.
 
 If CACHE is non-nil, results are cached and returned on subsequent calls.
 
@@ -785,22 +781,44 @@ Image files should not be larger than specified by 
`max-image-size'."
           (let* ((spec (car specs))
                 (type (plist-get spec :type))
                 (data (plist-get spec :data))
-                (file (plist-get spec :file))
-                found)
-           (when (image-type-available-p type)
-             (cond ((stringp file)
-                    (if (setq found (image-search-load-path file))
-                        (setq image
-                              (cons 'image (plist-put (copy-sequence spec)
-                                                      :file found)))))
-                   ((not (null data))
-                    (setq image (cons 'image spec)))))
+                (file (plist-get spec :file)))
+           (cond
+             ((stringp file)
+             (when (setq file (image-search-load-path file))
+                ;; At this point, remove the :type and :file properties.
+                ;; `create-image' will set them depending on image file.
+                (setq image (cons 'image (copy-sequence spec)))
+                (setf (image-property image :type) nil)
+                (setf (image-property image :file) nil)
+                (and (setq image (ignore-errors
+                                   (apply #'create-image file nil nil
+                                          (cdr image))))
+                     ;; Ensure, if a type has been provided, it is
+                     ;; consistent with the type returned by
+                     ;; `create-image'. If not, return nil.
+                     (not (null type))
+                     (not (eq type (image-property image :type)))
+                     (setq image nil))))
+            ((not (null data))
+              ;; At this point, remove the :type and :data properties.
+              ;; `create-image' will set them depending on image data.
+              (setq image (cons 'image (copy-sequence spec)))
+              (setf (image-property image :type) nil)
+              (setf (image-property image :data) nil)
+             (and (setq image (ignore-errors
+                                 (apply #'create-image data nil t
+                                        (cdr image))))
+                   ;; Ensure, if a type has been provided, it is
+                   ;; consistent with the type returned by
+                   ;; `create-image'. If not, return nil.
+                   (not (null type))
+                   (not (eq type (image-property image :type)))
+                   (setq image nil))))
            (setq specs (cdr specs))))
         (when cache
           (setf (gethash orig-specs find-image--cache) image))
         image)))
 
-
 ;;;###autoload
 (defmacro defimage (symbol specs &optional doc)
   "Define SYMBOL as an image, and return SYMBOL.
@@ -949,9 +967,10 @@ for the animation speed.  A negative value means to 
animate in reverse."
   (plist-put (cdr image) :animate-tardiness
              (+ (* (plist-get (cdr image) :animate-tardiness) 0.9)
                 (float-time (time-since target-time))))
-  (let ((buffer (plist-get (cdr image) :animate-buffer))
-        (position (plist-get (cdr image) :animate-position)))
-    (when (and (buffer-live-p buffer)
+  (let* ((buffer (plist-get (cdr image) :animate-buffer))
+         (position (plist-get (cdr image) :animate-position))
+         (continue-animation
+          (and (buffer-live-p buffer)
                ;; If we have a :animate-position setting, the caller
                ;; has requested that the animation be stopped if the
                ;; image is no longer displayed in the buffer.
@@ -968,7 +987,13 @@ for the animation speed.  A negative value means to 
animate in reverse."
                (or (< (plist-get (cdr image) :animate-tardiness) 2)
                   (progn
                     (message "Stopping animation; animation possibly too big")
-                    nil)))
+                    nil)))))
+    (if (not continue-animation)
+        ;; Eject from the animation cache since we've decided not to
+        ;; keep updating it.  This helps stop unbounded RAM usage when
+        ;; doing, for instance, `g' in an eww buffer with animated
+        ;; images.
+        (clear-image-cache nil image)
       (let* ((time (prog1 (current-time)
                     (image-show-frame image n t)))
             (speed (image-animate-get-speed image))
@@ -1264,6 +1289,24 @@ changing the displayed image size does not affect the 
saved image."
       (write-region (point-min) (point-max)
                     (read-file-name "Write image to file: ")))))
 
+(defun image-flip-horizontally ()
+  "Horizontally flip the image under point."
+  (interactive)
+  (let ((image (image--get-image)))
+    (image-flush image)
+    (setf (image-property image :flip)
+          (not (image-property image :flip)))))
+
+(defun image-flip-vertically ()
+  "Vertically flip the image under point."
+  (interactive)
+  (let ((image (image--get-image)))
+    (image-rotate 180)
+    (setf (image-property image :flip)
+          (not (image-property image :flip)))))
+
+(define-obsolete-function-alias 'image-refresh #'image-flush "29.1")
+
 (provide 'image)
 
 ;;; image.el ends here
diff --git a/lisp/image/exif.el b/lisp/image/exif.el
index fd4673dc1b..b25968af53 100644
--- a/lisp/image/exif.el
+++ b/lisp/image/exif.el
@@ -261,9 +261,9 @@ VALUE is an integer representing BYTES characters."
     (set-buffer-multibyte nil)
     (if le
         (dotimes (i bytes)
-          (insert (logand (lsh value (* i -8)) 255)))
+          (insert (logand (ash value (* i -8)) 255)))
       (dotimes (i bytes)
-        (insert (logand (lsh value (* (- (1- bytes) i) -8)) 255))))
+        (insert (logand (ash value (* (- (1- bytes) i) -8)) 255))))
     (insert 0)
     (buffer-string)))
 
diff --git a/lisp/image/gravatar.el b/lisp/image/gravatar.el
index 78a2df72c4..8c49c1edf2 100644
--- a/lisp/image/gravatar.el
+++ b/lisp/image/gravatar.el
@@ -45,7 +45,7 @@
   "Time to live in seconds for gravatar cache entries.
 If a requested gravatar has been cached for longer than this, it
 is retrieved anew.  The default value is 30 days."
-  :type 'integer
+  :type 'natnum
   ;; Restricted :type to number of seconds.
   :version "27.1"
   :group 'gravatar)
diff --git a/lisp/image/image-converter.el b/lisp/image/image-converter.el
index 9440c623f9..9c2f24819a 100644
--- a/lisp/image/image-converter.el
+++ b/lisp/image/image-converter.el
@@ -68,6 +68,8 @@ not, conversion will fail."
     (imagemagick :command "convert" :probe ("-list" "format")))
   "List of supported image converters to try.")
 
+(defvar image-converter--extra-converters (make-hash-table :test #'equal))
+
 (defun image-converter-initialize ()
   "Determine the external image converter to be used.
 This also determines which external formats we can parse."
@@ -123,15 +125,21 @@ converted image data is returned as a string."
     (error "IMAGE-FORMAT should be a symbol like `image/png'"))
   (with-temp-buffer
     (set-buffer-multibyte nil)
-    (when-let ((err (image-converter--convert
-                     image-converter
-                     (if (listp image)
-                         (plist-get (cdr image) :file)
-                       image)
-                     (if (listp image)
-                         (plist-get (cdr image) :data-p)
-                       image-format))))
-      (error "%s" err))
+    (let* ((source (if (listp image)
+                       (plist-get (cdr image) :file)
+                     image))
+           (format (if (listp image)
+                       (plist-get (cdr image) :data-p)
+                     image-format))
+           (type (if format
+                     (image-converter--mime-type format)
+                   (file-name-extension source)))
+           (extra-converter (gethash type image-converter--extra-converters)))
+      (if extra-converter
+          (funcall extra-converter source format)
+        (when-let ((err (image-converter--convert
+                         image-converter source format)))
+          (error "%s" err))))
     (if (listp image)
         ;; Return an image object that's the same as we were passed,
         ;; but ignore the :type value.
@@ -244,20 +252,22 @@ Only suffixes that map to `image-mode' are returned."
        (cadr (split-string (symbol-name image-format) "/"))))
 
 (defun image-converter--convert-magick (type source image-format)
-  (let ((command (image-converter--value type :command)))
+  (let ((command (image-converter--value type :command))
+        (coding-system-for-read 'no-conversion))
     (unless (zerop (if image-format
                        ;; We have the image data in SOURCE.
                        (progn
                          (insert source)
-                         (apply #'call-process-region (point-min) (point-max)
-                                (car command) t t nil
-                                (append
-                                 (cdr command)
-                                 (list (format "%s:-"
-                                               (image-converter--mime-type
-                                                image-format))
+                         (let ((coding-system-for-write 'no-conversion))
+                           (apply #'call-process-region (point-min) (point-max)
+                                  (car command) t t nil
+                                  (append
+                                   (cdr command)
+                                   (list (format "%s:-"
+                                                 (image-converter--mime-type
+                                                  image-format))
                                        (concat image-convert-to-format
-                                               ":-")))))
+                                               ":-"))))))
                      ;; SOURCE is a file name.
                      (apply #'call-process (car command)
                             nil t nil
@@ -272,18 +282,20 @@ Only suffixes that map to `image-mode' are returned."
 (cl-defmethod image-converter--convert ((type (eql 'ffmpeg)) source
                                         image-format)
   "Convert using ffmpeg."
-  (let ((command (image-converter--value type :command)))
+  (let ((command (image-converter--value type :command))
+        (coding-system-for-read 'no-conversion))
     (unless (zerop (if image-format
                        (progn
                          (insert source)
-                         (apply #'call-process-region
-                                (point-min) (point-max) (car command)
-                                t '(t nil) nil
-                                (append
-                                 (cdr command)
-                                 (list "-i" "-"
-                                       "-c:v" image-convert-to-format
-                                       "-f" "image2pipe" "-"))))
+                         (let ((coding-system-for-write 'no-conversion))
+                           (apply #'call-process-region
+                                  (point-min) (point-max) (car command)
+                                  t '(t nil) nil
+                                  (append
+                                   (cdr command)
+                                   (list "-i" "-"
+                                         "-c:v" image-convert-to-format
+                                         "-f" "image2pipe" "-")))))
                      (apply #'call-process
                             (car command)
                             nil '(t nil) nil
@@ -294,6 +306,21 @@ Only suffixes that map to `image-mode' are returned."
                                           "-")))))
       "ffmpeg error when converting")))
 
+;;;###autoload
+(defun image-converter-add-handler (suffix converter)
+  "Make Emacs use CONVERTER to parse image files that end with SUFFIX.
+CONVERTER is a function with two parameters, where the first is
+the file name or a string with the image data, and the second is
+non-nil if the first parameter is image data.  The converter
+should output the image in the current buffer, converted to
+`image-convert-to-format'."
+  (cl-pushnew suffix image-converter-file-name-extensions :test #'equal)
+  (setq image-converter-file-name-extensions
+        (sort image-converter-file-name-extensions #'string<))
+  (setq image-converter-regexp
+        (concat "\\." (regexp-opt image-converter-file-name-extensions) "\\'"))
+  (setf (gethash suffix image-converter--extra-converters) converter))
+
 (provide 'image-converter)
 
 ;;; image-converter.el ends here
diff --git a/lisp/imenu.el b/lisp/imenu.el
index 2636e77d08..dcd816cb7a 100644
--- a/lisp/imenu.el
+++ b/lisp/imenu.el
@@ -87,7 +87,7 @@ This might not yet be honored by all index-building 
functions."
 (defcustom imenu-auto-rescan-maxout 600000
   "Imenu auto-rescan is disabled in buffers larger than this size (in bytes).
 Also see `imenu-max-index-time'."
-  :type 'integer
+  :type 'natnum
   :version "26.2")
 
 (defcustom imenu-use-popup-menu 'on-mouse
@@ -132,7 +132,7 @@ element should come before the second.  The arguments are 
cons cells;
 
 (defcustom imenu-max-items 25
   "Maximum number of elements in a mouse menu for Imenu."
-  :type 'integer)
+  :type 'natnum)
 
 (defcustom imenu-space-replacement "."
   "The replacement string for spaces in index names.
@@ -464,14 +464,14 @@ Non-nil arguments are in recursive calls."
   `(keymap ,title
            ,@(mapcar
               (lambda (item)
-                `(,(car item) ,(car item)
+                `(,(intern (car item)) ,(car item)
                   ,@(cond
                      ((imenu--subalist-p item)
                       (imenu--create-keymap (car item) (cdr item) cmd))
                      (t
                       (lambda () (interactive)
                         (if cmd (funcall cmd item) item))))))
-              alist)))
+              (seq-filter #'identity alist))))
 
 (defun imenu--in-alist (str alist)
   "Check whether the string STR is contained in multi-level ALIST."
diff --git a/lisp/indent.el b/lisp/indent.el
index d6dee94016..b0c1a021da 100644
--- a/lisp/indent.el
+++ b/lisp/indent.el
@@ -270,11 +270,8 @@ Negative values of ARG indent backward, so you can remove 
all
 indentation by specifying a large negative ARG."
   (interactive "r\nP\np")
   (if (and (not arg) interactive)
-      (progn
-        (message
-        (substitute-command-keys
-         "Indent region with \\<indent-rigidly-map>\\[indent-rigidly-left], 
\\[indent-rigidly-right], \\[indent-rigidly-left-to-tab-stop], or 
\\[indent-rigidly-right-to-tab-stop]."))
-        (set-transient-map indent-rigidly-map t #'deactivate-mark))
+      (set-transient-map indent-rigidly-map t #'deactivate-mark
+                         "Indent region with %k")
     (save-excursion
       (goto-char end)
       (setq end (point-marker))
@@ -737,7 +734,9 @@ You can add or remove colons and then do 
\\<edit-tab-stops-map>\\[edit-tab-stops
     (while (> count 0)
       (insert "0123456789")
       (setq count (1- count))))
-  (insert "\nTo install changes, type C-c C-c")
+  (insert (substitute-command-keys
+           (concat "\nTo install changes, type \\<edit-tab-stops-map>"
+                   "\\[edit-tab-stops-note-changes]")))
   (goto-char (point-min)))
 
 (defun edit-tab-stops-note-changes ()
diff --git a/lisp/info-look.el b/lisp/info-look.el
index 6c8ef091a0..ce0a08dcbe 100644
--- a/lisp/info-look.el
+++ b/lisp/info-look.el
@@ -130,7 +130,8 @@ OTHER-MODES is a list of cross references to other help 
modes.")
 (defun info-lookup--expand-info (info)
   ;; We have a dynamic doc-spec function.
   (when (and (null (nth 3 info))
-             (nth 6 info))
+             (nth 6 info)
+             (functionp (nth 6 info)))
     (setf (nth 3 info) (funcall (nth 6 info))
           (nth 6 info) nil))
   info)
@@ -1068,7 +1069,6 @@ Return nil if there is nothing appropriate in the buffer 
near point."
    ("newsticker" "Index")
    ("octave" "(octave-mode)Variable Index" "(octave-mode)Lisp Function Index")
    ("org" "Variable Index" "Command and Function Index")
-   ("pgg" "Variable Index" "Function Index")
    ("rcirc" "Variable Index" "Index")
    ("reftex" "Index")
    ("sasl" "Variable Index" "Function Index")
diff --git a/lisp/info.el b/lisp/info.el
index f9d63b0f32..fb4c3fd782 100644
--- a/lisp/info.el
+++ b/lisp/info.el
@@ -133,8 +133,6 @@ orientation.  See `Info-nth-menu-item'.")
   :version "22.1"
   :type 'boolean)
 
-;; It's unfortunate that nil means no fontification, as opposed to no limit,
-;; since that differs from font-lock-maximum-size.
 (defcustom Info-fontify-maximum-menu-size 400000
   "Maximum size of menu to fontify if `font-lock-mode' is non-nil.
 Set to nil to disable node fontification; set to t for no limit."
@@ -260,7 +258,7 @@ This only has an effect if `Info-hide-note-references' is 
non-nil."
   "Depth of breadcrumbs to display.
 0 means do not display breadcrumbs."
   :version "23.1"
-  :type 'integer)
+  :type 'natnum)
 
 (defcustom Info-search-whitespace-regexp "\\s-+"
   "If non-nil, regular expression to match a sequence of whitespace chars.
@@ -291,12 +289,10 @@ with wrapping around the current Info node."
 (defvar Info-isearch-initial-history nil)
 (defvar Info-isearch-initial-history-list nil)
 
-(defcustom Info-mode-hook
-  ;; Try to obey obsolete Info-fontify settings.
-  (unless (and (boundp 'Info-fontify) (null Info-fontify))
-    '(turn-on-font-lock))
+(defcustom Info-mode-hook '(turn-on-font-lock)
   "Hook run when activating Info Mode."
-  :type 'hook)
+  :type 'hook
+  :version "29.1")
 
 (defcustom Info-selection-hook nil
   "Hook run when an Info node is selected as the current node."
@@ -2208,7 +2204,7 @@ and is not in the header line or a tag table."
     (let ((backward (< found beg-found)))
       (not
        (or
-       (and (not search-invisible)
+       (and (not (eq search-invisible t))
             (if backward
                 (or (text-property-not-all found beg-found 'invisible nil)
                     (text-property-not-all found beg-found 'display nil))
@@ -4384,7 +4380,7 @@ a string of ASCII characters.")
 
 ;; Autoload cookie needed by desktop.el
 ;;;###autoload
-(define-derived-mode Info-mode nil "Info" ;FIXME: Derive from special-mode?
+(define-derived-mode Info-mode special-mode "Info"
   "Info mode provides commands for browsing through the Info documentation 
tree.
 Documentation in Info is divided into \"nodes\", each of which discusses
 one topic and contains references to other nodes which discuss related
@@ -4522,7 +4518,7 @@ Advanced commands:
     ("java" . "ccmode") ("idl" . "ccmode") ("pike" . "ccmode")
     ("skeleton" . "autotype") ("auto-insert" . "autotype")
     ("copyright" . "autotype") ("executable" . "autotype")
-    ("time-stamp" . "autotype") ("quickurl" . "autotype")
+    ("time-stamp" . "autotype")
     ("tempo" . "autotype") ("hippie-expand" . "autotype")
     ("cvs" . "pcl-cvs") ("ada" . "ada-mode") "calc"
     ("calcAlg" . "calc") ("calcDigit" . "calc") ("calcVar" . "calc")
diff --git a/lisp/informat.el b/lisp/informat.el
index e7595fa541..c126ab5b1a 100644
--- a/lisp/informat.el
+++ b/lisp/informat.el
@@ -158,7 +158,7 @@
 ;;;###autoload
 (defcustom Info-split-threshold 262144
   "The number of characters by which `Info-split' splits an info file."
-  :type 'integer
+  :type 'natnum
   :version "23.1"
   :group 'texinfo)
 
diff --git a/lisp/international/characters.el b/lisp/international/characters.el
index ca28222c81..d6e83c81e7 100644
--- a/lisp/international/characters.el
+++ b/lisp/international/characters.el
@@ -1525,6 +1525,17 @@ Setup `char-width-table' appropriate for non-CJK 
language environment."
   (aset char-acronym-table (+ #xE0021 i) (format " %c TAG" (+ 33 i))))
 (aset char-acronym-table #xE007F "->|TAG") ; CANCEL TAG
 
+(dotimes (i 256)
+  (let* ((vs-number (1+ i))
+         (codepoint (if (< i 16)
+                        (+ #xfe00 i)
+                      (+ #xe0100 i -16)))
+         (delimiter (cond ((<= vs-number 9) "0")
+                          ((<= vs-number 99) "")
+                          (t " "))))
+    (aset char-acronym-table codepoint
+          (format "VS%s%s" delimiter vs-number))))
+
 ;; We can't use the \N{name} things here, because this file is used
 ;; too early in the build process.
 (defvar bidi-control-characters
@@ -1574,7 +1585,9 @@ option `glyphless-char-display'."
                                             #x80 #x9F method))
            ((eq target 'variation-selectors)
             (glyphless-set-char-table-range glyphless-char-display
-                                            #xFE00 #xFE0F method))
+                                            #xFE00 #xFE0F method)
+             (glyphless-set-char-table-range glyphless-char-display
+                                            #xE0100 #xE01EF method))
            ((or (eq target 'format-control)
                  (eq target 'bidi-control))
             (when unicode-category-table
@@ -1647,10 +1660,10 @@ GROUP must be one of these symbols:
                     that are relevant for bidirectional formatting control,
                     like U+2069 (PDI) and U+202B (RLE).
   `variation-selectors':
-                    Characters in the range U+FE00..U+FE0F, used for
-                    selecting alternate glyph presentations, such as
-                    Emoji vs Text presentation, of the preceding
-                    character(s).
+                    Characters in the range U+FE00..U+FE0F and
+                    U+E0100..U+E01EF, used for selecting alternate glyph
+                    presentations, such as Emoji vs Text presentation, of
+                    the preceding character(s).
   `no-font':        For GUI frames, characters for which no suitable
                     font is found; for text-mode frames, characters
                     that cannot be encoded by `terminal-coding-system'.
diff --git a/lisp/international/emoji.el b/lisp/international/emoji.el
index 8970a466b7..4f4d4f4832 100644
--- a/lisp/international/emoji.el
+++ b/lisp/international/emoji.el
@@ -73,18 +73,13 @@ representing names.  For instance:
 (defvar emoji--insert-buffer)
 
 ;;;###autoload
-(defun emoji-insert (&optional text)
-  "Choose and insert an emoji glyph.
-If TEXT (interactively, the prefix argument), choose the emoji
-by typing its Unicode Standard name (with completion), instead
-of selecting from emoji display."
-  (interactive "*P")
+(defun emoji-insert ()
+  "Choose and insert an emoji glyph."
+  (interactive "*")
   (emoji--init)
-  (if text
-      (emoji--choose-emoji)
-    (unless (fboundp 'emoji--command-Emoji)
-      (emoji--define-transient))
-    (funcall (intern "emoji--command-Emoji"))))
+  (unless (fboundp 'emoji--command-Emoji)
+    (emoji--define-transient))
+  (funcall (intern "emoji--command-Emoji")))
 
 ;;;###autoload
 (defun emoji-recent ()
@@ -700,6 +695,39 @@ We prefer the earliest unique letter."
              (emoji--define-transient
               (cons "Choose Emoji" (cons glyph derived))))))))))
 
+(defvar-keymap emoji-zoom-map
+  "+" #'emoji-zoom-increase
+  "-" #'emoji-zoom-decrease)
+
+;;;###autoload
+(defun emoji-zoom-increase (&optional factor)
+  "Increase the size of the character under point.
+FACTOR is the multiplication factor for the size."
+  (interactive)
+  (set-transient-map emoji-zoom-map t nil "Zoom with %k")
+  (let* ((factor (or factor 1.1))
+         (old (get-text-property (point) 'face))
+         (height (or (and (consp old)
+                          (plist-get old :height))
+                     1.0))
+         (inhibit-read-only t))
+    (with-silent-modifications
+      (if (consp old)
+          (add-text-properties
+           (point) (1+ (point))
+           (list 'face (plist-put (copy-sequence old) :height (* height 
factor))
+                 'rear-nonsticky t))
+        (add-face-text-property (point) (1+ (point))
+                                (list :height (* height factor)))
+        (put-text-property (point) (1+ (point))
+                           'rear-nonsticky t)))))
+
+;;;###autoload
+(defun emoji-zoom-decrease ()
+  "Decrease the size of the character under point."
+  (interactive)
+  (emoji-zoom-increase 0.9))
+
 (provide 'emoji)
 
 ;;; emoji.el ends here
diff --git a/lisp/international/iso-transl.el b/lisp/international/iso-transl.el
index 417f0076ef..5e9fd69ea0 100644
--- a/lisp/international/iso-transl.el
+++ b/lisp/international/iso-transl.el
@@ -76,6 +76,7 @@
     ("\"E"  . [?Ë])
     ("\"I"  . [?Ï])
     ("\"O"  . [?Ö])
+    ("\"S"  . [?ẞ])
     ("\"U"  . [?Ü])
     ("\"a"  . [?ä])
     ("\"e"  . [?ë])
@@ -207,6 +208,30 @@
     ("^i"   . [?î])
     ("^o"   . [?ô])
     ("^u"   . [?û])
+    ("^^A"  . [?Ǎ])
+    ("^^C"  . [?Č])
+    ("^^E"  . [?Ě])
+    ("^^G"  . [?Ǧ])
+    ("^^I"  . [?Ǐ])
+    ("^^K"  . [?Ǩ])
+    ("^^N"  . [?Ň])
+    ("^^O"  . [?Ǒ])
+    ("^^R"  . [?Ř])
+    ("^^S"  . [?Š])
+    ("^^U"  . [?Ǔ])
+    ("^^Z"  . [?Ž])
+    ("^^a"  . [?ǎ])
+    ("^^c"  . [?č])
+    ("^^e"  . [?ě])
+    ("^^g"  . [?ǧ])
+    ("^^i"  . [?ǐ])
+    ("^^k"  . [?ǩ])
+    ("^^n"  . [?ň])
+    ("^^o"  . [?ǒ])
+    ("^^r"  . [?ř])
+    ("^^s"  . [?š])
+    ("^^u"  . [?ǔ])
+    ("^^z"  . [?ž])
     ("_a"   . [?ª])
     ("_o"   . [?º])
     ("`A"   . [?À])
@@ -300,6 +325,7 @@ sequence VECTOR.  (VECTOR is normally one character long.)")
     ("German"
      ("A"  . [?Ä])
      ("O"  . [?Ö])
+     ("S"  . [?ẞ])
      ("U"  . [?Ü])
      ("a"  . [?ä])
      ("o"  . [?ö])
@@ -351,12 +377,12 @@ sequence VECTOR.  (VECTOR is normally one character 
long.)")
 
 (defun iso-transl-set-language (lang)
   "Set shorter key bindings for some characters relevant for LANG.
-This affects the `C-x 8' prefix.
+This affects the \\`C-x 8' prefix.
 
 Note that only a few languages are supported, and for more
 rigorous support it is recommended to use an input method
 instead.  Also note that many of these characters can be input
-with the regular `C-x 8' map without having to specify a language
+with the regular \\`C-x 8' map without having to specify a language
 here."
   (interactive (list (let ((completion-ignore-case t))
                       (completing-read "Set which language? "
diff --git a/lisp/international/ja-dic-utl.el b/lisp/international/ja-dic-utl.el
index cc636986f9..3f6500669a 100644
--- a/lisp/international/ja-dic-utl.el
+++ b/lisp/international/ja-dic-utl.el
@@ -112,11 +112,9 @@ without okurigana are placed at the head of the returned 
list."
                 (princ (substitute-command-keys "\
 The library `ja-dic' can't be loaded.
 
-The most common case is that you have not yet installed the library
-included in LEIM (Libraries of Emacs Input Method) which is
-distributed separately from Emacs.
-
-LEIM is available from the same ftp directory as Emacs.")))
+This might indicate a problem with your Emacs installation, as
+LEIM (Libraries of Emacs Input Method) should normally always be
+installed together with Emacs.")))
               (signal (car err) (cdr err)))))
 
   (let ((vec (make-vector len 0))
diff --git a/lisp/international/latin1-disp.el 
b/lisp/international/latin1-disp.el
index 7054077fb0..4de1d6084f 100644
--- a/lisp/international/latin1-disp.el
+++ b/lisp/international/latin1-disp.el
@@ -124,6 +124,7 @@ display for all of `latin1-display-sets'.  See also
             (?\™ "TM") ;; TRADE MARK SIGN
             (?\› ">") ;; SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
             (?•  "·")
+             (?ẞ "SS") ;; LATIN CAPITAL LETTER SHARP S
             )))
          (setq latin1-display t))
     (mapc #'latin1-display-reset latin1-display-sets)
@@ -755,6 +756,7 @@ use either \\[customize] or the function `latin1-display'."
             (latin1-display-ucs-per-lynx 1)
           (latin1-display-ucs-per-lynx -1))))
 
+;;;###autoload
 (defun latin1-display-ucs-per-lynx (arg)
   "Set up Latin-1/ASCII display for Unicode characters.
 This uses the transliterations of the Lynx browser.
diff --git a/lisp/international/mule-cmds.el b/lisp/international/mule-cmds.el
index 27defef648..12896cc4b0 100644
--- a/lisp/international/mule-cmds.el
+++ b/lisp/international/mule-cmds.el
@@ -1411,6 +1411,7 @@ This function is called with no argument.")
 Each element has the form:
    (INPUT-METHOD LANGUAGE-ENV ACTIVATE-FUNC TITLE DESCRIPTION ARGS...)
 See the function `register-input-method' for the meanings of the elements.")
+;; Autoload if this file no longer dumped.
 ;;;###autoload
 (put 'input-method-alist 'risky-local-variable t)
 
@@ -2198,8 +2199,7 @@ See `set-language-info-alist' for use in programs."
                    first nil))
            (dolist (elt l)
              (when (or (eq input-method elt)
-                       (eq t (compare-strings language-name nil nil
-                                              (nth 1 elt) nil nil t)))
+                       (string-equal-ignore-case language-name (nth 1 elt)))
                (when first
                  (insert "Input methods:\n")
                  (setq first nil))
@@ -2598,7 +2598,7 @@ Matching is done ignoring case and any hyphens and 
underscores in the
 names.  E.g. `ISO_8859-1' and `iso88591' both match `iso-8859-1'."
   (setq charset1 (replace-regexp-in-string "[-_]" "" charset1))
   (setq charset2 (replace-regexp-in-string "[-_]" "" charset2))
-  (eq t (compare-strings charset1 nil nil charset2 nil nil t)))
+  (string-equal-ignore-case charset1 charset2))
 
 (defvar locale-charset-alist nil
   "Coding system alist keyed on locale-style charset name.
@@ -3257,7 +3257,9 @@ as names, not numbers."
               "s" #'emoji-search
               "d" #'emoji-describe
               "r" #'emoji-recent
-              "l" #'emoji-list))
+              "l" #'emoji-list
+              "+" #'emoji-zoom-increase
+              "-" #'emoji-zoom-decrease))
 
 (defface confusingly-reordered
   '((((supports :underline (:style wave)))
diff --git a/lisp/international/mule-diag.el b/lisp/international/mule-diag.el
index 6b630c73e8..cdf2e527e2 100644
--- a/lisp/international/mule-diag.el
+++ b/lisp/international/mule-diag.el
@@ -1065,35 +1065,39 @@ see the function `describe-fontset' for the format of 
the list."
            (help-xref-button 1 'help-input-method (match-string 1))))))))
 
 (defun list-input-methods-1 ()
-  (if (not input-method-alist)
-      (princ "
-No input method is available, perhaps because you have not
-installed LEIM (Libraries of Emacs Input Methods).")
-    (princ (substitute-command-keys
-            "LANGUAGE\n  NAME (`TITLE' in mode line)\n"))
-    (princ "    SHORT-DESCRIPTION\n------------------------------\n")
-    (setq input-method-alist
-         (sort input-method-alist
-               (lambda (x y) (string< (nth 1 x) (nth 1 y)))))
-
-    (let (language)
-      (dolist (elt input-method-alist)
-       (when (not (equal language (nth 1 elt)))
-         (setq language (nth 1 elt))
-         (princ language)
-         (terpri))
-       (princ (format-message
-                "  %s (`%s' in mode line)\n    %s\n"
-                (car elt)
-                (let ((title (nth 3 elt)))
-                  (if (and (consp title) (stringp (car title)))
-                      (car title)
-                    title))
-                ;; If the doc is multi-line, indent all
-                ;; non-blank lines. (Bug#8066)
-                (replace-regexp-in-string
-                 "\n\\(.\\)" "\n    \\1"
-                 (substitute-command-keys (or (nth 4 elt) "")))))))))
+  (with-current-buffer standard-output
+    (if (not input-method-alist)
+        (insert "
+No input method is available.
+
+This might indicate a problem with your Emacs installation, as
+LEIM (Libraries of Emacs Input Method) should normally always be
+installed together with Emacs.")
+      (insert (substitute-command-keys
+               "LANGUAGE\n  NAME (`TITLE' in mode line)\n"))
+      (insert "    SHORT-DESCRIPTION\n------------------------------\n")
+      (setq input-method-alist
+            (sort input-method-alist
+                  (lambda (x y) (string< (nth 1 x) (nth 1 y)))))
+
+      (let (language)
+        (dolist (elt input-method-alist)
+          (when (not (equal language (nth 1 elt)))
+            (setq language (nth 1 elt))
+            (insert "\n" (propertize language 'face 'help-for-help-header) 
"\n\n"))
+          (insert (format-message
+                   "  %s (`%s' in mode line)\n    %s\n"
+                   (car elt)
+                   (let ((title (nth 3 elt)))
+                     (if (and (consp title) (stringp (car title)))
+                         (car title)
+                       title))
+                   ;; If the doc is multi-line, indent all
+                   ;; non-blank lines. (Bug#8066)
+                   (replace-regexp-in-string
+                    "\n\\(.\\)" "\n    \\1"
+                    (substitute-command-keys (or (nth 4 elt) ""))))))))))
+
 
 ;;; DIAGNOSIS
 
diff --git a/lisp/international/quail.el b/lisp/international/quail.el
index 529cf97215..4bb6dbcc8e 100644
--- a/lisp/international/quail.el
+++ b/lisp/international/quail.el
@@ -249,11 +249,9 @@ This activates input method defined by PACKAGE-NAME by 
running
                  (princ (car libraries))
                  (princ (substitute-command-keys "\" is not in `load-path'.
 
-The most common case is that you have not yet installed appropriate
-libraries in LEIM (Libraries of Emacs Input Method) which is
-distributed separately from Emacs.
-
-LEIM is available from the same ftp directory as Emacs.")))
+This might indicate a problem with your Emacs installation, as
+LEIM (Libraries of Emacs Input Method) should normally always be
+installed together with Emacs.")))
                (error "Can't use the Quail package `%s'" package-name))
            (setq libraries (cdr libraries))))))
   (quail-select-package package-name)
diff --git a/lisp/international/titdic-cnv.el b/lisp/international/titdic-cnv.el
index 2a91e7cb5e..080045e752 100644
--- a/lisp/international/titdic-cnv.el
+++ b/lisp/international/titdic-cnv.el
@@ -1191,10 +1191,7 @@ The library is named pinyin.el, and contains the constant
         (dst-file (cadr command-line-args-left))
         (coding-system-for-write 'utf-8-unix))
     (with-temp-file dst-file
-      (insert ";;; " (file-name-nondirectory dst-file)
-              "   -*- lexical-binding:t -*-
-;; This file is automatically generated from pinyin.map, by the
-;; function pinyin-convert.\n\n")
+      (generate-lisp-file-heading dst-file 'pinyin-convert)
       (insert "(defconst pinyin-character-map\n'(")
       (let ((pos (point)))
         (insert-file-contents src-file)
@@ -1214,7 +1211,7 @@ The library is named pinyin.el, and contains the constant
           (forward-line 1)))
       (insert ")\n\"An alist holding correspondences between pinyin syllables\
  and\nChinese characters.\")\n\n")
-      (insert "(provide 'pinyin)\n"))
+      (generate-lisp-file-trailer dst-file :compile t))
     (kill-emacs 0)))
 
 ;;; titdic-cnv.el ends here
diff --git a/lisp/isearch.el b/lisp/isearch.el
index 91aaa66a5b..9f1fbb14a4 100644
--- a/lisp/isearch.el
+++ b/lisp/isearch.el
@@ -54,6 +54,7 @@
 ;;; Code:
 
 (eval-when-compile (require 'cl-lib))
+(eval-when-compile (require 'subr-x))
 
 ;; Some additional options and constants.
 
@@ -465,6 +466,12 @@ and doesn't remove full-buffer highlighting after a 
search."
   :group 'lazy-count
   :version "27.1")
 
+(defvar lazy-count-invisible-format " (invisible %s)"
+  "Format of the number of invisible matches for the prompt.
+When invisible matches exist, their number is appended
+after the total number of matches.  Display nothing when
+this variable is nil.")
+
 
 ;; Define isearch help map.
 
@@ -530,8 +537,6 @@ This is like `describe-bindings', but displays only Isearch 
keys."
     (describe-function 'isearch-forward))
   (when isearch-mode (isearch-update)))
 
-(defalias 'isearch-mode-help 'isearch-describe-mode)
-
 
 ;; Define isearch-mode keymap.
 
@@ -1102,7 +1107,7 @@ In incremental searches, a space or spaces normally 
matches any
 whitespace defined by the variable `search-whitespace-regexp'.
 To search for a literal space and nothing else, enter C-q SPC.
 To toggle whitespace matching, use `isearch-toggle-lax-whitespace',
-usually bound to `M-s SPC' during isearch.
+usually bound to \\`M-s SPC' during isearch.
 This command does not support character folding."
   (interactive "P\np")
   (isearch-mode t (null not-regexp) nil (not no-recursive-edit)))
@@ -1276,6 +1281,7 @@ used to set the value of `isearch-regexp-function'."
 
        isearch-lazy-count-current nil
        isearch-lazy-count-total nil
+       isearch-lazy-count-invisible nil
 
        ;; Save the original value of `minibuffer-message-timeout', and
        ;; set it to nil so that isearch's messages don't get timed out.
@@ -2521,11 +2527,12 @@ If no input items have been entered yet, just beep."
   (if (null (cdr isearch-cmds))
       (ding)
     (isearch-pop-state))
-  ;; When going back to the hidden match, reopen it.
-  (when (and (eq search-invisible 'open) isearch-hide-immediately
-             isearch-other-end)
-    (isearch-range-invisible (min (point) isearch-other-end)
-                             (max (point) isearch-other-end)))
+  ;; When going back to the hidden match, reopen it and close other overlays.
+  (when (and (eq search-invisible 'open) isearch-hide-immediately)
+    (if isearch-other-end
+        (isearch-range-invisible (min (point) isearch-other-end)
+                                 (max (point) isearch-other-end))
+      (isearch-close-unnecessary-overlays (point) (point))))
   (isearch-update))
 
 (defun isearch-del-char (&optional arg)
@@ -2829,7 +2836,9 @@ The command accepts Unicode names like \"smiling face\" or
                            isearch-barrier
                            (1+ isearch-other-end)))))
       (isearch-search)
-      ))
+      (when (and (memq isearch-wrap-pause '(no no-ding))
+                 (not isearch-success))
+        (isearch-repeat (if isearch-forward 'forward 'backward)))))
   (isearch-push-state)
   (if isearch-op-fun (funcall isearch-op-fun))
   (isearch-update))
@@ -3527,7 +3536,12 @@ isearch-message-suffix prompt.  Otherwise, for 
isearch-message-prefix."
                     (- isearch-lazy-count-total
                        isearch-lazy-count-current
                        -1)))
-                (or isearch-lazy-count-total "?"))
+                (if (and isearch-lazy-count-invisible
+                         lazy-count-invisible-format)
+                    (concat (format "%s" (or isearch-lazy-count-total "?"))
+                            (format lazy-count-invisible-format
+                                    isearch-lazy-count-invisible))
+                  (or isearch-lazy-count-total "?")))
       "")))
 
 
@@ -3755,11 +3769,11 @@ Optional third argument, if t, means if fail just 
return nil (no error).
 ;; Verify if the current match is outside of each element of
 ;; `isearch-opened-overlays', if so close that overlay.
 
-(defun isearch-close-unnecessary-overlays (begin end)
+(defun isearch-close-unnecessary-overlays (beg end)
   (let ((overlays isearch-opened-overlays))
     (setq isearch-opened-overlays nil)
     (dolist (ov overlays)
-      (if (isearch-intersects-p begin end (overlay-start ov) (overlay-end ov))
+      (if (isearch-intersects-p beg end (overlay-start ov) (overlay-end ov))
          (push ov isearch-opened-overlays)
        (let ((fct-temp (overlay-get ov 'isearch-open-invisible-temporary)))
          (if fct-temp
@@ -3778,10 +3792,11 @@ Optional third argument, if t, means if fail just 
return nil (no error).
     (save-excursion
       (goto-char beg)
       (let (;; can-be-opened keeps track if we can open some overlays.
-           (can-be-opened (eq search-invisible 'open))
+           (can-be-opened (memq search-invisible '(open can-be-opened)))
            ;; the list of overlays that could be opened
            (crt-overlays nil))
-       (when (and can-be-opened isearch-hide-immediately)
+       (when (and can-be-opened isearch-hide-immediately
+                  (not (eq search-invisible 'can-be-opened)))
          (isearch-close-unnecessary-overlays beg end))
        ;; If the following character is currently invisible,
        ;; skip all characters with that same `invisible' property value.
@@ -3820,9 +3835,10 @@ Optional third argument, if t, means if fail just return 
nil (no error).
        (if (>= (point) end)
            (if (and can-be-opened (consp crt-overlays))
                (progn
-                 (setq isearch-opened-overlays
-                       (append isearch-opened-overlays crt-overlays))
-                 (mapc 'isearch-open-overlay-temporary crt-overlays)
+                 (unless (eq search-invisible 'can-be-opened)
+                   (setq isearch-opened-overlays
+                         (append isearch-opened-overlays crt-overlays))
+                   (mapc 'isearch-open-overlay-temporary crt-overlays))
                  nil)
              (setq isearch-hidden t)))))))
 
@@ -4006,6 +4022,7 @@ since they have special meaning in a regexp."
 (defvar isearch-lazy-highlight-error nil)
 (defvar isearch-lazy-count-current nil)
 (defvar isearch-lazy-count-total nil)
+(defvar isearch-lazy-count-invisible nil)
 (defvar isearch-lazy-count-hash (make-hash-table))
 (defvar lazy-count-update-hook nil
   "Hook run after new lazy count results are computed.")
@@ -4084,7 +4101,8 @@ by other Emacs features."
         ;; Reset old counter before going to count new numbers
         (clrhash isearch-lazy-count-hash)
         (setq isearch-lazy-count-current nil
-              isearch-lazy-count-total nil)
+              isearch-lazy-count-total nil
+              isearch-lazy-count-invisible nil)
         ;; Delay updating the message if possible, to avoid flicker
         (when (string-equal isearch-string "")
           (when (and isearch-mode (null isearch-message-function))
@@ -4164,10 +4182,10 @@ Attempt to do the search exactly the way the pending 
Isearch would."
            (isearch-regexp-lax-whitespace
             isearch-lazy-highlight-regexp-lax-whitespace)
            (isearch-forward isearch-lazy-highlight-forward)
-           ;; Don't match invisible text unless it can be opened
-           ;; or when counting matches and user can visit hidden matches
-           (search-invisible (or (eq search-invisible 'open)
-                                 (and isearch-lazy-count search-invisible)))
+           ;; Count all invisible matches, but highlight only
+           ;; matches that can be opened by visiting them later
+           (search-invisible (or (not (null isearch-lazy-count))
+                                 'can-be-opened))
            (retry t)
            (success nil))
        ;; Use a loop like in `isearch-search'.
@@ -4184,15 +4202,20 @@ Attempt to do the search exactly the way the pending 
Isearch would."
     (error nil)))
 
 (defun isearch-lazy-highlight-match (mb me)
-  (let ((ov (make-overlay mb me)))
-    (push ov isearch-lazy-highlight-overlays)
-    ;; 1000 is higher than ediff's 100+,
-    ;; but lower than isearch main overlay's 1001
-    (overlay-put ov 'priority 1000)
-    (overlay-put ov 'face 'lazy-highlight)
-    (unless (or (eq isearch-lazy-highlight 'all-windows)
-                isearch-lazy-highlight-buffer)
-      (overlay-put ov 'window (selected-window)))))
+  (when (or (not isearch-lazy-count)
+            ;; Recheck the match that possibly was intended
+            ;; for counting only, but not for highlighting
+            (let ((search-invisible 'can-be-opened))
+              (funcall isearch-filter-predicate mb me)))
+    (let ((ov (make-overlay mb me)))
+      (push ov isearch-lazy-highlight-overlays)
+      ;; 1000 is higher than ediff's 100+,
+      ;; but lower than isearch main overlay's 1001
+      (overlay-put ov 'priority 1000)
+      (overlay-put ov 'face 'lazy-highlight)
+      (unless (or (eq isearch-lazy-highlight 'all-windows)
+                  isearch-lazy-highlight-buffer)
+        (overlay-put ov 'window (selected-window))))))
 
 (defun isearch-lazy-highlight-start ()
   "Start a new lazy-highlight updating loop."
@@ -4326,11 +4349,22 @@ Attempt to do the search exactly the way the pending 
Isearch would."
                                (setq found nil)
                              (forward-char -1)))
                        (when isearch-lazy-count
-                         (setq isearch-lazy-count-total
-                               (1+ (or isearch-lazy-count-total 0)))
-                         (puthash (if isearch-lazy-highlight-forward me mb)
-                                  isearch-lazy-count-total
-                                  isearch-lazy-count-hash))
+                         ;; Count as invisible when can't open overlay,
+                         ;; but don't leave search-invisible with the
+                         ;; value `open' since then lazy-highlight
+                         ;; will open all overlays with matches.
+                         (if (not (let ((search-invisible
+                                         (if (eq search-invisible 'open)
+                                             'can-be-opened
+                                           search-invisible)))
+                                    (funcall isearch-filter-predicate mb me)))
+                             (setq isearch-lazy-count-invisible
+                                   (1+ (or isearch-lazy-count-invisible 0)))
+                           (setq isearch-lazy-count-total
+                                 (1+ (or isearch-lazy-count-total 0)))
+                           (puthash (if isearch-lazy-highlight-forward me mb)
+                                    isearch-lazy-count-total
+                                    isearch-lazy-count-hash)))
                        ;; Don't highlight the match when this loop is used
                        ;; only to count matches or when matches were already
                        ;; highlighted within the current window boundaries
@@ -4455,89 +4489,131 @@ LAX-WHITESPACE: The value of `isearch-lax-whitespace' 
and
         (funcall after-change nil nil nil)))))
 
 
-(defun isearch-search-fun-in-text-property (property &optional search-fun)
-  "Return the function to search inside text that has the specified PROPERTY.
+(defun isearch-search-fun-in-noncontiguous-region (search-fun bounds)
+  "Return the function that searches inside noncontiguous regions.
+A noncontiguous region is defined by the argument BOUNDS that
+is a list of cons cells of the form (START . END)."
+  (apply-partially
+   #'search-within-boundaries
+   search-fun
+   (lambda (pos)
+     (seq-some (lambda (b) (if isearch-forward
+                               (and (>= pos (car b)) (< pos (cdr b)))
+                             (and (> pos (car b)) (<= pos (cdr b)))))
+               bounds))
+   (lambda (pos)
+     (let ((bounds (flatten-list bounds))
+           found)
+       (unless isearch-forward
+         (setq bounds (nreverse bounds)))
+       (while (and bounds (not found))
+         (if (if isearch-forward (< pos (car bounds)) (> pos (car bounds)))
+             (setq found (car bounds))
+           (setq bounds (cdr bounds))))
+       found))))
+
+(defun isearch-search-fun-in-text-property (search-fun properties)
+  "Return the function to search inside text that has the specified PROPERTIES.
 The function will limit the search for matches only inside text which has
-this property in the current buffer.
-Optional argument SEARCH-FUN provides the function to search text, and
-defaults to the value of `isearch-search-fun-default'."
-  (lambda (string &optional bound noerror count)
-    (let* ((old (point))
-           ;; Check if point is already on the property.
-           (beg (when (get-text-property
-                       (if isearch-forward old (max (1- old) (point-min)))
-                       property)
-                  old))
-           end found (i 0)
-           (subregexp
-            (and isearch-regexp
-                 (save-match-data
-                   (catch 'subregexp
-                     (while (string-match "\\^\\|\\$" string i)
-                       (setq i (match-end 0))
-                       (when (subregexp-context-p string (match-beginning 0))
-                         ;; The ^/$ is not inside a char-range or escaped.
-                         (throw 'subregexp t))))))))
-      ;; Otherwise, try to search for the next property.
-      (unless beg
-        (setq beg (if isearch-forward
-                      (next-single-property-change old property)
-                    (previous-single-property-change old property)))
-        (when beg (goto-char beg)))
-      ;; Non-nil `beg' means there are more properties.
-      (while (and beg (not found))
-        ;; Search for the end of the current property.
-        (setq end (if isearch-forward
-                      (next-single-property-change beg property)
-                    (previous-single-property-change beg property)))
-        ;; Handle ^/$ specially by matching in a temporary buffer.
-        (if subregexp
-            (let* ((prop-beg
-                    (if (or (if isearch-forward (bobp) (eobp))
-                            (null (get-text-property
-                                   (+ (point) (if isearch-forward -1 0))
-                                   property)))
-                        ;; Already at the beginning of the field.
-                        beg
-                      ;; Get the real beginning of the field when
-                      ;; the search was started in the middle.
-                      (if isearch-forward
-                          (previous-single-property-change beg property)
-                        (next-single-property-change beg property))))
-                   (substring (buffer-substring prop-beg end))
-                   (offset (if isearch-forward prop-beg end))
-                   match-data)
-              (with-temp-buffer
-                (insert substring)
-                (goto-char (- beg offset -1))
-                ;; Apply ^/$ regexp on the whole extracted substring.
-                (setq found (funcall
-                             (or search-fun (isearch-search-fun-default))
-                             string (and bound (max (point-min)
-                                                    (min (point-max)
-                                                         (- bound offset -1))))
-                             noerror count))
-                ;; Adjust match data as if it's matched in original buffer.
-                (when found
-                  (setq found (+ found offset -1)
-                        match-data (mapcar (lambda (m) (+ m offset -1))
-                                           (match-data)))))
-              (when match-data (set-match-data match-data)))
-          (setq found (funcall
-                       (or search-fun (isearch-search-fun-default))
-                       string (if bound (if isearch-forward
-                                            (min bound end)
-                                          (max bound end))
-                                end)
-                       noerror count)))
-        ;; Get the next text property.
-        (unless found
-          (setq beg (if isearch-forward
-                        (next-single-property-change end property)
-                      (previous-single-property-change end property)))
-          (when beg (goto-char beg))))
-      (unless found (goto-char old))
-      found)))
+at least one of the text PROPERTIES.
+The argument SEARCH-FUN provides the function to search text, and
+defaults to the value of `isearch-search-fun-default' when nil."
+  (setq properties (ensure-list properties))
+  (apply-partially
+   #'search-within-boundaries
+   search-fun
+   (lambda (pos)
+     (let ((pos (if isearch-forward pos (max (1- pos) (point-min)))))
+       (seq-some (lambda (property)
+                   (get-text-property pos property))
+                 properties)))
+   (lambda (pos)
+     (let ((pos-list (if isearch-forward
+                         (mapcar (lambda (property)
+                                   (next-single-property-change
+                                    pos property))
+                                 properties)
+                       (mapcar (lambda (property)
+                                 (previous-single-property-change
+                                  pos property))
+                               properties))))
+       (setq pos-list (delq nil pos-list))
+       (when pos-list (if isearch-forward
+                          (seq-min pos-list)
+                        (seq-max pos-list)))))))
+
+(defun search-within-boundaries ( search-fun get-fun next-fun
+                                  string &optional bound noerror count)
+  (let* ((old (point))
+         ;; Check if point is already on the property.
+         (beg (when (funcall get-fun old) old))
+         end found (i 0)
+         (subregexp
+          (and isearch-regexp
+               (save-match-data
+                 (catch 'subregexp
+                   (while (string-match "\\^\\|\\$" string i)
+                     (setq i (match-end 0))
+                     (when (subregexp-context-p string (match-beginning 0))
+                       ;; The ^/$ is not inside a char-range or escaped.
+                       (throw 'subregexp t))))))))
+    ;; Otherwise, try to search for the next property.
+    (unless beg
+      (setq beg (funcall next-fun old))
+      (when beg (goto-char beg)))
+    ;; Non-nil `beg' means there are more properties.
+    (while (and beg (not found))
+      ;; Search for the end of the current property.
+      (setq end (funcall next-fun beg))
+      ;; Handle ^/$ specially by matching in a temporary buffer.
+      (if subregexp
+          (let* ((prop-beg
+                  (if (or (if isearch-forward (bobp) (eobp))
+                          (null (funcall get-fun
+                                         (+ (point)
+                                            (if isearch-forward -1 1)))))
+                      ;; Already at the beginning of the field.
+                      beg
+                    ;; Get the real beginning of the field when
+                    ;; the search was started in the middle.
+                    (let ((isearch-forward (not isearch-forward)))
+                      ;; Search in the reverse direction.
+                      (funcall next-fun beg))))
+                 (substring (buffer-substring prop-beg end))
+                 (offset (if isearch-forward prop-beg end))
+                 match-data)
+            (with-temp-buffer
+              (insert substring)
+              (goto-char (- beg offset -1))
+              ;; Apply ^/$ regexp on the whole extracted substring.
+              (setq found (funcall
+                           (or search-fun (isearch-search-fun-default))
+                           string (and bound (max (point-min)
+                                                  (min (point-max)
+                                                       (- bound offset -1))))
+                           noerror count))
+              ;; Adjust match data as if it's matched in original buffer.
+              (when found
+                (setq found (+ found offset -1)
+                      match-data (mapcar (lambda (m) (+ m offset -1))
+                                         (match-data)))))
+            (when found (goto-char found))
+            (when match-data (set-match-data
+                              (mapcar (lambda (m) (copy-marker m))
+                                      match-data))))
+        (setq found (funcall
+                     (or search-fun (isearch-search-fun-default))
+                     string (if bound (if isearch-forward
+                                          (min bound end)
+                                        (max bound end))
+                              end)
+                     noerror count)))
+      ;; Get the next text property.
+      (unless found
+        (setq beg (funcall next-fun end))
+        (when beg (goto-char beg))))
+    (unless found (goto-char old))
+    found))
 
 
 (defun isearch-resume (string regexp word forward message case-fold)
@@ -4572,6 +4648,8 @@ CASE-FOLD non-nil means the search was case-insensitive."
                        (replace-regexp-in-string "\"" "[\"“”]")))))
     (buffer-local-restore-state isearch-fold-quotes-mode--state)))
 
+(define-obsolete-function-alias 'isearch-mode-help #'isearch-describe-mode 
"29.1")
+
 (provide 'isearch)
 
 ;;; isearch.el ends here
diff --git a/lisp/jit-lock.el b/lisp/jit-lock.el
index 17969d5762..be26ca55f0 100644
--- a/lisp/jit-lock.el
+++ b/lisp/jit-lock.el
@@ -51,7 +51,7 @@ This variable controls both `display-time' and stealth 
fontification.
 
 The optimum value is a little over the typical number of buffer
 characters which fit in a typical window."
-  :type 'integer)
+  :type 'natnum)
 
 
 (defcustom jit-lock-stealth-time nil
@@ -242,20 +242,20 @@ If you need to debug code run from jit-lock, see 
`jit-lock-debug-mode'."
     (when (and jit-lock-stealth-time (null jit-lock-stealth-timer))
       (setq jit-lock-stealth-timer
             (run-with-idle-timer jit-lock-stealth-time t
-                                 'jit-lock-stealth-fontify)))
+                                 #'jit-lock-stealth-fontify)))
 
     ;; Create, but do not activate, the idle timer for repeated
     ;; stealth fontification.
     (when (and jit-lock-stealth-time (null jit-lock-stealth-repeat-timer))
       (setq jit-lock-stealth-repeat-timer (timer-create))
       (timer-set-function jit-lock-stealth-repeat-timer
-                          'jit-lock-stealth-fontify '(t)))
+                          #'jit-lock-stealth-fontify '(t)))
 
     ;; Init deferred fontification timer.
     (when (and jit-lock-defer-time (null jit-lock-defer-timer))
       (setq jit-lock-defer-timer
             (run-with-idle-timer jit-lock-defer-time t
-                                 'jit-lock-deferred-fontify)))
+                                 #'jit-lock-deferred-fontify)))
 
     ;; Initialize contextual fontification if requested.
     (when (eq jit-lock-contextually t)
@@ -265,13 +265,13 @@ If you need to debug code run from jit-lock, see 
`jit-lock-debug-mode'."
                                    (lambda ()
                                      (unless jit-lock--antiblink-grace-timer
                                        (jit-lock-context-fontify))))))
-      (add-hook 'post-command-hook 'jit-lock--antiblink-post-command nil t)
+      (add-hook 'post-command-hook #'jit-lock--antiblink-post-command nil t)
       (setq jit-lock-context-unfontify-pos
             (or jit-lock-context-unfontify-pos (point-max))))
 
     ;; Setup our hooks.
-    (add-hook 'after-change-functions 'jit-lock-after-change nil t)
-    (add-hook 'fontification-functions 'jit-lock-function nil t))
+    (add-hook 'after-change-functions #'jit-lock-after-change nil t)
+    (add-hook 'fontification-functions #'jit-lock-function nil t))
 
    ;; Turn Just-in-time Lock mode off.
    (t
@@ -294,8 +294,9 @@ If you need to debug code run from jit-lock, see 
`jit-lock-debug-mode'."
         (setq jit-lock-defer-timer nil)))
 
     ;; Remove hooks.
-    (remove-hook 'after-change-functions 'jit-lock-after-change t)
-    (remove-hook 'fontification-functions 'jit-lock-function))))
+    (remove-hook 'post-command-hook #'jit-lock--antiblink-post-command t)
+    (remove-hook 'after-change-functions #'jit-lock-after-change t)
+    (remove-hook 'fontification-functions #'jit-lock-function))))
 
 (define-minor-mode jit-lock-debug-mode
   "Minor mode to help debug code run from jit-lock.
@@ -707,8 +708,8 @@ will take place when text is fontified stealthily."
               (min jit-lock-context-unfontify-pos jit-lock-start))))))
 
 (defun jit-lock--antiblink-post-command ()
-  (let* ((new-l-b-p (copy-marker (line-beginning-position)))
-         (l-b-p-2 (line-beginning-position 2))
+  (let* ((new-l-b-p (copy-marker (syntax--lbp)))
+         (l-b-p-2 (syntax--lbp 2))
          (same-line
           (and jit-lock-antiblink-grace
                (not (= new-l-b-p l-b-p-2))
diff --git a/lisp/jsonrpc.el b/lisp/jsonrpc.el
index b84e9b74b1..90833e1c1d 100644
--- a/lisp/jsonrpc.el
+++ b/lisp/jsonrpc.el
@@ -277,7 +277,7 @@ the function is waiting, then it exits immediately, 
returning
 CANCEL-ON-INPUT-RETVAL.  Any future replies (normal or error) are
 ignored."
   (let* ((tag (cl-gensym "jsonrpc-request-catch-tag")) id-and-timer
-         cancelled
+         canceled
          (retval
           (unwind-protect
               (catch tag
@@ -287,26 +287,26 @@ ignored."
                   #'jsonrpc--async-request-1
                   connection method params
                   :success-fn (lambda (result)
-                                (unless cancelled
+                                (unless canceled
                                   (throw tag `(done ,result))))
                   :error-fn
                   (jsonrpc-lambda
                       (&key code message data)
-                    (unless cancelled
+                    (unless canceled
                       (throw tag `(error (jsonrpc-error-code . ,code)
                                          (jsonrpc-error-message . ,message)
                                          (jsonrpc-error-data . ,data)))))
                   :timeout-fn
                   (lambda ()
-                    (unless cancelled
+                    (unless canceled
                       (throw tag '(error (jsonrpc-error-message . "Timed 
out")))))
                   `(,@(when deferred `(:deferred ,deferred))
                     ,@(when timeout  `(:timeout  ,timeout)))))
                 (cond (cancel-on-input
                        (unwind-protect
                            (let ((inhibit-quit t)) (while (sit-for 30)))
-                         (setq cancelled t))
-                       `(cancelled ,cancel-on-input-retval))
+                         (setq canceled t))
+                       `(canceled ,cancel-on-input-retval))
                       (t (while t (accept-process-output nil 30)))))
             ;; In normal operation, cancellation is handled by the
             ;; timeout function and response filter, but we still have
diff --git a/lisp/keymap.el b/lisp/keymap.el
index 71454eba5e..107565590c 100644
--- a/lisp/keymap.el
+++ b/lisp/keymap.el
@@ -241,13 +241,13 @@ See `kbd' for a descripion of KEYS."
                      (setq bits (+ bits
                                    (cdr
                                     (assq (aref word 0)
-                                          '((?A . ?\A-\^@) (?C . ?\C-\^@)
-                                            (?H . ?\H-\^@) (?M . ?\M-\^@)
-                                            (?s . ?\s-\^@) (?S . ?\S-\^@))))))
+                                          '((?A . ?\A-\0) (?C . ?\C-\0)
+                                            (?H . ?\H-\0) (?M . ?\M-\0)
+                                            (?s . ?\s-\0) (?S . ?\S-\0))))))
                      (setq prefix (+ prefix 2))
                      (setq word (substring word 2)))
                    (when (string-match "^\\^.$" word)
-                     (setq bits (+ bits ?\C-\^@))
+                     (setq bits (+ bits ?\C-\0))
                      (setq prefix (1+ prefix))
                      (setq word (substring word 1)))
                    (let ((found (assoc word '(("NUL" . "\0") ("RET" . "\r")
@@ -262,19 +262,19 @@ See `kbd' for a descripion of KEYS."
                        (setq word (vector n))))
                    (cond ((= bits 0)
                           (setq key word))
-                         ((and (= bits ?\M-\^@) (stringp word)
+                         ((and (= bits ?\M-\0) (stringp word)
                                (string-match "^-?[0-9]+$" word))
                           (setq key (mapcar (lambda (x) (+ x bits))
                                             (append word nil))))
                          ((/= (length word) 1)
                           (error "%s must prefix a single character, not %s"
                                  (substring orig-word 0 prefix) word))
-                         ((and (/= (logand bits ?\C-\^@) 0) (stringp word)
+                         ((and (/= (logand bits ?\C-\0) 0) (stringp word)
                                ;; We used to accept . and ? here,
                                ;; but . is simply wrong,
                                ;; and C-? is not used (we use DEL instead).
                                (string-match "[@-_a-z]" word))
-                          (setq key (list (+ bits (- ?\C-\^@)
+                          (setq key (list (+ bits (- ?\C-\0)
                                              (logand (aref word 0) 31)))))
                          (t
                           (setq key (list (+ bits (aref word 0)))))))))
@@ -313,7 +313,7 @@ Modifiers have to be specified in this order:
 which is
 
    Alt-Control-Hyper-Meta-Shift-super"
-  (declare (pure t) (side-effect-free t))
+  (declare (pure t) (side-effect-free error-free))
   (let ((case-fold-search nil))
     (and
      (stringp keys)
@@ -530,7 +530,8 @@ should be a MENU form as accepted by `easy-menu-define'.
                    (keymap keymap)
                    (prefix (define-prefix-command prefix nil name))
                    (full (make-keymap name))
-                   (t (make-sparse-keymap name)))))
+                   (t (make-sparse-keymap name))))
+          seen-keys)
       (when suppress
         (suppress-keymap keymap (eq suppress 'nodigits)))
       (when parent
@@ -544,6 +545,9 @@ should be a MENU form as accepted by `easy-menu-define'.
           (let ((def (pop definitions)))
             (if (eq key :menu)
                 (easy-menu-define nil keymap "" def)
+              (if (member key seen-keys)
+                  (error "Duplicate definition for key: %S %s" key keymap)
+                (push key seen-keys))
               (keymap-set keymap key def)))))
       keymap)))
 
@@ -571,10 +575,25 @@ as the variable documentation string.
           (push (pop defs) opts))))
     (unless (zerop (% (length defs) 2))
       (error "Uneven number of key/definition pairs: %s" defs))
+    (let ((defs defs)
+          key seen-keys)
+      (while defs
+        (setq key (pop defs))
+        (pop defs)
+        (when (not (eq key :menu))
+          (if (member key seen-keys)
+              (error "Duplicate definition for key '%s' in keymap '%s'"
+                     key variable-name)
+            (push key seen-keys)))))
     `(defvar ,variable-name
        (define-keymap ,@(nreverse opts) ,@defs)
        ,@(and doc (list doc)))))
 
+(defun make-non-key-event (symbol)
+  "Mark SYMBOL as an event that shouldn't be returned from `where-is'."
+  (put symbol 'non-key-event t)
+  symbol)
+
 (provide 'keymap)
 
 ;;; keymap.el ends here
diff --git a/lisp/kmacro.el b/lisp/kmacro.el
index 5746b770a2..72420a6730 100644
--- a/lisp/kmacro.el
+++ b/lisp/kmacro.el
@@ -129,7 +129,7 @@ Set to nil if no mouse binding is desired."
 
 (defcustom kmacro-ring-max 8
   "Maximum number of keyboard macros to save in macro ring."
-  :type 'integer)
+  :type 'natnum)
 
 
 (defcustom kmacro-execute-before-append t
@@ -164,43 +164,41 @@ macro to be executed before appending to it."
 
 ;; Keymap
 
-(defvar kmacro-keymap
-  (let ((map (make-sparse-keymap)))
-    ;; Start, end, execute macros
-    (define-key map "s"    #'kmacro-start-macro)
-    (define-key map "\C-s" #'kmacro-start-macro)
-    (define-key map "\C-k" #'kmacro-end-or-call-macro-repeat)
-    (define-key map "r"    #'apply-macro-to-region-lines)
-    (define-key map "q"    #'kbd-macro-query)  ;; Like C-x q
-    (define-key map "d"    #'kmacro-redisplay)
-
-    ;; macro ring
-    (define-key map "\C-n" #'kmacro-cycle-ring-next)
-    (define-key map "\C-p" #'kmacro-cycle-ring-previous)
-    (define-key map "\C-v" #'kmacro-view-macro-repeat)
-    (define-key map "\C-d" #'kmacro-delete-ring-head)
-    (define-key map "\C-t" #'kmacro-swap-ring)
-    (define-key map "\C-l" #'kmacro-call-ring-2nd-repeat)
-
-    ;; macro counter
-    (define-key map "\C-f" #'kmacro-set-format)
-    (define-key map "\C-c" #'kmacro-set-counter)
-    (define-key map "\C-i" #'kmacro-insert-counter)
-    (define-key map "\C-a" #'kmacro-add-counter)
-
-    ;; macro editing
-    (define-key map "\C-e" #'kmacro-edit-macro-repeat)
-    (define-key map "\r"   #'kmacro-edit-macro)
-    (define-key map "e"    #'edit-kbd-macro)
-    (define-key map "l"    #'kmacro-edit-lossage)
-    (define-key map " "    #'kmacro-step-edit-macro)
-
-    ;; naming and binding
-    (define-key map "b"    #'kmacro-bind-to-key)
-    (define-key map "n"    #'kmacro-name-last-macro)
-    (define-key map "x"    #'kmacro-to-register)
-    map)
-  "Keymap for keyboard macro commands.")
+(defvar-keymap kmacro-keymap
+  :doc "Keymap for keyboard macro commands."
+  ;; Start, end, execute macros
+  "s"    #'kmacro-start-macro
+  "C-s"  #'kmacro-start-macro
+  "C-k"  #'kmacro-end-or-call-macro-repeat
+  "r"    #'apply-macro-to-region-lines
+  "q"    #'kbd-macro-query  ;; Like C-x q
+  "d"    #'kmacro-redisplay
+
+  ;; macro ring
+  "C-n"  #'kmacro-cycle-ring-next
+  "C-p"  #'kmacro-cycle-ring-previous
+  "C-v"  #'kmacro-view-macro-repeat
+  "C-d"  #'kmacro-delete-ring-head
+  "C-t"  #'kmacro-swap-ring
+  "C-l"  #'kmacro-call-ring-2nd-repeat
+
+  ;; macro counter
+  "C-f"  #'kmacro-set-format
+  "C-c"  #'kmacro-set-counter
+  "C-i"  #'kmacro-insert-counter
+  "C-a"  #'kmacro-add-counter
+
+  ;; macro editing
+  "C-e"  #'kmacro-edit-macro-repeat
+  "RET"  #'kmacro-edit-macro
+  "e"    #'edit-kbd-macro
+  "l"    #'kmacro-edit-lossage
+  "SPC"  #'kmacro-step-edit-macro
+
+  ;; naming and binding
+  "b"    #'kmacro-bind-to-key
+  "n"    #'kmacro-name-last-macro
+  "x"    #'kmacro-to-register)
 (defalias 'kmacro-keymap kmacro-keymap)
 
 ;;; Provide some binding for startup:
@@ -877,8 +875,8 @@ KEYS should be a vector or a string that obeys 
`key-valid-p'."
 
 (defun kmacro-bind-to-key (_arg)
   "When not defining or executing a macro, offer to bind last macro to a key.
-The key sequences `C-x C-k 0' through `C-x C-k 9' and `C-x C-k A'
-through `C-x C-k Z' are reserved for user bindings, and to bind to
+The key sequences \\`C-x C-k 0' through \\`C-x C-k 9' and \\`C-x C-k A'
+through \\`C-x C-k Z' are reserved for user bindings, and to bind to
 one of these sequences, just enter the digit or letter, rather than
 the whole sequence.
 
@@ -922,6 +920,7 @@ The ARG parameter is unused."
          (vectorp f)                   ;FIXME: Deprecated.
          (kmacro-p f)))))
 
+;;;###autoload
 (defun kmacro-name-last-macro (symbol)
   "Assign a name to the last keyboard macro defined.
 Argument SYMBOL is the name to define.
@@ -1004,7 +1003,7 @@ The ARG parameter is unused."
   "Display the last keyboard macro.
 If repeated, it shows previous elements in the macro ring.
 To execute the displayed macro ring item without changing the macro ring,
-just enter C-k.
+just enter \\`C-k'.
 This is like `kmacro-view-macro', but allows repeating macro commands
 without repeating the prefix."
   (interactive)
@@ -1049,34 +1048,30 @@ without repeating the prefix."
 (defvar kmacro-step-edit-help)          ;; kmacro step edit help enabled
 (defvar kmacro-step-edit-num-input-keys) ;; to ignore duplicate pre-command 
hook
 
-(defvar kmacro-step-edit-map
-  (let ((map (make-sparse-keymap)))
-    ;; query-replace-map answers include: `act', `skip', `act-and-show',
-    ;; `exit', `act-and-exit', `edit', `delete-and-edit', `recenter',
-    ;; `automatic', `backup', `exit-prefix', and `help'.")
-    ;; Also: `quit', `edit-replacement'
-
-    (set-keymap-parent map query-replace-map)
-
-    (define-key map "\t" 'act-repeat)
-    (define-key map [tab] 'act-repeat)
-    (define-key map "\C-k" 'skip-rest)
-    (define-key map "c" 'automatic)
-    (define-key map "f" 'skip-keep)
-    (define-key map "q" 'quit)
-    (define-key map "d" 'skip)
-    (define-key map "\C-d" 'skip)
-    (define-key map "i" 'insert)
-    (define-key map "I" 'insert-1)
-    (define-key map "r" 'replace)
-    (define-key map "R" 'replace-1)
-    (define-key map "a" 'append)
-    (define-key map "A" 'append-end)
-    map)
-  "Keymap that defines the responses to questions in `kmacro-step-edit-macro'.
+(defvar-keymap kmacro-step-edit-map
+  :doc "Keymap that defines the responses to questions in 
`kmacro-step-edit-macro'.
 This keymap is an extension to the `query-replace-map', allowing the
 following additional answers: `insert', `insert-1', `replace', `replace-1',
-`append', `append-end', `act-repeat', `skip-end', `skip-keep'.")
+`append', `append-end', `act-repeat', `skip-end', `skip-keep'."
+  ;; query-replace-map answers include: `act', `skip', `act-and-show',
+  ;; `exit', `act-and-exit', `edit', `delete-and-edit', `recenter',
+  ;; `automatic', `backup', `exit-prefix', and `help'.")
+  ;; Also: `quit', `edit-replacement'
+  :parent query-replace-map
+  "TAB"   'act-repeat
+  "<tab>" 'act-repeat
+  "C-k"   'skip-rest
+  "c"     'automatic
+  "f"     'skip-keep
+  "q"     'quit
+  "d"     'skip
+  "C-d"   'skip
+  "i"     'insert
+  "I"     'insert-1
+  "r"     'replace
+  "R"     'replace-1
+  "a"     'append
+  "A"     'append-end)
 
 (defun kmacro-step-edit-prompt (macro index)
   ;; Show step-edit prompt
diff --git a/lisp/language/european.el b/lisp/language/european.el
index 8e3aac7c2e..937215074b 100644
--- a/lisp/language/european.el
+++ b/lisp/language/european.el
@@ -390,7 +390,7 @@ Latin-9 is sometimes nicknamed `Latin-0'."))
 (define-coding-system-alias 'cp284 'ibm284)
 
 (define-coding-system 'ibm285
-  "UK english version of EBCDIC"
+  "UK English version of EBCDIC"
   :coding-type 'charset
   :charset-list '(ibm285)
   :mnemonic ?*)
diff --git a/lisp/language/ind-util.el b/lisp/language/ind-util.el
index 60ada03fa2..27facaa858 100644
--- a/lisp/language/ind-util.el
+++ b/lisp/language/ind-util.el
@@ -267,11 +267,11 @@
      ?த nil nil nil ?ந ?ன              ;; DENTALS
      ?ப nil nil nil ?ம                  ;; LABIALS
      ?ய ?ர ?ற ?ல ?ள ?ழ ?வ          ;; SEMIVOWELS
-     nil ?ஷ ?ஸ ?ஹ                    ;; SIBILANTS
+     ?ஶ ?ஷ ?ஸ ?ஹ                    ;; SIBILANTS
      nil nil nil nil nil nil nil nil      ;; NUKTAS
-     "ஜ்ஞ" "க்ஷ")
+     "ஜ்ஞ" "க்ஷ" "க்‌ஷ")
     (;; Misc Symbols
-     nil ?ஂ ?ஃ nil ?் nil nil)
+     nil ?ஂ ?ஃ nil ?் ?ௐ nil)
     (;; Digits
      nil nil nil nil nil nil nil nil nil nil)
     (;; Inscript-extra (4)  (#, $, ^, *, ])
@@ -290,11 +290,11 @@
      ?த nil nil nil ?ந ?ன              ;; DENTALS
      ?ப nil nil nil ?ம                  ;; LABIALS
      ?ய ?ர ?ற ?ல ?ள ?ழ ?வ          ;; SEMIVOWELS
-     nil ?ஷ ?ஸ ?ஹ                    ;; SIBILANTS
+     ?ஶ ?ஷ ?ஸ ?ஹ                    ;; SIBILANTS
      nil nil nil nil nil nil nil nil      ;; NUKTAS
-     "ஜ்ஞ" "க்ஷ")
+     "ஜ்ஞ" "க்ஷ" "க்‌ஷ")
     (;; Misc Symbols
-     nil ?ஂ ?ஃ nil ?் nil nil)
+     nil ?ஂ ?ஃ nil ?் ?ௐ nil)
     (;; Digits
      ?௦ ?௧ ?௨ ?௩ ?௪ ?௫ ?௬ ?௭ ?௮ ?௯)
     (;; Inscript-extra (4)  (#, $, ^, *, ])
@@ -315,8 +315,8 @@
   '(;; for encode/decode
     (;; vowels -- 18
      "a" ("aa" "A") "i" ("ii" "I") "u" ("uu" "U")
-     ("RRi" "R^i") ("LLi" "L^i") (".c" "e.c") "E" "e" "ai"
-     "o.c"  "O"   "o"   "au"  ("RRI" "R^I") ("LLI" "L^I"))
+     ("RRi" "R^i" "RRu" "R^u") ("LLi" "L^i") (".c" "e.c") "E" "e" "ai"
+     "o.c"  "O"   "o"   "au"  ("RRI" "R^I" "RRU" "R^U") ("LLI" "L^I"))
     (;; consonants -- 40
      "k"   "kh"  "g"   "gh"  ("~N" "N^")
      "ch" ("Ch" "chh") "j" "jh" ("~n" "JN")
diff --git a/lisp/language/indian.el b/lisp/language/indian.el
index 2887d410ad..407173827f 100644
--- a/lisp/language/indian.el
+++ b/lisp/language/indian.el
@@ -109,7 +109,7 @@ are supported in this language environment."))
  "Tamil" '((charset unicode)
           (coding-system utf-8)
           (coding-priority utf-8)
-          (input-method . "tamil-itrans")
+          (input-method . "tamil-phonetic")
            (sample-text . "Tamil (தமிழ்)       வணக்கம்")
           (documentation . "\
 South Indian Language Tamil is supported in this language environment."))
diff --git a/lisp/language/misc-lang.el b/lisp/language/misc-lang.el
index 1e915c2f83..3d5b68f84b 100644
--- a/lisp/language/misc-lang.el
+++ b/lisp/language/misc-lang.el
@@ -137,10 +137,13 @@ thin (i.e. 1-dot width) space."
 (set-char-table-range
  composition-function-table
  '(#x600 . #x74F)
- (list (vector "[\u200C\u200D][\u0600-\u074F\u200C\u200D]+"
-               1 #'arabic-shape-gstring)
-       (vector "[\u0600-\u074F\u200C\u200D]+"
+ (list (vector "[\u0600-\u074F\u200C\u200D]+"
                0 #'arabic-shape-gstring)))
+(set-char-table-range
+ composition-function-table
+ '(#x200C . #x200D)
+  (list (vector "[\u200C\u200D][\u0600-\u074F\u200C\u200D]+"
+                0 #'arabic-shape-gstring)))
 
 ;; The Egyptian Hieroglyph Format Controls were introduced in Unicode
 ;; Standard v12.0.  Apparently, they are not yet well supported in
diff --git a/lisp/ldefs-boot.el b/lisp/ldefs-boot.el
index f4e9d2732f..07dfc23a09 100644
--- a/lisp/ldefs-boot.el
+++ b/lisp/ldefs-boot.el
@@ -38,16 +38,16 @@ Rotate left Calc Solutions  \\[5x5-solve-rotate-left]
 Rotate right Calc Solutions \\[5x5-solve-rotate-right]
 Quit current game           \\[5x5-quit-game]
 
-(fn &optional SIZE)" t nil)
+(fn &optional SIZE)" t)
 (autoload '5x5-crack-randomly "5x5" "\
-Attempt to crack 5x5 using random solutions." t nil)
+Attempt to crack 5x5 using random solutions." t)
 (autoload '5x5-crack-mutating-current "5x5" "\
-Attempt to crack 5x5 by mutating the current solution." t nil)
+Attempt to crack 5x5 by mutating the current solution." t)
 (autoload '5x5-crack-mutating-best "5x5" "\
-Attempt to crack 5x5 by mutating the best solution." t nil)
+Attempt to crack 5x5 by mutating the best solution." t)
 (autoload '5x5-crack-xor-mutate "5x5" "\
 Attempt to crack 5x5 by xoring the current and best solution.
-Mutate the result." t nil)
+Mutate the result." t)
 (autoload '5x5-crack "5x5" "\
 Attempt to find a solution for 5x5.
 
@@ -56,7 +56,7 @@ two parameters, the first will be a grid vector array that is 
the current
 solution and the second will be the best solution so far.  The function
 should return a grid vector array that is the new solution.
 
-(fn BREEDER)" t nil)
+(fn BREEDER)" t)
 (register-definition-prefixes "5x5" '("5x5-"))
 
 
@@ -81,7 +81,7 @@ will be recognized as referring to the same user; when 
creating a new
 ChangeLog entry, one element will be chosen at random.")
 (custom-autoload 'add-log-mailing-address "add-log" t)
 (autoload 'prompt-for-change-log-name "add-log" "\
-Prompt for a change log name." nil nil)
+Prompt for a change log name.")
 (autoload 'find-change-log "add-log" "\
 Find a change log file for \\[add-change-log-entry] and return the name.
 
@@ -102,7 +102,7 @@ Once a file is found, `change-log-default-name' is set 
locally in the
 current buffer to the complete file name.
 Optional arg BUFFER-FILE overrides `buffer-file-name'.
 
-(fn &optional FILE-NAME BUFFER-FILE)" nil nil)
+(fn &optional FILE-NAME BUFFER-FILE)")
 (autoload 'add-change-log-entry "add-log" "\
 Find ChangeLog buffer, add an entry for today and an item for this file.
 Optional arg WHOAMI (interactive prefix) non-nil means prompt for
@@ -138,13 +138,13 @@ notices.
 Today's date is calculated according to `add-log-time-zone-rule' if
 non-nil, otherwise in local time.
 
-(fn &optional WHOAMI CHANGELOG-FILE-NAME OTHER-WINDOW NEW-ENTRY 
PUT-NEW-ENTRY-ON-NEW-LINE)" t nil)
+(fn &optional WHOAMI CHANGELOG-FILE-NAME OTHER-WINDOW NEW-ENTRY 
PUT-NEW-ENTRY-ON-NEW-LINE)" t)
 (autoload 'add-change-log-entry-other-window "add-log" "\
 Find change log file in other window and add entry and item.
 This is just like `add-change-log-entry' except that it displays
 the change log file in another window.
 
-(fn &optional WHOAMI FILE-NAME)" t nil)
+(fn &optional WHOAMI FILE-NAME)" t)
 (autoload 'change-log-mode "add-log" "\
 Major mode for editing change logs; like Indented Text mode.
 Prevents numeric backups and sets `left-margin' to 8 and `fill-column' to 74.
@@ -154,7 +154,7 @@ Runs `change-log-mode-hook'.
 
 \\{change-log-mode-map}
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'add-log-current-defun "add-log" "\
 Return name of function definition point is in, or nil.
 
@@ -167,7 +167,7 @@ identifiers followed by `:' or `='.  See variables
 `add-log-current-defun-header-regexp' and
 `add-log-current-defun-function'.
 
-Has a preference of looking backwards." nil nil)
+Has a preference of looking backwards.")
 (autoload 'change-log-merge "add-log" "\
 Merge the contents of change log file OTHER-LOG with this buffer.
 Both must be found in Change Log mode (since the merging depends on
@@ -177,7 +177,7 @@ or a buffer.
 Entries are inserted in chronological order.  Both the current and
 old-style time formats for entries are supported.
 
-(fn OTHER-LOG)" t nil)
+(fn OTHER-LOG)" t)
 (register-definition-prefixes "add-log" '("add-log-" "change-log-"))
 
 
@@ -206,11 +206,11 @@ COMPILE argument of `ad-activate' was supplied as nil.")
 (autoload 'ad-enable-advice "advice" "\
 Enables the advice of FUNCTION with CLASS and NAME.
 
-(fn FUNCTION CLASS NAME)" t nil)
+(fn FUNCTION CLASS NAME)" t)
 (autoload 'ad-disable-advice "advice" "\
 Disable the advice of FUNCTION with CLASS and NAME.
 
-(fn FUNCTION CLASS NAME)" t nil)
+(fn FUNCTION CLASS NAME)" t)
 (autoload 'ad-add-advice "advice" "\
 Add a piece of ADVICE to FUNCTION's list of advices in CLASS.
 
@@ -234,7 +234,7 @@ If FUNCTION was not advised already, its advice info will be
 initialized.  Redefining a piece of advice whose name is part of
 the cache-id will clear the cache.
 
-(fn FUNCTION ADVICE CLASS POSITION)" nil nil)
+(fn FUNCTION ADVICE CLASS POSITION)")
 (autoload 'ad-activate "advice" "\
 Activate all the advice information of an advised FUNCTION.
 If FUNCTION has a proper original definition then an advised
@@ -252,7 +252,7 @@ an advised function that has actual pieces of advice but 
none of them are
 enabled is equivalent to a call to `ad-deactivate'.  The current advised
 definition will always be cached for later usage.
 
-(fn FUNCTION &optional COMPILE)" t nil)
+(fn FUNCTION &optional COMPILE)" t)
 (autoload 'defadvice "advice" "\
 Define a piece of advice for FUNCTION (a symbol).
 The syntax of `defadvice' is as follows:
@@ -300,8 +300,8 @@ usage: (defadvice FUNCTION (CLASS NAME [POSITION] [ARGLIST] 
FLAG...)
           BODY...)
 
 (fn FUNCTION ARGS &rest BODY)" nil t)
-(function-put 'defadvice 'doc-string-elt '3)
-(function-put 'defadvice 'lisp-indent-function '2)
+(function-put 'defadvice 'doc-string-elt 3)
+(function-put 'defadvice 'lisp-indent-function 2)
 (register-definition-prefixes "advice" '("ad-"))
 
 
@@ -313,8 +313,8 @@ Interactively, BEG and END are the mark/point of the 
current region.
 
 Many modes define specific alignment rules, and some of these
 rules in some modes react to the current prefix argument.  For
-instance, in `text-mode', `M-x align' will align into columns
-based on space delimiters, while `C-u - M-x align' will align
+instance, in `text-mode', \\`M-x align' will align into columns
+based on space delimiters, while \\`C-u -' \\`M-x align' will align
 into columns based on the \"$\" character.  See the
 `align-rules-list' variable definition for the specific rules.
 
@@ -335,7 +335,7 @@ default rule lists defined in `align-rules-list' and
 `align-exclude-rules-list'.  See `align-rules-list' for more details
 on the format of these lists.
 
-(fn BEG END &optional SEPARATE RULES EXCLUDE-RULES)" t nil)
+(fn BEG END &optional SEPARATE RULES EXCLUDE-RULES)" t)
 (autoload 'align-regexp "align" "\
 Align the current region using an ad-hoc rule read from the minibuffer.
 BEG and END mark the limits of the region.  Interactively, this function
@@ -378,7 +378,7 @@ The non-interactive form of the previous example would look 
something like:
 This function is a nothing more than a small wrapper that helps you
 construct a rule to pass to `align-region', which does the real work.
 
-(fn BEG END REGEXP &optional GROUP SPACING REPEAT)" t nil)
+(fn BEG END REGEXP &optional GROUP SPACING REPEAT)" t)
 (autoload 'align-entire "align" "\
 Align the selected region as if it were one alignment section.
 BEG and END mark the extent of the region.  If RULES or EXCLUDE-RULES
@@ -386,7 +386,7 @@ is set to a list of rules (see `align-rules-list'), it can 
be used to
 override the default alignment rules that would have been used to
 align that section.
 
-(fn BEG END &optional RULES EXCLUDE-RULES)" t nil)
+(fn BEG END &optional RULES EXCLUDE-RULES)" t)
 (autoload 'align-current "align" "\
 Call `align' on the current alignment section.
 This function assumes you want to align only the current section, and
@@ -395,7 +395,7 @@ EXCLUDE-RULES is set to a list of rules (see 
`align-rules-list'), it
 can be used to override the default alignment rules that would have
 been used to align that section.
 
-(fn &optional RULES EXCLUDE-RULES)" t nil)
+(fn &optional RULES EXCLUDE-RULES)" t)
 (autoload 'align-highlight-rule "align" "\
 Highlight the whitespace which a given rule would have modified.
 BEG and END mark the extent of the region.  TITLE identifies the rule
@@ -404,13 +404,13 @@ list of rules (see `align-rules-list'), it can be used to 
override the
 default alignment rules that would have been used to identify the text
 to be colored.
 
-(fn BEG END TITLE &optional RULES EXCLUDE-RULES)" t nil)
+(fn BEG END TITLE &optional RULES EXCLUDE-RULES)" t)
 (autoload 'align-unhighlight-rule "align" "\
-Remove any highlighting that was added by `align-highlight-rule'." t nil)
+Remove any highlighting that was added by `align-highlight-rule'." t)
 (autoload 'align-newline-and-indent "align" "\
 A replacement function for `newline-and-indent', aligning as it goes.
 The alignment is done by calling `align' on the region that was
-indented." t nil)
+indented." t)
 (register-definition-prefixes "align" '("align-"))
 
 
@@ -422,7 +422,7 @@ Institute `allout-auto-activation'.
 
 Intended to be used as the `allout-auto-activation' :set function.
 
-(fn VAR VALUE)" nil nil)
+(fn VAR VALUE)")
 (autoload 'allout-setup "allout" "\
 Do fundamental Emacs session for allout auto-activation.
 
@@ -430,7 +430,7 @@ Establishes allout processing as part of visiting a file if
 `allout-auto-activation' is non-nil, or removes it otherwise.
 
 The proper way to use this is through customizing the setting of
-`allout-auto-activation'." nil nil)
+`allout-auto-activation'.")
 (defvar allout-auto-activation nil "\
 Configure allout outline mode auto-activation.
 
@@ -567,7 +567,7 @@ the HOT-SPOT Operation section.
 
         Misc commands:
         -------------
-M-x outlineify-sticky       Activate outline mode for current buffer,
+\\[allout-outlinify-sticky] Activate outline mode for current buffer,
                             and establish a default file-var setting
                             for `allout-layout'.
 \\[allout-mark-topic]       `allout-mark-topic'
@@ -639,7 +639,6 @@ hooks, by which independent code can cooperate with allout
 without changes to the allout core.  Here are key ones:
 
 `allout-mode-hook'
-`allout-mode-deactivate-hook' (deprecated)
 `allout-mode-off-hook'
 `allout-exposure-change-functions'
 `allout-structure-added-functions'
@@ -743,15 +742,16 @@ evaluate `allout-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
-(defalias 'outlinify-sticky #'outlineify-sticky)
-(autoload 'outlineify-sticky "allout" "\
+(fn &optional ARG)" t)
+(define-obsolete-function-alias 'outlinify-sticky #'allout-outlinify-sticky 
"29.1")
+(define-obsolete-function-alias 'outlineify-sticky #'allout-outlinify-sticky 
"29.1")
+(autoload 'allout-outlinify-sticky "allout" "\
 Activate outline mode and establish file var so it is started subsequently.
 
 See `allout-layout' and customization of `allout-auto-activation'
 for details on preparing Emacs for automatic allout activation.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "allout" '("allout-"))
 
 
@@ -763,7 +763,7 @@ Commission or decommission allout-widgets-mode along with 
allout-mode.
 
 Meant to be used by customization of `allout-widgets-auto-activation'.
 
-(fn VARNAME VALUE)" nil nil)
+(fn VARNAME VALUE)")
 (defvar allout-widgets-auto-activation nil "\
 Activate to enable allout icon graphics wherever allout mode is active.
 
@@ -815,7 +815,7 @@ evaluate `allout-widgets-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "allout-widgets" '("allout-"))
 
 
@@ -826,7 +826,7 @@ it is disabled.
 
 ;;; Generated autoloads from net/ange-ftp.el
 
-(defalias 'ange-ftp-re-read-dir 'ange-ftp-reread-dir)
+(define-obsolete-function-alias 'ange-ftp-re-read-dir #'ange-ftp-reread-dir 
"29.1")
 (autoload 'ange-ftp-reread-dir "ange-ftp" "\
 Reread remote directory DIR to update the directory cache.
 The implementation of remote FTP file names caches directory contents
@@ -834,11 +834,11 @@ for speed.  Therefore, when new remote files are created, 
Emacs
 may not know they exist.  You can use this command to reread a specific
 directory, so that Emacs will know its current contents.
 
-(fn &optional DIR)" t nil)
+(fn &optional DIR)" t)
 (autoload 'ange-ftp-hook-function "ange-ftp" "\
 
 
-(fn OPERATION &rest ARGS)" nil nil)
+(fn OPERATION &rest ARGS)")
 (register-definition-prefixes "ange-ftp" '("ange-ftp-" "ftp-error" 
"internal-ange-ftp-mode"))
 
 
@@ -852,7 +852,7 @@ passing through `animate-n-steps' positions before the 
final ones.
 If HPOS is nil (or omitted), center the string horizontally
 in the current window.
 
-(fn STRING VPOS &optional HPOS)" nil nil)
+(fn STRING VPOS &optional HPOS)")
 (autoload 'animate-sequence "animate" "\
 Display animation strings from LIST-OF-STRING with buffer *Animation*.
 Strings will be separated from each other by SPACE lines.
@@ -860,14 +860,14 @@ Strings will be separated from each other by SPACE lines.
 animation in the buffer named by variable's value, creating the
 buffer if one does not exist.
 
-(fn LIST-OF-STRINGS SPACE)" nil nil)
+(fn LIST-OF-STRINGS SPACE)")
 (autoload 'animate-birthday-present "animate" "\
 Return a birthday present in the buffer *Birthday-Present*.
 When optional arg NAME is non-nil or called-interactively, prompt for
 NAME of birthday present receiver and return a birthday present in
 the buffer *Birthday-Present-for-Name*.
 
-(fn &optional NAME)" t nil)
+(fn &optional NAME)" t)
 (register-definition-prefixes "animate" '("animat"))
 
 
@@ -875,7 +875,7 @@ the buffer *Birthday-Present-for-Name*.
 
 (push (purecopy '(ansi-color 3 4 2)) package--builtin-versions)
 (autoload 'ansi-color-for-comint-mode-on "ansi-color" "\
-Set `ansi-color-for-comint-mode' to t." t nil)
+Set `ansi-color-for-comint-mode' to t." t)
 (autoload 'ansi-color-process-output "ansi-color" "\
 Maybe translate SGR control sequences of comint output into text properties.
 
@@ -889,11 +889,11 @@ The comint output is assumed to lie between the marker
 
 This is a good function to put in `comint-output-filter-functions'.
 
-(fn IGNORED)" nil nil)
+(fn IGNORED)")
 (autoload 'ansi-color-compilation-filter "ansi-color" "\
 Maybe translate SGR control sequences into text properties.
 This function depends on the `ansi-color-for-compilation-mode'
-variable, and is meant to be used in `compilation-filter-hook'." nil nil)
+variable, and is meant to be used in `compilation-filter-hook'.")
 (register-definition-prefixes "ansi-color" '("ansi-color-"))
 
 
@@ -915,14 +915,14 @@ the rules.
 If the file for a super-grammar cannot be determined, special file names
 are used according to variable `antlr-unknown-file-formats' and a
 commentary with value `antlr-help-unknown-file-text' is added.  The
-*Help* buffer always starts with the text in `antlr-help-rules-intro'." t nil)
+*Help* buffer always starts with the text in `antlr-help-rules-intro'." t)
 (autoload 'antlr-mode "antlr-mode" "\
 Major mode for editing ANTLR grammar files.
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'antlr-set-tabs "antlr-mode" "\
 Use ANTLR's convention for TABs according to `antlr-tab-offset-alist'.
-Used in `antlr-mode'.  Also a useful function in `java-mode-hook'." nil nil)
+Used in `antlr-mode'.  Also a useful function in `java-mode-hook'.")
 (register-definition-prefixes "antlr-mode" '("antlr-"))
 
 
@@ -935,13 +935,13 @@ Optional argument WARNTIME is an integer (or string) 
giving the number
 of minutes before the appointment at which to start warning.
 The default is `appt-message-warning-time'.
 
-(fn TIME MSG &optional WARNTIME)" t nil)
+(fn TIME MSG &optional WARNTIME)" t)
 (autoload 'appt-activate "appt" "\
 Toggle checking of appointments.
 With optional numeric argument ARG, turn appointment checking on if
 ARG is positive, otherwise off.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "appt" '("appt-"))
 
 
@@ -955,7 +955,7 @@ literally, or a string which is used as a regexp to search 
for.
 SUBJECT is a string that is included in the prompt to identify what
 kind of objects to search.
 
-(fn SUBJECT)" nil nil)
+(fn SUBJECT)")
 (autoload 'apropos-user-option "apropos" "\
 Show user options that match PATTERN.
 PATTERN can be a word, a list of words (separated by spaces),
@@ -966,14 +966,14 @@ search for matches for any two (or more) of those words.
 With \\[universal-argument] prefix, or if `apropos-do-all' is non-nil, also 
show
 variables, not just user options.
 
-(fn PATTERN &optional DO-ALL)" t nil)
+(fn PATTERN &optional DO-ALL)" t)
 (autoload 'apropos-variable "apropos" "\
 Show variables that match PATTERN.
 With the optional argument DO-NOT-ALL non-nil (or when called
 interactively with the prefix \\[universal-argument]), show user
 options only, i.e. behave like `apropos-user-option'.
 
-(fn PATTERN &optional DO-NOT-ALL)" t nil)
+(fn PATTERN &optional DO-NOT-ALL)" t)
 (autoload 'apropos-local-variable "apropos" "\
 Show buffer-local variables that match PATTERN.
 Optional arg BUFFER (default: current buffer) is the buffer to check.
@@ -981,7 +981,7 @@ Optional arg BUFFER (default: current buffer) is the buffer 
to check.
 The output includes variables that are not yet set in BUFFER, but that
 will be buffer-local when set.
 
-(fn PATTERN &optional BUFFER)" t nil)
+(fn PATTERN &optional BUFFER)" t)
 (autoload 'apropos-function "apropos" "\
 Show functions that match PATTERN.
 
@@ -993,7 +993,7 @@ search for matches for any two (or more) of those words.
 This is the same as running `apropos-command' with a \\[universal-argument] 
prefix,
 or a non-nil `apropos-do-all' argument.
 
-(fn PATTERN)" t nil)
+(fn PATTERN)" t)
 (defalias 'command-apropos #'apropos-command)
 (autoload 'apropos-command "apropos" "\
 Show commands (interactively callable functions) that match PATTERN.
@@ -1011,11 +1011,11 @@ satisfy the predicate VAR-PREDICATE.
 When called from a Lisp program, a string PATTERN is used as a regexp,
 while a list of strings is used as a word list.
 
-(fn PATTERN &optional DO-ALL VAR-PREDICATE)" t nil)
+(fn PATTERN &optional DO-ALL VAR-PREDICATE)" t)
 (autoload 'apropos-documentation-property "apropos" "\
 Like (documentation-property SYMBOL PROPERTY RAW) but handle errors.
 
-(fn SYMBOL PROPERTY RAW)" nil nil)
+(fn SYMBOL PROPERTY RAW)")
 (autoload 'apropos "apropos" "\
 Show all meaningful Lisp symbols whose names match PATTERN.
 Symbols are shown if they are defined as functions, variables, or
@@ -1034,14 +1034,14 @@ Return list of symbols and documentation found.
 The *Apropos* window will be selected if `help-window-select' is
 non-nil.
 
-(fn PATTERN &optional DO-ALL)" t nil)
+(fn PATTERN &optional DO-ALL)" t)
 (autoload 'apropos-library "apropos" "\
 List the variables and functions defined by library FILE.
 FILE should be one of the libraries currently loaded and should
 thus be found in `load-history'.  If `apropos-do-all' is non-nil,
 the output includes key-bindings of commands.
 
-(fn FILE)" t nil)
+(fn FILE)" t)
 (autoload 'apropos-value "apropos" "\
 Show all symbols whose value's printed representation matches PATTERN.
 PATTERN can be a word, a list of words (separated by spaces),
@@ -1055,13 +1055,13 @@ names and values of properties.
 
 Returns list of symbols and values found.
 
-(fn PATTERN &optional DO-ALL)" t nil)
+(fn PATTERN &optional DO-ALL)" t)
 (autoload 'apropos-local-value "apropos" "\
 Show buffer-local variables whose values match PATTERN.
 This is like `apropos-value', but only for buffer-local variables.
 Optional arg BUFFER (default: current buffer) is the buffer to check.
 
-(fn PATTERN &optional BUFFER)" t nil)
+(fn PATTERN &optional BUFFER)" t)
 (autoload 'apropos-documentation "apropos" "\
 Show symbols whose documentation contains matches for PATTERN.
 PATTERN can be a word, a list of words (separated by spaces),
@@ -1076,7 +1076,7 @@ documentation strings.
 
 Returns list of symbols and documentation found.
 
-(fn PATTERN &optional DO-ALL)" t nil)
+(fn PATTERN &optional DO-ALL)" t)
 (register-definition-prefixes "apropos" '("apropos-"))
 
 
@@ -1095,7 +1095,7 @@ archive.
 
 \\{archive-mode-map}
 
-(fn &optional FORCE)" nil nil)
+(fn &optional FORCE)")
 (register-definition-prefixes "arc-mode" '("arc"))
 
 
@@ -1173,8 +1173,8 @@ take a numeric prefix argument):
 
 Entering array mode calls the function `array-mode-hook'.
 
-(fn)" t nil)
-(register-definition-prefixes "array" '("array-" "current-line" "limit-index" 
"move-to-column-untabify" "untabify-backward"))
+(fn)" t)
+(register-definition-prefixes "array" '("array-"))
 
 
 ;;; Generated autoloads from textmodes/artist.el
@@ -1348,25 +1348,25 @@ Variables
  This is a brief overview of the different variables.  For more info,
  see the documentation for the variables (type \\[describe-variable] 
<variable> RET).
 
- artist-rubber-banding         Interactively do rubber-banding or not
- artist-first-char             What to set at first/second point...
- artist-second-char            ...when not rubber-banding
- artist-interface-with-rect    If cut/copy/paste should interface with rect
- artist-arrows                 The arrows to use when drawing arrows
- artist-aspect-ratio           Character height-to-width for squares
- artist-trim-line-endings      Trimming of line endings
- artist-flood-fill-right-border        Right border when flood-filling
- artist-flood-fill-show-incrementally  Update display while filling
- artist-pointer-shape          Pointer shape to use while drawing
- artist-ellipse-left-char      Character to use for narrow ellipses
- artist-ellipse-right-char     Character to use for narrow ellipses
- artist-borderless-shapes       If shapes should have borders
- artist-picture-compatibility   Whether or not to be picture mode compatible
- artist-vaporize-fuzziness      Tolerance when recognizing lines
- artist-spray-interval          Seconds between repeated sprayings
- artist-spray-radius            Size of the spray-area
- artist-spray-chars             The spray-\"color\"
- artist-spray-new-chars         Initial spray-\"color\"
+ `artist-rubber-banding'              Interactively do rubber-banding or not
+ `artist-first-char'                  What to set at first/second point...
+ `artist-second-char'                 ...when not rubber-banding
+ `artist-interface-with-rect'         Should cut/copy/paste interface with rect
+ `artist-arrows'                      The arrows to use when drawing arrows
+ `artist-aspect-ratio'                Character height-to-width for squares
+ `artist-trim-line-endings'           Trimming of line endings
+ `artist-flood-fill-right-border'     Right border when flood-filling
+ `artist-flood-fill-show-incrementally'  Update display while filling
+ `artist-pointer-shape'               Pointer shape to use while drawing
+ `artist-ellipse-left-char'           Character to use for narrow ellipses
+ `artist-ellipse-right-char'          Character to use for narrow ellipses
+ `artist-borderless-shapes'           If shapes should have borders
+ `artist-picture-compatibility'       Picture mode compatibility on or off
+ `artist-vaporize-fuzziness'          Tolerance when recognizing lines
+ `artist-spray-interval'              Seconds between repeated sprayings
+ `artist-spray-radius'                Size of the spray-area
+ `artist-spray-chars'                 The spray-\"color\"
+ `artist-spray-new-char'              Initial spray-\"color\"
 
 Hooks
 
@@ -1391,7 +1391,7 @@ evaluate `artist-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "artist" '("artist-"))
 
 
@@ -1417,7 +1417,7 @@ Turning on Asm mode runs the hook `asm-mode-hook' at the 
end of initialization.
 Special commands:
 \\{asm-mode-map}
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "asm-mode" '("asm-"))
 
 
@@ -1427,6 +1427,10 @@ Special commands:
 How many seconds passwords are cached, or nil to disable expiring.
 Overrides `password-cache-expiry' through a let-binding.")
 (custom-autoload 'auth-source-cache-expiry "auth-source" t)
+(autoload 'auth-source-netrc-parse-all "auth-source" "\
+Parse FILE and return all entries.
+
+(fn FILE)")
 (autoload 'authinfo-mode "auth-source" "\
 Mode for editing .authinfo/.netrc files.
 
@@ -1436,7 +1440,7 @@ point is moved into the passwords (see 
`authinfo-hide-elements').
 
 \\{authinfo-mode-map}
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "auth-source" '("auth"))
 
 
@@ -1444,7 +1448,7 @@ point is moved into the passwords (see 
`authinfo-hide-elements').
 
 (push (purecopy '(auth-source-pass 5 0 0)) package--builtin-versions)
 (autoload 'auth-source-pass-enable "auth-source-pass" "\
-Enable auth-source-password-store." nil nil)
+Enable auth-source-password-store.")
 (autoload 'auth-source-pass-get "auth-source-pass" "\
 Return the value associated to KEY in the password-store entry ENTRY.
 
@@ -1458,12 +1462,21 @@ secret
 key1: value1
 key2: value2
 
-(fn KEY ENTRY)" nil nil)
+(fn KEY ENTRY)")
 (register-definition-prefixes "auth-source-pass" '("auth-source-pass-"))
 
 
 ;;; Generated autoloads from cedet/ede/auto.el
 
+(autoload 'ede-add-project-autoload "ede/auto" "\
+Add PROJAUTO, an EDE autoload definition to `ede-project-class-files'.
+Optional argument FLAG indicates how this autoload should be
+added.  Possible values are:
+  `generic' - A generic project type.  Keep this at the very end.
+  `unique' - A unique project type for a specific project.  Keep at the very
+             front of the list so more generic projects don't get priority.
+
+(fn PROJAUTO &optional FLAG)")
 (register-definition-prefixes "ede/auto" '("ede-"))
 
 
@@ -1472,7 +1485,7 @@ key2: value2
 (autoload 'autoconf-mode "autoconf" "\
 Major mode for editing Autoconf configure.ac files.
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "autoconf" '("autoconf-"))
 
 
@@ -1483,15 +1496,16 @@ Major mode for editing Autoconf configure.ac files.
 
 ;;; Generated autoloads from autoinsert.el
 
+(put 'auto-insert 'safe-local-variable #'null)
 (autoload 'auto-insert "autoinsert" "\
 Insert default contents into new files if variable `auto-insert' is non-nil.
-Matches the visited file name against the elements of `auto-insert-alist'." t 
nil)
+Matches the visited file name against the elements of `auto-insert-alist'." t)
 (autoload 'define-auto-insert "autoinsert" "\
 Associate CONDITION with (additional) ACTION in `auto-insert-alist'.
 Optional AFTER means to insert action after all existing actions for CONDITION,
 or if CONDITION had no actions, after all other CONDITIONs.
 
-(fn CONDITION ACTION &optional AFTER)" nil nil)
+(fn CONDITION ACTION &optional AFTER)")
 (function-put 'define-auto-insert 'lisp-indent-function 'defun)
 (defvar auto-insert-mode nil "\
 Non-nil if Auto-Insert mode is enabled.
@@ -1521,64 +1535,10 @@ evaluate `(default-value \\='auto-insert-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "autoinsert" '("auto-insert"))
 
 
-;;; Generated autoloads from emacs-lisp/autoload.el
-
-(put 'autoload-ensure-writable 'risky-local-variable t)
-(autoload 'update-file-autoloads "autoload" "\
-Update the autoloads for FILE.
-If prefix arg SAVE-AFTER is non-nil, save the buffer too.
-
-If FILE binds `generated-autoload-file' as a file-local variable,
-autoloads are written into that file.  Otherwise, the autoloads
-file is determined by OUTFILE.  If called interactively, prompt
-for OUTFILE; if called from Lisp with OUTFILE nil, use the
-existing value of `generated-autoload-file'.
-
-Return FILE if there was no autoload cookie in it, else nil.
-
-(fn FILE &optional SAVE-AFTER OUTFILE)" t nil)
-(autoload 'update-directory-autoloads "autoload" "\
-Update autoload definitions for Lisp files in the directories DIRS.
-In an interactive call, you must give one argument, the name of a
-single directory.  In a call from Lisp, you can supply multiple
-directories as separate arguments, but this usage is discouraged.
-
-The function does NOT recursively descend into subdirectories of the
-directory or directories specified.
-
-In an interactive call, prompt for a default output file for the
-autoload definitions.  When called from Lisp, use the existing
-value of `generated-autoload-file'.  If any Lisp file binds
-`generated-autoload-file' as a file-local variable, write its
-autoloads into the specified file instead.
-
-(fn &rest DIRS)" t nil)
-(make-obsolete 'update-directory-autoloads 'make-directory-autoloads '"28.1")
-(autoload 'make-directory-autoloads "autoload" "\
-Update autoload definitions for Lisp files in the directories DIRS.
-DIR can be either a single directory or a list of
-directories.  (The latter usage is discouraged.)
-
-The autoloads will be written to OUTPUT-FILE.  If any Lisp file
-binds `generated-autoload-file' as a file-local variable, write
-its autoloads into the specified file instead.
-
-The function does NOT recursively descend into subdirectories of the
-directory or directories specified.
-
-(fn DIR OUTPUT-FILE)" t nil)
-(autoload 'batch-update-autoloads "autoload" "\
-Update loaddefs.el autoloads in batch mode.
-Calls `update-directory-autoloads' on the command line arguments.
-Definitions are written to `generated-autoload-file' (which
-should be non-nil)." nil nil)
-(register-definition-prefixes "autoload" '("autoload-" 
"batch-update-autoloads--summary" "generate-" "make-autoload" 
"no-update-autoloads"))
-
-
 ;;; Generated autoloads from autorevert.el
 
 (autoload 'auto-revert-mode "autorevert" "\
@@ -1613,12 +1573,12 @@ evaluate `auto-revert-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'turn-on-auto-revert-mode "autorevert" "\
 Turn on Auto-Revert Mode.
 
 This function is designed to be added to hooks, for example:
-  (add-hook \\='c-mode-hook #\\='turn-on-auto-revert-mode)" nil nil)
+  (add-hook \\='c-mode-hook #\\='turn-on-auto-revert-mode)")
 (autoload 'auto-revert-tail-mode "autorevert" "\
 Toggle reverting tail of buffer when the file grows.
 
@@ -1652,12 +1612,12 @@ evaluate `auto-revert-tail-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'turn-on-auto-revert-tail-mode "autorevert" "\
 Turn on Auto-Revert Tail Mode.
 
 This function is designed to be added to hooks, for example:
-  (add-hook \\='my-logfile-mode-hook #\\='turn-on-auto-revert-tail-mode)" nil 
nil)
+  (add-hook \\='my-logfile-mode-hook #\\='turn-on-auto-revert-tail-mode)")
 (defvar global-auto-revert-mode nil "\
 Non-nil if Global Auto-Revert mode is enabled.
 See the `global-auto-revert-mode' command
@@ -1701,7 +1661,7 @@ evaluate `(default-value \\='global-auto-revert-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "autorevert" '("auto-revert-" 
"global-auto-revert-"))
 
 
@@ -1741,7 +1701,7 @@ Effects of the different modes:
 and `mouse-avoidance-nudge-dist' and `mouse-avoidance-nudge-var' for
 definition of \"random distance\".)
 
-(fn &optional MODE)" t nil)
+(fn &optional MODE)" t)
 (register-definition-prefixes "avoid" '("mouse-avoidance-"))
 
 
@@ -1750,7 +1710,7 @@ definition of \"random distance\".)
 (push (purecopy '(backtrace 1 0)) package--builtin-versions)
 (autoload 'backtrace "backtrace" "\
 Print a trace of Lisp function calls currently active.
-Output stream used is value of `standard-output'." nil nil)
+Output stream used is value of `standard-output'.")
 (register-definition-prefixes "backtrace" '("backtrace-"))
 
 
@@ -1770,7 +1730,7 @@ Run script using `bat-run' and `bat-run-args'.
 
 \\{bat-mode-map}
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "bat-mode" '("bat-"))
 
 
@@ -1780,7 +1740,7 @@ Run script using `bat-run' and `bat-run-args'.
 (autoload 'battery "battery" "\
 Display battery status information in the echo area.
 The text being displayed in the echo area is controlled by the variables
-`battery-echo-area-format' and `battery-status-function'." t nil)
+`battery-echo-area-format' and `battery-status-function'." t)
 (defvar display-battery-mode nil "\
 Non-nil if Display-Battery mode is enabled.
 See the `display-battery-mode' command
@@ -1815,8 +1775,8 @@ evaluate `(default-value \\='display-battery-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
-(register-definition-prefixes "battery" '("battery-" "my-"))
+(fn &optional ARG)" t)
+(register-definition-prefixes "battery" '("battery-"))
 
 
 ;;; Generated autoloads from emacs-lisp/benchmark.el
@@ -1833,7 +1793,7 @@ specifies a minimum number of seconds that the benchmark 
execution
 should take.  In that case the return value is prepended with the
 number of repetitions actually used.
 
-(fn FUNC &optional REPETITIONS)" nil nil)
+(fn FUNC &optional REPETITIONS)")
 (autoload 'benchmark-run "benchmark" "\
 Time execution of FORMS.
 If REPETITIONS is supplied as a number, run FORMS that many times,
@@ -1844,7 +1804,7 @@ garbage collections that ran, and the time taken by 
garbage collection.
 See also `benchmark-run-compiled'.
 
 (fn &optional REPETITIONS &rest FORMS)" nil t)
-(function-put 'benchmark-run 'lisp-indent-function '1)
+(function-put 'benchmark-run 'lisp-indent-function 1)
 (autoload 'benchmark-run-compiled "benchmark" "\
 Time execution of compiled version of FORMS.
 This is like `benchmark-run', but what is timed is a funcall of the
@@ -1852,7 +1812,7 @@ byte code obtained by wrapping FORMS in a `lambda' and 
compiling the
 result.  The overhead of the `lambda's is accounted for.
 
 (fn &optional REPETITIONS &rest FORMS)" nil t)
-(function-put 'benchmark-run-compiled 'lisp-indent-function '1)
+(function-put 'benchmark-run-compiled 'lisp-indent-function 1)
 (autoload 'benchmark "benchmark" "\
 Print the time taken for REPETITIONS executions of FORM.
 Interactively, REPETITIONS is taken from the prefix arg, and
@@ -1862,19 +1822,19 @@ For non-interactive use see also `benchmark-run' and
 FORM can also be a function in which case we measure the time it takes
 to call it without any argument.
 
-(fn REPETITIONS FORM)" t nil)
+(fn REPETITIONS FORM)" t)
 (autoload 'benchmark-progn "benchmark" "\
 Evaluate BODY and message the time taken.
 The return value is the value of the final form in BODY.
 
 (fn &rest BODY)" nil t)
-(function-put 'benchmark-progn 'lisp-indent-function '0)
+(function-put 'benchmark-progn 'lisp-indent-function 0)
 (register-definition-prefixes "benchmark" '("benchmark-"))
 
 
 ;;; Generated autoloads from textmodes/bib-mode.el
 
-(register-definition-prefixes "bib-mode" '("addbib" "bib-" "mark-bib" 
"return-key-bib" "unread-bib"))
+(register-definition-prefixes "bib-mode" '("bib-"))
 
 
 ;;; Generated autoloads from textmodes/bibtex.el
@@ -1893,7 +1853,7 @@ When called interactively, FORCE is t, CURRENT is t if 
current buffer
 visits a file using `bibtex-mode', and SELECT is t if current buffer
 does not use `bibtex-mode'.
 
-(fn &optional CURRENT FORCE SELECT)" t nil)
+(fn &optional CURRENT FORCE SELECT)" t)
 (autoload 'bibtex-mode "bibtex" "\
 Major mode for editing BibTeX files.
 
@@ -1947,7 +1907,7 @@ if that value is non-nil.
 
 \\{bibtex-mode-map}
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'bibtex-search-entry "bibtex" "\
 Move point to the beginning of BibTeX entry named KEY.
 Return position of entry if KEY is found or nil if not found.
@@ -1961,7 +1921,7 @@ Also, GLOBAL is t if the current mode is not `bibtex-mode'
 or `bibtex-search-entry-globally' is non-nil.
 A prefix arg negates the value of `bibtex-search-entry-globally'.
 
-(fn KEY &optional GLOBAL START DISPLAY)" t nil)
+(fn KEY &optional GLOBAL START DISPLAY)" t)
 (register-definition-prefixes "bibtex" '("bibtex-"))
 
 
@@ -1970,7 +1930,7 @@ A prefix arg negates the value of 
`bibtex-search-entry-globally'.
 (autoload 'bibtex-style-mode "bibtex-style" "\
 Major mode for editing BibTeX style files.
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "bibtex-style" '("bibtex-style-"))
 
 
@@ -1987,15 +1947,15 @@ Regular expression matching the start of a BinHex 
encoded region.")
 Binhex decode region between START and END without using an external program.
 If HEADER-ONLY is non-nil only decode header and return filename.
 
-(fn START END &optional HEADER-ONLY)" t nil)
+(fn START END &optional HEADER-ONLY)" t)
 (autoload 'binhex-decode-region-external "binhex" "\
 Binhex decode region between START and END using external decoder.
 
-(fn START END)" t nil)
+(fn START END)" t)
 (autoload 'binhex-decode-region "binhex" "\
 Binhex decode region between START and END.
 
-(fn START END)" t nil)
+(fn START END)" t)
 (register-definition-prefixes "binhex" '("binhex-"))
 
 
@@ -2113,16 +2073,16 @@ H * * * O - - - -         - - - - - - - -          - - 
- - - - - -
 Be sure to compare the second example of a hit with the first example of
 a reflection.
 
-(fn NUM)" t nil)
+(fn NUM)" t)
 (register-definition-prefixes "blackbox" '("bb-" "blackbox-"))
 
 
 ;;; Generated autoloads from bookmark.el
 
- (define-key ctl-x-r-map "b" 'bookmark-jump)
- (define-key ctl-x-r-map "m" 'bookmark-set)
- (define-key ctl-x-r-map "M" 'bookmark-set-no-overwrite)
- (define-key ctl-x-r-map "l" 'bookmark-bmenu-list)
+ (keymap-set ctl-x-r-map "b" #'bookmark-jump)
+ (keymap-set ctl-x-r-map "m" #'bookmark-set)
+ (keymap-set ctl-x-r-map "M" #'bookmark-set-no-overwrite)
+ (keymap-set ctl-x-r-map "l" #'bookmark-bmenu-list)
 (defvar-keymap bookmark-map :doc "\
 Keymap containing bindings to bookmark functions.
 It is not bound to any key by default: to bind it
@@ -2155,7 +2115,7 @@ Use \\[bookmark-delete] to remove bookmarks (you give it 
a name and
 it removes only the first instance of a bookmark with that name from
 the list of bookmarks.)
 
-(fn &optional NAME NO-OVERWRITE)" t nil)
+(fn &optional NAME NO-OVERWRITE)" t)
 (autoload 'bookmark-set-no-overwrite "bookmark" "\
 Set a bookmark named NAME at the current location.
 If NAME is nil, then prompt the user.
@@ -2184,7 +2144,7 @@ Use \\[bookmark-delete] to remove bookmarks (you give it 
a name and
 it removes only the first instance of a bookmark with that name from
 the list of bookmarks.)
 
-(fn &optional NAME PUSH-BOOKMARK)" t nil)
+(fn &optional NAME PUSH-BOOKMARK)" t)
 (autoload 'bookmark-jump "bookmark" "\
 Jump to bookmark BOOKMARK (a point in some file).
 You may have a problem using this function if the value of variable
@@ -2204,15 +2164,15 @@ If DISPLAY-FUNC is non-nil, it is a function to invoke 
to display the
 bookmark.  It defaults to `pop-to-buffer-same-window'.  A typical value for
 DISPLAY-FUNC would be `switch-to-buffer-other-window'.
 
-(fn BOOKMARK &optional DISPLAY-FUNC)" t nil)
+(fn BOOKMARK &optional DISPLAY-FUNC)" t)
 (autoload 'bookmark-jump-other-window "bookmark" "\
 Jump to BOOKMARK in another window.  See `bookmark-jump' for more.
 
-(fn BOOKMARK)" t nil)
+(fn BOOKMARK)" t)
 (autoload 'bookmark-jump-other-frame "bookmark" "\
 Jump to BOOKMARK in another frame.  See `bookmark-jump' for more.
 
-(fn BOOKMARK)" t nil)
+(fn BOOKMARK)" t)
 (autoload 'bookmark-relocate "bookmark" "\
 Relocate BOOKMARK-NAME to another file, reading file name with minibuffer.
 
@@ -2220,14 +2180,14 @@ This makes an already existing bookmark point to that 
file, instead of
 the one it used to point at.  Useful when a file has been renamed
 after a bookmark was set in it.
 
-(fn BOOKMARK-NAME)" t nil)
+(fn BOOKMARK-NAME)" t)
 (autoload 'bookmark-insert-location "bookmark" "\
 Insert the name of the file associated with BOOKMARK-NAME.
 
 Optional second arg NO-HISTORY means don't record this in the
 minibuffer history list `bookmark-history'.
 
-(fn BOOKMARK-NAME &optional NO-HISTORY)" t nil)
+(fn BOOKMARK-NAME &optional NO-HISTORY)" t)
 (defalias 'bookmark-locate 'bookmark-insert-location)
 (autoload 'bookmark-rename "bookmark" "\
 Change the name of OLD-NAME bookmark to NEW-NAME name.
@@ -2242,7 +2202,7 @@ While you are entering the new name, consecutive 
\\<bookmark-minibuffer-read-nam
 consecutive words from the text of the buffer into the new bookmark
 name.
 
-(fn OLD-NAME &optional NEW-NAME)" t nil)
+(fn OLD-NAME &optional NEW-NAME)" t)
 (autoload 'bookmark-insert "bookmark" "\
 Insert the text of the file pointed to by bookmark BOOKMARK-NAME.
 BOOKMARK-NAME is a bookmark name (a string), not a bookmark record.
@@ -2252,7 +2212,7 @@ You may have a problem using this function if the value 
of variable
 bookmarks.  See help on function `bookmark-load' for more about
 this.
 
-(fn BOOKMARK-NAME)" t nil)
+(fn BOOKMARK-NAME)" t)
 (autoload 'bookmark-delete "bookmark" "\
 Delete BOOKMARK-NAME from the bookmark list.
 
@@ -2263,15 +2223,15 @@ one most recently used in this file, if any).
 Optional second arg BATCH means don't update the bookmark list buffer,
 probably because we were called from there.
 
-(fn BOOKMARK-NAME &optional BATCH)" t nil)
+(fn BOOKMARK-NAME &optional BATCH)" t)
 (autoload 'bookmark-delete-all "bookmark" "\
 Permanently delete all bookmarks.
 If optional argument NO-CONFIRM is non-nil, don't ask for
 confirmation.
 
-(fn &optional NO-CONFIRM)" t nil)
+(fn &optional NO-CONFIRM)" t)
 (autoload 'bookmark-write "bookmark" "\
-Write bookmarks to a file (reading the file name with the minibuffer)." t nil)
+Write bookmarks to a file (reading the file name with the minibuffer)." t)
 (function-put 'bookmark-write 'interactive-only 'bookmark-save)
 (autoload 'bookmark-save "bookmark" "\
 Save currently defined bookmarks in FILE.
@@ -2286,7 +2246,7 @@ When you want to load in the bookmarks from a file, use
 for a file, defaulting to the file defined by variable
 `bookmark-default-file'.
 
-(fn &optional PARG FILE MAKE-DEFAULT)" t nil)
+(fn &optional PARG FILE MAKE-DEFAULT)" t)
 (autoload 'bookmark-load "bookmark" "\
 Load bookmarks from FILE (which must be in bookmark format).
 Appends loaded bookmarks to the front of the list of bookmarks.
@@ -2306,19 +2266,19 @@ If you load a file containing bookmarks with the same 
names as
 bookmarks already present in your Emacs, the new bookmarks will get
 unique numeric suffixes \"<2>\", \"<3>\", etc.
 
-(fn FILE &optional OVERWRITE NO-MSG DEFAULT)" t nil)
+(fn FILE &optional OVERWRITE NO-MSG DEFAULT)" t)
 (autoload 'bookmark-bmenu-get-buffer "bookmark" "\
 Return the Bookmark List, building it if it doesn't exists.
-Don't affect the buffer ring order." nil nil)
+Don't affect the buffer ring order.")
 (autoload 'bookmark-bmenu-list "bookmark" "\
 Display a list of existing bookmarks.
 The list is displayed in a buffer named `*Bookmark List*'.
 The leftmost column displays a D if the bookmark is flagged for
-deletion, or > if it is flagged for displaying." t nil)
+deletion, or > if it is flagged for displaying." t)
 (defalias 'list-bookmarks 'bookmark-bmenu-list)
 (defalias 'edit-bookmarks 'bookmark-bmenu-list)
 (autoload 'bookmark-bmenu-search "bookmark" "\
-Incremental search of bookmarks, hiding the non-matches as we go." 
'(bookmark-bmenu-mode) nil)
+Incremental search of bookmarks, hiding the non-matches as we go." 
'(bookmark-bmenu-mode))
 (defvar menu-bar-bookmark-map (let ((map (make-sparse-keymap "Bookmark 
functions"))) (bindings--define-key map [load] '(menu-item "Load a Bookmark 
File..." bookmark-load :help "Load bookmarks from a bookmark file)")) 
(bindings--define-key map [write] '(menu-item "Save Bookmarks As..." 
bookmark-write :help "Write bookmarks to a file (reading the file name with the 
minibuffer)")) (bindings--define-key map [save] '(menu-item "Save Bookmarks" 
bookmark-save :help "Save currently defined bookm [...]
 (defalias 'menu-bar-bookmark-map menu-bar-bookmark-map)
 (register-definition-prefixes "bookmark" '("bookmark-" 
"with-buffer-modified-unmodified"))
@@ -2359,7 +2319,7 @@ Currently, it also consults `browse-url-browser-function' 
first
 if it is set to an alist, although this usage is deprecated since
 Emacs 28.1 and will be removed in a future release.
 
-(fn URL &optional KIND)" nil nil)
+(fn URL &optional KIND)")
 (autoload 'browse-url-of-file "browse-url" "\
 Use a web browser to display FILE.
 Display the current buffer's file if FILE is nil or if called
@@ -2367,7 +2327,7 @@ interactively.  Turn the filename into a URL with function
 `browse-url-file-url'.  Pass the URL to a browser using the
 `browse-url' function then run `browse-url-of-file-hook'.
 
-(fn &optional FILE)" t nil)
+(fn &optional FILE)" t)
 (autoload 'browse-url-of-buffer "browse-url" "\
 Use a web browser to display BUFFER.
 See `browse-url' for details.
@@ -2376,14 +2336,14 @@ Display the current buffer if BUFFER is nil.  Display 
only the
 currently visible part of BUFFER (from a temporary file) if buffer is
 narrowed.
 
-(fn &optional BUFFER)" t nil)
+(fn &optional BUFFER)" t)
 (autoload 'browse-url-of-dired-file "browse-url" "\
-In Dired, ask a WWW browser to display the file named on this line." t nil)
+In Dired, ask a WWW browser to display the file named on this line." t)
 (autoload 'browse-url-of-region "browse-url" "\
 Use a web browser to display the current region.
 See `browse-url' for details.
 
-(fn MIN MAX)" t nil)
+(fn MIN MAX)" t)
 (autoload 'browse-url "browse-url" "\
 Open URL using a configurable method.
 This will typically (by default) open URL with an external web
@@ -2405,14 +2365,14 @@ significance of ARGS (most of the functions ignore it).
 If ARGS are omitted, the default is to pass
 `browse-url-new-window-flag' as ARGS.
 
-(fn URL &rest ARGS)" t nil)
+(fn URL &rest ARGS)" t)
 (autoload 'browse-url-at-point "browse-url" "\
 Open URL at point using a configurable method.
 See `browse-url' for details.
 Optional prefix argument ARG non-nil inverts the value of the option
 `browse-url-new-window-flag'.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'browse-url-with-browser-kind "browse-url" "\
 Browse URL with a browser of the given browser KIND.
 KIND is either `internal' or `external'.
@@ -2420,7 +2380,7 @@ KIND is either `internal' or `external'.
 When called interactively, the default browser kind is the
 opposite of the browser kind of `browse-url-browser-function'.
 
-(fn KIND URL &optional ARG)" t nil)
+(fn KIND URL &optional ARG)" t)
 (autoload 'browse-url-at-mouse "browse-url" "\
 Use a web browser to load a URL clicked with the mouse.
 See `browse-url' for details.
@@ -2428,13 +2388,13 @@ See `browse-url' for details.
 The URL is the one around or before the position of the mouse
 click but point is not changed.
 
-(fn EVENT)" t nil)
+(fn EVENT)" t)
 (autoload 'browse-url-xdg-open "browse-url" "\
 Pass the specified URL to the \"xdg-open\" command.
 xdg-open is a desktop utility that calls your preferred web browser.
 The optional argument IGNORED is not used.
 
-(fn URL &optional IGNORED)" t nil)
+(fn URL &optional IGNORED)" t)
 (autoload 'browse-url-mozilla "browse-url" "\
 Ask the Mozilla WWW browser to load URL.
 Default to the URL around or before point.  The strings in variable
@@ -2452,7 +2412,8 @@ new tab in an existing window instead.
 When called non-interactively, optional second argument NEW-WINDOW is
 used instead of `browse-url-new-window-flag'.
 
-(fn URL &optional NEW-WINDOW)" t nil)
+(fn URL &optional NEW-WINDOW)" t)
+(make-obsolete 'browse-url-mozilla 'nil "29.1")
 (autoload 'browse-url-firefox "browse-url" "\
 Ask the Firefox WWW browser to load URL.
 Defaults to the URL around or before point.  Passes the strings
@@ -2469,7 +2430,7 @@ is loaded in a new tab in an existing window instead.
 Non-interactively, this uses the optional second argument NEW-WINDOW
 instead of `browse-url-new-window-flag'.
 
-(fn URL &optional NEW-WINDOW)" t nil)
+(fn URL &optional NEW-WINDOW)" t)
 (autoload 'browse-url-chromium "browse-url" "\
 Ask the Chromium WWW browser to load URL.
 Default to the URL around or before point.  The strings in
@@ -2477,24 +2438,24 @@ variable `browse-url-chromium-arguments' are also 
passed to
 Chromium.
 The optional argument NEW-WINDOW is not used.
 
-(fn URL &optional NEW-WINDOW)" t nil)
+(fn URL &optional NEW-WINDOW)" t)
 (autoload 'browse-url-webpositive "browse-url" "\
 Ask the WebPositive WWW browser to load URL.
 Default to the URL around or before point.
 The optional argument NEW-WINDOW is not used.
 
-(fn URL &optional NEW-WINDOW)" t nil)
+(fn URL &optional NEW-WINDOW)" t)
 (autoload 'browse-url-default-haiku-browser "browse-url" "\
 Browse URL with the system default browser.
 Default to the URL around or before point.
 
-(fn URL &optional NEW-WINDOW)" t nil)
+(fn URL &optional NEW-WINDOW)" t)
 (autoload 'browse-url-emacs "browse-url" "\
 Ask Emacs to load URL into a buffer and show it in another window.
 Optional argument SAME-WINDOW non-nil means show the URL in the
 currently selected window instead.
 
-(fn URL &optional SAME-WINDOW)" t nil)
+(fn URL &optional SAME-WINDOW)" t)
 (autoload 'browse-url-gnome-moz "browse-url" "\
 Ask Mozilla to load URL via the GNOME program `gnome-moz-remote'.
 Default to the URL around or before point.  The strings in variable
@@ -2508,8 +2469,8 @@ effect of `browse-url-new-window-flag'.
 When called non-interactively, optional second argument NEW-WINDOW is
 used instead of `browse-url-new-window-flag'.
 
-(fn URL &optional NEW-WINDOW)" t nil)
-(make-obsolete 'browse-url-gnome-moz 'nil '"25.1")
+(fn URL &optional NEW-WINDOW)" t)
+(make-obsolete 'browse-url-gnome-moz 'nil "25.1")
 (autoload 'browse-url-conkeror "browse-url" "\
 Ask the Conkeror WWW browser to load URL.
 Default to the URL around or before point.  Also pass the strings
@@ -2528,8 +2489,8 @@ new window, load it in a new buffer in an existing window 
instead.
 When called non-interactively, use optional second argument
 NEW-WINDOW instead of `browse-url-new-window-flag'.
 
-(fn URL &optional NEW-WINDOW)" t nil)
-(make-obsolete 'browse-url-conkeror 'nil '"28.1")
+(fn URL &optional NEW-WINDOW)" t)
+(make-obsolete 'browse-url-conkeror 'nil "28.1")
 (autoload 'browse-url-w3 "browse-url" "\
 Ask the w3 WWW browser to load URL.
 Default to the URL around or before point.
@@ -2541,14 +2502,15 @@ prefix argument reverses the effect of 
`browse-url-new-window-flag'.
 When called non-interactively, optional second argument NEW-WINDOW is
 used instead of `browse-url-new-window-flag'.
 
-(fn URL &optional NEW-WINDOW)" t nil)
+(fn URL &optional NEW-WINDOW)" t)
+(make-obsolete 'browse-url-w3 'nil "29.1")
 (autoload 'browse-url-w3-gnudoit "browse-url" "\
 Ask another Emacs running gnuserv to load the URL using the W3 browser.
 The `browse-url-gnudoit-program' program is used with options given by
 `browse-url-gnudoit-args'.  Default to the URL around or before point.
 
-(fn URL &optional NEW-WINDOW)" t nil)
-(make-obsolete 'browse-url-w3-gnudoit 'nil '"25.1")
+(fn URL &optional NEW-WINDOW)" t)
+(make-obsolete 'browse-url-w3-gnudoit 'nil "25.1")
 (autoload 'browse-url-text-xterm "browse-url" "\
 Ask a text browser to load URL.
 URL defaults to the URL around or before point.
@@ -2557,7 +2519,7 @@ in an Xterm window using the Xterm program named by 
`browse-url-xterm-program'
 with possible additional arguments `browse-url-xterm-args'.
 The optional argument NEW-WINDOW is not used.
 
-(fn URL &optional NEW-WINDOW)" t nil)
+(fn URL &optional NEW-WINDOW)" t)
 (autoload 'browse-url-text-emacs "browse-url" "\
 Ask a text browser to load URL.
 URL defaults to the URL around or before point.
@@ -2572,7 +2534,7 @@ reverses the effect of `browse-url-new-window-flag'.
 When called non-interactively, optional second argument NEW-WINDOW is
 used instead of `browse-url-new-window-flag'.
 
-(fn URL &optional NEW-BUFFER)" t nil)
+(fn URL &optional NEW-BUFFER)" t)
 (autoload 'browse-url-mail "browse-url" "\
 Open a new mail message buffer within Emacs for the RFC 2368 URL.
 Default to using the mailto: URL around or before point as the
@@ -2588,7 +2550,7 @@ non-nil interactive prefix argument reverses the effect of
 When called non-interactively, optional second argument NEW-WINDOW is
 used instead of `browse-url-new-window-flag'.
 
-(fn URL &optional NEW-WINDOW)" t nil)
+(fn URL &optional NEW-WINDOW)" t)
 (autoload 'browse-url-generic "browse-url" "\
 Ask the WWW browser defined by `browse-url-generic-program' to load URL.
 Default to the URL around or before point.  A fresh copy of the
@@ -2596,13 +2558,13 @@ browser is started up in a new process with possible 
additional arguments
 `browse-url-generic-args'.  This is appropriate for browsers which
 don't offer a form of remote control.
 
-(fn URL &optional NEW-WINDOW)" t nil)
+(fn URL &optional NEW-WINDOW)" t)
 (autoload 'browse-url-kde "browse-url" "\
 Ask the KDE WWW browser to load URL.
 Default to the URL around or before point.
 The optional argument NEW-WINDOW is not used.
 
-(fn URL &optional NEW-WINDOW)" t nil)
+(fn URL &optional NEW-WINDOW)" t)
 (autoload 'browse-url-elinks "browse-url" "\
 Ask the Elinks WWW browser to load URL.
 Default to the URL around the point.
@@ -2613,19 +2575,19 @@ none yet running, a newly started instance.
 The Elinks command will be prepended by the program+arguments
 from `browse-url-elinks-wrapper'.
 
-(fn URL &optional NEW-WINDOW)" t nil)
+(fn URL &optional NEW-WINDOW)" t)
 (autoload 'browse-url-button-open "browse-url" "\
 Follow the link under point using `browse-url'.
 If EXTERNAL (the prefix if used interactively), open with the
 external browser instead of the default one.
 
-(fn &optional EXTERNAL MOUSE-EVENT)" t nil)
+(fn &optional EXTERNAL MOUSE-EVENT)" t)
 (autoload 'browse-url-button-open-url "browse-url" "\
 Open URL using `browse-url'.
 If `current-prefix-arg' is non-nil, use
 `browse-url-secondary-browser-function' instead.
 
-(fn URL)" nil nil)
+(fn URL)")
 (register-definition-prefixes "browse-url" '("browse-url-"))
 
 
@@ -2634,13 +2596,13 @@ If `current-prefix-arg' is non-nil, use
 (autoload 'bs-cycle-next "bs" "\
 Select next buffer defined by buffer cycling.
 The buffers taking part in buffer cycling are defined
-by buffer configuration `bs-cycle-configuration-name'." t nil)
+by buffer configuration `bs-cycle-configuration-name'." t)
 (autoload 'bs-cycle-previous "bs" "\
 Select previous buffer defined by buffer cycling.
 The buffers taking part in buffer cycling are defined
-by buffer configuration `bs-cycle-configuration-name'." t nil)
+by buffer configuration `bs-cycle-configuration-name'." t)
 (autoload 'bs-customize "bs" "\
-Customization of group bs for Buffer Selection Menu." t nil)
+Customization of group bs for Buffer Selection Menu." t)
 (autoload 'bs-show "bs" "\
 Make a menu of buffers so you can manipulate buffers or the buffer list.
 \\<bs-mode-map>
@@ -2650,12 +2612,12 @@ User can move with [up] or [down], select a buffer
 by \\[bs-select] or [SPC]
 
 Type \\[bs-kill] to leave Buffer Selection Menu without a selection.
-Type \\[bs-help] after invocation to get help on commands available.
+Type \\[describe-mode] after invocation to get help on commands available.
 With prefix argument ARG show a different buffer list.  Function
 `bs--configuration-name-for-prefix-arg' determine accordingly
 name of buffer configuration.
 
-(fn ARG)" t nil)
+(fn ARG)" t)
 (register-definition-prefixes "bs" '("bs-"))
 
 
@@ -2673,7 +2635,7 @@ columns on its right towards the left.
 \\[bubbles-set-game-easy] sets the difficulty to easy.
 \\[bubbles-set-game-medium] sets the difficulty to medium.
 \\[bubbles-set-game-difficult] sets the difficulty to difficult.
-\\[bubbles-set-game-hard] sets the difficulty to hard." t nil)
+\\[bubbles-set-game-hard] sets the difficulty to hard." t)
 (register-definition-prefixes "bubbles" '("bubbles-"))
 
 
@@ -2698,7 +2660,7 @@ evaluate `bug-reference-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'bug-reference-prog-mode "bug-reference" "\
 Like `bug-reference-mode', but only buttonize in comments and strings.
 
@@ -2717,7 +2679,7 @@ evaluate `bug-reference-prog-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "bug-reference" '("bug-reference-"))
 
 
@@ -2729,14 +2691,13 @@ it is disabled.
 ;;; Generated autoloads from emacs-lisp/bytecomp.el
 
 (put 'byte-compile-dynamic 'safe-local-variable 'booleanp)
-(put 'byte-compile-disable-print-circle 'safe-local-variable 'booleanp)
 (put 'byte-compile-dynamic-docstrings 'safe-local-variable 'booleanp)
 (put 'byte-compile-error-on-warn 'safe-local-variable 'booleanp)
 (put 'byte-compile-warnings 'safe-local-variable (lambda (v) (or (symbolp v) 
(null (delq nil (mapcar (lambda (x) (not (symbolp x))) v))))))
 (autoload 'byte-compile-warning-enabled-p "bytecomp" "\
 Return non-nil if WARNING is enabled, according to `byte-compile-warnings'.
 
-(fn WARNING &optional SYMBOL)" nil nil)
+(fn WARNING &optional SYMBOL)")
 (autoload 'byte-compile-disable-warning "bytecomp" "\
 Change `byte-compile-warnings' to disable WARNING.
 If `byte-compile-warnings' is t, set it to `(not WARNING)'.
@@ -2744,7 +2705,7 @@ Otherwise, if the first element is `not', add WARNING, 
else remove it.
 Normally you should let-bind `byte-compile-warnings' before calling this,
 else the global value will be modified.
 
-(fn WARNING)" nil nil)
+(fn WARNING)")
 (autoload 'byte-compile-enable-warning "bytecomp" "\
 Change `byte-compile-warnings' to enable WARNING.
 If `byte-compile-warnings' is t, do nothing.  Otherwise, if the
@@ -2752,12 +2713,17 @@ first element is `not', remove WARNING, else add it.
 Normally you should let-bind `byte-compile-warnings' before calling this,
 else the global value will be modified.
 
-(fn WARNING)" nil nil)
+(fn WARNING)")
+(autoload 'byte-compile-warn-obsolete "bytecomp" "\
+Warn that SYMBOL (a variable, function or generalized variable) is obsolete.
+TYPE is a string that say which one of these three types it is.
+
+(fn SYMBOL TYPE)")
 (autoload 'byte-force-recompile "bytecomp" "\
 Recompile every `.el' file in DIRECTORY that already has a `.elc' file.
 Files in subdirectories of DIRECTORY are processed also.
 
-(fn DIRECTORY)" t nil)
+(fn DIRECTORY)" t)
 (autoload 'byte-recompile-directory "bytecomp" "\
 Recompile every `.el' file in DIRECTORY that needs recompilation.
 This happens when a `.elc' file exists but is older than the `.el' file.
@@ -2777,29 +2743,32 @@ This command will normally not follow symlinks when 
compiling
 files.  If FOLLOW-SYMLINKS is non-nil, symlinked `.el' files will
 also be compiled.
 
-(fn DIRECTORY &optional ARG FORCE FOLLOW-SYMLINKS)" t nil)
+(fn DIRECTORY &optional ARG FORCE FOLLOW-SYMLINKS)" t)
 (put 'no-byte-compile 'safe-local-variable 'booleanp)
 (autoload 'byte-compile-file "bytecomp" "\
 Compile a file of Lisp code named FILENAME into a file of byte code.
 The output file's name is generated by passing FILENAME to the
 function `byte-compile-dest-file' (which see).
 The value is non-nil if there were no errors, nil if errors.
+If the file sets the file variable `no-byte-compile', it is not
+compiled, any existing output file is removed, and the return
+value is `no-byte-compile'.
 
 See also `emacs-lisp-byte-compile-and-load'.
 
-(fn FILENAME &optional LOAD)" t nil)
+(fn FILENAME &optional LOAD)" t)
 (set-advertised-calling-convention 'byte-compile-file '(filename) '"28.1")
 (autoload 'compile-defun "bytecomp" "\
 Compile and evaluate the current top-level form.
 Print the result in the echo area.
 With argument ARG, insert value in current buffer after the form.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'byte-compile "bytecomp" "\
 If FORM is a symbol, byte-compile its function definition.
 If FORM is a lambda or a macro, byte-compile it as a function.
 
-(fn FORM)" nil nil)
+(fn FORM)")
 (autoload 'display-call-tree "bytecomp" "\
 Display a call graph of a specified file.
 This lists which functions have been called, what functions called
@@ -2815,11 +2784,11 @@ The call tree also lists those functions which are not 
known to be called
 (that is, to which no calls have been compiled), and which cannot be
 invoked interactively.
 
-(fn &optional FILENAME)" t nil)
+(fn &optional FILENAME)" t)
 (autoload 'batch-byte-compile-if-not-done "bytecomp" "\
 Like `byte-compile-file' but doesn't recompile if already up to date.
 Use this from the command line, with `-batch';
-it won't work in an interactive Emacs." nil nil)
+it won't work in an interactive Emacs.")
 (autoload 'batch-byte-compile "bytecomp" "\
 Run `byte-compile-file' on the files remaining on the command line.
 Use this from the command line, with `-batch';
@@ -2836,7 +2805,7 @@ For example, invoke \"emacs -batch -f batch-byte-compile 
$emacs/ ~/*.el\".
 If NOFORCE is non-nil, don't recompile a file that seems to be
 already up-to-date.
 
-(fn &optional NOFORCE)" nil nil)
+(fn &optional NOFORCE)")
 (autoload 'batch-byte-recompile-directory "bytecomp" "\
 Run `byte-recompile-directory' on the dirs remaining on the command line.
 Must be used only with `-batch', and kills Emacs on completion.
@@ -2846,13 +2815,13 @@ Optional argument ARG is passed as second argument ARG 
to
 `byte-recompile-directory'; see there for its possible values
 and corresponding effects.
 
-(fn &optional ARG)" nil nil)
+(fn &optional ARG)")
 (register-definition-prefixes "bytecomp" '("batch-byte-compile-file" "byte" 
"displaying-byte-compile-warnings" "emacs-lisp-" "no-byte-compile"))
 
 
 ;;; Generated autoloads from cedet/semantic/bovine/c.el
 
-(register-definition-prefixes "semantic/bovine/c" '("c-mode" "semantic"))
+(register-definition-prefixes "semantic/bovine/c" '("semantic"))
 
 
 ;;; Generated autoloads from calendar/cal-bahai.el
@@ -2891,7 +2860,7 @@ List Yahrzeit dates for *Gregorian* DEATH-DATE from 
START-YEAR to END-YEAR.
 When called interactively from the calendar window, the date of death is taken
 from the cursor position.
 
-(fn DEATH-DATE START-YEAR END-YEAR)" t nil)
+(fn DEATH-DATE START-YEAR END-YEAR)" t)
 (register-definition-prefixes "cal-hebrew" '("calendar-hebrew-" 
"diary-hebrew-" "holiday-hebrew"))
 
 
@@ -2951,64 +2920,64 @@ from the cursor position.
 (autoload 'calc-dispatch "calc" "\
 Invoke the GNU Emacs Calculator.  See \\[calc-dispatch-help] for details.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'calc "calc" "\
 The Emacs Calculator.  Full documentation is listed under `calc-mode'.
 
-(fn &optional ARG FULL-DISPLAY INTERACTIVE)" t nil)
+(fn &optional ARG FULL-DISPLAY INTERACTIVE)" t)
 (autoload 'full-calc "calc" "\
 Invoke the Calculator and give it a full-sized window.
 
-(fn &optional INTERACTIVE)" t nil)
+(fn &optional INTERACTIVE)" t)
 (autoload 'quick-calc "calc" "\
 Do a quick calculation in the minibuffer without invoking full Calculator.
 With prefix argument INSERT, insert the result in the current
 buffer.  Otherwise, the result is copied into the kill ring.
 
-(fn &optional INSERT)" t nil)
+(fn &optional INSERT)" t)
 (autoload 'calc-eval "calc" "\
 Do a quick calculation and return the result as a string.
 Return value will either be the formatted result in string form,
 or a list containing a character position and an error message in string form.
 
-(fn STR &optional SEPARATOR &rest ARGS)" nil nil)
+(fn STR &optional SEPARATOR &rest ARGS)")
 (autoload 'calc-keypad "calc" "\
 Invoke the Calculator in \"visual keypad\" mode.
 This is most useful in the X window system.
 In this mode, click on the Calc \"buttons\" using the left mouse button.
 Or, position the cursor manually and do \\[calc-keypad-press].
 
-(fn &optional INTERACTIVE)" t nil)
+(fn &optional INTERACTIVE)" t)
 (autoload 'full-calc-keypad "calc" "\
 Invoke the Calculator in full-screen \"visual keypad\" mode.
 See calc-keypad for details.
 
-(fn &optional INTERACTIVE)" t nil)
+(fn &optional INTERACTIVE)" t)
 (autoload 'calc-grab-region "calc" "\
 Parse the region as a vector of numbers and push it on the Calculator stack.
 
-(fn TOP BOT ARG)" t nil)
+(fn TOP BOT ARG)" t)
 (autoload 'calc-grab-rectangle "calc" "\
 Parse a rectangle as a matrix of numbers and push it on the Calculator stack.
 
-(fn TOP BOT ARG)" t nil)
+(fn TOP BOT ARG)" t)
 (autoload 'calc-grab-sum-down "calc" "\
 Parse a rectangle as a matrix of numbers and sum its columns.
 
-(fn TOP BOT ARG)" t nil)
+(fn TOP BOT ARG)" t)
 (autoload 'calc-grab-sum-across "calc" "\
 Parse a rectangle as a matrix of numbers and sum its rows.
 
-(fn TOP BOT ARG)" t nil)
+(fn TOP BOT ARG)" t)
 (autoload 'calc-embedded "calc" "\
 Start Calc Embedded mode on the formula surrounding point.
 
-(fn ARG &optional END OBEG OEND)" t nil)
+(fn ARG &optional END OBEG OEND)" t)
 (autoload 'calc-embedded-activate "calc" "\
 Scan the current editing buffer for all embedded := and => formulas.
 Also looks for the equivalent TeX words, \\gets and \\evalto.
 
-(fn &optional ARG CBUF)" t nil)
+(fn &optional ARG CBUF)" t)
 (autoload 'defmath "calc" "\
 Define Calc function.
 
@@ -3022,7 +2991,7 @@ actual Lisp function name.
 See Info node `(calc)Defining Functions'.
 
 (fn FUNC ARGS &rest BODY)" nil t)
-(function-put 'defmath 'doc-string-elt '3)
+(function-put 'defmath 'doc-string-elt 3)
 (function-put 'defmath 'lisp-indent-function 'defun)
 (register-definition-prefixes "calc" '("calc" "defcalcmodevar" 
"inexact-result" "math-" "var-"))
 
@@ -3202,7 +3171,7 @@ See Info node `(calc)Defining Functions'.
 (autoload 'calc-undo "calc-undo" "\
 
 
-(fn N)" t nil)
+(fn N)" t)
 (register-definition-prefixes "calc-undo" '("calc-"))
 
 
@@ -3245,7 +3214,7 @@ See Info node `(calc)Defining Functions'.
 
 (autoload 'calculator "calculator" "\
 Run the Emacs calculator.
-See the documentation for `calculator-mode' for more information." t nil)
+See the documentation for `calculator-mode' for more information." t)
 (register-definition-prefixes "calculator" '("calculator-"))
 
 
@@ -3286,7 +3255,7 @@ Runs the following hooks:
 
 This function is suitable for execution in an init file.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "calendar" '("calendar-" "diary-" 
"holiday-buffer" "lunar-phases-buffer" "solar-sunrises-buffer"))
 
 
@@ -3295,13 +3264,13 @@ This function is suitable for execution in an init file.
 (autoload 'canlock-insert-header "canlock" "\
 Insert a Cancel-Key and/or a Cancel-Lock header if possible.
 
-(fn &optional ID-FOR-KEY ID-FOR-LOCK PASSWORD)" nil nil)
+(fn &optional ID-FOR-KEY ID-FOR-LOCK PASSWORD)")
 (autoload 'canlock-verify "canlock" "\
 Verify Cancel-Lock or Cancel-Key in BUFFER.
 If BUFFER is nil, the current buffer is assumed.  Signal an error if
 it fails.
 
-(fn &optional BUFFER)" t nil)
+(fn &optional BUFFER)" t)
 (register-definition-prefixes "canlock" '("canlock-"))
 
 
@@ -3333,7 +3302,7 @@ it fails.
 ;;; Generated autoloads from progmodes/cc-engine.el
 
 (autoload 'c-guess-basic-syntax "cc-engine" "\
-Return the syntactic context of the current line." nil nil)
+Return the syntactic context of the current line.")
 (register-definition-prefixes "cc-engine" '("c-"))
 
 
@@ -3357,7 +3326,7 @@ If given a prefix argument (or if the optional argument 
ACCUMULATE is
 non-nil) then the previous guess is extended, otherwise a new guess is
 made from scratch.
 
-(fn &optional ACCUMULATE)" t nil)
+(fn &optional ACCUMULATE)" t)
 (autoload 'c-guess-no-install "cc-guess" "\
 Guess the style in the region up to `c-guess-region-max'; don't install it.
 
@@ -3365,7 +3334,7 @@ If given a prefix argument (or if the optional argument 
ACCUMULATE is
 non-nil) then the previous guess is extended, otherwise a new guess is
 made from scratch.
 
-(fn &optional ACCUMULATE)" t nil)
+(fn &optional ACCUMULATE)" t)
 (autoload 'c-guess-buffer "cc-guess" "\
 Guess the style on the whole current buffer, and install it.
 
@@ -3375,7 +3344,7 @@ If given a prefix argument (or if the optional argument 
ACCUMULATE is
 non-nil) then the previous guess is extended, otherwise a new guess is
 made from scratch.
 
-(fn &optional ACCUMULATE)" t nil)
+(fn &optional ACCUMULATE)" t)
 (autoload 'c-guess-buffer-no-install "cc-guess" "\
 Guess the style on the whole current buffer; don't install it.
 
@@ -3383,7 +3352,7 @@ If given a prefix argument (or if the optional argument 
ACCUMULATE is
 non-nil) then the previous guess is extended, otherwise a new guess is
 made from scratch.
 
-(fn &optional ACCUMULATE)" t nil)
+(fn &optional ACCUMULATE)" t)
 (autoload 'c-guess-region "cc-guess" "\
 Guess the style on the region and install it.
 
@@ -3393,7 +3362,7 @@ If given a prefix argument (or if the optional argument 
ACCUMULATE is
 non-nil) then the previous guess is extended, otherwise a new guess is
 made from scratch.
 
-(fn START END &optional ACCUMULATE)" t nil)
+(fn START END &optional ACCUMULATE)" t)
 (autoload 'c-guess-region-no-install "cc-guess" "\
 Guess the style on the region; don't install it.
 
@@ -3417,7 +3386,7 @@ guess is made from scratch.
 Note that the larger the region to guess in, the slower the guessing.
 So you can limit the region with `c-guess-region-max'.
 
-(fn START END &optional ACCUMULATE)" t nil)
+(fn START END &optional ACCUMULATE)" t)
 (autoload 'c-guess-install "cc-guess" "\
 Install the latest guessed style into the current buffer.
 (This guessed style is a combination of `c-guess-guessed-basic-offset',
@@ -3427,7 +3396,7 @@ The style is entered into CC Mode's style system by
 `c-add-style'.  Its name is either STYLE-NAME, or a name based on
 the absolute file name of the file if STYLE-NAME is nil.
 
-(fn &optional STYLE-NAME)" t nil)
+(fn &optional STYLE-NAME)" t)
 (register-definition-prefixes "cc-guess" '("c-guess-"))
 
 
@@ -3452,7 +3421,7 @@ only some basic setup is done, and a call to 
`c-init-language-vars' or
 `c-init-language-vars-for' is necessary too (which gives more
 control).  See \"cc-mode.el\" for more info.
 
-(fn &optional NEW-STYLE-INIT)" nil nil)
+(fn &optional NEW-STYLE-INIT)")
  (add-to-list 'auto-mode-alist '("\\.\\(cc\\|hh\\)\\'" . c++-mode))
  (add-to-list 'auto-mode-alist '("\\.[ch]\\(pp\\|xx\\|\\+\\+\\)\\'" . 
c++-mode))
  (add-to-list 'auto-mode-alist '("\\.\\(CC?\\|HH?\\)\\'" . c++-mode))
@@ -3478,7 +3447,7 @@ initialization, then `c-mode-hook'.
 Key bindings:
 \\{c-mode-map}
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'c-or-c++-mode "cc-mode" "\
 Analyze buffer and enable either C or C++ mode.
 
@@ -3489,7 +3458,7 @@ should be used.
 
 This function attempts to use file contents to determine whether
 the code is C or C++ and based on that chooses whether to enable
-`c-mode' or `c++-mode'." t nil)
+`c-mode' or `c++-mode'." t)
 (autoload 'c++-mode "cc-mode" "\
 Major mode for editing C++ code.
 To submit a problem report, enter `\\[c-submit-bug-report]' from a
@@ -3506,7 +3475,7 @@ initialization, then `c++-mode-hook'.
 Key bindings:
 \\{c++-mode-map}
 
-(fn)" t nil)
+(fn)" t)
  (add-to-list 'auto-mode-alist '("\\.m\\'" . objc-mode))
 (autoload 'objc-mode "cc-mode" "\
 Major mode for editing Objective C code.
@@ -3524,7 +3493,7 @@ initialization, then `objc-mode-hook'.
 Key bindings:
 \\{objc-mode-map}
 
-(fn)" t nil)
+(fn)" t)
  (add-to-list 'auto-mode-alist '("\\.java\\'" . java-mode))
 (autoload 'java-mode "cc-mode" "\
 Major mode for editing Java code.
@@ -3542,7 +3511,7 @@ initialization, then `java-mode-hook'.
 Key bindings:
 \\{java-mode-map}
 
-(fn)" t nil)
+(fn)" t)
  (add-to-list 'auto-mode-alist '("\\.idl\\'" . idl-mode))
 (autoload 'idl-mode "cc-mode" "\
 Major mode for editing CORBA's IDL, PSDL and CIDL code.
@@ -3560,7 +3529,7 @@ initialization, then `idl-mode-hook'.
 Key bindings:
 \\{idl-mode-map}
 
-(fn)" t nil)
+(fn)" t)
  (add-to-list 'auto-mode-alist '("\\.\\(u?lpc\\|pike\\|pmod\\(\\.in\\)?\\)\\'" 
. pike-mode))
  (add-to-list 'interpreter-mode-alist '("pike" . pike-mode))
 (autoload 'pike-mode "cc-mode" "\
@@ -3579,7 +3548,7 @@ initialization, then `pike-mode-hook'.
 Key bindings:
 \\{pike-mode-map}
 
-(fn)" t nil)
+(fn)" t)
  (add-to-list 'auto-mode-alist '("\\.awk\\'" . awk-mode))
  (add-to-list 'interpreter-mode-alist '("awk" . awk-mode))
  (add-to-list 'interpreter-mode-alist '("mawk" . awk-mode))
@@ -3600,7 +3569,7 @@ initialization, then `awk-mode-hook'.
 Key bindings:
 \\{awk-mode-map}
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "cc-mode" '("awk-mode-map" "c++-mode-" "c-" 
"idl-mode-" "java-mode-" "objc-mode-" "pike-mode-"))
 
 
@@ -3629,7 +3598,7 @@ calls c-set-style internally in this way whilst 
initializing a buffer; if
 c-set-style is called like this from anywhere else, it will usually behave as
 a null operation.
 
-(fn STYLENAME &optional DONT-OVERRIDE)" t nil)
+(fn STYLENAME &optional DONT-OVERRIDE)" t)
 (autoload 'c-add-style "cc-styles" "\
 Add a style to `c-style-alist', or update an existing one.
 STYLE is a string identifying the style to add or update.  DESCRIPTION
@@ -3641,14 +3610,14 @@ See the variable `c-style-alist' for the semantics of 
BASESTYLE,
 VARIABLE and VALUE.  This function also sets the current style to
 STYLE using `c-set-style' if the optional SET-P flag is non-nil.
 
-(fn STYLE DESCRIPTION &optional SET-P)" t nil)
+(fn STYLE DESCRIPTION &optional SET-P)" t)
 (autoload 'c-set-offset "cc-styles" "\
 Change the value of a syntactic element symbol in `c-offsets-alist'.
 SYMBOL is the syntactic element symbol to change and OFFSET is the new
 offset for that syntactic element.  The optional argument is not used
 and exists only for compatibility reasons.
 
-(fn SYMBOL OFFSET &optional IGNORED)" t nil)
+(fn SYMBOL OFFSET &optional IGNORED)" t)
 (register-definition-prefixes "cc-styles" '("c-" "cc-choose-style-for-mode"))
 
 
@@ -3665,11 +3634,11 @@ and exists only for compatibility reasons.
 (autoload 'ccl-compile "ccl" "\
 Return the compiled code of CCL-PROGRAM as a vector of integers.
 
-(fn CCL-PROGRAM)" nil nil)
+(fn CCL-PROGRAM)")
 (autoload 'ccl-dump "ccl" "\
 Disassemble compiled CCL-code CODE.
 
-(fn CODE)" nil nil)
+(fn CODE)")
 (autoload 'declare-ccl-program "ccl" "\
 Declare NAME as a name of CCL program.
 
@@ -3927,7 +3896,7 @@ MAP-SET := MAP-IDs | (MAP-IDs) MAP-SET
 MAP-ID := integer
 
 (fn NAME CCL-PROGRAM &optional DOC)" nil t)
-(function-put 'define-ccl-program 'doc-string-elt '3)
+(function-put 'define-ccl-program 'doc-string-elt 3)
 (function-put 'define-ccl-program 'lisp-indent-function 'defun)
 (autoload 'check-ccl-program "ccl" "\
 Check validity of CCL-PROGRAM.
@@ -3943,7 +3912,7 @@ The return value is a vector of resulting CCL registers.
 
 See the documentation of `define-ccl-program' for the detail of CCL program.
 
-(fn CCL-PROG &rest ARGS)" nil nil)
+(fn CCL-PROG &rest ARGS)")
 (register-definition-prefixes "ccl" '("ccl-"))
 
 
@@ -3951,12 +3920,11 @@ See the documentation of `define-ccl-program' for the 
detail of CCL program.
 
 (autoload 'cconv-closure-convert "cconv" "\
 Main entry point for closure conversion.
--- FORM is a piece of Elisp code after macroexpansion.
--- TOPLEVEL(optional) is a boolean variable, true if we are at the root of AST
+FORM is a piece of Elisp code after macroexpansion.
 
 Returns a form where all lambdas don't have any free variables.
 
-(fn FORM)" nil nil)
+(fn FORM)")
 (register-definition-prefixes "cconv" '("cconv-"))
 
 
@@ -4001,7 +3969,7 @@ There are no special keybindings by default.
 Action blocks are treated as defuns, i.e. \\[beginning-of-defun] moves
 to the action header.
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'cfengine2-mode "cfengine" "\
 Major mode for editing CFEngine2 input.
 There are no special keybindings by default.
@@ -4009,9 +3977,9 @@ There are no special keybindings by default.
 Action blocks are treated as defuns, i.e. \\[beginning-of-defun] moves
 to the action header.
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'cfengine-auto-mode "cfengine" "\
-Choose `cfengine2-mode' or `cfengine3-mode' by buffer contents." t nil)
+Choose `cfengine2-mode' or `cfengine3-mode' by buffer contents." t)
 (register-definition-prefixes "cfengine" '("cfengine"))
 
 
@@ -4035,7 +4003,7 @@ just return the result of calling `regexp-quote' on 
STRING.
 FROM is for internal use.  It specifies an index in the STRING
 from which to start.
 
-(fn STRING &optional LAX FROM)" nil nil)
+(fn STRING &optional LAX FROM)")
 (register-definition-prefixes "char-fold" '("char-fold-"))
 
 
@@ -4055,12 +4023,12 @@ from which to start.
 Check veracity of all `declare-function' statements in FILE.
 See `check-declare-directory' for more information.
 
-(fn FILE)" t nil)
+(fn FILE)" t)
 (autoload 'check-declare-directory "check-declare" "\
 Check veracity of all `declare-function' statements under directory ROOT.
 Returns non-nil if any false statements are found.
 
-(fn ROOT)" t nil)
+(fn ROOT)" t)
 (register-definition-prefixes "check-declare" '("check-declare-"))
 
 
@@ -4077,13 +4045,13 @@ Returns non-nil if any false statements are found.
 (autoload 'checkdoc-list-of-strings-p "checkdoc" "\
 Return t when OBJ is a list of strings.
 
-(fn OBJ)" nil nil)
+(fn OBJ)")
 (put 'checkdoc-proper-noun-regexp 'safe-local-variable 'stringp)
 (put 'checkdoc-common-verbs-regexp 'safe-local-variable 'stringp)
 (autoload 'checkdoc "checkdoc" "\
 Interactively check the entire buffer for style errors.
 The current status of the check will be displayed in a buffer which
-the users will view as each check is completed." '(emacs-lisp-mode) nil)
+the users will view as each check is completed." '(emacs-lisp-mode))
 (autoload 'checkdoc-interactive "checkdoc" "\
 Interactively check the current buffer for doc string errors.
 Prefix argument START-HERE will start the checking from the current
@@ -4093,7 +4061,7 @@ errors.  Does not check for comment or space warnings.
 Optional argument SHOWSTATUS indicates that we should update the
 checkdoc status window instead of the usual behavior.
 
-(fn &optional START-HERE SHOWSTATUS)" '(emacs-lisp-mode) nil)
+(fn &optional START-HERE SHOWSTATUS)" '(emacs-lisp-mode))
 (autoload 'checkdoc-message-interactive "checkdoc" "\
 Interactively check the current buffer for message string errors.
 Prefix argument START-HERE will start the checking from the current
@@ -4103,23 +4071,23 @@ errors.  Does not check for comment or space warnings.
 Optional argument SHOWSTATUS indicates that we should update the
 checkdoc status window instead of the usual behavior.
 
-(fn &optional START-HERE SHOWSTATUS)" '(emacs-lisp-mode) nil)
+(fn &optional START-HERE SHOWSTATUS)" '(emacs-lisp-mode))
 (autoload 'checkdoc-eval-current-buffer "checkdoc" "\
 Evaluate and check documentation for the current buffer.
 Evaluation is done first because good documentation for something that
 doesn't work is just not useful.  Comments, doc strings, and rogue
-spacing are all verified." t nil)
+spacing are all verified." t)
 (autoload 'checkdoc-current-buffer "checkdoc" "\
 Check current buffer for document, comment, error style, and rogue spaces.
 With a prefix argument (in Lisp, the argument TAKE-NOTES),
 store all errors found in a warnings buffer,
 otherwise stop after the first error.
 
-(fn &optional TAKE-NOTES)" '(emacs-lisp-mode) nil)
+(fn &optional TAKE-NOTES)" '(emacs-lisp-mode))
 (autoload 'checkdoc-file "checkdoc" "\
 Check FILE for document, comment, error style, and rogue spaces.
 
-(fn FILE)" nil nil)
+(fn FILE)")
 (autoload 'checkdoc-start "checkdoc" "\
 Start scanning the current buffer for documentation string style errors.
 Only documentation strings are checked.
@@ -4127,20 +4095,20 @@ Use `checkdoc-continue' to continue checking if an 
error cannot be fixed.
 Prefix argument TAKE-NOTES means to collect all the warning messages into
 a separate buffer.
 
-(fn &optional TAKE-NOTES)" '(emacs-lisp-mode) nil)
+(fn &optional TAKE-NOTES)" '(emacs-lisp-mode))
 (autoload 'checkdoc-continue "checkdoc" "\
 Find the next doc string in the current buffer which has a style error.
 Prefix argument TAKE-NOTES means to continue through the whole
 buffer and save warnings in a separate buffer.
 
-(fn &optional TAKE-NOTES)" '(emacs-lisp-mode) nil)
+(fn &optional TAKE-NOTES)" '(emacs-lisp-mode))
 (autoload 'checkdoc-comments "checkdoc" "\
 Find missing comment sections in the current Emacs Lisp file.
 Prefix argument TAKE-NOTES non-nil means to save warnings in a
 separate buffer.  Otherwise print a message.  This returns the error
 if there is one.
 
-(fn &optional TAKE-NOTES)" '(emacs-lisp-mode) nil)
+(fn &optional TAKE-NOTES)" '(emacs-lisp-mode))
 (autoload 'checkdoc-rogue-spaces "checkdoc" "\
 Find extra spaces at the end of lines in the current file.
 Prefix argument TAKE-NOTES non-nil means to save warnings in a
@@ -4148,17 +4116,17 @@ separate buffer.  Otherwise print a message.  This 
returns the error
 if there is one.
 Optional argument INTERACT permits more interactive fixing.
 
-(fn &optional TAKE-NOTES INTERACT)" '(emacs-lisp-mode) nil)
+(fn &optional TAKE-NOTES INTERACT)" '(emacs-lisp-mode))
 (autoload 'checkdoc-message-text "checkdoc" "\
 Scan the buffer for occurrences of the error function, and verify text.
 Optional argument TAKE-NOTES causes all errors to be logged.
 
-(fn &optional TAKE-NOTES)" '(emacs-lisp-mode) nil)
+(fn &optional TAKE-NOTES)" '(emacs-lisp-mode))
 (autoload 'checkdoc-eval-defun "checkdoc" "\
 Evaluate the current form with `eval-defun' and check its documentation.
 Evaluation is done first so the form will be read before the
 documentation is checked.  If there is a documentation error, then the display
-of what was evaluated will be overwritten by the diagnostic message." t nil)
+of what was evaluated will be overwritten by the diagnostic message." t)
 (autoload 'checkdoc-defun "checkdoc" "\
 Examine the doc string of the function or variable under point.
 Call `error' if the doc string has problems.  If NO-ERROR is
@@ -4166,50 +4134,50 @@ non-nil, then do not call error, but call `message' 
instead.
 If the doc string passes the test, then check the function for rogue white
 space at the end of each line.
 
-(fn &optional NO-ERROR)" t nil)
+(fn &optional NO-ERROR)" t)
 (autoload 'checkdoc-dired "checkdoc" "\
 In Dired, run `checkdoc' on marked files.
 Skip anything that doesn't have the Emacs Lisp library file
 extension (\".el\").
 When called from Lisp, FILES is a list of filenames.
 
-(fn FILES)" '(dired-mode) nil)
+(fn FILES)" '(dired-mode))
 (autoload 'checkdoc-ispell "checkdoc" "\
 Check the style and spelling of everything interactively.
 Calls `checkdoc' with spell-checking turned on.
-Prefix argument is the same as for `checkdoc'." t nil)
+Prefix argument is the same as for `checkdoc'." t)
 (autoload 'checkdoc-ispell-current-buffer "checkdoc" "\
 Check the style and spelling of the current buffer.
 Calls `checkdoc-current-buffer' with spell-checking turned on.
-Prefix argument is the same as for `checkdoc-current-buffer'." t nil)
+Prefix argument is the same as for `checkdoc-current-buffer'." t)
 (autoload 'checkdoc-ispell-interactive "checkdoc" "\
 Check the style and spelling of the current buffer interactively.
 Calls `checkdoc-interactive' with spell-checking turned on.
-Prefix argument is the same as for `checkdoc-interactive'." t nil)
+Prefix argument is the same as for `checkdoc-interactive'." t)
 (autoload 'checkdoc-ispell-message-interactive "checkdoc" "\
 Check the style and spelling of message text interactively.
 Calls `checkdoc-message-interactive' with spell-checking turned on.
-Prefix argument is the same as for `checkdoc-message-interactive'." t nil)
+Prefix argument is the same as for `checkdoc-message-interactive'." t)
 (autoload 'checkdoc-ispell-message-text "checkdoc" "\
 Check the style and spelling of message text interactively.
 Calls `checkdoc-message-text' with spell-checking turned on.
-Prefix argument is the same as for `checkdoc-message-text'." t nil)
+Prefix argument is the same as for `checkdoc-message-text'." t)
 (autoload 'checkdoc-ispell-start "checkdoc" "\
 Check the style and spelling of the current buffer.
 Calls `checkdoc-start' with spell-checking turned on.
-Prefix argument is the same as for `checkdoc-start'." t nil)
+Prefix argument is the same as for `checkdoc-start'." t)
 (autoload 'checkdoc-ispell-continue "checkdoc" "\
 Check the style and spelling of the current buffer after point.
 Calls `checkdoc-continue' with spell-checking turned on.
-Prefix argument is the same as for `checkdoc-continue'." t nil)
+Prefix argument is the same as for `checkdoc-continue'." t)
 (autoload 'checkdoc-ispell-comments "checkdoc" "\
 Check the style and spelling of the current buffer's comments.
 Calls `checkdoc-comments' with spell-checking turned on.
-Prefix argument is the same as for `checkdoc-comments'." t nil)
+Prefix argument is the same as for `checkdoc-comments'." t)
 (autoload 'checkdoc-ispell-defun "checkdoc" "\
 Check the style and spelling of the current defun with Ispell.
 Calls `checkdoc-defun' with spell-checking turned on.
-Prefix argument is the same as for `checkdoc-defun'." t nil)
+Prefix argument is the same as for `checkdoc-defun'." t)
 (autoload 'checkdoc-minor-mode "checkdoc" "\
 Toggle automatic docstring checking (Checkdoc minor mode).
 
@@ -4233,9 +4201,9 @@ evaluate `checkdoc-minor-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'checkdoc-package-keywords "checkdoc" "\
-Find package keywords that aren't in `finder-known-keywords'." t nil)
+Find package keywords that aren't in `finder-known-keywords'." t)
 (register-definition-prefixes "checkdoc" '("checkdoc-"))
 
 
@@ -4245,24 +4213,24 @@ Find package keywords that aren't in 
`finder-known-keywords'." t nil)
 Decode HZ/ZW encoded text in the current region.
 Return the length of resulting text.
 
-(fn BEG END)" t nil)
+(fn BEG END)" t)
 (autoload 'decode-hz-buffer "china-util" "\
-Decode HZ/ZW encoded text in the current buffer." t nil)
+Decode HZ/ZW encoded text in the current buffer." t)
 (autoload 'encode-hz-region "china-util" "\
 Encode the text in the current region to HZ.
 Return the length of resulting text.
 
-(fn BEG END)" t nil)
+(fn BEG END)" t)
 (autoload 'encode-hz-buffer "china-util" "\
-Encode the text in the current buffer to HZ." t nil)
+Encode the text in the current buffer to HZ." t)
 (autoload 'post-read-decode-hz "china-util" "\
 
 
-(fn LEN)" nil nil)
+(fn LEN)")
 (autoload 'pre-write-encode-hz "china-util" "\
 
 
-(fn FROM TO)" nil nil)
+(fn FROM TO)")
 (register-definition-prefixes "china-util" '("decode-hz-line-continuation" 
"hz-" "hz/zw-start-gb" "iso2022-" "zw-start-gb"))
 
 
@@ -4275,26 +4243,26 @@ a form for evaluation.  If PATTERN is empty (or nil), 
every form in the
 command history is offered.  The form is placed in the minibuffer for
 editing and the result is evaluated.
 
-(fn &optional PATTERN)" t nil)
+(fn &optional PATTERN)" t)
 (autoload 'list-command-history "chistory" "\
 List history of commands that used the minibuffer.
 The number of commands listed is controlled by `list-command-history-max'.
 Calls value of `list-command-history-filter' (if non-nil) on each history
 element to judge if that element should be excluded from the list.
 
-The buffer is left in Command History mode." t nil)
+The buffer is left in Command History mode." t)
 (autoload 'command-history "chistory" "\
 Examine commands from variable `command-history' in a buffer.
 The number of commands listed is controlled by `list-command-history-max'.
 The command history is filtered by `list-command-history-filter' if non-nil.
-Use \\<command-history-map>\\[command-history-repeat] to repeat the command on 
the current line.
+Use \\<command-history-mode-map>\\[command-history-repeat] to repeat the 
command on the current line.
 
 Otherwise much like Emacs-Lisp Mode except that there is no self-insertion
 and digits provide prefix arguments.  Tab does not indent.
-\\{command-history-map}
+\\{command-history-mode-map}
 
 This command always recompiles the Command History listing
-and runs the normal hook `command-history-hook'." t nil)
+and runs the normal hook `command-history-hook'." t)
 (register-definition-prefixes "chistory" '("command-history-" 
"default-command-history-filter" "list-command-history-"))
 
 
@@ -4331,7 +4299,7 @@ evaluate `(default-value \\='cl-font-lock-built-in-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "cl-font-lock" '("cl-font-lock-"))
 
 
@@ -4352,12 +4320,12 @@ OPTIONS-AND-METHODS currently understands:
 DEFAULT-BODY, if present, is used as the body of a default method.
 
 (fn NAME ARGS [DOC-STRING] [OPTIONS-AND-METHODS...] &rest DEFAULT-BODY)" nil t)
-(function-put 'cl-defgeneric 'lisp-indent-function '2)
-(function-put 'cl-defgeneric 'doc-string-elt '3)
+(function-put 'cl-defgeneric 'lisp-indent-function 2)
+(function-put 'cl-defgeneric 'doc-string-elt 3)
 (autoload 'cl-generic-define "cl-generic" "\
 
 
-(fn NAME ARGS OPTIONS)" nil nil)
+(fn NAME ARGS OPTIONS)")
 (autoload 'cl-defmethod "cl-generic" "\
 Define a new method for generic function NAME.
 This defines an implementation of NAME to use for invocations
@@ -4405,11 +4373,11 @@ The set of acceptable TYPEs (also called 
\"specializers\") is defined
 (autoload 'cl-generic-define-method "cl-generic" "\
 
 
-(fn NAME QUALIFIERS ARGS CALL-CON FUNCTION)" nil nil)
+(fn NAME QUALIFIERS ARGS CALL-CON FUNCTION)")
 (autoload 'cl-find-method "cl-generic" "\
 
 
-(fn GENERIC QUALIFIERS SPECIALIZERS)" nil nil)
+(fn GENERIC QUALIFIERS SPECIALIZERS)")
 (register-definition-prefixes "cl-generic" '("cl-"))
 
 
@@ -4491,7 +4459,7 @@ If the current mode is actually `emacs-lisp-mode', look 
for a
 at `common-lisp-indent-function' and, if set, use its value
 instead.
 
-(fn INDENT-POINT STATE)" nil nil)
+(fn INDENT-POINT STATE)")
 (register-definition-prefixes "cl-indent" '("common-lisp-" "lisp-"))
 
 
@@ -4548,13 +4516,13 @@ evaluate `(default-value 
\\='cl-old-struct-compat-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "cl-lib" '("cl-"))
 
 
 ;;; Generated autoloads from emacs-lisp/cl-macs.el
 
-(register-definition-prefixes "cl-macs" '("cl-" "foo" "function-form"))
+(register-definition-prefixes "cl-macs" '("cl-"))
 
 
 ;;; Generated autoloads from emacs-lisp/cl-print.el
@@ -4566,13 +4534,13 @@ You can add methods to it to customize the output.
 But if you just want to print something, don't call this directly:
 call other entry points instead, such as `cl-prin1'.
 
-(fn OBJECT STREAM)" nil nil)
+(fn OBJECT STREAM)")
 (autoload 'cl-print-expand-ellipsis "cl-print" "\
 Print the expansion of an ellipsis to STREAM.
 VALUE should be the value of the `cl-print-ellipsis' text property
 which was attached to the ellipsis by `cl-prin1'.
 
-(fn VALUE STREAM)" nil nil)
+(fn VALUE STREAM)")
 (autoload 'cl-prin1 "cl-print" "\
 Print OBJECT on STREAM according to its type.
 Output is further controlled by the variables
@@ -4580,11 +4548,11 @@ Output is further controlled by the variables
 variables for the standard printing functions.  See Info
 node `(elisp)Output Variables'.
 
-(fn OBJECT &optional STREAM)" nil nil)
+(fn OBJECT &optional STREAM)")
 (autoload 'cl-prin1-to-string "cl-print" "\
 Return a string containing the `cl-prin1'-printed representation of OBJECT.
 
-(fn OBJECT)" nil nil)
+(fn OBJECT)")
 (autoload 'cl-print-to-string-with-limit "cl-print" "\
 Return a string containing a printed representation of VALUE.
 Attempt to get the length of the returned string under LIMIT
@@ -4601,7 +4569,7 @@ this function with `cl-prin1-expand-ellipsis' to expand an
 ellipsis, abbreviating the expansion to stay within a size
 limit.
 
-(fn PRINT-FUNCTION VALUE LIMIT)" nil nil)
+(fn PRINT-FUNCTION VALUE LIMIT)")
 (register-definition-prefixes "cl-print" '("cl-print-" "help-byte-code"))
 
 
@@ -4625,7 +4593,7 @@ otherwise use `c-macro-cppflags'.
 Noninteractive args are START, END, SUBST.
 For use inside Lisp programs, see also `c-macro-expansion'.
 
-(fn START END SUBST)" t nil)
+(fn START END SUBST)" t)
 (register-definition-prefixes "cmacexp" '("c-macro-"))
 
 
@@ -4644,7 +4612,7 @@ Runs the hook `inferior-scheme-mode-hook' (after the 
`comint-mode-hook'
 is run).
 (Type \\[describe-mode] in the process buffer for a list of commands.)
 
-(fn CMD)" t nil)
+(fn CMD)" t)
 (register-definition-prefixes "cmuscheme" '("cmuscheme-load-hook" 
"inferior-scheme-" "scheme-" "switch-to-scheme"))
 
 
@@ -4666,7 +4634,7 @@ Optional argument FRAME specifies the frame where the 
color is to be
 displayed.  If FRAME is omitted or nil, use the selected frame.
 If FRAME cannot display COLOR, return nil.
 
-(fn COLOR &optional FRAME)" nil nil)
+(fn COLOR &optional FRAME)")
 (register-definition-prefixes "color" '("color-"))
 
 
@@ -4703,7 +4671,7 @@ If PROGRAM is a string, any more args are arguments to 
PROGRAM.
 
 Return the (possibly newly created) process buffer.
 
-(fn NAME BUFFER PROGRAM &optional STARTFILE &rest SWITCHES)" nil nil)
+(fn NAME BUFFER PROGRAM &optional STARTFILE &rest SWITCHES)")
 (autoload 'make-comint "comint" "\
 Make a Comint process NAME in a buffer, running PROGRAM.
 The name of the buffer is made by surrounding NAME with `*'s.
@@ -4718,7 +4686,7 @@ If PROGRAM is a string, any more args are arguments to 
PROGRAM.
 
 Returns the (possibly newly created) process buffer.
 
-(fn NAME PROGRAM &optional STARTFILE &rest SWITCHES)" nil nil)
+(fn NAME PROGRAM &optional STARTFILE &rest SWITCHES)")
 (autoload 'comint-run "comint" "\
 Run PROGRAM in a Comint buffer and switch to that buffer.
 
@@ -4731,7 +4699,7 @@ hooks on this symbol are run in the buffer.
 
 See `make-comint' and `comint-exec'.
 
-(fn PROGRAM &optional SWITCHES)" t nil)
+(fn PROGRAM &optional SWITCHES)" t)
 (function-put 'comint-run 'interactive-only 'make-comint)
 (defvar comint-file-name-prefix (purecopy "") "\
 Prefix prepended to absolute file names taken from process input.
@@ -4743,26 +4711,26 @@ With prefix arg ECHO, echo output in process buffer.
 
 If NO-DISPLAY is non-nil, do not show the output buffer.
 
-(fn COMMAND OUTPUT-BUFFER ECHO &optional NO-DISPLAY)" t nil)
+(fn COMMAND OUTPUT-BUFFER ECHO &optional NO-DISPLAY)" t)
 (autoload 'comint-redirect-send-command-to-process "comint" "\
 Send COMMAND to PROCESS, with output to OUTPUT-BUFFER.
 With prefix arg, echo output in process buffer.
 
 If NO-DISPLAY is non-nil, do not show the output buffer.
 
-(fn COMMAND OUTPUT-BUFFER PROCESS ECHO &optional NO-DISPLAY)" t nil)
+(fn COMMAND OUTPUT-BUFFER PROCESS ECHO &optional NO-DISPLAY)" t)
 (autoload 'comint-redirect-results-list "comint" "\
 Send COMMAND to current process.
 Return a list of expressions in the output which match REGEXP.
 REGEXP-GROUP is the regular expression group in REGEXP to use.
 
-(fn COMMAND REGEXP REGEXP-GROUP)" nil nil)
+(fn COMMAND REGEXP REGEXP-GROUP)")
 (autoload 'comint-redirect-results-list-from-process "comint" "\
 Send COMMAND to PROCESS.
 Return a list of expressions in the output which match REGEXP.
 REGEXP-GROUP is the regular expression group in REGEXP to use.
 
-(fn PROCESS COMMAND REGEXP REGEXP-GROUP)" nil nil)
+(fn PROCESS COMMAND REGEXP REGEXP-GROUP)")
 (register-definition-prefixes "comint" '("comint-"))
 
 
@@ -4772,25 +4740,25 @@ REGEXP-GROUP is the regular expression group in REGEXP 
to use.
 (autoload 'comp-subr-trampoline-install "comp" "\
 Make SUBR-NAME effectively advice-able when called from native code.
 
-(fn SUBR-NAME)" nil nil)
+(fn SUBR-NAME)")
 (autoload 'comp-c-func-name "comp" "\
 Given NAME, return a name suitable for the native code.
 Add PREFIX in front of it.  If FIRST is not nil, pick the first
 available name ignoring compilation context and potential name
 clashes.
 
-(fn NAME PREFIX &optional FIRST)" nil nil)
+(fn NAME PREFIX &optional FIRST)")
 (autoload 'comp-clean-up-stale-eln "comp" "\
 Remove all FILE*.eln* files found in `native-comp-eln-load-path'.
 The files to be removed are those produced from the original source
 filename (including FILE).
 
-(fn FILE)" nil nil)
+(fn FILE)")
 (autoload 'comp-lookup-eln "comp" "\
 Given a Lisp source FILENAME return the corresponding .eln file if found.
 Search happens in `native-comp-eln-load-path'.
 
-(fn FILENAME)" nil nil)
+(fn FILENAME)")
 (autoload 'native-compile "comp" "\
 Compile FUNCTION-OR-FILE into native code.
 This is the synchronous entry-point for the Emacs Lisp native
@@ -4803,7 +4771,7 @@ If FUNCTION-OR-FILE is a filename, return the filename of 
the
 compiled object.  If FUNCTION-OR-FILE is a function symbol or a
 form, return the compiled function.
 
-(fn FUNCTION-OR-FILE &optional OUTPUT)" nil nil)
+(fn FUNCTION-OR-FILE &optional OUTPUT)")
 (autoload 'batch-native-compile "comp" "\
 Perform batch native compilation of remaining command-line arguments.
 
@@ -4815,14 +4783,14 @@ as part of building the source tarball, in which case 
the .eln file
 will be placed under the native-lisp/ directory (actually, in the
 last directory in `native-comp-eln-load-path').
 
-(fn &optional FOR-TARBALL)" nil nil)
+(fn &optional FOR-TARBALL)")
 (autoload 'batch-byte+native-compile "comp" "\
 Like `batch-native-compile', but used for bootstrap.
 Generate .elc files in addition to the .eln files.
 Force the produced .eln to be outputted in the eln system
 directory (the last entry in `native-comp-eln-load-path') unless
 `native-compile-target-directory' is non-nil.  If the environment
-variable \"NATIVE_DISABLED\" is set, only byte compile." nil nil)
+variable \"NATIVE_DISABLED\" is set, only byte compile.")
 (autoload 'native-compile-async "comp" "\
 Compile FILES asynchronously.
 FILES is one file or a list of filenames or directories.
@@ -4842,7 +4810,7 @@ a function -- A function selecting files with matching 
names.
 The variable `native-comp-async-jobs-number' specifies the number
 of (commands) to run simultaneously.
 
-(fn FILES &optional RECURSIVELY LOAD SELECTOR)" nil nil)
+(fn FILES &optional RECURSIVELY LOAD SELECTOR)")
 (register-definition-prefixes "comp" '("comp-" "make-comp-edge" "native-" 
"no-native-compile"))
 
 
@@ -4887,7 +4855,7 @@ on first call it advances points to the next difference,
 on second call it synchronizes points by skipping the difference,
 on third call it again advances points to the next difference and so on.
 
-(fn IGNORE-WHITESPACE)" t nil)
+(fn IGNORE-WHITESPACE)" t)
 (register-definition-prefixes "compare-w" '("compare-"))
 
 
@@ -4951,7 +4919,7 @@ You might also use mode hooks to specify it in certain 
modes, like this:
 
 It's often useful to leave a space at the end of the value.")
 (custom-autoload 'compile-command "compile" t)
-(put 'compile-command 'safe-local-variable (lambda (a) (and (stringp a) (or 
(not (boundp 'compilation-read-command)) compilation-read-command))))
+(put 'compile-command 'safe-local-variable (lambda (a) (and (stringp a) (if 
(boundp 'compilation-read-command) compilation-read-command t))))
 (defvar compilation-disable-input nil "\
 If non-nil, send end-of-file as compilation process input.
 This only affects platforms that support asynchronous processes (see
@@ -4986,7 +4954,11 @@ The name used for the buffer is actually whatever is 
returned by
 the function in `compilation-buffer-name-function', so you can set that
 to a function that generates a unique name.
 
-(fn COMMAND &optional COMINT)" t nil)
+(fn COMMAND &optional COMINT)" t)
+(autoload 'compilation--default-buffer-name "compile" "\
+
+
+(fn NAME-OF-MODE)")
 (autoload 'compilation-start "compile" "\
 Run compilation command COMMAND (low level interface).
 If COMMAND starts with a cd command, that becomes the `default-directory'.
@@ -5012,7 +4984,7 @@ point is not changed.
 
 Returns the compilation buffer created.
 
-(fn COMMAND &optional MODE NAME-FUNCTION HIGHLIGHT-REGEXP CONTINUE)" nil nil)
+(fn COMMAND &optional MODE NAME-FUNCTION HIGHLIGHT-REGEXP CONTINUE)")
 (autoload 'compilation-mode "compile" "\
 Major mode for compilation log buffers.
 \\<compilation-mode-map>To visit the source for a line-numbered error,
@@ -5023,7 +4995,7 @@ Runs `compilation-mode-hook' with `run-mode-hooks' (which 
see).
 
 \\{compilation-mode-map}
 
-(fn &optional NAME-OF-MODE)" t nil)
+(fn &optional NAME-OF-MODE)" t)
 (put 'define-compilation-mode 'doc-string-elt 3)
 (autoload 'compilation-shell-minor-mode "compile" "\
 Toggle Compilation Shell minor mode.
@@ -5048,7 +5020,7 @@ evaluate `compilation-shell-minor-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'compilation-minor-mode "compile" "\
 Toggle Compilation minor mode.
 
@@ -5071,12 +5043,12 @@ evaluate `compilation-minor-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'compilation-next-error-function "compile" "\
 Advance to the next error message and visit the file where the error was.
 This is the value of `next-error-function' in Compilation buffers.
 
-(fn N &optional RESET)" t nil)
+(fn N &optional RESET)" t)
 (register-definition-prefixes "compile" '("compil" "define-compilation-mode" 
"kill-compilation" "recompile"))
 
 
@@ -5123,7 +5095,7 @@ evaluate `(default-value \\='dynamic-completion-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "completion" '("*c-def-regexp*" 
"*lisp-def-regexp*" "accept-completion" "add-" "cdabbrev-" 
"check-completion-length" "clear-all-completions" "cmpl-" "complet" 
"current-completion-source" "delete-completion" "enable-completion" "find-" 
"inside-locate-completion-entry" "interactive-completion-string-reader" "kill-" 
"list-all-completions" "load-completions-from-file" "make-c" "next-cdabbrev" 
"num-cmpl-sources" "reset-cdabbrev" "save" "set-c" "symbol-" "use-comp [...]
 
 
@@ -5160,12 +5132,12 @@ See also `conf-space-mode', `conf-colon-mode', 
`conf-javaprop-mode',
 
 \\{conf-mode-map}
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'conf-unix-mode "conf-mode" "\
 Conf Mode starter for Unix style Conf files.
 Comments start with `#'.  For details see `conf-mode'.
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'conf-windows-mode "conf-mode" "\
 Conf Mode starter for Windows style Conf files.
 Comments start with `;'.
@@ -5180,16 +5152,12 @@ Default={5984FFE0-28D4-11CF-AE66-08002B2E1262}
 [{5984FFE0-28D4-11CF-AE66-08002B2E1262}]
 PersistMoniker=file://Folder.htt
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'conf-javaprop-mode "conf-mode" "\
 Conf Mode starter for Java properties files.
-Comments start with `#' but are also recognized with `//' or
-between `/*' and `*/'.
-For details see `conf-mode'.  Example:
+Comments start with `#'.  Example:
 
 # Conf mode font-locks this right with \\[conf-javaprop-mode] (Java properties)
-// another kind of comment
-/* yet another */
 
 name:value
 name=value
@@ -5198,7 +5166,7 @@ x.1 =
 x.2.y.1.z.1 =
 x.2.y.1.z.2.zz =
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'conf-space-mode "conf-mode" "\
 Conf Mode starter for space separated conf files.
 \"Assignments\" are with ` '.  Keywords before the parameters are
@@ -5222,12 +5190,12 @@ class desktop
 add /dev/audio         desktop
 add /dev/mixer         desktop
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'conf-space-keywords "conf-mode" "\
 Enter Conf Space mode using regexp KEYWORDS to match the keywords.
 See `conf-space-mode'.
 
-(fn KEYWORDS)" t nil)
+(fn KEYWORDS)" t)
 (autoload 'conf-colon-mode "conf-mode" "\
 Conf Mode starter for Colon files.
 \"Assignments\" are with `:'.
@@ -5238,7 +5206,7 @@ For details see `conf-mode'.  Example:
 <Multi_key> <exclam> <exclam>          : \"\\241\"     exclamdown
 <Multi_key> <c> <slash>                        : \"\\242\"     cent
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'conf-ppd-mode "conf-mode" "\
 Conf Mode starter for Adobe/CUPS PPD files.
 Comments start with `*%' and \"assignments\" are with `:'.
@@ -5249,7 +5217,7 @@ For details see `conf-mode'.  Example:
 *DefaultTransfer: Null
 *Transfer Null.Inverse: \"{ 1 exch sub }\"
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'conf-xdefaults-mode "conf-mode" "\
 Conf Mode starter for Xdefaults files.
 Comments start with `!' and \"assignments\" are with `:'.
@@ -5260,7 +5228,7 @@ For details see `conf-mode'.  Example:
 *background:                   gray99
 *foreground:                   black
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'conf-toml-mode "conf-mode" "\
 Conf Mode starter for TOML files.
 Comments start with `#' and \"assignments\" are with `='.
@@ -5271,7 +5239,7 @@ For details see `conf-mode'.  Example:
 [entry]
 value = \"some string\"
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'conf-desktop-mode "conf-mode" "\
 Conf Mode started for freedesktop.org Desktop files.
 Comments start with `#' and \"assignments\" are with `='.
@@ -5284,7 +5252,7 @@ For details see `conf-mode'.
        Exec=gimp-2.8 %U
        Terminal=false
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "conf-mode" '("conf-"))
 
 
@@ -5302,19 +5270,19 @@ of load, ENDMSG at the end.
 Interactively, PHRASE-FILE defaults to `cookie-file', unless that
 is nil or a prefix argument is used.
 
-(fn PHRASE-FILE &optional STARTMSG ENDMSG)" t nil)
+(fn PHRASE-FILE &optional STARTMSG ENDMSG)" t)
 (autoload 'cookie-insert "cookie1" "\
 Insert random phrases from PHRASE-FILE; COUNT of them.
 When the phrase file is read in, display STARTMSG at the beginning
 of load, ENDMSG at the end.
 
-(fn PHRASE-FILE &optional COUNT STARTMSG ENDMSG)" nil nil)
+(fn PHRASE-FILE &optional COUNT STARTMSG ENDMSG)")
 (autoload 'cookie-snarf "cookie1" "\
 Read the PHRASE-FILE, return it as a vector of strings.
 Emit STARTMSG and ENDMSG before and after.  Cache the result; second
 and subsequent calls on the same file won't go to disk.
 
-(fn PHRASE-FILE &optional STARTMSG ENDMSG)" nil nil)
+(fn PHRASE-FILE &optional STARTMSG ENDMSG)")
 (register-definition-prefixes "cookie1" '("cookie"))
 
 
@@ -5332,21 +5300,21 @@ following the copyright are updated as well.
 If non-nil, INTERACTIVEP tells the function to behave as when it's called
 interactively.
 
-(fn &optional ARG INTERACTIVEP)" t nil)
+(fn &optional ARG INTERACTIVEP)" t)
 (autoload 'copyright-fix-years "copyright" "\
 Convert 2 digit years to 4 digit years.
 Uses heuristic: year >= 50 means 19xx, < 50 means 20xx.
 If `copyright-year-ranges' (which see) is non-nil, also
-independently replaces consecutive years with a range." t nil)
+independently replaces consecutive years with a range." t)
 (autoload 'copyright "copyright" "\
 Insert a copyright by $ORGANIZATION notice at cursor.
 
-(fn &optional STR ARG)" t nil)
+(fn &optional STR ARG)" t)
 (autoload 'copyright-update-directory "copyright" "\
 Update copyright notice for all files in DIRECTORY matching MATCH.
 If FIX is non-nil, run `copyright-fix-years' instead.
 
-(fn DIRECTORY MATCH &optional FIX)" t nil)
+(fn DIRECTORY MATCH &optional FIX)" t)
 (register-definition-prefixes "copyright" '("copyright-"))
 
 
@@ -5535,14 +5503,14 @@ DO NOT FORGET to read micro-docs (available from `Perl' 
menu)
 or as help on variables `cperl-tips', `cperl-problems',
 `cperl-praise', `cperl-speed'.
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'cperl-perldoc "cperl-mode" "\
 Run `perldoc' on WORD.
 
-(fn WORD)" t nil)
+(fn WORD)" t)
 (autoload 'cperl-perldoc-at-point "cperl-mode" "\
-Run a `perldoc' on the word around point." t nil)
-(register-definition-prefixes "cperl-mode" '("cperl-" "pod2man-program"))
+Run a `perldoc' on the word around point." t)
+(register-definition-prefixes "cperl-mode" '("cperl-"))
 
 
 ;;; Generated autoloads from progmodes/cpp.el
@@ -5553,9 +5521,9 @@ This command pops up a buffer which you should edit to 
specify
 what kind of highlighting to use, and the criteria for highlighting.
 A prefix arg suppresses display of that buffer.
 
-(fn ARG)" t nil)
+(fn ARG)" t)
 (autoload 'cpp-parse-edit "cpp" "\
-Edit display information for cpp conditionals." t nil)
+Edit display information for cpp conditionals." t)
 (register-definition-prefixes "cpp" '("cpp-"))
 
 
@@ -5590,7 +5558,7 @@ contents of the minibuffer are \"alice,bob,eve\" and 
point is between
 This function returns a list of the strings that were read,
 with empty strings removed.
 
-(fn PROMPT TABLE &optional PREDICATE REQUIRE-MATCH INITIAL-INPUT HIST DEF 
INHERIT-INPUT-METHOD)" nil nil)
+(fn PROMPT TABLE &optional PREDICATE REQUIRE-MATCH INITIAL-INPUT HIST DEF 
INHERIT-INPUT-METHOD)")
 (register-definition-prefixes "crm" '("crm-"))
 
 
@@ -5622,12 +5590,12 @@ be used to fill comments.
 
 \\{css-mode-map}
 
-(fn)" t nil)
+(fn)" t)
  (add-to-list 'auto-mode-alist '("\\.scss\\'" . scss-mode))
 (autoload 'scss-mode "css-mode" "\
 Major mode to edit \"Sassy CSS\" files.
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'css-lookup-symbol "css-mode" "\
 Display the CSS documentation for SYMBOL, as found on MDN.
 When this command is used interactively, it picks a default
@@ -5635,7 +5603,7 @@ symbol based on the CSS text before point -- either an 
@-keyword,
 a property name, a pseudo-class, or a pseudo-element, depending
 on what is seen near point.
 
-(fn SYMBOL)" t nil)
+(fn SYMBOL)" t)
 (register-definition-prefixes "css-mode" '("css-" "scss-"))
 
 
@@ -5694,11 +5662,11 @@ evaluate `(default-value \\='cua-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'cua-selection-mode "cua-base" "\
 Enable CUA selection mode without the C-z/C-x/C-c/C-v bindings.
 
-(fn ARG)" t nil)
+(fn ARG)" t)
 (register-definition-prefixes "cua-base" '("cua-"))
 
 
@@ -5729,7 +5697,7 @@ evaluate `cua-rectangle-mark-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "cua-rect" '("cua-"))
 
 
@@ -5757,7 +5725,7 @@ evaluate `cursor-intangible-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'cursor-sensor-mode "cursor-sensor" "\
 Handle the `cursor-sensor-functions' text property.
 
@@ -5781,7 +5749,7 @@ evaluate `cursor-sensor-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "cursor-sensor" '("cursor-sensor-"))
 
 
@@ -5812,7 +5780,7 @@ If VARIABLE has a `custom-type' property, it must be a 
widget and the
 
 If given a prefix (or a COMMENT argument), also prompt for a comment.
 
-(fn VARIABLE VALUE &optional COMMENT)" t nil)
+(fn VARIABLE VALUE &optional COMMENT)" t)
 (autoload 'customize-set-variable "cus-edit" "\
 Set the default for VARIABLE to VALUE, and return VALUE.
 VALUE is a Lisp object.
@@ -5828,7 +5796,7 @@ If VARIABLE has a `custom-type' property, it must be a 
widget and the
 
 If given a prefix (or a COMMENT argument), also prompt for a comment.
 
-(fn VARIABLE VALUE &optional COMMENT)" t nil)
+(fn VARIABLE VALUE &optional COMMENT)" t)
 (autoload 'setopt "cus-edit" "\
 Set VARIABLE/VALUE pairs, and return the final VALUE.
 This is like `setq', but is meant for user options instead of
@@ -5839,7 +5807,7 @@ plain variables.  This means that `setopt' will execute 
any
 (autoload 'setopt--set "cus-edit" "\
 
 
-(fn VARIABLE VALUE)" nil nil)
+(fn VARIABLE VALUE)")
 (autoload 'customize-save-variable "cus-edit" "\
 Set the default for VARIABLE to VALUE, and save it for future sessions.
 Return VALUE.
@@ -5855,7 +5823,7 @@ If VARIABLE has a `custom-type' property, it must be a 
widget and the
 
 If given a prefix (or a COMMENT argument), also prompt for a comment.
 
-(fn VARIABLE VALUE &optional COMMENT)" t nil)
+(fn VARIABLE VALUE &optional COMMENT)" t)
 (autoload 'customize-push-and-save "cus-edit" "\
 Add ELTS to LIST-VAR and save for future sessions, safely.
 ELTS should be a list.  This function adds each entry to the
@@ -5865,39 +5833,39 @@ If Emacs is initialized, call `customize-save-variable' 
to save
 the resulting list value now.  Otherwise, add an entry to
 `after-init-hook' to save it after initialization.
 
-(fn LIST-VAR ELTS)" nil nil)
+(fn LIST-VAR ELTS)")
 (autoload 'customize "cus-edit" "\
 Select a customization buffer which you can use to set user options.
 User options are structured into \"groups\".
 Initially the top-level group `Emacs' and its immediate subgroups
-are shown; the contents of those subgroups are initially hidden." t nil)
+are shown; the contents of those subgroups are initially hidden." t)
 (autoload 'customize-mode "cus-edit" "\
 Customize options related to a major or minor mode.
 By default the current major mode is used.  With a prefix
 argument or if the current major mode has no known group, prompt
 for the MODE to customize.
 
-(fn MODE)" t nil)
+(fn MODE)" t)
 (autoload 'customize-group "cus-edit" "\
 Customize GROUP, which must be a customization group.
 If OTHER-WINDOW is non-nil, display in another window.
 
-(fn &optional GROUP OTHER-WINDOW)" t nil)
+(fn &optional GROUP OTHER-WINDOW)" t)
 (autoload 'customize-group-other-window "cus-edit" "\
 Customize GROUP, which must be a customization group, in another window.
 
-(fn &optional GROUP)" t nil)
+(fn &optional GROUP)" t)
 (defalias 'customize-variable 'customize-option)
 (autoload 'customize-option "cus-edit" "\
 Customize SYMBOL, which must be a user option.
 
-(fn SYMBOL)" t nil)
+(fn SYMBOL)" t)
 (defalias 'customize-variable-other-window 'customize-option-other-window)
 (autoload 'customize-option-other-window "cus-edit" "\
 Customize SYMBOL, which must be a user option.
 Show the buffer in another window, but don't select it.
 
-(fn SYMBOL)" t nil)
+(fn SYMBOL)" t)
 (defvar customize-package-emacs-version-alist nil "\
 Alist mapping versions of a package to Emacs versions.
 We use this for packages that have their own names, but are released
@@ -5928,8 +5896,7 @@ The value of PACKAGE needs to be unique and it needs to 
match the
 PACKAGE value appearing in the :package-version keyword.  Since
 the user might see the value in an error message, a good choice is
 the official name of the package, such as MH-E or Gnus.")
-(define-obsolete-function-alias 'customize-changed-options #'customize-changed 
"\
-28.1")
+(define-obsolete-function-alias 'customize-changed-options #'customize-changed 
"28.1")
 (autoload 'customize-changed "cus-edit" "\
 Customize all settings whose meanings have changed in Emacs itself.
 This includes new user options and faces, and new customization
@@ -5940,7 +5907,7 @@ release.
 With argument SINCE-VERSION (a string), customize all settings
 that were added or redefined since that version.
 
-(fn &optional SINCE-VERSION)" t nil)
+(fn &optional SINCE-VERSION)" t)
 (autoload 'customize-face "cus-edit" "\
 Customize FACE, which should be a face name or nil.
 If FACE is nil, customize all faces.  If FACE is actually a
@@ -5951,7 +5918,7 @@ If OTHER-WINDOW is non-nil, display in another window.
 Interactively, when point is on text which has a face specified,
 suggest to customize that face, if it's customizable.
 
-(fn &optional FACE OTHER-WINDOW)" t nil)
+(fn &optional FACE OTHER-WINDOW)" t)
 (autoload 'customize-face-other-window "cus-edit" "\
 Show customization buffer for face FACE in other window.
 If FACE is actually a face-alias, customize the face it is aliased to.
@@ -5959,13 +5926,13 @@ If FACE is actually a face-alias, customize the face it 
is aliased to.
 Interactively, when point is on text which has a face specified,
 suggest to customize that face, if it's customizable.
 
-(fn &optional FACE)" t nil)
+(fn &optional FACE)" t)
 (autoload 'customize-unsaved "cus-edit" "\
-Customize all options and faces set in this session but not saved." t nil)
+Customize all options and faces set in this session but not saved." t)
 (autoload 'customize-rogue "cus-edit" "\
-Customize all user variables modified outside customize." t nil)
+Customize all user variables modified outside customize." t)
 (autoload 'customize-saved "cus-edit" "\
-Customize all saved options and faces." t nil)
+Customize all saved options and faces." t)
 (autoload 'customize-apropos "cus-edit" "\
 Customize loaded options, faces and groups matching PATTERN.
 PATTERN can be a word, a list of words (separated by spaces),
@@ -5977,23 +5944,23 @@ If TYPE is `options', include only options.
 If TYPE is `faces', include only faces.
 If TYPE is `groups', include only groups.
 
-(fn PATTERN &optional TYPE)" t nil)
+(fn PATTERN &optional TYPE)" t)
 (autoload 'customize-apropos-options "cus-edit" "\
 Customize all loaded customizable options matching REGEXP.
 
-(fn REGEXP &optional IGNORED)" t nil)
+(fn REGEXP &optional IGNORED)" t)
 (autoload 'customize-apropos-faces "cus-edit" "\
 Customize all loaded faces matching REGEXP.
 
-(fn REGEXP)" t nil)
+(fn REGEXP)" t)
 (autoload 'customize-apropos-groups "cus-edit" "\
 Customize all loaded groups matching REGEXP.
 
-(fn REGEXP)" t nil)
+(fn REGEXP)" t)
 (autoload 'custom-prompt-customize-unsaved-options "cus-edit" "\
 Prompt user to customize any unsaved customization options.
 Return nil if user chooses to customize, for use in
-`kill-emacs-query-functions'." nil nil)
+`kill-emacs-query-functions'.")
 (autoload 'custom-buffer-create "cus-edit" "\
 Create a buffer containing OPTIONS.
 Optional NAME is the name of the buffer.
@@ -6002,7 +5969,7 @@ SYMBOL is a customization option, and WIDGET is a widget 
for editing
 that option.
 DESCRIPTION is unused.
 
-(fn OPTIONS &optional NAME DESCRIPTION)" nil nil)
+(fn OPTIONS &optional NAME DESCRIPTION)")
 (autoload 'custom-buffer-create-other-window "cus-edit" "\
 Create a buffer containing OPTIONS, and display it in another window.
 The result includes selecting that window.
@@ -6012,11 +5979,11 @@ SYMBOL is a customization option, and WIDGET is a 
widget for editing
 that option.
 DESCRIPTION is unused.
 
-(fn OPTIONS &optional NAME DESCRIPTION)" nil nil)
+(fn OPTIONS &optional NAME DESCRIPTION)")
 (autoload 'customize-browse "cus-edit" "\
 Create a tree browser for the customize hierarchy.
 
-(fn &optional GROUP)" t nil)
+(fn &optional GROUP)" t)
 (defvar custom-file nil "\
 File used for storing customization information.
 The default is nil, which means to use your init file
@@ -6051,21 +6018,37 @@ file.  Otherwise, Emacs will not load the file when it 
starts up,
 and hence will not set `custom-file' to that file either.")
 (custom-autoload 'custom-file "cus-edit" t)
 (autoload 'custom-save-all "cus-edit" "\
-Save all customizations in `custom-file'." nil nil)
+Save all customizations in `custom-file'.")
 (autoload 'customize-save-customized "cus-edit" "\
-Save all user options which have been set in this session." t nil)
+Save all user options which have been set in this session." t)
 (autoload 'custom-menu-create "cus-edit" "\
 Create menu for customization group SYMBOL.
 The menu is in a format applicable to `easy-menu-define'.
 
-(fn SYMBOL)" nil nil)
+(fn SYMBOL)")
 (autoload 'customize-menu-create "cus-edit" "\
 Return a customize menu for customization group SYMBOL.
 If optional NAME is given, use that as the name of the menu.
 Otherwise the menu will be named `Customize'.
 The format is suitable for use with `easy-menu-define'.
 
-(fn SYMBOL &optional NAME)" nil nil)
+(fn SYMBOL &optional NAME)")
+(autoload 'customize-icon "cus-edit" "\
+Customize ICON.
+
+(fn ICON)" t)
+(autoload 'custom-set-icons "cus-edit" "\
+Install user customizations of icon specs specified in ARGS.
+These settings are registered as theme `user'.
+The arguments should each be a list of the form:
+
+  (SYMBOL EXP)
+
+This stores EXP (without evaluating it) as the saved spec for SYMBOL.
+
+(fn &rest ARGS)")
+(autoload 'custom-save-icons "cus-edit" "\
+Save all customized icons in `custom-file'.")
 (register-definition-prefixes "cus-edit" '("Custom-" "cus" "widget-"))
 
 
@@ -6080,27 +6063,27 @@ from the Custom save file.
 BUFFER, if non-nil, should be a buffer to use; the default is
 named *Custom Theme*.
 
-(fn &optional THEME BUFFER)" t nil)
+(fn &optional THEME BUFFER)" t)
 (autoload 'custom-theme-visit-theme "cus-theme" "\
 Set up a Custom buffer to edit custom theme THEME.
 
-(fn THEME)" t nil)
+(fn THEME)" t)
 (autoload 'describe-theme "cus-theme" "\
 Display a description of the Custom theme THEME (a symbol).
 
-(fn THEME)" t nil)
+(fn THEME)" t)
 (autoload 'customize-themes "cus-theme" "\
 Display a selectable list of Custom themes.
 When called from Lisp, BUFFER should be the buffer to use; if
 omitted, a buffer named *Custom Themes* is used.
 
-(fn &optional BUFFER)" t nil)
+(fn &optional BUFFER)" t)
 (register-definition-prefixes "cus-theme" '("custom-" "describe-theme-1"))
 
 
 ;;; Generated autoloads from cedet/ede/custom.el
 
-(register-definition-prefixes "ede/custom" '("ede-" "eieio-ede-old-variables"))
+(register-definition-prefixes "ede/custom" '("ede-"))
 
 
 ;;; Generated autoloads from vc/cvs-status.el
@@ -6108,7 +6091,7 @@ omitted, a buffer named *Custom Themes* is used.
 (autoload 'cvs-status-mode "cvs-status" "\
 Mode used for cvs status output.
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "cvs-status" '("cvs-"))
 
 
@@ -6137,9 +6120,7 @@ evaluate `cwarn-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
-(define-obsolete-function-alias 'turn-on-cwarn-mode 'cwarn-mode "\
-24.1")
+(fn &optional ARG)" t)
 (put 'global-cwarn-mode 'globalized-minor-mode t)
 (defvar global-cwarn-mode nil "\
 Non-nil if Global Cwarn mode is enabled.
@@ -6163,7 +6144,7 @@ Cwarn mode is enabled in all buffers where
 
 See `cwarn-mode' for more information on Cwarn mode.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "cwarn" '("cwarn-" 
"turn-on-cwarn-mode-if-enabled"))
 
 
@@ -6172,11 +6153,11 @@ See `cwarn-mode' for more information on Cwarn mode.
 (autoload 'cyrillic-encode-koi8-r-char "cyril-util" "\
 Return KOI8-R external character code of CHAR if appropriate.
 
-(fn CHAR)" nil nil)
+(fn CHAR)")
 (autoload 'cyrillic-encode-alternativnyj-char "cyril-util" "\
 Return ALTERNATIVNYJ external character code of CHAR if appropriate.
 
-(fn CHAR)" nil nil)
+(fn CHAR)")
 (autoload 'standard-display-cyrillic-translit "cyril-util" "\
 Display a Cyrillic buffer using a transliteration.
 For readability, the table is slightly
@@ -6188,7 +6169,7 @@ Possible values are listed in `cyrillic-language-alist'.
 If the argument is t, we use the default cyrillic transliteration.
 If the argument is nil, we return the display table to its standard state.
 
-(fn &optional CYRILLIC-LANGUAGE)" t nil)
+(fn &optional CYRILLIC-LANGUAGE)" t)
 (register-definition-prefixes "cyril-util" '("cyrillic-language-alist"))
 
 
@@ -6210,7 +6191,7 @@ completions.
 If the prefix argument is 16 (which comes from \\[universal-argument] 
\\[universal-argument]),
 then it searches *all* buffers.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'dabbrev-expand "dabbrev" "\
 Expand previous word \"dynamically\".
 
@@ -6235,7 +6216,7 @@ direction of search to backward if set non-nil.
 
 See also `dabbrev-abbrev-char-regexp' and \\[dabbrev-completion].
 
-(fn ARG)" t nil)
+(fn ARG)" t)
 (register-definition-prefixes "dabbrev" '("dabbrev-"))
 
 
@@ -6244,7 +6225,7 @@ See also `dabbrev-abbrev-char-regexp' and 
\\[dabbrev-completion].
 (autoload 'data-debug-new-buffer "data-debug" "\
 Create a new data-debug buffer with NAME.
 
-(fn NAME)" nil nil)
+(fn NAME)")
 (register-definition-prefixes "data-debug" '("data-debug-"))
 
 
@@ -6260,12 +6241,12 @@ Create a new data-debug buffer with NAME.
 
 ;;; Generated autoloads from cedet/semantic/db-ebrowse.el
 
-(register-definition-prefixes "semantic/db-ebrowse" '("c++-mode" 
"semanticdb-"))
+(register-definition-prefixes "semantic/db-ebrowse" '("semanticdb-"))
 
 
 ;;; Generated autoloads from cedet/semantic/db-el.el
 
-(register-definition-prefixes "semantic/db-el" '("emacs-lisp-mode" 
"semanticdb-"))
+(register-definition-prefixes "semantic/db-el" '("semanticdb-"))
 
 
 ;;; Generated autoloads from cedet/semantic/db-file.el
@@ -6285,7 +6266,7 @@ Create a new data-debug buffer with NAME.
 
 ;;; Generated autoloads from cedet/semantic/db-javascript.el
 
-(register-definition-prefixes "semantic/db-javascript" '("javascript-mode" 
"semanticdb-"))
+(register-definition-prefixes "semantic/db-javascript" '("semanticdb-"))
 
 
 ;;; Generated autoloads from cedet/semantic/db-mode.el
@@ -6311,14 +6292,14 @@ EVENT is a D-Bus event, see `dbus-check-event'.  
HANDLER, being
 part of the event, is called with arguments ARGS (without type information).
 If the HANDLER returns a `dbus-error', it is propagated as return message.
 
-(fn EVENT)" t nil)
+(fn EVENT)" t)
 (function-put 'dbus-handle-event 'completion-predicate #'ignore)
 (autoload 'dbus-monitor "dbus" "\
 Invoke `dbus-register-monitor' interactively, and switch to the buffer.
 BUS is either a Lisp keyword, `:system' or `:session', or a
 string denoting the bus address.  The value nil defaults to `:session'.
 
-(fn &optional BUS)" t nil)
+(fn &optional BUS)" t)
 (register-definition-prefixes "dbus" '("dbus-"))
 
 
@@ -6442,7 +6423,7 @@ $
 There is some minimal font-lock support (see vars
 `dcl-font-lock-defaults' and `dcl-font-lock-keywords').
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "dcl-mode" '("dcl-"))
 
 
@@ -6461,7 +6442,7 @@ first will be printed into the backtrace buffer.
 If `inhibit-redisplay' is non-nil when this function is called,
 the debugger will not be entered.
 
-(fn &rest ARGS)" t nil)
+(fn &rest ARGS)" t)
 (autoload 'debug-on-entry "debug" "\
 Request FUNCTION to invoke debugger each time it is called.
 
@@ -6477,14 +6458,14 @@ primitive functions only works when that function is 
called from Lisp.
 Use \\[cancel-debug-on-entry] to cancel the effect of this command.
 Redefining FUNCTION also cancels it.
 
-(fn FUNCTION)" t nil)
+(fn FUNCTION)" t)
 (autoload 'cancel-debug-on-entry "debug" "\
 Undo effect of \\[debug-on-entry] on FUNCTION.
 If FUNCTION is nil, cancel `debug-on-entry' for all functions.
 When called interactively, prompt for FUNCTION in the minibuffer.
 To specify a nil argument interactively, exit with an empty minibuffer.
 
-(fn &optional FUNCTION)" t nil)
+(fn &optional FUNCTION)" t)
 (autoload 'debug-on-variable-change "debug" "\
 Trigger a debugger invocation when VARIABLE is changed.
 
@@ -6503,7 +6484,7 @@ Use \\[cancel-debug-on-variable-change] to cancel the 
effect of
 this command.  Uninterning VARIABLE or making it an alias of
 another symbol also cancels it.
 
-(fn VARIABLE)" t nil)
+(fn VARIABLE)" t)
 (defalias 'debug-watch #'debug-on-variable-change)
 (autoload 'cancel-debug-on-variable-change "debug" "\
 Undo effect of \\[debug-on-variable-change] on VARIABLE.
@@ -6511,7 +6492,7 @@ If VARIABLE is nil, cancel `debug-on-variable-change' for 
all variables.
 When called interactively, prompt for VARIABLE in the minibuffer.
 To specify a nil argument interactively, exit with an empty minibuffer.
 
-(fn &optional VARIABLE)" t nil)
+(fn &optional VARIABLE)" t)
 (defalias 'cancel-debug-watch #'cancel-debug-on-variable-change)
 (register-definition-prefixes "debug" '("debug" "inhibit-debug-on-entry"))
 
@@ -6534,7 +6515,7 @@ To specify a nil argument interactively, exit with an 
empty minibuffer.
 ;;; Generated autoloads from play/decipher.el
 
 (autoload 'decipher "decipher" "\
-Format a buffer of ciphertext for cryptanalysis and enter Decipher mode." t 
nil)
+Format a buffer of ciphertext for cryptanalysis and enter Decipher mode." t)
 (autoload 'decipher-mode "decipher" "\
 Major mode for decrypting monoalphabetic substitution ciphers.
 Lower-case letters enter plaintext.
@@ -6551,7 +6532,7 @@ The most useful commands are:
 \\[decipher-make-checkpoint]  Save the current cipher alphabet (checkpoint)
 \\[decipher-restore-checkpoint]  Restore a saved cipher alphabet (checkpoint)
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "decipher" '("decipher-"))
 
 
@@ -6563,7 +6544,7 @@ The most useful commands are:
 ;;; Generated autoloads from delim-col.el
 
 (autoload 'delimit-columns-customize "delim-col" "\
-Customize the `columns' group." t nil)
+Customize the `columns' group." t)
 (autoload 'delimit-columns-region "delim-col" "\
 Prettify all columns in a text region.
 
@@ -6587,7 +6568,7 @@ See the `delimit-columns-str-before',
 `delimit-columns-extra' variables for customization of the
 look.
 
-(fn START END)" t nil)
+(fn START END)" t)
 (autoload 'delimit-columns-rectangle "delim-col" "\
 Prettify all columns in a text rectangle.
 
@@ -6595,7 +6576,7 @@ See `delimit-columns-region' for what this entails.
 
 START and END delimit the corners of the text rectangle.
 
-(fn START END)" t nil)
+(fn START END)" t)
 (register-definition-prefixes "delim-col" '("delimit-columns-"))
 
 
@@ -6635,13 +6616,13 @@ evaluate `(default-value \\='delete-selection-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'delete-active-region "delsel" "\
 Delete the active region.
 If KILLP is non-nil, or if called interactively with a prefix argument,
 the active region is killed instead of deleted.
 
-(fn &optional KILLP)" t nil)
+(fn &optional KILLP)" t)
 (register-definition-prefixes "delsel" '("del" "minibuffer-keyboard-quit"))
 
 
@@ -6712,7 +6693,7 @@ the hook will be named `foo-mode-hook'.
 See Info node `(elisp)Derived Modes' for more details.
 
 (fn CHILD PARENT NAME [DOCSTRING] [KEYWORD-ARGS...] &rest BODY)" nil t)
-(function-put 'define-derived-mode 'doc-string-elt '4)
+(function-put 'define-derived-mode 'doc-string-elt 4)
 (function-put 'define-derived-mode 'lisp-indent-function 'defun)
 (autoload 'derived-mode-init-mode-variables "derived" "\
 Initialize variables for a new MODE.
@@ -6720,7 +6701,7 @@ Right now, if they don't already exist, set up a blank 
keymap, an
 empty syntax table, and an empty abbrev table -- these will be merged
 the first time the mode is used.
 
-(fn MODE)" nil nil)
+(fn MODE)")
 (register-definition-prefixes "derived" '("derived-mode-"))
 
 
@@ -6734,7 +6715,7 @@ If optional second argument OUTPUT-BUFFER is non-nil,
 insert the output into that buffer, and don't initialize or clear it
 otherwise.
 
-(fn POS &optional OUTPUT-BUFFER BUFFER)" t nil)
+(fn POS &optional OUTPUT-BUFFER BUFFER)" t)
 (autoload 'describe-char "descr-text" "\
 Describe position POS (interactively, point) and the char after POS.
 POS is taken to be in BUFFER, or the current buffer if BUFFER is nil.
@@ -6761,7 +6742,7 @@ The character information includes:
    Unicode Data Base;
  and widgets, buttons, overlays, and text properties relevant to POS.
 
-(fn POS &optional BUFFER)" t nil)
+(fn POS &optional BUFFER)" t)
 (autoload 'describe-char-eldoc "descr-text" "\
 Return a description of character at point for use by ElDoc mode.
 
@@ -6775,7 +6756,7 @@ minibuffer window for width limit.
 This function can be used as a value of
 `eldoc-documentation-functions' variable.
 
-(fn CALLBACK &rest _)" nil nil)
+(fn CALLBACK &rest _)")
 (register-definition-prefixes "descr-text" '("describe-"))
 
 
@@ -6821,7 +6802,7 @@ evaluate `(default-value \\='desktop-save-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (defvar desktop-locals-to-save '(desktop-locals-to-save truncate-lines 
case-fold-search case-replace fill-column overwrite-mode 
change-log-default-name line-number-mode column-number-mode 
size-indication-mode buffer-file-coding-system buffer-display-time 
indent-tabs-mode tab-width indicate-buffer-boundaries indicate-empty-lines 
show-trailing-whitespace) "\
 List of local variables to save for each buffer.
 The variables are saved only when they really are local.  Conventional minor
@@ -6930,7 +6911,7 @@ a regular expression in the list 
`desktop-clear-preserve-buffers'.
 Furthermore, it clears the variables listed in `desktop-globals-to-clear'.
 When called interactively and `desktop-restore-frames' is non-nil, it also
 deletes all frames except the selected one (and its minibuffer frame,
-if different)." t nil)
+if different)." t)
 (autoload 'desktop-save "desktop" "\
 Save the state of Emacs in a desktop file in directory DIRNAME.
 Optional argument RELEASE non-nil says we're done with this
@@ -6966,10 +6947,10 @@ In a non-interactive call, VERSION can be given as an 
integer, either
 206 or 208, to specify the format version in which to save the file,
 no questions asked.
 
-(fn DIRNAME &optional RELEASE ONLY-IF-CHANGED VERSION)" t nil)
+(fn DIRNAME &optional RELEASE ONLY-IF-CHANGED VERSION)" t)
 (autoload 'desktop-remove "desktop" "\
 Delete desktop file in `desktop-dirname'.
-This function also sets `desktop-dirname' to nil." t nil)
+This function also sets `desktop-dirname' to nil." t)
 (autoload 'desktop-read "desktop" "\
 Read and process the desktop file in directory DIRNAME.
 Look for a desktop file in DIRNAME, or if DIRNAME is omitted, look in
@@ -6980,18 +6961,18 @@ Interactively, with prefix arg \\[universal-argument], 
ask for DIRNAME.
 This function is a no-op when Emacs is running in batch mode.
 It returns t if a desktop file was loaded, nil otherwise.
 
-(fn DIRNAME)" t nil)
+(fn DIRNAME)" t)
 (autoload 'desktop-change-dir "desktop" "\
 Change to desktop saved in DIRNAME.
 Kill the desktop as specified by variables `desktop-save-mode' and
 `desktop-save', then clear the desktop and load the desktop file in
 directory DIRNAME.
 
-(fn DIRNAME)" t nil)
+(fn DIRNAME)" t)
 (autoload 'desktop-save-in-desktop-dir "desktop" "\
-Save the desktop in directory `desktop-dirname'." t nil)
+Save the desktop in directory `desktop-dirname'." t)
 (autoload 'desktop-revert "desktop" "\
-Revert to the last loaded desktop." t nil)
+Revert to the last loaded desktop." t)
 (register-definition-prefixes "desktop" '("desktop-"))
 
 
@@ -7009,26 +6990,26 @@ You can control what lines will be unwrapped by frobbing
 indicating the minimum and maximum length of an unwrapped citation line.  If
 NODISPLAY is non-nil, don't redisplay the article buffer.
 
-(fn &optional NODISPLAY)" '(gnus-article-mode gnus-summary-mode) nil)
+(fn &optional NODISPLAY)" '(gnus-article-mode gnus-summary-mode))
 (autoload 'gnus-article-outlook-repair-attribution "deuglify" "\
 Repair a broken attribution line.
 If NODISPLAY is non-nil, don't redisplay the article buffer.
 
-(fn &optional NODISPLAY)" '(gnus-article-mode gnus-summary-mode) nil)
+(fn &optional NODISPLAY)" '(gnus-article-mode gnus-summary-mode))
 (autoload 'gnus-article-outlook-rearrange-citation "deuglify" "\
 Repair broken citations.
 If NODISPLAY is non-nil, don't redisplay the article buffer.
 
-(fn &optional NODISPLAY)" '(gnus-article-mode gnus-summary-mode) nil)
+(fn &optional NODISPLAY)" '(gnus-article-mode gnus-summary-mode))
 (autoload 'gnus-outlook-deuglify-article "deuglify" "\
 Full deuglify of broken Outlook (Express) articles.
 Treat \"smartquotes\", unwrap lines, repair attribution and
 rearrange citation.  If NODISPLAY is non-nil, don't redisplay the
 article buffer.
 
-(fn &optional NODISPLAY)" '(gnus-article-mode gnus-summary-mode) nil)
+(fn &optional NODISPLAY)" '(gnus-article-mode gnus-summary-mode))
 (autoload 'gnus-article-outlook-deuglify-article "deuglify" "\
-Deuglify broken Outlook (Express) articles and redisplay." '(gnus-article-mode 
gnus-summary-mode) nil)
+Deuglify broken Outlook (Express) articles and redisplay." '(gnus-article-mode 
gnus-summary-mode))
 (register-definition-prefixes "deuglify" '("gnus-outlook-"))
 
 
@@ -7045,7 +7026,7 @@ If no argument is provided, the number of days of diary 
entries is governed
 by the variable `diary-number-of-entries'.  A value of ARG less than 1
 does nothing.  This function is suitable for execution in an init file.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'diary-mail-entries "diary-lib" "\
 Send a mail message showing diary entries for next NDAYS days.
 If no prefix argument is given, NDAYS is set to `diary-mail-days'.
@@ -7068,11 +7049,11 @@ ensure that all relevant variables are set.
 
 # diary-rem.el ends here
 
-(fn &optional NDAYS)" t nil)
+(fn &optional NDAYS)" t)
 (autoload 'diary-mode "diary-lib" "\
 Major mode for editing the diary file.
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "diary-lib" '("calendar-mark-" "diary-"))
 
 
@@ -7086,7 +7067,7 @@ protocol defined in RFC 2229.
 This is a quick reference to this mode describing the default key bindings:
 \\<dictionary-mode-map>
 * \\[dictionary-close] close the dictionary buffer
-* \\[dictionary-help] display this help information
+* \\[describe-mode] display this help information
 * \\[dictionary-search] ask for a new word to search
 * \\[dictionary-lookup-definition] search the word at point
 * \\[forward-button] or TAB place point to the next link
@@ -7096,29 +7077,29 @@ This is a quick reference to this mode describing the 
default key bindings:
 * \\[dictionary-select-dictionary] select the default dictionary
 * \\[dictionary-select-strategy] select the default search strategy
 
-* RET or <mouse-2> visit that link" nil nil)
+* \\`RET' or \\`<mouse-2>' visit that link")
 (autoload 'dictionary "dictionary" "\
-Create a new dictionary buffer and install `dictionary-mode'." t nil)
+Create a new dictionary buffer and install `dictionary-mode'." t)
 (autoload 'dictionary-search "dictionary" "\
 Search the WORD in DICTIONARY if given or in all if nil.
 It presents the selection or word at point as default input and
 allows editing it.
 
-(fn WORD &optional DICTIONARY)" t nil)
+(fn WORD &optional DICTIONARY)" t)
 (autoload 'dictionary-lookup-definition "dictionary" "\
-Unconditionally lookup the word at point." t nil)
+Unconditionally lookup the word at point." t)
 (autoload 'dictionary-match-words "dictionary" "\
 Search PATTERN in current default dictionary using default strategy.
 
-(fn &optional PATTERN &rest IGNORED)" t nil)
+(fn &optional PATTERN &rest IGNORED)" t)
 (autoload 'dictionary-mouse-popup-matching-words "dictionary" "\
 Display entries matching the word at the cursor retrieved using EVENT.
 
-(fn EVENT)" t nil)
+(fn EVENT)" t)
 (autoload 'dictionary-popup-matching-words "dictionary" "\
 Display entries matching WORD or the current word if not given.
 
-(fn &optional WORD)" t nil)
+(fn &optional WORD)" t)
 (autoload 'dictionary-tooltip-mode "dictionary" "\
 Display tooltips for the current word.
 
@@ -7126,7 +7107,7 @@ This function can be used to enable or disable the 
tooltip mode
 for the current buffer (based on ARG).  If global-tooltip-mode is
 active it will overwrite that mode for the current buffer.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'global-dictionary-tooltip-mode "dictionary" "\
 Enable/disable `dictionary-tooltip-mode' for all buffers.
 
@@ -7136,14 +7117,14 @@ It can be overwritten for each buffer using 
`dictionary-tooltip-mode'.
 Note: (global-dictionary-tooltip-mode 0) will not disable the mode
 any buffer where (dictionary-tooltip-mode 1) has been called.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'dictionary-context-menu "dictionary" "\
 Populate MENU with dictionary commands at CLICK.
 When you add this function to `context-menu-functions',
 the context menu will contain an item that searches
 the word at mouse click.
 
-(fn MENU CLICK)" nil nil)
+(fn MENU CLICK)")
 (register-definition-prefixes "dictionary" '("dictionary-" 
"global-dictionary-tooltip-mode"))
 
 
@@ -7184,7 +7165,7 @@ command.
 
 Non-interactively, OLD and NEW may each be a file or a buffer.
 
-(fn OLD NEW &optional SWITCHES NO-ASYNC)" t nil)
+(fn OLD NEW &optional SWITCHES NO-ASYNC)" t)
 (autoload 'diff-backup "diff" "\
 Diff this file with its backup file or vice versa.
 Uses the latest backup, if there are several numerical backups.
@@ -7192,16 +7173,16 @@ If this file is a backup, diff it with its original.
 The backup file is the first file given to `diff'.
 With prefix arg SWITCHES, prompt for diff switches.
 
-(fn FILE &optional SWITCHES)" t nil)
+(fn FILE &optional SWITCHES)" t)
 (autoload 'diff-latest-backup-file "diff" "\
 Return the latest existing backup of file FN, or nil.
 
-(fn FN)" nil nil)
+(fn FN)")
 (autoload 'diff-buffer-with-file "diff" "\
 View the differences between BUFFER and its associated file.
 This requires the external program `diff' to be in your `exec-path'.
 
-(fn &optional BUFFER)" t nil)
+(fn &optional BUFFER)" t)
 (autoload 'diff-buffers "diff" "\
 Find and display the differences between OLD and NEW buffers.
 
@@ -7219,7 +7200,7 @@ OLD and NEW may each be a buffer or a buffer name.
 
 Also see the `diff-entire-buffers' variable.
 
-(fn OLD NEW &optional SWITCHES NO-ASYNC)" t nil)
+(fn OLD NEW &optional SWITCHES NO-ASYNC)" t)
 (register-definition-prefixes "diff" '("diff-"))
 
 
@@ -7240,7 +7221,7 @@ a diff with \\[diff-reverse-direction].
 
 \\{diff-mode-map}
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'diff-minor-mode "diff-mode" "\
 Toggle Diff minor mode.
 
@@ -7260,7 +7241,7 @@ evaluate `diff-minor-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "diff-mode" '("diff-"))
 
 
@@ -7269,11 +7250,14 @@ it is disabled.
 (autoload 'dig "dig" "\
 Query addresses of a DOMAIN using dig.
 See `dig-invoke' for an explanation for the parameters.
-When called interactively, DOMAIN is prompted for.  If given a prefix,
-also prompt for the QUERY-TYPE parameter.
+When called interactively, DOMAIN is prompted for.
+
+If given a \\[universal-argument] prefix, also prompt for the QUERY-TYPE 
parameter.
+
+If given a \\[universal-argument] \\[universal-argument] prefix, also prompt 
for the SERVER parameter.
 
-(fn DOMAIN &optional QUERY-TYPE QUERY-CLASS QUERY-OPTION DIG-OPTION SERVER)" t 
nil)
-(register-definition-prefixes "dig" '("dig-" "query-dig"))
+(fn DOMAIN &optional QUERY-TYPE QUERY-CLASS QUERY-OPTION DIG-OPTION SERVER)" t)
+(register-definition-prefixes "dig" '("dig-"))
 
 
 ;;; Generated autoloads from cedet/ede/dired.el
@@ -7330,26 +7314,26 @@ Type \\[describe-mode] after entering Dired for more 
info.
 
 If DIRNAME is already in a Dired buffer, that buffer is used without refresh.
 
-(fn DIRNAME &optional SWITCHES)" t nil)
+(fn DIRNAME &optional SWITCHES)" t)
  (define-key ctl-x-4-map "d" 'dired-other-window)
 (autoload 'dired-other-window "dired" "\
 \"Edit\" directory DIRNAME.  Like `dired' but select in another window.
 
-(fn DIRNAME &optional SWITCHES)" t nil)
+(fn DIRNAME &optional SWITCHES)" t)
  (define-key ctl-x-5-map "d" 'dired-other-frame)
 (autoload 'dired-other-frame "dired" "\
 \"Edit\" directory DIRNAME.  Like `dired' but make a new frame.
 
-(fn DIRNAME &optional SWITCHES)" t nil)
+(fn DIRNAME &optional SWITCHES)" t)
  (define-key tab-prefix-map "d" 'dired-other-tab)
 (autoload 'dired-other-tab "dired" "\
 \"Edit\" directory DIRNAME.  Like `dired' but make a new tab.
 
-(fn DIRNAME &optional SWITCHES)" t nil)
+(fn DIRNAME &optional SWITCHES)" t)
 (autoload 'dired-noselect "dired" "\
 Like `dired' but return the Dired buffer as value, do not select it.
 
-(fn DIR-OR-LIST &optional SWITCHES)" nil nil)
+(fn DIR-OR-LIST &optional SWITCHES)")
 (autoload 'dired-mode "dired" "\
 Mode for \"editing\" directory listings.
 In Dired, you are \"editing\" a list of the files in a directory and
@@ -7382,7 +7366,7 @@ Type \\[dired-do-copy] to Copy files.
 Type \\[dired-sort-toggle-or-edit] to toggle Sorting by name/date or change 
the `ls' switches.
 Type \\[revert-buffer] to read all currently expanded directories aGain.
   This retains all marks and hides subdirs again that were hidden before.
-Use `SPC' and `DEL' to move down and up by lines.
+Use \\`SPC' and \\`DEL' to move down and up by lines.
 
 If Dired ever gets confused, you can either type \\[revert-buffer] to read the
 directories again, type \\[dired-do-redisplay] to relist the file at point or 
the marked files or a
@@ -7400,7 +7384,7 @@ This mode runs the following hooks:
 Keybindings:
 \\{dired-mode-map}
 
-(fn &optional DIRNAME SWITCHES)" nil nil)
+(fn &optional DIRNAME SWITCHES)")
  (put 'dired-find-alternate-file 'disabled t)
 (autoload 'dired-jump "dired" "\
 Jump to Dired buffer corresponding to current buffer.
@@ -7418,17 +7402,17 @@ When OTHER-WINDOW is non-nil, jump to Dired buffer in 
other window.
 When FILE-NAME is non-nil, jump to its line in Dired.
 Interactively with prefix argument, read FILE-NAME.
 
-(fn &optional OTHER-WINDOW FILE-NAME)" t nil)
+(fn &optional OTHER-WINDOW FILE-NAME)" t)
 (autoload 'dired-jump-other-window "dired" "\
 Like \\[dired-jump] (`dired-jump') but in other window.
 
-(fn &optional FILE-NAME)" t nil)
+(fn &optional FILE-NAME)" t)
 (register-definition-prefixes "dired" '("dired-"))
 
 
 ;;; Generated autoloads from dired-aux.el
 
-(register-definition-prefixes "dired-aux" '("dired-" 
"minibuffer-default-add-dired-shell-commands"))
+(register-definition-prefixes "dired-aux" '("dired-"))
 
 
 ;;; Generated autoloads from dired-x.el
@@ -7463,7 +7447,7 @@ evaluate `dirtrack-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'dirtrack "dirtrack" "\
 Determine the current directory from the process output for a prompt.
 This filter function is used by `dirtrack-mode'.  It looks for
@@ -7471,7 +7455,7 @@ the prompt specified by `dirtrack-list', and calls
 `shell-process-cd' if the directory seems to have changed away
 from `default-directory'.
 
-(fn INPUT)" nil nil)
+(fn INPUT)")
 (register-definition-prefixes "dirtrack" '("dirtrack-"))
 
 
@@ -7484,34 +7468,34 @@ OBJECT can be a symbol defined as a function, or a 
function itself
 If OBJECT is not already compiled, we compile it, but do not
 redefine OBJECT if it is a symbol.
 
-(fn OBJECT &optional BUFFER INDENT INTERACTIVE-P)" t nil)
+(fn OBJECT &optional BUFFER INDENT INTERACTIVE-P)" t)
 (register-definition-prefixes "disass" '("disassemble-"))
 
 
 ;;; Generated autoloads from disp-table.el
 
 (autoload 'make-display-table "disp-table" "\
-Return a new, empty display table." nil nil)
+Return a new, empty display table.")
 (autoload 'display-table-slot "disp-table" "\
 Return the value of the extra slot in DISPLAY-TABLE named SLOT.
 SLOT may be a number from 0 to 5 inclusive, or a slot name (symbol).
 Valid symbols are `truncation', `wrap', `escape', `control',
 `selective-display', and `vertical-border'.
 
-(fn DISPLAY-TABLE SLOT)" nil nil)
+(fn DISPLAY-TABLE SLOT)")
 (autoload 'set-display-table-slot "disp-table" "\
 Set the value of the extra slot in DISPLAY-TABLE named SLOT to VALUE.
 SLOT may be a number from 0 to 5 inclusive, or a name (symbol).
 Valid symbols are `truncation', `wrap', `escape', `control',
 `selective-display', and `vertical-border'.
 
-(fn DISPLAY-TABLE SLOT VALUE)" nil nil)
+(fn DISPLAY-TABLE SLOT VALUE)")
 (autoload 'describe-display-table "disp-table" "\
 Describe the display table DT in a help buffer.
 
-(fn DT)" nil nil)
+(fn DT)")
 (autoload 'describe-current-display-table "disp-table" "\
-Describe the display table in use in the selected window and buffer." t nil)
+Describe the display table in use in the selected window and buffer." t)
 (autoload 'standard-display-8bit "disp-table" "\
 Display characters representing raw bytes in the range L to H literally.
 
@@ -7525,47 +7509,47 @@ byte.
 Note that ASCII printable characters (SPC to TILDA) are displayed
 in the default way after this call.
 
-(fn L H)" nil nil)
+(fn L H)")
 (autoload 'standard-display-default "disp-table" "\
 Display characters in the range L to H using the default notation.
 
-(fn L H)" nil nil)
+(fn L H)")
 (autoload 'standard-display-ascii "disp-table" "\
 Display character C using printable string S.
 
-(fn C S)" nil nil)
+(fn C S)")
 (autoload 'standard-display-g1 "disp-table" "\
 Display character C as character SC in the g1 character set.
 This function assumes that your terminal uses the SO/SI characters;
 it is meaningless for a graphical frame.
 
-(fn C SC)" nil nil)
+(fn C SC)")
 (autoload 'standard-display-graphic "disp-table" "\
 Display character C as character GC in graphics character set.
 This function assumes VT100-compatible escapes; it is meaningless
 for a graphical frame.
 
-(fn C GC)" nil nil)
+(fn C GC)")
 (autoload 'standard-display-underline "disp-table" "\
 Display character C as character UC plus underlining.
 
-(fn C UC)" nil nil)
+(fn C UC)")
 (autoload 'create-glyph "disp-table" "\
 Allocate a glyph code to display by sending STRING to the terminal.
 
-(fn STRING)" nil nil)
+(fn STRING)")
 (autoload 'make-glyph-code "disp-table" "\
 Return a glyph code representing char CHAR with face FACE.
 
-(fn CHAR &optional FACE)" nil nil)
+(fn CHAR &optional FACE)")
 (autoload 'glyph-char "disp-table" "\
 Return the character of glyph code GLYPH.
 
-(fn GLYPH)" nil nil)
+(fn GLYPH)")
 (autoload 'glyph-face "disp-table" "\
 Return the face of glyph code GLYPH, or nil if glyph has default face.
 
-(fn GLYPH)" nil nil)
+(fn GLYPH)")
 (autoload 'standard-display-european "disp-table" "\
 Semi-obsolete way to toggle display of ISO 8859 European characters.
 
@@ -7585,7 +7569,7 @@ from Lisp code also selects Latin-1 as the language 
environment.
 This provides increased compatibility for users who call this function
 in `.emacs'.
 
-(fn ARG)" nil nil)
+(fn ARG)")
 (register-definition-prefixes "disp-table" '("display-table-print-array"))
 
 
@@ -7618,7 +7602,7 @@ evaluate `display-fill-column-indicator-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (put 'global-display-fill-column-indicator-mode 'globalized-minor-mode t)
 (defvar global-display-fill-column-indicator-mode nil "\
 Non-nil if Global Display-Fill-Column-Indicator mode is enabled.
@@ -7646,7 +7630,7 @@ Display-Fill-Column-Indicator mode.
 `global-display-fill-column-indicator-modes' is used to control which
 modes this minor mode is used in.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (defvar global-display-fill-column-indicator-modes '((not special-mode) t) "\
 Which major modes `display-fill-column-indicator-mode' is switched on in.
 This variable can be either t (all major modes), nil (no major modes),
@@ -7690,7 +7674,7 @@ evaluate `display-line-numbers-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (put 'global-display-line-numbers-mode 'globalized-minor-mode t)
 (defvar global-display-line-numbers-mode nil "\
 Non-nil if Global Display-Line-Numbers mode is enabled.
@@ -7715,7 +7699,7 @@ Display-Line-Numbers mode is enabled in all buffers where
 See `display-line-numbers-mode' for more information on
 Display-Line-Numbers mode.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (defvar header-line-indent "" "\
 String to indent at the start if the header line.
 This is used in `header-line-indent-mode', and buffers that have
@@ -7762,7 +7746,7 @@ evaluate `header-line-indent-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "display-line-numbers" '("display-line-numbers-" 
"header-line-indent--"))
 
 
@@ -7777,7 +7761,7 @@ If ARG is positive, require ARG chars of continuity.
 If ARG is negative, require -ARG words of continuity.
 Default is 2.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 
 
 ;;; Generated autoloads from dnd.el
@@ -7805,7 +7789,7 @@ Query a DNS server for NAME of TYPE.
 If FULL, return the entire record returned.
 If REVERSE, look up an IP address.
 
-(fn NAME &optional TYPE FULL REVERSE)" nil nil)
+(fn NAME &optional TYPE FULL REVERSE)")
 (register-definition-prefixes "dns" '("dns-"))
 
 
@@ -7821,10 +7805,10 @@ table and its own syntax table.
 
 Turning on DNS mode runs `dns-mode-hook'.
 
-(fn)" t nil)
+(fn)" t)
  (defalias 'zone-mode 'dns-mode)
 (autoload 'dns-mode-soa-increment-serial "dns-mode" "\
-Locate SOA record and increment the serial field." t nil)
+Locate SOA record and increment the serial field." t)
 (register-definition-prefixes "dns-mode" '("dns-mode-"))
 
 
@@ -7840,7 +7824,7 @@ Return non-nil if document type TYPE is available for 
`doc-view'.
 Document types are symbols like `dvi', `ps', `pdf', `epub',
 `cbz', `fb2', `xps', `oxps', or`odf' (any OpenDocument format).
 
-(fn TYPE)" nil nil)
+(fn TYPE)")
 (autoload 'doc-view-mode "doc-view" "\
 Major mode in DocView buffers.
 
@@ -7849,11 +7833,11 @@ and DVI files (as PNG images) in Emacs buffers.
 
 You can use \\<doc-view-mode-map>\\[doc-view-toggle-display] to
 toggle between displaying the document or editing it as text.
-\\{doc-view-mode-map}" t nil)
+\\{doc-view-mode-map}" t)
 (autoload 'doc-view-mode-maybe "doc-view" "\
 Switch to `doc-view-mode' if possible.
 If the required external tools are not available, then fallback
-to the next best mode." nil nil)
+to the next best mode.")
 (autoload 'doc-view-minor-mode "doc-view" "\
 Toggle displaying buffer via Doc View (Doc View minor mode).
 
@@ -7873,19 +7857,19 @@ evaluate `doc-view-minor-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'doc-view-bookmark-jump "doc-view" "\
 
 
-(fn BMK)" nil nil)
+(fn BMK)")
 (register-definition-prefixes "doc-view" '("doc-view-"))
 
 
 ;;; Generated autoloads from play/doctor.el
 
 (autoload 'doctor "doctor" "\
-Switch to *doctor* buffer and start giving psychotherapy." t nil)
-(register-definition-prefixes "doctor" '("doc" "make-doctor-variables"))
+Switch to *doctor* buffer and start giving psychotherapy." t)
+(register-definition-prefixes "doctor" '("doc"))
 
 
 ;;; Generated autoloads from cedet/srecode/document.el
@@ -7935,14 +7919,14 @@ evaluate `double-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "double" '("double-"))
 
 
 ;;; Generated autoloads from play/dunnet.el
 
 (autoload 'dunnet "dunnet" "\
-Switch to *dungeon* buffer and start game." t nil)
+Switch to *dungeon* buffer and start game." t)
 (register-definition-prefixes "dunnet" '("dun" "obj-special"))
 
 
@@ -8026,7 +8010,7 @@ the keywords can also be preceded by the obsolete triplet
 INIT-VALUE LIGHTER KEYMAP.
 
 (fn MODE DOC [KEYWORD VAL ... &rest BODY])" nil t)
-(function-put 'define-minor-mode 'doc-string-elt '2)
+(function-put 'define-minor-mode 'doc-string-elt 2)
 (function-put 'define-minor-mode 'lisp-indent-function 'defun)
 (defalias 'easy-mmode-define-global-mode #'define-globalized-minor-mode)
 (defalias 'define-global-minor-mode #'define-globalized-minor-mode)
@@ -8060,7 +8044,7 @@ after running the major mode's hook.  However, MODE is 
not turned
 on if the hook has explicitly disabled it.
 
 (fn GLOBAL-MODE MODE TURN-ON [KEY VALUE]... BODY...)" nil t)
-(function-put 'define-globalized-minor-mode 'doc-string-elt '2)
+(function-put 'define-globalized-minor-mode 'doc-string-elt 2)
 (function-put 'define-globalized-minor-mode 'lisp-indent-function 'defun)
 (autoload 'easy-mmode-define-keymap "easy-mmode" "\
 Return a keymap built from bindings BS.
@@ -8079,7 +8063,7 @@ Valid keywords and arguments are:
   :suppress  Non-nil to call `suppress-keymap' on keymap,
              `nodigits' to suppress digits as prefix arguments.
 
-(fn BS &optional NAME M ARGS)" nil nil)
+(fn BS &optional NAME M ARGS)")
 (autoload 'easy-mmode-defmap "easy-mmode" "\
 Define a constant M whose value is the result of `easy-mmode-define-keymap'.
 The M, BS, and ARGS arguments are as per that function.  DOC is
@@ -8088,15 +8072,15 @@ the constant's documentation.
 This macro is deprecated; use `defvar-keymap' instead.
 
 (fn M BS DOC &rest ARGS)" nil t)
-(function-put 'easy-mmode-defmap 'doc-string-elt '3)
-(function-put 'easy-mmode-defmap 'lisp-indent-function '1)
+(function-put 'easy-mmode-defmap 'doc-string-elt 3)
+(function-put 'easy-mmode-defmap 'lisp-indent-function 1)
 (autoload 'easy-mmode-defsyntax "easy-mmode" "\
 Define variable ST as a syntax-table.
 CSS contains a list of syntax specifications of the form (CHAR . SYNTAX).
 
 (fn ST CSS DOC &rest ARGS)" nil t)
-(function-put 'easy-mmode-defsyntax 'doc-string-elt '3)
-(function-put 'easy-mmode-defsyntax 'lisp-indent-function '1)
+(function-put 'easy-mmode-defsyntax 'doc-string-elt 3)
+(function-put 'easy-mmode-defsyntax 'lisp-indent-function 1)
 (register-definition-prefixes "easy-mmode" '("easy-mmode-"))
 
 
@@ -8137,9 +8121,8 @@ CSS contains a list of syntax specifications of the form 
(CHAR . SYNTAX).
 
 ;;; Generated autoloads from progmodes/ebnf2ps.el
 
-(push (purecopy '(ebnf2ps 4 4)) package--builtin-versions)
 (autoload 'ebnf-customize "ebnf2ps" "\
-Customization for ebnf group." t nil)
+Customization for ebnf group." t)
 (autoload 'ebnf-print-directory "ebnf2ps" "\
 Generate and print a PostScript syntactic chart image of DIRECTORY.
 
@@ -8150,7 +8133,7 @@ processed.
 
 See also `ebnf-print-buffer'.
 
-(fn &optional DIRECTORY)" t nil)
+(fn &optional DIRECTORY)" t)
 (autoload 'ebnf-print-file "ebnf2ps" "\
 Generate and print a PostScript syntactic chart image of the file FILE.
 
@@ -8159,7 +8142,7 @@ killed after process termination.
 
 See also `ebnf-print-buffer'.
 
-(fn FILE &optional DO-NOT-KILL-BUFFER-WHEN-DONE)" t nil)
+(fn FILE &optional DO-NOT-KILL-BUFFER-WHEN-DONE)" t)
 (autoload 'ebnf-print-buffer "ebnf2ps" "\
 Generate and print a PostScript syntactic chart image of the buffer.
 
@@ -8172,12 +8155,12 @@ is nil, send the image to the printer.  If FILENAME is 
a string, save
 the PostScript image in a file with that name.  If FILENAME is a
 number, prompt the user for the name of the file to save in.
 
-(fn &optional FILENAME)" t nil)
+(fn &optional FILENAME)" t)
 (autoload 'ebnf-print-region "ebnf2ps" "\
 Generate and print a PostScript syntactic chart image of the region.
 Like `ebnf-print-buffer', but prints just the current region.
 
-(fn FROM TO &optional FILENAME)" t nil)
+(fn FROM TO &optional FILENAME)" t)
 (autoload 'ebnf-spool-directory "ebnf2ps" "\
 Generate and spool a PostScript syntactic chart image of DIRECTORY.
 
@@ -8188,7 +8171,7 @@ processed.
 
 See also `ebnf-spool-buffer'.
 
-(fn &optional DIRECTORY)" t nil)
+(fn &optional DIRECTORY)" t)
 (autoload 'ebnf-spool-file "ebnf2ps" "\
 Generate and spool a PostScript syntactic chart image of the file FILE.
 
@@ -8197,20 +8180,20 @@ killed after process termination.
 
 See also `ebnf-spool-buffer'.
 
-(fn FILE &optional DO-NOT-KILL-BUFFER-WHEN-DONE)" t nil)
+(fn FILE &optional DO-NOT-KILL-BUFFER-WHEN-DONE)" t)
 (autoload 'ebnf-spool-buffer "ebnf2ps" "\
 Generate and spool a PostScript syntactic chart image of the buffer.
 Like `ebnf-print-buffer' except that the PostScript image is saved in a
 local buffer to be sent to the printer later.
 
-Use the command `ebnf-despool' to send the spooled images to the printer." t 
nil)
+Use the command `ebnf-despool' to send the spooled images to the printer." t)
 (autoload 'ebnf-spool-region "ebnf2ps" "\
 Generate a PostScript syntactic chart image of the region and spool locally.
 Like `ebnf-spool-buffer', but spools just the current region.
 
 Use the command `ebnf-despool' to send the spooled images to the printer.
 
-(fn FROM TO)" t nil)
+(fn FROM TO)" t)
 (autoload 'ebnf-eps-directory "ebnf2ps" "\
 Generate EPS files from EBNF files in DIRECTORY.
 
@@ -8221,7 +8204,7 @@ processed.
 
 See also `ebnf-eps-buffer'.
 
-(fn &optional DIRECTORY)" t nil)
+(fn &optional DIRECTORY)" t)
 (autoload 'ebnf-eps-file "ebnf2ps" "\
 Generate an EPS file from EBNF file FILE.
 
@@ -8230,7 +8213,7 @@ killed after EPS generation.
 
 See also `ebnf-eps-buffer'.
 
-(fn FILE &optional DO-NOT-KILL-BUFFER-WHEN-DONE)" t nil)
+(fn FILE &optional DO-NOT-KILL-BUFFER-WHEN-DONE)" t)
 (autoload 'ebnf-eps-buffer "ebnf2ps" "\
 Generate a PostScript syntactic chart image of the buffer in an EPS file.
 
@@ -8249,7 +8232,7 @@ The EPS file name has the following form:
             file name used in this case will be \"ebnf--A_B_+_C.eps\".
 
 WARNING: This function does *NOT* ask any confirmation to override existing
-        files." t nil)
+        files." t)
 (autoload 'ebnf-eps-region "ebnf2ps" "\
 Generate a PostScript syntactic chart image of the region in an EPS file.
 
@@ -8270,7 +8253,7 @@ The EPS file name has the following form:
 WARNING: This function does *NOT* ask any confirmation to override existing
         files.
 
-(fn FROM TO)" t nil)
+(fn FROM TO)" t)
 (defalias 'ebnf-despool #'ps-despool)
 (autoload 'ebnf-syntax-directory "ebnf2ps" "\
 Do a syntactic analysis of the files in DIRECTORY.
@@ -8282,7 +8265,7 @@ are processed.
 
 See also `ebnf-syntax-buffer'.
 
-(fn &optional DIRECTORY)" t nil)
+(fn &optional DIRECTORY)" t)
 (autoload 'ebnf-syntax-file "ebnf2ps" "\
 Do a syntactic analysis of the named FILE.
 
@@ -8291,39 +8274,39 @@ killed after syntax checking.
 
 See also `ebnf-syntax-buffer'.
 
-(fn FILE &optional DO-NOT-KILL-BUFFER-WHEN-DONE)" t nil)
+(fn FILE &optional DO-NOT-KILL-BUFFER-WHEN-DONE)" t)
 (autoload 'ebnf-syntax-buffer "ebnf2ps" "\
-Do a syntactic analysis of the current buffer." t nil)
+Do a syntactic analysis of the current buffer." t)
 (autoload 'ebnf-syntax-region "ebnf2ps" "\
 Do a syntactic analysis of a region.
 
-(fn FROM TO)" t nil)
+(fn FROM TO)" t)
 (autoload 'ebnf-setup "ebnf2ps" "\
-Return the current ebnf2ps setup." nil nil)
+Return the current ebnf2ps setup.")
 (autoload 'ebnf-find-style "ebnf2ps" "\
 Return style definition if NAME is already defined; otherwise, return nil.
 
 See `ebnf-style-database' documentation.
 
-(fn NAME)" t nil)
+(fn NAME)" t)
 (autoload 'ebnf-insert-style "ebnf2ps" "\
 Insert a new style NAME with inheritance INHERITS and values VALUES.
 
 See `ebnf-style-database' documentation.
 
-(fn NAME INHERITS &rest VALUES)" t nil)
+(fn NAME INHERITS &rest VALUES)" t)
 (autoload 'ebnf-delete-style "ebnf2ps" "\
 Delete style NAME.
 
 See `ebnf-style-database' documentation.
 
-(fn NAME)" t nil)
+(fn NAME)" t)
 (autoload 'ebnf-merge-style "ebnf2ps" "\
 Merge values of style NAME with style VALUES.
 
 See `ebnf-style-database' documentation.
 
-(fn NAME &rest VALUES)" t nil)
+(fn NAME &rest VALUES)" t)
 (autoload 'ebnf-apply-style "ebnf2ps" "\
 Set STYLE as the current style.
 
@@ -8331,7 +8314,7 @@ Returns the old style symbol.
 
 See `ebnf-style-database' documentation.
 
-(fn STYLE)" t nil)
+(fn STYLE)" t)
 (autoload 'ebnf-reset-style "ebnf2ps" "\
 Reset current style.
 
@@ -8339,7 +8322,7 @@ Returns the old style symbol.
 
 See `ebnf-style-database' documentation.
 
-(fn &optional STYLE)" t nil)
+(fn &optional STYLE)" t)
 (autoload 'ebnf-push-style "ebnf2ps" "\
 Push the current style onto a stack and set STYLE as the current style.
 
@@ -8349,7 +8332,7 @@ See also `ebnf-pop-style'.
 
 See `ebnf-style-database' documentation.
 
-(fn &optional STYLE)" t nil)
+(fn &optional STYLE)" t)
 (autoload 'ebnf-pop-style "ebnf2ps" "\
 Pop a style from the stack of pushed styles and set it as the current style.
 
@@ -8357,7 +8340,7 @@ Returns the old style symbol.
 
 See also `ebnf-push-style'.
 
-See `ebnf-style-database' documentation." t nil)
+See `ebnf-style-database' documentation." t)
 (register-definition-prefixes "ebnf2ps" '("ebnf-"))
 
 
@@ -8368,57 +8351,57 @@ Major mode for Ebrowse class tree buffers.
 Each line corresponds to a class in a class tree.
 Letters do not insert themselves, they are commands.
 File operations in the tree buffer work on class tree data structures.
-E.g.\\[save-buffer] writes the tree to the file it was loaded from.
+E.g. \\[save-buffer] writes the tree to the file it was loaded from.
 
 Tree mode key bindings:
 \\{ebrowse-tree-mode-map}
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'ebrowse-electric-choose-tree "ebrowse" "\
-Return a buffer containing a tree or nil if no tree found or canceled." t nil)
+Return a buffer containing a tree or nil if no tree found or canceled." t)
 (autoload 'ebrowse-member-mode "ebrowse" "\
 Major mode for Ebrowse member buffers.
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'ebrowse-tags-view-declaration "ebrowse" "\
-View declaration of member at point." t nil)
+View declaration of member at point." t)
 (autoload 'ebrowse-tags-find-declaration "ebrowse" "\
-Find declaration of member at point." t nil)
+Find declaration of member at point." t)
 (autoload 'ebrowse-tags-view-definition "ebrowse" "\
-View definition of member at point." t nil)
+View definition of member at point." t)
 (autoload 'ebrowse-tags-find-definition "ebrowse" "\
-Find definition of member at point." t nil)
+Find definition of member at point." t)
 (autoload 'ebrowse-tags-find-declaration-other-window "ebrowse" "\
-Find declaration of member at point in other window." t nil)
+Find declaration of member at point in other window." t)
 (autoload 'ebrowse-tags-view-definition-other-window "ebrowse" "\
-View definition of member at point in other window." t nil)
+View definition of member at point in other window." t)
 (autoload 'ebrowse-tags-find-definition-other-window "ebrowse" "\
-Find definition of member at point in other window." t nil)
+Find definition of member at point in other window." t)
 (autoload 'ebrowse-tags-find-declaration-other-frame "ebrowse" "\
-Find definition of member at point in other frame." t nil)
+Find definition of member at point in other frame." t)
 (autoload 'ebrowse-tags-view-definition-other-frame "ebrowse" "\
-View definition of member at point in other frame." t nil)
+View definition of member at point in other frame." t)
 (autoload 'ebrowse-tags-find-definition-other-frame "ebrowse" "\
-Find definition of member at point in other frame." t nil)
+Find definition of member at point in other frame." t)
 (autoload 'ebrowse-tags-complete-symbol "ebrowse" "\
 Perform completion on the C++ symbol preceding point.
 A second call of this function without changing point inserts the next match.
 A call with prefix PREFIX reads the symbol to insert from the minibuffer with
 completion.
 
-(fn PREFIX)" '("P") nil)
+(fn PREFIX)" '("P"))
 (autoload 'ebrowse-tags-loop-continue "ebrowse" "\
 Repeat last operation on files in tree.
 FIRST-TIME non-nil means this is not a repetition, but the first time.
 TREE-BUFFER if indirectly specifies which files to loop over.
 
-(fn &optional FIRST-TIME TREE-BUFFER)" t nil)
+(fn &optional FIRST-TIME TREE-BUFFER)" t)
 (autoload 'ebrowse-tags-search "ebrowse" "\
 Search for REGEXP in all files in a tree.
 If marked classes exist, process marked classes, only.
 If regular expression is nil, repeat last search.
 
-(fn REGEXP)" t nil)
+(fn REGEXP)" t)
 (autoload 'ebrowse-tags-query-replace "ebrowse" "\
 Query replace FROM with TO in all files of a class tree.
 With prefix arg, process files of marked classes only.
@@ -8428,7 +8411,7 @@ what to do with it.  Type SPC or `y' to replace the match,
 DEL or `n' to skip and go to the next match.  For more directions,
 type \\[help-command] at that time.
 
-(fn FROM TO)" t nil)
+(fn FROM TO)" t)
 (autoload 'ebrowse-tags-search-member-use "ebrowse" "\
 Search for call sites of a member.
 If FIX-NAME is specified, search uses of that member.
@@ -8436,29 +8419,29 @@ Otherwise, read a member name from the minibuffer.
 Searches in all files mentioned in a class tree for something that
 looks like a function call to the member.
 
-(fn &optional FIX-NAME)" t nil)
+(fn &optional FIX-NAME)" t)
 (autoload 'ebrowse-back-in-position-stack "ebrowse" "\
 Move backward in the position stack.
 Prefix arg ARG says how much.
 
-(fn ARG)" t nil)
+(fn ARG)" t)
 (autoload 'ebrowse-forward-in-position-stack "ebrowse" "\
 Move forward in the position stack.
 Prefix arg ARG says how much.
 
-(fn ARG)" t nil)
+(fn ARG)" t)
 (autoload 'ebrowse-electric-position-menu "ebrowse" "\
-List positions in the position stack in an electric buffer." t nil)
+List positions in the position stack in an electric buffer." t)
 (autoload 'ebrowse-save-tree "ebrowse" "\
-Save current tree in same file it was loaded from." t nil)
+Save current tree in same file it was loaded from." t)
 (autoload 'ebrowse-save-tree-as "ebrowse" "\
 Write the current tree data structure to a file.
 Read the file name from the minibuffer if interactive.
 Otherwise, FILE-NAME specifies the file to save the tree in.
 
-(fn &optional FILE-NAME)" t nil)
+(fn &optional FILE-NAME)" t)
 (autoload 'ebrowse-statistics "ebrowse" "\
-Display statistics for a class tree." t nil)
+Display statistics for a class tree." t)
 (register-definition-prefixes "ebrowse" '("ebrowse-" 
"electric-buffer-menu-mode-hook"))
 
 
@@ -8490,7 +8473,7 @@ Run hooks in `electric-buffer-menu-mode-hook' on entry.
 \\[Electric-buffer-menu-mode-view-buffer] -- view buffer, returning when done.
 \\[Buffer-menu-backup-unmark] -- back up a line and remove marks.
 
-(fn ARG)" t nil)
+(fn ARG)" t)
 (register-definition-prefixes "ebuff-menu" '("Electric-buffer-menu-" 
"electric-buffer-"))
 
 
@@ -8500,20 +8483,20 @@ Run hooks in `electric-buffer-menu-mode-hook' on entry.
 Edit current history line in minibuffer and execute result.
 With prefix arg NOCONFIRM, execute current line as-is without editing.
 
-(fn &optional NOCONFIRM)" t nil)
+(fn &optional NOCONFIRM)" t)
 (register-definition-prefixes "echistory" '("Electric-history-" "electric-"))
 
 
 ;;; Generated autoloads from ecomplete.el
 
 (autoload 'ecomplete-setup "ecomplete" "\
-Read the .ecompleterc file." nil nil)
+Read the .ecompleterc file.")
 (register-definition-prefixes "ecomplete" '("ecomplete-"))
 
 
 ;;; Generated autoloads from cedet/ede.el
 
-(push (purecopy '(ede 1 2)) package--builtin-versions)
+(push (purecopy '(ede 2 0)) package--builtin-versions)
 (defvar global-ede-mode nil "\
 Non-nil if Global Ede mode is enabled.
 See the `global-ede-mode' command
@@ -8542,7 +8525,7 @@ evaluate `(default-value \\='global-ede-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "ede" '("ede" "global-ede-mode-map" 
"project-try-ede"))
 
 
@@ -8577,7 +8560,7 @@ Return t if SPEC uses only extant spec symbols.
 An extant spec symbol is a symbol that is not a function and has a
 `edebug-form-spec' property.
 
-(fn SPEC)" nil nil)
+(fn SPEC)")
 (defalias 'edebug-defun 'edebug-eval-top-level-form)
 (autoload 'edebug-eval-top-level-form "edebug" "\
 Evaluate the top level form point is in, stepping through with Edebug.
@@ -8595,12 +8578,12 @@ If the current defun is actually a call to `defvar' or 
`defcustom',
 evaluating it this way resets the variable using its initial value
 expression even if the variable already has some other value.
 (Normally `defvar' and `defcustom' do not alter the value if there
-already is one.)" t nil)
+already is one.)" t)
 (autoload 'edebug-all-defs "edebug" "\
-Toggle edebugging of all definitions." t nil)
+Toggle edebugging of all definitions." t)
 (autoload 'edebug-all-forms "edebug" "\
-Toggle edebugging of all forms." t nil)
-(register-definition-prefixes "edebug" '("arglist" "backquote-form" 
"def-declarations" "edebug" "function-form" "interactive" "lambda-" "name" 
"nested-backquote-form"))
+Toggle edebugging of all forms." t)
+(register-definition-prefixes "edebug" '("edebug"))
 
 
 ;;; Generated autoloads from vc/ediff.el
@@ -8611,25 +8594,25 @@ Run Ediff on a pair of files, FILE-A and FILE-B.
 STARTUP-HOOKS is a list of functions that Emacs calls without
 arguments after setting up the Ediff buffers.
 
-(fn FILE-A FILE-B &optional STARTUP-HOOKS)" t nil)
+(fn FILE-A FILE-B &optional STARTUP-HOOKS)" t)
 (autoload 'ediff-files3 "ediff" "\
 Run Ediff on three files, FILE-A, FILE-B, and FILE-C.
 STARTUP-HOOKS is a list of functions that Emacs calls without
 arguments after setting up the Ediff buffers.
 
-(fn FILE-A FILE-B FILE-C &optional STARTUP-HOOKS)" t nil)
+(fn FILE-A FILE-B FILE-C &optional STARTUP-HOOKS)" t)
 (defalias 'ediff3 #'ediff-files3)
 (defalias 'ediff #'ediff-files)
 (autoload 'ediff-current-file "ediff" "\
 Start ediff between current buffer and its file on disk.
 This command can be used instead of `revert-buffer'.  If there is
-nothing to revert then this command fails." t nil)
+nothing to revert then this command fails." t)
 (autoload 'ediff-backup "ediff" "\
 Run Ediff on FILE and its backup file.
 Uses the latest backup, if there are several numerical backups.
 If this file is a backup, `ediff' it with its original.
 
-(fn FILE)" t nil)
+(fn FILE)" t)
 (autoload 'ediff-buffers "ediff" "\
 Run Ediff on a pair of buffers, BUFFER-A and BUFFER-B.
 STARTUP-HOOKS is a list of functions that Emacs calls without
@@ -8640,7 +8623,7 @@ symbol describing the Ediff job type; it defaults to
 `ediff-last-dir-C', `ediff-buffers3', `ediff-merge-buffers', or
 `ediff-merge-buffers-with-ancestor'.
 
-(fn BUFFER-A BUFFER-B &optional STARTUP-HOOKS JOB-NAME)" t nil)
+(fn BUFFER-A BUFFER-B &optional STARTUP-HOOKS JOB-NAME)" t)
 (defalias 'ebuffers #'ediff-buffers)
 (autoload 'ediff-buffers3 "ediff" "\
 Run Ediff on three buffers, BUFFER-A, BUFFER-B, and BUFFER-C.
@@ -8652,7 +8635,7 @@ symbol describing the Ediff job type; it defaults to
 `ediff-last-dir-C', `ediff-buffers', `ediff-merge-buffers', or
 `ediff-merge-buffers-with-ancestor'.
 
-(fn BUFFER-A BUFFER-B BUFFER-C &optional STARTUP-HOOKS JOB-NAME)" t nil)
+(fn BUFFER-A BUFFER-B BUFFER-C &optional STARTUP-HOOKS JOB-NAME)" t)
 (defalias 'ebuffers3 #'ediff-buffers3)
 (autoload 'ediff-directories "ediff" "\
 Run Ediff on directories DIR1 and DIR2, comparing files.
@@ -8661,14 +8644,14 @@ Consider only files that have the same name in both 
directories.
 REGEXP is nil or a regular expression; only file names that match
 the regexp are considered.
 
-(fn DIR1 DIR2 REGEXP)" t nil)
+(fn DIR1 DIR2 REGEXP)" t)
 (defalias 'edirs #'ediff-directories)
 (autoload 'ediff-directory-revisions "ediff" "\
 Run Ediff on a directory, DIR1, comparing its files with their revisions.
 The second argument, REGEXP, is a regular expression that filters the file
 names.  Only the files that are under revision control are taken into account.
 
-(fn DIR1 REGEXP)" t nil)
+(fn DIR1 REGEXP)" t)
 (defalias 'edir-revisions #'ediff-directory-revisions)
 (autoload 'ediff-directories3 "ediff" "\
 Run Ediff on directories DIR1, DIR2, and DIR3, comparing files.
@@ -8677,7 +8660,7 @@ Consider only files that have the same name in all three 
directories.
 REGEXP is nil or a regular expression; only file names that match
 the regexp are considered.
 
-(fn DIR1 DIR2 DIR3 REGEXP)" t nil)
+(fn DIR1 DIR2 DIR3 REGEXP)" t)
 (defalias 'edirs3 #'ediff-directories3)
 (autoload 'ediff-merge-directories "ediff" "\
 Run Ediff on a pair of directories, DIR1 and DIR2, merging files that have
@@ -8685,7 +8668,7 @@ the same name in both.  The third argument, REGEXP, is 
nil or a regular
 expression; only file names that match the regexp are considered.
 MERGE-AUTOSTORE-DIR is the directory in which to store merged files.
 
-(fn DIR1 DIR2 REGEXP &optional MERGE-AUTOSTORE-DIR)" t nil)
+(fn DIR1 DIR2 REGEXP &optional MERGE-AUTOSTORE-DIR)" t)
 (defalias 'edirs-merge #'ediff-merge-directories)
 (autoload 'ediff-merge-directories-with-ancestor "ediff" "\
 Merge files in DIR1 and DIR2 using files in ANCESTOR-DIR as ancestors.
@@ -8695,14 +8678,14 @@ without ancestor.  The fourth argument, REGEXP, is nil 
or a regular expression;
 only file names that match the regexp are considered.
 MERGE-AUTOSTORE-DIR is the directory in which to store merged files.
 
-(fn DIR1 DIR2 ANCESTOR-DIR REGEXP &optional MERGE-AUTOSTORE-DIR)" t nil)
+(fn DIR1 DIR2 ANCESTOR-DIR REGEXP &optional MERGE-AUTOSTORE-DIR)" t)
 (autoload 'ediff-merge-directory-revisions "ediff" "\
 Run Ediff on a directory, DIR1, merging its files with their revisions.
 The second argument, REGEXP, is a regular expression that filters the file
 names.  Only the files that are under revision control are taken into account.
 MERGE-AUTOSTORE-DIR is the directory in which to store merged files.
 
-(fn DIR1 REGEXP &optional MERGE-AUTOSTORE-DIR)" t nil)
+(fn DIR1 REGEXP &optional MERGE-AUTOSTORE-DIR)" t)
 (defalias 'edir-merge-revisions #'ediff-merge-directory-revisions)
 (autoload 'ediff-merge-directory-revisions-with-ancestor "ediff" "\
 Run Ediff on DIR1 and merge its files with their revisions and ancestors.
@@ -8710,7 +8693,7 @@ The second argument, REGEXP, is a regular expression that 
filters the file
 names.  Only the files that are under revision control are taken into account.
 MERGE-AUTOSTORE-DIR is the directory in which to store merged files.
 
-(fn DIR1 REGEXP &optional MERGE-AUTOSTORE-DIR)" t nil)
+(fn DIR1 REGEXP &optional MERGE-AUTOSTORE-DIR)" t)
 (defalias 'edir-merge-revisions-with-ancestor 
'ediff-merge-directory-revisions-with-ancestor)
 (defalias 'edirs-merge-with-ancestor 'ediff-merge-directories-with-ancestor)
 (autoload 'ediff-windows-wordwise "ediff" "\
@@ -8723,7 +8706,7 @@ If WIND-B is nil, use window next to WIND-A.
 STARTUP-HOOKS is a list of functions that Emacs calls without
 arguments after setting up the Ediff buffers.
 
-(fn DUMB-MODE &optional WIND-A WIND-B STARTUP-HOOKS)" t nil)
+(fn DUMB-MODE &optional WIND-A WIND-B STARTUP-HOOKS)" t)
 (autoload 'ediff-windows-linewise "ediff" "\
 Compare WIND-A and WIND-B, which are selected by clicking, linewise.
 This compares the portions of text visible in each of the two windows.
@@ -8734,7 +8717,7 @@ If WIND-B is nil, use window next to WIND-A.
 STARTUP-HOOKS is a list of functions that Emacs calls without
 arguments after setting up the Ediff buffers.
 
-(fn DUMB-MODE &optional WIND-A WIND-B STARTUP-HOOKS)" t nil)
+(fn DUMB-MODE &optional WIND-A WIND-B STARTUP-HOOKS)" t)
 (autoload 'ediff-regions-wordwise "ediff" "\
 Run Ediff on a pair of regions in specified buffers.
 BUFFER-A and BUFFER-B are the buffers to be compared.
@@ -8744,7 +8727,7 @@ use `ediff-regions-linewise' instead.
 STARTUP-HOOKS is a list of functions that Emacs calls without
 arguments after setting up the Ediff buffers.
 
-(fn BUFFER-A BUFFER-B &optional STARTUP-HOOKS)" t nil)
+(fn BUFFER-A BUFFER-B &optional STARTUP-HOOKS)" t)
 (autoload 'ediff-regions-linewise "ediff" "\
 Run Ediff on a pair of regions in specified buffers.
 BUFFER-A and BUFFER-B are the buffers to be compared.
@@ -8755,7 +8738,7 @@ lines.  For small regions, use `ediff-regions-wordwise'.
 STARTUP-HOOKS is a list of functions that Emacs calls without
 arguments after setting up the Ediff buffers.
 
-(fn BUFFER-A BUFFER-B &optional STARTUP-HOOKS)" t nil)
+(fn BUFFER-A BUFFER-B &optional STARTUP-HOOKS)" t)
 (defalias 'ediff-merge 'ediff-merge-files)
 (autoload 'ediff-merge-files "ediff" "\
 Merge two files without ancestor.
@@ -8764,7 +8747,7 @@ STARTUP-HOOKS is a list of functions that Emacs calls 
without
 arguments after setting up the Ediff buffers.  MERGE-BUFFER-FILE
 is the name of the file to be associated with the merge buffer..
 
-(fn FILE-A FILE-B &optional STARTUP-HOOKS MERGE-BUFFER-FILE)" t nil)
+(fn FILE-A FILE-B &optional STARTUP-HOOKS MERGE-BUFFER-FILE)" t)
 (autoload 'ediff-merge-files-with-ancestor "ediff" "\
 Merge two files with ancestor.
 FILE-A and FILE-B are the names of the files to be merged, and
@@ -8773,7 +8756,7 @@ a list of functions that Emacs calls without arguments 
after
 setting up the Ediff buffers.  MERGE-BUFFER-FILE is the name of
 the file to be associated with the merge buffer.
 
-(fn FILE-A FILE-B FILE-ANCESTOR &optional STARTUP-HOOKS MERGE-BUFFER-FILE)" t 
nil)
+(fn FILE-A FILE-B FILE-ANCESTOR &optional STARTUP-HOOKS MERGE-BUFFER-FILE)" t)
 (defalias 'ediff-merge-with-ancestor 'ediff-merge-files-with-ancestor)
 (autoload 'ediff-merge-buffers "ediff" "\
 Merge buffers without ancestor.
@@ -8787,7 +8770,7 @@ symbol describing the Ediff job type; it defaults to
 `ediff-merge-buffers-with-ancestor'.  MERGE-BUFFER-FILE is the
 name of the file to be associated with the merge buffer.
 
-(fn BUFFER-A BUFFER-B &optional STARTUP-HOOKS JOB-NAME MERGE-BUFFER-FILE)" t 
nil)
+(fn BUFFER-A BUFFER-B &optional STARTUP-HOOKS JOB-NAME MERGE-BUFFER-FILE)" t)
 (autoload 'ediff-merge-buffers-with-ancestor "ediff" "\
 Merge buffers with ancestor.
 BUFFER-A and BUFFER-B are the buffers to be merged, and
@@ -8800,7 +8783,7 @@ also be one of `ediff-merge-files-with-ancestor',
 `ediff-buffers3', or `ediff-merge-buffers'.  MERGE-BUFFER-FILE is
 the name of the file to be associated with the merge buffer.
 
-(fn BUFFER-A BUFFER-B BUFFER-ANCESTOR &optional STARTUP-HOOKS JOB-NAME 
MERGE-BUFFER-FILE)" t nil)
+(fn BUFFER-A BUFFER-B BUFFER-ANCESTOR &optional STARTUP-HOOKS JOB-NAME 
MERGE-BUFFER-FILE)" t)
 (autoload 'ediff-merge-revisions "ediff" "\
 Run Ediff by merging two revisions of a file.
 The file is the optional FILE argument or the file visited by the
@@ -8809,7 +8792,7 @@ calls without arguments after setting up the Ediff 
buffers.
 MERGE-BUFFER-FILE is the name of the file to be associated with
 the merge buffer.
 
-(fn &optional FILE STARTUP-HOOKS MERGE-BUFFER-FILE)" t nil)
+(fn &optional FILE STARTUP-HOOKS MERGE-BUFFER-FILE)" t)
 (autoload 'ediff-merge-revisions-with-ancestor "ediff" "\
 Run Ediff by merging two revisions of a file with a common ancestor.
 The file is the optional FILE argument or the file visited by the
@@ -8818,7 +8801,7 @@ calls without arguments after setting up the Ediff 
buffers.
 MERGE-BUFFER-FILE is the name of the file to be associated with
 the merge buffer.
 
-(fn &optional FILE STARTUP-HOOKS MERGE-BUFFER-FILE)" t nil)
+(fn &optional FILE STARTUP-HOOKS MERGE-BUFFER-FILE)" t)
 (autoload 'ediff-patch-file "ediff" "\
 Query for a file name, and then run Ediff by patching that file.
 If optional PATCH-BUF is given, use the patch in that buffer
@@ -8826,7 +8809,7 @@ and don't ask the user.
 If prefix argument ARG, then: if even argument, assume that the
 patch is in a buffer.  If odd -- assume it is in a file.
 
-(fn &optional ARG PATCH-BUF)" t nil)
+(fn &optional ARG PATCH-BUF)" t)
 (autoload 'ediff-patch-buffer "ediff" "\
 Run Ediff by patching the buffer specified at prompt.
 Without the optional prefix ARG, asks if the patch is in some buffer and
@@ -8836,7 +8819,7 @@ With ARG=2, assumes the patch is in a buffer and prompts 
for the buffer.
 PATCH-BUF is an optional argument, which specifies the buffer that contains the
 patch.  If not given, the user is prompted according to the prefix argument.
 
-(fn &optional ARG PATCH-BUF)" t nil)
+(fn &optional ARG PATCH-BUF)" t)
 (defalias 'epatch 'ediff-patch-file)
 (defalias 'epatch-buffer 'ediff-patch-buffer)
 (autoload 'ediff-revision "ediff" "\
@@ -8847,33 +8830,33 @@ Uses `vc.el' or `rcs.el' depending on 
`ediff-version-control-package'.
 STARTUP-HOOKS is a list of functions that Emacs calls without
 arguments after setting up the Ediff buffers.
 
-(fn &optional FILE STARTUP-HOOKS)" t nil)
+(fn &optional FILE STARTUP-HOOKS)" t)
 (defalias 'erevision 'ediff-revision)
 (autoload 'ediff-version "ediff" "\
 Return string describing the version of Ediff.
-When called interactively, displays the version." t nil)
+When called interactively, displays the version." t)
 (autoload 'ediff-documentation "ediff" "\
 Display Ediff's manual.
 With optional NODE, goes to that node.
 
-(fn &optional NODE)" t nil)
+(fn &optional NODE)" t)
 (autoload 'ediff-files-command "ediff" "\
-Call `ediff-files' with the next two command line arguments." nil nil)
+Call `ediff-files' with the next two command line arguments.")
 (autoload 'ediff3-files-command "ediff" "\
-Call `ediff3-files' with the next three command line arguments." nil nil)
+Call `ediff3-files' with the next three command line arguments.")
 (autoload 'ediff-merge-command "ediff" "\
-Call `ediff-merge-files' with the next two command line arguments." nil nil)
+Call `ediff-merge-files' with the next two command line arguments.")
 (autoload 'ediff-merge-with-ancestor-command "ediff" "\
-Call `ediff-merge-files-with-ancestor' with next three command line 
arguments." nil nil)
+Call `ediff-merge-files-with-ancestor' with next three command line 
arguments.")
 (autoload 'ediff-directories-command "ediff" "\
-Call `ediff-directories' with the next three command line arguments." nil nil)
+Call `ediff-directories' with the next three command line arguments.")
 (autoload 'ediff-directories3-command "ediff" "\
-Call `ediff-directories3' with the next four command line arguments." nil nil)
+Call `ediff-directories3' with the next four command line arguments.")
 (autoload 'ediff-merge-directories-command "ediff" "\
-Call `ediff-merge-directories' with the next three command line arguments." 
nil nil)
+Call `ediff-merge-directories' with the next three command line arguments.")
 (autoload 'ediff-merge-directories-with-ancestor-command "ediff" "\
 Call `ediff-merge-directories-with-ancestor' with the next four command line
-arguments." nil nil)
+arguments.")
 (register-definition-prefixes "ediff" '("ediff-"))
 
 
@@ -8884,7 +8867,7 @@ arguments." nil nil)
 
 ;;; Generated autoloads from vc/ediff-help.el
 
-(autoload 'ediff-customize "ediff-help" nil t nil)
+(autoload 'ediff-customize "ediff-help" nil t)
 (register-definition-prefixes "ediff-help" '("ediff-"))
 
 
@@ -8901,7 +8884,7 @@ arguments." nil nil)
 ;;; Generated autoloads from vc/ediff-mult.el
 
 (autoload 'ediff-show-registry "ediff-mult" "\
-Display Ediff's registry." t nil)
+Display Ediff's registry." t)
 (defalias 'eregistry #'ediff-show-registry)
 (register-definition-prefixes "ediff-mult" '("ediff-"))
 
@@ -8916,11 +8899,11 @@ Display Ediff's registry." t nil)
 (autoload 'ediff-toggle-multiframe "ediff-util" "\
 Switch from multiframe display to single-frame display and back.
 To change the default, set the variable `ediff-window-setup-function',
-which see." t nil)
+which see." t)
 (autoload 'ediff-toggle-use-toolbar "ediff-util" "\
 Enable or disable Ediff toolbar.
 Works only in versions of Emacs that support toolbars.
-To change the default, set the variable `ediff-use-toolbar-p', which see." t 
nil)
+To change the default, set the variable `ediff-use-toolbar-p', which see." t)
 (register-definition-prefixes "ediff-util" '("ediff-"))
 
 
@@ -8944,21 +8927,21 @@ To change the default, set the variable 
`ediff-use-toolbar-p', which see." t nil
 (autoload 'edit-kbd-macro "edmacro" "\
 Edit a keyboard macro.
 At the prompt, type any key sequence which is bound to a keyboard macro.
-Or, type `\\[kmacro-end-and-call-macro]' or RET to edit the last
+Or, type `\\[kmacro-end-and-call-macro]' or \\`RET' to edit the last
 keyboard macro, `\\[view-lossage]' to edit the last 300
 keystrokes as a keyboard macro, or `\\[execute-extended-command]'
 to edit a macro by its command name.
 With a prefix argument, format the macro in a more concise way.
 
-(fn KEYS &optional PREFIX FINISH-HOOK STORE-HOOK)" t nil)
+(fn KEYS &optional PREFIX FINISH-HOOK STORE-HOOK)" t)
 (autoload 'edit-last-kbd-macro "edmacro" "\
 Edit the most recently defined keyboard macro.
 
-(fn &optional PREFIX)" t nil)
+(fn &optional PREFIX)" t)
 (autoload 'edit-named-kbd-macro "edmacro" "\
 Edit a keyboard macro which has been given a name by `name-last-kbd-macro'.
 
-(fn &optional PREFIX)" t nil)
+(fn &optional PREFIX)" t)
 (autoload 'read-kbd-macro "edmacro" "\
 Read the region as a keyboard macro definition.
 The region is interpreted as spelled-out keystrokes, e.g., \"M-x abc RET\".
@@ -8971,7 +8954,7 @@ the result is returned rather than being installed as the 
current macro.
 The result will be a string if possible, otherwise an event vector.
 Second argument NEED-VECTOR means to return an event vector always.
 
-(fn START &optional END)" t nil)
+(fn START &optional END)" t)
 (autoload 'format-kbd-macro "edmacro" "\
 Return the keyboard macro MACRO as a human-readable string.
 This string is suitable for passing to `read-kbd-macro'.
@@ -8979,7 +8962,7 @@ Second argument VERBOSE means to put one command per line 
with comments.
 If VERBOSE is `1', put everything on one line.  If VERBOSE is omitted
 or nil, use a compact 80-column format.
 
-(fn &optional MACRO VERBOSE)" nil nil)
+(fn &optional MACRO VERBOSE)")
 (register-definition-prefixes "edmacro" '("edmacro-"))
 
 
@@ -8990,9 +8973,9 @@ Set scroll margins.
 Argument TOP is the top margin in number of lines or percent of window.
 Argument BOTTOM is the bottom margin in number of lines or percent of window.
 
-(fn TOP BOTTOM)" t nil)
+(fn TOP BOTTOM)" t)
 (autoload 'edt-emulation-on "edt" "\
-Turn on EDT Emulation." t nil)
+Turn on EDT Emulation." t)
 (register-definition-prefixes "edt" '("edt-"))
 
 
@@ -9042,17 +9025,29 @@ When the user exits (with `electric-help-exit', or 
otherwise), the help
 buffer's window disappears (i.e., we use `save-window-excursion'), and
 BUFFER is put back into its original major mode.
 
-(fn THUNK &optional BUFFER NOERASE MINHEIGHT)" nil nil)
+(fn THUNK &optional BUFFER NOERASE MINHEIGHT)")
 (autoload 'electric-helpify "ehelp" "\
 
 
-(fn FUN &optional NAME)" nil nil)
+(fn FUN &optional NAME)")
 (register-definition-prefixes "ehelp" '("ehelp-" "electric-"))
 
 
 ;;; Generated autoloads from emacs-lisp/eieio.el
 
 (push (purecopy '(eieio 1 4)) package--builtin-versions)
+(autoload 'make-instance "eieio" "\
+Make a new instance of CLASS based on INITARGS.
+For example:
+
+  (make-instance \\='foo)
+
+INITARGS is a property list with keywords based on the `:initarg'
+for each slot.  For example:
+
+  (make-instance \\='foo :slot1 value1 :slotN valueN)
+
+(fn CLASS &rest INITARGS)")
 (register-definition-prefixes "eieio" '("child-of-class-p" "defclass" "eieio-" 
"find-class" "obj" "oref" "oset" "same-class-p" "set-slot-value" "slot-" 
"with-slots"))
 
 
@@ -9072,12 +9067,17 @@ This function creates a mock-class for CNAME and adds 
it into
 SUPERCLASSES as children.
 It creates an autoload function for CNAME's constructor.
 
-(fn CNAME SUPERCLASSES FILENAME DOC)" nil nil)
+(fn CNAME SUPERCLASSES FILENAME DOC)")
 (register-definition-prefixes "eieio-core" '("class-" "eieio-" 
"inconsistent-class-hierarchy" "invalid-slot-" "unbound-slot"))
 
 
 ;;; Generated autoloads from emacs-lisp/eieio-custom.el
 
+(autoload 'customize-object "eieio-custom" "\
+Customize OBJ in a custom buffer.
+Optional argument GROUP is the sub-group of slots to display.
+
+(fn OBJ &optional GROUP)")
 (register-definition-prefixes "eieio-custom" '("eieio-"))
 
 
@@ -9088,6 +9088,18 @@ It creates an autoload function for CNAME's constructor.
 
 ;;; Generated autoloads from emacs-lisp/eieio-opt.el
 
+(autoload 'eieio-browse "eieio-opt" "\
+Create an object browser window to show all objects.
+If optional ROOT-CLASS, then start with that, otherwise start with
+variable `eieio-default-superclass'.
+
+(fn &optional ROOT-CLASS)" t)
+(define-obsolete-function-alias 'eieio-help-class 'cl--describe-class "25.1")
+(autoload 'eieio-help-constructor "eieio-opt" "\
+Describe CTR if it is a class constructor.
+
+(fn CTR)")
+(make-obsolete 'eieio-help-constructor '"use `describe-function' or 
`cl--describe-class'." "29.1")
 (register-definition-prefixes "eieio-opt" '("eieio-"))
 
 
@@ -9103,12 +9115,12 @@ It creates an autoload function for CNAME's constructor.
 
 ;;; Generated autoloads from cedet/semantic/bovine/el.el
 
-(register-definition-prefixes "semantic/bovine/el" '("emacs-lisp-mode" 
"semantic-"))
+(register-definition-prefixes "semantic/bovine/el" '("semantic-"))
 
 
 ;;; Generated autoloads from emacs-lisp/eldoc.el
 
-(push (purecopy '(eldoc 1 12 0)) package--builtin-versions)
+(push (purecopy '(eldoc 1 13 0)) package--builtin-versions)
 
 
 ;;; Generated autoloads from elec-pair.el
@@ -9146,7 +9158,7 @@ evaluate `(default-value \\='electric-pair-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'electric-pair-local-mode "elec-pair" "\
 Toggle `electric-pair-mode' only in this buffer.
 
@@ -9166,7 +9178,7 @@ evaluate `(buffer-local-value \\='electric-pair-mode
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "elec-pair" '("electric-pair-"))
 
 
@@ -9195,7 +9207,7 @@ evaluate `elide-head-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'elide-head "elide-head" "\
 Hide header material in buffer according to `elide-head-headers-to-hide'.
 
@@ -9204,8 +9216,8 @@ an elided material again.
 
 This is suitable as an entry on `find-file-hook' or appropriate mode hooks.
 
-(fn &optional ARG)" t nil)
-(make-obsolete 'elide-head 'elide-head-mode '"29.1")
+(fn &optional ARG)" t)
+(make-obsolete 'elide-head 'elide-head-mode "29.1")
 (register-definition-prefixes "elide-head" '("elide-head-"))
 
 
@@ -9214,24 +9226,24 @@ This is suitable as an entry on `find-file-hook' or 
appropriate mode hooks.
 (autoload 'elint-file "elint" "\
 Lint the file FILE.
 
-(fn FILE)" t nil)
+(fn FILE)" t)
 (autoload 'elint-directory "elint" "\
 Lint all the .el files in DIRECTORY.
 A complicated directory may require a lot of memory.
 
-(fn DIRECTORY)" t nil)
+(fn DIRECTORY)" t)
 (autoload 'elint-current-buffer "elint" "\
 Lint the current buffer.
-If necessary, this first calls `elint-initialize'." t nil)
+If necessary, this first calls `elint-initialize'." t)
 (autoload 'elint-defun "elint" "\
 Lint the function at point.
-If necessary, this first calls `elint-initialize'." t nil)
+If necessary, this first calls `elint-initialize'." t)
 (autoload 'elint-initialize "elint" "\
 Initialize elint.
 If elint is already initialized, this does nothing, unless
 optional prefix argument REINIT is non-nil.
 
-(fn &optional REINIT)" t nil)
+(fn &optional REINIT)" t)
 (register-definition-prefixes "elint" '("elint-"))
 
 
@@ -9241,14 +9253,14 @@ optional prefix argument REINIT is non-nil.
 Instrument FUNSYM for profiling.
 FUNSYM must be a symbol of a defined function.
 
-(fn FUNSYM)" t nil)
+(fn FUNSYM)" t)
 (autoload 'elp-instrument-list "elp" "\
 Instrument, for profiling, all functions in `elp-function-list'.
 Use optional LIST if provided instead.
 If called interactively, prompt for LIST in the minibuffer;
 type \"nil\" to use `elp-function-list'.
 
-(fn &optional LIST)" t nil)
+(fn &optional LIST)" t)
 (autoload 'elp-instrument-package "elp" "\
 Instrument for profiling, all functions which start with PREFIX.
 For example, to instrument all ELP functions, do the following:
@@ -9260,12 +9272,12 @@ instrumented.  If you run this function, and then later 
load
 further functions that start with PREFIX, they will not be
 instrumented automatically.
 
-(fn PREFIX)" t nil)
+(fn PREFIX)" t)
 (autoload 'elp-results "elp" "\
 Display current profiling results.
 If `elp-reset-after-results' is non-nil, then current profiling
 information for all instrumented functions is reset after results are
-displayed." t nil)
+displayed." t)
 (register-definition-prefixes "elp" '("elp-"))
 
 
@@ -9301,7 +9313,7 @@ displayed." t nil)
 
 ;;; Generated autoloads from eshell/em-extpipe.el
 
-(register-definition-prefixes "em-extpipe" '("em-extpipe--or-with-catch" 
"eshell-"))
+(register-definition-prefixes "em-extpipe" '("eshell-"))
 
 
 ;;; Generated autoloads from eshell/em-glob.el
@@ -9356,7 +9368,7 @@ displayed." t nil)
 
 ;;; Generated autoloads from eshell/em-unix.el
 
-(register-definition-prefixes "em-unix" '("eshell" "nil-blank-string"))
+(register-definition-prefixes "em-unix" '("eshell"))
 
 
 ;;; Generated autoloads from eshell/em-xtra.el
@@ -9369,6 +9381,17 @@ displayed." t nil)
 (register-definition-prefixes "ede/emacs" '("ede-emacs-"))
 
 
+;;; Generated autoloads from textmodes/emacs-authors-mode.el
+
+(autoload 'emacs-authors-mode "emacs-authors-mode" "\
+Major mode for viewing \"etc/AUTHORS\" from the Emacs distribution.
+Provides some basic font locking and not much else.
+
+(fn)" t)
+(define-obsolete-function-alias 'etc-authors-mode #'emacs-authors-mode "29.1")
+(register-definition-prefixes "emacs-authors-mode" '("emacs-authors-" 
"etc-authors-"))
+
+
 ;;; Generated autoloads from emacs-lock.el
 
 (autoload 'emacs-lock-mode "emacs-lock" "\
@@ -9392,8 +9415,8 @@ Other values are interpreted as usual.
 See also `emacs-lock-unlockable-modes', which exempts buffers under
 some major modes from being locked under some circumstances.
 
-(fn &optional ARG)" t nil)
-(register-definition-prefixes "emacs-lock" '("emacs-lock-" 
"toggle-emacs-lock"))
+(fn &optional ARG)" t)
+(register-definition-prefixes "emacs-lock" '("emacs-lock-"))
 
 
 ;;; Generated autoloads from textmodes/emacs-news-mode.el
@@ -9401,11 +9424,11 @@ some major modes from being locked under some 
circumstances.
 (autoload 'emacs-news-mode "emacs-news-mode" "\
 Major mode for editing the Emacs NEWS file.
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'emacs-news-view-mode "emacs-news-mode" "\
 Major mode for viewing the Emacs NEWS file.
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "emacs-news-mode" '("emacs-news-"))
 
 
@@ -9419,7 +9442,7 @@ Already submitted bugs can be found in the Emacs bug 
tracker:
 
   
https://debbugs.gnu.org/cgi/pkgreport.cgi?package=emacs;max-bugs=100;base-order=1;bug-rev=1
 
-(fn TOPIC &optional UNUSED)" t nil)
+(fn TOPIC &optional UNUSED)" t)
 (set-advertised-calling-convention 'report-emacs-bug '(topic) '"24.5")
 (autoload 'submit-emacs-patch "emacsbug" "\
 Send an Emacs patch to the Emacs maintainers.
@@ -9427,7 +9450,7 @@ Interactively, you will be prompted for SUBJECT and a 
patch FILE
 name (which will be attached to the mail).  You will end up in a
 Message buffer where you can explain more about the patch.
 
-(fn SUBJECT FILE)" t nil)
+(fn SUBJECT FILE)" t)
 (register-definition-prefixes "emacsbug" '("emacs-bug--system-description" 
"report-emacs-bug-"))
 
 
@@ -9436,65 +9459,60 @@ Message buffer where you can explain more about the 
patch.
 (autoload 'emerge-files "emerge" "\
 Run Emerge on two files FILE-A and FILE-B.
 
-(fn ARG FILE-A FILE-B FILE-OUT &optional STARTUP-HOOKS QUIT-HOOKS)" t nil)
+(fn ARG FILE-A FILE-B FILE-OUT &optional STARTUP-HOOKS QUIT-HOOKS)" t)
 (autoload 'emerge-files-with-ancestor "emerge" "\
 Run Emerge on two files, giving another file as the ancestor.
 
-(fn ARG FILE-A FILE-B FILE-ANCESTOR FILE-OUT &optional STARTUP-HOOKS 
QUIT-HOOKS)" t nil)
+(fn ARG FILE-A FILE-B FILE-ANCESTOR FILE-OUT &optional STARTUP-HOOKS 
QUIT-HOOKS)" t)
 (autoload 'emerge-buffers "emerge" "\
 Run Emerge on two buffers BUFFER-A and BUFFER-B.
 
-(fn BUFFER-A BUFFER-B &optional STARTUP-HOOKS QUIT-HOOKS)" t nil)
+(fn BUFFER-A BUFFER-B &optional STARTUP-HOOKS QUIT-HOOKS)" t)
 (autoload 'emerge-buffers-with-ancestor "emerge" "\
 Run Emerge on two buffers, giving another buffer as the ancestor.
 
-(fn BUFFER-A BUFFER-B BUFFER-ANCESTOR &optional STARTUP-HOOKS QUIT-HOOKS)" t 
nil)
-(autoload 'emerge-files-command "emerge" nil nil nil)
-(autoload 'emerge-files-with-ancestor-command "emerge" nil nil nil)
+(fn BUFFER-A BUFFER-B BUFFER-ANCESTOR &optional STARTUP-HOOKS QUIT-HOOKS)" t)
+(autoload 'emerge-files-command "emerge")
+(autoload 'emerge-files-with-ancestor-command "emerge")
 (autoload 'emerge-files-remote "emerge" "\
 
 
-(fn FILE-A FILE-B FILE-OUT)" nil nil)
+(fn FILE-A FILE-B FILE-OUT)")
 (autoload 'emerge-files-with-ancestor-remote "emerge" "\
 
 
-(fn FILE-A FILE-B FILE-ANC FILE-OUT)" nil nil)
+(fn FILE-A FILE-B FILE-ANC FILE-OUT)")
 (autoload 'emerge-revisions "emerge" "\
 Emerge two RCS revisions of a file.
 
-(fn ARG FILE REVISION-A REVISION-B &optional STARTUP-HOOKS QUIT-HOOKS)" t nil)
+(fn ARG FILE REVISION-A REVISION-B &optional STARTUP-HOOKS QUIT-HOOKS)" t)
 (autoload 'emerge-revisions-with-ancestor "emerge" "\
 Emerge two RCS revisions of a file, with another revision as ancestor.
 
-(fn ARG FILE REVISION-A REVISION-B ANCESTOR &optional STARTUP-HOOKS 
QUIT-HOOKS)" t nil)
+(fn ARG FILE REVISION-A REVISION-B ANCESTOR &optional STARTUP-HOOKS 
QUIT-HOOKS)" t)
 (autoload 'emerge-merge-directories "emerge" "\
 
 
-(fn A-DIR B-DIR ANCESTOR-DIR OUTPUT-DIR)" t nil)
+(fn A-DIR B-DIR ANCESTOR-DIR OUTPUT-DIR)" t)
 (register-definition-prefixes "emerge" '("emerge-"))
 
 
 ;;; Generated autoloads from international/emoji.el
 
 (autoload 'emoji-insert "emoji" "\
-Choose and insert an emoji glyph.
-If TEXT (interactively, the prefix argument), choose the emoji
-by typing its Unicode Standard name (with completion), instead
-of selecting from emoji display.
-
-(fn &optional TEXT)" t nil)
+Choose and insert an emoji glyph." t)
 (autoload 'emoji-recent "emoji" "\
-Choose and insert one of the recently-used emoji glyphs." t nil)
+Choose and insert one of the recently-used emoji glyphs." t)
 (autoload 'emoji-search "emoji" "\
 Choose and insert an emoji glyph by typing its Unicode name.
 This command prompts for an emoji name, with completion, and
 inserts it.  It recognizes the Unicode Standard names of emoji,
-and also consults the `emoji-alternate-names' alist." t nil)
+and also consults the `emoji-alternate-names' alist." t)
 (autoload 'emoji-list "emoji" "\
 List emojis and insert the one that's selected.
 Select the emoji by typing \\<emoji-list-mode-map>\\[emoji-list-select] on its 
picture.
 The glyph will be inserted into the buffer that was current
-when the command was invoked." t nil)
+when the command was invoked." t)
 (autoload 'emoji-describe "emoji" "\
 Display the name of the grapheme cluster composed from GLYPH.
 GLYPH should be a string of one or more characters which together
@@ -9504,7 +9522,14 @@ could also be any character, not just emoji).
 If called from Lisp, return the name as a string; return nil if
 the name is not known.
 
-(fn GLYPH &optional INTERACTIVE)" t nil)
+(fn GLYPH &optional INTERACTIVE)" t)
+(autoload 'emoji-zoom-increase "emoji" "\
+Increase the size of the character under point.
+FACTOR is the multiplication factor for the size.
+
+(fn &optional FACTOR)" t)
+(autoload 'emoji-zoom-decrease "emoji" "\
+Decrease the size of the character under point." t)
 (register-definition-prefixes "emoji" '("emoji-"))
 
 
@@ -9539,15 +9564,15 @@ evaluate `enriched-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'enriched-encode "enriched" "\
 
 
-(fn FROM TO ORIG-BUF)" nil nil)
+(fn FROM TO ORIG-BUF)")
 (autoload 'enriched-decode "enriched" "\
 
 
-(fn FROM TO)" nil nil)
+(fn FROM TO)")
 (register-definition-prefixes "enriched" '("enriched-"))
 
 
@@ -9556,11 +9581,11 @@ it is disabled.
 (autoload 'epa-list-keys "epa" "\
 List all keys matched with NAME from the public keyring.
 
-(fn &optional NAME)" t nil)
+(fn &optional NAME)" t)
 (autoload 'epa-list-secret-keys "epa" "\
 List all keys matched with NAME from the private keyring.
 
-(fn &optional NAME)" t nil)
+(fn &optional NAME)" t)
 (autoload 'epa-select-keys "epa" "\
 Display a user's keyring and ask him to select keys.
 CONTEXT is an `epg-context'.
@@ -9569,24 +9594,24 @@ NAMES is a list of strings to be matched with keys.  If 
it is nil, all
 the keys are listed.
 If SECRET is non-nil, list secret keys instead of public keys.
 
-(fn CONTEXT PROMPT &optional NAMES SECRET)" nil nil)
+(fn CONTEXT PROMPT &optional NAMES SECRET)")
 (autoload 'epa-decrypt-file "epa" "\
 Decrypt DECRYPT-FILE into PLAIN-FILE.
 If you do not specify PLAIN-FILE, this functions prompts for the value to use.
 
-(fn DECRYPT-FILE &optional PLAIN-FILE)" t nil)
+(fn DECRYPT-FILE &optional PLAIN-FILE)" t)
 (autoload 'epa-verify-file "epa" "\
 Verify FILE.
 
-(fn FILE)" t nil)
+(fn FILE)" t)
 (autoload 'epa-sign-file "epa" "\
 Sign FILE by SIGNERS keys selected.
 
-(fn FILE SIGNERS MODE)" t nil)
+(fn FILE SIGNERS MODE)" t)
 (autoload 'epa-encrypt-file "epa" "\
 Encrypt FILE for RECIPIENTS.
 
-(fn FILE RECIPIENTS)" t nil)
+(fn FILE RECIPIENTS)" t)
 (autoload 'epa-decrypt-region "epa" "\
 Decrypt the current region between START and END.
 
@@ -9610,14 +9635,14 @@ For example:
     (epg-decrypt-string context (buffer-substring start end))
     \\='utf-8))
 
-(fn START END &optional MAKE-BUFFER-FUNCTION)" t nil)
+(fn START END &optional MAKE-BUFFER-FUNCTION)" t)
 (autoload 'epa-decrypt-armor-in-region "epa" "\
 Decrypt OpenPGP armors in the current region between START and END.
 
 Don't use this command in Lisp programs!
 See the reason described in the `epa-decrypt-region' documentation.
 
-(fn START END)" t nil)
+(fn START END)" t)
 (function-put 'epa-decrypt-armor-in-region 'interactive-only 't)
 (autoload 'epa-verify-region "epa" "\
 Verify the current region between START and END.
@@ -9637,7 +9662,7 @@ For example:
     (epg-verify-string context (buffer-substring start end))
     \\='utf-8))
 
-(fn START END)" t nil)
+(fn START END)" t)
 (function-put 'epa-verify-region 'interactive-only 't)
 (autoload 'epa-verify-cleartext-in-region "epa" "\
 Verify OpenPGP cleartext signed messages in current region from START to END.
@@ -9645,7 +9670,7 @@ Verify OpenPGP cleartext signed messages in current 
region from START to END.
 Don't use this command in Lisp programs!
 See the reason described in the `epa-verify-region' documentation.
 
-(fn START END)" t nil)
+(fn START END)" t)
 (function-put 'epa-verify-cleartext-in-region 'interactive-only 't)
 (autoload 'epa-sign-region "epa" "\
 Sign the current region between START and END by SIGNERS keys selected.
@@ -9664,7 +9689,7 @@ For example:
     context
     (encode-coding-string (buffer-substring start end) \\='utf-8)))
 
-(fn START END SIGNERS MODE)" t nil)
+(fn START END SIGNERS MODE)" t)
 (function-put 'epa-sign-region 'interactive-only 't)
 (autoload 'epa-encrypt-region "epa" "\
 Encrypt the current region between START and END for RECIPIENTS.
@@ -9684,45 +9709,45 @@ For example:
     (encode-coding-string (buffer-substring start end) \\='utf-8)
     nil))
 
-(fn START END RECIPIENTS SIGN SIGNERS)" t nil)
+(fn START END RECIPIENTS SIGN SIGNERS)" t)
 (function-put 'epa-encrypt-region 'interactive-only 't)
 (autoload 'epa-delete-keys "epa" "\
 Delete selected KEYS.
 
-(fn KEYS &optional ALLOW-SECRET)" t nil)
+(fn KEYS &optional ALLOW-SECRET)" t)
 (autoload 'epa-import-keys "epa" "\
 Import keys from FILE.
 
-(fn FILE)" t nil)
+(fn FILE)" t)
 (autoload 'epa-import-keys-region "epa" "\
 Import keys from the region.
 
-(fn START END)" t nil)
+(fn START END)" t)
 (autoload 'epa-import-armor-in-region "epa" "\
 Import keys in the OpenPGP armor format in the current region from START to 
END.
 
-(fn START END)" t nil)
+(fn START END)" t)
 (autoload 'epa-export-keys "epa" "\
 Export selected KEYS to FILE.
 
-(fn KEYS FILE)" t nil)
+(fn KEYS FILE)" t)
 (autoload 'epa-insert-keys "epa" "\
 Insert selected KEYS after the point.
 
-(fn KEYS)" t nil)
+(fn KEYS)" t)
 (register-definition-prefixes "epa" '("epa-"))
 
 
 ;;; Generated autoloads from epa-dired.el
 
 (autoload 'epa-dired-do-decrypt "epa-dired" "\
-Decrypt marked files." t nil)
+Decrypt marked files." t)
 (autoload 'epa-dired-do-verify "epa-dired" "\
-Verify marked files." t nil)
+Verify marked files." t)
 (autoload 'epa-dired-do-sign "epa-dired" "\
-Sign marked files." t nil)
+Sign marked files." t)
 (autoload 'epa-dired-do-encrypt "epa-dired" "\
-Encrypt marked files." t nil)
+Encrypt marked files." t)
 
 
 ;;; Generated autoloads from epa-file.el
@@ -9730,9 +9755,9 @@ Encrypt marked files." t nil)
 (autoload 'epa-file-handler "epa-file" "\
 
 
-(fn OPERATION &rest ARGS)" nil nil)
-(autoload 'epa-file-enable "epa-file" nil t nil)
-(autoload 'epa-file-disable "epa-file" nil t nil)
+(fn OPERATION &rest ARGS)")
+(autoload 'epa-file-enable "epa-file" nil t)
+(autoload 'epa-file-disable "epa-file" nil t)
 (register-definition-prefixes "epa-file" '("epa-"))
 
 
@@ -9749,7 +9774,7 @@ exact matches.
 Note that the request may fail if the query is not specific
 enough, since keyservers have strict timeout settings.
 
-(fn QUERY EXACT)" t nil)
+(fn QUERY EXACT)" t)
 (register-definition-prefixes "epa-ks" '("epa-k"))
 
 
@@ -9772,14 +9797,14 @@ evaluate `epa-mail-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'epa-mail-decrypt "epa-mail" "\
 Decrypt OpenPGP armors in the current buffer.
-The buffer is expected to contain a mail message." t nil)
+The buffer is expected to contain a mail message." t)
 (function-put 'epa-mail-decrypt 'interactive-only 't)
 (autoload 'epa-mail-verify "epa-mail" "\
 Verify OpenPGP cleartext signed messages in the current buffer.
-The buffer is expected to contain a mail message." t nil)
+The buffer is expected to contain a mail message." t)
 (function-put 'epa-mail-verify 'interactive-only 't)
 (autoload 'epa-mail-sign "epa-mail" "\
 Sign the current buffer.
@@ -9788,7 +9813,7 @@ performed with your default key.
 With prefix argument, asks you to select interactively the key to
 use from your key ring.
 
-(fn START END SIGNERS MODE)" t nil)
+(fn START END SIGNERS MODE)" t)
 (function-put 'epa-mail-sign 'interactive-only 't)
 (autoload 'epa-mail-encrypt "epa-mail" "\
 Encrypt the outgoing mail message in the current buffer.
@@ -9803,10 +9828,10 @@ or nil meaning use the defaults.
 
 SIGNERS is a list of keys to sign the message with.
 
-(fn &optional RECIPIENTS SIGNERS)" t nil)
+(fn &optional RECIPIENTS SIGNERS)" t)
 (autoload 'epa-mail-import-keys "epa-mail" "\
 Import keys in the OpenPGP armor format in the current buffer.
-The buffer is expected to contain a mail message." t nil)
+The buffer is expected to contain a mail message." t)
 (function-put 'epa-mail-import-keys 'interactive-only 't)
 (defvar epa-global-mail-mode nil "\
 Non-nil if Epa-Global-Mail mode is enabled.
@@ -9833,7 +9858,7 @@ evaluate `(default-value \\='epa-global-mail-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "epa-mail" '("epa-mail-"))
 
 
@@ -9843,7 +9868,7 @@ it is disabled.
 (autoload 'epg-make-context "epg" "\
 Return a context object.
 
-(fn &optional PROTOCOL ARMOR TEXTMODE INCLUDE-CERTS CIPHER-ALGORITHM 
DIGEST-ALGORITHM COMPRESS-ALGORITHM)" nil nil)
+(fn &optional PROTOCOL ARMOR TEXTMODE INCLUDE-CERTS CIPHER-ALGORITHM 
DIGEST-ALGORITHM COMPRESS-ALGORITHM)")
 (register-definition-prefixes "epg" '("epg-"))
 
 
@@ -9860,10 +9885,10 @@ Then it walks through PROGRAM-ALIST or
 Otherwise, it tries the programs listed in the entry until the
 version requirement is met.
 
-(fn PROTOCOL &optional NO-CACHE PROGRAM-ALIST)" nil nil)
+(fn PROTOCOL &optional NO-CACHE PROGRAM-ALIST)")
 (autoload 'epg-configuration "epg-config" "\
-Return a list of internal configuration parameters of `epg-gpg-program'." nil 
nil)
-(make-obsolete 'epg-configuration 'epg-find-configuration '"25.1")
+Return a list of internal configuration parameters of `epg-gpg-program'.")
+(make-obsolete 'epg-configuration 'epg-find-configuration "25.1")
 (autoload 'epg-check-configuration "epg-config" "\
 Verify that a sufficient version of GnuPG is installed.
 CONFIG should be a `epg-configuration' object (a plist).
@@ -9872,11 +9897,11 @@ REQ-VERSIONS should be a list with elements of the form 
(MIN
 semi-open range of acceptable versions.  REQ-VERSIONS may also be
 a single minimum version string.
 
-(fn CONFIG &optional REQ-VERSIONS)" nil nil)
+(fn CONFIG &optional REQ-VERSIONS)")
 (autoload 'epg-expand-group "epg-config" "\
 Look at CONFIG and try to expand GROUP.
 
-(fn CONFIG GROUP)" nil nil)
+(fn CONFIG GROUP)")
 (register-definition-prefixes "epg-config" '("epg-"))
 
 
@@ -9884,7 +9909,7 @@ Look at CONFIG and try to expand GROUP.
 
 (push (purecopy '(erc 5 4 1)) package--builtin-versions)
 (autoload 'erc-select-read-args "erc" "\
-Prompt the user for values of nick, server, port, and password." nil nil)
+Prompt the user for values of nick, server, port, and password.")
 (autoload 'erc "erc" "\
 ERC is a powerful, modular, and extensible IRC client.
 This function is the main entry point for ERC.
@@ -9895,8 +9920,10 @@ 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))
+   id
 
 That is, if called with
 
@@ -9906,7 +9933,11 @@ 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.
 
-(fn &key (SERVER (erc-compute-server)) (PORT (erc-compute-port)) (NICK 
(erc-compute-nick)) PASSWORD (FULL-NAME (erc-compute-full-name)))" 
'((erc-select-read-args)) nil)
+When present, ID should be an opaque object used to identify the
+connection unequivocally.  This is rarely needed and not available
+interactively.
+
+(fn &key (SERVER (erc-compute-server)) (PORT (erc-compute-port)) (NICK 
(erc-compute-nick)) (USER (erc-compute-user)) PASSWORD (FULL-NAME 
(erc-compute-full-name)) ID)" '((erc-select-read-args)))
 (defalias 'erc-select #'erc)
 (autoload 'erc-tls "erc" "\
 ERC is a powerful, modular, and extensible IRC client.
@@ -9922,6 +9953,7 @@ Non-interactively, it takes the keyword arguments
    password
    (full-name (erc-compute-full-name))
    client-certificate
+   id
 
 That is, if called with
 
@@ -9946,13 +9978,19 @@ Example usage:
              \\='(\"/home/bandali/my-cert.key\"
                \"/home/bandali/my-cert.crt\"))
 
-(fn &key (SERVER (erc-compute-server)) (PORT (erc-compute-port)) (NICK 
(erc-compute-nick)) PASSWORD (FULL-NAME (erc-compute-full-name)) 
CLIENT-CERTIFICATE)" '((let ((erc-default-port erc-default-port-tls)) 
(erc-select-read-args))) nil)
+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.
+
+(fn &key (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 ID)" '((let ((erc-default-port 
erc-default-port-tls)) (erc-select-read-args))))
 (autoload 'erc-handle-irc-url "erc" "\
 Use ERC to IRC on HOST:PORT in CHANNEL as USER with PASSWORD.
 If ERC is already connected to HOST:PORT, simply /join CHANNEL.
 Otherwise, connect to HOST:PORT as USER and /join CHANNEL.
 
-(fn HOST PORT CHANNEL USER PASSWORD)" nil nil)
+(fn HOST PORT CHANNEL USER PASSWORD)")
 (register-definition-prefixes "erc" '("define-erc-module" "erc-"))
 
 
@@ -10061,9 +10099,10 @@ Otherwise, connect to HOST:PORT as USER and /join 
CHANNEL.
 (autoload 'erc-determine-network "erc-networks" "\
 Return the name of the network or \"Unknown\" as a symbol.
 Use the server parameter NETWORK if provided, otherwise parse the
-server name and search for a match in `erc-networks-alist'." nil nil)
+server name and search for a match in `erc-networks-alist'.")
+(make-obsolete 'erc-determine-network '"maybe see `erc-networks--determine'" 
"29.1")
 (autoload 'erc-server-select "erc-networks" "\
-Interactively select a server to connect to using `erc-server-alist'." t nil)
+Interactively select a server to connect to using `erc-server-alist'." t)
 (register-definition-prefixes "erc-networks" '("erc-"))
 
 
@@ -10172,7 +10211,7 @@ ert-run-tests-batch-and-exit\" useful.
 
 Returns the stats object.
 
-(fn &optional SELECTOR)" nil nil)
+(fn &optional SELECTOR)")
 (autoload 'ert-run-tests-batch-and-exit "ert" "\
 Like `ert-run-tests-batch', but exits Emacs when done.
 
@@ -10181,25 +10220,25 @@ on unexpected results, or 2 if the tool detected an 
error outside
 of the tests (e.g. invalid SELECTOR or bug in the code that runs
 the tests).
 
-(fn &optional SELECTOR)" nil nil)
+(fn &optional SELECTOR)")
 (autoload 'ert-run-tests-interactively "ert" "\
 Run the tests specified by SELECTOR and display the results in a buffer.
 
 SELECTOR works as described in `ert-select-tests'.
 
-(fn SELECTOR)" t nil)
+(fn SELECTOR)" t)
 (defalias 'ert #'ert-run-tests-interactively)
 (autoload 'ert-describe-test "ert" "\
 Display the documentation for TEST-OR-TEST-NAME (a symbol or ert-test).
 
-(fn TEST-OR-TEST-NAME)" t nil)
+(fn TEST-OR-TEST-NAME)" t)
 (register-definition-prefixes "ert" '("ert-"))
 
 
 ;;; Generated autoloads from emacs-lisp/ert-x.el
 
 (autoload 'ert-kill-all-test-buffers "ert-x" "\
-Kill all test buffers that are still live." t nil)
+Kill all test buffers that are still live." t)
 (register-definition-prefixes "ert-x" '("ert-"))
 
 
@@ -10211,7 +10250,7 @@ This mode mainly provides some font locking.
 
 \\{erts-mode-map}
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "erts-mode" '("erts-"))
 
 
@@ -10240,11 +10279,11 @@ This mode mainly provides some font locking.
 (autoload 'eshell-mode "esh-mode" "\
 Emacs shell interactive mode.
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'eshell-bookmark-jump "esh-mode" "\
 Default bookmark handler for Eshell buffers.
 
-(fn BOOKMARK)" nil nil)
+(fn BOOKMARK)")
 (register-definition-prefixes "esh-mode" '("eshell"))
 
 
@@ -10293,12 +10332,12 @@ value of `eshell-buffer-name', which see.
 Eshell is a shell-like command interpreter.  For more
 information on Eshell, see Info node `(eshell)Top'.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'eshell-command "eshell" "\
 Execute the Eshell command string COMMAND.
 With prefix ARG, insert output into the current buffer at point.
 
-(fn &optional COMMAND ARG)" t nil)
+(fn &optional COMMAND ARG)" t)
 (autoload 'eshell-command-result "eshell" "\
 Execute the given Eshell COMMAND, and return the result.
 The result might be any Lisp object.
@@ -10306,7 +10345,7 @@ If STATUS-VAR is a symbol, it will be set to the exit 
status of the
 command.  This is the only way to determine whether the value returned
 corresponding to a successful execution.
 
-(fn COMMAND &optional STATUS-VAR)" nil nil)
+(fn COMMAND &optional STATUS-VAR)")
 (register-definition-prefixes "eshell" '("eshell-"))
 
 
@@ -10357,7 +10396,7 @@ Otherwise, `find-tag-default' is used.")
 (autoload 'tags-table-mode "etags" "\
 Major mode for tags table file buffers.
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'visit-tags-table "etags" "\
 Tell tags commands to use tags table file FILE.
 FILE should be the name of a file created with the `etags' program.
@@ -10370,7 +10409,7 @@ When you find a tag with \\[find-tag], the buffer it 
finds the tag
 in is given a local value of this variable which is the name of the tags
 file the tag was in.
 
-(fn FILE &optional LOCAL)" t nil)
+(fn FILE &optional LOCAL)" t)
 (autoload 'visit-tags-table-buffer "etags" "\
 Select the buffer containing the current tags table.
 Optional arg CONT specifies which tags table to visit.
@@ -10384,13 +10423,13 @@ Optional second arg CBUF, if non-nil, specifies the 
initial buffer,
 which is important if that buffer has a local value of `tags-file-name'.
 Returns t if it visits a tags table, or nil if there are no more in the list.
 
-(fn &optional CONT CBUF)" nil nil)
+(fn &optional CONT CBUF)")
 (autoload 'tags-table-files "etags" "\
 Return a list of files in the current tags table.
 Assumes the tags table is the current buffer.  The file names are returned
 as they appeared in the `etags' command that created the table, usually
-without directory names." nil nil)
-(autoload 'tags-lazy-completion-table "etags" nil nil nil)
+without directory names.")
+(autoload 'tags-lazy-completion-table "etags")
  (defun tags-completion-at-point-function ()
   (if (or tags-table-list tags-file-name)
       (progn
@@ -10416,7 +10455,7 @@ Contrast this with the ring of marks gone to by the 
command.
 
 See documentation of variable `tags-file-name'.
 
-(fn TAGNAME &optional NEXT-P REGEXP-P)" t nil)
+(fn TAGNAME &optional NEXT-P REGEXP-P)" t)
 (autoload 'find-tag "etags" "\
 Find tag (in current tags table) whose name contains TAGNAME.
 Select the buffer containing the tag's definition, and move point there.
@@ -10436,8 +10475,8 @@ Contrast this with the ring of marks gone to by the 
command.
 
 See documentation of variable `tags-file-name'.
 
-(fn TAGNAME &optional NEXT-P REGEXP-P)" t nil)
-(make-obsolete 'find-tag 'xref-find-definitions '"25.1")
+(fn TAGNAME &optional NEXT-P REGEXP-P)" t)
+(make-obsolete 'find-tag 'xref-find-definitions "25.1")
 (autoload 'find-tag-other-window "etags" "\
 Find tag (in current tags table) whose name contains TAGNAME.
 Select the buffer containing the tag's definition in another window, and
@@ -10458,8 +10497,8 @@ Contrast this with the ring of marks gone to by the 
command.
 
 See documentation of variable `tags-file-name'.
 
-(fn TAGNAME &optional NEXT-P REGEXP-P)" t nil)
-(make-obsolete 'find-tag-other-window 'xref-find-definitions-other-window 
'"25.1")
+(fn TAGNAME &optional NEXT-P REGEXP-P)" t)
+(make-obsolete 'find-tag-other-window 'xref-find-definitions-other-window 
"25.1")
 (autoload 'find-tag-other-frame "etags" "\
 Find tag (in current tags table) whose name contains TAGNAME.
 Select the buffer containing the tag's definition in another frame, and
@@ -10480,8 +10519,8 @@ Contrast this with the ring of marks gone to by the 
command.
 
 See documentation of variable `tags-file-name'.
 
-(fn TAGNAME &optional NEXT-P)" t nil)
-(make-obsolete 'find-tag-other-frame 'xref-find-definitions-other-frame 
'"25.1")
+(fn TAGNAME &optional NEXT-P)" t)
+(make-obsolete 'find-tag-other-frame 'xref-find-definitions-other-frame "25.1")
 (autoload 'find-tag-regexp "etags" "\
 Find tag (in current tags table) whose name matches REGEXP.
 Select the buffer containing the tag's definition and move point there.
@@ -10500,8 +10539,8 @@ Contrast this with the ring of marks gone to by the 
command.
 
 See documentation of variable `tags-file-name'.
 
-(fn REGEXP &optional NEXT-P OTHER-WINDOW)" t nil)
-(make-obsolete 'find-tag-regexp 'xref-find-apropos '"25.1")
+(fn REGEXP &optional NEXT-P OTHER-WINDOW)" t)
+(make-obsolete 'find-tag-regexp 'xref-find-apropos "25.1")
 (defalias 'pop-tag-mark 'xref-go-back)
 (defalias 'next-file 'tags-next-file)
 (autoload 'tags-next-file "etags" "\
@@ -10517,14 +10556,14 @@ Non-nil second argument NOVISIT means use a temporary 
buffer
 Value is nil if the file was already visited;
 if the file was newly read in, the value is the filename.
 
-(fn &optional INITIALIZE NOVISIT)" t nil)
+(fn &optional INITIALIZE NOVISIT)" t)
 (autoload 'tags-loop-continue "etags" "\
 Continue last \\[tags-search] or \\[tags-query-replace] command.
 Used noninteractively with non-nil argument to begin such a command (the
 argument is passed to `next-file', which see).
 
-(fn &optional FIRST-TIME)" t nil)
-(make-obsolete 'tags-loop-continue 'fileloop-continue '"27.1")
+(fn &optional FIRST-TIME)" t)
+(make-obsolete 'tags-loop-continue 'fileloop-continue "27.1")
 (autoload 'tags-search "etags" "\
 Search through all files listed in tags table for match for REGEXP.
 Stops when a match is found.
@@ -10535,7 +10574,7 @@ files to search.  The search will be restricted to 
these files.
 
 Also see the documentation of the `tags-file-name' variable.
 
-(fn REGEXP &optional FILES)" t nil)
+(fn REGEXP &optional FILES)" t)
 (autoload 'tags-query-replace "etags" "\
 Do `query-replace-regexp' of FROM with TO on all files listed in tags table.
 Third arg DELIMITED (prefix arg) means replace only word-delimited matches.
@@ -10549,7 +10588,7 @@ type \\[help-command] at that time.
 
 For non-interactive use, this is superseded by `fileloop-initialize-replace'.
 
-(fn FROM TO &optional DELIMITED FILES)" t nil)
+(fn FROM TO &optional DELIMITED FILES)" t)
 (set-advertised-calling-convention 'tags-query-replace '(from to &optional 
delimited) '"27.1")
 (autoload 'list-tags "etags" "\
 Display list of tags in file FILE.
@@ -10559,38 +10598,28 @@ usually without a directory specification.  If called
 interactively, FILE defaults to the file name of the current
 buffer.
 
-(fn FILE &optional NEXT-MATCH)" t nil)
+(fn FILE &optional NEXT-MATCH)" t)
 (autoload 'tags-apropos "etags" "\
 Display list of all tags in tags table REGEXP matches.
 
-(fn REGEXP)" t nil)
-(make-obsolete 'tags-apropos 'xref-find-apropos '"25.1")
+(fn REGEXP)" t)
+(make-obsolete 'tags-apropos 'xref-find-apropos "25.1")
 (autoload 'select-tags-table "etags" "\
 Select a tags table file from a menu of those you have already used.
 The list of tags tables to select from is stored in `tags-table-set-list';
-see the doc of that variable if you want to add names to the list." t nil)
+see the doc of that variable if you want to add names to the list." t)
 (autoload 'complete-tag "etags" "\
 Perform tags completion on the text around point.
 Completes to the set of names listed in the current tags table.
 The string to complete is chosen in the same way as the default
-for \\[find-tag] (which see)." t nil)
-(autoload 'etags--xref-backend "etags" nil nil nil)
+for \\[find-tag] (which see)." t)
+(autoload 'etags--xref-backend "etags")
 (register-definition-prefixes "etags" '("default-tags-table-function" "etags-" 
"file-of-tag" "find-tag-" "goto-tag-location-function" 
"initialize-new-tags-table" "last-tag" "list-tags-function" 
"select-tags-table-" "snarf-tag-function" "tag" "verify-tags-table-function"))
 
 
-;;; Generated autoloads from textmodes/etc-authors-mode.el
-
-(autoload 'etc-authors-mode "etc-authors-mode" "\
-Major mode for viewing \"etc/AUTHORS\" from the Emacs distribution.
-Provides some basic font locking and not much else.
-
-(fn)" t nil)
-(register-definition-prefixes "etc-authors-mode" '("etc-authors-"))
-
-
 ;;; Generated autoloads from language/ethio-util.el
 
-(autoload 'setup-ethiopic-environment-internal "ethio-util" nil nil nil)
+(autoload 'setup-ethiopic-environment-internal "ethio-util")
 (autoload 'ethio-sera-to-fidel-buffer "ethio-util" "\
 Convert the current buffer from SERA to FIDEL.
 
@@ -10607,7 +10636,7 @@ even if the buffer is read-only.
 See also the descriptions of the variables
 `ethio-use-colon-for-colon' and `ethio-use-three-dot-question'.
 
-(fn &optional SECONDARY FORCE)" t nil)
+(fn &optional SECONDARY FORCE)" t)
 (autoload 'ethio-sera-to-fidel-region "ethio-util" "\
 Convert the characters in region from SERA to FIDEL.
 
@@ -10624,13 +10653,13 @@ conversion even if the buffer is read-only.
 See also the descriptions of the variables
 `ethio-use-colon-for-colon' and `ethio-use-three-dot-question'.
 
-(fn BEGIN END &optional SECONDARY FORCE)" t nil)
+(fn BEGIN END &optional SECONDARY FORCE)" t)
 (autoload 'ethio-sera-to-fidel-marker "ethio-util" "\
 Convert the regions surrounded by \"<sera>\" and \"</sera>\" from SERA to 
FIDEL.
 Assume that each region begins with `ethio-primary-language'.
 The markers \"<sera>\" and \"</sera>\" themselves are not deleted.
 
-(fn &optional FORCE)" t nil)
+(fn &optional FORCE)" t)
 (autoload 'ethio-fidel-to-sera-buffer "ethio-util" "\
 Replace all the FIDEL characters in the current buffer to the SERA format.
 The variable `ethio-primary-language' specifies the primary
@@ -10647,7 +10676,7 @@ See also the descriptions of the variables
 `ethio-use-colon-for-colon', `ethio-use-three-dot-question',
 `ethio-quote-vowel-always' and `ethio-numeric-reduction'.
 
-(fn &optional SECONDARY FORCE)" t nil)
+(fn &optional SECONDARY FORCE)" t)
 (autoload 'ethio-fidel-to-sera-region "ethio-util" "\
 Replace all the FIDEL characters in the region to the SERA format.
 
@@ -10665,14 +10694,14 @@ See also the descriptions of the variables
 `ethio-use-colon-for-colon', `ethio-use-three-dot-question',
 `ethio-quote-vowel-always' and `ethio-numeric-reduction'.
 
-(fn BEGIN END &optional SECONDARY FORCE)" t nil)
+(fn BEGIN END &optional SECONDARY FORCE)" t)
 (autoload 'ethio-fidel-to-sera-marker "ethio-util" "\
 Convert the regions surrounded by \"<sera>\" and \"</sera>\" from FIDEL to 
SERA.
 The markers \"<sera>\" and \"</sera>\" themselves are not deleted.
 
-(fn &optional FORCE)" t nil)
+(fn &optional FORCE)" t)
 (autoload 'ethio-modify-vowel "ethio-util" "\
-Modify the vowel of the FIDEL that is under the cursor." t nil)
+Modify the vowel of the FIDEL that is under the cursor." t)
 (autoload 'ethio-replace-space "ethio-util" "\
 Replace ASCII spaces with Ethiopic word separators in the region.
 
@@ -10686,15 +10715,15 @@ If CH = 3, with the Ethiopic colon-like word 
separator.
 
 The 2nd and 3rd arguments BEGIN and END specify the region.
 
-(fn CH BEGIN END)" t nil)
+(fn CH BEGIN END)" t)
 (autoload 'ethio-input-special-character "ethio-util" "\
 This function is deprecated.
 
-(fn ARG)" t nil)
+(fn ARG)" t)
 (autoload 'ethio-fidel-to-tex-buffer "ethio-util" "\
-Convert each fidel characters in the current buffer into a fidel-tex command." 
t nil)
+Convert each fidel characters in the current buffer into a fidel-tex command." 
t)
 (autoload 'ethio-tex-to-fidel-buffer "ethio-util" "\
-Convert fidel-tex commands in the current buffer into fidel chars." t nil)
+Convert fidel-tex commands in the current buffer into fidel chars." t)
 (autoload 'ethio-fidel-to-java-buffer "ethio-util" "\
 Convert Ethiopic characters into the Java escape sequences.
 
@@ -10702,22 +10731,22 @@ Each escape sequence is of the form \\uXXXX, where 
XXXX is the
 character's codepoint (in hex) in Unicode.
 
 If `ethio-java-save-lowercase' is non-nil, use [0-9a-f].
-Otherwise, [0-9A-F]." nil nil)
+Otherwise, [0-9A-F].")
 (autoload 'ethio-java-to-fidel-buffer "ethio-util" "\
-Convert the Java escape sequences into corresponding Ethiopic characters." nil 
nil)
+Convert the Java escape sequences into corresponding Ethiopic characters.")
 (autoload 'ethio-find-file "ethio-util" "\
-Transliterate file content into Ethiopic depending on filename suffix." nil 
nil)
+Transliterate file content into Ethiopic depending on filename suffix.")
 (autoload 'ethio-write-file "ethio-util" "\
-Transliterate Ethiopic characters in ASCII depending on the file extension." 
nil nil)
+Transliterate Ethiopic characters in ASCII depending on the file extension.")
 (autoload 'ethio-insert-ethio-space "ethio-util" "\
 Insert the Ethiopic word delimiter (the colon-like character).
 With ARG, insert that many delimiters.
 
-(fn ARG)" t nil)
+(fn ARG)" t)
 (autoload 'ethio-composition-function "ethio-util" "\
 
 
-(fn POS TO FONT-OBJECT STRING DIRECTION)" nil nil)
+(fn POS TO FONT-OBJECT STRING DIRECTION)")
 (register-definition-prefixes "ethio-util" '("ethio-" 
"exit-ethiopic-environment"))
 
 
@@ -10733,17 +10762,17 @@ Set the directory server to SERVER using PROTOCOL.
 Unless NO-SAVE is non-nil, the server is saved as the default
 server for future sessions.
 
-(fn SERVER PROTOCOL &optional NO-SAVE)" t nil)
+(fn SERVER PROTOCOL &optional NO-SAVE)" t)
 (autoload 'eudc-get-email "eudc" "\
 Get the email field of NAME from the directory server.
 If ERROR is non-nil, report an error if there is none.
 
-(fn NAME &optional ERROR)" t nil)
+(fn NAME &optional ERROR)" t)
 (autoload 'eudc-get-phone "eudc" "\
 Get the phone field of NAME from the directory server.
 If ERROR is non-nil, report an error if there is none.
 
-(fn NAME &optional ERROR)" t nil)
+(fn NAME &optional ERROR)" t)
 (autoload 'eudc-expand-try-all "eudc" "\
 Wrap `eudc-expand-inline' with a prefix argument.
 If TRY-ALL-SERVERS -- the prefix argument when called
@@ -10751,7 +10780,7 @@ interactively -- is non-nil, collect results from all 
servers.
 If TRY-ALL-SERVERS is nil, do not try subsequent servers after
 one server returns any match.
 
-(fn &optional TRY-ALL-SERVERS)" t nil)
+(fn &optional TRY-ALL-SERVERS)" t)
 (autoload 'eudc-expand-inline "eudc" "\
 Query the directory server, and expand the query string before point.
 The query string consists of the buffer substring from the point back to
@@ -10767,11 +10796,11 @@ Multiple servers can be tried with the same query 
until one finds a match,
 see `eudc-inline-expansion-servers'.  If TRY-ALL-SERVERS is
 non-nil, collect results from all servers.
 
-(fn &optional SAVE-QUERY-AS-KILL TRY-ALL-SERVERS)" t nil)
+(fn &optional SAVE-QUERY-AS-KILL TRY-ALL-SERVERS)" t)
 (autoload 'eudc-format-inline-expansion-result "eudc" "\
 Format a query result according to `eudc-inline-expansion-format'.
 
-(fn RES QUERY-ATTRS)" nil nil)
+(fn RES QUERY-ATTRS)")
 (autoload 'eudc-query-with-words "eudc" "\
 Query the directory server, and return the matching responses.
 The variable `eudc-inline-query-format' controls how to associate the
@@ -10783,16 +10812,16 @@ Multiple servers can be tried with the same query 
until one finds a match,
 see `eudc-inline-expansion-servers'.   When TRY-ALL-SERVERS is non-nil,
 keep collecting results from subsequent servers after the first match.
 
-(fn QUERY-WORDS &optional TRY-ALL-SERVERS)" nil nil)
+(fn QUERY-WORDS &optional TRY-ALL-SERVERS)")
 (autoload 'eudc-query-form "eudc" "\
 Display a form to query the directory server.
 If given a non-nil argument GET-FIELDS-FROM-SERVER, the function first
 queries the server for the existing fields and displays a corresponding form.
 
-(fn &optional GET-FIELDS-FROM-SERVER)" t nil)
+(fn &optional GET-FIELDS-FROM-SERVER)" t)
 (autoload 'eudc-load-eudc "eudc" "\
 Load the Emacs Unified Directory Client.
-This does nothing except loading eudc by autoload side-effect." t nil)
+This does nothing except loading eudc by autoload side-effect." t)
 (defvar eudc-tools-menu (let ((map (make-sparse-keymap "Directory Servers"))) 
(define-key map [phone] `(menu-item ,(purecopy "Get Phone") eudc-get-phone 
:help ,(purecopy "Get the phone field of name from the directory server"))) 
(define-key map [email] `(menu-item ,(purecopy "Get Email") eudc-get-email 
:help ,(purecopy "Get the email field of NAME from the directory server"))) 
(define-key map [separator-eudc-email] menu-bar-separator) (define-key map 
[expand-inline] `(menu-item ,(purecop [...]
 (fset 'eudc-tools-menu (symbol-value 'eudc-tools-menu))
 (register-definition-prefixes "eudc" '("eudc-"))
@@ -10803,27 +10832,27 @@ This does nothing except loading eudc by autoload 
side-effect." t nil)
 (autoload 'eudc-display-generic-binary "eudc-bob" "\
 Display a button for unidentified binary DATA.
 
-(fn DATA)" nil nil)
+(fn DATA)")
 (autoload 'eudc-display-url "eudc-bob" "\
 Display URL and make it clickable.
 
-(fn URL)" nil nil)
+(fn URL)")
 (autoload 'eudc-display-mail "eudc-bob" "\
 Display e-mail address and make it clickable.
 
-(fn MAIL)" nil nil)
+(fn MAIL)")
 (autoload 'eudc-display-sound "eudc-bob" "\
 Display a button to play the sound DATA.
 
-(fn DATA)" nil nil)
+(fn DATA)")
 (autoload 'eudc-display-jpeg-inline "eudc-bob" "\
 Display the JPEG DATA inline at point if possible.
 
-(fn DATA)" nil nil)
+(fn DATA)")
 (autoload 'eudc-display-jpeg-as-button "eudc-bob" "\
 Display a button for the JPEG DATA.
 
-(fn DATA)" nil nil)
+(fn DATA)")
 (register-definition-prefixes "eudc-bob" '("eudc-bob-"))
 
 
@@ -10841,7 +10870,7 @@ words before point.
 
 The return value is either nil when no match is found, or a
 completion table as required for functions listed in
-`completion-at-point-functions'." nil nil)
+`completion-at-point-functions'.")
 (autoload 'eudc-capf-message-expand-name "eudc-capf" "\
 Email address completion function for `message-completion-alist'.
 
@@ -10850,7 +10879,7 @@ replacing any existing entry for `message-expand-name' 
there,
 with an appropriate regular expression such as for example
 `message-email-recipient-header-regexp', then EUDC will be
 queried for email addresses, and the results delivered to
-`completion-at-point'." nil nil)
+`completion-at-point'.")
 (register-definition-prefixes "eudc-capf" '("eudc-capf-modes"))
 
 
@@ -10858,16 +10887,16 @@ queried for email addresses, and the results 
delivered to
 
 (autoload 'eudc-insert-record-at-point-into-bbdb "eudc-export" "\
 Insert record at point into the BBDB database.
-This function can only be called from a directory query result buffer." t nil)
+This function can only be called from a directory query result buffer." t)
 (autoload 'eudc-try-bbdb-insert "eudc-export" "\
-Call `eudc-insert-record-at-point-into-bbdb' if on a record." t nil)
+Call `eudc-insert-record-at-point-into-bbdb' if on a record." t)
 (register-definition-prefixes "eudc-export" '("eudc-"))
 
 
 ;;; Generated autoloads from net/eudc-hotlist.el
 
 (autoload 'eudc-edit-hotlist "eudc-hotlist" "\
-Edit the hotlist of directory servers in a specialized buffer." t nil)
+Edit the hotlist of directory servers in a specialized buffer." t)
 (register-definition-prefixes "eudc-hotlist" '("eudc-hotlist-"))
 
 
@@ -10917,7 +10946,7 @@ Normally, a newline is automatically inserted after the 
header,
 the footer and every node's printed representation.  Optional
 fourth arg NOSEP non-nil inhibits this.
 
-(fn PRETTY-PRINTER &optional HEADER FOOTER NOSEP)" nil nil)
+(fn PRETTY-PRINTER &optional HEADER FOOTER NOSEP)")
 (register-definition-prefixes "ewoc" '("ewoc-"))
 
 
@@ -10941,7 +10970,7 @@ This can also be used on the command line directly:
 
  emacs -f eww-browse https://gnu.org
 
-will start Emacs and browse the GNU web site." t nil)
+will start Emacs and browse the GNU web site." t)
 (autoload 'eww "eww" "\
 Fetch URL and render the page.
 If the input doesn't look like an URL or a domain name, the
@@ -10954,24 +10983,26 @@ If BUFFER, the data to be rendered is in that buffer. 
 In that
 case, this function doesn't actually fetch URL.  BUFFER will be
 killed after rendering.
 
-(fn URL &optional NEW-BUFFER BUFFER)" t nil)
+For more information, see Info node `(eww) Top'.
+
+(fn URL &optional NEW-BUFFER BUFFER)" t)
  (defalias 'browse-web 'eww)
 (autoload 'eww-open-file "eww" "\
 Render FILE using EWW.
 
-(fn FILE)" t nil)
+(fn FILE)" t)
 (autoload 'eww-search-words "eww" "\
 Search the web for the text in the region.
 If region is active (and not whitespace), search the web for
 the text between region beginning and end.  Else, prompt the
 user for a search string.  See the variable `eww-search-prefix'
-for the search engine used." t nil)
+for the search engine used." t)
 (autoload 'eww-mode "eww" "\
 Mode for browsing the web.
 
 \\{eww-mode-map}
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'eww-browse-url "eww" "\
 Ask the EWW browser to load URL.
 
@@ -10987,14 +11018,14 @@ in the tab-bar on an existing frame.  See more 
options in
 Non-interactively, this uses the optional second argument NEW-WINDOW
 instead of `browse-url-new-window-flag'.
 
-(fn URL &optional NEW-WINDOW)" nil nil)
+(fn URL &optional NEW-WINDOW)")
 (autoload 'eww-list-bookmarks "eww" "\
-Display the bookmarks." t nil)
+Display the bookmarks." t)
 (autoload 'eww-bookmark-jump "eww" "\
 Default bookmark handler for EWW buffers.
 
-(fn BOOKMARK)" nil nil)
-(register-definition-prefixes "eww" '("erc--download-directory" "eww-"))
+(fn BOOKMARK)")
+(register-definition-prefixes "eww" '("eww-"))
 
 
 ;;; Generated autoloads from progmodes/executable.el
@@ -11003,14 +11034,14 @@ Default bookmark handler for EWW buffers.
 Check if PROGRAM handles arguments Posix-style.
 If PROGRAM is non-nil, use that instead of \"find\".
 
-(fn &optional PROGRAM)" nil nil)
+(fn &optional PROGRAM)")
 (autoload 'executable-interpret "executable" "\
 Run script with user-specified args, and collect output in a buffer.
 While script runs asynchronously, you can use the \\[next-error]
 command to find the next error.  The buffer is also in `comint-mode' and
 `compilation-shell-minor-mode', so that you can answer any prompts.
 
-(fn COMMAND)" t nil)
+(fn COMMAND)" t)
 (autoload 'executable-set-magic "executable" "\
 Set this buffer's interpreter to INTERPRETER with optional ARGUMENT.
 The variables `executable-magicless-file-regexp', `executable-prefix-env',
@@ -11018,11 +11049,11 @@ The variables `executable-magicless-file-regexp', 
`executable-prefix-env',
 when and how magic numbers are inserted or replaced and scripts made
 executable.
 
-(fn INTERPRETER &optional ARGUMENT NO-QUERY-FLAG INSERT-FLAG)" t nil)
+(fn INTERPRETER &optional ARGUMENT NO-QUERY-FLAG INSERT-FLAG)" t)
 (autoload 'executable-make-buffer-file-executable-if-script-p "executable" "\
 Make file executable according to umask if not already executable.
 If file already has any execute bits set at all, do not change existing
-file modes." nil nil)
+file modes.")
 (register-definition-prefixes "executable" '("executable-"))
 
 
@@ -11055,16 +11086,16 @@ cyclically with the functions 
`expand-jump-to-previous-slot' and
 
 If ARG is omitted, point is placed at the end of the expanded text.
 
-(fn TABLE ABBREVS)" nil nil)
+(fn TABLE ABBREVS)")
 (autoload 'expand-abbrev-hook "expand" "\
 Abbrev hook used to do the expansion job of expand abbrevs.
-See `expand-add-abbrevs'.  Value is non-nil if expansion was done." nil nil)
+See `expand-add-abbrevs'.  Value is non-nil if expansion was done.")
 (autoload 'expand-jump-to-previous-slot "expand" "\
 Move the cursor to the previous slot in the last abbrev expansion.
-This is used only in conjunction with `expand-add-abbrevs'." t nil)
+This is used only in conjunction with `expand-add-abbrevs'." t)
 (autoload 'expand-jump-to-next-slot "expand" "\
 Move the cursor to the next slot in the last abbrev expansion.
-This is used only in conjunction with `expand-add-abbrevs'." t nil)
+This is used only in conjunction with `expand-add-abbrevs'." t)
  (define-key abbrev-map "p" 'expand-jump-to-previous-slot)
  (define-key abbrev-map "n" 'expand-jump-to-next-slot)
 (register-definition-prefixes "expand" '("expand-"))
@@ -11147,7 +11178,7 @@ Variables controlling indentation style and extra 
features:
 Turning on F90 mode calls the value of the variable `f90-mode-hook'
 with no args, if that value is non-nil.
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "f90" '("f90-"))
 
 
@@ -11175,13 +11206,13 @@ attributes.
 The base (lowest priority) remapping may be set to something
 other than the normal definition of FACE via `face-remap-set-base'.
 
-(fn FACE &rest SPECS)" nil nil)
+(fn FACE &rest SPECS)")
 (autoload 'face-remap-reset-base "face-remap" "\
 Set the base remapping of FACE to the normal definition of FACE.
 This causes the remappings specified by `face-remap-add-relative'
 to apply on top of the normal definition of FACE.
 
-(fn FACE)" nil nil)
+(fn FACE)")
 (autoload 'face-remap-set-base "face-remap" "\
 Set the base remapping of FACE in the current buffer to SPECS.
 This causes the remappings specified by `face-remap-add-relative'
@@ -11196,7 +11227,7 @@ to use the normal definition of FACE as the base 
remapping; note that
 this is different from SPECS containing a single value nil, which means
 not to inherit from the global definition of FACE at all.
 
-(fn FACE &rest SPECS)" nil nil)
+(fn FACE &rest SPECS)")
 (autoload 'text-scale-set "face-remap" "\
 Set the scale factor of the default face in the current buffer to LEVEL.
 If LEVEL is non-zero, `text-scale-mode' is enabled, otherwise it is disabled.
@@ -11206,9 +11237,9 @@ Each step scales the height of the default face by the 
variable
 `text-scale-mode-step' (a negative number decreases the height by
 the same amount).
 
-(fn LEVEL)" t nil)
+(fn LEVEL)" t)
 (autoload 'text-scale-increase "face-remap" "\
-Increase the height of the default face in the current buffer by INC steps.
+Increase the font size of the default face in current buffer by INC steps.
 If the new height is other than the default, `text-scale-mode' is enabled.
 
 Each step scales the height of the default face by the variable
@@ -11216,30 +11247,29 @@ Each step scales the height of the default face by 
the variable
 height by the same amount).  As a special case, an argument of 0
 will remove any scaling currently active.
 
-(fn INC)" t nil)
+(fn INC)" t)
 (autoload 'text-scale-decrease "face-remap" "\
-Decrease the height of the default face in the current buffer by DEC steps.
+Decrease the font size of the default face in the current buffer by DEC steps.
 See `text-scale-increase' for more details.
 
-(fn DEC)" t nil)
+(fn DEC)" t)
  (define-key ctl-x-map [(control ?+)] 'text-scale-adjust)
  (define-key ctl-x-map [(control ?-)] 'text-scale-adjust)
  (define-key ctl-x-map [(control ?=)] 'text-scale-adjust)
  (define-key ctl-x-map [(control ?0)] 'text-scale-adjust)
 (autoload 'text-scale-adjust "face-remap" "\
-Adjust the height of the default face by INC.
-
+Adjust the font size in the current buffer by INC steps.
 INC may be passed as a numeric prefix argument.
 
 The actual adjustment made depends on the final component of the
 keybinding used to invoke the command, with all modifiers removed:
 
-   +, =   Increase the height of the default face by one step
-   -      Decrease the height of the default face by one step
-   0      Reset the height of the default face to the global default
+   \\`+', \\`='   Increase font size in current buffer by one step
+   \\`-'      Decrease font size in current buffer by one step
+   \\`0'      Reset the font size to the global default
 
 After adjusting, continue to read input events and further adjust
-the face height as long as the input event read
+the font size as long as the input event read
 (with all modifiers removed) is one of the above characters.
 
 Each step scales the height of the default face by the variable
@@ -11253,12 +11283,48 @@ even when it is bound in a non-top-level keymap.  For 
binding in
 a top-level keymap, `text-scale-increase' or
 `text-scale-decrease' may be more appropriate.
 
-(fn INC)" t nil)
+Most faces are affected by these font size changes, but not faces
+that have an explicit `:height' setting.  The two exceptions to
+this are the `default' and `header-line' faces: they will both be
+scaled even if they have an explicit `:height' setting.
+
+See also the related command `global-text-scale-adjust'.
+
+(fn INC)" t)
  (define-key global-map [pinch] 'text-scale-pinch)
 (autoload 'text-scale-pinch "face-remap" "\
 Adjust the height of the default face by the scale in the pinch event EVENT.
 
-(fn EVENT)" t nil)
+(fn EVENT)" t)
+ (define-key ctl-x-map [(control meta ?+)] 'global-text-scale-adjust)
+ (define-key ctl-x-map [(control meta ?=)] 'global-text-scale-adjust)
+ (define-key ctl-x-map [(control meta ?-)] 'global-text-scale-adjust)
+ (define-key ctl-x-map [(control meta ?0)] 'global-text-scale-adjust)
+(autoload 'global-text-scale-adjust "face-remap" "\
+Globally adjust the font size by INCREMENT.
+
+Interactively, INCREMENT may be passed as a numeric prefix argument.
+
+The adjustment made depends on the final component of the key binding
+used to invoke the command, with all modifiers removed:
+
+   \\`+', \\`='   Globally increase the height of the default face
+   \\`-'      Globally decrease the height of the default face
+   \\`0'      Globally reset the height of the default face
+
+After adjusting, further adjust the font size as long as the key,
+with all modifiers removed, is one of the above characters.
+
+Buffer-local face adjustments have higher priority than global
+face adjustments.
+
+The variable `global-text-scale-adjust-resizes-frames' controls
+whether the frames are resized to keep the same number of lines
+and characters per line when the font size is adjusted.
+
+See also the related command `text-scale-adjust'.
+
+(fn INCREMENT)" t)
 (autoload 'buffer-face-mode "face-remap" "\
 Minor mode for a buffer-specific default face.
 
@@ -11279,7 +11345,7 @@ evaluate `buffer-face-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'buffer-face-set "face-remap" "\
 Enable `buffer-face-mode', using face specs SPECS.
 Each argument in SPECS should be a face, i.e. either a face name
@@ -11291,7 +11357,7 @@ one face is listed, that specifies an aggregate face, 
like in a
 This function makes the variable `buffer-face-mode-face' buffer
 local, and sets it to FACE.
 
-(fn &rest SPECS)" t nil)
+(fn &rest SPECS)" t)
 (autoload 'buffer-face-toggle "face-remap" "\
 Toggle `buffer-face-mode', using face specs SPECS.
 Each argument in SPECS should be a face, i.e. either a face name
@@ -11307,14 +11373,14 @@ face, then is left enabled, but the face changed to 
reflect SPECS.
 This function will make the variable `buffer-face-mode-face'
 buffer local, and set it to SPECS.
 
-(fn &rest SPECS)" t nil)
+(fn &rest SPECS)" t)
 (autoload 'variable-pitch-mode "face-remap" "\
 Variable-pitch default-face mode.
 An interface to `buffer-face-mode' which uses the `variable-pitch' face.
 Besides the choice of face, it is the same as `buffer-face-mode'.
 
-(fn &optional ARG)" t nil)
-(register-definition-prefixes "face-remap" '("buffer-face-mode-" "face-" 
"internal-lisp-face-attributes" "text-scale-"))
+(fn &optional ARG)" t)
+(register-definition-prefixes "face-remap" '("buffer-face-mode-" "face-" 
"global-text-scale-adjust-" "internal-lisp-face-attributes" "text-scale-"))
 
 
 ;;; Generated autoloads from facemenu.el
@@ -11336,7 +11402,7 @@ If the optional argument CALLBACK is non-nil, it should 
be a
 function to call each time the user types RET or clicks on a
 color.  The function should accept a single argument, the color name.
 
-(fn &optional LIST BUFFER-NAME CALLBACK)" t nil)
+(fn &optional LIST BUFFER-NAME CALLBACK)" t)
 (register-definition-prefixes "facemenu" '("facemenu-" "list-colors-"))
 
 
@@ -11344,7 +11410,7 @@ color.  The function should accept a single argument, 
the color name.
 
 (push (purecopy '(faceup 0 0 6)) package--builtin-versions)
 (autoload 'faceup-view-buffer "faceup" "\
-Display the faceup representation of the current buffer." t nil)
+Display the faceup representation of the current buffer." t)
 (autoload 'faceup-write-file "faceup" "\
 Save the faceup representation of the current buffer to the file FILE-NAME.
 
@@ -11355,13 +11421,13 @@ If optional second arg CONFIRM is non-nil, this 
function
 asks for confirmation before overwriting an existing file.
 Interactively, confirmation is required unless you supply a prefix argument.
 
-(fn &optional FILE-NAME CONFIRM)" t nil)
+(fn &optional FILE-NAME CONFIRM)" t)
 (autoload 'faceup-render-view-buffer "faceup" "\
 Convert BUFFER containing Faceup markup to a new buffer and display it.
 
-(fn &optional BUFFER)" t nil)
+(fn &optional BUFFER)" t)
 (autoload 'faceup-clean-buffer "faceup" "\
-Remove faceup markup from buffer." t nil)
+Remove faceup markup from buffer." t)
 (autoload 'faceup-defexplainer "faceup" "\
 Define an Ert explainer function for FUNCTION.
 
@@ -11383,24 +11449,24 @@ FUNCTION must return an explanation when the test 
fails and
 (autoload 'feedmail-send-it "feedmail" "\
 Send the current mail buffer using the Feedmail package.
 This is a suitable value for `send-mail-function'.  It can be used
-with various lower-level mechanisms to provide features such as queueing." nil 
nil)
+with various lower-level mechanisms to provide features such as queueing.")
 (autoload 'feedmail-run-the-queue-no-prompts "feedmail" "\
 Like `feedmail-run-the-queue', but suppress confirmation prompts.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'feedmail-run-the-queue-global-prompt "feedmail" "\
 Like `feedmail-run-the-queue', but with a global confirmation prompt.
 This is generally most useful if run non-interactively, since you can
 bail out with an appropriate answer to the global confirmation prompt.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'feedmail-run-the-queue "feedmail" "\
 Visit each message in the feedmail queue directory and send it out.
 Return value is a list of three things: number of messages sent, number of
 messages skipped, and number of non-message things in the queue (commonly
 backup file names and the like).
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'feedmail-queue-reminder "feedmail" "\
 Perform some kind of reminder activity about queued and draft messages.
 Called with an optional symbol argument which says what kind of event
@@ -11420,13 +11486,13 @@ expected to perform the reminder activity.  You can 
supply your own reminder
 functions by redefining `feedmail-queue-reminder-alist'.  If you don't want any
 reminders, you can set `feedmail-queue-reminder-alist' to nil.
 
-(fn &optional WHAT-EVENT)" t nil)
+(fn &optional WHAT-EVENT)" t)
 (register-definition-prefixes "feedmail" '("feedmail-"))
 
 
 ;;; Generated autoloads from ffap.el
 
-(defvar ffap-file-finder 'find-file "\
+(defvar ffap-file-finder #'find-file "\
 The command called by `find-file-at-point' to find a file.")
 (custom-autoload 'ffap-file-finder "ffap" t)
 (autoload 'ffap-next "ffap" "\
@@ -11437,18 +11503,24 @@ Interactively: use a single prefix 
\\[universal-argument] to search backwards,
 double prefix to wrap forward, triple to wrap backwards.
 Actual search is done by the function `ffap-next-guess'.
 
-(fn &optional BACK WRAP)" t nil)
+(fn &optional BACK WRAP)" t)
+(autoload 'ffap-machine-at-point "ffap" "\
+Return machine name at point if it exists, or nil.")
+(autoload 'ffap-url-at-point "ffap" "\
+Return URL from around point if it exists, or nil.
+
+Sets the variable `ffap-string-at-point-region' to the bounds of URL, if any.")
 (autoload 'find-file-at-point "ffap" "\
 Find FILENAME, guessing a default from text around point.
 If `ffap-url-regexp' is not nil, the FILENAME may also be an URL.
 With a prefix, this command behaves exactly like `ffap-file-finder'.
 If `ffap-require-prefix' is set, the prefix meaning is reversed.
-See also the variables `ffap-dired-wildcards', `ffap-newfile-prompt',
+See also the variables `ffap-dired-wildcards',
 `ffap-url-unwrap-local', `ffap-url-unwrap-remote',
 `ffap-file-name-with-spaces', and the functions `ffap-file-at-point'
 and `ffap-url-at-point'.
 
-(fn &optional FILENAME)" t nil)
+(fn &optional FILENAME)" t)
 (defalias 'ffap 'find-file-at-point)
 (autoload 'ffap-menu "ffap" "\
 Put up a menu of files and URLs mentioned in this buffer.
@@ -11457,7 +11529,7 @@ cached in `ffap-menu-alist', and rebuilt by 
`ffap-menu-rescan'.
 The optional RESCAN argument (a prefix, interactively) forces
 a rebuild.  Searches with `ffap-menu-regexp'.
 
-(fn &optional RESCAN)" t nil)
+(fn &optional RESCAN)" t)
 (autoload 'ffap-at-mouse "ffap" "\
 Find file or URL guessed from text around mouse click.
 Interactively, calls `ffap-at-mouse-fallback' if no guess is found.
@@ -11466,17 +11538,17 @@ Return value:
   * if the fallback is called, return whatever it returns
   * otherwise, nil
 
-(fn E)" t nil)
+(fn E)" t)
 (autoload 'dired-at-point "ffap" "\
 Start Dired, defaulting to file at point.  See `ffap'.
 If `dired-at-point-require-prefix' is set, the prefix meaning is reversed.
 
-(fn &optional FILENAME)" t nil)
+(fn &optional FILENAME)" t)
 (autoload 'ffap-guess-file-name-at-point "ffap" "\
 Try to get a file name at point.
-This hook is intended to be put in `file-name-at-point-functions'." nil nil)
+This hook is intended to be put in `file-name-at-point-functions'.")
 (autoload 'ffap-bindings "ffap" "\
-Evaluate the forms in variable `ffap-bindings'." t nil)
+Evaluate the forms in variable `ffap-bindings'." t)
 (register-definition-prefixes "ffap" '("dired-at-point-" "ffap-" 
"find-file-literally-at-point"))
 
 
@@ -11492,7 +11564,7 @@ Add all files in DIRECTORY to the file cache.
 If called from Lisp with a non-nil REGEXP argument is non-nil,
 only add files whose names match REGEXP.
 
-(fn DIRECTORY &optional REGEXP)" t nil)
+(fn DIRECTORY &optional REGEXP)" t)
 (autoload 'file-cache-add-directory-list "filecache" "\
 Add DIRECTORIES (a list of directory names) to the file cache.
 If called interactively, read the directory names one by one.
@@ -11500,21 +11572,21 @@ If the optional REGEXP argument is non-nil, only 
files which match it
 will be added to the cache.  Note that the REGEXP is applied to the
 files in each directory, not to the directory list itself.
 
-(fn DIRECTORIES &optional REGEXP)" t nil)
+(fn DIRECTORIES &optional REGEXP)" t)
 (autoload 'file-cache-add-file "filecache" "\
 Add FILE to the file cache.
 
-(fn FILE)" t nil)
+(fn FILE)" t)
 (autoload 'file-cache-add-directory-using-find "filecache" "\
 Use the `find' command to add files to the file cache.
 Find is run in DIRECTORY.
 
-(fn DIRECTORY)" t nil)
+(fn DIRECTORY)" t)
 (autoload 'file-cache-add-directory-using-locate "filecache" "\
 Use the `locate' command to add files to the file cache.
 STRING is passed as an argument to the locate command.
 
-(fn STRING)" t nil)
+(fn STRING)" t)
 (autoload 'file-cache-add-directory-recursively "filecache" "\
 Add DIR and any subdirectories to the file-cache.
 This function does not use any external programs.
@@ -11522,7 +11594,7 @@ If the optional REGEXP argument is non-nil, only files 
which match it
 will be added to the cache.  Note that the REGEXP is applied to the
 files in each directory, not to the directory list itself.
 
-(fn DIR &optional REGEXP)" t nil)
+(fn DIR &optional REGEXP)" t)
 (autoload 'file-cache-minibuffer-complete "filecache" "\
 Complete a filename in the minibuffer using a preloaded cache.
 Filecache does two kinds of substitution: it completes on names in
@@ -11531,7 +11603,7 @@ the directories that the name is available in.  With a 
prefix argument,
 the name is considered already unique; only the second substitution
 (directories) is done.
 
-(fn ARG)" t nil)
+(fn ARG)" t)
 (register-definition-prefixes "filecache" '("file-cache-"))
 
 
@@ -11548,11 +11620,11 @@ to perform the operation on the current file buffer 
and when done
 should return non-nil to mean that we should immediately continue
 operating on the next file and nil otherwise.
 
-(fn FILES SCAN-FUNCTION OPERATE-FUNCTION)" nil nil)
+(fn FILES SCAN-FUNCTION OPERATE-FUNCTION)")
 (autoload 'fileloop-initialize-search "fileloop" "\
 
 
-(fn REGEXP FILES CASE-FOLD)" nil nil)
+(fn REGEXP FILES CASE-FOLD)")
 (autoload 'fileloop-initialize-replace "fileloop" "\
 Initialize a new round of query&replace on several files.
 FROM is a regexp and TO is the replacement to use.
@@ -11566,7 +11638,7 @@ CASE-FOLD can be t, nil, or `default':
      `case-fold-search' instead.
 DELIMITED if non-nil means replace only word-delimited matches.
 
-(fn FROM TO FILES CASE-FOLD &optional DELIMITED)" nil nil)
+(fn FROM TO FILES CASE-FOLD &optional DELIMITED)")
 (register-definition-prefixes "fileloop" '("fileloop-"))
 
 
@@ -11577,7 +11649,7 @@ Handle a file system monitoring event, coming from 
backends.
 If OBJECT is a filewatch event, call its callback.
 Otherwise, signal a `file-notify-error'.
 
-(fn OBJECT)" t nil)
+(fn OBJECT)" t)
 (function-put 'file-notify-handle-event 'completion-predicate #'ignore)
 (register-definition-prefixes "filenotify" '("file-notify-"))
 
@@ -11600,11 +11672,11 @@ If there is no Local Variables list in the current 
file buffer
 then this function adds the first line containing the string
 `Local Variables:' and the last line containing the string `End:'.
 
-(fn VARIABLE VALUE &optional INTERACTIVE)" t nil)
+(fn VARIABLE VALUE &optional INTERACTIVE)" t)
 (autoload 'delete-file-local-variable "files-x" "\
 Delete all settings of file-local VARIABLE from the Local Variables list.
 
-(fn VARIABLE &optional INTERACTIVE)" t nil)
+(fn VARIABLE &optional INTERACTIVE)" t)
 (autoload 'add-file-local-variable-prop-line "files-x" "\
 Add file-local VARIABLE with its VALUE to the -*- line.
 
@@ -11615,25 +11687,25 @@ the -*- line.
 If there is no -*- line at the beginning of the current file buffer
 then this function adds it.
 
-(fn VARIABLE VALUE &optional INTERACTIVE)" t nil)
+(fn VARIABLE VALUE &optional INTERACTIVE)" t)
 (autoload 'delete-file-local-variable-prop-line "files-x" "\
 Delete all settings of file-local VARIABLE from the -*- line.
 
-(fn VARIABLE &optional INTERACTIVE)" t nil)
+(fn VARIABLE &optional INTERACTIVE)" t)
 (autoload 'add-dir-local-variable "files-x" "\
 Add directory-local VARIABLE with its VALUE and MODE to .dir-locals.el.
 
-(fn MODE VARIABLE VALUE)" t nil)
+(fn MODE VARIABLE VALUE)" t)
 (autoload 'delete-dir-local-variable "files-x" "\
 Delete all MODE settings of file-local VARIABLE from .dir-locals.el.
 
-(fn MODE VARIABLE)" t nil)
+(fn MODE VARIABLE)" t)
 (autoload 'copy-file-locals-to-dir-locals "files-x" "\
-Copy file-local variables to .dir-locals.el." t nil)
+Copy file-local variables to .dir-locals.el." t)
 (autoload 'copy-dir-locals-to-file-locals "files-x" "\
-Copy directory-local variables to the Local Variables list." t nil)
+Copy directory-local variables to the Local Variables list." t)
 (autoload 'copy-dir-locals-to-file-locals-prop-line "files-x" "\
-Copy directory-local variables to the -*- line." t nil)
+Copy directory-local variables to the -*- line." t)
 (defvar enable-connection-local-variables t "\
 Non-nil means enable use of connection-local variables.")
 (autoload 'connection-local-set-profiles "files-x" "\
@@ -11648,7 +11720,7 @@ PROFILES are applied to the corresponding process 
buffer.  The
 variables for a connection profile are defined using
 `connection-local-set-profile-variables'.
 
-(fn CRITERIA &rest PROFILES)" nil nil)
+(fn CRITERIA &rest PROFILES)")
 (autoload 'connection-local-set-profile-variables "files-x" "\
 Map the symbol PROFILE to a list of variable settings.
 VARIABLES is a list that declares connection-local variables for
@@ -11662,13 +11734,13 @@ variables are set in the server's process buffer 
according to the
 VARIABLES list of the connection profile.  The list is processed
 in order.
 
-(fn PROFILE VARIABLES)" nil nil)
+(fn PROFILE VARIABLES)")
 (autoload 'hack-connection-local-variables-apply "files-x" "\
 Apply connection-local variables identified by CRITERIA.
 Other local variables, like file-local and dir-local variables,
 will not be changed.
 
-(fn CRITERIA)" nil nil)
+(fn CRITERIA)")
 (autoload 'with-connection-local-variables "files-x" "\
 Apply connection-local variables according to `default-directory'.
 Execute BODY, and unwind connection-local variables.
@@ -11678,11 +11750,11 @@ Execute BODY, and unwind connection-local variables.
 Apply connection-local variables according to `default-directory'.
 Call BODY-FUN with no args, and then unwind connection-local variables.
 
-(fn BODY-FUN)" nil nil)
+(fn BODY-FUN)")
 (autoload 'path-separator "files-x" "\
-The connection-local value of `path-separator'." nil nil)
+The connection-local value of `path-separator'.")
 (autoload 'null-device "files-x" "\
-The connection-local value of `null-device'." nil nil)
+The connection-local value of `null-device'.")
 (register-definition-prefixes "files-x" '("connection-local-" 
"dir-locals-to-string" "hack-connection-local-variables" "modify-" 
"read-file-local-variable"))
 
 
@@ -11690,7 +11762,7 @@ The connection-local value of `null-device'." nil nil)
 
 (autoload 'filesets-init "filesets" "\
 Filesets initialization.
-Set up hooks, load the cache file -- if existing -- and build the menu." nil 
nil)
+Set up hooks, load the cache file -- if existing -- and build the menu.")
 (register-definition-prefixes "filesets" '("filesets-"))
 
 
@@ -11729,7 +11801,7 @@ For example:
 `default-directory' is used as the initial search path.  The
 result is a string that should be ready for the command line.
 
-(fn &rest SUBFINDS)" nil nil)
+(fn &rest SUBFINDS)")
 (register-definition-prefixes "find-cmd" '("find-"))
 
 
@@ -11747,7 +11819,25 @@ use in place of \"-ls\" as the final argument.
 Collect output in the \"*Find*\" buffer.  To kill the job before
 it finishes, type \\[kill-find].
 
-(fn DIR ARGS)" t nil)
+For more information on how to write valid find expressions for
+ARGS, see Info node `(find) Finding Files'.  If you are not
+using GNU findutils (on macOS and *BSD systems), see instead the
+man page for \"find\".
+
+(fn DIR ARGS)" t)
+(autoload 'find-dired-with-command "find-dired" "\
+Run `find' and go into Dired mode on a buffer of the output.
+The user-supplied COMMAND is run after changing into DIR and should look like
+
+    find . GLOBALARGS \\( ARGS \\) -ls
+
+The car of the variable `find-ls-option' specifies what to
+use in place of \"-ls\" as the starting input.
+
+Collect output in the \"*Find*\" buffer.  To kill the job before
+it finishes, type \\[kill-find].
+
+(fn DIR COMMAND)" t)
 (autoload 'find-name-dired "find-dired" "\
 Search DIR recursively for files matching the globbing PATTERN,
 and run Dired on those files.
@@ -11758,7 +11848,7 @@ The default command run (after changing into DIR) is
 
 See `find-name-arg' to customize the arguments.
 
-(fn DIR PATTERN)" t nil)
+(fn DIR PATTERN)" t)
 (autoload 'find-grep-dired "find-dired" "\
 Find files in DIR that contain matches for REGEXP and start Dired on output.
 The command run (after changing into DIR) is
@@ -11769,8 +11859,8 @@ The command run (after changing into DIR) is
 where the first string in the value of the variable `find-ls-option'
 specifies what to use in place of \"-ls\" as the final argument.
 
-(fn DIR REGEXP)" t nil)
-(register-definition-prefixes "find-dired" '("find-" "kill-find" 
"lookfor-dired"))
+(fn DIR REGEXP)" t)
+(register-definition-prefixes "find-dired" '("find-" "kill-find"))
 
 
 ;;; Generated autoloads from find-file.el
@@ -11789,7 +11879,7 @@ See also the documentation for `ff-find-other-file'.
 
 If optional IN-OTHER-WINDOW is non-nil, find the file in another window.
 
-(fn &optional IN-OTHER-WINDOW)" t nil)
+(fn &optional IN-OTHER-WINDOW)" t)
 (defalias 'ff-find-related-file #'ff-find-other-file)
 (autoload 'ff-find-other-file "find-file" "\
 Find the header or source file corresponding to this file.
@@ -11848,15 +11938,13 @@ Variables of interest include:
  - `ff-file-created-hook'
    List of functions to be called if the other file has been created.
 
-(fn &optional IN-OTHER-WINDOW IGNORE-INCLUDE EVENT)" t nil)
-(define-obsolete-function-alias 'ff-mouse-find-other-file #'ff-find-other-file 
"\
-28.1")
-(define-obsolete-function-alias 'ff-mouse-find-other-file-other-window 
#'ff-find-other-file-other-window "\
-28.1")
+(fn &optional IN-OTHER-WINDOW IGNORE-INCLUDE EVENT)" t)
+(define-obsolete-function-alias 'ff-mouse-find-other-file #'ff-find-other-file 
"28.1")
+(define-obsolete-function-alias 'ff-mouse-find-other-file-other-window 
#'ff-find-other-file-other-window "28.1")
 (autoload 'ff-find-other-file-other-window "find-file" "\
 Visit the file you point at in another window.
 
-(fn EVENT)" t nil)
+(fn EVENT)" t)
 (register-definition-prefixes "find-file" '("cc-" "ff-" 
"modula2-other-file-alist"))
 
 
@@ -11873,25 +11961,25 @@ This function searches `find-library-source-path' if 
non-nil, and
 See the `find-library-include-other-files' user option for
 customizing the candidate completions.
 
-(fn LIBRARY)" t nil)
+(fn LIBRARY)" t)
 (autoload 'read-library-name "find-func" "\
 Read and return a library name, defaulting to the one near point.
 
 A library name is the filename of an Emacs Lisp library located
 in a directory under `load-path' (or `find-library-source-path',
-if non-nil)." nil nil)
+if non-nil).")
 (autoload 'find-library-other-window "find-func" "\
 Find the Emacs Lisp source of LIBRARY in another window.
 
 See `find-library' for more details.
 
-(fn LIBRARY)" t nil)
+(fn LIBRARY)" t)
 (autoload 'find-library-other-frame "find-func" "\
 Find the Emacs Lisp source of LIBRARY in another frame.
 
 See `find-library' for more details.
 
-(fn LIBRARY)" t nil)
+(fn LIBRARY)" t)
 (autoload 'find-function-search-for-symbol "find-func" "\
 Search for SYMBOL's definition of type TYPE in LIBRARY.
 Visit the library in a buffer, and return a cons cell (BUFFER . POSITION),
@@ -11902,7 +11990,7 @@ Otherwise, TYPE specifies the kind of definition,
 and it is interpreted via `find-function-regexp-alist'.
 The search is done in the source for library LIBRARY.
 
-(fn SYMBOL TYPE LIBRARY)" nil nil)
+(fn SYMBOL TYPE LIBRARY)")
 (autoload 'find-function-noselect "find-func" "\
 Return a pair (BUFFER . POINT) pointing to the definition of FUNCTION.
 
@@ -11915,7 +12003,7 @@ If FUNCTION is a built-in function, this function 
normally
 attempts to find it in the Emacs C sources; however, if LISP-ONLY
 is non-nil, signal an error instead.
 
-(fn FUNCTION &optional LISP-ONLY)" nil nil)
+(fn FUNCTION &optional LISP-ONLY)")
 (autoload 'find-function "find-func" "\
 Find the definition of the FUNCTION near point.
 
@@ -11926,19 +12014,19 @@ Set mark before moving, if the buffer already existed.
 
 See also `find-function-recenter-line' and `find-function-after-hook'.
 
-(fn FUNCTION)" t nil)
+(fn FUNCTION)" t)
 (autoload 'find-function-other-window "find-func" "\
 Find, in another window, the definition of FUNCTION near point.
 
 See `find-function' for more details.
 
-(fn FUNCTION)" t nil)
+(fn FUNCTION)" t)
 (autoload 'find-function-other-frame "find-func" "\
 Find, in another frame, the definition of FUNCTION near point.
 
 See `find-function' for more details.
 
-(fn FUNCTION)" t nil)
+(fn FUNCTION)" t)
 (autoload 'find-variable-noselect "find-func" "\
 Return a pair `(BUFFER . POINT)' pointing to the definition of VARIABLE.
 
@@ -11946,7 +12034,7 @@ Finds the library containing the definition of VARIABLE 
in a buffer and
 the point of the definition.  The buffer is not selected.
 If the variable's definition can't be found in the buffer, return (BUFFER).
 
-(fn VARIABLE &optional FILE)" nil nil)
+(fn VARIABLE &optional FILE)")
 (autoload 'find-variable "find-func" "\
 Find the definition of the VARIABLE at or before point.
 
@@ -11958,19 +12046,19 @@ Set mark before moving, if the buffer already existed.
 
 See also `find-function-recenter-line' and `find-function-after-hook'.
 
-(fn VARIABLE)" t nil)
+(fn VARIABLE)" t)
 (autoload 'find-variable-other-window "find-func" "\
 Find, in another window, the definition of VARIABLE near point.
 
 See `find-variable' for more details.
 
-(fn VARIABLE)" t nil)
+(fn VARIABLE)" t)
 (autoload 'find-variable-other-frame "find-func" "\
 Find, in another frame, the definition of VARIABLE near point.
 
 See `find-variable' for more details.
 
-(fn VARIABLE)" t nil)
+(fn VARIABLE)" t)
 (autoload 'find-definition-noselect "find-func" "\
 Return a pair `(BUFFER . POINT)' pointing to the definition of SYMBOL.
 If the definition can't be found in the buffer, return (BUFFER).
@@ -11978,7 +12066,7 @@ TYPE says what type of definition: nil for a function, 
`defvar' for a
 variable, `defface' for a face.  This function does not switch to the
 buffer nor display it.
 
-(fn SYMBOL TYPE &optional FILE)" nil nil)
+(fn SYMBOL TYPE &optional FILE)")
 (autoload 'find-face-definition "find-func" "\
 Find the definition of FACE.  FACE defaults to the name near point.
 
@@ -11990,28 +12078,28 @@ Set mark before moving, if the buffer already existed.
 
 See also `find-function-recenter-line' and `find-function-after-hook'.
 
-(fn FACE)" t nil)
+(fn FACE)" t)
 (autoload 'find-function-on-key "find-func" "\
 Find the function that KEY invokes.  KEY is a string.
 Set mark before moving, if the buffer already existed.
 
-(fn KEY)" t nil)
+(fn KEY)" t)
 (autoload 'find-function-on-key-other-window "find-func" "\
 Find, in the other window, the function that KEY invokes.
 See `find-function-on-key'.
 
-(fn KEY)" t nil)
+(fn KEY)" t)
 (autoload 'find-function-on-key-other-frame "find-func" "\
 Find, in the other frame, the function that KEY invokes.
 See `find-function-on-key'.
 
-(fn KEY)" t nil)
+(fn KEY)" t)
 (autoload 'find-function-at-point "find-func" "\
-Find directly the function at point in the other window." t nil)
+Find directly the function at point in the other window." t)
 (autoload 'find-variable-at-point "find-func" "\
-Find directly the variable at point in the other window." t nil)
+Find directly the variable at point in the other window." t)
 (autoload 'find-function-setup-keys "find-func" "\
-Define some key bindings for the `find-function' family of functions." nil nil)
+Define some key bindings for the `find-function' family of functions.")
 (register-definition-prefixes "find-func" '("find-" 
"read-library-name--find-files"))
 
 
@@ -12020,29 +12108,29 @@ Define some key bindings for the `find-function' 
family of functions." nil nil)
 (autoload 'find-lisp-find-dired "find-lisp" "\
 Find files in DIR, matching REGEXP.
 
-(fn DIR REGEXP)" t nil)
+(fn DIR REGEXP)" t)
 (autoload 'find-lisp-find-dired-subdirectories "find-lisp" "\
 Find all subdirectories of DIR.
 
-(fn DIR)" t nil)
+(fn DIR)" t)
 (autoload 'find-lisp-find-dired-filter "find-lisp" "\
 Change the filter on a `find-lisp-find-dired' buffer to REGEXP.
 
-(fn REGEXP)" t nil)
+(fn REGEXP)" t)
 (register-definition-prefixes "find-lisp" '("find-lisp-"))
 
 
 ;;; Generated autoloads from finder.el
 
 (autoload 'finder-list-keywords "finder" "\
-Display descriptions of the keywords in the Finder buffer." t nil)
+Display descriptions of the keywords in the Finder buffer." t)
 (autoload 'finder-commentary "finder" "\
 Display FILE's commentary section.
 FILE should be in a form suitable for passing to `locate-library'.
 
-(fn FILE)" t nil)
+(fn FILE)" t)
 (autoload 'finder-by-keyword "finder" "\
-Find packages matching a given keyword." t nil)
+Find packages matching a given keyword." t)
 (register-definition-prefixes "finder" '("finder-" 
"generated-finder-keywords-file"))
 
 
@@ -12053,7 +12141,7 @@ Toggle flow control handling.
 When handling is enabled, user can type C-s as C-\\, and C-q as C-^.
 With arg, enable flow control mode if arg is positive, otherwise disable.
 
-(fn &optional ARGUMENT)" t nil)
+(fn &optional ARGUMENT)" t)
 (autoload 'enable-flow-control-on "flow-ctrl" "\
 Enable flow control if using one of a specified set of terminal types.
 Use `(enable-flow-control-on \"vt100\" \"h19\")' to enable flow control
@@ -12061,7 +12149,7 @@ on VT-100 and H19 terminals.  When flow control is 
enabled,
 you must type C-\\ to get the effect of a C-s, and type C-^
 to get the effect of a C-q.
 
-(fn &rest LOSING-TERMINAL-TYPES)" nil nil)
+(fn &rest LOSING-TERMINAL-TYPES)")
 (register-definition-prefixes "flow-ctrl" '("flow-control-c-"))
 
 
@@ -12070,7 +12158,7 @@ to get the effect of a C-q.
 (autoload 'fill-flowed-encode "flow-fill" "\
 
 
-(fn &optional BUFFER)" nil nil)
+(fn &optional BUFFER)")
 (autoload 'fill-flowed "flow-fill" "\
 Apply RFC2646 decoding to BUFFER.
 If BUFFER is nil, default to the current buffer.
@@ -12078,7 +12166,7 @@ If BUFFER is nil, default to the current buffer.
 If DELETE-SPACE, delete RFC2646 spaces padding at the end of
 lines.
 
-(fn &optional BUFFER DELETE-SPACE)" nil nil)
+(fn &optional BUFFER DELETE-SPACE)")
 (register-definition-prefixes "flow-fill" '("fill-flowed-"))
 
 
@@ -12114,7 +12202,7 @@ created diagnostic, overriding the default properties 
and any
 properties listed in the `flymake-overlay-control' property of
 the diagnostic's type symbol.
 
-(fn LOCUS BEG END TYPE TEXT &optional DATA OVERLAY-PROPERTIES)" nil nil)
+(fn LOCUS BEG END TYPE TEXT &optional DATA OVERLAY-PROPERTIES)")
 (autoload 'flymake-diagnostics "flymake" "\
 Get Flymake diagnostics in region determined by BEG and END.
 
@@ -12122,13 +12210,13 @@ If neither BEG or END is supplied, use whole 
accessible buffer,
 otherwise if BEG is non-nil and END is nil, consider only
 diagnostics at BEG.
 
-(fn &optional BEG END)" nil nil)
+(fn &optional BEG END)")
 (autoload 'flymake-diag-region "flymake" "\
 Compute BUFFER's region (BEG . END) corresponding to LINE and COL.
 If COL is nil, return a region just for LINE.  Return nil if the
 region is invalid.  This function saves match data.
 
-(fn BUFFER LINE &optional COL)" nil nil)
+(fn BUFFER LINE &optional COL)")
 (autoload 'flymake-mode "flymake" "\
 Toggle Flymake mode on or off.
 
@@ -12183,11 +12271,11 @@ evaluate `flymake-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'flymake-mode-on "flymake" "\
-Turn Flymake mode on." nil nil)
+Turn Flymake mode on.")
 (autoload 'flymake-mode-off "flymake" "\
-Turn Flymake mode off." nil nil)
+Turn Flymake mode off.")
 (register-definition-prefixes "flymake" '("flymake-"))
 
 
@@ -12199,7 +12287,7 @@ This backend uses `flymake-cc-command' (which see) to 
launch a
 process that is passed the current buffer's contents via stdin.
 REPORT-FN is Flymake's callback.
 
-(fn REPORT-FN &rest ARGS)" nil nil)
+(fn REPORT-FN &rest ARGS)")
 (register-definition-prefixes "flymake-cc" '("flymake-cc-"))
 
 
@@ -12212,7 +12300,7 @@ REPORT-FN is Flymake's callback.
 ;;; Generated autoloads from textmodes/flyspell.el
 
 (autoload 'flyspell-prog-mode "flyspell" "\
-Turn on `flyspell-mode' for comments and strings." t nil)
+Turn on `flyspell-mode' for comments and strings." t)
 (defvar flyspell-mode nil "Non-nil if Flyspell mode is enabled.")
 (autoload 'flyspell-mode "flyspell" "\
 Toggle on-the-fly spell checking (Flyspell mode).
@@ -12260,22 +12348,22 @@ evaluate `flyspell-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'turn-on-flyspell "flyspell" "\
-Unconditionally turn on Flyspell mode." nil nil)
+Unconditionally turn on Flyspell mode.")
 (autoload 'turn-off-flyspell "flyspell" "\
-Unconditionally turn off Flyspell mode." nil nil)
+Unconditionally turn off Flyspell mode.")
 (autoload 'flyspell-mode-off "flyspell" "\
-Turn Flyspell mode off." nil nil)
+Turn Flyspell mode off.")
 (autoload 'flyspell-region "flyspell" "\
 Flyspell text between BEG and END.
 
 Make sure `flyspell-mode' is turned on if you want the highlight
 of a misspelled word removed when you've corrected it.
 
-(fn BEG END)" t nil)
+(fn BEG END)" t)
 (autoload 'flyspell-buffer "flyspell" "\
-Flyspell whole buffer." t nil)
+Flyspell whole buffer." t)
 (register-definition-prefixes "flyspell" '("flyspell-" 
"mail-mode-flyspell-verify" "make-flyspell-overlay" "sgml-mode-flyspell-verify" 
"tex"))
 
 
@@ -12288,9 +12376,9 @@ Flyspell whole buffer." t nil)
 ;;; Generated autoloads from follow.el
 
 (autoload 'turn-on-follow-mode "follow" "\
-Turn on Follow mode.  Please see the function `follow-mode'." nil nil)
+Turn on Follow mode.  Please see the function `follow-mode'.")
 (autoload 'turn-off-follow-mode "follow" "\
-Turn off Follow mode.  Please see the function `follow-mode'." nil nil)
+Turn off Follow mode.  Please see the function `follow-mode'.")
 (autoload 'follow-mode "follow" "\
 Toggle Follow mode.
 
@@ -12337,7 +12425,7 @@ evaluate `follow-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'follow-scroll-up-window "follow" "\
 Scroll text in a Follow mode window up by that window's size.
 The other windows in the window chain will scroll synchronously.
@@ -12350,7 +12438,7 @@ Negative ARG means scroll downward.
 
 Works like `scroll-up' when not in Follow mode.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'follow-scroll-down-window "follow" "\
 Scroll text in a Follow mode window down by that window's size.
 The other windows in the window chain will scroll synchronously.
@@ -12363,7 +12451,7 @@ Negative ARG means scroll upward.
 
 Works like `scroll-down' when not in Follow mode.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'follow-scroll-up "follow" "\
 Scroll text in a Follow mode window chain up.
 
@@ -12375,7 +12463,7 @@ Negative ARG means scroll downward.
 
 Works like `scroll-up' when not in Follow mode.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'follow-scroll-down "follow" "\
 Scroll text in a Follow mode window chain down.
 
@@ -12387,7 +12475,7 @@ Negative ARG means scroll upward.
 
 Works like `scroll-down' when not in Follow mode.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'follow-delete-other-windows-and-split "follow" "\
 Create two side by side windows and enter Follow mode.
 
@@ -12402,7 +12490,7 @@ If ARG is positive, the leftmost window is selected.  
If negative,
 the rightmost is selected.  If ARG is nil, the leftmost window is
 selected if the original window is the first one in the frame.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "follow" '("follow-"))
 
 
@@ -12435,7 +12523,7 @@ evaluate `footnote-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "footnote" '("footnote-"))
 
 
@@ -12494,7 +12582,7 @@ any occurrences of \"%%\" in FORMAT verbatim in the 
result.
 If SPLIT, instead of returning a single string, a list of strings
 is returned, where each format spec is its own element.
 
-(fn FORMAT SPECIFICATION &optional IGNORE-MISSING SPLIT)" nil nil)
+(fn FORMAT SPECIFICATION &optional IGNORE-MISSING SPLIT)")
 (register-definition-prefixes "format-spec" '("format-spec-"))
 
 
@@ -12519,15 +12607,15 @@ Commands:                        Equivalent keys in 
read-only mode:
  C-c C-s        forms-search-forward       s
  C-c C-x        forms-exit                 x
 
-(fn &optional PRIMARY)" t nil)
+(fn &optional PRIMARY)" t)
 (autoload 'forms-find-file "forms" "\
 Visit a file in Forms mode.
 
-(fn FN)" t nil)
+(fn FN)" t)
 (autoload 'forms-find-file-other-window "forms" "\
 Visit a file in Forms mode in other window.
 
-(fn FN)" t nil)
+(fn FN)" t)
 (register-definition-prefixes "forms" '("forms-"))
 
 
@@ -12603,7 +12691,7 @@ Variables controlling indentation style and extra 
features:
 Turning on Fortran mode calls the value of the variable `fortran-mode-hook'
 with no args, if that value is non-nil.
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "fortran" '("fortran-"))
 
 
@@ -12615,21 +12703,21 @@ Add STRING to a fortune file FILE.
 Interactively, if called with a prefix argument,
 read the file name to use.  Otherwise use the value of `fortune-file'.
 
-(fn STRING FILE)" t nil)
+(fn STRING FILE)" t)
 (autoload 'fortune-from-region "fortune" "\
 Append the current region to a local fortune-like data file.
 
 Interactively, if called with a prefix argument,
 read the file name to use.  Otherwise use the value of `fortune-file'.
 
-(fn BEG END FILE)" t nil)
+(fn BEG END FILE)" t)
 (autoload 'fortune-compile "fortune" "\
 Compile fortune file.
 
 If called with a prefix asks for the FILE to compile, otherwise uses
 the value of `fortune-file'.  This currently cannot handle directories.
 
-(fn &optional FILE)" t nil)
+(fn &optional FILE)" t)
 (autoload 'fortune-to-signature "fortune" "\
 Create signature from output of the fortune program.
 
@@ -12638,13 +12726,13 @@ otherwise uses the value of `fortune-file'.  If you 
want to have fortune
 choose from a set of files in a directory, call interactively with prefix
 and choose the directory as the fortune-file.
 
-(fn &optional FILE)" t nil)
+(fn &optional FILE)" t)
 (autoload 'fortune-message "fortune" "\
 Display a fortune cookie to the mini-buffer.
 If called with a prefix, it has the same behavior as `fortune'.
 Optional FILE is a fortune file from which a cookie will be selected.
 
-(fn &optional FILE)" t nil)
+(fn &optional FILE)" t)
 (autoload 'fortune "fortune" "\
 Display a fortune cookie.
 If called with a prefix asks for the FILE to choose the fortune from,
@@ -12652,7 +12740,7 @@ otherwise uses the value of `fortune-file'.  If you 
want to have fortune
 choose from a set of files in a directory, call interactively with prefix
 and choose the directory as the fortune-file.
 
-(fn &optional FILE)" t nil)
+(fn &optional FILE)" t)
 (register-definition-prefixes "fortune" '("fortune-"))
 
 
@@ -12727,17 +12815,17 @@ invocations, and once assigned is never changed 
unless the same
 frame is duplicated (via `frameset-restore'), in which case the
 newest frame keeps the id and the old frame's is set to nil.
 
-(fn FRAME)" nil nil)
+(fn FRAME)")
 (autoload 'frameset-frame-id-equal-p "frameset" "\
 Return non-nil if FRAME's id matches ID.
 
-(fn FRAME ID)" nil nil)
+(fn FRAME ID)")
 (autoload 'frameset-frame-with-id "frameset" "\
 Return the live frame with id ID, if exists; else nil.
 If FRAME-LIST is a list of frames, check these frames only.
 If nil, check all live frames.
 
-(fn ID &optional FRAME-LIST)" nil nil)
+(fn ID &optional FRAME-LIST)")
 (autoload 'frameset-save "frameset" "\
 Return a frameset for FRAME-LIST, a list of frames.
 Dead frames and non-frame objects are silently removed from the list.
@@ -12750,7 +12838,7 @@ PREDICATE is a predicate function, which must return 
non-nil for frames that
 should be saved; if PREDICATE is nil, all frames from FRAME-LIST are saved.
 PROPERTIES is a user-defined property list to add to the frameset.
 
-(fn FRAME-LIST &key APP NAME DESCRIPTION FILTERS PREDICATE PROPERTIES)" nil 
nil)
+(fn FRAME-LIST &key APP NAME DESCRIPTION FILTERS PREDICATE PROPERTIES)")
 (autoload 'frameset-restore "frameset" "\
 Restore a FRAMESET into the current display(s).
 
@@ -12810,7 +12898,7 @@ restoration, including those that have been reused or 
created anew.
 
 All keyword parameters default to nil.
 
-(fn FRAMESET &key PREDICATE FILTERS REUSE-FRAMES FORCE-DISPLAY FORCE-ONSCREEN 
CLEANUP-FRAMES)" nil nil)
+(fn FRAMESET &key PREDICATE FILTERS REUSE-FRAMES FORCE-DISPLAY FORCE-ONSCREEN 
CLEANUP-FRAMES)")
 (autoload 'frameset-to-register "frameset" "\
 Store the current frameset in register REGISTER.
 Use \\[jump-to-register] to restore the frameset.
@@ -12818,7 +12906,7 @@ Argument is a character, naming the register.
 
 Interactively, reads the register using `register-read-with-preview'.
 
-(fn REGISTER)" t nil)
+(fn REGISTER)" t)
 (register-definition-prefixes "frameset" '("frameset-"))
 
 
@@ -12889,7 +12977,7 @@ evaluate `(default-value \\='gdb-enable-debug)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'gdb "gdb-mi" "\
 Run gdb passing it COMMAND-LINE as arguments.
 
@@ -12948,8 +13036,8 @@ detailed description of this mode.
 |                                   | D      gdb-delete-breakpoint     |
 +-----------------------------------+----------------------------------+
 
-(fn COMMAND-LINE)" t nil)
-(register-definition-prefixes "gdb-mi" '("breakpoint" "def-gdb-" "gdb" "gud-" 
"hollow-right-triangle" "nil"))
+(fn COMMAND-LINE)" t)
+(register-definition-prefixes "gdb-mi" '("breakpoint" "def-gdb-" "gdb" "gud-" 
"hollow-right-triangle"))
 
 
 ;;; Generated autoloads from emacs-lisp/generator.el
@@ -13002,12 +13090,12 @@ mode hook `MODE-hook'.
 See the file generic-x.el for some examples of `define-generic-mode'.
 
 (fn MODE COMMENT-LIST KEYWORD-LIST FONT-LOCK-LIST AUTO-MODE-LIST FUNCTION-LIST 
&optional DOCSTRING)" nil t)
-(function-put 'define-generic-mode 'lisp-indent-function '1)
-(function-put 'define-generic-mode 'doc-string-elt '7)
+(function-put 'define-generic-mode 'lisp-indent-function 1)
+(function-put 'define-generic-mode 'doc-string-elt 7)
 (autoload 'generic-mode-internal "generic" "\
 Go into the generic mode MODE.
 
-(fn MODE COMMENT-LIST KEYWORD-LIST FONT-LOCK-LIST FUNCTION-LIST)" nil nil)
+(fn MODE COMMENT-LIST KEYWORD-LIST FONT-LOCK-LIST FUNCTION-LIST)")
 (autoload 'generic-mode "generic" "\
 Enter generic mode MODE.
 
@@ -13018,7 +13106,7 @@ own mode, but have comment characters, keywords, and 
the like.)
 To define a generic-mode, use the function `define-generic-mode'.
 Some generic modes are defined in `generic-x.el'.
 
-(fn MODE)" t nil)
+(fn MODE)" t)
 (autoload 'generic-make-keywords-list "generic" "\
 Return a `font-lock-keywords' construct that highlights KEYWORD-LIST.
 KEYWORD-LIST is a list of keyword strings that should be
@@ -13028,8 +13116,8 @@ PREFIX and SUFFIX.  Then it returns a construct based 
on this
 regular expression that can be used as an element of
 `font-lock-keywords'.
 
-(fn KEYWORD-LIST FACE &optional PREFIX SUFFIX)" nil nil)
-(make-obsolete 'generic-make-keywords-list 'regexp-opt '"24.4")
+(fn KEYWORD-LIST FACE &optional PREFIX SUFFIX)")
+(make-obsolete 'generic-make-keywords-list 'regexp-opt "24.4")
 (register-definition-prefixes "generic" '("generic-"))
 
 
@@ -13065,7 +13153,7 @@ evaluate `glasses-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "glasses" '("glasses-"))
 
 
@@ -13097,7 +13185,7 @@ evaluate `glyphless-display-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "glyphless-mode" '("glyphless-mode-"))
 
 
@@ -13107,7 +13195,7 @@ it is disabled.
 Potentially concat a list of regexps into a single one.
 The concatenation is done with logical ORs.
 
-(fn REGEXP)" nil nil)
+(fn REGEXP)")
 (autoload 'gmm-message "gmm-utils" "\
 If LEVEL is lower than `gmm-verbose' print ARGS using `message'.
 
@@ -13118,16 +13206,16 @@ Guideline for numbers:
 7 - not very important messages on stuff
 9 - messages inside loops.
 
-(fn LEVEL &rest ARGS)" nil nil)
+(fn LEVEL &rest ARGS)")
 (autoload 'gmm-error "gmm-utils" "\
 Beep an error if LEVEL is equal to or less than `gmm-verbose'.
 ARGS are passed to `message'.
 
-(fn LEVEL &rest ARGS)" nil nil)
+(fn LEVEL &rest ARGS)")
 (autoload 'gmm-widget-p "gmm-utils" "\
 Non-nil if SYMBOL is a widget.
 
-(fn SYMBOL)" nil nil)
+(fn SYMBOL)")
 (autoload 'gmm-tool-bar-from-list "gmm-utils" "\
 Make a tool bar from ICON-LIST.
 
@@ -13146,7 +13234,7 @@ runs the command find-file\", then use `new-file' in 
ZAP-LIST.
 
 DEFAULT-MAP specifies the default key map for ICON-LIST.
 
-(fn ICON-LIST ZAP-LIST DEFAULT-MAP)" nil nil)
+(fn ICON-LIST ZAP-LIST DEFAULT-MAP)")
 (register-definition-prefixes "gmm-utils" '("defun-gmm" "gmm-"))
 
 
@@ -13157,11 +13245,11 @@ DEFAULT-MAP specifies the default key map for 
ICON-LIST.
 (autoload 'gnus-child-no-server "gnus" "\
 Read network news as a child, without connecting to the local server.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'gnus-slave-no-server "gnus" "\
 Read network news as a child, without connecting to the local server.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'gnus-no-server "gnus" "\
 Read network news.
 If ARG is a positive number, Gnus will use that as the startup level.
@@ -13171,15 +13259,15 @@ an NNTP server to use.
 As opposed to `gnus', this command will not connect to the local
 server.
 
-(fn &optional ARG CHILD)" t nil)
+(fn &optional ARG CHILD)" t)
 (autoload 'gnus-child "gnus" "\
 Read news as a child.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'gnus-slave "gnus" "\
 Read news as a child.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'gnus-other-frame "gnus" "\
 Pop up a frame to read news.
 This will call one of the Gnus commands which is specified by the user
@@ -13191,31 +13279,31 @@ such as \"unix:0\" to specify where to pop up a 
frame.  If DISPLAY is
 omitted or the function `make-frame-on-display' is not available, the
 current display is used.
 
-(fn &optional ARG DISPLAY)" t nil)
+(fn &optional ARG DISPLAY)" t)
 (autoload 'gnus "gnus" "\
 Read network news.
 If ARG is non-nil and a positive number, Gnus will use that as the
 startup level.  If ARG is non-nil and not a positive number, Gnus will
 prompt the user for the name of an NNTP server to use.
 
-(fn &optional ARG DONT-CONNECT CHILD)" t nil)
+(fn &optional ARG DONT-CONNECT CHILD)" t)
 (register-definition-prefixes "gnus" '("gnus-"))
 
 
 ;;; Generated autoloads from gnus/gnus-agent.el
 
 (autoload 'gnus-unplugged "gnus-agent" "\
-Start Gnus unplugged." t nil)
+Start Gnus unplugged." t)
 (autoload 'gnus-plugged "gnus-agent" "\
-Start Gnus plugged." t nil)
+Start Gnus plugged." t)
 (autoload 'gnus-child-unplugged "gnus-agent" "\
 Read news as a child unplugged.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'gnus-slave-unplugged "gnus-agent" "\
 Read news as a child unplugged.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'gnus-agentize "gnus-agent" "\
 Allow Gnus to be an offline newsreader.
 
@@ -13225,9 +13313,9 @@ customize `gnus-agent' to nil.
 
 This will modify the `gnus-setup-news-hook', and
 `message-send-mail-real-function' variables, and install the Gnus agent
-minor mode in all Gnus buffers." t nil)
+minor mode in all Gnus buffers." t)
 (autoload 'gnus-agent-possibly-save-gcc "gnus-agent" "\
-Save GCC if Gnus is unplugged." nil nil)
+Save GCC if Gnus is unplugged.")
 (autoload 'gnus-agent-rename-group "gnus-agent" "\
 Rename fully-qualified OLD-GROUP as NEW-GROUP.
 Always updates the agent, even when disabled, as the old agent
@@ -13235,7 +13323,7 @@ files would corrupt gnus when the agent was next 
enabled.
 Depends upon the caller to determine whether group renaming is
 supported.
 
-(fn OLD-GROUP NEW-GROUP)" nil nil)
+(fn OLD-GROUP NEW-GROUP)")
 (autoload 'gnus-agent-delete-group "gnus-agent" "\
 Delete fully-qualified GROUP.
 Always updates the agent, even when disabled, as the old agent
@@ -13243,37 +13331,37 @@ files would corrupt gnus when the agent was next 
enabled.
 Depends upon the caller to determine whether group deletion is
 supported.
 
-(fn GROUP)" nil nil)
+(fn GROUP)")
 (autoload 'gnus-agent-get-undownloaded-list "gnus-agent" "\
-Construct list of articles that have not been downloaded." nil nil)
+Construct list of articles that have not been downloaded.")
 (autoload 'gnus-agent-possibly-alter-active "gnus-agent" "\
 Possibly expand a group's active range to include articles
 downloaded into the agent.
 
-(fn GROUP ACTIVE &optional INFO)" nil nil)
+(fn GROUP ACTIVE &optional INFO)")
 (autoload 'gnus-agent-find-parameter "gnus-agent" "\
 Search for GROUPs SYMBOL in the group's parameters, the group's
 topic parameters, the group's category, or the customizable
 variables.  Returns the first non-nil value found.
 
-(fn GROUP SYMBOL)" nil nil)
+(fn GROUP SYMBOL)")
 (autoload 'gnus-agent-batch-fetch "gnus-agent" "\
-Start Gnus and fetch session." t nil)
+Start Gnus and fetch session." t)
 (autoload 'gnus-agent-batch "gnus-agent" "\
-Start Gnus, send queue and fetch session." t nil)
+Start Gnus, send queue and fetch session." t)
 (autoload 'gnus-agent-regenerate "gnus-agent" "\
 Regenerate all agent covered files.
 CLEAN is obsolete and ignored.
 
-(fn &optional CLEAN REREAD)" t nil)
+(fn &optional CLEAN REREAD)" t)
 (register-definition-prefixes "gnus-agent" '("gnus-"))
 
 
 ;;; Generated autoloads from gnus/gnus-art.el
 
 (autoload 'gnus-article-prepare-display "gnus-art" "\
-Make the current buffer look like a nice article." nil nil)
-(register-definition-prefixes "gnus-art" '(":keymap" "article-" "gnus-"))
+Make the current buffer look like a nice article.")
+(register-definition-prefixes "gnus-art" '("article-" "gnus-"))
 
 
 ;;; Generated autoloads from gnus/gnus-async.el
@@ -13289,16 +13377,16 @@ Make the current buffer look like a nice article." 
nil nil)
 ;;; Generated autoloads from gnus/gnus-bookmark.el
 
 (autoload 'gnus-bookmark-set "gnus-bookmark" "\
-Set a bookmark for this article." '(gnus-article-mode gnus-summary-mode) nil)
+Set a bookmark for this article." '(gnus-article-mode gnus-summary-mode))
 (autoload 'gnus-bookmark-jump "gnus-bookmark" "\
 Jump to a Gnus bookmark (BMK-NAME).
 
-(fn &optional BMK-NAME)" t nil)
+(fn &optional BMK-NAME)" t)
 (autoload 'gnus-bookmark-bmenu-list "gnus-bookmark" "\
 Display a list of existing Gnus bookmarks.
 The list is displayed in a buffer named `*Gnus Bookmark List*'.
 The leftmost column displays a D if the bookmark is flagged for
-deletion, or > if it is flagged for displaying." t nil)
+deletion, or > if it is flagged for displaying." t)
 (register-definition-prefixes "gnus-bookmark" '("gnus-bookmark-"))
 
 
@@ -13308,15 +13396,15 @@ deletion, or > if it is flagged for displaying." t 
nil)
 Go through all groups and put the articles into the cache.
 
 Usage:
-$ emacs -batch -l ~/.emacs -l gnus -f gnus-jog-cache" t nil)
+$ emacs -batch -l ~/.emacs -l gnus -f gnus-jog-cache" t)
 (autoload 'gnus-cache-generate-active "gnus-cache" "\
 Generate the cache active file.
 
-(fn &optional DIRECTORY)" t nil)
+(fn &optional DIRECTORY)" t)
 (autoload 'gnus-cache-generate-nov-databases "gnus-cache" "\
 Generate NOV files recursively starting in DIR.
 
-(fn DIR)" t nil)
+(fn DIR)" t)
 (autoload 'gnus-cache-rename-group "gnus-cache" "\
 Rename OLD-GROUP as NEW-GROUP.
 Always updates the cache, even when disabled, as the old cache
@@ -13324,7 +13412,7 @@ files would corrupt Gnus when the cache was next 
enabled.  It
 depends on the caller to determine whether group renaming is
 supported.
 
-(fn OLD-GROUP NEW-GROUP)" nil nil)
+(fn OLD-GROUP NEW-GROUP)")
 (autoload 'gnus-cache-delete-group "gnus-cache" "\
 Delete GROUP from the cache.
 Always updates the cache, even when disabled, as the old cache
@@ -13332,7 +13420,7 @@ files would corrupt gnus when the cache was next 
enabled.
 Depends upon the caller to determine whether group deletion is
 supported.
 
-(fn GROUP)" nil nil)
+(fn GROUP)")
 (register-definition-prefixes "gnus-cache" '("gnus-"))
 
 
@@ -13375,9 +13463,9 @@ The value of `message-draft-headers' determines which 
headers are
 generated when the article is delayed.  Remaining headers are
 generated when the article is sent.
 
-(fn DELAY)" '(message-mode) nil)
+(fn DELAY)" '(message-mode))
 (autoload 'gnus-delay-send-queue "gnus-delay" "\
-Send all the delayed messages that are due now." t nil)
+Send all the delayed messages that are due now." t)
 (autoload 'gnus-delay-initialize "gnus-delay" "\
 Initialize the gnus-delay package.
 This sets up a key binding in `message-mode' to delay a message.
@@ -13386,7 +13474,7 @@ This tells Gnus to look for delayed messages after 
getting new news.
 The optional arg NO-KEYMAP is ignored.
 Checking delayed messages is skipped if optional arg NO-CHECK is non-nil.
 
-(fn &optional NO-KEYMAP NO-CHECK)" nil nil)
+(fn &optional NO-KEYMAP NO-CHECK)")
 (register-definition-prefixes "gnus-delay" '("gnus-delay-"))
 
 
@@ -13400,25 +13488,25 @@ Checking delayed messages is skipped if optional arg 
NO-CHECK is non-nil.
 (autoload 'gnus-user-format-function-d "gnus-diary" "\
 
 
-(fn HEADER)" nil nil)
+(fn HEADER)")
 (autoload 'gnus-user-format-function-D "gnus-diary" "\
 
 
-(fn HEADER)" nil nil)
+(fn HEADER)")
 (register-definition-prefixes "gnus-diary" '("gnus-"))
 
 
 ;;; Generated autoloads from gnus/gnus-dired.el
 
 (autoload 'turn-on-gnus-dired-mode "gnus-dired" "\
-Convenience method to turn on `gnus-dired-mode'." t nil)
+Convenience method to turn on `gnus-dired-mode'." t)
 (register-definition-prefixes "gnus-dired" '("gnus-dired-"))
 
 
 ;;; Generated autoloads from gnus/gnus-draft.el
 
 (autoload 'gnus-draft-reminder "gnus-draft" "\
-Reminder user if there are unsent drafts." t nil)
+Reminder user if there are unsent drafts." t)
 (register-definition-prefixes "gnus-draft" '("gnus-"))
 
 
@@ -13438,45 +13526,45 @@ Reminder user if there are unsent drafts." t nil)
 Return file from DIR with extension EXT.
 Omit matches of OMIT, and process them by FUN.
 
-(fn DIR EXT OMIT FUN)" nil nil)
+(fn DIR EXT OMIT FUN)")
 (autoload 'message-goto-eoh "message" nil t)
 (autoload 'gnus-random-x-face "gnus-fun" "\
 Return X-Face header data chosen randomly from `gnus-x-face-directory'.
 
-Files matching `gnus-x-face-omit-files' are not considered." t nil)
+Files matching `gnus-x-face-omit-files' are not considered." t)
 (autoload 'gnus-insert-random-x-face-header "gnus-fun" "\
-Insert a random X-Face header from `gnus-x-face-directory'." t nil)
+Insert a random X-Face header from `gnus-x-face-directory'." t)
 (autoload 'gnus-x-face-from-file "gnus-fun" "\
 Insert an X-Face header based on an image FILE.
 
 Depending on `gnus-convert-image-to-x-face-command' it may accept
 different input formats.
 
-(fn FILE)" t nil)
+(fn FILE)" t)
 (autoload 'gnus-face-from-file "gnus-fun" "\
 Return a Face header based on an image FILE.
 
 Depending on `gnus-convert-image-to-face-command' it may accept
 different input formats.
 
-(fn FILE)" t nil)
+(fn FILE)" t)
 (autoload 'gnus-convert-face-to-png "gnus-fun" "\
 Convert FACE (which is base64-encoded) to a PNG.
 The PNG is returned as a string.
 
-(fn FACE)" nil nil)
+(fn FACE)")
 (autoload 'gnus-convert-png-to-face "gnus-fun" "\
 Convert FILE to a Face.
 FILE should be a PNG file that's 48x48 and smaller than or equal to
 726 bytes.
 
-(fn FILE)" nil nil)
+(fn FILE)")
 (autoload 'gnus-random-face "gnus-fun" "\
 Return randomly chosen Face from `gnus-face-directory'.
 
-Files matching `gnus-face-omit-files' are not considered." t nil)
+Files matching `gnus-face-omit-files' are not considered." t)
 (autoload 'gnus-insert-random-face-header "gnus-fun" "\
-Insert a random Face header from `gnus-face-directory'." nil nil)
+Insert a random Face header from `gnus-face-directory'.")
 (register-definition-prefixes "gnus-fun" '("gnus-"))
 
 
@@ -13486,12 +13574,12 @@ Insert a random Face header from 
`gnus-face-directory'." nil nil)
 Display gravatar in the From header.
 If gravatar is already displayed, remove it.
 
-(fn &optional FORCE)" '(gnus-article-mode gnus-summary-mode) nil)
+(fn &optional FORCE)" '(gnus-article-mode gnus-summary-mode))
 (autoload 'gnus-treat-mail-gravatar "gnus-gravatar" "\
 Display gravatars in the Cc and To headers.
 If gravatars are already displayed, remove them.
 
-(fn &optional FORCE)" '(gnus-article-mode gnus-summary-mode) nil)
+(fn &optional FORCE)" '(gnus-article-mode gnus-summary-mode))
 (register-definition-prefixes "gnus-gravatar" '("gnus-gravatar-"))
 
 
@@ -13502,18 +13590,18 @@ Start Gnus if necessary and enter GROUP.
 If ARTICLES, display those articles.
 Returns whether the fetching was successful or not.
 
-(fn GROUP &optional ARTICLES)" t nil)
+(fn GROUP &optional ARTICLES)" t)
 (autoload 'gnus-fetch-group-other-frame "gnus-group" "\
 Pop up a frame and enter GROUP.
 
-(fn GROUP)" t nil)
+(fn GROUP)" t)
 (autoload 'gnus-read-ephemeral-emacs-bug-group "gnus-group" "\
 Browse Emacs bug reports with IDS in an ephemeral group.
 The arguments have the same meaning as those of
 `gnus-read-ephemeral-bug-group', which see.
 
-(fn IDS &optional WINDOW-CONF)" t nil)
-(register-definition-prefixes "gnus-group" '(":keymap" "gnus-"))
+(fn IDS &optional WINDOW-CONF)" t)
+(register-definition-prefixes "gnus-group" '("gnus-"))
 
 
 ;;; Generated autoloads from gnus/gnus-html.el
@@ -13521,11 +13609,11 @@ The arguments have the same meaning as those of
 (autoload 'gnus-article-html "gnus-html" "\
 
 
-(fn &optional HANDLE)" nil nil)
+(fn &optional HANDLE)")
 (autoload 'gnus-html-prefetch-images "gnus-html" "\
 
 
-(fn SUMMARY)" nil nil)
+(fn SUMMARY)")
 (register-definition-prefixes "gnus-html" '("gnus-"))
 
 
@@ -13534,7 +13622,7 @@ The arguments have the same meaning as those of
 (autoload 'gnus-icalendar-mm-inline "gnus-icalendar" "\
 
 
-(fn HANDLE)" nil nil)
+(fn HANDLE)")
 (register-definition-prefixes "gnus-icalendar" '("gnus-icalendar"))
 
 
@@ -13548,7 +13636,7 @@ The arguments have the same meaning as those of
 (defalias 'gnus-batch-kill 'gnus-batch-score)
 (autoload 'gnus-batch-score "gnus-kill" "\
 Run batched scoring.
-Usage: emacs -batch -l ~/.emacs -l gnus -f gnus-batch-score" t nil)
+Usage: emacs -batch -l ~/.emacs -l gnus -f gnus-batch-score" t)
 (register-definition-prefixes "gnus-kill" '("gnus-"))
 
 
@@ -13564,12 +13652,12 @@ Usage: emacs -batch -l ~/.emacs -l gnus -f 
gnus-batch-score" t nil)
 
 ;;; Generated autoloads from gnus/gnus-ml.el
 
-(autoload 'turn-on-gnus-mailing-list-mode "gnus-ml" nil nil nil)
+(autoload 'turn-on-gnus-mailing-list-mode "gnus-ml")
 (autoload 'gnus-mailing-list-insinuate "gnus-ml" "\
 Setup group parameters from List-Post header.
 If FORCE is non-nil, replace the old ones.
 
-(fn &optional FORCE)" t nil)
+(fn &optional FORCE)" t)
 (autoload 'gnus-mailing-list-mode "gnus-ml" "\
 Minor mode for providing mailing-list commands.
 
@@ -13590,7 +13678,7 @@ evaluate `gnus-mailing-list-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "gnus-ml" '("gnus-mailing-list-"))
 
 
@@ -13618,7 +13706,7 @@ elaborate fancy splits may also be useful to split mail 
that doesn't
 match any of the group-specified splitting rules.  See
 `gnus-group-split-fancy' for details.
 
-(fn &optional AUTO-UPDATE CATCH-ALL)" t nil)
+(fn &optional AUTO-UPDATE CATCH-ALL)" t)
 (autoload 'gnus-group-split-update "gnus-mlspl" "\
 Computes `nnmail-split-fancy' from group params and CATCH-ALL.
 It does this by calling (gnus-group-split-fancy nil nil CATCH-ALL).
@@ -13626,12 +13714,12 @@ It does this by calling (gnus-group-split-fancy nil 
nil CATCH-ALL).
 If CATCH-ALL is nil, `gnus-group-split-default-catch-all-group' is used
 instead.  This variable is set by `gnus-group-split-setup'.
 
-(fn &optional CATCH-ALL)" t nil)
+(fn &optional CATCH-ALL)" t)
 (autoload 'gnus-group-split "gnus-mlspl" "\
 Use information from group parameters in order to split mail.
 See `gnus-group-split-fancy' for more information.
 
-`gnus-group-split' is a valid value for `nnmail-split-methods'." nil nil)
+`gnus-group-split' is a valid value for `nnmail-split-methods'.")
 (autoload 'gnus-group-split-fancy "gnus-mlspl" "\
 Uses information from group parameters in order to split mail.
 It can be embedded into `nnmail-split-fancy' lists with the SPLIT
@@ -13683,7 +13771,7 @@ Calling (gnus-group-split-fancy nil nil 
\"mail.others\") returns:
           - \"bugs-foo\" - \"rambling-foo\" \"mail.foo\"))
    \"mail.others\")
 
-(fn &optional GROUPS NO-CROSSPOST CATCH-ALL)" nil nil)
+(fn &optional GROUPS NO-CROSSPOST CATCH-ALL)")
 (register-definition-prefixes "gnus-mlspl" '("gnus-group-split-"))
 
 
@@ -13696,17 +13784,17 @@ Gcc: header for archiving purposes.
 If Gnus isn't running, a plain `message-mail' setup is used
 instead.
 
-(fn &optional TO SUBJECT OTHER-HEADERS CONTINUE SWITCH-ACTION YANK-ACTION 
SEND-ACTIONS RETURN-ACTION)" t nil)
+(fn &optional TO SUBJECT OTHER-HEADERS CONTINUE SWITCH-ACTION YANK-ACTION 
SEND-ACTIONS RETURN-ACTION)" t)
 (autoload 'gnus-button-mailto "gnus-msg" "\
 Mail to ADDRESS.
 
-(fn ADDRESS)" nil nil)
+(fn ADDRESS)")
 (autoload 'gnus-button-reply "gnus-msg" "\
 Like `message-reply'.
 
-(fn &optional TO-ADDRESS WIDE)" t nil)
+(fn &optional TO-ADDRESS WIDE)" t)
 (define-mail-user-agent 'gnus-user-agent 'gnus-msg-mail 'message-send-and-exit 
'message-kill-buffer 'message-send-hook)
-(register-definition-prefixes "gnus-msg" '(":prefix" "gnus-"))
+(register-definition-prefixes "gnus-msg" '("gnus-"))
 
 
 ;;; Generated autoloads from gnus/gnus-notifications.el
@@ -13718,7 +13806,7 @@ or equal to `gnus-notifications-minimum-level' and send 
a
 notification using `notifications-notify' for it.
 
 This is typically a function to add in
-`gnus-after-getting-new-news-hook'" nil nil)
+`gnus-after-getting-new-news-hook'")
 (register-definition-prefixes "gnus-notifications" '("gnus-notifications-"))
 
 
@@ -13726,13 +13814,13 @@ This is typically a function to add in
 
 (autoload 'gnus-treat-from-picon "gnus-picon" "\
 Display picons in the From header.
-If picons are already displayed, remove them." '(gnus-article-mode 
gnus-summary-mode) nil)
+If picons are already displayed, remove them." '(gnus-article-mode 
gnus-summary-mode))
 (autoload 'gnus-treat-mail-picon "gnus-picon" "\
 Display picons in the Cc and To headers.
-If picons are already displayed, remove them." '(gnus-article-mode 
gnus-summary-mode) nil)
+If picons are already displayed, remove them." '(gnus-article-mode 
gnus-summary-mode))
 (autoload 'gnus-treat-newsgroups-picon "gnus-picon" "\
 Display picons in the Newsgroups and Followup-To headers.
-If picons are already displayed, remove them." '(gnus-article-mode 
gnus-summary-mode) nil)
+If picons are already displayed, remove them." '(gnus-article-mode 
gnus-summary-mode))
 (register-definition-prefixes "gnus-picon" '("gnus-picon-"))
 
 
@@ -13743,55 +13831,55 @@ Return a list of elements of LIST1 that do not appear 
in LIST2.
 Both lists have to be sorted over <.
 The tail of LIST1 is not copied.
 
-(fn LIST1 LIST2)" nil nil)
+(fn LIST1 LIST2)")
 (autoload 'gnus-sorted-ndifference "gnus-range" "\
 Return a list of elements of LIST1 that do not appear in LIST2.
 Both lists have to be sorted over <.
 LIST1 is modified.
 
-(fn LIST1 LIST2)" nil nil)
+(fn LIST1 LIST2)")
 (autoload 'gnus-sorted-complement "gnus-range" "\
 Return a list of elements that are in LIST1 or LIST2 but not both.
 Both lists have to be sorted over <.
 
-(fn LIST1 LIST2)" nil nil)
+(fn LIST1 LIST2)")
 (autoload 'gnus-intersection "gnus-range" "\
 
 
-(fn LIST1 LIST2)" nil nil)
-(make-obsolete 'gnus-intersection 'seq-intersection '"28.1")
+(fn LIST1 LIST2)")
+(make-obsolete 'gnus-intersection 'seq-intersection "28.1")
 (autoload 'gnus-sorted-intersection "gnus-range" "\
 Return intersection of LIST1 and LIST2.
 LIST1 and LIST2 have to be sorted over <.
 
-(fn LIST1 LIST2)" nil nil)
-(defalias 'gnus-set-sorted-intersection 'gnus-sorted-nintersection)
+(fn LIST1 LIST2)")
+(defalias 'gnus-set-sorted-intersection #'gnus-sorted-nintersection)
 (autoload 'gnus-sorted-nintersection "gnus-range" "\
 Return intersection of LIST1 and LIST2 by modifying cdr pointers of LIST1.
 LIST1 and LIST2 have to be sorted over <.
 
-(fn LIST1 LIST2)" nil nil)
+(fn LIST1 LIST2)")
 (autoload 'gnus-sorted-union "gnus-range" "\
 Return union of LIST1 and LIST2.
 LIST1 and LIST2 have to be sorted over <.
 
-(fn LIST1 LIST2)" nil nil)
+(fn LIST1 LIST2)")
 (autoload 'gnus-sorted-nunion "gnus-range" "\
 Return union of LIST1 and LIST2 by modifying cdr pointers of LIST1.
 LIST1 and LIST2 have to be sorted over <.
 
-(fn LIST1 LIST2)" nil nil)
+(fn LIST1 LIST2)")
 (autoload 'gnus-add-to-sorted-list "gnus-range" "\
 Add NUM into sorted LIST by side effect.
 
-(fn LIST NUM)" nil nil)
+(fn LIST NUM)")
 (register-definition-prefixes "gnus-range" '("gnus-"))
 
 
 ;;; Generated autoloads from gnus/gnus-registry.el
 
 (autoload 'gnus-registry-initialize "gnus-registry" "\
-Initialize the Gnus registry." t nil)
+Initialize the Gnus registry." t)
 (register-definition-prefixes "gnus-registry" '("gnus-"))
 
 
@@ -13827,13 +13915,13 @@ Update the Sieve script in gnus-sieve-file, by 
replacing the region
 between gnus-sieve-region-start and gnus-sieve-region-end with
 (gnus-sieve-script gnus-sieve-select-method gnus-sieve-crosspost), then
 execute gnus-sieve-update-shell-command.
-See the documentation for these variables and functions for details." t nil)
+See the documentation for these variables and functions for details." t)
 (autoload 'gnus-sieve-generate "gnus-sieve" "\
 Generate the Sieve script in gnus-sieve-file, by replacing the region
 between gnus-sieve-region-start and gnus-sieve-region-end with
 (gnus-sieve-script gnus-sieve-select-method gnus-sieve-crosspost).
-See the documentation for these variables and functions for details." t nil)
-(autoload 'gnus-sieve-article-add-rule "gnus-sieve" nil '(gnus-article-mode 
gnus-summary-mode) nil)
+See the documentation for these variables and functions for details." t)
+(autoload 'gnus-sieve-article-add-rule "gnus-sieve" nil '(gnus-article-mode 
gnus-summary-mode))
 (register-definition-prefixes "gnus-sieve" '("gnus-sieve-"))
 
 
@@ -13842,7 +13930,7 @@ See the documentation for these variables and functions 
for details." t nil)
 (autoload 'gnus-update-format "gnus-spec" "\
 Update the format specification near point.
 
-(fn VAR)" t nil)
+(fn VAR)" t)
 (register-definition-prefixes "gnus-spec" '("gnus-"))
 
 
@@ -13856,7 +13944,7 @@ Update the format specification near point.
 (autoload 'gnus-declare-backend "gnus-start" "\
 Declare back end NAME with ABILITIES as a Gnus back end.
 
-(fn NAME &rest ABILITIES)" nil nil)
+(fn NAME &rest ABILITIES)")
 (register-definition-prefixes "gnus-start" '("gnus-"))
 
 
@@ -13866,8 +13954,8 @@ Declare back end NAME with ABILITIES as a Gnus back end.
 Handler function for record returned by `gnus-summary-bookmark-make-record'.
 BOOKMARK is a bookmark name or a bookmark record.
 
-(fn BOOKMARK)" nil nil)
-(register-definition-prefixes "gnus-sum" '(":keymap" "gnus-"))
+(fn BOOKMARK)")
+(register-definition-prefixes "gnus-sum" '("gnus-"))
 
 
 ;;; Generated autoloads from gnus/gnus-topic.el
@@ -13900,7 +13988,7 @@ BOOKMARK is a bookmark name or a bookmark record.
 (autoload 'gnus-add-configuration "gnus-win" "\
 Add the window configuration CONF to `gnus-buffer-configuration'.
 
-(fn CONF)" nil nil)
+(fn CONF)")
 (register-definition-prefixes "gnus-win" '("gnus-"))
 
 
@@ -13930,7 +14018,7 @@ Gomoku game, and ought to be upgraded to use the full 
modern rules.
 
 Use \\[describe-mode] for more info.
 
-(fn &optional N M)" t nil)
+(fn &optional N M)" t)
 (register-definition-prefixes "gomoku" '("gomoku-"))
 
 
@@ -13942,7 +14030,7 @@ Send mail to address at point.  See documentation for
 `goto-address-find-address-at-point'.  If no address is found
 there, then load the URL at or before point.
 
-(fn &optional EVENT)" t nil)
+(fn &optional EVENT)" t)
 (autoload 'goto-address "goto-addr" "\
 Sets up goto-address functionality in the current buffer.
 Allows user to use mouse/keyboard command to click to go to a URL
@@ -13951,7 +14039,7 @@ By default, goto-address binds `goto-address-at-point' 
to mouse-2 and C-c RET
 only on URLs and e-mail addresses.
 
 Also fontifies the buffer appropriately (see `goto-address-fontify-p' and
-`goto-address-highlight-p' for more information)." t nil)
+`goto-address-highlight-p' for more information)." t)
 (put 'goto-address 'safe-local-eval-function t)
 (autoload 'goto-address-mode "goto-addr" "\
 Minor mode to buttonize URLs and e-mail addresses in the current buffer.
@@ -13970,7 +14058,7 @@ evaluate `goto-address-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (put 'global-goto-address-mode 'globalized-minor-mode t)
 (defvar global-goto-address-mode nil "\
 Non-nil if Global Goto-Address mode is enabled.
@@ -13994,7 +14082,7 @@ Goto-Address mode is enabled in all buffers where
 
 See `goto-address-mode' for more information on Goto-Address mode.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'goto-address-prog-mode "goto-addr" "\
 Like `goto-address-mode', but only for comments and strings.
 
@@ -14013,7 +14101,7 @@ evaluate `goto-address-prog-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "goto-addr" '("goto-addr"))
 
 
@@ -14022,7 +14110,7 @@ it is disabled.
 (autoload 'wisent-grammar-mode "semantic/wisent/grammar" "\
 Major mode for editing Wisent grammars.
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "semantic/wisent/grammar" '("semantic-grammar-" 
"wisent-"))
 
 
@@ -14031,7 +14119,7 @@ Major mode for editing Wisent grammars.
 (autoload 'bovine-grammar-mode "semantic/bovine/grammar" "\
 Major mode for editing Bovine grammars.
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "semantic/bovine/grammar" '("bovine-" 
"semantic-grammar-"))
 
 
@@ -14048,13 +14136,13 @@ When finished, call CALLBACK as (apply CALLBACK 
GRAVATAR CBARGS),
 where GRAVATAR is either an image descriptor, or the symbol
 `error' if the retrieval failed.
 
-(fn MAIL-ADDRESS CALLBACK &optional CBARGS)" nil nil)
+(fn MAIL-ADDRESS CALLBACK &optional CBARGS)")
 (autoload 'gravatar-retrieve-synchronously "gravatar" "\
 Synchronously retrieve a gravatar for MAIL-ADDRESS.
 Value is either an image descriptor, or the symbol `error' if the
 retrieval failed.
 
-(fn MAIL-ADDRESS)" nil nil)
+(fn MAIL-ADDRESS)")
 (register-definition-prefixes "gravatar" '("gravatar-"))
 
 
@@ -14063,6 +14151,33 @@ retrieval failed.
 (defvar grep-window-height nil "\
 Number of lines in a grep window.  If nil, use `compilation-window-height'.")
 (custom-autoload 'grep-window-height "grep" t)
+(defvar grep-highlight-matches 'auto-detect "\
+Use special markers to highlight grep matches.
+
+Some grep programs are able to surround matches with special
+markers in grep output.  Such markers can be used to highlight
+matches in grep mode.  This requires `font-lock-mode' to be active
+in grep buffers, so if you have globally disabled `font-lock-mode',
+you will not get highlighting.
+
+This option sets the environment variable GREP_COLORS to specify
+markers for highlighting and adds the --color option in front of
+any explicit grep options before starting the grep.
+
+When this option is `auto', grep uses `--color=auto' to highlight
+matches only when it outputs to a terminal (when `grep' is the last
+command in the pipe), thus avoiding the use of any potentially-harmful
+escape sequences when standard output goes to a file or pipe.
+
+To make grep highlight matches even into a pipe, you need the option
+`always' that forces grep to use `--color=always' to unconditionally
+output escape sequences.
+
+If the value is `auto-detect' (the default), `grep' will call
+`grep-compute-defaults' to compute the value.  To change the
+default value, use \\[customize] or call the function
+`grep-apply-setting'.")
+(custom-autoload 'grep-highlight-matches "grep" nil)
 (defvar grep-command nil "\
 The default grep command for \\[grep].
 If the grep program used supports an option to always include file names
@@ -14087,6 +14202,8 @@ for easier editing.")
 (defvar grep-setup-hook nil "\
 List of hook functions run by `grep-process-setup' (see `run-hooks').")
 (custom-autoload 'grep-setup-hook "grep" t)
+(defvar grep-match-face 'match "\
+Face name to use for grep matches.")
 (defconst grep-regexp-alist `((,(concat "^\\(?:" 
"\\(?1:[^\0\n]+\\)\\(?3:\0\\)\\(?2:[0-9]+\\):" "\\|" "\\(?1:" 
"\\(?:[a-zA-Z]:\\)?" "[^\n:]+?[^\n/:]\\):[\11 ]*\\(?2:[1-9][0-9]*\\)[\11 ]*:" 
"\\)") 1 2 (,(lambda nil (when grep-highlight-matches (let* ((beg (match-end 
0)) (end (save-excursion (goto-char beg) (line-end-position))) (mbeg 
(text-property-any beg end 'font-lock-face grep-match-face))) (when mbeg (- 
mbeg beg))))) \, (lambda nil (when grep-highlight-matches (let* ((beg 
(match-end  [...]
 Regexp used to match grep hits.
 See `compilation-error-regexp-alist' for format details.")
@@ -14117,17 +14234,17 @@ History list for grep.")
 History list for `grep-find'.")
 (autoload 'grep-process-setup "grep" "\
 Setup compilation variables and buffer for `grep'.
-Set up `compilation-exit-message-function' and run `grep-setup-hook'." nil nil)
+Set up `compilation-exit-message-function' and run `grep-setup-hook'.")
 (autoload 'grep-compute-defaults "grep" "\
 Compute the defaults for the `grep' command.
 The value depends on `grep-command', `grep-template',
 `grep-use-null-device', `grep-find-command', `grep-find-template',
 `grep-use-null-filename-separator', `grep-find-use-xargs',
-`grep-highlight-matches', and `grep-quoting-style'." nil nil)
+`grep-highlight-matches', and `grep-quoting-style'.")
 (autoload 'grep-mode "grep" "\
 Sets `grep-last-buffer' and `compilation-window-height'.
 
-(fn)" nil nil)
+(fn)")
 (autoload 'grep "grep" "\
 Run Grep with user-specified COMMAND-ARGS.
 The output from the command goes to the \"*grep*\" buffer.
@@ -14150,7 +14267,7 @@ tag the cursor is over, substituting it into the last 
Grep command
 in the Grep command history (or into `grep-command' if that history
 list is empty).
 
-(fn COMMAND-ARGS)" t nil)
+(fn COMMAND-ARGS)" t)
 (autoload 'grep-find "grep" "\
 Run grep via find, with user-specified args COMMAND-ARGS.
 Collect output in the \"*grep*\" buffer.
@@ -14160,7 +14277,7 @@ to find the text that grep hits refer to.
 This command uses a special history list for its arguments, so you can
 easily repeat a find command.
 
-(fn COMMAND-ARGS)" t nil)
+(fn COMMAND-ARGS)" t)
 (defalias 'find-grep #'grep-find)
 (autoload 'lgrep "grep" "\
 Run grep, searching for REGEXP in FILES in directory DIR.
@@ -14183,7 +14300,7 @@ This command shares argument histories with \\[rgrep] 
and \\[grep].
 If CONFIRM is non-nil, the user will be given an opportunity to edit the
 command before it's run.
 
-(fn REGEXP &optional FILES DIR CONFIRM)" t nil)
+(fn REGEXP &optional FILES DIR CONFIRM)" t)
 (autoload 'rgrep "grep" "\
 Recursively grep for REGEXP in FILES in directory tree rooted at DIR.
 The search is limited to file names matching shell pattern FILES.
@@ -14209,7 +14326,11 @@ to specify a command to run.
 If CONFIRM is non-nil, the user will be given an opportunity to edit the
 command before it's run.
 
-(fn REGEXP &optional FILES DIR CONFIRM)" t nil)
+Interactively, the user can use the \\`M-c' command while entering
+the regexp to indicate whether the grep should be case sensitive
+or not.
+
+(fn REGEXP &optional FILES DIR CONFIRM)" t)
 (autoload 'zrgrep "grep" "\
 Recursively grep for REGEXP in gzipped FILES in tree rooted at DIR.
 Like `rgrep' but uses `zgrep' for `grep-program', sets the default
@@ -14218,7 +14339,7 @@ file name to `*.gz', and sets `grep-highlight-matches' 
to `always'.
 If CONFIRM is non-nil, the user will be given an opportunity to edit the
 command before it's run.
 
-(fn REGEXP &optional FILES DIR CONFIRM TEMPLATE)" t nil)
+(fn REGEXP &optional FILES DIR CONFIRM TEMPLATE)" t)
 (defalias 'rzgrep #'zrgrep)
 (register-definition-prefixes "grep" '("grep-" "kill-grep" "rgrep-"))
 
@@ -14246,19 +14367,19 @@ will run in *gud-PID*, otherwise it will run in 
*gud*; in these
 cases the initial working directory is the `default-directory' of
 the buffer in which this command was invoked.
 
-(fn COMMAND-LINE)" t nil)
+(fn COMMAND-LINE)" t)
 (autoload 'sdb "gud" "\
 Run sdb on program FILE in buffer *gud-FILE*.
 The directory containing FILE becomes the initial working directory
 and source-file directory for your debugger.
 
-(fn COMMAND-LINE)" t nil)
+(fn COMMAND-LINE)" t)
 (autoload 'dbx "gud" "\
 Run dbx on program FILE in buffer *gud-FILE*.
 The directory containing FILE becomes the initial working directory
 and source-file directory for your debugger.
 
-(fn COMMAND-LINE)" t nil)
+(fn COMMAND-LINE)" t)
 (autoload 'xdb "gud" "\
 Run xdb on program FILE in buffer *gud-FILE*.
 The directory containing FILE becomes the initial working directory
@@ -14267,7 +14388,7 @@ and source-file directory for your debugger.
 You can set the variable `gud-xdb-directories' to a list of program source
 directories if your program contains sources from more than one directory.
 
-(fn COMMAND-LINE)" t nil)
+(fn COMMAND-LINE)" t)
 (autoload 'perldb "gud" "\
 Debug a perl program with gud.
 Interactively, this will prompt you for a command line.
@@ -14278,7 +14399,7 @@ Noninteractively, COMMAND-LINE should be on the form
 The directory containing the perl program becomes the initial
 working directory and source-file directory for your debugger.
 
-(fn COMMAND-LINE)" t nil)
+(fn COMMAND-LINE)" t)
 (autoload 'pdb "gud" "\
 Run COMMAND-LINE in the `*gud-FILE*' buffer to debug Python programs.
 
@@ -14290,13 +14411,13 @@ If called interactively, the command line will be 
prompted for.
 The directory containing this file becomes the initial working
 directory and source-file directory for your debugger.
 
-(fn COMMAND-LINE)" t nil)
+(fn COMMAND-LINE)" t)
 (autoload 'guiler "gud" "\
 Run guiler on program FILE in buffer `*gud-FILE*'.
 The directory containing FILE becomes the initial working directory
 and source-file directory for your debugger.
 
-(fn COMMAND-LINE)" t nil)
+(fn COMMAND-LINE)" t)
 (autoload 'jdb "gud" "\
 Run jdb with command line COMMAND-LINE in a buffer.
 The buffer is named \"*gud*\" if no initial class is given or
@@ -14311,11 +14432,11 @@ original source file access method.
 For general information about commands available to control jdb from
 gud, see `gud-mode'.
 
-(fn COMMAND-LINE)" t nil)
+(fn COMMAND-LINE)" t)
 (autoload 'gdb-script-mode "gud" "\
 Major mode for editing GDB scripts.
 
-(fn)" t nil)
+(fn)" t)
 (defvar gud-tooltip-mode nil "\
 Non-nil if Gud-Tooltip mode is enabled.
 See the `gud-tooltip-mode' command
@@ -14341,7 +14462,7 @@ evaluate `(default-value \\='gud-tooltip-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "gud" '("gdb-" "gud-"))
 
 
@@ -14357,7 +14478,7 @@ with a (not necessarily copyable) Elisp expression that 
returns the value to
 set it to.
 DO must return an Elisp expression.
 
-(fn PLACE DO)" nil nil)
+(fn PLACE DO)")
 (autoload 'gv-letplace "gv" "\
 Build the code manipulating the generalized variable PLACE.
 GETTER will be bound to a copyable expression that returns the value
@@ -14370,7 +14491,7 @@ The returned value will then be an Elisp expression 
that first evaluates
 all the parts of PLACE that can be evaluated and then runs E.
 
 (fn (GETTER SETTER) PLACE &rest BODY)" nil t)
-(function-put 'gv-letplace 'lisp-indent-function '2)
+(function-put 'gv-letplace 'lisp-indent-function 2)
 (autoload 'gv-define-expander "gv" "\
 Use HANDLER to handle NAME as a generalized var.
 NAME is a symbol: the name of a function, macro, or special form.
@@ -14378,11 +14499,11 @@ HANDLER is a function which takes an argument DO 
followed by the same
 arguments as NAME.  DO is a function as defined in `gv-get'.
 
 (fn NAME HANDLER)" nil t)
-(function-put 'gv-define-expander 'lisp-indent-function '1)
+(function-put 'gv-define-expander 'lisp-indent-function 1)
 (autoload 'gv--defun-declaration "gv" "\
 
 
-(fn SYMBOL NAME ARGS HANDLER &optional FIX)" nil nil)
+(fn SYMBOL NAME ARGS HANDLER &optional FIX)")
 (defsubst gv--expander-defun-declaration (&rest args) (apply 
#'gv--defun-declaration 'gv-expander args))
 (defsubst gv--setter-defun-declaration (&rest args) (apply 
#'gv--defun-declaration 'gv-setter args))
 (or (assq 'gv-expander defun-declarations-alist) (let ((x (list 'gv-expander 
#'gv--expander-defun-declaration))) (push x macro-declarations-alist) (push x 
defun-declarations-alist)))
@@ -14401,7 +14522,7 @@ to be pure and copyable.  Example use:
   (gv-define-setter aref (v a i) \\=`(aset ,a ,i ,v))
 
 (fn NAME ARGLIST &rest BODY)" nil t)
-(function-put 'gv-define-setter 'lisp-indent-function '2)
+(function-put 'gv-define-setter 'lisp-indent-function 2)
 (autoload 'gv-define-simple-setter "gv" "\
 Define a simple setter method for generalized variable NAME.
 This macro is an easy-to-use substitute for `gv-define-expander' that works
@@ -14433,7 +14554,7 @@ simple PLACEs such as (symbol-function \\='foo) which 
will also work in dynamic
 binding mode.
 
 (fn PLACE)" nil t)
-(register-definition-prefixes "gv" '("gv-"))
+(register-definition-prefixes "gv" '("gv-" 
"make-obsolete-generalized-variable"))
 
 
 ;;; Generated autoloads from play/handwrite.el
@@ -14446,7 +14567,7 @@ and `handwrite-13pt' set up for various sizes of output.
 Variables: `handwrite-linespace'     (default 12)
            `handwrite-fontsize'      (default 11)
            `handwrite-numlines'      (default 60)
-           `handwrite-pagenumbering' (default nil)" t nil)
+           `handwrite-pagenumbering' (default nil)" t)
 (register-definition-prefixes "handwrite" '("handwrite-" 
"menu-bar-handwrite-map"))
 
 
@@ -14457,8 +14578,8 @@ Activate Hangul input method INPUT-METHOD.
 FUNC is a function to handle input key.
 HELP-TEXT is a text set in `hangul-input-method-help-text'.
 
-(fn INPUT-METHOD FUNC HELP-TEXT &rest ARGS)" nil nil)
-(register-definition-prefixes "quail/hangul" '("alphabetp" "hangul" 
"notzerop"))
+(fn INPUT-METHOD FUNC HELP-TEXT &rest ARGS)")
+(register-definition-prefixes "quail/hangul" '("hangul" "notzerop"))
 
 
 ;;; Generated autoloads from language/hanja-util.el
@@ -14471,18 +14592,15 @@ HELP-TEXT is a text set in 
`hangul-input-method-help-text'.
 (autoload 'hanoi "hanoi" "\
 Towers of Hanoi diversion.  Use NRINGS rings.
 
-(fn NRINGS)" t nil)
+(fn NRINGS)" t)
 (autoload 'hanoi-unix "hanoi" "\
-Towers of Hanoi, UNIX doomsday version.
-Displays 32-ring towers that have been progressing at one move per
-second since 1970-01-01 00:00:00 GMT.
+Towers of Hanoi, 32-bit UNIX doomsday version.
+Display 32-ring towers that have been progressing at one move per
+second since 1970-01-01 00:00:00 UTC.
 
-Repent before ring 31 moves." t nil)
+Repent before ring 31 moves." t)
 (autoload 'hanoi-unix-64 "hanoi" "\
-Like `hanoi-unix', but pretend to have a 64-bit clock.
-This is, necessarily (as of Emacs 20.3), a crock.  When the
-`current-time' interface is made s2G-compliant, hanoi.el will need
-to be updated." t nil)
+Like `hanoi-unix', but with a 64-bit clock." t)
 (register-definition-prefixes "hanoi" '("hanoi-"))
 
 
@@ -14491,34 +14609,34 @@ to be updated." t nil)
 (autoload 'hashcash-insert-payment "hashcash" "\
 Insert X-Payment and X-Hashcash headers with a payment for ARG.
 
-(fn ARG)" t nil)
+(fn ARG)" t)
 (autoload 'hashcash-insert-payment-async "hashcash" "\
 Insert X-Payment and X-Hashcash headers with a payment for ARG
 Only start calculation.  Results are inserted when ready.
 
-(fn ARG)" t nil)
+(fn ARG)" t)
 (autoload 'hashcash-verify-payment "hashcash" "\
 Verify a hashcash payment.
 
-(fn TOKEN &optional RESOURCE AMOUNT)" nil nil)
+(fn TOKEN &optional RESOURCE AMOUNT)")
 (autoload 'mail-add-payment "hashcash" "\
 Add X-Payment: and X-Hashcash: headers with a hashcash payment
 for each recipient address.  Prefix arg sets default payment temporarily.
 Set ASYNC to t to start asynchronous calculation.  (See
 `mail-add-payment-async').
 
-(fn &optional ARG ASYNC)" t nil)
+(fn &optional ARG ASYNC)" t)
 (autoload 'mail-add-payment-async "hashcash" "\
 Add X-Payment: and X-Hashcash: headers with a hashcash payment
 for each recipient address.  Prefix arg sets default payment temporarily.
 Calculation is asynchronous.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'mail-check-payment "hashcash" "\
 Look for a valid X-Payment: or X-Hashcash: header.
 Prefix arg sets default accept amount temporarily.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "hashcash" '("hashcash-"))
 
 
@@ -14532,12 +14650,12 @@ If KBD is non-nil, `kbd-help' is used instead, and any
 `help-echo' property is ignored.  In this case, the return value
 can also be t, if that is the value of the `kbd-help' property.
 
-(fn &optional KBD)" nil nil)
+(fn &optional KBD)")
 (autoload 'help-at-pt-kbd-string "help-at-pt" "\
 Return the keyboard help string at point.
 If the `kbd-help' text or overlay property at point produces a
 string, return it.  Otherwise, use the `help-echo' property.
-If this produces no string either, return nil." nil nil)
+If this produces no string either, return nil.")
 (autoload 'display-local-help "help-at-pt" "\
 Display local help in the echo area.
 This command, by default, displays a short help message, namely
@@ -14555,13 +14673,13 @@ If DESCRIBE-BUTTON in non-nil (interactively, the 
prefix arg), and
 there's a button/widget at point, pop a buffer describing that
 button/widget instead.
 
-(fn &optional INHIBIT-WARNING DESCRIBE-BUTTON)" t nil)
+(fn &optional INHIBIT-WARNING DESCRIBE-BUTTON)" t)
 (autoload 'help-at-pt-cancel-timer "help-at-pt" "\
 Cancel any timer set by `help-at-pt-set-timer'.
-This disables `help-at-pt-display-when-idle'." t nil)
+This disables `help-at-pt-display-when-idle'." t)
 (autoload 'help-at-pt-set-timer "help-at-pt" "\
 Enable `help-at-pt-display-when-idle'.
-This is done by setting a timer, if none is currently active." t nil)
+This is done by setting a timer, if none is currently active." t)
 (defvar help-at-pt-display-when-idle 'never "\
 Automatically show local help on point-over.
 If the value is t, the string obtained from any `kbd-help' or
@@ -14610,7 +14728,7 @@ do not run HOOK.  If there are not enough regions to 
move over,
 an error results and the number of available regions is mentioned
 in the error message.  Point is not moved and HOOK is not run.
 
-(fn PROP &optional ARG HOOK)" nil nil)
+(fn PROP &optional ARG HOOK)")
 (autoload 'scan-buf-next-region "help-at-pt" "\
 Go to the start of the next region with non-nil help-echo.
 Print the help found there using `display-local-help'.  Adjacent
@@ -14631,7 +14749,7 @@ help-echo region without any local help being 
available.  This is
 because `help-echo' can be a function evaluating to nil.  This
 rarely happens in practice.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'scan-buf-previous-region "help-at-pt" "\
 Go to the start of the previous region with non-nil help-echo.
 Print the help found there using `display-local-help'.  Adjacent
@@ -14639,7 +14757,7 @@ areas with different non-nil help-echo properties are 
considered
 different regions.  With numeric argument ARG, behaves like
 `scan-buf-next-region' with argument -ARG.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "help-at-pt" '("help-at-pt-" 
"scan-buf-move-hook"))
 
 
@@ -14652,18 +14770,18 @@ When called from Lisp, FUNCTION may also be a 
function object.
 See the `help-enable-symbol-autoload' variable for special
 handling of autoloaded functions.
 
-(fn FUNCTION)" t nil)
+(fn FUNCTION)" t)
 (autoload 'describe-command "help-fns" "\
 Display the full documentation of COMMAND (a symbol).
 When called from Lisp, COMMAND may also be a function object.
 
-(fn COMMAND)" t nil)
+(fn COMMAND)" t)
 (autoload 'help-C-file-name "help-fns" "\
 Return the name of the C file where SUBR-OR-VAR is defined.
 KIND should be `var' for a variable or `subr' for a subroutine.
 If we can't find the file name, nil is returned.
 
-(fn SUBR-OR-VAR KIND)" nil nil)
+(fn SUBR-OR-VAR KIND)")
 (autoload 'find-lisp-object-file-name "help-fns" "\
 Guess the file that defined the Lisp object OBJECT, of type TYPE.
 OBJECT should be a symbol associated with a function, variable, or face;
@@ -14683,17 +14801,17 @@ If ALSO-C-SOURCE is non-nil, instead of returning 
`C-source',
 this function will attempt to locate the definition of OBJECT in
 the C sources, too.
 
-(fn OBJECT TYPE &optional ALSO-C-SOURCE)" nil nil)
+(fn OBJECT TYPE &optional ALSO-C-SOURCE)")
 (autoload 'describe-function-1 "help-fns" "\
 
 
-(fn FUNCTION)" nil nil)
+(fn FUNCTION)")
 (autoload 'variable-at-point "help-fns" "\
 Return the bound variable symbol found at or before point.
 Return 0 if there is no such symbol.
 If ANY-SYMBOL is non-nil, don't insist the symbol be bound.
 
-(fn &optional ANY-SYMBOL)" nil nil)
+(fn &optional ANY-SYMBOL)")
 (autoload 'describe-variable "help-fns" "\
 Display the full documentation of VARIABLE (a symbol).
 Returns the documentation as a string, also.
@@ -14701,7 +14819,7 @@ If VARIABLE has a buffer-local value in BUFFER or FRAME
 (default to the current buffer and current frame),
 it is displayed along with the global value.
 
-(fn VARIABLE &optional BUFFER FRAME)" t nil)
+(fn VARIABLE &optional BUFFER FRAME)" t)
 (autoload 'describe-face "help-fns" "\
 Display the properties of face FACE on FRAME.
 Interactively, FACE defaults to the faces of the character after point
@@ -14711,7 +14829,7 @@ If the optional argument FRAME is given, report on face 
FACE in that frame.
 If FRAME is t, report on the defaults for face FACE (for new frames).
 If FRAME is omitted or nil, use the selected frame.
 
-(fn FACE &optional FRAME)" t nil)
+(fn FACE &optional FRAME)" t)
 (autoload 'describe-symbol "help-fns" "\
 Display the full documentation of SYMBOL.
 Will show the info of SYMBOL as a function, variable, and/or face.
@@ -14719,26 +14837,26 @@ Optional arguments BUFFER and FRAME specify for which 
buffer and
 frame to show the information about SYMBOL; they default to the
 current buffer and the selected frame, respectively.
 
-(fn SYMBOL &optional BUFFER FRAME)" t nil)
+(fn SYMBOL &optional BUFFER FRAME)" t)
 (autoload 'describe-syntax "help-fns" "\
 Describe the syntax specifications in the syntax table of BUFFER.
 The descriptions are inserted in a help buffer, which is then displayed.
 BUFFER defaults to the current buffer.
 
-(fn &optional BUFFER)" t nil)
+(fn &optional BUFFER)" t)
 (autoload 'describe-categories "help-fns" "\
 Describe the category specifications in the current category table.
 The descriptions are inserted in a buffer, which is then displayed.
 If BUFFER is non-nil, then describe BUFFER's category table instead.
 BUFFER should be a buffer or a buffer name.
 
-(fn &optional BUFFER)" t nil)
+(fn &optional BUFFER)" t)
 (autoload 'describe-keymap "help-fns" "\
 Describe key bindings in KEYMAP.
 When called interactively, prompt for a variable that has a
 keymap value.
 
-(fn KEYMAP)" t nil)
+(fn KEYMAP)" t)
 (autoload 'describe-mode "help-fns" "\
 Display documentation of current major mode and minor modes.
 A brief summary of the minor modes comes first, followed by the
@@ -14752,7 +14870,7 @@ whose documentation describes the minor mode.
 If called from Lisp with a non-nil BUFFER argument, display
 documentation for the major and minor modes of that buffer.
 
-(fn &optional BUFFER)" t nil)
+(fn &optional BUFFER)" t)
 (autoload 'describe-widget "help-fns" "\
 Display a buffer with information about a widget.
 You can use this command to describe buttons (e.g., the links in a *Help*
@@ -14766,15 +14884,15 @@ When called from Lisp, POS may be a buffer position 
or a mouse position list.
 Calls each function of the list `describe-widget-functions' in turn, until
 one of them returns non-nil.
 
-(fn &optional POS)" t nil)
+(fn &optional POS)" t)
 (autoload 'doc-file-to-man "help-fns" "\
 Produce an nroff buffer containing the doc-strings from the DOC file.
 
-(fn FILE)" t nil)
+(fn FILE)" t)
 (autoload 'doc-file-to-info "help-fns" "\
 Produce a texinfo buffer with sorted doc-strings from the DOC file.
 
-(fn FILE)" t nil)
+(fn FILE)" t)
 (register-definition-prefixes "help-fns" '("describe-" "help-" 
"keymap-name-history"))
 
 
@@ -14795,7 +14913,7 @@ gives the window that lists the options.")
 (autoload 'help-mode--add-function-link "help-mode" "\
 
 
-(fn STR FUN)" nil nil)
+(fn STR FUN)")
 (autoload 'help-mode "help-mode" "\
 Major mode for viewing help text and navigating references in it.
 Also see the `help-enable-variable-value-editing' variable.
@@ -14803,13 +14921,13 @@ Also see the `help-enable-variable-value-editing' 
variable.
 Commands:
 \\{help-mode-map}
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'help-mode-setup "help-mode" "\
-Enter Help mode in the current buffer." nil nil)
-(make-obsolete 'help-mode-setup 'nil '"29.1")
+Enter Help mode in the current buffer.")
+(make-obsolete 'help-mode-setup 'nil "29.1")
 (autoload 'help-mode-finish "help-mode" "\
-Finalize Help mode setup in current buffer." nil nil)
-(make-obsolete 'help-mode-finish 'nil '"29.1")
+Finalize Help mode setup in current buffer.")
+(make-obsolete 'help-mode-finish 'nil "29.1")
 (autoload 'help-setup-xref "help-mode" "\
 Invoked from commands using the \"*Help*\" buffer to install some xref info.
 
@@ -14822,14 +14940,14 @@ This should be called very early, before the output 
buffer is cleared,
 because we want to record the \"previous\" position of point so we can
 restore it properly when going back.
 
-(fn ITEM INTERACTIVE-P)" nil nil)
+(fn ITEM INTERACTIVE-P)")
 (autoload 'help-buffer "help-mode" "\
 Return the name of a buffer for inserting help.
 If `help-xref-following' is non-nil and the current buffer is
 derived from `help-mode', this is the name of the current buffer.
 
 Otherwise, return \"*Help*\", creating a buffer with that name if
-it does not already exist." nil nil)
+it does not already exist.")
 (autoload 'help-make-xrefs "help-mode" "\
 Parse and hyperlink documentation cross-references in the given BUFFER.
 
@@ -14851,7 +14969,7 @@ A special reference `back' is made to return back 
through a stack of
 help buffers.  Variable `help-back-label' specifies the text for
 that.
 
-(fn &optional BUFFER)" t nil)
+(fn &optional BUFFER)" t)
 (autoload 'help-xref-button "help-mode" "\
 Make a hyperlink for cross-reference text previously matched.
 MATCH-NUMBER is the subexpression of interest in the last matched
@@ -14859,35 +14977,37 @@ regexp.  TYPE is the type of button to use.  Any 
remaining arguments are
 passed to the button's help-function when it is invoked.
 See `help-make-xrefs'.
 
-(fn MATCH-NUMBER TYPE &rest ARGS)" nil nil)
+This function removes quotes surrounding the match if the
+variable `help-clean-buttons' is non-nil.
+
+(fn MATCH-NUMBER TYPE &rest ARGS)")
 (autoload 'help-insert-xref-button "help-mode" "\
 Insert STRING and make a hyperlink from cross-reference text on it.
 TYPE is the type of button to use.  Any remaining arguments are passed
 to the button's help-function when it is invoked.
 See `help-make-xrefs'.
 
-(fn STRING TYPE &rest ARGS)" nil nil)
+(fn STRING TYPE &rest ARGS)")
 (autoload 'help-xref-on-pp "help-mode" "\
 Add xrefs for symbols in `pp's output between FROM and TO.
 
-(fn FROM TO)" nil nil)
-(define-obsolete-function-alias 'help-xref-interned 'describe-symbol "\
-25.1")
+(fn FROM TO)")
+(define-obsolete-function-alias 'help-xref-interned #'describe-symbol "25.1")
 (autoload 'help-bookmark-jump "help-mode" "\
 Jump to `help-mode' bookmark BOOKMARK.
 Handler function for record returned by `help-bookmark-make-record'.
 BOOKMARK is a bookmark name or a bookmark record.
 
-(fn BOOKMARK)" nil nil)
+(fn BOOKMARK)")
 (register-definition-prefixes "help-mode" '("describe-symbol-backends" 
"help-"))
 
 
 ;;; Generated autoloads from emacs-lisp/helper.el
 
 (autoload 'Helper-describe-bindings "helper" "\
-Describe local key bindings of current mode." t nil)
+Describe local key bindings of current mode." t)
 (autoload 'Helper-help "helper" "\
-Provide help for current mode." t nil)
+Provide help for current mode." t)
 (register-definition-prefixes "helper" '("Helper-"))
 
 
@@ -14980,17 +15100,17 @@ You can use \\[hexl-find-file] to visit a file in 
Hexl mode.
 
 \\[describe-bindings] for advanced commands.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'hexl-find-file "hexl" "\
 Edit file FILENAME as a binary file in hex dump format.
 Switch to a buffer visiting file FILENAME, creating one if none exists,
 and edit the file in `hexl-mode'.  The buffer's coding-system will be
 no-conversion, unlike if you visit it normally and then invoke `hexl-mode'.
 
-(fn FILENAME)" t nil)
+(fn FILENAME)" t)
 (autoload 'hexlify-buffer "hexl" "\
 Convert a binary buffer to hexl format.
-This discards the buffer's undo information." t nil)
+This discards the buffer's undo information." t)
 (register-definition-prefixes "hexl" '("dehexlify-buffer" "hexl-"))
 
 
@@ -15002,11 +15122,11 @@ Search `hfy-rgb-load-path' if FILE is not specified.
 Loads the variable `hfy-rgb-txt-color-map', which is used by
 `hfy-fallback-color-values'.
 
-(fn &optional FILE)" t nil)
+(fn &optional FILE)" t)
 (autoload 'hfy-fallback-color-values "hfy-cmap" "\
 Use a fallback method for obtaining the rgb values for a color.
 
-(fn COLOR-STRING)" nil nil)
+(fn COLOR-STRING)")
 (register-definition-prefixes "hfy-cmap" '("hfy-" 
"htmlfontify-unload-rgb-file"))
 
 
@@ -15089,7 +15209,7 @@ evaluate `hi-lock-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (put 'global-hi-lock-mode 'globalized-minor-mode t)
 (defvar global-hi-lock-mode nil "\
 Non-nil if Global Hi-Lock mode is enabled.
@@ -15113,7 +15233,7 @@ Hi-Lock mode is enabled in all buffers where
 
 See `hi-lock-mode' for more information on Hi-Lock mode.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (defalias 'highlight-lines-matching-regexp 'hi-lock-line-face-buffer)
 (autoload 'hi-lock-line-face-buffer "hi-lock" "\
 Highlight all lines that match REGEXP using FACE.
@@ -15131,7 +15251,7 @@ Use Font lock mode, if enabled, to highlight REGEXP.  
Otherwise,
 use overlays for highlighting.  If overlays are used, the
 highlighting will not update as you type.
 
-(fn REGEXP &optional FACE)" t nil)
+(fn REGEXP &optional FACE)" t)
 (defalias 'highlight-regexp 'hi-lock-face-buffer)
 (autoload 'hi-lock-face-buffer "hi-lock" "\
 Set face of each match of REGEXP to FACE.
@@ -15154,7 +15274,7 @@ is considered \"enabled\" in a buffer if its 
`major-mode'
 causes `font-lock-specified-p' to return non-nil, which means
 the major mode specifies support for Font Lock.
 
-(fn REGEXP &optional FACE SUBEXP LIGHTER)" t nil)
+(fn REGEXP &optional FACE SUBEXP LIGHTER)" t)
 (defalias 'highlight-phrase 'hi-lock-face-phrase-buffer)
 (autoload 'hi-lock-face-phrase-buffer "hi-lock" "\
 Set face of each match of phrase REGEXP to FACE.
@@ -15172,7 +15292,7 @@ is considered \"enabled\" in a buffer if its 
`major-mode'
 causes `font-lock-specified-p' to return non-nil, which means
 the major mode specifies support for Font Lock.
 
-(fn REGEXP &optional FACE)" t nil)
+(fn REGEXP &optional FACE)" t)
 (defalias 'highlight-symbol-at-point 'hi-lock-face-symbol-at-point)
 (autoload 'hi-lock-face-symbol-at-point "hi-lock" "\
 Highlight each instance of the symbol at point.
@@ -15187,7 +15307,7 @@ This uses Font lock mode if it is enabled; otherwise it 
uses overlays,
 in which case the highlighting will not update as you type.  The Font
 Lock mode is considered \"enabled\" in a buffer if its `major-mode'
 causes `font-lock-specified-p' to return non-nil, which means
-the major mode specifies support for Font Lock." t nil)
+the major mode specifies support for Font Lock." t)
 (defalias 'unhighlight-regexp 'hi-lock-unface-buffer)
 (autoload 'hi-lock-unface-buffer "hi-lock" "\
 Remove highlighting of each match to REGEXP set by hi-lock.
@@ -15196,19 +15316,19 @@ previously inserted by hi-lock interactive functions.
 If REGEXP is t (or if \\[universal-argument] was specified interactively),
 then remove all hi-lock highlighting.
 
-(fn REGEXP)" t nil)
+(fn REGEXP)" t)
 (autoload 'hi-lock-write-interactive-patterns "hi-lock" "\
 Write interactively added patterns, if any, into buffer at point.
 
 Interactively added patterns are those normally specified using
 `highlight-regexp' and `highlight-lines-matching-regexp'; they can
-be found in variable `hi-lock-interactive-patterns'." t nil)
+be found in variable `hi-lock-interactive-patterns'." t)
 (autoload 'hi-lock-find-patterns "hi-lock" "\
-Add patterns from the current buffer to the list of hi-lock patterns." t nil)
+Add patterns from the current buffer to the list of hi-lock patterns." t)
 (autoload 'hi-lock-context-menu "hi-lock" "\
 Populate MENU with a menu item to highlight symbol at CLICK.
 
-(fn MENU CLICK)" nil nil)
+(fn MENU CLICK)")
 (register-definition-prefixes "hi-lock" '("hi-lock-" 
"highlight-symbol-at-mouse" "turn-on-hi-lock-if-enabled"))
 
 
@@ -15265,7 +15385,7 @@ evaluate `hide-ifdef-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "hideif" '("backward-ifdef" "down-ifdef" 
"forward-ifdef" "hide-ifdef" "hif-" "intern-safe" "next-ifdef" "previous-ifdef" 
"show-ifdef" "up-ifdef"))
 
 
@@ -15331,9 +15451,9 @@ evaluate `hs-minor-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'turn-off-hideshow "hideshow" "\
-Unconditionally turn off `hs-minor-mode'." nil nil)
+Unconditionally turn off `hs-minor-mode'.")
 (register-definition-prefixes "hideshow" '("hs-"))
 
 
@@ -15377,7 +15497,7 @@ evaluate `highlight-changes-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'highlight-changes-visible-mode "hilit-chg" "\
 Toggle visibility of highlighting due to Highlight Changes mode.
 
@@ -15405,16 +15525,16 @@ evaluate `highlight-changes-visible-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'highlight-changes-remove-highlight "hilit-chg" "\
 Remove the change face from the region between BEG and END.
 This allows you to manually remove highlighting from uninteresting changes.
 
-(fn BEG END)" t nil)
+(fn BEG END)" t)
 (autoload 'highlight-changes-next-change "hilit-chg" "\
-Move to the beginning of the next change, if in Highlight Changes mode." t nil)
+Move to the beginning of the next change, if in Highlight Changes mode." t)
 (autoload 'highlight-changes-previous-change "hilit-chg" "\
-Move to the beginning of the previous change, if in Highlight Changes mode." t 
nil)
+Move to the beginning of the previous change, if in Highlight Changes mode." t)
 (autoload 'highlight-changes-rotate-faces "hilit-chg" "\
 \"Age\" changes if in Highlight Changes mode and the changes are visible.
 
@@ -15427,7 +15547,7 @@ You can automatically rotate colors when the buffer is 
saved by adding
 this function to `write-file-functions' as a buffer-local value.  To do
 this, eval the following in the buffer to be saved:
 
-  (add-hook \\='write-file-functions \\='highlight-changes-rotate-faces nil 
t)" t nil)
+  (add-hook \\='write-file-functions \\='highlight-changes-rotate-faces nil 
t)" t)
 (autoload 'highlight-compare-buffers "hilit-chg" "\
 Compare two buffers and highlight the differences.
 
@@ -15443,7 +15563,7 @@ If a buffer is read-only, differences will be 
highlighted but no property
 changes are made, so \\[highlight-changes-next-change] and
 \\[highlight-changes-previous-change] will not work.
 
-(fn BUF-A BUF-B)" t nil)
+(fn BUF-A BUF-B)" t)
 (autoload 'highlight-compare-with-file "hilit-chg" "\
 Compare this buffer with a file, and highlight differences.
 
@@ -15458,7 +15578,7 @@ If the buffer is read-only, differences will be 
highlighted but no property
 changes are made, so \\[highlight-changes-next-change] and
 \\[highlight-changes-previous-change] will not work.
 
-(fn FILE-B)" t nil)
+(fn FILE-B)" t)
 (put 'global-highlight-changes-mode 'globalized-minor-mode t)
 (defvar global-highlight-changes-mode nil "\
 Non-nil if Global Highlight-Changes mode is enabled.
@@ -15483,7 +15603,7 @@ Highlight-Changes mode is enabled in all buffers where
 See `highlight-changes-mode' for more information on Highlight-Changes
 mode.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "hilit-chg" '("highlight-" "hilit-chg-"))
 
 
@@ -15504,13 +15624,13 @@ With a positive numeric argument, jumps directly to 
the ARG next
 function in this list.  With a negative argument or just 
\\[universal-argument],
 undoes the expansion.
 
-(fn ARG)" t nil)
+(fn ARG)" t)
 (autoload 'make-hippie-expand-function "hippie-exp" "\
 Construct a function similar to `hippie-expand'.
 Make it use the expansion functions in TRY-LIST.  An optional second
 argument VERBOSE non-nil makes the function verbose.
 
-(fn TRY-LIST &optional VERBOSE)" nil nil)
+(fn TRY-LIST &optional VERBOSE)")
 (register-definition-prefixes "hippie-exp" '("he-" "hippie-expand-" "try-"))
 
 
@@ -15543,7 +15663,7 @@ evaluate `hl-line-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (defvar global-hl-line-mode nil "\
 Non-nil if Global Hl-Line mode is enabled.
 See the `global-hl-line-mode' command
@@ -15576,7 +15696,7 @@ evaluate `(default-value \\='global-hl-line-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "hl-line" '("global-hl-line-" "hl-line-"))
 
 
@@ -15643,7 +15763,7 @@ Display the holidays for last month, this month, and 
next month.
 If called with an optional prefix argument ARG, prompts for month and year.
 This function is suitable for execution in an init file.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'list-holidays "holidays" "\
 Display holidays for years Y1 to Y2 (inclusive).
 Y2 defaults to Y1.  The optional list of holidays L defaults to
@@ -15669,7 +15789,7 @@ The list of holiday lists is computed by the
 by redefining that function, or use `add-function' to add
 values.
 
-(fn Y1 &optional Y2 L LABEL)" t nil)
+(fn Y1 &optional Y2 L LABEL)" t)
 (defalias 'holiday-list 'list-holidays)
 (register-definition-prefixes "holidays" '("calendar-" "holiday-"))
 
@@ -15700,14 +15820,14 @@ If the SRCDIR and FILE arguments are set, lookup 
etags derived
 entries in the `hfy-tags-cache' and add HTML anchors and
 hyperlinks as appropriate.
 
-(fn &optional SRCDIR FILE)" t nil)
+(fn &optional SRCDIR FILE)" t)
 (autoload 'htmlfontify-copy-and-link-dir "htmlfontify" "\
 Trawl SRCDIR and write fontified-and-hyperlinked output in DSTDIR.
 F-EXT and L-EXT specify values for `hfy-extn' and `hfy-link-extn'.
 
 You may also want to set `hfy-page-header' and `hfy-page-footer'.
 
-(fn SRCDIR DSTDIR &optional F-EXT L-EXT)" t nil)
+(fn SRCDIR DSTDIR &optional F-EXT L-EXT)" t)
 (register-definition-prefixes "htmlfontify" '("hfy-" "htmlfontify-"))
 
 
@@ -15827,13 +15947,13 @@ Display a list of buffers, in another window.
 If optional argument FILES-ONLY is non-nil, then add a filter for
 buffers which are visiting a file.
 
-(fn &optional FILES-ONLY)" t nil)
+(fn &optional FILES-ONLY)" t)
 (autoload 'ibuffer-other-window "ibuffer" "\
 Like `ibuffer', but displayed in another window by default.
 If optional argument FILES-ONLY is non-nil, then add a filter for
 buffers which are visiting a file.
 
-(fn &optional FILES-ONLY)" t nil)
+(fn &optional FILES-ONLY)" t)
 (autoload 'ibuffer "ibuffer" "\
 Begin using Ibuffer to edit a list of buffers.
 Type \\<ibuffer-mode-map>\\[describe-mode] after entering ibuffer for more 
information.
@@ -15852,13 +15972,13 @@ FORMATS is the value to use for `ibuffer-formats'.
   If specified, then the variable `ibuffer-formats' will have
   that value locally in this buffer.
 
-(fn &optional OTHER-WINDOW-P NAME QUALIFIERS NOSELECT SHRINK FILTER-GROUPS 
FORMATS)" t nil)
+(fn &optional OTHER-WINDOW-P NAME QUALIFIERS NOSELECT SHRINK FILTER-GROUPS 
FORMATS)" t)
 (autoload 'ibuffer-jump "ibuffer" "\
 Call Ibuffer and set point at the line listing the current buffer.
 If optional arg OTHER-WINDOW is non-nil, then use another window.
 
-(fn &optional OTHER-WINDOW)" t nil)
-(register-definition-prefixes "ibuffer" '("filename" "ibuffer-" "locked" 
"mark" "mod" "name" "process" "read-only" "recency" "size"))
+(fn &optional OTHER-WINDOW)" t)
+(register-definition-prefixes "ibuffer" '("ibuffer-"))
 
 
 ;;; Generated autoloads from calendar/icalendar.el
@@ -15868,7 +15988,7 @@ Export diary file to iCalendar format.
 All diary entries in the file DIARY-FILENAME are converted to iCalendar
 format.  The result is appended to the file ICAL-FILENAME.
 
-(fn DIARY-FILENAME ICAL-FILENAME)" t nil)
+(fn DIARY-FILENAME ICAL-FILENAME)" t)
 (autoload 'icalendar-export-region "icalendar" "\
 Export region in diary file to iCalendar format.
 All diary entries in the region from MIN to MAX in the current buffer are
@@ -15878,7 +15998,7 @@ This function attempts to return t if something goes 
wrong.  In this
 case an error string which describes all the errors and problems is
 written into the buffer `*icalendar-errors*'.
 
-(fn MIN MAX ICAL-FILENAME)" t nil)
+(fn MIN MAX ICAL-FILENAME)" t)
 (autoload 'icalendar-import-file "icalendar" "\
 Import an iCalendar file and append to a diary file.
 Argument ICAL-FILENAME output iCalendar file.
@@ -15886,7 +16006,7 @@ Argument DIARY-FILENAME input `diary-file'.
 Optional argument NON-MARKING determines whether events are created as
 non-marking or not.
 
-(fn ICAL-FILENAME DIARY-FILENAME &optional NON-MARKING)" t nil)
+(fn ICAL-FILENAME DIARY-FILENAME &optional NON-MARKING)" t)
 (autoload 'icalendar-import-buffer "icalendar" "\
 Extract iCalendar events from current buffer.
 
@@ -15905,7 +16025,7 @@ Return code t means that importing worked well, return 
code nil
 means that an error has occurred.  Error messages will be in the
 buffer `*icalendar-errors*'.
 
-(fn &optional DIARY-FILENAME DO-NOT-ASK NON-MARKING)" t nil)
+(fn &optional DIARY-FILENAME DO-NOT-ASK NON-MARKING)" t)
 (register-definition-prefixes "icalendar" '("icalendar-"))
 
 
@@ -15939,7 +16059,7 @@ evaluate `(default-value \\='fido-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (defvar icomplete-mode nil "\
 Non-nil if Icomplete mode is enabled.
 See the `icomplete-mode' command
@@ -15978,7 +16098,7 @@ evaluate `(default-value \\='icomplete-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (defvar icomplete-vertical-mode nil "\
 Non-nil if Icomplete-Vertical mode is enabled.
 See the `icomplete-vertical-mode' command
@@ -16011,7 +16131,7 @@ evaluate `(default-value \\='icomplete-vertical-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (defvar fido-vertical-mode nil "\
 Non-nil if Fido-Vertical mode is enabled.
 See the `fido-vertical-mode' command
@@ -16040,7 +16160,7 @@ evaluate `(default-value \\='fido-vertical-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (when (locate-library "obsolete/iswitchb")
  (autoload 'iswitchb-mode "iswitchb" "Toggle Iswitchb mode." t)
  (make-obsolete 'iswitchb-mode
@@ -16083,10 +16203,19 @@ Variables controlling indentation style:
 Turning on Icon mode calls the value of the variable `icon-mode-hook'
 with no args, if that value is non-nil.
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "icon" '("beginning-of-icon-defun" 
"calculate-icon-indent" "electric-icon-brace" "end-of-icon-defun" "icon-" 
"indent-icon-exp" "mark-icon-function"))
 
 
+;;; Generated autoloads from emacs-lisp/icons.el
+
+(autoload 'describe-icon "icons" "\
+Pop to a buffer to describe ICON.
+
+(fn ICON)" t)
+(register-definition-prefixes "icons" '("button" "define-icon" "icon"))
+
+
 ;;; Generated autoloads from cedet/semantic/idle.el
 
 (register-definition-prefixes "semantic/idle" '("define-semantic-idle-service" 
"global-semantic-idle-summary-mode" "semantic-"))
@@ -16122,7 +16251,7 @@ See also the variable `idlwave-shell-prompt-pattern'.
 
 (Type \\[describe-mode] in the shell buffer for a list of commands.)
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "idlw-shell" '("idlwave-"))
 
 
@@ -16254,7 +16383,7 @@ The main features of this mode are
 
 \\{idlwave-mode-map}
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "idlwave" '("idlwave-"))
 
 
@@ -16282,7 +16411,7 @@ However, if ARG arg equals `files', remap only commands 
for files, or
 if it equals `buffers', remap only commands for buffer switching.
 This function also adds a hook to the minibuffer.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'ido-switch-buffer "ido" "\
 Switch to another buffer.
 The buffer is displayed according to `ido-default-buffer-method' -- the
@@ -16314,11 +16443,11 @@ RET   Select the buffer at the front of the list of 
matches.
 \\[ido-completion-help]        Show list of matching buffers in separate 
window.
 \\[ido-enter-find-file]        Drop into `ido-find-file'.
 \\[ido-kill-buffer-at-head]    Kill buffer at head of buffer list.
-\\[ido-toggle-ignore]  Toggle ignoring buffers listed in 
`ido-ignore-buffers'." t nil)
+\\[ido-toggle-ignore]  Toggle ignoring buffers listed in 
`ido-ignore-buffers'." t)
 (autoload 'ido-switch-buffer-other-window "ido" "\
 Switch to another buffer and show it in another window.
 The buffer name is selected interactively by typing a substring.
-For details of keybindings, see `ido-switch-buffer'." t nil)
+For details of keybindings, see `ido-switch-buffer'." t)
 (autoload 'ido-display-buffer "ido" "\
 Display a buffer in another window but don't select it.
 
@@ -16329,27 +16458,27 @@ window.
 The buffer name is selected interactively by typing a substring.
 For details of keybindings, see `ido-switch-buffer'.
 
-(fn &optional ACTION)" t nil)
+(fn &optional ACTION)" t)
 (autoload 'ido-display-buffer-other-frame "ido" "\
 Display a buffer preferably in another frame.
 The buffer name is selected interactively by typing a substring.
-For details of keybindings, see `ido-switch-buffer'." t nil)
+For details of keybindings, see `ido-switch-buffer'." t)
 (autoload 'ido-kill-buffer "ido" "\
 Kill a buffer.
 The buffer name is selected interactively by typing a substring.
-For details of keybindings, see `ido-switch-buffer'." t nil)
+For details of keybindings, see `ido-switch-buffer'." t)
 (autoload 'ido-insert-buffer "ido" "\
 Insert contents of a buffer in current buffer after point.
 The buffer name is selected interactively by typing a substring.
-For details of keybindings, see `ido-switch-buffer'." t nil)
+For details of keybindings, see `ido-switch-buffer'." t)
 (autoload 'ido-switch-buffer-other-frame "ido" "\
 Switch to another buffer and show it in another frame.
 The buffer name is selected interactively by typing a substring.
-For details of keybindings, see `ido-switch-buffer'." t nil)
+For details of keybindings, see `ido-switch-buffer'." t)
 (autoload 'ido-find-file-in-dir "ido" "\
 Switch to another file starting from DIR.
 
-(fn DIR)" t nil)
+(fn DIR)" t)
 (autoload 'ido-find-file "ido" "\
 Edit file with name obtained via minibuffer.
 The file is displayed according to `ido-default-file-method' -- the
@@ -16392,59 +16521,59 @@ RET   Select the file at the front of the list of 
matches.
 \\[ido-toggle-literal] Toggle literal reading of this file.
 \\[ido-completion-help]        Show list of matching files in separate window.
 \\[ido-toggle-ignore]  Toggle ignoring files listed in `ido-ignore-files'.
-\\[ido-reread-directory]       Reread the current directory." t nil)
+\\[ido-reread-directory]       Reread the current directory." t)
 (autoload 'ido-find-file-other-window "ido" "\
 Switch to another file and show it in another window.
 The file name is selected interactively by typing a substring.
-For details of keybindings, see `ido-find-file'." t nil)
+For details of keybindings, see `ido-find-file'." t)
 (autoload 'ido-find-alternate-file "ido" "\
 Find another file, select its buffer, kill previous buffer.
 The file name is selected interactively by typing a substring.
-For details of keybindings, see `ido-find-file'." t nil)
+For details of keybindings, see `ido-find-file'." t)
 (autoload 'ido-find-alternate-file-other-window "ido" "\
 Find file as a replacement for the file in the next window.
 The file name is selected interactively by typing a substring.
-For details of keybindings, see `ido-find-file'." t nil)
+For details of keybindings, see `ido-find-file'." t)
 (autoload 'ido-find-file-read-only "ido" "\
 Edit file read-only with name obtained via minibuffer.
 The file name is selected interactively by typing a substring.
-For details of keybindings, see `ido-find-file'." t nil)
+For details of keybindings, see `ido-find-file'." t)
 (autoload 'ido-find-file-read-only-other-window "ido" "\
 Edit file read-only in other window with name obtained via minibuffer.
 The file name is selected interactively by typing a substring.
-For details of keybindings, see `ido-find-file'." t nil)
+For details of keybindings, see `ido-find-file'." t)
 (autoload 'ido-find-file-read-only-other-frame "ido" "\
 Edit file read-only in other frame with name obtained via minibuffer.
 The file name is selected interactively by typing a substring.
-For details of keybindings, see `ido-find-file'." t nil)
+For details of keybindings, see `ido-find-file'." t)
 (autoload 'ido-display-file "ido" "\
 Display a file in another window but don't select it.
 The file name is selected interactively by typing a substring.
-For details of keybindings, see `ido-find-file'." t nil)
+For details of keybindings, see `ido-find-file'." t)
 (autoload 'ido-find-file-other-frame "ido" "\
 Switch to another file and show it in another frame.
 The file name is selected interactively by typing a substring.
-For details of keybindings, see `ido-find-file'." t nil)
+For details of keybindings, see `ido-find-file'." t)
 (autoload 'ido-write-file "ido" "\
 Write current buffer to a file.
 The file name is selected interactively by typing a substring.
-For details of keybindings, see `ido-find-file'." t nil)
+For details of keybindings, see `ido-find-file'." t)
 (autoload 'ido-insert-file "ido" "\
 Insert contents of file in current buffer.
 The file name is selected interactively by typing a substring.
-For details of keybindings, see `ido-find-file'." t nil)
+For details of keybindings, see `ido-find-file'." t)
 (autoload 'ido-dired "ido" "\
 Call `dired' the Ido way.
 The directory is selected interactively by typing a substring.
-For details of keybindings, see `ido-find-file'." t nil)
+For details of keybindings, see `ido-find-file'." t)
 (autoload 'ido-dired-other-window "ido" "\
 \"Edit\" a directory.  Like `ido-dired' but select in another window.
 The directory is selected interactively by typing a substring.
-For details of keybindings, see `ido-find-file'." t nil)
+For details of keybindings, see `ido-find-file'." t)
 (autoload 'ido-dired-other-frame "ido" "\
 \"Edit\" a directory.  Like `ido-dired' but make a new frame.
 The directory is selected interactively by typing a substring.
-For details of keybindings, see `ido-find-file'." t nil)
+For details of keybindings, see `ido-find-file'." t)
 (autoload 'ido-read-buffer "ido" "\
 Ido replacement for the built-in `read-buffer'.
 Return the name of a buffer selected.
@@ -16454,19 +16583,19 @@ If REQUIRE-MATCH is non-nil, an existing buffer must 
be selected.
 Optional arg PREDICATE if non-nil is a function limiting the
 buffers that can be considered.
 
-(fn PROMPT &optional DEFAULT REQUIRE-MATCH PREDICATE)" nil nil)
+(fn PROMPT &optional DEFAULT REQUIRE-MATCH PREDICATE)")
 (autoload 'ido-read-file-name "ido" "\
 Ido replacement for the built-in `read-file-name'.
 Read file name, prompting with PROMPT and completing in directory DIR.
 See `read-file-name' for additional parameters.
 
-(fn PROMPT &optional DIR DEFAULT-FILENAME MUSTMATCH INITIAL PREDICATE)" nil 
nil)
+(fn PROMPT &optional DIR DEFAULT-FILENAME MUSTMATCH INITIAL PREDICATE)")
 (autoload 'ido-read-directory-name "ido" "\
 Ido replacement for the built-in `read-directory-name'.
 Read directory name, prompting with PROMPT and completing in directory DIR.
 See `read-directory-name' for additional parameters.
 
-(fn PROMPT &optional DIR DEFAULT-DIRNAME MUSTMATCH INITIAL)" nil nil)
+(fn PROMPT &optional DIR DEFAULT-DIRNAME MUSTMATCH INITIAL)")
 (autoload 'ido-completing-read "ido" "\
 Ido replacement for the built-in `completing-read'.
 Read a string in the minibuffer with Ido-style completion.
@@ -16483,7 +16612,7 @@ If INITIAL-INPUT is non-nil, insert it in the 
minibuffer initially,
 HIST, if non-nil, specifies a history list.
 DEF, if non-nil, is the default value.
 
-(fn PROMPT CHOICES &optional PREDICATE REQUIRE-MATCH INITIAL-INPUT HIST DEF 
INHERIT-INPUT-METHOD)" nil nil)
+(fn PROMPT CHOICES &optional PREDICATE REQUIRE-MATCH INITIAL-INPUT HIST DEF 
INHERIT-INPUT-METHOD)")
 (register-definition-prefixes "ido" '("ido-"))
 
 
@@ -16500,7 +16629,7 @@ Switches to the buffer named BUF-NAME if provided 
(`*ielm*' by default),
 or creates it if it does not exist.
 See `inferior-emacs-lisp-mode' for details.
 
-(fn &optional BUF-NAME)" t nil)
+(fn &optional BUF-NAME)" t)
 (register-definition-prefixes "ielm" '("ielm-" "inferior-emacs-lisp-mode"))
 
 
@@ -16516,8 +16645,6 @@ See `inferior-emacs-lisp-mode' for details.
 
 ;;; Generated autoloads from iimage.el
 
-(define-obsolete-function-alias 'turn-on-iimage-mode 'iimage-mode "\
-24.1")
 (autoload 'iimage-mode "iimage" "\
 Toggle Iimage mode on or off.
 
@@ -16535,7 +16662,7 @@ evaluate `iimage-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "iimage" '("iimage-" "turn-off-iimage-mode"))
 
 
@@ -16546,24 +16673,24 @@ Determine the image type from image data DATA.
 Value is a symbol specifying the image type or nil if type cannot
 be determined.
 
-(fn DATA)" nil nil)
+(fn DATA)")
 (autoload 'image-type-from-buffer "image" "\
 Determine the image type from data in the current buffer.
 Value is a symbol specifying the image type or nil if type cannot
-be determined." nil nil)
+be determined.")
 (autoload 'image-type-from-file-header "image" "\
 Determine the type of image file FILE from its first few bytes.
 Value is a symbol specifying the image type, or nil if type cannot
 be determined.
 
-(fn FILE)" nil nil)
+(fn FILE)")
 (autoload 'image-type-from-file-name "image" "\
 Determine the type of image file FILE from its name.
 Value is a symbol specifying the image type, or nil if type cannot
 be determined.
 
-(fn FILE)" nil nil)
-(make-obsolete 'image-type-from-file-name 'image-supported-file-p '"29.1")
+(fn FILE)")
+(make-obsolete 'image-type-from-file-name 'image-supported-file-p "29.1")
 (autoload 'image-type "image" "\
 Determine and return image type.
 SOURCE is an image file name or image data.
@@ -16577,12 +16704,12 @@ data.  If DATA-P is a symbol with a name on the format
 `image/jpeg', that may be used as a hint to determine the image
 type if we can't otherwise guess it.
 
-(fn SOURCE &optional TYPE DATA-P)" nil nil)
+(fn SOURCE &optional TYPE DATA-P)")
 (autoload 'image-type-available-p "image" "\
 Return t if image type TYPE is available.
 Image types are symbols like `xbm' or `jpeg'.
 
-(fn TYPE)" nil nil)
+(fn TYPE)")
 (autoload 'image-type-auto-detected-p "image" "\
 Return t if the current buffer contains an auto-detectable image.
 This function is intended to be used from `magic-fallback-mode-alist'.
@@ -16591,7 +16718,7 @@ The buffer is considered to contain an auto-detectable 
image if
 its beginning matches an image type in `image-type-header-regexps',
 and that image type is present in `image-type-auto-detectable' with a
 non-nil value.  If that value is non-nil, but not t, then the image type
-must be available." nil nil)
+must be available.")
 (autoload 'create-image "image" "\
 Create an image.
 FILE-OR-DATA is an image file name or image data.
@@ -16617,7 +16744,7 @@ Image file names that are not absolute are searched for 
in the
 \"images\" sub-directory of `data-directory' and
 `x-bitmap-file-path' (in that order).
 
-(fn FILE-OR-DATA &optional TYPE DATA-P &rest PROPS)" nil nil)
+(fn FILE-OR-DATA &optional TYPE DATA-P &rest PROPS)")
 (autoload 'put-image "image" "\
 Put image IMAGE in front of POS in the current buffer.
 IMAGE must be an image created with `create-image' or `defimage'.
@@ -16631,7 +16758,7 @@ display it in the text area, a value of `left-margin' 
means
 display it in the left marginal area, a value of `right-margin'
 means display it in the right marginal area.
 
-(fn IMAGE POS &optional STRING AREA)" nil nil)
+(fn IMAGE POS &optional STRING AREA)")
 (autoload 'insert-image "image" "\
 Insert IMAGE into current buffer at point.
 IMAGE is displayed by inserting STRING into the current buffer
@@ -16655,7 +16782,7 @@ Normally `isearch' is able to search for STRING in the 
buffer
 even if it's hidden behind a displayed image.  If INHIBIT-ISEARCH
 is non-nil, this is inhibited.
 
-(fn IMAGE &optional STRING AREA SLICE INHIBIT-ISEARCH)" nil nil)
+(fn IMAGE &optional STRING AREA SLICE INHIBIT-ISEARCH)")
 (autoload 'insert-sliced-image "image" "\
 Insert IMAGE into current buffer at point.
 IMAGE is displayed by inserting STRING into the current buffer
@@ -16667,13 +16794,13 @@ display it in the left marginal area, a value of 
`right-margin'
 means display it in the right marginal area.
 The image is automatically split into ROWS x COLS slices.
 
-(fn IMAGE &optional STRING AREA ROWS COLS)" nil nil)
+(fn IMAGE &optional STRING AREA ROWS COLS)")
 (autoload 'remove-images "image" "\
 Remove images between START and END in BUFFER.
 Remove only images that were put in BUFFER with calls to `put-image'.
 BUFFER nil or omitted means use the current buffer.
 
-(fn START END &optional BUFFER)" nil nil)
+(fn START END &optional BUFFER)")
 (autoload 'find-image "image" "\
 Find an image, choosing one of a list of image specifications.
 
@@ -16681,13 +16808,15 @@ SPECS is a list of image specifications.
 
 Each image specification in SPECS is a property list.  The contents of
 a specification are image type dependent.  All specifications must at
-least contain the properties `:type TYPE' and either `:file FILE' or
-`:data DATA', where TYPE is a symbol specifying the image type,
-e.g. `xbm', FILE is the file to load the image from, and DATA is a
-string containing the actual image data.  The specification whose TYPE
-is supported, and FILE exists, is used to construct the image
-specification to be returned.  Return nil if no specification is
-satisfied.
+least contain either the property `:file FILE' or `:data DATA',
+where FILE is the file to load the image from, and DATA is a string
+containing the actual image data.  If the property `:type TYPE' is
+omitted or nil, try to determine the image type from its first few
+bytes of image data.  If that doesn't work, and the property `:file
+FILE' provide a file name, use its file extension as image type.
+If `:type TYPE' is provided, it must match the actual type
+determined for FILE or DATA by `create-image'.  Return nil if no
+specification is satisfied.
 
 If CACHE is non-nil, results are cached and returned on subsequent calls.
 
@@ -16695,7 +16824,7 @@ The image is looked for in `image-load-path'.
 
 Image files should not be larger than specified by `max-image-size'.
 
-(fn SPECS &optional CACHE)" nil nil)
+(fn SPECS &optional CACHE)")
 (autoload 'defimage "image" "\
 Define SYMBOL as an image, and return SYMBOL.
 
@@ -16717,7 +16846,7 @@ Example:
                          (:type xbm :file \"~/test1.xbm\")))
 
 (fn SYMBOL SPECS &optional DOC)" nil t)
-(function-put 'defimage 'doc-string-elt '3)
+(function-put 'defimage 'doc-string-elt 3)
 (function-put 'defimage 'lisp-indent-function 'defun)
 (autoload 'imagemagick-register-types "image" "\
 Register file types that can be handled by ImageMagick.
@@ -16729,14 +16858,23 @@ Emacs visits them in Image mode.  They are also added 
to
 `image-type-file-name-regexps', so that the `image-type' function
 recognizes these files as having image type `imagemagick'.
 
-If Emacs is compiled without ImageMagick support, this does nothing." nil nil)
+If Emacs is compiled without ImageMagick support, this does nothing.")
 (autoload 'image-at-point-p "image" "\
-Return non-nil if there is an image at point." nil nil)
+Return non-nil if there is an image at point.")
 (register-definition-prefixes "image" '("find-image--cache" "image" 
"unknown-image-type"))
 
 
 ;;; Generated autoloads from image/image-converter.el
 
+(autoload 'image-converter-add-handler "image-converter" "\
+Make Emacs use CONVERTER to parse image files that end with SUFFIX.
+CONVERTER is a function with two parameters, where the first is
+the file name or a string with the image data, and the second is
+non-nil if the first parameter is image data.  The converter
+should output the image in the current buffer, converted to
+`image-convert-to-format'.
+
+(fn SUFFIX CONVERTER)")
 (register-definition-prefixes "image-converter" '("image-convert"))
 
 
@@ -16750,7 +16888,7 @@ current line.  ARG, if non-nil, specifies the files to 
use instead
 of the marked files.  If ARG is an integer, use the next ARG (or
 previous -ARG, if ARG<0) files.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'image-dired-dired-with-window-configuration "image-dired" "\
 Open directory DIR and create a default window configuration.
 
@@ -16769,7 +16907,7 @@ If called with prefix argument ARG, skip splitting of 
windows.
 The current window configuration is saved and can be restored by
 calling `image-dired-restore-window-configuration'.
 
-(fn DIR &optional ARG)" t nil)
+(fn DIR &optional ARG)" t)
 (autoload 'image-dired-display-thumbs "image-dired" "\
 Display thumbnails of all marked files, in `image-dired-thumbnail-buffer'.
 If a thumbnail image does not exist for a file, it is created on the
@@ -16791,7 +16929,7 @@ used or not.  If non-nil, use `display-buffer' instead 
of
 `image-dired-previous-line-and-display' where we do not want the
 thumbnail buffer to be selected.
 
-(fn &optional ARG APPEND DO-NOT-POP)" t nil)
+(fn &optional ARG APPEND DO-NOT-POP)" t)
 (autoload 'image-dired-show-all-from-dir "image-dired" "\
 Make a thumbnail buffer for all images in DIR and display it.
 Any file matching `image-file-name-regexp' is considered an image
@@ -16802,19 +16940,19 @@ If the number of image files in DIR exceeds
 before creating the thumbnail buffer.  If that variable is nil,
 never ask for confirmation.
 
-(fn DIR)" t nil)
+(fn DIR)" t)
 (defalias 'image-dired 'image-dired-show-all-from-dir)
 (autoload 'image-dired-tag-files "image-dired" "\
 Tag marked file(s) in Dired.  With prefix ARG, tag file at point.
 
-(fn ARG)" t nil)
+(fn ARG)" t)
 (autoload 'image-dired-delete-tag "image-dired" "\
 Remove tag for selected file(s).
 With prefix argument ARG, remove tag from file at point.
 
-(fn ARG)" t nil)
+(fn ARG)" t)
 (autoload 'image-dired-jump-thumbnail-buffer "image-dired" "\
-Jump to thumbnail buffer." t nil)
+Jump to thumbnail buffer." t)
 (autoload 'image-dired-minor-mode "image-dired" "\
 Setup easy-to-use keybindings for the commands to be used in Dired mode.
 
@@ -16836,21 +16974,21 @@ evaluate `image-dired-minor-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'image-dired-display-thumbs-append "image-dired" "\
-Append thumbnails to `image-dired-thumbnail-buffer'." t nil)
+Append thumbnails to `image-dired-thumbnail-buffer'." t)
 (autoload 'image-dired-display-thumb "image-dired" "\
-Shorthand for `image-dired-display-thumbs' with prefix argument." t nil)
+Shorthand for `image-dired-display-thumbs' with prefix argument." t)
 (autoload 'image-dired-dired-display-external "image-dired" "\
-Display file at point using an external viewer." t nil)
+Display file at point using an external viewer." t)
 (autoload 'image-dired-dired-display-image "image-dired" "\
 Display current image file.
 See documentation for `image-dired-display-image' for more information.
 With prefix argument ARG, display image in its original size.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'image-dired-dired-comment-files "image-dired" "\
-Add comment to current or marked files in Dired." t nil)
+Add comment to current or marked files in Dired." t)
 (autoload 'image-dired-mark-tagged-files "image-dired" "\
 Use REGEXP to mark files with matching tag.
 A `tag' is a keyword, a piece of meta data, associated with an
@@ -16859,19 +16997,17 @@ lets you input a regexp and this will be matched 
against all tags
 on all image files in the database file.  The files that have a
 matching tag will be marked in the Dired buffer.
 
-(fn REGEXP)" t nil)
+(fn REGEXP)" t)
 (autoload 'image-dired-dired-edit-comment-and-tags "image-dired" "\
 Edit comment and tags of current or marked image files.
 Edit comment and tags for all marked image files in an
-easy-to-use form." t nil)
+easy-to-use form." t)
 (autoload 'image-dired-bookmark-jump "image-dired" "\
 Default bookmark handler for Image-Dired buffers.
 
-(fn BOOKMARK)" nil nil)
-(define-obsolete-function-alias 'tumme #'image-dired "\
-24.4")
-(define-obsolete-function-alias 'image-dired-setup-dired-keybindings 
#'image-dired-minor-mode "\
-26.1")
+(fn BOOKMARK)")
+(define-obsolete-function-alias 'tumme #'image-dired "24.4")
+(define-obsolete-function-alias 'image-dired-setup-dired-keybindings 
#'image-dired-minor-mode "26.1")
 (register-definition-prefixes "image-dired" '("image-dired-"))
 
 
@@ -16898,14 +17034,14 @@ enabled, setting this variable directly does not take 
effect unless
 the variable is set using \\[customize].")
 (custom-autoload 'image-file-name-regexps "image-file" nil)
 (autoload 'image-file-name-regexp "image-file" "\
-Return a regular expression matching image-file filenames." nil nil)
+Return a regular expression matching image-file filenames.")
 (autoload 'insert-image-file "image-file" "\
 Insert the image file FILE into the current buffer.
 Optional arguments VISIT, BEG, END, and REPLACE are interpreted
 as for the command `insert-file-contents'.  Return list of
 absolute file name and number of characters inserted.
 
-(fn FILE &optional VISIT BEG END REPLACE)" nil nil)
+(fn FILE &optional VISIT BEG END REPLACE)")
 (defvar auto-image-file-mode nil "\
 Non-nil if Auto-Image-File mode is enabled.
 See the `auto-image-file-mode' command
@@ -16935,7 +17071,7 @@ evaluate `(default-value \\='auto-image-file-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "image-file" '("image-file-"))
 
 
@@ -16947,13 +17083,12 @@ You can use 
\\<image-mode-map>\\[image-toggle-display] or \\[image-toggle-hex-di
 as an image and display as text or hex.
 
 Key bindings:
-\\{image-mode-map}" t nil)
+\\{image-mode-map}" t)
 (autoload 'image-minor-mode "image-mode" "\
 Toggle Image minor mode in this buffer.
 
-Image minor mode provides the key \\<image-mode-map>\\[image-toggle-display],
-to switch back to `image-mode' and display an image file as the
-actual image.
+Image minor mode provides the key \\<image-mode-map>\\[image-toggle-display], 
to switch back to
+`image-mode' and display an image file as the actual image.
 
 This is a minor mode.  If called interactively, toggle the `Image
 minor mode' mode.  If the prefix argument is positive, enable the
@@ -16969,15 +17104,15 @@ evaluate `image-minor-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'image-mode-to-text "image-mode" "\
 Set a non-image mode as major mode in combination with image minor mode.
 A non-mage major mode found from `auto-mode-alist' or fundamental mode
-displays an image file as text." nil nil)
+displays an image file as text.")
 (autoload 'image-bookmark-jump "image-mode" "\
 
 
-(fn BMK)" nil nil)
+(fn BMK)")
 (register-definition-prefixes "image-mode" '("image-"))
 
 
@@ -17102,17 +17237,17 @@ Add an `imenu' entry to the menu bar for the current 
buffer.
 NAME is a string used to name the menu bar item.
 See the command `imenu' for more information.
 
-(fn NAME)" t nil)
+(fn NAME)" t)
 (autoload 'imenu-add-menubar-index "imenu" "\
 Add an Imenu \"Index\" entry on the menu bar for the current buffer.
 
-A trivial interface to `imenu-add-to-menubar' suitable for use in a hook." t 
nil)
+A trivial interface to `imenu-add-to-menubar' suitable for use in a hook." t)
 (autoload 'imenu "imenu" "\
 Jump to a place in the buffer chosen using a buffer menu or mouse menu.
 INDEX-ITEM specifies the position.  See `imenu-choose-buffer-index'
 for more information.
 
-(fn INDEX-ITEM)" t nil)
+(fn INDEX-ITEM)" t)
 (register-definition-prefixes "imenu" '("imenu-"))
 
 
@@ -17126,29 +17261,29 @@ for more information.
 (autoload 'indian-compose-region "ind-util" "\
 Compose the region according to `composition-function-table'.
 
-(fn FROM TO)" t nil)
+(fn FROM TO)" t)
 (autoload 'indian-compose-string "ind-util" "\
 
 
-(fn STRING)" nil nil)
+(fn STRING)")
 (autoload 'in-is13194-post-read-conversion "ind-util" "\
 
 
-(fn LEN)" nil nil)
+(fn LEN)")
 (autoload 'in-is13194-pre-write-conversion "ind-util" "\
 
 
-(fn FROM TO)" nil nil)
+(fn FROM TO)")
 (autoload 'indian-2-column-to-ucs-region "ind-util" "\
 Convert old Emacs Devanagari characters to UCS.
 
-(fn FROM TO)" t nil)
+(fn FROM TO)" t)
 (register-definition-prefixes "ind-util" '("combinatorial" "indian-" 
"is13194-"))
 
 
 ;;; Generated autoloads from leim/quail/indian.el
 
-(register-definition-prefixes "quail/indian" '("indian-mlm-mozhi-u" 
"inscript-" "quail-"))
+(register-definition-prefixes "quail/indian" '("indian-mlm-mozhi-u" 
"inscript-" "quail-" "tamil-"))
 
 
 ;;; Generated autoloads from progmodes/inf-lisp.el
@@ -17167,7 +17302,7 @@ quoted using shell quote syntax.
 
 (Type \\[describe-mode] in the process buffer for a list of commands.)
 
-(fn CMD)" t nil)
+(fn CMD)" t)
 (defalias 'run-lisp 'inferior-lisp)
 (register-definition-prefixes "inf-lisp" '("inferior-lisp-" "lisp-" 
"switch-to-lisp"))
 
@@ -17193,7 +17328,7 @@ environment variable INFOPATH is set.")
 (autoload 'info-other-window "info" "\
 Like `info' but show the Info buffer in another window.
 
-(fn &optional FILE-OR-NODE BUFFER)" t nil)
+(fn &optional FILE-OR-NODE BUFFER)" t)
  (put 'info 'info-file (purecopy "emacs"))
 (autoload 'info "info" "\
 Enter Info, the documentation browser.
@@ -17217,23 +17352,23 @@ in all the directories in that path.
 
 See a list of available Info commands in `Info-mode'.
 
-(fn &optional FILE-OR-NODE BUFFER)" t nil)
+(fn &optional FILE-OR-NODE BUFFER)" t)
 (autoload 'info-emacs-manual "info" "\
-Display the Emacs manual in Info mode." t nil)
+Display the Emacs manual in Info mode." t)
 (autoload 'info-emacs-bug "info" "\
-Display the \"Reporting Bugs\" section of the Emacs manual in Info mode." t 
nil)
+Display the \"Reporting Bugs\" section of the Emacs manual in Info mode." t)
 (autoload 'info-standalone "info" "\
 Run Emacs as a standalone Info reader.
 Usage:  emacs -f info-standalone [filename]
-In standalone mode, \\<Info-mode-map>\\[quit-window] exits Emacs itself." nil 
nil)
+In standalone mode, \\<Info-mode-map>\\[quit-window] exits Emacs itself.")
 (autoload 'Info-on-current-buffer "info" "\
 Use Info mode to browse the current Info buffer.
 With a prefix arg, this queries for the node name to visit first;
 otherwise, that defaults to `Top'.
 
-(fn &optional NODENAME)" t nil)
+(fn &optional NODENAME)" t)
 (autoload 'Info-directory "info" "\
-Go to the Info directory node." t nil)
+Go to the Info directory node." t)
 (autoload 'Info-index "info" "\
 Look up a string TOPIC in the index for this manual and go to that entry.
 If there are no exact matches to the specified topic, this chooses
@@ -17241,21 +17376,21 @@ the first match which is a case-insensitive substring 
of a topic.
 Use the \\<Info-mode-map>\\[Info-index-next] command to see the other matches.
 Give an empty topic name to go to the Index node itself.
 
-(fn TOPIC)" t nil)
+(fn TOPIC)" t)
 (autoload 'info-apropos "info" "\
 Search indices of all known Info files on your system for STRING.
 If REGEXP (interactively, the prefix), use a regexp match.
 
 Display a menu of the possible matches.
 
-(fn STRING &optional REGEXP)" t nil)
+(fn STRING &optional REGEXP)" t)
 (autoload 'info-finder "info" "\
 Display descriptions of the keywords in the Finder virtual manual.
 In interactive use, a prefix argument directs this command to read
 a list of keywords separated by comma.  After that, it displays a node
 with a list of packages that contain all specified keywords.
 
-(fn &optional KEYWORDS)" t nil)
+(fn &optional KEYWORDS)" t)
 (autoload 'Info-mode "info" "\
 Info mode provides commands for browsing through the Info documentation tree.
 Documentation in Info is divided into \"nodes\", each of which discusses
@@ -17319,7 +17454,7 @@ Advanced commands:
 \\[universal-argument] \\[info]        Move to new Info file with completion.
 \\[universal-argument] N \\[info]      Select Info buffer with prefix number 
in the name *info*<N>.
 
-(fn)" t nil)
+(fn)" t)
  (put 'Info-goto-emacs-command-node 'info-file (purecopy "emacs"))
 (autoload 'Info-goto-emacs-command-node "info" "\
 Go to the Info node in the Emacs manual for command COMMAND.
@@ -17328,7 +17463,7 @@ or in another manual found via COMMAND's `info-file' 
property or
 the variable `Info-file-list-for-emacs'.
 COMMAND must be a symbol or string.
 
-(fn COMMAND)" t nil)
+(fn COMMAND)" t)
  (put 'Info-goto-emacs-key-command-node 'info-file (purecopy "emacs"))
 (autoload 'Info-goto-emacs-key-command-node "info" "\
 Go to the node in the Emacs manual which describes the command bound to KEY.
@@ -17338,15 +17473,15 @@ The command is found by looking up in Emacs manual's 
indices
 or in another manual found via COMMAND's `info-file' property or
 the variable `Info-file-list-for-emacs'.
 
-(fn KEY)" t nil)
+(fn KEY)" t)
 (autoload 'Info-speedbar-browser "info" "\
 Initialize speedbar to display an Info node browser.
-This will add a speedbar major display mode." t nil)
+This will add a speedbar major display mode." t)
 (autoload 'Info-bookmark-jump "info" "\
 This implements the `handler' function interface for the record
 type returned by `Info-bookmark-make-record', which see.
 
-(fn BMK)" nil nil)
+(fn BMK)")
 (autoload 'info-display-manual "info" "\
 Display an Info buffer displaying MANUAL.
 If there is an existing Info buffer for MANUAL, display it.
@@ -17354,7 +17489,7 @@ Otherwise, visit the manual in a new Info buffer.  In 
interactive
 use, a prefix argument directs this command to limit the
 completion alternatives to currently visited manuals.
 
-(fn MANUAL)" t nil)
+(fn MANUAL)" t)
 (register-definition-prefixes "info" '("Info-" "info-"))
 
 
@@ -17364,7 +17499,7 @@ completion alternatives to currently visited manuals.
 Throw away all cached data.
 This command is useful if the user wants to start at the beginning without
 quitting Emacs, for example, after some Info documents were updated on the
-system." t nil)
+system." t)
  (put 'info-lookup-symbol 'info-file "emacs")
 (autoload 'info-lookup-symbol "info-look" "\
 Look up and display documentation of SYMBOL in the relevant Info manual.
@@ -17384,7 +17519,7 @@ always prompts for MODE.
 Is SAME-WINDOW, try to reuse the current window instead of
 popping up a new one.
 
-(fn SYMBOL &optional MODE SAME-WINDOW)" t nil)
+(fn SYMBOL &optional MODE SAME-WINDOW)" t)
  (put 'info-lookup-file 'info-file "emacs")
 (autoload 'info-lookup-file "info-look" "\
 Look up and display documentation of FILE in the relevant Info manual.
@@ -17401,15 +17536,15 @@ mode doesn't have any Info manuals known to Emacs, 
the command will
 prompt for MODE to use, with completion.  With prefix arg, the command
 always prompts for MODE.
 
-(fn FILE &optional MODE)" t nil)
+(fn FILE &optional MODE)" t)
 (autoload 'info-complete-symbol "info-look" "\
 Perform completion on symbol preceding point.
 
-(fn &optional MODE)" t nil)
+(fn &optional MODE)" t)
 (autoload 'info-complete-file "info-look" "\
 Perform completion on file preceding point.
 
-(fn &optional MODE)" t nil)
+(fn &optional MODE)" t)
 (register-definition-prefixes "info-look" '("info-"))
 
 
@@ -17442,7 +17577,7 @@ not external references, which makes it rather easy for 
mistakes
 to creep in or node name changes to go unnoticed.
 `Info-validate' doesn't check external references either.
 
-(fn FILENAME)" t nil)
+(fn FILENAME)" t)
 (autoload 'info-xref-check-all "info-xref" "\
 Check external references in all info documents in the info path.
 `Info-directory-list' and `Info-additional-directory-list' are
@@ -17454,7 +17589,7 @@ info files don't necessarily have a \".info\" extension 
and in
 particular the Emacs manuals normally don't.  If you have a
 source code directory in `Info-directory-list' then a lot of
 extraneous files might be read.  This will be time consuming but
-should be harmless." t nil)
+should be harmless." t)
 (autoload 'info-xref-check-all-custom "info-xref" "\
 Check info references in all customize groups and variables.
 Info references can be in `custom-manual' or `info-link' entries
@@ -17462,7 +17597,7 @@ of the `custom-links' for a variable.
 
 Any `custom-load' autoloads in variables are loaded in order to
 get full link information.  This will be a lot of Lisp packages
-and can take a long time." t nil)
+and can take a long time." t)
 (autoload 'info-xref-docstrings "info-xref" "\
 Check docstring info node references in source files.
 The given files are searched for docstring hyperlinks like
@@ -17484,7 +17619,7 @@ and links can be in the file commentary or elsewhere 
too.  Even
 .elc files can usually be checked successfully if you don't have
 the sources handy.
 
-(fn FILENAME-LIST)" t nil)
+(fn FILENAME-LIST)" t)
 (register-definition-prefixes "info-xref" '("info-xref-"))
 
 
@@ -17493,7 +17628,7 @@ the sources handy.
 (autoload 'Info-tagify "informat" "\
 Create or update Info file tag table in current buffer or in a region.
 
-(fn &optional INPUT-BUFFER-NAME)" t nil)
+(fn &optional INPUT-BUFFER-NAME)" t)
 (defvar Info-split-threshold 262144 "\
 The number of characters by which `Info-split' splits an info file.")
 (custom-autoload 'Info-split-threshold "informat" t)
@@ -17509,15 +17644,15 @@ should be saved in place of the original visited file.
 The subfiles are written in the same directory the original file is
 in, with names generated by appending `-' and a number to the original
 file name.  The indirect file still functions as an Info file, but it
-contains just the tag table and a directory of subfiles." t nil)
+contains just the tag table and a directory of subfiles." t)
 (autoload 'Info-validate "informat" "\
 Check current buffer for validity as an Info file.
-Check that every node pointer points to an existing node." t nil)
+Check that every node pointer points to an existing node." t)
 (autoload 'batch-info-validate "informat" "\
 Run `Info-validate' on the files remaining on the command line.
 Must be used only with -batch, and kills Emacs on completion.
 Each file will be processed even if an error occurred previously.
-For example, invoke \"emacs -batch -f batch-info-validate $info/ ~/*.info\"" 
nil nil)
+For example, invoke \"emacs -batch -f batch-info-validate $info/ ~/*.info\"")
 (register-definition-prefixes "informat" '("Info-validate-"))
 
 
@@ -17531,7 +17666,7 @@ See Info node `(elisp)Defining Functions' for more 
details.
 
 (fn NAME ARGS &rest BODY)" nil t)
 (function-put 'define-inline 'lisp-indent-function 'defun)
-(function-put 'define-inline 'doc-string-elt '3)
+(function-put 'define-inline 'doc-string-elt 3)
 (register-definition-prefixes "inline" '("inline-"))
 
 
@@ -17548,15 +17683,15 @@ See Info node `(elisp)Defining Functions' for more 
details.
 ;;; Generated autoloads from international/isearch-x.el
 
 (autoload 'isearch-toggle-specified-input-method "isearch-x" "\
-Select an input method and turn it on in interactive search." t nil)
+Select an input method and turn it on in interactive search." t)
 (autoload 'isearch-toggle-input-method "isearch-x" "\
-Toggle input method in interactive search." t nil)
+Toggle input method in interactive search." t)
 (autoload 'isearch-transient-input-method "isearch-x" "\
-Activate transient input method in interactive search." t nil)
+Activate transient input method in interactive search." t)
 (autoload 'isearch-process-search-multibyte-characters "isearch-x" "\
 
 
-(fn LAST-CHAR &optional COUNT)" nil nil)
+(fn LAST-CHAR &optional COUNT)")
 (register-definition-prefixes "isearch-x" '("isearch-"))
 
 
@@ -17567,7 +17702,7 @@ Activate transient input method in interactive search." 
t nil)
 Active isearchb mode for subsequent alphanumeric keystrokes.
 Executing this command again will terminate the search; or, if
 the search has not yet begun, will toggle to the last buffer
-accessed via isearchb." t nil)
+accessed via isearchb." t)
 (register-definition-prefixes "isearchb" '("isearchb"))
 
 
@@ -17584,71 +17719,71 @@ Translate the region between FROM and TO using the 
table
 `iso-spanish-trans-tab'.
 Optional arg BUFFER is ignored (for use in `format-alist').
 
-(fn FROM TO &optional BUFFER)" t nil)
+(fn FROM TO &optional BUFFER)" t)
 (autoload 'iso-german "iso-cvt" "\
 Translate net conventions for German to ISO 8859-1.
 Translate the region FROM and TO using the table
 `iso-german-trans-tab'.
 Optional arg BUFFER is ignored (for use in `format-alist').
 
-(fn FROM TO &optional BUFFER)" t nil)
+(fn FROM TO &optional BUFFER)" t)
 (autoload 'iso-iso2tex "iso-cvt" "\
 Translate ISO 8859-1 characters to TeX sequences.
 Translate the region between FROM and TO using the table
 `iso-iso2tex-trans-tab'.
 Optional arg BUFFER is ignored (for use in `format-alist').
 
-(fn FROM TO &optional BUFFER)" t nil)
+(fn FROM TO &optional BUFFER)" t)
 (autoload 'iso-tex2iso "iso-cvt" "\
 Translate TeX sequences to ISO 8859-1 characters.
 Translate the region between FROM and TO using the table
 `iso-tex2iso-trans-tab'.
 Optional arg BUFFER is ignored (for use in `format-alist').
 
-(fn FROM TO &optional BUFFER)" t nil)
+(fn FROM TO &optional BUFFER)" t)
 (autoload 'iso-gtex2iso "iso-cvt" "\
 Translate German TeX sequences to ISO 8859-1 characters.
 Translate the region between FROM and TO using the table
 `iso-gtex2iso-trans-tab'.
 Optional arg BUFFER is ignored (for use in `format-alist').
 
-(fn FROM TO &optional BUFFER)" t nil)
+(fn FROM TO &optional BUFFER)" t)
 (autoload 'iso-iso2gtex "iso-cvt" "\
 Translate ISO 8859-1 characters to German TeX sequences.
 Translate the region between FROM and TO using the table
 `iso-iso2gtex-trans-tab'.
 Optional arg BUFFER is ignored (for use in `format-alist').
 
-(fn FROM TO &optional BUFFER)" t nil)
+(fn FROM TO &optional BUFFER)" t)
 (autoload 'iso-iso2duden "iso-cvt" "\
 Translate ISO 8859-1 characters to Duden sequences.
 Translate the region between FROM and TO using the table
 `iso-iso2duden-trans-tab'.
 Optional arg BUFFER is ignored (for use in `format-alist').
 
-(fn FROM TO &optional BUFFER)" t nil)
+(fn FROM TO &optional BUFFER)" t)
 (autoload 'iso-iso2sgml "iso-cvt" "\
 Translate ISO 8859-1 characters in the region to SGML entities.
 Use entities from \"ISO 8879:1986//ENTITIES Added Latin 1//EN\".
 Optional arg BUFFER is ignored (for use in `format-alist').
 
-(fn FROM TO &optional BUFFER)" t nil)
+(fn FROM TO &optional BUFFER)" t)
 (autoload 'iso-sgml2iso "iso-cvt" "\
 Translate SGML entities in the region to ISO 8859-1 characters.
 Use entities from \"ISO 8879:1986//ENTITIES Added Latin 1//EN\".
 Optional arg BUFFER is ignored (for use in `format-alist').
 
-(fn FROM TO &optional BUFFER)" t nil)
+(fn FROM TO &optional BUFFER)" t)
 (autoload 'iso-cvt-read-only "iso-cvt" "\
 Warn that format is read-only.
 
-(fn &rest IGNORE)" t nil)
+(fn &rest IGNORE)" t)
 (autoload 'iso-cvt-write-only "iso-cvt" "\
 Warn that format is write-only.
 
-(fn &rest IGNORE)" t nil)
+(fn &rest IGNORE)" t)
 (autoload 'iso-cvt-define-menu "iso-cvt" "\
-Add submenus to the File menu, to convert to and from various formats." t nil)
+Add submenus to the File menu, to convert to and from various formats." t)
 (register-definition-prefixes "iso-cvt" '("iso-"))
 
 
@@ -17720,12 +17855,12 @@ nil           word is correct or spelling is accepted.
 (\"word\" arg)  word is hand entered.
 quit          spell session exited.
 
-(fn &optional FOLLOWING QUIETLY CONTINUE REGION)" t nil)
+(fn &optional FOLLOWING QUIETLY CONTINUE REGION)" t)
 (autoload 'ispell-pdict-save "ispell" "\
 Check to see if the personal dictionary has been modified.
 If so, ask if it needs to be saved.
 
-(fn &optional NO-QUERY FORCE-SAVE)" t nil)
+(fn &optional NO-QUERY FORCE-SAVE)" t)
 (autoload 'ispell-help "ispell" "\
 Display a list of the options available when a misspelling is encountered.
 
@@ -17748,13 +17883,13 @@ Selections are:
 \\`m'     Place typed-in value in personal dictionary, then recheck current 
word.
 \\`C-l'   Redraw screen.
 \\`C-r'   Recursive edit.
-\\`C-z'   Suspend Emacs or iconify frame." nil nil)
+\\`C-z'   Suspend Emacs or iconify frame.")
 (autoload 'ispell-kill-ispell "ispell" "\
 Kill current Ispell process (so that you may start a fresh one).
 With NO-ERROR, just return non-nil if there was no Ispell running.
 With CLEAR, buffer session localwords are cleaned.
 
-(fn &optional NO-ERROR CLEAR)" t nil)
+(fn &optional NO-ERROR CLEAR)" t)
 (autoload 'ispell-change-dictionary "ispell" "\
 Change to dictionary DICT for Ispell.
 With a prefix arg, set it \"globally\", for all buffers.
@@ -17762,7 +17897,7 @@ Without a prefix arg, set it \"locally\", just for this 
buffer.
 
 By just answering RET you can find out what the current dictionary is.
 
-(fn DICT &optional ARG)" t nil)
+(fn DICT &optional ARG)" t)
 (autoload 'ispell-region "ispell" "\
 Interactively check a region for spelling errors.
 Leave the mark at the last misspelled word that the user was queried about.
@@ -17770,7 +17905,7 @@ Leave the mark at the last misspelled word that the 
user was queried about.
 Return nil if spell session was terminated, otherwise returns shift offset
 amount for last line processed.
 
-(fn REG-START REG-END &optional RECHECKP SHIFT)" t nil)
+(fn REG-START REG-END &optional RECHECKP SHIFT)" t)
 (autoload 'ispell-comments-and-strings "ispell" "\
 Check comments and strings in the current buffer for spelling errors.
 If called interactively with an active region, check only comments and
@@ -17778,19 +17913,19 @@ strings in the region.
 When called from Lisp, START and END buffer positions can be provided
 to limit the check.
 
-(fn &optional START END)" t nil)
+(fn &optional START END)" t)
 (autoload 'ispell-comment-or-string-at-point "ispell" "\
-Check the comment or string containing point for spelling errors." t nil)
+Check the comment or string containing point for spelling errors." t)
 (autoload 'ispell-buffer "ispell" "\
 Check the current buffer for spelling errors interactively.
-Leave the mark at the last misspelled word that the user was queried about." t 
nil)
+Leave the mark at the last misspelled word that the user was queried about." t)
 (autoload 'ispell-buffer-with-debug "ispell" "\
 `ispell-buffer' with some output sent to `ispell-debug-buffer'.
 If APPEND is non-nil, don't erase previous debugging output.
 
-(fn &optional APPEND)" t nil)
+(fn &optional APPEND)" t)
 (autoload 'ispell-continue "ispell" "\
-Continue a halted spelling session beginning with the current word." t nil)
+Continue a halted spelling session beginning with the current word." t)
 (autoload 'ispell-complete-word "ispell" "\
 Try to complete the word before or at point.
 If optional INTERIOR-FRAG is non-nil, then the word may be a character
@@ -17798,9 +17933,9 @@ sequence inside of a word.
 
 Standard ispell choices are then available.
 
-(fn &optional INTERIOR-FRAG)" t nil)
+(fn &optional INTERIOR-FRAG)" t)
 (autoload 'ispell-complete-word-interior-frag "ispell" "\
-Completes word matching character sequence inside a word." t nil)
+Completes word matching character sequence inside a word." t)
 (autoload 'ispell "ispell" "\
 Interactively check a region or buffer for spelling errors.
 If `transient-mark-mode' is on, and a region is active, spell-check
@@ -17809,7 +17944,7 @@ that region.  Otherwise spell-check the buffer.
 Ispell dictionaries are not distributed with Emacs.  If you are
 looking for a dictionary, please see the distribution of the GNU ispell
 program, or do an Internet search; there are various dictionaries
-available on the net." t nil)
+available on the net." t)
 (autoload 'ispell-minor-mode "ispell" "\
 Toggle last-word spell checking (Ispell minor mode).
 
@@ -17838,7 +17973,7 @@ evaluate `ispell-minor-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'ispell-message "ispell" "\
 Check the spelling of a mail message or news post.
 Don't check spelling of message headers except the Subject field.
@@ -17857,7 +17992,7 @@ in your init file:
 
 You can bind this to the key C-c i in GNUS or mail by adding to
 `news-reply-mode-hook' or `mail-mode-hook' the following lambda expression:
-   (lambda () (local-set-key \"\\C-ci\" \\='ispell-message))" t nil)
+   (lambda () (local-set-key \"\\C-ci\" \\='ispell-message))" t)
 (register-definition-prefixes "ispell" '("check-ispell-version" "ispell-"))
 
 
@@ -17873,7 +18008,7 @@ You can bind this to the key C-c i in GNUS or mail by 
adding to
 
 ;;; Generated autoloads from language/japan-util.el
 
-(autoload 'setup-japanese-environment-internal "japan-util" nil nil nil)
+(autoload 'setup-japanese-environment-internal "japan-util")
 (autoload 'japanese-katakana "japan-util" "\
 Convert argument to Katakana and return that.
 The argument may be a character or string.  The result has the same type.
@@ -17883,55 +18018,55 @@ Optional argument HANKAKU t means to convert to 
`hankaku' Katakana
 may be a string even if OBJ is a character if two Katakanas are
 necessary to represent OBJ.
 
-(fn OBJ &optional HANKAKU)" nil nil)
+(fn OBJ &optional HANKAKU)")
 (autoload 'japanese-hiragana "japan-util" "\
 Convert argument to Hiragana and return that.
 The argument may be a character or string.  The result has the same type.
 The argument object is not altered--the value is a copy.
 
-(fn OBJ)" nil nil)
+(fn OBJ)")
 (autoload 'japanese-hankaku "japan-util" "\
 Convert argument to `hankaku' and return that.
 The argument may be a character or string.  The result has the same type.
 The argument object is not altered--the value is a copy.
 Optional argument ASCII-ONLY non-nil means to return only ASCII character.
 
-(fn OBJ &optional ASCII-ONLY)" nil nil)
+(fn OBJ &optional ASCII-ONLY)")
 (autoload 'japanese-zenkaku "japan-util" "\
 Convert argument to `zenkaku' and return that.
 The argument may be a character or string.  The result has the same type.
 The argument object is not altered--the value is a copy.
 
-(fn OBJ)" nil nil)
+(fn OBJ)")
 (autoload 'japanese-katakana-region "japan-util" "\
 Convert Japanese `hiragana' chars in the region to `katakana' chars.
 Optional argument HANKAKU t means to convert to `hankaku katakana' character
 of which charset is `japanese-jisx0201-kana'.
 
-(fn FROM TO &optional HANKAKU)" t nil)
+(fn FROM TO &optional HANKAKU)" t)
 (autoload 'japanese-hiragana-region "japan-util" "\
 Convert Japanese `katakana' chars in the region to `hiragana' chars.
 
-(fn FROM TO)" t nil)
+(fn FROM TO)" t)
 (autoload 'japanese-hankaku-region "japan-util" "\
 Convert Japanese `zenkaku' chars in the region to `hankaku' chars.
 `Zenkaku' chars belong to `japanese-jisx0208'
 `Hankaku' chars belong to `ascii' or `japanese-jisx0201-kana'.
 Optional argument ASCII-ONLY non-nil means to convert only to ASCII char.
 
-(fn FROM TO &optional ASCII-ONLY)" t nil)
+(fn FROM TO &optional ASCII-ONLY)" t)
 (autoload 'japanese-zenkaku-region "japan-util" "\
 Convert hankaku' chars in the region to Japanese `zenkaku' chars.
 `Zenkaku' chars belong to `japanese-jisx0208'
 `Hankaku' chars belong to `ascii' or `japanese-jisx0201-kana'.
 Optional argument KATAKANA-ONLY non-nil means to convert only KATAKANA char.
 
-(fn FROM TO &optional KATAKANA-ONLY)" t nil)
+(fn FROM TO &optional KATAKANA-ONLY)" t)
 (autoload 'read-hiragana-string "japan-util" "\
 Read a Hiragana string from the minibuffer, prompting with string PROMPT.
 If non-nil, second arg INITIAL-INPUT is a string to insert before reading.
 
-(fn PROMPT &optional INITIAL-INPUT)" nil nil)
+(fn PROMPT &optional INITIAL-INPUT)")
 (register-definition-prefixes "japan-util" '("japanese-"))
 
 
@@ -17964,12 +18099,12 @@ It is not recommended to set this variable 
permanently to anything but nil.")
 (autoload 'jka-compr-handler "jka-compr" "\
 
 
-(fn OPERATION &rest ARGS)" nil nil)
+(fn OPERATION &rest ARGS)")
 (autoload 'jka-compr-uninstall "jka-compr" "\
 Uninstall jka-compr.
 This removes the entries in `file-name-handler-alist' and `auto-mode-alist'
 and `inhibit-local-variables-suffixes' that were added
-by `jka-compr-install'." nil nil)
+by `jka-compr-install'.")
 (register-definition-prefixes "jka-compr" '("compression-error" "jka-compr-"))
 
 
@@ -17979,7 +18114,11 @@ by `jka-compr-install'." nil nil)
 (autoload 'js-mode "js" "\
 Major mode for editing JavaScript.
 
-(fn)" t nil)
+(fn)" t)
+(autoload 'js-json-mode "js" "\
+
+
+(fn)" t)
 (autoload 'js-jsx-mode "js" "\
 Major mode for editing JavaScript+JSX.
 
@@ -17993,7 +18132,7 @@ could set `js-jsx-syntax' to t in your init file, or in 
a
 `js-jsx-enable' in `js-mode-hook'.  You may be better served by
 one of the aforementioned options instead of using this mode.
 
-(fn)" t nil)
+(fn)" t)
  (defalias 'javascript-mode 'js-mode)
 (dolist (name (list "node" "nodejs" "gjs" "rhino")) (add-to-list 
'interpreter-mode-alist (cons (purecopy name) 'js-mode)))
 (register-definition-prefixes "js" '("js-"))
@@ -18058,7 +18197,7 @@ keys are bound.
 If SETUP is `numeric' and the optional fourth argument DECIMAL is non-nil,
 the decimal key on the keypad is mapped to DECIMAL instead of `.'
 
-(fn SETUP &optional NUMLOCK SHIFT DECIMAL)" nil nil)
+(fn SETUP &optional NUMLOCK SHIFT DECIMAL)")
 
 
 ;;; Generated autoloads from international/kinsoku.el
@@ -18077,7 +18216,7 @@ shorter.
 in one place, and is used for the text processing described above in
 the context of text formatting.
 
-(fn LINEBEG)" nil nil)
+(fn LINEBEG)")
 (register-definition-prefixes "kinsoku" '("kinsoku-"))
 
 
@@ -18097,7 +18236,7 @@ positions FROM and TO (integers or markers) specifying 
the target region.
 When it returns, the point is at the tail of the selected conversion,
 and the return value is the length of the conversion.
 
-(fn FROM TO)" t nil)
+(fn FROM TO)" t)
 (register-definition-prefixes "kkc" '("kkc-"))
 
 
@@ -18110,8 +18249,7 @@ and the return value is the length of the conversion.
  (global-set-key [f4] #'kmacro-end-or-call-macro)
  (global-set-key "\C-x\C-k" #'kmacro-keymap)
  (autoload 'kmacro-keymap "kmacro" "Keymap for keyboard macro commands." t 
'keymap)
-(define-obsolete-function-alias 'kmacro-exec-ring-item #'funcall "\
-29.1" "Execute item ITEM from the macro ring.
+(define-obsolete-function-alias 'kmacro-exec-ring-item #'funcall "29.1" 
"Execute item ITEM from the macro ring.
 ARG is the number of times to execute the item.")
 (autoload 'kmacro-start-macro "kmacro" "\
 Record subsequent keyboard input, defining a keyboard macro.
@@ -18136,7 +18274,7 @@ Use \\[kmacro-name-last-macro] to give it a name that 
will remain valid even
 after another macro is defined.
 Use \\[kmacro-bind-to-key] to bind it to a key sequence.
 
-(fn ARG)" t nil)
+(fn ARG)" t)
 (autoload 'kmacro-end-macro "kmacro" "\
 Finish defining a keyboard macro.
 The definition was started by \\[kmacro-start-macro].
@@ -18148,7 +18286,7 @@ With numeric arg, repeat macro now that many times,
 counting the definition just completed as the first repetition.
 An argument of zero means repeat until error.
 
-(fn ARG)" t nil)
+(fn ARG)" t)
 (autoload 'kmacro-call-macro "kmacro" "\
 Call the keyboard MACRO that you defined with \\[kmacro-start-macro].
 A prefix argument serves as a repeat count.  Zero means repeat until error.
@@ -18162,7 +18300,7 @@ for details on how to adjust or disable this behavior.
 To give a macro a name so you can call it even after defining others,
 use \\[kmacro-name-last-macro].
 
-(fn ARG &optional NO-REPEAT END-MACRO MACRO)" t nil)
+(fn ARG &optional NO-REPEAT END-MACRO MACRO)" t)
 (autoload 'kmacro-start-macro-or-insert-counter "kmacro" "\
 Record subsequent keyboard input, defining a keyboard macro.
 The commands are recorded even as they are executed.
@@ -18184,13 +18322,13 @@ The macro counter can be set directly via 
\\[kmacro-set-counter] and \\[kmacro-a
 The format of the inserted value of the counter can be controlled
 via \\[kmacro-set-format].
 
-(fn ARG)" t nil)
+(fn ARG)" t)
 (autoload 'kmacro-end-or-call-macro "kmacro" "\
 End kbd macro if currently being defined; else call last kbd macro.
 With numeric prefix ARG, repeat macro that many times.
 With \\[universal-argument], call second macro in macro ring.
 
-(fn ARG &optional NO-REPEAT)" t nil)
+(fn ARG &optional NO-REPEAT)" t)
 (autoload 'kmacro-end-and-call-macro "kmacro" "\
 Call last keyboard macro, ending it first if currently being defined.
 With numeric prefix ARG, repeat macro that many times.
@@ -18199,22 +18337,29 @@ Zero argument means repeat until there is an error.
 To give a macro a name, so you can call it even after defining other
 macros, use \\[kmacro-name-last-macro].
 
-(fn ARG &optional NO-REPEAT)" t nil)
+(fn ARG &optional NO-REPEAT)" t)
 (autoload 'kmacro-end-call-mouse "kmacro" "\
 Move point to the position clicked with the mouse and call last kbd macro.
 If kbd macro currently being defined end it before activating it.
 
-(fn EVENT)" t nil)
+(fn EVENT)" t)
 (autoload 'kmacro "kmacro" "\
 Create a `kmacro' for macro bound to symbol or key.
 KEYS should be a vector or a string that obeys `key-valid-p'.
 
-(fn KEYS &optional COUNTER FORMAT)" nil nil)
+(fn KEYS &optional COUNTER FORMAT)")
 (autoload 'kmacro-lambda-form "kmacro" "\
 
 
-(fn MAC &optional COUNTER FORMAT)" nil nil)
-(make-obsolete 'kmacro-lambda-form 'kmacro '"29.1")
+(fn MAC &optional COUNTER FORMAT)")
+(make-obsolete 'kmacro-lambda-form 'kmacro "29.1")
+(autoload 'kmacro-name-last-macro "kmacro" "\
+Assign a name to the last keyboard macro defined.
+Argument SYMBOL is the name to define.
+The symbol's function definition becomes the keyboard macro string.
+Such a \"function\" cannot be called from Lisp, but it is a valid editor 
command.
+
+(fn SYMBOL)" t)
 (register-definition-prefixes "kmacro" '("kmacro-"))
 
 
@@ -18223,7 +18368,7 @@ KEYS should be a vector or a string that obeys 
`key-valid-p'.
 (defvar default-korean-keyboard (purecopy (if (string-search "3" (or (getenv 
"HANGUL_KEYBOARD_TYPE") "")) "3" "")) "\
 The kind of Korean keyboard for Korean (Hangul) input method.
 \"\" for 2, \"3\" for 3, and \"3f\" for 3f.")
-(autoload 'setup-korean-environment-internal "korea-util" nil nil nil)
+(autoload 'setup-korean-environment-internal "korea-util")
 (register-definition-prefixes "korea-util" '("exit-korean-environment" 
"isearch-" "korean-key-bindings" "quail-hangul-switch-" 
"toggle-korean-input-method"))
 
 
@@ -18237,7 +18382,7 @@ The kind of Korean keyboard for Korean (Hangul) input 
method.
 (autoload 'lao-compose-string "lao-util" "\
 
 
-(fn STR)" nil nil)
+(fn STR)")
 (autoload 'lao-transcribe-single-roman-syllable-to-lao "lao-util" "\
 Transcribe a Romanized Lao syllable in the region FROM and TO to Lao string.
 Only the first syllable is transcribed.
@@ -18248,19 +18393,19 @@ LAO-STRING is the Lao character transcription of it.
 Optional 3rd arg STR, if non-nil, is a string to search for Roman Lao
 syllable.  In that case, FROM and TO are indexes to STR.
 
-(fn FROM TO &optional STR)" nil nil)
+(fn FROM TO &optional STR)")
 (autoload 'lao-transcribe-roman-to-lao-string "lao-util" "\
 Transcribe Romanized Lao string STR to Lao character string.
 
-(fn STR)" nil nil)
+(fn STR)")
 (autoload 'lao-composition-function "lao-util" "\
 
 
-(fn GSTRING DIRECTION)" nil nil)
+(fn GSTRING DIRECTION)")
 (autoload 'lao-compose-region "lao-util" "\
 
 
-(fn FROM TO)" t nil)
+(fn FROM TO)" t)
 (register-definition-prefixes "lao-util" '("lao-"))
 
 
@@ -18275,18 +18420,18 @@ Used by the function 
`latexenc-find-file-coding-system'.")
 Return the corresponding coding-system for the specified input encoding.
 Return nil if no matching coding system can be found.
 
-(fn INPUTENC)" nil nil)
+(fn INPUTENC)")
 (autoload 'latexenc-coding-system-to-inputenc "latexenc" "\
 Return the corresponding input encoding for the specified coding system.
 Return nil if no matching input encoding can be found.
 
-(fn CS)" nil nil)
+(fn CS)")
 (autoload 'latexenc-find-file-coding-system "latexenc" "\
 Determine the coding system of a LaTeX file if it uses \"inputenc.sty\".
 The mapping from LaTeX's \"inputenc.sty\" encoding names to Emacs
 coding system names is determined from `latex-inputenc-coding-alist'.
 
-(fn ARG-LIST)" nil nil)
+(fn ARG-LIST)")
 (register-definition-prefixes "latexenc" '("latexenc-dont-use-"))
 
 
@@ -18314,7 +18459,7 @@ must be in `latin1-display-sets'.  With no arguments, 
reset the
 display for all of `latin1-display-sets'.  See also
 `latin1-display-setup'.
 
-(fn &rest SETS)" nil nil)
+(fn &rest SETS)")
 (defvar latin1-display-ucs-per-lynx nil "\
 Set up Latin-1/ASCII display for Unicode characters.
 This uses the transliterations of the Lynx browser.  The display isn't
@@ -18331,7 +18476,7 @@ use either \\[customize] or the function 
`latin1-display'.")
 (autoload 'ld-script-mode "ld-script" "\
 A major mode to edit GNU ld script files.
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "ld-script" '("ld-script-"))
 
 
@@ -18357,7 +18502,7 @@ Major mode for editing Less files (http://lesscss.org/).
 Special commands:
 \\{less-css-mode-map}
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "less-css-mode" '("less-css-"))
 
 
@@ -18394,7 +18539,7 @@ inside the original alist by using dots inside the 
symbol, as
 displayed in the example above.
 
 (fn ALIST &rest BODY)" nil t)
-(function-put 'let-alist 'lisp-indent-function '1)
+(function-put 'let-alist 'lisp-indent-function 1)
 (register-definition-prefixes "let-alist" '("let-alist--"))
 
 
@@ -18420,7 +18565,7 @@ generations (the default is `life-step-time').
 When called from Lisp, optional argument STEP-TIME is the time to
 sleep in seconds.
 
-(fn &optional STEP-TIME)" t nil)
+(fn &optional STEP-TIME)" t)
 (register-definition-prefixes "life" '("life-"))
 
 
@@ -18449,7 +18594,7 @@ evaluate `linum-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (put 'global-linum-mode 'globalized-minor-mode t)
 (defvar global-linum-mode nil "\
 Non-nil if Global Linum mode is enabled.
@@ -18472,7 +18617,7 @@ Linum mode is enabled in all buffers where `linum-on' 
would do it.
 
 See `linum-mode' for more information on Linum mode.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "linum" '("linum-"))
 
 
@@ -18504,23 +18649,31 @@ binds `generated-autoload-file' as a file-local 
variable, write
 its autoloads into the specified file instead.
 
 The function does NOT recursively descend into subdirectories of the
-directory or directories specified.
+directory or directories specified by DIRS.
+
+Optional argument EXCLUDED-FILES, if non-nil, should be a list of
+files, such as preloaded files, whose autoloads should not be written
+to OUTPUT-FILE.
 
-If EXTRA-DATA, include this string at the start of the generated file.
+If EXTRA-DATA is non-nil, it should be a string; include that string
+at the beginning of the generated file.  This will also force the
+generation of OUTPUT-FILE even if there are no autoloads to put into
+that file.
 
-If INCLUDE-PACKAGE-VERSION, include package version data.
+If INCLUDE-PACKAGE-VERSION is non-nil, include package version data.
 
-If GENERATE-FULL, don't update, but regenerate all the loaddefs files.
+If GENERATE-FULL is non-nil, regenerate all the loaddefs files anew,
+instead of just updating them with the new/changed autoloads.
 
-(fn DIR OUTPUT-FILE &optional EXCLUDED-FILES EXTRA-DATA 
INCLUDE-PACKAGE-VERSION GENERATE-FULL)" nil nil)
+(fn DIR OUTPUT-FILE &optional EXCLUDED-FILES EXTRA-DATA 
INCLUDE-PACKAGE-VERSION GENERATE-FULL)")
 (autoload 'loaddefs-generate-batch "loaddefs-gen" "\
 Generate loaddefs.el files in batch mode.
 This scans for ;;;###autoload forms and related things.
 
 The first element on the command line should be the (main)
 loaddefs.el output file, and the rest are the directories to
-use." nil nil)
-(register-definition-prefixes "loaddefs-gen" '("autoload-" 
"generated-autoload-" "loaddefs-generate--"))
+use.")
+(register-definition-prefixes "loaddefs-gen" '("autoload-" 
"generated-autoload-" "loaddefs-generate--" "no-update-autoloads"))
 
 
 ;;; Generated autoloads from loadhist.el
@@ -18548,7 +18701,7 @@ definitions in the variable `unload-function-defs-list' 
and could
 remove symbols from it in the event that the package has done
 something strange, such as redefining an Emacs function.
 
-(fn FEATURE &optional FORCE)" t nil)
+(fn FEATURE &optional FORCE)" t)
 (register-definition-prefixes "loadhist" '("feature-" "file-" "loadhist-" 
"read-feature" "unload-"))
 
 
@@ -18585,7 +18738,7 @@ the docstring of that function for its meaning.
 After preparing the results buffer, this runs `dired-mode-hook' and
 then `locate-post-command-hook'.
 
-(fn SEARCH-STRING &optional FILTER ARG)" t nil)
+(fn SEARCH-STRING &optional FILTER ARG)" t)
 (autoload 'locate-with-filter "locate" "\
 Run the executable program `locate' with a filter.
 This function is similar to the function `locate', which see.
@@ -18601,7 +18754,7 @@ ARG is the interactive prefix arg, which has the same 
effect as in `locate'.
 When called from Lisp, this function is identical with `locate',
 except that FILTER is not optional.
 
-(fn SEARCH-STRING FILTER &optional ARG)" t nil)
+(fn SEARCH-STRING FILTER &optional ARG)" t)
 (register-definition-prefixes "locate" '("locate-"))
 
 
@@ -18631,7 +18784,7 @@ If BUFFER is non-nil, `log-edit' will switch to that 
buffer, use it
 to edit the log message and go back to the current buffer when
 done.  Otherwise, this function will use the current buffer.
 
-(fn CALLBACK &optional SETUP PARAMS BUFFER MODE &rest IGNORE)" nil nil)
+(fn CALLBACK &optional SETUP PARAMS BUFFER MODE &rest IGNORE)")
 (register-definition-prefixes "log-edit" '("log-edit-"))
 
 
@@ -18640,7 +18793,7 @@ done.  Otherwise, this function will use the current 
buffer.
 (autoload 'log-view-mode "log-view" "\
 Major mode for browsing CVS log output.
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "log-view" '("log-view-"))
 
 
@@ -18685,7 +18838,7 @@ argument.")
 (autoload 'lpr-buffer "lpr" "\
 Print buffer contents without pagination or page headers.
 See the variables `lpr-switches' and `lpr-command'
-for customization of the printer command." t nil)
+for customization of the printer command." t)
 (autoload 'print-buffer "lpr" "\
 Paginate and print buffer contents.
 
@@ -18698,13 +18851,13 @@ Otherwise, the switches in `lpr-headers-switches' are 
used
 in the print command itself; we expect them to request pagination.
 
 See the variables `lpr-switches' and `lpr-command'
-for further customization of the printer command." t nil)
+for further customization of the printer command." t)
 (autoload 'lpr-region "lpr" "\
 Print region contents without pagination or page headers.
 See the variables `lpr-switches' and `lpr-command'
 for customization of the printer command.
 
-(fn START END)" t nil)
+(fn START END)" t)
 (autoload 'print-region "lpr" "\
 Paginate and print the region contents.
 
@@ -18719,7 +18872,7 @@ in the print command itself; we expect them to request 
pagination.
 See the variables `lpr-switches' and `lpr-command'
 for further customization of the printer command.
 
-(fn START END)" t nil)
+(fn START END)" t)
 (register-definition-prefixes "lpr" '("lpr-" "print"))
 
 
@@ -18744,7 +18897,7 @@ Display the quarters of the moon for last month, this 
month, and next month.
 If called with an optional prefix argument ARG, prompts for month and year.
 This function is suitable for execution in an init file.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "lunar" '("calendar-lunar-phases" 
"diary-lunar-phases" "eclipse-check" "lunar-"))
 
 
@@ -18753,7 +18906,7 @@ This function is suitable for execution in an init file.
 (autoload 'm4-mode "m4-mode" "\
 A major mode to edit m4 macro files.
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "m4-mode" '("m4-"))
 
 
@@ -18775,7 +18928,7 @@ bindings.
 To save a kbd macro, visit a file of Lisp code such as your `~/.emacs',
 use this command, and then save the file.
 
-(fn MACRONAME &optional KEYS)" t nil)
+(fn MACRONAME &optional KEYS)" t)
 (autoload 'kbd-macro-query "macros" "\
 Query user during kbd macro execution.
 
@@ -18794,7 +18947,7 @@ Your options are: \\<query-replace-map>
 \\[recenter]   Redisplay the screen, then ask again.
 \\[edit]       Enter recursive edit; ask again when you exit from that.
 
-(fn FLAG)" t nil)
+(fn FLAG)" t)
 (autoload 'apply-macro-to-region-lines "macros" "\
 Apply last keyboard macro to all lines in the region.
 For each line that begins in the region, move to the beginning of
@@ -18836,7 +18989,7 @@ and write a macro to massage a word into a table entry:
 and then select the region of un-tablified names and use
 `\\[apply-macro-to-region-lines]' to build the table from the names.
 
-(fn TOP BOTTOM &optional MACRO)" t nil)
+(fn TOP BOTTOM &optional MACRO)" t)
  (define-key ctl-x-map "q" 'kbd-macro-query)
 (register-definition-prefixes "macros" '("macro"))
 
@@ -18871,19 +19024,19 @@ non-display use, you should probably use
 than `mail-header-parse-address', but does less post-processing
 to the results.
 
-(fn ADDRESS &optional ALL)" nil nil)
+(fn ADDRESS &optional ALL)")
 (autoload 'what-domain "mail-extr" "\
 Convert mail domain DOMAIN to the country it corresponds to.
 
-(fn DOMAIN)" t nil)
+(fn DOMAIN)" t)
 (register-definition-prefixes "mail-extr" '("mail-extr-"))
 
 
 ;;; Generated autoloads from mail/mail-hist.el
 
 (autoload 'mail-hist-define-keys "mail-hist" "\
-Define keys for accessing mail header history.  For use in hooks." nil nil)
-(autoload 'mail-hist-enable "mail-hist" nil nil nil)
+Define keys for accessing mail header history.  For use in hooks.")
+(autoload 'mail-hist-enable "mail-hist")
 (defvar mail-hist-keep-history t "\
 Non-nil means keep a history for headers and text of outgoing mail.")
 (custom-autoload 'mail-hist-keep-history "mail-hist" t)
@@ -18892,7 +19045,7 @@ Put headers and contents of this message into mail 
header history.
 Each header has its own independent history, as does the body of the
 message.
 
-This function normally would be called when the message is sent." nil nil)
+This function normally would be called when the message is sent.")
 (register-definition-prefixes "mail-hist" '("mail-hist-"))
 
 
@@ -18929,7 +19082,7 @@ also the To field, unless this would leave an empty To 
field.")
 (autoload 'mail-file-babyl-p "mail-utils" "\
 Return non-nil if FILE is a Babyl file.
 
-(fn FILE)" nil nil)
+(fn FILE)")
 (autoload 'mail-quote-printable "mail-utils" "\
 Convert a string to the \"quoted printable\" Q encoding if necessary.
 If the string contains only ASCII characters and no troublesome ones,
@@ -18938,19 +19091,19 @@ we return it unconverted.
 If the optional argument WRAPPER is non-nil,
 we add the wrapper characters =?ISO-8859-1?Q?....?=.
 
-(fn STRING &optional WRAPPER)" nil nil)
+(fn STRING &optional WRAPPER)")
 (autoload 'mail-quote-printable-region "mail-utils" "\
 Convert the region to the \"quoted printable\" Q encoding.
 If the optional argument WRAPPER is non-nil,
 we add the wrapper characters =?ISO-8859-1?Q?....?=.
 
-(fn BEG END &optional WRAPPER)" t nil)
+(fn BEG END &optional WRAPPER)" t)
 (autoload 'mail-unquote-printable "mail-utils" "\
 Undo the \"quoted printable\" encoding.
 If the optional argument WRAPPER is non-nil,
 we expect to find and remove the wrapper characters =?ISO-8859-1?Q?....?=.
 
-(fn STRING &optional WRAPPER)" nil nil)
+(fn STRING &optional WRAPPER)")
 (autoload 'mail-unquote-printable-region "mail-utils" "\
 Undo the \"quoted printable\" encoding in buffer from BEG to END.
 If the optional argument WRAPPER is non-nil,
@@ -18962,7 +19115,7 @@ If UNIBYTE is non-nil, insert converted characters as 
unibyte.
 That is useful if you are going to character code decoding afterward,
 as Rmail does.
 
-(fn BEG END &optional WRAPPER NOERROR UNIBYTE)" t nil)
+(fn BEG END &optional WRAPPER NOERROR UNIBYTE)" t)
 (autoload 'mail-fetch-field "mail-utils" "\
 Return the value of the header field whose type is FIELD-NAME.
 If second arg LAST is non-nil, use the last field of type FIELD-NAME.
@@ -18973,7 +19126,7 @@ included in the result.
 The buffer should be narrowed to just the header, else false
 matches may be returned from the message body.
 
-(fn FIELD-NAME &optional LAST ALL LIST DELETE)" nil nil)
+(fn FIELD-NAME &optional LAST ALL LIST DELETE)")
 (register-definition-prefixes "mail-utils" '("mail-"))
 
 
@@ -19009,14 +19162,14 @@ evaluate `(default-value \\='mail-abbrevs-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'mail-abbrevs-setup "mailabbrev" "\
-Initialize use of the `mailabbrev' package." nil nil)
+Initialize use of the `mailabbrev' package.")
 (autoload 'build-mail-abbrevs "mailabbrev" "\
 Read mail aliases from personal mail alias file and set `mail-abbrevs'.
 By default this is the file specified by `mail-personal-alias-file'.
 
-(fn &optional FILE RECURSIVEP)" nil nil)
+(fn &optional FILE RECURSIVEP)")
 (autoload 'define-mail-abbrev "mailabbrev" "\
 Define NAME as a mail alias abbrev that translates to DEFINITION.
 If DEFINITION contains multiple addresses, separate them with commas.
@@ -19026,7 +19179,7 @@ from a mailrc file.  In that case, addresses are 
separated with
 spaces and addresses with embedded spaces are surrounded by
 double-quotes.
 
-(fn NAME DEFINITION &optional FROM-MAILRC-FILE)" t nil)
+(fn NAME DEFINITION &optional FROM-MAILRC-FILE)" t)
 (register-definition-prefixes "mailabbrev" '("mail-" "merge-mail-abbrevs" 
"rebuild-mail-abbrevs"))
 
 
@@ -19050,7 +19203,7 @@ their `Resent-' variants.
 Optional second arg EXCLUDE may be a regular expression defining text to be
 removed from alias expansions.
 
-(fn BEG END &optional EXCLUDE)" t nil)
+(fn BEG END &optional EXCLUDE)" t)
 (autoload 'define-mail-alias "mailalias" "\
 Define NAME as a mail alias that translates to DEFINITION.
 This means that sending a message to NAME will actually send to DEFINITION.
@@ -19060,17 +19213,10 @@ If FROM-MAILRC-FILE is non-nil, then addresses in 
DEFINITION
 can be separated by spaces; an address can contain spaces
 if it is quoted with double-quotes.
 
-(fn NAME DEFINITION &optional FROM-MAILRC-FILE)" t nil)
+(fn NAME DEFINITION &optional FROM-MAILRC-FILE)" t)
 (autoload 'mail-completion-at-point-function "mailalias" "\
 Compute completion data for mail aliases.
-For use on `completion-at-point-functions'." nil nil)
-(autoload 'mail-complete "mailalias" "\
-Perform completion on header field or word preceding point.
-Completable headers are according to `mail-complete-alist'.  If none matches
-current header, calls `mail-complete-function' and passes prefix ARG if any.
-
-(fn ARG)" t nil)
-(make-obsolete 'mail-complete 'mail-completion-at-point-function '"24.1")
+For use on `completion-at-point-functions'.")
 (register-definition-prefixes "mailalias" '("build-mail-aliases" "mail-"))
 
 
@@ -19080,7 +19226,7 @@ current header, calls `mail-complete-function' and 
passes prefix ARG if any.
 Return a file name extension based on a MIME-TYPE.
 For instance, `image/png' will result in `png'.
 
-(fn MIME-TYPE)" nil nil)
+(fn MIME-TYPE)")
 (register-definition-prefixes "mailcap" '("mailcap-"))
 
 
@@ -19089,7 +19235,7 @@ For instance, `image/png' will result in `png'.
 (autoload 'mailclient-send-it "mailclient" "\
 Pass current buffer on to the system's mail client.
 Suitable value for `send-mail-function'.
-The mail client is taken to be the handler of mailto URLs." nil nil)
+The mail client is taken to be the handler of mailto URLs.")
 (register-definition-prefixes "mailclient" '("mailclient-"))
 
 
@@ -19105,42 +19251,42 @@ Call Mairix with SEARCH.
 If THREADS is non-nil, also display whole threads of found
 messages.  Results will be put into the default search file.
 
-(fn SEARCH THREADS)" t nil)
+(fn SEARCH THREADS)" t)
 (autoload 'mairix-use-saved-search "mairix" "\
-Use a saved search for querying Mairix." t nil)
+Use a saved search for querying Mairix." t)
 (autoload 'mairix-edit-saved-searches-customize "mairix" "\
-Edit the list of saved searches in a customization buffer." t nil)
+Edit the list of saved searches in a customization buffer." t)
 (autoload 'mairix-search-from-this-article "mairix" "\
 Search messages from sender of the current article.
 This is effectively a shortcut for calling `mairix-search' with
 f:current_from.  If prefix THREADS is non-nil, include whole
 threads.
 
-(fn THREADS)" t nil)
+(fn THREADS)" t)
 (autoload 'mairix-search-thread-this-article "mairix" "\
 Search thread for the current article.
 This is effectively a shortcut for calling `mairix-search'
-with m:msgid of the current article and enabled threads." t nil)
+with m:msgid of the current article and enabled threads." t)
 (autoload 'mairix-widget-search-based-on-article "mairix" "\
-Create mairix query based on current article using widgets." t nil)
+Create mairix query based on current article using widgets." t)
 (autoload 'mairix-edit-saved-searches "mairix" "\
-Edit current mairix searches." t nil)
+Edit current mairix searches." t)
 (autoload 'mairix-widget-search "mairix" "\
 Create mairix query interactively using graphical widgets.
 MVALUES may contain values from current article.
 
-(fn &optional MVALUES)" t nil)
+(fn &optional MVALUES)" t)
 (autoload 'mairix-update-database "mairix" "\
 Call mairix for updating the database for SERVERS.
 Mairix will be called asynchronously unless
 `mairix-synchronous-update' is t.  Mairix will be called with
-`mairix-update-options'." t nil)
+`mairix-update-options'." t)
 (register-definition-prefixes "mairix" '("mairix-"))
 
 
 ;;; Generated autoloads from cedet/semantic/bovine/make.el
 
-(register-definition-prefixes "semantic/bovine/make" '("makefile-mode" 
"semantic-"))
+(register-definition-prefixes "semantic/bovine/make" '("semantic-"))
 
 
 ;;; Generated autoloads from cedet/ede/make.el
@@ -19235,27 +19381,27 @@ Makefile mode can be configured by modifying the 
following variables:
    on one of those in the minibuffer whenever you enter a `.'.
    at the beginning of a line in Makefile mode.
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'makefile-automake-mode "make-mode" "\
 An adapted `makefile-mode' that knows about automake.
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'makefile-gmake-mode "make-mode" "\
 An adapted `makefile-mode' that knows about gmake.
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'makefile-makepp-mode "make-mode" "\
 An adapted `makefile-mode' that knows about makepp.
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'makefile-bsdmake-mode "make-mode" "\
 An adapted `makefile-mode' that knows about BSD make.
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'makefile-imake-mode "make-mode" "\
 An adapted `makefile-mode' that knows about imake.
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "make-mode" '("makefile-"))
 
 
@@ -19269,14 +19415,6 @@ An adapted `makefile-mode' that knows about imake.
 (register-definition-prefixes "makeinfo" '("makeinfo-"))
 
 
-;;; Generated autoloads from makesum.el
-
-(autoload 'make-command-summary "makesum" "\
-Make a summary of current key bindings in the buffer *Summary*.
-Previous contents of that buffer are killed first." t nil)
-(register-definition-prefixes "makesum" '("double-column"))
-
-
 ;;; Generated autoloads from man.el
 
 (defalias 'manual-entry 'man)
@@ -19321,19 +19459,19 @@ Note that in some cases you will need to use 
\\[quoted-insert] to quote the
 SPC character in the above examples, because this command attempts
 to auto-complete your input based on the installed manual pages.
 
-(fn MAN-ARGS)" t nil)
+(fn MAN-ARGS)" t)
 (autoload 'man-follow "man" "\
 Get a Un*x manual page of the item under point and put it in a buffer.
 
-(fn MAN-ARGS)" '(man-common) nil)
+(fn MAN-ARGS)" '(man-common))
 (autoload 'Man-bookmark-jump "man" "\
 Default bookmark handler for Man buffers.
 
-(fn BOOKMARK)" nil nil)
+(fn BOOKMARK)")
 (autoload 'Man-context-menu "man" "\
 Populate MENU with commands that open a man page at point.
 
-(fn MENU CLICK)" nil nil)
+(fn MENU CLICK)")
 (register-definition-prefixes "man" '("Man-" "man"))
 
 
@@ -19376,7 +19514,7 @@ evaluate `master-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "master" '("master-"))
 
 
@@ -19413,7 +19551,7 @@ evaluate `(default-value 
\\='minibuffer-depth-indicate-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "mb-depth" '("minibuffer-depth-"))
 
 
@@ -19429,7 +19567,7 @@ Generate a report of how Emacs is using memory.
 
 This report is approximate, and will commonly over-count memory
 usage by variables, because shared data structures will usually
-by counted more than once." t nil)
+by counted more than once." t)
 (register-definition-prefixes "memory-report" '("memory-report-"))
 
 
@@ -19442,96 +19580,96 @@ Like `text-mode', but with these additional commands:
 
 \\{message-mode-map}
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'message-mail "message" "\
 Start editing a mail message to be sent.
 OTHER-HEADERS is an alist of header/value pairs.  CONTINUE says whether
 to continue editing a message already being composed.  SWITCH-FUNCTION
 is a function used to switch to and display the mail buffer.
 
-(fn &optional TO SUBJECT OTHER-HEADERS CONTINUE SWITCH-FUNCTION YANK-ACTION 
SEND-ACTIONS RETURN-ACTION &rest _)" t nil)
+(fn &optional TO SUBJECT OTHER-HEADERS CONTINUE SWITCH-FUNCTION YANK-ACTION 
SEND-ACTIONS RETURN-ACTION &rest _)" t)
 (autoload 'message-news "message" "\
 Start editing a news article to be sent.
 
-(fn &optional NEWSGROUPS SUBJECT)" t nil)
+(fn &optional NEWSGROUPS SUBJECT)" t)
 (autoload 'message-reply "message" "\
 Start editing a reply to the article in the current buffer.
 
-(fn &optional TO-ADDRESS WIDE SWITCH-FUNCTION)" t nil)
+(fn &optional TO-ADDRESS WIDE SWITCH-FUNCTION)" t)
 (autoload 'message-wide-reply "message" "\
 Make a \"wide\" reply to the message in the current buffer.
 
-(fn &optional TO-ADDRESS)" t nil)
+(fn &optional TO-ADDRESS)" t)
 (autoload 'message-followup "message" "\
 Follow up to the message in the current buffer.
 If TO-NEWSGROUPS, use that as the new Newsgroups line.
 
-(fn &optional TO-NEWSGROUPS)" t nil)
+(fn &optional TO-NEWSGROUPS)" t)
 (autoload 'message-cancel-news "message" "\
 Cancel an article you posted.
 If ARG, allow editing of the cancellation message.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'message-supersede "message" "\
 Start composing a message to supersede the current message.
 This is done simply by taking the old article and adding a Supersedes
-header line with the old Message-ID." t nil)
+header line with the old Message-ID." t)
 (autoload 'message-recover "message" "\
-Reread contents of current buffer from its last auto-save file." t nil)
+Reread contents of current buffer from its last auto-save file." t)
 (autoload 'message-forward "message" "\
 Forward the current message via mail.
 Optional NEWS will use news to forward instead of mail.
 Optional DIGEST will use digest to forward.
 
-(fn &optional NEWS DIGEST)" t nil)
+(fn &optional NEWS DIGEST)" t)
 (autoload 'message-forward-make-body "message" "\
 
 
-(fn FORWARD-BUFFER &optional DIGEST)" nil nil)
+(fn FORWARD-BUFFER &optional DIGEST)")
 (autoload 'message-forward-rmail-make-body "message" "\
 
 
-(fn FORWARD-BUFFER)" nil nil)
+(fn FORWARD-BUFFER)")
 (autoload 'message-insinuate-rmail "message" "\
-Let RMAIL use message to forward." t nil)
+Let RMAIL use message to forward." t)
 (autoload 'message-resend "message" "\
 Resend the current article to ADDRESS.
 
-(fn ADDRESS)" t nil)
+(fn ADDRESS)" t)
 (autoload 'message-bounce "message" "\
 Re-mail the current message.
 This only makes sense if the current message is a bounce message that
 contains some mail you have written which has been bounced back to
-you." t nil)
+you." t)
 (autoload 'message-mail-other-window "message" "\
 Like `message-mail' command, but display mail buffer in another window.
 
-(fn &optional TO SUBJECT)" t nil)
+(fn &optional TO SUBJECT)" t)
 (autoload 'message-mail-other-frame "message" "\
 Like `message-mail' command, but display mail buffer in another frame.
 
-(fn &optional TO SUBJECT)" t nil)
+(fn &optional TO SUBJECT)" t)
 (autoload 'message-news-other-window "message" "\
 Start editing a news article to be sent.
 
-(fn &optional NEWSGROUPS SUBJECT)" t nil)
+(fn &optional NEWSGROUPS SUBJECT)" t)
 (autoload 'message-news-other-frame "message" "\
 Start editing a news article to be sent.
 
-(fn &optional NEWSGROUPS SUBJECT)" t nil)
+(fn &optional NEWSGROUPS SUBJECT)" t)
 (autoload 'message-bold-region "message" "\
 Bold all nonblank characters in the region.
 Works by overstriking characters.
 Called from program, takes two arguments START and END
 which specify the range to operate on.
 
-(fn START END)" t nil)
+(fn START END)" t)
 (autoload 'message-unbold-region "message" "\
 Remove all boldness (overstruck characters) in the region.
 Called from program, takes two arguments START and END
 which specify the range to operate on.
 
-(fn START END)" t nil)
+(fn START END)" t)
 (autoload 'message-mailto "message" "\
 Command to parse command line mailto: links.
 This is meant to be used for MIME handlers: Setting the handler
@@ -19539,7 +19677,7 @@ for \"x-scheme-handler/mailto;\" to \"emacs -f 
message-mailto %u\"
 will then start up Emacs ready to compose mail.  For emacsclient use
   emacsclient -e \\='(message-mailto \"%u\")'
 
-(fn &optional URL)" t nil)
+(fn &optional URL)" t)
 (register-definition-prefixes "message" '("message-"))
 
 
@@ -19549,12 +19687,12 @@ will then start up Emacs ready to compose mail.  For 
emacsclient use
 (autoload 'metafont-mode "meta-mode" "\
 Major mode for editing Metafont sources.
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'metapost-mode "meta-mode" "\
 Major mode for editing MetaPost sources.
 
-(fn)" t nil)
-(register-definition-prefixes "meta-mode" 
'("font-lock-match-meta-declaration-item-and-skip-to-next" "meta"))
+(fn)" t)
+(register-definition-prefixes "meta-mode" '("meta"))
 
 
 ;;; Generated autoloads from mh-e/mh-acros.el
@@ -19576,10 +19714,10 @@ Major mode for editing MetaPost sources.
 
 (autoload 'mh-smail "mh-comp" "\
 Compose a message with the MH mail system.
-See `mh-send' for more details on composing mail." t nil)
+See `mh-send' for more details on composing mail." t)
 (autoload 'mh-smail-other-window "mh-comp" "\
 Compose a message with the MH mail system in other window.
-See `mh-send' for more details on composing mail." t nil)
+See `mh-send' for more details on composing mail." t)
 (autoload 'mh-smail-batch "mh-comp" "\
 Compose a message with the MH mail system.
 
@@ -19593,7 +19731,7 @@ SUBJECT, and OTHER-HEADERS. Additional arguments are 
IGNORED.
 This function remains for Emacs 21 compatibility. New
 applications should use `mh-user-agent-compose'.
 
-(fn &optional TO SUBJECT OTHER-HEADERS &rest IGNORED)" nil nil)
+(fn &optional TO SUBJECT OTHER-HEADERS &rest IGNORED)")
 (define-mail-user-agent 'mh-e-user-agent 'mh-user-agent-compose 
'mh-send-letter 'mh-fully-kill-draft 'mh-before-send-letter-hook)
 (autoload 'mh-user-agent-compose "mh-comp" "\
 Set up mail composition draft with the MH mail system.
@@ -19611,7 +19749,7 @@ are strings.
 
 Any additional arguments are IGNORED.
 
-(fn &optional TO SUBJECT OTHER-HEADERS &rest IGNORED)" nil nil)
+(fn &optional TO SUBJECT OTHER-HEADERS &rest IGNORED)")
 (autoload 'mh-send-letter "mh-comp" "\
 Save draft and send message.
 
@@ -19637,22 +19775,17 @@ use `mh-send-prog' to tell MH-E the name.
 The hook `mh-annotate-msg-hook' is run after annotating the
 message and scan line.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'mh-fully-kill-draft "mh-comp" "\
 Quit editing and delete draft message.
 
 If for some reason you are not happy with the draft, you can use
 this command to kill the draft buffer and delete the draft
 message. Use the command \\[kill-buffer] if you don't want to
-delete the draft message." t nil)
+delete the draft message." t)
 (register-definition-prefixes "mh-comp" '("mh-"))
 
 
-;;; Generated autoloads from mh-e/mh-compat.el
-
-(register-definition-prefixes "mh-compat" '("mh-"))
-
-
 ;;; Generated autoloads from mh-e/mh-e.el
 
 (push (purecopy '(mh-e 8 6 -4)) package--builtin-versions)
@@ -19660,7 +19793,7 @@ delete the draft message." t nil)
 (put 'mh-lib 'risky-local-variable t)
 (put 'mh-lib-progs 'risky-local-variable t)
 (autoload 'mh-version "mh-e" "\
-Display version information about MH-E and the MH mail handling system." t nil)
+Display version information about MH-E and the MH mail handling system." t)
 (register-definition-prefixes "mh-e" '("defcustom-mh" "defface-mh" 
"defgroup-mh" "mh-"))
 
 
@@ -19673,7 +19806,7 @@ Scan an MH folder if ARG is non-nil.
 This function is an entry point to MH-E, the Emacs interface to
 the MH mail system.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'mh-nmail "mh-folder" "\
 Check for new mail in inbox folder.
 Scan an MH folder if ARG is non-nil.
@@ -19681,7 +19814,7 @@ Scan an MH folder if ARG is non-nil.
 This function is an entry point to MH-E, the Emacs interface to
 the MH mail system.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'mh-folder-mode "mh-folder" "\
 Major MH-E mode for \"editing\" an MH folder scan 
listing.\\<mh-folder-mode-map>
 
@@ -19738,8 +19871,8 @@ perform the operation on all messages in that region.
 
 \\{mh-folder-mode-map}
 
-(fn)" t nil)
-(register-definition-prefixes "mh-folder" '(":keymap" "mh-"))
+(fn)" t)
+(register-definition-prefixes "mh-folder" '("mh-"))
 
 
 ;;; Generated autoloads from mh-e/mh-funcs.el
@@ -19764,7 +19897,7 @@ perform the operation on all messages in that region.
 
 ;;; Generated autoloads from mh-e/mh-letter.el
 
-(register-definition-prefixes "mh-letter" '(":keymap" "mh-"))
+(register-definition-prefixes "mh-letter" '("mh-"))
 
 
 ;;; Generated autoloads from mh-e/mh-limit.el
@@ -19789,7 +19922,7 @@ perform the operation on all messages in that region.
 
 ;;; Generated autoloads from mh-e/mh-search.el
 
-(register-definition-prefixes "mh-search" '(":keymap" "mh-"))
+(register-definition-prefixes "mh-search" '("mh-"))
 
 
 ;;; Generated autoloads from mh-e/mh-seq.el
@@ -19799,12 +19932,12 @@ perform the operation on all messages in that region.
 
 ;;; Generated autoloads from mh-e/mh-show.el
 
-(register-definition-prefixes "mh-show" '(":keymap" "mh-"))
+(register-definition-prefixes "mh-show" '("mh-"))
 
 
 ;;; Generated autoloads from mh-e/mh-speed.el
 
-(register-definition-prefixes "mh-speed" '(":keymap" "mh-"))
+(register-definition-prefixes "mh-speed" '("mh-"))
 
 
 ;;; Generated autoloads from mh-e/mh-thread.el
@@ -19836,7 +19969,7 @@ Code inside a <script> element is indented using the 
rules from
 `js-mode'; and code inside a <style> element is indented using
 the rules from `css-mode'.
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "mhtml-mode" '("mhtml-"))
 
 
@@ -19867,7 +20000,7 @@ evaluate `(default-value \\='midnight-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'clean-buffer-list "midnight" "\
 Kill old buffers that have not been displayed recently.
 The relevant variables are `clean-buffer-list-delay-general',
@@ -19878,13 +20011,13 @@ The relevant variables are 
`clean-buffer-list-delay-general',
 While processing buffers, this procedure displays messages containing
 the current date/time, buffer name, how many seconds ago it was
 displayed (can be nil if the buffer was never displayed) and its
-lifetime, i.e., its \"age\" when it will be purged." t nil)
+lifetime, i.e., its \"age\" when it will be purged." t)
 (autoload 'midnight-delay-set "midnight" "\
 Modify `midnight-timer' according to `midnight-delay'.
 Sets the first argument SYMB (which must be symbol `midnight-delay')
 to its second argument TM.
 
-(fn SYMB TM)" nil nil)
+(fn SYMB TM)")
 (register-definition-prefixes "midnight" '("clean-buffer-list-" "midnight-"))
 
 
@@ -19923,7 +20056,7 @@ evaluate `(default-value 
\\='minibuffer-electric-default-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "minibuf-eldef" '("minibuf"))
 
 
@@ -19935,7 +20068,23 @@ Copy ARG characters, but not past the end of that line.
 If no argument given, copy the entire rest of the line.
 The characters copied are inserted in the buffer before point.
 
-(fn &optional ARG)" t nil)
+Also see the `duplicate-line' command.
+
+(fn &optional ARG)" t)
+(autoload 'duplicate-line "misc" "\
+Duplicate the current line N times.
+Interactively, N is the prefix numeric argument, and defaults to 1.
+Also see the `copy-from-above-command' command.
+
+(fn &optional N)" t)
+(autoload 'duplicate-dwim "misc" "\
+Duplicate the current line or region N times.
+If the region is inactive, duplicate the current line (like `duplicate-line').
+Otherwise, duplicate the region, which remains active afterwards.
+If the region is rectangular, duplicate on its right-hand side.
+Interactively, N is the prefix numeric argument, and defaults to 1.
+
+(fn &optional N)" t)
 (autoload 'zap-up-to-char "misc" "\
 Kill up to, but not including ARGth occurrence of CHAR.
 When run interactively, the argument INTERACTIVE is non-nil.
@@ -19945,25 +20094,25 @@ Ignores CHAR at point.
 If called interactively, do a case sensitive search if CHAR
 is an upper-case character.
 
-(fn ARG CHAR &optional INTERACTIVE)" t nil)
+(fn ARG CHAR &optional INTERACTIVE)" t)
 (autoload 'mark-beginning-of-buffer "misc" "\
-Set mark at the beginning of the buffer." t nil)
+Set mark at the beginning of the buffer." t)
 (autoload 'mark-end-of-buffer "misc" "\
-Set mark at the end of the buffer." t nil)
+Set mark at the end of the buffer." t)
 (autoload 'upcase-char "misc" "\
 Uppercasify ARG chars starting from point.  Point doesn't move.
 
-(fn ARG)" t nil)
+(fn ARG)" t)
 (autoload 'forward-to-word "misc" "\
 Move forward until encountering the beginning of a word.
 With argument, do this that many times.
 
-(fn ARG)" t nil)
+(fn ARG)" t)
 (autoload 'backward-to-word "misc" "\
 Move backward until encountering the end of a word.
 With argument, do this that many times.
 
-(fn ARG)" t nil)
+(fn ARG)" t)
 (autoload 'butterfly "misc" "\
 Use butterflies to flip the desired bit on the drive platter.
 Open hands and let the delicate wings flap once.  The disturbance
@@ -19971,8 +20120,8 @@ ripples outward, changing the flow of the eddy currents 
in the
 upper atmosphere.  These cause momentary pockets of higher-pressure
 air to form, which act as lenses that deflect incoming cosmic rays,
 focusing them to strike the drive platter and flip the desired bit.
-You can type `M-x butterfly C-M-c' to run it.  This is a permuted
-variation of `C-x M-c M-butterfly' from url `https://xkcd.com/378/'." t nil)
+You can type \\`M-x butterfly C-M-c' to run it.  This is a permuted
+variation of `C-x M-c M-butterfly' from url `https://xkcd.com/378/'." t)
 (autoload 'list-dynamic-libraries "misc" "\
 Display a list of all dynamic libraries known to Emacs.
 (These are the libraries listed in `dynamic-library-alist'.)
@@ -19982,7 +20131,7 @@ Optional argument BUFFER specifies a buffer to use, 
instead of
 \"*Dynamic Libraries*\".
 The return value is always nil.
 
-(fn &optional LOADED-ONLY-P BUFFER)" t nil)
+(fn &optional LOADED-ONLY-P BUFFER)" t)
 (register-definition-prefixes "misc" '("list-dynamic-libraries--"))
 
 
@@ -20024,9 +20173,9 @@ This is nil if Isearch is not currently searching more 
than one buffer.")
 Sequence of files visited by multiple file buffers Isearch.")
 (autoload 'multi-isearch-setup "misearch" "\
 Set up isearch to search multiple buffers.
-Intended to be added to `isearch-mode-hook'." nil nil)
+Intended to be added to `isearch-mode-hook'.")
 (autoload 'multi-isearch-switch-buffer "misearch" "\
-Switch to the next buffer in multi-buffer search." nil nil)
+Switch to the next buffer in multi-buffer search.")
 (autoload 'multi-isearch-buffers "misearch" "\
 Start multi-buffer Isearch on a list of BUFFERS.
 This list can contain live buffers or their names.
@@ -20034,7 +20183,7 @@ Interactively read buffer names to search, one by one, 
ended with RET.
 With a prefix argument, ask for a regexp, and search in buffers
 whose names match the specified regexp.
 
-(fn BUFFERS)" t nil)
+(fn BUFFERS)" t)
 (autoload 'multi-isearch-buffers-regexp "misearch" "\
 Start multi-buffer regexp Isearch on a list of BUFFERS.
 This list can contain live buffers or their names.
@@ -20042,7 +20191,7 @@ Interactively read buffer names to search, one by one, 
ended with RET.
 With a prefix argument, ask for a regexp, and search in buffers
 whose names match the specified regexp.
 
-(fn BUFFERS)" t nil)
+(fn BUFFERS)" t)
 (autoload 'multi-isearch-files "misearch" "\
 Start multi-buffer Isearch on a list of FILES.
 Relative file names in this list are expanded to absolute
@@ -20051,7 +20200,7 @@ Interactively read file names to search, one by one, 
ended with RET.
 With a prefix argument, ask for a wildcard, and search in file buffers
 whose file names match the specified wildcard.
 
-(fn FILES)" t nil)
+(fn FILES)" t)
 (autoload 'multi-isearch-files-regexp "misearch" "\
 Start multi-buffer regexp Isearch on a list of FILES.
 Relative file names in this list are expanded to absolute
@@ -20060,7 +20209,7 @@ Interactively read file names to search, one by one, 
ended with RET.
 With a prefix argument, ask for a wildcard, and search in file buffers
 whose file names match the specified wildcard.
 
-(fn FILES)" t nil)
+(fn FILES)" t)
 (register-definition-prefixes "misearch" '("misearch-unload-function" 
"multi-isearch-"))
 
 
@@ -20070,7 +20219,7 @@ whose file names match the specified wildcard.
 (autoload 'mixal-mode "mixal-mode" "\
 Major mode for the mixal asm language.
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "mixal-mode" '("mixal-"))
 
 
@@ -20091,12 +20240,11 @@ Major mode for the mixal asm language.
 
 ;;; Generated autoloads from gnus/mm-encode.el
 
-(define-obsolete-function-alias 'mm-default-file-encoding 
#'mm-default-file-type "\
-28.1")
+(define-obsolete-function-alias 'mm-default-file-encoding 
#'mm-default-file-type "28.1")
 (autoload 'mm-default-file-type "mm-encode" "\
 Return a default content type for FILE.
 
-(fn FILE)" nil nil)
+(fn FILE)")
 (register-definition-prefixes "mm-encode" '("mm-"))
 
 
@@ -20105,14 +20253,14 @@ Return a default content type for FILE.
 (autoload 'mm-extern-cache-contents "mm-extern" "\
 Put the external-body part of HANDLE into its cache.
 
-(fn HANDLE)" nil nil)
+(fn HANDLE)")
 (autoload 'mm-inline-external-body "mm-extern" "\
 Show the external-body part of HANDLE.
 This function replaces the buffer of HANDLE with a buffer contains
 the entire message.
 If NO-DISPLAY is nil, display it.  Otherwise, do nothing after replacing.
 
-(fn HANDLE &optional NO-DISPLAY)" nil nil)
+(fn HANDLE &optional NO-DISPLAY)")
 (register-definition-prefixes "mm-extern" '("mm-extern-"))
 
 
@@ -20124,7 +20272,7 @@ This function replaces the buffer of HANDLE with a 
buffer contains
 the entire message.
 If NO-DISPLAY is nil, display it.  Otherwise, do nothing after replacing.
 
-(fn HANDLE &optional NO-DISPLAY)" nil nil)
+(fn HANDLE &optional NO-DISPLAY)")
 (register-definition-prefixes "mm-partial" '("mm-partial-find-parts"))
 
 
@@ -20134,11 +20282,11 @@ If NO-DISPLAY is nil, display it.  Otherwise, do 
nothing after replacing.
 Insert file contents of URL.
 If `mm-url-use-external' is non-nil, use `mm-url-program'.
 
-(fn URL)" nil nil)
+(fn URL)")
 (autoload 'mm-url-insert-file-contents-external "mm-url" "\
 Insert file contents of URL using `mm-url-program'.
 
-(fn URL)" nil nil)
+(fn URL)")
 (register-definition-prefixes "mm-url" '("mm-url-"))
 
 
@@ -20155,12 +20303,12 @@ The optional NOHEADER means there's no header in the 
buffer.
 MIME-TYPE specifies a MIME type and parameters, which defaults to the
 value of `mm-uu-text-plain-type'.
 
-(fn &optional NOHEADER MIME-TYPE)" nil nil)
+(fn &optional NOHEADER MIME-TYPE)")
 (autoload 'mm-uu-dissect-text-parts "mm-uu" "\
 Dissect text parts and put uu handles into HANDLE.
 Assume text has been decoded if DECODED is non-nil.
 
-(fn HANDLE &optional DECODED)" nil nil)
+(fn HANDLE &optional DECODED)")
 (register-definition-prefixes "mm-uu" '("mm-"))
 
 
@@ -20172,7 +20320,7 @@ Assume text has been decoded if DECODED is non-nil.
 ;;; Generated autoloads from gnus/mml.el
 
 (autoload 'mml-to-mime "mml" "\
-Translate the current buffer from MML to MIME." nil nil)
+Translate the current buffer from MML to MIME.")
 (autoload 'mml-attach-file "mml" "\
 Attach a file to the outgoing MIME message.
 The file is not inserted or encoded until you send the message with
@@ -20192,7 +20340,7 @@ If given a prefix interactively, no prompting will be 
done for
 the TYPE, DESCRIPTION or DISPOSITION values.  Instead defaults
 will be computed and used.
 
-(fn FILE &optional TYPE DESCRIPTION DISPOSITION)" t nil)
+(fn FILE &optional TYPE DESCRIPTION DISPOSITION)" t)
 (register-definition-prefixes "mml" '("mime-to-mml" "mml-"))
 
 
@@ -20211,11 +20359,11 @@ will be computed and used.
 (autoload 'mml1991-encrypt "mml1991" "\
 
 
-(fn CONT &optional SIGN)" nil nil)
+(fn CONT &optional SIGN)")
 (autoload 'mml1991-sign "mml1991" "\
 
 
-(fn CONT)" nil nil)
+(fn CONT)")
 (register-definition-prefixes "mml1991" '("mml1991-"))
 
 
@@ -20224,28 +20372,28 @@ will be computed and used.
 (autoload 'mml2015-decrypt "mml2015" "\
 
 
-(fn HANDLE CTL)" nil nil)
+(fn HANDLE CTL)")
 (autoload 'mml2015-decrypt-test "mml2015" "\
 
 
-(fn HANDLE CTL)" nil nil)
+(fn HANDLE CTL)")
 (autoload 'mml2015-verify "mml2015" "\
 
 
-(fn HANDLE CTL)" nil nil)
+(fn HANDLE CTL)")
 (autoload 'mml2015-verify-test "mml2015" "\
 
 
-(fn HANDLE CTL)" nil nil)
+(fn HANDLE CTL)")
 (autoload 'mml2015-encrypt "mml2015" "\
 
 
-(fn CONT &optional SIGN)" nil nil)
+(fn CONT &optional SIGN)")
 (autoload 'mml2015-sign "mml2015" "\
 
 
-(fn CONT)" nil nil)
-(autoload 'mml2015-self-encrypt "mml2015" nil nil nil)
+(fn CONT)")
+(autoload 'mml2015-self-encrypt "mml2015")
 (register-definition-prefixes "mml2015" '("mml2015-"))
 
 
@@ -20292,7 +20440,7 @@ followed by the first character of the construct.
    `m2-compile-command' holds the command to compile a Modula-2 program.
    `m2-link-command' holds the command to link a Modula-2 program.
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "modula2" '("m2-" "m3-font-lock-keywords"))
 
 
@@ -20302,19 +20450,19 @@ followed by the first character of the construct.
 Convert plain text in region to Morse code.
 See <https://en.wikipedia.org/wiki/Morse_code>.
 
-(fn BEG END)" t nil)
+(fn BEG END)" t)
 (autoload 'unmorse-region "morse" "\
 Convert Morse coded text in region to plain text.
 
-(fn BEG END)" t nil)
+(fn BEG END)" t)
 (autoload 'nato-region "morse" "\
 Convert plain text in region to NATO spelling alphabet.
 
-(fn BEG END)" t nil)
+(fn BEG END)" t)
 (autoload 'denato-region "morse" "\
 Convert NATO spelling alphabet text in region to plain text.
 
-(fn BEG END)" t nil)
+(fn BEG END)" t)
 (register-definition-prefixes "morse" '("morse-code" "nato-alphabet"))
 
 
@@ -20347,7 +20495,7 @@ hemisphere you're in.)
 To test this function, evaluate:
     (global-set-key [down-mouse-2] \\='mouse-drag-throw)
 
-(fn START-EVENT)" t nil)
+(fn START-EVENT)" t)
 (autoload 'mouse-drag-drag "mouse-drag" "\
 \"Drag\" the page according to a mouse drag.
 
@@ -20364,21 +20512,21 @@ middle button in Tk text widgets.
 To test this function, evaluate:
     (global-set-key [down-mouse-2] \\='mouse-drag-drag)
 
-(fn START-EVENT)" t nil)
+(fn START-EVENT)" t)
 (register-definition-prefixes "mouse-drag" '("mouse-"))
 
 
 ;;; Generated autoloads from mpc.el
 
 (autoload 'mpc "mpc" "\
-Main entry point for MPC." t nil)
-(register-definition-prefixes "mpc" '("mpc-" "tag-browser-tagtypes"))
+Main entry point for MPC." t)
+(register-definition-prefixes "mpc" '("mpc-"))
 
 
 ;;; Generated autoloads from play/mpuz.el
 
 (autoload 'mpuz "mpuz" "\
-Multiplication puzzle with GNU Emacs." t nil)
+Multiplication puzzle with GNU Emacs." t)
 (register-definition-prefixes "mpuz" '("mpuz-"))
 
 
@@ -20417,7 +20565,7 @@ evaluate `(default-value \\='msb-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "msb" '("mouse-select-buffer" "msb"))
 
 
@@ -20427,7 +20575,7 @@ it is disabled.
 Show the list of non-empty spool files in the *spools* buffer.
 Buffer is not displayed if SHOW is non-nil.
 
-(fn &optional NOSHOW)" t nil)
+(fn &optional NOSHOW)" t)
 (register-definition-prefixes "mspools" '("mspools-"))
 
 
@@ -20445,7 +20593,7 @@ ISO-2022-based coding systems.
 With prefix ARG, the output format gets more cryptic,
 but still shows the full information.
 
-(fn ARG)" t nil)
+(fn ARG)" t)
 (autoload 'read-charset "mule-diag" "\
 Read a character set from the minibuffer, prompting with string PROMPT.
 It must be an Emacs character set listed in the variable `charset-list'.
@@ -20456,19 +20604,19 @@ INITIAL-INPUT, if non-nil, is a string inserted in 
the minibuffer initially.
 See the documentation of the function `completing-read' for the detailed
 meanings of these arguments.
 
-(fn PROMPT &optional DEFAULT-VALUE INITIAL-INPUT)" nil nil)
+(fn PROMPT &optional DEFAULT-VALUE INITIAL-INPUT)")
 (autoload 'list-charset-chars "mule-diag" "\
 Display a list of characters in character set CHARSET.
 
-(fn CHARSET)" t nil)
+(fn CHARSET)" t)
 (autoload 'describe-character-set "mule-diag" "\
 Display information about built-in character set CHARSET.
 
-(fn CHARSET)" t nil)
+(fn CHARSET)" t)
 (autoload 'describe-coding-system "mule-diag" "\
 Display information about CODING-SYSTEM.
 
-(fn CODING-SYSTEM)" t nil)
+(fn CODING-SYSTEM)" t)
 (autoload 'describe-current-coding-system-briefly "mule-diag" "\
 Display coding systems currently used in a brief format in echo area.
 
@@ -20490,9 +20638,9 @@ in place of `..':
   `default-process-coding-system' for read
   eol-type of `default-process-coding-system' for read
   `default-process-coding-system' for write
-  eol-type of `default-process-coding-system'" t nil)
+  eol-type of `default-process-coding-system'" t)
 (autoload 'describe-current-coding-system "mule-diag" "\
-Display coding systems currently used, in detail." t nil)
+Display coding systems currently used, in detail." t)
 (autoload 'list-coding-systems "mule-diag" "\
 Display a list of all coding systems.
 This shows the mnemonic letter, name, and description of each coding system.
@@ -20500,40 +20648,40 @@ This shows the mnemonic letter, name, and description 
of each coding system.
 With prefix ARG, the output format gets more cryptic,
 but still contains full information about each coding system.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'list-coding-categories "mule-diag" "\
-Display a list of all coding categories." nil nil)
+Display a list of all coding categories.")
 (autoload 'describe-font "mule-diag" "\
 Display information about a font whose name is FONTNAME.
 
-(fn FONTNAME)" t nil)
+(fn FONTNAME)" t)
 (autoload 'describe-fontset "mule-diag" "\
 Display information about FONTSET.
 This shows which font is used for which character(s).
 
-(fn FONTSET)" t nil)
+(fn FONTSET)" t)
 (autoload 'list-fontsets "mule-diag" "\
 Display a list of all fontsets.
 This shows the name, size, and style of each fontset.
 With prefix arg, also list the fonts contained in each fontset;
 see the function `describe-fontset' for the format of the list.
 
-(fn ARG)" t nil)
+(fn ARG)" t)
 (autoload 'list-input-methods "mule-diag" "\
-Display information about all input methods." t nil)
+Display information about all input methods." t)
 (autoload 'mule-diag "mule-diag" "\
 Display diagnosis of the multilingual environment (Mule).
 
 This shows various information related to the current multilingual
 environment, including lists of input methods, coding systems,
 character sets, and fontsets (if Emacs is running under a window
-system which uses fontsets)." t nil)
+system which uses fontsets)." t)
 (autoload 'font-show-log "mule-diag" "\
 Show log of font listing and opening.
 Prefix arg LIMIT says how many fonts to show for each listing.
 The default is 20.  If LIMIT is negative, do not limit the listing.
 
-(fn &optional LIMIT)" t nil)
+(fn &optional LIMIT)" t)
 (register-definition-prefixes "mule-diag" '("charset-history" 
"describe-font-internal" "insert-section" "list-" "mule--kbd-at" "print-" 
"sort-listed-character-sets"))
 
 
@@ -20542,7 +20690,7 @@ The default is 20.  If LIMIT is negative, do not limit 
the listing.
 (autoload 'store-substring "mule-util" "\
 Embed OBJ (string or character) at index IDX of STRING.
 
-(fn STRING IDX OBJ)" nil nil)
+(fn STRING IDX OBJ)")
 (autoload 'truncate-string-to-width "mule-util" "\
 Truncate string STR to end at column END-COLUMN.
 The optional 3rd arg START-COLUMN, if non-nil, specifies the starting
@@ -20576,7 +20724,7 @@ If ELLIPSIS-TEXT-PROPERTY is non-nil, a too-long string 
will not
 be truncated, but instead the elided parts will be covered by a
 `display' text property showing the ellipsis.
 
-(fn STR END-COLUMN &optional START-COLUMN PADDING ELLIPSIS 
ELLIPSIS-TEXT-PROPERTY)" nil nil)
+(fn STR END-COLUMN &optional START-COLUMN PADDING ELLIPSIS 
ELLIPSIS-TEXT-PROPERTY)")
 (defsubst nested-alist-p (obj) "\
 Return t if OBJ is a nested alist.
 
@@ -20595,7 +20743,7 @@ Optional 5th argument BRANCHES if non-nil is branches 
for a keyseq
 longer than KEYSEQ.
 See the documentation of `nested-alist-p' for more detail.
 
-(fn KEYSEQ ENTRY ALIST &optional LEN BRANCHES)" nil nil)
+(fn KEYSEQ ENTRY ALIST &optional LEN BRANCHES)")
 (autoload 'lookup-nested-alist "mule-util" "\
 Look up key sequence KEYSEQ in nested alist ALIST.  Return the definition.
 Optional 3rd argument LEN specifies the length of KEYSEQ.
@@ -20608,23 +20756,23 @@ If ALIST is not deep enough for KEYSEQ, return number 
which is
 Optional 5th argument NIL-FOR-TOO-LONG non-nil means return nil
  even if ALIST is not deep enough.
 
-(fn KEYSEQ ALIST &optional LEN START NIL-FOR-TOO-LONG)" nil nil)
+(fn KEYSEQ ALIST &optional LEN START NIL-FOR-TOO-LONG)")
 (autoload 'coding-system-post-read-conversion "mule-util" "\
 Return the value of CODING-SYSTEM's `post-read-conversion' property.
 
-(fn CODING-SYSTEM)" nil nil)
+(fn CODING-SYSTEM)")
 (autoload 'coding-system-pre-write-conversion "mule-util" "\
 Return the value of CODING-SYSTEM's `pre-write-conversion' property.
 
-(fn CODING-SYSTEM)" nil nil)
+(fn CODING-SYSTEM)")
 (autoload 'coding-system-translation-table-for-decode "mule-util" "\
 Return the value of CODING-SYSTEM's `decode-translation-table' property.
 
-(fn CODING-SYSTEM)" nil nil)
+(fn CODING-SYSTEM)")
 (autoload 'coding-system-translation-table-for-encode "mule-util" "\
 Return the value of CODING-SYSTEM's `encode-translation-table' property.
 
-(fn CODING-SYSTEM)" nil nil)
+(fn CODING-SYSTEM)")
 (autoload 'with-coding-priority "mule-util" "\
 Execute BODY like `progn' with CODING-SYSTEMS at the front of priority list.
 CODING-SYSTEMS is a list of coding systems.  See `set-coding-system-priority'.
@@ -20632,13 +20780,13 @@ This affects the implicit sorting of lists of coding 
systems returned by
 operations such as `find-coding-systems-region'.
 
 (fn CODING-SYSTEMS &rest BODY)" nil t)
-(function-put 'with-coding-priority 'lisp-indent-function '1)
+(function-put 'with-coding-priority 'lisp-indent-function 1)
 (autoload 'detect-coding-with-language-environment "mule-util" "\
 Detect a coding system for the text between FROM and TO with LANG-ENV.
 The detection takes into account the coding system priorities for the
 language environment LANG-ENV.
 
-(fn FROM TO LANG-ENV)" nil nil)
+(fn FROM TO LANG-ENV)")
 (autoload 'filepos-to-bufferpos "mule-util" "\
 Try to return the buffer position corresponding to a particular file position.
 The file position is given as a (0-based) BYTE count.
@@ -20653,7 +20801,7 @@ QUALITY can be:
     EOL format is not yet decided.)
   nil, in which case we may return nil rather than an approximation.
 
-(fn BYTE &optional QUALITY CODING-SYSTEM)" nil nil)
+(fn BYTE &optional QUALITY CODING-SYSTEM)")
 (autoload 'bufferpos-to-filepos "mule-util" "\
 Try to return the file byte corresponding to a particular buffer POSITION.
 Value is the file position given as a (0-based) byte count.
@@ -20668,7 +20816,7 @@ QUALITY can be:
     EOL format is not yet decided.)
   nil, in which case we may return nil rather than an approximation.
 
-(fn POSITION &optional QUALITY CODING-SYSTEM)" nil nil)
+(fn POSITION &optional QUALITY CODING-SYSTEM)")
 (register-definition-prefixes "mule-util" '("filepos-to-bufferpos--dos" 
"truncate-string-ellipsis"))
 
 
@@ -20686,7 +20834,7 @@ List all values in the \"multisession\" database.
 If CHOOSE-STORAGE (interactively, the prefix), query for the
 storage method to list.
 
-(fn &optional CHOOSE-STORAGE)" t nil)
+(fn &optional CHOOSE-STORAGE)" t)
 (register-definition-prefixes "multisession" '("multisession-"))
 
 
@@ -20717,32 +20865,32 @@ evaluate `(default-value \\='mouse-wheel-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "mwheel" '("mouse-wheel-" "mwheel-"))
 
 
 ;;; Generated autoloads from net/net-utils.el
 
 (autoload 'ifconfig "net-utils" "\
-Run `ifconfig-program' and display diagnostic output." t nil)
+Run `ifconfig-program' and display diagnostic output." t)
 (autoload 'iwconfig "net-utils" "\
-Run `iwconfig-program' and display diagnostic output." t nil)
+Run `iwconfig-program' and display diagnostic output." t)
 (autoload 'netstat "net-utils" "\
-Run `netstat-program' and display diagnostic output." t nil)
+Run `netstat-program' and display diagnostic output." t)
 (autoload 'arp "net-utils" "\
-Run `arp-program' and display diagnostic output." t nil)
+Run `arp-program' and display diagnostic output." t)
 (autoload 'route "net-utils" "\
-Run `route-program' and display diagnostic output." t nil)
+Run `route-program' and display diagnostic output." t)
 (autoload 'traceroute "net-utils" "\
 Run `traceroute-program' for TARGET.
 
-(fn TARGET)" t nil)
+(fn TARGET)" t)
 (autoload 'ping "net-utils" "\
 Ping HOST.
 If your system's ping continues until interrupted, you can try setting
 `ping-program-options'.
 
-(fn HOST)" t nil)
+(fn HOST)" t)
 (autoload 'nslookup-host "net-utils" "\
 Look up the DNS information for HOST (name or IP address).
 Optional argument NAME-SERVER says which server to use for
@@ -20755,7 +20903,7 @@ See also: `nslookup-host-ipv4', `nslookup-host-ipv6' for
 non-interactive versions of this function more suitable for use
 in Lisp code.
 
-(fn HOST &optional NAME-SERVER)" t nil)
+(fn HOST &optional NAME-SERVER)" t)
 (autoload 'nslookup-host-ipv4 "net-utils" "\
 Return the IPv4 address for HOST (name or IP address).
 Optional argument NAME-SERVER says which server to use for DNS
@@ -20767,7 +20915,7 @@ vector of octets.
 
 This command uses `nslookup-program' to look up DNS records.
 
-(fn HOST &optional NAME-SERVER FORMAT)" nil nil)
+(fn HOST &optional NAME-SERVER FORMAT)")
 (autoload 'nslookup-host-ipv6 "net-utils" "\
 Return the IPv6 address for HOST (name or IP address).
 Optional argument NAME-SERVER says which server to use for DNS
@@ -20779,9 +20927,9 @@ vector of hextets.
 
 This command uses `nslookup-program' to look up DNS records.
 
-(fn HOST &optional NAME-SERVER FORMAT)" nil nil)
+(fn HOST &optional NAME-SERVER FORMAT)")
 (autoload 'nslookup "net-utils" "\
-Run `nslookup-program'." t nil)
+Run `nslookup-program'." t)
 (autoload 'dns-lookup-host "net-utils" "\
 Look up the DNS information for HOST (name or IP address).
 Optional argument NAME-SERVER says which server to use for
@@ -20790,7 +20938,7 @@ Interactively, prompt for NAME-SERVER if invoked with 
prefix argument.
 
 This command uses `dns-lookup-program' for looking up the DNS information.
 
-(fn HOST &optional NAME-SERVER)" t nil)
+(fn HOST &optional NAME-SERVER)" t)
 (autoload 'run-dig "net-utils" "\
 Look up DNS information for HOST (name or IP address).
 Optional argument NAME-SERVER says which server to use for
@@ -20799,46 +20947,36 @@ Interactively, prompt for NAME-SERVER if invoked with 
prefix argument.
 
 This command uses `dig-program' for looking up the DNS information.
 
-(fn HOST &optional NAME-SERVER)" t nil)
+(fn HOST &optional NAME-SERVER)" t)
+(make-obsolete 'run-dig 'dig "29.1")
 (autoload 'ftp "net-utils" "\
 Run `ftp-program' to connect to HOST.
 
-(fn HOST)" t nil)
+(fn HOST)" t)
 (autoload 'finger "net-utils" "\
 Finger USER on HOST.
 This command uses `finger-X.500-host-regexps'
 and `network-connection-service-alist', which see.
 
-(fn USER HOST)" t nil)
+(fn USER HOST)" t)
 (autoload 'whois "net-utils" "\
 Send SEARCH-STRING to server defined by the `whois-server-name' variable.
 If `whois-guess-server' is non-nil, then try to deduce the correct server
 from SEARCH-STRING.  With argument, prompt for whois server.
 The port is deduced from `network-connection-service-alist'.
 
-(fn ARG SEARCH-STRING)" t nil)
-(autoload 'whois-reverse-lookup "net-utils" nil t nil)
+(fn ARG SEARCH-STRING)" t)
+(autoload 'whois-reverse-lookup "net-utils" nil t)
 (autoload 'network-connection-to-service "net-utils" "\
 Open a network connection to SERVICE on HOST.
 This command uses `network-connection-service-alist', which see.
 
-(fn HOST SERVICE)" t nil)
+(fn HOST SERVICE)" t)
 (autoload 'network-connection "net-utils" "\
 Open a network connection to HOST on PORT.
 
-(fn HOST PORT)" t nil)
-(register-definition-prefixes "net-utils" '("arp-program" "dig-program" 
"dns-lookup-program" "finger-X.500-host-regexps" "ftp-" "ifconfig-program" 
"ipconfig" "iwconfig-program" "net" "nslookup-" "ping-program" "route-program" 
"run-network-program" "smbclient" "traceroute-program" "whois-"))
-
-
-;;; Generated autoloads from net/netrc.el
-
-(autoload 'netrc-credentials "netrc" "\
-Return a user name/password pair.
-Port specifications will be prioritized in the order they are
-listed in the PORTS list.
-
-(fn MACHINE &rest PORTS)" nil nil)
-(register-definition-prefixes "netrc" '("netrc-"))
+(fn HOST PORT)" t)
+(register-definition-prefixes "net-utils" '("arp-program" "dns-lookup-program" 
"finger-X.500-host-regexps" "ftp-" "ifconfig-program" "ipconfig" 
"iwconfig-program" "net" "nslookup-" "ping-program" "route-program" 
"run-network-program" "smbclient" "traceroute-program" "whois-"))
 
 
 ;;; Generated autoloads from net/network-stream.el
@@ -20949,9 +21087,8 @@ type (either `gnutls-x509pki' or `gnutls-anon'), and the
 remaining elements should be a keyword list accepted by
 gnutls-boot (as returned by `gnutls-boot-parameters').
 
-(fn NAME BUFFER HOST SERVICE &rest PARAMETERS)" nil nil)
-(define-obsolete-function-alias 'open-protocol-stream #'open-network-stream "\
-26.1")
+(fn NAME BUFFER HOST SERVICE &rest PARAMETERS)")
+(define-obsolete-function-alias 'open-protocol-stream #'open-network-stream 
"26.1")
 (register-definition-prefixes "network-stream" '("network-stream-"))
 
 
@@ -20960,7 +21097,7 @@ gnutls-boot (as returned by `gnutls-boot-parameters').
 (autoload 'newsticker-running-p "newst-backend" "\
 Check whether newsticker is running.
 Return t if newsticker is running, nil otherwise.  Newsticker is
-considered to be running if the newsticker timer list is not empty." nil nil)
+considered to be running if the newsticker timer list is not empty.")
 (autoload 'newsticker-start "newst-backend" "\
 Start the newsticker.
 Start the timers for display and retrieval.  If the newsticker, i.e. the
@@ -20968,21 +21105,21 @@ timers, are running already a warning message is 
printed unless
 DO-NOT-COMPLAIN-IF-RUNNING is not nil.
 Run `newsticker-start-hook' if newsticker was not running already.
 
-(fn &optional DO-NOT-COMPLAIN-IF-RUNNING)" t nil)
+(fn &optional DO-NOT-COMPLAIN-IF-RUNNING)" t)
 (register-definition-prefixes "newst-backend" '("newsticker-"))
 
 
 ;;; Generated autoloads from net/newst-plainview.el
 
 (autoload 'newsticker-plainview "newst-plainview" "\
-Start newsticker plainview." t nil)
+Start newsticker plainview." t)
 (register-definition-prefixes "newst-plainview" '("newsticker-"))
 
 
 ;;; Generated autoloads from net/newst-reader.el
 
 (autoload 'newsticker-show-news "newst-reader" "\
-Start reading news.  You may want to bind this to a key." t nil)
+Start reading news.  You may want to bind this to a key." t)
 (register-definition-prefixes "newst-reader" '("newsticker-"))
 
 
@@ -20992,18 +21129,18 @@ Start reading news.  You may want to bind this to a 
key." t nil)
 Check whether newsticker's actual ticker is running.
 Return t if ticker is running, nil otherwise.  Newsticker is
 considered to be running if the newsticker timer list is not
-empty." nil nil)
+empty.")
 (autoload 'newsticker-start-ticker "newst-ticker" "\
 Start newsticker's ticker (but not the news retrieval).
 Start display timer for the actual ticker if wanted and not
-running already." t nil)
+running already." t)
 (register-definition-prefixes "newst-ticker" '("newsticker-"))
 
 
 ;;; Generated autoloads from net/newst-treeview.el
 
 (autoload 'newsticker-treeview "newst-treeview" "\
-Start newsticker treeview." t nil)
+Start newsticker treeview." t)
 (register-definition-prefixes "newst-treeview" '("newsticker-"))
 
 
@@ -21027,7 +21164,7 @@ Start newsticker treeview." t nil)
 (autoload 'nndiary-generate-nov-databases "nndiary" "\
 Generate NOV databases in all nndiary directories.
 
-(fn &optional SERVER)" t nil)
+(fn &optional SERVER)" t)
 (register-definition-prefixes "nndiary" '("nndiary-"))
 
 
@@ -21045,7 +21182,7 @@ as the last checked definition, if t or `first', add as 
the
 first definition, and if any other symbol, add after that
 symbol in the alist.
 
-(fn DEFINITION &optional POSITION)" nil nil)
+(fn DEFINITION &optional POSITION)")
 (register-definition-prefixes "nndoc" '("nndoc-"))
 
 
@@ -21063,7 +21200,7 @@ symbol in the alist.
 
 (autoload 'nnfolder-generate-active-file "nnfolder" "\
 Look for mbox folders in the nnfolder directory and make them into groups.
-This command does not work if you use short group names." t nil)
+This command does not work if you use short group names." t)
 (register-definition-prefixes "nnfolder" '("nnfolder-"))
 
 
@@ -21112,7 +21249,7 @@ This command does not work if you use short group 
names." t nil)
 (autoload 'nnml-generate-nov-databases "nnml" "\
 Generate NOV databases in all nnml directories.
 
-(fn &optional SERVER)" t nil)
+(fn &optional SERVER)" t)
 (register-definition-prefixes "nnml" '("nnml-"))
 
 
@@ -21174,21 +21311,21 @@ If nil, the feature is disabled, i.e., all commands 
work normally.")
 (autoload 'disabled-command-function "novice" "\
 
 
-(fn &optional CMD KEYS)" nil nil)
+(fn &optional CMD KEYS)")
 (autoload 'enable-command "novice" "\
 Allow COMMAND to be executed without special confirmation from now on.
 COMMAND must be a symbol.
 This command alters the user's .emacs file so that this will apply
 to future sessions.
 
-(fn COMMAND)" t nil)
+(fn COMMAND)" t)
 (autoload 'disable-command "novice" "\
 Require special confirmation to execute COMMAND from now on.
 COMMAND must be a symbol.
 This command alters your init file so that this choice applies to
 future sessions.
 
-(fn COMMAND)" t nil)
+(fn COMMAND)" t)
 (register-definition-prefixes "novice" '("en/disable-command"))
 
 
@@ -21201,7 +21338,7 @@ Turning on Nroff mode runs `text-mode-hook', then 
`nroff-mode-hook'.
 Also, try `nroff-electric-mode', for automatically inserting
 closing requests for requests that are used in matched pairs.
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "nroff-mode" '("nroff-"))
 
 
@@ -21280,7 +21417,7 @@ to nil.  For more details, see the function 
`nxml-forward-balanced-item'.
 Many aspects this mode can be customized using
 \\[customize-group] nxml RET.
 
-(fn)" t nil)
+(fn)" t)
 (defalias 'xml-mode 'nxml-mode)
 (register-definition-prefixes "nxml-mode" '("nxml-"))
 
@@ -21552,7 +21689,7 @@ Insert a citation at point.
 Insertion is done according to the processor set in 
`org-cite-insert-processor'.
 ARG is the prefix argument received when calling interactively the function.
 
-(fn ARG)" t nil)
+(fn ARG)" t)
 (register-definition-prefixes "oc" '("org-cite-"))
 
 
@@ -21580,7 +21717,7 @@ ARG is the prefix argument received when calling 
interactively the function.
 
  (add-to-list 'auto-mode-alist '("\\.m\\'" . octave-maybe-mode))
 (autoload 'octave-maybe-mode "octave" "\
-Select `octave-mode' if the current buffer seems to hold Octave code." nil nil)
+Select `octave-mode' if the current buffer seems to hold Octave code.")
 (autoload 'octave-mode "octave" "\
 Major mode for editing Octave code.
 
@@ -21594,7 +21731,7 @@ See Info node `(octave-mode) Using Octave Mode' for 
more details.
 Key bindings:
 \\{octave-mode-map}
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'inferior-octave "octave" "\
 Run an inferior Octave process, I/O via `inferior-octave-buffer'.
 This buffer is put in Inferior Octave mode.  See `inferior-octave-mode'.
@@ -21608,7 +21745,7 @@ Additional commands to be executed on startup can be 
provided either in
 the file specified by `inferior-octave-startup-file' or by the default
 startup file, `~/.emacs-octave'.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (defalias 'run-octave 'inferior-octave)
 (register-definition-prefixes "octave" '("inferior-octave-" "octave-"))
 
@@ -21690,8 +21827,7 @@ startup file, `~/.emacs-octave'.
 
 ;;; Generated autoloads from progmodes/opascal.el
 
-(define-obsolete-function-alias 'delphi-mode #'opascal-mode "\
-24.4")
+(define-obsolete-function-alias 'delphi-mode #'opascal-mode "24.4")
 (autoload 'opascal-mode "opascal" "\
 Major mode for editing OPascal code.
 \\<opascal-mode-map>
@@ -21719,7 +21855,7 @@ Coloring:
  `opascal-keyword-face'                (default `font-lock-keyword-face')
     Face used to color OPascal keywords.
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "opascal" '("opascal-"))
 
 
@@ -21729,7 +21865,7 @@ Coloring:
 (autoload 'org-babel-do-load-languages "org" "\
 Load the languages defined in `org-babel-load-languages'.
 
-(fn SYM VALUE)" nil nil)
+(fn SYM VALUE)")
 (autoload 'org-babel-load-file "org" "\
 Load Emacs Lisp source code blocks in the Org FILE.
 This function exports the source code using `org-babel-tangle'
@@ -21737,7 +21873,7 @@ and then loads the resulting file using `load-file'.  
With
 optional prefix argument COMPILE, the tangled Emacs Lisp file is
 byte-compiled before it is loaded.
 
-(fn FILE &optional COMPILE)" t nil)
+(fn FILE &optional COMPILE)" t)
 (autoload 'org-version "org" "\
 Show the Org version.
 Interactively, or when MESSAGE is non-nil, show it in echo area.
@@ -21745,13 +21881,13 @@ With prefix argument, or when HERE is non-nil, insert 
it at point.
 In non-interactive uses, a reduced version string is output unless
 FULL is given.
 
-(fn &optional HERE FULL MESSAGE)" t nil)
+(fn &optional HERE FULL MESSAGE)" t)
 (autoload 'org-load-modules-maybe "org" "\
 Load all extensions listed in `org-modules'.
 
-(fn &optional FORCE)" nil nil)
+(fn &optional FORCE)")
 (autoload 'org-clock-persistence-insinuate "org" "\
-Set up hooks for clock persistence." nil nil)
+Set up hooks for clock persistence.")
 (autoload 'org-mode "org" "\
 Outline-based notes management and organizer, alias
 \"Carsten's outline-mode for keeping track of everything.\"
@@ -21771,7 +21907,7 @@ The following commands are available:
 
 \\{org-mode-map}
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'org-cycle "org" "\
 TAB-action and visibility cycling for Org mode.
 
@@ -21822,20 +21958,20 @@ there is no headline there, and if the variable 
`org-cycle-global-at-bob'
 is non-nil, this function acts as if called with prefix argument 
(`\\[universal-argument] TAB',
 same as `S-TAB') also when called without prefix argument.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'org-global-cycle "org" "\
 Cycle the global visibility.  For details see `org-cycle'.
 With `\\[universal-argument]' prefix ARG, switch to startup visibility.
 With a numeric prefix, show all headlines up to that level.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'org-run-like-in-org-mode "org" "\
 Run a command, pretending that the current buffer is in Org mode.
 This will temporarily bind local variables that are typically bound in
 Org mode to the values they have in Org mode, and then interactively
 call CMD.
 
-(fn CMD)" nil nil)
+(fn CMD)")
 (autoload 'org-open-file "org" "\
 Open the file at PATH.
 First, this expands any special file name abbreviations.  Then the
@@ -21858,14 +21994,14 @@ link, please customize `org-link-frame-setup'.
 
 If the file does not exist, throw an error.
 
-(fn PATH &optional IN-EMACS LINE SEARCH)" nil nil)
+(fn PATH &optional IN-EMACS LINE SEARCH)")
 (autoload 'org-open-at-point-global "org" "\
 Follow a link or a time-stamp like Org mode does.
 Also follow links and emails as seen by `thing-at-point'.
 This command can be called in any mode to follow an external
 link or a time-stamp that has Org mode syntax.  Its behavior
 is undefined when called on internal links like fuzzy links.
-Raise a user error when there is nothing to follow." t nil)
+Raise a user error when there is nothing to follow." t)
 (autoload 'org-offer-links-in-entry "org" "\
 Offer links in the current entry and return the selected link.
 If there is only one link, return it.
@@ -21873,7 +22009,7 @@ If NTH is an integer, return the NTH link found.
 If ZERO is a string, check also this string for a link, and if
 there is one, return it.
 
-(fn BUFFER MARKER &optional NTH ZERO)" nil nil)
+(fn BUFFER MARKER &optional NTH ZERO)")
 (autoload 'org-switchb "org" "\
 Switch between Org buffers.
 
@@ -21881,11 +22017,11 @@ With `\\[universal-argument]' prefix, restrict 
available buffers to files.
 
 With `\\[universal-argument] \\[universal-argument]' prefix, restrict 
available buffers to agenda files.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'org-cycle-agenda-files "org" "\
 Cycle through the files in `org-agenda-files'.
 If the current buffer visits an agenda file, find the next one in the list.
-If the current buffer does not, find the first agenda file." t nil)
+If the current buffer does not, find the first agenda file." t)
 (autoload 'org-submit-bug-report "org" "\
 Submit a bug report on Org via mail.
 
@@ -21893,14 +22029,14 @@ Don't hesitate to report any problems or inaccurate 
documentation.
 
 If you don't have setup sending mail from (X)Emacs, please copy the
 output buffer into your mail program, as it gives us important
-information about your Org version and configuration." t nil)
+information about your Org version and configuration." t)
 (autoload 'org-reload "org" "\
 Reload all Org Lisp files.
 With prefix arg UNCOMPILED, load the uncompiled versions.
 
-(fn &optional UNCOMPILED)" t nil)
+(fn &optional UNCOMPILED)" t)
 (autoload 'org-customize "org" "\
-Call the customize function with org as argument." t nil)
+Call the customize function with org as argument." t)
 (register-definition-prefixes "org" '("org-" "turn-on-org-cdlatex"))
 
 
@@ -21909,7 +22045,7 @@ Call the customize function with org as argument." t 
nil)
 (autoload 'org-toggle-sticky-agenda "org-agenda" "\
 Toggle `org-agenda-sticky'.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'org-agenda "org-agenda" "\
 Dispatch agenda commands to collect entries to the agenda buffer.
 Prompts for a command to execute.  Any prefix arg will be passed
@@ -21944,7 +22080,7 @@ first press `<' once to indicate that the agenda should 
be temporarily
 Pressing `<' twice means to restrict to the current subtree or region
 (if active).
 
-(fn &optional ARG KEYS RESTRICTION)" t nil)
+(fn &optional ARG KEYS RESTRICTION)" t)
 (autoload 'org-batch-agenda "org-agenda" "\
 Run an agenda command in batch mode and send the result to STDOUT.
 If CMD-KEY is a string of length 1, it is used as a key in
@@ -21993,7 +22129,7 @@ agenda-day   The day in the agenda where this is listed
 (autoload 'org-store-agenda-views "org-agenda" "\
 Store agenda views.
 
-(fn &rest PARAMETERS)" t nil)
+(fn &rest PARAMETERS)" t)
 (autoload 'org-batch-store-agenda-views "org-agenda" "\
 Run all custom agenda commands that have a file argument.
 
@@ -22013,7 +22149,7 @@ given in `org-agenda-start-on-weekday'.
 When WITH-HOUR is non-nil, only include scheduled and deadline
 items if they have an hour specification like [h]h:mm.
 
-(fn &optional ARG START-DAY SPAN WITH-HOUR)" t nil)
+(fn &optional ARG START-DAY SPAN WITH-HOUR)" t)
 (autoload 'org-search-view "org-agenda" "\
 Show all entries that contain a phrase or words or regular expressions.
 
@@ -22059,7 +22195,7 @@ This command searches the agenda files, and in addition 
the files
 listed in `org-agenda-text-search-extra-files' unless a restriction lock
 is active.
 
-(fn &optional TODO-ONLY STRING EDIT-AT)" t nil)
+(fn &optional TODO-ONLY STRING EDIT-AT)" t)
 (autoload 'org-todo-list "org-agenda" "\
 Show all (not done) TODO entries from all agenda files in a single list.
 The prefix arg can be used to select a specific TODO keyword and limit
@@ -22067,19 +22203,19 @@ the list to these.  When using 
`\\[universal-argument]', you will be prompted
 for a keyword.  A numeric prefix directly selects the Nth keyword in
 `org-todo-keywords-1'.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'org-tags-view "org-agenda" "\
 Show all headlines for all `org-agenda-files' matching a TAGS criterion.
 The prefix arg TODO-ONLY limits the search to TODO entries.
 
-(fn &optional TODO-ONLY MATCH)" t nil)
+(fn &optional TODO-ONLY MATCH)" t)
 (autoload 'org-agenda-list-stuck-projects "org-agenda" "\
 Create agenda view for projects that are stuck.
 Stuck projects are project that have no next actions.  For the definitions
 of what a project is and how to check if it stuck, customize the variable
 `org-stuck-projects'.
 
-(fn &rest IGNORE)" t nil)
+(fn &rest IGNORE)" t)
 (autoload 'org-diary "org-agenda" "\
 Return diary information from org files.
 This function can be used in a \"sexp\" diary entry in the Emacs calendar.
@@ -22107,11 +22243,11 @@ The function expects the lisp variables `entry' and 
`date' to be provided
 by the caller, because this is how the calendar works.  Don't use this
 function from a program - use `org-agenda-get-day-entries' instead.
 
-(fn &rest ARGS)" nil nil)
+(fn &rest ARGS)")
 (autoload 'org-agenda-check-for-timestamp-as-reason-to-ignore-todo-item 
"org-agenda" "\
 Do we have a reason to ignore this TODO entry because it has a time stamp?
 
-(fn &optional END)" nil nil)
+(fn &optional END)")
 (autoload 'org-agenda-set-restriction-lock "org-agenda" "\
 Set restriction lock for agenda to current subtree or file.
 When in a restricted subtree, remove it.
@@ -22121,10 +22257,10 @@ or if type is \\='(4), or if the cursor is before the 
first headline
 in the file.  Otherwise, only apply the restriction to the current
 subtree.
 
-(fn &optional TYPE)" t nil)
+(fn &optional TYPE)" t)
 (autoload 'org-calendar-goto-agenda "org-agenda" "\
 Compute the Org agenda for the calendar date displayed at the cursor.
-This is a command that has to be installed in `calendar-mode-map'." t nil)
+This is a command that has to be installed in `calendar-mode-map'." t)
 (autoload 'org-agenda-to-appt "org-agenda" "\
 Activate appointments found in `org-agenda-files'.
 
@@ -22158,7 +22294,7 @@ details and examples.
 If an entry has a APPT_WARNTIME property, its value will be used
 to override `appt-message-warning-time'.
 
-(fn &optional REFRESH FILTER &rest ARGS)" t nil)
+(fn &optional REFRESH FILTER &rest ARGS)" t)
 (register-definition-prefixes "org-agenda" '("org-"))
 
 
@@ -22182,7 +22318,7 @@ to override `appt-message-warning-time'.
 (autoload 'org-capture-string "org-capture" "\
 Capture STRING with the template selected by KEYS.
 
-(fn STRING &optional KEYS)" t nil)
+(fn STRING &optional KEYS)" t)
 (autoload 'org-capture "org-capture" "\
 Capture something.
 \\<org-capture-mode-map>
@@ -22212,9 +22348,9 @@ agenda will use the date at point as the default date.  
Then, a
 `C-1' prefix will tell the capture process to use the HH:MM time
 of the day at point (if any) or the current HH:MM time.
 
-(fn &optional GOTO KEYS)" t nil)
+(fn &optional GOTO KEYS)" t)
 (autoload 'org-capture-import-remember-templates "org-capture" "\
-Set `org-capture-templates' to be similar to `org-remember-templates'." t nil)
+Set `org-capture-templates' to be similar to `org-remember-templates'." t)
 (register-definition-prefixes "org-capture" '("org-capture-"))
 
 
@@ -22236,15 +22372,15 @@ Set `org-capture-templates' to be similar to 
`org-remember-templates'." t nil)
 ;;; Generated autoloads from org/org-crypt.el
 
 (autoload 'org-encrypt-entry "org-crypt" "\
-Encrypt the content of the current headline." t nil)
+Encrypt the content of the current headline." t)
 (autoload 'org-decrypt-entry "org-crypt" "\
-Decrypt the content of the current headline." t nil)
+Decrypt the content of the current headline." t)
 (autoload 'org-encrypt-entries "org-crypt" "\
-Encrypt all top-level entries in the current buffer." t nil)
+Encrypt all top-level entries in the current buffer." t)
 (autoload 'org-decrypt-entries "org-crypt" "\
-Decrypt all entries in the current buffer." t nil)
+Decrypt all entries in the current buffer." t)
 (autoload 'org-crypt-use-before-save-magic "org-crypt" "\
-Add a hook to automatically encrypt entries before a file is saved to disk." 
nil nil)
+Add a hook to automatically encrypt entries before a file is saved to disk.")
 (register-definition-prefixes "org-crypt" '("org-"))
 
 
@@ -22397,10 +22533,10 @@ Add a hook to automatically encrypt entries before a 
file is saved to disk." nil
 
 (autoload 'org-release "org-version" "\
 The release version of Org.
-Inserted by installing Org mode or when a release is made." nil nil)
+Inserted by installing Org mode or when a release is made.")
 (autoload 'org-git-version "org-version" "\
 The Git version of Org mode.
-Inserted by installing Org or when a release is made." nil nil)
+Inserted by installing Org or when a release is made.")
 
 
 ;;; Generated autoloads from outline.el
@@ -22431,7 +22567,7 @@ beginning of the line.  The longer the match, the 
deeper the level.
 Turning on outline mode calls the value of `text-mode-hook' and then of
 `outline-mode-hook', if they are non-nil.
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'outline-minor-mode "outline" "\
 Toggle Outline minor mode.
 
@@ -22451,7 +22587,7 @@ evaluate `outline-minor-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "outline" '("outline-"))
 
 
@@ -22512,7 +22648,7 @@ Export is done in a buffer named \"*Org KOMA-LETTER 
Export*\".  It
 will be displayed if `org-export-show-temporary-export-buffer' is
 non-nil.
 
-(fn &optional ASYNC SUBTREEP VISIBLE-ONLY BODY-ONLY EXT-PLIST)" t nil)
+(fn &optional ASYNC SUBTREEP VISIBLE-ONLY BODY-ONLY EXT-PLIST)" t)
 (autoload 'org-koma-letter-export-to-latex "ox-koma-letter" "\
 Export current buffer as a KOMA Scrlttr2 letter (tex).
 
@@ -22544,7 +22680,7 @@ directory.
 
 Return output file's name.
 
-(fn &optional ASYNC SUBTREEP VISIBLE-ONLY BODY-ONLY EXT-PLIST)" t nil)
+(fn &optional ASYNC SUBTREEP VISIBLE-ONLY BODY-ONLY EXT-PLIST)" t)
 (autoload 'org-koma-letter-export-to-pdf "ox-koma-letter" "\
 Export current buffer as a KOMA Scrlttr2 letter (pdf).
 
@@ -22573,7 +22709,7 @@ file-local settings.
 
 Return PDF file's name.
 
-(fn &optional ASYNC SUBTREEP VISIBLE-ONLY BODY-ONLY EXT-PLIST)" t nil)
+(fn &optional ASYNC SUBTREEP VISIBLE-ONLY BODY-ONLY EXT-PLIST)" t)
 (register-definition-prefixes "ox-koma-letter" '("org-koma-letter-"))
 
 
@@ -22632,15 +22768,17 @@ call (package-activate-all) in your init-file.")
 Directory containing the user's Emacs Lisp packages.
 The directory name should be absolute.
 Apart from this directory, Emacs also looks for system-wide
-packages in `package-directory-list'." :type 'directory :initialize 
#'custom-initialize-delay :risky t :version "24.1")
+packages in `package-directory-list'." :type 'directory :initialize 
#'custom-initialize-delay :risky t :group 'applications :version "24.1")
 (custom-autoload 'package-user-dir "package" t)
 (defcustom package-directory-list (let (result) (dolist (f load-path) (and 
(stringp f) (equal (file-name-nondirectory f) "site-lisp") (push 
(expand-file-name "elpa" f) result))) (nreverse result)) "\
 List of additional directories containing Emacs Lisp packages.
 Each directory name should be absolute.
 
 These directories contain packages intended for system-wide; in
-contrast, `package-user-dir' contains packages for personal use." :type 
'(repeat directory) :initialize #'custom-initialize-delay :risky t :version 
"24.1")
+contrast, `package-user-dir' contains packages for personal use." :type 
'(repeat directory) :initialize #'custom-initialize-delay :group 'applications 
:risky t :version "24.1")
 (custom-autoload 'package-directory-list "package" t)
+(defvar package-activated-list nil "\
+List of the names of currently activated packages.")
 (defvar package--activated nil "\
 Non-nil if `package-activate-all' has been run.")
 (autoload 'package-initialize "package" "\
@@ -22659,14 +22797,15 @@ superfluous call to `package-initialize' from your 
init-file.  If
 you have code which must run before `package-initialize', put
 that code in the early init-file.
 
-(fn &optional NO-ACTIVATE)" t nil)
+(fn &optional NO-ACTIVATE)" t)
 (defun package-activate-all nil "\
 Activate all installed packages.
 The variable `package-load-list' controls which packages to load." (setq 
package--activated t) (let* ((elc (concat package-quickstart-file "c")) (qs (if 
(file-readable-p elc) elc (if (file-readable-p package-quickstart-file) 
package-quickstart-file)))) (if (and qs (not (bound-and-true-p 
package-activated-list))) (let ((load-source-file-function nil)) (unless 
(boundp 'package-activated-list) (setq package-activated-list nil)) (load qs 
nil 'nomessage)) (require 'package) (package--activate [...]
+(autoload 'package--activate-all "package")
 (autoload 'package-import-keyring "package" "\
 Import keys from FILE.
 
-(fn &optional FILE)" t nil)
+(fn &optional FILE)" t)
 (autoload 'package-refresh-contents "package" "\
 Download descriptions of all configured ELPA packages.
 For each archive configured in the variable `package-archives',
@@ -22675,7 +22814,7 @@ and make them available for download.
 Optional argument ASYNC specifies whether to perform the
 downloads in the background.
 
-(fn &optional ASYNC)" t nil)
+(fn &optional ASYNC)" t)
 (autoload 'package-installed-p "package" "\
 Return non-nil if PACKAGE, of MIN-VERSION or newer, is installed.
 If PACKAGE is a symbol, it is the package name and MIN-VERSION
@@ -22683,7 +22822,7 @@ should be a version list.
 
 If PACKAGE is a `package-desc' object, MIN-VERSION is ignored.
 
-(fn PACKAGE &optional MIN-VERSION)" nil nil)
+(fn PACKAGE &optional MIN-VERSION)")
 (autoload 'package-install "package" "\
 Install the package PKG.
 PKG can be a `package-desc' or a symbol naming one of the
@@ -22700,17 +22839,17 @@ non-nil, install the package but do not add it to
 If PKG is a `package-desc' and it is already installed, don't try
 to install it but still mark it as selected.
 
-(fn PKG &optional DONT-SELECT)" t nil)
+(fn PKG &optional DONT-SELECT)" t)
 (autoload 'package-update "package" "\
 Update package NAME if a newer version exists.
 
-(fn NAME)" t nil)
+(fn NAME)" t)
 (autoload 'package-update-all "package" "\
 Refresh package list and upgrade all packages.
 If QUERY, ask the user before updating packages.  When called
 interactively, QUERY is always true.
 
-(fn &optional QUERY)" t nil)
+(fn &optional QUERY)" t)
 (autoload 'package-install-from-buffer "package" "\
 Install a package from the current buffer.
 The current buffer is assumed to be a single .el or .tar file or
@@ -22721,36 +22860,46 @@ Specially, if current buffer is a directory, the 
-pkg.el
 description file is not mandatory, in which case the information
 is derived from the main .el file in the directory.
 
-Downloads and installs required packages as needed." t nil)
+Downloads and installs required packages as needed." t)
 (autoload 'package-install-file "package" "\
 Install a package from FILE.
 The file can either be a tar file, an Emacs Lisp file, or a
 directory.
 
-(fn FILE)" t nil)
+(fn FILE)" t)
 (autoload 'package-install-selected-packages "package" "\
 Ensure packages in `package-selected-packages' are installed.
 If some packages are not installed, propose to install them.
 If optional argument NOCONFIRM is non-nil, don't ask for
 confirmation to install packages.
 
-(fn &optional NOCONFIRM)" t nil)
+(fn &optional NOCONFIRM)" t)
 (autoload 'package-reinstall "package" "\
 Reinstall package PKG.
 PKG should be either a symbol, the package name, or a `package-desc'
 object.
 
-(fn PKG)" t nil)
+(fn PKG)" t)
+(autoload 'package-recompile "package" "\
+Byte-compile package PKG again.
+PKG should be either a symbol, the package name, or a `package-desc'
+object.
+
+(fn PKG)" t)
+(autoload 'package-recompile-all "package" "\
+Byte-compile all installed packages.
+This is meant to be used only in the case the byte-compiled files
+are invalid due to changed byte-code, macros or the like." t)
 (autoload 'package-autoremove "package" "\
 Remove packages that are no longer needed.
 
 Packages that are no more needed by other packages in
 `package-selected-packages' and their dependencies
-will be deleted." t nil)
+will be deleted." t)
 (autoload 'describe-package "package" "\
 Display the full documentation of PACKAGE (a symbol).
 
-(fn PACKAGE)" t nil)
+(fn PACKAGE)" t)
 (autoload 'list-packages "package" "\
 Display a list of packages.
 This first fetches the updated list of packages before
@@ -22759,7 +22908,7 @@ The list is displayed in a buffer named `*Packages*', 
and
 includes the package's version, availability status, and a
 short description.
 
-(fn &optional NO-FETCH)" t nil)
+(fn &optional NO-FETCH)" t)
 (defalias 'package-list-packages 'list-packages)
 (autoload 'package-get-version "package" "\
 Return the version number of the package in which this is used.
@@ -22767,10 +22916,10 @@ Assumes it is used from an Elisp file placed inside 
the top-level directory
 of an installed ELPA package.
 The return value is a string (or nil in case we can't find it).
 It works in more cases if the call is in the file which contains
-the `Version:' header." nil nil)
+the `Version:' header.")
 (function-put 'package-get-version 'pure 't)
 (defcustom package-quickstart-file (locate-user-emacs-file 
"package-quickstart.el") "\
-Location of the file used to speed up activation of packages at startup." 
:type 'file :initialize #'custom-initialize-delay :version "27.1")
+Location of the file used to speed up activation of packages at startup." 
:type 'file :group 'applications :initialize #'custom-initialize-delay :version 
"27.1")
 (custom-autoload 'package-quickstart-file "package" t)
 (register-definition-prefixes "package" '("bad-signature" "define-package" 
"describe-package-1" "package-"))
 
@@ -22790,7 +22939,7 @@ is created.  The directory need not have any initial 
contents
 (i.e., you can use this command to populate an initially empty
 archive).
 
-(fn FILE)" t nil)
+(fn FILE)" t)
 (register-definition-prefixes "package-x" '("package-"))
 
 
@@ -22813,7 +22962,7 @@ The values returned are identical to those of 
`decode-time', but
 any unknown values other than DST are returned as nil, and an
 unknown DST value is returned as -1.
 
-(fn STRING)" nil nil)
+(fn STRING)")
 (register-definition-prefixes "parse-time" '("parse-"))
 
 
@@ -22861,7 +23010,7 @@ Variables controlling indentation/edit style:
 See also the user variables `pascal-type-keywords', `pascal-start-keywords' and
 `pascal-separator-keywords'.
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "pascal" '("electric-pascal-" "pascal-"))
 
 
@@ -22877,7 +23026,7 @@ Whether passwords are cached at all is controlled by 
`password-cache'.")
 (autoload 'password-in-cache-p "password-cache" "\
 Check if KEY is in the cache.
 
-(fn KEY)" nil nil)
+(fn KEY)")
 (register-definition-prefixes "password-cache" '("password-"))
 
 
@@ -22924,9 +23073,9 @@ See Info node `(elisp) Pattern-Matching Conditional' in 
the
 Emacs Lisp manual for more information and examples.
 
 (fn EXP &rest CASES)" nil t)
-(function-put 'pcase 'lisp-indent-function '1)
+(function-put 'pcase 'lisp-indent-function 1)
 (put 'pcase 'function-documentation '(pcase--make-docstring))
-(autoload 'pcase--make-docstring "pcase" nil nil nil)
+(autoload 'pcase--make-docstring "pcase")
 (autoload 'pcase-exhaustive "pcase" "\
 The exhaustive version of `pcase' (which see).
 If EXP fails to match any of the patterns in CASES, an error is
@@ -22936,7 +23085,7 @@ In contrast, `pcase' will return nil if there is no 
match, but
 not signal an error.
 
 (fn EXP &rest CASES)" nil t)
-(function-put 'pcase-exhaustive 'lisp-indent-function '1)
+(function-put 'pcase-exhaustive 'lisp-indent-function 1)
 (autoload 'pcase-lambda "pcase" "\
 Like `lambda' but allow each argument to be a pattern.
 I.e. accepts the usual &optional and &rest keywords, but every
@@ -22944,7 +23093,7 @@ formal argument can be any pattern accepted by `pcase' 
(a mere
 variable name being but a special case of it).
 
 (fn LAMBDA-LIST &rest BODY)" nil t)
-(function-put 'pcase-lambda 'doc-string-elt '2)
+(function-put 'pcase-lambda 'doc-string-elt 2)
 (function-put 'pcase-lambda 'lisp-indent-function 'defun)
 (autoload 'pcase-let* "pcase" "\
 Like `let*', but supports destructuring BINDINGS using `pcase' patterns.
@@ -22957,7 +23106,7 @@ respective PATTERN; a mismatch may signal an error or 
may go
 undetected, binding variables to arbitrary values, such as nil.
 
 (fn BINDINGS &rest BODY)" nil t)
-(function-put 'pcase-let* 'lisp-indent-function '1)
+(function-put 'pcase-let* 'lisp-indent-function 1)
 (autoload 'pcase-let "pcase" "\
 Like `let', but supports destructuring BINDINGS using `pcase' patterns.
 BODY should be a list of expressions, and BINDINGS should be a list of
@@ -22971,7 +23120,7 @@ respective PATTERN; a mismatch may signal an error or 
may go
 undetected, binding variables to arbitrary values, such as nil.
 
 (fn BINDINGS &rest BODY)" nil t)
-(function-put 'pcase-let 'lisp-indent-function '1)
+(function-put 'pcase-let 'lisp-indent-function 1)
 (autoload 'pcase-dolist "pcase" "\
 Eval BODY once for each set of bindings defined by PATTERN and LIST elements.
 PATTERN should be a `pcase' pattern describing the structure of
@@ -22984,7 +23133,7 @@ destructuring bindings of variables in PATTERN to the 
subfields
 of the elements of LIST is performed as if by `pcase-let'.
 
 (fn (PATTERN LIST) BODY...)" nil t)
-(function-put 'pcase-dolist 'lisp-indent-function '1)
+(function-put 'pcase-dolist 'lisp-indent-function 1)
 (autoload 'pcase-setq "pcase" "\
 Assign values to variables by destructuring with `pcase'.
 PATTERNS are normal `pcase' patterns, and VALUES are expression.
@@ -23006,30 +23155,30 @@ By convention, DOC should use \"EXPVAL\" to stand
 for the result of evaluating EXP (first arg to `pcase').
 
 (fn NAME ARGS [DOC] &rest BODY...)" nil t)
-(function-put 'pcase-defmacro 'lisp-indent-function '2)
-(function-put 'pcase-defmacro 'doc-string-elt '3)
+(function-put 'pcase-defmacro 'lisp-indent-function 2)
+(function-put 'pcase-defmacro 'doc-string-elt 3)
 (register-definition-prefixes "pcase" '("pcase-"))
 
 
 ;;; Generated autoloads from pcmpl-cvs.el
 
 (autoload 'pcomplete/cvs "pcmpl-cvs" "\
-Completion rules for the `cvs' command." nil nil)
+Completion rules for the `cvs' command.")
 (register-definition-prefixes "pcmpl-cvs" '("pcmpl-cvs-"))
 
 
 ;;; Generated autoloads from pcmpl-gnu.el
 
 (autoload 'pcomplete/gzip "pcmpl-gnu" "\
-Completion for `gzip'." nil nil)
+Completion for `gzip'.")
 (autoload 'pcomplete/bzip2 "pcmpl-gnu" "\
-Completion for `bzip2'." nil nil)
+Completion for `bzip2'.")
 (autoload 'pcomplete/make "pcmpl-gnu" "\
-Completion for GNU `make'." nil nil)
+Completion for GNU `make'.")
 (autoload 'pcomplete/tar "pcmpl-gnu" "\
-Completion for the GNU tar utility." nil nil)
+Completion for the GNU tar utility.")
 (autoload 'pcomplete/find "pcmpl-gnu" "\
-Completion for the GNU find utility." nil nil)
+Completion for the GNU find utility.")
 (defalias 'pcomplete/gdb 'pcomplete/xargs)
 (register-definition-prefixes "pcmpl-gnu" '("pcmpl-gnu-" "pcomplete/find"))
 
@@ -23037,63 +23186,62 @@ Completion for the GNU find utility." nil nil)
 ;;; Generated autoloads from pcmpl-linux.el
 
 (autoload 'pcomplete/kill "pcmpl-linux" "\
-Completion for GNU/Linux `kill', using /proc filesystem." nil nil)
+Completion for GNU/Linux `kill', using /proc filesystem.")
 (autoload 'pcomplete/umount "pcmpl-linux" "\
-Completion for GNU/Linux `umount'." nil nil)
+Completion for GNU/Linux `umount'.")
 (autoload 'pcomplete/mount "pcmpl-linux" "\
-Completion for GNU/Linux `mount'." nil nil)
+Completion for GNU/Linux `mount'.")
 (register-definition-prefixes "pcmpl-linux" '("pcmpl-linux-" 
"pcomplete-pare-list"))
 
 
 ;;; Generated autoloads from pcmpl-rpm.el
 
 (autoload 'pcomplete/rpm "pcmpl-rpm" "\
-Completion for the `rpm' command." nil nil)
+Completion for the `rpm' command.")
 (register-definition-prefixes "pcmpl-rpm" '("pcmpl-rpm-"))
 
 
 ;;; Generated autoloads from pcmpl-unix.el
 
 (autoload 'pcomplete/cd "pcmpl-unix" "\
-Completion for `cd'." nil nil)
+Completion for `cd'.")
 (defalias 'pcomplete/pushd 'pcomplete/cd)
 (autoload 'pcomplete/rmdir "pcmpl-unix" "\
-Completion for `rmdir'." nil nil)
+Completion for `rmdir'.")
 (autoload 'pcomplete/rm "pcmpl-unix" "\
-Completion for `rm'." nil nil)
+Completion for `rm'.")
 (autoload 'pcomplete/xargs "pcmpl-unix" "\
-Completion for `xargs'." nil nil)
+Completion for `xargs'.")
 (defalias 'pcomplete/time 'pcomplete/xargs)
 (autoload 'pcomplete/which "pcmpl-unix" "\
-Completion for `which'." nil nil)
+Completion for `which'.")
 (autoload 'pcomplete/chown "pcmpl-unix" "\
-Completion for the `chown' command." nil nil)
+Completion for the `chown' command.")
 (autoload 'pcomplete/chgrp "pcmpl-unix" "\
-Completion for the `chgrp' command." nil nil)
+Completion for the `chgrp' command.")
 (autoload 'pcomplete/ssh "pcmpl-unix" "\
-Completion rules for the `ssh' command." nil nil)
+Completion rules for the `ssh' command.")
+(defalias 'pcomplete/rsh #'pcomplete/ssh)
 (autoload 'pcomplete/scp "pcmpl-unix" "\
 Completion rules for the `scp' command.
-Includes files as well as host names followed by a colon." nil nil)
-(autoload 'pcomplete/telnet "pcmpl-unix" nil nil nil)
-(autoload 'pcomplete/rsh "pcmpl-unix" "\
-Complete `rsh', which, after the user and hostname, is like xargs." nil nil)
+Includes files as well as host names followed by a colon.")
+(autoload 'pcomplete/telnet "pcmpl-unix")
 (register-definition-prefixes "pcmpl-unix" '("pcmpl-" "pcomplete/"))
 
 
 ;;; Generated autoloads from pcmpl-x.el
 
 (autoload 'pcomplete/tlmgr "pcmpl-x" "\
-Completion for the `tlmgr' command." nil nil)
+Completion for the `tlmgr' command.")
 (autoload 'pcomplete/ack "pcmpl-x" "\
 Completion for the `ack' command.
 Start an argument with `-' to complete short options and `--' for
-long options." nil nil)
+long options.")
 (defalias 'pcomplete/ack-grep 'pcomplete/ack)
 (autoload 'pcomplete/ag "pcmpl-x" "\
-Completion for the `ag' command." nil nil)
+Completion for the `ag' command.")
 (autoload 'pcomplete/bcc32 "pcmpl-x" "\
-Completion function for Borland's C++ compiler." nil nil)
+Completion function for Borland's C++ compiler.")
 (defalias 'pcomplete/bcc 'pcomplete/bcc32)
 (register-definition-prefixes "pcmpl-x" '("pcmpl-x-"))
 
@@ -23105,32 +23253,32 @@ Support extensible programmable completion.
 To use this function, just bind the TAB key to it, or add it to your
 completion functions list (it should occur fairly early in the list).
 
-(fn &optional INTERACTIVELY)" t nil)
-(make-obsolete 'pcomplete '"use completion-at-point and 
pcomplete-completions-at-point" '"27.1")
+(fn &optional INTERACTIVELY)" t)
+(make-obsolete 'pcomplete '"use completion-at-point and 
pcomplete-completions-at-point" "27.1")
 (autoload 'pcomplete-reverse "pcomplete" "\
-If cycling completion is in use, cycle backwards." t nil)
+If cycling completion is in use, cycle backwards." t)
 (autoload 'pcomplete-expand-and-complete "pcomplete" "\
 Expand the textual value of the current argument.
-This will modify the current buffer." t nil)
+This will modify the current buffer." t)
 (autoload 'pcomplete-continue "pcomplete" "\
-Complete without reference to any cycling completions." t nil)
+Complete without reference to any cycling completions." t)
 (autoload 'pcomplete-expand "pcomplete" "\
 Expand the textual value of the current argument.
-This will modify the current buffer." t nil)
+This will modify the current buffer." t)
 (autoload 'pcomplete-help "pcomplete" "\
-Display any help information relative to the current argument." t nil)
-(make-obsolete 'pcomplete-help '"use completion-help-at-point and 
pcomplete-completions-at-point" '"27.1")
+Display any help information relative to the current argument." t)
+(make-obsolete 'pcomplete-help '"use completion-help-at-point and 
pcomplete-completions-at-point" "27.1")
 (autoload 'pcomplete-list "pcomplete" "\
-Show the list of possible completions for the current argument." t nil)
+Show the list of possible completions for the current argument." t)
 (autoload 'pcomplete-comint-setup "pcomplete" "\
 Setup a comint buffer to use pcomplete.
 COMPLETEF-SYM should be the symbol where the
 dynamic-complete-functions are kept.  For comint mode itself,
 this is `comint-dynamic-complete-functions'.
 
-(fn COMPLETEF-SYM)" nil nil)
+(fn COMPLETEF-SYM)")
 (autoload 'pcomplete-shell-setup "pcomplete" "\
-Setup `shell-mode' to use pcomplete." nil nil)
+Setup `shell-mode' to use pcomplete.")
 (register-definition-prefixes "pcomplete" '("pcomplete-"))
 
 
@@ -23148,7 +23296,7 @@ and run `cvs-mode' on it.
 
 With a prefix argument, prompt for cvs FLAGS to use.
 
-(fn MODULES DIR FLAGS &optional ROOT)" t nil)
+(fn MODULES DIR FLAGS &optional ROOT)" t)
 (autoload 'cvs-quickdir "pcvs" "\
 Open a *cvs* buffer on DIR without running cvs.
 With a prefix argument, prompt for a directory to use.
@@ -23157,7 +23305,7 @@ A prefix arg >8 (ex: \\[universal-argument] 
\\[universal-argument]),
 Optional argument NOSHOW if non-nil means not to display the buffer.
 FLAGS is ignored.
 
-(fn DIR &optional FLAGS NOSHOW)" t nil)
+(fn DIR &optional FLAGS NOSHOW)" t)
 (autoload 'cvs-examine "pcvs" "\
 Run a `cvs -n update' in the specified DIRECTORY.
 That is, check what needs to be done, but don't change the disc.
@@ -23167,7 +23315,7 @@ A prefix arg >8 (ex: \\[universal-argument] 
\\[universal-argument]),
   prevents reuse of an existing *cvs* buffer.
 Optional argument NOSHOW if non-nil means not to display the buffer.
 
-(fn DIRECTORY FLAGS &optional NOSHOW)" t nil)
+(fn DIRECTORY FLAGS &optional NOSHOW)" t)
 (autoload 'cvs-update "pcvs" "\
 Run a `cvs update' in the current working DIRECTORY.
 Feed the output to a *cvs* buffer and run `cvs-mode' on it.
@@ -23177,7 +23325,7 @@ A prefix arg >8 (ex: \\[universal-argument] 
\\[universal-argument]),
 The prefix is also passed to `cvs-flags-query' to select the FLAGS
   passed to cvs.
 
-(fn DIRECTORY FLAGS)" t nil)
+(fn DIRECTORY FLAGS)" t)
 (autoload 'cvs-status "pcvs" "\
 Run a `cvs status' in the current working DIRECTORY.
 Feed the output to a *cvs* buffer and run `cvs-mode' on it.
@@ -23186,7 +23334,7 @@ A prefix arg >8 (ex: \\[universal-argument] 
\\[universal-argument]),
   prevents reuse of an existing *cvs* buffer.
 Optional argument NOSHOW if non-nil means not to display the buffer.
 
-(fn DIRECTORY FLAGS &optional NOSHOW)" t nil)
+(fn DIRECTORY FLAGS &optional NOSHOW)" t)
 (defvar cvs-dired-action 'cvs-quickdir "\
 The action to be performed when opening a CVS directory.
 Sensible values are `cvs-examine', `cvs-status' and `cvs-quickdir'.")
@@ -23240,7 +23388,7 @@ Launch `perl-flymake-command' (which see) and pass to 
its
 standard input the contents of the current buffer.  The output of
 this command is analyzed for error and warning messages.
 
-(fn REPORT-FN &rest ARGS)" nil nil)
+(fn REPORT-FN &rest ARGS)")
 (autoload 'perl-mode "perl-mode" "\
 Major mode for editing Perl code.
 Expression and list commands understand all Perl brackets.
@@ -23289,8 +23437,13 @@ Various indentation styles:       K&R  BSD  BLK  GNU  
LW
 
 Turning on Perl mode runs the normal hook `perl-mode-hook'.
 
-(fn)" t nil)
-(register-definition-prefixes "perl-mode" '("indent-perl-exp" 
"mark-perl-function" "perl-"))
+(fn)" t)
+(register-definition-prefixes "perl-mode" '("perl-"))
+
+
+;;; Generated autoloads from pgtk-dnd.el
+
+(register-definition-prefixes "pgtk-dnd" '("pgtk-dnd-"))
 
 
 ;;; Generated autoloads from textmodes/picture.el
@@ -23364,16 +23517,11 @@ by supplying an argument.
 Entry to this mode calls the value of `picture-mode-hook' if non-nil.
 
 Note that Picture mode commands will work outside of Picture mode, but
-they are not by default assigned to keys." t nil)
+they are not by default assigned to keys." t)
 (defalias 'edit-picture 'picture-mode)
 (register-definition-prefixes "picture" '("picture-"))
 
 
-;;; Generated autoloads from language/pinyin.el
-
-(register-definition-prefixes "pinyin" '("pinyin-character-map"))
-
-
 ;;; Generated autoloads from textmodes/pixel-fill.el
 
 (register-definition-prefixes "pixel-fill" '("pixel-fill-"))
@@ -23406,7 +23554,7 @@ evaluate `(default-value \\='pixel-scroll-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (defvar pixel-scroll-precision-mode nil "\
 Non-nil if Pixel-Scroll-Precision mode is enabled.
 See the `pixel-scroll-precision-mode' command
@@ -23436,20 +23584,21 @@ evaluate `(default-value 
\\='pixel-scroll-precision-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "pixel-scroll" '("pixel-"))
 
 
 ;;; Generated autoloads from plstore.el
 
+(put 'plstore-encrypt-to 'safe-local-variable (lambda (val) (or (stringp val) 
(and (listp val) (catch 'safe (mapc (lambda (elt) (unless (stringp elt) (throw 
'safe nil))) val) t)))))
 (autoload 'plstore-open "plstore" "\
 Create a plstore instance associated with FILE.
 
-(fn FILE)" nil nil)
+(fn FILE)")
 (autoload 'plstore-mode "plstore" "\
 Major mode for editing PLSTORE files.
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "plstore" '("plstore-"))
 
 
@@ -23464,7 +23613,7 @@ Major mode for editing PLSTORE files.
 Return a (DECODING . ENCODING) pair, according to PO file's charset.
 Called through `file-coding-system-alist', before the file is visited for real.
 
-(fn ARG-LIST)" nil nil)
+(fn ARG-LIST)")
 (register-definition-prefixes "po" '("po-"))
 
 
@@ -23477,7 +23626,7 @@ Move left and right bats and try to bounce the ball to 
your opponent.
 
 pong-mode keybindings:\\<pong-mode-map>
 
-\\{pong-mode-map}" t nil)
+\\{pong-mode-map}" t)
 (register-definition-prefixes "pong" '("pong-"))
 
 
@@ -23487,7 +23636,7 @@ pong-mode keybindings:\\<pong-mode-map>
 Transfer contents of a maildrop to the specified FILE.
 Use streaming commands.
 
-(fn FILE)" nil nil)
+(fn FILE)")
 (register-definition-prefixes "pop3" '("pop3-"))
 
 
@@ -23498,9 +23647,9 @@ Return a string containing the pretty-printed 
representation of OBJECT.
 OBJECT can be any Lisp object.  Quoting characters are used as needed
 to make output that `read' can handle, whenever this is possible.
 
-(fn OBJECT)" nil nil)
+(fn OBJECT)")
 (autoload 'pp-buffer "pp" "\
-Prettify the current buffer with printed representation of a Lisp object." t 
nil)
+Prettify the current buffer with printed representation of a Lisp object." t)
 (autoload 'pp "pp" "\
 Output the pretty-printed representation of OBJECT, any Lisp object.
 Quoting characters are printed as needed to make output that `read'
@@ -23514,7 +23663,7 @@ and vectors.  Bind `pp-use-max-width' to a non-nil 
value to do so.
 
 Output stream is STREAM, or value of `standard-output' (which see).
 
-(fn OBJECT &optional STREAM)" nil nil)
+(fn OBJECT &optional STREAM)")
 (autoload 'pp-display-expression "pp" "\
 Prettify and display EXPRESSION in an appropriate way, depending on length.
 If LISP, format with `pp-emacs-lisp-code'; use `pp' otherwise.
@@ -23522,39 +23671,38 @@ If LISP, format with `pp-emacs-lisp-code'; use `pp' 
otherwise.
 If a temporary buffer is needed for representation, it will be named
 after OUT-BUFFER-NAME.
 
-(fn EXPRESSION OUT-BUFFER-NAME &optional LISP)" nil nil)
+(fn EXPRESSION OUT-BUFFER-NAME &optional LISP)")
 (autoload 'pp-eval-expression "pp" "\
 Evaluate EXPRESSION and pretty-print its value.
 Also add the value to the front of the list in the variable `values'.
 
-(fn EXPRESSION)" t nil)
+(fn EXPRESSION)" t)
 (autoload 'pp-macroexpand-expression "pp" "\
 Macroexpand EXPRESSION and pretty-print its value.
 
-(fn EXPRESSION)" t nil)
+(fn EXPRESSION)" t)
 (autoload 'pp-eval-last-sexp "pp" "\
 Run `pp-eval-expression' on sexp before point.
 With ARG, pretty-print output into current buffer.
 Ignores leading comment characters.
 
-(fn ARG)" t nil)
+(fn ARG)" t)
 (autoload 'pp-macroexpand-last-sexp "pp" "\
 Run `pp-macroexpand-expression' on sexp before point.
 With ARG, pretty-print output into current buffer.
 Ignores leading comment characters.
 
-(fn ARG)" t nil)
+(fn ARG)" t)
 (autoload 'pp-emacs-lisp-code "pp" "\
 Insert SEXP into the current buffer, formatted as Emacs Lisp code.
 Use the `pp-max-width' variable to control the desired line length.
 
-(fn SEXP)" nil nil)
+(fn SEXP)")
 (register-definition-prefixes "pp" '("pp-"))
 
 
 ;;; Generated autoloads from printing.el
 
-(push (purecopy '(printing 6 9 3)) package--builtin-versions)
 (autoload 'pr-interface "printing" "\
 Activate the printing interface buffer.
 
@@ -23562,7 +23710,7 @@ If BUFFER is nil, the current buffer is used for 
printing.
 
 For more information, type \\[pr-interface-help].
 
-(fn &optional BUFFER)" t nil)
+(fn &optional BUFFER)" t)
 (autoload 'pr-ps-directory-preview "printing" "\
 Preview directory using ghostview.
 
@@ -23580,7 +23728,7 @@ file name.
 
 See also documentation for `pr-list-directory'.
 
-(fn N-UP DIR FILE-REGEXP &optional FILENAME)" t nil)
+(fn N-UP DIR FILE-REGEXP &optional FILENAME)" t)
 (autoload 'pr-ps-directory-using-ghostscript "printing" "\
 Print directory using PostScript through ghostscript.
 
@@ -23598,7 +23746,7 @@ file name.
 
 See also documentation for `pr-list-directory'.
 
-(fn N-UP DIR FILE-REGEXP &optional FILENAME)" t nil)
+(fn N-UP DIR FILE-REGEXP &optional FILENAME)" t)
 (autoload 'pr-ps-directory-print "printing" "\
 Print directory using PostScript printer.
 
@@ -23616,7 +23764,7 @@ file name.
 
 See also documentation for `pr-list-directory'.
 
-(fn N-UP DIR FILE-REGEXP &optional FILENAME)" t nil)
+(fn N-UP DIR FILE-REGEXP &optional FILENAME)" t)
 (autoload 'pr-ps-directory-ps-print "printing" "\
 Print directory using PostScript printer or through ghostscript.
 
@@ -23636,7 +23784,7 @@ file name.
 
 See also documentation for `pr-list-directory'.
 
-(fn N-UP DIR FILE-REGEXP &optional FILENAME)" t nil)
+(fn N-UP DIR FILE-REGEXP &optional FILENAME)" t)
 (autoload 'pr-ps-buffer-preview "printing" "\
 Preview buffer using ghostview.
 
@@ -23649,7 +23797,7 @@ argument FILENAME is treated as follows: if it's nil, 
save the image in a
 temporary file.  If FILENAME is a string, save the PostScript image in a file
 with that name.  If FILENAME is t, prompts for a file name.
 
-(fn N-UP &optional FILENAME)" t nil)
+(fn N-UP &optional FILENAME)" t)
 (autoload 'pr-ps-buffer-using-ghostscript "printing" "\
 Print buffer using PostScript through ghostscript.
 
@@ -23662,7 +23810,7 @@ argument FILENAME is treated as follows: if it's nil, 
send the image to the
 printer.  If FILENAME is a string, save the PostScript image in a file with
 that name.  If FILENAME is t, prompts for a file name.
 
-(fn N-UP &optional FILENAME)" t nil)
+(fn N-UP &optional FILENAME)" t)
 (autoload 'pr-ps-buffer-print "printing" "\
 Print buffer using PostScript printer.
 
@@ -23675,7 +23823,7 @@ argument FILENAME is treated as follows: if it's nil, 
send the image to the
 printer.  If FILENAME is a string, save the PostScript image in a file with
 that name.  If FILENAME is t, prompts for a file name.
 
-(fn N-UP &optional FILENAME)" t nil)
+(fn N-UP &optional FILENAME)" t)
 (autoload 'pr-ps-buffer-ps-print "printing" "\
 Print buffer using PostScript printer or through ghostscript.
 
@@ -23690,55 +23838,55 @@ argument FILENAME is treated as follows: if it's nil, 
send the image to the
 printer.  If FILENAME is a string, save the PostScript image in a file with
 that name.  If FILENAME is t, prompts for a file name.
 
-(fn N-UP &optional FILENAME)" t nil)
+(fn N-UP &optional FILENAME)" t)
 (autoload 'pr-ps-region-preview "printing" "\
 Preview region using ghostview.
 
 See also `pr-ps-buffer-preview'.
 
-(fn N-UP &optional FILENAME)" t nil)
+(fn N-UP &optional FILENAME)" t)
 (autoload 'pr-ps-region-using-ghostscript "printing" "\
 Print region using PostScript through ghostscript.
 
 See also `pr-ps-buffer-using-ghostscript'.
 
-(fn N-UP &optional FILENAME)" t nil)
+(fn N-UP &optional FILENAME)" t)
 (autoload 'pr-ps-region-print "printing" "\
 Print region using PostScript printer.
 
 See also `pr-ps-buffer-print'.
 
-(fn N-UP &optional FILENAME)" t nil)
+(fn N-UP &optional FILENAME)" t)
 (autoload 'pr-ps-region-ps-print "printing" "\
 Print region using PostScript printer or through ghostscript.
 
 See also `pr-ps-buffer-ps-print'.
 
-(fn N-UP &optional FILENAME)" t nil)
+(fn N-UP &optional FILENAME)" t)
 (autoload 'pr-ps-mode-preview "printing" "\
 Preview major mode using ghostview.
 
 See also `pr-ps-buffer-preview'.
 
-(fn N-UP &optional FILENAME)" t nil)
+(fn N-UP &optional FILENAME)" t)
 (autoload 'pr-ps-mode-using-ghostscript "printing" "\
 Print major mode using PostScript through ghostscript.
 
 See also `pr-ps-buffer-using-ghostscript'.
 
-(fn N-UP &optional FILENAME)" t nil)
+(fn N-UP &optional FILENAME)" t)
 (autoload 'pr-ps-mode-print "printing" "\
 Print major mode using PostScript printer.
 
 See also `pr-ps-buffer-print'.
 
-(fn N-UP &optional FILENAME)" t nil)
+(fn N-UP &optional FILENAME)" t)
 (autoload 'pr-ps-mode-ps-print "printing" "\
 Print major mode using PostScript or through ghostscript.
 
 See also `pr-ps-buffer-ps-print'.
 
-(fn N-UP &optional FILENAME)" t nil)
+(fn N-UP &optional FILENAME)" t)
 (autoload 'pr-printify-directory "printing" "\
 Replace nonprinting characters in directory with printable representations.
 The printable representations use ^ (for ASCII control characters) or hex.
@@ -23752,15 +23900,15 @@ prompts for FILE(name)-REGEXP.
 
 See also documentation for `pr-list-directory'.
 
-(fn &optional DIR FILE-REGEXP)" t nil)
+(fn &optional DIR FILE-REGEXP)" t)
 (autoload 'pr-printify-buffer "printing" "\
 Replace nonprinting characters in buffer with printable representations.
 The printable representations use ^ (for ASCII control characters) or hex.
-The characters tab, linefeed, space, return and formfeed are not affected." t 
nil)
+The characters tab, linefeed, space, return and formfeed are not affected." t)
 (autoload 'pr-printify-region "printing" "\
 Replace nonprinting characters in region with printable representations.
 The printable representations use ^ (for ASCII control characters) or hex.
-The characters tab, linefeed, space, return and formfeed are not affected." t 
nil)
+The characters tab, linefeed, space, return and formfeed are not affected." t)
 (autoload 'pr-txt-directory "printing" "\
 Print directory using text printer.
 
@@ -23772,13 +23920,13 @@ prompts for FILE(name)-REGEXP.
 
 See also documentation for `pr-list-directory'.
 
-(fn &optional DIR FILE-REGEXP)" t nil)
+(fn &optional DIR FILE-REGEXP)" t)
 (autoload 'pr-txt-buffer "printing" "\
-Print buffer using text printer." t nil)
+Print buffer using text printer." t)
 (autoload 'pr-txt-region "printing" "\
-Print region using text printer." t nil)
+Print region using text printer." t)
 (autoload 'pr-txt-mode "printing" "\
-Print major mode using text printer." t nil)
+Print major mode using text printer." t)
 (autoload 'pr-despool-preview "printing" "\
 Preview spooled PostScript.
 
@@ -23790,7 +23938,7 @@ Noninteractively, the argument FILENAME is treated as 
follows: if it is nil,
 save the image in a temporary file.  If FILENAME is a string, save the
 PostScript image in a file with that name.
 
-(fn &optional FILENAME)" t nil)
+(fn &optional FILENAME)" t)
 (autoload 'pr-despool-using-ghostscript "printing" "\
 Print spooled PostScript using ghostscript.
 
@@ -23802,7 +23950,7 @@ Noninteractively, the argument FILENAME is treated as 
follows: if it is nil,
 send the image to the printer.  If FILENAME is a string, save the PostScript
 image in a file with that name.
 
-(fn &optional FILENAME)" t nil)
+(fn &optional FILENAME)" t)
 (autoload 'pr-despool-print "printing" "\
 Send the spooled PostScript to the printer.
 
@@ -23814,7 +23962,7 @@ Noninteractively, the argument FILENAME is treated as 
follows: if it is nil,
 send the image to the printer.  If FILENAME is a string, save the PostScript
 image in a file with that name.
 
-(fn &optional FILENAME)" t nil)
+(fn &optional FILENAME)" t)
 (autoload 'pr-despool-ps-print "printing" "\
 Send the spooled PostScript to the printer or use ghostscript to print it.
 
@@ -23826,27 +23974,27 @@ Noninteractively, the argument FILENAME is treated as 
follows: if it is nil,
 send the image to the printer.  If FILENAME is a string, save the PostScript
 image in a file with that name.
 
-(fn &optional FILENAME)" t nil)
+(fn &optional FILENAME)" t)
 (autoload 'pr-ps-file-preview "printing" "\
 Preview PostScript file FILENAME.
 
-(fn FILENAME)" t nil)
+(fn FILENAME)" t)
 (autoload 'pr-ps-file-up-preview "printing" "\
 Preview PostScript file FILENAME.
 
-(fn N-UP IFILENAME &optional OFILENAME)" t nil)
+(fn N-UP IFILENAME &optional OFILENAME)" t)
 (autoload 'pr-ps-file-using-ghostscript "printing" "\
 Print PostScript file FILENAME using ghostscript.
 
-(fn FILENAME)" t nil)
+(fn FILENAME)" t)
 (autoload 'pr-ps-file-print "printing" "\
 Print PostScript file FILENAME.
 
-(fn FILENAME)" t nil)
+(fn FILENAME)" t)
 (autoload 'pr-ps-file-ps-print "printing" "\
 Send PostScript file FILENAME to printer or use ghostscript to print it.
 
-(fn FILENAME)" t nil)
+(fn FILENAME)" t)
 (autoload 'pr-ps-file-up-ps-print "printing" "\
 Process a PostScript file IFILENAME and send it to printer.
 
@@ -23863,81 +24011,81 @@ nil, send the image to the printer.  If OFILENAME is 
a string, save the
 PostScript image in a file with that name.  If OFILENAME is t, prompts for a
 file name.
 
-(fn N-UP IFILENAME &optional OFILENAME)" t nil)
+(fn N-UP IFILENAME &optional OFILENAME)" t)
 (autoload 'pr-toggle-file-duplex "printing" "\
-Toggle duplex for PostScript file." t nil)
+Toggle duplex for PostScript file." t)
 (autoload 'pr-toggle-file-tumble "printing" "\
 Toggle tumble for PostScript file.
 
 If tumble is off, produces a printing suitable for binding on the left or
 right.
 If tumble is on, produces a printing suitable for binding at the top or
-bottom." t nil)
+bottom." t)
 (autoload 'pr-toggle-file-landscape "printing" "\
-Toggle landscape for PostScript file." t nil)
+Toggle landscape for PostScript file." t)
 (autoload 'pr-toggle-ghostscript "printing" "\
-Toggle printing using ghostscript." t nil)
+Toggle printing using ghostscript." t)
 (autoload 'pr-toggle-faces "printing" "\
-Toggle printing with faces." t nil)
+Toggle printing with faces." t)
 (autoload 'pr-toggle-spool "printing" "\
-Toggle spooling." t nil)
+Toggle spooling." t)
 (autoload 'pr-toggle-duplex "printing" "\
-Toggle duplex." t nil)
+Toggle duplex." t)
 (autoload 'pr-toggle-tumble "printing" "\
 Toggle tumble.
 
 If tumble is off, produces a printing suitable for binding on the left or
 right.
 If tumble is on, produces a printing suitable for binding at the top or
-bottom." t nil)
+bottom." t)
 (autoload 'pr-toggle-landscape "printing" "\
-Toggle landscape." t nil)
+Toggle landscape." t)
 (autoload 'pr-toggle-upside-down "printing" "\
-Toggle upside-down." t nil)
+Toggle upside-down." t)
 (autoload 'pr-toggle-line "printing" "\
-Toggle line number." t nil)
+Toggle line number." t)
 (autoload 'pr-toggle-zebra "printing" "\
-Toggle zebra stripes." t nil)
+Toggle zebra stripes." t)
 (autoload 'pr-toggle-header "printing" "\
-Toggle printing header." t nil)
+Toggle printing header." t)
 (autoload 'pr-toggle-header-frame "printing" "\
-Toggle printing header frame." t nil)
+Toggle printing header frame." t)
 (autoload 'pr-toggle-lock "printing" "\
-Toggle menu lock." t nil)
+Toggle menu lock." t)
 (autoload 'pr-toggle-region "printing" "\
-Toggle whether the region is automagically detected." t nil)
+Toggle whether the region is automagically detected." t)
 (autoload 'pr-toggle-mode "printing" "\
-Toggle auto mode." t nil)
+Toggle auto mode." t)
 (autoload 'pr-customize "printing" "\
 Customization of the `printing' group.
 
-(fn &rest IGNORE)" t nil)
+(fn &rest IGNORE)" t)
 (autoload 'lpr-customize "printing" "\
 Customization of the `lpr' group.
 
-(fn &rest IGNORE)" t nil)
+(fn &rest IGNORE)" t)
 (autoload 'pr-help "printing" "\
 Help for the printing package.
 
-(fn &rest IGNORE)" t nil)
+(fn &rest IGNORE)" t)
 (autoload 'pr-ps-name "printing" "\
-Interactively select a PostScript printer." t nil)
+Interactively select a PostScript printer." t)
 (autoload 'pr-txt-name "printing" "\
-Interactively select a text printer." t nil)
+Interactively select a text printer." t)
 (autoload 'pr-ps-utility "printing" "\
-Interactively select a PostScript utility." t nil)
+Interactively select a PostScript utility." t)
 (autoload 'pr-show-ps-setup "printing" "\
 Show current ps-print settings.
 
-(fn &rest IGNORE)" t nil)
+(fn &rest IGNORE)" t)
 (autoload 'pr-show-pr-setup "printing" "\
 Show current printing settings.
 
-(fn &rest IGNORE)" t nil)
+(fn &rest IGNORE)" t)
 (autoload 'pr-show-lpr-setup "printing" "\
 Show current lpr settings.
 
-(fn &rest IGNORE)" t nil)
+(fn &rest IGNORE)" t)
 (autoload 'pr-ps-fast-fire "printing" "\
 Fast fire function for PostScript printing.
 
@@ -23999,7 +24147,7 @@ zero and the argument SELECT is treated as follows:
 Note that this command always behaves as if `pr-auto-region' and `pr-auto-mode'
 are both set to t.
 
-(fn N-UP &optional SELECT)" t nil)
+(fn N-UP &optional SELECT)" t)
 (autoload 'pr-txt-fast-fire "printing" "\
 Fast fire function for text printing.
 
@@ -24024,7 +24172,7 @@ Noninteractively, the argument SELECT-PRINTER is 
treated as follows:
 Note that this command always behaves as if `pr-auto-region' and `pr-auto-mode'
 are both set to t.
 
-(fn &optional SELECT-PRINTER)" t nil)
+(fn &optional SELECT-PRINTER)" t)
 (register-definition-prefixes "printing" '("lpr-setup" "pr-"))
 
 
@@ -24045,7 +24193,7 @@ This function runs the normal hook 
`proced-post-display-hook'.
 See `proced-mode' for a description of features available in
 Proced buffers.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "proced" '("proced-"))
 
 
@@ -24061,19 +24209,19 @@ If MODE is `mem' or `cpu+mem', start profiler that 
samples CPU
    if SIGPROF is not supported, or is unreliable, or is not sampling
    at a high enough frequency.
 
-(fn MODE)" t nil)
+(fn MODE)" t)
 (autoload 'profiler-find-profile "profiler" "\
 Open profile FILENAME.
 
-(fn FILENAME)" t nil)
+(fn FILENAME)" t)
 (autoload 'profiler-find-profile-other-window "profiler" "\
 Open profile FILENAME.
 
-(fn FILENAME)" t nil)
+(fn FILENAME)" t)
 (autoload 'profiler-find-profile-other-frame "profiler" "\
 Open profile FILENAME.
 
-(fn FILENAME)" t nil)
+(fn FILENAME)" t)
 (register-definition-prefixes "profiler" '("profiler-"))
 
 
@@ -24152,7 +24300,7 @@ ignored (per `project-ignores').
 See the doc string of `project-find-functions' for the general form
 of the project instance object.
 
-(fn &optional MAYBE-PROMPT DIRECTORY)" nil nil)
+(fn &optional MAYBE-PROMPT DIRECTORY)")
 (defvar project-prefix-map (let ((map (make-sparse-keymap))) (define-key map 
"!" 'project-shell-command) (define-key map "&" 'project-async-shell-command) 
(define-key map "f" 'project-find-file) (define-key map "F" 
'project-or-external-find-file) (define-key map "b" 'project-switch-to-buffer) 
(define-key map "s" 'project-shell) (define-key map "d" 'project-find-dir) 
(define-key map "D" 'project-dired) (define-key map "v" 'project-vc-dir) 
(define-key map "c" 'project-compile) (define-key  [...]
 Keymap for project commands.")
  (define-key ctl-x-map "p" project-prefix-map)
@@ -24162,7 +24310,7 @@ Run project command, displaying resultant buffer in 
another window.
 The following commands are available:
 
 \\{project-prefix-map}
-\\{project-other-window-map}" t nil)
+\\{project-other-window-map}" t)
  (define-key ctl-x-4-map "p" #'project-other-window-command)
 (autoload 'project-other-frame-command "project" "\
 Run project command, displaying resultant buffer in another frame.
@@ -24170,14 +24318,14 @@ Run project command, displaying resultant buffer in 
another frame.
 The following commands are available:
 
 \\{project-prefix-map}
-\\{project-other-frame-map}" t nil)
+\\{project-other-frame-map}" t)
  (define-key ctl-x-5-map "p" #'project-other-frame-command)
 (autoload 'project-other-tab-command "project" "\
 Run project command, displaying resultant buffer in a new tab.
 
 The following commands are available:
 
-\\{project-prefix-map}" t nil)
+\\{project-prefix-map}" t)
 (when (bound-and-true-p tab-prefix-map) (define-key tab-prefix-map "p" 
#'project-other-tab-command))
 (autoload 'project-find-regexp "project" "\
 Find all matches for REGEXP in the current project's roots.
@@ -24188,13 +24336,13 @@ e.g. entering `ch' is equivalent to `*.[ch]'.  As 
whitespace
 triggers completion when entering a pattern, including it
 requires quoting, e.g. `\\[quoted-insert]<space>'.
 
-(fn REGEXP)" t nil)
+(fn REGEXP)" t)
 (autoload 'project-or-external-find-regexp "project" "\
 Find all matches for REGEXP in the project roots or external roots.
 With \\[universal-argument] prefix, you can specify the file name
 pattern to search for.
 
-(fn REGEXP)" t nil)
+(fn REGEXP)" t)
 (autoload 'project-find-file "project" "\
 Visit a file (with completion) in the current project.
 
@@ -24205,7 +24353,7 @@ If INCLUDE-ALL is non-nil, or with prefix argument when 
called
 interactively, include all files under the project root, except
 for VCS directories listed in `vc-directory-exclusion-list'.
 
-(fn &optional INCLUDE-ALL)" t nil)
+(fn &optional INCLUDE-ALL)" t)
 (autoload 'project-or-external-find-file "project" "\
 Visit a file (with completion) in the current project or external roots.
 
@@ -24216,30 +24364,30 @@ If INCLUDE-ALL is non-nil, or with prefix argument 
when called
 interactively, include all files under the project root, except
 for VCS directories listed in `vc-directory-exclusion-list'.
 
-(fn &optional INCLUDE-ALL)" t nil)
+(fn &optional INCLUDE-ALL)" t)
 (autoload 'project-find-dir "project" "\
-Start Dired in a directory inside the current project." t nil)
+Start Dired in a directory inside the current project." t)
 (autoload 'project-dired "project" "\
-Start Dired in the current project's root." t nil)
+Start Dired in the current project's root." t)
 (autoload 'project-vc-dir "project" "\
-Run VC-Dir in the current project's root." t nil)
+Run VC-Dir in the current project's root." t)
 (autoload 'project-shell "project" "\
 Start an inferior shell in the current project's root directory.
 If a buffer already exists for running a shell in the project's root,
 switch to it.  Otherwise, create a new shell buffer.
 With \\[universal-argument] prefix arg, create a new inferior shell buffer even
-if one already exists." t nil)
+if one already exists." t)
 (autoload 'project-eshell "project" "\
 Start Eshell in the current project's root directory.
 If a buffer already exists for running Eshell in the project's root,
 switch to it.  Otherwise, create a new Eshell buffer.
 With \\[universal-argument] prefix arg, create a new Eshell buffer even
-if one already exists." t nil)
+if one already exists." t)
 (autoload 'project-async-shell-command "project" "\
-Run `async-shell-command' in the current project's root directory." t nil)
+Run `async-shell-command' in the current project's root directory." t)
 (function-put 'project-async-shell-command 'interactive-only 
'async-shell-command)
 (autoload 'project-shell-command "project" "\
-Run `shell-command' in the current project's root directory." t nil)
+Run `shell-command' in the current project's root directory." t)
 (function-put 'project-shell-command 'interactive-only 'shell-command)
 (autoload 'project-search "project" "\
 Search for REGEXP in all the files of the project.
@@ -24247,7 +24395,7 @@ Stops when a match is found.
 To continue searching for the next match, use the
 command \\[fileloop-continue].
 
-(fn REGEXP)" t nil)
+(fn REGEXP)" t)
 (autoload 'project-query-replace-regexp "project" "\
 Query-replace REGEXP in all the files of the project.
 Stops when a match is found and prompts for whether to replace it.
@@ -24258,9 +24406,9 @@ type \\[help-command] at that time.
 If you exit the `query-replace', you can later continue the
 `query-replace' loop using the command \\[fileloop-continue].
 
-(fn FROM TO)" t nil)
+(fn FROM TO)" t)
 (autoload 'project-compile "project" "\
-Run `compile' in the project root." t nil)
+Run `compile' in the project root." t)
 (function-put 'project-compile 'interactive-only 'compile)
 (autoload 'project-switch-to-buffer "project" "\
 Display buffer BUFFER-OR-NAME in the selected window.
@@ -24269,7 +24417,7 @@ current project.  Two buffers belong to the same 
project if their
 project instances, as reported by `project-current' in each
 buffer, are identical.
 
-(fn BUFFER-OR-NAME)" t nil)
+(fn BUFFER-OR-NAME)" t)
 (autoload 'project-display-buffer "project" "\
 Display BUFFER-OR-NAME in some window, without selecting it.
 When called interactively, prompts for a buffer belonging to the
@@ -24280,7 +24428,7 @@ buffer, are identical.
 This function uses `display-buffer' as a subroutine, which see
 for how it is determined where the buffer will be displayed.
 
-(fn BUFFER-OR-NAME)" t nil)
+(fn BUFFER-OR-NAME)" t)
 (autoload 'project-display-buffer-other-frame "project" "\
 Display BUFFER-OR-NAME preferably in another frame.
 When called interactively, prompts for a buffer belonging to the
@@ -24292,7 +24440,7 @@ This function uses `display-buffer-other-frame' as a 
subroutine,
 which see for how it is determined where the buffer will be
 displayed.
 
-(fn BUFFER-OR-NAME)" t nil)
+(fn BUFFER-OR-NAME)" t)
 (autoload 'project-kill-buffers "project" "\
 Kill the buffers belonging to the current project.
 Two buffers belong to the same project if their project
@@ -24305,23 +24453,23 @@ interactively.
 
 Also see the `project-kill-buffers-display-buffer-list' variable.
 
-(fn &optional NO-CONFIRM)" t nil)
+(fn &optional NO-CONFIRM)" t)
 (autoload 'project-remember-project "project" "\
 Add project PR to the front of the project list.
 Save the result in `project-list-file' if the list of projects
 has changed, and NO-WRITE is nil.
 
-(fn PR &optional NO-WRITE)" nil nil)
+(fn PR &optional NO-WRITE)")
 (autoload 'project-forget-project "project" "\
 Remove directory PROJECT-ROOT from the project list.
 PROJECT-ROOT is the root directory of a known project listed in
 the project list.
 
-(fn PROJECT-ROOT)" t nil)
+(fn PROJECT-ROOT)" t)
 (autoload 'project-known-project-roots "project" "\
-Return the list of root directories of all known projects." nil nil)
+Return the list of root directories of all known projects.")
 (autoload 'project-execute-extended-command "project" "\
-Execute an extended command in project root." t nil)
+Execute an extended command in project root." t)
 (function-put 'project-execute-extended-command 'interactive-only 
'command-execute)
 (autoload 'project-switch-project "project" "\
 \"Switch\" to another project by running an Emacs command.
@@ -24331,7 +24479,7 @@ made from `project-switch-commands'.
 When called in a program, it will use the project corresponding
 to directory DIR.
 
-(fn DIR)" t nil)
+(fn DIR)" t)
 (register-definition-prefixes "project" '("project-"))
 
 
@@ -24356,17 +24504,17 @@ To find out what version of Prolog mode you are 
running, enter
 Commands:
 \\{prolog-mode-map}
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'mercury-mode "prolog" "\
 Major mode for editing Mercury programs.
 Actually this is just customized `prolog-mode'.
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'run-prolog "prolog" "\
 Run an inferior Prolog process, input and output via buffer *prolog*.
 With prefix argument ARG, restart the Prolog process if running before.
 
-(fn ARG)" t nil)
+(fn ARG)" t)
 (register-definition-prefixes "prolog" '("mercury-mode-map" "prolog-"))
 
 
@@ -24379,11 +24527,6 @@ The default value is 
(\"/usr/local/share/emacs/fonts/bdf\").")
 (register-definition-prefixes "ps-bdf" '("bdf-"))
 
 
-;;; Generated autoloads from ps-def.el
-
-(register-definition-prefixes "ps-def" '("ps-"))
-
-
 ;;; Generated autoloads from progmodes/ps-mode.el
 
 (push (purecopy '(ps-mode 1 1 9)) package--builtin-versions)
@@ -24425,7 +24568,7 @@ point to the corresponding spot in the PostScript 
window, if input
 to the interpreter was sent from that window.
 Typing \\<ps-run-mode-map>\\[ps-run-goto-error] when the cursor is at the 
number has the same effect.
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "ps-mode" '("ps-"))
 
 
@@ -24436,7 +24579,6 @@ Typing \\<ps-run-mode-map>\\[ps-run-goto-error] when 
the cursor is at the number
 
 ;;; Generated autoloads from ps-print.el
 
-(push (purecopy '(ps-print 7 3 5)) package--builtin-versions)
 (defvar ps-page-dimensions-database (purecopy (list (list 'a4 (/ (* 72 21.0) 
2.54) (/ (* 72 29.7) 2.54) "A4") (list 'a3 (/ (* 72 29.7) 2.54) (/ (* 72 42.0) 
2.54) "A3") (list 'letter (* 72 8.5) (* 72 11.0) "Letter") (list 'legal (* 72 
8.5) (* 72 14.0) "Legal") (list 'letter-small (* 72 7.68) (* 72 10.16) 
"LetterSmall") (list 'tabloid (* 72 11.0) (* 72 17.0) "Tabloid") (list 'ledger 
(* 72 17.0) (* 72 11.0) "Ledger") (list 'statement (* 72 5.5) (* 72 8.5) 
"Statement") (list 'executive (* 72 [...]
 List associating a symbolic paper type to its width, height and doc media.
 See `ps-paper-type'.")
@@ -24446,7 +24588,7 @@ Specify the size of paper to format for.
 Should be one of the paper types defined in `ps-page-dimensions-database', for
 example `letter', `legal' or `a4'.")
 (custom-autoload 'ps-paper-type "ps-print" t)
-(defvar ps-print-color-p (fboundp 'x-color-values) "\
+(defvar ps-print-color-p t "\
 Specify how buffer's text color is printed.
 
 Valid values are:
@@ -24461,7 +24603,7 @@ Valid values are:
 Any other value is treated as t.")
 (custom-autoload 'ps-print-color-p "ps-print" t)
 (autoload 'ps-print-customize "ps-print" "\
-Customization of ps-print group." t nil)
+Customization of ps-print group." t)
 (autoload 'ps-print-buffer "ps-print" "\
 Generate and print a PostScript image of the buffer.
 
@@ -24473,46 +24615,46 @@ Noninteractively, the argument FILENAME is treated as 
follows: if it is nil,
 send the image to the printer.  If FILENAME is a string, save the PostScript
 image in a file with that name.
 
-(fn &optional FILENAME)" t nil)
+(fn &optional FILENAME)" t)
 (autoload 'ps-print-buffer-with-faces "ps-print" "\
 Generate and print a PostScript image of the buffer.
 Like `ps-print-buffer', but includes font, color, and underline information in
 the generated image.  This command works only if you are using a window system,
 so it has a way to determine color values.
 
-(fn &optional FILENAME)" t nil)
+(fn &optional FILENAME)" t)
 (autoload 'ps-print-region "ps-print" "\
 Generate and print a PostScript image of the region.
 Like `ps-print-buffer', but prints just the current region.
 
-(fn FROM TO &optional FILENAME)" t nil)
+(fn FROM TO &optional FILENAME)" t)
 (autoload 'ps-print-region-with-faces "ps-print" "\
 Generate and print a PostScript image of the region.
 Like `ps-print-region', but includes font, color, and underline information in
 the generated image.  This command works only if you are using a window system,
 so it has a way to determine color values.
 
-(fn FROM TO &optional FILENAME)" t nil)
+(fn FROM TO &optional FILENAME)" t)
 (autoload 'ps-spool-buffer "ps-print" "\
 Generate and spool a PostScript image of the buffer.
 Like `ps-print-buffer' except that the PostScript image is saved in a local
 buffer to be sent to the printer later.
 
-Use the command `ps-despool' to send the spooled images to the printer." t nil)
+Use the command `ps-despool' to send the spooled images to the printer." t)
 (autoload 'ps-spool-buffer-with-faces "ps-print" "\
 Generate and spool a PostScript image of the buffer.
 Like the command `ps-spool-buffer', but includes font, color, and underline
 information in the generated image.  This command works only if you are using
 a window system, so it has a way to determine color values.
 
-Use the command `ps-despool' to send the spooled images to the printer." t nil)
+Use the command `ps-despool' to send the spooled images to the printer." t)
 (autoload 'ps-spool-region "ps-print" "\
 Generate a PostScript image of the region and spool locally.
 Like `ps-spool-buffer', but spools just the current region.
 
 Use the command `ps-despool' to send the spooled images to the printer.
 
-(fn FROM TO)" t nil)
+(fn FROM TO)" t)
 (autoload 'ps-spool-region-with-faces "ps-print" "\
 Generate a PostScript image of the region and spool locally.
 Like `ps-spool-region', but includes font, color, and underline information in
@@ -24521,7 +24663,7 @@ so it has a way to determine color values.
 
 Use the command `ps-despool' to send the spooled images to the printer.
 
-(fn FROM TO)" t nil)
+(fn FROM TO)" t)
 (autoload 'ps-despool "ps-print" "\
 Send the spooled PostScript to the printer.
 
@@ -24533,24 +24675,24 @@ Noninteractively, the argument FILENAME is treated as 
follows: if it is nil,
 send the image to the printer.  If FILENAME is a string, save the PostScript
 image in a file with that name.
 
-(fn &optional FILENAME)" t nil)
+(fn &optional FILENAME)" t)
 (autoload 'ps-line-lengths "ps-print" "\
 Display the correspondence between a line length and a font size.
 Done using the current ps-print setup.
 Try: pr -t file | awk \\='{printf \"%3d %s
-\", length($0), $0}\\=' | sort -r | head" t nil)
+\", length($0), $0}\\=' | sort -r | head" t)
 (autoload 'ps-nb-pages-buffer "ps-print" "\
 Display number of pages to print this buffer, for various font heights.
 The table depends on the current ps-print setup.
 
-(fn NB-LINES)" t nil)
+(fn NB-LINES)" t)
 (autoload 'ps-nb-pages-region "ps-print" "\
 Display number of pages to print the region, for various font heights.
 The table depends on the current ps-print setup.
 
-(fn NB-LINES)" t nil)
+(fn NB-LINES)" t)
 (autoload 'ps-setup "ps-print" "\
-Return the current PostScript-generation setup." nil nil)
+Return the current PostScript-generation setup.")
 (autoload 'ps-extend-face-list "ps-print" "\
 Extend face in ALIST-SYM.
 
@@ -24564,7 +24706,7 @@ The elements in FACE-EXTENSION-LIST are like those for 
`ps-extend-face'.
 
 See `ps-extend-face' for documentation.
 
-(fn FACE-EXTENSION-LIST &optional MERGE-P ALIST-SYM)" nil nil)
+(fn FACE-EXTENSION-LIST &optional MERGE-P ALIST-SYM)")
 (autoload 'ps-extend-face "ps-print" "\
 Extend face in ALIST-SYM.
 
@@ -24595,7 +24737,7 @@ EXTENSION is one of the following symbols:
 
 If EXTENSION is any other symbol, it is ignored.
 
-(fn FACE-EXTENSION &optional MERGE-P ALIST-SYM)" nil nil)
+(fn FACE-EXTENSION &optional MERGE-P ALIST-SYM)")
 (register-definition-prefixes "ps-print" '("ps-"))
 
 
@@ -24613,12 +24755,12 @@ If POINT is nil or missing, the current point is used 
instead.
 
 Optional argument FACE specifies the face to do the highlighting.
 
-(fn &optional POINT FACE)" nil nil)
+(fn &optional POINT FACE)")
 (autoload 'pulse-momentary-highlight-region "pulse" "\
 Highlight between START and END, unhighlighting before next command.
 Optional argument FACE specifies the face to do the highlighting.
 
-(fn START END &optional FACE)" nil nil)
+(fn START END &optional FACE)")
 (register-definition-prefixes "pulse" '("pulse-"))
 
 
@@ -24650,13 +24792,13 @@ Runs the hook `inferior-python-mode-hook' after
 `comint-mode-hook' is run.  (Type \\[describe-mode] in the
 process buffer for a list of commands.)
 
-(fn &optional CMD DEDICATED SHOW)" t nil)
+(fn &optional CMD DEDICATED SHOW)" t)
 (autoload 'python-mode "python" "\
 Major mode for editing Python files.
 
 \\{python-mode-map}
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "python" '("inferior-python-mode" "python-" 
"run-python-internal"))
 
 
@@ -24679,14 +24821,14 @@ The CODING-SYSTEM argument is a historical hangover 
and is deprecated.
 QP encodes raw bytes and should be decoded into raw bytes.  Decoding
 them into characters should be done separately.
 
-(fn FROM TO &optional CODING-SYSTEM)" t nil)
+(fn FROM TO &optional CODING-SYSTEM)" t)
 (register-definition-prefixes "qp" '("quoted-printable-"))
 
 
 ;;; Generated autoloads from international/quail.el
 
 (autoload 'quail-title "quail" "\
-Return the title of the current Quail package." nil nil)
+Return the title of the current Quail package.")
 (autoload 'quail-use-package "quail" "\
 Start using Quail package PACKAGE-NAME.
 The remaining arguments are LIBRARIES to be loaded before using the package.
@@ -24694,7 +24836,7 @@ The remaining arguments are LIBRARIES to be loaded 
before using the package.
 This activates input method defined by PACKAGE-NAME by running
 `quail-activate', which see.
 
-(fn PACKAGE-NAME &rest LIBRARIES)" nil nil)
+(fn PACKAGE-NAME &rest LIBRARIES)")
 (autoload 'quail-define-package "quail" "\
 Define NAME as a new Quail package for input LANGUAGE.
 TITLE is a string to be displayed at mode-line to indicate this package.
@@ -24775,7 +24917,7 @@ If SIMPLE is non-nil, then we do not alter the meanings 
of
 commands such as \\[forward-char], \\[backward-char], \\[next-line], 
\\[previous-line] and \\[indent-for-tab-command]; they are treated as
 non-Quail commands.
 
-(fn NAME LANGUAGE TITLE &optional GUIDANCE DOCSTRING TRANSLATION-KEYS 
FORGET-LAST-SELECTION DETERMINISTIC KBD-TRANSLATE SHOW-LAYOUT CREATE-DECODE-MAP 
MAXIMUM-SHORTEST OVERLAY-PLIST UPDATE-TRANSLATION-FUNCTION CONVERSION-KEYS 
SIMPLE)" nil nil)
+(fn NAME LANGUAGE TITLE &optional GUIDANCE DOCSTRING TRANSLATION-KEYS 
FORGET-LAST-SELECTION DETERMINISTIC KBD-TRANSLATE SHOW-LAYOUT CREATE-DECODE-MAP 
MAXIMUM-SHORTEST OVERLAY-PLIST UPDATE-TRANSLATION-FUNCTION CONVERSION-KEYS 
SIMPLE)")
 (autoload 'quail-set-keyboard-layout "quail" "\
 Set the current keyboard layout to the same as keyboard KBD-TYPE.
 
@@ -24785,14 +24927,14 @@ standard layout defined in 
`quail-keyboard-layout-standard'.  This
 function tells Quail system the layout of your keyboard so that what
 you type is correctly handled.
 
-(fn KBD-TYPE)" t nil)
+(fn KBD-TYPE)" t)
 (autoload 'quail-show-keyboard-layout "quail" "\
 Show the physical layout of the keyboard type KEYBOARD-TYPE.
 
 The variable `quail-keyboard-layout-type' holds the currently selected
 keyboard type.
 
-(fn &optional KEYBOARD-TYPE)" t nil)
+(fn &optional KEYBOARD-TYPE)" t)
 (autoload 'quail-define-rules "quail" "\
 Define translation rules of the current Quail package.
 Each argument is a list of KEY and TRANSLATION.
@@ -24835,7 +24977,7 @@ which to install MAP.
 
 The installed map can be referred by the function `quail-map'.
 
-(fn MAP &optional NAME)" nil nil)
+(fn MAP &optional NAME)")
 (autoload 'quail-install-decode-map "quail" "\
 Install the Quail decode map DECODE-MAP in the current Quail package.
 
@@ -24844,7 +24986,7 @@ which to install MAP.
 
 The installed decode map can be referred by the function `quail-decode-map'.
 
-(fn DECODE-MAP &optional NAME)" nil nil)
+(fn DECODE-MAP &optional NAME)")
 (autoload 'quail-defrule "quail" "\
 Add one translation rule, KEY to TRANSLATION, in the current Quail package.
 KEY is a string meaning a sequence of keystrokes to be translated.
@@ -24870,7 +25012,7 @@ current Quail package.
 Optional 4th argument APPEND, if non-nil, appends TRANSLATION
 to the current translations for KEY instead of replacing them.
 
-(fn KEY TRANSLATION &optional NAME APPEND)" nil nil)
+(fn KEY TRANSLATION &optional NAME APPEND)")
 (autoload 'quail-defrule-internal "quail" "\
 Define KEY as TRANS in a Quail map MAP.
 
@@ -24882,7 +25024,7 @@ Optional 5th arg DECODE-MAP is a Quail decode map.
 Optional 6th arg PROPS is a property list annotating TRANS.  See the
 function `quail-define-rules' for the detail.
 
-(fn KEY TRANS MAP &optional APPEND DECODE-MAP PROPS)" nil nil)
+(fn KEY TRANS MAP &optional APPEND DECODE-MAP PROPS)")
 (autoload 'quail-update-leim-list-file "quail" "\
 Update entries for Quail packages in `LEIM' list file in directory DIRNAME.
 DIRNAME is a directory containing Emacs input methods;
@@ -24896,68 +25038,10 @@ When called from a program, the remaining arguments 
are additional
 directory names to search for Quail packages under `quail' subdirectory
 of each directory.
 
-(fn DIRNAME &rest DIRNAMES)" t nil)
+(fn DIRNAME &rest DIRNAMES)" t)
 (register-definition-prefixes "quail" '("quail-"))
 
 
-;;; Generated autoloads from net/quickurl.el
-
-(defconst quickurl-reread-hook-postfix "\n;; Local Variables:\n;; eval: (progn 
(require 'quickurl) (add-hook 'write-file-functions (lambda () (quickurl-read) 
nil) nil t))\n;; End:\n" "\
-Example `quickurl-postfix' text that adds a local variable to the
-`quickurl-url-file' so that if you edit it by hand it will ensure that
-`quickurl-urls' is updated with the new URL list.
-
-To make use of this do something like:
-
-  (setq quickurl-postfix quickurl-reread-hook-postfix)
-
-in your init file (after loading/requiring quickurl).")
-(autoload 'quickurl "quickurl" "\
-Insert a URL based on LOOKUP.
-
-If not supplied LOOKUP is taken to be the word at point in the current
-buffer, this default action can be modified via
-`quickurl-grab-lookup-function'.
-
-(fn &optional LOOKUP)" t nil)
-(autoload 'quickurl-ask "quickurl" "\
-Insert a URL, with `completing-read' prompt, based on LOOKUP.
-
-(fn LOOKUP)" t nil)
-(autoload 'quickurl-add-url "quickurl" "\
-Allow the user to interactively add a new URL associated with WORD.
-
-See `quickurl-grab-url' for details on how the default word/URL combination
-is decided.
-
-(fn WORD URL COMMENT)" t nil)
-(autoload 'quickurl-browse-url "quickurl" "\
-Browse the URL associated with LOOKUP.
-
-If not supplied LOOKUP is taken to be the word at point in the
-current buffer, this default action can be modified via
-`quickurl-grab-lookup-function'.
-
-(fn &optional LOOKUP)" t nil)
-(autoload 'quickurl-browse-url-ask "quickurl" "\
-Browse the URL, with `completing-read' prompt, associated with LOOKUP.
-
-(fn LOOKUP)" t nil)
-(autoload 'quickurl-edit-urls "quickurl" "\
-Pull `quickurl-url-file' into a buffer for hand editing." t nil)
-(autoload 'quickurl-list-mode "quickurl" "\
-A mode for browsing the quickurl URL list.
-
-The key bindings for `quickurl-list-mode' are:
-
-\\{quickurl-list-mode-map}
-
-(fn)" t nil)
-(autoload 'quickurl-list "quickurl" "\
-Display `quickurl-list' as a formatted list using `quickurl-list-mode'." t nil)
-(register-definition-prefixes "quickurl" '("quickurl-"))
-
-
 ;;; Generated autoloads from emacs-lisp/radix-tree.el
 
 (register-definition-prefixes "radix-tree" '("radix-tree-"))
@@ -24977,7 +25061,7 @@ Do not connect to a server if it is already connected.
 
 If ARG is non-nil, instead prompt for connection parameters.
 
-(fn ARG)" t nil)
+(fn ARG)" t)
 (defalias 'irc 'rcirc)
 (autoload 'rcirc-connect "rcirc" "\
 Connect to SERVER.
@@ -24986,7 +25070,7 @@ ENCRYPTION, CERTFP, SERVER-ALIAS are interpreted as in
 `rcirc-server-alist'.  STARTUP-CHANNELS is a list of channels
 that are joined after authentication.
 
-(fn SERVER &optional PORT NICK USER-NAME FULL-NAME STARTUP-CHANNELS PASSWORD 
ENCRYPTION CERTFP SERVER-ALIAS)" nil nil)
+(fn SERVER &optional PORT NICK USER-NAME FULL-NAME STARTUP-CHANNELS PASSWORD 
ENCRYPTION CERTFP SERVER-ALIAS)")
 (defvar rcirc-track-minor-mode nil "\
 Non-nil if Rcirc-Track minor mode is enabled.
 See the `rcirc-track-minor-mode' command
@@ -25013,7 +25097,7 @@ evaluate `(default-value \\='rcirc-track-minor-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "rcirc" '("rcirc-" "with-rcirc-"))
 
 
@@ -25032,12 +25116,18 @@ matching parts of the target buffer will be 
highlighted.
 Case-sensitivity can be toggled with \\[reb-toggle-case].  The
 regexp builder supports three different forms of input which can
 be set with \\[reb-change-syntax].  More options and details are
-provided in the Commentary section of this library." t nil)
+provided in the Commentary section of this library." t)
 (register-definition-prefixes "re-builder" '("re-builder-unload-function" 
"reb-"))
 
 
 ;;; Generated autoloads from recentf.el
 
+(autoload 'recentf-open "recentf" "\
+Prompt for FILE in `recentf-list' and visit it.
+Enable `recentf-mode' if it isn't already.
+
+(fn FILE)" t)
+(defalias 'recentf 'recentf-open)
 (defvar recentf-mode nil "\
 Non-nil if Recentf mode is enabled.
 See the `recentf-mode' command
@@ -25047,7 +25137,14 @@ either customize it (see the info node `Easy 
Customization')
 or call the function `recentf-mode'.")
 (custom-autoload 'recentf-mode "recentf" nil)
 (autoload 'recentf-mode "recentf" "\
-Toggle \"Open Recent\" menu (Recentf mode).
+Toggle keeping track of opened files (Recentf mode).
+
+This mode maintains a list of recently opened files and makes it
+easy to visit them.  The recent files list is automatically saved
+across Emacs sessions.
+
+You can use `recentf-open' or `recentf-open-files' to visit
+files.
 
 When Recentf mode is enabled, a \"Open Recent\" submenu is
 displayed in the \"File\" menu, containing a list of files that
@@ -25074,7 +25171,7 @@ evaluate `(default-value \\='recentf-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "recentf" '("recentf-"))
 
 
@@ -25090,7 +25187,7 @@ When called from a program the rectangle's corners are 
START and END.
 With a prefix (or a FILL) argument, also fill lines where nothing has
 to be deleted.
 
-(fn START END &optional FILL)" t nil)
+(fn START END &optional FILL)" t)
 (autoload 'delete-extract-rectangle "rect" "\
 Delete the contents of the rectangle with corners at START and END.
 Return it as a list of strings, one for each line of the rectangle.
@@ -25099,12 +25196,12 @@ When called from a program the rectangle's corners 
are START and END.
 With an optional FILL argument, also fill lines where nothing has to be
 deleted.
 
-(fn START END &optional FILL)" nil nil)
+(fn START END &optional FILL)")
 (autoload 'extract-rectangle "rect" "\
 Return the contents of the rectangle with corners at START and END.
 Return it as a list of strings, one for each line of the rectangle.
 
-(fn START END)" nil nil)
+(fn START END)")
 (autoload 'kill-rectangle "rect" "\
 Delete the region-rectangle and save it as the last killed one.
 
@@ -25120,13 +25217,13 @@ you can use this command to copy text from a 
read-only buffer.
 (If the variable `kill-read-only-ok' is non-nil, then this won't
 even beep.)
 
-(fn START END &optional FILL)" t nil)
+(fn START END &optional FILL)" t)
 (autoload 'copy-rectangle-as-kill "rect" "\
 Copy the region-rectangle and save it as the last killed one.
 
-(fn START END)" t nil)
+(fn START END)" t)
 (autoload 'yank-rectangle "rect" "\
-Yank the last killed rectangle with upper left corner at point." t nil)
+Yank the last killed rectangle with upper left corner at point." t)
 (autoload 'insert-rectangle "rect" "\
 Insert text of RECTANGLE with upper left corner at point.
 RECTANGLE's first line is inserted at point, its second
@@ -25135,7 +25232,7 @@ RECTANGLE should be a list of strings.
 After this command, the mark is at the upper left corner
 and point is at the lower right corner.
 
-(fn RECTANGLE)" nil nil)
+(fn RECTANGLE)")
 (autoload 'open-rectangle "rect" "\
 Blank out the region-rectangle, shifting text right.
 
@@ -25146,8 +25243,8 @@ When called from a program the rectangle's corners are 
START and END.
 With a prefix (or a FILL) argument, fill with blanks even if there is
 no text on the right side of the rectangle.
 
-(fn START END &optional FILL)" t nil)
-(defalias 'close-rectangle 'delete-whitespace-rectangle)
+(fn START END &optional FILL)" t)
+(define-obsolete-function-alias 'close-rectangle #'delete-whitespace-rectangle 
"29.1")
 (autoload 'delete-whitespace-rectangle "rect" "\
 Delete all whitespace following a specified column in each line.
 The left edge of the rectangle specifies the position in each line
@@ -25157,7 +25254,7 @@ rectangle, all contiguous whitespace starting at that 
column is deleted.
 When called from a program the rectangle's corners are START and END.
 With a prefix (or a FILL) argument, also fill too short lines.
 
-(fn START END &optional FILL)" t nil)
+(fn START END &optional FILL)" t)
 (autoload 'string-rectangle "rect" "\
 Replace rectangle contents with STRING on each line.
 The length of STRING need not be the same as the rectangle width.
@@ -25168,8 +25265,8 @@ the minibuffer.
 
 Called from a program, takes three args; START, END and STRING.
 
-(fn START END STRING)" t nil)
-(defalias 'replace-rectangle 'string-rectangle)
+(fn START END STRING)" t)
+(define-obsolete-function-alias 'replace-rectangle #'string-rectangle "29.1")
 (autoload 'string-insert-rectangle "rect" "\
 Insert STRING on each line of region-rectangle, shifting text right.
 
@@ -25177,7 +25274,7 @@ When called from a program, the rectangle's corners are 
START and END.
 The left edge of the rectangle specifies the column for insertion.
 This command does not delete or overwrite any existing text.
 
-(fn START END STRING)" t nil)
+(fn START END STRING)" t)
 (autoload 'clear-rectangle "rect" "\
 Blank out the region-rectangle.
 The text previously in the region is overwritten with blanks.
@@ -25186,7 +25283,7 @@ When called from a program the rectangle's corners are 
START and END.
 With a prefix (or a FILL) argument, also fill with blanks the parts of the
 rectangle which were empty.
 
-(fn START END &optional FILL)" t nil)
+(fn START END &optional FILL)" t)
 (autoload 'rectangle-number-lines "rect" "\
 Insert numbers in front of the region-rectangle.
 
@@ -25195,7 +25292,7 @@ counting.  FORMAT, if non-nil, should be a format 
string to pass
 to `format' along with the line count.  When called interactively
 with a prefix argument, prompt for START-AT and FORMAT.
 
-(fn START END START-AT &optional FORMAT)" t nil)
+(fn START END START-AT &optional FORMAT)" t)
 (autoload 'rectangle-mark-mode "rect" "\
 Toggle the region as rectangular.
 
@@ -25216,7 +25313,7 @@ evaluate `rectangle-mark-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "rect" '("apply-on-rectangle" 
"clear-rectangle-line" "delete-" "extract-rectangle-" "killed-rectangle" "ope" 
"rectangle-" "spaces-string" "string-rectangle-"))
 
 
@@ -25256,7 +25353,7 @@ evaluate `refill-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "refill" '("refill-"))
 
 
@@ -25272,7 +25369,7 @@ it is disabled.
 (autoload 'reftex-isearch-minor-mode "reftex-global" nil t)
 (autoload 'reftex-index-phrases-mode "reftex-index" nil t)
 (autoload 'turn-on-reftex "reftex" "\
-Turn on RefTeX mode." nil nil)
+Turn on RefTeX mode.")
 (autoload 'reftex-mode "reftex" "\
 Minor mode with distinct support for \\label, \\ref and \\cite in LaTeX.
 
@@ -25318,10 +25415,10 @@ evaluate `reftex-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'reftex-reset-scanning-information "reftex" "\
 Reset the symbols containing information from buffer scanning.
-This enforces rescanning the buffer on next use." nil nil)
+This enforces rescanning the buffer on next use.")
 (register-definition-prefixes "reftex" '("reftex-"))
 
 
@@ -25428,13 +25525,13 @@ usually more efficient than that of a simplified 
version:
              (mapconcat \\='regexp-quote strings \"\\\\|\")
              (cdr parens))))
 
-(fn STRINGS &optional PAREN)" nil nil)
+(fn STRINGS &optional PAREN)")
 (autoload 'regexp-opt-depth "regexp-opt" "\
 Return the depth of REGEXP.
 This means the number of non-shy regexp grouping constructs
 (parenthesized expressions) in REGEXP.
 
-(fn REGEXP)" nil nil)
+(fn REGEXP)")
 (register-definition-prefixes "regexp-opt" '("regexp-opt-"))
 
 
@@ -25457,16 +25554,16 @@ or nil to bring up a blank `remember-buffer'.
 
 With a prefix or a visible region, use the region as INITIAL.
 
-(fn &optional INITIAL)" t nil)
+(fn &optional INITIAL)" t)
 (autoload 'remember-other-frame "remember" "\
 Call `remember' in another frame.
 
-(fn &optional INITIAL)" t nil)
+(fn &optional INITIAL)" t)
 (autoload 'remember-clipboard "remember" "\
 Remember the contents of the current clipboard.
-Most useful for remembering things from other applications." t nil)
+Most useful for remembering things from other applications." t)
 (autoload 'remember-diary-extract-entries "remember" "\
-Extract diary entries from the region based on `remember-diary-regexp'." nil 
nil)
+Extract diary entries from the region based on `remember-diary-regexp'.")
 (autoload 'remember-notes "remember" "\
 Return the notes buffer, creating it if needed, and maybe switch to it.
 This buffer is for notes that you want to preserve across Emacs sessions.
@@ -25488,7 +25585,7 @@ Set `initial-buffer-choice' to `remember-notes' to 
visit your notes buffer
 when Emacs starts.  Set `remember-notes-buffer-name' to \"*scratch*\"
 to turn the *scratch* buffer into your notes buffer.
 
-(fn &optional SWITCH-TO)" t nil)
+(fn &optional SWITCH-TO)" t)
 (register-definition-prefixes "remember" '("remember-"))
 
 
@@ -25509,7 +25606,7 @@ sequence.  This behavior can be modified by the global 
variable
 \"most recently executed command\" shall be read as \"most
 recently executed command not bound to an input event\".
 
-(fn REPEAT-ARG)" t nil)
+(fn REPEAT-ARG)" t)
 (defvar repeat-map nil "\
 The value of the repeating transient map for the next command.
 A command called from the map can set it again to the same map when
@@ -25543,7 +25640,7 @@ evaluate `(default-value \\='repeat-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "repeat" '("describe-repeat-maps" "repeat-"))
 
 
@@ -25573,7 +25670,7 @@ to initialize a message, which the user can then edit 
and finally send
 (or decline to send).  The variable `mail-user-agent' controls which
 mail-sending package is used for editing and sending the message.
 
-(fn ADDRESS PKGNAME VARLIST &optional PRE-HOOKS POST-HOOKS SALUTATION)" nil 
nil)
+(fn ADDRESS PKGNAME VARLIST &optional PRE-HOOKS POST-HOOKS SALUTATION)")
 (register-definition-prefixes "reporter" '("reporter-"))
 
 
@@ -25600,7 +25697,7 @@ first comment line visible (if point is in a comment).
 If INTERACTIVE is non-nil, as it is interactively,
 report errors as appropriate for this kind of usage.
 
-(fn &optional ARG INTERACTIVE)" t nil)
+(fn &optional ARG INTERACTIVE)" t)
 (register-definition-prefixes "reposition" '("repos-count-screen-lines"))
 
 
@@ -25628,7 +25725,7 @@ evaluate `reveal-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (defvar global-reveal-mode nil "\
 Non-nil if Global Reveal mode is enabled.
 See the `global-reveal-mode' command
@@ -25656,7 +25753,7 @@ evaluate `(default-value \\='global-reveal-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "reveal" '("reveal-"))
 
 
@@ -25700,57 +25797,14 @@ it is disabled.
 (autoload 'ring-p "ring" "\
 Return t if X is a ring; nil otherwise.
 
-(fn X)" nil nil)
+(fn X)")
 (autoload 'make-ring "ring" "\
 Make a ring that can contain SIZE elements.
 
-(fn SIZE)" nil nil)
+(fn SIZE)")
 (register-definition-prefixes "ring" '("ring-"))
 
 
-;;; Generated autoloads from net/rlogin.el
-
-(autoload 'rlogin "rlogin" "\
-Open a network login connection via `rlogin' with args INPUT-ARGS.
-INPUT-ARGS should start with a host name; it may also contain
-other arguments for `rlogin'.
-
-Input is sent line-at-a-time to the remote connection.
-
-Communication with the remote host is recorded in a buffer `*rlogin-HOST*'
-(or `*rlogin-USER@HOST*' if the remote username differs).
-If a prefix argument is given and the buffer `*rlogin-HOST*' already exists,
-a new buffer with a different connection will be made.
-
-When called from a program, if the optional second argument BUFFER is
-a string or buffer, it specifies the buffer to use.
-
-The variable `rlogin-program' contains the name of the actual program to
-run.  It can be a relative or absolute path.
-
-The variable `rlogin-explicit-args' is a list of arguments to give to
-the rlogin when starting.  They are added after any arguments given in
-INPUT-ARGS.
-
-If the default value of `rlogin-directory-tracking-mode' is t, then the
-default directory in that buffer is set to a remote (FTP) file name to
-access your home directory on the remote machine.  Occasionally this causes
-an error, if you cannot access the home directory on that machine.  This
-error is harmless as long as you don't try to use that default directory.
-
-If `rlogin-directory-tracking-mode' is neither t nor nil, then the default
-directory is initially set up to your (local) home directory.
-This is useful if the remote machine and your local machine
-share the same files via NFS.  This is the default.
-
-If you wish to change directory tracking styles during a session, use the
-function `rlogin-directory-tracking-mode' rather than simply setting the
-variable.
-
-(fn INPUT-ARGS &optional BUFFER)" t nil)
-(register-definition-prefixes "rlogin" '("rlogin-"))
-
-
 ;;; Generated autoloads from mail/rmail.el
 
 (defvar rmail-file-name (purecopy "~/RMAIL") "\
@@ -25764,7 +25818,7 @@ Its name should end with a slash." :initialize 
#'custom-initialize-delay :type '
 Return t if the current movemail variant is any of VARIANTS.
 Currently known variants are `emacs' and `mailutils'.
 
-(fn &rest VARIANTS)" nil nil)
+(fn &rest VARIANTS)")
 (defvar rmail-user-mail-address-regexp nil "\
 Regexp matching user mail addresses.
 If non-nil, this variable is used to identify the correspondent
@@ -25779,14 +25833,6 @@ Then it should be a regexp matching your mail 
addresses.
 
 Setting this variable has an effect only before reading a mail.")
 (custom-autoload 'rmail-user-mail-address-regexp "rmail" t)
-(define-obsolete-variable-alias 'rmail-dont-reply-to-names 
'mail-dont-reply-to-names "\
-24.1")
-(defvar rmail-default-dont-reply-to-names nil "\
-Regexp specifying part of the default value of `mail-dont-reply-to-names'.
-This is used when the user does not set `mail-dont-reply-to-names'
-explicitly.")
-(make-obsolete-variable 'rmail-default-dont-reply-to-names 
'mail-dont-reply-to-names "\
-24.1")
 (defvar rmail-ignored-headers (purecopy (concat 
"^via:\\|^mail-from:\\|^origin:\\|^references:\\|^sender:" 
"\\|^status:\\|^received:\\|^x400-originator:\\|^x400-recipients:" 
"\\|^x400-received:\\|^x400-mts-identifier:\\|^x400-content-type:" 
"\\|^\\(resent-\\|\\)message-id:\\|^summary-line:\\|^resent-date:" 
"\\|^nntp-posting-host:\\|^path:\\|^x-char.*:\\|^x-face:\\|^face:" 
"\\|^x-mailer:\\|^delivered-to:\\|^lines:" 
"\\|^content-transfer-encoding:\\|^x-coding-system:" "\\|^return-path:\\|^ [...]
 Regexp to match header fields that Rmail should normally hide.
 (See also `rmail-nonignored-headers', which overrides this regexp.)
@@ -25851,7 +25897,7 @@ have a chance to specify a file name with the 
minibuffer.
 
 If `rmail-display-summary' is non-nil, make a summary for this RMAIL file.
 
-(fn &optional FILE-NAME-ARG)" t nil)
+(fn &optional FILE-NAME-ARG)" t)
 (autoload 'rmail-mode "rmail" "\
 Rmail Mode is used by \\<rmail-mode-map>\\[rmail] for editing Rmail files.
 All normal editing commands are turned off.
@@ -25901,15 +25947,15 @@ Instead, these commands are available:
 \\[rmail-summary-by-recipients]   Summarize only messages with particular 
recipient(s).
 \\[rmail-summary-by-regexp]   Summarize only messages with particular 
regexp(s).
 \\[rmail-summary-by-topic]   Summarize only messages with subject line 
regexp(s).
-\\[rmail-toggle-header]        Toggle display of complete header." t nil)
+\\[rmail-toggle-header]        Toggle display of complete header." t)
 (autoload 'rmail-input "rmail" "\
 Run Rmail on file FILENAME.
 
-(fn FILENAME)" t nil)
+(fn FILENAME)" t)
 (autoload 'rmail-set-remote-password "rmail" "\
 Set PASSWORD to be used for retrieving mail from a POP or IMAP server.
 
-(fn PASSWORD)" t nil)
+(fn PASSWORD)" t)
 (register-definition-prefixes "rmail" '("mail-" "rmail-"))
 
 
@@ -25921,7 +25967,7 @@ Set PASSWORD to be used for retrieving mail from a POP 
or IMAP server.
 ;;; Generated autoloads from mail/rmailedit.el
 
 (autoload 'rmail-edit-current-message "rmailedit" "\
-Edit the contents of this message." t nil)
+Edit the contents of this message." t)
 (register-definition-prefixes "rmailedit" '("rmail-"))
 
 
@@ -25932,34 +25978,34 @@ Add LABEL to labels associated with current RMAIL 
message.
 Completes (see `rmail-read-label') over known labels when reading.
 LABEL may be a symbol or string.  Only one label is allowed.
 
-(fn LABEL)" t nil)
+(fn LABEL)" t)
 (autoload 'rmail-kill-label "rmailkwd" "\
 Remove LABEL from labels associated with current RMAIL message.
 Completes (see `rmail-read-label') over known labels when reading.
 LABEL may be a symbol or string.  Only one label is allowed.
 
-(fn LABEL)" t nil)
+(fn LABEL)" t)
 (autoload 'rmail-read-label "rmailkwd" "\
 Read a label with completion, prompting with PROMPT.
 Completions are chosen from `rmail-label-obarray'.  The default
 is `rmail-last-label', if that is non-nil.  Updates `rmail-last-label'
 according to the choice made, and returns a symbol.
 
-(fn PROMPT)" nil nil)
+(fn PROMPT)")
 (autoload 'rmail-previous-labeled-message "rmailkwd" "\
 Show previous message with one of the labels LABELS.
 LABELS should be a comma-separated list of label names.
 If LABELS is empty, the last set of labels specified is used.
 With prefix argument N moves backward N messages with these labels.
 
-(fn N LABELS)" t nil)
+(fn N LABELS)" t)
 (autoload 'rmail-next-labeled-message "rmailkwd" "\
 Show next message with one of the labels LABELS.
 LABELS should be a comma-separated list of label names.
 If LABELS is empty, the last set of labels specified is used.
 With prefix argument N moves forward N messages with these labels.
 
-(fn N LABELS)" t nil)
+(fn N LABELS)" t)
 (register-definition-prefixes "rmailkwd" '("rmail-"))
 
 
@@ -25984,7 +26030,7 @@ By default, this displays text and multipart messages, 
and offers to
 download attachments as specified by `rmail-mime-attachment-dirs-alist'.
 The arguments ARG and STATE have no effect in this case.
 
-(fn &optional ARG STATE)" t nil)
+(fn &optional ARG STATE)" t)
 (register-definition-prefixes "rmailmm" '("rmail-"))
 
 
@@ -25997,7 +26043,7 @@ If FILE-NAME is empty, remove any existing inbox list.
 
 This applies only to the current session.
 
-(fn FILE-NAME)" t nil)
+(fn FILE-NAME)" t)
 
 
 ;;; Generated autoloads from mail/rmailout.el
@@ -26038,7 +26084,7 @@ message (if writing a file directly).
 Set the optional fourth argument NOT-RMAIL non-nil if you call this
 from a non-Rmail buffer.  In this case, COUNT is ignored.
 
-(fn FILE-NAME &optional COUNT NOATTRIBUTE NOT-RMAIL)" t nil)
+(fn FILE-NAME &optional COUNT NOATTRIBUTE NOT-RMAIL)" t)
 (autoload 'rmail-output-as-seen "rmailout" "\
 Append this message to mbox file named FILE-NAME.
 The details are as for `rmail-output', except that:
@@ -26050,7 +26096,7 @@ Note that if NOT-RMAIL is non-nil, there is no 
difference between this
 function and `rmail-output'.  This argument may be removed in future,
 so you should call `rmail-output' directly in that case.
 
-(fn FILE-NAME &optional COUNT NOATTRIBUTE NOT-RMAIL)" t nil)
+(fn FILE-NAME &optional COUNT NOATTRIBUTE NOT-RMAIL)" t)
 (autoload 'rmail-output-body-to-file "rmailout" "\
 Write this message body to the file FILE-NAME.
 Interactively, the default file name comes from either the message
@@ -26063,7 +26109,7 @@ Note that this overwrites FILE-NAME (after 
confirmation), rather
 than appending to it.  Deletes the message after writing if
 `rmail-delete-after-output' is non-nil.
 
-(fn FILE-NAME)" t nil)
+(fn FILE-NAME)" t)
 (register-definition-prefixes "rmailout" '("rmail-"))
 
 
@@ -26073,25 +26119,25 @@ than appending to it.  Deletes the message after 
writing if
 Sort messages of current Rmail buffer by \"Date\" header.
 If prefix argument REVERSE is non-nil, sorts in reverse order.
 
-(fn REVERSE)" t nil)
+(fn REVERSE)" t)
 (autoload 'rmail-sort-by-subject "rmailsort" "\
 Sort messages of current Rmail buffer by \"Subject\" header.
 Ignores any \"Re: \" prefix.  If prefix argument REVERSE is
 non-nil, sorts in reverse order.
 
-(fn REVERSE)" t nil)
+(fn REVERSE)" t)
 (autoload 'rmail-sort-by-author "rmailsort" "\
 Sort messages of current Rmail buffer by author.
 This uses either the \"From\" or \"Sender\" header, downcased.
 If prefix argument REVERSE is non-nil, sorts in reverse order.
 
-(fn REVERSE)" t nil)
+(fn REVERSE)" t)
 (autoload 'rmail-sort-by-recipient "rmailsort" "\
 Sort messages of current Rmail buffer by recipient.
 This uses either the \"To\" or \"Apparently-To\" header, downcased.
 If prefix argument REVERSE is non-nil, sorts in reverse order.
 
-(fn REVERSE)" t nil)
+(fn REVERSE)" t)
 (autoload 'rmail-sort-by-correspondent "rmailsort" "\
 Sort messages of current Rmail buffer by other correspondent.
 This uses either the \"From\", \"Sender\", \"To\", or
@@ -26099,12 +26145,12 @@ This uses either the \"From\", \"Sender\", \"To\", or
 excluded by `mail-dont-reply-to-names'.  If prefix argument
 REVERSE is non-nil, sorts in reverse order.
 
-(fn REVERSE)" t nil)
+(fn REVERSE)" t)
 (autoload 'rmail-sort-by-lines "rmailsort" "\
 Sort messages of current Rmail buffer by the number of lines.
 If prefix argument REVERSE is non-nil, sorts in reverse order.
 
-(fn REVERSE)" t nil)
+(fn REVERSE)" t)
 (autoload 'rmail-sort-by-labels "rmailsort" "\
 Sort messages of current Rmail buffer by labels.
 LABELS is a comma-separated list of labels.  The order of these
@@ -26113,19 +26159,19 @@ label come first, messages with the second label come 
second, and
 so on.  Messages that have none of these labels come last.
 If prefix argument REVERSE is non-nil, sorts in reverse order.
 
-(fn REVERSE LABELS)" t nil)
+(fn REVERSE LABELS)" t)
 (register-definition-prefixes "rmailsort" '("rmail-"))
 
 
 ;;; Generated autoloads from mail/rmailsum.el
 
 (autoload 'rmail-summary "rmailsum" "\
-Display a summary of all messages, one line per message." t nil)
+Display a summary of all messages, one line per message." t)
 (autoload 'rmail-summary-by-labels "rmailsum" "\
 Display a summary of all messages with one or more LABELS.
 LABELS should be a string containing the desired labels, separated by commas.
 
-(fn LABELS)" t nil)
+(fn LABELS)" t)
 (autoload 'rmail-summary-by-recipients "rmailsum" "\
 Display a summary of all messages with the given RECIPIENTS.
 Normally checks the To, From and Cc fields of headers;
@@ -26133,88 +26179,37 @@ but if PRIMARY-ONLY is non-nil (prefix arg given),
  only look in the To and From fields.
 RECIPIENTS is a regular expression.
 
-(fn RECIPIENTS &optional PRIMARY-ONLY)" t nil)
+(fn RECIPIENTS &optional PRIMARY-ONLY)" t)
 (autoload 'rmail-summary-by-regexp "rmailsum" "\
 Display a summary of all messages according to regexp REGEXP.
 If the regular expression is found in the header of the message
 (including in the date and other lines, as well as the subject line),
 Emacs will list the message in the summary.
 
-(fn REGEXP)" t nil)
+(fn REGEXP)" t)
 (autoload 'rmail-summary-by-topic "rmailsum" "\
 Display a summary of all messages with the given SUBJECT.
 Normally checks just the Subject field of headers; but with prefix
 argument WHOLE-MESSAGE is non-nil, looks in the whole message.
 SUBJECT is a regular expression.
 
-(fn SUBJECT &optional WHOLE-MESSAGE)" t nil)
+(fn SUBJECT &optional WHOLE-MESSAGE)" t)
 (autoload 'rmail-summary-by-senders "rmailsum" "\
 Display a summary of all messages whose \"From\" field matches SENDERS.
 SENDERS is a regular expression.  The default for SENDERS matches the
 sender of the current message.
 
-(fn SENDERS)" t nil)
+(fn SENDERS)" t)
 (register-definition-prefixes "rmailsum" '("rmail-"))
 
 
-;;; Generated autoloads from emacs-lisp/rmc.el
-
-(autoload 'read-multiple-choice "rmc" "\
-Ask user to select an entry from CHOICES, promting with PROMPT.
-This function allows to ask the user a multiple-choice question.
-
-CHOICES should be a list of the form (KEY NAME [DESCRIPTION]).
-KEY is a character the user should type to select the entry.
-NAME is a short name for the entry to be displayed while prompting
-(if there's no room, it might be shortened).
-DESCRIPTION is an optional longer description of the entry; it will
-be displayed in a help buffer if the user requests more help.  This
-help description has a fixed format in columns.  For greater
-flexibility, instead of passing a DESCRIPTION, the caller can pass
-the optional argument HELP-STRING.  This argument is a string that
-should contain a more detailed description of all of the possible
-choices.  `read-multiple-choice' will display that description in a
-help buffer if the user requests that.
-If optional argument SHOW-HELP is non-nil, show the help screen
-immediately, before any user input.  If SHOW-HELP is a string,
-use it as the name of the help buffer.
-
-This function translates user input into responses by consulting
-the bindings in `query-replace-map'; see the documentation of
-that variable for more information.  The relevant bindings for the
-purposes of this function are `recenter', `scroll-up', `scroll-down',
-and `edit'.
-If the user types the `recenter', `scroll-up', or `scroll-down'
-responses, the function performs the requested window recentering or
-scrolling, and then asks the question again.  If the user enters `edit',
-the function starts a recursive edit.  When the user exit the recursive
-edit, the multiple-choice prompt gains focus again.
-
-When `use-dialog-box' is t (the default), and the command using this
-function was invoked via the mouse, this function pops up a GUI dialog
-to collect the user input, but only if Emacs is capable of using GUI
-dialogs.  Otherwise, the function will always use text-mode dialogs.
-
-The return value is the matching entry from the CHOICES list.
-
-Usage example:
-
-(read-multiple-choice \"Continue connecting?\"
-                      \\='((?a \"always\")
-                        (?s \"session only\")
-                        (?n \"no\")))
-
-(fn PROMPT CHOICES &optional HELP-STRING SHOW-HELP)" nil nil)
-(register-definition-prefixes "rmc" '("rmc--"))
-
-
 ;;; Generated autoloads from nxml/rng-cmpct.el
 
 (autoload 'rng-c-load-schema "rng-cmpct" "\
 Load a schema in RELAX NG compact syntax from FILENAME.
 Return a pattern.
 
-(fn FILENAME)" nil nil)
+(fn FILENAME)")
 (register-definition-prefixes "rng-cmpct" '("rng-"))
 
 
@@ -26243,7 +26238,7 @@ Return a pattern.
 (autoload 'rng-nxml-mode-init "rng-nxml" "\
 Initialize `nxml-mode' to take advantage of `rng-validate-mode'.
 This is typically called from `nxml-mode-hook'.
-Validation will be enabled if `rng-nxml-auto-validate-flag' is non-nil." t nil)
+Validation will be enabled if `rng-nxml-auto-validate-flag' is non-nil." t)
 (register-definition-prefixes "rng-nxml" '("rng-"))
 
 
@@ -26306,7 +26301,7 @@ evaluate `rng-validate-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "rng-valid" '("rng-"))
 
 
@@ -26331,7 +26326,7 @@ The object returned can be any convenient non-nil 
value, provided
 that, if two strings represent the same value, the returned objects
 must be equal.
 
-(fn NAME PARAMS)" nil nil)
+(fn NAME PARAMS)")
 (register-definition-prefixes "rng-xsd" '("rng-xsd-" 
"xsd-duration-reference-dates"))
 
 
@@ -26356,11 +26351,11 @@ NAME is the string specifying a robin package.
 INPUT is a string that specifies the input pattern.
 OUTPUT is either a character or a string to be generated.
 
-(fn NAME INPUT OUTPUT)" nil nil)
+(fn NAME INPUT OUTPUT)")
 (autoload 'robin-use-package "robin" "\
 Start using robin package NAME, which is a string.
 
-(fn NAME)" nil nil)
+(fn NAME)")
 (register-definition-prefixes "robin" '("robin-"))
 
 
@@ -26372,15 +26367,15 @@ If OBJECT is a buffer, encrypt the region between 
START and END.
 If OBJECT is a string, encrypt it in its entirety, ignoring START
 and END, and return the encrypted string.
 
-(fn OBJECT &optional START END)" nil nil)
+(fn OBJECT &optional START END)")
 (autoload 'rot13-string "rot13" "\
 Return ROT13 encryption of STRING.
 
-(fn STRING)" nil nil)
+(fn STRING)")
 (autoload 'rot13-region "rot13" "\
 ROT13 encrypt the region between START and END in current buffer.
 
-(fn START END)" t nil)
+(fn START END)" t)
 (autoload 'rot13-other-window "rot13" "\
 Display current buffer in ROT13 in another window.
 The text itself is not modified, only the way it is displayed is affected.
@@ -26389,9 +26384,9 @@ To terminate the ROT13 display, delete that window.  As 
long as that window
 is not deleted, any buffer displayed in it will become instantly encoded
 in ROT13.
 
-See also `toggle-rot13-mode'." t nil)
+See also `toggle-rot13-mode'." t)
 (autoload 'toggle-rot13-mode "rot13" "\
-Toggle the use of ROT13 encoding for the current window." t nil)
+Toggle the use of ROT13 encoding for the current window." t)
 (register-definition-prefixes "rot13" '("rot13-"))
 
 
@@ -26408,7 +26403,7 @@ highlighting.
 
 \\{rst-mode-map}
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'rst-minor-mode "rst" "\
 Toggle ReST minor mode.
 
@@ -26430,7 +26425,7 @@ evaluate `rst-minor-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "rst" '("rst-"))
 
 
@@ -26445,7 +26440,7 @@ it is disabled.
 (autoload 'ruby-mode "ruby-mode" "\
 Major mode for editing Ruby code.
 
-(fn)" t nil)
+(fn)" t)
 (add-to-list 'auto-mode-alist (cons (purecopy (concat "\\(?:\\.\\(?:" 
"rbw?\\|ru\\|rake\\|thor" "\\|jbuilder\\|rabl\\|gemspec\\|podspec" "\\)" "\\|/" 
"\\(?:Gem\\|Rake\\|Cap\\|Thor" "\\|Puppet\\|Berks\\|Brew" 
"\\|Vagrant\\|Guard\\|Pod\\)file" "\\)\\'")) 'ruby-mode))
 (dolist (name (list "ruby" "rbx" "jruby" "ruby1.9" "ruby1.8")) (add-to-list 
'interpreter-mode-alist (cons (purecopy name) 'ruby-mode)))
 (register-definition-prefixes "ruby-mode" '("ruby-"))
@@ -26473,7 +26468,7 @@ evaluate `ruler-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "ruler-mode" '("ruler-"))
 
 
@@ -26488,7 +26483,7 @@ group.
 
 For extending the `rx' notation in FORM, use `rx-define' or `rx-let-eval'.
 
-(fn FORM &optional NO-GROUP)" nil nil)
+(fn FORM &optional NO-GROUP)")
 (autoload 'rx "rx" "\
 Translate regular expressions REGEXPS in sexp form to a regexp string.
 Each argument is one of the forms below; RX is a subform, and RX... stands
@@ -26618,7 +26613,7 @@ To make global rx extensions, use `rx-define'.
 For more details, see Info node `(elisp) Extending Rx'.
 
 (fn BINDINGS BODY...)" nil t)
-(function-put 'rx-let-eval 'lisp-indent-function '1)
+(function-put 'rx-let-eval 'lisp-indent-function 1)
 (autoload 'rx-let "rx" "\
 Evaluate BODY with local BINDINGS for `rx'.
 BINDINGS is an unevaluated list of bindings each on the form
@@ -26640,7 +26635,7 @@ To make global rx extensions, use `rx-define'.
 For more details, see Info node `(elisp) Extending Rx'.
 
 (fn BINDINGS BODY...)" nil t)
-(function-put 'rx-let 'lisp-indent-function '1)
+(function-put 'rx-let 'lisp-indent-function 1)
 (autoload 'rx-define "rx" "\
 Define NAME as a global `rx' definition.
 If the ARGS list is omitted, define NAME as an alias for the `rx'
@@ -26673,9 +26668,13 @@ following constructs:
   (backref REF)    matches whatever the submatch REF matched.
                    REF can be a number, as usual, or a name
                    introduced by a previous (let REF ...)
-                   construct." (let* ((rx--pcase-vars nil) (regexp 
(rx--to-expr (rx--pcase-transform (cons 'seq regexps))))) `(and (pred stringp) 
,(pcase (length rx--pcase-vars) (0 `(pred (string-match ,regexp))) (1 `(app 
(lambda (s) (if (string-match ,regexp s) (match-string 1 s) 0)) (and ,(car 
rx--pcase-vars) (pred (not numberp))))) (nvars `(app (lambda (s) (and 
(string-match ,regexp s) ,(rx--reduce-right (lambda (a b) `(cons ,a ,b)) 
(mapcar (lambda (i) `(match-string ,i s)) (number-se [...]
+                   construct." (rx--pcase-expand regexps)))
 (define-symbol-prop 'rx--pcase-macroexpander 'edebug-form-spec 'nil)
 (define-symbol-prop 'rx 'pcase-macroexpander #'rx--pcase-macroexpander)
+(autoload 'rx--pcase-expand "rx" "\
+
+
+(fn REGEXPS)")
 (register-definition-prefixes "rx" '("rx-"))
 
 
@@ -26762,7 +26761,7 @@ evaluate `(default-value \\='savehist-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "savehist" '("savehist-"))
 
 
@@ -26796,7 +26795,7 @@ evaluate `(default-value \\='save-place-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'save-place-local-mode "saveplace" "\
 Toggle whether to save your place in this file between sessions.
 
@@ -26824,8 +26823,8 @@ evaluate `save-place-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
-(register-definition-prefixes "saveplace" '("load-save-place-alist-from-file" 
"save-place"))
+(fn &optional ARG)" t)
+(register-definition-prefixes "saveplace" '("save-place"))
 
 
 ;;; Generated autoloads from cedet/semantic/sb.el
@@ -26853,7 +26852,7 @@ Delete converts tabs to spaces as it moves back.
 Blank lines separate paragraphs.  Semicolons start comments.
 \\{scheme-mode-map}
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'dsssl-mode "scheme" "\
 Major mode for editing DSSSL code.
 Editing commands are similar to those of `lisp-mode'.
@@ -26866,7 +26865,7 @@ Entering this mode runs the hooks `scheme-mode-hook' 
and then
 `dsssl-mode-hook' and inserts the value of `dsssl-sgml-declaration' if
 that variable's value is a string.
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "scheme" '("dsssl-" "scheme-"))
 
 
@@ -26888,7 +26887,7 @@ This mode is an extended emacs-lisp mode.
 
 \\{gnus-score-mode-map}
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "score-mode" '("gnus-score-" "score-mode-"))
 
 
@@ -26922,7 +26921,7 @@ evaluate `(default-value \\='scroll-all-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "scroll-all" '("scroll-all-"))
 
 
@@ -26958,7 +26957,7 @@ evaluate `scroll-lock-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "scroll-lock" '("scroll-lock-"))
 
 
@@ -27033,7 +27032,7 @@ evaluate `(default-value \\='semantic-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "semantic" '("bovinate" "semantic-"))
 
 
@@ -27173,12 +27172,12 @@ variable `message-default-mail-headers' instead.")
 (custom-autoload 'mail-default-headers "sendmail" t)
 (autoload 'sendmail-query-once "sendmail" "\
 Query for `send-mail-function' and send mail with it.
-This also saves the value of `send-mail-function' via Customize." nil nil)
+This also saves the value of `send-mail-function' via Customize.")
 (define-mail-user-agent 'sendmail-user-agent #'sendmail-user-agent-compose 
#'mail-send-and-exit)
 (autoload 'sendmail-user-agent-compose "sendmail" "\
 
 
-(fn &optional TO SUBJECT OTHER-HEADERS CONTINUE SWITCH-FUNCTION YANK-ACTION 
SEND-ACTIONS RETURN-ACTION &rest IGNORED)" nil nil)
+(fn &optional TO SUBJECT OTHER-HEADERS CONTINUE SWITCH-FUNCTION YANK-ACTION 
SEND-ACTIONS RETURN-ACTION &rest IGNORED)")
 (autoload 'mail-mode "sendmail" "\
 Major mode for editing mail to be sent.
 Like Text Mode but with these additional commands:
@@ -27201,7 +27200,12 @@ Here are commands that move to a header field (and 
create it if there isn't):
 Turning on Mail mode runs the normal hooks `text-mode-hook' and
 `mail-mode-hook' (in that order).
 
-(fn)" t nil)
+(fn)" t)
+(autoload 'mail-send-and-exit "sendmail" "\
+Send message like `mail-send', then, if no errors, exit from mail buffer.
+Prefix arg means don't delete this window.
+
+(fn &optional ARG)" t)
 (defvar mail-mailing-lists nil "\
 List of mailing list addresses the user is subscribed to.
 The variable is used to trigger insertion of the \"Mail-Followup-To\"
@@ -27270,121 +27274,21 @@ The seventh argument ACTIONS is a list of actions to 
take
  when the message is sent, we apply FUNCTION to ARGS.
  This is how Rmail arranges to mark messages `answered'.
 
-(fn &optional NOERASE TO SUBJECT IN-REPLY-TO CC REPLYBUFFER ACTIONS 
RETURN-ACTION)" t nil)
+(fn &optional NOERASE TO SUBJECT IN-REPLY-TO CC REPLYBUFFER ACTIONS 
RETURN-ACTION)" t)
 (autoload 'mail-other-window "sendmail" "\
 Like `mail' command, but display mail buffer in another window.
 
-(fn &optional NOERASE TO SUBJECT IN-REPLY-TO CC REPLYBUFFER SENDACTIONS)" t 
nil)
+(fn &optional NOERASE TO SUBJECT IN-REPLY-TO CC REPLYBUFFER SENDACTIONS)" t)
 (autoload 'mail-other-frame "sendmail" "\
 Like `mail' command, but display mail buffer in another frame.
 
-(fn &optional NOERASE TO SUBJECT IN-REPLY-TO CC REPLYBUFFER SENDACTIONS)" t 
nil)
+(fn &optional NOERASE TO SUBJECT IN-REPLY-TO CC REPLYBUFFER SENDACTIONS)" t)
 (register-definition-prefixes "sendmail" '("mail-" "sendmail-"))
 
 
 ;;; Generated autoloads from emacs-lisp/seq.el
 
 (push (purecopy '(seq 2 23)) package--builtin-versions)
-(autoload 'seq-subseq "seq" "\
-Return the sequence of elements of SEQUENCE from START to END.
-END is exclusive.
-
-If END is omitted, it defaults to the length of the sequence.  If
-START or END is negative, it counts from the end.  Signal an
-error if START or END are outside of the sequence (i.e too large
-if positive or too small if negative).
-
-(fn SEQUENCE START &optional END)" nil nil)
-(autoload 'seq-take "seq" "\
-Take the first N elements of SEQUENCE and return the result.
-The result is a sequence of the same type as SEQUENCE.
-
-If N is a negative integer or zero, an empty sequence is
-returned.
-
-(fn SEQUENCE N)" nil nil)
-(autoload 'seq-sort-by "seq" "\
-Sort SEQUENCE using PRED as a comparison function.
-Elements of SEQUENCE are transformed by FUNCTION before being
-sorted.  FUNCTION must be a function of one argument.
-
-(fn FUNCTION PRED SEQUENCE)" nil nil)
-(autoload 'seq-filter "seq" "\
-Return a list of all elements for which (PRED element) is non-nil in SEQUENCE.
-
-(fn PRED SEQUENCE)" nil nil)
-(autoload 'seq-remove "seq" "\
-Return a list of all the elements for which (PRED element) is nil in SEQUENCE.
-
-(fn PRED SEQUENCE)" nil nil)
-(autoload 'seq-reduce "seq" "\
-Reduce the function FUNCTION across SEQUENCE, starting with INITIAL-VALUE.
-
-Return the result of calling FUNCTION with INITIAL-VALUE and the
-first element of SEQUENCE, then calling FUNCTION with that result
-and the second element of SEQUENCE, then with that result and the
-third element of SEQUENCE, etc.  FUNCTION will be called with
-INITIAL-VALUE (and then the accumulated value) as the first
-argument, and the elements from SEQUENCE as the second argument.
-
-If SEQUENCE is empty, return INITIAL-VALUE and FUNCTION is not called.
-
-(fn FUNCTION SEQUENCE INITIAL-VALUE)" nil nil)
-(autoload 'seq-every-p "seq" "\
-Return non-nil if (PRED element) is non-nil for all elements of SEQUENCE.
-
-(fn PRED SEQUENCE)" nil nil)
-(autoload 'seq-some "seq" "\
-Return non-nil if PRED is satisfied for at least one element of SEQUENCE.
-If so, return the first non-nil value returned by PRED.
-
-(fn PRED SEQUENCE)" nil nil)
-(autoload 'seq-find "seq" "\
-Return the first element for which (PRED element) is non-nil in SEQUENCE.
-If no element is found, return DEFAULT.
-
-Note that `seq-find' has an ambiguity if the found element is
-identical to DEFAULT, as it cannot be known if an element was
-found or not.
-
-(fn PRED SEQUENCE &optional DEFAULT)" nil nil)
-(autoload 'seq-position "seq" "\
-Return the index of the first element in SEQUENCE that is equal to ELT.
-Equality is defined by TESTFN if non-nil or by `equal' if nil.
-
-(fn SEQUENCE ELT &optional TESTFN)" nil nil)
-(autoload 'seq-uniq "seq" "\
-Return a list of the elements of SEQUENCE with duplicates removed.
-TESTFN is used to compare elements, or `equal' if TESTFN is nil.
-
-(fn SEQUENCE &optional TESTFN)" nil nil)
-(autoload 'seq-union "seq" "\
-Return a list of all elements that appear in either SEQUENCE1 or SEQUENCE2.
-Equality is defined by TESTFN if non-nil or by `equal' if nil.
-
-(fn SEQUENCE1 SEQUENCE2 &optional TESTFN)" nil nil)
-(autoload 'seq-intersection "seq" "\
-Return a list of the elements that appear in both SEQUENCE1 and SEQUENCE2.
-Equality is defined by TESTFN if non-nil or by `equal' if nil.
-
-(fn SEQUENCE1 SEQUENCE2 &optional TESTFN)" nil nil)
-(autoload 'seq-group-by "seq" "\
-Apply FUNCTION to each element of SEQUENCE.
-Separate the elements of SEQUENCE into an alist using the results as
-keys.  Keys are compared using `equal'.
-
-(fn FUNCTION SEQUENCE)" nil nil)
-(autoload 'seq-max "seq" "\
-Return the largest element of SEQUENCE.
-SEQUENCE must be a sequence of numbers or markers.
-
-(fn SEQUENCE)" nil nil)
-(autoload 'seq-random-elt "seq" "\
-Return a random element from SEQUENCE.
-Signal an error if SEQUENCE is empty.
-
-(fn SEQUENCE)" nil nil)
-(register-definition-prefixes "seq" '("seq-"))
 
 
 ;;; Generated autoloads from server.el
@@ -27412,13 +27316,13 @@ To force-start a server, do \\[server-force-delete] 
and then
 To check from a Lisp program whether a server is running, use
 the `server-process' variable.
 
-(fn &optional LEAVE-DEAD INHIBIT-PROMPT)" t nil)
+(fn &optional LEAVE-DEAD INHIBIT-PROMPT)" t)
 (autoload 'server-force-delete "server" "\
 Unconditionally delete connection file for server NAME.
 If server is running, it is first stopped.
 NAME defaults to `server-name'.  With argument, ask for NAME.
 
-(fn &optional NAME)" t nil)
+(fn &optional NAME)" t)
 (defvar server-mode nil "\
 Non-nil if Server mode is enabled.
 See the `server-mode' command
@@ -27448,7 +27352,7 @@ evaluate `(default-value \\='server-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'server-save-buffers-kill-terminal "server" "\
 Offer to save each buffer, then kill the current client.
 With ARG non-nil, silently save all file-visiting buffers, then kill.
@@ -27456,7 +27360,7 @@ 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.
 
-(fn ARG)" nil nil)
+(fn ARG)")
 (autoload 'server-stop-automatically "server" "\
 Automatically stop server as specified by ARG.
 
@@ -27478,7 +27382,7 @@ 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)" nil nil)
+(fn ARG)")
 (register-definition-prefixes "server" '("server-"))
 
 
@@ -27519,7 +27423,7 @@ part):
 \\{ses-mode-print-map}
 These are active only in the minibuffer, when entering or editing a
 formula:
-\\{ses-mode-edit-map}" t nil)
+\\{ses-mode-edit-map}" t)
 (register-definition-prefixes "ses" '("ses"))
 
 
@@ -27544,7 +27448,7 @@ Do \\[describe-variable] sgml- SPC to see available 
variables.
 Do \\[describe-key] on the following bindings to discover what they do.
 \\{sgml-mode-map}
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'html-mode "sgml-mode" "\
 Major mode based on SGML mode for editing HTML documents.
 This allows inserting skeleton constructs used in hypertext documents with
@@ -27583,7 +27487,7 @@ To work around that, do:
 
 \\{html-mode-map}
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "sgml-mode" '("html-" "sgml-"))
 
 
@@ -27642,7 +27546,7 @@ indicate what shell it is use `sh-alias-alist' to 
translate.
 If your shell gives error messages with line numbers, you can use 
\\[executable-interpret]
 with your script for an edit-interpret-debug cycle.
 
-(fn)" t nil)
+(fn)" t)
 (defalias 'shell-script-mode 'sh-mode)
 (register-definition-prefixes "sh-script" '("sh-"))
 
@@ -27691,7 +27595,7 @@ considered to shadow a later file XXX.el, and 
vice-versa.
 Shadowings are located by calling the (non-interactive) companion
 function, `load-path-shadows-find'.
 
-(fn &optional STRINGP)" t nil)
+(fn &optional STRINGP)" t)
 (register-definition-prefixes "shadow" '("load-path-shadows-"))
 
 
@@ -27705,21 +27609,21 @@ defined by a name, the network address of a primary 
host (the one we copy
 files to), and a regular expression that matches the hostnames of all the
 sites in the cluster.
 
-(fn NAME)" t nil)
+(fn NAME)" t)
 (autoload 'shadow-define-literal-group "shadowfile" "\
 Declare a single file to be shared between sites.
 It may have different filenames on each site.  When this file is edited, the
 new version will be copied to each of the other locations.  Sites can be
-specific hostnames, or names of clusters (see `shadow-define-cluster')." t nil)
+specific hostnames, or names of clusters (see `shadow-define-cluster')." t)
 (autoload 'shadow-define-regexp-group "shadowfile" "\
 Make each of a group of files be shared between hosts.
 Prompts for regular expression; files matching this are shared between a list
 of sites, which are also prompted for.  The filenames must be identical on all
 hosts (if they aren't, use `shadow-define-literal-group' instead of this
 function).  Each site can be either a hostname or the name of a cluster (see
-`shadow-define-cluster')." t nil)
+`shadow-define-cluster')." t)
 (autoload 'shadow-initialize "shadowfile" "\
-Set up file shadowing." t nil)
+Set up file shadowing." t)
 (register-definition-prefixes "shadowfile" '("shadow"))
 
 
@@ -27742,7 +27646,7 @@ Split STRING (a shell command) into a list of strings.
 General shell syntax, like single and double quoting, as well as
 backslash quoting, is respected.
 
-(fn STRING)" nil nil)
+(fn STRING)")
 (autoload 'shell "shell" "\
 Run an inferior shell, with I/O through BUFFER (which defaults to `*shell*').
 Interactively, a prefix arg means to prompt for BUFFER.
@@ -27779,20 +27683,84 @@ Make the shell buffer the current buffer, and return 
it.
 
 (Type \\[describe-mode] in the shell buffer for a list of commands.)
 
-(fn &optional BUFFER FILE-NAME)" t nil)
+(fn &optional BUFFER FILE-NAME)" t)
 (register-definition-prefixes "shell" '("dirs" "explicit-" "shell-"))
 
 
 ;;; Generated autoloads from emacs-lisp/shortdoc.el
 
+(defvar shortdoc--groups nil)
+(defmacro define-short-documentation-group (group &rest functions) "\
+Add GROUP to the list of defined documentation groups.
+FUNCTIONS is a list of elements on the form:
+
+  (FUNC
+   :no-manual BOOL
+   :args ARGS
+   :eval EVAL
+   :no-eval EXAMPLE-FORM
+   :no-value EXAMPLE-FORM
+   :no-eval* EXAMPLE-FORM
+   :result RESULT-FORM
+   :result-string RESULT-STRING
+   :eg-result RESULT-FORM
+   :eg-result-string RESULT-STRING)
+
+FUNC is the function being documented.
+
+NO-MANUAL should be non-nil if FUNC isn't documented in the
+manual.
+
+ARGS is optional list of function FUNC's arguments.  FUNC's
+signature is displayed automatically if ARGS is not present.
+Specifying ARGS might be useful where you don't want to document
+some of the uncommon arguments a function might have.
+
+While the `:no-manual' and `:args' property can be used for
+any (FUNC ..) form, all of the other properties shown above
+cannot be used simultaneously in such a form.
+
+Here are some common forms with examples of properties that go
+together:
+
+1. Document a form or string, and its evaluated return value.
+   (FUNC
+    :eval EVAL)
+
+If EVAL is a string, it will be inserted as is, and then that
+string will be `read' and evaluated.
+
+2. Document a form or string, but manually document its evaluation
+   result.  The provided form will not be evaluated.
+
+  (FUNC
+   :no-eval EXAMPLE-FORM
+   :result RESULT-FORM)   ;Use `:result-string' if value is in string form
+
+Using `:no-value' is the same as using `:no-eval'.
+
+Use `:no-eval*' instead of `:no-eval' where the successful
+execution of the documented form depends on some conditions.
+
+3. Document a form or string EXAMPLE-FORM.  Also manually
+   document an example result.  This result could be unrelated to
+   the documented form.
+
+  (FUNC
+   :no-eval EXAMPLE-FORM
+   :eg-result RESULT-FORM) ;Use `:eg-result-string' if value is in string form
+
+A FUNC form can have any number of `:no-eval' (or `:no-value'),
+`:no-eval*', `:result', `:result-string', `:eg-result' and
+`:eg-result-string' properties." (declare (indent defun)) `(progn (setq 
shortdoc--groups (delq (assq ',group shortdoc--groups) shortdoc--groups)) (push 
(cons ',group ',functions) shortdoc--groups)))
 (autoload 'shortdoc-display-group "shortdoc" "\
 Pop to a buffer with short documentation summary for functions in GROUP.
 If FUNCTION is non-nil, place point on the entry for FUNCTION (if any).
 If SAME-WINDOW, don't pop to a new window.
 
-(fn GROUP &optional FUNCTION SAME-WINDOW)" t nil)
+(fn GROUP &optional FUNCTION SAME-WINDOW)" t)
 (defalias 'shortdoc #'shortdoc-display-group)
-(register-definition-prefixes "shortdoc" '("alist" "buffer" 
"define-short-documentation-group" "file" "hash-table" "keymaps" "list" 
"number" "overlay" "process" "regexp" "sequence" "shortdoc-" "string" 
"text-properties" "vector"))
+(register-definition-prefixes "shortdoc" '("shortdoc-"))
 
 
 ;;; Generated autoloads from net/shr.el
@@ -27800,13 +27768,13 @@ If SAME-WINDOW, don't pop to a new window.
 (autoload 'shr-render-region "shr" "\
 Display the HTML rendering of the region between BEGIN and END.
 
-(fn BEGIN END &optional BUFFER)" t nil)
+(fn BEGIN END &optional BUFFER)" t)
 (autoload 'shr-insert-document "shr" "\
 Render the parsed document DOM into the current buffer.
 DOM should be a parse tree as generated by
 `libxml-parse-html-region' or similar.
 
-(fn DOM)" nil nil)
+(fn DOM)")
 (register-definition-prefixes "shr" '("shr-"))
 
 
@@ -27820,19 +27788,19 @@ DOM should be a parse tree as generated by
 (autoload 'sieve-manage "sieve" "\
 
 
-(fn SERVER &optional PORT)" t nil)
+(fn SERVER &optional PORT)" t)
 (autoload 'sieve-upload "sieve" "\
 
 
-(fn &optional NAME)" t nil)
+(fn &optional NAME)" t)
 (autoload 'sieve-upload-and-bury "sieve" "\
 
 
-(fn &optional NAME)" t nil)
+(fn &optional NAME)" t)
 (autoload 'sieve-upload-and-kill "sieve" "\
 
 
-(fn &optional NAME)" t nil)
+(fn &optional NAME)" t)
 (register-definition-prefixes "sieve" '("sieve-"))
 
 
@@ -27847,7 +27815,7 @@ DOM should be a parse tree as generated by
 Major mode for editing Sieve code.
 Turning on Sieve mode runs `sieve-mode-hook'.
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "sieve-mode" '("sieve-"))
 
 
@@ -27896,7 +27864,7 @@ Variables controlling indentation style:
 Turning on SIMULA mode calls the value of the variable simula-mode-hook
 with no arguments, if that value is non-nil.
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "simula" '("simula-"))
 
 
@@ -27915,7 +27883,7 @@ DOCUMENTATION is that of the command.
 SKELETON is as defined under `skeleton-insert'.
 
 (fn COMMAND DOCUMENTATION &rest SKELETON)" nil t)
-(function-put 'define-skeleton 'doc-string-elt '2)
+(function-put 'define-skeleton 'doc-string-elt 2)
 (function-put 'define-skeleton 'lisp-indent-function 'defun)
 (autoload 'skeleton-proxy-new "skeleton" "\
 Insert SKELETON.
@@ -27928,7 +27896,7 @@ This command can also be an abbrev expansion (3rd and 
4th columns in
 Optional second argument STR may also be a string which will be the value
 of `str' whereas the skeleton's interactor is then ignored.
 
-(fn SKELETON &optional STR ARG)" nil nil)
+(fn SKELETON &optional STR ARG)")
 (autoload 'skeleton-insert "skeleton" "\
 Insert the complex statement skeleton SKELETON describes very concisely.
 
@@ -28000,7 +27968,7 @@ available:
        input   initial input (string or cons with index) while reading str
        v1, v2  local variables for memorizing anything you want
 
-(fn SKELETON &optional REGIONS STR)" nil nil)
+(fn SKELETON &optional REGIONS STR)")
 (autoload 'skeleton-pair-insert-maybe "skeleton" "\
 Insert the character you type ARG times.
 
@@ -28016,7 +27984,7 @@ the defaults are used.  These are (), [], {}, <> and 
(grave
 accent, apostrophe) for the paired ones, and the same character
 twice for the others.
 
-(fn ARG)" t nil)
+(fn ARG)" t)
 (register-definition-prefixes "skeleton" '("skeleton-"))
 
 
@@ -28037,13 +28005,13 @@ If non-nil, PREPROC is called with no argument in a 
buffer that contains
 a copy of a region, just before preparing it to for `diff'.  It can be
 used to replace chars to try and eliminate some spurious differences.
 
-(fn BEG1 END1 BEG2 END2 PROPS-C &optional PREPROC PROPS-R PROPS-A)" nil nil)
+(fn BEG1 END1 BEG2 END2 PROPS-C &optional PREPROC PROPS-R PROPS-A)")
 (autoload 'smerge-ediff "smerge-mode" "\
 Invoke ediff to resolve the conflicts.
 NAME-UPPER, NAME-LOWER, and NAME-BASE, if non-nil, are used for the
 buffer names.
 
-(fn &optional NAME-UPPER NAME-LOWER NAME-BASE)" t nil)
+(fn &optional NAME-UPPER NAME-LOWER NAME-BASE)" t)
 (autoload 'smerge-mode "smerge-mode" "\
 Minor mode to simplify editing output from the diff3 program.
 
@@ -28063,12 +28031,12 @@ evaluate `smerge-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'smerge-start-session "smerge-mode" "\
 Turn on `smerge-mode' and move point to first conflict marker.
 If no conflict maker is found, turn off `smerge-mode'.
 
-(fn &optional INTERACTIVELY)" t nil)
+(fn &optional INTERACTIVELY)" t)
 (register-definition-prefixes "smerge-mode" '("smerge-"))
 
 
@@ -28083,12 +28051,12 @@ If no conflict maker is found, turn off `smerge-mode'.
 Replace in the region `smiley-regexp-alist' matches with corresponding images.
 A list of images is returned.
 
-(fn START END)" t nil)
+(fn START END)" t)
 (autoload 'smiley-buffer "smiley" "\
 Run `smiley-region' at the BUFFER, specified in the argument or
 interactively.  If there's no argument, do it at the current buffer.
 
-(fn &optional BUFFER)" t nil)
+(fn &optional BUFFER)" t)
 (register-definition-prefixes "smiley" '("gnus-smiley-file-types" "smiley-"))
 
 
@@ -28099,9 +28067,9 @@ interactively.  If there's no argument, do it at the 
current buffer.
 
 ;;; Generated autoloads from mail/smtpmail.el
 
-(autoload 'smtpmail-send-it "smtpmail" nil nil nil)
+(autoload 'smtpmail-send-it "smtpmail")
 (autoload 'smtpmail-send-queued-mail "smtpmail" "\
-Send mail that was queued as a result of setting `smtpmail-queue-mail'." t nil)
+Send mail that was queued as a result of setting `smtpmail-queue-mail'." t)
 (register-definition-prefixes "smtpmail" '("smtpmail-"))
 
 
@@ -28121,7 +28089,7 @@ Snake mode keybindings:
 \\[snake-move-left]    Makes the snake move left
 \\[snake-move-right]   Makes the snake move right
 \\[snake-move-up]      Makes the snake move up
-\\[snake-move-down]    Makes the snake move down" t nil)
+\\[snake-move-down]    Makes the snake move down" t)
 (register-definition-prefixes "snake" '("snake-"))
 
 
@@ -28135,7 +28103,7 @@ Comments start with -- and end with newline or another 
--.
 Delete converts tabs to spaces as it moves back.
 \\{snmp-mode-map}
 Turning on `snmp-mode' runs the hooks in `snmp-common-mode-hook', then
-`snmp-mode-hook'." t nil)
+`snmp-mode-hook'." t)
 (autoload 'snmpv2-mode "snmp-mode" "\
 Major mode for editing SNMPv2 MIBs.
 Expression and list commands understand all C brackets.
@@ -28144,7 +28112,7 @@ Comments start with -- and end with newline or another 
--.
 Delete converts tabs to spaces as it moves back.
 \\{snmp-mode-map}
 Turning on `snmp-mode' runs the hooks in `snmp-common-mode-hook',
-then `snmpv2-mode-hook'." t nil)
+then `snmpv2-mode-hook'." t)
 (register-definition-prefixes "snmp-mode" '("snmp"))
 
 
@@ -28152,9 +28120,9 @@ then `snmpv2-mode-hook'." t nil)
 
 (push (purecopy '(so-long 1 1 2)) package--builtin-versions)
 (autoload 'so-long-commentary "so-long" "\
-View the `so-long' library's documentation in `outline-mode'." t nil)
+View the `so-long' library's documentation in `outline-mode'." t)
 (autoload 'so-long-customize "so-long" "\
-Open the customization group `so-long'." t nil)
+Open the customization group `so-long'." t)
 (autoload 'so-long-minor-mode "so-long" "\
 This is the minor mode equivalent of `so-long-mode'.
 
@@ -28178,7 +28146,7 @@ evaluate `so-long-minor-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'so-long-mode "so-long" "\
 This major mode is the default `so-long-action' option.
 
@@ -28204,9 +28172,9 @@ values), despite potential performance issues, type 
\\[so-long-revert].
 Use \\[so-long-commentary] for more information.
 
 Use \\[so-long-customize] to open the customization group `so-long' to
-configure the behaviour.
+configure the behavior.
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'so-long "so-long" "\
 Invoke `so-long-action' and run `so-long-hook'.
 
@@ -28222,11 +28190,11 @@ With a prefix argument, select the action to use 
interactively.
 If an action was already active in the buffer, it will be reverted before
 invoking the new action.
 
-(fn &optional ACTION)" t nil)
+(fn &optional ACTION)" t)
 (autoload 'so-long-enable "so-long" "\
 Enable the `so-long' library's functionality.
 
-Equivalent to calling (global-so-long-mode 1)" t nil)
+Equivalent to calling (global-so-long-mode 1)" t)
 (defvar global-so-long-mode nil "\
 Non-nil if Global So-Long mode is enabled.
 See the `global-so-long-mode' command
@@ -28251,7 +28219,7 @@ When such files are detected by `so-long-predicate', we 
invoke the selected
 Use \\[so-long-commentary] for more information.
 
 Use \\[so-long-customize] to open the customization group `so-long' to
-configure the behaviour.
+configure the behavior.
 
 This is a global minor mode.  If called interactively, toggle the
 `Global So-Long mode' mode.  If the prefix argument is positive,
@@ -28267,7 +28235,7 @@ evaluate `(default-value \\='global-so-long-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "so-long" '("so-long-" "turn-o"))
 
 
@@ -28297,7 +28265,7 @@ longitude, latitude, time zone, and date, and always 
use standard time.
 
 This function is suitable for execution in an init file.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "solar" '("calendar-" "diary-sunrise-sunset" 
"solar-"))
 
 
@@ -28371,7 +28339,7 @@ Pick your favorite shortcuts:
 
 \\{solitaire-mode-map}
 
-(fn ARG)" t nil)
+(fn ARG)" t)
 (register-definition-prefixes "solitaire" '("solitaire-"))
 
 
@@ -28427,7 +28395,7 @@ the keys are numbers, with `compare-buffer-substrings' 
if the
 keys are cons cells (the car and cdr of each cons cell are taken
 as start and end positions), and with `string<' otherwise.
 
-(fn REVERSE NEXTRECFUN ENDRECFUN &optional STARTKEYFUN ENDKEYFUN PREDICATE)" 
nil nil)
+(fn REVERSE NEXTRECFUN ENDRECFUN &optional STARTKEYFUN ENDKEYFUN PREDICATE)")
 (autoload 'sort-lines "sort" "\
 Sort lines in region alphabetically; REVERSE non-nil means descending order.
 Interactively, REVERSE is the prefix argument, and BEG and END are the region.
@@ -28436,7 +28404,7 @@ REVERSE (non-nil means reverse order), BEG and END 
(region to sort).
 The variable `sort-fold-case' determines whether alphabetic case affects
 the sort order.
 
-(fn REVERSE BEG END)" t nil)
+(fn REVERSE BEG END)" t)
 (autoload 'sort-paragraphs "sort" "\
 Sort paragraphs in region alphabetically; argument means descending order.
 Called from a program, there are three arguments:
@@ -28444,7 +28412,7 @@ REVERSE (non-nil means reverse order), BEG and END 
(region to sort).
 The variable `sort-fold-case' determines whether alphabetic case affects
 the sort order.
 
-(fn REVERSE BEG END)" t nil)
+(fn REVERSE BEG END)" t)
 (autoload 'sort-pages "sort" "\
 Sort pages in region alphabetically; argument means descending order.
 Called from a program, there are three arguments:
@@ -28452,7 +28420,7 @@ REVERSE (non-nil means reverse order), BEG and END 
(region to sort).
 The variable `sort-fold-case' determines whether alphabetic case affects
 the sort order.
 
-(fn REVERSE BEG END)" t nil)
+(fn REVERSE BEG END)" t)
 (put 'sort-numeric-base 'safe-local-variable 'integerp)
 (autoload 'sort-numeric-fields "sort" "\
 Sort lines in region numerically by the ARGth field of each line.
@@ -28464,7 +28432,7 @@ With a negative arg, sorts by the ARGth field counted 
from the right.
 Called from a program, there are three arguments:
 FIELD, BEG and END.  BEG and END specify region to sort.
 
-(fn FIELD BEG END)" t nil)
+(fn FIELD BEG END)" t)
 (autoload 'sort-fields "sort" "\
 Sort lines in region lexicographically by the ARGth field of each line.
 Fields are separated by whitespace and numbered from 1 up.
@@ -28474,7 +28442,7 @@ FIELD, BEG and END.  BEG and END specify region to sort.
 The variable `sort-fold-case' determines whether alphabetic case affects
 the sort order.
 
-(fn FIELD BEG END)" t nil)
+(fn FIELD BEG END)" t)
 (autoload 'sort-regexp-fields "sort" "\
 Sort the text in the region lexicographically.
 If called interactively, prompt for two regular expressions,
@@ -28501,7 +28469,7 @@ For example: to sort lines in the region by the first 
word on each line
  starting with the letter \"f\",
  RECORD-REGEXP would be \"^.*$\" and KEY would be \"\\\\=\\<f\\\\w*\\\\>\"
 
-(fn REVERSE RECORD-REGEXP KEY-REGEXP BEG END)" t nil)
+(fn REVERSE RECORD-REGEXP KEY-REGEXP BEG END)" t)
 (autoload 'sort-columns "sort" "\
 Sort lines in region alphabetically by a certain range of columns.
 For the purpose of this command, the region BEG...END includes
@@ -28517,7 +28485,7 @@ and it doesn't know how to handle that.  Also, when 
possible,
 it uses the `sort' utility program, which doesn't understand tabs.
 Use \\[untabify] to convert tabs to spaces before sorting.
 
-(fn REVERSE &optional BEG END)" t nil)
+(fn REVERSE &optional BEG END)" t)
 (autoload 'reverse-region "sort" "\
 Reverse the order of lines in a region.
 When called from Lisp, takes two point or marker arguments, BEG and END.
@@ -28526,7 +28494,7 @@ to be reversed is the line starting after BEG.
 If END is not at the end of a line, the last line to be reversed
 is the one that ends before END.
 
-(fn BEG END)" t nil)
+(fn BEG END)" t)
 (autoload 'delete-duplicate-lines "sort" "\
 Delete all but one copy of any identical lines in the region.
 Non-interactively, arguments BEG and END delimit the region.
@@ -28546,7 +28514,7 @@ If the argument KEEP-BLANKS is non-nil (interactively, 
with a
 Returns the number of deleted lines.  Interactively, or if INTERACTIVE
 is non-nil, it also prints a message describing the number of deletions.
 
-(fn BEG END &optional REVERSE ADJACENT KEEP-BLANKS INTERACTIVE)" t nil)
+(fn BEG END &optional REVERSE ADJACENT KEEP-BLANKS INTERACTIVE)" t)
 (register-definition-prefixes "sort" '("sort-"))
 
 
@@ -28569,8 +28537,8 @@ can call `spam-initialize' before you set spam-use-* 
variables on
 explicitly, and matters only if you need the extra headers
 installed through `spam-necessary-extra-headers'.
 
-(fn &rest SYMBOLS)" t nil)
-(register-definition-prefixes "spam" '(":keymap" "spam-"))
+(fn &rest SYMBOLS)" t)
+(register-definition-prefixes "spam" '("spam-"))
 
 
 ;;; Generated autoloads from gnus/spam-report.el
@@ -28582,27 +28550,27 @@ If FILE is given, use it instead of 
`spam-report-requests-file'.
 If KEEP is t, leave old requests in the file.  If KEEP is the
 symbol `ask', query before flushing the queue file.
 
-(fn &optional FILE KEEP)" t nil)
+(fn &optional FILE KEEP)" t)
 (autoload 'spam-report-url-ping-mm-url "spam-report" "\
 Ping a host through HTTP, addressing a specific GET resource.
 Use the external program specified in `mm-url-program' to connect
 to server.
 
-(fn HOST REPORT)" nil nil)
+(fn HOST REPORT)")
 (autoload 'spam-report-url-to-file "spam-report" "\
 Collect spam report requests in `spam-report-requests-file'.
 Customize `spam-report-url-ping-function' to use this function.
 
-(fn HOST REPORT)" nil nil)
+(fn HOST REPORT)")
 (autoload 'spam-report-agentize "spam-report" "\
 Add spam-report support to the Agent.
 Spam reports will be queued with \\[spam-report-url-to-file] when
 the Agent is unplugged, and will be submitted in a batch when the
-Agent is plugged." t nil)
+Agent is plugged." t)
 (autoload 'spam-report-deagentize "spam-report" "\
 Remove spam-report support from the Agent.
 Spam reports will be queued with the method used when
-\\[spam-report-agentize] was run." t nil)
+\\[spam-report-agentize] was run." t)
 (register-definition-prefixes "spam-report" '("spam-report-"))
 
 
@@ -28632,20 +28600,20 @@ supported at a time.
 `speedbar-before-popup-hook' is called before popping up the speedbar frame.
 `speedbar-before-delete-hook' is called before the frame is deleted.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'speedbar-get-focus "speedbar" "\
 Change frame focus to or from the speedbar frame.
 If the selected frame is not speedbar, then speedbar frame is
-selected.  If the speedbar frame is active, then select the attached frame." t 
nil)
+selected.  If the speedbar frame is active, then select the attached frame." t)
 (register-definition-prefixes "speedbar" '("speedbar-"))
 
 
 ;;; Generated autoloads from play/spook.el
 
 (autoload 'spook "spook" "\
-Add that special touch of class to your outgoing mail." t nil)
+Add that special touch of class to your outgoing mail." t)
 (autoload 'snarf-spooks "spook" "\
-Return a vector containing the lines from `spook-phrases-file'." nil nil)
+Return a vector containing the lines from `spook-phrases-file'.")
 (register-definition-prefixes "spook" '("spook-phrase"))
 
 
@@ -28671,7 +28639,7 @@ For example:
 adds a fontification pattern to fontify identifiers ending in
 `_t' as data types.
 
-(fn PRODUCT KEYWORDS &optional APPEND)" nil nil)
+(fn PRODUCT KEYWORDS &optional APPEND)")
 (autoload 'sql-mode "sql" "\
 Major mode to edit SQL.
 
@@ -28700,7 +28668,7 @@ must tell Emacs.  Here's how to do that in your init 
file:
           (lambda ()
            (modify-syntax-entry ?\\\\ \"\\\\\" sql-mode-syntax-table)))
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'sql-connect "sql" "\
 Connect to an interactive session using CONNECTION settings.
 
@@ -28710,7 +28678,7 @@ their settings.
 The user will not be prompted for any login parameters if a value
 is specified in the connection settings.
 
-(fn CONNECTION &optional BUF-NAME)" t nil)
+(fn CONNECTION &optional BUF-NAME)" t)
 (autoload 'sql-product-interactive "sql" "\
 Run PRODUCT interpreter as an inferior process.
 
@@ -28724,7 +28692,7 @@ the call to \\[sql-product-interactive] with
 
 (Type \\[describe-mode] in the SQL buffer for a list of commands.)
 
-(fn &optional PRODUCT NEW-NAME)" t nil)
+(fn &optional PRODUCT NEW-NAME)" t)
 (autoload 'sql-oracle "sql" "\
 Run sqlplus by Oracle as an inferior process.
 
@@ -28754,7 +28722,7 @@ The default comes from `process-coding-system-alist' and
 
 (Type \\[describe-mode] in the SQL buffer for a list of commands.)
 
-(fn &optional BUFFER)" t nil)
+(fn &optional BUFFER)" t)
 (autoload 'sql-sybase "sql" "\
 Run isql by Sybase as an inferior process.
 
@@ -28784,7 +28752,7 @@ The default comes from `process-coding-system-alist' and
 
 (Type \\[describe-mode] in the SQL buffer for a list of commands.)
 
-(fn &optional BUFFER)" t nil)
+(fn &optional BUFFER)" t)
 (autoload 'sql-informix "sql" "\
 Run dbaccess by Informix as an inferior process.
 
@@ -28812,7 +28780,7 @@ The default comes from `process-coding-system-alist' and
 
 (Type \\[describe-mode] in the SQL buffer for a list of commands.)
 
-(fn &optional BUFFER)" t nil)
+(fn &optional BUFFER)" t)
 (autoload 'sql-sqlite "sql" "\
 Run sqlite as an inferior process.
 
@@ -28844,7 +28812,7 @@ The default comes from `process-coding-system-alist' and
 
 (Type \\[describe-mode] in the SQL buffer for a list of commands.)
 
-(fn &optional BUFFER)" t nil)
+(fn &optional BUFFER)" t)
 (autoload 'sql-mysql "sql" "\
 Run mysql by TcX as an inferior process.
 
@@ -28876,7 +28844,7 @@ The default comes from `process-coding-system-alist' and
 
 (Type \\[describe-mode] in the SQL buffer for a list of commands.)
 
-(fn &optional BUFFER)" t nil)
+(fn &optional BUFFER)" t)
 (autoload 'sql-mariadb "sql" "\
 Run mysql by MariaDB as an inferior process.
 
@@ -28908,7 +28876,7 @@ The default comes from `process-coding-system-alist' and
 
 (Type \\[describe-mode] in the SQL buffer for a list of commands.)
 
-(fn &optional BUFFER)" t nil)
+(fn &optional BUFFER)" t)
 (autoload 'sql-solid "sql" "\
 Run solsql by Solid as an inferior process.
 
@@ -28937,7 +28905,7 @@ The default comes from `process-coding-system-alist' and
 
 (Type \\[describe-mode] in the SQL buffer for a list of commands.)
 
-(fn &optional BUFFER)" t nil)
+(fn &optional BUFFER)" t)
 (autoload 'sql-ingres "sql" "\
 Run sql by Ingres as an inferior process.
 
@@ -28965,7 +28933,7 @@ The default comes from `process-coding-system-alist' and
 
 (Type \\[describe-mode] in the SQL buffer for a list of commands.)
 
-(fn &optional BUFFER)" t nil)
+(fn &optional BUFFER)" t)
 (autoload 'sql-ms "sql" "\
 Run osql by Microsoft as an inferior process.
 
@@ -28995,7 +28963,7 @@ The default comes from `process-coding-system-alist' and
 
 (Type \\[describe-mode] in the SQL buffer for a list of commands.)
 
-(fn &optional BUFFER)" t nil)
+(fn &optional BUFFER)" t)
 (autoload 'sql-postgres "sql" "\
 Run psql by Postgres as an inferior process.
 
@@ -29029,7 +28997,7 @@ Try to set `comint-output-filter-functions' like this:
 
 (Type \\[describe-mode] in the SQL buffer for a list of commands.)
 
-(fn &optional BUFFER)" t nil)
+(fn &optional BUFFER)" t)
 (autoload 'sql-interbase "sql" "\
 Run isql by Interbase as an inferior process.
 
@@ -29058,7 +29026,7 @@ The default comes from `process-coding-system-alist' and
 
 (Type \\[describe-mode] in the SQL buffer for a list of commands.)
 
-(fn &optional BUFFER)" t nil)
+(fn &optional BUFFER)" t)
 (autoload 'sql-db2 "sql" "\
 Run db2 by IBM as an inferior process.
 
@@ -29091,7 +29059,7 @@ The default comes from `process-coding-system-alist' and
 
 (Type \\[describe-mode] in the SQL buffer for a list of commands.)
 
-(fn &optional BUFFER)" t nil)
+(fn &optional BUFFER)" t)
 (autoload 'sql-linter "sql" "\
 Run inl by RELEX as an inferior process.
 
@@ -29121,11 +29089,11 @@ buffer.
 
 (Type \\[describe-mode] in the SQL buffer for a list of commands.)
 
-(fn &optional BUFFER)" t nil)
+(fn &optional BUFFER)" t)
 (autoload 'sql-vertica "sql" "\
 Run vsql as an inferior process.
 
-(fn &optional BUFFER)" t nil)
+(fn &optional BUFFER)" t)
 (register-definition-prefixes "sql" '("sql-"))
 
 
@@ -29139,7 +29107,7 @@ Run vsql as an inferior process.
 (autoload 'sqlite-mode-open-file "sqlite-mode" "\
 Browse the contents of an sqlite file.
 
-(fn FILE)" t nil)
+(fn FILE)" t)
 (register-definition-prefixes "sqlite-mode" '("sqlite-"))
 
 
@@ -29164,7 +29132,7 @@ Browse the contents of an sqlite file.
 (autoload 'srecode-template-mode "srecode/srt-mode" "\
 Major-mode for writing SRecode macros.
 
-(fn)" t nil)
+(fn)" t)
 (defalias 'srt-mode #'srecode-template-mode)
 (register-definition-prefixes "srecode/srt-mode" '("semantic-" "srecode-"))
 
@@ -29183,7 +29151,7 @@ PROMPT will be inserted at the start of the buffer, but 
won't be
 included in the resulting string.  If PROMPT is nil, no help text
 will be inserted.
 
-(fn PROMPT STRING SUCCESS-CALLBACK &key ABORT-CALLBACK)" nil nil)
+(fn PROMPT STRING SUCCESS-CALLBACK &key ABORT-CALLBACK)")
 (autoload 'read-string-from-buffer "string-edit" "\
 Switch to a new buffer to edit STRING in a recursive edit.
 The user finishes editing with \\<string-edit-mode-map>\\[string-edit-done], 
or aborts with \\<string-edit-mode-map>\\[string-edit-abort]).
@@ -29192,7 +29160,7 @@ PROMPT will be inserted at the start of the buffer, but 
won't be
 included in the resulting string.  If nil, no prompt will be
 inserted in the buffer.
 
-(fn PROMPT STRING)" nil nil)
+(fn PROMPT STRING)")
 (register-definition-prefixes "string-edit" '("string-edit-"))
 
 
@@ -29207,7 +29175,7 @@ documentation for the `strokes-define-stroke' function.
 
 See also `strokes-global-set-stroke-string'.
 
-(fn STROKE COMMAND)" t nil)
+(fn STROKE COMMAND)" t)
 (autoload 'strokes-read-stroke "strokes" "\
 Read a simple stroke (interactively) and return the stroke.
 Optional PROMPT in minibuffer displays before and during stroke reading.
@@ -29216,7 +29184,7 @@ entered in the strokes buffer if the variable
 `strokes-use-strokes-buffer' is non-nil.
 Optional EVENT is acceptable as the starting event of the stroke.
 
-(fn &optional PROMPT EVENT)" nil nil)
+(fn &optional PROMPT EVENT)")
 (autoload 'strokes-read-complex-stroke "strokes" "\
 Read a complex stroke (interactively) and return the stroke.
 Optional PROMPT in minibuffer displays before and during stroke reading.
@@ -29225,32 +29193,32 @@ is implemented by allowing the user to paint with 
button 1 or button 2 and
 then complete the stroke with button 3.
 Optional EVENT is acceptable as the starting event of the stroke.
 
-(fn &optional PROMPT EVENT)" nil nil)
+(fn &optional PROMPT EVENT)")
 (autoload 'strokes-do-stroke "strokes" "\
 Read a simple stroke from the user and then execute its command.
 This must be bound to a mouse event.
 
-(fn EVENT)" t nil)
+(fn EVENT)" t)
 (autoload 'strokes-do-complex-stroke "strokes" "\
 Read a complex stroke from the user and then execute its command.
 This must be bound to a mouse event.
 
-(fn EVENT)" t nil)
+(fn EVENT)" t)
 (autoload 'strokes-describe-stroke "strokes" "\
 Displays the command which STROKE maps to, reading STROKE interactively.
 
-(fn STROKE)" t nil)
+(fn STROKE)" t)
 (autoload 'strokes-help "strokes" "\
-Get instruction on using the Strokes package." t nil)
+Get instruction on using the Strokes package." t)
 (autoload 'strokes-load-user-strokes "strokes" "\
-Load user-defined strokes from file named by `strokes-file'." t nil)
+Load user-defined strokes from file named by `strokes-file'." t)
 (autoload 'strokes-list-strokes "strokes" "\
 Pop up a buffer containing an alphabetical listing of strokes in STROKES-MAP.
 With CHRONOLOGICAL prefix arg (\\[universal-argument]) list strokes 
chronologically
 by command name.
 If STROKES-MAP is not given, `strokes-global-map' will be used instead.
 
-(fn &optional CHRONOLOGICAL STROKES-MAP)" t nil)
+(fn &optional CHRONOLOGICAL STROKES-MAP)" t)
 (defvar strokes-mode nil "\
 Non-nil if Strokes mode is enabled.
 See the `strokes-mode' command
@@ -29289,15 +29257,15 @@ evaluate `(default-value \\='strokes-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'strokes-decode-buffer "strokes" "\
 Decode stroke strings in BUFFER and display their corresponding glyphs.
 Optional BUFFER defaults to the current buffer.
 Optional FORCE non-nil will ignore the buffer's read-only status.
 
-(fn &optional BUFFER FORCE)" t nil)
+(fn &optional BUFFER FORCE)" t)
 (autoload 'strokes-compose-complex-stroke "strokes" "\
-Read a complex stroke and insert its glyph into the current buffer." t nil)
+Read a complex stroke and insert its glyph into the current buffer." t)
 (register-definition-prefixes "strokes" '("strokes-"))
 
 
@@ -29306,37 +29274,53 @@ Read a complex stroke and insert its glyph into the 
current buffer." t nil)
 (autoload 'studlify-region "studly" "\
 Studlify-case the region.
 
-(fn BEGIN END)" t nil)
+(fn BEGIN END)" t)
 (autoload 'studlify-word "studly" "\
 Studlify-case the current word, or COUNT words if given an argument.
 
-(fn COUNT)" t nil)
+(fn COUNT)" t)
 (autoload 'studlify-buffer "studly" "\
-Studlify-case the current buffer." t nil)
+Studlify-case the current buffer." t)
 
 
 ;;; Generated autoloads from emacs-lisp/subr-x.el
 
 (autoload 'string-truncate-left "subr-x" "\
-Truncate STRING to LENGTH, replacing initial surplus with \"...\".
-
-(fn STRING LENGTH)" nil nil)
+If STRING is longer than LENGTH, return a truncated version.
+When truncating, \"...\" is always prepended to the string, so
+the resulting string may be longer than the original if LENGTH is
+3 or smaller.
+
+(fn STRING LENGTH)")
+(defsubst string-blank-p (string) "\
+Check whether STRING is either empty or only whitespace.
+The following characters count as whitespace here: space, tab, newline and
+carriage return." (string-match-p "\\`[ \11\n\15]*\\'" string))
 (autoload 'string-clean-whitespace "subr-x" "\
 Clean up whitespace in STRING.
 All sequences of whitespaces in STRING are collapsed into a
 single space character, and leading/trailing whitespace is
 removed.
 
-(fn STRING)" nil nil)
+(fn STRING)")
+(autoload 'named-let "subr-x" "\
+Looping construct taken from Scheme.
+Like `let', bind variables in BINDINGS and then evaluate BODY,
+but with the twist that BODY can evaluate itself recursively by
+calling NAME, where the arguments passed to NAME are used
+as the new values of the bound variables in the recursive invocation.
+
+(fn NAME BINDINGS &rest BODY)" nil t)
+(function-put 'named-let 'lisp-indent-function 2)
 (autoload 'string-pixel-width "subr-x" "\
 Return the width of STRING in pixels.
 
-(fn STRING)" nil nil)
+(fn STRING)")
 (autoload 'string-glyph-split "subr-x" "\
 Split STRING into a list of strings representing separate glyphs.
 This takes into account combining characters and grapheme clusters.
 
-(fn STRING)" nil nil)
+(fn STRING)")
 (autoload 'add-display-text-property "subr-x" "\
 Add display property PROP with VALUE to the text from START to END.
 If any text in the region has a non-nil `display' property, those
@@ -29345,18 +29329,17 @@ properties are retained.
 If OBJECT is non-nil, it should be a string or a buffer.  If nil,
 this defaults to the current buffer.
 
-(fn START END PROP VALUE &optional OBJECT)" nil nil)
+(fn START END PROP VALUE &optional OBJECT)")
 (autoload 'read-process-name "subr-x" "\
 Query the user for a process and return the process object.
 
-(fn PROMPT)" nil nil)
-(register-definition-prefixes "subr-x" '("hash-table-" 
"internal--thread-argument" "named-let" "replace-region-contents" "string-" 
"thread-" "with-"))
+(fn PROMPT)")
+(register-definition-prefixes "subr-x" '("emacs-etc--hide-local-variables" 
"hash-table-" "internal--thread-argument" "replace-region-contents" "string-" 
"thread-" "with-buffer-unmodified-if-unchanged"))
 
 
 ;;; Generated autoloads from progmodes/subword.el
 
-(define-obsolete-function-alias 'capitalized-words-mode 'subword-mode "\
-25.1")
+(define-obsolete-function-alias 'capitalized-words-mode 'subword-mode "25.1")
 (autoload 'subword-mode "subword" "\
 Toggle subword movement and editing (Subword mode).
 
@@ -29392,7 +29375,7 @@ evaluate `subword-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (put 'global-subword-mode 'globalized-minor-mode t)
 (defvar global-subword-mode nil "\
 Non-nil if Global Subword mode is enabled.
@@ -29416,7 +29399,7 @@ Subword mode is enabled in all buffers where `(lambda 
nil
 
 See `subword-mode' for more information on Subword mode.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'superword-mode "subword" "\
 Toggle superword movement and editing (Superword mode).
 
@@ -29441,7 +29424,7 @@ evaluate `superword-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (put 'global-superword-mode 'globalized-minor-mode t)
 (defvar global-superword-mode nil "\
 Non-nil if Global Superword mode is enabled.
@@ -29465,7 +29448,7 @@ Superword mode is enabled in all buffers where `(lambda 
nil
 
 See `superword-mode' for more information on Superword mode.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "subword" '("subword-" "superword-mode-map"))
 
 
@@ -29494,7 +29477,7 @@ original message but it does require a few things:
 
 The region need not be active (and typically isn't when this
 function is called).  Also, the hook `sc-pre-hook' is run before,
-and `sc-post-hook' is run after the guts of this function." nil nil)
+and `sc-post-hook' is run after the guts of this function.")
 (register-definition-prefixes "supercite" '("sc-"))
 
 
@@ -29544,7 +29527,7 @@ evaluate `(default-value \\='gpm-mouse-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "t-mouse" '("gpm-mouse-"))
 
 
@@ -29567,7 +29550,7 @@ evaluate `tab-line-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (defvar-local tab-line-exclude nil)
 (put 'global-tab-line-mode 'globalized-minor-mode t)
 (defvar global-tab-line-mode nil "\
@@ -29592,7 +29575,7 @@ would do it.
 
 See `tab-line-mode' for more information on Tab-Line mode.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "tab-line" '("tab-line-"))
 
 
@@ -29607,7 +29590,7 @@ Called non-interactively, the region is specified by 
arguments
 START and END, rather than by the position of point and mark.
 The variable `tab-width' controls the spacing of tab stops.
 
-(fn START END &optional ARG)" t nil)
+(fn START END &optional ARG)" t)
 (autoload 'tabify "tabify" "\
 Convert multiple spaces in region to tabs when possible.
 A group of spaces is partially replaced by tabs
@@ -29619,7 +29602,7 @@ Called non-interactively, the region is specified by 
arguments
 START and END, rather than by the position of point and mark.
 The variable `tab-width' controls the spacing of tab stops.
 
-(fn START END &optional ARG)" t nil)
+(fn START END &optional ARG)" t)
 (register-definition-prefixes "tabify" '("tabify-regexp"))
 
 
@@ -29651,7 +29634,7 @@ evaluate `table-fixed-width-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'table-insert "table" "\
 Insert an editable text table.
 Insert a table of specified number of COLUMNS and ROWS.  Optional
@@ -29773,7 +29756,7 @@ Inside a table cell has a special keymap.
 
 \\{table-cell-map}
 
-(fn COLUMNS ROWS &optional CELL-WIDTH CELL-HEIGHT)" t nil)
+(fn COLUMNS ROWS &optional CELL-WIDTH CELL-HEIGHT)" t)
 (autoload 'table-insert-row "table" "\
 Insert N table row(s).
 When point is in a table the newly inserted row(s) are placed above
@@ -29781,7 +29764,7 @@ the current row.  When point is outside of the table it 
must be below
 the table within the table width range, then the newly created row(s)
 are appended at the bottom of the table.
 
-(fn N)" t nil)
+(fn N)" t)
 (autoload 'table-insert-column "table" "\
 Insert N table column(s).
 When point is in a table the newly inserted column(s) are placed left
@@ -29789,12 +29772,12 @@ of the current column.  When point is outside of the 
table it must be
 right side of the table within the table height range, then the newly
 created column(s) are appended at the right of the table.
 
-(fn N)" t nil)
+(fn N)" t)
 (autoload 'table-insert-row-column "table" "\
 Insert row(s) or column(s).
 See `table-insert-row' and `table-insert-column'.
 
-(fn ROW-COLUMN N)" t nil)
+(fn ROW-COLUMN N)" t)
 (autoload 'table-recognize "table" "\
 Recognize all tables within the current buffer and activate them.
 Scans the entire buffer and recognizes valid table cells.  If the
@@ -29802,8 +29785,8 @@ optional numeric prefix argument ARG is negative the 
tables in the
 buffer become inactive, meaning the tables become plain text and loses
 all the table specific features.
 
-(fn &optional ARG)" t nil)
-(autoload 'table-unrecognize "table" nil t nil)
+(fn &optional ARG)" t)
+(autoload 'table-unrecognize "table" nil t)
 (autoload 'table-recognize-region "table" "\
 Recognize all tables within region.
 BEG and END specify the region to work on.  If the optional numeric
@@ -29811,19 +29794,19 @@ prefix argument ARG is negative the tables in the 
region become
 inactive, meaning the tables become plain text and lose all the table
 specific features.
 
-(fn BEG END &optional ARG)" t nil)
+(fn BEG END &optional ARG)" t)
 (autoload 'table-unrecognize-region "table" "\
 
 
-(fn BEG END)" t nil)
+(fn BEG END)" t)
 (autoload 'table-recognize-table "table" "\
 Recognize a table at point.
 If the optional numeric prefix argument ARG is negative the table
 becomes inactive, meaning the table becomes plain text and loses all
 the table specific features.
 
-(fn &optional ARG)" t nil)
-(autoload 'table-unrecognize-table "table" nil t nil)
+(fn &optional ARG)" t)
+(autoload 'table-unrecognize-table "table" nil t)
 (autoload 'table-recognize-cell "table" "\
 Recognize a table cell that contains current point.
 Probe the cell dimension and prepare the cell information.  The
@@ -29832,8 +29815,8 @@ must not be specified.  When the optional numeric 
prefix argument ARG
 is negative the cell becomes inactive, meaning that the cell becomes
 plain text and loses all the table specific features.
 
-(fn &optional FORCE NO-COPY ARG)" t nil)
-(autoload 'table-unrecognize-cell "table" nil t nil)
+(fn &optional FORCE NO-COPY ARG)" t)
+(autoload 'table-unrecognize-cell "table" nil t)
 (autoload 'table-heighten-cell "table" "\
 Heighten the current cell by N lines by expanding the cell vertically.
 Heightening is done by adding blank lines at the bottom of the current
@@ -29842,7 +29825,7 @@ heightened in order to keep the rectangular table 
structure.  The
 optional argument NO-COPY is internal use only and must not be
 specified.
 
-(fn N &optional NO-COPY NO-UPDATE)" t nil)
+(fn N &optional NO-COPY NO-UPDATE)" t)
 (autoload 'table-shorten-cell "table" "\
 Shorten the current cell by N lines by shrinking the cell vertically.
 Shortening is done by removing blank lines from the bottom of the cell
@@ -29852,19 +29835,19 @@ is applicable to all the cells aligned horizontally 
with the current
 one because they are also shortened in order to keep the rectangular
 table structure.
 
-(fn N)" t nil)
+(fn N)" t)
 (autoload 'table-widen-cell "table" "\
 Widen the current cell by N columns and expand the cell horizontally.
 Some other cells in the same table are widen as well to keep the
 table's rectangle structure.
 
-(fn N &optional NO-COPY NO-UPDATE)" t nil)
+(fn N &optional NO-COPY NO-UPDATE)" t)
 (autoload 'table-narrow-cell "table" "\
 Narrow the current cell by N columns and shrink the cell horizontally.
 Some other cells in the same table are narrowed as well to keep the
 table's rectangle structure.
 
-(fn N)" t nil)
+(fn N)" t)
 (autoload 'table-forward-cell "table" "\
 Move point forward to the beginning of the next cell.
 With argument ARG, do it ARG times;
@@ -29904,36 +29887,36 @@ You can actually try how it works in this buffer.  
Press
 |  |6 |  |  |  |6 |  | +--+--+--+--+  +--+--+--+--+  +--+-----+--+
 +--+--+--+  +--+--+--+
 
-(fn &optional ARG NO-RECOGNIZE UNRECOGNIZE)" t nil)
+(fn &optional ARG NO-RECOGNIZE UNRECOGNIZE)" t)
 (autoload 'table-backward-cell "table" "\
 Move backward to the beginning of the previous cell.
 With argument ARG, do it ARG times;
 a negative argument ARG = -N means move forward N cells.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'table-span-cell "table" "\
 Span current cell into adjacent cell in DIRECTION.
 DIRECTION is one of symbols; right, left, above or below.
 
-(fn DIRECTION)" t nil)
+(fn DIRECTION)" t)
 (autoload 'table-split-cell-vertically "table" "\
 Split current cell vertically.
-Creates a cell above and a cell below the current point location." t nil)
+Creates a cell above and a cell below the current point location." t)
 (autoload 'table-split-cell-horizontally "table" "\
 Split current cell horizontally.
 Creates a cell on the left and a cell on the right of the current
-point location." t nil)
+point location." t)
 (autoload 'table-split-cell "table" "\
 Split current cell in ORIENTATION.
 ORIENTATION is a symbol either horizontally or vertically.
 
-(fn ORIENTATION)" t nil)
+(fn ORIENTATION)" t)
 (autoload 'table-justify "table" "\
 Justify contents of a cell, a row of cells or a column of cells.
 WHAT is a symbol `cell', `row' or `column'.  JUSTIFY is a symbol
 `left', `center', `right', `top', `middle', `bottom' or `none'.
 
-(fn WHAT JUSTIFY)" t nil)
+(fn WHAT JUSTIFY)" t)
 (autoload 'table-justify-cell "table" "\
 Justify cell contents.
 JUSTIFY is a symbol `left', `center' or `right' for horizontal, or `top',
@@ -29941,19 +29924,19 @@ JUSTIFY is a symbol `left', `center' or `right' for 
horizontal, or `top',
 non-nil the justify operation is limited to the current paragraph,
 otherwise the entire cell contents is justified.
 
-(fn JUSTIFY &optional PARAGRAPH)" t nil)
+(fn JUSTIFY &optional PARAGRAPH)" t)
 (autoload 'table-justify-row "table" "\
 Justify cells of a row.
 JUSTIFY is a symbol `left', `center' or `right' for horizontal,
 or `top', `middle', `bottom' or `none' for vertical.
 
-(fn JUSTIFY)" t nil)
+(fn JUSTIFY)" t)
 (autoload 'table-justify-column "table" "\
 Justify cells of a column.
 JUSTIFY is a symbol `left', `center' or `right' for horizontal,
 or `top', `middle', `bottom' or `none' for vertical.
 
-(fn JUSTIFY)" t nil)
+(fn JUSTIFY)" t)
 (autoload 'table-query-dimension "table" "\
 Return the dimension of the current cell and the current table.
 The result is a list (cw ch tw th c r cells) where cw is the cell
@@ -29966,7 +29949,7 @@ the number tends to be larger than it appears for the 
tables with
 non-uniform cell structure (heavily spanned and split).  When optional
 WHERE is provided the cell and table at that location is reported.
 
-(fn &optional WHERE)" t nil)
+(fn &optional WHERE)" t)
 (autoload 'table-generate-source "table" "\
 Generate source of the current table in the specified language.
 LANGUAGE is a symbol that specifies the language to describe the
@@ -29994,7 +29977,7 @@ CALS (DocBook DTD):
         URL `https://www.oasis-open.org/html/a502.htm'
         URL 
`https://www.oreilly.com/catalog/docbook/chapter/book/table.html#AEN114751'
 
-(fn LANGUAGE &optional DEST-BUFFER CAPTION)" t nil)
+(fn LANGUAGE &optional DEST-BUFFER CAPTION)" t)
 (autoload 'table-insert-sequence "table" "\
 Travel cells forward while inserting a specified sequence string in each cell.
 STR is the base string from which the sequence starts.  When STR is an
@@ -30030,21 +30013,21 @@ Example:
     (table-forward-cell 1)
     (table-insert-sequence \"64\" 0 1 2 \\='left))
 
-(fn STR N INCREMENT INTERVAL JUSTIFY)" t nil)
+(fn STR N INCREMENT INTERVAL JUSTIFY)" t)
 (autoload 'table-delete-row "table" "\
 Delete N row(s) of cells.
 Delete N rows of cells from current row.  The current row is the row
 contains the current cell where point is located.  Each row must
 consists from cells of same height.
 
-(fn N)" t nil)
+(fn N)" t)
 (autoload 'table-delete-column "table" "\
 Delete N column(s) of cells.
 Delete N columns of cells from current column.  The current column is
 the column contains the current cell where point is located.  Each
 column must consists from cells of same width.
 
-(fn N)" t nil)
+(fn N)" t)
 (autoload 'table-capture "table" "\
 Convert plain text into a table by capturing the text in the region.
 Create a table with the text in region as cell contents.  BEG and END
@@ -30156,18 +30139,18 @@ By applying `table-release', which does the opposite 
process, the
 contents become once again plain text.  `table-release' works as
 companion command to `table-capture' this way.
 
-(fn BEG END &optional COL-DELIM-REGEXP ROW-DELIM-REGEXP JUSTIFY MIN-CELL-WIDTH 
COLUMNS)" t nil)
+(fn BEG END &optional COL-DELIM-REGEXP ROW-DELIM-REGEXP JUSTIFY MIN-CELL-WIDTH 
COLUMNS)" t)
 (autoload 'table-release "table" "\
 Convert a table into plain text by removing the frame from a table.
 Remove the frame from a table and deactivate the table.  This command
 converts a table into plain text without frames.  It is a companion to
-`table-capture' which does the opposite process." t nil)
+`table-capture' which does the opposite process." t)
 (register-definition-prefixes "table" '("*table--" "table-"))
 
 
 ;;; Generated autoloads from cedet/srecode/table.el
 
-(register-definition-prefixes "srecode/table" '("object-sort-list" "srecode-"))
+(register-definition-prefixes "srecode/table" '("srecode-"))
 
 
 ;;; Generated autoloads from emacs-lisp/tabulated-list.el
@@ -30200,9 +30183,9 @@ converts a table into plain text without frames.  It is 
a companion to
 (autoload 'talk-connect "talk" "\
 Connect to display DISPLAY for the Emacs talk group.
 
-(fn DISPLAY)" t nil)
+(fn DISPLAY)" t)
 (autoload 'talk "talk" "\
-Connect to the Emacs talk group from the current X display or tty frame." t 
nil)
+Connect to the Emacs talk group from the current X display or tty frame." t)
 (register-definition-prefixes "talk" '("talk-"))
 
 
@@ -30224,7 +30207,7 @@ inside of a tar archive without extracting it and 
re-archiving it.
 See also: variables `tar-update-datestamp' and `tar-anal-blocksize'.
 \\{tar-mode-map}
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "tar-mode" '("tar-"))
 
 
@@ -30258,18 +30241,18 @@ Turning on Tcl mode runs `tcl-mode-hook'.  Read the 
documentation for
 `tcl-mode-hook' to see what kinds of interesting hook functions
 already exist.
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'inferior-tcl "tcl" "\
 Run inferior Tcl process.
 Prefix arg means enter program name interactively.
 See documentation for function `inferior-tcl-mode' for more information.
 
-(fn CMD)" t nil)
+(fn CMD)" t)
 (autoload 'tcl-help-on-word "tcl" "\
 Get help on Tcl command.  Default is word at point.
 Prefix argument means invert sense of `tcl-use-smart-word-finder'.
 
-(fn COMMAND &optional ARG)" t nil)
+(fn COMMAND &optional ARG)" t)
 (register-definition-prefixes "tcl" '("inferior-tcl-" "run-tcl" 
"switch-to-tcl" "tcl-"))
 
 
@@ -30291,13 +30274,14 @@ is controlled by the contents of the global variable 
`telnet-host-properties',
 falling back on the value of the global variable `telnet-program'.
 Normally input is edited in Emacs and sent a line at a time.
 
-(fn HOST &optional PORT)" t nil)
+(fn HOST &optional PORT)" t)
 (autoload 'rsh "telnet" "\
 Open a network login connection to host named HOST (a string).
 Communication with HOST is recorded in a buffer `*rsh-HOST*'.
 Normally input is edited in Emacs and sent a line at a time.
 
-(fn HOST)" t nil)
+(fn HOST)" t)
+(make-obsolete 'rsh 'nil "29.1")
 (register-definition-prefixes "telnet" '("send-process-next-char" "telnet-"))
 
 
@@ -30320,7 +30304,7 @@ If there is already a running process in that buffer, 
it is not restarted.
 Optional third arg STARTFILE is the name of a file to send the contents of to
 the process.  Any more args are arguments to PROGRAM.
 
-(fn NAME PROGRAM &optional STARTFILE &rest SWITCHES)" nil nil)
+(fn NAME PROGRAM &optional STARTFILE &rest SWITCHES)")
 (autoload 'term "term" "\
 Start a terminal-emulator in a new buffer.
 The buffer is in Term mode; see `term-mode' for the
@@ -30328,13 +30312,13 @@ commands to use in that buffer.
 
 \\<term-raw-map>Type \\[switch-to-buffer] to switch to another buffer.
 
-(fn PROGRAM)" t nil)
+(fn PROGRAM)" t)
 (autoload 'ansi-term "term" "\
 Start a terminal-emulator in a new buffer.
 This is almost the same as `term' apart from always creating a new buffer,
-and `C-x' being marked as a `term-escape-char'.
+and \\`C-x' being marked as a `term-escape-char'.
 
-(fn PROGRAM &optional NEW-BUFFER-NAME)" t nil)
+(fn PROGRAM &optional NEW-BUFFER-NAME)" t)
 (autoload 'serial-term "term" "\
 Start a terminal-emulator for a serial port in a new buffer.
 PORT is the path or name of the serial port.  For example, this
@@ -30354,7 +30338,7 @@ use in that buffer.
 
 \\<term-raw-map>Type \\[switch-to-buffer] to switch to another buffer.
 
-(fn PORT SPEED &optional LINE-MODE)" t nil)
+(fn PORT SPEED &optional LINE-MODE)" t)
 (register-definition-prefixes "term" '("ansi-term-color-vector" "serial-" 
"term-"))
 
 
@@ -30364,9 +30348,9 @@ use in that buffer.
 Use Edebug to instrument for coverage all macros and functions in FILENAME.
 If BYTE-COMPILE is non-nil, byte compile each function after instrumenting.
 
-(fn FILENAME &optional BYTE-COMPILE)" t nil)
+(fn FILENAME &optional BYTE-COMPILE)" t)
 (autoload 'testcover-this-defun "testcover" "\
-Start coverage on function under point." t nil)
+Start coverage on function under point." t)
 (register-definition-prefixes "testcover" '("testcover-"))
 
 
@@ -30387,7 +30371,7 @@ as to form complete rows.
 \\[tetris-move-right]  Move the shape one square to the right
 \\[tetris-rotate-prev] Rotate the shape clockwise
 \\[tetris-rotate-next] Rotate the shape anticlockwise
-\\[tetris-move-bottom] Drop the shape to the bottom of the playing area" t nil)
+\\[tetris-move-bottom] Drop the shape to the bottom of the playing area" t)
 (register-definition-prefixes "tetris" '("tetris-"))
 
 
@@ -30504,7 +30488,7 @@ this file is for plain TeX, LaTeX, or SliTeX and calls 
`plain-tex-mode',
 such as if there are no commands in the file, the value of `tex-default-mode'
 says which mode to use.
 
-(fn)" t nil)
+(fn)" t)
 (defalias 'TeX-mode #'tex-mode)
 (defalias 'plain-TeX-mode #'plain-tex-mode)
 (defalias 'LaTeX-mode #'latex-mode)
@@ -30549,7 +30533,7 @@ Entering Plain-tex mode runs the hook `text-mode-hook', 
then the hook
 `tex-mode-hook', and finally the hook `plain-tex-mode-hook'.  When the
 special subshell is initiated, the hook `tex-shell-hook' is run.
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'latex-mode "tex-mode" "\
 Major mode for editing files of input for LaTeX.
 Makes $ and } display the characters they match.
@@ -30591,7 +30575,7 @@ Entering Latex mode runs the hook `text-mode-hook', then
 `tex-mode-hook', and finally `latex-mode-hook'.  When the special
 subshell is initiated, `tex-shell-hook' is run.
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'slitex-mode "tex-mode" "\
 Major mode for editing files of input for SliTeX.
 Makes $ and } display the characters they match.
@@ -30634,12 +30618,12 @@ Entering SliTeX mode runs the hook `text-mode-hook', 
then the hook
 `slitex-mode-hook'.  When the special subshell is initiated, the hook
 `tex-shell-hook' is run.
 
-(fn)" t nil)
-(autoload 'tex-start-shell "tex-mode" nil nil nil)
+(fn)" t)
+(autoload 'tex-start-shell "tex-mode")
 (autoload 'doctex-mode "tex-mode" "\
 Major mode to edit DocTeX files.
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "tex-mode" '("doctex-font-lock-" "latex-" 
"plain-tex-mode-map" "tex-"))
 
 
@@ -30664,14 +30648,14 @@ Non-nil argument (prefix, if interactive) means don't 
make tag table
 and don't split the file if large.  You can use `Info-tagify' and
 `Info-split' to do these manually.
 
-(fn &optional NOSPLIT)" t nil)
+(fn &optional NOSPLIT)" t)
 (autoload 'texinfo-format-region "texinfmt" "\
 Convert the current region of the Texinfo file to Info format.
 This lets you see what that part of the file will look like in Info.
 The command is bound to \\[texinfo-format-region].  The text that is
 converted to Info is stored in a temporary buffer.
 
-(fn REGION-BEGINNING REGION-END)" t nil)
+(fn REGION-BEGINNING REGION-END)" t)
 (autoload 'texi2info "texinfmt" "\
 Convert the current buffer (written in Texinfo code) into an Info file.
 The Info file output is generated in a buffer visiting the Info file
@@ -30685,7 +30669,7 @@ Texinfo source buffer is not changed.
 Non-nil argument (prefix, if interactive) means don't split the file
 if large.  You can use `Info-split' to do this manually.
 
-(fn &optional NOSPLIT)" t nil)
+(fn &optional NOSPLIT)" t)
 (register-definition-prefixes "texinfmt" '("batch-texinfo-format" "texinf"))
 
 
@@ -30764,7 +30748,7 @@ be the first node in the file.
 Entering Texinfo mode calls the value of `text-mode-hook', and then the
 value of `texinfo-mode-hook'.
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "texinfo" '("texinfo-"))
 
 
@@ -30812,7 +30796,7 @@ Available values of TYPE and corresponding OBJECTs are:
 If the user option `textsec-check' is nil, these checks are
 disabled, and this function always returns nil.
 
-(fn OBJECT TYPE)" nil nil)
+(fn OBJECT TYPE)")
 (register-definition-prefixes "textsec-check" '("textsec-check"))
 
 
@@ -30828,17 +30812,17 @@ Compose Thai characters in the region.
 When called from a program, expects two arguments,
 positions (integers or markers) specifying the region.
 
-(fn BEG END)" t nil)
+(fn BEG END)" t)
 (autoload 'thai-compose-string "thai-util" "\
 Compose Thai characters in STRING and return the resulting string.
 
-(fn STRING)" nil nil)
+(fn STRING)")
 (autoload 'thai-compose-buffer "thai-util" "\
-Compose Thai characters in the current buffer." t nil)
+Compose Thai characters in the current buffer." t)
 (autoload 'thai-composition-function "thai-util" "\
 
 
-(fn GSTRING DIRECTION)" nil nil)
+(fn GSTRING DIRECTION)")
 (register-definition-prefixes "thai-util" 
'("exit-thai-language-environment-internal" 
"setup-thai-language-environment-internal" "thai-"))
 
 
@@ -30856,7 +30840,7 @@ Possibilities include `symbol', `list', `sexp', 
`defun', `number',
 `filename', `url', `email', `uuid', `word', `sentence', `whitespace',
 `line', and `page'.
 
-(fn THING &optional N)" nil nil)
+(fn THING &optional N)")
 (autoload 'bounds-of-thing-at-point "thingatpt" "\
 Determine the start and end buffer locations for the THING at point.
 THING should be a symbol specifying a type of syntactic entity.
@@ -30870,13 +30854,13 @@ valid THING.
 Return a cons cell (START . END) giving the start and end
 positions of the thing found.
 
-(fn THING)" nil nil)
+(fn THING)")
 (autoload 'thing-at-point "thingatpt" "\
 Return the THING at point.
 THING should be a symbol specifying a type of syntactic entity.
 Possibilities include `symbol', `list', `sexp', `defun',
 `filename', `existing-filename', `url', `email', `uuid', `word',
-`sentence', `whitespace', `line', `number', and `page'.
+`sentence', `whitespace', `line', `number', `face' and `page'.
 
 When the optional argument NO-PROPERTIES is non-nil,
 strip text properties from the return value.
@@ -30884,33 +30868,33 @@ strip text properties from the return value.
 See the file `thingatpt.el' for documentation on how to define
 a symbol as a valid THING.
 
-(fn THING &optional NO-PROPERTIES)" nil nil)
+(fn THING &optional NO-PROPERTIES)")
 (autoload 'bounds-of-thing-at-mouse "thingatpt" "\
 Determine start and end locations for THING at mouse click given by EVENT.
 Like `bounds-of-thing-at-point', but tries to use the position in EVENT
 where the mouse button is clicked to find the thing nearby.
 
-(fn EVENT THING)" nil nil)
+(fn EVENT THING)")
 (autoload 'thing-at-mouse "thingatpt" "\
 Return the THING at mouse click specified by EVENT.
 Like `thing-at-point', but tries to use the position in EVENT
 where the mouse button is clicked to find the thing nearby.
 
-(fn EVENT THING &optional NO-PROPERTIES)" nil nil)
+(fn EVENT THING &optional NO-PROPERTIES)")
 (autoload 'sexp-at-point "thingatpt" "\
-Return the sexp at point, or nil if none is found." nil nil)
+Return the sexp at point, or nil if none is found.")
 (autoload 'symbol-at-point "thingatpt" "\
-Return the symbol at point, or nil if none is found." nil nil)
+Return the symbol at point, or nil if none is found.")
 (autoload 'number-at-point "thingatpt" "\
 Return the number at point, or nil if none is found.
 Decimal numbers like \"14\" or \"-14.5\", as well as hex numbers
-like \"0xBEEF09\" or \"#xBEEF09\", are recognized." nil nil)
+like \"0xBEEF09\" or \"#xBEEF09\", are recognized.")
 (autoload 'list-at-point "thingatpt" "\
 Return the Lisp list at point, or nil if none is found.
 If IGNORE-COMMENT-OR-STRING is non-nil comments and strings are
 treated as white space.
 
-(fn &optional IGNORE-COMMENT-OR-STRING)" nil nil)
+(fn &optional IGNORE-COMMENT-OR-STRING)")
 (register-definition-prefixes "thingatpt" '("beginning-of-thing" 
"define-thing-chars" "end-of-thing" "filename" "form-at-point" "in-string-p" 
"sentence-at-point" "thing-at-point-" "word-at-point"))
 
 
@@ -30921,9 +30905,9 @@ Handle thread events, propagated by `thread-signal'.
 An EVENT has the format
   (thread-event THREAD ERROR-SYMBOL DATA)
 
-(fn EVENT)" t nil)
+(fn EVENT)" t)
 (autoload 'list-threads "thread" "\
-Display a list of threads." t nil)
+Display a list of threads." t)
  (put 'list-threads 'disabled "Beware: manually canceling threads can ruin 
your Emacs session.")
 (register-definition-prefixes "thread" '("thread-list-"))
 
@@ -30933,20 +30917,20 @@ Display a list of threads." t nil)
 (autoload 'thumbs-find-thumb "thumbs" "\
 Display the thumbnail for IMG.
 
-(fn IMG)" t nil)
+(fn IMG)" t)
 (autoload 'thumbs-show-from-dir "thumbs" "\
 Make a preview buffer for all images in DIR.
 Optional argument REG to select file matching a regexp,
 and SAME-WINDOW to show thumbs in the same window.
 
-(fn DIR &optional REG SAME-WINDOW)" t nil)
+(fn DIR &optional REG SAME-WINDOW)" t)
 (autoload 'thumbs-dired-show-marked "thumbs" "\
-In dired, make a thumbs buffer with marked files." t nil)
+In dired, make a thumbs buffer with marked files." t)
 (autoload 'thumbs-dired-show "thumbs" "\
-In dired, make a thumbs buffer with all files in current directory." t nil)
+In dired, make a thumbs buffer with all files in current directory." t)
 (defalias 'thumbs 'thumbs-show-from-dir)
 (autoload 'thumbs-dired-setroot "thumbs" "\
-In dired, call the setroot program on the image at point." t nil)
+In dired, call the setroot program on the image at point." t)
 (register-definition-prefixes "thumbs" '("thumbs-"))
 
 
@@ -30962,56 +30946,56 @@ In dired, call the setroot program on the image at 
point." t nil)
 Check if char CH is Tibetan character.
 Returns non-nil if CH is Tibetan.  Otherwise, returns nil.
 
-(fn CH)" nil nil)
+(fn CH)")
 (autoload 'tibetan-tibetan-to-transcription "tibet-util" "\
 Transcribe Tibetan string STR and return the corresponding Roman string.
 
-(fn STR)" nil nil)
+(fn STR)")
 (autoload 'tibetan-transcription-to-tibetan "tibet-util" "\
 Convert Tibetan Roman string STR to Tibetan character string.
 The returned string has no composition information.
 
-(fn STR)" nil nil)
+(fn STR)")
 (autoload 'tibetan-compose-string "tibet-util" "\
 Compose Tibetan string STR.
 
-(fn STR)" nil nil)
+(fn STR)")
 (autoload 'tibetan-compose-region "tibet-util" "\
 Compose Tibetan text the region BEG and END.
 
-(fn BEG END)" t nil)
+(fn BEG END)" t)
 (autoload 'tibetan-decompose-region "tibet-util" "\
 Decompose Tibetan text in the region FROM and TO.
 This is different from `decompose-region' because precomposed
 Tibetan characters are decomposed into normal Tibetan character
 sequences.
 
-(fn FROM TO)" t nil)
+(fn FROM TO)" t)
 (autoload 'tibetan-decompose-string "tibet-util" "\
 Decompose Tibetan string STR.
 This is different from `decompose-string' because precomposed
 Tibetan characters are decomposed into normal Tibetan character
 sequences.
 
-(fn STR)" nil nil)
+(fn STR)")
 (autoload 'tibetan-decompose-buffer "tibet-util" "\
 Decomposes Tibetan characters in the buffer into their components.
-See also the documentation of the function `tibetan-decompose-region'." t nil)
+See also the documentation of the function `tibetan-decompose-region'." t)
 (autoload 'tibetan-compose-buffer "tibet-util" "\
 Composes Tibetan character components in the buffer.
-See also docstring of the function `tibetan-compose-region'." t nil)
+See also docstring of the function `tibetan-compose-region'." t)
 (autoload 'tibetan-post-read-conversion "tibet-util" "\
 
 
-(fn LEN)" nil nil)
+(fn LEN)")
 (autoload 'tibetan-pre-write-conversion "tibet-util" "\
 
 
-(fn FROM TO)" nil nil)
+(fn FROM TO)")
 (autoload 'tibetan-pre-write-canonicalize-for-unicode "tibet-util" "\
 
 
-(fn FROM TO)" nil nil)
+(fn FROM TO)")
 (register-definition-prefixes "tibet-util" '("tibetan-"))
 
 
@@ -31032,7 +31016,7 @@ This function performs no refilling of the changed text.
 If DONT-ASK is set, or called interactively with prefix argument, user
 won't be prompted for confirmation of each substitution.
 
-(fn BEG END &optional DONT-ASK)" t nil)
+(fn BEG END &optional DONT-ASK)" t)
 (autoload 'tildify-buffer "tildify" "\
 Add hard spaces in the current buffer.
 See variables `tildify-pattern', `tildify-space-string', and
@@ -31042,7 +31026,7 @@ This function performs no refilling of the changed text.
 If DONT-ASK is set, or called interactively with prefix argument, user
 won't be prompted for confirmation of each substitution.
 
-(fn &optional DONT-ASK)" t nil)
+(fn &optional DONT-ASK)" t)
 (autoload 'tildify-space "tildify" "\
 Convert space before point into a hard space if the context is right.
 
@@ -31063,7 +31047,7 @@ Otherwise, if
    `tildify-space-string' variable,
 remove the hard space and leave only the space character.
 
-This function is meant to be used as a `post-self-insert-hook'." t nil)
+This function is meant to be used as a `post-self-insert-hook'." t)
 (autoload 'tildify-mode "tildify" "\
 Adds electric behavior to space character.
 
@@ -31090,7 +31074,7 @@ evaluate `tildify-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "tildify" '("tildify-"))
 
 
@@ -31105,7 +31089,7 @@ Enable display of time, load level, and mail flag in 
mode lines.
 This display updates automatically every minute.
 If `display-time-day-and-date' is non-nil, the current day and date
 are displayed as well.
-This runs the normal hook `display-time-hook' after each update." t nil)
+This runs the normal hook `display-time-hook' after each update." t)
 (defvar display-time-mode nil "\
 Non-nil if Display-Time mode is enabled.
 See the `display-time-mode' command
@@ -31137,13 +31121,12 @@ evaluate `(default-value \\='display-time-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
-(define-obsolete-function-alias 'display-time-world #'world-clock "\
-28.1")
+(fn &optional ARG)" t)
+(define-obsolete-function-alias 'display-time-world #'world-clock "28.1")
 (autoload 'world-clock "time" "\
 Display a world clock buffer with times in various time zones.
 The variable `world-clock-list' specifies which time zones to use.
-To turn off the world time display, go to the window and type 
`\\[quit-window]'." t nil)
+To turn off the world time display, go to the window and type 
`\\[quit-window]'." t)
 (autoload 'emacs-uptime "time" "\
 Return a string giving the uptime of this instance of Emacs.
 FORMAT is a string to format the result, using `format-seconds'.
@@ -31151,13 +31134,13 @@ For example, the Unix uptime command format is \"%D, 
%z%2h:%.2m\".
 If the optional argument HERE is non-nil, insert string at
 point.
 
-(fn &optional FORMAT HERE)" t nil)
+(fn &optional FORMAT HERE)" t)
 (autoload 'emacs-init-time "time" "\
 Return a string giving the duration of the Emacs initialization.
 FORMAT is a string to format the result, using `format'.  If nil,
 the default format \"%f seconds\" is used.
 
-(fn &optional FORMAT)" t nil)
+(fn &optional FORMAT)" t)
 (register-definition-prefixes "time" '("display-time-" 
"legacy-style-world-list" "time--display-world-list" "world-clock-" 
"zoneinfo-style-world-list"))
 
 
@@ -31168,50 +31151,52 @@ Parse a string DATE that represents a date-time and 
return a time value.
 DATE should be in one of the forms recognized by `parse-time-string'.
 If DATE lacks timezone information, GMT is assumed.
 
-(fn DATE)" nil nil)
-(defalias 'time-to-seconds 'float-time)
-(defalias 'seconds-to-time 'time-convert)
+(fn DATE)")
+(defalias 'time-to-seconds #'float-time)
+(autoload 'seconds-to-time "time-date" "\
+Convert SECONDS to a proper time, like `current-time' would.
+
+(fn SECONDS)")
 (autoload 'days-to-time "time-date" "\
 Convert DAYS into a time value.
 
-(fn DAYS)" nil nil)
+(fn DAYS)")
 (autoload 'time-since "time-date" "\
 Return the time elapsed since TIME.
 TIME should be either a time value or a date-time string.
 
-(fn TIME)" nil nil)
-(define-obsolete-function-alias 'subtract-time 'time-subtract "\
-26.1")
+(fn TIME)")
+(define-obsolete-function-alias 'subtract-time #'time-subtract "26.1")
 (autoload 'date-to-day "time-date" "\
 Return the absolute date of DATE, a date-time string.
 The absolute date is the number of days elapsed since the imaginary
 Gregorian date Sunday, December 31, 1 BC.
 
-(fn DATE)" nil nil)
+(fn DATE)")
 (autoload 'days-between "time-date" "\
 Return the number of days between DATE1 and DATE2.
 DATE1 and DATE2 should be date-time strings.
 
-(fn DATE1 DATE2)" nil nil)
+(fn DATE1 DATE2)")
 (autoload 'date-leap-year-p "time-date" "\
 Return t if YEAR is a leap year.
 
-(fn YEAR)" nil nil)
+(fn YEAR)")
 (autoload 'time-to-day-in-year "time-date" "\
 Return the day number within the year corresponding to TIME.
 
-(fn TIME)" nil nil)
+(fn TIME)")
 (autoload 'time-to-days "time-date" "\
 The absolute date corresponding to TIME, a time value.
 The absolute date is the number of days elapsed since the imaginary
 Gregorian date Sunday, December 31, 1 BC.
 
-(fn TIME)" nil nil)
+(fn TIME)")
 (autoload 'safe-date-to-time "time-date" "\
 Parse a string DATE that represents a date-time and return a time value.
-If DATE is malformed, return a time value of zeros.
+If DATE is malformed, return a time value of zero.
 
-(fn DATE)" nil nil)
+(fn DATE)")
 (autoload 'format-seconds "time-date" "\
 Use format control STRING to format the number SECONDS.
 The valid format specifiers are:
@@ -31242,11 +31227,11 @@ The \"%x\" specifier does not print anything.  When 
it is used,
 specifiers must be given in order of decreasing size.  To the
 right of \"%x\", trailing zero units are not output.
 
-(fn STRING SECONDS)" nil nil)
+(fn STRING SECONDS)")
 (autoload 'seconds-to-string "time-date" "\
 Convert the time interval in seconds to a short string.
 
-(fn DELAY)" nil nil)
+(fn DELAY)")
 (register-definition-prefixes "time-date" '("date-" "decoded-time-" 
"encode-time-value" "seconds-to-string" "time-" "with-decoded-time-value"))
 
 
@@ -31258,7 +31243,7 @@ Convert the time interval in seconds to a short string.
 Return non-nil if ZONE is of the correct type for a timezone rule.
 Valid ZONE values are described in the documentation of `format-time-string'.
 
-(fn ZONE)" nil nil)
+(fn ZONE)")
 (put 'time-stamp-line-limit 'safe-local-variable 'integerp)
 (put 'time-stamp-start 'safe-local-variable 'stringp)
 (put 'time-stamp-end 'safe-local-variable 'stringp)
@@ -31296,12 +31281,12 @@ If the file has no time-stamp template, this function 
does nothing.
 You can set `time-stamp-pattern' in a file's local variables list
 to customize the information in the time stamp and where it is written.
 
-The time stamp is updated only if `time-stamp-active' is non-nil." t nil)
+The time stamp is updated only if `time-stamp-active' is non-nil." t)
 (autoload 'time-stamp-toggle-active "time-stamp" "\
 Toggle `time-stamp-active', setting whether \\[time-stamp] updates a buffer.
 With ARG, turn time stamping on if and only if ARG is positive.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "time-stamp" '("time-stamp-"))
 
 
@@ -31328,7 +31313,7 @@ display (non-nil means on).
 If using a customized `timeclock-workday' value, this should be
 set before switching this mode on.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'timeclock-in "timeclock" "\
 Clock in, recording the current time moment in the timelog.
 With a numeric prefix ARG, record the fact that today has only that
@@ -31343,7 +31328,7 @@ FIND-PROJECT is non-nil -- or the user calls 
`timeclock-in'
 interactively -- call the function `timeclock-get-project-function' to
 discover the name of the project.
 
-(fn &optional ARG PROJECT FIND-PROJECT)" t nil)
+(fn &optional ARG PROJECT FIND-PROJECT)" t)
 (autoload 'timeclock-out "timeclock" "\
 Clock out, recording the current time moment in the timelog.
 If a prefix ARG is given, the user has completed the project that was
@@ -31354,14 +31339,14 @@ FIND-REASON is non-nil -- or the user calls 
`timeclock-out'
 interactively -- call the function `timeclock-get-reason-function' to
 discover the reason.
 
-(fn &optional ARG REASON FIND-REASON)" t nil)
+(fn &optional ARG REASON FIND-REASON)" t)
 (autoload 'timeclock-status-string "timeclock" "\
 Report the overall timeclock status at the present moment.
 If SHOW-SECONDS is non-nil, display second resolution.
 If TODAY-ONLY is non-nil, the display will be relative only to time
 worked today, ignoring the time worked on previous days.
 
-(fn &optional SHOW-SECONDS TODAY-ONLY)" t nil)
+(fn &optional SHOW-SECONDS TODAY-ONLY)" t)
 (autoload 'timeclock-change "timeclock" "\
 Change to working on a different project.
 This clocks out of the current project, then clocks in on a new one.
@@ -31369,13 +31354,13 @@ With a prefix ARG, consider the previous project as 
finished at the
 time of changeover.  PROJECT is the name of the last project you were
 working on.
 
-(fn &optional ARG PROJECT)" t nil)
+(fn &optional ARG PROJECT)" t)
 (autoload 'timeclock-query-out "timeclock" "\
 Ask the user whether to clock out.
-This is a useful function for adding to `kill-emacs-query-functions'." nil nil)
+This is a useful function for adding to `kill-emacs-query-functions'.")
 (autoload 'timeclock-reread-log "timeclock" "\
 Re-read the timeclock, to account for external changes.
-Returns the new value of `timeclock-discrepancy'." t nil)
+Returns the new value of `timeclock-discrepancy'." t)
 (autoload 'timeclock-workday-remaining-string "timeclock" "\
 Return a string representing the amount of time left today.
 Display second resolution if SHOW-SECONDS is non-nil.  If TODAY-ONLY
@@ -31383,13 +31368,13 @@ is non-nil, the display will be relative only to time 
worked today.
 See `timeclock-relative' for more information about the meaning of
 \"relative to today\".
 
-(fn &optional SHOW-SECONDS TODAY-ONLY)" t nil)
+(fn &optional SHOW-SECONDS TODAY-ONLY)" t)
 (autoload 'timeclock-workday-elapsed-string "timeclock" "\
 Return a string representing the amount of time worked today.
 Display seconds resolution if SHOW-SECONDS is non-nil.  If RELATIVE is
 non-nil, the amount returned will be relative to past time worked.
 
-(fn &optional SHOW-SECONDS)" t nil)
+(fn &optional SHOW-SECONDS)" t)
 (autoload 'timeclock-when-to-leave-string "timeclock" "\
 Return a string representing the end of today's workday.
 This string is relative to the value of `timeclock-workday'.  If
@@ -31397,7 +31382,7 @@ SHOW-SECONDS is non-nil, the value printed/returned 
will include
 seconds.  If TODAY-ONLY is non-nil, the value returned will be
 relative only to the time worked today, and not to past time.
 
-(fn &optional SHOW-SECONDS TODAY-ONLY)" t nil)
+(fn &optional SHOW-SECONDS TODAY-ONLY)" t)
 (register-definition-prefixes "timeclock" '("timeclock-"))
 
 
@@ -31406,7 +31391,7 @@ relative only to the time worked today, and not to past 
time.
 (autoload 'list-timers "timer-list" "\
 List all timers in a buffer.
 
-(fn &optional IGNORE-AUTO NONCONFIRM)" t nil)
+(fn &optional IGNORE-AUTO NONCONFIRM)" t)
  (put 'list-timers 'disabled "Beware: manually canceling timers can ruin your 
Emacs session.")
 (register-definition-prefixes "timer-list" '("timer-list-"))
 
@@ -31423,7 +31408,7 @@ Convert a TIT dictionary of FILENAME into a Quail 
package.
 Optional argument DIRNAME if specified is the directory name under which
 the generated Quail package is saved.
 
-(fn FILENAME &optional DIRNAME)" t nil)
+(fn FILENAME &optional DIRNAME)" t)
 (autoload 'batch-titdic-convert "titdic-cnv" "\
 Run `titdic-convert' on the files remaining on the command line.
 Use this from the command line, with `-batch';
@@ -31432,7 +31417,7 @@ For example, invoke \"emacs -batch -f 
batch-titdic-convert XXX.tit\" to
  generate Quail package file \"xxx.el\" from TIT dictionary file \"XXX.tit\".
 To get complete usage, invoke \"emacs -batch -f batch-titdic-convert -h\".
 
-(fn &optional FORCE)" nil nil)
+(fn &optional FORCE)")
 (register-definition-prefixes "titdic-cnv" '("batch-miscdic-convert" "ctlau-" 
"miscdic-convert" "pinyin-convert" "py-converter" "quail-" "quick-" "tit-" 
"tsang-" "ziranma-converter"))
 
 
@@ -31449,14 +31434,14 @@ Note that \\[menu-bar-open] by default drops down TTY 
menus; if you want it
 to invoke `tmm-menubar' instead, customize the variable
 `tty-menu-open-use-tmm' to a non-nil value.
 
-(fn &optional X-POSITION)" t nil)
+(fn &optional X-POSITION)" t)
 (autoload 'tmm-menubar-mouse "tmm" "\
 Text-mode emulation of looking and choosing from a menubar.
 This command is used when you click the mouse in the menubar
 on a console which has no window system but does have a mouse.
 See the documentation for `tmm-prompt'.
 
-(fn EVENT)" t nil)
+(fn EVENT)" t)
 (autoload 'tmm-prompt "tmm" "\
 Text-mode emulation of calling the bindings in keymap.
 Creates a text-mode menu of possible choices.  You can access the elements
@@ -31472,7 +31457,7 @@ Its value should be an event that has a binding in MENU.
 NO-EXECUTE, if non-nil, means to return the command the user selects
 instead of executing it.
 
-(fn MENU &optional IN-POPUP DEFAULT-ITEM NO-EXECUTE)" nil nil)
+(fn MENU &optional IN-POPUP DEFAULT-ITEM NO-EXECUTE)")
 (register-definition-prefixes "tmm" '("tmm-"))
 
 
@@ -31515,25 +31500,25 @@ by default.  The done items are hidden, but typing
 items.  With non-nil user option `todo-show-with-done' both todo
 and done items are always shown on visiting a category.
 
-(fn &optional SOLICIT-FILE INTERACTIVE)" t nil)
+(fn &optional SOLICIT-FILE INTERACTIVE)" t)
 (autoload 'todo-mode "todo-mode" "\
 Major mode for displaying, navigating and editing todo lists.
 
 \\{todo-mode-map}
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'todo-archive-mode "todo-mode" "\
 Major mode for archived todo categories.
 
 \\{todo-archive-mode-map}
 
-(fn)" t nil)
+(fn)" t)
 (autoload 'todo-filtered-items-mode "todo-mode" "\
 Mode for displaying and reprioritizing top priority Todo.
 
 \\{todo-filtered-items-mode-map}
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "todo-mode" '("todo-"))
 
 
@@ -31543,7 +31528,7 @@ Mode for displaying and reprioritizing top priority 
Todo.
 Toggle tool bar on or off, based on the status of the current frame.
 See `tool-bar-mode' for more information.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'tool-bar-add-item "tool-bar" "\
 Add an item to the tool bar.
 ICON names the image, DEF is the key definition and KEY is a symbol
@@ -31559,7 +31544,7 @@ ICON.xbm, using `find-image'.
 Use this function only to make bindings in the global value of `tool-bar-map'.
 To define items in any other map, use `tool-bar-local-item'.
 
-(fn ICON DEF KEY &rest PROPS)" nil nil)
+(fn ICON DEF KEY &rest PROPS)")
 (autoload 'tool-bar-local-item "tool-bar" "\
 Add an item to the tool bar in map MAP.
 ICON names the image, DEF is the key definition and KEY is a symbol
@@ -31572,7 +31557,7 @@ function will first try to use low-color/ICON.xpm if 
`display-color-cells'
 is less or equal to 256, then ICON.xpm, then ICON.pbm, and finally
 ICON.xbm, using `find-image'.
 
-(fn ICON DEF KEY MAP &rest PROPS)" nil nil)
+(fn ICON DEF KEY MAP &rest PROPS)")
 (autoload 'tool-bar-add-item-from-menu "tool-bar" "\
 Define tool bar binding for COMMAND in keymap MAP using the given ICON.
 This makes a binding for COMMAND in `tool-bar-map', copying its
@@ -31586,7 +31571,7 @@ MAP must contain appropriate binding for `[menu-bar]' 
which holds a keymap.
 Use this function only to make bindings in the global value of `tool-bar-map'.
 To define items in any other map, use `tool-bar-local-item-from-menu'.
 
-(fn COMMAND ICON &optional MAP &rest PROPS)" nil nil)
+(fn COMMAND ICON &optional MAP &rest PROPS)")
 (autoload 'tool-bar-local-item-from-menu "tool-bar" "\
 Define local tool bar binding for COMMAND using the given ICON.
 This makes a binding for COMMAND in IN-MAP, copying its binding from
@@ -31598,7 +31583,7 @@ properties to add to the binding.
 FROM-MAP must contain appropriate binding for `[menu-bar]' which
 holds a keymap.
 
-(fn COMMAND ICON IN-MAP &optional FROM-MAP &rest PROPS)" nil nil)
+(fn COMMAND ICON IN-MAP &optional FROM-MAP &rest PROPS)")
 (register-definition-prefixes "tool-bar" '("toggle-tool-bar-mode-from-frame" 
"tool-bar-"))
 
 
@@ -31615,7 +31600,7 @@ PROCESS should be a subprocess capable of sending and 
receiving
 streams of bytes.  It may be a local process, or it may be connected
 to a tcp server on another machine.
 
-(fn PROCESS)" nil nil)
+(fn PROCESS)")
 (register-definition-prefixes "tq" '("tq-"))
 
 
@@ -31628,7 +31613,7 @@ Trace output will by default go to that buffer.")
 Helper function to get internal values.
 You can call this function to add internal values in the trace buffer.
 
-(fn &rest VALUES)" nil nil)
+(fn &rest VALUES)")
 (autoload 'trace-function-foreground "trace" "\
 Trace calls to function FUNCTION.
 With a prefix argument, also prompt for the trace buffer (default
@@ -31649,13 +31634,13 @@ stuff - use `trace-function-background' instead.
 
 To stop tracing a function, use `untrace-function' or `untrace-all'.
 
-(fn FUNCTION &optional BUFFER CONTEXT)" t nil)
+(fn FUNCTION &optional BUFFER CONTEXT)" t)
 (autoload 'trace-function-background "trace" "\
 Trace calls to function FUNCTION, quietly.
 This is like `trace-function-foreground', but without popping up
 the output buffer or changing the window configuration.
 
-(fn FUNCTION &optional BUFFER CONTEXT)" t nil)
+(fn FUNCTION &optional BUFFER CONTEXT)" t)
 (defalias 'trace-function 'trace-function-foreground)
 (register-definition-prefixes "trace" '("inhibit-trace" "trace-" "untrace-"))
 
@@ -31684,6 +31669,15 @@ Regular expression matching file names handled by 
Tramp autoload.
 It must match the initial `tramp-syntax' settings.  It should not
 match file names at root of the underlying local file system,
 like \"/sys\" or \"/C:\".")
+(defvar tramp-foreign-file-name-handler-alist nil "\
+Alist of elements (FUNCTION . HANDLER) for foreign methods handled specially.
+If (FUNCTION FILENAME) returns non-nil, then all I/O on that file is done by
+calling HANDLER.")
+(autoload 'tramp-file-name-handler "tramp" "\
+Invoke Tramp file name handler for OPERATION and ARGS.
+Fall back to normal file name handler if no Tramp file name handler exists.
+
+(fn OPERATION &rest ARGS)")
 (defun tramp-autoload-file-name-handler (operation &rest args) "\
 Load Tramp file name handler, and perform OPERATION." 
(tramp-unload-file-name-handlers) (when tramp-mode (let ((default-directory 
temporary-file-directory)) (when (bound-and-true-p tramp-archive-autoload) 
(load "tramp-archive" 'noerror 'nomessage)) (load "tramp" 'noerror 
'nomessage))) (apply operation args))
 (defun tramp-register-autoload-file-name-handlers nil "\
@@ -31713,6 +31707,7 @@ List of suffixes which indicate a compressed file.
 It must be supported by libarchive(3).")
 (defmacro tramp-archive-autoload-file-name-regexp nil "\
 Regular expression matching archive file names." '(concat "\\`" "\\(" ".+" 
"\\." (regexp-opt tramp-archive-suffixes) "\\(?:" "\\." (regexp-opt 
tramp-archive-compression-suffixes) "\\)*" "\\)" "\\(" "/" ".*" "\\)" "\\'"))
+(autoload 'tramp-archive-file-name-handler "tramp-archive")
 (defun tramp-archive-autoload-file-name-handler (operation &rest args) "\
 Load Tramp archive file name handler, and perform OPERATION." (defvar 
tramp-archive-autoload) (let ((default-directory temporary-file-directory) 
(tramp-archive-autoload tramp-archive-enabled)) (apply 
#'tramp-autoload-file-name-handler operation args)))
 (defun tramp-register-archive-file-name-handler nil "\
@@ -31724,7 +31719,7 @@ Add archive file name handler to 
`file-name-handler-alist'." (when (and tramp-ar
 
 ;;; Generated autoloads from net/tramp-cache.el
 
-(register-definition-prefixes "tramp-cache" '("tramp-"))
+(register-definition-prefixes "tramp-cache" '("tramp-" "with-tramp-"))
 
 
 ;;; Generated autoloads from net/tramp-cmds.el
@@ -31800,6 +31795,48 @@ Add archive file name handler to 
`file-name-handler-alist'." (when (and tramp-ar
 
 ;;; Generated autoloads from transient.el
 
+(autoload 'transient-define-prefix "transient" "\
+Define NAME as a transient prefix command.
+
+ARGLIST are the arguments that command takes.
+DOCSTRING is the documentation string and is optional.
+
+These arguments can optionally be followed by key-value pairs.
+Each key has to be a keyword symbol, either `:class' or a keyword
+argument supported by the constructor of that class.  The
+`transient-prefix' class is used if the class is not specified
+explicitly.
+
+GROUPs add key bindings for infix and suffix commands and specify
+how these bindings are presented in the popup buffer.  At least
+one GROUP has to be specified.  See info node `(transient)Binding
+Suffix and Infix Commands'.
+
+The BODY is optional.  If it is omitted, then ARGLIST is also
+ignored and the function definition becomes:
+
+  (lambda ()
+    (interactive)
+    (transient-setup \\='NAME))
+
+If BODY is specified, then it must begin with an `interactive'
+form that matches ARGLIST, and it must call `transient-setup'.
+It may however call that function only when some condition is
+satisfied; that is one of the reason why you might want to use
+an explicit BODY.
+
+All transients have a (possibly nil) value, which is exported
+when suffix commands are called, so that they can consume that
+value.  For some transients it might be necessary to have a sort
+of secondary value, called a scope.  Such a scope would usually
+be set in the commands `interactive' form and has to be passed
+to the setup function:
+
+  (transient-setup \\='NAME nil nil :scope SCOPE)
+
+(fn NAME ARGLIST [DOCSTRING] [KEYWORD VALUE]... GROUP... [BODY...])" nil t)
+(function-put 'transient-define-prefix 'lisp-indent-function 'defun)
+(function-put 'transient-define-prefix 'doc-string-elt 3)
 (autoload 'transient-insert-suffix "transient" "\
 Insert a SUFFIX into PREFIX before LOC.
 PREFIX is a prefix command, a symbol.
@@ -31808,9 +31845,11 @@ SUFFIX is a suffix command or a group specification (of
 LOC is a command, a key vector, a key description (a string
   as returned by `key-description'), or a coordination list
   (whose last element may also be a command or key).
+Remove a conflicting binding unless optional KEEP-OTHER is
+  non-nil.
 See info node `(transient)Modifying Existing Transients'.
 
-(fn PREFIX LOC SUFFIX)" nil nil)
+(fn PREFIX LOC SUFFIX &optional KEEP-OTHER)")
 (function-put 'transient-insert-suffix 'lisp-indent-function 'defun)
 (autoload 'transient-append-suffix "transient" "\
 Insert a SUFFIX into PREFIX after LOC.
@@ -31820,9 +31859,11 @@ SUFFIX is a suffix command or a group specification (of
 LOC is a command, a key vector, a key description (a string
   as returned by `key-description'), or a coordination list
   (whose last element may also be a command or key).
+Remove a conflicting binding unless optional KEEP-OTHER is
+  non-nil.
 See info node `(transient)Modifying Existing Transients'.
 
-(fn PREFIX LOC SUFFIX)" nil nil)
+(fn PREFIX LOC SUFFIX &optional KEEP-OTHER)")
 (function-put 'transient-append-suffix 'lisp-indent-function 'defun)
 (autoload 'transient-replace-suffix "transient" "\
 Replace the suffix at LOC in PREFIX with SUFFIX.
@@ -31834,7 +31875,7 @@ LOC is a command, a key vector, a key description (a 
string
   (whose last element may also be a command or key).
 See info node `(transient)Modifying Existing Transients'.
 
-(fn PREFIX LOC SUFFIX)" nil nil)
+(fn PREFIX LOC SUFFIX)")
 (function-put 'transient-replace-suffix 'lisp-indent-function 'defun)
 (autoload 'transient-remove-suffix "transient" "\
 Remove the suffix or group at LOC in PREFIX.
@@ -31844,9 +31885,9 @@ LOC is a command, a key vector, a key description (a 
string
   (whose last element may also be a command or key).
 See info node `(transient)Modifying Existing Transients'.
 
-(fn PREFIX LOC)" nil nil)
+(fn PREFIX LOC)")
 (function-put 'transient-remove-suffix 'lisp-indent-function 'defun)
-(register-definition-prefixes "transient" '("magit--fit-window-to-buffer" 
"transient-"))
+(register-definition-prefixes "transient" '("transient"))
 
 
 ;;; Generated autoloads from tree-widget.el
@@ -31873,7 +31914,7 @@ When the tutorial buffer is killed the content and the 
point
 position in the buffer is saved so that the tutorial may be
 resumed later.
 
-(fn &optional ARG DONT-ASK-FOR-REVERT)" t nil)
+(fn &optional ARG DONT-ASK-FOR-REVERT)" t)
 (register-definition-prefixes "tutorial" '("get-lang-string" "lang-strings" 
"tutorial--"))
 
 
@@ -31882,7 +31923,7 @@ resumed later.
 (autoload 'tai-viet-composition-function "tv-util" "\
 
 
-(fn FROM TO FONT-OBJECT STRING DIRECTION)" nil nil)
+(fn FROM TO FONT-OBJECT STRING DIRECTION)")
 (register-definition-prefixes "tv-util" '("tai-viet-"))
 
 
@@ -31899,7 +31940,7 @@ for details.).  It runs `2C-other-buffer-hook' in the 
new buffer.
 When called again, restores the screen layout with the current buffer
 first and the associated buffer to its right.
 
-(fn &optional BUFFER)" t nil)
+(fn &optional BUFFER)" t)
 (autoload '2C-associate-buffer "two-column" "\
 Associate another BUFFER with this one in two-column minor mode.
 Can also be used to associate a just previously visited file, by
@@ -31907,7 +31948,7 @@ accepting the proposed default buffer.
 
 (See  \\[describe-mode] .)
 
-(fn BUFFER)" t nil)
+(fn BUFFER)" t)
 (autoload '2C-split "two-column" "\
 Split a two-column text at point, into two buffers in two-column minor mode.
 Point becomes the local value of `2C-window-width'.  Only lines that
@@ -31926,7 +31967,7 @@ First column's text    sSs  Second column's text
 
 (See  \\[describe-mode] .)
 
-(fn ARG)" t nil)
+(fn ARG)" t)
 (register-definition-prefixes "two-column" '("2C-"))
 
 
@@ -32026,7 +32067,7 @@ evaluate `(default-value \\='type-break-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'type-break "type-break" "\
 Take a typing break.
 
@@ -32034,11 +32075,11 @@ During the break, a demo selected from the functions 
listed in
 `type-break-demo-functions' is run.
 
 After the typing break is finished, the next break is scheduled
-as per the function `type-break-schedule'." t nil)
+as per the function `type-break-schedule'." t)
 (autoload 'type-break-statistics "type-break" "\
 Print statistics about typing breaks in a temporary buffer.
 This includes the last time a typing break was taken, when the next one is
-scheduled, the keystroke thresholds and the current keystroke count, etc." t 
nil)
+scheduled, the keystroke thresholds and the current keystroke count, etc." t)
 (autoload 'type-break-guesstimate-keystroke-threshold "type-break" "\
 Guess values for the minimum/maximum keystroke threshold for typing breaks.
 
@@ -32061,20 +32102,8 @@ fraction of the maximum threshold to which to set the 
minimum threshold.
 FRAC should be the inverse of the fractional value; for example, a value of
 2 would mean to use one half, a value of 4 would mean to use one quarter, etc.
 
-(fn WPM &optional WORDLEN FRAC)" t nil)
-(register-definition-prefixes "type-break" '("timep" "type-break-"))
-
-
-;;; Generated autoloads from mail/uce.el
-
-(autoload 'uce-reply-to-uce "uce" "\
-Compose a reply to unsolicited commercial email (UCE).
-Sets up a reply buffer addressed to: the sender, his postmaster,
-his abuse@ address, and the postmaster of the mail relay used.
-You might need to set `uce-mail-reader' before using this.
-
-(fn &optional IGNORED)" t nil)
-(register-definition-prefixes "uce" '("uce-"))
+(fn WPM &optional WORDLEN FRAC)" t)
+(register-definition-prefixes "type-break" '("type-break-"))
 
 
 ;;; Generated autoloads from international/ucs-normalize.el
@@ -32088,7 +32117,7 @@ For instance:
 
   (string-glyph-compose \"Å\") => \"Å\"
 
-(fn STRING)" nil nil)
+(fn STRING)")
 (autoload 'string-glyph-decompose "ucs-normalize" "\
 Decompose STRING according to the Unicode NFD.
 This returns a new string that is the canonical decomposition of STRING,
@@ -32096,7 +32125,7 @@ a.k.a. the \"Unicode Normalization Form D\" of STRING.  
For instance:
 
   (ucs-normalize-NFD-string \"Å\") => \"Å\"
 
-(fn STRING)" nil nil)
+(fn STRING)")
 (register-definition-prefixes "ucs-normalize" '("ucs-normalize-" "utf-8-hfs"))
 
 
@@ -32108,17 +32137,25 @@ Works by overstriking underscores.
 Called from program, takes two arguments START and END
 which specify the range to operate on.
 
-(fn START END)" t nil)
+(fn START END)" t)
 (autoload 'ununderline-region "underline" "\
 Remove all underlining (overstruck underscores) in the region.
 Called from program, takes two arguments START and END
 which specify the range to operate on.
 
-(fn START END)" t nil)
+(fn START END)" t)
 
 
 ;;; Generated autoloads from mail/undigest.el
 
+(autoload 'undigestify-rmail-message "undigest" "\
+Break up a digest message into its constituent messages.
+Leaves original message, deleted, before the undigestified messages." t)
+(autoload 'unforward-rmail-message "undigest" "\
+Extract a forwarded message from the containing message.
+This puts the forwarded message into a separate rmail message following
+the containing message.  This command is only useful when messages are
+forwarded with `rmail-enable-mime-composing' set to nil." t)
 (register-definition-prefixes "undigest" '("rmail-"))
 
 
@@ -32131,7 +32168,7 @@ With ARG, activate UCS input method if and only if ARG 
is positive.
 While this input method is active, the variable
 `input-method-function' is bound to the function `ucs-input-method'.
 
-(fn &optional ARG)" nil nil)
+(fn &optional ARG)")
 (register-definition-prefixes "quail/uni-input" '("ucs-input-"))
 
 
@@ -32142,12 +32179,12 @@ Convert old-style Rmail Babyl files to mbox format.
 Specify the input Rmail Babyl file names as command line arguments.
 For each Rmail file, the corresponding output file name
 is made by adding `.mail' at the end.
-For example, invoke `emacs -batch -f batch-unrmail RMAIL'." nil nil)
+For example, invoke `emacs -batch -f batch-unrmail RMAIL'.")
 (autoload 'unrmail "unrmail" "\
 Convert old-style Rmail Babyl file FILE to mbox format file TO-FILE.
 The variable `unrmail-mbox-format' controls which mbox format to use.
 
-(fn FILE TO-FILE)" t nil)
+(fn FILE TO-FILE)" t)
 (register-definition-prefixes "unrmail" '("unrmail-mbox-format"))
 
 
@@ -32158,7 +32195,7 @@ Return nil if evaluating FORM couldn't possibly do any 
harm.
 Otherwise result is a reason why FORM is unsafe.
 VARS is a list of symbols with local bindings like `unsafep-vars'.
 
-(fn FORM &optional VARS)" nil nil)
+(fn FORM &optional VARS)")
 (register-definition-prefixes "unsafep" '("safe-functions" "unsafep-"))
 
 
@@ -32198,7 +32235,7 @@ the server.
 If URL is a multibyte string, it will be encoded as utf-8 and
 URL-encoded before it's used.
 
-(fn URL CALLBACK &optional CBARGS SILENT INHIBIT-COOKIES)" nil nil)
+(fn URL CALLBACK &optional CBARGS SILENT INHIBIT-COOKIES)")
 (autoload 'url-retrieve-synchronously "url" "\
 Retrieve URL synchronously.
 Return the buffer containing the data, or nil if there are no data
@@ -32210,15 +32247,10 @@ If INHIBIT-COOKIES is non-nil, refuse to store 
cookies.  If
 TIMEOUT is passed, it should be a number that says (in seconds)
 how long to wait for a response before giving up.
 
-(fn URL &optional SILENT INHIBIT-COOKIES TIMEOUT)" nil nil)
+(fn URL &optional SILENT INHIBIT-COOKIES TIMEOUT)")
 (register-definition-prefixes "url" '("url-"))
 
 
-;;; Generated autoloads from url/url-about.el
-
-(register-definition-prefixes "url-about" '("url-"))
-
-
 ;;; Generated autoloads from url/url-auth.el
 
 (autoload 'url-get-authentication "url-auth" "\
@@ -32240,7 +32272,7 @@ TYPE   is the type of authentication to be returned.  
This is either a string
 PROMPT is boolean - specifies whether to ask the user for a username/password
        if one cannot be found in the cache
 
-(fn URL REALM TYPE PROMPT &optional ARGS)" nil nil)
+(fn URL REALM TYPE PROMPT &optional ARGS)")
 (autoload 'url-register-auth-scheme "url-auth" "\
 Register an HTTP authentication method.
 
@@ -32253,7 +32285,7 @@ RATING   a rating between 1 and 10 of the strength of 
the authentication.
          This is used when asking for the best authentication for a specific
          URL.  The item with the highest rating is returned.
 
-(fn TYPE &optional FUNCTION RATING)" nil nil)
+(fn TYPE &optional FUNCTION RATING)")
 (register-definition-prefixes "url-auth" '("url-"))
 
 
@@ -32262,16 +32294,16 @@ RATING   a rating between 1 and 10 of the strength of 
the authentication.
 (autoload 'url-store-in-cache "url-cache" "\
 Store buffer BUFF in the cache.
 
-(fn &optional BUFF)" nil nil)
+(fn &optional BUFF)")
 (autoload 'url-is-cached "url-cache" "\
 Return non-nil if the URL is cached.
 The actual return value is the last modification time of the cache file.
 
-(fn URL)" nil nil)
+(fn URL)")
 (autoload 'url-cache-extract "url-cache" "\
 Extract FNAM from the local disk cache.
 
-(fn FNAM)" nil nil)
+(fn FNAM)")
 (register-definition-prefixes "url-cache" '("url-"))
 
 
@@ -32280,7 +32312,7 @@ Extract FNAM from the local disk cache.
 (autoload 'url-cid "url-cid" "\
 
 
-(fn URL)" nil nil)
+(fn URL)")
 (register-definition-prefixes "url-cid" '("url-cid-gnus"))
 
 
@@ -32295,7 +32327,7 @@ Extract FNAM from the local disk cache.
 Return WebDAV protocol version supported by URL.
 Returns nil if WebDAV is not supported.
 
-(fn URL)" nil nil)
+(fn URL)")
 (autoload 'url-dav-request "url-dav" "\
 Perform WebDAV operation METHOD on URL.  Return the parsed responses.
 Automatically creates an XML request body if TAG is non-nil.
@@ -32312,19 +32344,14 @@ NAMESPACES is an assoc list of (NAMESPACE . 
EXPANSION), and these are
 added to the <TAG> element.  The DAV=DAV: namespace is automatically
 added to this list, so most requests can just pass in nil.
 
-(fn URL METHOD TAG BODY &optional DEPTH HEADERS NAMESPACES)" nil nil)
+(fn URL METHOD TAG BODY &optional DEPTH HEADERS NAMESPACES)")
 (autoload 'url-dav-vc-registered "url-dav" "\
 
 
-(fn URL)" nil nil)
+(fn URL)")
 (register-definition-prefixes "url-dav" '("url-dav-"))
 
 
-;;; Generated autoloads from url/url-dired.el
-
-(register-definition-prefixes "url-dired" '("url-"))
-
-
 ;;; Generated autoloads from url/url-domsuf.el
 
 (register-definition-prefixes "url-domsuf" '("url-domsuf-"))
@@ -32340,7 +32367,7 @@ added to this list, so most requests can just pass in 
nil.
 (autoload 'url-file "url-file" "\
 Handle file: and ftp: URLs.
 
-(fn URL CALLBACK CBARGS)" nil nil)
+(fn URL CALLBACK CBARGS)")
 (register-definition-prefixes "url-file" '("url-"))
 
 
@@ -32359,7 +32386,7 @@ Handle file: and ftp: URLs.
 (autoload 'url-gateway-nslookup-host "url-gw" "\
 Attempt to resolve the given HOST using nslookup if possible.
 
-(fn HOST)" t nil)
+(fn HOST)" t)
 (autoload 'url-open-stream "url-gw" "\
 Open a stream to HOST, possibly via a gateway.
 Args per `open-network-stream'.
@@ -32369,7 +32396,7 @@ Might do a non-blocking connection; use 
`process-status' to check.
 Optional arg GATEWAY-METHOD specifies the gateway to be used,
 overriding the value of `url-gateway-method'.
 
-(fn NAME BUFFER HOST SERVICE &optional GATEWAY-METHOD)" nil nil)
+(fn NAME BUFFER HOST SERVICE &optional GATEWAY-METHOD)")
 (register-definition-prefixes "url-gw" '("url-"))
 
 
@@ -32409,13 +32436,13 @@ evaluate `(default-value \\='url-handler-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'url-file-handler "url-handlers" "\
 Function called from the `file-name-handler-alist' routines.
 OPERATION is what needs to be done (`file-exists-p', etc.).
 ARGS are the arguments that would have been passed to OPERATION.
 
-(fn OPERATION &rest ARGS)" nil nil)
+(fn OPERATION &rest ARGS)")
 (autoload 'url-copy-file "url-handlers" "\
 Copy URL to NEWNAME.  Both arguments must be strings.
 Signal a `file-already-exists' error if file NEWNAME already
@@ -32423,23 +32450,23 @@ exists, unless a third argument OK-IF-ALREADY-EXISTS 
is supplied
 and non-nil.  An integer as third argument means request
 confirmation if NEWNAME already exists.
 
-(fn URL NEWNAME &optional OK-IF-ALREADY-EXISTS &rest IGNORED)" nil nil)
+(fn URL NEWNAME &optional OK-IF-ALREADY-EXISTS &rest IGNORED)")
 (autoload 'url-file-local-copy "url-handlers" "\
 Copy URL into a temporary file on this machine.
 Returns the name of the local copy, or nil, if FILE is directly
 accessible.
 
-(fn URL &rest IGNORED)" nil nil)
+(fn URL &rest IGNORED)")
 (autoload 'url-insert-buffer-contents "url-handlers" "\
 Insert the contents of BUFFER into current buffer.
 This is like `url-insert', but also decodes the current buffer as
 if it had been inserted from a file named URL.
 
-(fn BUFFER URL &optional VISIT BEG END REPLACE)" nil nil)
+(fn BUFFER URL &optional VISIT BEG END REPLACE)")
 (autoload 'url-insert-file-contents "url-handlers" "\
 
 
-(fn URL &optional VISIT BEG END REPLACE)" nil nil)
+(fn URL &optional VISIT BEG END REPLACE)")
 (register-definition-prefixes "url-handlers" '("url-"))
 
 
@@ -32469,7 +32496,7 @@ if it had been inserted from a file named URL.
 (autoload 'url-irc "url-irc" "\
 
 
-(fn URL)" nil nil)
+(fn URL)")
 (register-definition-prefixes "url-irc" '("url-irc-"))
 
 
@@ -32481,7 +32508,7 @@ The return value is a buffer displaying the search 
results in HTML.
 URL can be a URL string, or a URL record of the type returned by
 `url-generic-parse-url'.
 
-(fn URL)" nil nil)
+(fn URL)")
 (register-definition-prefixes "url-ldap" '("url-ldap-"))
 
 
@@ -32490,11 +32517,11 @@ URL can be a URL string, or a URL record of the type 
returned by
 (autoload 'url-mail "url-mailto" "\
 
 
-(fn &rest ARGS)" t nil)
+(fn &rest ARGS)" t)
 (autoload 'url-mailto "url-mailto" "\
 Handle the mailto: URL syntax.
 
-(fn URL)" nil nil)
+(fn URL)")
 (register-definition-prefixes "url-mailto" '("url-mail-goto-field"))
 
 
@@ -32508,22 +32535,22 @@ Handle the mailto: URL syntax.
 (autoload 'url-man "url-misc" "\
 Fetch a Unix manual page URL.
 
-(fn URL)" nil nil)
+(fn URL)")
 (autoload 'url-info "url-misc" "\
 Fetch a GNU Info URL.
 
-(fn URL)" nil nil)
+(fn URL)")
 (autoload 'url-generic-emulator-loader "url-misc" "\
 
 
-(fn URL)" nil nil)
+(fn URL)")
 (defalias 'url-rlogin 'url-generic-emulator-loader)
 (defalias 'url-telnet 'url-generic-emulator-loader)
 (defalias 'url-tn3270 'url-generic-emulator-loader)
 (autoload 'url-data "url-misc" "\
 Fetch a data URL (RFC 2397).
 
-(fn URL)" nil nil)
+(fn URL)")
 (register-definition-prefixes "url-misc" '("url-do-terminal-emulator"))
 
 
@@ -32532,11 +32559,11 @@ Fetch a data URL (RFC 2397).
 (autoload 'url-news "url-news" "\
 
 
-(fn URL)" nil nil)
+(fn URL)")
 (autoload 'url-snews "url-news" "\
 
 
-(fn URL)" nil nil)
+(fn URL)")
 (register-definition-prefixes "url-news" '("url-news-"))
 
 
@@ -32550,7 +32577,7 @@ Fetch a data URL (RFC 2397).
 (autoload 'url-recreate-url "url-parse" "\
 Recreate a URL string from the parsed URLOBJ.
 
-(fn URLOBJ)" nil nil)
+(fn URLOBJ)")
 (autoload 'url-generic-parse-url "url-parse" "\
 Return an URL-struct of the parts of URL.
 The CL-style struct contains the following fields:
@@ -32590,14 +32617,14 @@ parses to
   ATTRIBUTES = nil
   FULLNESS = t
 
-(fn URL)" nil nil)
+(fn URL)")
 (register-definition-prefixes "url-parse" '("url-"))
 
 
 ;;; Generated autoloads from url/url-privacy.el
 
 (autoload 'url-setup-privacy-info "url-privacy" "\
-Setup variables that expose info about you and your system." t nil)
+Setup variables that expose info about you and your system." t)
 (register-definition-prefixes "url-privacy" '("url-device-type"))
 
 
@@ -32615,7 +32642,7 @@ but with limits on the degree of parallelism.  The 
variable
 `url-queue-parallel-processes' sets the number of concurrent processes.
 The variable `url-queue-timeout' sets a timeout.
 
-(fn URL CALLBACK &optional CBARGS SILENT INHIBIT-COOKIES)" nil nil)
+(fn URL CALLBACK &optional CBARGS SILENT INHIBIT-COOKIES)")
 (register-definition-prefixes "url-queue" '("url-queue"))
 
 
@@ -32630,7 +32657,7 @@ Function called from the `file-name-handler-alist' 
routines.
 OPERATION is what needs to be done.  ARGS are the arguments that
 would have been passed to OPERATION.
 
-(fn OPERATION &rest ARGS)" nil nil)
+(fn OPERATION &rest ARGS)")
 (register-definition-prefixes "url-tramp" '("url-tramp-convert-"))
 
 
@@ -32647,11 +32674,11 @@ If a list, it is a list of the types of messages to 
be logged.")
 (autoload 'url-debug "url-util" "\
 
 
-(fn TAG &rest ARGS)" nil nil)
+(fn TAG &rest ARGS)")
 (autoload 'url-parse-args "url-util" "\
 
 
-(fn STR &optional NODOWNCASE)" nil nil)
+(fn STR &optional NODOWNCASE)")
 (autoload 'url-insert-entities-in-string "url-util" "\
 Convert HTML markup-start characters to entity references in STRING.
 Also replaces the \" character, so that the result may be safely used as
@@ -32662,50 +32689,49 @@ conversion.  Replaces these characters as follows:
     >  ==>  &gt;
     \"  ==>  &quot;
 
-(fn STRING)" nil nil)
+(fn STRING)")
 (autoload 'url-normalize-url "url-util" "\
 Return a \"normalized\" version of URL.
 Strips out default port numbers, etc.
 
-(fn URL)" nil nil)
+(fn URL)")
 (autoload 'url-lazy-message "url-util" "\
 Just like `message', but is a no-op if called more than once a second.
 Will not do anything if `url-show-status' is nil.
 
-(fn &rest ARGS)" nil nil)
+(fn &rest ARGS)")
 (autoload 'url-get-normalized-date "url-util" "\
 Return a date string that most HTTP servers can understand.
 
-(fn &optional SPECIFIED-TIME)" nil nil)
-(autoload 'url-eat-trailing-space "url-util" "\
-Remove spaces/tabs at the end of a string.
-
-(fn X)" nil nil)
-(autoload 'url-strip-leading-spaces "url-util" "\
-Remove spaces at the front of a string.
+(fn &optional SPECIFIED-TIME)")
+(define-obsolete-function-alias 'url-eat-trailing-space #'string-trim-right 
"29.1")
+(define-obsolete-function-alias 'url-strip-leading-spaces #'string-trim-left 
"29.1")
+(autoload 'url-display-message "url-util" "\
+Like `message', but do nothing if `url-show-status' is nil.
 
-(fn X)" nil nil)
+(fn FMT &rest ARGS)")
 (autoload 'url-display-percentage "url-util" "\
 
 
-(fn FMT PERC &rest ARGS)" nil nil)
+(fn FMT PERC &rest ARGS)")
+(make-obsolete 'url-display-percentage 'url-display-message "29.1")
 (autoload 'url-percentage "url-util" "\
 
 
-(fn X Y)" nil nil)
+(fn X Y)")
 (defalias 'url-basepath 'url-file-directory)
 (autoload 'url-file-directory "url-util" "\
 Return the directory part of FILE, for a URL.
 
-(fn FILE)" nil nil)
+(fn FILE)")
 (autoload 'url-file-nondirectory "url-util" "\
 Return the nondirectory part of FILE, for a URL.
 
-(fn FILE)" nil nil)
+(fn FILE)")
 (autoload 'url-parse-query-string "url-util" "\
 
 
-(fn QUERY &optional DOWNCASE ALLOW-NEWLINES)" nil nil)
+(fn QUERY &optional DOWNCASE ALLOW-NEWLINES)")
 (autoload 'url-build-query-string "url-util" "\
 Build a query-string.
 
@@ -32728,7 +32754,7 @@ When SEMICOLONS is given, the separator will be \";\".
 When KEEP-EMPTY is given, empty values will show as \"key=\"
 instead of just \"key\" as in the example above.
 
-(fn QUERY &optional SEMICOLONS KEEP-EMPTY)" nil nil)
+(fn QUERY &optional SEMICOLONS KEEP-EMPTY)")
 (autoload 'url-unhex-string "url-util" "\
 Decode %XX sequences in a percent-encoded URL.
 If optional second argument ALLOW-NEWLINES is non-nil, then allow the
@@ -32738,7 +32764,7 @@ forbidden in URL encoding.
 The resulting string in general requires decoding using an
 appropriate coding-system; see `decode-coding-string'.
 
-(fn STR &optional ALLOW-NEWLINES)" nil nil)
+(fn STR &optional ALLOW-NEWLINES)")
 (autoload 'url-hexify-string "url-util" "\
 URI-encode STRING and return the result.
 If STRING is multibyte, it is first converted to a utf-8 byte
@@ -32752,7 +32778,7 @@ allowed characters.  Otherwise, ALLOWED-CHARS should be 
either a
 list of allowed chars, or a vector whose Nth element is non-nil
 if character N is allowed.
 
-(fn STRING &optional ALLOWED-CHARS)" nil nil)
+(fn STRING &optional ALLOWED-CHARS)")
 (autoload 'url-encode-url "url-util" "\
 Return a properly URI-encoded version of URL.
 This function also performs URI normalization, e.g. converting
@@ -32760,18 +32786,18 @@ the scheme to lowercase if it is uppercase.  Apart 
from
 normalization, if URL is already URI-encoded, this function
 should return it unchanged.
 
-(fn URL)" nil nil)
+(fn URL)")
 (autoload 'url-file-extension "url-util" "\
 Return the filename extension of FNAME.
 If optional argument X is t, then return the basename
 of the file with the extension stripped off.
 
-(fn FNAME &optional X)" nil nil)
+(fn FNAME &optional X)")
 (autoload 'url-truncate-url-for-viewing "url-util" "\
 Return a shortened version of URL that is WIDTH characters wide or less.
 WIDTH defaults to the current frame width.
 
-(fn URL &optional WIDTH)" nil nil)
+(fn URL &optional WIDTH)")
 (autoload 'url-view-url "url-util" "\
 View the current document's URL.
 Optional argument NO-SHOW means just return the URL, don't show it in
@@ -32779,7 +32805,7 @@ the minibuffer.
 
 This uses `url-current-object', set locally to the buffer.
 
-(fn &optional NO-SHOW)" t nil)
+(fn &optional NO-SHOW)" t)
 (autoload 'url-domain "url-util" "\
 Return the domain of the host of the URL.
 Return nil if this can't be determined.
@@ -32787,7 +32813,7 @@ Return nil if this can't be determined.
 For instance, this function will return \"fsf.co.uk\" if the host in URL
 is \"www.fsf.co.uk\".
 
-(fn URL)" nil nil)
+(fn URL)")
 (register-definition-prefixes "url-util" '("url-"))
 
 
@@ -32809,11 +32835,11 @@ This function has a choice of three things to do:
 You can redefine this function to choose among those three alternatives
 in any way you like.
 
-(fn FILE OPPONENT)" nil nil)
+(fn FILE OPPONENT)")
 (autoload 'userlock--ask-user-about-supersession-threat "userlock" "\
 
 
-(fn FILENAME)" nil nil)
+(fn FILENAME)")
 (autoload 'ask-user-about-supersession-threat "userlock" "\
 Ask a user who is about to modify an obsolete buffer what to do.
 This function has two choices: it can return, in which case the modification
@@ -32823,11 +32849,11 @@ in which case the proposed buffer modification will 
not be made.
 You can rewrite this to use any criterion you like to choose which one to do.
 The buffer in question is current when this function is called.
 
-(fn FILENAME)" nil nil)
+(fn FILENAME)")
 (autoload 'userlock--handle-unlock-error "userlock" "\
 Report an ERROR that occurred while unlocking a file.
 
-(fn ERROR)" nil nil)
+(fn ERROR)")
 (register-definition-prefixes "userlock" '("ask-user-about-" "file-" 
"userlock--check-content-unchanged"))
 
 
@@ -32836,19 +32862,19 @@ Report an ERROR that occurred while unlocking a file.
 (autoload 'utf-7-post-read-conversion "utf-7" "\
 
 
-(fn LEN)" nil nil)
+(fn LEN)")
 (autoload 'utf-7-imap-post-read-conversion "utf-7" "\
 
 
-(fn LEN)" nil nil)
+(fn LEN)")
 (autoload 'utf-7-pre-write-conversion "utf-7" "\
 
 
-(fn FROM TO)" nil nil)
+(fn FROM TO)")
 (autoload 'utf-7-imap-pre-write-conversion "utf-7" "\
 
 
-(fn FROM TO)" nil nil)
+(fn FROM TO)")
 (register-definition-prefixes "utf-7" '("utf-7-"))
 
 
@@ -32857,7 +32883,7 @@ Report an ERROR that occurred while unlocking a file.
 (autoload 'utf7-encode "utf7" "\
 Encode UTF-7 STRING.  Use IMAP modification if FOR-IMAP is non-nil.
 
-(fn STRING &optional FOR-IMAP)" nil nil)
+(fn STRING &optional FOR-IMAP)")
 (register-definition-prefixes "utf7" '("utf7-"))
 
 
@@ -32883,17 +32909,17 @@ Uudecode region between START and END using external 
program.
 If FILE-NAME is non-nil, save the result to FILE-NAME.  The program
 used is specified by `uudecode-decoder-program'.
 
-(fn START END &optional FILE-NAME)" t nil)
+(fn START END &optional FILE-NAME)" t)
 (autoload 'uudecode-decode-region-internal "uudecode" "\
 Uudecode region between START and END without using an external program.
 If FILE-NAME is non-nil, save the result to FILE-NAME.
 
-(fn START END &optional FILE-NAME)" t nil)
+(fn START END &optional FILE-NAME)" t)
 (autoload 'uudecode-decode-region "uudecode" "\
 Uudecode region between START and END.
 If FILE-NAME is non-nil, save the result to FILE-NAME.
 
-(fn START END &optional FILE-NAME)" nil nil)
+(fn START END &optional FILE-NAME)")
 (register-definition-prefixes "uudecode" '("uudecode-"))
 
 
@@ -32926,7 +32952,7 @@ be reported.
 If NO-ERROR is nil, signal an error that no VC backend is
 responsible for the given file.
 
-(fn FILE &optional NO-ERROR)" nil nil)
+(fn FILE &optional NO-ERROR)")
 (autoload 'vc-next-action "vc" "\
 Do the next logical version control operation on the current fileset.
 This requires that all files in the current VC fileset be in the
@@ -32954,7 +32980,7 @@ When using this command to register a new file (or 
files), it
 will automatically deduce which VC repository to register it
 with, using the most specific one.
 
-(fn VERBOSE)" t nil)
+(fn VERBOSE)" t)
 (autoload 'vc-register "vc" "\
 Register into a version control system.
 If VC-FILESET is given, register the files in that fileset.
@@ -32968,7 +32994,7 @@ directory are already registered under that backend) 
will be used to
 register the file.  If no backend declares itself responsible, the
 first backend that could register the file is used.
 
-(fn &optional VC-FILESET COMMENT)" t nil)
+(fn &optional VC-FILESET COMMENT)" t)
 (autoload 'vc-ignore "vc" "\
 Ignore FILE under the VCS of DIRECTORY.
 
@@ -32983,7 +33009,7 @@ When called interactively, prompt for a FILE to ignore, 
unless a
 prefix argument is given, in which case prompt for a file FILE to
 remove from the list of ignored files.
 
-(fn FILE &optional DIRECTORY REMOVE)" t nil)
+(fn FILE &optional DIRECTORY REMOVE)" t)
 (autoload 'vc-version-diff "vc" "\
 Report diffs between revisions REV1 and REV2 in the repository history.
 This compares two revisions of the current fileset.
@@ -32992,11 +33018,11 @@ of the last commit.
 If REV2 is nil, it defaults to the work tree, i.e. the current
 state of each file in the fileset.
 
-(fn FILES REV1 REV2)" t nil)
+(fn FILES REV1 REV2)" t)
 (autoload 'vc-root-version-diff "vc" "\
 Report diffs between REV1 and REV2 revisions of the whole tree.
 
-(fn FILES REV1 REV2)" t nil)
+(fn FILES REV1 REV2)" t)
 (autoload 'vc-diff "vc" "\
 Display diffs between file revisions.
 Normally this compares the currently selected fileset with their
@@ -33006,12 +33032,12 @@ designators specifying which revisions to compare.
 The optional argument NOT-URGENT non-nil means it is ok to say no to
 saving the buffer.
 
-(fn &optional HISTORIC NOT-URGENT)" t nil)
+(fn &optional HISTORIC NOT-URGENT)" t)
 (autoload 'vc-diff-mergebase "vc" "\
 Report diffs between the merge base of REV1 and REV2 revisions.
 The merge base is a common ancestor between REV1 and REV2 revisions.
 
-(fn FILES REV1 REV2)" t nil)
+(fn FILES REV1 REV2)" t)
 (autoload 'vc-version-ediff "vc" "\
 Show differences between REV1 and REV2 of FILES using ediff.
 This compares two revisions of the files in FILES.  Currently,
@@ -33022,7 +33048,7 @@ of the last commit.
 If REV2 is nil, it defaults to the work tree, i.e. the current
 state of each file in FILES.
 
-(fn FILES REV1 REV2)" t nil)
+(fn FILES REV1 REV2)" t)
 (autoload 'vc-ediff "vc" "\
 Display diffs between file revisions using ediff.
 Normally this compares the currently selected fileset with their
@@ -33032,7 +33058,7 @@ designators specifying which revisions to compare.
 The optional argument NOT-URGENT non-nil means it is ok to say no to
 saving the buffer.
 
-(fn HISTORIC &optional NOT-URGENT)" t nil)
+(fn HISTORIC &optional NOT-URGENT)" t)
 (autoload 'vc-root-diff "vc" "\
 Display diffs between VC-controlled whole tree revisions.
 Normally, this compares the tree corresponding to the current
@@ -33043,20 +33069,20 @@ designators specifying which revisions to compare.
 The optional argument NOT-URGENT non-nil means it is ok to say no to
 saving the buffer.
 
-(fn HISTORIC &optional NOT-URGENT)" t nil)
+(fn HISTORIC &optional NOT-URGENT)" t)
 (autoload 'vc-root-dir "vc" "\
 Return the root directory for the current VC tree.
-Return nil if the root directory cannot be identified." nil nil)
+Return nil if the root directory cannot be identified.")
 (autoload 'vc-revision-other-window "vc" "\
 Visit revision REV of the current file in another window.
 If the current file is named `F', the revision is named `F.~REV~'.
 If `F.~REV~' already exists, use it instead of checking it out again.
 
-(fn REV)" t nil)
+(fn REV)" t)
 (autoload 'vc-insert-headers "vc" "\
 Insert headers into a file for use with a version control system.
 Headers desired are inserted at point, and are pulled from
-the variable `vc-BACKEND-header'." t nil)
+the variable `vc-BACKEND-header'." t)
 (autoload 'vc-merge "vc" "\
 Perform a version control merge operation.
 You must be visiting a version controlled file, or in a `vc-dir' buffer.
@@ -33069,14 +33095,14 @@ between two revisions into the current fileset.  This 
asks for
 two revisions to merge from in the minibuffer.  If the first
 revision is a branch number, then merge all changes from that
 branch.  If the first revision is empty, merge the most recent
-changes from the current branch." t nil)
+changes from the current branch." t)
 (autoload 'vc-message-unresolved-conflicts "vc" "\
 Display a message indicating unresolved conflicts in FILENAME.
 
-(fn FILENAME)" nil nil)
+(fn FILENAME)")
 (defalias 'vc-resolve-conflicts 'smerge-ediff)
 (autoload 'vc-find-conflicted-file "vc" "\
-Visit the next conflicted file in the current project." t nil)
+Visit the next conflicted file in the current project." t)
 (autoload 'vc-create-tag "vc" "\
 Descending recursively from DIR, make a tag called NAME.
 For each registered file, the working revision becomes part of
@@ -33084,7 +33110,7 @@ the named configuration.  If the prefix argument 
BRANCHP is
 given, the tag is made as a new branch and the files are
 checked out in that new branch.
 
-(fn DIR NAME BRANCHP)" t nil)
+(fn DIR NAME BRANCHP)" t)
 (autoload 'vc-retrieve-tag "vc" "\
 For each file in or below DIR, retrieve their tagged version NAME.
 NAME can name a branch, in which case this command will switch to the
@@ -33097,7 +33123,7 @@ locked files at or below DIR (but if NAME is empty, 
locked files are
 allowed and simply skipped).
 This function runs the hook `vc-retrieve-tag-hook' when finished.
 
-(fn DIR NAME)" t nil)
+(fn DIR NAME)" t)
 (autoload 'vc-print-log "vc" "\
 List the change log of the current fileset in a window.
 If WORKING-REVISION is non-nil, leave point at that revision.
@@ -33107,7 +33133,7 @@ number of revisions to show; the default is 
`vc-log-show-limit'.
 When called interactively with a prefix argument, prompt for
 WORKING-REVISION and LIMIT.
 
-(fn &optional WORKING-REVISION LIMIT)" t nil)
+(fn &optional WORKING-REVISION LIMIT)" t)
 (autoload 'vc-print-root-log "vc" "\
 List the revision history for the current VC controlled tree in a window.
 If LIMIT is non-nil, it should be a number specifying the maximum
@@ -33118,21 +33144,21 @@ A special case is when the prefix argument is 1: in 
this case
 the command asks for the ID of a revision, and shows that revision
 with its diffs (if the underlying VCS supports that).
 
-(fn &optional LIMIT REVISION)" t nil)
+(fn &optional LIMIT REVISION)" t)
 (autoload 'vc-print-branch-log "vc" "\
 Show the change log for BRANCH root in a window.
 
-(fn BRANCH)" t nil)
+(fn BRANCH)" t)
 (autoload 'vc-log-incoming "vc" "\
 Show log of changes that will be received with pull from REMOTE-LOCATION.
 When called interactively with a prefix argument, prompt for REMOTE-LOCATION.
 
-(fn &optional REMOTE-LOCATION)" t nil)
+(fn &optional REMOTE-LOCATION)" t)
 (autoload 'vc-log-outgoing "vc" "\
 Show log of changes that will be sent with a push operation to REMOTE-LOCATION.
 When called interactively with a prefix argument, prompt for REMOTE-LOCATION.
 
-(fn &optional REMOTE-LOCATION)" t nil)
+(fn &optional REMOTE-LOCATION)" t)
 (autoload 'vc-log-search "vc" "\
 Search the log of changes for PATTERN.
 
@@ -33144,23 +33170,23 @@ Display all entries that match log messages in long 
format.
 With a prefix argument, ask for a command to run that will output
 log entries.
 
-(fn PATTERN)" t nil)
+(fn PATTERN)" t)
 (autoload 'vc-log-mergebase "vc" "\
 Show a log of changes between the merge base of REV1 and REV2 revisions.
 The merge base is a common ancestor between REV1 and REV2 revisions.
 
-(fn FILES REV1 REV2)" t nil)
+(fn FILES REV1 REV2)" t)
 (autoload 'vc-region-history "vc" "\
 Show the history of the region between FROM and TO.
 
 If called interactively, show the history between point and
 mark.
 
-(fn FROM TO)" t nil)
+(fn FROM TO)" t)
 (autoload 'vc-revert "vc" "\
 Revert working copies of the selected fileset to their repository contents.
 This asks for confirmation if the buffer contents are not identical
-to the working revision (except for keyword expansion)." t nil)
+to the working revision (except for keyword expansion)." t)
 (autoload 'vc-pull "vc" "\
 Update the current fileset or branch.
 You must be visiting a version controlled file, or in a `vc-dir' buffer.
@@ -33175,7 +33201,7 @@ file, this simply replaces the work file with the 
latest revision
 on its branch.  If the file contains changes, any changes in the
 tip revision are merged into the working file.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (defalias 'vc-update 'vc-pull)
 (autoload 'vc-push "vc" "\
 Push the current branch.
@@ -33188,7 +33214,7 @@ VCS command to run.
 On a non-distributed version control system, this signals an error.
 It also signals an error in a Bazaar bound branch.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'vc-switch-backend "vc" "\
 Make BACKEND the current version control system for FILE.
 FILE must already be registered in BACKEND.  The change is not
@@ -33197,8 +33223,8 @@ VC's perspective on FILE, it does not register or 
unregister it.
 By default, this command cycles through the registered backends.
 To get a prompt, use a prefix argument.
 
-(fn FILE BACKEND)" t nil)
-(make-obsolete 'vc-switch-backend 'nil '"28.1")
+(fn FILE BACKEND)" t)
+(make-obsolete 'vc-switch-backend 'nil "28.1")
 (autoload 'vc-transfer-file "vc" "\
 Transfer FILE to another version control system NEW-BACKEND.
 If NEW-BACKEND has a higher precedence than FILE's current backend
@@ -33209,19 +33235,19 @@ backend, then commit all changes that were made under 
the current
 backend to NEW-BACKEND, and unregister FILE from the current backend.
 (If FILE is not yet registered under NEW-BACKEND, register it.)
 
-(fn FILE NEW-BACKEND)" nil nil)
+(fn FILE NEW-BACKEND)")
 (autoload 'vc-delete-file "vc" "\
 Delete file and mark it as such in the version control system.
 If called interactively, read FILE, defaulting to the current
 buffer's file name if it's under version control.
 
-(fn FILE)" t nil)
+(fn FILE)" t)
 (autoload 'vc-rename-file "vc" "\
 Rename file OLD to NEW in both work area and repository.
 If called interactively, read OLD and NEW, defaulting OLD to the
 current buffer's file name if it's under version control.
 
-(fn OLD NEW)" t nil)
+(fn OLD NEW)" t)
 (autoload 'vc-update-change-log "vc" "\
 Find change log file and add entries from recent version control logs.
 Normally, find log entries for all registered files in the default
@@ -33236,7 +33262,7 @@ log for the default directory, which may not be 
appropriate.
 From a program, any ARGS are assumed to be filenames for which
 log entries should be gathered.
 
-(fn &rest ARGS)" t nil)
+(fn &rest ARGS)" t)
 (register-definition-prefixes "vc" '("vc-" "with-vc-properties"))
 
 
@@ -33274,7 +33300,7 @@ mode-specific menu.  `vc-annotate-color-map' and
 `vc-annotate-background-mode' specifies whether the color map
 should be applied to the background or to the foreground.
 
-(fn FILE REV &optional DISPLAY-MODE BUF MOVE-POINT-TO VC-BK)" t nil)
+(fn FILE REV &optional DISPLAY-MODE BUF MOVE-POINT-TO VC-BK)" t)
 (register-definition-prefixes "vc-annotate" '("vc-"))
 
 
@@ -33313,7 +33339,7 @@ Name of the format file in a .bzr directory.")
 (autoload 'vc-dir-root "vc-dir" "\
 Run `vc-dir' in the repository root directory without prompt.
 If the default directory of the current buffer is
-not under version control, prompt for a directory." t nil)
+not under version control, prompt for a directory." t)
 (autoload 'vc-dir "vc-dir" "\
 Show the VC status for \"interesting\" files in and below DIR.
 This allows you to mark files and perform VC operations on them.
@@ -33331,13 +33357,13 @@ These are the commands available for use in the file 
status buffer:
 
 \\{vc-dir-mode-map}
 
-(fn DIR &optional BACKEND)" t nil)
+(fn DIR &optional BACKEND)" t)
 (autoload 'vc-dir-bookmark-jump "vc-dir" "\
 Provide the `bookmark-jump' behavior for a `vc-dir' buffer.
 This implements the `handler' function interface for the record
 type returned by `vc-dir-bookmark-make-record'.
 
-(fn BMK)" nil nil)
+(fn BMK)")
 (register-definition-prefixes "vc-dir" '("vc-"))
 
 
@@ -33359,7 +33385,7 @@ that is inserted into the command line before the 
filename.
 Return the return value of the slave command in the synchronous
 case, and the process object in the asynchronous case.
 
-(fn BUFFER OKSTATUS COMMAND FILE-OR-LIST &rest FLAGS)" nil nil)
+(fn BUFFER OKSTATUS COMMAND FILE-OR-LIST &rest FLAGS)")
 (register-definition-prefixes "vc-dispatcher" '("vc-"))
 
 
@@ -33495,7 +33521,7 @@ Key bindings:
 
 \\{vera-mode-map}
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "vera-mode" '("vera-"))
 
 
@@ -33637,7 +33663,7 @@ Key bindings specific to `verilog-mode-map' are:
 
 \\{verilog-mode-map}
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "verilog-mode" '("electric-verilog-" "verilog-" 
"vl-"))
 
 
@@ -34190,7 +34216,7 @@ Key bindings:
 
 \\{vhdl-mode-map}
 
-(fn)" t nil)
+(fn)" t)
 (register-definition-prefixes "vhdl-mode" '("vhdl-"))
 
 
@@ -34199,31 +34225,31 @@ Key bindings:
 (autoload 'viet-encode-viscii-char "viet-util" "\
 Return VISCII character code of CHAR if appropriate.
 
-(fn CHAR)" nil nil)
+(fn CHAR)")
 (autoload 'viet-decode-viqr-region "viet-util" "\
 Convert `VIQR' mnemonics of the current region to Vietnamese characters.
 When called from a program, expects two arguments,
 positions (integers or markers) specifying the stretch of the region.
 
-(fn FROM TO)" t nil)
+(fn FROM TO)" t)
 (autoload 'viet-decode-viqr-buffer "viet-util" "\
-Convert `VIQR' mnemonics of the current buffer to Vietnamese characters." t 
nil)
+Convert `VIQR' mnemonics of the current buffer to Vietnamese characters." t)
 (autoload 'viet-encode-viqr-region "viet-util" "\
 Convert Vietnamese characters of the current region to `VIQR' mnemonics.
 When called from a program, expects two arguments,
 positions (integers or markers) specifying the stretch of the region.
 
-(fn FROM TO)" t nil)
+(fn FROM TO)" t)
 (autoload 'viet-encode-viqr-buffer "viet-util" "\
-Convert Vietnamese characters of the current buffer to `VIQR' mnemonics." t 
nil)
+Convert Vietnamese characters of the current buffer to `VIQR' mnemonics." t)
 (autoload 'viqr-post-read-conversion "viet-util" "\
 
 
-(fn LEN)" nil nil)
+(fn LEN)")
 (autoload 'viqr-pre-write-conversion "viet-util" "\
 
 
-(fn FROM TO)" nil nil)
+(fn FROM TO)")
 (register-definition-prefixes "viet-util" '("viet-viqr-alist" "viqr-regexp"))
 
 
@@ -34240,7 +34266,7 @@ functions that enable or disable view mode.")
 (autoload 'kill-buffer-if-not-modified "view" "\
 Like `kill-buffer', but does nothing if buffer BUF is modified.
 
-(fn BUF)" nil nil)
+(fn BUF)")
 (autoload 'view-file "view" "\
 View FILE in View mode, returning to previous buffer when done.
 Emacs commands editing the buffer contents are not available; instead, a
@@ -34251,7 +34277,7 @@ For a list of all View commands, type H or h while 
viewing.
 
 This command runs the normal hook `view-mode-hook'.
 
-(fn FILE)" t nil)
+(fn FILE)" t)
 (autoload 'view-file-other-window "view" "\
 View FILE in View mode in another window.
 When done, return that window to its previous buffer, and kill the
@@ -34265,7 +34291,7 @@ For a list of all View commands, type H or h while 
viewing.
 
 This command runs the normal hook `view-mode-hook'.
 
-(fn FILE)" t nil)
+(fn FILE)" t)
 (autoload 'view-file-other-frame "view" "\
 View FILE in View mode in another frame.
 When done, kill the buffer visiting FILE if unmodified and if it wasn't
@@ -34280,7 +34306,7 @@ For a list of all View commands, type H or h while 
viewing.
 
 This command runs the normal hook `view-mode-hook'.
 
-(fn FILE)" t nil)
+(fn FILE)" t)
 (autoload 'view-buffer "view" "\
 View BUFFER in View mode, returning to previous buffer when done.
 Emacs commands editing the buffer contents are not available; instead, a
@@ -34304,7 +34330,7 @@ This function does not enable View mode if the buffer's 
major mode
 has a `special' mode-class, because such modes usually have their
 own View-like bindings.
 
-(fn BUFFER &optional EXIT-ACTION)" t nil)
+(fn BUFFER &optional EXIT-ACTION)" t)
 (autoload 'view-buffer-other-window "view" "\
 View BUFFER in View mode in another window.
 Emacs commands editing the buffer contents are not available;
@@ -34325,7 +34351,7 @@ This function does not enable View mode if the buffer's 
major mode
 has a `special' mode-class, because such modes usually have their
 own View-like bindings.
 
-(fn BUFFER &optional NOT-RETURN EXIT-ACTION)" t nil)
+(fn BUFFER &optional NOT-RETURN EXIT-ACTION)" t)
 (autoload 'view-buffer-other-frame "view" "\
 View BUFFER in View mode in another frame.
 Emacs commands editing the buffer contents are not available;
@@ -34346,7 +34372,7 @@ This function does not enable View mode if the buffer's 
major mode
 has a `special' mode-class, because such modes usually have their
 own View-like bindings.
 
-(fn BUFFER &optional NOT-RETURN EXIT-ACTION)" t nil)
+(fn BUFFER &optional NOT-RETURN EXIT-ACTION)" t)
 (autoload 'view-mode "view" "\
 Toggle View mode, a minor mode for viewing text but not editing it.
 
@@ -34441,19 +34467,7 @@ evaluate `view-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
-(autoload 'view-return-to-alist-update "view" "\
-Update `view-return-to-alist' of buffer BUFFER.
-Remove from `view-return-to-alist' all entries referencing dead
-windows.  Optional argument ITEM non-nil means add ITEM to
-`view-return-to-alist' after purging.  For a description of items
-that can be added see the RETURN-TO-ALIST argument of the
-function `view-mode-exit'.  If `view-return-to-alist' contains an
-entry for the selected window, purge that entry from
-`view-return-to-alist' before adding ITEM.
-
-(fn BUFFER &optional ITEM)" nil nil)
-(make-obsolete 'view-return-to-alist-update '"this function has no effect." 
'"24.1")
+(fn &optional ARG)" t)
 (autoload 'view-mode-enter "view" "\
 Enter View mode and set up exit from view mode depending on optional arguments.
 Optional argument QUIT-RESTORE if non-nil must specify a valid
@@ -34469,21 +34483,21 @@ For a list of all View commands, type H or h while 
viewing.
 
 This function runs the normal hook `view-mode-hook'.
 
-(fn &optional QUIT-RESTORE EXIT-ACTION)" nil nil)
+(fn &optional QUIT-RESTORE EXIT-ACTION)")
 (autoload 'View-exit-and-edit "view" "\
-Exit View mode and make the current buffer editable." t nil)
+Exit View mode and make the current buffer editable." t)
 (register-definition-prefixes "view" '("View-" "view-"))
 
 
 ;;; Generated autoloads from emulation/viper.el
 
-(push (purecopy '(viper 3 14 1)) package--builtin-versions)
+(push (purecopy '(viper 3 14 2)) package--builtin-versions)
 (autoload 'toggle-viper-mode "viper" "\
 Toggle Viper on/off.
-If Viper is enabled, turn it off.  Otherwise, turn it on." t nil)
+If Viper is enabled, turn it off.  Otherwise, turn it on." t)
 (autoload 'viper-mode "viper" "\
-Turn on Viper emulation of Vi in Emacs.  See Info node `(viper)Top'." t nil)
-(register-definition-prefixes "viper" '("set-viper-state-in-major-mode" 
"this-major-mode-requires-vi-state" "viper-"))
+Turn on Viper emulation of Vi in Emacs.  See Info node `(viper)Top'." t)
+(register-definition-prefixes "viper" '("viper-"))
 
 
 ;;; Generated autoloads from emulation/viper-cmd.el
@@ -34503,7 +34517,7 @@ Turn on Viper emulation of Vi in Emacs.  See Info node 
`(viper)Top'." t nil)
 
 ;;; Generated autoloads from emulation/viper-keym.el
 
-(register-definition-prefixes "viper-keym" '("ex-read-filename-map" "viper-"))
+(register-definition-prefixes "viper-keym" '("viper-"))
 
 
 ;;; Generated autoloads from emulation/viper-macs.el
@@ -34598,7 +34612,7 @@ disable automatic display of the warning or disable the 
warning
 entirely by setting `warning-suppress-types' or
 `warning-suppress-log-types' on their behalf.
 
-(fn TYPE MESSAGE &optional LEVEL BUFFER-NAME)" nil nil)
+(fn TYPE MESSAGE &optional LEVEL BUFFER-NAME)")
 (autoload 'lwarn "warnings" "\
 Display a warning message made from (format-message MESSAGE ARGS...).
 \\<special-mode-map>
@@ -34619,15 +34633,15 @@ LEVEL should be either :debug, :warning, :error, or 
:emergency
 :warning   -- suspicious data or circumstances.
 :debug     -- info for debugging only.
 
-(fn TYPE LEVEL MESSAGE &rest ARGS)" nil nil)
+(fn TYPE LEVEL MESSAGE &rest ARGS)")
 (autoload 'warn "warnings" "\
 Display a warning message made from (format-message MESSAGE ARGS...).
 Aside from generating the message with `format-message',
 this is equivalent to `display-warning', using
 `emacs' as the type and `:warning' as the level.
 
-(fn MESSAGE &rest ARGS)" nil nil)
-(register-definition-prefixes "warnings" '("warning-"))
+(fn MESSAGE &rest ARGS)")
+(register-definition-prefixes "warnings" '("warning"))
 
 
 ;;; Generated autoloads from wdired.el
@@ -34640,7 +34654,7 @@ buffer, the target of the links, and the permission 
bits of the
 files.  After typing \\[wdired-finish-edit], Emacs modifies the files and
 directories to reflect your edits.
 
-See `wdired-mode'." t nil)
+See `wdired-mode'." t)
 (register-definition-prefixes "wdired" '("wdired-"))
 
 
@@ -34653,7 +34667,7 @@ See the documentation for the `webjump-sites' variable 
for how to customize the
 hotlist.
 
 Please submit bug reports and other feedback to the author, Neil W. Van Dyke
-<nwv@acm.org>." t nil)
+<nwv@acm.org>." t)
 (register-definition-prefixes "webjump" '("webjump-"))
 
 
@@ -34661,8 +34675,6 @@ Please submit bug reports and other feedback to the 
author, Neil W. Van Dyke
 
  (put 'which-func-format 'risky-local-variable t)
  (put 'which-func-current 'risky-local-variable t)
-(define-obsolete-function-alias 'which-func-mode 'which-function-mode "\
-24.1")
 (defvar which-function-mode nil "\
 Non-nil if Which-Function mode is enabled.
 See the `which-function-mode' command
@@ -34692,7 +34704,7 @@ evaluate `(default-value \\='which-function-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "which-func" '("which-func"))
 
 
@@ -34722,7 +34734,7 @@ evaluate `whitespace-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'whitespace-newline-mode "whitespace" "\
 Toggle newline visualization (Whitespace Newline mode).
 
@@ -34748,7 +34760,7 @@ evaluate `whitespace-newline-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (defvar global-whitespace-mode nil "\
 Non-nil if Global Whitespace mode is enabled.
 See the `global-whitespace-mode' command
@@ -34778,7 +34790,7 @@ evaluate `(default-value \\='global-whitespace-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (defvar global-whitespace-newline-mode nil "\
 Non-nil if Global Whitespace-Newline mode is enabled.
 See the `global-whitespace-newline-mode' command
@@ -34812,7 +34824,7 @@ evaluate `(default-value 
\\='global-whitespace-newline-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'whitespace-toggle-options "whitespace" "\
 Toggle local `whitespace-mode' options.
 
@@ -34883,7 +34895,7 @@ The valid symbols are:
 
 See `whitespace-style' and `indent-tabs-mode' for documentation.
 
-(fn ARG)" t nil)
+(fn ARG)" t)
 (autoload 'global-whitespace-toggle-options "whitespace" "\
 Toggle global `whitespace-mode' options.
 
@@ -34903,6 +34915,7 @@ Interactively, it accepts one of the following chars:
    r   toggle trailing blanks visualization
    l   toggle \"long lines\" visualization
    L   toggle \"long lines\" tail visualization
+   C-l toggle \"long lines\" one character visualization
    n   toggle NEWLINE visualization
    e   toggle empty line at bob and/or eob visualization
    C-i toggle indentation SPACEs visualization (via `indent-tabs-mode')
@@ -34933,6 +34946,7 @@ The valid symbols are:
    trailing            toggle trailing blanks visualization
    lines               toggle \"long lines\" visualization
    lines-tail          toggle \"long lines\" tail visualization
+   lines-char          toggle \"long lines\" one character visualization
    newline             toggle NEWLINE visualization
    empty               toggle empty line at bob and/or eob visualization
    indentation         toggle indentation SPACEs visualization
@@ -34954,7 +34968,7 @@ The valid symbols are:
 
 See `whitespace-style' and `indent-tabs-mode' for documentation.
 
-(fn ARG)" t nil)
+(fn ARG)" t)
 (autoload 'whitespace-cleanup "whitespace" "\
 Cleanup some blank problems in all buffer or at region.
 
@@ -35006,7 +35020,7 @@ The problems cleaned up are:
    `space-after-tab::space', replace TABs by SPACEs.
 
 See `whitespace-style', `indent-tabs-mode' and `tab-width' for
-documentation." t nil)
+documentation." t)
 (autoload 'whitespace-cleanup-region "whitespace" "\
 Cleanup some blank problems at region.
 
@@ -35047,13 +35061,13 @@ The problems cleaned up are:
 See `whitespace-style', `indent-tabs-mode' and `tab-width' for
 documentation.
 
-(fn START END)" t nil)
+(fn START END)" t)
 (autoload 'whitespace-report "whitespace" "\
 Report some whitespace problems in buffer.
 
 Perform `whitespace-report-region' on the current buffer.
 
-(fn &optional FORCE REPORT-IF-BOGUS)" t nil)
+(fn &optional FORCE REPORT-IF-BOGUS)" t)
 (autoload 'whitespace-report-region "whitespace" "\
 Report some whitespace problems in a region.
 
@@ -35091,7 +35105,7 @@ See `whitespace-style' for documentation.
 See also `whitespace-cleanup' and `whitespace-cleanup-region' for
 cleaning up these problems.
 
-(fn START END &optional FORCE REPORT-IF-BOGUS)" t nil)
+(fn START END &optional FORCE REPORT-IF-BOGUS)" t)
 (register-definition-prefixes "whitespace" '("whitespace-"))
 
 
@@ -35100,15 +35114,15 @@ cleaning up these problems.
 (autoload 'widget-browse-at "wid-browse" "\
 Browse the widget under point.
 
-(fn POS)" t nil)
+(fn POS)" t)
 (autoload 'widget-browse "wid-browse" "\
 Create a widget browser for WIDGET.
 
-(fn WIDGET)" t nil)
+(fn WIDGET)" t)
 (autoload 'widget-browse-other-window "wid-browse" "\
 Show widget browser for WIDGET in other window.
 
-(fn &optional WIDGET)" t nil)
+(fn &optional WIDGET)" t)
 (autoload 'widget-minor-mode "wid-browse" "\
 Minor mode for traversing widgets.
 
@@ -35126,7 +35140,7 @@ evaluate `widget-minor-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "wid-browse" '("widget-"))
 
 
@@ -35135,31 +35149,36 @@ it is disabled.
 (autoload 'widgetp "wid-edit" "\
 Return non-nil if WIDGET is a widget.
 
-(fn WIDGET)" nil nil)
+(fn WIDGET)")
 (autoload 'widget-prompt-value "wid-edit" "\
 Prompt for a value matching WIDGET, using PROMPT.
 The current value is assumed to be VALUE, unless UNBOUND is non-nil.
 
-(fn WIDGET PROMPT &optional VALUE UNBOUND)" nil nil)
+(fn WIDGET PROMPT &optional VALUE UNBOUND)")
 (autoload 'widget-create "wid-edit" "\
 Create widget of TYPE.
 The optional ARGS are additional keyword arguments.
 
-(fn TYPE &rest ARGS)" nil nil)
+(fn TYPE &rest ARGS)")
 (autoload 'widget-delete "wid-edit" "\
 Delete WIDGET.
 
-(fn WIDGET)" nil nil)
+(fn WIDGET)")
+(autoload 'widget-convert "wid-edit" "\
+Convert TYPE to a widget without inserting it in the buffer.
+The optional ARGS are additional keyword arguments.
+
+(fn TYPE &rest ARGS)")
 (autoload 'widget-insert "wid-edit" "\
 Call `insert' with ARGS even if surrounding text is read only.
 
-(fn &rest ARGS)" nil nil)
+(fn &rest ARGS)")
 (defvar widget-keymap (let ((map (make-sparse-keymap))) (define-key map "\11" 
'widget-forward) (define-key map "\33\11" 'widget-backward) (define-key map 
[(shift tab)] 'widget-backward) (put 'widget-backward :advertised-binding 
[(shift tab)]) (define-key map [backtab] 'widget-backward) (define-key map 
[down-mouse-2] 'widget-button-click) (define-key map [down-mouse-1] 
'widget-button-click) (define-key map [(control 109)] 'widget-button-press) 
map) "\
 Keymap containing useful binding for buffers containing widgets.
 Recommended as a parent keymap for modes using widgets.
 Note that such modes will need to require wid-edit.")
 (autoload 'widget-setup "wid-edit" "\
-Setup current buffer so editing string widgets works." nil nil)
+Setup current buffer so editing string widgets works.")
 (register-definition-prefixes "wid-edit" '("widget-"))
 
 
@@ -35174,7 +35193,7 @@ it is relative to the top edge (for positive ARG) or 
the bottom edge
 If no window is at the desired location, an error is signaled
 unless `windmove-create-window' is non-nil and a new window is created.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'windmove-up "windmove" "\
 Select the window above the current one.
 With no prefix argument, or with prefix argument equal to zero, \"up\"
@@ -35184,7 +35203,7 @@ negative ARG) of the current window.
 If no window is at the desired location, an error is signaled
 unless `windmove-create-window' is non-nil and a new window is created.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'windmove-right "windmove" "\
 Select the window to the right of the current one.
 With no prefix argument, or with prefix argument equal to zero,
@@ -35194,7 +35213,7 @@ bottom edge (for negative ARG) of the current window.
 If no window is at the desired location, an error is signaled
 unless `windmove-create-window' is non-nil and a new window is created.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'windmove-down "windmove" "\
 Select the window below the current one.
 With no prefix argument, or with prefix argument equal to zero,
@@ -35204,7 +35223,7 @@ it is relative to the left edge (for positive ARG) or 
the right edge
 If no window is at the desired location, an error is signaled
 unless `windmove-create-window' is non-nil and a new window is created.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (defvar windmove-mode t "\
 Non-nil if Windmove mode is enabled.
 See the `windmove-mode' command
@@ -35227,7 +35246,7 @@ evaluate `(default-value \\='windmove-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'windmove-default-keybindings "windmove" "\
 Set up keybindings for `windmove'.
 Keybindings are of the form MODIFIERS-{left,right,up,down},
@@ -35236,43 +35255,43 @@ If MODIFIERS is `none', the keybindings will be 
directly bound to
 the arrow keys.
 Default value of MODIFIERS is `shift'.
 
-(fn &optional MODIFIERS)" t nil)
+(fn &optional MODIFIERS)" t)
 (autoload 'windmove-display-left "windmove" "\
 Display the next buffer in window to the left of the current one.
 See the logic of the prefix ARG and `windmove-display-no-select'
 in `windmove-display-in-direction'.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'windmove-display-up "windmove" "\
 Display the next buffer in window above the current one.
 See the logic of the prefix ARG and `windmove-display-no-select'
 in `windmove-display-in-direction'.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'windmove-display-right "windmove" "\
 Display the next buffer in window to the right of the current one.
 See the logic of the prefix ARG and `windmove-display-no-select'
 in `windmove-display-in-direction'.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'windmove-display-down "windmove" "\
 Display the next buffer in window below the current one.
 See the logic of the prefix ARG and `windmove-display-no-select'
 in `windmove-display-in-direction'.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'windmove-display-same-window "windmove" "\
 Display the next buffer in the same window.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'windmove-display-new-frame "windmove" "\
 Display the next buffer in a new frame.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'windmove-display-new-tab "windmove" "\
 Display the next buffer in a new tab.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'windmove-display-default-keybindings "windmove" "\
 Set up keybindings for directional buffer display.
 Keys are bound to commands that display the next buffer in the specified
@@ -35282,31 +35301,31 @@ If MODIFIERS is `none', the keybindings will be 
directly bound to
 the arrow keys.
 Default value of MODIFIERS is `shift-meta'.
 
-(fn &optional MODIFIERS)" t nil)
+(fn &optional MODIFIERS)" t)
 (autoload 'windmove-delete-left "windmove" "\
 Delete the window to the left of the current one.
 If prefix ARG is \\[universal-argument], delete the selected window and
 select the window that was to the left of the current one.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'windmove-delete-up "windmove" "\
 Delete the window above the current one.
 If prefix ARG is \\[universal-argument], delete the selected window and
 select the window that was above the current one.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'windmove-delete-right "windmove" "\
 Delete the window to the right of the current one.
 If prefix ARG is \\[universal-argument], delete the selected window and
 select the window that was to the right of the current one.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'windmove-delete-down "windmove" "\
 Delete the window below the current one.
 If prefix ARG is \\[universal-argument], delete the selected window and
 select the window that was below the current one.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (autoload 'windmove-delete-default-keybindings "windmove" "\
 Set up keybindings for directional window deletion.
 Keys are bound to commands that delete windows in the specified
@@ -35317,15 +35336,15 @@ If PREFIX is `none', no prefix is used.  If MODIFIERS 
is `none',
 the keybindings are directly bound to the arrow keys.
 Default value of PREFIX is \\`C-x' and MODIFIERS is `shift'.
 
-(fn &optional PREFIX MODIFIERS)" t nil)
+(fn &optional PREFIX MODIFIERS)" t)
 (autoload 'windmove-swap-states-left "windmove" "\
-Swap the states with the window on the left from the current one." t nil)
+Swap the states with the window on the left from the current one." t)
 (autoload 'windmove-swap-states-up "windmove" "\
-Swap the states with the window above from the current one." t nil)
+Swap the states with the window above from the current one." t)
 (autoload 'windmove-swap-states-down "windmove" "\
-Swap the states with the window below from the current one." t nil)
+Swap the states with the window below from the current one." t)
 (autoload 'windmove-swap-states-right "windmove" "\
-Swap the states with the window on the right from the current one." t nil)
+Swap the states with the window on the right from the current one." t)
 (autoload 'windmove-swap-states-default-keybindings "windmove" "\
 Set up keybindings for directional window swap states.
 Keys are bound to commands that swap the states of the selected window
@@ -35336,7 +35355,7 @@ If MODIFIERS is `none', the keybindings will be 
directly bound to the
 arrow keys.
 Default value of MODIFIERS is `shift-super'.
 
-(fn &optional MODIFIERS)" t nil)
+(fn &optional MODIFIERS)" t)
 (register-definition-prefixes "windmove" '("windmove-"))
 
 
@@ -35357,8 +35376,8 @@ Winner mode is a global minor mode that records the 
changes in
 the window configuration (i.e. how the frames are partitioned
 into windows) so that the changes can be \"undone\" using the
 command `winner-undo'.  By default this one is bound to the key
-sequence `C-c <left>'.  If you change your mind (while undoing),
-you can press `C-c <right>' (calling `winner-redo').
+sequence \\`C-c <left>'.  If you change your mind (while undoing),
+you can press \\`C-c <right>' (calling `winner-redo').
 
 This is a global minor mode.  If called interactively, toggle the
 `Winner mode' mode.  If the prefix argument is positive, enable
@@ -35374,7 +35393,7 @@ evaluate `(default-value \\='winner-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "winner" '("winner-"))
 
 
@@ -35408,9 +35427,9 @@ updated (e.g. to re-interpret the current directory).
 Used non-interactively, arguments are optional: if given then TOPIC
 should be a topic string and non-nil RE-CACHE forces re-caching.
 
-(fn &optional TOPIC RE-CACHE)" t nil)
+(fn &optional TOPIC RE-CACHE)" t)
 (autoload 'woman-dired-find-file "woman" "\
-In dired, run the WoMan man-page browser on this file." t nil)
+In dired, run the WoMan man-page browser on this file." t)
 (autoload 'woman-find-file "woman" "\
 Find, decode and browse a specific UN*X man-page source file FILE-NAME.
 Use existing buffer if possible; reformat only if prefix arg given.
@@ -35420,12 +35439,12 @@ No external programs are used, except that `gunzip' 
will be used to
 decompress the file if appropriate.  See the documentation for the
 `woman' command for further details.
 
-(fn FILE-NAME &optional REFORMAT)" t nil)
+(fn FILE-NAME &optional REFORMAT)" t)
 (autoload 'woman-bookmark-jump "woman" "\
 Default bookmark handler for Woman buffers.
 
-(fn BOOKMARK)" nil nil)
-(register-definition-prefixes "woman" '("WoMan-" "menu-bar-manuals-menu" 
"set-woman-file-regexp" "woman"))
+(fn BOOKMARK)")
+(register-definition-prefixes "woman" '("WoMan-" "woman"))
 
 
 ;;; Generated autoloads from textmodes/word-wrap-mode.el
@@ -35450,7 +35469,7 @@ evaluate `word-wrap-whitespace-mode'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (put 'global-word-wrap-whitespace-mode 'globalized-minor-mode t)
 (defvar global-word-wrap-whitespace-mode nil "\
 Non-nil if Global Word-Wrap-Whitespace mode is enabled.
@@ -35475,7 +35494,7 @@ Word-Wrap-Whitespace mode is enabled in all buffers 
where
 See `word-wrap-whitespace-mode' for more information on
 Word-Wrap-Whitespace mode.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "word-wrap-mode" 
'("word-wrap-whitespace-characters"))
 
 
@@ -35512,7 +35531,7 @@ Both features can be combined by providing a cons cell
 
   (symbol-qnames . ALIST).
 
-(fn FILE &optional PARSE-DTD PARSE-NS)" nil nil)
+(fn FILE &optional PARSE-DTD PARSE-NS)")
 (autoload 'xml-parse-region "xml" "\
 Parse the region from BEG to END in BUFFER.
 Return the XML parse tree, or raise an error if the region does
@@ -35539,12 +35558,12 @@ Both features can be combined by providing a cons cell
 
   (symbol-qnames . ALIST).
 
-(fn &optional BEG END BUFFER PARSE-DTD PARSE-NS)" nil nil)
+(fn &optional BEG END BUFFER PARSE-DTD PARSE-NS)")
 (autoload 'xml-remove-comments "xml" "\
 Remove XML/HTML comments in the region between BEG and END.
 All text between the <!-- ... --> markers will be removed.
 
-(fn BEG END)" nil nil)
+(fn BEG END)")
 (register-definition-prefixes "xml" '("xml-"))
 
 
@@ -35561,31 +35580,30 @@ If there is XML that is not well-formed that looks 
like an XML
 declaration, return nil.  Otherwise, return t.
 If LIMIT is non-nil, then do not consider characters beyond LIMIT.
 
-(fn &optional LIMIT)" nil nil)
+(fn &optional LIMIT)")
 (register-definition-prefixes "xmltok" '("xmltok-"))
 
 
 ;;; Generated autoloads from progmodes/xref.el
 
-(push (purecopy '(xref 1 4 1)) package--builtin-versions)
-(autoload 'xref-find-backend "xref" nil nil nil)
-(define-obsolete-function-alias 'xref-pop-marker-stack #'xref-go-back "\
-29.1")
+(push (purecopy '(xref 1 5 0)) package--builtin-versions)
+(autoload 'xref-find-backend "xref")
+(define-obsolete-function-alias 'xref-pop-marker-stack #'xref-go-back "29.1")
 (autoload 'xref-go-back "xref" "\
 Go back to the previous position in xref history.
-To undo, use \\[xref-go-forward]." t nil)
+To undo, use \\[xref-go-forward]." t)
 (autoload 'xref-go-forward "xref" "\
-Got to the point where a previous \\[xref-go-back] was invoked." t nil)
+Got to the point where a previous \\[xref-go-back] was invoked." t)
 (autoload 'xref-marker-stack-empty-p "xref" "\
-Whether the xref back-history is empty." nil nil)
+Whether the xref back-history is empty.")
 (autoload 'xref-forward-history-empty-p "xref" "\
-Whether the xref forward-history is empty." nil nil)
+Whether the xref forward-history is empty.")
 (autoload 'xref-show-xrefs "xref" "\
 Display some Xref values produced by FETCHER using DISPLAY-ACTION.
 The meanings of both arguments are the same as documented in
 `xref-show-xrefs-function'.
 
-(fn FETCHER DISPLAY-ACTION)" nil nil)
+(fn FETCHER DISPLAY-ACTION)")
 (autoload 'xref-find-definitions "xref" "\
 Find the definition of the identifier at point.
 With prefix argument or when there's no identifier at point,
@@ -35598,15 +35616,15 @@ buffer where the user can select from the list.
 
 Use \\[xref-go-back] to return back to where you invoked this command.
 
-(fn IDENTIFIER)" t nil)
+(fn IDENTIFIER)" t)
 (autoload 'xref-find-definitions-other-window "xref" "\
 Like `xref-find-definitions' but switch to the other window.
 
-(fn IDENTIFIER)" t nil)
+(fn IDENTIFIER)" t)
 (autoload 'xref-find-definitions-other-frame "xref" "\
 Like `xref-find-definitions' but switch to the other frame.
 
-(fn IDENTIFIER)" t nil)
+(fn IDENTIFIER)" t)
 (autoload 'xref-find-references "xref" "\
 Find references to the identifier at point.
 This command might prompt for the identifier as needed, perhaps
@@ -35615,24 +35633,24 @@ With prefix argument, or if 
`xref-prompt-for-identifier' is t,
 always prompt for the identifier.  If `xref-prompt-for-identifier'
 is nil, prompt only if there's no usable symbol at point.
 
-(fn IDENTIFIER)" t nil)
+(fn IDENTIFIER)" t)
 (autoload 'xref-find-definitions-at-mouse "xref" "\
 Find the definition of identifier at or around mouse click.
 This command is intended to be bound to a mouse event.
 
-(fn EVENT)" t nil)
+(fn EVENT)" t)
 (autoload 'xref-find-references-at-mouse "xref" "\
 Find references to the identifier at or around mouse click.
 This command is intended to be bound to a mouse event.
 
-(fn EVENT)" t nil)
+(fn EVENT)" t)
 (autoload 'xref-find-apropos "xref" "\
 Find all meaningful symbols that match PATTERN.
 The argument has the same meaning as in `apropos'.
 See `tags-apropos-additional-actions' for how to augment the
 output of this command when the backend is etags.
 
-(fn PATTERN)" t nil)
+(fn PATTERN)" t)
  (define-key esc-map "." #'xref-find-definitions)
  (define-key esc-map "," #'xref-go-back)
  (define-key esc-map [?\C-,] #'xref-go-forward)
@@ -35648,7 +35666,7 @@ This function uses the Semantic Symbol Reference API, 
see
 `semantic-symref-tool-alist' for details on which tools are used,
 and when.
 
-(fn SYMBOL DIR)" nil nil)
+(fn SYMBOL DIR)")
 (autoload 'xref-matches-in-directory "xref" "\
 Find all matches for REGEXP in directory DIR.
 Return a list of xref values.
@@ -35656,7 +35674,7 @@ Only files matching some of FILES and none of IGNORES 
are searched.
 FILES is a string with glob patterns separated by spaces.
 IGNORES is a list of glob patterns for files to ignore.
 
-(fn REGEXP FILES DIR IGNORES)" nil nil)
+(fn REGEXP FILES DIR IGNORES)")
 (autoload 'xref-matches-in-files "xref" "\
 Find all matches for REGEXP in FILES.
 Return a list of xref values.
@@ -35665,13 +35683,13 @@ FILES must be a list of absolute file names.
 See `xref-search-program' and `xref-search-program-alist' for how
 to control which program to use when looking for matches.
 
-(fn REGEXP FILES)" nil nil)
+(fn REGEXP FILES)")
 (register-definition-prefixes "xref" '("xref-"))
 
 
 ;;; Generated autoloads from progmodes/xscheme.el
 
-(register-definition-prefixes "xscheme" '("default-xscheme-runlight" 
"exit-scheme-interaction-mode" "global-set-scheme-interaction-buffer" "local-" 
"reset-scheme" "run-scheme" "scheme-" "start-scheme" "verify-xscheme-buffer" 
"xscheme-"))
+(register-definition-prefixes "xscheme" '("exit-scheme-interaction-mode" 
"global-set-scheme-interaction-buffer" "local-" "reset-scheme" "run-scheme" 
"scheme-" "start-scheme" "xscheme-"))
 
 
 ;;; Generated autoloads from nxml/xsd-regexp.el
@@ -35713,7 +35731,7 @@ evaluate `(default-value \\='xterm-mouse-mode)'.
 The mode's hook is called both when the mode is enabled and when
 it is disabled.
 
-(fn &optional ARG)" t nil)
+(fn &optional ARG)" t)
 (register-definition-prefixes "xt-mouse" '("turn-o" "xt-mouse-epoch" 
"xterm-mouse-"))
 
 
@@ -35724,13 +35742,13 @@ Ask xwidget-webkit to browse URL.
 NEW-SESSION specifies whether to create a new xwidget-webkit session.
 Interactively, URL defaults to the string looking like a url around point.
 
-(fn URL &optional NEW-SESSION)" t nil)
+(fn URL &optional NEW-SESSION)" t)
 (autoload 'xwidget-webkit-bookmark-jump-handler "xwidget" "\
 Jump to the web page bookmarked by the bookmark record BOOKMARK.
 If `xwidget-webkit-bookmark-jump-new-session' is non-nil, create
 a new xwidget-webkit session, otherwise use an existing session.
 
-(fn BOOKMARK)" nil nil)
+(fn BOOKMARK)")
 (register-definition-prefixes "xwidget" '("xwidget-"))
 
 
@@ -35743,7 +35761,7 @@ accepting the media type.  The mode has to register 
itself using
 the `yank-media-handler' mechanism.
 
 Also see `yank-media-types' for a command that lets you explore
-all the different selection types." t nil)
+all the different selection types." t)
 (autoload 'yank-media-handler "yank-media" "\
 Register HANDLER for dealing with `yank-media' actions for TYPES.
 TYPES should be a MIME media type symbol, a regexp, or a list
@@ -35753,7 +35771,7 @@ HANDLER is a function that will be called with two 
arguments: The
 MIME type (a symbol on the form `image/png') and the selection
 data (a string).
 
-(fn TYPES HANDLER)" nil nil)
+(fn TYPES HANDLER)")
 (register-definition-prefixes "yank-media" '("yank-media-"))
 
 
@@ -35762,9 +35780,9 @@ data (a string).
 (autoload 'yenc-decode-region "yenc" "\
 Yenc decode region between START and END using an internal decoder.
 
-(fn START END)" t nil)
+(fn START END)" t)
 (autoload 'yenc-extract-filename "yenc" "\
-Extract file name from an yenc header." nil nil)
+Extract file name from an yenc header.")
 (register-definition-prefixes "yenc" '("yenc-"))
 
 
@@ -35776,7 +35794,7 @@ Extract file name from an yenc header." nil nil)
 ;;; Generated autoloads from play/zone.el
 
 (autoload 'zone "zone" "\
-Zone out, completely." t nil)
+Zone out, completely." t)
 (register-definition-prefixes "zone" '("zone-"))
 
 ;;; End of scraped data
@@ -35784,8 +35802,8 @@ Zone out, completely." t nil)
 (provide 'loaddefs)
 
 ;; Local Variables:
-;; version-control: never
 ;; no-byte-compile: t
+;; version-control: never
 ;; no-update-autoloads: t
 ;; coding: utf-8-emacs-unix
 ;; End:
diff --git a/lisp/leim/quail/hangul.el b/lisp/leim/quail/hangul.el
index 0ef5b2d5c7..83fee1e04c 100644
--- a/lisp/leim/quail/hangul.el
+++ b/lisp/leim/quail/hangul.el
@@ -103,9 +103,10 @@
   (make-vector 6 0))
 
 (defsubst notzerop (number)
+  (declare (obsolete "use `(not (zerop ...))'." "29.1"))
   (not (zerop number)))
 
-(defsubst alphabetp (char)
+(defsubst hangul-alphabetp (char)
   (or (and (>= char ?A) (<= char ?Z))
       (and (>= char ?a) (<= char ?z))))
 
@@ -191,10 +192,10 @@ and insert CHAR to new `hangul-queue'."
              (aset hangul-queue 0 char))
             ((and (zerop (aref hangul-queue 1))
                   (zerop (aref hangul-queue 2))
-                  (notzerop (hangul-djamo 'cho (aref hangul-queue 0) char)))
+                  (not (zerop (hangul-djamo 'cho (aref hangul-queue 0) char))))
              (aset hangul-queue 1 char))
             ((and (zerop (aref hangul-queue 4))
-                  (notzerop (aref hangul-queue 2))
+                  (not (zerop (aref hangul-queue 2)))
                   (/= char 8)
                   (/= char 19)
                   (/= char 25)
@@ -213,7 +214,7 @@ and insert CHAR to new `hangul-queue'."
                     char)))
              (aset hangul-queue 4 char))
             ((and (zerop (aref hangul-queue 5))
-                  (notzerop (hangul-djamo 'jong (aref hangul-queue 4) char))
+                  (not (zerop (hangul-djamo 'jong (aref hangul-queue 4) char)))
                   (numberp
                    (hangul-character
                     (+ (aref hangul-queue 0)
@@ -246,14 +247,14 @@ Other parts are the same as a 
`hangul2-input-method-jaum'."
              (aset hangul-queue 2 char))
             ((and (zerop (aref hangul-queue 3))
                   (zerop (aref hangul-queue 4))
-                  (notzerop (hangul-djamo 'jung (aref hangul-queue 2) char)))
+                  (not (zerop (hangul-djamo 'jung (aref hangul-queue 2) 
char))))
              (aset hangul-queue 3 char)))
       (hangul-insert-character hangul-queue)
     (let ((next-char (vector 0 0 char 0 0 0)))
-      (cond ((notzerop (aref hangul-queue 5))
+      (cond ((not (zerop (aref hangul-queue 5)))
             (aset next-char 0 (aref hangul-queue 5))
             (aset hangul-queue 5 0))
-           ((notzerop (aref hangul-queue 4))
+            ((not (zerop (aref hangul-queue 4)))
             (aset next-char 0 (aref hangul-queue 4))
             (aset hangul-queue 4 0)))
       (hangul-insert-character hangul-queue
@@ -271,7 +272,7 @@ Other parts are the same as a `hangul2-input-method-jaum'."
              (aset hangul-queue 0 char))
             ((and (zerop (aref hangul-queue 1))
                   (zerop (aref hangul-queue 2))
-                  (notzerop (hangul-djamo 'cho (aref hangul-queue 0) char)))
+                  (not (zerop (hangul-djamo 'cho (aref hangul-queue 0) char))))
              (aset hangul-queue 1 char)))
       (hangul-insert-character hangul-queue)
     (hangul-insert-character hangul-queue
@@ -287,7 +288,7 @@ Other parts are the same as a `hangul3-input-method-cho'."
                   (zerop (aref hangul-queue 4)))
              (aset hangul-queue 2 char))
             ((and (zerop (aref hangul-queue 3))
-                  (notzerop (hangul-djamo 'jung (aref hangul-queue 2) char)))
+                  (not (zerop (hangul-djamo 'jung (aref hangul-queue 2) 
char))))
              (aset hangul-queue 3 char)))
       (hangul-insert-character hangul-queue)
     (hangul-insert-character hangul-queue
@@ -300,8 +301,8 @@ This function processes a Hangul 3-Bulsik Jongseong.
 The Jongseong can be located in a Jongseong position.
 Other parts are the same as a `hangul3-input-method-cho'."
   (if (cond ((and (zerop (aref hangul-queue 4))
-                  (notzerop (aref hangul-queue 0))
-                  (notzerop (aref hangul-queue 2))
+                  (not (zerop (aref hangul-queue 0)))
+                  (not (zerop (aref hangul-queue 2)))
                   (numberp
                    (hangul-character
                     (+ (aref hangul-queue 0)
@@ -317,7 +318,7 @@ Other parts are the same as a `hangul3-input-method-cho'."
                     char)))
              (aset hangul-queue 4 char))
             ((and (zerop (aref hangul-queue 5))
-                  (notzerop (hangul-djamo 'jong (aref hangul-queue 4) char))
+                  (not (zerop (hangul-djamo 'jong (aref hangul-queue 4) char)))
                   (numberp
                    (hangul-character
                     (+ (aref hangul-queue 0)
@@ -349,7 +350,7 @@ Other parts are the same as a `hangul3-input-method-cho'."
     (while (and (> i 0) (zerop (aref hangul-queue i)))
       (setq i (1- i)))
     (aset hangul-queue i 0))
-  (if (notzerop (apply #'+ (append hangul-queue nil)))
+  (if (not (zerop (apply #'+ (append hangul-queue nil))))
       (hangul-insert-character hangul-queue)
     (delete-char -1)))
 
@@ -388,7 +389,7 @@ When a Korean input method is off, convert the following 
hangul character."
 
 (defun hangul2-input-method (key)
   "2-Bulsik input method."
-  (if (or buffer-read-only (not (alphabetp key)))
+  (if (or buffer-read-only (not (hangul-alphabetp key)))
       (list key)
     (quail-setup-overlays nil)
     (let ((input-method-function nil)
@@ -405,7 +406,7 @@ When a Korean input method is off, convert the following 
hangul character."
                (cond ((and (stringp seq)
                            (= 1 (length seq))
                            (setq key (aref seq 0))
-                           (alphabetp key))
+                            (hangul-alphabetp key))
                       (hangul2-input-method-internal key))
                      ((commandp cmd)
                       (call-interactively cmd))
@@ -546,6 +547,8 @@ HELP-TEXT is a text set in `hangul-input-method-help-text'."
   (with-output-to-temp-buffer "*Help*"
     (princ hangul-input-method-help-text)))
 
+(define-obsolete-function-alias 'alphabetp 'hangul-alphabetp "29.1")
+
 (provide 'hangul)
 
 ;; Local Variables:
diff --git a/lisp/leim/quail/indian.el b/lisp/leim/quail/indian.el
index 8fffcc3511..431d8369c1 100644
--- a/lisp/leim/quail/indian.el
+++ b/lisp/leim/quail/indian.el
@@ -127,47 +127,34 @@
  indian-mlm-itrans-v5-hash "malayalam-itrans" "Malayalam" "MlmIT"
  "Malayalam transliteration by ITRANS method.")
 
-(defvar quail-tamil-itrans-syllable-table
-  (let ((vowels
-        '(("அ" nil "a")
-          ("ஆ" "ா" "A")
-          ("இ" "ி" "i")
-          ("ஈ" "ீ" "I")
-          ("உ" "ு" "u")
-          ("ஊ" "ூ" "U")
-          ("எ" "ெ" "e")
-          ("ஏ" "ே" "E")
-          ("ஐ" "ை" "ai")
-          ("ஒ" "ொ" "o")
-          ("ஓ" "ோ" "O")
-          ("ஔ" "ௌ" "au")))
-       (consonants
-        '(("க" "k")                    ; U+0B95
-          ("ங" "N^")                   ; U+0B99
-          ("ச" "ch")                   ; U+0B9A
-          ("ஞ" "JN")                   ; U+0B9E
-          ("ட" "T")                    ; U+0B9F
-          ("ண" "N")                    ; U+0BA3
-          ("த" "t")                    ; U+0BA4
-          ("ந" "n")                    ; U+0BA8
-          ("ப" "p")                    ; U+0BAA
-          ("ம" "m")                    ; U+0BAE
-          ("ய" "y")                    ; U+0BAF
-          ("ர" "r")                    ; U+0BB0
-          ("ல" "l")                    ; U+0BB2
-          ("வ" "v")                    ; U+0BB5
-          ("ழ" "z")                    ; U+0BB4
-          ("ள" "L")                    ; U+0BB3
-          ("ற" "rh")                   ; U+0BB1
-          ("ன" "nh")                   ; U+0BA9
-          ("ஜ" "j")                    ; U+0B9C
-          ("ஶ" nil)                    ; U+0BB6
-          ("ஷ" "Sh")                   ; U+0BB7
-          ("ஸ" "s")                    ; U+0BB8
-          ("ஹ" "h")                    ; U+0BB9
-          ("க்ஷ" "x" )                 ; U+0B95
-          ))
-       (virama #x0BCD)
+;; This is needed since the Unicode codepoint order does not reflect
+;; the actual order in the Tamil language.
+(defvar quail-tamil-itrans--consonant-order
+  '("க" "ங" "ச" "ஞ" "ட" "ண"
+    "த" "ந" "ப" "ம" "ய" "ர"
+    "ல" "வ" "ழ" "ள" "ற" "ன"
+    "ஜ" "ஸ" "ஷ" "ஹ" "க்ஷ"
+    "க்‌ஷ" "ஶ"))
+
+(defun quail-tamil-itrans-compute-syllable-table (vowels consonants)
+  "Return the syllable table for the input method as a string.
+VOWELS is a list of (VOWEL SIGN INPUT-SEQ) where VOWEL is the
+Tamil vowel character, SIGN is the vowel sign corresponding to
+that vowel character or nil for none, and INPUT-SEQ is the input
+sequence to insert VOWEL.
+
+CONSONANTS is a list of (CONSONANT INPUT-SEQ...) where CONSONANT
+is the Tamil consonant character, and INPUT-SEQ is one or more
+strings that describe how to insert CONSONANT."
+  (setq vowels (sort vowels
+                     (lambda (x y)
+                       (string-lessp (car x) (car y)))))
+  (setq consonants
+     (sort consonants
+         (lambda (x y)
+           (or (seq-position (car x) quail-tamil-itrans--consonant-order) 1000)
+           (or (seq-position (car y) quail-tamil-itrans--consonant-order) 
1000))))
+  (let ((virama #x0BCD)
        clm)
     (with-temp-buffer
       (insert "\n")
@@ -197,21 +184,45 @@
          (insert (propertize "\t" 'display (list 'space :align-to clm))
                  (car c) (or (nth 1 v) ""))
          (setq clm (+ clm 6)))
-       (insert "\n" (or (nth 1 c) "")
-               (propertize "\t" 'display '(space :align-to 4))
-               "|")
-       (setq clm 6)
-
-       (dolist (v vowels)
-         (apply #'insert (propertize "\t" 'display (list 'space :align-to clm))
-                (if (nth 1 c) (list (nth 1 c) (nth 2 v)) (list "")))
-         (setq clm (+ clm 6))))
+        (dolist (ct (cdr c))
+         (insert "\n" (or ct "")
+                 (propertize "\t" 'display '(space :align-to 4))
+                 "|")
+         (setq clm 6)
+          (dolist (v vowels)
+           (apply #'insert (propertize "\t" 'display (list 'space :align-to 
clm))
+                  (if ct (list ct (nth 2 v)) (list "")))
+           (setq clm (+ clm 6)))))
       (insert "\n")
       (insert "----+")
       (insert-char ?- 74)
       (insert "\n")
       (buffer-string))))
 
+(defvar quail-tamil-itrans-syllable-table
+  (quail-tamil-itrans-compute-syllable-table
+   (let ((vowels (car indian-tml-base-table))
+         trans v ret)
+     (dotimes (i (length vowels))
+       (when (setq v (nth i vowels))
+         (when (characterp (car v))
+           (setcar v (string (car v))))
+         (setq trans (nth i (car indian-itrans-v5-table-for-tamil)))
+         (push (append v (list (if (listp trans) (car trans) trans)))
+               ret)))
+     ret)
+   (let ((consonants (cadr indian-tml-base-table))
+         trans c ret)
+     (dotimes (i (length consonants))
+       (when (setq c (nth i consonants))
+         (when (characterp c)
+           (setq c (string c)))
+         (setq trans (nth i (cadr indian-itrans-v5-table-for-tamil)))
+         (push (cons c (if (listp trans) trans (list trans)))
+               ret)))
+     (setq ret (nreverse ret))
+     ret)))
+
 (defvar quail-tamil-itrans-numerics-and-symbols-table
   (let ((numerics '((?௰ "பத்து") (?௱ "நூறு") (?௲ "ஆயிரம்")))
        (symbols '((?௳ "நாள்") (?௴ "மாதம்") (?௵ "வருடம்")
@@ -244,25 +255,28 @@
       (insert "\n")
       (buffer-string))))
 
-(defun quail-tamil-itrans-compute-signs-table (digitp)
+(defun quail-tamil-itrans-compute-signs-table (digitp various)
   "Compute the signs table for the tamil-itrans input method.
-If DIGITP is non-nil, include the digits translation as well."
-  (let ((various '((?ஃ . "H") ("ஸ்ரீ" . "srii") (?ௐ)))
-       (digits "௦௧௨௩௪௫௬௭௮௯")
+If DIGITP is non-nil, include the digits translation as well.
+If VARIOUS is non-nil, then it should a list of (CHAR TRANS)
+where CHAR is the character/string to translate and TRANS is
+CHAR's translation."
+  (let ((digits "௦௧௨௩௪௫௬௭௮௯")
        (width 6) clm)
     (with-temp-buffer
-      (insert "\n" (make-string 18 ?-) "+")
-      (when digitp (insert (make-string 60 ?-)))
+      (insert "\n" (make-string 18 ?-))
+      (when digitp
+        (insert "+" (make-string 60 ?-)))
       (insert "\n")
       (insert
        (propertize "\t" 'display '(space :align-to 5)) "various"
-       (propertize "\t" 'display '(space :align-to 18)) "|")
+       (propertize "\t" 'display '(space :align-to 18)))
       (when digitp
         (insert
-         (propertize "\t" 'display '(space :align-to 45)) "digits"))
-      (insert "\n" (make-string 18 ?-) "+")
+          "|" (propertize "\t" 'display '(space :align-to 45)) "digits"))
+      (insert "\n" (make-string 18 ?-))
       (when digitp
-        (insert (make-string 60 ?-)))
+        (insert "+" (make-string 60 ?-)))
       (insert "\n")
       (setq clm 0)
 
@@ -270,7 +284,8 @@ If DIGITP is non-nil, include the digits translation as 
well."
        (insert (propertize "\t" 'display (list 'space :align-to clm))
                (car (nth i various)))
        (setq clm (+ clm width)))
-      (insert (propertize "\t" 'display '(space :align-to 18)) "|")
+      (when digitp
+        (insert (propertize "\t" 'display '(space :align-to 18)) "|"))
       (setq clm 20)
       (when digitp
         (dotimes (i 10)
@@ -281,25 +296,28 @@ If DIGITP is non-nil, include the digits translation as 
well."
       (setq clm 0)
       (dotimes (i (length various))
        (insert (propertize "\t" 'display (list 'space :align-to clm))
-               (or (cdr (nth i various)) ""))
+               (or (cadr (nth i various)) ""))
        (setq clm (+ clm width)))
-      (insert (propertize "\t" 'display '(space :align-to 18)) "|")
+      (when digitp
+        (insert (propertize "\t" 'display '(space :align-to 18)) "|"))
       (setq clm 20)
       (when digitp
         (dotimes (i 10)
          (insert (propertize "\t" 'display (list 'space :align-to clm))
                  (format "%d" i))
          (setq clm (+ clm width))))
-      (insert "\n" (make-string 18 ?-) "+")
+      (insert "\n" (make-string 18 ?-))
       (when digitp
-        (insert (make-string 60 ?-) "\n"))
+        (insert "+" (make-string 60 ?-) "\n"))
       (buffer-string))))
 
 (defvar quail-tamil-itrans-various-signs-and-digits-table
-  (quail-tamil-itrans-compute-signs-table t))
+  (quail-tamil-itrans-compute-signs-table
+   t '((?ஃ "H") ("ஸ்ரீ" "srii") (?ௐ "OM"))))
 
 (defvar quail-tamil-itrans-various-signs-table
-  (quail-tamil-itrans-compute-signs-table nil))
+  (quail-tamil-itrans-compute-signs-table
+   nil '((?ஃ "H") ("ஸ்ரீ" "srii") (?ௐ "OM"))))
 
 (if nil
     (quail-define-package "tamil-itrans" "Tamil" "TmlIT" t "Tamil ITRANS"))
@@ -347,6 +365,160 @@ Their descriptions are included for easy reference.
 
 Full key sequences are listed below:")
 
+;;;
+;;; Tamil phonetic input method
+;;;
+
+;; Define the input method straightaway.
+(quail-define-package "tamil-phonetic" "Tamil" "ழ" t
+ "Customisable Tamil phonetic input method.
+To change the translation rules of the input method, customize
+`tamil-translation-rules'.
+
+To use native Tamil digits, customize `tamil-translation-rules'
+accordingly.
+
+To end the current translation process, say 
\\<quail-translation-keymap>\\[quail-select-current] (defined in
+`quail-translation-keymap').  This is useful when there's a
+conflict between two possible translation.
+
+The current input scheme is:
+
+### Basic syllables (உயிர்மெய் எழுத்துக்கள்) ###
+\\=\\<tamil--syllable-table>
+
+### Miscellaneous ####
+\\=\\<tamil--signs-table>
+
+The following characters have NO input sequence associated with
+them by default.  Their descriptions are included for easy
+reference.
+\\=\\<quail-tamil-itrans-numerics-and-symbols-table>
+
+Full key sequences are listed below:"
+ nil nil nil nil nil nil t)
+
+(defvar tamil--syllable-table nil)
+(defvar tamil--signs-table nil)
+(defvar tamil--hashtables
+  (cons (make-hash-table :test #'equal)
+        (make-hash-table :test #'equal)))
+(defvar tamil--vowel-signs
+  '(("அ" . t) ("ஆ" . ?ா) ("இ" . ?ி) ("ஈ" . ?ீ)
+    ("உ" . ?ு) ("ஊ" . ?ூ) ("எ" . ?ெ) ("ஏ" . ?ே)
+    ("ஐ" . ?ை) ("ஒ" . ?ொ) ("ஓ" . ?ோ) ("ஔ" . ?ௌ)))
+
+(defun tamil--setter (sym val)
+  (set-default sym val)
+  (tamil--update-quail-rules val))
+
+(defun tamil--make-tables (rules)
+  (let (v v-table v-trans
+          c-table c-trans
+          m-table m-trans)
+    (dolist (ch rules)
+      (cond
+       ;; Vowel.
+       ((setq v (assoc-default (car ch) tamil--vowel-signs))
+        (push (list (car ch) (and (characterp v) v)) v-table)
+        (push (cdr ch) v-trans))
+       ;; Consonant.  It needs to end with pulli.
+       ((string-suffix-p "்" (car ch))
+        ;; Strip the pulli now.
+        (push (substring (car ch) 0 -1) c-table)
+        (push (cdr ch) c-trans))
+       ;; If nothing else, then consider it a misc character.
+       (t (push (car ch) m-table)
+          (push (cdr ch) m-trans))))
+    (list v-table v-trans c-table c-trans m-table m-trans)))
+
+(defun tamil--update-quail-rules (rules &optional name)
+  ;; This function does pretty much what `indian-make-hash' does
+  ;; except that we don't try to copy the structure of
+  ;; `indian-tml-base-table' which leads to less code hassle.
+  (let* ((quail-current-package (assoc (or name "tamil-phonetic") 
quail-package-alist))
+         (tables (tamil--make-tables rules))
+         (v (nth 0 tables))
+         (v-trans (nth 1 tables))
+         (c (nth 2 tables))
+         (c-trans (nth 3 tables))
+         (m (nth 4 tables))
+         (m-trans (nth 5 tables))
+         (pulli (string #x0BCD)))
+    (clrhash (car tamil--hashtables))
+    (clrhash (cdr tamil--hashtables))
+    (indian--puthash-v v v-trans tamil--hashtables)
+    (indian--puthash-c c c-trans pulli tamil--hashtables)
+    (indian--puthash-cv c c-trans v v-trans tamil--hashtables)
+    (indian--puthash-m m m-trans tamil--hashtables)
+    ;; Now override the current translation rules.
+    ;; Empty quail map is '(list nil)'.
+    (setf (nth 2 quail-current-package) '(nil))
+    (maphash (lambda (k v)
+               (quail-defrule k (if (length= v 1)
+                                    (string-to-char v)
+                                  (vector v))))
+             (cdr tamil--hashtables))
+    (setq  tamil--syllable-table
+           (quail-tamil-itrans-compute-syllable-table
+            (mapcar (lambda (ch) (append ch (pop v-trans))) v)
+            (mapcar (lambda (ch) (cons ch (pop c-trans))) c))
+           tamil--signs-table
+           (quail-tamil-itrans-compute-signs-table
+            nil
+            (append (mapcar (lambda (ch) (cons ch (pop m-trans))) m)
+                    (and (gethash "ஸ்" (car tamil--hashtables))
+                         `(("ஸ்ரீ" ,(concat (gethash "ஸ்" (car 
tamil--hashtables))
+                                          (gethash "ரீ" (car 
tamil--hashtables)))))))))))
+
+(defgroup tamil-input nil
+  "Translation rules for the Tamil input method."
+  :prefix "tamil-"
+  :group 'leim)
+
+(defcustom tamil-translation-rules
+  ;; Vowels.
+  '(("அ" "a") ("ஆ" "aa") ("இ" "i") ("ஈ" "ii")
+    ("உ" "u") ("ஊ" "uu") ("எ" "e") ("ஏ" "ee")
+    ("ஐ" "ai") ("ஒ" "o") ("ஓ" "oo") ("ஔ" "au" "ow")
+
+    ;; Consonants.
+    ("க்" "k" "g") ("ங்" "ng") ("ச்" "ch" "s") ("ஞ்" "nj") ("ட்" "t" "d")
+    ("ண்" "N") ("த்" "th" "dh") ("ந்" "nh") ("ப்" "p" "b") ("ம்" "m")
+    ("ய்" "y") ("ர்" "r") ("ல்" "l") ("வ்" "v") ("ழ்" "z" "zh")
+    ("ள்" "L") ("ற்" "rh") ("ன்" "n")
+    ;; Sanskrit.
+    ("ஜ்" "j") ("ஸ்" "S") ("ஷ்" "sh") ("ஹ்" "h")
+    ("க்‌ஷ்" "ksh") ("க்ஷ்" "ksH") ("ஶ்" "Z")
+
+    ;; Misc.  ஃ is neither a consonant nor a vowel.
+    ("ஃ" "F" "q")
+    ("ௐ" "OM"))
+  "List of input sequences to translate to Tamil characters.
+Each element should be (CHARACTER INPUT-SEQUENCES...) where
+CHARACTER is the Tamil character, and INPUT-SEQUENCES are one
+or more input sequences which produce that character.
+
+CHARACTER is considered as a consonant (மெய் எழுத்து) if it ends
+with a pulli (virama).
+
+CHARACTER that is neither a vowel nor a consonant is inserted as
+is."
+  :group 'tamil-input
+  :type '(alist :key-type string :value-type (repeat string))
+  :set #'tamil--setter
+  :version "29.1"
+  :options
+  (delq nil
+        (append (mapcar #'car tamil--vowel-signs)
+                (mapcar (lambda (x) (if (characterp x)
+                                        (string x #x0BCD)
+                                      (and x (concat x "்"))))
+                        (nth 1 indian-tml-base-table))
+                '("ஃ" "ௐ")
+                ;; Digits.
+                (mapcar #'string (nth 3 indian-tml-base-digits-table)))))
+
 ;;;
 ;;; Input by Inscript
 ;;;
@@ -530,7 +702,7 @@ Full key sequences are listed below:")
 ;; Probhat Input Method
 (quail-define-package
  "bengali-probhat" "Bengali" "BngPB" t
- "Probhat keyboard for Bengali/Bangla" nil t nil nil nil nil nil nil nil nil t)
+ "Probhat keyboard for Bengali/Bangla" nil t nil t t nil nil nil nil nil t)
 
 (quail-define-rules
   ("!" ?!)
@@ -681,7 +853,7 @@ Full key sequences are listed below:")
 (quail-define-package "malayalam-mozhi" "Malayalam" "MlmMI" t
                       "Malayalam transliteration by Mozhi method."
                       nil nil t nil nil nil t nil
-                      #'indian-mlm-mozhi-update-translation)
+                      #'indian-mlm-mozhi-update-translation nil t)
 
 (maphash
  (lambda (key val)
diff --git a/lisp/leim/quail/persian.el b/lisp/leim/quail/persian.el
index 61428c94f0..07d006c2a4 100644
--- a/lisp/leim/quail/persian.el
+++ b/lisp/leim/quail/persian.el
@@ -23,7 +23,7 @@
 ;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 ;;; Commentary:
-;;
+
 ;; This file contains a collection of input methods for
 ;; Persian languages (Farsi, Urdu, Pashto/Afghanic, ...)
 ;;
@@ -402,7 +402,7 @@
 
 ;;;;;;;;;;;  isiri-6219 Table 6 -- جدول ۶ - حروِفِ  عربی
  ("F" ?إ)
- ("D" ?\u0671)     ;; (ucs-insert #x0671)ٱ   named: حرفِ الفِ وصل
+ ("D" ?\u0671)     ;; (insert-char #x0671)ٱ   named: حرفِ الفِ وصل
  ("K"  ?ك)         ;;  Arabic kaf
  ("Th" ?ة)         ;; ta marbuteh
  ("Y"  ?ي)
@@ -421,40 +421,40 @@
  ("8"  ?۸)
  ("9"  ?۹)
 
- ("\\/" ?\u066B)     ;; (ucs-insert #x066B)٫   named: ممیزِ فارسی
- ("\\," ?\u066C)     ;; (ucs-insert #x066C)٬   named: جداکننده‌ی هزارهای فارسی
- ("%" ?\u066A)       ;; (ucs-insert #x066A)٪   named: درصدِ فارسی
- ("+" ?\u002B)     ;; (ucs-insert #x002B)+   named: علامتِ به‌اضافه
- ("-" ?\u2212)     ;; (ucs-insert #x2212)−   named: علامتِ منها
- ("\\*" ?\u00D7)     ;; (ucs-insert #x00D7)×   named: علامتِ ضرب
- ("\\-" ?\u00F7)    ;; (ucs-insert #x00F7)÷   named: علامتِ تقسیم
- ("<" ?\u003C)     ;; (ucs-insert #x003C)<   named: علامتِ کوچکتر
- ("=" ?\u003D)     ;; (ucs-insert #x003D)=   named: علامتِ مساوی
- (">" ?\u003E)     ;; (ucs-insert #x003E)>   named: علامتِ بزرگتر
+ ("\\/" ?\u066B)     ;; (insert-char #x066B)٫   named: ممیزِ فارسی
+ ("\\," ?\u066C)     ;; (insert-char #x066C)٬   named: جداکننده‌ی هزارهای فارسی
+ ("%" ?\u066A)       ;; (insert-char #x066A)٪   named: درصدِ فارسی
+ ("+" ?\u002B)     ;; (insert-char #x002B)+   named: علامتِ به‌اضافه
+ ("-" ?\u2212)     ;; (insert-char #x2212)−   named: علامتِ منها
+ ("\\*" ?\u00D7)     ;; (insert-char #x00D7)×   named: علامتِ ضرب
+ ("\\-" ?\u00F7)    ;; (insert-char #x00F7)÷   named: علامتِ تقسیم
+ ("<" ?\u003C)     ;; (insert-char #x003C)<   named: علامتِ کوچکتر
+ ("=" ?\u003D)     ;; (insert-char #x003D)=   named: علامتِ مساوی
+ (">" ?\u003E)     ;; (insert-char #x003E)>   named: علامتِ بزرگتر
 
 
 ;;;;;;;;;;;  isiri-6219 Table 2 -- جدول ۲ -  علائم نقطه گذاریِ مشترک
  ;;; Space
  ("."  ?.)  ;;
- (":" ?\u003A)     ;; (ucs-insert #x003A):   named:
- ("!" ?\u0021)     ;; (ucs-insert #x0021)!   named:
- ("\\." ?\u2026)     ;; (ucs-insert #x2026)…   named:
- ("\\-" ?\u2010)     ;; (ucs-insert #x2010)‐   named:
- ("-" ?\u002D)     ;; (ucs-insert #x002D)-   named:
+ (":" ?\u003A)     ;; (insert-char #x003A):   named:
+ ("!" ?\u0021)     ;; (insert-char #x0021)!   named:
+ ("\\." ?\u2026)     ;; (insert-char #x2026)…   named:
+ ("\\-" ?\u2010)     ;; (insert-char #x2010)‐   named:
+ ("-" ?\u002D)     ;; (insert-char #x002D)-   named:
  ("|" ?|)
  ;;("\\\\" ?\)
  ("//" ?/)
- ("*" ?\u002A)     ;; (ucs-insert #x002A)*   named:
- ("(" ?\u0028)     ;; (ucs-insert #x0028)(   named:
- (")" ?\u0029)     ;; (ucs-insert #x0029))   named:
- ("[" ?\u005B)     ;; (ucs-insert #x005B)[   named:
- ("[" ?\u005D)     ;; (ucs-insert #x005D)]   named:
- ("{" ?\u007B)     ;; (ucs-insert #x007B){   named:
- ("}" ?\u007D)     ;; (ucs-insert #x007D)}   named:
- ("\\<" ?\u00AB)     ;; (ucs-insert #x00AB)«   named:
- ("\\>" ?\u00BB)     ;; (ucs-insert #x00BB)»   named:
- ("N" ?\u00AB)     ;; (ucs-insert #x00AB)«   named:
- ("M" ?\u00BB)     ;; (ucs-insert #x00BB)»   named:
+ ("*" ?\u002A)     ;; (insert-char #x002A)*   named:
+ ("(" ?\u0028)     ;; (insert-char #x0028)(   named:
+ (")" ?\u0029)     ;; (insert-char #x0029))   named:
+ ("[" ?\u005B)     ;; (insert-char #x005B)[   named:
+ ("[" ?\u005D)     ;; (insert-char #x005D)]   named:
+ ("{" ?\u007B)     ;; (insert-char #x007B){   named:
+ ("}" ?\u007D)     ;; (insert-char #x007D)}   named:
+ ("\\<" ?\u00AB)     ;; (insert-char #x00AB)«   named:
+ ("\\>" ?\u00BB)     ;; (insert-char #x00BB)»   named:
+ ("N" ?\u00AB)     ;; (insert-char #x00AB)«   named:
+ ("M" ?\u00BB)     ;; (insert-char #x00BB)»   named:
 
 ;;;;;;;;;;;  isiri-6219 Table 3 -- جدول ۳ -  علائم نقطه گذاریِ فارسی
  ("," ?،)  ;; farsi
@@ -466,20 +466,20 @@
 ;;;;;;;;;;;  isiri-6219 Table 1 -- جدول ۱ -  نویسه‌های کنترلی
  ;; LF
  ;; CR
- ("&zwnj;" ?\u200C) ;; (ucs-insert #x200C)‌   named: فاصله‌ی مجازی
+ ("&zwnj;" ?\u200C) ;; (insert-char #x200C)‌   named: فاصله‌ی مجازی
  ("/" ?\u200C)      ;;
- ("&zwj;" ?\u200D)  ;; (ucs-insert #x200D)‍   named: اتصالِ مجازی
+ ("&zwj;" ?\u200D)  ;; (insert-char #x200D)‍   named: اتصالِ مجازی
  ("J" ?\u200D)      ;;
- ("&lrm;" ?\u200E)  ;; (ucs-insert #x200E)‎   named: نشانه‌ی چپ‌به‌راست
- ("&rlm;" ?\u200F)  ;; (ucs-insert #x200F)‏   named: نشانه‌ی راست‌به‌چپ
- ("&ls;" ?\u2028)   ;; (ucs-insert #x2028)
   named: جداکننده‌ی سطرها
- ("&ps;" ?\u2028)   ;; (ucs-insert #x2029)
   named: جداکننده‌ی بندها
- ("&lre;" ?\u202A)   ;; (ucs-insert #x202A)‪   named: زیرمتنِ چپ‌به‌راست
- ("&rle;" ?\u202B)   ;; (ucs-insert #x202B)   named: زیرمتنِ راست‌به‌چپ
- ("&pdf;" ?\u202C)   ;; (ucs-insert #x202C)   named: پایانِ زیرمتن
- ("&lro;" ?\u202D)   ;; (ucs-insert #x202D)   named: زیرمتنِ اکیداً چپ‌به‌راست
- ("&rlo;" ?\u202D)   ;; (ucs-insert #x202E)   named: زیرمتنِ اکیداً راست‌به‌چپ
- ("&bom;" ?\uFEFF)   ;; (ucs-insert #xFEFF)   named: نشانه‌ی ترتیبِ بایت‌ها
+ ("&lrm;" ?\u200E)  ;; (insert-char #x200E)‎   named: نشانه‌ی چپ‌به‌راست
+ ("&rlm;" ?\u200F)  ;; (insert-char #x200F)‏   named: نشانه‌ی راست‌به‌چپ
+ ("&ls;" ?\u2028)   ;; (insert-char #x2028)
   named: جداکننده‌ی سطرها
+ ("&ps;" ?\u2028)   ;; (insert-char #x2029)
   named: جداکننده‌ی بندها
+ ("&lre;" ?\u202A)   ;; (insert-char #x202A)‪   named: زیرمتنِ چپ‌به‌راست
+ ("&rle;" ?\u202B)   ;; (insert-char #x202B)   named: زیرمتنِ راست‌به‌چپ
+ ("&pdf;" ?\u202C)   ;; (insert-char #x202C)   named: پایانِ زیرمتن
+ ("&lro;" ?\u202D)   ;; (insert-char #x202D)   named: زیرمتنِ اکیداً چپ‌به‌راست
+ ("&rlo;" ?\u202D)   ;; (insert-char #x202E)   named: زیرمتنِ اکیداً راست‌به‌چپ
+ ("&bom;" ?\uFEFF)   ;; (insert-char #xFEFF)   named: نشانه‌ی ترتیبِ بایت‌ها
 
 
 ;;;;;;;;;;;  isiri-6219 Table 7 -- جدول ۷ -  نشانه‌هایِ فارسی
@@ -491,14 +491,14 @@
  ("O" ?ٌ)  ;; دو پيش فارسى -- تنوين رفع
  ("~"  ?ّ)  ;; tashdid ;;  تشديد فارسى
  ("@" ?ْ)   ;; ساکن فارسى
- ("U" ?\u0653)  ;; (ucs-insert #x0653)ٓ   named: مدِ فارسی
+ ("U" ?\u0653)  ;; (insert-char #x0653)ٓ   named: مدِ فارسی
  ("`" ?ٔ)  ;; همزه فارسى بالا
- ("C" ?\u0655)  ;; (ucs-insert #x0655)ٕ   named: همزه فارسى پایین
- ("$" ?\u0670)  ;; (ucs-insert #x0670)ٰ   named: الفِ مقصوره‌ی فارسی
+ ("C" ?\u0655)  ;; (insert-char #x0655)ٕ   named: همزه فارسى پایین
+ ("$" ?\u0670)  ;; (insert-char #x0670)ٰ   named: الفِ مقصوره‌ی فارسی
 
 
 ;;;;;;;;;;;  isiri-6219 Table 8 - Forbidden Characters -- جدول ۸ - نویسه‌هایِ 
ممنوع
-;;  ;; he ye (ucs-insert 1728)  (ucs-insert #x06c0) kills emacs-24.0.90
+;;  ;; he ye (insert-char 1728)  (insert-char #x06c0) kills emacs-24.0.90
 ;; arabic digits 0-9
 
 
@@ -508,7 +508,7 @@
  ("\\~" ?~)
  ("\\@" ?@)
  ("\\#" ?#)
- ("\\$" ?\uFDFC)  ;; (ucs-insert #xFDFC)﷼   named:
+ ("\\$" ?\uFDFC)  ;; (insert-char #xFDFC)﷼   named:
  ("\\^" ?^)
  ("\\1" ?1)
  ("\\2" ?2)
diff --git a/lisp/linum.el b/lisp/linum.el
index d491da5206..1b897a2bd2 100644
--- a/lisp/linum.el
+++ b/lisp/linum.el
@@ -89,9 +89,6 @@ Linum mode is a buffer-local minor mode."
                                            'linum-update-current) nil t)
           (add-hook 'after-change-functions 'linum-after-change nil t))
         (add-hook 'window-scroll-functions 'linum-after-scroll nil t)
-        ;; Using both window-size-change-functions and
-        ;; window-configuration-change-hook seems redundant. --Stef
-        ;; (add-hook 'window-size-change-functions 'linum-after-size nil t)
         (add-hook 'change-major-mode-hook 'linum-delete-overlays nil t)
         (add-hook 'window-configuration-change-hook
                   ;; FIXME: If the buffer is shown in N windows, this
@@ -101,7 +98,6 @@ Linum mode is a buffer-local minor mode."
         (linum-update-current))
     (remove-hook 'post-command-hook 'linum-update-current t)
     (remove-hook 'post-command-hook 'linum-schedule t)
-    ;; (remove-hook 'window-size-change-functions 'linum-after-size t)
     (remove-hook 'window-scroll-functions 'linum-after-scroll t)
     (remove-hook 'after-change-functions 'linum-after-change t)
     (remove-hook 'window-configuration-change-hook 'linum-update-current t)
@@ -231,16 +227,10 @@ Linum mode is a buffer-local minor mode."
 (defun linum-after-scroll (win _start)
   (linum-update (window-buffer win)))
 
-;; (defun linum-after-size (frame)
-;;   (linum-after-config))
-
 (defun linum-schedule ()
   ;; schedule an update; the delay gives Emacs a chance for display changes
   (run-with-idle-timer 0 nil #'linum-update-current))
 
-;; (defun linum-after-config ()
-;;   (walk-windows (lambda (w) (linum-update (window-buffer w))) nil 'visible))
-
 (defun linum-unload-function ()
   "Unload the Linum library."
   (global-linum-mode -1)
diff --git a/lisp/loadhist.el b/lisp/loadhist.el
index 39481ab068..b4ed043246 100644
--- a/lisp/loadhist.el
+++ b/lisp/loadhist.el
@@ -128,7 +128,7 @@ from a file."
     font-lock-unfontify-region-function
     kill-buffer-query-functions kill-emacs-query-functions
     lisp-indent-function mouse-position-function
-    redisplay-end-trigger-functions suspend-tty-functions
+    suspend-tty-functions
     temp-buffer-show-function window-scroll-functions
     window-size-change-functions write-contents-functions
     write-file-functions write-region-annotate-functions)
diff --git a/lisp/loadup.el b/lisp/loadup.el
index aa15a3bbe8..634a331436 100644
--- a/lisp/loadup.el
+++ b/lisp/loadup.el
@@ -32,9 +32,6 @@
 ;; If you add a file to be loaded here, keep the following points in mind:
 
 ;; i) If the file is no-byte-compile, explicitly load the .el version.
-;; Such files should (where possible) obey the doc-string conventions
-;; expected by make-docfile.  They should also be added to the
-;; uncompiled[] list in make-docfile.c.
 
 ;; ii) If the file is dumped with Emacs (on any platform), put the
 ;; load statement at the start of a line (leading whitespace is ok).
@@ -42,11 +39,9 @@
 ;; iii) If the file is _not_ dumped with Emacs, make sure the load
 ;; statement is _not_ at the start of a line.  See pcase for an example.
 
-;; These rules are so that src/Makefile can construct lisp.mk automatically.
-;; This ensures both that the Lisp files are compiled (if necessary)
-;; before the emacs executable is dumped, and that they are passed to
-;; make-docfile.  (Any that are not processed for DOC will not have
-;; doc strings in the dumped Emacs.)
+;; These rules are so that src/Makefile can construct lisp.mk
+;; automatically.  This ensures that the Lisp files are compiled (if
+;; necessary) before the emacs executable is dumped.
 
 ;;; Code:
 
@@ -159,8 +154,7 @@
 ;; Load-time macro-expansion can only take effect after setting
 ;; load-source-file-function because of where it is called in lread.c.
 (load "emacs-lisp/macroexp")
-(if (or (byte-code-function-p (symbol-function 'macroexpand-all))
-        (subr-native-elisp-p (symbol-function 'macroexpand-all)))
+(if (compiled-function-p (symbol-function 'macroexpand-all))
     nil
   ;; Since loaddefs is not yet loaded, macroexp's uses of pcase will simply
   ;; fail until pcase is explicitly loaded.  This also means that we have to
@@ -185,9 +179,10 @@
 ;; should be updated by overwriting it with an up-to-date copy of
 ;; loaddefs.el that is not corrupted by local changes.
 ;; admin/update_autogen can be used to update ldefs-boot.el periodically.
-(condition-case nil (load "loaddefs.el")
-  ;; In case loaddefs hasn't been generated yet.
-  (file-error (load "ldefs-boot.el")))
+(condition-case nil
+    (load "loaddefs")
+  (file-error
+   (load "ldefs-boot.el")))
 
 (let ((new (make-hash-table :test #'equal)))
   ;; Now that loaddefs has populated definition-prefixes, purify its contents.
@@ -253,6 +248,7 @@
   ;; A particularly demanding file to load; 1600 does not seem to be enough.
   (load "emacs-lisp/cl-generic"))
 (load "simple")
+(load "emacs-lisp/seq")
 (load "emacs-lisp/nadvice")
 (load "minibuffer") ;Needs cl-generic (and define-minor-mode).
 (load "frame")
@@ -346,10 +342,8 @@
         (load "term/ns-win"))))
 (if (featurep 'pgtk)
     (progn
+      (load "pgtk-dnd")
       (load "term/common-win")
-      ;; Don't load ucs-normalize.el unless uni-*.el files were
-      ;; already produced, because it needs uni-*.el files that might
-      ;; not be built early enough during bootstrap.
       (load "term/pgtk-win")))
 (if (fboundp 'x-create-frame)
     ;; Do it after loading term/foo-win.el since the value of the
@@ -398,6 +392,9 @@
       (message "Warning: Change in load-path due to site-load will be \
 lost after dumping")))
 
+;; Used by `kill-buffer', for instance.
+(load "emacs-lisp/rmc")
+
 ;; Make sure default-directory is unibyte when dumping.  This is
 ;; because we cannot decode and encode it correctly (since the locale
 ;; environment is not, and should not be, set up).  default-directory
@@ -481,17 +478,12 @@ lost after dumping")))
   ;; installed or if the source directory got moved.  This is set to be
   ;; a pair in the form of:
   ;;     (rel-filename-from-install-bin . rel-filename-from-local-bin).
-  (let ((h (make-hash-table :test #'eq))
-        (bin-dest-dir (cadr (member "--bin-dest" command-line-args)))
+  (let ((bin-dest-dir (cadr (member "--bin-dest" command-line-args)))
         (eln-dest-dir (cadr (member "--eln-dest" command-line-args))))
     (when (and bin-dest-dir eln-dest-dir)
       (setq eln-dest-dir
             (concat eln-dest-dir "native-lisp/" comp-native-version-dir "/"))
-      (mapatoms (lambda (s)
-                  (let ((f (symbol-function s)))
-                    (when (subr-native-elisp-p f)
-                      (puthash (subr-native-comp-unit f) nil h)))))
-      (maphash (lambda (cu _)
+      (maphash (lambda (_ cu)
                  (let* ((file (native-comp-unit-file cu))
                         (preloaded (equal (substring (file-name-directory file)
                                                      -10 -1)
@@ -511,7 +503,7 @@ lost after dumping")))
                                          bin-dest-dir)
                      ;; Relative filename from the built uninstalled binary.
                      (file-relative-name file invocation-directory)))))
-              h))))
+              comp-loaded-comp-units-h))))
 
 (when (hash-table-p purify-flag)
   (let ((strings 0)
diff --git a/lisp/ls-lisp.el b/lisp/ls-lisp.el
index 6d1f449568..3e50b0dcc8 100644
--- a/lisp/ls-lisp.el
+++ b/lisp/ls-lisp.el
@@ -100,14 +100,6 @@ update the dependent variables."
           (ls-lisp-set-options)))
   :group 'ls-lisp)
 
-;; Only made an obsolete alias in 23.3.  Before that, the initial
-;; value was set according to:
-;;  (or (memq ls-lisp-emulation '(MS-Windows MacOS))
-;;      (and (boundp 'ls-lisp-dired-ignore-case) ls-lisp-dired-ignore-case))
-;; Which isn't the right thing to do.
-(define-obsolete-variable-alias 'ls-lisp-dired-ignore-case
-  'ls-lisp-ignore-case "21.1")
-
 (defcustom ls-lisp-ignore-case
   (memq ls-lisp-emulation '(MS-Windows MacOS))
   "Non-nil causes ls-lisp alphabetic sorting to ignore case."
diff --git a/lisp/mail/binhex.el b/lisp/mail/binhex.el
index ad6ce19a95..93dd8697bd 100644
--- a/lisp/mail/binhex.el
+++ b/lisp/mail/binhex.el
@@ -23,9 +23,13 @@
 ;;; Commentary:
 
 ;; BinHex is a binary-to-text encoding scheme similar to uuencode.
+;; It was used on the classic Mac OS, last released in 2001.
+;;
 ;; The command `binhex-decode-region' decodes BinHex-encoded text, via
 ;; the external program "hexbin" if that is available, or an Emacs
 ;; Lisp implementation if not.
+;;
+;; See also: https://en.wikipedia.org/wiki/BinHex
 
 ;;; Code:
 
diff --git a/lisp/mail/emacsbug.el b/lisp/mail/emacsbug.el
index df2b7a7453..d72809b186 100644
--- a/lisp/mail/emacsbug.el
+++ b/lisp/mail/emacsbug.el
@@ -1,7 +1,6 @@
 ;;; emacsbug.el --- command to report Emacs bugs to appropriate mailing list  
-*- lexical-binding: t; -*-
 
-;; Copyright (C) 1985, 1994, 1997-1998, 2000-2022 Free Software
-;; Foundation, Inc.
+;; Copyright (C) 1985-2022 Free Software Foundation, Inc.
 
 ;; Author: K. Shane Hartman
 ;; Maintainer: emacs-devel@gnu.org
@@ -30,6 +29,9 @@
 ;; to complete the process.  Alternatively, compose the bug report in
 ;; Emacs then paste it into your normal mail client.
 
+;; `M-x submit-emacs-patch' can be used to send a patch to the Emacs
+;; maintainers.
+
 ;;; Code:
 
 (require 'sendmail)
@@ -40,9 +42,6 @@
   :group 'maint
   :group 'mail)
 
-(define-obsolete-variable-alias 'report-emacs-bug-pretest-address
-  'report-emacs-bug-address "24.1")
-
 (defcustom report-emacs-bug-no-confirmation nil
   "If non-nil, suppress the confirmations asked for the sake of novice users."
   :type 'boolean)
@@ -348,10 +347,10 @@ usually do not have translators for other 
languages.\n\n")))
 
     ;; This is so the user has to type something in order to send easily.
     (use-local-map (nconc (make-sparse-keymap) (current-local-map)))
-    (define-key (current-local-map) "\C-c\C-i" #'info-emacs-bug)
+    (keymap-set (current-local-map) "C-c C-i" #'info-emacs-bug)
     (if can-insert-mail
-       (define-key (current-local-map) "\C-c\M-i"
-         #'report-emacs-bug-insert-to-mailer))
+        (keymap-set (current-local-map) "C-c M-i"
+                    #'report-emacs-bug-insert-to-mailer))
     (setq report-emacs-bug-send-command (get mail-user-agent 'sendfunc)
          report-emacs-bug-send-hook (get mail-user-agent 'hookvar))
     (if report-emacs-bug-send-command
@@ -360,20 +359,23 @@ usually do not have translators for other 
languages.\n\n")))
     (unless report-emacs-bug-no-explanations
       (with-output-to-temp-buffer "*Bug Help*"
        (princ "While in the mail buffer:\n\n")
-        (if report-emacs-bug-send-command
-            (princ (substitute-command-keys
-                    (format "  Type \\[%s] to send the bug report.\n"
-                            report-emacs-bug-send-command))))
-       (princ (substitute-command-keys
-               "  Type \\[kill-buffer] RET to cancel (don't send it).\n"))
-       (if can-insert-mail
-           (princ (substitute-command-keys
-                   "  Type \\[report-emacs-bug-insert-to-mailer] to copy text 
to your preferred mail program.\n")))
-       (terpri)
-       (princ (substitute-command-keys
-               "  Type \\[info-emacs-bug] to visit in Info the Emacs Manual 
section
+        (let ((help
+               (substitute-command-keys
+                (format "%s%s%s%s"
+                        (if report-emacs-bug-send-command
+                            (format "  Type \\[%s] to send the bug report.\n"
+                                    report-emacs-bug-send-command)
+                          "")
+                        "  Type \\[kill-buffer] \\`RET' to cancel (don't send 
it).\n"
+                        (if can-insert-mail
+                            "  Type \\[report-emacs-bug-insert-to-mailer] to \
+copy text to your preferred mail program.\n"
+                          "")
+                        "  Type \\[info-emacs-bug] to visit in Info the Emacs 
Manual section
     about when and how to write a bug report, and what
-    information you should include to help fix the bug.")))
+    information you should include to help fix the bug."))))
+          (with-current-buffer "*Bug Help*"
+            (insert help))))
       (shrink-window-if-larger-than-buffer (get-buffer-window "*Bug Help*")))
     ;; Make it less likely people will send empty messages.
     (if report-emacs-bug-send-hook
@@ -385,10 +387,12 @@ usually do not have translators for other 
languages.\n\n")))
     (goto-char user-point)))
 
 (defun emacs-bug--system-description ()
-  (insert "\nIn " (emacs-version))
-  (if emacs-build-system
-      (insert " built on " emacs-build-system))
-  (insert "\n")
+  (let ((start (point)))
+    (insert "\nIn " (emacs-version))
+    (if emacs-build-system
+        (insert " built on " emacs-build-system))
+    (insert "\n")
+    (fill-region-as-paragraph start (point)))
 
   (if (stringp emacs-repository-version)
       (insert "Repository revision: " emacs-repository-version "\n"))
@@ -501,9 +505,10 @@ Message buffer where you can explain more about the patch."
     (erase-buffer)
     (insert "Thank you for considering submitting a patch to the Emacs 
project.\n\n"
             "Please describe what the patch fixes (or, if it's a new feature, 
what it\n"
-            "implements) in the mail buffer below.  When done, use the `C-c 
C-c' command\n"
+            "implements) in the mail buffer below.  When done, use the "
+            (substitute-command-keys 
"\\<message-mode-map>\\[message-send-and-exit] command\n")
             "to send the patch as an email to the Emacs issue tracker.\n\n"
-            "If this is the first time you've submitted an Emacs patch, 
please\n"
+            "If this is the first time you're submitting an Emacs patch, 
please\n"
             "read the ")
     (insert-text-button
      "CONTRIBUTE"
@@ -515,13 +520,14 @@ Message buffer where you can explain more about the 
patch."
     (goto-char (point-min))
     (view-mode 1)
     (button-mode 1))
-  (message-mail-other-window report-emacs-bug-address subject)
+  (compose-mail-other-window report-emacs-bug-address subject)
   (message-goto-body)
   (insert "\n\n\n")
   (emacs-bug--system-description)
   (mml-attach-file file "text/patch" nil "attachment")
   (message-goto-body)
-  (message "Write a description of the patch and use `C-c C-c' to send it")
+  (message "Write a description of the patch and use %s to send it"
+           (substitute-command-keys "\\[message-send-and-exit]"))
   (add-hook 'message-send-hook
             (lambda ()
               (message-goto-body)
diff --git a/lisp/mail/feedmail.el b/lisp/mail/feedmail.el
index af12417f70..989a8b3cd6 100644
--- a/lisp/mail/feedmail.el
+++ b/lisp/mail/feedmail.el
@@ -211,14 +211,6 @@
 ;;
 ;;;;;;;;
 ;;
-;; I think the LCD is no longer being updated, but if it were, this
-;; would be a proper LCD record.  There is an old version of
-;; feedmail.el in the LCD archive.  It works but is missing a lot of
-;; features.
-;;
-;; LCD record:
-;; feedmail|WJCarpenter|bill-feedmail@carpenter.ORG|Outbound mail queue 
handling|01-??-??|11-beta-??|feedmail.el
-;;
 ;; Change log:
 ;; original,      31 March 1991
 ;; patchlevel 1,   5 April 1991
diff --git a/lisp/mail/footnote.el b/lisp/mail/footnote.el
index 29e16c419b..a594fa3ccb 100644
--- a/lisp/mail/footnote.el
+++ b/lisp/mail/footnote.el
@@ -93,6 +93,7 @@ displaying footnotes."
 (defcustom footnote-use-message-mode t ; Nowhere used.
   "If non-nil, assume Footnoting will be done in `message-mode'."
   :type 'boolean)
+(make-obsolete-variable 'footnote-use-message-mode "it does nothing." "29.1")
 
 (defcustom footnote-body-tag-spacing 2
   "Number of spaces separating a footnote body tag and its text.
@@ -839,22 +840,18 @@ being set it is automatically widened."
       (when (looking-at (footnote--current-regexp))
         (goto-char (match-end 0))))))
 
-(defvar footnote-mode-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "a" #'footnote-add-footnote)
-    (define-key map "b" #'footnote-back-to-message)
-    (define-key map "c" #'footnote-cycle-style)
-    (define-key map "d" #'footnote-delete-footnote)
-    (define-key map "g" #'footnote-goto-footnote)
-    (define-key map "r" #'footnote-renumber-footnotes)
-    (define-key map "s" #'footnote-set-style)
-    map))
-
-(defvar footnote-minor-mode-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map footnote-prefix footnote-mode-map)
-    map)
-  "Keymap used for binding footnote minor mode.")
+(defvar-keymap footnote-mode-map
+  "a" #'footnote-add-footnote
+  "b" #'footnote-back-to-message
+  "c" #'footnote-cycle-style
+  "d" #'footnote-delete-footnote
+  "g" #'footnote-goto-footnote
+  "r" #'footnote-renumber-footnotes
+  "s" #'footnote-set-style)
+
+(defvar-keymap footnote-minor-mode-map
+  :doc "Keymap used for binding footnote minor mode."
+  (key-description footnote-prefix) footnote-mode-map)
 
 (defmacro footnote--local-advice (mode variable function)
   "Add advice to a variable holding buffer-local functions.
@@ -888,7 +885,6 @@ play around with the following keys:
   (footnote--local-advice footnote-mode fill-paragraph-function
                           footnote--fill-paragraph)
   (when footnote-mode
-    ;; (footnote-setup-keybindings)
     (make-local-variable 'footnote-style)
     (make-local-variable 'footnote-body-tag-spacing)
     (make-local-variable 'footnote-spaced-footnotes)
diff --git a/lisp/mail/hashcash.el b/lisp/mail/hashcash.el
index b343a017e3..eebb140088 100644
--- a/lisp/mail/hashcash.el
+++ b/lisp/mail/hashcash.el
@@ -1,6 +1,6 @@
 ;;; hashcash.el --- Add hashcash payments to email  -*- lexical-binding:t -*-
 
-;; Copyright (C) 2003-2005, 2007-2022 Free Software Foundation, Inc.
+;; Copyright (C) 2003-2022 Free Software Foundation, Inc.
 
 ;; Written by: Paul Foley <mycroft@actrix.gen.nz> (1997-2002)
 ;; Maintainer: emacs-devel@gnu.org
@@ -57,7 +57,7 @@
   "The default number of bits to pay to unknown users.
 If this is zero, no payment header will be generated.
 See `hashcash-payment-alist'."
-  :type 'integer
+  :type 'natnum
   :group 'hashcash)
 
 (defcustom hashcash-payment-alist '()
@@ -77,7 +77,7 @@ present, is the string to be hashed; if not present ADDR will 
be used."
 
 (defcustom hashcash-default-accept-payment 20
   "The default minimum number of bits to accept on incoming payments."
-  :type 'integer
+  :type 'natnum
   :group 'hashcash)
 
 (defcustom hashcash-accept-resources `((,user-mail-address nil))
@@ -95,10 +95,12 @@ If this is not in your PATH, specify an absolute file name."
   :type '(choice (const nil) file)
   :group 'hashcash)
 
-(defcustom hashcash-extra-generate-parameters nil
+(defcustom hashcash-extra-generate-parameters '("-Z2")
   "A list of parameter strings passed to `hashcash-program' when minting.
-For example, you may want to set this to (\"-Z2\") to reduce header length."
+For example, on very old hardware, you may want to set this
+to (\"-Z0\") to disable compression."
   :type '(repeat string)
+  :version "29.1"
   :group 'hashcash)
 
 (defcustom hashcash-double-spend-database "hashcash.db"
diff --git a/lisp/mail/ietf-drums.el b/lisp/mail/ietf-drums.el
index d1ad671b16..b7d96a1053 100644
--- a/lisp/mail/ietf-drums.el
+++ b/lisp/mail/ietf-drums.el
@@ -189,6 +189,19 @@ the Content-Transfer-Encoding header of a mail."
 
 (defun ietf-drums-parse-address (string &optional decode)
   "Parse STRING and return a MAILBOX / DISPLAY-NAME pair.
+STRING here is supposed to be an RFC822(bis) mail address, and
+will commonly look like, for instance:
+
+  \"=?utf-8?Q?Andr=C3=A9?= <andre@example.com>\"
+
+If you have an already-decoded address, like
+
+  \"André <andre@example.com>\"
+
+this function can't be used to parse that.  Instead, use
+`mail-header-parse-address-lax' to make a guess at what's the
+name and what's the address.
+
 If DECODE, the DISPLAY-NAME will have RFC2047 decoding performed
 (that's the \"=?utf...q...=?\") stuff."
   (when decode
diff --git a/lisp/mail/mail-extr.el b/lisp/mail/mail-extr.el
index 50ba04ccc1..25ce4ea902 100644
--- a/lisp/mail/mail-extr.el
+++ b/lisp/mail/mail-extr.el
@@ -1,7 +1,6 @@
 ;;; mail-extr.el --- extract full name and address from email header  -*- 
lexical-binding: t; -*-
 
-;; Copyright (C) 1991-1994, 1997, 2001-2022 Free Software Foundation,
-;; Inc.
+;; Copyright (C) 1991-2022 Free Software Foundation, Inc.
 
 ;; Author: Joe Wells <jbw@cs.bu.edu>
 ;; Maintainer: emacs-devel@gnu.org
@@ -240,8 +239,7 @@ we will act as though we couldn't find a full name in the 
address."
 ;; Matches a leading title that is not part of the name (does not
 ;; contribute to uniquely identifying the person).
 (defcustom mail-extr-full-name-prefixes
-  (purecopy
-   "\\(Prof\\|D[Rr]\\|Mrs?\\|Rev\\|Rabbi\\|SysOp\\|LCDR\\)\\.?[ \t\n]")
+  "\\(Prof\\|D[Rr]\\|Mrs?\\|Rev\\|Rabbi\\|SysOp\\|LCDR\\)\\.?[ \t\n]"
   "Matches prefixes to the full name that identify a person's position.
 These are stripped from the full name because they do not contribute to
 uniquely identifying the person."
@@ -279,45 +277,42 @@ by translating things like \"foo!bar!baz@host\" into 
\"baz@bar.UUCP\"."
 ;; Yes, there are weird people with digits in their names.
 ;; You will also notice the consideration for the
 ;; Swedish/Finnish/Norwegian character set.
-(defconst mail-extr-all-letters-but-separators
-  (purecopy "][[:alnum:]{|}'~`"))
+(defconst mail-extr-all-letters-but-separators "][[:alnum:]{|}'~`")
 
 ;; Any character that can occur in a name in an RFC 822 (or later)
 ;; address including the separator (hyphen and possibly period) for
 ;; multipart names.
 ;; #### should . be in here?
 (defconst mail-extr-all-letters
-  (purecopy (concat mail-extr-all-letters-but-separators "-")))
+  (concat mail-extr-all-letters-but-separators "-"))
 
 ;; Any character that can start a name.
 ;; Keep this set as minimal as possible.
-(defconst mail-extr-first-letters (purecopy "[:alpha:]"))
+(defconst mail-extr-first-letters "[:alpha:]")
 
 ;; Any character that can end a name.
 ;; Keep this set as minimal as possible.
-(defconst mail-extr-last-letters (purecopy "[:alpha:]`'."))
+(defconst mail-extr-last-letters "[:alpha:]`'.")
 
 (defconst mail-extr-leading-garbage "\\W+")
 
 ;; (defconst mail-extr-non-begin-name-chars
-;;   (purecopy (concat "^" mail-extr-first-letters)))
+;;   (concat "^" mail-extr-first-letters))
 ;; (defconst mail-extr-non-end-name-chars
-;;   (purecopy (concat "^" mail-extr-last-letters)))
+;;   (concat "^" mail-extr-last-letters))
 
 ;; Matches periods used instead of spaces.  Must not match the period
 ;; following an initial.
 (defconst mail-extr-bad-dot-pattern
-  (purecopy
-   (format "\\([%s][%s]\\)\\.+\\([%s]\\)"
-          mail-extr-all-letters
-          mail-extr-last-letters
-          mail-extr-first-letters)))
+  (format "\\([%s][%s]\\)\\.+\\([%s]\\)"
+          mail-extr-all-letters
+          mail-extr-last-letters
+          mail-extr-first-letters))
 
 ;; Matches an embedded or leading nickname that should be removed.
 ;; (defconst mail-extr-nickname-pattern
-;;   (purecopy
-;;    (format "\\([ .]\\|\\`\\)[\"'`[(]\\([ .%s]+\\)[]\"')] "
-;;            mail-extr-all-letters)))
+;;   (format "\\([ .]\\|\\`\\)[\"'`[(]\\([ .%s]+\\)[]\"')] "
+;;           mail-extr-all-letters))
 
 ;; Matches the occurrence of a generational name suffix, and the last
 ;; character of the preceding name.  This is important because we want to
@@ -325,59 +320,56 @@ by translating things like \"foo!bar!baz@host\" into 
\"baz@bar.UUCP\"."
 ;; *** Perhaps this should be a user-customizable variable.  However, the
 ;; *** regular expression is fairly tricky to alter, so maybe not.
 (defconst mail-extr-full-name-suffix-pattern
-  (purecopy
-   (format
-    "\\(,? ?\\([JjSs][Rr]\\.?\\|V?I+V?\\)\\)\\([^%s]\\([^%s]\\|\\'\\)\\|\\'\\)"
-    mail-extr-all-letters mail-extr-all-letters)))
+  (format
+   "\\(,? ?\\([JjSs][Rr]\\.?\\|V?I+V?\\)\\)\\([^%s]\\([^%s]\\|\\'\\)\\|\\'\\)"
+   mail-extr-all-letters mail-extr-all-letters))
 
-(defconst mail-extr-roman-numeral-pattern (purecopy "V?I+V?\\b"))
+(defconst mail-extr-roman-numeral-pattern "V?I+V?\\b")
 
 ;; Matches a trailing uppercase (with other characters possible) acronym.
 ;; Must not match a trailing uppercase last name or trailing initial
 (defconst mail-extr-weird-acronym-pattern
-  (purecopy "\\([A-Z]+[-_/]\\|[A-Z][A-Z][A-Z]?\\b\\)"))
+  "\\([A-Z]+[-_/]\\|[A-Z][A-Z][A-Z]?\\b\\)")
 
 ;; Matches a mixed-case or lowercase name (not an initial).
 ;; #### Match Latin1 lower case letters here too?
 ;; (defconst mail-extr-mixed-case-name-pattern
-;;   (purecopy
-;;    (format
-;;     "\\b\\([a-z][%s]*[%s]\\|[%s][%s]*[a-z][%s]*[%s]\\|[%s][%s]*[a-z]\\)"
-;;     mail-extr-all-letters mail-extr-last-letters
-;;     mail-extr-first-letters mail-extr-all-letters mail-extr-all-letters
-;;     mail-extr-last-letters mail-extr-first-letters mail-extr-all-letters)))
+;;   (format
+;;    "\\b\\([a-z][%s]*[%s]\\|[%s][%s]*[a-z][%s]*[%s]\\|[%s][%s]*[a-z]\\)"
+;;    mail-extr-all-letters mail-extr-last-letters
+;;    mail-extr-first-letters mail-extr-all-letters mail-extr-all-letters
+;;    mail-extr-last-letters mail-extr-first-letters mail-extr-all-letters))
 
 ;; Matches a trailing alternative address.
 ;; #### Match Latin1 letters here too?
 ;; #### Match _ before @ here too?
 (defconst mail-extr-alternative-address-pattern
-  (purecopy "\\(aka *\\)?[a-zA-Z.]+[!@][a-zA-Z.]"))
+  "\\(aka *\\)?[a-zA-Z.]+[!@][a-zA-Z.]")
 
 ;; Matches a variety of trailing comments not including comma-delimited
 ;; comments.
 (defconst mail-extr-trailing-comment-start-pattern
-  (purecopy " [-{]\\|--\\|[+@#></;]"))
+  " [-{]\\|--\\|[+@#></;]")
 
 ;; Matches a name (not an initial).
 ;; This doesn't force a word boundary at the end because sometimes a
 ;; comment is separated by a `-' with no preceding space.
 (defconst mail-extr-name-pattern
-  (purecopy (format "\\b[%s][%s]*[%s]"
-                   mail-extr-first-letters
-                   mail-extr-all-letters
-                   mail-extr-last-letters)))
+  (format "\\b[%s][%s]*[%s]"
+          mail-extr-first-letters
+          mail-extr-all-letters
+          mail-extr-last-letters))
 
 (defconst mail-extr-initial-pattern
-  (purecopy (format "\\b[%s]\\([. ]\\|\\b\\)" mail-extr-first-letters)))
+  (format "\\b[%s]\\([. ]\\|\\b\\)" mail-extr-first-letters))
 
 ;; Matches a single name before a comma.
 ;; (defconst mail-extr-last-name-first-pattern
-;;   (purecopy (concat "\\`" mail-extr-name-pattern ",")))
+;;   (concat "\\`" mail-extr-name-pattern ","))
 
 ;; Matches telephone extensions.
 (defconst mail-extr-telephone-extension-pattern
-  (purecopy
-   "\\(\\([Ee]xt\\|[Tt]ph\\|[Tt]el\\|[Xx]\\)\\.?\\)? *\\+?[0-9][- 0-9]+"))
+  "\\(\\([Ee]xt\\|[Tt]ph\\|[Tt]el\\|[Xx]\\)\\.?\\)? *\\+?[0-9][- 0-9]+")
 
 ;; Matches ham radio call signs.
 ;; Help from: Mat Maessen N2NJZ <maessm@rpi.edu>, Mark Feit
@@ -386,7 +378,7 @@ by translating things like \"foo!bar!baz@host\" into 
\"baz@bar.UUCP\"."
 ;; KE9TV KF0NV N1API N3FU N3GZE N3IGS N4KCC N7IKQ N9HHU W4YHF W6ANK WA2SUH
 ;; WB7VZI N2NJZ NR3G KJ4KK AB4UM AL7NI KH6OH WN3KBT N4TMI W1A N0NZO
 (defconst mail-extr-ham-call-sign-pattern
-  (purecopy "\\b\\(DX[0-9]+\\|[AKNW][A-Z]?[0-9][A-Z][A-Z]?[A-Z]?\\)"))
+  "\\b\\(DX[0-9]+\\|[AKNW][A-Z]?[0-9][A-Z][A-Z]?[A-Z]?\\)")
 
 ;; Possible trailing suffixes: "\\(/\\(KT\\|A[AEG]\\|[R0-9]\\)\\)?"
 ;; /KT == Temporary Technician (has CSC but not "real" license)
@@ -400,31 +392,29 @@ by translating things like \"foo!bar!baz@host\" into 
\"baz@bar.UUCP\"."
 
 ;; Matches normal single-part name
 (defconst mail-extr-normal-name-pattern
-  (purecopy (format "\\b[%s][%s]+[%s]"
-                   mail-extr-first-letters
-                   mail-extr-all-letters-but-separators
-                   mail-extr-last-letters)))
+  (format "\\b[%s][%s]+[%s]"
+          mail-extr-first-letters
+          mail-extr-all-letters-but-separators
+          mail-extr-last-letters))
 
 ;; Matches a single word name.
 ;; (defconst mail-extr-one-name-pattern
-;;   (purecopy (concat "\\`" mail-extr-normal-name-pattern "\\'")))
+;;   (concat "\\`" mail-extr-normal-name-pattern "\\'"))
 
 ;; Matches normal two names with missing middle initial
 ;; The first name is not allowed to have a hyphen because this can cause
 ;; false matches where the "middle initial" is actually the first letter
 ;; of the second part of the first name.
 (defconst mail-extr-two-name-pattern
-  (purecopy
-   (concat "\\`\\(" mail-extr-normal-name-pattern
-          "\\|" mail-extr-initial-pattern
-          "\\) +\\(" mail-extr-name-pattern "\\)\\(,\\|\\'\\)")))
+  (concat "\\`\\(" mail-extr-normal-name-pattern
+          "\\|" mail-extr-initial-pattern
+          "\\) +\\(" mail-extr-name-pattern "\\)\\(,\\|\\'\\)"))
 
 (defconst mail-extr-listserv-list-name-pattern
-  (purecopy "Multiple recipients of list \\([-A-Z]+\\)"))
+  "Multiple recipients of list \\([-A-Z]+\\)")
 
 (defconst mail-extr-stupid-vms-date-stamp-pattern
-  (purecopy
-   "[0-9][0-9]-[JFMASOND][aepuco][nbrylgptvc]-[0-9][0-9][0-9][0-9] [0-9]+ *"))
+  "[0-9][0-9]-[JFMASOND][aepuco][nbrylgptvc]-[0-9][0-9][0-9][0-9] [0-9]+ *")
 
 ;;; HZ -- GB (PRC Chinese character encoding) in ASCII embedding protocol
 ;;
@@ -443,25 +433,23 @@ by translating things like \"foo!bar!baz@host\" into 
\"baz@bar.UUCP\"."
 ;; mode from GB back to ASCII.  (Note that the escape-from-GB code '~}'
 ;; ($7E7D) is outside the defined GB range.)
 (defconst mail-extr-hz-embedded-gb-encoded-chinese-pattern
-  (purecopy "~{\\([^~].\\|~[^}]\\)+~}"))
+  "~{\\([^~].\\|~[^}]\\)+~}")
 
 ;; The leading optional lowercase letters are for a bastardized version of
 ;; the encoding, as is the optional nature of the final slash.
 (defconst mail-extr-x400-encoded-address-pattern
-  (purecopy "[a-z]?[a-z]?\\(/[A-Za-z]+\\(\\.[A-Za-z]+\\)?=[^/]+\\)+/?\\'"))
+  "[a-z]?[a-z]?\\(/[A-Za-z]+\\(\\.[A-Za-z]+\\)?=[^/]+\\)+/?\\'")
 
 (defconst mail-extr-x400-encoded-address-field-pattern-format
-  (purecopy "/%s=\\([^/]+\\)\\(/\\|\\'\\)"))
+  "/%s=\\([^/]+\\)\\(/\\|\\'\\)")
 
 (defconst mail-extr-x400-encoded-address-surname-pattern
   ;; S stands for Surname (family name).
-  (purecopy
-   (format mail-extr-x400-encoded-address-field-pattern-format "[Ss]")))
+  (format mail-extr-x400-encoded-address-field-pattern-format "[Ss]"))
 
 (defconst mail-extr-x400-encoded-address-given-name-pattern
   ;; G stands for Given name.
-  (purecopy
-   (format mail-extr-x400-encoded-address-field-pattern-format "[Gg]")))
+  (format mail-extr-x400-encoded-address-field-pattern-format "[Gg]"))
 
 (defconst mail-extr-x400-encoded-address-full-name-pattern
   ;; PN stands for Personal Name.  When used it represents the combination
@@ -469,8 +457,7 @@ by translating things like \"foo!bar!baz@host\" into 
\"baz@bar.UUCP\"."
   ;; "The one system I used having this field asked it with the prompt
   ;; `Personal Name'.  But they mapped it into G and S on outgoing real
   ;; X.400 addresses.  As they mapped G and S into PN on incoming..."
-  (purecopy
-   (format mail-extr-x400-encoded-address-field-pattern-format "[Pp][Nn]")))
+  (format mail-extr-x400-encoded-address-field-pattern-format "[Pp][Nn]"))
 
 
 
@@ -716,7 +703,6 @@ to the results."
        value-list)
 
     (with-current-buffer (get-buffer-create extraction-buffer)
-      (fundamental-mode)
       (buffer-disable-undo extraction-buffer)
       (set-syntax-table mail-extr-address-syntax-table)
       (widen)
@@ -738,7 +724,6 @@ to the results."
       (set-text-properties (point-min) (point-max) nil)
 
       (with-current-buffer (get-buffer-create canonicalization-buffer)
-       (fundamental-mode)
        (buffer-disable-undo canonicalization-buffer)
        (setq case-fold-search nil))
 
diff --git a/lisp/mail/mail-hist.el b/lisp/mail/mail-hist.el
index e02d4218dd..a13f9de174 100644
--- a/lisp/mail/mail-hist.el
+++ b/lisp/mail/mail-hist.el
@@ -80,7 +80,7 @@ previous/next input.")
 (defcustom mail-hist-history-size (or kill-ring-max 1729)
   "The maximum number of elements in a mail field's history.
 Oldest elements are dumped first."
-  :type 'integer)
+  :type 'natnum)
 
 ;;;###autoload
 (defcustom mail-hist-keep-history t
diff --git a/lisp/mail/mail-parse.el b/lisp/mail/mail-parse.el
index ec719850e2..d28b8b5843 100644
--- a/lisp/mail/mail-parse.el
+++ b/lisp/mail/mail-parse.el
@@ -85,10 +85,10 @@ The return value is a list with mail/name pairs."
   "Parse STRING as a mail address.
 Returns a mail/name pair.
 
-This function will first try to parse STRING as a
-standards-compliant address string, and if that fails, try to use
-heuristics to determine the email address and the name in the
-string."
+This function uses heuristics to determine the email address and
+the name in the string.  If you have an RFC822(bis)
+standards-compliant STRING, use `mail-header-parse-address'
+instead."
   (with-temp-buffer
     (insert (string-clean-whitespace string))
     ;; Find the bit with the @ and guess that that's the mail.
diff --git a/lisp/mail/mail-utils.el b/lisp/mail/mail-utils.el
index 952970d07c..a6e508155f 100644
--- a/lisp/mail/mail-utils.el
+++ b/lisp/mail/mail-utils.el
@@ -59,7 +59,7 @@ also the To field, unless this would leave an empty To field."
 (defun mail-string-delete (string start end)
   "Return a string containing all of STRING except the part
 from START (inclusive) to END (exclusive)."
-  ;; FIXME: This is not used anywhere.  Make obsolete?
+  (declare (obsolete substring "29.1"))
   (if (null end) (substring string 0 start)
     (concat (substring string 0 start)
            (substring string end nil))))
@@ -239,12 +239,8 @@ comma-separated list, and return the pruned list."
   ;; Or just set the default directly in the defcustom.
   (if (null mail-dont-reply-to-names)
       (setq mail-dont-reply-to-names
-            ;; `rmail-default-dont-reply-to-names' is obsolete.
-           (let ((a (bound-and-true-p rmail-default-dont-reply-to-names))
-                 (b (if (> (length user-mail-address) 0)
-                        (concat "\\`" (regexp-quote user-mail-address) 
"\\'"))))
-             (cond ((and a b) (concat a "\\|" b))
-                   ((or a b))))))
+            (if (> (length user-mail-address) 0)
+                (concat "\\`" (regexp-quote user-mail-address) "\\'"))))
   ;; Split up DESTINATIONS and match each element separately.
   (let ((start-pos 0) (cur-pos 0)
        (case-fold-search t))
@@ -281,9 +277,6 @@ comma-separated list, and return the pruned list."
       (substring destinations (match-end 0))
     destinations))
 
-;; Legacy name
-(define-obsolete-function-alias 'rmail-dont-reply-to #'mail-dont-reply-to 
"24.1")
-
 
 ;;;###autoload
 (defun mail-fetch-field (field-name &optional last all list delete)
@@ -317,7 +310,7 @@ matches may be returned from the message body."
                                      (buffer-substring-no-properties
                                       opoint (point)))))
                 (if delete
-                    (delete-region (point-at-bol) (point)))))
+                    (delete-region (line-beginning-position) (point)))))
            (if list
                value
              (and (not (string= value "")) value)))
@@ -333,7 +326,8 @@ matches may be returned from the message body."
                 (prog1
                     (buffer-substring-no-properties opoint (point))
                   (if delete
-                      (delete-region (point-at-bol) (1+ (point))))))))))))
+                      (delete-region (line-beginning-position)
+                                     (1+ (point))))))))))))
 
 ;; Parse a list of tokens separated by commas.
 ;; It runs from point to the end of the visible part of the buffer.
diff --git a/lisp/mail/mailabbrev.el b/lisp/mail/mailabbrev.el
index e4061bd2f1..0e0fb51200 100644
--- a/lisp/mail/mailabbrev.el
+++ b/lisp/mail/mailabbrev.el
@@ -163,7 +163,7 @@ no aliases, which is represented by this being a table with 
no entries.)")
     (if (file-exists-p mail-personal-alias-file)
        (let ((modtime (file-attribute-modification-time
                        (file-attributes mail-personal-alias-file))))
-         (if (not (equal mail-abbrev-modtime modtime))
+         (if (not (time-equal-p mail-abbrev-modtime modtime))
              (progn
                (setq mail-abbrev-modtime modtime)
                (build-mail-abbrevs)))))))
@@ -394,7 +394,7 @@ with a space."
     (let (p)
       (save-excursion
        (while (>= (current-column) fill-column)
-         (while (and (search-backward "," (point-at-bol) 'move)
+          (while (and (search-backward "," (line-beginning-position) 'move)
                      (>= (current-column) (1- fill-column))
                      (setq p (point))))
          (when (or (not (bolp))
diff --git a/lisp/mail/mailalias.el b/lisp/mail/mailalias.el
index ba7cf58d38..57fb1117b6 100644
--- a/lisp/mail/mailalias.el
+++ b/lisp/mail/mailalias.el
@@ -72,11 +72,10 @@ When t this still needs to be initialized.")
     )
   "Alist of header field and expression to return alist for completion.
 The expression may reference the variable `pattern'
-which will hold the string being completed.
-If not on matching header, `mail-complete-function' gets called instead."
+which will hold the string being completed."
   :type 'alist
+  :risky t
   :group 'mailalias)
-(put 'mail-complete-alist 'risky-local-variable t)
 
 ;;;###autoload
 (defcustom mail-complete-style 'angles
@@ -90,13 +89,6 @@ If `angles', they look like:
   :type '(choice (const angles) (const parens) (const nil))
   :group 'mailalias)
 
-(defcustom mail-complete-function 'ispell-complete-word
-  "Function to call when completing outside `mail-complete-alist'-header."
-  :type '(choice function (const nil))
-  :group 'mailalias)
-(make-obsolete-variable 'mail-complete-function
-                        'completion-at-point-functions "24.1")
-
 (defcustom mail-directory-function nil
   "Function to get completions from directory service or nil for none.
 See `mail-directory-requery'."
@@ -129,8 +121,8 @@ or like this:
 
   (remote-shell-program \"HOST\" \"-n\" \"COMMAND \\='^\" pattern \"\\='\")"
   :type 'sexp
+  :risky t
   :group 'mailalias)
-(put 'mail-directory-process 'risky-local-variable t)
 
 (defcustom mail-directory-stream nil
   "List of (HOST SERVICE) for stream connection to mail directory."
@@ -140,8 +132,8 @@ or like this:
                                (string :tag "Service name"))
                        (plist :inline t
                               :tag "Additional open-network-stream 
parameters")))
+  :risky t
   :group 'mailalias)
-(put 'mail-directory-stream 'risky-local-variable t)
 
 (defcustom mail-directory-parser nil
   "How to interpret the output of `mail-directory-function'.
@@ -151,8 +143,8 @@ Three types of values are possible:
   - regexp means first \\(grouping\\) in successive matches is name
   - function called at beginning of buffer that returns an alist of names"
   :type '(choice (const nil) regexp function)
+  :risky t
   :group 'mailalias)
-(put 'mail-directory-parser 'risky-local-variable t)
 
 ;; Internal variables.
 
@@ -433,25 +425,6 @@ For use on `completion-at-point-functions'."
                          (let ((pattern prefix)) (eval list-exp))))))
           (list beg end table)))))
 
-;;;###autoload
-(defun mail-complete (arg)
-  "Perform completion on header field or word preceding point.
-Completable headers are according to `mail-complete-alist'.  If none matches
-current header, calls `mail-complete-function' and passes prefix ARG if any."
-  (declare (obsolete mail-completion-at-point-function "24.1"))
-  (interactive "P")
-  ;; Read the defaults first, if we have not done so.
-  (sendmail-sync-aliases)
-  (if (eq mail-aliases t)
-      (progn
-       (setq mail-aliases nil)
-       (if (file-exists-p mail-personal-alias-file)
-           (build-mail-aliases))))
-  (let ((data (mail-completion-at-point-function)))
-    (if data
-        (apply #'completion-in-region data)
-      (funcall mail-complete-function arg))))
-
 (defun mail-completion-expand (table)
   "Build new completion table that expands aliases.
 Completes like TABLE except that if the completion is a valid alias,
diff --git a/lisp/mail/mspools.el b/lisp/mail/mspools.el
index 2c3851f835..0673493487 100644
--- a/lisp/mail/mspools.el
+++ b/lisp/mail/mspools.el
@@ -55,7 +55,6 @@
 ;; `mspools-using-vm' for details.
 
 ;;; Basic installation.
-;; (autoload 'mspools-show "mspools" "Show outstanding mail spools." t)
 ;; (setq mspools-folder-directory "~/MAIL/")
 ;;
 ;; If you use VM, mspools-folder-directory will default to vm-folder-directory
@@ -165,17 +164,13 @@ your primary spool is.  If this fails, set it to 
something like
 (defvar mspools-buffer "*spools*"
   "Name of buffer for displaying spool info.")
 
-(defvar mspools-mode-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "\C-c\C-c" #'mspools-visit-spool)
-    (define-key map "\C-m" #'mspools-visit-spool)
-    (define-key map " " #'mspools-visit-spool)
-    (define-key map "n" #'next-line)
-    (define-key map "p" #'previous-line)
-    map)
-  "Keymap for the *spools* buffer.")
-
-;;; Code
+(defvar-keymap mspools-mode-map
+  :doc "Keymap for the *spools* buffer."
+  "C-c C-c" #'mspools-visit-spool
+  "RET"     #'mspools-visit-spool
+  "SPC"     #'mspools-visit-spool
+  "n"       #'next-line
+  "p"       #'previous-line)
 
 ;;; VM Specific code
 (if mspools-using-vm
@@ -269,7 +264,7 @@ Buffer is not displayed if SHOW is non-nil."
              (delete-char 1))))
 
       (message "folder %s spool %s" folder-name spool-name)
-      (forward-line (if (eq (count-lines (point-min) (point-at-eol))
+      (forward-line (if (eq (count-lines (point-min) (line-end-position))
                            mspools-files-len)
                        ;; FIXME: Why use `mspools-files-len' instead
                         ;; of looking if we're on the last line and
@@ -312,7 +307,7 @@ Buffer is not displayed if SHOW is non-nil."
 
 (defun mspools-get-spool-name ()
   "Return the name of the spool on the current line."
-  (let ((line-num (1- (count-lines (point-min) (point-at-eol)))))
+  (let ((line-num (1- (count-lines (point-min) (line-end-position)))))
     ;; FIXME: Why not extract the name directly from the current line's text?
     (car (nth line-num mspools-files))))
 
diff --git a/lisp/mail/rfc2047.el b/lisp/mail/rfc2047.el
index bb0d646346..abb95a63f1 100644
--- a/lisp/mail/rfc2047.el
+++ b/lisp/mail/rfc2047.el
@@ -45,6 +45,9 @@
   '(("Newsgroups" . nil)
     ("Followup-To" . nil)
     ("Message-ID" . nil)
+    ;; This header must be pre-encoded by the MTA, so avoid
+    ;; double-encoding it.
+    ("Content-Disposition" . default)
     ("\\(Resent-\\)?\\(From\\|Cc\\|To\\|Bcc\\|\\(In-\\)?Reply-To\\|Sender\
 
\\|Mail-Followup-To\\|Mail-Copies-To\\|Approved\\|Disposition-Notification-To\\)"
 . address-mime)
     (t . mime))
@@ -172,7 +175,7 @@ This is either `base64' or `quoted-printable'."
    (progn
      (forward-line 1)
      (if (re-search-forward "^[^ \n\t]" nil t)
-        (point-at-bol)
+         (line-beginning-position)
        (point-max))))
   (goto-char (point-min)))
 
@@ -678,14 +681,14 @@ Point moves to the end of the region."
             (goto-char b)
             (setq b (point-marker)
                   e (set-marker (make-marker) e))
-            (rfc2047-fold-region (point-at-bol) b)
+             (rfc2047-fold-region (line-beginning-position) b)
             (goto-char b)
             (skip-chars-backward "^ \t\n")
             (unless (= 0 (skip-chars-backward " \t"))
               ;; `crest' may contain whitespace and an open parenthesis.
               (setq crest (buffer-substring-no-properties (point) b)))
             (setq eword (rfc2047-encode-1
-                         (- b (point-at-bol))
+                          (- b (line-beginning-position))
                          (replace-regexp-in-string
                           "\n\\([ \t]?\\)" "\\1"
                           (buffer-substring-no-properties b e))
@@ -821,18 +824,18 @@ Return the new end point."
     (goto-char (point-min))
     (let ((bol (save-restriction
                 (widen)
-                (point-at-bol)))
-         (eol (point-at-eol)))
+                 (line-beginning-position)))
+          (eol (line-end-position)))
       (forward-line 1)
       (while (not (eobp))
        (if (and (looking-at "[ \t]")
-                (< (- (point-at-eol) bol) 76))
+                 (< (- (line-end-position) bol) 76))
            (delete-region eol (progn
                                 (goto-char eol)
                                 (skip-chars-forward "\r\n")
                                 (point)))
-         (setq bol (point-at-bol)))
-       (setq eol (point-at-eol))
+          (setq bol (line-beginning-position)))
+        (setq eol (line-end-position))
        (forward-line 1)))))
 
 (defun rfc2047-b-encode-string (string)
diff --git a/lisp/mail/rmail.el b/lisp/mail/rmail.el
index adb61aa09d..4bfec22b3a 100644
--- a/lisp/mail/rmail.el
+++ b/lisp/mail/rmail.el
@@ -314,20 +314,6 @@ Setting this variable has an effect only before reading a 
mail."
   :group 'rmail-retrieve
   :version "21.1")
 
-;;;###autoload
-(define-obsolete-variable-alias 'rmail-dont-reply-to-names
-  'mail-dont-reply-to-names "24.1")
-
-;; Prior to 24.1, this used to contain "\\`info-".
-;;;###autoload
-(defvar rmail-default-dont-reply-to-names nil
-  "Regexp specifying part of the default value of `mail-dont-reply-to-names'.
-This is used when the user does not set `mail-dont-reply-to-names'
-explicitly.")
-;;;###autoload
-(make-obsolete-variable 'rmail-default-dont-reply-to-names
-                        'mail-dont-reply-to-names "24.1")
-
 ;;;###autoload
 (defcustom rmail-ignored-headers
   (purecopy
@@ -388,7 +374,7 @@ If nil, display all header fields except those matched by
 ;;;###autoload
 (defcustom rmail-retry-ignored-headers (purecopy 
"^x-authentication-warning:\\|^x-detected-operating-system:\\|^x-spam[-a-z]*:\\|content-type:\\|content-transfer-encoding:\\|mime-version:\\|message-id:")
   "Headers that should be stripped when retrying a failed message."
-  :type '(choice regexp (const nil :tag "None"))
+  :type '(choice regexp (const :value nil :tag "None"))
   :group 'rmail-headers
   :version "23.2")        ; added x-detected-operating-system, x-spam
 
@@ -462,8 +448,8 @@ as argument, to ask the user that question."
                 (const :tag "Confirm with y-or-n-p" y-or-n-p)
                 (const :tag "Confirm with yes-or-no-p" yes-or-no-p))
   :version "21.1"
+  :risky t
   :group 'rmail-files)
-(put 'rmail-confirm-expunge 'risky-local-variable t)
 
 ;;;###autoload
 (defvar rmail-mode-hook nil
@@ -1465,9 +1451,7 @@ If so restore the actual mbox message collection."
   (setq-local font-lock-defaults
               '(rmail-font-lock-keywords
                 t t nil nil
-                (font-lock-maximum-size . nil)
-                (font-lock-dont-widen . t)
-                (font-lock-inhibit-thing-lock . (lazy-lock-mode 
fast-lock-mode))))
+                (font-lock-dont-widen . t)))
   (setq-local require-final-newline nil)
   (setq-local version-control 'never)
   (add-hook 'kill-buffer-hook #'rmail-mode-kill-summary nil t)
diff --git a/lisp/mail/rmailedit.el b/lisp/mail/rmailedit.el
index 79bd02fd67..553fac26f9 100644
--- a/lisp/mail/rmailedit.el
+++ b/lisp/mail/rmailedit.el
@@ -34,13 +34,10 @@
   :group 'rmail-edit)
 
 
-(defvar rmail-edit-map
-  (let ((map (make-sparse-keymap)))
-    ;; Make a keymap that inherits text-mode-map.
-    (set-keymap-parent map text-mode-map)
-    (define-key map "\C-c\C-c" #'rmail-cease-edit)
-    (define-key map "\C-c\C-]" #'rmail-abort-edit)
-    map))
+(defvar-keymap rmail-edit-map
+  :parent text-mode-map
+  "C-c C-c" #'rmail-cease-edit
+  "C-c C-]" #'rmail-abort-edit)
 
 (declare-function rmail-summary-disable "rmailsum" ())
 
diff --git a/lisp/mail/rmailmm.el b/lisp/mail/rmailmm.el
index 79f421bdcd..416f7d1ea8 100644
--- a/lisp/mail/rmailmm.el
+++ b/lisp/mail/rmailmm.el
@@ -796,8 +796,9 @@ directly."
      ((string-match "text/" content-type)
       (setq type 'text))
      ((string-match "image/\\(.*\\)" content-type)
-      (setq type (image-supported-file-p
-                 (concat "." (match-string 1 content-type))))
+      (setq type (and (fboundp 'image-supported-file-p)
+                      (image-supported-file-p
+                      (concat "." (match-string 1 content-type)))))
       (when (and type
                  rmail-mime-show-images
                 (not (eq rmail-mime-show-images 'button))
diff --git a/lisp/mail/rmailsum.el b/lisp/mail/rmailsum.el
index b23fbc3f60..b959f45250 100644
--- a/lisp/mail/rmailsum.el
+++ b/lisp/mail/rmailsum.el
@@ -1480,11 +1480,10 @@ argument says to read a file name and use that file as 
the inbox."
 (declare-function rmail-output-read-file-name "rmailout" ())
 (declare-function mail-send-and-exit "sendmail" (&optional arg))
 
-(defvar rmail-summary-edit-map
-  (let ((map (nconc (make-sparse-keymap) text-mode-map)))
-    (define-key map "\C-c\C-c" #'rmail-cease-edit)
-    (define-key map "\C-c\C-]" #'rmail-abort-edit)
-    map))
+(defvar-keymap rmail-summary-edit-map
+  :parent text-mode-map
+  "C-c C-c" #'rmail-cease-edit
+  "C-c C-]" #'rmail-abort-edit)
 
 (defun rmail-summary-edit-current-message ()
   "Edit the contents of this message."
@@ -1728,8 +1727,6 @@ even if the header display is currently pruned."
        (if (< i n)
            (rmail-summary-next-msg 1))))))
 
-(defalias 'rmail-summary-output-to-rmail-file 'rmail-summary-output)
-
 (declare-function rmail-output-as-seen "rmailout"
                  (file-name &optional count noattribute from-gnus))
 
@@ -1875,6 +1872,9 @@ the summary is only showing a subset of messages."
               (funcall sortfun reverse))
       (select-window selwin))))
 
+(define-obsolete-function-alias 'rmail-summary-output-to-rmail-file
+  #'rmail-summary-output "29.1")
+
 (provide 'rmailsum)
 
 ;;; rmailsum.el ends here
diff --git a/lisp/mail/sendmail.el b/lisp/mail/sendmail.el
index c55cdc8412..387792eb31 100644
--- a/lisp/mail/sendmail.el
+++ b/lisp/mail/sendmail.el
@@ -49,7 +49,9 @@
        ((file-exists-p "/usr/lib/sendmail") "/usr/lib/sendmail")
        ((file-exists-p "/usr/ucblib/sendmail") "/usr/ucblib/sendmail")
        (t "sendmail")))
-  "Program used to send messages."
+  "Program used to send messages.
+If the program returns a non-zero error code, or outputs any
+text, sending is considered \"failed\" by Emacs."
   :version "24.1"              ; add executable-find, remove fakemail
   :type 'file)
 
@@ -372,8 +374,8 @@ and should insert whatever you want to insert."
   :type '(choice (const :tag "None" nil)
                 (const :tag "Use `.signature' file" t)
                 (string :tag "String to insert")
-                (sexp :tag "Expression to evaluate")))
-(put 'mail-signature 'risky-local-variable t)
+                 (sexp :tag "Expression to evaluate"))
+  :risky t)
 
 ;;;###autoload
 (defcustom mail-signature-file (purecopy "~/.signature")
@@ -430,20 +432,6 @@ support Delivery Status Notification."
                        (const :tag "Success" success)))
   :version "22.1")
 
-;; Note: could use /usr/ucb/mail instead of sendmail;
-;; options -t, and -v if not interactive.
-(defvar mail-mailer-swallows-blank-line nil
-  "Set this non-nil if the system's mailer runs the header and body together.
-The actual value should be an expression to evaluate that returns
-non-nil if the problem will actually occur.
-\(As far as we know, this is not an issue on any system still supported
-by Emacs.)")
-
-(put 'mail-mailer-swallows-blank-line 'risky-local-variable t) ; gets evalled
-(make-obsolete-variable 'mail-mailer-swallows-blank-line
-                       "no need to set this on any modern system."
-                        "24.1" 'set)
-
 (defvar mail-mode-syntax-table
   ;; define-derived-mode will make it inherit from text-mode-syntax-table.
   (let ((st (make-syntax-table)))
@@ -551,7 +539,7 @@ This also saves the value of `send-mail-function' via 
Customize."
   (when mail-personal-alias-file
     (let ((modtime (file-attribute-modification-time
                    (file-attributes mail-personal-alias-file))))
-      (or (equal mail-alias-modtime modtime)
+      (or (time-equal-p mail-alias-modtime modtime)
          (setq mail-alias-modtime modtime
                mail-aliases t)))))
 
@@ -834,6 +822,7 @@ If within the headers, this makes the new lines into 
continuation lines."
 
 ;; User-level commands for sending.
 
+;;;###autoload
 (defun mail-send-and-exit (&optional arg)
   "Send message like `mail-send', then, if no errors, exit from mail buffer.
 Prefix arg means don't delete this window."
@@ -1304,13 +1293,11 @@ external program defined by `sendmail-program'."
                   ;; should override any specified in the message itself.
                     (when where-content-type
                       (goto-char where-content-type)
-                      (delete-region (point-at-bol)
+                       (delete-region (line-beginning-position)
                                      (progn (forward-line 1) (point)))))))
            ;; Insert an extra newline if we need it to work around
            ;; Sun's bug that swallows newlines.
            (goto-char (1+ delimline))
-           (if (eval mail-mailer-swallows-blank-line)
-               (newline))
            ;; Find and handle any Fcc fields.
            (goto-char (point-min))
            (if (re-search-forward "^Fcc:" delimline t)
@@ -1495,28 +1482,6 @@ just append to the file, in Babyl format if necessary."
                 (with-current-buffer buffer
                   (set-visited-file-modtime)))))))))
 
-(defun mail-sent-via ()
-  "Make a Sent-via header line from each To or Cc header line."
-  (declare (obsolete "nobody can remember what it is for." "24.1"))
-  (interactive)
-  (save-excursion
-    ;; put a marker at the end of the header
-    (let ((end (copy-marker (mail-header-end)))
-         (case-fold-search t))
-      (goto-char (point-min))
-      ;; search for the To: lines and make Sent-via: lines from them
-      ;; search for the next To: line
-      (while (re-search-forward "^\\(to\\|cc\\):" end t)
-       ;; Grab this line plus all its continuations, sans the `to:'.
-       (let ((to-line
-              (buffer-substring (point)
-                                (progn
-                                  (if (re-search-forward "^[^ \t\n]" end t)
-                                      (backward-char 1)
-                                    (goto-char end))
-                                  (point)))))
-         ;; Insert a copy, with altered header field name.
-         (insert-before-markers "Sent-via:" to-line))))))
 
 (defun mail-to ()
   "Move point to end of To field, creating it if necessary."
@@ -1839,8 +1804,6 @@ If the current line has `mail-yank-prefix', insert it on 
the new line."
       (or (bolp) (newline))
       (goto-char start))))
 
-(define-obsolete-function-alias 'mail-attach-file #'mail-insert-file "24.1")
-
 (declare-function mml-attach-file "mml"
                  (file &optional type description disposition))
 
diff --git a/lisp/mail/smtpmail.el b/lisp/mail/smtpmail.el
index 88e55e968c..8573532eac 100644
--- a/lisp/mail/smtpmail.el
+++ b/lisp/mail/smtpmail.el
@@ -171,7 +171,7 @@ attempt."
   "The number of times smtpmail will retry sending when getting transient 
errors.
 These are errors with a code of 4xx from the SMTP server, which
 mean \"try again\"."
-  :type 'integer
+  :type 'natnum
   :version "27.1")
 
 (defcustom smtpmail-store-queue-variables nil
@@ -342,8 +342,6 @@ for `smtpmail-try-auth-method'.")
            ;; Insert an extra newline if we need it to work around
            ;; Sun's bug that swallows newlines.
            (goto-char (1+ delimline))
-           (if (eval mail-mailer-swallows-blank-line t)
-               (newline))
            ;; Find and handle any Fcc fields.
            (goto-char (point-min))
            (if (re-search-forward "^Fcc:" delimline t)
@@ -476,7 +474,7 @@ for `smtpmail-try-auth-method'.")
                        (smtpmail--sanitize-error-message result))))))
        (delete-file file-data)
        (delete-file file-elisp)
-       (delete-region (point-at-bol) (point-at-bol 2)))
+        (delete-region (line-beginning-position) (line-beginning-position 2)))
       (write-region (point-min) (point-max) qfile))))
 
 (defun smtpmail--sanitize-error-message (string)
@@ -552,7 +550,6 @@ for `smtpmail-try-auth-method'.")
                      :require (and ask-for-password
                                    '(:user :secret))
                      :create ask-for-password)))
-         (mech (or (plist-get auth-info :smtp-auth) (car mechs)))
          (user (plist-get auth-info :user))
          (password (auth-info-password auth-info))
         (save-function (and ask-for-password
@@ -572,18 +569,26 @@ for `smtpmail-try-auth-method'.")
              :require '(:user :secret)
              :create t))
            password (auth-info-password auth-info)))
-    (let ((result (catch 'done
-                    (if (and mech user password)
-                       (smtpmail-try-auth-method process mech user password)
-                      ;; No mechanism, or no credentials.
-                      mech))))
-      (if (stringp result)
-         (progn
-           (auth-source-forget+ :host host :port port)
-           (throw 'done result))
-       (when save-function
-         (funcall save-function))
-       result))))
+    (let ((mechs (or (ensure-list (plist-get auth-info :smtp-auth))
+                     mechs))
+          (result ""))
+      (when (and mechs user password)
+        (while (and mechs
+                    (stringp result))
+          (setq result (catch 'done
+                        (smtpmail-try-auth-method
+                          process (intern-soft (pop mechs)) user password))))
+        ;; A string result is an error.
+        (if (stringp result)
+            (progn
+              ;; All methods failed.
+              ;; Forget the credentials.
+             (auth-source-forget+ :host host :port port)
+              (throw 'done result))
+          ;; Success.
+         (when save-function
+           (funcall save-function))
+          result)))))
 
 (cl-defgeneric smtpmail-try-auth-method (_process mech _user _password)
   "Perform authentication of type MECH for USER with PASSWORD.
@@ -801,7 +806,11 @@ Returns an error if the server cannot be contacted."
                                (plist-get (cdr result) :capabilities)
                                "\r\n")))
                  (let ((name
-                        (with-case-table ascii-case-table ;FIXME: Why?
+                         ;; Use ASCII case-table to prevent I
+                         ;; downcasing to a dotless i under some
+                         ;; language environments.  See
+                         ;; 
https://lists.gnu.org/archive/html/emacs-devel/2007-03/msg01760.html.
+                        (with-case-table ascii-case-table
                           (mapcar (lambda (s) (intern (downcase s)))
                                   (split-string (substring line 4) "[ ]")))))
                    (when (= (length name) 1)
@@ -1048,7 +1057,8 @@ Returns an error if the server cannot be contacted."
     (while data-continue
       (with-current-buffer buffer
         (progress-reporter-update pr (point))
-        (setq sending-data (buffer-substring (point-at-bol) (point-at-eol)))
+        (setq sending-data (buffer-substring (line-beginning-position)
+                                             (line-end-position)))
        (end-of-line 2)
         (setq data-continue (not (eobp))))
       (smtpmail-send-data-1 process sending-data))
diff --git a/lisp/mail/supercite.el b/lisp/mail/supercite.el
index 5dc5ee38ff..98f46a3af5 100644
--- a/lisp/mail/supercite.el
+++ b/lisp/mail/supercite.el
@@ -1,6 +1,6 @@
 ;;; supercite.el --- minor mode for citing mail and news replies  -*- 
lexical-binding: t; -*-
 
-;; Copyright (C) 1993, 1997, 2001-2022 Free Software Foundation, Inc.
+;; Copyright (C) 1993-2022 Free Software Foundation, Inc.
 
 ;; Author: 1993 Barry A. Warsaw <bwarsaw@python.org>
 ;; Maintainer: emacs-devel@gnu.org
@@ -22,11 +22,6 @@
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
-;; LCD Archive Entry
-;; supercite|Barry A. Warsaw|supercite-help@python.org
-;; |Mail and news reply citation package
-;; |1993/09/22 18:58:46|3.1|
-
 ;;; Commentary:
 
 ;;; Code:
@@ -146,8 +141,8 @@ a variable whose value is a citation frame."
   :type '(repeat (list symbol (repeat (cons regexp
                                            (choice (repeat (repeat sexp))
                                                    symbol)))))
+  :risky t
   :group 'supercite-frames)
-(put 'sc-cite-frame-alist 'risky-local-variable t)
 
 (defcustom sc-uncite-frame-alist '()
   "Alist for frame selection during unciting.
@@ -155,8 +150,8 @@ See the variable `sc-cite-frame-alist' for details."
   :type '(repeat (list symbol (repeat (cons regexp
                                            (choice (repeat (repeat sexp))
                                                    symbol)))))
+  :risky t
   :group 'supercite-frames)
-(put 'sc-uncite-frame-alist 'risky-local-variable t)
 
 (defcustom sc-recite-frame-alist '()
   "Alist for frame selection during reciting.
@@ -164,8 +159,8 @@ See the variable `sc-cite-frame-alist' for details."
   :type '(repeat (list symbol (repeat (cons regexp
                                            (choice (repeat (repeat sexp))
                                                    symbol)))))
+  :risky t
   :group 'supercite-frames)
-(put 'sc-recite-frame-alist 'risky-local-variable t)
 
 (defcustom sc-default-cite-frame
   '(;; initialize fill state and temporary variables when entering
@@ -211,8 +206,8 @@ See the variable `sc-cite-frame-alist' for details."
     (end                        (sc-fill-if-different "")))
   "Default REGI frame for citing a region."
   :type '(repeat (repeat sexp))
+  :risky t
   :group 'supercite-frames)
-(put 'sc-default-cite-frame 'risky-local-variable t)
 
 (defcustom sc-default-uncite-frame
   '(;; do nothing on a blank line
@@ -221,8 +216,8 @@ See the variable `sc-cite-frame-alist' for details."
     ((sc-cite-regexp) (sc-uncite-line)))
   "Default REGI frame for unciting a region."
   :type '(repeat (repeat sexp))
+  :risky t
   :group 'supercite-frames)
-(put 'sc-default-uncite-frame 'risky-local-variable t)
 
 (defcustom sc-default-recite-frame
   '(;; initialize fill state when entering frame
@@ -237,8 +232,8 @@ See the variable `sc-cite-frame-alist' for details."
     (end              (sc-fill-if-different "")))
   "Default REGI frame for reciting a region."
   :type '(repeat (repeat sexp))
+  :risky t
   :group 'supercite-frames)
-(put 'sc-default-recite-frame 'risky-local-variable t)
 
 (defcustom sc-cite-region-limit t
   "This variable controls automatic citation of yanked text.
@@ -428,8 +423,8 @@ to be consulted during attribution selection."
                       (repeat (cons regexp
                                     (choice (sexp :tag "List to eval")
                                             string)))))
+  :risky t
   :group 'supercite-attr)
-(put 'sc-attrib-selection-list 'risky-local-variable t)
 
 (defcustom sc-attribs-preselect-hook nil
   "Hook to run before selecting an attribution."
@@ -483,8 +478,8 @@ The variable `sc-preferred-header-style' controls which 
function in
 this list is chosen for automatic reference header insertions.
 Electric reference mode will cycle through this list of functions."
   :type '(repeat sexp)
+  :risky t
   :group 'supercite)
-(put 'sc-rewrite-header-list 'risky-local-variable t)
 
 (defcustom sc-titlecue-regexp "\\s +-+\\s +"
   "Regular expression describing the separator between names and titles.
@@ -525,75 +520,67 @@ string."
 ;; ======================================================================
 ;; supercite keymaps
 
-(defvar sc-T-keymap
-  (let ((map (make-sparse-keymap)))
-    (define-key map "a" #'sc-S-preferred-attribution-list)
-    (define-key map "b" #'sc-T-mail-nuke-blank-lines)
-    (define-key map "c" #'sc-T-confirm-always)
-    (define-key map "d" #'sc-T-downcase)
-    (define-key map "e" #'sc-T-electric-references)
-    (define-key map "f" #'sc-T-auto-fill-region)
-    (define-key map "h" #'sc-T-describe)
-    (define-key map "l" #'sc-S-cite-region-limit)
-    (define-key map "n" #'sc-S-mail-nuke-mail-headers)
-    (define-key map "N" #'sc-S-mail-header-nuke-list)
-    (define-key map "o" #'sc-T-electric-circular)
-    (define-key map "p" #'sc-S-preferred-header-style)
-    (define-key map "s" #'sc-T-nested-citation)
-    (define-key map "u" #'sc-T-use-only-preferences)
-    (define-key map "w" #'sc-T-fixup-whitespace)
-    (define-key map "?" #'sc-T-describe)
-    map)
-  "Keymap for sub-keymap of setting and toggling functions.")
-
-(defvar sc-mode-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "c"    #'sc-cite-region)
-    (define-key map "f"    #'sc-mail-field-query)
-    (define-key map "g"    #'sc-mail-process-headers)
-    (define-key map "h"    #'sc-describe)
-    (define-key map "i"    #'sc-insert-citation)
-    (define-key map "o"    #'sc-open-line)
-    (define-key map "r"    #'sc-recite-region)
-    (define-key map "\C-p" #'sc-raw-mode-toggle)
-    (define-key map "u"    #'sc-uncite-region)
-    (define-key map "w"    #'sc-insert-reference)
-    (define-key map "\C-t"   sc-T-keymap)
-    (define-key map "?"    #'sc-describe)
-    map)
-  "Keymap for Supercite quasi-mode.")
-
-(defvar sc-electric-mode-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "p"    #'sc-eref-prev)
-    (define-key map "n"    #'sc-eref-next)
-    (define-key map "s"    #'sc-eref-setn)
-    (define-key map "j"    #'sc-eref-jump)
-    (define-key map "x"    #'sc-eref-abort)
-    (define-key map "q"    #'sc-eref-abort)
-    (define-key map "\r"   #'sc-eref-exit)
-    (define-key map "\n"   #'sc-eref-exit)
-    (define-key map "g"    #'sc-eref-goto)
-    (define-key map "?"    #'describe-mode)
-    (define-key map "\C-h" #'describe-mode)
-    (define-key map [f1]   #'describe-mode)
-    (define-key map [help] #'describe-mode)
-    map)
-  "Keymap for `sc-electric-mode' electric references mode.")
-
-
-(defvar sc-minibuffer-local-completion-map
-  (let ((map (copy-keymap minibuffer-local-completion-map)))
-    (define-key map "\C-t" #'sc-toggle-fn)
-    (define-key map " "    #'self-insert-command)
-    map)
-  "Keymap for minibuffer confirmation of attribution strings.")
-
-(defvar sc-minibuffer-local-map
-  (let ((map (copy-keymap minibuffer-local-map)))
-    (define-key map "\C-t" #'sc-toggle-fn)
-    map)
-  "Keymap for minibuffer confirmation of attribution strings.")
+(defvar-keymap sc-T-keymap
+  :doc "Keymap for sub-keymap of setting and toggling functions."
+  "a" #'sc-S-preferred-attribution-list
+  "b" #'sc-T-mail-nuke-blank-lines
+  "c" #'sc-T-confirm-always
+  "d" #'sc-T-downcase
+  "e" #'sc-T-electric-references
+  "f" #'sc-T-auto-fill-region
+  "h" #'sc-T-describe
+  "l" #'sc-S-cite-region-limit
+  "n" #'sc-S-mail-nuke-mail-headers
+  "N" #'sc-S-mail-header-nuke-list
+  "o" #'sc-T-electric-circular
+  "p" #'sc-S-preferred-header-style
+  "s" #'sc-T-nested-citation
+  "u" #'sc-T-use-only-preferences
+  "w" #'sc-T-fixup-whitespace
+  "?" #'sc-T-describe)
+
+(defvar-keymap sc-mode-map
+  :doc "Keymap for Supercite quasi-mode."
+  "c"   #'sc-cite-region
+  "f"   #'sc-mail-field-query
+  "g"   #'sc-mail-process-headers
+  "h"   #'sc-describe
+  "i"   #'sc-insert-citation
+  "o"   #'sc-open-line
+  "r"   #'sc-recite-region
+  "C-p" #'sc-raw-mode-toggle
+  "u"   #'sc-uncite-region
+  "w"   #'sc-insert-reference
+  "C-t" sc-T-keymap
+  "?"   #'sc-describe)
+
+(defvar-keymap sc-electric-mode-map
+  :doc "Keymap for `sc-electric-mode' electric references mode."
+  "p"      #'sc-eref-prev
+  "n"      #'sc-eref-next
+  "s"      #'sc-eref-setn
+  "j"      #'sc-eref-jump
+  "x"      #'sc-eref-abort
+  "q"      #'sc-eref-abort
+  "RET"    #'sc-eref-exit
+  "C-j"    #'sc-eref-exit
+  "g"      #'sc-eref-goto
+  "?"      #'describe-mode
+  "C-h"    #'describe-mode
+  "<f1>"   #'describe-mode
+  "<help>" #'describe-mode)
+
+
+(defvar-keymap sc-minibuffer-local-completion-map
+  :doc "Keymap for minibuffer confirmation of attribution strings."
+  :parent minibuffer-local-completion-map
+  "C-t" #'sc-toggle-fn
+  "SPC" #'self-insert-command)
+
+(defvar-keymap sc-minibuffer-local-map
+  :doc "Keymap for minibuffer confirmation of attribution strings."
+  :parent minibuffer-local-map
+  "C-t" #'sc-toggle-fn)
 
 
 ;; ======================================================================
diff --git a/lisp/mail/uce.el b/lisp/mail/uce.el
deleted file mode 100644
index 2672cfca1f..0000000000
--- a/lisp/mail/uce.el
+++ /dev/null
@@ -1,400 +0,0 @@
-;;; uce.el --- facilitate reply to unsolicited commercial email  -*- 
lexical-binding: t; -*-
-
-;; Copyright (C) 1996, 1998, 2000-2022 Free Software Foundation, Inc.
-
-;; Author: stanislav shalunov <shalunov@mccme.ru>
-;; Created: 10 Dec 1996
-;; Keywords: mail, uce, unsolicited commercial email
-
-;; 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 code in this file provides a semi-automatic means of replying
-;; to unsolicited commercial email (UCE) you might get.  Currently, it
-;; only works with Rmail and Gnus.  If you would like to make it work
-;; with other mail readers, see the mail-client dependent section of
-;; uce-reply-to-uce.  Please let me know about your changes so I can
-;; incorporate them.  I'd appreciate it.
-
-;; NOTE: We don't recommend using this feature; see the message in
-;; 'uce-reply-to-uce' for the reasons.
-
-;; The command uce-reply-to-uce, if called when the current message
-;; buffer is a UCE, will setup a reply *mail* buffer as follows.  It
-;; scans the full headers of the message for: 1) the normal return
-;; address of the sender (From, Reply-To lines), and puts these
-;; addresses into the To: header, along with abuse@offenders.host; 2)
-;; the mailhub that first saw this message, and adds the address of
-;; its postmaster into the To: header; and 3), finally, it looks at
-;; the Message-Id and adds the postmaster of that host to the list of
-;; addresses.
-
-;; Then, we add an "Errors-To: nobody@localhost" header, so that if
-;; some of these addresses are not actually correct, we will never see
-;; bounced mail.  Also, mail-self-blind and mail-archive-file-name
-;; take no effect: the ideology is that we don't want to save junk or
-;; replies to junk.
-
-;; Then we insert a template into the buffer (a customizable message
-;; that explains what has happened), customizable signature, and the
-;; original message with full headers and envelope for postmasters.
-;; Then the buffer is left for editing.
-
-;; The reason that the function uce-reply-to-uce is mail-client
-;; dependent is that we want the full headers of the original message,
-;; nothing stripped.  If we use the normal means of inserting the
-;; original message into the *mail* buffer, headers like Received:
-;; (not really headers, but envelope lines) will be stripped, while
-;; they bear valuable information for us and postmasters.  I do wish
-;; that there would be some portable way to write this function, but I
-;; am not aware of any.
-
-;; Usage:
-
-;; Place uce.el in your load-path (and optionally byte-compile it).
-;; Add the following line to your init file:
-;; (autoload 'uce-reply-to-uce "uce" "Reply to UCEs" t nil)
-;; If you want to use it with Gnus rather than Rmail:
-;; (setq uce-mail-reader 'gnus)
-
-;; Options:
-
-;; uce-message-text is a template that will be inserted into buffer.
-;; It has a reasonable default.  If you want to write some scarier
-;; one, please do so and send it to me.  Please keep it polite.
-
-;; uce-signature behaves just like mail-signature.  If nil, nothing is
-;; inserted, if t, file ~/.signature is used, if a string, its
-;; contents are inserted into buffer.
-
-;; uce-uce-separator is a line that separates your message from the
-;; UCE that you enclose.
-
-;; uce-subject-line will be used as the subject of the outgoing message.
-
-
-;;; Change Log:
-
-;; Dec 10, 1996 -- posted draft version to gnu.sources.emacs
-
-;; Dec 11, 1996 -- fixed some typos, and Francesco Potortì
-;; <F.Potorti@cnuce.cnr.it> pointed out that my use of defvar was
-;; weird, suggested fix, and added let form.
-
-;; Dec 17, 1996 -- made scanning for host names little bit more clever
-;; (obviously bogus stuff like localhost is now ignored).
-
-;; Nov 11, 1997 -- incorporated changes from Mikael Djurfeldt
-;; <mdj@nada.kth.se> to make uce.el work with Gnus.  Changed the text
-;; of message that is sent.
-
-;; Dec 3, 1997 -- changes from Gareth Jones <gdj1@gdjones.demon.co.uk>
-;; handling Received headers following some line like `From:'.
-
-;; Aug 16, 2000 -- changes from Detlev Zundel
-;; <detlev.zundel@stud.uni-karlsruhe.de> to make uce.el work with the
-;; latest Gnus.  Lars told him it should work for all versions of Gnus
-;; younger than three years.
-
-
-;;; Code:
-
-(defvar gnus-original-article-buffer)
-(defvar mail-reply-buffer)
-
-(require 'sendmail)
-;; Those sections of code which are dependent upon
-;; RMAIL are only evaluated if we have received a message with RMAIL...
-;;(require 'rmail)
-
-(defgroup uce nil
-  "Facilitate reply to unsolicited commercial email."
-  :prefix "uce-"
-  :group 'mail)
-
-(defcustom uce-mail-reader 'rmail
-  "A symbol indicating which mail reader you are using.
-Choose from: `gnus', `rmail'."
-  :type '(choice (const gnus) (const rmail))
-  :version "20.3")
-
-(defcustom uce-setup-hook nil
-  "Hook to run after UCE rant message is composed.
-This hook is run after `mail-setup-hook', which is run as well."
-  :type 'hook)
-
-(defcustom uce-message-text
-  "Recently, I have received an Unsolicited Commercial E-mail from you.
-I do not like UCE's and I would like to inform you that sending
-unsolicited messages to someone while he or she may have to pay for
-reading your message may be illegal.  Anyway, it is highly annoying
-and not welcome by anyone.  It is rude, after all.
-
-If you think that this is a good way to advertise your products or
-services you are mistaken.  Spamming will only make people hate you, not
-buy from you.
-
-If you have any list of people you send unsolicited commercial emails to,
-REMOVE me from such list immediately.  I suggest that you make this list
-just empty.
-
-       ----------------------------------------------------
-
-If you are not an administrator of any site and still have received
-this message then your email address is being abused by some spammer.
-They fake your address in From: or Reply-To: header.  In this case,
-you might want to show this message to your system administrator, and
-ask him/her to investigate this matter.
-
-Note to the postmaster(s): I append the text of UCE in question to
-this message; I would like to hear from you about action(s) taken.
-This message has been sent to postmasters at the host that is
-mentioned as original sender's host (I do realize that it may be
-faked, but I think that if your domain name is being abused this way
-you might want to learn about it, and take actions) and to the
-postmaster whose host was used as mail relay for this message.  If
-message was sent not by your user, could you please compare time when
-this message was sent (use time in Received: field of the envelope
-rather than Date: field) with your sendmail logs and see what host was
-using your sendmail at this moment of time.
-
-Thank you."
-
-  "This is the text that `uce-reply-to-uce' command will put in reply buffer.
-Some of spamming programs in use will be set up to read all incoming
-to spam address email, and will remove people who put the word `remove'
-on beginning of some line from the spamming list.  So, when you set it
-up, it might be a good idea to actually use this feature.
-
-Value nil means insert no text by default, lets you type it in."
-  :type '(choice (const nil) string))
-
-(defcustom uce-uce-separator
-  "----- original unsolicited commercial email follows -----"
-  "Line that will begin quoting of the UCE.
-Value nil means use no separator."
-  :type '(choice (const nil) string))
-
-(defcustom uce-signature mail-signature
-"Text to put as your signature after the note to UCE sender.
-Value nil means none, t means insert `~/.signature' file (if it happens
-to exist), if this variable is a string this string will be inserted
-as your signature."
-  :type '(choice (const nil) (const t) string))
-
-(defcustom uce-default-headers
-  "Errors-To: nobody@localhost\nPrecedence: bulk\n"
-  "Additional headers to use when responding to a UCE with 
\\[uce-reply-to-uce].
-These are mostly meant for headers that prevent delivery errors reporting."
-  :type '(choice (const nil) string))
-
-(defcustom uce-subject-line
-  "Spam alert: unsolicited commercial e-mail"
-  "Subject of the message that will be sent in response to a UCE."
-  :type 'string)
-
-;; End of user options.
-
-
-(defvar rmail-buffer)
-(declare-function rmail-msg-is-pruned "rmail" ())
-(declare-function mail-strip-quoted-names "mail-utils" (address))
-(declare-function rmail-maybe-set-message-counters "rmail" ())
-(declare-function rmail-toggle-header "rmail" (&optional arg))
-
-(defvar uce--usage-warning-displayed nil)
-
-;;;###autoload
-(defun uce-reply-to-uce (&optional _ignored)
-  "Compose a reply to unsolicited commercial email (UCE).
-Sets up a reply buffer addressed to: the sender, his postmaster,
-his abuse@ address, and the postmaster of the mail relay used.
-You might need to set `uce-mail-reader' before using this."
-  (interactive)
-  ;; Start of mail-client dependent section.
-  (let ((message-buffer
-        (cond ((eq uce-mail-reader 'gnus) gnus-original-article-buffer)
-              ((eq uce-mail-reader 'rmail) (bound-and-true-p rmail-buffer))
-              (t (error
-                  "Variable uce-mail-reader set to unrecognized value"))))
-       pruned)
-    (or (and message-buffer (get-buffer message-buffer))
-       (error "No mail buffer, cannot find UCE"))
-    (switch-to-buffer message-buffer)
-    ;; We need the message with headers pruned.
-    ;; Why?  All we do is get the from and reply-to headers.  ?
-    (and (eq uce-mail-reader 'rmail)
-        (not (setq pruned (rmail-msg-is-pruned)))
-        (rmail-toggle-header 1))
-    (let ((to (mail-strip-quoted-names (mail-fetch-field "from" t)))
-         (reply-to (mail-fetch-field "reply-to"))
-         temp)
-      ;; Initial setting of the list of recipients of our message; that's
-      ;; what they are pretending to be.
-      (setq to (if to
-                  (format "%s" (mail-strip-quoted-names to))
-                ""))
-      (if reply-to
-         (setq to (format "%s, %s" to (mail-strip-quoted-names reply-to))))
-      (let (first-at-sign end-of-hostname sender-host)
-       (setq first-at-sign (string-search "@" to)
-             end-of-hostname (string-match "[ ,>]" to first-at-sign)
-             sender-host (substring to first-at-sign end-of-hostname))
-       (if (string-search "." sender-host)
-           (setq to (format "%s, postmaster%s, abuse%s"
-                            to sender-host sender-host))))
-      (setq mail-send-actions nil)
-      (setq mail-reply-buffer nil)
-      (when (eq uce-mail-reader 'rmail)
-       (rmail-toggle-header 0)
-       (rmail-maybe-set-message-counters)) ; why?
-      (copy-region-as-kill (point-min) (point-max))
-      ;; Restore the initial header state we found.
-      (and pruned (rmail-toggle-header 1))
-      (switch-to-buffer "*mail*")
-      (erase-buffer)
-      (yank)
-      (goto-char (point-min))
-      ;; Delete any internal Rmail headers.
-      (when (eq uce-mail-reader 'rmail)
-       (search-forward "\n\n")
-       (while (re-search-backward "^X-RMAIL" nil t)
-         (delete-region (point) (line-beginning-position 2)))
-       (goto-char (point-min)))
-      ;; Now find the mail hub that first accepted this message.
-      ;; This should try to find the last Received: header.
-      ;; Sometimes there may be other headers in between Received: headers.
-      (cond ((eq uce-mail-reader 'gnus)
-            ;; Does Gnus always have Lines: in the end?
-            (re-search-forward "^Lines:")
-            (beginning-of-line))
-           ((eq uce-mail-reader 'rmail)
-            (search-forward "\n\n")))
-      (re-search-backward "^Received:")
-      ;; Is this always good?  It's the only thing I saw when I checked
-      ;; a few messages.
-      ;;(if (not (re-search-forward ": \\(from\\|by\\) " eol t))
-      (unless (re-search-forward "\\(from\\|by\\) " (line-end-position) 'move)
-       (if (looking-at "[ \t\n]+\\(from\\|by\\) ")
-           (goto-char (match-end 0))
-         (error "Failed to extract hub address")))
-      (setq temp (point))
-      (search-forward " ")
-      (forward-char -1)
-      ;; And add its postmaster to the list of addresses.
-      (if (string-search "." (buffer-substring temp (point)))
-         (setq to (format "%s, postmaster@%s"
-                          to (buffer-substring temp (point)))))
-      ;; Also look at the message-id, it helps *very* often.
-      (and (search-forward "\nMessage-Id: " nil t)
-          ;; Not all Message-Id:'s have an `@' sign.
-          (search-forward "@" (line-end-position) t)
-          (progn
-            (setq temp (point))
-            (search-forward ">")
-            (forward-char -1)
-            (if (string-search "." (buffer-substring temp (point)))
-                (setq to (format "%s, postmaster@%s"
-                                 to (buffer-substring temp (point)))))))
-      (when (eq uce-mail-reader 'gnus)
-       ;; Does Gnus always have Lines: in the end?
-       (re-search-forward "^Lines:")
-       (beginning-of-line)
-       (setq temp (point))
-       (search-forward "\n\n" nil t)
-       (forward-line -1)
-       (delete-region temp (point)))
-      ;; End of mail-client dependent section.
-      (auto-save-mode auto-save-default)
-      (mail-mode)
-      (goto-char (point-min))
-      (insert "To: ")
-      (save-excursion
-       (if to
-           (let ((fill-prefix "\t")
-                 (address-start (point)))
-             (insert to "\n")
-             (fill-region-as-paragraph address-start (point)))
-         (newline))
-       (insert "Subject: " uce-subject-line "\n")
-       (if uce-default-headers
-           (insert uce-default-headers))
-       (if mail-default-headers
-           (insert mail-default-headers))
-       (if mail-default-reply-to
-           (insert "Reply-To: " mail-default-reply-to "\n"))
-       (insert mail-header-separator "\n")
-       ;; Insert all our text.  Then go back to the place where we started.
-       (if to (setq to (point)))
-       ;; Text of ranting.
-       (if uce-message-text
-           (insert uce-message-text))
-       ;; Signature.
-       (cond ((eq uce-signature t)
-              (if (file-exists-p "~/.signature")
-                  (progn
-                    (insert "\n\n-- \n")
-                    (forward-char (cadr (insert-file-contents 
"~/.signature"))))))
-             (uce-signature
-              (insert "\n\n-- \n" uce-signature)))
-       ;; And text of the original message.
-       (if uce-uce-separator
-           (insert "\n\n" uce-uce-separator "\n"))
-       ;; If message doesn't end with a newline, insert it.
-       (goto-char (point-max))
-       (or (bolp) (newline)))
-      ;; And go back to the beginning of text.
-      (if to (goto-char to))
-      (or to (set-buffer-modified-p nil))
-      ;; Run hooks before we leave buffer for editing.  Reasonable usage
-      ;; might be to set up special key bindings, replace standard
-      ;; functions in mail-mode, etc.
-      (run-hooks 'mail-setup-hook 'uce-setup-hook)))
-  (unless uce--usage-warning-displayed
-    (setq uce--usage-warning-displayed t)
-    (pop-to-buffer (get-buffer-create "uce-reply-to-uce warning"))
-    (insert "\
--- !!! NOTE !!! ---------------------------------------------
-
-Replying to spam is at best pointless, but most likely actively
-harmful.
-
-- You will confirm that your email address is valid, thus ensuring
-  you get more spam.
-
-- You will leak information and open yourself up for further
-  attack.  For example, they could use your \"geolocation\" to find
-  your home address and phone number.
-
-- The sender address is likely fake.
-
-- You help them refine their methods of spamming.
-
-Therefore, we strongly recommend that you do not use this package.
-Use a spam filter instead, or just delete the spam.
-
--------------------------------------------------------------
-")))
-
-(defun uce-insert-ranting (&optional _ignored)
-  "Insert text of the usual reply to UCE into current buffer."
-  (interactive "P")
-  (insert uce-message-text))
-
-(provide 'uce)
-
-;;; uce.el ends here
diff --git a/lisp/mail/undigest.el b/lisp/mail/undigest.el
index c6d29bc4e7..cdb1bec478 100644
--- a/lisp/mail/undigest.el
+++ b/lisp/mail/undigest.el
@@ -378,8 +378,4 @@ forwarded with `rmail-enable-mime-composing' set to nil."
 
 (provide 'undigest)
 
-;; Local Variables:
-;; generated-autoload-file: "rmail-loaddefs.el"
-;; End:
-
 ;;; undigest.el ends here
diff --git a/lisp/mail/unrmail.el b/lisp/mail/unrmail.el
index 8ce5afa962..9e7194e4a0 100644
--- a/lisp/mail/unrmail.el
+++ b/lisp/mail/unrmail.el
@@ -208,7 +208,7 @@ The variable `unrmail-mbox-format' controls which mbox 
format to use."
              (setq mail-from (or (let ((from (mail-fetch-field "Mail-From")))
                                    ;; mail-mbox-from (below) returns a
                                    ;; string that ends in a newline, but
-                                   ;; but mail-fetch-field does not, so
+                                   ;; mail-fetch-field does not, so
                                    ;; we append a newline here.
                                    (if from
                                        (format "%s\n" from)))
diff --git a/lisp/makesum.el b/lisp/makesum.el
deleted file mode 100644
index 4084358ca9..0000000000
--- a/lisp/makesum.el
+++ /dev/null
@@ -1,109 +0,0 @@
-;;; makesum.el --- generate key binding summary for Emacs  -*- 
lexical-binding:t -*-
-
-;; Copyright (C) 1985, 2001-2022 Free Software Foundation, Inc.
-
-;; Maintainer: emacs-devel@gnu.org
-;; Keywords: help
-
-;; 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:
-
-;; Displays a nice human-readable summary of all keybindings in a
-;; two-column format.
-
-;;; Code:
-
-;;;###autoload
-(defun make-command-summary ()
-  "Make a summary of current key bindings in the buffer *Summary*.
-Previous contents of that buffer are killed first."
-  (interactive)
-  (message "Making command summary...")
-  ;; This puts a description of bindings in a buffer called *Help*.
-  (save-window-excursion
-   (describe-bindings))
-  (with-output-to-temp-buffer "*Summary*"
-    (save-excursion
-     (let ((cur-mode mode-name))
-       (set-buffer standard-output)
-       (erase-buffer)
-       (insert-buffer-substring "*Help*")
-       (goto-char (point-min))
-       (delete-region (point) (progn (forward-line 1) (point)))
-       (while (search-forward "         " nil t)
-        (replace-match "  "))
-       (goto-char (point-min))
-       (while (search-forward "-@ " nil t)
-        (replace-match "-SP"))
-       (goto-char (point-min))
-       (while (search-forward "  .. ~ " nil t)
-        (replace-match "SP .. ~"))
-       (goto-char (point-min))
-       (while (search-forward "C-?" nil t)
-        (replace-match "DEL"))
-       (goto-char (point-min))
-       (while (search-forward "C-i" nil t)
-        (replace-match "TAB"))
-       (goto-char (point-min))
-       (when (re-search-forward "^Local Bindings:" nil t)
-         (forward-char -1)
-         (insert " for " (format-mode-line cur-mode) " Mode")
-         (while (search-forward "??\n" nil t)
-           (delete-region (point)
-                          (progn
-                            (forward-line -1)
-                            (point)))))
-       (goto-char (point-min))
-       (insert "Emacs command summary, " (substring (current-time-string) 0 10)
-              ".\n")
-       ;; Delete "key    binding" and underlining of dashes.
-       (delete-region (point) (progn (forward-line 2) (point)))
-       (forward-line 1)                        ;Skip blank line
-       (while (not (eobp))
-        (let ((beg (point)))
-          (or (re-search-forward "^$" nil t)
-              (goto-char (point-max)))
-          (double-column beg (point))
-          (forward-line 1)))
-       (goto-char (point-min)))))
-  (message "Making command summary...done"))
-
-(defun double-column (start end)
-  "Reformat buffer contents from START to END into two columns."
-  (interactive "r")
-  (let (half lines
-        (nlines (count-lines start end))
-       (from-end (- (point-max) end)))
-    (when (> nlines 1)
-      (setq half (/ (1+ nlines) 2))
-      (goto-char start)
-      (save-excursion
-       (forward-line half)
-       (dotimes (_ (- nlines half))
-         (push (buffer-substring (point) (line-end-position))
-               lines)
-        (delete-region (point) (progn (forward-line 1) (point)))))
-      (dolist (line (nreverse lines))
-        (end-of-line)
-       (indent-to 41)
-        (insert line)
-        (forward-line 1)))
-    (goto-char (- (point-max) from-end))))
-
-(provide 'makesum)
-
-;;; makesum.el ends here
diff --git a/lisp/man.el b/lisp/man.el
index 951e0ef9ad..7ba7bee417 100644
--- a/lisp/man.el
+++ b/lisp/man.el
@@ -168,13 +168,14 @@ pushy      -- make the manpage the current buffer in the 
current window
 bully      -- make the manpage the current buffer and only window (sf)
 aggressive -- make the manpage the current buffer in the other window (sf)
 friendly   -- display manpage in the other window but don't make current (sf)
+thrifty    -- reuse an existing manpage window if possible (sf)
 polite     -- don't display manpage, but prints message and beep when ready
 quiet      -- like `polite', but don't beep
 meek       -- make no indication that the manpage is ready
 
 Any other value of `Man-notify-method' is equivalent to `meek'."
   :type '(radio (const newframe) (const pushy) (const bully)
-               (const aggressive) (const friendly)
+               (const aggressive) (const friendly) (const thrifty)
                (const polite) (const quiet) (const meek))
   :group 'man)
 
@@ -1229,6 +1230,11 @@ See the variable `Man-notify-method' for the different 
notification behaviors."
        (and (frame-live-p saved-frame)
             (select-frame saved-frame))
        (display-buffer man-buffer 'not-this-window))
+      ('thrifty
+       (and (frame-live-p saved-frame)
+            (select-frame saved-frame))
+       (display-buffer man-buffer '(display-buffer-reuse-mode-window
+                                    (mode . Man-mode))))
       ('polite
        (beep)
        (message "Manual buffer %s is ready" (buffer-name man-buffer)))
@@ -1241,8 +1247,7 @@ See the variable `Man-notify-method' for the different 
notification behaviors."
 (defun Man-softhyphen-to-minus ()
   ;; \255 is SOFT HYPHEN in Latin-N.  Versions of Debian man, at
   ;; least, emit it even when not in a Latin-N locale.
-  (unless (eq t (compare-strings "latin-" 0 nil
-                                current-language-environment 0 6 t))
+  (unless (string-prefix-p "latin-" current-language-environment t)
     (goto-char (point-min))
     (while (search-forward "­" nil t) (replace-match "-"))))
 
diff --git a/lisp/menu-bar.el b/lisp/menu-bar.el
index 488bf05f3a..c2c18320b1 100644
--- a/lisp/menu-bar.el
+++ b/lisp/menu-bar.el
@@ -47,7 +47,7 @@
 
 ;; This definition is just to show what this looks like.
 ;; It gets modified in place when menu-bar-update-buffers is called.
-(defvar global-buffers-menu-map (make-sparse-keymap "Buffers"))
+(defvar-keymap global-buffers-menu-map :name "Buffers")
 
 (defvar menu-bar-print-menu
   (let ((menu (make-sparse-keymap "Print")))
@@ -584,9 +584,6 @@
 
     menu))
 
-(define-obsolete-function-alias
-  'menu-bar-kill-ring-save 'kill-ring-save "24.1")
-
 ;; These are alternative definitions for the cut, paste and copy
 ;; menu items.  Use them if your system expects these to use the clipboard.
 
@@ -683,7 +680,7 @@ Do the same for the keys of the same name."
       '(menu-item "Custom Themes" customize-themes
                   :help "Choose a pre-defined customization theme"))
     menu))
-;(defvar menu-bar-preferences-menu (make-sparse-keymap "Preferences"))
+;(defvar-keymap menu-bar-preferences-menu :name "Preferences")
 
 (defmacro menu-bar-make-mm-toggle (fname doc help &optional props)
   "Make a menu-item for a global minor mode toggle.
@@ -749,7 +746,11 @@ by \"Save Options\" in Custom buffers.")
        ;; interactively, because the purpose is to mark the variable as a
        ;; candidate for `Save Options', and we do not want to save options that
        ;; the user has already set explicitly in the init file.
-       (when interactively (customize-mark-as-set ',variable)))
+       (when interactively
+         (customize-mark-as-set ',variable))
+       ;; Toggle menu items must make sure that the menu is updated so
+       ;; that toggle marks are drawn in the right state.
+       (force-mode-line-update t))
      '(menu-item ,item-name ,command :help ,help
                  :button (:toggle . (and (default-boundp ',variable)
                                          (default-value ',variable)))
@@ -792,6 +793,7 @@ The selected font will be the default on both the existing 
and future frames."
     (dolist (elt '(scroll-bar-mode
                   debug-on-quit debug-on-error
                   ;; Somehow this works, when tool-bar and menu-bar don't.
+                   desktop-save-mode
                   tooltip-mode window-divider-mode
                   save-place-mode uniquify-buffer-name-style fringe-mode
                   indicate-empty-lines indicate-buffer-boundaries
@@ -2189,12 +2191,12 @@ otherwise it could decide to silently do nothing."
 
 (defcustom yank-menu-length 20
   "Text of items in `yank-menu' longer than this will be truncated."
-  :type 'integer
+  :type 'natnum
   :group 'menu)
 
 (defcustom yank-menu-max-items 60
   "Maximum number of entries to display in the `yank-menu'."
-  :type 'integer
+  :type 'natnum
   :group 'menu
   :version "29.1")
 
diff --git a/lisp/mh-e/mh-acros.el b/lisp/mh-e/mh-acros.el
index 805b0820b0..2b4807ab69 100644
--- a/lisp/mh-e/mh-acros.el
+++ b/lisp/mh-e/mh-acros.el
@@ -269,11 +269,25 @@ MH-E functions."
                  binders)
        (let* ,binders ,@body))))
 
+;; Emacs 24 made flet obsolete and suggested either cl-flet or
+;; cl-letf. This macro is based upon gmm-flet from Gnus.
+(defmacro mh-flet (bindings &rest body)
+  "Make temporary overriding function definitions.
+That is, temporarily rebind the functions listed in BINDINGS and then
+execute BODY.  BINDINGS is a list containing one or more lists of the
+form (FUNCNAME ARGLIST BODY...), similar to defun."
+  (declare (indent 1) (debug ((&rest (sexp sexp &rest form)) &rest form)))
+  (if (fboundp 'cl-letf)
+      `(cl-letf ,(mapcar (lambda (binding)
+                           `((symbol-function ',(car binding))
+                             (lambda ,@(cdr binding))))
+                         bindings)
+         ,@body)
+    `(flet ,bindings ,@body)))
+
 (provide 'mh-acros)
 
 ;; Local Variables:
-;; no-byte-compile: t
-;; indent-tabs-mode: nil
 ;; sentence-end-double-space: nil
 ;; End:
 
diff --git a/lisp/mh-e/mh-alias.el b/lisp/mh-e/mh-alias.el
index f39caac893..3ceb419023 100644
--- a/lisp/mh-e/mh-alias.el
+++ b/lisp/mh-e/mh-alias.el
@@ -245,10 +245,6 @@ Blind aliases or users from /etc/passwd are not expanded."
    (t
     (mh-alias-ali alias))))
 
-(eval-and-compile
-  (require 'crm nil t)                 ; completing-read-multiple
-  (require 'multi-prompt nil t))
-
 ;;;###mh-autoload
 (defun mh-read-address (prompt)
   "Read an address from the minibuffer with PROMPT."
@@ -662,7 +658,6 @@ show buffer, the message in the show buffer doesn't match."
 (provide 'mh-alias)
 
 ;; Local Variables:
-;; indent-tabs-mode: nil
 ;; sentence-end-double-space: nil
 ;; End:
 
diff --git a/lisp/mh-e/mh-buffers.el b/lisp/mh-e/mh-buffers.el
index f21b57663b..4b15b77413 100644
--- a/lisp/mh-e/mh-buffers.el
+++ b/lisp/mh-e/mh-buffers.el
@@ -75,7 +75,6 @@ The function returns the size of the final size of the log 
buffer."
 (provide 'mh-buffers)
 
 ;; Local Variables:
-;; indent-tabs-mode: nil
 ;; sentence-end-double-space: nil
 ;; End:
 
diff --git a/lisp/mh-e/mh-comp.el b/lisp/mh-e/mh-comp.el
index a9f6274e9d..678bffd168 100644
--- a/lisp/mh-e/mh-comp.el
+++ b/lisp/mh-e/mh-comp.el
@@ -1272,7 +1272,6 @@ discarded."
 (provide 'mh-comp)
 
 ;; Local Variables:
-;; indent-tabs-mode: nil
 ;; sentence-end-double-space: nil
 ;; End:
 
diff --git a/lisp/mh-e/mh-compat.el b/lisp/mh-e/mh-compat.el
deleted file mode 100644
index 7a09429e4e..0000000000
--- a/lisp/mh-e/mh-compat.el
+++ /dev/null
@@ -1,151 +0,0 @@
-;;; mh-compat.el --- make MH-E compatible with various versions of Emacs  -*- 
lexical-binding: t; -*-
-
-;; Copyright (C) 2006-2022 Free Software Foundation, Inc.
-
-;; Author: Bill Wohler <wohler@newt.com>
-;; Keywords: mail
-;; See: mh-e.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:
-
-;;; Code:
-
-;; This is a good place to gather code that is used for compatibility
-;; between different versions of Emacs. Please document which versions
-;; of Emacs that the defsubst, defalias, or defmacro applies. That
-;; way, it's easy to occasionally go through this file and see which
-;; macros we can retire.
-
-;; Please use mh-gnus.el when providing compatibility with different
-;; versions of Gnus.
-
-;; Items are listed alphabetically.
-
-(eval-when-compile (require 'mh-acros))
-
-(define-obsolete-function-alias 'mh-require #'require "29.1")
-(define-obsolete-function-alias 'mh-assoc-string #'assoc-string "29.1")
-(define-obsolete-function-alias 'mh-cancel-timer #'cancel-timer "29.1")
-
-;; Emacs 24 made flet obsolete and suggested either cl-flet or
-;; cl-letf. This macro is based upon gmm-flet from Gnus.
-(defmacro mh-flet (bindings &rest body)
-  "Make temporary overriding function definitions.
-That is, temporarily rebind the functions listed in BINDINGS and then
-execute BODY.  BINDINGS is a list containing one or more lists of the
-form (FUNCNAME ARGLIST BODY...), similar to defun."
-  (declare (indent 1) (debug ((&rest (sexp sexp &rest form)) &rest form)))
-  (if (fboundp 'cl-letf)
-      `(cl-letf ,(mapcar (lambda (binding)
-                           `((symbol-function ',(car binding))
-                             (lambda ,@(cdr binding))))
-                         bindings)
-         ,@body)
-    `(flet ,bindings ,@body)))
-
-(define-obsolete-function-alias 'mh-display-color-cells
-  #'display-color-cells "29.1")
-
-(defmacro mh-display-completion-list (completions &optional common-substring)
-  "Display the list of COMPLETIONS.
-See documentation for `display-completion-list' for a description of the
-arguments COMPLETIONS.
-The optional argument COMMON-SUBSTRING, if non-nil, should be a string
-specifying a common substring for adding the faces
-`completions-first-difference' and `completions-common-part' to
-the completions."
-  `(display-completion-list
-    (completion-hilit-commonality ,completions
-                                  ,(length common-substring) nil)))
-
-(define-obsolete-function-alias 'mh-face-foreground
-  #'face-foreground "29.1")
-
-(define-obsolete-function-alias 'mh-face-background
-  #'face-background "29.1")
-
-(define-obsolete-function-alias 'mh-font-lock-add-keywords
-  #'font-lock-add-keywords "29.1")
-
-;; Not preloaded in without-x builds.
-(declare-function image-load-path-for-library "image")
-(define-obsolete-function-alias 'mh-image-load-path-for-library
-  #'image-load-path-for-library "29.1")
-
-;; Not preloaded in without-x builds.
-(declare-function image-search-load-path "image")
-(define-obsolete-function-alias 'mh-image-search-load-path
-  #'image-search-load-path "29.1")
-
-(define-obsolete-function-alias 'mh-line-beginning-position
-  #'line-beginning-position "29.1")
-
-(define-obsolete-function-alias 'mh-line-end-position
-  #'line-end-position "29.1")
-
-(require 'mailabbrev nil t)
-(define-obsolete-function-alias 'mh-mail-abbrev-make-syntax-table
-  #'mail-abbrev-make-syntax-table "29.1")
-
-(define-obsolete-function-alias 'mh-define-obsolete-variable-alias
-  #'define-obsolete-variable-alias "29.1")
-
-(define-obsolete-function-alias 'mh-make-obsolete-variable
-  #'make-obsolete-variable "29.1")
-
-(define-obsolete-function-alias 'mh-match-string-no-properties
-  #'match-string-no-properties "29.1")
-
-(define-obsolete-function-alias 'mh-replace-regexp-in-string
-  #'replace-regexp-in-string "29.1")
-
-(define-obsolete-function-alias 'mh-test-completion
-  #'test-completion "29.1")
-
-(defconst mh-url-unreserved-chars
-  '(
-    ?a ?b ?c ?d ?e ?f ?g ?h ?i ?j ?k ?l ?m ?n ?o ?p ?q ?r ?s ?t ?u ?v ?w ?x ?y 
?z
-       ?A ?B ?C ?D ?E ?F ?G ?H ?I ?J ?K ?L ?M ?N ?O ?P ?Q ?R ?S ?T ?U ?V ?W ?X 
?Y ?Z
-       ?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9
-       ?- ?_ ?. ?! ?~ ?* ?' ?\( ?\))
-  "A list of characters that are _NOT_ reserved in the URL spec.
-This is taken from RFC 2396.")
-(make-obsolete-variable 'mh-url-unreserved-chars 'url-unreserved-chars "29.1")
-
-(define-obsolete-function-alias 'mh-url-hexify-string
-  #'url-hexify-string "29.1")
-
-(define-obsolete-function-alias 'mh-view-mode-enter
-  #'view-mode-enter "29.1")
-
-(define-obsolete-function-alias 'mh-window-full-height-p
-  #'window-full-height-p "29.1")
-
-(defmacro mh-write-file-functions ()
-  "Return `write-file-functions'."
-  (declare (obsolete nil "29.1"))
-  ''write-file-functions)
-
-(provide 'mh-compat)
-
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; sentence-end-double-space: nil
-;; End:
-
-;;; mh-compat.el ends here
diff --git a/lisp/mh-e/mh-e.el b/lisp/mh-e/mh-e.el
index 872f0d79d2..f6031df9c2 100644
--- a/lisp/mh-e/mh-e.el
+++ b/lisp/mh-e/mh-e.el
@@ -86,7 +86,6 @@
 (require 'cl-lib)
 
 (require 'mh-buffers)
-(require 'mh-compat)
 
 
 
@@ -163,8 +162,9 @@ User's mail folder directory.")
 
 ;; Maps declared here so that they can be used in docstrings.
 
-(defvar mh-folder-mode-map (make-keymap)
-  "Keymap for MH-Folder mode.")
+(defvar-keymap mh-folder-mode-map
+  :doc "Keymap for MH-Folder mode."
+  :full t)
 
 (defvar mh-folder-seq-tool-bar-map nil
   "Keymap for MH-Folder tool bar.")
@@ -172,8 +172,8 @@ User's mail folder directory.")
 (defvar mh-folder-tool-bar-map nil
   "Keymap for MH-Folder tool bar.")
 
-(defvar mh-inc-spool-map (make-sparse-keymap)
-  "Keymap for MH-E's mh-inc-spool commands.")
+(defvar-keymap mh-inc-spool-map
+  :doc "Keymap for MH-E's mh-inc-spool commands.")
 
 (defvar mh-letter-mode-map (copy-keymap text-mode-map)
   "Keymap for MH-Letter mode.")
@@ -181,11 +181,11 @@ User's mail folder directory.")
 (defvar mh-letter-tool-bar-map nil
   "Keymap for MH-Letter tool bar.")
 
-(defvar mh-search-mode-map (make-sparse-keymap)
-  "Keymap for MH-Search mode.")
+(defvar-keymap mh-search-mode-map
+  :doc "Keymap for MH-Search mode.")
 
-(defvar mh-show-mode-map (make-sparse-keymap)
-  "Keymap MH-Show mode.")
+(defvar-keymap mh-show-mode-map
+  :doc "Keymap for MH-Show mode.")
 
 (defvar mh-show-seq-tool-bar-map nil
   "Keymap for MH-Show tool bar.")
@@ -388,11 +388,11 @@ gnus-version)
   (insert "MH-E " mh-version "\n\n")
   ;; MH-E compilation details.
   (insert "MH-E compilation details:\n")
-  (let* ((compiled-mhe (byte-code-function-p (symbol-function 'mh-version)))
+  (let* ((compiled-mhe (compiled-function-p (symbol-function 'mh-version)))
          (gnus-compiled-version (if compiled-mhe
                                     (mh-macro-expansion-time-gnus-version)
                                   "N/A")))
-    (insert " Byte compiled:\t\t" (if compiled-mhe "yes" "no") "\n"
+    (insert " Compiled:\t\t" (if compiled-mhe "yes" "no") "\n"
             " Gnus (compile-time):\t" gnus-compiled-version "\n"
             " Gnus (run-time):\t" (mh-run-time-gnus-version) "\n\n"))
   ;; Emacs version.
@@ -1790,16 +1790,7 @@ message without line wrapping."
 This option is used to select between a variety of mail security
 mechanisms. The default is \"PGP (MIME)\" if it is supported;
 otherwise, the default is \"None\". Other mechanisms include
-vanilla \"PGP\" and \"S/MIME\".
-
-The `pgg' customization group may have some settings which may
-interest you (see Info node `(pgg)').
-
-In particular, I turn on the option `pgg-encrypt-for-me' so that
-all messages I encrypt are encrypted with my public key as well.
-If you keep a copy of all of your outgoing mail with a \"Fcc:\"
-header field, this setting is vital so that you can read the mail
-you write!"
+vanilla \"PGP\" and \"S/MIME\"."
   :type '(choice (const :tag "PGP (MIME)" "pgpmime")
                  (const :tag "PGP" "pgp")
                  (const :tag "S/MIME" "smime")
@@ -3715,7 +3706,6 @@ The background and foreground are used in the image."
 (provide 'mh-e)
 
 ;; Local Variables:
-;; indent-tabs-mode: nil
 ;; sentence-end-double-space: nil
 ;; End:
 
diff --git a/lisp/mh-e/mh-folder.el b/lisp/mh-e/mh-folder.el
index 09df0465ed..308660431a 100644
--- a/lisp/mh-e/mh-folder.el
+++ b/lisp/mh-e/mh-folder.el
@@ -510,7 +510,7 @@ font-lock is done highlighting.")
   nil)
 
 ;; Register mh-folder-mode as supporting which-function-mode...
-(eval-and-compile (require 'which-func nil t))
+(require 'which-func)
 (when (and (boundp 'which-func-modes) (listp which-func-modes))
   (add-to-list 'which-func-modes 'mh-folder-mode))
 
@@ -583,7 +583,7 @@ perform the operation on all messages in that region.
   (make-local-variable 'desktop-save-buffer)
   (setq desktop-save-buffer t)
   (setq-local
-   mh-colors-available-flag (mh-colors-available-p)
+   mh-colors-available-flag (display-color-p)
                                         ; Do we have colors available
    mh-current-folder (buffer-name)      ; Name of folder, a string
    mh-show-buffer (format "show-%s" (buffer-name)) ; Buffer that displays msgs
@@ -2012,7 +2012,6 @@ If MSG is nil then act on the message at point"
 (provide 'mh-folder)
 
 ;; Local Variables:
-;; indent-tabs-mode: nil
 ;; sentence-end-double-space: nil
 ;; End:
 
diff --git a/lisp/mh-e/mh-funcs.el b/lisp/mh-e/mh-funcs.el
index ef0a76b9a4..ab89ef2a3d 100644
--- a/lisp/mh-e/mh-funcs.el
+++ b/lisp/mh-e/mh-funcs.el
@@ -95,9 +95,9 @@ RANGE is read in interactive use."
 Remove all of the messages (files) within the current folder, and
 then remove the folder (directory) itself.
 
-Run the abnormal hook `mh-kill-folder-suppress-prompt-hooks'. The
-hook functions are called with no arguments and should return a
-non-nil value to suppress the normal prompt when you remove a
+Run the abnormal hook `mh-kill-folder-suppress-prompt-functions'.
+The hook functions are called with no arguments and should return
+a non-nil value to suppress the normal prompt when you remove a
 folder. This is useful for folders that are easily regenerated."
   (interactive)
   (if (or (run-hook-with-args-until-success
@@ -366,7 +366,6 @@ Arguments are IGNORED (for `revert-buffer')."
 (provide 'mh-funcs)
 
 ;; Local Variables:
-;; indent-tabs-mode: nil
 ;; sentence-end-double-space: nil
 ;; End:
 
diff --git a/lisp/mh-e/mh-gnus.el b/lisp/mh-e/mh-gnus.el
index c341b09683..b797000566 100644
--- a/lisp/mh-e/mh-gnus.el
+++ b/lisp/mh-e/mh-gnus.el
@@ -28,12 +28,11 @@
 
 (require 'mh-e)
 
-(eval-and-compile
-  (require 'gnus-util nil t)
-  (require 'mm-bodies nil t)
-  (require 'mm-decode nil t)
-  (require 'mm-view nil t)
-  (require 'mml nil t))
+(require 'gnus-util)
+(require 'mm-bodies)
+(require 'mm-decode)
+(require 'mm-view)
+(require 'mml)
 
 (defun mh-gnus-local-map-property (map)
   "Return a list suitable for a text property list specifying keymap MAP."
@@ -109,7 +108,6 @@ PROMPT overrides the default one used to ask user for a 
file name."
 
 ;; Local Variables:
 ;; no-update-autoloads: t
-;; indent-tabs-mode: nil
 ;; sentence-end-double-space: nil
 ;; End:
 
diff --git a/lisp/mh-e/mh-identity.el b/lisp/mh-e/mh-identity.el
index 43eaeb7aa0..bcdf91299b 100644
--- a/lisp/mh-e/mh-identity.el
+++ b/lisp/mh-e/mh-identity.el
@@ -39,8 +39,10 @@
 
 (autoload 'mml-insert-tag "mml")
 
-(defvar-local mh-identity-pgg-default-user-id nil
-  "Holds the GPG key ID to be used by pgg.el.
+(define-obsolete-variable-alias 'mh-identity-pgg-default-user-id
+  'mh-identity-gpg-default-user-id "29.1")
+(defvar-local mh-identity-gpg-default-user-id nil
+  "Holds the GPG key ID.
 This is normally set as part of an Identity in
 `mh-identity-list'.")
 
@@ -202,15 +204,15 @@ See `mh-identity-list'."
 (defun mh-identity-handler-gpg-identity (_field action &optional value)
   "Process header FIELD \":pgg-default-user-id\".
 The ACTION is one of `remove' or `add'. If `add', the VALUE is added.
-The buffer-local variable `mh-identity-pgg-default-user-id' is set to
+The buffer-local variable `mh-identity-gpg-default-user-id' is set to
 VALUE when action `add' is selected."
   (cond
    ((or (equal action 'remove)
         (not value)
         (string= value ""))
-    (setq mh-identity-pgg-default-user-id nil))
+    (setq mh-identity-gpg-default-user-id nil))
    ((equal action 'add)
-    (setq mh-identity-pgg-default-user-id value))))
+    (setq mh-identity-gpg-default-user-id value))))
 
 ;;;###mh-autoload
 (defun mh-identity-handler-signature (_field action &optional value)
@@ -316,7 +318,6 @@ the header."
 (provide 'mh-identity)
 
 ;; Local Variables:
-;; indent-tabs-mode: nil
 ;; sentence-end-double-space: nil
 ;; End:
 
diff --git a/lisp/mh-e/mh-inc.el b/lisp/mh-e/mh-inc.el
index 2c29ec3223..cc6ebfef42 100644
--- a/lisp/mh-e/mh-inc.el
+++ b/lisp/mh-e/mh-inc.el
@@ -78,7 +78,6 @@
 (provide 'mh-inc)
 
 ;; Local Variables:
-;; indent-tabs-mode: nil
 ;; sentence-end-double-space: nil
 ;; End:
 
diff --git a/lisp/mh-e/mh-junk.el b/lisp/mh-e/mh-junk.el
index 1f773b878a..be1b7642eb 100644
--- a/lisp/mh-e/mh-junk.el
+++ b/lisp/mh-e/mh-junk.el
@@ -540,7 +540,6 @@ See `mh-spamprobe-blocklist' for more information."
 (provide 'mh-junk)
 
 ;; Local Variables:
-;; indent-tabs-mode: nil
 ;; sentence-end-double-space: nil
 ;; End:
 
diff --git a/lisp/mh-e/mh-letter.el b/lisp/mh-e/mh-letter.el
index 4e3e101231..723e5bb36c 100644
--- a/lisp/mh-e/mh-letter.el
+++ b/lisp/mh-e/mh-letter.el
@@ -864,16 +864,17 @@ Any match found replaces the text from BEGIN to END."
           ((stringp completion)
            (if (equal word completion)
                (with-output-to-temp-buffer completions-buffer
-                 (mh-display-completion-list
-                  (all-completions word choices)
-                  ;; The `common-substring' arg only works if it's a prefix.
-                  (unless (and (functionp choices)
-                               (let ((bounds
-                                      (funcall choices
-                                               word nil '(boundaries . ""))))
-                                 (and (eq 'boundaries (car-safe bounds))
-                                      (< 0 (cadr bounds)))))
-                    word)))
+                 (display-completion-list
+                  (completion-hilit-commonality
+                   (all-completions word choices)
+                   ;; The `common-substring' arg only works if it's a prefix.
+                   (unless (and (functionp choices)
+                                (let ((bounds
+                                       (funcall choices
+                                                word nil '(boundaries . ""))))
+                                  (and (eq 'boundaries (car-safe bounds))
+                                       (< 0 (cadr bounds)))))
+                     word))))
              (ignore-errors
                (kill-buffer completions-buffer))
              (delete-region begin end)
@@ -935,7 +936,6 @@ Otherwise, simply insert MH-INS-STRING before each line."
 (provide 'mh-letter)
 
 ;; Local Variables:
-;; indent-tabs-mode: nil
 ;; sentence-end-double-space: nil
 ;; End:
 
diff --git a/lisp/mh-e/mh-limit.el b/lisp/mh-e/mh-limit.el
index 3e731e22a1..da3e5b4f35 100644
--- a/lisp/mh-e/mh-limit.el
+++ b/lisp/mh-e/mh-limit.el
@@ -325,7 +325,6 @@ The MH command pick is used to do the match."
 (provide 'mh-limit)
 
 ;; Local Variables:
-;; indent-tabs-mode: nil
 ;; sentence-end-double-space: nil
 ;; End:
 
diff --git a/lisp/mh-e/mh-mime.el b/lisp/mh-e/mh-mime.el
index d2e07977e5..316463b989 100644
--- a/lisp/mh-e/mh-mime.el
+++ b/lisp/mh-e/mh-mime.el
@@ -379,10 +379,8 @@ do the work."
           ((and (or prompt
                     (equal t mh-mime-save-parts-default-directory))
                 mh-mime-save-parts-directory)
-           (read-directory-name (format-prompt
-                                 "Store in directory"
-                                 mh-mime-save-parts-directory)
-                           "" mh-mime-save-parts-directory t ""))
+           (read-directory-name "Store in directory: "
+                                mh-mime-save-parts-directory nil t))
           ((stringp mh-mime-save-parts-default-directory)
            mh-mime-save-parts-default-directory)
           (t
@@ -394,18 +392,19 @@ do the work."
       (if (equal nil mh-mime-save-parts-default-directory)
           (setq mh-mime-save-parts-directory directory))
       (with-current-buffer (get-buffer-create mh-log-buffer)
-        (cd directory)
-        (setq mh-mime-save-parts-directory directory)
-        (let ((initial-size (mh-truncate-log-buffer)))
-          (apply #'call-process
-                 (expand-file-name command mh-progs) nil t nil
-                 (mh-list-to-string (list folder msg "-auto"
-                                          (if (not (mh-variant-p 'nmh))
-                                              "-store"))))
-          (if (> (buffer-size) initial-size)
-              (save-window-excursion
-                (switch-to-buffer-other-window mh-log-buffer)
-                (sit-for 3))))))))
+        (let (default-directory)
+          (cd directory)
+          (setq mh-mime-save-parts-directory directory)
+          (let ((initial-size (mh-truncate-log-buffer)))
+            (apply #'call-process
+                   (expand-file-name command mh-progs) nil t nil
+                   (mh-list-to-string (list folder msg "-auto"
+                                            (if (not (mh-variant-p 'nmh))
+                                                "-store"))))
+            (if (> (buffer-size) initial-size)
+                (save-window-excursion
+                  (switch-to-buffer-other-window mh-log-buffer)
+                  (sit-for 3)))))))))
 
 ;;;###mh-autoload
 (defun mh-toggle-mh-decode-mime-flag ()
@@ -1141,15 +1140,7 @@ this ;-)"
   "Check if show buffer is small.
 This is used to decide if smileys and graphical emphasis should be
 displayed."
-  (let ((max nil))
-    ;; FIXME: font-lock-maximum-size is obsolete.
-    (when (and (boundp 'font-lock-maximum-size) font-lock-maximum-size)
-      (cond ((numberp font-lock-maximum-size)
-             (setq max font-lock-maximum-size))
-            ((listp font-lock-maximum-size)
-             (setq max (cdr (or (assoc 'mh-show-mode font-lock-maximum-size)
-                                (assoc t font-lock-maximum-size)))))))
-    (or (not (numberp max)) (>= (/ max 8) (buffer-size)))))
+  (>= 64000 (buffer-size)))
 
 
 
@@ -1511,7 +1502,7 @@ a prefix argument NOCONFIRM."
     (after-find-file nil nil nil nil t)))
 
 ;; Shush compiler.
-(defvar mh-identity-pgg-default-user-id)
+(defvar mh-identity-gpg-default-user-id)
 
 ;;;###mh-autoload
 (defun mh-mml-secure-message-encrypt (method)
@@ -1522,7 +1513,7 @@ message. Use the command \\[mh-mml-unsecure-message] to 
remove
 this tag. Use a prefix argument METHOD to be prompted for one of
 the possible security methods (see `mh-mml-method-default')."
   (interactive (list (mh-mml-query-cryptographic-method)))
-  (mh-secure-message method "encrypt" mh-identity-pgg-default-user-id))
+  (mh-secure-message method "encrypt" mh-identity-gpg-default-user-id))
 
 ;;;###mh-autoload
 (defun mh-mml-secure-message-sign (method)
@@ -1533,7 +1524,7 @@ message. Use the command \\[mh-mml-unsecure-message] to 
remove
 this tag. Use a prefix argument METHOD to be prompted for one of
 the possible security methods (see `mh-mml-method-default')."
   (interactive (list (mh-mml-query-cryptographic-method)))
-  (mh-secure-message method "sign" mh-identity-pgg-default-user-id))
+  (mh-secure-message method "sign" mh-identity-gpg-default-user-id))
 
 ;;;###mh-autoload
 (defun mh-mml-secure-message-signencrypt (method)
@@ -1544,7 +1535,7 @@ message. Use the command \\[mh-mml-unsecure-message] to 
remove
 this tag. Use a prefix argument METHOD to be prompted for one of
 the possible security methods (see `mh-mml-method-default')."
   (interactive (list (mh-mml-query-cryptographic-method)))
-  (mh-secure-message method "signencrypt" mh-identity-pgg-default-user-id))
+  (mh-secure-message method "signencrypt" mh-identity-gpg-default-user-id))
 
 (defvar mh-mml-cryptographic-method-history ())
 
@@ -1578,9 +1569,9 @@ IDENTITY is optionally the default-user-id to use."
         (save-excursion
           (goto-char (point-min))
           (mh-goto-header-end 1)
-          (if mh-identity-pgg-default-user-id
+          (if mh-identity-gpg-default-user-id
               (mml-insert-tag 'secure 'method method 'mode mode
-                              'sender mh-identity-pgg-default-user-id)
+                              'sender mh-identity-gpg-default-user-id)
             (mml-insert-tag 'secure 'method method 'mode mode)))))))
 
 ;;;###mh-autoload
@@ -1797,7 +1788,6 @@ initialized. Always use the command 
`mh-have-file-command'.")
 (provide 'mh-mime)
 
 ;; Local Variables:
-;; indent-tabs-mode: nil
 ;; sentence-end-double-space: nil
 ;; End:
 
diff --git a/lisp/mh-e/mh-print.el b/lisp/mh-e/mh-print.el
index 2eec8d9160..78906b68ad 100644
--- a/lisp/mh-e/mh-print.el
+++ b/lisp/mh-e/mh-print.el
@@ -242,7 +242,6 @@ Consider using \\[mh-ps-print-msg] instead."
 (provide 'mh-print)
 
 ;; Local Variables:
-;; indent-tabs-mode: nil
 ;; sentence-end-double-space: nil
 ;; End:
 
diff --git a/lisp/mh-e/mh-scan.el b/lisp/mh-e/mh-scan.el
index 06381a2e0e..4b4c594286 100644
--- a/lisp/mh-e/mh-scan.el
+++ b/lisp/mh-e/mh-scan.el
@@ -526,7 +526,6 @@ comes after that."
 (provide 'mh-scan)
 
 ;; Local Variables:
-;; indent-tabs-mode: nil
 ;; sentence-end-double-space: nil
 ;; End:
 
diff --git a/lisp/mh-e/mh-search.el b/lisp/mh-e/mh-search.el
index c5519eba0a..058ea4499f 100644
--- a/lisp/mh-e/mh-search.el
+++ b/lisp/mh-e/mh-search.el
@@ -1411,7 +1411,7 @@ being the list of messages originally from that folder."
     (when cur-msg (mh-goto-msg cur-msg t t))
     (set-buffer-modified-p old-buffer-modified-flag)))
 
-(eval-and-compile (require 'which-func nil t))
+(require 'which-func)
 
 ;;;###mh-autoload
 (defun mh-index-create-imenu-index ()
@@ -1932,7 +1932,6 @@ folder buffer."
 (provide 'mh-search)
 
 ;; Local Variables:
-;; indent-tabs-mode: nil
 ;; sentence-end-double-space: nil
 ;; End:
 
diff --git a/lisp/mh-e/mh-seq.el b/lisp/mh-e/mh-seq.el
index a95c7c03d1..c82a1a53ba 100644
--- a/lisp/mh-e/mh-seq.el
+++ b/lisp/mh-e/mh-seq.el
@@ -802,7 +802,7 @@ that note messages to be refiled."
   "Return a list of message numbers from point to the end of the line.
 Expands ranges into set of individual numbers."
   (let ((msgs ())
-        (end-of-line (point-at-eol))
+        (end-of-line (line-end-position))
         num)
     (while (re-search-forward "[0-9]+" end-of-line t)
       (setq num (string-to-number (buffer-substring (match-beginning 0)
@@ -996,7 +996,6 @@ removed."
 (provide 'mh-seq)
 
 ;; Local Variables:
-;; indent-tabs-mode: nil
 ;; sentence-end-double-space: nil
 ;; End:
 
diff --git a/lisp/mh-e/mh-show.el b/lisp/mh-e/mh-show.el
index cc76b8d7e6..1731d75738 100644
--- a/lisp/mh-e/mh-show.el
+++ b/lisp/mh-e/mh-show.el
@@ -894,7 +894,6 @@ See also `mh-folder-mode'.
 (provide 'mh-show)
 
 ;; Local Variables:
-;; indent-tabs-mode: nil
 ;; sentence-end-double-space: nil
 ;; End:
 
diff --git a/lisp/mh-e/mh-speed.el b/lisp/mh-e/mh-speed.el
index a7e9c9bd67..3babea7612 100644
--- a/lisp/mh-e/mh-speed.el
+++ b/lisp/mh-e/mh-speed.el
@@ -568,7 +568,6 @@ The function invalidates the latest ancestor that is 
present."
 (provide 'mh-speed)
 
 ;; Local Variables:
-;; indent-tabs-mode: nil
 ;; sentence-end-double-space: nil
 ;; End:
 
diff --git a/lisp/mh-e/mh-thread.el b/lisp/mh-e/mh-thread.el
index 139e9b74cb..2358ba4bc6 100644
--- a/lisp/mh-e/mh-thread.el
+++ b/lisp/mh-e/mh-thread.el
@@ -865,7 +865,6 @@ This function can only be used the folder is threaded."
 (provide 'mh-thread)
 
 ;; Local Variables:
-;; indent-tabs-mode: nil
 ;; sentence-end-double-space: nil
 ;; End:
 
diff --git a/lisp/mh-e/mh-tool-bar.el b/lisp/mh-e/mh-tool-bar.el
index 17df075cfa..933b3b633a 100644
--- a/lisp/mh-e/mh-tool-bar.el
+++ b/lisp/mh-e/mh-tool-bar.el
@@ -376,7 +376,6 @@ This button runs `mh-widen'"))
 (provide 'mh-tool-bar)
 
 ;; Local Variables:
-;; indent-tabs-mode: nil
 ;; sentence-end-double-space: nil
 ;; End:
 
diff --git a/lisp/mh-e/mh-utils.el b/lisp/mh-e/mh-utils.el
index d7a92be5b5..b2c79350c4 100644
--- a/lisp/mh-e/mh-utils.el
+++ b/lisp/mh-e/mh-utils.el
@@ -29,6 +29,7 @@
 (require 'mh-e)
 
 (require 'font-lock)
+(require 'mailabbrev)
 
 ;;; CL Replacements
 
@@ -58,13 +59,6 @@ used in lieu of `search' in the CL package."
           (point))
       (set-syntax-table syntax-table))))
 
-;;;###mh-autoload
-(defun mh-colors-available-p ()
-  "Check if colors are available in the Emacs being used."
-  ;; FIXME: Can this be replaced with `display-color-p'?
-  (let ((color-cells (display-color-cells)))
-    (and (numberp color-cells) (>= color-cells 8))))
-
 ;;;###mh-autoload
 (defun mh-colors-in-use-p ()
   "Check if colors are being used in the folder buffer."
@@ -444,10 +438,8 @@ no effect."
         (setq folder (format "%s/%s/" mh-current-folder-name
                              (substring folder 1))))
       ;; XXX: Purge empty strings from the list that split-string
-      ;; returns. In XEmacs, (split-string "+foo/" "/") returns
-      ;; ("+foo" "") while in GNU Emacs it returns ("+foo"). In the
-      ;; code it is assumed that the components list has no empty
-      ;; strings.
+      ;; returns. In the code it is assumed that the components list
+      ;; has no empty strings.
       (let ((components (delete "" (split-string folder "/")))
             (result ()))
         ;; Remove .. and . from the pathname.
@@ -1006,10 +998,12 @@ If the current line is too long truncate a part of it as 
well."
     (goto-char (point-min))
     (re-search-forward mh-signature-separator-regexp nil t)))
 
+;;;###mh-autoload
+(define-obsolete-function-alias 'mh-colors-available-p #'display-color-p 
"29.1")
+
 (provide 'mh-utils)
 
 ;; Local Variables:
-;; indent-tabs-mode: nil
 ;; sentence-end-double-space: nil
 ;; End:
 
diff --git a/lisp/mh-e/mh-xface.el b/lisp/mh-e/mh-xface.el
index b144c58d69..d6ecd83655 100644
--- a/lisp/mh-e/mh-xface.el
+++ b/lisp/mh-e/mh-xface.el
@@ -414,7 +414,6 @@ The argument CHANGE is ignored."
 (provide 'mh-xface)
 
 ;; Local Variables:
-;; indent-tabs-mode: nil
 ;; sentence-end-double-space: nil
 ;; End:
 
diff --git a/lisp/midnight.el b/lisp/midnight.el
index 3e309a5c88..60d9b565ef 100644
--- a/lisp/midnight.el
+++ b/lisp/midnight.el
@@ -67,14 +67,14 @@ The autokilling is done by `clean-buffer-list' when it is 
in `midnight-hook'.
 Currently displayed and/or modified (unsaved) buffers, as well as buffers
 matching `clean-buffer-list-kill-never-buffer-names' and
 `clean-buffer-list-kill-never-regexps' are excluded."
-  :type 'integer)
+  :type 'natnum)
 
 (defcustom clean-buffer-list-delay-special 3600
   "The number of seconds before some buffers become eligible for autokilling.
 Buffers matched by `clean-buffer-list-kill-regexps' and
 `clean-buffer-list-kill-buffer-names' are killed if they were last
 displayed more than this many seconds ago."
-  :type 'integer)
+  :type 'natnum)
 
 (defcustom clean-buffer-list-kill-regexps '("\\`\\*Man ")
   "List of regexps saying which buffers will be killed at midnight.
diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el
index 23251a5474..3daab8a1e8 100644
--- a/lisp/minibuffer.el
+++ b/lisp/minibuffer.el
@@ -634,9 +634,6 @@ for use at QPOS."
       (let ((qstr (funcall qfun completion)))
        (cons qstr (length qstr))))))
 
-(defun completion--string-equal-p (s1 s2)
-  (eq t (compare-strings s1 nil nil s2 nil nil 'ignore-case)))
-
 (defun completion--twq-all (string ustring completions boundary
                                    _unquote requote)
   (when completions
@@ -650,7 +647,7 @@ for use at QPOS."
          (qfullprefix (substring string 0 qfullpos))
         ;; FIXME: This assertion can be wrong, e.g. in Cygwin, where
         ;; (unquote "c:\bin") => "/usr/bin" but (unquote "c:\") => "/".
-         ;;(cl-assert (completion--string-equal-p
+         ;;(cl-assert (string-equal-ignore-case
          ;;            (funcall unquote qfullprefix)
          ;;            (concat (substring ustring 0 boundary) prefix))
          ;;           t))
@@ -688,7 +685,7 @@ for use at QPOS."
                            (let* ((rest (substring completion
                                                    0 (length prefix)))
                                   (qrest (funcall qfun rest)))
-                             (if (completion--string-equal-p qprefix qrest)
+                             (if (string-equal-ignore-case qprefix qrest)
                                  (propertize qrest 'face
                                              'completions-common-part)
                                qprefix))))
@@ -696,7 +693,7 @@ for use at QPOS."
                   ;; FIXME: Similarly here, Cygwin's mapping trips this
                   ;; assertion.
                    ;;(cl-assert
-                   ;; (completion--string-equal-p
+                   ;; (string-equal-ignore-case
                   ;;  (funcall unquote
                   ;;           (concat (substring string 0 qboundary)
                   ;;                   qcompletion))
@@ -1309,10 +1306,8 @@ when the buffer's text is already an exact match."
       ;; for appearance, the string is rewritten if the case changes.
       (let* ((comp-pos (cdr comp))
              (completion (car comp))
-             (completed (not (eq t (compare-strings completion nil nil
-                                                    string nil nil t))))
-             (unchanged (eq t (compare-strings completion nil nil
-                                               string nil nil nil))))
+             (completed (not (string-equal-ignore-case completion string)))
+             (unchanged (string-equal completion string)))
         (if unchanged
            (goto-char end)
           ;; Insert in minibuffer the chars we got.
@@ -1677,8 +1672,8 @@ DONT-CYCLE tells the function not to setup cycling."
                    map)))))))))
 
 (defvar minibuffer-confirm-exit-commands
-  '(completion-at-point minibuffer-complete
-    minibuffer-complete-word PC-complete PC-complete-word)
+  '( completion-at-point minibuffer-complete
+     minibuffer-complete-word)
   "List of commands which cause an immediately following
 `minibuffer-complete-and-exit' to ask for extra confirmation.")
 
@@ -2135,7 +2130,7 @@ and with BASE-SIZE appended as the last element."
         (lambda (elem)
           (let ((str
                  ;; Don't modify the string itself, but a copy, since the
-                 ;; the string may be read-only or used for other purposes.
+                 ;; string may be read-only or used for other purposes.
                  ;; Furthermore, since `completions' may come from
                  ;; display-completion-list, `elem' may be a list.
                  (if (consp elem)
@@ -2225,25 +2220,6 @@ These include:
      `exact'    - text is a valid completion but may be further
                   completed.")
 
-(defvar completion-annotate-function
-  nil
-  ;; Note: there's a lot of scope as for when to add annotations and
-  ;; what annotations to add.  E.g. completing-help.el allowed adding
-  ;; the first line of docstrings to M-x completion.  But there's
-  ;; a tension, since such annotations, while useful at times, can
-  ;; actually drown the useful information.
-  ;; So completion-annotate-function should be used parsimoniously, or
-  ;; else only used upon a user's request (e.g. we could add a command
-  ;; to completion-list-mode to add annotations to the current
-  ;; completions).
-  "Function to add annotations in the *Completions* buffer.
-The function takes a completion and should either return nil, or a string that
-will be displayed next to the completion.  The function can access the
-completion table and predicates via `minibuffer-completion-table' and related
-variables.")
-(make-obsolete-variable 'completion-annotate-function
-                        'completion-extra-properties "24.1")
-
 (defun completion--done (string &optional finished message)
   (let* ((exit-fun (plist-get completion-extra-properties :exit-function))
          (pre-msg (and exit-fun (current-message))))
@@ -2314,8 +2290,7 @@ variables.")
                                            minibuffer-completion-predicate))
              (ann-fun (or (completion-metadata-get all-md 'annotation-function)
                           (plist-get completion-extra-properties
-                                     :annotation-function)
-                          completion-annotate-function))
+                                     :annotation-function)))
              (aff-fun (or (completion-metadata-get all-md 'affixation-function)
                           (plist-get completion-extra-properties
                                      :affixation-function)))
@@ -2789,9 +2764,6 @@ Gets combined either with 
`minibuffer-local-completion-map' or
 with `minibuffer-local-must-match-map'."
   "SPC" nil)
 
-(defvar minibuffer-local-filename-must-match-map (make-sparse-keymap))
-(make-obsolete-variable 'minibuffer-local-filename-must-match-map nil "24.1")
-
 (defvar-keymap minibuffer-local-ns-map
   :doc "Local keymap for the minibuffer when spaces are not allowed."
   :parent minibuffer-local-map
@@ -3090,7 +3062,8 @@ such as making the current buffer visit no file in the 
case of
   :type 'boolean)
 
 (defcustom minibuffer-beginning-of-buffer-movement nil
-  "Control how the `M-<' command in the minibuffer behaves.
+  "Control how the \\<minibuffer-local-map>\\[minibuffer-beginning-of-buffer] \
+command in the minibuffer behaves.
 If non-nil, the command will go to the end of the prompt (if
 point is after the end of the prompt).  If nil, it will behave
 like the `beginning-of-buffer' command."
@@ -3159,8 +3132,9 @@ Fourth arg MUSTMATCH can take the following values:
   input, but she needs to confirm her choice if she called
   `minibuffer-complete' right before `minibuffer-complete-and-exit'
   and the input is not an existing file.
-- a function, which will be called with the input as the argument.
-  If it returns a non-nil value, the minibuffer is exited with that value.
+- a function, which will be called with the input as the
+  argument.  If the function returns a non-nil value, the
+  minibuffer is exited with that argument as the value.
 - anything else behaves like t except that typing RET does not exit if it
   does non-null completion.
 
@@ -4428,27 +4402,41 @@ minibuffer, but don't quit the completions window."
 Like `minibuffer-complete' but completes on the history items
 instead of the default completion table."
   (interactive)
-  (let ((completions-sort nil)
-        (history (mapcar (lambda (h)
-                           ;; Support e.g. `C-x ESC ESC TAB' as
-                           ;; a replacement of `list-command-history'
-                           (if (consp h) (format "%S" h) h))
-                         (symbol-value minibuffer-history-variable))))
-    (completion-in-region (minibuffer--completion-prompt-end) (point-max)
-                          history nil)))
+  (let* ((history (symbol-value minibuffer-history-variable))
+         (completions
+          (if (listp history)
+              ;; Support e.g. `C-x ESC ESC TAB' as
+              ;; a replacement of `list-command-history'
+              (mapcar (lambda (h)
+                        (if (stringp h) h (format "%S" h)))
+                      history)
+            (user-error "No history available"))))
+    ;; FIXME: Can we make it work for CRM?
+    (completion-in-region
+     (minibuffer--completion-prompt-end) (point-max)
+     (lambda (string pred action)
+       (if (eq action 'metadata)
+           '(metadata (display-sort-function . identity)
+                      (cycle-sort-function . identity))
+         (complete-with-action action completions string pred))))))
 
 (defun minibuffer-complete-defaults ()
   "Complete minibuffer defaults as far as possible.
 Like `minibuffer-complete' but completes on the default items
 instead of the completion table."
   (interactive)
-  (let ((completions-sort nil))
-    (when (and (not minibuffer-default-add-done)
-               (functionp minibuffer-default-add-function))
-      (setq minibuffer-default-add-done t
-            minibuffer-default (funcall minibuffer-default-add-function)))
-    (completion-in-region (minibuffer--completion-prompt-end) (point-max)
-                          (ensure-list minibuffer-default) nil)))
+  (when (and (not minibuffer-default-add-done)
+             (functionp minibuffer-default-add-function))
+    (setq minibuffer-default-add-done t
+          minibuffer-default (funcall minibuffer-default-add-function)))
+  (let ((completions (ensure-list minibuffer-default)))
+    (completion-in-region
+     (minibuffer--completion-prompt-end) (point-max)
+     (lambda (string pred action)
+       (if (eq action 'metadata)
+           '(metadata (display-sort-function . identity)
+                      (cycle-sort-function . identity))
+         (complete-with-action action completions string pred))))))
 
 (define-key minibuffer-local-map [?\C-x up] 'minibuffer-complete-history)
 (define-key minibuffer-local-map [?\C-x down] 'minibuffer-complete-defaults)
diff --git a/lisp/misc.el b/lisp/misc.el
index 0bb8ee6c7b..a53571f463 100644
--- a/lisp/misc.el
+++ b/lisp/misc.el
@@ -33,7 +33,9 @@
   "Copy characters from previous nonblank line, starting just above point.
 Copy ARG characters, but not past the end of that line.
 If no argument given, copy the entire rest of the line.
-The characters copied are inserted in the buffer before point."
+The characters copied are inserted in the buffer before point.
+
+Also see the `duplicate-line' command."
   (interactive "P")
   (let ((cc (current-column))
        n
@@ -61,6 +63,59 @@ The characters copied are inserted in the buffer before 
point."
                                 (+ n (point)))))))
     (insert string)))
 
+;;;###autoload
+(defun duplicate-line (&optional n)
+  "Duplicate the current line N times.
+Interactively, N is the prefix numeric argument, and defaults to 1.
+Also see the `copy-from-above-command' command."
+  (interactive "p")
+  (unless n
+    (setq n 1))
+  (let ((line (buffer-substring (line-beginning-position) 
(line-end-position))))
+    (save-excursion
+      (forward-line 1)
+      (unless (bolp)
+        (insert "\n"))
+      (dotimes (_ n)
+        (insert line "\n")))))
+
+(declare-function rectangle--duplicate-right "rect" (n))
+
+;; `duplicate-dwim' preserves an active region and changes the buffer
+;; outside of it: disregard the region when immediately undoing the
+;; actions of this command.
+(put 'duplicate-dwim 'undo-inhibit-region t)
+
+;;;###autoload
+(defun duplicate-dwim (&optional n)
+  "Duplicate the current line or region N times.
+If the region is inactive, duplicate the current line (like `duplicate-line').
+Otherwise, duplicate the region, which remains active afterwards.
+If the region is rectangular, duplicate on its right-hand side.
+Interactively, N is the prefix numeric argument, and defaults to 1."
+  (interactive "p")
+  (unless n
+    (setq n 1))
+  (cond
+   ;; Duplicate rectangle.
+   ((bound-and-true-p rectangle-mark-mode)
+    (rectangle--duplicate-right n)
+    (setq deactivate-mark nil))
+
+   ;; Duplicate (contiguous) region.
+   ((use-region-p)
+    (let* ((beg (region-beginning))
+           (end (region-end))
+           (text (buffer-substring beg end)))
+      (save-excursion
+        (goto-char end)
+        (dotimes (_ n)
+          (insert text))))
+    (setq deactivate-mark nil))
+
+   ;; Duplicate line.
+   (t (duplicate-line n))))
+
 ;; Variation of `zap-to-char'.
 
 ;;;###autoload
@@ -133,7 +188,7 @@ ripples outward, changing the flow of the eddy currents in 
the
 upper atmosphere.  These cause momentary pockets of higher-pressure
 air to form, which act as lenses that deflect incoming cosmic rays,
 focusing them to strike the drive platter and flip the desired bit.
-You can type `M-x butterfly C-M-c' to run it.  This is a permuted
+You can type \\`M-x butterfly C-M-c' to run it.  This is a permuted
 variation of `C-x M-c M-butterfly' from url `https://xkcd.com/378/'."
   (interactive)
   (if (yes-or-no-p "Do you really want to unleash the powers of the butterfly? 
")
diff --git a/lisp/mouse.el b/lisp/mouse.el
index 14cb20c234..e38a4f8a71 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -1,6 +1,6 @@
 ;;; mouse.el --- window system-independent mouse support  -*- lexical-binding: 
t -*-
 
-;; Copyright (C) 1993-1995, 1999-2022 Free Software Foundation, Inc.
+;; Copyright (C) 1993-2022 Free Software Foundation, Inc.
 
 ;; Maintainer: emacs-devel@gnu.org
 ;; Keywords: hardware, mouse
@@ -31,8 +31,6 @@
 
 (eval-when-compile (require 'rect))
 
-;;; Utility functions.
-
 ;; Indent track-mouse like progn.
 (put 'track-mouse 'lisp-indent-function 0)
 
@@ -655,7 +653,13 @@ This command must be bound to a mouse click."
   (interactive "e")
   (unless (one-window-p t)
     (mouse-minibuffer-check click)
-    (delete-window (posn-window (event-start click)))))
+    ;; Only delete the window if the user hasn't moved point out of
+    ;; the mode line before releasing the button.
+    (when (and (eq (posn-area (event-end click))
+                   'mode-line)
+               (eq (posn-window (event-end click))
+                   (posn-window (event-start click))))
+      (delete-window (posn-window (event-start click))))))
 
 (defun mouse-select-window (click)
   "Select the window clicked on; don't move point."
@@ -681,10 +685,13 @@ This command must be bound to a mouse click."
     (switch-to-buffer buf)
     (delete-window window)))
 
-(defun mouse-delete-other-windows ()
+(defun mouse-delete-other-windows (click)
   "Delete all windows except the one you click on."
-  (interactive "@")
-  (delete-other-windows))
+  (interactive "e")
+  (when (and (eq (posn-area (event-end click)) 'mode-line)
+             (eq (posn-window (event-start click))
+                 (posn-window (event-end click))))
+    (delete-other-windows (posn-window (event-start click)))))
 
 (defun mouse-split-window-vertically (click)
   "Select Emacs window mouse is on, then split it vertically in half.
@@ -862,6 +869,9 @@ must be one of the symbols `header', `mode', or `vertical'."
               map)
             t (lambda () (setq track-mouse old-track-mouse)))))))
 
+;; In no-X builds, dnd.el isn't preloaded.
+(autoload 'dnd-begin-file-drag "dnd")
+
 (defun mouse-drag-mode-line (start-event)
   "Change the height of a window by dragging on its mode line.
 START-EVENT is the starting mouse event of the drag action.
@@ -1191,7 +1201,7 @@ frame with the mouse."
                            (<= (- right parent-right) snap-width)
                            snap-x (<= (- last-x snap-x) snap-width))
                       ;; Stay snapped when the mouse moved rightward but
-                      ;; not more more than `snap-width' pixels from the
+                      ;; not more than `snap-width' pixels from the
                       ;; time FRAME snapped.
                       (setq left (- parent-right native-width)))
                      (t
@@ -1213,7 +1223,7 @@ frame with the mouse."
                            (<= (- parent-top top) snap-width)
                            snap-y (<= (- snap-y last-y) snap-width))
                       ;; Stay snapped when the mouse moved upward but
-                      ;; not more more than `snap-width' pixels from the
+                      ;; not more than `snap-width' pixels from the
                       ;; time FRAME snapped.
                       (setq top parent-top))
                      (t
@@ -1235,7 +1245,7 @@ frame with the mouse."
                            (<= (- bottom parent-bottom) snap-width)
                            snap-y (<= (- last-y snap-y) snap-width))
                       ;; Stay snapped when the mouse moved downward but
-                      ;; not more more than `snap-width' pixels from the
+                      ;; not more than `snap-width' pixels from the
                       ;; time FRAME snapped.
                       (setq top (- parent-bottom native-height)))
                      (t
@@ -1439,7 +1449,8 @@ command alters the kill ring or not."
         ;; Don't set this-command to `kill-region', so a following
         ;; C-w won't double the text in the kill ring.  Ignore
         ;; `last-command' so we don't append to a preceding kill.
-        (let (this-command last-command deactivate-mark)
+        (let ((last-command last-command)
+               this-command deactivate-mark)
           (copy-region-as-kill beg end)))
     (if (numberp beg) (goto-char beg))
     ;; On a text terminal, bounce the cursor.
@@ -1542,6 +1553,7 @@ is dragged over to."
       (mouse-drag-and-drop-region start-event)
     ;; Give temporary modes such as isearch a chance to turn off.
     (run-hooks 'mouse-leave-buffer-hook)
+    (ignore-preserving-kill-region)
     (mouse-drag-track start-event)))
 
 ;; Inhibit the region-confinement when undoing mouse-drag-region
@@ -1751,7 +1763,8 @@ The region will be defined with mark and point."
                                             nil start-point))
                         ((>= mouse-row bottom)
                          (mouse-scroll-subr start-window (1+ (- mouse-row 
bottom))
-                                            nil start-point))))))))
+                                            nil start-point))))))
+                 (ignore-preserving-kill-region)))
              map)
            t (lambda ()
                (funcall cleanup)
diff --git a/lisp/mpc.el b/lisp/mpc.el
index dc61ce78bd..ba95308bf6 100644
--- a/lisp/mpc.el
+++ b/lisp/mpc.el
@@ -1126,32 +1126,30 @@ If PLAYLIST is t or nil or missing, use the main 
playlist."
 
 ;;; The actual UI code ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(defvar mpc-mode-map
-  (let ((map (make-sparse-keymap)))
-    ;; (define-key map "\e"          #'mpc-stop)
-    (define-key map "q"              #'mpc-quit)
-    (define-key map "\r"             #'mpc-select)
-    (define-key map [(shift return)] #'mpc-select-toggle)
-    (define-key map [mouse-2]        #'mpc-select)
-    (define-key map [S-mouse-2]      #'mpc-select-extend)
-    (define-key map [C-mouse-2]      #'mpc-select-toggle)
-    (define-key map [drag-mouse-2]   #'mpc-drag-n-drop)
-    ;; We use `always' because a binding to t is like a binding to nil.
-    (define-key map [follow-link] :always)
-    ;; But follow-link doesn't apply blindly to header-line and
-    ;; mode-line clicks.
-    (define-key map [header-line follow-link] #'ignore)
-    (define-key map [mode-line follow-link] #'ignore)
-    ;; Doesn't work because the first click changes the buffer, so the second
-    ;; is applied elsewhere :-(
-    ;; (define-key map [(double mouse-2)] #'mpc-play-at-point)
-    (define-key map "p" #'mpc-pause)
-    (define-key map "s" #'mpc-toggle-play)
-    (define-key map ">" #'mpc-next)
-    (define-key map "<" #'mpc-prev)
-    (define-key map "g" #'mpc-seek-current)
-    (define-key map "o" #'mpc-goto-playing-song)
-    map))
+(defvar-keymap mpc-mode-map
+  ;; "ESC"                         #'mpc-stop
+  "q"                           #'mpc-quit
+  "RET"                         #'mpc-select
+  "S-<return>"                  #'mpc-select-toggle
+  "<mouse-2>"                   #'mpc-select
+  "S-<mouse-2>"                 #'mpc-select-extend
+  "C-<mouse-2>"                 #'mpc-select-toggle
+  "<drag-mouse-2>"              #'mpc-drag-n-drop
+  ;; We use `always' because a binding to t is like a binding to nil.
+  "<follow-link>"               :always
+  ;; But follow-link doesn't apply blindly to header-line and
+  ;; mode-line clicks.
+  "<header-line> <follow-link>" #'ignore
+  "<mode-line> <follow-link>"   #'ignore
+  ;; Doesn't work because the first click changes the buffer, so the second
+  ;; is applied elsewhere :-(
+  ;; "<double-mouse-2>"            #'mpc-play-at-point
+  "p"                           #'mpc-pause
+  "s"                           #'mpc-toggle-play
+  ">"                           #'mpc-next
+  "<"                           #'mpc-prev
+  "g"                           #'mpc-seek-current
+  "o"                           #'mpc-goto-playing-song)
 
 (easy-menu-define mpc-mode-menu mpc-mode-map
   "Menu for MPC mode."
@@ -1571,8 +1569,9 @@ when constructing the set of constraints."
         (mpc-tagbrowser-refresh)
         buf))))
 
-(defvar tag-browser-tagtypes
-  (lazy-completion-table tag-browser-tagtypes
+(define-obsolete-variable-alias 'tag-browser-tagtypes 
'mpc-tag-browser-tagtypes "29.1")
+(defvar mpc-tag-browser-tagtypes
+  (lazy-completion-table mpc-tag-browser-tagtypes
                          (lambda ()
                            (append '("Playlist" "Directory")
                                    (mpc-cmd-tagtypes)))))
@@ -1583,7 +1582,7 @@ when constructing the set of constraints."
    (list
     (let ((completion-ignore-case t))
       (intern
-       (completing-read "Tag: " tag-browser-tagtypes nil 'require-match)))))
+       (completing-read "Tag: " mpc-tag-browser-tagtypes nil 
'require-match)))))
   (let* ((newbuf (mpc-tagbrowser-buf tag))
          (win (get-buffer-window newbuf 0)))
     (if win (select-window win)
@@ -1748,11 +1747,9 @@ Return non-nil if a selection was deactivated."
 ;;   present (because we're in the non-selected part and the parent is
 ;;   in the selected part).
 
-(defvar mpc-tagbrowser-dir-mode-map
-  (let ((map (make-sparse-keymap)))
-    (set-keymap-parent map mpc-tagbrowser-mode-map)
-    (define-key map [?\M-\C-m] #'mpc-tagbrowser-dir-toggle)
-    map))
+(defvar-keymap mpc-tagbrowser-dir-mode-map
+  :parent mpc-tagbrowser-mode-map
+  "M-RET" #'mpc-tagbrowser-dir-toggle)
 
 ;; (defvar mpc-tagbrowser-dir-keywords
 ;;   '(mpc-tagbrowser-dir-hide-prefix))
@@ -1859,17 +1856,15 @@ A value of t means the main playlist.")
 
 ;;; Volume management ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(defvar mpc-volume-map
-  (let ((map (make-sparse-keymap)))
-    ;; Bind the up-events rather than the down-event, so the
-    ;; `message' isn't canceled by the subsequent up-event binding.
-    (define-key map [down-mouse-1]             #'ignore)
-    (define-key map [mouse-1]                  #'mpc-volume-mouse-set)
-    (define-key map [header-line mouse-1]      #'mpc-volume-mouse-set)
-    (define-key map [header-line down-mouse-1] #'ignore)
-    (define-key map [mode-line mouse-1]        #'mpc-volume-mouse-set)
-    (define-key map [mode-line down-mouse-1]   #'ignore)
-    map))
+(defvar-keymap mpc-volume-map
+  ;; Bind the up-events rather than the down-event, so the
+  ;; `message' isn't canceled by the subsequent up-event binding.
+  "<down-mouse-1>"               #'ignore
+  "<mouse-1>"                    #'mpc-volume-mouse-set
+  "<header-line> <mouse-1>"      #'mpc-volume-mouse-set
+  "<header-line> <down-mouse-1>" #'ignore
+  "<mode-line> <mouse-1>"        #'mpc-volume-mouse-set
+  "<mode-line> <down-mouse-1>"   #'ignore)
 
 (defvar mpc-volume nil) (put 'mpc-volume 'risky-local-variable t)
 
@@ -1937,10 +1932,8 @@ A value of t means the main playlist.")
 
 (defvar mpc-previous-window-config nil)
 
-(defvar mpc-songs-mode-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map [remap mpc-select] #'mpc-songs-jump-to)
-    map))
+(defvar-keymap mpc-songs-mode-map
+  "<remap> <mpc-select>" #'mpc-songs-jump-to)
 
 (defvar mpc-songpointer-set-visible nil)
 
diff --git a/lisp/msb.el b/lisp/msb.el
index 6e1d03ac27..6843df2edc 100644
--- a/lisp/msb.el
+++ b/lisp/msb.el
@@ -103,7 +103,7 @@
     ((eq major-mode 'Man-mode)
      4090
      "Manuals (%d)")
-    ((eq major-mode 'w3-mode)
+    ((eq major-mode 'eww-mode)
      4020
      "WWW (%d)")
     ((or (memq major-mode
@@ -154,7 +154,7 @@
     ((eq major-mode 'Man-mode)
      5030
      "Manuals (%d)")
-    ((eq major-mode 'w3-mode)
+    ((eq major-mode 'eww-mode)
      5020
      "WWW (%d)")
     ((or (memq major-mode
@@ -299,7 +299,7 @@ If the value is not a number, then the value 10 is used."
 (defcustom msb-display-most-recently-used 15
   "How many buffers should be in the most-recently-used menu.
 No buffers at all if less than 1 or nil (or any non-number)."
-  :type 'integer
+  :type 'natnum
   :set #'msb-custom-set)
 
 (defcustom msb-most-recently-used-title "Most recently used (%d)"
@@ -353,9 +353,6 @@ This is instead of the groups in `msb-menu-cond'."
   :type 'boolean
   :set #'msb-custom-set)
 
-(define-obsolete-variable-alias 'msb-after-load-hooks
-  'msb-after-load-hook "24.1")
-
 (defcustom msb-after-load-hook nil
   "Hook run after the msb package has been loaded."
   :type 'hook
diff --git a/lisp/mwheel.el b/lisp/mwheel.el
index be493b3653..ba5255fc07 100644
--- a/lisp/mwheel.el
+++ b/lisp/mwheel.el
@@ -1,6 +1,7 @@
 ;;; mwheel.el --- Mouse wheel support  -*- lexical-binding:t -*-
 
-;; Copyright (C) 1998, 2000-2022 Free Software Foundation, Inc.
+;; Copyright (C) 1998-2022 Free Software Foundation, Inc.
+
 ;; Keywords: mouse
 ;; Package: emacs
 
@@ -22,7 +23,7 @@
 ;;; Commentary:
 
 ;; This enables the use of the mouse wheel (or scroll wheel) in Emacs.
-;; Under X11/X.Org, the wheel events are sent as button4/button5
+;; Under X11/X.Org, the wheel events are sent as mouse-4/mouse-5
 ;; events.
 
 ;; Mouse wheel support is already enabled by default on most graphical
@@ -32,7 +33,7 @@
 
 ;; Implementation note:
 ;;
-;; I for one would prefer some way of converting the button4/button5
+;; I for one would prefer some way of converting the mouse-4/mouse-5
 ;; events into different event types, like 'mwheel-up' or
 ;; 'mwheel-down', but I cannot find a way to do this very easily (or
 ;; portably), so for now I just live with it.
@@ -40,6 +41,7 @@
 (require 'timer)
 
 (defvar mouse-wheel-mode)
+
 (defvar mouse-wheel--installed-bindings-alist nil
   "Alist of all installed mouse wheel key bindings.")
 
@@ -112,7 +114,10 @@ set to the event sent when clicking on the mouse wheel 
button."
   :type 'number)
 
 (defcustom mouse-wheel-scroll-amount
-  '(1 ((shift) . hscroll) ((meta) . nil) ((control) . text-scale))
+  '(1 ((shift) . hscroll)
+      ((meta) . nil)
+      ((control meta) . global-text-scale)
+      ((control) . text-scale))
   "Amount to scroll windows by when spinning the mouse wheel.
 This is an alist mapping the modifier key to the amount to scroll when
 the wheel is moved with the modifier key depressed.
@@ -127,9 +132,11 @@ less than a full screen.
 If AMOUNT is the symbol `hscroll', this means that with MODIFIER,
 the mouse wheel will scroll horizontally instead of vertically.
 
-If AMOUNT is the symbol `text-scale', this means that with
-MODIFIER, the mouse wheel will change the face height instead of
-scrolling."
+If AMOUNT is the symbol `text-scale' or `global-text-scale', this
+means that with MODIFIER, the mouse wheel will change the font size
+instead of scrolling (by adjusting the font height of the default
+face, either locally in the buffer or globally).  For more
+information, see `text-scale-adjust' and `global-text-scale-adjust'."
   :group 'mouse
   :type '(cons
          (choice :tag "Normal"
@@ -154,7 +161,8 @@ scrolling."
                     (integer :tag "Scroll specific # of lines")
                     (float :tag "Scroll fraction of window")
                     (const :tag "Scroll horizontally" :value hscroll)
-                    (const :tag "Change face size" :value text-scale)))))
+                    (const :tag "Change buffer face size" :value text-scale)
+                    (const :tag "Change global face size" :value 
global-text-scale)))))
   :set 'mouse-wheel-change-button
   :version "28.1")
 
@@ -417,7 +425,8 @@ value of ARG, and the command uses it in subsequent 
scrolls."
 (put 'mwheel-scroll 'scroll-command t)
 
 (defun mouse-wheel-text-scale (event)
-  "Increase or decrease the height of the default face according to the EVENT."
+  "Adjust font size of the default face according to EVENT.
+See also `text-scale-adjust'."
   (interactive (list last-input-event))
   (let ((selected-window (selected-window))
         (scroll-window (mouse-wheel--get-scroll-window event))
@@ -432,6 +441,20 @@ value of ARG, and the command uses it in subsequent 
scrolls."
                (text-scale-decrease 1)))
       (select-window selected-window))))
 
+(declare-function global-text-scale-adjust "face-remap.el" (increment))
+(defun mouse-wheel-global-text-scale (event)
+  "Increase or decrease the global font size according to the EVENT.
+This invokes `global-text-scale-adjust', which see."
+  (interactive (list last-input-event))
+  (let ((button (mwheel-event-button event)))
+    (unwind-protect
+        (cond ((memq button (list mouse-wheel-down-event
+                                  mouse-wheel-down-alternate-event))
+               (global-text-scale-adjust 1))
+              ((memq button (list mouse-wheel-up-event
+                                  mouse-wheel-up-alternate-event))
+               (global-text-scale-adjust -1))))))
+
 (defun mouse-wheel--add-binding (key fun)
   "Bind mouse wheel button KEY to function FUN.
 Save it for later removal by `mouse-wheel--remove-bindings'."
@@ -484,8 +507,15 @@ an event used for scrolling, such as 
`mouse-wheel-down-event'."
                            mouse-wheel-down-alternate-event
                            mouse-wheel-up-alternate-event))
         (when event
-          (mouse-wheel--add-binding `[,(list (caar binding) event)]
+          (mouse-wheel--add-binding `[,(append (car binding) (list event))]
                                     'mouse-wheel-text-scale))))
+     ((and (consp binding) (eq (cdr binding) 'global-text-scale))
+      (dolist (event (list mouse-wheel-down-event mouse-wheel-up-event
+                           mouse-wheel-down-alternate-event
+                           mouse-wheel-up-alternate-event))
+        (when event
+          (mouse-wheel--add-binding `[,(append (car binding) (list event))]
+                                    'mouse-wheel-global-text-scale))))
      ;; Bindings for scrolling.
      (t
       (dolist (event (list mouse-wheel-down-event mouse-wheel-up-event
diff --git a/lisp/net/ange-ftp.el b/lisp/net/ange-ftp.el
index 9937c022d9..6ffa65a2dd 100644
--- a/lisp/net/ange-ftp.el
+++ b/lisp/net/ange-ftp.el
@@ -1,9 +1,8 @@
 ;;; ange-ftp.el --- transparent FTP support for GNU Emacs  -*- 
lexical-binding:t -*-
 
-;; Copyright (C) 1989-1996, 1998, 2000-2022 Free Software Foundation,
-;; Inc.
+;; Copyright (C) 1989-2022 Free Software Foundation, Inc.
 
-;; Author: Andy Norman (ange@hplb.hpl.hp.com)
+;; Author: Andy Norman <ange@hplb.hpl.hp.com>
 ;; Maintainer: emacs-devel@gnu.org
 ;; Keywords: comm
 
@@ -870,13 +869,10 @@ Both telnet and rlogin do something like this."
 (defcustom ange-ftp-gateway-program remote-shell-program
   "Name of program to spawn a shell on the gateway machine.
 
-Valid candidates are rsh (remsh on some systems), telnet and rlogin.
 See also the gateway variable above."
   :group 'ange-ftp
-  :type '(choice (const "rsh")
-                (const "telnet")
-                (const "rlogin")
-                string))
+  :type 'string
+  :version "29.1")
 
 (defcustom ange-ftp-gateway-prompt-pattern "^[^#$%>;\n]*[#$%>;] *"
   "Regexp matching prompt after complete login sequence on gateway machine.
@@ -4103,11 +4099,11 @@ E.g.,
 ;; Put these lines uncommented in your .emacs if you want C-r to refresh
 ;; ange-ftp's cache whilst doing filename completion.
 ;;
-;;(define-key minibuffer-local-completion-map "\C-r" 'ange-ftp-re-read-dir)
-;;(define-key minibuffer-local-must-match-map "\C-r" 'ange-ftp-re-read-dir)
+;;(define-key minibuffer-local-completion-map "\C-r" 'ange-ftp-reread-dir)
+;;(define-key minibuffer-local-must-match-map "\C-r" 'ange-ftp-reread-dir)
 
 ;;;###autoload
-(defalias 'ange-ftp-re-read-dir 'ange-ftp-reread-dir)
+(define-obsolete-function-alias 'ange-ftp-re-read-dir #'ange-ftp-reread-dir 
"29.1")
 
 ;;;###autoload
 (defun ange-ftp-reread-dir (&optional dir)
diff --git a/lisp/net/browse-url.el b/lisp/net/browse-url.el
index 5b58c8ed86..2d528c4862 100644
--- a/lisp/net/browse-url.el
+++ b/lisp/net/browse-url.el
@@ -1,4 +1,4 @@
-;;; browse-url.el --- pass a URL to a WWW browser  -*- lexical-binding: t; -*-
+;;; browse-url.el --- pass a URL to a web browser  -*- lexical-binding: t; -*-
 
 ;; Copyright (C) 1995-2022 Free Software Foundation, Inc.
 
@@ -24,24 +24,28 @@
 
 ;;; Commentary:
 
-;; This package provides functions which read a URL (Uniform Resource
-;; Locator) from the minibuffer, defaulting to the URL around point,
-;; and ask a World-Wide Web browser to load it.  It can also load the
-;; URL associated with the current buffer.  Different browsers use
-;; different methods of remote control so there is one function for
-;; each supported browser.  If the chosen browser is not running, it
-;; is started.  Currently there is support for the following browsers,
-;; as well as some other obsolete ones:
+;; This package provides functions which read a URL from the
+;; minibuffer, defaulting to the URL around point, and ask a web
+;; browser to load it.  It can also load the URL at point, or one
+;; associated with the current buffer.  The main functions are:
+
+;;   `browse-url'             Open URL
+;;   `browse-url-at-point'    Open URL at point
+;;   `browse-url-of-buffer'   Use web browser to display buffer
+;;   `browse-url-of-file'     Use web browser to display file
+
+;; Different browsers use different methods of remote control so there
+;; is one function for each supported browser.  If the chosen browser
+;; is not running, it is started.  Currently there is support for the
+;; following browsers, as well as some other obsolete ones:
 
 ;; Function                           Browser     Earliest version
-;; browse-url-mozilla                 Mozilla     Don't know
 ;; browse-url-firefox                 Firefox     Don't know (tried with 1.0.1)
 ;; browse-url-chrome                  Chrome      47.0.2526.111
 ;; browse-url-chromium                Chromium    3.0
 ;; browse-url-epiphany                GNOME Web (Epiphany)    Don't know
 ;; browse-url-webpositive             WebPositive 1.2-alpha (Haiku R1/beta3)
-;; browse-url-w3                      w3          0
-;; browse-url-text-*                 Any text browser     0
+;; browse-url-text-*                  Any text browser     0
 ;; browse-url-generic                 arbitrary
 ;; browse-url-default-windows-browser MS-Windows browser
 ;; browse-url-default-macosx-browser  macOS browser
@@ -50,14 +54,12 @@
 ;; browse-url-elinks                  Elinks      Don't know (tried with 
0.12.GIT)
 ;; eww-browse-url                     Emacs Web Wowser
 
-;; Browsers can cache Web pages so it may be necessary to tell them to
+;; Browsers can cache web pages so it may be necessary to tell them to
 ;; reload the current page if it has changed (e.g., if you have edited
 ;; it).  There is currently no perfect automatic solution to this.
 
-;; This package generalizes function html-previewer-process in Marc
-;; Andreessen's html-mode (LCD modes/html-mode.el.Z).  See also the
-;; ffap.el package.  The huge hyperbole package also contains similar
-;; functions.
+;; See also the ffap.el package.  The huge hyperbole package also
+;; contains similar functions.
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Usage
@@ -83,34 +85,34 @@
 ;; M-x browse-url-of-dired-file RET
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Customization (~/.emacs)
+;; Customization (Init File)
 
 ;; To see what variables are available for customization, type
 ;; `M-x set-variable browse-url TAB'.  Better, use
 ;; `M-x customize-group browse-url'.
 
-;; Bind the browse-url commands to keys with the `C-c C-z' prefix
-;; (as used by html-helper-mode):
-;;     (global-set-key "\C-c\C-z." 'browse-url-at-point)
-;;     (global-set-key "\C-c\C-zb" 'browse-url-of-buffer)
-;;     (global-set-key "\C-c\C-zr" 'browse-url-of-region)
-;;     (global-set-key "\C-c\C-zu" 'browse-url)
-;;     (global-set-key "\C-c\C-zv" 'browse-url-of-file)
+;; Bind the browse-url commands to keys with the `C-c C-z' prefix:
+
+;;     (keymap-global-set "C-c C-z ." 'browse-url-at-point)
+;;     (keymap-global-set "C-c C-z b" 'browse-url-of-buffer)
+;;     (keymap-global-set "C-c C-z r" 'browse-url-of-region)
+;;     (keymap-global-set "C-c C-z u" 'browse-url)
+;;     (keymap-global-set "C-c C-z v" 'browse-url-of-file)
 ;;     (add-hook 'dired-mode-hook
 ;;               (lambda ()
-;;                  (local-set-key "\C-c\C-zf" 'browse-url-of-dired-file)))
+;;                  (keymap-local-set "C-c C-z f" 'browse-url-of-dired-file)))
 
 ;; Browse URLs in mail messages under RMAIL by clicking mouse-2:
 ;;     (add-hook 'rmail-mode-hook (lambda () ; rmail-mode startup
-;;       (define-key rmail-mode-map [mouse-2] 'browse-url-at-mouse)))
+;;       (keymap-set rmail-mode-map [mouse-2] 'browse-url-at-mouse)))
 ;; Alternatively, add `goto-address' to `rmail-show-message-hook'.
 
 ;; Gnus provides a standard feature to activate URLs in article
 ;; buffers for invocation of browse-url.
 
-;; Use the Emacs w3 browser when not running under X11:
+;; Use the Emacs Web Wowser (EWW) when not running under X11:
 ;;     (or (eq window-system 'x)
-;;         (setq browse-url-browser-function 'browse-url-w3))
+;;         (setq browse-url-browser-function #'eww-browse-url))
 
 ;; To always save modified buffers before displaying the file in a browser:
 ;;     (setq browse-url-save-file t)
@@ -149,15 +151,14 @@
   :group 'comm)
 
 (defvar browse-url--browser-defcustom-type
-  '(choice
-    (function-item :tag "Emacs W3" :value  browse-url-w3)
-    (function-item :tag "eww" :value  eww-browse-url)
-    (function-item :tag "Mozilla" :value  browse-url-mozilla)
+  `(choice
+    (function-item :tag "Emacs Web Wowser (EWW)" :value  eww-browse-url)
     (function-item :tag "Firefox" :value browse-url-firefox)
     (function-item :tag "Google Chrome" :value browse-url-chrome)
     (function-item :tag "Chromium" :value browse-url-chromium)
     (function-item :tag "GNOME Web (Epiphany)" :value  browse-url-epiphany)
-    (function-item :tag "WebPositive" :value browse-url-webpositive)
+    ,@(when (eq system-type 'haiku)
+        (list '(function-item :tag "WebPositive" :value 
browse-url-webpositive)))
     (function-item :tag "Text browser in an xterm window"
                   :value browse-url-text-xterm)
     (function-item :tag "Text browser in an Emacs window"
@@ -165,11 +166,13 @@
     (function-item :tag "KDE" :value browse-url-kde)
     (function-item :tag "Elinks" :value browse-url-elinks)
     (function-item :tag "Specified by `Browse Url Generic Program'"
-                  :value browse-url-generic)
-    (function-item :tag "Default Windows browser"
-                  :value browse-url-default-windows-browser)
-    (function-item :tag "Default macOS browser"
-                  :value browse-url-default-macosx-browser)
+                   :value browse-url-generic)
+    ,@(when (eq system-type 'windows-nt)
+        (list '(function-item :tag "Default Windows browser"
+                              :value browse-url-default-windows-browser)))
+    ,@(when (eq system-type 'darwin)
+        (list '(function-item :tag "Default macOS browser"
+                              :value browse-url-default-macosx-browser)))
     (function-item :tag "Default browser"
                   :value browse-url-default-browser)
     (function :tag "Your own function")
@@ -247,16 +250,19 @@ be used instead."
 (defcustom browse-url-mozilla-program "mozilla"
   "The name by which to invoke Mozilla."
   :type 'string)
+(make-obsolete-variable 'browse-url-mozilla-program nil "29.1")
 
 (defcustom browse-url-mozilla-arguments nil
   "A list of strings to pass to Mozilla as arguments."
   :type '(repeat (string :tag "Argument")))
+(make-obsolete-variable 'browse-url-mozilla-arguments nil "29.1")
 
 (defcustom browse-url-mozilla-startup-arguments browse-url-mozilla-arguments
   "A list of strings to pass to Mozilla when it starts up.
 Defaults to the value of `browse-url-mozilla-arguments' at the time
 `browse-url' is loaded."
   :type '(repeat (string :tag "Argument")))
+(make-obsolete-variable 'browse-url-mozilla-startup-arguments nil "29.1")
 
 (defun browse-url--find-executable (candidates default)
   (while (and candidates (not (executable-find (car candidates))))
@@ -340,6 +346,7 @@ Defaults to the value of `browse-url-epiphany-arguments' at 
the time
 If non-nil, then open the URL in a new tab rather than a new window if
 `browse-url-mozilla' is asked to open it in a new window."
   :type 'boolean)
+(make-obsolete-variable 'browse-url-mozilla-new-window-is-tab nil "29.1")
 
 (defcustom browse-url-firefox-new-window-is-tab nil
   "Whether to open up new windows in a tab or a new window.
@@ -396,7 +403,7 @@ commands reverses the effect of this variable."
 Any substring of a filename matching one of the REGEXPs is replaced by
 the corresponding STRING using `replace-match', not treating STRING
 literally.  All pairs are applied in the order given.  The default
-value converts ange-ftp/EFS-style file names into ftp URLs and prepends
+value converts ange-ftp-style file names into ftp URLs and prepends
 `file:' to any file name beginning with `/'.
 
 For example, adding to the default a specific translation of an ange-ftp
@@ -404,7 +411,7 @@ address to an HTTP URL:
 
     (setq browse-url-filename-alist
          \\='((\"/webmaster@webserver:/home/www/html/\" .
-            \"http://www.acme.co.uk/\";)
+             \"https://www.example.org/\";)
             (\"^/\\(ftp@\\|anonymous@\\)?\\([^:/]+\\):/*\" . \"ftp://\\2/\";)
             (\"^/\\([^:@/]+@\\)?\\([^:/]+\\):/*\" . \"ftp://\\1\\2/\";)
            (\"^/+\" . \"file:/\")))"
@@ -437,11 +444,13 @@ These might set its size, for instance."
 (defcustom browse-url-gnudoit-program "gnudoit"
   "The name of the `gnudoit' program used by `browse-url-w3-gnudoit'."
   :type 'string)
+(make-obsolete-variable 'browse-url-gnudoit-program nil "29.1")
 
 (defcustom browse-url-gnudoit-args '("-q")
   "A list of strings defining options for `browse-url-gnudoit-program'.
 These might set the port, for instance."
   :type '(repeat (string :tag "Argument")))
+(make-obsolete-variable 'browse-url-gnudoit-args nil "29.1")
 
 (defcustom browse-url-generic-program nil
   "The name of the browser program used by `browse-url-generic'."
@@ -643,11 +652,24 @@ regarding its parameter treatment."
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; URL input
 
+(defcustom browse-url-default-scheme "http"
+  "URL scheme that `browse-url' (and related commands) will use by default.
+
+For example, when point is on an URL fragment like
+\"www.example.org\", `browse-url' will assume that this is an
+\"http\" URL by default (i.e. \"http://www.example.org\";).
+
+Note that if you set this to \"https\", websites that do not yet
+support HTTPS may not load correctly in your web browser.  Such
+websites are increasingly rare, but they do still exist."
+  :type 'string
+  :version "29.1")
+
 (defun browse-url-url-at-point ()
   (or (thing-at-point 'url t)
       ;; assume that the user is pointing at something like gnu.org/gnu
       (let ((f (thing-at-point 'filename t)))
-        (and f (concat "http://"; f)))))
+        (and f (concat browse-url-default-scheme "://" f)))))
 
 ;; Having this as a separate function called by the browser-specific
 ;; functions allows them to be stand-alone commands, making it easier
@@ -959,8 +981,7 @@ The optional NEW-WINDOW argument is not used."
                             ;; quotes in the MAILTO URLs, so we prefer
                             ;; to leave the URL with its embedded %nn
                             ;; encoding intact.
-                            (if (eq t (compare-strings url nil 7
-                                                       "file://" nil nil))
+                            (if (string-prefix-p "file://" url)
                                 (url-unhex-string url)
                               url)))))
 
@@ -1024,20 +1045,17 @@ instead of `browse-url-new-window-flag'."
      'browse-url-default-haiku-browser)
     ((browse-url-can-use-xdg-open) 'browse-url-xdg-open)
 ;;;    ((executable-find browse-url-gnome-moz-program) 'browse-url-gnome-moz)
-    ((executable-find browse-url-mozilla-program) 'browse-url-mozilla)
     ((executable-find browse-url-firefox-program) 'browse-url-firefox)
     ((executable-find browse-url-chromium-program) 'browse-url-chromium)
     ((executable-find browse-url-kde-program) 'browse-url-kde)
     ((executable-find browse-url-chrome-program) 'browse-url-chrome)
     ((executable-find browse-url-webpositive-program) 'browse-url-webpositive)
     ((executable-find browse-url-xterm-program) 'browse-url-text-xterm)
-    ((locate-library "w3") 'browse-url-w3)
-    (t
-     (lambda (&rest _ignore) (error "No usable browser found"))))
+    (t #'eww-browse-url))
    url args))
 
 (function-put 'browse-url-default-browser 'browse-url-browser-kind
-              ;; Well, most probably external if we ignore w3.
+              ;; Well, most probably external if we ignore EWW.
               'external)
 
 (defun browse-url-can-use-xdg-open ()
@@ -1078,6 +1096,7 @@ new tab in an existing window instead.
 
 When called non-interactively, optional second argument NEW-WINDOW is
 used instead of `browse-url-new-window-flag'."
+  (declare (obsolete nil "29.1"))
   (interactive (browse-url-interactive-arg "URL: "))
   (setq url (browse-url-encode-url url))
   (let* ((process-environment (browse-url-process-environment))
@@ -1104,6 +1123,7 @@ used instead of `browse-url-new-window-flag'."
 
 (defun browse-url-mozilla-sentinel (process url)
   "Handle a change to the process communicating with Mozilla."
+  (declare (obsolete nil "29.1"))
   (or (eq (process-exit-status process) 0)
       (let* ((process-environment (browse-url-process-environment)))
        ;; Mozilla is not running - start it
@@ -1365,6 +1385,7 @@ prefix argument reverses the effect of 
`browse-url-new-window-flag'.
 
 When called non-interactively, optional second argument NEW-WINDOW is
 used instead of `browse-url-new-window-flag'."
+  (declare (obsolete nil "29.1"))
   (interactive (browse-url-interactive-arg "W3 URL: "))
   (require 'w3)                        ; w3-fetch-other-window not autoloaded
   (if (browse-url-maybe-new-window new-window)
diff --git a/lisp/net/dbus.el b/lisp/net/dbus.el
index d4d4ed54e9..6c978c5a5f 100644
--- a/lisp/net/dbus.el
+++ b/lisp/net/dbus.el
@@ -941,9 +941,7 @@ association to the service from D-Bus."
 
     ;; Loop over the registered functions.
     (dolist (elt entry)
-      (when (equal
-            value
-            (butlast (cdr elt) (- (length (cdr elt)) (length value))))
+      (when (equal value (take (length value) (cdr elt)))
        (setq ret t)
        ;; Compute new hash value.  If it is empty, remove it from the
        ;; hash table.
diff --git a/lisp/net/dictionary.el b/lisp/net/dictionary.el
index e0824f3971..43dd28ff6d 100644
--- a/lisp/net/dictionary.el
+++ b/lisp/net/dictionary.el
@@ -89,7 +89,7 @@ You can specify here:
 This port is probably always 2628 so there should be no need to modify it."
   :group 'dictionary
   :set #'dictionary-set-server-var
-  :type 'number
+  :type 'natnum
   :version "28.1")
 
 (defcustom dictionary-identification
@@ -119,7 +119,7 @@ one dictionary yields matches."
   "exact"
   "The default strategy for listing matching words within a popup window.
 
-The following algorithm (defined by the dictd server) are supported
+The following algorithms (defined by the dictd server) are supported
 by the choice value:
 
 - Exact match
@@ -130,7 +130,7 @@ by the choice value:
 
   The found word sounds similar to the searched word.  For this match type
   the soundex algorithm defined by Donald E. Knuth is used.  It will only
-  works with english words and the algorithm is not very reliable (i.e.,
+  work with English words and the algorithm is not very reliable (i.e.,
   the soundex algorithm is quite simple).
 
 - Levenshtein distance one
@@ -206,7 +206,7 @@ where the current word was found."
   "The port of the proxy server, used only when `dictionary-use-http-proxy' is 
set."
   :group 'dictionary-proxy
   :set #'dictionary-set-server-var
-  :type 'number
+  :type 'natnum
   :version "28.1")
 
 (defcustom dictionary-use-single-buffer
@@ -326,26 +326,22 @@ is utf-8"
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Global variables
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-(defvar dictionary-mode-map
-  (let ((map (make-sparse-keymap)))
-    (suppress-keymap map)
-    (set-keymap-parent map button-buffer-map)
-
-    (define-key map "q" #'dictionary-close)
-    (define-key map "h" #'dictionary-help)
-    (define-key map "s" #'dictionary-search)
-    (define-key map "d" #'dictionary-lookup-definition)
-    (define-key map "D" #'dictionary-select-dictionary)
-    (define-key map "M" #'dictionary-select-strategy)
-    (define-key map "m" #'dictionary-match-words)
-    (define-key map "l" #'dictionary-previous)
-    (define-key map "n" #'forward-button)
-    (define-key map "p" #'backward-button)
-    (define-key map " " #'scroll-up-command)
-    (define-key map [?\S-\ ] #'scroll-down-command)
-    (define-key map (read-kbd-macro "M-SPC") #'scroll-down-command)
-    map)
-  "Keymap for the dictionary mode.")
+(defvar-keymap dictionary-mode-map
+  :doc "Keymap for the dictionary mode."
+  :suppress t :parent button-buffer-map
+  "q"     #'dictionary-close
+  "h"     #'describe-mode
+  "s"     #'dictionary-search
+  "d"     #'dictionary-lookup-definition
+  "D"     #'dictionary-select-dictionary
+  "M"     #'dictionary-select-strategy
+  "m"     #'dictionary-match-words
+  "l"     #'dictionary-previous
+  "n"     #'forward-button
+  "p"     #'backward-button
+  "SPC"   #'scroll-up-command
+  "S-SPC" #'scroll-down-command
+  "M-SPC" #'scroll-down-command)
 
 (defvar dictionary-connection
   nil
@@ -361,7 +357,7 @@ is utf-8"
 
 (defvar dictionary-color-support
   (condition-case nil
-      (x-display-color-p)
+      (display-color-p)
     (error nil))
   "Determines if the Emacs has support to display color.")
 
@@ -383,7 +379,7 @@ protocol defined in RFC 2229.
 This is a quick reference to this mode describing the default key bindings:
 \\<dictionary-mode-map>
 * \\[dictionary-close] close the dictionary buffer
-* \\[dictionary-help] display this help information
+* \\[describe-mode] display this help information
 * \\[dictionary-search] ask for a new word to search
 * \\[dictionary-lookup-definition] search the word at point
 * \\[forward-button] or TAB place point to the next link
@@ -393,7 +389,7 @@ This is a quick reference to this mode describing the 
default key bindings:
 * \\[dictionary-select-dictionary] select the default dictionary
 * \\[dictionary-select-strategy] select the default search strategy
 
-* RET or <mouse-2> visit that link"
+* \\`RET' or \\`<mouse-2>' visit that link"
 
   (unless (eq major-mode 'dictionary-mode)
     (cl-incf dictionary-instances))
@@ -759,31 +755,31 @@ of matching words."
       (progn
         (insert-button "[Back]" :type 'dictionary-button
                        'callback 'dictionary-restore-state
-                       'help-echo (purecopy "Mouse-2 to go backwards in 
history"))
+                       'help-echo "Mouse-2 to go backwards in history")
        (insert " ")
         (insert-button "[Search definition]" :type 'dictionary-button
                        'callback 'dictionary-search
-                       'help-echo (purecopy "Mouse-2 to look up a new word"))
+                       'help-echo "Mouse-2 to look up a new word")
        (insert "         ")
 
        (insert-button "[Matching words]" :type 'dictionary-button
                        'callback 'dictionary-match-words
-                       'help-echo (purecopy "Mouse-2 to find matches for a 
pattern"))
+                       'help-echo "Mouse-2 to find matches for a pattern")
        (insert "        ")
 
        (insert-button "[Quit]" :type 'dictionary-button
                        'callback 'dictionary-close
-                       'help-echo (purecopy "Mouse-2 to close this window"))
+                       'help-echo "Mouse-2 to close this window")
 
        (insert "\n       ")
 
         (insert-button "[Select dictionary]" :type 'dictionary-button
                        'callback 'dictionary-select-dictionary
-                       'help-echo (purecopy "Mouse-2 to select dictionary for 
future searches"))
+                       'help-echo "Mouse-2 to select dictionary for future 
searches")
        (insert "         ")
         (insert-button "[Select match strategy]" :type 'dictionary-button
                        'callback 'dictionary-select-strategy
-                       'help-echo (purecopy "Mouse-2 to select matching 
algorithm"))
+                       'help-echo "Mouse-2 to select matching algorithm")
        (insert "\n\n")))
   (setq dictionary-marker (point-marker)))
 
@@ -932,13 +928,13 @@ If PATTERN is omitted, it defaults to \"[ 
\\f\\t\\n\\r\\v]+\"."
           (insert-button (concat dictionary ": " translated) :type 
'dictionary-link
                          'callback 'dictionary-set-dictionary
                          'data (cons dictionary description)
-                         'help-echo (purecopy "Mouse-2 to select this 
dictionary"))
+                         'help-echo "Mouse-2 to select this dictionary")
           (unless (dictionary-special-dictionary dictionary)
             (insert " ")
             (insert-button "(Details)" :type 'dictionary-link
                            'callback 'dictionary-set-dictionary
                            'list-data (list (cons dictionary description) t)
-                           'help-echo (purecopy "Mouse-2 to get more 
information")))
+                           'help-echo "Mouse-2 to get more information"))
          (insert "\n")))))
 
 (defun dictionary-set-dictionary (param &optional more)
@@ -976,7 +972,7 @@ If PATTERN is omitted, it defaults to \"[ 
\\f\\t\\n\\r\\v]+\"."
           (insert-button description :type 'dictionary-link
                          'callback 'dictionary-set-dictionary
                          'data (cons dictionary description)
-                         'help-echo (purecopy "Mouse-2 to select this 
dictionary"))
+                         'help-echo "Mouse-2 to select this dictionary")
          (insert "\n\n")
          (setq reply (dictionary-read-answer))
          (insert reply)
@@ -1027,7 +1023,7 @@ If PATTERN is omitted, it defaults to \"[ 
\\f\\t\\n\\r\\v]+\"."
           (insert-button description :type 'dictionary-link
                          'callback 'dictionary-set-strategy
                          'data strategy
-                         'help-echo (purecopy "Mouse-2 to select this matching 
algorithm"))
+                         'help-echo "Mouse-2 to select this matching 
algorithm")
          (insert "\n")))))
 
 (defun dictionary-set-strategy (strategy &rest _ignored)
@@ -1128,7 +1124,7 @@ If PATTERN is omitted, it defaults to \"[ 
\\f\\t\\n\\r\\v]+\"."
                     (insert-button word :type 'dictionary-link
                                    'callback 'dictionary-new-search
                                    'data (cons word dictionary)
-                                   'help-echo (purecopy "Mouse-2 to lookup 
word"))
+                                   'help-echo "Mouse-2 to lookup word")
                    (insert "\n")) (reverse word-list))
            (insert "\n")))
        list))
@@ -1188,7 +1184,8 @@ allows editing it."
 
 (defun dictionary-help ()
   "Display a little help."
-  (interactive)
+  (declare (obsolete describe-mode "29.1"))
+  (interactive nil dictionary-mode)
   (describe-function 'dictionary-mode))
 
 ;;;###autoload
diff --git a/lisp/net/dig.el b/lisp/net/dig.el
index f7f1500454..d6436c579b 100644
--- a/lisp/net/dig.el
+++ b/lisp/net/dig.el
@@ -22,18 +22,14 @@
 
 ;;; Commentary:
 
-;; This provide an interface for "dig".
+;; This provides an interface for "dig".
 ;;
-;; For interactive use, try M-x dig and type a hostname.  Use `q' to quit
-;; dig buffer.
+;; For interactive use, try `M-x dig' and type a hostname.  Use `q' to
+;; quit dig buffer.
 ;;
-;; For use in elisp programs, call `dig-invoke' and use
+;; For use in Emacs Lisp programs, call `dig-invoke' and use
 ;; `dig-extract-rr' to extract resource records.
 
-;;; Release history:
-
-;; 2000-10-28  posted on gnu.emacs.sources
-
 ;;; Code:
 
 (defgroup dig nil
@@ -44,6 +40,11 @@
   "Name of dig (domain information groper) binary."
   :type 'file)
 
+(defcustom dig-program-options nil
+  "Options for the dig program."
+  :type '(repeat string)
+  :version "26.1")
+
 (defcustom dig-dns-server nil
   "DNS server to query.
 If nil, use system defaults."
@@ -59,8 +60,8 @@ If nil, use system defaults."
   :type 'sexp)
 
 (defun dig-invoke (domain &optional
-                         query-type query-class query-option
-                         dig-option server)
+                       query-type query-class query-option
+                       dig-option server)
   "Call dig with given arguments and return buffer containing output.
 DOMAIN is a string with a DNS domain.  QUERY-TYPE is an optional
 string with a DNS type.  QUERY-CLASS is an optional string with a DNS
@@ -79,7 +80,8 @@ and is a commonly available debugging tool."
     (push domain cmdline)
     (if server (push (concat "@" server) cmdline)
       (if dig-dns-server (push (concat "@" dig-dns-server) cmdline)))
-    (apply #'call-process dig-program nil buf nil cmdline)
+    (apply #'call-process dig-program nil buf nil
+           (append dig-program-options cmdline))
     buf))
 
 (defun dig-extract-rr (domain &optional type class)
@@ -117,11 +119,9 @@ Buffer should contain output generated by `dig-invoke'."
       (setq str (replace-match "" nil nil str)))
     str))
 
-(defvar dig-mode-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "g" nil)
-    (define-key map "q" #'dig-exit)
-    map))
+(defvar-keymap dig-mode-map
+  "g" nil
+  "q" #'dig-exit)
 
 (define-derived-mode dig-mode special-mode "Dig"
   "Major mode for displaying dig output."
@@ -132,7 +132,7 @@ Buffer should contain output generated by `dig-invoke'."
 
 (defun dig-exit ()
   "Quit dig output buffer."
-  (interactive)
+  (interactive nil dig-mode)
   (quit-window t))
 
 ;;;###autoload
@@ -140,12 +140,23 @@ Buffer should contain output generated by `dig-invoke'."
                   query-type query-class query-option dig-option server)
   "Query addresses of a DOMAIN using dig.
 See `dig-invoke' for an explanation for the parameters.
-When called interactively, DOMAIN is prompted for.  If given a prefix,
-also prompt for the QUERY-TYPE parameter."
+When called interactively, DOMAIN is prompted for.
+
+If given a \\[universal-argument] prefix, also prompt \
+for the QUERY-TYPE parameter.
+
+If given a \\[universal-argument] \\[universal-argument] \
+prefix, also prompt for the SERVER parameter."
   (interactive
-   (list (read-string "Host: ")
+   (list (let ((default (ffap-machine-at-point)))
+           (read-string (format-prompt "Host" default) nil nil default))
          (and current-prefix-arg
               (read-string "Query type: "))))
+  (when (and (numberp (car current-prefix-arg))
+             (>= (car current-prefix-arg) 16))
+    (let ((serv (read-from-minibuffer "Name server: ")))
+      (when (not (equal serv ""))
+        (setq server serv))))
   (pop-to-buffer-same-window
    (dig-invoke domain query-type query-class query-option dig-option server))
   (goto-char (point-min))
@@ -153,20 +164,21 @@ also prompt for the QUERY-TYPE parameter."
        (forward-line))
   (dig-mode))
 
-;; named for consistency with query-dns in dns.el
-(defun query-dig (domain &optional
-                        query-type query-class query-option dig-option server)
+(defun dig-query (domain &optional
+                         query-type query-class query-option dig-option server)
   "Query addresses of a DOMAIN using dig.
 It works by calling `dig-invoke' and `dig-extract-rr'.
 Optional arguments are passed to `dig-invoke' and `dig-extract-rr'.
 Returns nil for domain/class/type queries that result in no data."
-(let ((buffer (dig-invoke domain query-type query-class
-                         query-option dig-option server)))
-  (when buffer
-    (pop-to-buffer-same-window buffer)
-    (let ((digger (dig-extract-rr domain query-type query-class)))
-      (kill-buffer buffer)
-      digger))))
+  (let ((buffer (dig-invoke domain query-type query-class
+                            query-option dig-option server)))
+    (when buffer
+      (pop-to-buffer-same-window buffer)
+      (let ((digger (dig-extract-rr domain query-type query-class)))
+        (kill-buffer buffer)
+        digger))))
+
+(define-obsolete-function-alias 'query-dig #'dig-query "29.1")
 
 (provide 'dig)
 
diff --git a/lisp/net/eudc-capf.el b/lisp/net/eudc-capf.el
index 68cbfd93ff..92f0c80493 100644
--- a/lisp/net/eudc-capf.el
+++ b/lisp/net/eudc-capf.el
@@ -71,7 +71,7 @@
 ;;    setting.
 ;;
 ;;    The value of the variable `eudc-capf-modes' indicates which
-;;    major modes do such a setup as part of their initialisation
+;;    major modes do such a setup as part of their initialization
 ;;    code.
 
 ;;; Code:
diff --git a/lisp/net/eudc-export.el b/lisp/net/eudc-export.el
index 3f7d9c0060..2f841336e0 100644
--- a/lisp/net/eudc-export.el
+++ b/lisp/net/eudc-export.el
@@ -210,7 +210,7 @@ LOCATION is used as the phone location for BBDB."
     (while (eudc-move-to-next-record)
       (and (overlays-at (point))
           (setq record (overlay-get (car (overlays-at (point))) 'eudc-record))
-          (1+ nbrec)
+           (setq nbrec (1+ nbrec))
           (eudc-create-bbdb-record record t)))
     (message "%d records imported into BBDB" nbrec)))
 
diff --git a/lisp/net/eudc-hotlist.el b/lisp/net/eudc-hotlist.el
index 26afd76805..458d13fb24 100644
--- a/lisp/net/eudc-hotlist.el
+++ b/lisp/net/eudc-hotlist.el
@@ -32,29 +32,26 @@
 
 (require 'eudc)
 
-(defvar eudc-hotlist-menu nil)
 (defvar eudc-hotlist-list-beginning nil)
 
-(defvar eudc-hotlist-mode-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "a" #'eudc-hotlist-add-server)
-    (define-key map "d" #'eudc-hotlist-delete-server)
-    (define-key map "s" #'eudc-hotlist-select-server)
-    (define-key map "t" #'eudc-hotlist-transpose-servers)
-    (define-key map "q" #'eudc-hotlist-quit-edit)
-    (define-key map "x" #'kill-current-buffer)
-    map))
+(defvar-keymap eudc-hotlist-mode-map
+  "a" #'eudc-hotlist-add-server
+  "d" #'eudc-hotlist-delete-server
+  "s" #'eudc-hotlist-select-server
+  "t" #'eudc-hotlist-transpose-servers
+  "q" #'eudc-hotlist-quit-edit
+  "x" #'kill-current-buffer)
 
 (define-derived-mode eudc-hotlist-mode fundamental-mode "EUDC-Servers"
   "Major mode used to edit the hotlist of servers.
 
-These are the special commands of this mode:
-    a -- Add a new server to the list.
-    d -- Delete the server at point from the list.
-    s -- Select the server at point.
-    t -- Transpose the server at point and the previous one
-    q -- Commit the changes and quit.
-    x -- Quit without committing the changes."
+These are the special commands of this mode:\\<eudc-hotlist-mode-map>
+    \\[eudc-hotlist-add-server] -- Add a new server to the list.
+    \\[eudc-hotlist-delete-server] -- Delete the server at point from the list.
+    \\[eudc-hotlist-select-server] -- Select the server at point.
+    \\[eudc-hotlist-transpose-servers] -- Transpose the server at point and 
the previous one
+    \\[eudc-hotlist-quit-edit] -- Commit the changes and quit.
+    \\[kill-current-buffer] -- Quit without committing the changes."
   (setq buffer-read-only t))
 
 ;;;###autoload
diff --git a/lisp/net/eudc-vars.el b/lisp/net/eudc-vars.el
index 90d89e87fb..dea17f3424 100644
--- a/lisp/net/eudc-vars.el
+++ b/lisp/net/eudc-vars.el
@@ -194,7 +194,7 @@ must be set in a protocol/server-local fashion, see 
`eudc-server-set' and
 (defcustom eudc-inline-expansion-format nil
   "Specify the format of the expansion of inline queries.
 This variable controls what `eudc-expand-inline' actually inserts
-in the buffer. It is either a list, or a function.
+in the buffer.  It is either a list, or a function.
 
 When set to a list, the expansion result will be formatted
 according to the first element of the list, a string, which is
@@ -214,13 +214,14 @@ used to format the PHRASE, and COMMENT parts, 
respectively.  It
 receives a single argument, which is an alist of
 protocol-specific attributes describing the recipient.  To access
 the alist elements using generic EUDC attribute names, such as
-for example name, or email, use `eudc-translate-attribute-list'.
-The function should return a list, which should contain two
-elements.  If the first element is a string, it will be used as
-the PHRASE part, quoting it if necessary. If the second element
-is a string, it will be used as the COMMENT part, unless it
-contains characters not allowed in the COMMENT part by RFC 5322,
-in which case the COMMENT part will be omitted."
+for example name, or email, use `eudc-translate-query' with
+REVERSE set to t to transform the received attribute alist.  The
+function should return a list, which should contain two elements.
+If the first element is a string, it will be used as the PHRASE
+part, quoting it if necessary.  If the second element is a string,
+it will be used as the COMMENT part, unless it contains
+characters not allowed in the COMMENT part by RFC 5322, in which
+case the COMMENT part will be omitted."
   :type '(choice (const :tag "RFC 5322 formatted \"first last <address>\"" nil)
                  (function :tag "RFC 5322 phrase/comment formatting function")
                  (list :tag "Format string (deprecated)"
@@ -283,6 +284,7 @@ If nil, query all servers available from 
`eudc-inline-expansion-servers'."
                                             (firstname . "First Name")
                                             (cn . "Full Name")
                                             (sn . "Surname")
+                                            (name . "Surname")
                                             (givenname . "First Name")
                                             (ou . "Unit")
                                             (labeledurl . "URL")
diff --git a/lisp/net/eudc.el b/lisp/net/eudc.el
index 808d2ca509..40cb25fca2 100644
--- a/lisp/net/eudc.el
+++ b/lisp/net/eudc.el
@@ -55,16 +55,14 @@
 
 (defvar eudc-form-widget-list nil)
 
-(defvar eudc-mode-map
-  (let ((map (make-sparse-keymap)))
-    (set-keymap-parent map widget-keymap)
-    (define-key map "q" #'kill-current-buffer)
-    (define-key map "x" #'kill-current-buffer)
-    (define-key map "f" #'eudc-query-form)
-    (define-key map "b" #'eudc-try-bbdb-insert)
-    (define-key map "n" #'eudc-move-to-next-record)
-    (define-key map "p" #'eudc-move-to-previous-record)
-    map))
+(defvar-keymap eudc-mode-map
+  :parent widget-keymap
+  "q" #'kill-current-buffer
+  "x" #'kill-current-buffer
+  "f" #'eudc-query-form
+  "b" #'eudc-try-bbdb-insert
+  "n" #'eudc-move-to-next-record
+  "p" #'eudc-move-to-previous-record)
 
 (defvar mode-popup-menu)
 
@@ -382,32 +380,51 @@ accordingly.  Otherwise it is set to its EUDC default 
binding."
            (cons protocol eudc-known-protocols))))
 
 
-(defun eudc-translate-query (query)
+(defun eudc-translate-query (query &optional reverse)
   "Translate attribute names of QUERY.
 The translation is done according to
-`eudc-protocol-attributes-translation-alist'."
+`eudc-protocol-attributes-translation-alist'.
+
+When REVERSE is nil or omitted, the attribute names are
+translated from EUDC generic names to protocol-specific
+names. When REVERSE is non-nil, the translation is from
+protocol-specific names back to EUDC generic names."
   (if eudc-protocol-attributes-translation-alist
       (mapcar (lambda (attribute)
-                (let ((trans (assq (car attribute)
-                                   (symbol-value 
eudc-protocol-attributes-translation-alist))))
+                (let ((trans
+                       (if reverse
+                           (rassq (car attribute)
+                                  (symbol-value 
eudc-protocol-attributes-translation-alist))
+                         (assq (car attribute)
+                               (symbol-value 
eudc-protocol-attributes-translation-alist)))))
                   (if trans
-                      (cons (cdr trans) (cdr attribute))
+                      (cons (if reverse (car trans) (cdr trans))
+                            (cdr attribute))
                     attribute)))
              query)
     query))
 
-(defun eudc-translate-attribute-list (list)
+(defun eudc-translate-attribute-list (list &optional reverse)
   "Translate a list of attribute names LIST.
 The translation is done according to
-`eudc-protocol-attributes-translation-alist'."
+`eudc-protocol-attributes-translation-alist'.
+
+When REVERSE is nil or omitted, the attribute names are
+translated from EUDC generic names to protocol-specific
+names. When REVERSE is non-nil, the translation is from
+protocol-specific names back to EUDC generic names."
   (if eudc-protocol-attributes-translation-alist
       (let (trans)
        (mapcar (lambda (attribute)
-                  (setq trans (assq attribute
-                                    (symbol-value 
eudc-protocol-attributes-translation-alist)))
-                  (if trans
-                      (cdr trans)
-                    attribute))
+                 (setq trans
+                        (if reverse
+                            (rassq attribute
+                                  (symbol-value 
eudc-protocol-attributes-translation-alist))
+                          (assq attribute
+                               (symbol-value 
eudc-protocol-attributes-translation-alist))))
+                 (if trans
+                     (if reverse (car trans) (cdr trans))
+                   attribute))
                list))
     list))
 
@@ -720,7 +737,7 @@ server for future sessions."
 (defun eudc-get-email (name &optional error)
   "Get the email field of NAME from the directory server.
 If ERROR is non-nil, report an error if there is none."
-  (interactive "sName: \np")
+  (interactive "sSurname: \np")
   (or eudc-server
       (call-interactively 'eudc-set-server))
   (let ((result (eudc-query (list (cons 'name name)) '(email)))
@@ -738,7 +755,7 @@ If ERROR is non-nil, report an error if there is none."
 (defun eudc-get-phone (name &optional error)
   "Get the phone field of NAME from the directory server.
 If ERROR is non-nil, report an error if there is none."
-  (interactive "sName: \np")
+  (interactive "sSurname: \np")
   (or eudc-server
       (call-interactively 'eudc-set-server))
   (let ((result (eudc-query (list (cons 'name name)) '(phone)))
@@ -839,7 +856,7 @@ non-nil, collect results from all servers."
   (let* ((end (point))
         (beg (save-excursion
                (if (re-search-backward "\\([:,]\\|^\\)[ \t]*"
-                                       (point-at-bol) 'move)
+                                        (line-beginning-position) 'move)
                    (goto-char (match-end 0)))
                (point)))
         (query-words (split-string (buffer-substring-no-properties beg end)
@@ -908,7 +925,7 @@ non-nil, collect results from all servers."
 `eudc-inline-expansion-format' is expected to return a list.")
           nil))))
 
-   ;; fallback behaviour (nil function, or non-matching type)
+   ;; fallback behavior (nil function, or non-matching type)
    (t
     (let ((fname (cdr (assq (nth 0 query-attrs) res)))
           (lname (cdr (assq (nth 1 query-attrs) res)))
@@ -1025,7 +1042,10 @@ queries the server for the existing fields and displays 
a corresponding form."
        pt)
     (switch-to-buffer buffer)
     (let ((inhibit-read-only t))
+    (remove-hook 'after-change-functions 'widget-after-change t)
+    (delete-all-overlays)
     (erase-buffer)
+    (add-hook 'after-change-functions 'widget-after-change nil t)
     (kill-all-local-variables)
     (make-local-variable 'eudc-form-widget-list)
     (widget-insert "Directory Query Form\n")
diff --git a/lisp/net/eudcb-ldap.el b/lisp/net/eudcb-ldap.el
index 1201c84f2d..86fe99f9e7 100644
--- a/lisp/net/eudcb-ldap.el
+++ b/lisp/net/eudcb-ldap.el
@@ -38,14 +38,6 @@
 
 ;;{{{      Internal cooking
 
-(defalias 'eudc-ldap-get-host-parameter
-  (if (fboundp 'ldap-get-host-parameter)
-      #'ldap-get-host-parameter
-    (lambda (host parameter)
-      "Get the value of PARAMETER for HOST in `ldap-host-parameters-alist'."
-      (plist-get (cdr (assoc host ldap-host-parameters-alist))
-                parameter))))
-
 (defvar eudc-ldap-attributes-translation-alist
   '((name . sn)
     (firstname . givenname)
@@ -209,7 +201,7 @@ attribute names are returned.  Default to `person'."
 
 (defun eudc-ldap-check-base ()
   "Check if the current LDAP server has a configured search base."
-  (unless (or (eudc-ldap-get-host-parameter eudc-server 'base)
+  (unless (or (ldap-get-host-parameter eudc-server 'base)
              ldap-default-base
               (null (y-or-n-p "No search base defined.  Configure it now?")))
     ;; If the server is not in ldap-host-parameters-alist we add it for the
@@ -224,6 +216,8 @@ attribute names are returned.  Default to `person'."
 
 (eudc-register-protocol 'ldap)
 
+(define-obsolete-function-alias 'eudc-ldap-get-host-parameter 
#'ldap-get-host-parameter "29.1")
+
 (provide 'eudcb-ldap)
 
 ;;; eudcb-ldap.el ends here
diff --git a/lisp/net/eudcb-macos-contacts.el b/lisp/net/eudcb-macos-contacts.el
index c02b5689e7..7495dcbc9c 100644
--- a/lisp/net/eudcb-macos-contacts.el
+++ b/lisp/net/eudcb-macos-contacts.el
@@ -25,8 +25,17 @@
 ;;    Contacts app on localhost, so no 3rd party tools are needed.
 
 ;;; Usage:
-;;    (require 'eudcb-macos-contacts)
-;;    (eudc-macos-contacts-set-server "localhost")
+;;    To load the library, first `require' it:
+;;
+;;      (require 'eudcb-macos-contacts)
+;;
+;;    In the simplest case then just use:
+;;
+;;      (eudc-macos-contacts-set-server "localhost")
+;;
+;;    When using `eudc-server-hotlist', instead use:
+;;
+;;      (add-to-list 'eudc-server-hotlist '("localhost" . macos-contacts))
 
 ;;; Code:
 
@@ -35,44 +44,139 @@
 
 ;;{{{      Internal cooking
 
-(defvar eudc-macos-contacts-conversion-alist nil)
+(defvar eudc-macos-contacts-attributes-translation-alist
+  '((name      . last_name)
+    (firstname . first_name)
+    (email     . email)
+    (phone     . phone)
+    (title     . job_title)
+    (o         . organization)
+    (ou        . department))
+  "See `eudc-protocol-attributes-translation-alist'.")
+
+(defconst eudc-macos-contacts--unsearchable-attributes
+  '(email phone)
+  "See `eudc-macos-contacts-search-helper'.")
 
 ;; hook ourselves into the EUDC framework
 (eudc-protocol-set 'eudc-query-function
-                  'eudc-macos-contacts-query-internal
-                  'macos-contacts)
+                   'eudc-macos-contacts-query-internal
+                   'macos-contacts)
 (eudc-protocol-set 'eudc-list-attributes-function
-                  nil
-                  'macos-contacts)
-(eudc-protocol-set 'eudc-macos-contacts-conversion-alist
-                  nil
-                  'macos-contacts)
+                   nil
+                   'macos-contacts)
+(eudc-protocol-set 'eudc-protocol-attributes-translation-alist
+                   'eudc-macos-contacts-attributes-translation-alist
+                   'macos-contacts)
 (eudc-protocol-set 'eudc-protocol-has-default-query-attributes
-                  nil
-                  'macos-contacts)
+                   nil
+                   'macos-contacts)
 
-(defun eudc-macos-contacts-search-helper (str)
+(defun eudc-macos-contacts-search-helper (query)
   "Helper function to query the Contacts app via AppleScript.
-Searches for all persons with a case-insensitive substring match
-of STR in any of their name fields (first, middle, or last)."
-  (if (executable-find "osascript")
-      (call-process "osascript" nil t nil
-                   "-e"
-                   (format "
-set results to {}
-tell application \"Address Book\"
-       set pList to every person whose (name contains \"%s\")
-       repeat with pers in pList
-               repeat with emailAddr in emails of pers
-                       set results to results & {name of pers & \":\" & value ¬
-                       of emailAddr & \"\n\"}
-               end repeat
-       end repeat
-       get results as text
-end tell" str))
-    (message (concat "[eudc] Error in macOS Contacts backend: "
-                    "`osascript' executable not found. "
-                    "Is this is a macOS 10.0 or later system?"))))
+Searches for all persons matching QUERY.  QUERY is a list of cons
+cells (ATTR . VALUE) where ATTRs should be valid macOS Contacts
+attribute names with space characters replaced by `_' characters.
+Thus, to for instance search for the \"first name\" attribute in
+the Contacts app, the corresponding ATTR would be the symbol
+`first_name'.
+
+Note that due to the way the Contacts app exposes its data via
+AppleScript, the attributes listed in
+`eudc-macos-contacts--unsearchable-attributes' can not be searched
+efficiently.  If and when one of these attributes appears in
+QUERY, it is thus skipped, and the query is composed from the
+other attributes in the QUERY."
+  (let ((crit-idx 0)
+        (query-str (string)))
+    ;; assemble a query string for use in an AppleScript "whose"
+    ;; filter clause; generally, this has the form
+    ;; (ATTR1 contains "VALUE1") and (ATTR2 contains "VALUE2") and ...
+    (dolist (criterion query)
+      (let ((attr (string-replace "_" " " (symbol-name (car criterion))))
+            (term (cdr criterion)))
+        ;; defend against unusable attribute names as they cause
+        ;; AppleScript to emit an error message, which in turn will
+        ;; cause elisp errors during results parsing in
+        ;; `eudc-macos-contacts-query-internal'
+        (if (or (not (rassq (car criterion)
+                            eudc-macos-contacts-attributes-translation-alist))
+                (memq (car criterion)
+                      eudc-macos-contacts--unsearchable-attributes))
+            (message (concat "[eudc] Warning in macOS Contacts backend: "
+                             "can not search in attribute "
+                             (format "\"%s\"; skipping it."  attr)))
+          (progn
+            (when (> crit-idx 0)
+              (setq query-str (concat query-str " and ")))
+            (setq query-str (concat query-str
+                                    (format "(%s contains \"%s\")" attr term)))
+            (setq crit-idx (1+ crit-idx))))))
+    ;; if a useful query string could be assembled, insert it into the
+    ;; AppleScript template, and run the resulting script; results are
+    ;; captured in the current buffer
+    (if (not (string= query-str ""))
+        (if (executable-find "osascript")
+            (call-process "osascript" nil t nil
+                          "-e"
+                          (format "
+on joinLines(theText)
+        if (theText is missing value) or (theText is \"\") then
+                return \"\"
+        else
+                set thePars to paragraphs of theText
+                set result to {}
+                repeat with para in thePars
+                        set result to result & {para & space}
+                end repeat
+                return text 1 thru -2 of (result as text)
+        end if
+end joinLines
+
+on run
+        set results to {}
+        tell application \"Address Book\"
+                set pList to every person whose %s
+                repeat with pers in pList
+                        set pText to ¬
+                                first name of pers & \":\" & ¬
+                                last name of pers & \":\"
+                        if (job title of pers is not missing value) then ¬
+                                set pText to pText ¬
+                                        & my joinLines(job title of pers)
+                        set pText to pText & \":\"
+                        if (department of pers is not missing value) then ¬
+                                set pText to pText ¬
+                                        & my joinLines(department of pers)
+                        set pText to pText & \":\"
+                        if (organization of pers is not missing value) then ¬
+                                set pText to pText ¬
+                                        & my joinLines(organization of pers)
+                        set pText to pText & \":\"
+                        if (count emails of pers) > 0 then
+                                repeat with emailAddr in emails of pers
+                                        set pText to pText & value ¬
+                                                of emailAddr & \",\"
+                                end repeat
+                                set pText to text 1 thru -2 of pText
+                        end if
+                        set pText to pText & \":\"
+                        if (count phones of pers) > 0 then
+                                repeat with phoneNmbr in phones of pers
+                                        set pText to pText & value ¬
+                                                of phoneNmbr & \",\"
+                                end repeat
+                                set pText to text 1 thru -2 of pText
+                        end if
+                        set results to results & {pText & \"\n\"}
+                end repeat
+                get results as text
+        end tell
+end run
+" query-str))
+          (message (concat "[eudc] Error in macOS Contacts backend: "
+                           "`osascript' executable not found. "
+                           "Is this is a macOS 10.0 or later system?"))))))
 
 (defun eudc-macos-contacts-query-internal (query &optional _return-attrs)
   "Query macOS Contacts with QUERY.
@@ -81,24 +185,29 @@ macOS Contacts attribute names.
 RETURN-ATTRS is a list of attributes to return, defaulting to
 `eudc-default-return-attributes'."
   (let ((macos-contacts-buffer (get-buffer-create " *macOS Contacts*"))
-       result)
+        result)
     (with-current-buffer macos-contacts-buffer
       (erase-buffer)
-      (dolist (term query)
-       (eudc-macos-contacts-search-helper (cdr term)))
+      (eudc-macos-contacts-search-helper query)
       (delete-duplicate-lines (point-min) (point-max))
       (goto-char (point-min))
       (while (not (eobp))
-       (if (not (equal (line-beginning-position) (line-end-position)))
-           (let* ((args (split-string (buffer-substring
-                                       (point) (line-end-position))
-                                      ":"))
-                  (name (nth 0 args))
-                  (email (nth 1 args)))
-             (setq result (cons `((name . ,name)
-                                  (email . ,email))
-                                result))))
-       (forward-line))
+        (if (not (equal (line-beginning-position) (line-end-position)))
+            (let ((keys '(first_name last_name job_title department
+                          organization email phone))
+                  record)
+              (dolist (field (split-string (buffer-substring
+                                            (point) (line-end-position))
+                                           ":"))
+                (let ((key (pop keys)))
+                  (unless (string= "" field)
+                    (pcase key
+                      ((or 'email 'phone) (dolist (x (split-string field ","))
+                                            (push (cons key x) record)))
+                      (_ (push (cons key field) record))))))
+              (unless (length= record 0)
+                (push (nreverse record) result))))
+        (forward-line))
       result)))
 
 ;;}}}
diff --git a/lisp/net/eww.el b/lisp/net/eww.el
index 8f02be12ff..6ed0719eca 100644
--- a/lisp/net/eww.el
+++ b/lisp/net/eww.el
@@ -64,7 +64,7 @@ The action to be taken can be further customized via
   :version "28.1"
   :type 'regexp)
 
-(defun erc--download-directory ()
+(defun eww--download-directory ()
   "Return the name of the download directory.
 If ~/Downloads/ exists, that will be used, and if not, the
 DOWNLOAD XDG user directory will be returned.  If that's
@@ -75,7 +75,7 @@ undefined, ~/Downloads/ is returned anyway."
         (file-name-as-directory dir))
       "~/Downloads/"))
 
-(defcustom eww-download-directory 'erc--download-directory
+(defcustom eww-download-directory 'eww--download-directory
   "Directory where files will downloaded.
 This should either be a directory name or a function (called with
 no parameters) that returns a directory name."
@@ -349,6 +349,8 @@ This can also be used on the command line directly:
 
 will start Emacs and browse the GNU web site."
   (interactive)
+  (unless command-line-args-left
+    (user-error "No URL given"))
   (eww (pop command-line-args-left)))
 
 
@@ -363,7 +365,9 @@ new buffer instead of reusing the default EWW buffer.
 
 If BUFFER, the data to be rendered is in that buffer.  In that
 case, this function doesn't actually fetch URL.  BUFFER will be
-killed after rendering."
+killed after rendering.
+
+For more information, see Info node `(eww) Top'."
   (interactive
    (let ((uris (eww-suggested-uris)))
      (list (read-string (format-prompt "Enter URL or keywords"
@@ -833,7 +837,7 @@ The renaming scheme is performed in accordance with
                (when url
                  (setq url (propertize url 'face 'variable-pitch))
                  (let* ((parsed (url-generic-parse-url url))
-                        (host-length (shr-string-pixel-width
+                        (host-length (string-pixel-width
                                       (propertize
                                        (format "%s://%s" (url-type parsed)
                                                (url-host parsed))
@@ -842,17 +846,17 @@ The renaming scheme is performed in accordance with
                    (cond
                     ;; The host bit is wider than the window, so nix
                     ;; the title.
-                    ((> (+ host-length (shr-string-pixel-width "xxxxx")) width)
+                    ((> (+ host-length (string-pixel-width "xxxxx")) width)
                      (setq title ""))
                     ;; Trim the title.
-                    ((> (+ (shr-string-pixel-width (concat title "xx"))
+                    ((> (+ (string-pixel-width (concat title "xx"))
                            host-length)
                         width)
                      (setq title
                            (concat
                             (eww--limit-string-pixelwise
                              title (- width host-length
-                                      (shr-string-pixel-width
+                                      (string-pixel-width
                                        (propertize "...: " 'face
                                                    'variable-pitch))))
                             (propertize "..." 'face 'variable-pitch)))))))
@@ -932,9 +936,9 @@ The renaming scheme is performed in accordance with
 
 (defun eww-links-at-point ()
   "Return list of URIs, if any, linked at point."
-  (remq nil
-       (list (get-text-property (point) 'shr-url)
-             (get-text-property (point) 'image-url))))
+  (seq-filter #'stringp
+             (list (get-text-property (point) 'shr-url)
+                   (get-text-property (point) 'image-url))))
 
 (defun eww-view-source ()
   "View the HTML source code of the current page."
@@ -1207,6 +1211,8 @@ instead of `browse-url-new-window-flag'."
   (let ((url-allow-non-local-files t))
     (eww url)))
 
+(function-put 'eww-browse-url 'browse-url-browser-kind 'internal)
+
 (defun eww-back-url ()
   "Go to the previously displayed page."
   (interactive nil eww-mode)
diff --git a/lisp/net/imap.el b/lisp/net/imap.el
index ac24efdccb..fe78fbe833 100644
--- a/lisp/net/imap.el
+++ b/lisp/net/imap.el
@@ -175,16 +175,15 @@ the list is tried until a successful connection is made."
   :type '(repeat string))
 
 (defcustom imap-shell-program '("ssh %s imapd"
-                               "rsh %s imapd"
-                               "ssh %g ssh %s imapd"
-                               "rsh %g rsh %s imapd")
+                                "ssh %g ssh %s imapd")
   "A list of strings, containing commands for IMAP connection.
 Within a string, %s is replaced with the server address, %p with port
 number on server, %g with `imap-shell-host', and %l with
 `imap-default-user'.  The program should read IMAP commands from stdin
 and write IMAP response to stdout.  Each entry in the list is tried
 until a successful connection is made."
-  :type '(repeat string))
+  :type '(repeat string)
+  :version "29.1")
 
 (defcustom imap-process-connection-type nil
   "Value for `process-connection-type' to use for Kerberos4, GSSAPI, shell and 
SSL.
@@ -2557,7 +2556,7 @@ Return nil if no complete line has arrived."
                              ;; next line for Courier IMAP bug.
                              (skip-chars-forward " ")
                              (point)))
-               (> (skip-chars-forward "^ )" (point-at-eol)) 0))
+                (> (skip-chars-forward "^ )" (line-end-position)) 0))
       (push (buffer-substring start (point)) flag-list))
     (cl-assert (eq (char-after) ?\)) nil "In imap-parse-flag-list 2")
     (imap-forward)
diff --git a/lisp/net/ldap.el b/lisp/net/ldap.el
index da45457891..5e14589d19 100644
--- a/lisp/net/ldap.el
+++ b/lisp/net/ldap.el
@@ -54,7 +54,7 @@ a separator."
 Initialized from the LDAP library at build time.
 Default value is 389."
   :type '(choice (const :tag "Use library default" nil)
-                (integer :tag "Port number")))
+                 (natnum :tag "Port number")))
 
 (defcustom ldap-default-base nil
   "Default base for LDAP searches.
@@ -694,7 +694,7 @@ an alist of attribute/value pairs."
        (while (progn
                 (skip-chars-forward " \t\n")
                 (not (eobp)))
-         (setq dn (buffer-substring (point) (point-at-eol)))
+          (setq dn (buffer-substring (point) (line-end-position)))
          (forward-line 1)
           (while (looking-at "^\\([A-Za-z][-A-Za-z0-9]*\
 \\|[0-9]+\\(?:\\.[0-9]+\\)*\\)\\(;[-A-Za-z0-9]+\\)*[=:\t ]+\
diff --git a/lisp/net/mailcap.el b/lisp/net/mailcap.el
index 8ba7f1bec3..469643dbca 100644
--- a/lisp/net/mailcap.el
+++ b/lisp/net/mailcap.el
@@ -87,11 +87,9 @@ you have an entry for \"image/*\" in your ~/.mailcap file."
 
 (defcustom mailcap-user-mime-data nil
   "A list of viewers preferred for different MIME types.
-The elements of the list are alists of the following structure
+The elements of the list are lists of the following structure
 
-  ((viewer . VIEWER)
-   (type   . MIME-TYPE)
-   (test   . TEST))
+  (VIEWER MIME-TYPE TEST)
 
 where VIEWER is either a Lisp command, e.g., a major mode, or a
 string containing a shell command for viewing files of the
@@ -974,6 +972,7 @@ If NO-DECODE is non-nil, don't decode STRING."
     (".ai"    . "application/postscript")
     (".jpe"   . "image/jpeg")
     (".jpeg"  . "image/jpeg")
+    (".webp"  . "image/webp")
     (".org"   . "text/x-org"))
   "An alist of file extensions and corresponding MIME content-types.
 This exists for you to customize the information in Lisp.  It is
diff --git a/lisp/net/mairix.el b/lisp/net/mairix.el
index d84763b162..0b99d2a0b7 100644
--- a/lisp/net/mairix.el
+++ b/lisp/net/mairix.el
@@ -743,21 +743,20 @@ VALUES may contain values for editable fields from 
current article."
 
 ;;;; Major mode for editing/deleting/saving searches
 
-(defvar mairix-searches-mode-map
-  (let ((map (make-keymap)))
-    (define-key map [(return)] 'mairix-select-search)
-    (define-key map [(down)] 'mairix-next-search)
-    (define-key map [(up)] 'mairix-previous-search)
-    (define-key map [(right)] 'mairix-next-search)
-    (define-key map [(left)] 'mairix-previous-search)
-    (define-key map "\C-p" 'mairix-previous-search)
-    (define-key map "\C-n" 'mairix-next-search)
-    (define-key map [(q)] 'mairix-select-quit)
-    (define-key map [(e)] 'mairix-select-edit)
-    (define-key map [(d)] 'mairix-select-delete)
-    (define-key map [(s)] 'mairix-select-save)
-    map)
-  "`mairix-searches-mode' keymap.")
+(defvar-keymap mairix-searches-mode-map
+  :doc "`mairix-searches-mode' keymap."
+  :full t
+  "<return>" #'mairix-select-search
+  "<down>"   #'mairix-next-search
+  "<up>"     #'mairix-previous-search
+  "<right>"  #'mairix-next-search
+  "<left>"   #'mairix-previous-search
+  "C-p"      #'mairix-previous-search
+  "C-n"      #'mairix-next-search
+  "q"        #'mairix-select-quit
+  "e"        #'mairix-select-edit
+  "d"        #'mairix-select-delete
+  "s"        #'mairix-select-save)
 
 (defvar mairix-searches-mode-font-lock-keywords
   '(("^\\([0-9]+\\)"
diff --git a/lisp/net/net-utils.el b/lisp/net/net-utils.el
index 411b6ed413..192c8446eb 100644
--- a/lisp/net/net-utils.el
+++ b/lisp/net/net-utils.el
@@ -23,11 +23,10 @@
 
 ;;; Commentary:
 
-;;
 ;; There are three main areas of functionality:
 ;;
 ;; * Wrap common network utility programs (ping, traceroute, netstat,
-;; nslookup, arp, route). Note that these wrappers are of the diagnostic
+;; nslookup, arp, route).  Note that these wrappers are of the diagnostic
 ;; functions of these programs only.
 ;;
 ;; * Implement some very basic protocols in Emacs Lisp (finger and whois)
@@ -39,7 +38,7 @@
 ;;; Code:
 
 ;; On some systems, programs like ifconfig are not in normal user
-;; path, but rather in /sbin, /usr/sbin, etc (but non-root users can
+;; path, but rather in /sbin, /usr/sbin, etc. (but non-root users can
 ;; still use them for queries).  Actually the trend these
 ;; days is for /sbin to be a symlink to /usr/sbin, but we still need to
 ;; search both for older systems.
@@ -176,15 +175,6 @@ This variable is only used if the variable
 `comint-use-prompt-regexp' is non-nil."
   :type  'regexp)
 
-(defcustom dig-program "dig"
-  "Program to query DNS information."
-  :type  'string)
-
-(defcustom dig-program-options nil
-  "Options for the dig program."
-  :type '(repeat string)
-  :version "26.1")
-
 (defcustom ftp-program "ftp"
   "Program to run to do FTP transfers."
   :type  'string)
@@ -280,6 +270,7 @@ This variable is only used if the variable
 
 (define-derived-mode net-utils-mode special-mode "NetworkUtil"
   "Major mode for interacting with an external network utility."
+  :interactive nil
   (setq-local font-lock-defaults
               '((net-utils-font-lock-keywords)))
   (setq-local revert-buffer-function #'net-utils--revert-function))
@@ -288,31 +279,6 @@ This variable is only used if the variable
 ;; Utility functions
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-;; Simplified versions of some at-point functions from ffap.el.
-;; It's not worth loading all of ffap just for these.
-(defun net-utils-machine-at-point ()
-  (let ((pt (point)))
-    (buffer-substring-no-properties
-     (save-excursion
-       (skip-chars-backward "-a-zA-Z0-9.")
-       (point))
-     (save-excursion
-       (skip-chars-forward "-a-zA-Z0-9.")
-       (skip-chars-backward "." pt)
-       (point)))))
-
-(defun net-utils-url-at-point ()
-  (let ((pt (point)))
-    (buffer-substring-no-properties
-     (save-excursion
-       (skip-chars-backward "--:=&?$+@-Z_a-z~#,%")
-       (skip-chars-forward "^A-Za-z0-9" pt)
-       (point))
-     (save-excursion
-       (skip-chars-forward "--:=&?$+@-Z_a-z~#,%")
-       (skip-chars-backward ":;.,!?" pt)
-       (point)))))
-
 (defun net-utils-remove-ctrl-m-filter (process output-string)
   "Remove trailing control Ms."
   (with-current-buffer (process-buffer process)
@@ -464,7 +430,8 @@ This variable is only used if the variable
 If your system's ping continues until interrupted, you can try setting
 `ping-program-options'."
   (interactive
-   (list (read-from-minibuffer "Ping host: " (net-utils-machine-at-point))))
+   (list (let ((default (ffap-machine-at-point)))
+           (read-string (format-prompt "Ping host" default) nil nil default))))
   (let ((options
         (if ping-program-options
             (append ping-program-options (list host))
@@ -475,15 +442,6 @@ If your system's ping continues until interrupted, you can 
try setting
      ping-program
      options)))
 
-;; FIXME -- Needs to be a process filter
-;; (defun netstat-with-filter (filter)
-;;   "Run netstat program."
-;;   (interactive "sFilter: ")
-;;   (netstat)
-;;   (set-buffer (get-buffer "*Netstat*"))
-;;   (goto-char (point-min))
-;;   (delete-matching-lines filter))
-
 ;;;###autoload
 (defun nslookup-host (host &optional name-server)
   "Look up the DNS information for HOST (name or IP address).
@@ -497,7 +455,8 @@ See also: `nslookup-host-ipv4', `nslookup-host-ipv6' for
 non-interactive versions of this function more suitable for use
 in Lisp code."
   (interactive
-   (list (read-from-minibuffer "Lookup host: " (net-utils-machine-at-point))
+   (list (let ((default (ffap-machine-at-point)))
+           (read-string (format-prompt "Lookup host" default) nil nil default))
          (if current-prefix-arg (read-from-minibuffer "Name server: "))))
   (let ((options
          (append nslookup-program-options (list host)
@@ -589,14 +548,12 @@ This command uses `nslookup-program' to look up DNS 
records."
 
 (autoload 'comint-mode "comint" nil t)
 
-(defvar nslookup-mode-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "\t" #'completion-at-point)
-    map))
+(defvar-keymap nslookup-mode-map
+  "TAB" #'completion-at-point)
 
-;; Using a derived mode gives us keymaps, hooks, etc.
 (define-derived-mode nslookup-mode comint-mode "Nslookup"
   "Major mode for interacting with the nslookup program."
+  :interactive nil
   (setq-local font-lock-defaults
               '((nslookup-font-lock-keywords)))
   (setq comint-prompt-regexp nslookup-prompt-regexp)
@@ -611,7 +568,8 @@ Interactively, prompt for NAME-SERVER if invoked with 
prefix argument.
 
 This command uses `dns-lookup-program' for looking up the DNS information."
   (interactive
-   (list (read-from-minibuffer "Lookup host: " (net-utils-machine-at-point))
+   (list (let ((default (ffap-machine-at-point)))
+           (read-string (format-prompt "Lookup host" default) nil nil default))
          (if current-prefix-arg (read-from-minibuffer "Name server: "))))
   (let ((options
          (append dns-lookup-program-options (list host)
@@ -633,20 +591,12 @@ DNS resolution.
 Interactively, prompt for NAME-SERVER if invoked with prefix argument.
 
 This command uses `dig-program' for looking up the DNS information."
+  (declare (obsolete dig "29.1"))
   (interactive
-   (list (read-from-minibuffer "Lookup host: " (net-utils-machine-at-point))
+   (list (let ((default (ffap-machine-at-point)))
+           (read-string (format-prompt "Lookup host" default) nil nil default))
          (if current-prefix-arg (read-from-minibuffer "Name server: "))))
-  (let ((options
-         (append dig-program-options (list host)
-                 (if name-server (list (concat "@" name-server))))))
-  (net-utils-run-program
-   "Dig"
-   (concat "** "
-          (mapconcat #'identity
-                     (list "Dig" host dig-program)
-                     " ** "))
-   dig-program
-   options)))
+  (dig host nil nil nil nil name-server))
 
 (autoload 'comint-exec "comint")
 (declare-function comint-watch-for-password-prompt "comint" (string))
@@ -656,9 +606,8 @@ This command uses `dig-program' for looking up the DNS 
information."
 (defun ftp (host)
   "Run `ftp-program' to connect to HOST."
   (interactive
-   (list
-    (read-from-minibuffer
-     "Ftp to Host: " (net-utils-machine-at-point))))
+   (list (let ((default (ffap-machine-at-point)))
+           (read-string (format-prompt "Ftp to Host" default) nil nil 
default))))
   (let ((buf (get-buffer-create (concat "*ftp [" host "]*"))))
     (set-buffer buf)
     (ftp-mode)
@@ -668,14 +617,12 @@ This command uses `dig-program' for looking up the DNS 
information."
                   (list host)))
     (pop-to-buffer buf)))
 
-(defvar ftp-mode-map
-  (let ((map (make-sparse-keymap)))
-    ;; Occasionally useful
-    (define-key map "\t" #'completion-at-point)
-    map))
+(defvar-keymap ftp-mode-map
+  "TAB" #'completion-at-point)
 
 (define-derived-mode ftp-mode comint-mode "FTP"
   "Major mode for interacting with the ftp program."
+  :interactive nil
   (setq comint-prompt-regexp ftp-prompt-regexp)
   (setq comint-input-autoexpand t)
   ;; Only add the password-prompting hook if it's not already in the
@@ -695,8 +642,8 @@ This command uses `dig-program' for looking up the DNS 
information."
 This command uses `smbclient-program' to connect to HOST."
   (interactive
    (list
-    (read-from-minibuffer
-     "Connect to Host: " (net-utils-machine-at-point))
+    (let ((default (ffap-machine-at-point)))
+      (read-string (format-prompt "Connect to Host" default) nil nil default))
     (read-from-minibuffer "SMB Service: ")))
   (let* ((name (format "smbclient [%s\\%s]" host service))
         (buf (get-buffer-create (concat "*" name "*")))
@@ -714,8 +661,8 @@ This command uses `smbclient-program' to connect to HOST."
 This command uses `smbclient-program' to connect to HOST."
   (interactive
    (list
-    (read-from-minibuffer
-     "Connect to Host: " (net-utils-machine-at-point))))
+    (let ((default (ffap-machine-at-point)))
+      (read-string (format-prompt "Connect to Host" default) nil nil 
default))))
   (let ((buf (get-buffer-create (format "*SMB Shares on %s*" host))))
     (set-buffer buf)
     (smbclient-mode)
@@ -725,6 +672,7 @@ This command uses `smbclient-program' to connect to HOST."
 
 (define-derived-mode smbclient-mode comint-mode "smbclient"
   "Major mode for interacting with the smbclient program."
+  :interactive nil
   (setq comint-prompt-regexp smbclient-prompt-regexp)
   (setq comint-input-autoexpand t)
   ;; Only add the password-prompting hook if it's not already in the
@@ -813,15 +761,15 @@ and `network-connection-service-alist', which see."
   ;; uses a string like "pbreton@cs.umb.edu", we won't ask for the
   ;; host name. If we don't see an "@", we'll prompt for the host.
   (interactive
-    (let* ((answer (read-from-minibuffer "Finger User: "
-                                        (net-utils-url-at-point)))
+    (let* ((answer (let ((default (ffap-url-at-point)))
+                     (read-string (format-prompt "Finger User" default) nil 
nil default)))
           (index  (string-match (regexp-quote "@") answer)))
       (if index
          (list (substring answer 0 index)
                (substring answer (1+ index)))
        (list answer
-             (read-from-minibuffer "At Host: "
-                                   (net-utils-machine-at-point))))))
+              (let ((default (ffap-machine-at-point)))
+                (read-string (format-prompt "At Host" default) nil nil 
default))))))
   (let* ((user-and-host (concat user "@" host))
         (process-name (concat "Finger [" user-and-host "]"))
         (regexps finger-X.500-host-regexps)
@@ -940,10 +888,9 @@ The port is deduced from 
`network-connection-service-alist'."
 ;;; General Network connection
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-;; Using a derived mode gives us keymaps, hooks, etc.
-(define-derived-mode
-  network-connection-mode comint-mode "Network-Connection"
-  "Major mode for interacting with the `network-connection' program.")
+(define-derived-mode network-connection-mode comint-mode "Network-Connection"
+  "Major mode for interacting with the `network-connection' program."
+  :interactive nil)
 
 (defun network-connection-mode-setup (host service)
   (setq-local network-connection-host host)
@@ -955,7 +902,8 @@ The port is deduced from 
`network-connection-service-alist'."
 This command uses `network-connection-service-alist', which see."
   (interactive
    (list
-    (read-from-minibuffer "Host: " (net-utils-machine-at-point))
+    (let ((default (ffap-machine-at-point)))
+      (read-string (format-prompt "Host" default) nil nil default))
     (completing-read "Service: "
                     (mapcar
                       (lambda (elt)
@@ -1008,6 +956,9 @@ This command uses `network-connection-service-alist', 
which see."
       (and old-comint-input-ring
           (setq comint-input-ring old-comint-input-ring)))))
 
+(define-obsolete-function-alias 'net-utils-machine-at-point 
#'ffap-machine-at-point "29.1")
+(define-obsolete-function-alias 'net-utils-url-at-point #'ffap-url-at-point 
"29.1")
+
 (provide 'net-utils)
 
 ;;; net-utils.el ends here
diff --git a/lisp/net/netrc.el b/lisp/net/netrc.el
deleted file mode 100644
index c272c07e4c..0000000000
--- a/lisp/net/netrc.el
+++ /dev/null
@@ -1,238 +0,0 @@
-;;; netrc.el --- .netrc parsing functionality  -*- lexical-binding: t -*-
-
-;; Copyright (C) 1996-2022 Free Software Foundation, Inc.
-
-;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
-;; Keywords: news
-;;
-;;  Modularized by Ted Zlatanov <tzz@lifelogs.com>
-;;  when it was part of Gnus.
-
-;; 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:
-
-;; Just the .netrc parsing functionality, abstracted so other packages
-;; besides Gnus can use it.
-
-;;; Code:
-
-;;;
-;;; .netrc and .authinfo rc parsing
-;;;
-
-(defgroup netrc nil
- "Netrc configuration."
- :group 'comm)
-
-(defcustom netrc-file "~/.authinfo"
-  "File where user credentials are stored."
-  :version "24.1"
-  :type 'file)
-
-(defvar netrc-services-file "/etc/services"
-  "The name of the services file.")
-
-(defvar netrc-cache nil)
-
-(defun netrc-parse (&optional file)
-  "Parse FILE and return a list of all entries in the file."
-  (interactive "fFile to Parse: ")
-  (unless file
-    (setq file netrc-file))
-  (if (listp file)
-      ;; We got already parsed contents; just return it.
-      file
-    (when (file-exists-p file)
-      (with-temp-buffer
-       (let ((tokens '("machine" "default" "login"
-                       "password" "account" "macdef" "force"
-                       "port"))
-             alist elem result pair)
-          (if (and netrc-cache
-                  (equal (car netrc-cache) (file-attribute-modification-time
-                                             (file-attributes file))))
-             (insert (base64-decode-string (rot13-string (cdr netrc-cache))))
-           (insert-file-contents file)
-           (when (string-match "\\.gpg\\'" file)
-             ;; Store the contents of the file heavily encrypted in memory.
-             (setq netrc-cache (cons (file-attribute-modification-time
-                                       (file-attributes file))
-                                     (rot13-string
-                                      (base64-encode-string
-                                       (buffer-string)))))))
-         (goto-char (point-min))
-         ;; Go through the file, line by line.
-         (while (not (eobp))
-           (narrow-to-region (point) (point-at-eol))
-           ;; For each line, get the tokens and values.
-           (while (not (eobp))
-             (skip-chars-forward "\t ")
-             ;; Skip lines that begin with a "#".
-             (if (eq (char-after) ?#)
-                 (goto-char (point-max))
-               (unless (eobp)
-                 (setq elem
-                       (if (= (following-char) ?\")
-                           (read (current-buffer))
-                         (buffer-substring
-                          (point) (progn (skip-chars-forward "^\t ")
-                                         (point)))))
-                 (cond
-                  ((equal elem "macdef")
-                   ;; We skip past the macro definition.
-                   (widen)
-                   (while (and (zerop (forward-line 1))
-                               (looking-at "$")))
-                   (narrow-to-region (point) (point)))
-                  ((member elem tokens)
-                   ;; Tokens that don't have a following value are ignored,
-                   ;; except "default".
-                   (when (and pair (or (cdr pair)
-                                       (equal (car pair) "default")))
-                     (push pair alist))
-                   (setq pair (list elem)))
-                  (t
-                   ;; Values that haven't got a preceding token are ignored.
-                   (when pair
-                     (setcdr pair elem)
-                     (push pair alist)
-                     (setq pair nil)))))))
-           (when alist
-             (push (nreverse alist) result))
-           (setq alist nil
-                 pair nil)
-           (widen)
-           (forward-line 1))
-         (nreverse result))))))
-
-(defun netrc-machine (list machine &optional port defaultport)
-  "Return the netrc values from LIST for MACHINE or for the default entry.
-If PORT specified, only return entries with matching port tokens.
-Entries without port tokens default to DEFAULTPORT."
-  (let ((rest list)
-       result)
-    (while list
-      (when (equal (cdr (assoc "machine" (car list))) machine)
-       (push (car list) result))
-      (pop list))
-    (unless result
-      ;; No machine name matches, so we look for default entries.
-      (while rest
-       (when (assoc "default" (car rest))
-         (let ((elem (car rest)))
-           (setq elem (delete (assoc "default" elem) elem))
-           (push elem result)))
-       (pop rest)))
-    (when result
-      (setq result (nreverse result))
-      (if (not port)
-         (car result)
-       (while (and result
-                   (not (netrc-port-equal
-                         (or port defaultport "nntp")
-                         ;; when port is not given in the netrc file,
-                         ;; it should mean "any port"
-                         (or (netrc-get (car result) "port")
-                             defaultport port))))
-         (pop result))
-       (car result)))))
-
-(defun netrc-machine-user-or-password (mode authinfo-file-or-list machines 
ports defaults)
-  "Get the user name or password according to MODE from AUTHINFO-FILE-OR-LIST.
-Matches a machine from MACHINES and a port from PORTS, giving
-default ports DEFAULTS to `netrc-machine'.
-
-MODE can be \"login\" or \"password\", suitable for passing to
-`netrc-get'."
-  (let ((authinfo-list (if (stringp authinfo-file-or-list)
-                          (netrc-parse authinfo-file-or-list)
-                        authinfo-file-or-list))
-       (ports (or ports '(nil)))
-       (defaults (or defaults '(nil)))
-       info)
-    (if (listp mode)
-       (setq info
-             (mapcar
-              (lambda (mode-element)
-                (netrc-machine-user-or-password
-                 mode-element
-                 authinfo-list
-                 machines
-                 ports
-                 defaults))
-              mode))
-      (dolist (machine machines)
-       (dolist (default defaults)
-         (dolist (port ports)
-           (let ((alist (netrc-machine authinfo-list machine port default)))
-             (setq info (or (netrc-get alist mode) info)))))))
-    info))
-
-(defun netrc-get (alist type)
-  "Return the value of token TYPE from ALIST."
-  (cdr (assoc type alist)))
-
-(defun netrc-port-equal (port1 port2)
-  (when (numberp port1)
-    (setq port1 (or (netrc-find-service-name port1) port1)))
-  (when (numberp port2)
-    (setq port2 (or (netrc-find-service-name port2) port2)))
-  (equal port1 port2))
-
-(defun netrc-parse-services ()
-  (when (file-exists-p netrc-services-file)
-    (let ((services nil))
-      (with-temp-buffer
-       (insert-file-contents netrc-services-file)
-       (while (search-forward "#" nil t)
-         (delete-region (1- (point)) (point-at-eol)))
-       (goto-char (point-min))
-       (while (re-search-forward
-               "^ *\\([^ \n\t]+\\)[ \t]+\\([0-9]+\\)/\\([^ \t\n]+\\)" nil t)
-         (push (list (match-string 1) (string-to-number (match-string 2))
-                     (intern (downcase (match-string 3))))
-               services))
-       (nreverse services)))))
-
-(defun netrc-find-service-name (number &optional type)
-  (let ((services (netrc-parse-services))
-       service)
-    (setq type (or type 'tcp))
-    (while (and (setq service (pop services))
-               (not (and (= number (cadr service))
-                         (eq type (car (cddr service)))))))
-    (car service)))
-
-;;;###autoload
-(defun netrc-credentials (machine &rest ports)
-  "Return a user name/password pair.
-Port specifications will be prioritized in the order they are
-listed in the PORTS list."
-  (let ((list (netrc-parse))
-       found)
-    (if (not ports)
-       (setq found (netrc-machine list machine))
-      (while (and ports
-                 (not found))
-       (setq found (netrc-machine list machine (pop ports)))))
-    (when found
-      (list (cdr (assoc "login" found))
-           (cdr (assoc "password" found))))))
-
-(provide 'netrc)
-
-;;; netrc.el ends here
diff --git a/lisp/net/newst-backend.el b/lisp/net/newst-backend.el
index 7ae58884f9..f65ef522f2 100644
--- a/lisp/net/newst-backend.el
+++ b/lisp/net/newst-backend.el
@@ -40,7 +40,6 @@
 
 ;; Silence warnings
 (defvar newsticker-groups)
-(defvar w3-mode-map)
 (defvar w3m-minor-mode-map)
 
 (defvar newsticker--retrieval-timer-list nil
@@ -1553,12 +1552,8 @@ argument, which is one of the items in ITEMLIST."
 
 (defun newsticker--remove-whitespace (string)
   "Remove leading and trailing whitespace from STRING."
-  ;; we must have ...+ but not ...* in the regexps otherwise xemacs loops
-  ;; endlessly...
-  (when (and string (stringp string))
-    (replace-regexp-in-string
-     "[ \t\r\n]+$" ""
-     (replace-regexp-in-string "^[ \t\r\n]+" "" string))))
+  (when (stringp string)
+    (string-trim string)))
 
 (defun newsticker--do-forget-preformatted (item)
   "Forget pre-formatted data for ITEM.
diff --git a/lisp/net/newst-plainview.el b/lisp/net/newst-plainview.el
index df574dfa2f..4eb6f6c695 100644
--- a/lisp/net/newst-plainview.el
+++ b/lisp/net/newst-plainview.el
@@ -37,7 +37,6 @@
 (require 'xml)
 
 ;; Silence warnings
-(defvar w3-mode-map)
 (defvar w3m-minor-mode-map)
 
 ;; ======================================================================
@@ -1232,7 +1231,6 @@ item-retrieval time is added as well."
   (newsticker--buffer-do-insert-text item 'desc feed-name-symbol))
 
 (defvar w3m-fill-column)
-(defvar w3-maximum-line-length)
 
 (defun newsticker--buffer-do-insert-text (item type feed-name-symbol)
   "Actually insert contents of news item, format it, render it and all that.
@@ -1366,19 +1364,14 @@ FEED-NAME-SYMBOL tells to which feed this item belongs."
                             "</?[A-Za-z1-6]*\\|&#?[A-Za-z0-9]+;" pos-text-end 
t)
                        ;; (message "%s" (newsticker--title item))
                        (let ((w3m-fill-column (if newsticker-use-full-width
-                                                  -1 fill-column))
-                             (w3-maximum-line-length
-                              (if newsticker-use-full-width nil fill-column)))
+                                                  -1 fill-column)))
                          (save-excursion
                            (funcall newsticker-html-renderer pos-text-start
                                     pos-text-end)))
-                       (cond ((eq newsticker-html-renderer 'w3m-region)
-                              (add-text-properties pos (point-max)
-                                                   (list 'keymap
-                                                         w3m-minor-mode-map)))
-                             ((eq newsticker-html-renderer 'w3-region)
-                              (add-text-properties pos (point-max)
-                                                   (list 'keymap 
w3-mode-map))))
+                       (when (eq newsticker-html-renderer 'w3m-region)
+                         (add-text-properties pos (point-max)
+                                              (list 'keymap
+                                                    w3m-minor-mode-map)))
                        (setq is-rendered-HTML t)))
                  (error
                   (message "Error: HTML rendering failed: %s, %s"
diff --git a/lisp/net/newst-reader.el b/lisp/net/newst-reader.el
index 7e00ac93e7..4a7f0b8e3e 100644
--- a/lisp/net/newst-reader.el
+++ b/lisp/net/newst-reader.el
@@ -112,18 +112,18 @@ window is used when filling.  See also 
`newsticker-justification'."
   "Function for rendering HTML contents.
 If non-nil, newsticker.el will call this function whenever it
 finds HTML-like tags in item descriptions.
-Possible functions include `shr-render-region', `w3m-region', `w3-region', and
+Possible functions include `shr-render-region', `w3m-region', and
 `newsticker-htmlr-render'.
-Newsticker automatically loads the respective package w3m, w3, or
+Newsticker automatically loads the respective package w3m, or
 htmlr if this option is set."
   :type '(choice :tag "Function"
                  (const :tag "None" nil)
                  (const :tag "SHR" shr-render-region)
-                 (const :tag "w3" w3-region)
                  (const :tag "w3m" w3m-region)
                  (const :tag "htmlr" newsticker-htmlr-render))
   :set #'newsticker--set-customvar-formatting
-  :group 'newsticker-reader)
+  :group 'newsticker-reader
+  :version "29.1")
 
 (defcustom newsticker-date-format
   "(%A, %H:%M)"
@@ -315,8 +315,6 @@ Return the image."
   (if newsticker-html-renderer
       (cond ((eq newsticker-html-renderer 'w3m-region)
              (require 'w3m))
-            ((eq newsticker-html-renderer 'w3-region)
-             (require 'w3-auto))
             ((eq newsticker-html-renderer 'newsticker-htmlr-render)
              (require 'htmlr))))
   (funcall newsticker-frontend))
diff --git a/lisp/net/newst-treeview.el b/lisp/net/newst-treeview.el
index b429a33dec..a1ac55bc7a 100644
--- a/lisp/net/newst-treeview.el
+++ b/lisp/net/newst-treeview.el
@@ -252,7 +252,6 @@ their id stays constant."
 
 (declare-function w3m-toggle-inline-images "ext:w3m" (&optional force 
no-cache))
 (defvar w3m-fill-column)
-(defvar w3-maximum-line-length)
 
 (defun newsticker--treeview-render-text (start end)
   "Render text between markers START and END."
@@ -272,17 +271,13 @@ their id stays constant."
                      "</?[A-Za-z1-6]*\\|&#?[A-Za-z0-9]+;" end t)
                 ;; (message "%s" (newsticker--title item))
                 (let ((w3m-fill-column (if newsticker-use-full-width
-                                           -1 fill-column))
-                      (w3-maximum-line-length
-                       (if newsticker-use-full-width nil fill-column)))
+                                           -1 fill-column)))
                   (select-window (newsticker--treeview-item-window))
                   (save-excursion
                     (funcall newsticker-html-renderer start end)))
                 ;;(cond ((eq newsticker-html-renderer 'w3m-region)
                 ;;     (add-text-properties start end (list 'keymap
                 ;;                                        w3m-minor-mode-map)))
-                ;;((eq newsticker-html-renderer 'w3-region)
-                ;;(add-text-properties start end (list 'keymap w3-mode-map))))
                 (if (eq newsticker-html-renderer 'w3m-region)
                     (w3m-toggle-inline-images t))
                 t)))
@@ -366,7 +361,8 @@ AGES is the list of ages that are to be shown."
   (mapc (lambda (feed)
           (let ((feed-name-symbol (intern (car feed))))
             (mapc (lambda (item)
-                    (when (memq (newsticker--age item) ages)
+                    (when (or (memq 'all ages)
+                              (memq (newsticker--age item) ages))
                       (newsticker--treeview-list-add-item
                        item feed-name-symbol t)))
                   (newsticker--treeview-list-sort-items
@@ -545,7 +541,7 @@ The sort function is chosen according to the value of
         (let ((inhibit-read-only t))
           (goto-char (point-min))
           (while (not (eobp))
-            (let* ((pos (point-at-eol))
+            (let* ((pos (line-end-position))
                    (item (get-text-property (point) :nt-item))
                    (age (newsticker--age item))
                    (selected (get-text-property (point) :nt-selected))
@@ -583,7 +579,8 @@ The sort function is chosen according to the value of
   (newsticker--treeview-list-clear-highlight)
   (with-current-buffer (newsticker--treeview-list-buffer)
     (let ((inhibit-read-only t))
-      (put-text-property (point-at-bol) (point-at-eol) :nt-selected t))
+      (put-text-property (line-beginning-position) (line-end-position)
+                         :nt-selected t))
     (newsticker--treeview-list-update-faces)))
 
 (defun newsticker--treeview-list-highlight-start ()
@@ -608,14 +605,10 @@ If CLEAR-BUFFER is non-nil the list buffer is completely 
erased."
     (newsticker--treeview-list-update-faces)
     (goto-char (point-min))))
 
-(defvar newsticker-treeview-list-sort-button-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map [header-line mouse-1]
-      #'newsticker--treeview-list-sort-by-column)
-    (define-key map [header-line mouse-2]
-      #'newsticker--treeview-list-sort-by-column)
-    map)
-  "Local keymap for newsticker treeview list window sort buttons.")
+(defvar-keymap newsticker-treeview-list-sort-button-map
+  :doc "Local keymap for newsticker treeview list window sort buttons."
+  "<header-line> <mouse-1>" #'newsticker--treeview-list-sort-by-column
+  "<header-line> <mouse-2>" #'newsticker--treeview-list-sort-by-column)
 
 (defun newsticker--treeview-list-sort-by-column (&optional event)
   "Sort the newsticker list window buffer by the column clicked on.
@@ -1088,7 +1081,7 @@ Arguments are ignored."
       (with-current-buffer (newsticker--treeview-tree-buffer)
         (goto-char pos)
         (move-overlay newsticker--tree-selection-overlay
-                      (point-at-bol) (1+ (point-at-eol))
+                      (line-beginning-position) (1+ (line-end-position))
                       (current-buffer)))
       (if (window-live-p (newsticker--treeview-tree-window))
           (set-window-point (newsticker--treeview-tree-window) pos)))))
@@ -1227,11 +1220,11 @@ Note: does not update the layout."
     (newsticker--treeview-list-update t)
     (newsticker--treeview-item-update)
     (newsticker--treeview-tree-update-tags)
-    (cond (newsticker--treeview-current-feed
-           (newsticker--treeview-list-items newsticker--treeview-current-feed))
-          (newsticker--treeview-current-vfeed
+    (cond (newsticker--treeview-current-vfeed
            (newsticker--treeview-list-items-with-age
-            (intern newsticker--treeview-current-vfeed))))
+            (intern newsticker--treeview-current-vfeed)))
+          (newsticker--treeview-current-feed
+           (newsticker--treeview-list-items 
newsticker--treeview-current-feed)))
     (newsticker--treeview-tree-update-highlight)
     (newsticker--treeview-list-update-highlight)
     (let ((cur-feed (or newsticker--treeview-current-feed
@@ -2012,41 +2005,39 @@ Return t if groups have changed, nil otherwise."
     menu)
   "Map for newsticker item menu.")
 
-(defvar newsticker-treeview-mode-map
-  (let ((map (make-sparse-keymap 'newsticker-treeview-mode-map)))
-    (define-key map " " #'newsticker-treeview-next-page)
-    (define-key map "a" #'newsticker-add-url)
-    (define-key map "b" #'newsticker-treeview-browse-url-item)
-    (define-key map "c" #'newsticker-treeview-customize-current-feed)
-    (define-key map "F" #'newsticker-treeview-prev-feed)
-    (define-key map "f" #'newsticker-treeview-next-feed)
-    (define-key map "g" #'newsticker-treeview-get-news)
-    (define-key map "G" #'newsticker-get-all-news)
-    (define-key map "i" #'newsticker-treeview-toggle-item-immortal)
-    (define-key map "j" #'newsticker-treeview-jump)
-    (define-key map "n" #'newsticker-treeview-next-item)
-    (define-key map "N" #'newsticker-treeview-next-new-or-immortal-item)
-    (define-key map "O" #'newsticker-treeview-mark-list-items-old)
-    (define-key map "o" #'newsticker-treeview-mark-item-old)
-    (define-key map "p" #'newsticker-treeview-prev-item)
-    (define-key map "P" #'newsticker-treeview-prev-new-or-immortal-item)
-    (define-key map "q" #'newsticker-treeview-quit)
-    (define-key map "S" #'newsticker-treeview-save-item)
-    (define-key map "s" #'newsticker-treeview-save)
-    (define-key map "u" #'newsticker-treeview-update)
-    (define-key map "v" #'newsticker-treeview-browse-url)
-    ;;(define-key map "\n" #'newsticker-treeview-scroll-item)
-    ;;(define-key map "\C-m" #'newsticker-treeview-scroll-item)
-    (define-key map "\M-m" #'newsticker-group-move-feed)
-    (define-key map "\M-a" #'newsticker-group-add-group)
-    (define-key map "\M-d" #'newsticker-group-delete-group)
-    (define-key map "\M-r" #'newsticker-group-rename-group)
-    (define-key map [M-down] #'newsticker-group-shift-feed-down)
-    (define-key map [M-up] #'newsticker-group-shift-feed-up)
-    (define-key map [M-S-down] #'newsticker-group-shift-group-down)
-    (define-key map [M-S-up] #'newsticker-group-shift-group-up)
-    map)
-  "Mode map for newsticker treeview.")
+(defvar-keymap newsticker-treeview-mode-map
+  :doc "Mode map for newsticker treeview."
+  "SPC"        #'newsticker-treeview-next-page
+  "a"          #'newsticker-add-url
+  "b"          #'newsticker-treeview-browse-url-item
+  "c"          #'newsticker-treeview-customize-current-feed
+  "F"          #'newsticker-treeview-prev-feed
+  "f"          #'newsticker-treeview-next-feed
+  "g"          #'newsticker-treeview-get-news
+  "G"          #'newsticker-get-all-news
+  "i"          #'newsticker-treeview-toggle-item-immortal
+  "j"          #'newsticker-treeview-jump
+  "n"          #'newsticker-treeview-next-item
+  "N"          #'newsticker-treeview-next-new-or-immortal-item
+  "O"          #'newsticker-treeview-mark-list-items-old
+  "o"          #'newsticker-treeview-mark-item-old
+  "p"          #'newsticker-treeview-prev-item
+  "P"          #'newsticker-treeview-prev-new-or-immortal-item
+  "q"          #'newsticker-treeview-quit
+  "S"          #'newsticker-treeview-save-item
+  "s"          #'newsticker-treeview-save
+  "u"          #'newsticker-treeview-update
+  "v"          #'newsticker-treeview-browse-url
+  ;;"C-j"      #'newsticker-treeview-scroll-item
+  ;;"RET"      #'newsticker-treeview-scroll-item
+  "M-m"        #'newsticker-group-move-feed
+  "M-a"        #'newsticker-group-add-group
+  "M-d"        #'newsticker-group-delete-group
+  "M-r"        #'newsticker-group-rename-group
+  "M-<down>"   #'newsticker-group-shift-feed-down
+  "M-<up>"     #'newsticker-group-shift-feed-up
+  "M-S-<down>" #'newsticker-group-shift-group-down
+  "M-S-<up>"   #'newsticker-group-shift-group-up)
 
 (define-derived-mode newsticker-treeview-mode fundamental-mode "Newsticker TV"
   "Major mode for Newsticker Treeview.
diff --git a/lisp/net/pop3.el b/lisp/net/pop3.el
index 0f6dfb6ad4..9d59ddf978 100644
--- a/lisp/net/pop3.el
+++ b/lisp/net/pop3.el
@@ -59,7 +59,7 @@
 (defcustom pop3-port 110
   "POP3 port."
   :version "22.1" ;; Oort Gnus
-  :type 'number
+  :type 'natnum
   :group 'pop3)
 
 (defcustom pop3-password-required t
@@ -88,7 +88,7 @@ valid value is `apop'."
 The lower the number, the more latency-sensitive the fetching
 will be.  If your pop3 server doesn't support streaming at all,
 set this to 1."
-  :type 'number
+  :type 'natnum
   :version "24.1"
   :group 'pop3)
 
@@ -469,7 +469,7 @@ Return non-nil if it is necessary to update the local UIDL 
file."
              (delete-char -3)
              (if (eq (char-before) ?\))
                  (insert ")\n ")
-               (goto-char (1+ (point-at-bol)))
+                (goto-char (1+ (line-beginning-position)))
                (delete-region (point) (point-max)))))
          (when (eq (char-before) ? )
            (delete-char -2))
diff --git a/lisp/net/quickurl.el b/lisp/net/quickurl.el
deleted file mode 100644
index 598a7da071..0000000000
--- a/lisp/net/quickurl.el
+++ /dev/null
@@ -1,525 +0,0 @@
-;;; quickurl.el --- insert a URL based on text at point in buffer  -*- 
lexical-binding: t; -*-
-
-;; Copyright (C) 1999-2022 Free Software Foundation, Inc.
-
-;; Author: Dave Pearson <davep@davep.org>
-;; Created: 1999-05-28
-;; Keywords: hypermedia
-
-;; 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 package provides a simple method of inserting a URL based on the
-;; text at point in the current buffer.  This is part of an on-going effort
-;; to increase the information I provide people while reducing the amount
-;; of typing I need to do.  No-doubt there are undiscovered Emacs packages
-;; out there that do all of this and do it better, feel free to point me to
-;; them, in the mean time I'm having fun playing with Emacs Lisp.
-;;
-;; The URLs are stored in an external file as a list of either cons cells,
-;; or lists.  A cons cell entry looks like this:
-;;
-;;    (<Lookup> . <URL>)
-;;
-;; where <Lookup> is a string that acts as the keyword lookup and <URL> is
-;; the URL associated with it.  An example might be:
-;;
-;;    ("GNU" . "https://www.gnu.org/";)
-;;
-;; A list entry looks like:
-;;
-;;    (<Lookup> <URL> <Comment>)
-;;
-;; where <Lookup> and <URL> are the same as with the cons cell and <Comment>
-;; is any text you like that describes the URL.  This description will be
-;; used when presenting a list of URLS using `quickurl-list'.  An example
-;; might be:
-;;
-;;    ("FSF" "https://www.fsf.org/"; "The Free Software Foundation")
-;;
-;; Given the above, your quickurl file might look like:
-;;
-;; (("GNU"    . "https://www.gnu.org/";)
-;;  ("FSF"      "https://www.fsf.org/"; "The Free Software Foundation")
-;;  ("emacs"  . "https://www.emacs.org/";)
-;;  ("davep"    "http://www.davep.org/"; "Dave's homepage"))
-;;
-;; In case you're wondering about the mixture of cons cells and lists,
-;; quickurl started life using just the cons cells, there were no comments.
-;; URL comments are a later addition and so there is a mixture to keep
-;; backward compatibility with existing URL lists.
-;;
-;; The name and location of the file is up to you, the default name used by
-;; `quickurl' is stored in `quickurl-url-file'.
-;;
-;; quickurl is always available from:
-;;
-;;   <URL:http://www.davep.org/emacs/quickurl.el>
-
-;;; TODO:
-;;
-;; o The quickurl-browse-url* functions pretty much duplicate their non
-;;   browsing friends. It would feel better if a more generic solution could
-;;   be found.
-
-;;; Code:
-
-;; Things we need:
-
-(eval-when-compile (require 'cl-lib))
-(require 'thingatpt)
-(require 'pp)
-(require 'browse-url)
-
-;; Customize options.
-
-(defgroup quickurl nil
-  "Insert a URL based on text at point in buffer."
-  :version "21.1"
-  :group  'abbrev
-  :prefix "quickurl-")
-
-(defcustom quickurl-url-file
-  (locate-user-emacs-file "quickurls" ".quickurls")
-  "File that contains the URL list."
-  :version "24.4"                       ; added locate-user-emacs-file
-  :type  'file)
-
-(defcustom quickurl-format-function #'quickurl-format-url
-  "Function to format the URL before insertion into the current buffer."
-  :type  'function)
-
-(defcustom quickurl-sort-function #'quickurl-sort-urls
-  "Function to sort the URL list."
-  :type  'function)
-
-(defcustom quickurl-grab-lookup-function #'current-word
-  "Function to grab the thing to lookup."
-  :type  'function)
-
-(defun quickurl--assoc-function (key alist)
-  "Default function for `quickurl-assoc-function'."
-  (assoc-string key alist t))
-
-(defcustom quickurl-assoc-function #'quickurl--assoc-function
-  "Function to use for alist lookup into `quickurl-urls'."
-  :version "26.1"                 ; was the obsolete assoc-ignore-case
-  :type  'function)
-
-(defcustom quickurl-completion-ignore-case t
-  "Should `quickurl-ask' ignore case when doing the input lookup?"
-  :type  'boolean)
-
-(defcustom quickurl-prefix ";; -*- lisp -*-\n\n"
-  "Text to write to `quickurl-url-file' before writing the URL list."
-  :type  'string)
-
-(defcustom quickurl-postfix ""
-  "Text to write to `quickurl-url-file' after writing the URL list.
-
-See the constant `quickurl-reread-hook-postfix' for some example text that
-could be used here."
-  :type  'string)
-
-(defcustom quickurl-list-mode-hook nil
-  "Hooks for `quickurl-list-mode'."
-  :type  'hook)
-
-;; Constants.
-
-;;;###autoload
-(defconst quickurl-reread-hook-postfix
-    "
-;; Local Variables:
-;; eval: (progn (require 'quickurl) (add-hook 'write-file-functions (lambda () 
(quickurl-read) nil) nil t))
-;; End:
-"
-  "Example `quickurl-postfix' text that adds a local variable to the
-`quickurl-url-file' so that if you edit it by hand it will ensure that
-`quickurl-urls' is updated with the new URL list.
-
-To make use of this do something like:
-
-  (setq quickurl-postfix quickurl-reread-hook-postfix)
-
-in your init file (after loading/requiring quickurl).")
-
-;; Non-customize variables.
-
-(defvar quickurl-urls nil
-  "URL alist for use with `quickurl' and `quickurl-ask'.")
-
-(defvar quickurl-list-mode-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "a"           #'quickurl-list-add-url)
-    (define-key map [(control m)] #'quickurl-list-insert-url)
-    (define-key map "u"           #'quickurl-list-insert-naked-url)
-    (define-key map " "           #'quickurl-list-insert-with-lookup)
-    (define-key map "l"           #'quickurl-list-insert-lookup)
-    (define-key map "d"           #'quickurl-list-insert-with-desc)
-    (define-key map [(control g)] #'quickurl-list-quit)
-    (define-key map "q"           #'quickurl-list-quit)
-    (define-key map [mouse-2]     #'quickurl-list-mouse-select)
-    map)
-  "Local keymap for a `quickurl-list-mode' buffer.")
-
-(defvar quickurl-list-buffer-name "*quickurl-list*"
-  "Name for the URL listing buffer.")
-
-(defvar quickurl-list-last-buffer nil
-  "`current-buffer' when `quickurl-list' was called.")
-
-;; Functions for working with a URL entry.
-
-(defun quickurl-url-commented-p (url)
-  "Does the URL have a comment?"
-  (listp (cdr url)))
-
-(defun quickurl-make-url (keyword url &optional comment)
-  "Create a URL from KEYWORD, URL and (optionally) COMMENT."
-  (if (and comment (not (zerop (length comment))))
-      (list keyword url comment)
-    (cons keyword url)))
-
-(defalias 'quickurl-url-keyword #'car
-  "Return the keyword for the URL.
-\n\(fn URL)")
-
-(defun quickurl-url-url (url)
-  "Return the actual URL of the URL.
-
-Note that this function is a setfable place."
-  (declare (gv-setter (lambda (store)
-                        `(setf (if (quickurl-url-commented-p ,url)
-                                   (cadr ,url)
-                                 (cdr ,url))
-                               ,store))))
-  (if (quickurl-url-commented-p url)
-      (cadr url)
-    (cdr url)))
-
-(defun quickurl-url-comment (url)
-  "Get the comment from a URL.
-
-If the URL has no comment an empty string is returned.  Also note
-that this function is a setfable place."
-  (declare
-   (gv-setter (lambda (store)
-                `(if (quickurl-url-commented-p ,url)
-                     (if (zerop (length ,store))
-                         (setf (cdr ,url) (cadr ,url))
-                       (setf (nth 2 ,url) ,store))
-                   (unless (zerop (length ,store))
-                     (setf (cdr ,url) (list (cdr ,url) ,store)))))))
-  (if (quickurl-url-commented-p url)
-      (nth 2 url)
-    ""))
-
-(defun quickurl-url-description (url)
-  "Return a description for the URL.
-
-If the URL has a comment then this is returned, otherwise the keyword is
-returned."
-  (let ((desc (quickurl-url-comment url)))
-    (if (zerop (length desc))
-        (quickurl-url-keyword url)
-      desc)))
-
-;; Main code:
-
-(defun quickurl-format-url (url)
-  (format "<URL:%s>" (quickurl-url-url url)))
-
-(defun quickurl-sort-urls (list)
-  "Sort URLs in LIST according to their `quickurl-url-description'."
-  (sort list
-        (lambda (x y)
-          (string<
-           (downcase (quickurl-url-description x))
-           (downcase (quickurl-url-description y))))))
-
-(defun quickurl-read (&optional buffer)
-  "`read' the URL list from BUFFER into `quickurl-urls'.
-
-BUFFER, if nil, defaults to current buffer.
-Note that this function moves point to `point-min' before doing the `read'
-It also restores point after the `read'."
-  (save-excursion
-    (goto-char (point-min))
-    (setq quickurl-urls (funcall quickurl-sort-function
-                                 (read (or buffer (current-buffer)))))))
-
-(defun quickurl-load-urls ()
-  "Load the contents of `quickurl-url-file' into `quickurl-urls'."
-  (when (file-exists-p quickurl-url-file)
-    (with-temp-buffer
-      (insert-file-contents quickurl-url-file)
-      (quickurl-read))))
-
-(defun quickurl-save-urls ()
-  "Save the contents of `quickurl-urls' to `quickurl-url-file'."
-  (with-temp-buffer
-    (let ((standard-output (current-buffer))
-          (print-length nil))
-      (princ quickurl-prefix)
-      (pp quickurl-urls)
-      (princ quickurl-postfix)
-      (write-region (point-min) (point-max) quickurl-url-file nil 0))))
-
-(defun quickurl-find-url (lookup)
-  "Return URL associated with key LOOKUP.
-
-The lookup is done by looking in the alist `quickurl-urls' and the `cons'
-for the URL is returned.  The actual method used to look into the alist
-depends on the setting of the variable `quickurl-assoc-function'."
-  (funcall quickurl-assoc-function lookup quickurl-urls))
-
-(defun quickurl-insert (url &optional silent)
-  "Insert URL, formatted using `quickurl-format-function'.
-
-Also display a `message' saying what the URL was unless SILENT is non-nil."
-  (insert (funcall quickurl-format-function url))
-  (unless silent
-    (message "Found %s" (quickurl-url-url url))))
-
-;;;###autoload
-(defun quickurl (&optional lookup)
-  "Insert a URL based on LOOKUP.
-
-If not supplied LOOKUP is taken to be the word at point in the current
-buffer, this default action can be modified via
-`quickurl-grab-lookup-function'."
-  (interactive)
-  (when (or lookup
-            (setq lookup (funcall quickurl-grab-lookup-function)))
-    (quickurl-load-urls)
-    (let ((url (quickurl-find-url lookup)))
-      (if (null url)
-          (error "No URL associated with \"%s\"" lookup)
-        (when (looking-at "\\w")
-          (skip-syntax-forward "\\w"))
-        (insert " ")
-        (quickurl-insert url)))))
-
-;;;###autoload
-(defun quickurl-ask (lookup)
-  "Insert a URL, with `completing-read' prompt, based on LOOKUP."
-  (interactive
-   (list
-    (progn
-      (quickurl-load-urls)
-      (let ((completion-ignore-case quickurl-completion-ignore-case))
-        (completing-read "Lookup: " quickurl-urls nil t)))))
-  (let ((url (quickurl-find-url lookup)))
-    (when url
-      (quickurl-insert url))))
-
-(defun quickurl-grab-url ()
-  "Attempt to grab a word/URL pair from point in the current buffer.
-
-Point should be somewhere on the URL and the word is taken to be the thing
-that is returned from calling `quickurl-grab-lookup-function' once a
-`backward-word' has been issued at the start of the URL.
-
-It is assumed that the URL is either \"unguarded\" or is wrapped inside an
-<URL:...> wrapper."
-  (let ((url (thing-at-point 'url)))
-    (when url
-      (save-excursion
-        (beginning-of-thing 'url)
-        ;; `beginning-of-thing' doesn't take you to the start of a marked-up
-        ;; URL, only to the start of the URL within the "markup". So, we
-        ;; need to do a little more work to get to where we want to be.
-        (when (thing-at-point-looking-at thing-at-point-markedup-url-regexp)
-          (search-backward "<URL:"))
-        (backward-word-strictly 1)
-        (let ((word (funcall quickurl-grab-lookup-function)))
-          (when word
-            (quickurl-make-url
-             ;; The grab function may return the word with properties. I don't
-             ;; want the properties. I couldn't find a method of stripping
-             ;; them from a "string" so this will have to do. If you know of
-             ;; a better method of doing this I'd love to know.
-             (with-temp-buffer
-               (insert word)
-               (buffer-substring-no-properties (point-min) (point-max)))
-             url)))))))
-
-;;;###autoload
-(defun quickurl-add-url (word url comment)
-  "Allow the user to interactively add a new URL associated with WORD.
-
-See `quickurl-grab-url' for details on how the default word/URL combination
-is decided."
-  (interactive (let ((word-url (quickurl-grab-url)))
-                 (list (read-string "Word: "    (quickurl-url-keyword 
word-url))
-                       (read-string "URL: "     (quickurl-url-url word-url))
-                       (read-string "Comment: " (quickurl-url-comment 
word-url)))))
-  (if (zerop (length word))
-      (error "You must specify a WORD for lookup")
-    (quickurl-load-urls)
-    (let* ((current-url (quickurl-find-url word))
-           (add-it      (if current-url
-                            (if (called-interactively-p 'interactive)
-                                (y-or-n-p (format "\"%s\" exists, replace URL? 
" word))
-                              t)
-                          t)))
-      (when add-it
-        (if current-url
-            (progn
-              (setf (quickurl-url-url current-url) url)
-              (setf (quickurl-url-comment current-url) comment))
-          (push (quickurl-make-url word url comment) quickurl-urls))
-        (setq quickurl-urls (funcall quickurl-sort-function quickurl-urls))
-        (quickurl-save-urls)
-        (when (get-buffer quickurl-list-buffer-name)
-          (quickurl-list-populate-buffer))
-        (when (called-interactively-p 'interactive)
-          (message "Added %s" url))))))
-
-;;;###autoload
-(defun quickurl-browse-url (&optional lookup)
-  "Browse the URL associated with LOOKUP.
-
-If not supplied LOOKUP is taken to be the word at point in the
-current buffer, this default action can be modified via
-`quickurl-grab-lookup-function'."
-  (interactive)
-  (when (or lookup
-            (setq lookup (funcall quickurl-grab-lookup-function)))
-    (quickurl-load-urls)
-    (let ((url (quickurl-find-url lookup)))
-      (if url
-          (browse-url (quickurl-url-url url))
-        (error "No URL associated with \"%s\"" lookup)))))
-
-;;;###autoload
-(defun quickurl-browse-url-ask (lookup)
-  "Browse the URL, with `completing-read' prompt, associated with LOOKUP."
-  (interactive (list
-                (progn
-                  (quickurl-load-urls)
-                  (completing-read "Browse: " quickurl-urls nil t))))
-  (let ((url (quickurl-find-url lookup)))
-    (when url
-      (browse-url (quickurl-url-url url)))))
-
-;;;###autoload
-(defun quickurl-edit-urls ()
-  "Pull `quickurl-url-file' into a buffer for hand editing."
-  (interactive)
-  (find-file quickurl-url-file))
-
-;; quickurl-list mode.
-
-;;;###autoload
-(define-derived-mode quickurl-list-mode special-mode "Quickurl"
-  "A mode for browsing the quickurl URL list.
-
-The key bindings for `quickurl-list-mode' are:
-
-\\{quickurl-list-mode-map}"
-  (setq truncate-lines t))
-
-;;;###autoload
-(defun quickurl-list ()
-  "Display `quickurl-list' as a formatted list using `quickurl-list-mode'."
-  (interactive)
-  (quickurl-load-urls)
-  (unless (string= (buffer-name) quickurl-list-buffer-name)
-    (setq quickurl-list-last-buffer (current-buffer)))
-  (pop-to-buffer quickurl-list-buffer-name)
-  (quickurl-list-populate-buffer)
-  (quickurl-list-mode))
-
-(defun quickurl-list-populate-buffer ()
-  "Populate the `quickurl-list' buffer."
-  (with-current-buffer (get-buffer quickurl-list-buffer-name)
-    (let* ((sizes (or (cl-loop for url in quickurl-urls
-                               collect (length (quickurl-url-description url)))
-                      (list 20)))
-           (fmt (format "%%-%ds %%s\n" (apply #'max sizes)))
-           (inhibit-read-only t))
-      (erase-buffer)
-      (dolist (url quickurl-urls)
-        (let ((start (point)))
-          (insert (format fmt (quickurl-url-description url)
-                          (quickurl-url-url url)))
-          (add-text-properties
-           start (1- (point))
-           '(mouse-face highlight help-echo "mouse-2: insert this URL"))))
-      (goto-char (point-min)))))
-
-(defun quickurl-list-add-url (word url comment)
-  "Wrapper for `quickurl-add-url' that doesn't guess the parameters."
-  (interactive "sWord: \nsURL: \nsComment: ")
-  (quickurl-add-url word url comment))
-
-(defun quickurl-list-quit ()
-  "Kill the buffer named `quickurl-list-buffer-name'."
-  (interactive)
-  (quit-window t))
-
-(defun quickurl-list-mouse-select (event)
-  "Select the URL under the mouse click."
-  (interactive "e")
-  (goto-char (posn-point (event-end event)))
-  (quickurl-list-insert-url))
-
-(defun quickurl-list-insert (type)
-  "Insert the URL under cursor into `quickurl-list-last-buffer'.
-TYPE dictates what will be inserted, options are:
-  `url'         - Insert the URL as <URL:url>
-  `naked-url'   - Insert the URL with no formatting
-  `with-lookup' - Insert \"lookup <URL:url>\"
-  `with-desc'   - Insert \"description <URL:url>\"
-  `lookup'      - Insert the lookup for that URL"
-  (let ((url (nth (count-lines (point-min) (line-beginning-position))
-                  quickurl-urls)))
-    (if url
-        (with-current-buffer quickurl-list-last-buffer
-          (insert
-           (pcase type
-             ('url         (funcall quickurl-format-function url))
-             ('naked-url   (quickurl-url-url url))
-             ('with-lookup (format "%s <URL:%s>"
-                                   (quickurl-url-keyword url)
-                                   (quickurl-url-url url)))
-             ('with-desc   (format "%S <URL:%s>"
-                                   (quickurl-url-description url)
-                                   (quickurl-url-url url)))
-             ('lookup      (quickurl-url-keyword url)))))
-      (error "No URL details on that line"))
-    url))
-
-(defmacro quickurl-list-make-inserter (type)
-  "Macro to make a key-response function for use in `quickurl-list-mode-map'."
-  `(defun ,(intern (format "quickurl-list-insert-%S" type)) ()
-    ,(format "Insert the result of calling `quickurl-list-insert' with `%s'." 
type)
-    (interactive)
-    (when (quickurl-list-insert ',type)
-      (quickurl-list-quit))))
-
-(quickurl-list-make-inserter url)
-(quickurl-list-make-inserter naked-url)
-(quickurl-list-make-inserter with-lookup)
-(quickurl-list-make-inserter with-desc)
-(quickurl-list-make-inserter lookup)
-
-(provide 'quickurl)
-
-;;; quickurl.el ends here
diff --git a/lisp/net/rcirc.el b/lisp/net/rcirc.el
index 0d30b34922..71505dcaa3 100644
--- a/lisp/net/rcirc.el
+++ b/lisp/net/rcirc.el
@@ -130,7 +130,7 @@ be displayed instead."
 
 (defcustom rcirc-default-port 6667
   "The default port to connect to."
-  :type 'integer)
+  :type 'natnum)
 
 (defcustom rcirc-default-nick (user-login-name)
   "Your nick."
@@ -267,6 +267,7 @@ The ARGUMENTS for each METHOD symbol are:
 Examples:
  ((\"Libera.Chat\" nickserv \"bob\" \"p455w0rd\")
   (\"Libera.Chat\" chanserv \"bob\" \"#bobland\" \"passwd99\")
+  (\"Libera.Chat\" certfp \"/path/to/key\" \"/path/to/cert\")
   (\"bitlbee\" bitlbee \"robert\" \"sekrit\")
   (\"dal.net\" nickserv \"bob\" \"sekrit\" \"NickServ@services.dal.net\")
   (\"quakenet.org\" quakenet \"bobby\" \"sekrit\")
@@ -1345,33 +1346,30 @@ The list is updated automatically by 
`defun-rcirc-command'.")
   'set-rcirc-encode-coding-system
   "28.1")
 
-(defvar rcirc-mode-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map (kbd "RET") 'rcirc-send-input)
-    (define-key map (kbd "M-p") 'rcirc-insert-prev-input)
-    (define-key map (kbd "M-n") 'rcirc-insert-next-input)
-    (define-key map (kbd "TAB") 'completion-at-point)
-    (define-key map (kbd "C-c C-b") 'rcirc-browse-url)
-    (define-key map (kbd "C-c C-c") 'rcirc-edit-multiline)
-    (define-key map (kbd "C-c C-j") 'rcirc-cmd-join)
-    (define-key map (kbd "C-c C-k") 'rcirc-cmd-kick)
-    (define-key map (kbd "C-c C-l") 'rcirc-toggle-low-priority)
-    (define-key map (kbd "C-c C-d") 'rcirc-cmd-mode)
-    (define-key map (kbd "C-c C-m") 'rcirc-cmd-msg)
-    (define-key map (kbd "C-c C-r") 'rcirc-cmd-nick) ; rename
-    (define-key map (kbd "C-c C-o") 'rcirc-omit-mode)
-    (define-key map (kbd "C-c C-p") 'rcirc-cmd-part)
-    (define-key map (kbd "C-c C-q") 'rcirc-cmd-query)
-    (define-key map (kbd "C-c C-t") 'rcirc-cmd-topic)
-    (define-key map (kbd "C-c C-n") 'rcirc-cmd-names)
-    (define-key map (kbd "C-c C-w") 'rcirc-cmd-whois)
-    (define-key map (kbd "C-c C-x") 'rcirc-cmd-quit)
-    (define-key map (kbd "C-c TAB") ; C-i
-      'rcirc-toggle-ignore-buffer-activity)
-    (define-key map (kbd "C-c C-s") 'rcirc-switch-to-server-buffer)
-    (define-key map (kbd "C-c C-a") 'rcirc-jump-to-first-unread-line)
-    map)
-  "Keymap for rcirc mode.")
+(defvar-keymap rcirc-mode-map
+  :doc "Keymap for rcirc mode."
+  "RET"     #'rcirc-send-input
+  "M-p"     #'rcirc-insert-prev-input
+  "M-n"     #'rcirc-insert-next-input
+  "TAB"     #'completion-at-point
+  "C-c C-b" #'rcirc-browse-url
+  "C-c C-c" #'rcirc-edit-multiline
+  "C-c C-j" #'rcirc-cmd-join
+  "C-c C-k" #'rcirc-cmd-kick
+  "C-c C-l" #'rcirc-toggle-low-priority
+  "C-c C-d" #'rcirc-cmd-mode
+  "C-c C-m" #'rcirc-cmd-msg
+  "C-c C-r" #'rcirc-cmd-nick ; rename
+  "C-c C-o" #'rcirc-omit-mode
+  "C-c C-p" #'rcirc-cmd-part
+  "C-c C-q" #'rcirc-cmd-query
+  "C-c C-t" #'rcirc-cmd-topic
+  "C-c C-n" #'rcirc-cmd-names
+  "C-c C-w" #'rcirc-cmd-whois
+  "C-c C-x" #'rcirc-cmd-quit
+  "C-c C-i" #'rcirc-toggle-ignore-buffer-activity
+  "C-c C-s" #'rcirc-switch-to-server-buffer
+  "C-c C-a" #'rcirc-jump-to-first-unread-line)
 
 (defvar-local rcirc-short-buffer-name nil
   "Generated abbreviation to use to indicate buffer activity.")
@@ -1390,6 +1388,21 @@ Each element looks like (FILENAME . TEXT).")
   "The current number of responses printed in this channel.
 This number is independent of the number of lines in the buffer.")
 
+(defun rcirc--electric-pair-inhibit (char)
+  "Check whether CHAR should be paired by `electric-pair-mode'.
+This uses the default value inhibition predicate (as set by
+`electric-pair-inhibit-predicate'), but ignores all text prior to
+the prompt so that mismatches parentheses by some other message
+does not confuse the pairing."
+  (let ((fallback (default-value 'electric-pair-inhibit-predicate)))
+    ;; The assumption is that this function is only bound by
+    ;; `rcirc-mode', and should never be the global default.
+    (cl-assert (not (eq fallback #'rcirc--electric-pair-inhibit)))
+    (save-restriction
+      (widen)
+      (narrow-to-region rcirc-prompt-start-marker (point-max))
+      (funcall fallback char))))
+
 (defun rcirc-mode (process target)
   "Initialize an IRC buffer for writing with TARGET.
 PROCESS is the process object used for communication.
@@ -1461,6 +1474,9 @@ PROCESS is the process object used for communication.
   (when rcirc-cycle-completion-flag
     (setq-local completion-cycle-threshold t))
 
+  (setq-local electric-pair-inhibit-predicate
+              #'rcirc--electric-pair-inhibit)
+
   (run-mode-hooks 'rcirc-mode-hook))
 
 (defun rcirc-update-prompt (&optional all)
@@ -1624,7 +1640,7 @@ Create the buffer if it doesn't exist."
     (goto-char (point-max))
     (when (not (equal 0 (- (point) rcirc-prompt-end-marker)))
       ;; delete a trailing newline
-      (when (eq (point) (point-at-bol))
+      (when (eq (point) (line-beginning-position))
        (delete-char -1))
       (let ((input (buffer-substring-no-properties
                    rcirc-prompt-end-marker (point))))
@@ -1708,16 +1724,17 @@ extracted."
       (setq rcirc-parent-buffer parent)
       (insert text)
       (and (> pos 0) (goto-char pos))
-      (message "Type C-c C-c to return text to %s, or C-c C-k to cancel" 
parent))))
-
-(defvar rcirc-multiline-minor-mode-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map (kbd "C-c C-c") 'rcirc-multiline-minor-submit)
-    (define-key map (kbd "C-x C-s") 'rcirc-multiline-minor-submit)
-    (define-key map (kbd "C-c C-k") 'rcirc-multiline-minor-cancel)
-    (define-key map (kbd "ESC ESC ESC") 'rcirc-multiline-minor-cancel)
-    map)
-  "Keymap for multiline mode in rcirc.")
+      (message "Type %s to return text to %s, or %s to cancel"
+               (substitute-command-keys "\\[rcirc-multiline-minor-submit]")
+               parent
+               (substitute-command-keys "\\[rcirc-multiline-minor-cancel]")))))
+
+(defvar-keymap rcirc-multiline-minor-mode-map
+  :doc "Keymap for multiline mode in rcirc."
+  "C-c C-c"     #'rcirc-multiline-minor-submit
+  "C-x C-s"     #'rcirc-multiline-minor-submit
+  "C-c C-k"     #'rcirc-multiline-minor-cancel
+  "ESC ESC ESC" #'rcirc-multiline-minor-cancel)
 
 (define-minor-mode rcirc-multiline-minor-mode
   "Minor mode for editing multiple lines in rcirc."
@@ -2265,12 +2282,10 @@ This function does not alter the INPUT string."
     (mapconcat rcirc-nick-filter sorted sep)))
 
 ;;; activity tracking
-(defvar rcirc-track-minor-mode-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map (kbd "C-c C-@") 'rcirc-next-active-buffer)
-    (define-key map (kbd "C-c C-SPC") 'rcirc-next-active-buffer)
-    map)
-  "Keymap for rcirc track minor mode.")
+(defvar-keymap rcirc-track-minor-mode-map
+  :doc "Keymap for rcirc track minor mode."
+  "C-c C-@"   #'rcirc-next-active-buffer
+  "C-c C-SPC" #'rcirc-next-active-buffer)
 
 (defcustom rcirc-track-abbrevate-flag t
   "Non-nil means `rcirc-track-minor-mode' should abbreviate names."
@@ -3298,7 +3313,7 @@ PROCESS is the process object for the current connection."
       (with-current-buffer chat-buffer
        (rcirc-print process sender "NICK" old-nick new-nick)
        (setq rcirc-target new-nick)
-       (rename-buffer (rcirc-generate-new-buffer-name process new-nick)))
+       (rename-buffer (rcirc-generate-new-buffer-name process new-nick) t))
       (setf rcirc-buffer-alist
             (cons (cons new-nick chat-buffer)
                   (delq (assoc-string old-nick rcirc-buffer-alist t)
@@ -3479,7 +3494,7 @@ form \"PARAMETER\" to enable a feature, 
\"PARAMETER=VALUE\" to
 configure a specific option or \"-PARAMETER\" to disable a
 previously specified feature.  SENDER is passed on to
 `rcirc-handler-generic'.  PROCESS is the process object for the
-current connection.  Note that this is not the behaviour as
+current connection.  Note that this is not the behavior as
 specified in RFC2812, where 005 stood for RPL_BOUNCE."
   (rcirc-handler-generic process "005" sender args text)
   (with-rcirc-process-buffer process
diff --git a/lisp/net/rlogin.el b/lisp/net/rlogin.el
deleted file mode 100644
index 98b660dcc4..0000000000
--- a/lisp/net/rlogin.el
+++ /dev/null
@@ -1,313 +0,0 @@
-;;; rlogin.el --- remote login interface  -*- lexical-binding:t -*-
-
-;; Copyright (C) 1992-1995, 1997-1998, 2001-2022 Free Software
-;; Foundation, Inc.
-
-;; Author: Noah Friedman <friedman@splode.com>
-;; Keywords: unix, comm
-
-;; 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:
-
-;; Support for remote logins using `rlogin'.
-;; This program is layered on top of shell.el; the code here only accounts
-;; for the variations needed to handle a remote process, e.g. directory
-;; tracking and the sending of some special characters.
-
-;; If you wish for rlogin mode to prompt you in the minibuffer for
-;; passwords when a password prompt appears, just enter
-;; M-x comint-send-invisible and type in your line (or tweak
-;; `comint-password-prompt-regexp' to match your password prompt).
-
-;;; Code:
-
-;; FIXME?
-;; Maybe this file should be obsolete.
-;; https://lists.gnu.org/r/emacs-devel/2013-02/msg00517.html
-;; It only adds rlogin-directory-tracking-mode.  Is that useful?
-
-(require 'comint)
-(require 'shell)
-
-(defgroup rlogin nil
-  "Remote login interface."
-  :group 'processes
-  :group 'unix)
-
-(defcustom rlogin-program "ssh"
-  "Name of program to invoke remote login."
-  :version "24.4"                       ; rlogin -> ssh
-  :type 'string
-  :group 'rlogin)
-
-(defcustom rlogin-explicit-args '("-t" "-t")
-  "List of arguments to pass to `rlogin-program' on the command line."
-  :version "24.4"                       ; nil -> -t -t
-  :type '(repeat (string :tag "Argument"))
-  :group 'rlogin)
-
-(defcustom rlogin-mode-hook nil
-  "Hooks to run after setting current buffer to rlogin-mode."
-  :type 'hook
-  :group 'rlogin)
-
-(defcustom rlogin-process-connection-type
-  ;; Solaris 2.x `rlogin' will spew a bunch of ioctl error messages if
-  ;; stdin isn't a tty.
-  (and (string-match "rlogin" rlogin-program)
-       (string-match-p "-solaris2" system-configuration) t)
-  "If non-nil, use a pty for the local rlogin process.
-If nil, use a pipe (if pipes are supported on the local system).
-
-Generally it is better not to waste ptys on systems which have a static
-number of them.  On the other hand, some implementations of `rlogin' assume
-a pty is being used, and errors will result from using a pipe instead."
-  :set-after '(rlogin-program)
-  :type '(choice (const :tag "pipes" nil)
-                (other :tag "ptys" t))
-  :group 'rlogin)
-
-(defcustom rlogin-directory-tracking-mode 'local
-  "Control whether and how to do directory tracking in an rlogin buffer.
-
-nil means don't do directory tracking.
-
-t means do so using an ftp remote file name.
-
-Any other value means do directory tracking using local file names.
-This works only if the remote machine and the local one
-share the same directories (through NFS).  This is the default.
-
-This variable becomes local to a buffer when set in any fashion for it.
-
-It is better to use the function of the same name to change the behavior of
-directory tracking in an rlogin session once it has begun, rather than
-simply setting this variable, since the function does the necessary
-re-synching of directories."
-  :type '(choice (const :tag "off" nil)
-                (const :tag "ftp" t)
-                (other :tag "local" local))
-  :group 'rlogin)
-
-(make-variable-buffer-local 'rlogin-directory-tracking-mode)
-
-(defcustom rlogin-host nil
-  "The name of the default remote host.  This variable is buffer-local."
-  :type '(choice (const nil) string)
-  :group 'rlogin)
-
-(defcustom rlogin-remote-user nil
-  "The username used on the remote host.
-This variable is buffer-local and defaults to your local user name.
-If rlogin is invoked with the `-l' option to specify the remote username,
-this variable is set from that."
-  :type '(choice (const nil) string)
-  :group 'rlogin)
-
-(defvar rlogin-mode-map
-  (let ((map (if (consp shell-mode-map)
-                 (cons 'keymap shell-mode-map)
-               (copy-keymap shell-mode-map))))
-    (define-key map "\C-c\C-c" 'rlogin-send-Ctrl-C)
-    (define-key map "\C-c\C-d" 'rlogin-send-Ctrl-D)
-    (define-key map "\C-c\C-z" 'rlogin-send-Ctrl-Z)
-    (define-key map "\C-c\C-\\" 'rlogin-send-Ctrl-backslash)
-    (define-key map "\C-d" 'rlogin-delchar-or-send-Ctrl-D)
-    (define-key map "\C-i" 'rlogin-tab-or-complete)
-    map)
-  "Keymap for `rlogin-mode'.")
-
-
-
-(defvar rlogin-history nil)
-
-;;;###autoload
-(defun rlogin (input-args &optional buffer)
-  "Open a network login connection via `rlogin' with args INPUT-ARGS.
-INPUT-ARGS should start with a host name; it may also contain
-other arguments for `rlogin'.
-
-Input is sent line-at-a-time to the remote connection.
-
-Communication with the remote host is recorded in a buffer `*rlogin-HOST*'
-\(or `*rlogin-USER@HOST*' if the remote username differs).
-If a prefix argument is given and the buffer `*rlogin-HOST*' already exists,
-a new buffer with a different connection will be made.
-
-When called from a program, if the optional second argument BUFFER is
-a string or buffer, it specifies the buffer to use.
-
-The variable `rlogin-program' contains the name of the actual program to
-run.  It can be a relative or absolute path.
-
-The variable `rlogin-explicit-args' is a list of arguments to give to
-the rlogin when starting.  They are added after any arguments given in
-INPUT-ARGS.
-
-If the default value of `rlogin-directory-tracking-mode' is t, then the
-default directory in that buffer is set to a remote (FTP) file name to
-access your home directory on the remote machine.  Occasionally this causes
-an error, if you cannot access the home directory on that machine.  This
-error is harmless as long as you don't try to use that default directory.
-
-If `rlogin-directory-tracking-mode' is neither t nor nil, then the default
-directory is initially set up to your (local) home directory.
-This is useful if the remote machine and your local machine
-share the same files via NFS.  This is the default.
-
-If you wish to change directory tracking styles during a session, use the
-function `rlogin-directory-tracking-mode' rather than simply setting the
-variable."
-  (interactive (list
-               (read-from-minibuffer (format-message
-                                       "Arguments for `%s' (hostname first): "
-                                       (file-name-nondirectory rlogin-program))
-                                     nil nil nil 'rlogin-history)
-               current-prefix-arg))
-  (let* ((process-connection-type rlogin-process-connection-type)
-         (args (if rlogin-explicit-args
-                   (append (split-string input-args)
-                           rlogin-explicit-args)
-                 (split-string input-args)))
-         (host (let ((tail args))
-                 ;; Find first arg that doesn't look like an option.
-                 ;; This still loses for args that take values, feh.
-                 (while (and tail (= ?- (aref (car tail) 0)))
-                   (setq tail (cdr tail)))
-                 (car tail)))
-        (user (or (car (cdr (member "-l" args)))
-                   (user-login-name)))
-         (buffer-name (if (string= user (user-login-name))
-                          (format "*rlogin-%s*" host)
-                        (format "*rlogin-%s@%s*" user host))))
-    (cond ((null buffer))
-         ((stringp buffer)
-          (setq buffer-name buffer))
-          ((bufferp buffer)
-           (setq buffer-name (buffer-name buffer)))
-          ((numberp buffer)
-           (setq buffer-name (format "%s<%d>" buffer-name buffer)))
-          (t
-           (setq buffer-name (generate-new-buffer-name buffer-name))))
-    (setq buffer (get-buffer-create buffer-name))
-    (switch-to-buffer buffer-name)
-    (unless (comint-check-proc buffer-name)
-      (comint-exec buffer buffer-name rlogin-program nil args)
-      (rlogin-mode)
-      (setq-local rlogin-host host)
-      (setq-local rlogin-remote-user user)
-      (ignore-errors
-        (cond ((eq rlogin-directory-tracking-mode t)
-               ;; Do this here, rather than calling the tracking mode
-               ;; function, to avoid a gratuitous resync check; the default
-               ;; should be the user's home directory, be it local or remote.
-               (setq comint-file-name-prefix
-                     (concat "/-:" rlogin-remote-user "@" rlogin-host ":"))
-               (cd-absolute comint-file-name-prefix))
-              ((null rlogin-directory-tracking-mode))
-              (t
-               (cd-absolute (concat comint-file-name-prefix "~/"))))))))
-
-(put 'rlogin-mode 'mode-class 'special)
-
-(define-derived-mode rlogin-mode shell-mode "Rlogin"
-  (setq shell-dirtrackp rlogin-directory-tracking-mode)
-  (make-local-variable 'comint-file-name-prefix))
-
-(defun rlogin-directory-tracking-mode (&optional prefix)
-  "Do remote or local directory tracking, or disable entirely.
-
-If called with no prefix argument or a unspecified prefix argument (just
-`\\[universal-argument]' with no number) do remote directory tracking via
-ange-ftp.  If called as a function, give it no argument.
-
-If called with a negative prefix argument, disable directory tracking
-entirely.
-
-If called with a positive, numeric prefix argument, for example
-\\[universal-argument] 1 \\[rlogin-directory-tracking-mode],
-then do directory tracking but assume the remote filesystem is the same as
-the local system.  This only works in general if the remote machine and the
-local one share the same directories (e.g. through NFS)."
-  (interactive "P")
-  (cond
-   ((or (null prefix)
-        (consp prefix))
-    (setq rlogin-directory-tracking-mode t)
-    (setq shell-dirtrackp t)
-    (setq comint-file-name-prefix
-          (concat "/-:" rlogin-remote-user "@" rlogin-host ":")))
-   ((< prefix 0)
-    (setq rlogin-directory-tracking-mode nil)
-    (setq shell-dirtrackp nil))
-   (t
-    (setq rlogin-directory-tracking-mode 'local)
-    (setq comint-file-name-prefix "")
-    (setq shell-dirtrackp t)))
-  (cond
-   (shell-dirtrackp
-    (let* ((proc (get-buffer-process (current-buffer)))
-           (proc-mark (process-mark proc))
-           (current-input (buffer-substring proc-mark (point-max)))
-           (orig-point (point))
-           (offset (and (>= orig-point proc-mark)
-                        (- (point-max) orig-point))))
-      (unwind-protect
-          (progn
-            (delete-region proc-mark (point-max))
-            (goto-char (point-max))
-            (shell-resync-dirs))
-        (goto-char proc-mark)
-        (insert current-input)
-        (if offset
-            (goto-char (- (point-max) offset))
-          (goto-char orig-point)))))))
-
-
-(defun rlogin-send-Ctrl-C ()
-  (interactive)
-  (process-send-string nil "\C-c"))
-
-(defun rlogin-send-Ctrl-D ()
-  (interactive)
-  (process-send-string nil "\C-d"))
-
-(defun rlogin-send-Ctrl-Z ()
-  (interactive)
-  (process-send-string nil "\C-z"))
-
-(defun rlogin-send-Ctrl-backslash ()
-  (interactive)
-  (process-send-string nil "\C-\\"))
-
-(defun rlogin-delchar-or-send-Ctrl-D (arg)
-  "Delete ARG characters forward, or send a C-d to process if at end of 
buffer."
-  (interactive "p")
-  (if (eobp)
-      (rlogin-send-Ctrl-D)
-    (delete-char arg)))
-
-(defun rlogin-tab-or-complete ()
-  "Complete file name if doing directory tracking, or just insert TAB."
-  (interactive)
-  (if rlogin-directory-tracking-mode
-      (completion-at-point)
-    (insert "\C-i")))
-
-(provide 'rlogin)
-
-;;; rlogin.el ends here
diff --git a/lisp/net/secrets.el b/lisp/net/secrets.el
index d8341774e4..c4f97a92fb 100644
--- a/lisp/net/secrets.el
+++ b/lisp/net/secrets.el
@@ -741,14 +741,13 @@ ITEM can also be an object path, which is used if 
contained in COLLECTION."
 
 ;;; Visualization.
 
-(defvar secrets-mode-map
-  (let ((map (make-sparse-keymap)))
-    (set-keymap-parent map (make-composed-keymap special-mode-map 
widget-keymap))
-    (define-key map "n" #'next-line)
-    (define-key map "p" #'previous-line)
-    (define-key map "z" #'kill-current-buffer)
-    map)
-  "Keymap used in `secrets-mode' buffers.")
+(defvar-keymap secrets-mode-map
+  :doc "Keymap used in `secrets-mode' buffers."
+  :parent (make-composed-keymap special-mode-map
+                                widget-keymap)
+  "n" #'next-line
+  "p" #'previous-line
+  "z" #'kill-current-buffer)
 
 (define-derived-mode secrets-mode special-mode "Secrets"
   "Major mode for presenting password entries retrieved by Security Service.
diff --git a/lisp/net/shr.el b/lisp/net/shr.el
index 505a093392..248faeb223 100644
--- a/lisp/net/shr.el
+++ b/lisp/net/shr.el
@@ -232,6 +232,11 @@ temporarily blinks with this face."
   "Face used for rendering <code> blocks."
   :version "29.1")
 
+(defface shr-mark
+  '((t :background "yellow" :foreground "black"))
+  "Face used for <mark> elements."
+  :version "29.1")
+
 (defcustom shr-inhibit-images nil
   "If non-nil, inhibit loading images."
   :version "28.1"
@@ -285,11 +290,10 @@ and other things:
   "O" #'shr-save-contents
   "RET" #'shr-browse-url)
 
-(defvar shr-image-map
-  (let ((map (copy-keymap shr-map)))
-    (when (boundp 'image-map)
-      (set-keymap-parent map image-map))
-    map))
+(defvar-keymap shr-image-map
+  :parent (if (boundp 'image-map)
+              (make-composed-keymap shr-map image-map)
+            shr-map))
 
 ;; Public functions and commands.
 (declare-function libxml-parse-html-region "xml.c"
@@ -337,6 +341,11 @@ and other things:
            0))
     (pixel-fill-width)))
 
+(defmacro shr-string-pixel-width (string)
+  `(if (not shr-use-fonts)
+       (length ,string)
+     (string-pixel-width ,string)))
+
 ;;;###autoload
 (defun shr-insert-document (dom)
   "Render the parsed document DOM into the current buffer.
@@ -361,6 +370,7 @@ DOM should be a parse tree as generated by
            (shr--window-width)))
         (max-specpdl-size max-specpdl-size)
         (shr--link-targets nil)
+        (hscroll (window-hscroll))
         ;; `bidi-display-reordering' is supposed to be only used for
         ;; debugging purposes, but Shr's naïve filling algorithm
         ;; cannot cope with the complexity of RTL text in an LTR
@@ -380,17 +390,20 @@ DOM should be a parse tree as generated by
     ;; below will misbehave, because it silently assumes that it
     ;; starts with a non-hscrolled window (vertical-motion will move
     ;; to a wrong place otherwise).
-    (set-window-hscroll nil 0)
-    (shr-descend dom)
-    (shr-fill-lines start (point))
-    (shr--remove-blank-lines-at-the-end start (point))
-    (shr--set-target-ids shr--link-targets)
+    (unwind-protect
+        (progn
+          (set-window-hscroll nil 0)
+          (shr-descend dom)
+          (shr-fill-lines start (point))
+          (shr--remove-blank-lines-at-the-end start (point))
+          (shr--set-target-ids shr--link-targets))
+      (set-window-hscroll nil hscroll))
     (when shr-warning
       (message "%s" shr-warning))))
 
 (defun shr--set-target-ids (ids)
   ;; If the buffer is empty, there's no point in setting targets.
-  (unless (zerop (buffer-size))
+  (unless (zerop (- (point-max) (point-min)))
     ;; We may have several targets in the same place (if you have
     ;; several <span id='foo'> things after one another).  So group
     ;; them by position.
@@ -673,19 +686,6 @@ size, and full-buffer size."
        (goto-char (mark))
        (shr-pixel-column))))
 
-(defun shr-string-pixel-width (string)
-  (if (not shr-use-fonts)
-      (length string)
-    ;; Save and restore point across with-temp-buffer, since
-    ;; shr-pixel-column uses save-window-excursion, which can reset
-    ;; point to 1.
-    (let ((pt (point)))
-      (prog1
-         (with-temp-buffer
-           (insert string)
-           (shr-pixel-column))
-       (goto-char pt)))))
-
 (defsubst shr--translate-insertion-chars ()
   ;; Remove soft hyphens.
   (goto-char (point-min))
@@ -819,7 +819,7 @@ size, and full-buffer size."
             (let* ((props (copy-sequence (text-properties-at (point))))
                    (face (plist-get props 'face)))
               ;; We don't want to use the faces on the indentation, because
-              ;; that's ugly, but we do want to use the background colour.
+              ;; that's ugly, but we do want to use the background color.
               (when face
                 (setq props (plist-put props 'face (shr-face-background 
face))))
              (add-text-properties gap-start (point) props))))
@@ -1426,6 +1426,14 @@ ones, in case fg and bg are nil."
   ;; The `tt' tag is deprecated in favor of `code'.
   (shr-tag-code dom))
 
+(defun shr-tag-mark (dom)
+  (when (and (not (bobp))
+             (not (= (char-after (1- (point))) ?\s)))
+    (insert " "))
+  (let ((start (point)))
+    (shr-generic dom)
+    (shr-add-font start (point) 'shr-mark)))
+
 (defun shr-tag-ins (cont)
   (let* ((start (point))
          (color "green")
@@ -1732,35 +1740,14 @@ BASE is the URL of the HTML being rendered."
     shr-cookie-policy)))
 
 (defun shr--preferred-image (dom)
-  (let ((srcset (dom-attr dom 'srcset))
-        (frame-width (frame-pixel-width))
-        (width (string-to-number (or (dom-attr dom 'width) "100")))
-        candidate)
-    (when (> (length srcset) 0)
-      ;; srcset consist of a series of URL/size specifications
-      ;; separated by the ", " string.
-      (setq srcset
-            (sort (mapcar
-                   (lambda (elem)
-                     (let ((spec (split-string elem "[\t\n\r ]+")))
-                       (cond
-                        ((= (length spec) 1)
-                         ;; Make sure it's well formed.
-                         (list (car spec) 0))
-                        ((string-match "\\([0-9]+\\)x\\'" (cadr spec))
-                         ;; If we have an "x" form, then use the width
-                         ;; spec to compute the real width.
-                         (list (car spec)
-                               (* width (string-to-number
-                                         (match-string 1 (cadr spec))))))
-                        (t
-                         (list (car spec)
-                               (string-to-number (cadr spec)))))))
-                   (split-string (replace-regexp-in-string
-                                 "\\`[\t\n\r ]+\\|[\t\n\r ]+\\'" "" srcset)
-                                "[\t\n\r ]*,[\t\n\r ]*"))
-                  (lambda (e1 e2)
-                    (> (cadr e1) (cadr e2)))))
+  (let* ((srcset (and (dom-attr dom 'srcset)
+                      (shr--parse-srcset (dom-attr dom 'srcset)
+                                         (and (dom-attr dom 'width)
+                                              (string-to-number
+                                               (dom-attr dom 'width))))))
+         (frame-width (frame-pixel-width))
+         candidate)
+    (when srcset
       ;; Choose the smallest picture that's bigger than the current
       ;; frame.
       (setq candidate (caar srcset))
@@ -1770,6 +1757,42 @@ BASE is the URL of the HTML being rendered."
         (pop srcset)))
     (or candidate (dom-attr dom 'src))))
 
+(defun shr--parse-srcset (srcset &optional width)
+  (setq srcset (string-trim srcset)
+        width (or width 100))
+  (when (> (length srcset) 0)
+    ;; srcset consists of a series of URL/size specifications separated
+    ;; by the " ," string.
+    (sort (mapcar
+           (lambda (elem)
+             (let ((spec (split-string elem "[\t\n\r ]+")))
+               (cond
+                ((= (length spec) 1)
+                 ;; Make sure it's well formed.
+                 (list (car spec) 0))
+                ((string-match "\\([0-9]+\\)x\\'" (cadr spec))
+                 ;; If we have an "x" form, then use the width
+                 ;; spec to compute the real width.
+                 (list (car spec)
+                       (* width (string-to-number
+                                 (match-string 1 (cadr spec))))))
+                (t
+                 (list (car spec)
+                       (string-to-number (cadr spec)))))))
+           (with-temp-buffer
+             (insert srcset)
+             (goto-char (point-min))
+             (let ((bits nil))
+               (while (re-search-forward "[^\t\n\r ]+[\t\n\r ]+[^\t\n\r ,]+"
+                                         nil t)
+                 (push (match-string 0) bits)
+                 (if (looking-at "[\t\n\r ]*,[\t\n\r ]*")
+                     (goto-char (match-end 0))
+                   (goto-char (point-max))))
+               bits)))
+          (lambda (e1 e2)
+            (> (cadr e1) (cadr e2))))))
+
 (defun shr-string-number (string)
   (if (null string)
       nil
diff --git a/lisp/net/sieve-manage.el b/lisp/net/sieve-manage.el
index 50342b9105..a39e35a53a 100644
--- a/lisp/net/sieve-manage.el
+++ b/lisp/net/sieve-manage.el
@@ -131,7 +131,7 @@ for doing the actual authentication."
 
 (defcustom sieve-manage-default-port "sieve"
   "Default port number or service name for managesieve protocol."
-  :type '(choice integer string)
+  :type '(choice natnum string)
   :version "24.4")
 
 (defcustom sieve-manage-default-stream 'network
diff --git a/lisp/net/sieve-mode.el b/lisp/net/sieve-mode.el
index 58fd41d899..f62af03534 100644
--- a/lisp/net/sieve-mode.el
+++ b/lisp/net/sieve-mode.el
@@ -137,13 +137,11 @@
 
 ;; Key map definition
 
-(defvar sieve-mode-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "\C-c\C-l" #'sieve-upload)
-    (define-key map "\C-c\C-c" #'sieve-upload-and-kill)
-    (define-key map "\C-c\C-m" #'sieve-manage)
-    map)
-  "Key map used in sieve mode.")
+(defvar-keymap sieve-mode-map
+  :doc "Keymap used in sieve mode."
+  "C-c C-l" #'sieve-upload
+  "C-c C-c" #'sieve-upload-and-kill
+  "C-c RET" #'sieve-manage)
 
 ;; Menu
 
diff --git a/lisp/net/sieve.el b/lisp/net/sieve.el
index 630ea04070..3a6067ee10 100644
--- a/lisp/net/sieve.el
+++ b/lisp/net/sieve.el
@@ -106,33 +106,31 @@ require \"fileinto\";
 ;; FIXME: This is arguably a bug/problem in `easy-menu-define'.
 (declare-function sieve-manage-mode-menu "sieve")
 
-(defvar sieve-manage-mode-map
-  (let ((map (make-sparse-keymap)))
-    ;; various
-    (define-key map "?" #'sieve-help)
-    (define-key map "h" #'sieve-help)
-    ;; activating
-    (define-key map "m" #'sieve-activate)
-    (define-key map "u" #'sieve-deactivate)
-    (define-key map "\M-\C-?" #'sieve-deactivate-all)
-    ;; navigation keys
-    (define-key map "\C-p" #'sieve-prev-line)
-    (define-key map [up] #'sieve-prev-line)
-    (define-key map "\C-n" #'sieve-next-line)
-    (define-key map [down] #'sieve-next-line)
-    (define-key map " " #'sieve-next-line)
-    (define-key map "n" #'sieve-next-line)
-    (define-key map "p" #'sieve-prev-line)
-    (define-key map "\C-m" #'sieve-edit-script)
-    (define-key map "f" #'sieve-edit-script)
-    ;; (define-key map "o" #'sieve-edit-script-other-window)
-    (define-key map "r" #'sieve-remove)
-    (define-key map "q" #'sieve-bury-buffer)
-    (define-key map "Q" #'sieve-manage-quit)
-    (define-key map [(down-mouse-2)] #'sieve-edit-script)
-    (define-key map [(down-mouse-3)] #'sieve-manage-mode-menu)
-    map)
-  "Keymap for `sieve-manage-mode'.")
+(defvar-keymap sieve-manage-mode-map
+  :doc "Keymap for `sieve-manage-mode'."
+  ;; various
+  "?"      #'sieve-help
+  "h"      #'sieve-help
+  ;; activating
+  "m"      #'sieve-activate
+  "u"      #'sieve-deactivate
+  "M-DEL"  #'sieve-deactivate-all
+  ;; navigation keys
+  "C-p"    #'sieve-prev-line
+  "<up>"   #'sieve-prev-line
+  "C-n"    #'sieve-next-line
+  "<down>" #'sieve-next-line
+  "SPC"    #'sieve-next-line
+  "n"      #'sieve-next-line
+  "p"      #'sieve-prev-line
+  "RET"    #'sieve-edit-script
+  "f"      #'sieve-edit-script
+  ;; "o"   #'sieve-edit-script-other-window
+  "r"      #'sieve-remove
+  "q"      #'sieve-bury-buffer
+  "Q"      #'sieve-manage-quit
+  "<down-mouse-2>" #'sieve-edit-script
+  "<down-mouse-3>" #'sieve-manage-mode-menu)
 
 (easy-menu-define sieve-manage-mode-menu sieve-manage-mode-map
   "Sieve Menu."
diff --git a/lisp/net/snmp-mode.el b/lisp/net/snmp-mode.el
index de84b4f8dd..394c4a9666 100644
--- a/lisp/net/snmp-mode.el
+++ b/lisp/net/snmp-mode.el
@@ -248,14 +248,12 @@ This is used during Tempo template completion."
 
 ;; Set up our keymap
 ;;
-(defvar snmp-mode-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "\177"         'backward-delete-char-untabify)
-    (define-key map "\C-c\C-i"     'tempo-complete-tag)
-    (define-key map "\C-c\C-f"     'tempo-forward-mark)
-    (define-key map "\C-c\C-b"     'tempo-backward-mark)
-    map)
-  "Keymap used in SNMP mode.")
+(defvar-keymap snmp-mode-map
+  :doc "Keymap used in SNMP mode."
+  "DEL"     #'backward-delete-char-untabify
+  "C-c TAB" #'tempo-complete-tag
+  "C-c C-f" #'tempo-forward-mark
+  "C-c C-b" #'tempo-backward-mark)
 
 
 ;; Set up our syntax table
diff --git a/lisp/net/socks.el b/lisp/net/socks.el
index 8df0773e1d..2ba1c20566 100644
--- a/lisp/net/socks.el
+++ b/lisp/net/socks.el
@@ -407,11 +407,10 @@ When ATYPE indicates an IP, param ADDRESS must be given 
as raw bytes."
     (setq version (process-get proc 'socks-server-protocol))
     (cond
      ((equal version 'http)
-      (setq request (format (eval-when-compile
-                             (concat
-                              "CONNECT %s:%d HTTP/1.0\r\n"
-                              "User-Agent: Emacs/SOCKS v1.0\r\n"
-                              "\r\n"))
+      (setq request (format (concat
+                            "CONNECT %s:%d HTTP/1.0\r\n"
+                            "User-Agent: Emacs/SOCKS v1.0\r\n"
+                            "\r\n")
                            (cond
                             ((equal atype socks-address-type-name) address)
                             (t
diff --git a/lisp/net/telnet.el b/lisp/net/telnet.el
index 0d54d2220b..bea79e8933 100644
--- a/lisp/net/telnet.el
+++ b/lisp/net/telnet.el
@@ -1,7 +1,6 @@
 ;;; telnet.el --- run a telnet session from within an Emacs buffer  -*- 
lexical-binding: t; -*-
 
-;; Copyright (C) 1985, 1988, 1992, 1994, 2001-2022 Free Software
-;; Foundation, Inc.
+;; Copyright (C) 1985-2022 Free Software Foundation, Inc.
 
 ;; Author: William F. Schelter
 ;; Maintainer: emacs-devel@gnu.org
@@ -24,11 +23,11 @@
 
 ;;; Commentary:
 
-;; This mode is intended to be used for telnet or rsh to a remote host;
-;; `telnet' and `rsh' are the two entry points.  Multiple telnet or rsh
-;; sessions are supported.
+;; This mode is intended to be used for telnet to a remote host;
+;; `telnet' is the entry point.  Multiple telnet sessions are
+;; supported.
 ;;
-;; Normally, input is sent to the remote telnet/rsh line-by-line, as you
+;; Normally, input is sent to the remote telnet line-by-line, as you
 ;; type RET or LFD.  C-c C-c sends a C-c to the remote immediately;
 ;; C-c C-z sends C-z immediately.  C-c C-q followed by any character
 ;; sends that character immediately.
@@ -61,14 +60,13 @@ PROGRAM says which program to run, to talk to that machine.
 LOGIN-NAME, which is optional, says what to log in as on that machine.")
 
 (defvar telnet-new-line "\r")
-(defvar telnet-mode-map
-  (let ((map (nconc (make-sparse-keymap) comint-mode-map)))
-    (define-key map "\C-m" #'telnet-send-input)
-    ;; (define-key map "\C-j" #'telnet-send-input)
-    (define-key map "\C-c\C-q" #'send-process-next-char)
-    (define-key map "\C-c\C-c" #'telnet-interrupt-subjob)
-    (define-key map "\C-c\C-z" #'telnet-c-z)
-    map))
+(defvar-keymap telnet-mode-map
+  :parent comint-mode-map
+  "RET"     #'telnet-send-input
+  ;; "C-j"  #'telnet-send-input
+  "C-c C-q" #'send-process-next-char
+  "C-c C-c" #'telnet-interrupt-subjob
+  "C-c C-z" #'telnet-c-z)
 
 (defvar telnet-prompt-pattern "^[^#$%>\n]*[#$%>] *")
 (defvar telnet-replace-c-g nil)
@@ -95,7 +93,7 @@ Should be set to the number of terminal writes telnet will 
make
 rejecting one login and prompting again for a username and password.")
 
 (defvar telnet-connect-command nil
-  "Command used to start the `telnet' (or `rsh') connection.")
+  "Command used to start the `telnet' connection.")
 
 (defun telnet-interrupt-subjob ()
   "Interrupt the program running through telnet on the remote host."
@@ -246,7 +244,7 @@ Normally input is edited in Emacs and sent a line at a 
time."
 (put 'telnet-mode 'mode-class 'special)
 
 (define-derived-mode telnet-mode comint-mode "Telnet"
-  "This mode is for using telnet (or rsh) from a buffer to another host.
+  "This mode is for using telnet from a buffer to another host.
 It has most of the same commands as `comint-mode'.
 There is a variable `telnet-interrupt-string' which is the character
 sent to try to stop execution of a job on the remote host.
@@ -261,6 +259,7 @@ Data is sent to the remote host when RET is typed."
   "Open a network login connection to host named HOST (a string).
 Communication with HOST is recorded in a buffer `*rsh-HOST*'.
 Normally input is edited in Emacs and sent a line at a time."
+  (declare (obsolete nil "29.1"))
   (interactive "sOpen rsh connection to host: ")
   (require 'shell)
   (let ((name (concat "rsh-" host )))
diff --git a/lisp/net/tramp-adb.el b/lisp/net/tramp-adb.el
index 8268b2d167..b38b908edb 100644
--- a/lisp/net/tramp-adb.el
+++ b/lisp/net/tramp-adb.el
@@ -55,7 +55,7 @@ It is used for TCP/IP devices."
 (defconst tramp-adb-method "adb"
   "When this method name is used, forward all calls to Android Debug Bridge.")
 
-(defcustom tramp-adb-prompt "^[^#$\n\r]*[#$][[:space:]]"
+(defcustom tramp-adb-prompt (rx bol (* (not (any "#$\n\r"))) (any "#$") space)
   "Regexp used as prompt in almquist shell."
   :type 'regexp
   :version "28.1"
@@ -63,31 +63,28 @@ It is used for TCP/IP devices."
 
 (eval-and-compile
   (defconst tramp-adb-ls-date-year-regexp
-    "[[:digit:]]\\{4\\}-[[:digit:]]\\{2\\}-[[:digit:]]\\{2\\}"
+    (rx (= 4 digit) "-" (= 2 digit) "-" (= 2 digit))
     "Regexp for date year format in ls output."))
 
 (eval-and-compile
-  (defconst tramp-adb-ls-date-time-regexp
-    "[[:digit:]]\\{2\\}:[[:digit:]]\\{2\\}"
+  (defconst tramp-adb-ls-date-time-regexp (rx (= 2 digit) ":" (= 2 digit))
   "Regexp for date time format in ls output."))
 
 (defconst tramp-adb-ls-date-regexp
-  (concat
-   "[[:space:]]" tramp-adb-ls-date-year-regexp
-   "[[:space:]]" tramp-adb-ls-date-time-regexp
-   "[[:space:]]")
+  (rx space (regexp tramp-adb-ls-date-year-regexp)
+      space (regexp tramp-adb-ls-date-time-regexp)
+      space)
   "Regexp for date format in ls output.")
 
 (defconst tramp-adb-ls-toolbox-regexp
-  (concat
-   "^[[:space:]]*\\([-.[:alpha:]]+\\)" ; \1 permissions
-   "\\(?:[[:space:]]+[[:digit:]]+\\)?" ; links (Android 7/toybox)
-   "[[:space:]]*\\([^[:space:]]+\\)"   ; \2 username
-   "[[:space:]]+\\([^[:space:]]+\\)"   ; \3 group
-   "[[:space:]]+\\([[:digit:]]+\\)"    ; \4 size
-   "[[:space:]]+\\(" tramp-adb-ls-date-year-regexp
-   "[[:space:]]" tramp-adb-ls-date-time-regexp "\\)" ; \5 date
-   "[[:space:]]\\(.*\\)$")             ; \6 filename
+  (rx bol (* space) (group (+ (any ".-" alpha)))               ; \1 permissions
+      (? (+ space) (+ digit))                        ; links (Android 7/toybox)
+      (* space) (group (+ (not space)))                                ; \2 
username
+      (+ space) (group (+ (not space)))                                ; \3 
group
+      (+ space) (group (+ digit))                              ; \4 size
+      (+ space) (group (regexp tramp-adb-ls-date-year-regexp)
+                space (regexp tramp-adb-ls-date-time-regexp))  ; \5 date
+      space (group (* nonl)) eol)                              ; \6 filename
   "Regexp for ls output.")
 
 ;;;###tramp-autoload
@@ -95,7 +92,7 @@ It is used for TCP/IP devices."
  (add-to-list 'tramp-methods
              `(,tramp-adb-method
                 (tramp-login-program ,tramp-adb-program)
-                (tramp-login-args    (("shell")))
+                (tramp-login-args    (("-s" "%d") ("shell")))
                 (tramp-direct-async  t)
                (tramp-tmpdir        "/data/local/tmp")
                 (tramp-default-port  5555)))
@@ -182,8 +179,8 @@ It is used for TCP/IP devices."
     (substitute-in-file-name . tramp-handle-substitute-in-file-name)
     (temporary-file-directory . tramp-handle-temporary-file-directory)
     (tramp-get-home-directory . ignore)
-    (tramp-get-remote-gid . ignore)
-    (tramp-get-remote-uid . ignore)
+    (tramp-get-remote-gid . tramp-adb-handle-get-remote-gid)
+    (tramp-get-remote-uid . tramp-adb-handle-get-remote-uid)
     (tramp-set-file-uid-gid . ignore)
     (unhandled-file-name-directory . ignore)
     (unlock-file . tramp-handle-unlock-file)
@@ -220,7 +217,8 @@ arguments to pass to the OPERATION."
   (delq nil
        (mapcar
         (lambda (line)
-          (when (string-match "^\\(\\S-+\\)[[:space:]]+device$" line)
+          (when (string-match
+                 (rx bol (group (+ (not space))) (+ space) "device" eol) line)
             ;; Replace ":" by "#".
             `(nil ,(tramp-compat-string-replace
                     ":" tramp-prefix-port-format (match-string 1 line)))))
@@ -237,10 +235,10 @@ arguments to pass to the OPERATION."
        (goto-char (point-min))
        (forward-line)
        (when (looking-at
-              (concat "[[:space:]]*[^[:space:]]+"
-                      "[[:space:]]+\\([[:digit:]]+\\)"
-                      "[[:space:]]+\\([[:digit:]]+\\)"
-                      "[[:space:]]+\\([[:digit:]]+\\)"))
+              (rx (* space) (+ (not space))
+                  (+ space) (group (+ digit))
+                  (+ space) (group (+ digit))
+                  (+ space) (group (+ digit))))
          ;; The values are given as 1k numbers, so we must change
          ;; them to number of bytes.
          (list (* 1024 (string-to-number (match-string 1)))
@@ -252,25 +250,23 @@ arguments to pass to the OPERATION."
 
 (defun tramp-adb-handle-file-attributes (filename &optional id-format)
   "Like `file-attributes' for Tramp files."
-  (unless id-format (setq id-format 'integer))
-  (ignore-errors
-    (with-parsed-tramp-file-name filename nil
-      (with-tramp-file-property
-         v localname (format "file-attributes-%s" id-format)
-       (and
-        (tramp-adb-send-command-and-check
-         v (format "%s -d -l %s"
-                   (tramp-adb-get-ls-command v)
-                   (tramp-shell-quote-argument localname)))
-        (with-current-buffer (tramp-get-buffer v)
-          (tramp-adb-sh-fix-ls-output)
-          (cdar (tramp-do-parse-file-attributes-with-ls v id-format))))))))
-
-(defun tramp-do-parse-file-attributes-with-ls (vec &optional id-format)
+  ;; The result is cached in `tramp-convert-file-attributes'.
+  (with-parsed-tramp-file-name filename nil
+    (tramp-convert-file-attributes v localname id-format
+      (and
+       (tramp-adb-send-command-and-check
+       v (format "%s -d -l %s | cat"
+                 (tramp-adb-get-ls-command v)
+                 (tramp-shell-quote-argument localname)))
+       (with-current-buffer (tramp-get-buffer v)
+        (tramp-adb-sh-fix-ls-output)
+        (cdar (tramp-do-parse-file-attributes-with-ls v)))))))
+
+(defun tramp-do-parse-file-attributes-with-ls (vec)
   "Parse `file-attributes' for Tramp files using the ls(1) command."
   (with-current-buffer (tramp-get-buffer vec)
     (goto-char (point-min))
-    (let ((file-properties nil))
+    (let (file-properties)
       (while (re-search-forward tramp-adb-ls-toolbox-regexp nil t)
        (let* ((mod-string (match-string 1))
               (is-dir (eq ?d (aref mod-string 0)))
@@ -282,16 +278,16 @@ arguments to pass to the OPERATION."
               (name (match-string 6))
               (symlink-target
                (and is-symlink
-                    (cadr (split-string name "\\( -> \\|\n\\)")))))
+                    (cadr (split-string name (rx (group (| " -> " "\n"))))))))
          (push (list
                 (if is-symlink
-                    (car (split-string name "\\( -> \\|\n\\)"))
+                    (car (split-string name (rx (group (| " -> " "\n")))))
                   name)
                 (or is-dir symlink-target)
                 1     ;link-count
                 ;; no way to handle numeric ids in Androids ash
-                (if (eq id-format 'integer) 0 uid)
-                (if (eq id-format 'integer) 0 gid)
+                (cons uid tramp-unknown-id-integer)
+                (cons gid tramp-unknown-id-integer)
                 tramp-time-dont-know   ; atime
                 ;; `date-to-time' checks `iso8601-parse', which might fail.
                 (let (signal-hook-function)
@@ -308,54 +304,31 @@ arguments to pass to the OPERATION."
 (defun tramp-adb-handle-directory-files-and-attributes
   (directory &optional full match nosort id-format count)
   "Like `directory-files-and-attributes' for Tramp files."
-  (unless (file-exists-p directory)
-    (tramp-error (tramp-dissect-file-name directory) 'file-missing directory))
-  (when (file-directory-p directory)
-    (with-parsed-tramp-file-name (expand-file-name directory) nil
-      (copy-tree
-       (with-tramp-file-property
-          v localname (format "directory-files-and-attributes-%s-%s-%s-%s-%s"
-                              full match id-format nosort count)
-        (with-current-buffer (tramp-get-buffer v)
-          (when (tramp-adb-send-command-and-check
-                 v (format "%s -a -l %s"
-                           (tramp-adb-get-ls-command v)
-                           (tramp-shell-quote-argument localname)))
-            ;; We insert also filename/. and filename/.., because "ls" doesn't.
-            ;; Looks like it does include them in toybox, since Android 6.
-            (unless (re-search-backward "\\.$" nil t)
-              (narrow-to-region (point-max) (point-max))
-              (tramp-adb-send-command
-               v (format "%s -d -a -l %s %s"
-                         (tramp-adb-get-ls-command v)
-                         (tramp-shell-quote-argument
-                          (tramp-compat-file-name-concat localname "."))
-                         (tramp-shell-quote-argument
-                          (tramp-compat-file-name-concat localname ".."))))
-              (widen)))
-          (tramp-adb-sh-fix-ls-output)
-          (let ((result (tramp-do-parse-file-attributes-with-ls
-                         v (or id-format 'integer))))
-            (when full
-              (setq result
-                    (mapcar
-                     (lambda (x)
-                       (cons (expand-file-name (car x) directory) (cdr x)))
-                     result)))
-            (unless nosort
-              (setq result
-                    (sort result (lambda (x y) (string< (car x) (car y))))))
-
-             (setq result (delq nil
-                                (mapcar
-                                 (lambda (x) (if (or (not match)
-                                                     (string-match-p
-                                                      match (car x)))
-                                                 x))
-                                 result)))
-            (when (and (natnump count) (> count 0))
-              (setq result (nbutlast result (- (length result) count))))
-             result)))))))
+  (tramp-skeleton-directory-files-and-attributes
+      directory full match nosort id-format count
+    (with-current-buffer (tramp-get-buffer v)
+      (when (tramp-adb-send-command-and-check
+            v (format "%s -a -l %s | cat"
+                      (tramp-adb-get-ls-command v)
+                      (tramp-shell-quote-argument localname)))
+       ;; We insert also filename/. and filename/.., because "ls"
+       ;; doesn't on some file systems, like "sdcard".
+       (unless (re-search-backward (rx "." eol) nil t)
+         (narrow-to-region (point-max) (point-max))
+         (tramp-adb-send-command
+          v (format "%s -d -a -l %s %s | cat"
+                    (tramp-adb-get-ls-command v)
+                    (tramp-shell-quote-argument
+                     (tramp-compat-file-name-concat localname "."))
+                    (tramp-shell-quote-argument
+                     (tramp-compat-file-name-concat localname ".."))))
+         (tramp-compat-replace-regexp-in-region
+          (rx (literal (tramp-compat-file-name-unquote
+                        (file-name-as-directory localname))))
+          "" (point-min))
+         (widen)))
+      (tramp-adb-sh-fix-ls-output)
+      (tramp-do-parse-file-attributes-with-ls v))))
 
 (defun tramp-adb-get-ls-command (vec)
   "Determine `ls' command and its arguments."
@@ -389,16 +362,12 @@ Emacs dired can't find files."
     (goto-char (point-min))
     (while
        (search-forward-regexp
-        (eval-when-compile
-          (concat
-           "[[:space:]]"
-           "\\([[:space:]]" tramp-adb-ls-date-year-regexp "[[:space:]]\\)"))
+        (rx space (group space (regexp tramp-adb-ls-date-year-regexp) space))
         nil t)
       (replace-match "0\\1" "\\1" nil)
       ;; Insert missing "/".
       (when (looking-at-p
-            (eval-when-compile
-              (concat tramp-adb-ls-date-time-regexp "[[:space:]]+$")))
+            (rx (regexp tramp-adb-ls-date-time-regexp) (+ space) eol))
        (end-of-line)
        (insert "/")))
     ;; Sort entries.
@@ -479,7 +448,7 @@ Emacs dired can't find files."
    (with-parsed-tramp-file-name (expand-file-name directory) nil
      (with-tramp-file-property v localname "file-name-all-completions"
        (tramp-adb-send-command
-       v (format "%s -a %s"
+       v (format "%s -a %s | cat"
                  (tramp-adb-get-ls-command v)
                  (tramp-shell-quote-argument localname)))
        (mapcar
@@ -490,34 +459,30 @@ Emacs dired can't find files."
        (with-current-buffer (tramp-get-buffer v)
          (delete-dups
           (append
-           ;; In older Android versions, "." and ".." are not
-           ;; included.  In newer versions (toybox, since Android 6)
-           ;; they are.  We fix this by `delete-dups'.
+           ;; On some file systems like "sdcard", "." and ".." are
+           ;; not included.  We fix this by `delete-dups'.
            '("." "..")
            (delq
             nil
             (mapcar
-             (lambda (l) (and (not (string-match-p "^[[:space:]]*$" l)) l))
+             (lambda (l)
+               (and (not (string-match-p (rx bol (* space) eol) l)) l))
              (split-string (buffer-string) "\n")))))))))))
 
 (defun tramp-adb-handle-file-local-copy (filename)
   "Like `file-local-copy' for Tramp files."
-  (with-parsed-tramp-file-name filename nil
-    (unless (file-exists-p (file-truename filename))
-      (tramp-error v 'file-missing filename))
-    (let ((tmpfile (tramp-compat-make-temp-file filename)))
-      (with-tramp-progress-reporter
-         v 3 (format "Fetching %s to tmp file %s" filename tmpfile)
-       ;; "adb pull ..." does not always return an error code.
-       (unless
-           (and (tramp-adb-execute-adb-command
-                 v "pull" (tramp-compat-file-name-unquote localname) tmpfile)
-                (file-exists-p tmpfile))
-         (ignore-errors (delete-file tmpfile))
-         (tramp-error
-          v 'file-error "Cannot make local copy of file `%s'" filename))
-       (set-file-modes tmpfile (logior (or (file-modes filename) 0) #o0400)))
-      tmpfile)))
+  (tramp-skeleton-file-local-copy filename
+    (with-tramp-progress-reporter
+       v 3 (format "Fetching %s to tmp file %s" filename tmpfile)
+      ;; "adb pull ..." does not always return an error code.
+      (unless
+         (and (tramp-adb-execute-adb-command
+               v "pull" (tramp-compat-file-name-unquote localname) tmpfile)
+              (file-exists-p tmpfile))
+       (ignore-errors (delete-file tmpfile))
+       (tramp-error
+        v 'file-error "Cannot make local copy of file `%s'" filename))
+      (set-file-modes tmpfile (logior (or (file-modes filename) 0) #o0400)))))
 
 (defun tramp-adb-handle-file-executable-p (filename)
   "Like `file-executable-p' for Tramp files."
@@ -549,34 +514,39 @@ Emacs dired can't find files."
   (start end filename &optional append visit lockname mustbenew)
   "Like `write-region' for Tramp files."
   (tramp-skeleton-write-region start end filename append visit lockname 
mustbenew
-    (let ((tmpfile (tramp-compat-make-temp-file filename)))
-      (when (and append (file-exists-p filename))
-       (copy-file filename tmpfile 'ok)
-       (set-file-modes tmpfile (logior (or (file-modes tmpfile) 0) #o0600)))
-      (let (create-lockfiles)
-        (write-region start end tmpfile append 'no-message))
-      (with-tramp-progress-reporter
-         v 3 (format-message
-              "Moving tmp file `%s' to `%s'" tmpfile filename)
-       (unwind-protect
-           (unless (tramp-adb-execute-adb-command
-                    v "push" tmpfile (tramp-compat-file-name-unquote 
localname))
-             (tramp-error v 'file-error "Cannot write: `%s'" filename))
-         (delete-file tmpfile))))))
+    ;; If `start' is the empty string, it is likely that a temporary
+    ;; file is created.  Do it directly.
+    (if (and (stringp start) (string-empty-p start))
+       (tramp-adb-send-command-and-check
+        v (format "echo -n \"\" >%s" (tramp-shell-quote-argument localname)))
+
+      (let ((tmpfile (tramp-compat-make-temp-file filename)))
+       (when (and append (file-exists-p filename))
+         (copy-file filename tmpfile 'ok)
+         (set-file-modes tmpfile (logior (or (file-modes tmpfile) 0) #o0600)))
+       (let (create-lockfiles)
+          (write-region start end tmpfile append 'no-message))
+       (with-tramp-progress-reporter
+           v 3 (format-message
+                "Moving tmp file `%s' to `%s'" tmpfile filename)
+         (unwind-protect
+             (unless (tramp-adb-execute-adb-command
+                      v "push" tmpfile
+                      (tramp-compat-file-name-unquote localname))
+               (tramp-error v 'file-error "Cannot write: `%s'" filename))
+           (delete-file tmpfile)))))))
 
 (defun tramp-adb-handle-set-file-modes (filename mode &optional flag)
   "Like `set-file-modes' for Tramp files."
-  (with-parsed-tramp-file-name filename nil
-    ;; ADB shell does not support "chmod -h".
-    (unless (and (eq flag 'nofollow) (file-symlink-p filename))
-      (tramp-flush-file-properties v localname)
+  ;; ADB shell does not support "chmod -h".
+  (unless (and (eq flag 'nofollow) (file-symlink-p filename))
+    (tramp-skeleton-set-file-modes-times-uid-gid filename
       (tramp-adb-send-command-and-check
        v (format "chmod %o %s" mode (tramp-shell-quote-argument localname))))))
 
 (defun tramp-adb-handle-set-file-times (filename &optional time flag)
   "Like `set-file-times' for Tramp files."
-  (with-parsed-tramp-file-name filename nil
-    (tramp-flush-file-properties v localname)
+  (tramp-skeleton-set-file-modes-times-uid-gid filename
     (let ((time (if (or (null time)
                        (tramp-compat-time-equal-p time tramp-time-doesnt-exist)
                        (tramp-compat-time-equal-p time tramp-time-dont-know))
@@ -590,9 +560,10 @@ Emacs dired can't find files."
       ;; (introduced in POSIX.1-2008) fails.
       (tramp-adb-send-command-and-check
        v (format
-         (concat "touch -d %s %s %s 2>%s || "
-                 "touch -d %s %s %s 2>%s || "
-                 "touch -t %s %s %s")
+         (eval-when-compile
+           (concat "touch -d %s %s %s 2>%s || "
+                   "touch -d %s %s %s 2>%s || "
+                   "touch -t %s %s %s"))
          (format-time-string "%Y-%m-%dT%H:%M:%S.%NZ" time t)
          nofollow quoted-name (tramp-get-remote-null-device v)
          (format-time-string "%Y-%m-%dT%H:%M:%S" time t)
@@ -617,62 +588,61 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are 
completely ignored."
          ;; let-bind `jka-compr-inhibit' to t.
          (jka-compr-inhibit t))
       (with-parsed-tramp-file-name (if t1 filename newname) nil
-       (unless (file-exists-p filename)
-         (tramp-error v 'file-missing filename))
-       (when (and (not ok-if-already-exists) (file-exists-p newname))
-         (tramp-error v 'file-already-exists newname))
-       (when (and (file-directory-p newname)
-                  (not (directory-name-p newname)))
-         (tramp-error v 'file-error "File is a directory %s" newname))
-
-       (with-tramp-progress-reporter
-           v 0 (format "Copying %s to %s" filename newname)
-         (if (and t1 t2 (tramp-equal-remote filename newname))
-             (let ((l1 (tramp-file-local-name filename))
-                   (l2 (tramp-file-local-name newname)))
-               ;; We must also flush the cache of the directory,
-               ;; because `file-attributes' reads the values from
-               ;; there.
-               (tramp-flush-file-properties v l2)
-               ;; Short track.
-               (tramp-adb-barf-unless-okay
-                v (format
-                   "cp -f %s %s"
-                   (tramp-shell-quote-argument l1)
-                   (tramp-shell-quote-argument l2))
-                "Error copying %s to %s" filename newname))
-
-           (if-let ((tmpfile (file-local-copy filename)))
-               ;; Remote filename.
-               (condition-case err
-                   (rename-file tmpfile newname ok-if-already-exists)
-                 ((error quit)
-                  (delete-file tmpfile)
-                  (signal (car err) (cdr err))))
-
-             ;; Remote newname.
-             (when (and (file-directory-p newname)
-                        (directory-name-p newname))
-               (setq newname
-                     (expand-file-name
-                      (file-name-nondirectory filename) newname)))
-
-             (with-parsed-tramp-file-name newname nil
-               (when (and (not ok-if-already-exists)
-                          (file-exists-p newname))
-                 (tramp-error v 'file-already-exists newname))
-
-               ;; We must also flush the cache of the directory,
-               ;; because `file-attributes' reads the values from
-               ;; there.
-               (tramp-flush-file-properties v localname)
-               (unless (tramp-adb-execute-adb-command
-                        v "push"
-                        (tramp-compat-file-name-unquote filename)
-                        (tramp-compat-file-name-unquote localname))
-                 (tramp-error
-                  v 'file-error
-                  "Cannot copy `%s' `%s'" filename newname))))))))
+       (tramp-barf-if-file-missing v filename
+         (when (and (not ok-if-already-exists) (file-exists-p newname))
+           (tramp-error v 'file-already-exists newname))
+         (when (and (file-directory-p newname)
+                    (not (directory-name-p newname)))
+           (tramp-error v 'file-error "File is a directory %s" newname))
+
+         (with-tramp-progress-reporter
+             v 0 (format "Copying %s to %s" filename newname)
+           (if (and t1 t2 (tramp-equal-remote filename newname))
+               (let ((l1 (tramp-file-local-name filename))
+                     (l2 (tramp-file-local-name newname)))
+                 ;; We must also flush the cache of the directory,
+                 ;; because `file-attributes' reads the values from
+                 ;; there.
+                 (tramp-flush-file-properties v l2)
+                 ;; Short track.
+                 (tramp-adb-barf-unless-okay
+                  v (format
+                     "cp -f %s %s"
+                     (tramp-shell-quote-argument l1)
+                     (tramp-shell-quote-argument l2))
+                  "Error copying %s to %s" filename newname))
+
+             (if-let ((tmpfile (file-local-copy filename)))
+                 ;; Remote filename.
+                 (condition-case err
+                     (rename-file tmpfile newname ok-if-already-exists)
+                   ((error quit)
+                    (delete-file tmpfile)
+                    (signal (car err) (cdr err))))
+
+               ;; Remote newname.
+               (when (and (file-directory-p newname)
+                          (directory-name-p newname))
+                 (setq newname
+                       (expand-file-name
+                        (file-name-nondirectory filename) newname)))
+
+               (with-parsed-tramp-file-name newname nil
+                 (when (and (not ok-if-already-exists)
+                            (file-exists-p newname))
+                   (tramp-error v 'file-already-exists newname))
+
+                 ;; We must also flush the cache of the directory,
+                 ;; because `file-attributes' reads the values from
+                 ;; there.
+                 (tramp-flush-file-properties v localname)
+                 (unless (tramp-adb-execute-adb-command
+                          v "push"
+                          (tramp-compat-file-name-unquote filename)
+                          (tramp-compat-file-name-unquote localname))
+                   (tramp-error
+                    v 'file-error
+                    "Cannot copy `%s' `%s'" filename newname)))))))))
 
     ;; KEEP-DATE handling.
     (when keep-date
@@ -698,37 +668,38 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are 
completely ignored."
          ;; let-bind `jka-compr-inhibit' to t.
          (jka-compr-inhibit t))
       (with-parsed-tramp-file-name (if t1 filename newname) nil
-       (unless (file-exists-p filename)
-         (tramp-error v 'file-missing filename))
-       (when (and (not ok-if-already-exists) (file-exists-p newname))
-         (tramp-error v 'file-already-exists newname))
-       (when (and (file-directory-p newname)
-                  (not (directory-name-p newname)))
-         (tramp-error v 'file-error "File is a directory %s" newname))
-
-       (with-tramp-progress-reporter
-           v 0 (format "Renaming %s to %s" filename newname)
-         (if (and t1 t2
-                  (tramp-equal-remote filename newname)
-                  (not (file-directory-p filename)))
-             (let ((l1 (tramp-file-local-name filename))
-                   (l2 (tramp-file-local-name newname)))
-               ;; We must also flush the cache of the directory, because
-               ;; `file-attributes' reads the values from there.
-               (tramp-flush-file-properties v l1)
-               (tramp-flush-file-properties v l2)
-               ;; Short track.
-               (tramp-adb-barf-unless-okay
-                v (format
-                   "mv -f %s %s"
-                   (tramp-shell-quote-argument l1)
-                   (tramp-shell-quote-argument l2))
-                "Error renaming %s to %s" filename newname))
-
-           ;; Rename by copy.
-           (copy-file
-            filename newname ok-if-already-exists 'keep-time 'preserve-uid-gid)
-           (delete-file filename)))))))
+       (tramp-barf-if-file-missing v filename
+         (when (and (not ok-if-already-exists) (file-exists-p newname))
+           (tramp-error v 'file-already-exists newname))
+         (when (and (file-directory-p newname)
+                    (not (directory-name-p newname)))
+           (tramp-error v 'file-error "File is a directory %s" newname))
+
+         (with-tramp-progress-reporter
+             v 0 (format "Renaming %s to %s" filename newname)
+           (if (and t1 t2
+                    (tramp-equal-remote filename newname)
+                    (not (file-directory-p filename)))
+               (let ((l1 (tramp-file-local-name filename))
+                     (l2 (tramp-file-local-name newname)))
+                 ;; We must also flush the cache of the directory,
+                 ;; because `file-attributes' reads the values from
+                 ;; there.
+                 (tramp-flush-file-properties v l1)
+                 (tramp-flush-file-properties v l2)
+                 ;; Short track.
+                 (tramp-adb-barf-unless-okay
+                  v (format
+                     "mv -f %s %s"
+                     (tramp-shell-quote-argument l1)
+                     (tramp-shell-quote-argument l2))
+                  "Error renaming %s to %s" filename newname))
+
+             ;; Rename by copy.
+             (copy-file
+              filename newname ok-if-already-exists
+              'keep-time 'preserve-uid-gid)
+             (delete-file filename))))))))
 
 (defun tramp-adb-get-signal-strings (vec)
   "Strings to return by `process-file' in case of signals."
@@ -747,10 +718,9 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are 
completely ignored."
       (setcar result 0)
       (dolist (line signals)
        (when (string-match
-              (concat
-               "^[[:space:]]*\\([[:digit:]]+\\)"
-               "[[:space:]]+\\S-+[[:space:]]+"
-               "\\([[:alpha:]].*\\)$")
+              (rx bol (* space) (group (+ digit))
+                  (+ space) (+ (not space))
+                  (+ space) (group alpha (* nonl)) eol)
               line)
          (setcar
           (nthcdr (string-to-number (match-string 1 line)) result)
@@ -859,7 +829,7 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are 
completely ignored."
       ;; because the remote process could have changed them.
       (when tmpinput (delete-file tmpinput))
       (when process-file-side-effects
-        (tramp-flush-directory-properties v ""))
+        (tramp-flush-directory-properties v "/"))
 
       ;; Return exit status.
       (if (equal ret -1)
@@ -904,7 +874,10 @@ implementation will be used."
            (signal 'wrong-type-argument (list #'symbolp coding)))
          (when (eq connection-type t)
            (setq connection-type 'pty))
-         (unless (memq connection-type '(nil pipe pty))
+         (unless (or (and (consp connection-type)
+                          (memq (car connection-type) '(nil pipe pty))
+                          (memq (cdr connection-type) '(nil pipe pty)))
+                     (memq connection-type '(nil pipe pty)))
            (signal 'wrong-type-argument (list #'symbolp connection-type)))
          (unless (or (null filter) (eq filter t) (functionp filter))
            (signal 'wrong-type-argument (list #'functionp filter)))
@@ -942,9 +915,10 @@ implementation will be used."
                  (or (null program) tramp-process-connection-type))
                 (bmp (and (buffer-live-p buffer) (buffer-modified-p buffer)))
                 (name1 name)
-                (i 0))
+                (i 0)
+                p)
 
-           (when (string-match-p "[[:multibyte:]]" command)
+           (when (string-match-p (rx multibyte) command)
              (tramp-error
               v 'file-error "Cannot apply multi-byte command `%s'" command))
 
@@ -953,34 +927,36 @@ implementation will be used."
              (setq i (1+ i)
                    name1 (format "%s<%d>" name i)))
            (setq name name1)
-           ;; Set the new process properties.
-           (tramp-set-connection-property v "process-name" name)
-           (tramp-set-connection-property v "process-buffer" buffer)
-
-           (with-current-buffer (tramp-get-connection-buffer v)
-             (unwind-protect
-                 ;; We catch this event.  Otherwise, `make-process'
-                 ;; could be called on the local host.
-                 (save-excursion
-                   (save-restriction
-                     ;; Activate narrowing in order to save BUFFER
-                     ;; contents.  Clear also the modification time;
-                     ;; otherwise we might be interrupted by
-                     ;; `verify-visited-file-modtime'.
-                     (let ((buffer-undo-list t)
-                           (inhibit-read-only t)
-                           (coding-system-for-write
-                            (if (symbolp coding) coding (car coding)))
-                           (coding-system-for-read
-                            (if (symbolp coding) coding (cdr coding))))
-                       (clear-visited-file-modtime)
-                       (narrow-to-region (point-max) (point-max))
-                       ;; We call `tramp-adb-maybe-open-connection',
-                       ;; in order to cleanup the prompt afterwards.
-                       (tramp-adb-maybe-open-connection v)
-                       (delete-region (point-min) (point-max))
-                       ;; Send the command.
-                       (let* ((p (tramp-get-connection-process v)))
+
+           (with-tramp-saved-connection-properties
+               v '("process-name" "process-buffer")
+             ;; Set the new process properties.
+             (tramp-set-connection-property v "process-name" name)
+             (tramp-set-connection-property v "process-buffer" buffer)
+             (with-current-buffer (tramp-get-connection-buffer v)
+               (unwind-protect
+                   ;; We catch this event.  Otherwise, `make-process'
+                   ;; could be called on the local host.
+                   (save-excursion
+                     (save-restriction
+                       ;; Activate narrowing in order to save BUFFER
+                       ;; contents.  Clear also the modification
+                       ;; time; otherwise we might be interrupted by
+                       ;; `verify-visited-file-modtime'.
+                       (let ((buffer-undo-list t)
+                             (inhibit-read-only t)
+                             (coding-system-for-write
+                              (if (symbolp coding) coding (car coding)))
+                             (coding-system-for-read
+                              (if (symbolp coding) coding (cdr coding))))
+                         (clear-visited-file-modtime)
+                         (narrow-to-region (point-max) (point-max))
+                         ;; We call `tramp-adb-maybe-open-connection',
+                         ;; in order to cleanup the prompt afterwards.
+                         (tramp-adb-maybe-open-connection v)
+                         (delete-region (point-min) (point-max))
+                         ;; Send the command.
+                         (setq p (tramp-get-connection-process v))
                           (tramp-adb-send-command v command nil t) ; nooutput
                          ;; Set sentinel and filter.
                          (when sentinel
@@ -995,56 +971,56 @@ implementation will be used."
                          ;; the process could have finished already.
                          (ignore-errors
                            (set-process-query-on-exit-flag p (null noquery))
-                           (set-marker (process-mark p) (point)))
-                         ;; We must flush them here already;
-                         ;; otherwise `rename-file', `delete-file' or
-                         ;; `insert-file-contents' will fail.
-                         (tramp-flush-connection-property v "process-name")
-                         (tramp-flush-connection-property v "process-buffer")
-                         ;; Copy tmpstderr file.
-                         (when (and (stringp stderr)
-                                    (not (tramp-tramp-file-p stderr)))
-                           (add-function
-                            :after (process-sentinel p)
-                            (lambda (_proc _msg)
-                              (rename-file remote-tmpstderr stderr))))
-                         ;; Read initial output.  Remove the first
-                         ;; line, which is the command echo.
-                         (unless (eq filter t)
-                           (while
-                               (progn
-                                 (goto-char (point-min))
-                                 (not (re-search-forward "[\n]" nil t)))
-                             (tramp-accept-process-output p 0))
-                           (delete-region (point-min) (point)))
-                         ;; Provide error buffer.  This shows only
-                         ;; initial error messages; messages arriving
-                         ;; later on will be inserted when the
-                         ;; process is deleted.  The temporary file
-                         ;; will exist until the process is deleted.
-                         (when (bufferp stderr)
-                           (with-current-buffer stderr
-                             (insert-file-contents-literally
-                              remote-tmpstderr 'visit))
-                           ;; Delete tmpstderr file.
-                           (add-function
-                            :after (process-sentinel p)
-                            (lambda (_proc _msg)
-                              (with-current-buffer stderr
-                                (insert-file-contents-literally
-                                 remote-tmpstderr 'visit nil nil 'replace))
-                              (delete-file remote-tmpstderr))))
-                         ;; Return process.
-                         p))))
-
-               ;; Save exit.
-               (if (string-prefix-p tramp-temp-buffer-name (buffer-name))
-                   (ignore-errors
-                     (set-process-buffer (tramp-get-connection-process v) nil)
-                     (kill-buffer (current-buffer)))
-                 (set-buffer-modified-p bmp))
-               (tramp-flush-connection-property v "process-name")
-               (tramp-flush-connection-property v "process-buffer")))))))))
+                           (set-marker (process-mark p) (point))
+                           ;; We must flush them here already;
+                           ;; otherwise `rename-file', `delete-file'
+                           ;; or `insert-file-contents' will fail.
+                           (tramp-flush-connection-property v "process-name")
+                           (tramp-flush-connection-property
+                            v "process-buffer")
+                           ;; Copy tmpstderr file.
+                           (when (and (stringp stderr)
+                                      (not (tramp-tramp-file-p stderr)))
+                             (add-function
+                              :after (process-sentinel p)
+                              (lambda (_proc _msg)
+                                (rename-file remote-tmpstderr stderr))))
+                           ;; Read initial output.  Remove the first
+                           ;; line, which is the command echo.
+                           (unless (eq filter t)
+                             (while
+                                 (progn
+                                   (goto-char (point-min))
+                                   (not (search-forward "\n" nil t)))
+                               (tramp-accept-process-output p 0))
+                             (delete-region (point-min) (point)))
+                           ;; Provide error buffer.  This shows only
+                           ;; initial error messages; messages
+                           ;; arriving later on will be inserted when
+                           ;; the process is deleted.  The temporary
+                           ;; file will exist until the process is
+                           ;; deleted.
+                           (when (bufferp stderr)
+                             (with-current-buffer stderr
+                               (insert-file-contents-literally
+                                remote-tmpstderr 'visit))
+                             ;; Delete tmpstderr file.
+                             (add-function
+                              :after (process-sentinel p)
+                              (lambda (_proc _msg)
+                                (with-current-buffer stderr
+                                  (insert-file-contents-literally
+                                   remote-tmpstderr 'visit nil nil 'replace))
+                                (delete-file remote-tmpstderr))))
+                           ;; Return process.
+                           p))))
+
+                 ;; Save exit.
+                 (if (string-prefix-p tramp-temp-buffer-name (buffer-name))
+                     (ignore-errors
+                       (set-process-buffer p nil)
+                       (kill-buffer (current-buffer)))
+                   (set-buffer-modified-p bmp)))))))))))
 
 (defun tramp-adb-handle-exec-path ()
   "Like `exec-path' for Tramp files."
@@ -1061,6 +1037,36 @@ implementation will be used."
    ;; The equivalent to `exec-directory'.
    `(,(tramp-file-local-name (expand-file-name default-directory)))))
 
+(defun tramp-adb-handle-get-remote-uid (vec id-format)
+  "Like `tramp-get-remote-uid' for Tramp files.
+ ID-FORMAT valid values are `string' and `integer'."
+ ;; The result is cached in `tramp-get-remote-uid'.
+  (tramp-adb-send-command
+   vec
+   (format "id -u%s %s"
+          (if (equal id-format 'integer) "" "n")
+          (if (equal id-format 'integer)
+              "" "| sed -e s/^/\\\"/ -e s/\\$/\\\"/")))
+  (with-current-buffer (tramp-get-connection-buffer vec)
+    ;; Read the expression.
+    (goto-char (point-min))
+    (read (current-buffer))))
+
+(defun tramp-adb-handle-get-remote-gid (vec id-format)
+  "Like `tramp-get-remote-gid' for Tramp files.
+ID-FORMAT valid values are `string' and `integer'."
+  ;; The result is cached in `tramp-get-remote-gid'.
+  (tramp-adb-send-command
+   vec
+   (format "id -g%s %s"
+          (if (equal id-format 'integer) "" "n")
+          (if (equal id-format 'integer)
+              "" "| sed -e s/^/\\\"/ -e s/\\$/\\\"/")))
+  (with-current-buffer (tramp-get-connection-buffer vec)
+    ;; Read the expression.
+    (goto-char (point-min))
+    (read (current-buffer))))
+
 (defun tramp-adb-get-device (vec)
   "Return full host name from VEC to be used in shell execution.
 E.g. a host name \"192.168.1.1#5555\" returns \"192.168.1.1:5555\"
@@ -1113,7 +1119,7 @@ error and non-nil on success."
 
 (defun tramp-adb-send-command (vec command &optional neveropen nooutput)
   "Send the COMMAND to connection VEC."
-  (if (string-match-p "[[:multibyte:]]" command)
+  (if (string-match-p (rx multibyte) command)
       ;; Multibyte codepoints with four bytes are not supported at
       ;; least by toybox.
 
@@ -1137,12 +1143,12 @@ error and non-nil on success."
          ;; We can't use stty to disable echo of command.  stty is said
          ;; to be added to toybox 0.7.6.  busybox shall have it, but this
          ;; isn't used any longer for Android.
-         (delete-matching-lines (regexp-quote command))
+         (delete-matching-lines (rx (literal command)))
          ;; When the local machine is W32, there are still trailing ^M.
          ;; There must be a better solution by setting the correct coding
          ;; system, but this requires changes in core Tramp.
          (goto-char (point-min))
-         (while (re-search-forward "\r+$" nil t)
+         (while (re-search-forward (rx (+ "\r") eol) nil t)
            (replace-match "" nil nil)))))))
 
 (defun tramp-adb-send-command-and-check (vec command &optional exit-status)
@@ -1158,7 +1164,7 @@ the exit status."
           (format "%s; echo tramp_exit_status $?" command)
         "echo tramp_exit_status $?"))
   (with-current-buffer (tramp-get-connection-buffer vec)
-    (unless (tramp-search-regexp "tramp_exit_status [[:digit:]]+")
+    (unless (tramp-search-regexp (rx "tramp_exit_status " (+ digit)))
       (tramp-error
        vec 'file-error "Couldn't find exit status of `%s'" command))
     (skip-chars-forward "^ ")
@@ -1186,12 +1192,12 @@ FMT and ARGS are passed to `error'."
          (let ((inhibit-read-only t))
            (goto-char (point-min))
            ;; ADB terminal sends "^H" sequences.
-           (when (re-search-forward "<\b+" (point-at-eol) t)
+           (when (re-search-forward (rx "<" (+ "\b")) (line-end-position) t)
              (forward-line 1)
              (delete-region (point-min) (point)))
            ;; Delete the prompt.
             (goto-char (point-min))
-            (when (re-search-forward prompt (point-at-eol) t)
+            (when (re-search-forward prompt (line-end-position) t)
               (forward-line 1)
               (delete-region (point-min) (point)))
            (when (tramp-search-regexp prompt)
@@ -1220,7 +1226,7 @@ connection if a previous connection has died for some 
reason."
     ;; Maybe we know already that "su" is not supported.  We cannot
     ;; use a connection property, because we have not checked yet
     ;; whether it is still the same device.
-    (when (and user (not (tramp-get-file-property vec "" "su-command-p" t)))
+    (when (and user (not (tramp-get-file-property vec "/" "su-command-p" t)))
       (tramp-error vec 'file-error "Cannot switch to user `%s'" user))
 
     (unless (process-live-p p)
@@ -1231,9 +1237,8 @@ connection if a previous connection has died for some 
reason."
        (with-tramp-progress-reporter vec 3 "Opening adb shell connection"
          (let* ((coding-system-for-read 'utf-8-dos) ; Is this correct?
                 (process-connection-type tramp-process-connection-type)
-                (args (if (> (length host) 0)
-                          (list "-s" device "shell")
-                        (list "shell")))
+                (args (tramp-expand-args
+                       vec 'tramp-login-args ?d (or device "")))
                 (p (let ((default-directory
                            tramp-compat-temporary-file-directory))
                      (apply #'start-process (tramp-get-connection-name vec) buf
@@ -1261,7 +1266,7 @@ connection if a previous connection has died for some 
reason."
 
            ;; Change prompt.
            (tramp-set-connection-property
-            p "prompt" (regexp-quote (format "///%s#$" prompt)))
+            p "prompt" (rx "///" (literal prompt) "#$"))
            (tramp-adb-send-command
             vec (format "PS1=\"///\"\"%s\"\"#$\"" prompt))
 
@@ -1279,12 +1284,12 @@ connection if a previous connection has died for some 
reason."
            (tramp-message vec 5 "Checking system information")
            (tramp-adb-send-command
             vec
-            (concat
-             "echo \\\"`getprop ro.product.model` "
-             "`getprop ro.product.version` "
-             "`getprop ro.build.version.release`\\\""))
-           (let ((old-getprop
-                  (tramp-get-connection-property vec "getprop" nil))
+            (eval-when-compile
+              (concat
+               "echo \\\"`getprop ro.product.model` "
+               "`getprop ro.product.version` "
+               "`getprop ro.build.version.release`\\\"")))
+           (let ((old-getprop (tramp-get-connection-property vec "getprop"))
                  (new-getprop
                   (tramp-set-connection-property
                    vec "getprop"
@@ -1307,7 +1312,7 @@ connection if a previous connection has died for some 
reason."
              (unless (tramp-adb-send-command-and-check vec nil)
                (delete-process p)
                ;; Do not flush, we need the nil value.
-               (tramp-set-file-property vec "" "su-command-p" nil)
+               (tramp-set-file-property vec "/" "su-command-p" nil)
                (tramp-error
                 vec 'file-error "Cannot switch to user `%s'" user)))
 
@@ -1360,7 +1365,7 @@ connection if a previous connection has died for some 
reason."
     (funcall orig-fun)))
 
 (add-function
- :around  (symbol-function #'shell-mode) #'tramp-adb-tolerate-tilde)
+ :around (symbol-function #'shell-mode) #'tramp-adb-tolerate-tilde)
 (add-hook 'tramp-adb-unload-hook
          (lambda ()
            (remove-function
diff --git a/lisp/net/tramp-archive.el b/lisp/net/tramp-archive.el
index f30aa021b6..0d931b42da 100644
--- a/lisp/net/tramp-archive.el
+++ b/lisp/net/tramp-archive.el
@@ -168,7 +168,8 @@
 It must be supported by libarchive(3).")
 
 ;; <https://unix-memo.readthedocs.io/en/latest/vfs.html>
-;;    read and write: tar, cpio, pax , gzip , zip, bzip2, xz, lzip, lzma, ar, 
mtree, iso9660, compress.
+;;    read and write: tar, cpio, pax , gzip , zip, bzip2, xz, lzip,
+;;                    lzma, ar, mtree, iso9660, compress.
 ;;    read only: 7-Zip, mtree, xar, lha/lzh, rar, microsoft cab.
 
 ;;;###autoload
@@ -183,14 +184,17 @@ It must be supported by libarchive(3).")
 ;;;###autoload
 (progn (defmacro tramp-archive-autoload-file-name-regexp ()
   "Regular expression matching archive file names."
-  '(concat
-    "\\`" "\\(" ".+" "\\."
-      ;; Default suffixes ...
-      (regexp-opt tramp-archive-suffixes)
-      ;; ... with compression.
-      "\\(?:" "\\." (regexp-opt tramp-archive-compression-suffixes) "\\)*"
-    "\\)" ;; \1
-    "\\(" "/" ".*" "\\)" "\\'"))) ;; \2
+  '(rx bos
+       ;; \1
+       (group
+       (+ nonl)
+       ;; Default suffixes ...
+       "." (regexp (regexp-opt tramp-archive-suffixes))
+       ;; ... with compression.
+       (? "." (regexp (regexp-opt tramp-archive-compression-suffixes))))
+       ;; \2
+       (group "/" (* nonl))
+       eos)))
 
 (put #'tramp-archive-autoload-file-name-regexp 'tramp-autoload t)
 
@@ -227,7 +231,7 @@ It must be supported by libarchive(3).")
     (delete-file . tramp-archive-handle-not-implemented)
     ;; `diff-latest-backup-file' performed by default handler.
     (directory-file-name . tramp-archive-handle-directory-file-name)
-    (directory-files . tramp-handle-directory-files)
+    (directory-files . tramp-archive-handle-directory-files)
     (directory-files-and-attributes
      . tramp-handle-directory-files-and-attributes)
     (dired-compress-file . tramp-archive-handle-not-implemented)
@@ -240,7 +244,7 @@ It must be supported by libarchive(3).")
     (file-directory-p . tramp-handle-file-directory-p)
     (file-equal-p . tramp-handle-file-equal-p)
     (file-executable-p . tramp-archive-handle-file-executable-p)
-    (file-exists-p . tramp-handle-file-exists-p)
+    (file-exists-p . tramp-archive-handle-file-exists-p)
     (file-in-directory-p . tramp-handle-file-in-directory-p)
     (file-local-copy . tramp-archive-handle-file-local-copy)
     (file-locked-p . ignore)
@@ -309,7 +313,8 @@ Operations not mentioned here will be handled by the 
default Emacs primitives.")
             #'tramp-archive-file-name-p))
     (apply #'tramp-file-name-for-operation operation args)))
 
-(defun tramp-archive-run-real-handler (operation args)
+;;;###tramp-autoload
+(progn (defun tramp-archive-run-real-handler (operation args)
   "Invoke normal file name handler for OPERATION.
 First arg specifies the OPERATION, second arg ARGS is a list of
 arguments to pass to the OPERATION."
@@ -319,8 +324,12 @@ arguments to pass to the OPERATION."
            ,(and (eq inhibit-file-name-operation operation)
                  inhibit-file-name-handlers)))
         (inhibit-file-name-operation operation))
-    (apply operation args)))
+    (apply operation args))))
 
+;; Starting with Emacs 29, `tramp-archive-file-name-handler' is
+;; autoloaded.  But it must still be in tramp-loaddefs.el for older
+;; Emacsen.
+;;;###autoload(autoload 'tramp-archive-file-name-handler "tramp-archive")
 ;;;###tramp-autoload
 (defun tramp-archive-file-name-handler (operation &rest args)
   "Invoke the file archive related OPERATION.
@@ -347,6 +356,13 @@ arguments to pass to the OPERATION."
                (tramp-archive-run-real-handler
                  #'file-directory-p (list archive)))
             (tramp-archive-run-real-handler operation args)
+         ;; The default directory of the Tramp connection buffer
+         ;; cannot be accessed.  (Bug#56628)
+         ;; FIXME: It is superfluous to set it every single loop.
+         ;; But there is no place to set it when creating the buffer.
+         (with-current-buffer
+             (tramp-get-buffer (tramp-archive-dissect-file-name filename))
+           (setq default-directory (file-name-as-directory archive)))
           ;; Now run the handler.
           (let ((tramp-methods (cons `(,tramp-archive-method) tramp-methods))
                (tramp-gvfs-methods tramp-archive-all-gvfs-methods)
@@ -604,6 +620,27 @@ offered."
       ;; example.  So we return `directory'.
       directory)))
 
+(defun tramp-archive-handle-directory-files
+    (directory &optional full match nosort count)
+  "Like `directory-files' for Tramp files."
+  (unless (file-exists-p directory)
+    (tramp-error (tramp-dissect-file-name directory) 'file-missing directory))
+  (when (file-directory-p directory)
+    (setq directory (file-name-as-directory (expand-file-name directory)))
+    (let ((temp (nreverse (file-name-all-completions "" directory)))
+         result item)
+
+      (while temp
+       (setq item (directory-file-name (pop temp)))
+       (when (or (null match) (string-match-p match item))
+         (push (if full (concat directory item) item)
+               result)))
+      (unless nosort
+        (setq result (sort result #'string<)))
+      (when (and (natnump count) (> count 0))
+       (setq result (tramp-compat-ntake count result)))
+      result)))
+
 (defun tramp-archive-handle-dired-uncache (dir)
   "Like `dired-uncache' for file archives."
   (dired-uncache (tramp-archive-gvfs-file-name dir)))
@@ -616,6 +653,10 @@ offered."
   "Like `file-executable-p' for file archives."
   (file-executable-p (tramp-archive-gvfs-file-name filename)))
 
+(defun tramp-archive-handle-file-exists-p (filename)
+  "Like `file-exists-p' for file archives."
+  (file-exists-p (tramp-archive-gvfs-file-name filename)))
+
 (defun tramp-archive-handle-file-local-copy (filename)
   "Like `file-local-copy' for file archives."
   (file-local-copy (tramp-archive-gvfs-file-name filename)))
diff --git a/lisp/net/tramp-cache.el b/lisp/net/tramp-cache.el
index dc1e3d28b5..6a3e60f703 100644
--- a/lisp/net/tramp-cache.el
+++ b/lisp/net/tramp-cache.el
@@ -48,7 +48,7 @@
 ;; - The key is a process.  These are temporary properties related to
 ;;   an open connection.  Examples: "scripts" keeps shell script
 ;;   definitions already sent to the remote shell, "last-cmd-time" is
-;;   the time stamp a command has been sent to the remote process.
+;;   the timestamp a command has been sent to the remote process.
 ;;
 ;; - The key is nil.  These are temporary properties related to the
 ;;   local machine.  Examples: "parse-passwd" and "parse-group" keep
@@ -75,8 +75,9 @@
 
 ;;; Code:
 
-(require 'tramp)
-(autoload 'time-stamp-string "time-stamp")
+(require 'tramp-compat)
+(require 'tramp-loaddefs)
+(require 'time-stamp)
 
 ;;; -- Cache --
 
@@ -129,15 +130,11 @@ If KEY is `tramp-cache-undefined', don't create anything, 
and return nil."
          hash))))
 
 ;;;###tramp-autoload
-(defun tramp-get-file-property (key file property default)
+(defun tramp-get-file-property (key file property &optional default)
   "Get the PROPERTY of FILE from the cache context of KEY.
 Return DEFAULT if not set."
   ;; Unify localname.  Remove hop from `tramp-file-name' structure.
-  (setq file (tramp-compat-file-name-unquote file)
-       key (copy-tramp-file-name key))
-  (setf (tramp-file-name-localname key)
-       (tramp-run-real-handler #'directory-file-name (list file))
-       (tramp-file-name-hop key) nil)
+  (setq key (tramp-file-name-unify key file))
   (let* ((hash (tramp-get-hash-table key))
         (cached (and (hash-table-p hash) (gethash property hash)))
         (cached-at (and (consp cached) (format-time-string "%T" (car cached))))
@@ -161,7 +158,8 @@ Return DEFAULT if not set."
 
     (tramp-message
      key 8 "%s %s %s; inhibit: %s; cache used: %s; cached at: %s"
-     file property value remote-file-name-inhibit-cache cache-used cached-at)
+     (tramp-file-name-localname key)
+     property value remote-file-name-inhibit-cache cache-used cached-at)
     ;; For analysis purposes, count the number of getting this file attribute.
     (when (>= tramp-verbose 10)
       (let* ((var (intern (concat "tramp-cache-get-count-" property)))
@@ -181,15 +179,12 @@ Return DEFAULT if not set."
   "Set the PROPERTY of FILE to VALUE, in the cache context of KEY.
 Return VALUE."
   ;; Unify localname.  Remove hop from `tramp-file-name' structure.
-  (setq file (tramp-compat-file-name-unquote file)
-       key (copy-tramp-file-name key))
-  (setf (tramp-file-name-localname key)
-       (tramp-run-real-handler #'directory-file-name (list file))
-       (tramp-file-name-hop key) nil)
+  (setq key (tramp-file-name-unify key file))
   (let ((hash (tramp-get-hash-table key)))
     ;; We put the timestamp there.
     (puthash property (cons (current-time) value) hash)
-    (tramp-message key 8 "%s %s %s" file property value)
+    (tramp-message
+     key 8 "%s %s %s" (tramp-file-name-localname key) property value)
     ;; For analysis purposes, count the number of setting this file attribute.
     (when (>= tramp-verbose 10)
       (let* ((var (intern (concat "tramp-cache-set-count-" property)))
@@ -204,17 +199,19 @@ Return VALUE."
            (dolist (var (all-completions "tramp-cache-set-count-" obarray))
              (unintern var obarray))))
 
+;;;###tramp-autoload
+(defun tramp-file-property-p (key file property)
+  "Check whether PROPERTY of FILE is defined in the cache context of KEY."
+  (not (eq (tramp-get-file-property key file property tramp-cache-undefined)
+          tramp-cache-undefined)))
+
 ;;;###tramp-autoload
 (defun tramp-flush-file-property (key file property)
   "Remove PROPERTY of FILE in the cache context of KEY."
   ;; Unify localname.  Remove hop from `tramp-file-name' structure.
-  (setq file (tramp-compat-file-name-unquote file)
-       key (copy-tramp-file-name key))
-  (setf (tramp-file-name-localname key)
-       (tramp-run-real-handler #'directory-file-name (list file))
-       (tramp-file-name-hop key) nil)
+  (setq key (tramp-file-name-unify key file))
   (remhash property (tramp-get-hash-table key))
-  (tramp-message key 8 "%s %s" file property)
+  (tramp-message key 8 "%s %s" (tramp-file-name-localname key) property)
   (when (>= tramp-verbose 10)
     (let ((var (intern (concat "tramp-cache-set-count-" property))))
       (makunbound var))))
@@ -226,27 +223,21 @@ Return VALUE."
     (when-let ((file (file-name-directory file))
               (file (directory-file-name file)))
       ;; Unify localname.  Remove hop from `tramp-file-name' structure.
-      (setq file (tramp-compat-file-name-unquote file)
-           key (copy-tramp-file-name key))
-      (setf (tramp-file-name-localname key) file
-           (tramp-file-name-hop key) nil)
+      (setq key (tramp-file-name-unify key file))
       (dolist (property (hash-table-keys (tramp-get-hash-table key)))
        (when (string-match-p
-              "^\\(directory-\\|file-name-all-completions\\|file-entries\\)"
+              (rx
+               bos (| "directory-" "file-name-all-completions" "file-entries"))
               property)
          (tramp-flush-file-property key file property))))))
 
 ;;;###tramp-autoload
 (defun tramp-flush-file-properties (key file)
   "Remove all properties of FILE in the cache context of KEY."
-  (let* ((file (tramp-run-real-handler #'directory-file-name (list file)))
-        (truename (tramp-get-file-property key file "file-truename" nil)))
+  (let ((truename (tramp-get-file-property key file "file-truename")))
     ;; Unify localname.  Remove hop from `tramp-file-name' structure.
-    (setq file (tramp-compat-file-name-unquote file)
-         key (copy-tramp-file-name key))
-    (setf (tramp-file-name-localname key) file
-         (tramp-file-name-hop key) nil)
-    (tramp-message key 8 "%s" file)
+    (setq key (tramp-file-name-unify key file))
+    (tramp-message key 8 "%s" (tramp-file-name-localname key))
     (remhash key tramp-cache-data)
     ;; Remove file properties of symlinks.
     (when (and (stringp truename)
@@ -259,10 +250,9 @@ Return VALUE."
 (defun tramp-flush-directory-properties (key directory)
   "Remove all properties of DIRECTORY in the cache context of KEY.
 Remove also properties of all files in subdirectories."
-  (setq directory (tramp-compat-file-name-unquote directory))
-  (let* ((directory (tramp-run-real-handler
-                   #'directory-file-name (list directory)))
-        (truename (tramp-get-file-property key directory "file-truename" nil)))
+  (let* ((directory
+         (directory-file-name (tramp-compat-file-name-unquote directory)))
+        (truename (tramp-get-file-property key directory "file-truename")))
     (tramp-message key 8 "%s" directory)
     (dolist (key (hash-table-keys tramp-cache-data))
       (when (and (tramp-file-name-p key)
@@ -282,19 +272,20 @@ Remove also properties of all files in subdirectories."
 ;; not show proper directory contents when a file has been copied or
 ;; deleted before.  We must apply `save-match-data', because it would
 ;; corrupt other packages otherwise (reported from org).
+;;;###tramp-autoload
 (defun tramp-flush-file-function ()
   "Flush all Tramp cache properties from `buffer-file-name'.
 This is suppressed for temporary buffers."
   (save-match-data
     (unless (or (null (buffer-name))
-               (string-match-p "^\\( \\|\\*\\)" (buffer-name)))
+               (string-match-p (rx bos (| " " "*")) (buffer-name)))
       (let ((bfn (if (stringp (buffer-file-name))
                     (buffer-file-name)
                   default-directory))
            (tramp-verbose 0))
        (when (tramp-tramp-file-p bfn)
-         (with-parsed-tramp-file-name bfn nil
-           (tramp-flush-file-properties v localname)))))))
+         (tramp-flush-file-properties
+          (tramp-dissect-file-name bfn) (tramp-file-local-name bfn)))))))
 
 (add-hook 'before-revert-hook #'tramp-flush-file-function)
 (add-hook 'eshell-pre-command-hook #'tramp-flush-file-function)
@@ -308,10 +299,65 @@ This is suppressed for temporary buffers."
            (remove-hook 'kill-buffer-hook
                         #'tramp-flush-file-function)))
 
+;;;###tramp-autoload
+(defmacro with-tramp-file-property (key file property &rest body)
+  "Check in Tramp cache for PROPERTY, otherwise execute BODY and set cache.
+FILE must be a local file name on a connection identified via KEY."
+  (declare (indent 3) (debug t))
+  `(let ((value (tramp-get-file-property
+                ,key ,file ,property tramp-cache-undefined)))
+     (when (eq value tramp-cache-undefined)
+       ;; We cannot pass @body as parameter to
+       ;; `tramp-set-file-property' because it mangles our debug
+       ;; messages.
+       (setq value (progn ,@body))
+       (tramp-set-file-property ,key ,file ,property value))
+     value))
+
+;;;###tramp-autoload
+(defmacro with-tramp-saved-file-property (key file property &rest body)
+  "Save PROPERTY, run BODY, reset PROPERTY.
+Preserve timestamps."
+  (declare (indent 3) (debug t))
+  `(progn
+     ;; Unify localname.  Remove hop from `tramp-file-name' structure.
+     (setq ,key (tramp-file-name-unify ,key ,file))
+     (let* ((hash (tramp-get-hash-table ,key))
+           (cached (and (hash-table-p hash) (gethash ,property hash))))
+       (unwind-protect (progn ,@body)
+        ;; Reset PROPERTY.  Recompute hash, it could have been flushed.
+         (setq hash (tramp-get-hash-table ,key))
+        (if (consp cached)
+            (puthash ,property cached hash)
+          (remhash ,property hash))))))
+
+;;;###tramp-autoload
+(defmacro with-tramp-saved-file-properties (key file properties &rest body)
+  "Save PROPERTIES, run BODY, reset PROPERTIES.
+PROPERTIES is a list of file properties (strings).
+Preserve timestamps."
+  (declare (indent 3) (debug t))
+  `(progn
+     ;; Unify localname.  Remove hop from `tramp-file-name' structure.
+     (setq ,key (tramp-file-name-unify ,key ,file))
+     (let* ((hash (tramp-get-hash-table ,key))
+           (values
+            (and (hash-table-p hash)
+                 (mapcar
+                  (lambda (property) (cons property (gethash property hash)))
+                  ,properties))))
+       (unwind-protect (progn ,@body)
+        ;; Reset PROPERTIES.  Recompute hash, it could have been flushed.
+         (setq hash (tramp-get-hash-table ,key))
+        (dolist (value values)
+          (if (consp (cdr value))
+              (puthash (car value) (cdr value) hash)
+            (remhash (car value) hash)))))))
+
 ;;; -- Properties --
 
 ;;;###tramp-autoload
-(defun tramp-get-connection-property (key property default)
+(defun tramp-get-connection-property (key property &optional default)
   "Get the named PROPERTY for the connection.
 KEY identifies the connection, it is either a process or a
 `tramp-file-name' structure.  A special case is nil, which is
@@ -390,6 +436,57 @@ used to cache connection properties of the local machine."
        (or tramp-cache-data-changed (tramp-file-name-p key)))
   (remhash key tramp-cache-data))
 
+;;;###tramp-autoload
+(defmacro with-tramp-connection-property (key property &rest body)
+  "Check in Tramp for property PROPERTY, otherwise execute BODY and set."
+  (declare (indent 2) (debug t))
+  `(let ((value (tramp-get-connection-property
+                ,key ,property tramp-cache-undefined)))
+     (when (eq value tramp-cache-undefined)
+       ;; We cannot pass ,@body as parameter to
+       ;; `tramp-set-connection-property' because it mangles our debug
+       ;; messages.
+       (setq value (progn ,@body))
+       (tramp-set-connection-property ,key ,property value))
+     value))
+
+;;;###tramp-autoload
+(defmacro with-tramp-saved-connection-property (key property &rest body)
+  "Save PROPERTY, run BODY, reset PROPERTY."
+  (declare (indent 2) (debug t))
+  `(progn
+     (setq ,key (tramp-file-name-unify ,key))
+     (let* ((hash (tramp-get-hash-table ,key))
+           (cached (and (hash-table-p hash)
+                        (gethash ,property hash tramp-cache-undefined))))
+       (unwind-protect (progn ,@body)
+        ;; Reset PROPERTY.  Recompute hash, it could have been flushed.
+         (setq hash (tramp-get-hash-table ,key))
+        (if (not (eq cached tramp-cache-undefined))
+            (puthash ,property cached hash)
+          (remhash ,property hash))))))
+
+;;;###tramp-autoload
+(defmacro with-tramp-saved-connection-properties (key properties &rest body)
+  "Save PROPERTIES, run BODY, reset PROPERTIES.
+PROPERTIES is a list of file properties (strings)."
+  (declare (indent 2) (debug t))
+  `(progn
+     (setq ,key (tramp-file-name-unify ,key))
+     (let* ((hash (tramp-get-hash-table ,key))
+           (values
+            (mapcar
+             (lambda (property)
+               (cons property (gethash property hash tramp-cache-undefined)))
+             ,properties)))
+       (unwind-protect (progn ,@body)
+       ;; Reset PROPERTIES.  Recompute hash, it could have been flushed.
+       (setq hash (tramp-get-hash-table ,key))
+       (dolist (value values)
+        (if (not (eq (cdr value) tramp-cache-undefined))
+            (puthash (car value) (cdr value) hash)
+          (remhash (car value) hash)))))))
+
 ;;;###tramp-autoload
 (defun tramp-cache-print (table)
   "Print hash table TABLE."
@@ -427,7 +524,7 @@ used to cache connection properties of the local machine."
 
 ;;;###tramp-autoload
 (defun tramp-list-connections ()
-  "Return all known `tramp-file-name' structs according to `tramp-cache'."
+  "Return all active `tramp-file-name' structs according to 
`tramp-cache-data'."
   (let ((tramp-verbose 0))
     (delq nil (mapcar
               (lambda (key)
diff --git a/lisp/net/tramp-cmds.el b/lisp/net/tramp-cmds.el
index 006683bdcc..a7ac135266 100644
--- a/lisp/net/tramp-cmds.el
+++ b/lisp/net/tramp-cmds.el
@@ -34,6 +34,7 @@
 (declare-function mml-mode "mml")
 (declare-function mml-insert-empty-tag "mml")
 (declare-function reporter-dump-variable "reporter")
+(defvar mm-7bit-chars)
 (defvar reporter-eval-buffer)
 (defvar reporter-prompt-for-summary-p)
 
@@ -46,7 +47,7 @@ SYNTAX can be one of the symbols `default' (default),
    (let ((input (completing-read
                 "Enter Tramp syntax: " (tramp-syntax-values) nil t
                 (symbol-name tramp-syntax))))
-     (unless (string-equal input "")
+     (unless (string-empty-p input)
        (list (intern input)))))
   (when syntax
     (customize-set-variable 'tramp-syntax syntax)))
@@ -135,11 +136,11 @@ When called interactively, a Tramp connection has to be 
selected."
                     (get-buffer (tramp-debug-buffer-name vec)))
                   (unless keep-debug
                     (get-buffer (tramp-trace-buffer-name vec)))
-                  (tramp-get-connection-property vec "process-buffer" nil)))
+                  (tramp-get-connection-property vec "process-buffer")))
       (when (bufferp buf) (kill-buffer buf)))
 
     ;; Flush file cache.
-    (tramp-flush-directory-properties vec "")
+    (tramp-flush-directory-properties vec "/")
 
     ;; Flush connection cache.
     (tramp-flush-connection-properties vec)
@@ -502,7 +503,7 @@ This is needed if there are compatibility problems."
       ((dir (tramp-compat-funcall
             'package-desc-dir
             (car (alist-get 'tramp (bound-and-true-p package-alist))))))
-    (dolist (elc (directory-files dir 'full "\\.elc\\'"))
+    (dolist (elc (directory-files dir 'full (rx ".elc" eos)))
       (delete-file elc))
     (with-current-buffer (get-buffer-create byte-compile-log-buffer)
       (let ((inhibit-read-only t))
@@ -604,7 +605,7 @@ buffer in your bug report.
       ;; There are non-7bit characters to be masked.
       (when (and (stringp val)
                 (string-match-p
-                 (concat "[^" (bound-and-true-p mm-7bit-chars) "]") val))
+                 (rx-to-string `(not (any ,mm-7bit-chars))) val))
        (with-current-buffer reporter-eval-buffer
          (set varsym
               `(decode-coding-string
@@ -613,20 +614,21 @@ buffer in your bug report.
                 'raw-text)))))
 
     ;; Dump variable.
-    (reporter-dump-variable varsym mailbuf)
+    (goto-char (point-max))
+    (save-excursion
+      (reporter-dump-variable varsym mailbuf))
 
     (unless (hash-table-p val)
       ;; Remove string quotation.
-      (forward-line -1)
       (when (looking-at
-            (concat "\\(^.*\\)" "\""                       ;; \1 "
-                    "\\((base64-decode-string \\)" "\\\\"  ;; \2 \
-                    "\\(\".*\\)" "\\\\"                    ;; \3 \
-                    "\\(\")\\)" "\"$"))                    ;; \4 "
+            (rx bol (group (* anychar)) "\""          ;; \1 "
+                (group "(base64-decode-string ") "\\" ;; \2 \
+                (group "\"" (* anychar)) "\\"         ;; \3 \
+                (group "\")") "\"" eol))              ;; \4 "
        (replace-match "\\1\\2\\3\\4")
        (beginning-of-line)
-       (insert " ;; Variable encoded due to non-printable characters.\n"))
-      (forward-line 1))
+       (insert " ;; Variable encoded due to non-printable characters.\n")))
+    (goto-char (point-max))
 
     ;; Reset VARSYM to old value.
     (with-current-buffer reporter-eval-buffer
@@ -656,21 +658,27 @@ buffer in your bug report.
        (erase-buffer)
        (insert (format "\n;; %s\n(setq-local\n" (buffer-name buffer)))
        (lisp-indent-line)
-       (dolist
-           (varsym
-            (sort
-             (append
-              (mapcar
-               #'intern
-               (all-completions "tramp-" (buffer-local-variables buffer)))
-              ;; Non-tramp variables of interest.
-              '(connection-local-variables-alist default-directory))
-             #'string<))
-           (reporter-dump-variable varsym elbuf))
+       (dolist (varsym
+                (sort
+                 (append
+                  (mapcar
+                   #'intern
+                   (all-completions "tramp-" (buffer-local-variables buffer)))
+                  ;; Non-tramp variables of interest.
+                  '(connection-local-variables-alist default-directory))
+                 #'string<))
+         (reporter-dump-variable varsym elbuf))
        (lisp-indent-line)
        (insert ")\n"))
       (insert-buffer-substring elbuf)))
 
+  ;; Beautify encoded values.
+  (goto-char (point-min))
+  (while (re-search-forward
+         (rx "'" (group "(decode-coding-string")) nil 'noerror)
+    (replace-match "\\1"))
+  (goto-char (point-max))
+
   ;; Dump load-path shadows.
   (insert "\nload-path shadows:\n==================\n")
   (ignore-errors
@@ -683,7 +691,7 @@ buffer in your bug report.
         (eq major-mode 'message-mode)
         (bound-and-true-p mml-mode))
 
-    (let ((tramp-buf-regexp "\\*\\(debug \\)?tramp/")
+    (let ((tramp-buf-regexp (rx "*" (? "debug ") "tramp/"))
          (buffer-list (tramp-list-tramp-buffers))
          (curbuf (current-buffer)))
 
@@ -694,7 +702,7 @@ buffer in your bug report.
        (setq buffer-read-only nil)
        (goto-char (point-min))
        (while (not (eobp))
-         (if (re-search-forward tramp-buf-regexp (point-at-eol) t)
+         (if (re-search-forward tramp-buf-regexp (line-end-position) t)
              (forward-line 1)
            (forward-line 0)
            (let ((start (point)))
@@ -722,7 +730,7 @@ the debug buffer(s).")
 
        (when (y-or-n-p "Do you want to append the buffer(s)?")
          ;; OK, let's send.  First we delete the buffer list.
-         (kill-buffer nil)
+         (kill-buffer)
          (switch-to-buffer curbuf)
          (goto-char (point-max))
          (insert (propertize "\n" 'display "\n\
diff --git a/lisp/net/tramp-compat.el b/lisp/net/tramp-compat.el
index bd6d53afcb..b7c0a3113e 100644
--- a/lisp/net/tramp-compat.el
+++ b/lisp/net/tramp-compat.el
@@ -31,7 +31,7 @@
 
 (require 'auth-source)
 (require 'format-spec)
-(require 'ls-lisp)  ;; Due to `tramp-handle-insert-directory'.
+(require 'ls-lisp) ;; Due to `tramp-handle-insert-directory'.
 (require 'parse-time)
 (require 'shell)
 (require 'subr-x)
@@ -79,6 +79,7 @@ Add the extension of F, if existing."
 
 ;; `file-name-quoted-p', `file-name-quote' and `file-name-unquote' got
 ;; a second argument in Emacs 27.1.
+;;;###tramp-autoload
 (defalias 'tramp-compat-file-name-quoted-p
   (if (equal (func-arity #'file-name-quoted-p) '(1 . 2))
       #'file-name-quoted-p
@@ -234,17 +235,17 @@ CONDITION can also be a list of error conditions."
   (if (fboundp 'string-replace)
       #'string-replace
     (lambda (from-string to-string in-string)
-      (let ((case-fold-search nil))
+      (let (case-fold-search)
         (replace-regexp-in-string
-         (regexp-quote from-string) to-string in-string t t)))))
+         (rx (literal from-string)) to-string in-string t t)))))
 
 ;; Function `string-search' is new in Emacs 28.1.
 (defalias 'tramp-compat-string-search
   (if (fboundp 'string-search)
       #'string-search
     (lambda (needle haystack &optional start-pos)
-      (let ((case-fold-search nil))
-        (string-match-p (regexp-quote needle) haystack start-pos)))))
+      (let (case-fold-search)
+        (string-match-p (rx (literal needle)) haystack start-pos)))))
 
 ;; Function `make-lock-file-name' is new in Emacs 28.1.
 (defalias 'tramp-compat-make-lock-file-name
@@ -294,6 +295,64 @@ CONDITION can also be a list of error conditions."
           (setq secret (funcall secret)))
        secret))))
 
+;; Function `take' is new in Emacs 29.1.
+(defalias 'tramp-compat-take
+  (if (fboundp 'take)
+      #'take
+    (lambda (n list)
+      (when (and (natnump n) (> n 0))
+       (if (>= n (length list))
+           list (butlast list (- (length list) n)))))))
+
+;; Function `ntake' is new in Emacs 29.1.
+(defalias 'tramp-compat-ntake
+  (if (fboundp 'ntake)
+      #'ntake
+    (lambda (n list)
+      (when (and (natnump n) (> n 0))
+       (if (>= n (length list))
+           list (nbutlast list (- (length list) n)))))))
+
+;; Function `string-equal-ignore-case' is new in Emacs 29.1.
+(defalias 'tramp-compat-string-equal-ignore-case
+  (if (fboundp 'string-equal-ignore-case)
+      #'string-equal-ignore-case
+    (lambda (string1 string2)
+      (eq t (compare-strings string1 nil nil string2 nil nil t)))))
+
+;; Function `auth-source-netrc-parse-all' is new in Emacs 29.1.
+;; `netrc-parse' has been obsoleted in parallel.
+(defalias 'tramp-compat-auth-source-netrc-parse-all
+  (if (fboundp 'auth-source-netrc-parse-all)
+      #'auth-source-netrc-parse-all
+    (lambda (&optional file)
+      (declare-function netrc-parse "netrc")
+      (autoload 'netrc-parse "netrc")
+      (netrc-parse file))))
+
+;; Function `replace-regexp-in-region' is new in Emacs 28.1.
+(defalias 'tramp-compat-replace-regexp-in-region
+  (if (fboundp 'replace-regexp-in-region)
+      #'replace-regexp-in-region
+    (lambda (regexp replacement &optional start end)
+      (if start
+         (when (< start (point-min))
+            (error "Start before start of buffer"))
+       (setq start (point)))
+      (if end
+         (when (> end (point-max))
+            (error "End after end of buffer"))
+       (setq end (point-max)))
+      (save-excursion
+       (let ((matches 0)
+              (case-fold-search nil))
+         (goto-char start)
+         (while (re-search-forward regexp end t)
+            (replace-match replacement t)
+            (setq matches (1+ matches)))
+         (and (not (zerop matches))
+               matches))))))
+
 (dolist (elt (all-completions "tramp-compat-" obarray 'functionp))
   (put (intern elt) 'tramp-suppress-trace t))
 
@@ -310,6 +369,6 @@ CONDITION can also be a list of error conditions."
 ;;   parentheses with a backslash in docstrings anymore.
 ;;
 ;; * Starting with Emacs 27.1, there's `make-empty-file'.  Could be
-;;   used instead of `write-region'.
+;;   used instead of `(write-region "" ...)'.
 
 ;;; tramp-compat.el ends here
diff --git a/lisp/net/tramp-crypt.el b/lisp/net/tramp-crypt.el
index ca7bcf35ce..e7bb1ebe33 100644
--- a/lisp/net/tramp-crypt.el
+++ b/lisp/net/tramp-crypt.el
@@ -23,50 +23,50 @@
 
 ;;; Commentary:
 
-;; Access functions for crypted remote files.  It uses encfs to
+;; Access functions for encrypted remote files.  It uses encfs to
 ;; encrypt / decrypt the files on a remote directory.  A remote
-;; directory, which shall include crypted files, must be declared in
+;; directory where you wish files to be encrypted must be declared in
 ;; `tramp-crypt-directories' via command `tramp-crypt-add-directory'.
 ;; All files in that directory, including all subdirectories, are
-;; stored there encrypted.  This includes file names and directory
+;; stored encrypted.  This includes file names and directory
 ;; names.
 
 ;; This package is just responsible for the encryption part.  Copying
-;; of the crypted files is still the responsibility of the remote file
-;; name handlers.
+;; of the encrypted files is still the responsibility of the remote
+;; file name handlers.
 
 ;; A password protected encfs configuration file is created the very
-;; first time you access a crypted remote directory.  It is kept in
-;; your user directory "~/.emacs.d/" with the url-encoded directory
-;; name as part of the basename, and ".encfs6.xml" as suffix.  Do not
-;; lose this file and the corresponding password; otherwise there is
-;; no way to decrypt your crypted files.
+;; first time you access an encrypted remote directory.  It is kept in
+;; your user directory (usually "~/.emacs.d/") with the url-encoded
+;; directory name as part of the basename, and ".encfs6.xml" as
+;; suffix.  Do not lose this file and the corresponding password;
+;; otherwise there is no way to decrypt your encrypted files.
 
 ;; If the user option `tramp-crypt-save-encfs-config-remote' is
 ;; non-nil (the default), the encfs configuration file ".encfs6.xml"
-;; is also kept in the crypted remote directory.  It depends on you,
+;; is also kept in the encrypted remote directory.  It depends on you,
 ;; whether you regard the password protection of this file as
-;; sufficient.
+;; sufficient security.
 
 ;; If you use a remote file name with a quoted localname part, this
 ;; localname and the corresponding file will not be encrypted/
-;; decrypted.  For example, if you have a crypted remote directory
-;; "/nextcloud:user@host:/crypted_dir", the command
+;; decrypted.  For example, if you have an encrypted remote directory
+;; "/nextcloud:user@host:/encrypted_dir", the command
 ;;
-;;   C-x d /nextcloud:user@host:/crypted_dir
+;;   C-x d /nextcloud:user@host:/encrypted_dir
 ;;
 ;; will show the directory listing with the plain file names, and the
 ;; command
 ;;
-;;   C-x d /nextcloud:user@host:/:/crypted_dir
+;;   C-x d /nextcloud:user@host:/:/encrypted_dir
 ;;
 ;; will show the directory with the encrypted file names, and visiting
-;; a file will show its crypted contents.  However, it is highly
-;; discouraged to mix crypted and not crypted files in the same
+;; a file will show its encrypted contents.  However, it is highly
+;; discouraged to mix encrypted and non-encrypted files in the same
 ;; directory.
 
-;; If a remote directory shall not include crypted files anymore, it
-;; must be indicated by the command `tramp-crypt-remove-directory'.
+;; To disable encryption for a particular remote directory, use the
+;; command `tramp-crypt-remove-directory'.
 
 ;;; Code:
 
@@ -78,7 +78,7 @@
 (autoload 'text-property-search-forward "text-property-search")
 
 (defconst tramp-crypt-method "crypt"
-  "Method name for crypted remote directories.")
+  "Method name for encrypted remote directories.")
 
 (defcustom tramp-crypt-encfs-program "encfs"
   "Name of the encfs program."
@@ -96,7 +96,7 @@
   "Configuration option for encfs.
 This could be either \"--standard\" or \"--paranoia\".  The file
 name IV chaining mode mode will always be disabled when
-initializing a new crypted remote directory."
+initializing a new encrypted remote directory."
   :group 'tramp
   :version "28.1"
   :type '(choice (const "--standard")
@@ -120,7 +120,7 @@ initializing a new crypted remote directory."
 They are completed by \"M-x TAB\" only when encryption support is enabled."
   (and tramp-crypt-enabled
        ;; `tramp-crypt-remove-directory' needs to be completed only in
-       ;; case we have already crypted directories.
+       ;; case we have already encrypted directories.
        (or (not (eq symbol #'tramp-crypt-remove-directory))
           tramp-crypt-directories)))
 
@@ -129,21 +129,21 @@ They are completed by \"M-x TAB\" only when encryption 
support is enabled."
   "Encfs configuration file name.")
 
 (defcustom tramp-crypt-save-encfs-config-remote t
-  "Whether to keep the encfs configuration file in the crypted remote 
directory."
+  "Whether to keep the encfs configuration file in the encrypted remote 
directory."
   :group 'tramp
   :version "28.1"
   :type 'boolean)
 
 ;;;###tramp-autoload
 (defvar tramp-crypt-directories nil
-  "List of crypted remote directories.")
+  "List of encrypted remote directories.")
 
 ;; It must be a `defsubst' in order to push the whole code into
 ;; tramp-loaddefs.el.  Otherwise, there would be recursive autoloading.
 ;;;###tramp-autoload
 (defsubst tramp-crypt-file-name-p (name)
-  "Return the crypted remote directory NAME belongs to.
-If NAME doesn't belong to a crypted remote directory, retun nil."
+  "Return the encrypted remote directory NAME belongs to.
+If NAME doesn't belong to an encrypted remote directory, return nil."
   (catch 'crypt-file-name-p
     (and tramp-crypt-enabled (stringp name)
         (not (tramp-compat-file-name-quoted-p name))
@@ -151,7 +151,7 @@ If NAME doesn't belong to a crypted remote directory, retun 
nil."
         (dolist (dir tramp-crypt-directories)
           (and (string-prefix-p
                 dir (file-name-as-directory (expand-file-name name)))
-               (throw  'crypt-file-name-p dir))))))
+               (throw 'crypt-file-name-p dir))))))
 
 
 ;; New handlers should be added here.
@@ -244,7 +244,7 @@ If NAME doesn't belong to a crypted remote directory, retun 
nil."
 Operations not mentioned here will be handled by the default Emacs 
primitives.")
 
 (defsubst tramp-crypt-file-name-for-operation (operation &rest args)
-  "Like `tramp-file-name-for-operation', but for crypted remote files."
+  "Like `tramp-file-name-for-operation', but for encrypted remote files."
   (let ((tfnfo (apply #'tramp-file-name-for-operation operation args)))
     ;; `tramp-file-name-for-operation' returns already the first argument
     ;; if it is remote.  So we check a possible second argument.
@@ -268,7 +268,7 @@ arguments to pass to the OPERATION."
 
 ;;;###tramp-autoload
 (defun tramp-crypt-file-name-handler (operation &rest args)
-  "Invoke the crypted remote file related OPERATION.
+  "Invoke the encrypted remote file related OPERATION.
 First arg specifies the OPERATION, second arg is a list of
 arguments to pass to the OPERATION."
   (if-let ((filename
@@ -413,7 +413,7 @@ ARGS are the arguments.  It returns t if ran successful, 
and nil otherwise."
        t))))
 
 (defun tramp-crypt-do-encrypt-or-decrypt-file-name (op name)
-  "Return encrypted / decrypted NAME if NAME belongs to a crypted directory.
+  "Return encrypted / decrypted NAME if NAME belongs to an encrypted directory.
 OP must be `encrypt' or `decrypt'.  Raise an error if this fails.
 Otherwise, return NAME."
   (if-let ((tramp-crypt-enabled t)
@@ -426,7 +426,7 @@ Otherwise, return NAME."
        (if (directory-name-p name) #'file-name-as-directory #'identity)
        (concat
        dir
-       (unless (string-equal localname "/")
+       (unless (string-match-p (rx bos (? "/") eos) localname)
          (with-tramp-file-property
              crypt-vec localname (concat (symbol-name op) "-file-name")
            (unless (tramp-crypt-send-command
@@ -437,22 +437,22 @@ Otherwise, return NAME."
               (if (eq op 'encrypt) "Encoding" "Decoding") name))
            (with-current-buffer (tramp-get-connection-buffer crypt-vec)
              (goto-char (point-min))
-             (buffer-substring (point-min) (point-at-eol)))))))
+             (buffer-substring (point-min) (line-end-position)))))))
     ;; Nothing to do.
     name))
 
 (defsubst tramp-crypt-encrypt-file-name (name)
-  "Return encrypted NAME if NAME belongs to a crypted directory.
+  "Return encrypted NAME if NAME belongs to an encrypted directory.
 Otherwise, return NAME."
   (tramp-crypt-do-encrypt-or-decrypt-file-name 'encrypt name))
 
 (defsubst tramp-crypt-decrypt-file-name (name)
-  "Return decrypted NAME if NAME belongs to a crypted directory.
+  "Return decrypted NAME if NAME belongs to an encrypted directory.
 Otherwise, return NAME."
   (tramp-crypt-do-encrypt-or-decrypt-file-name 'decrypt name))
 
 (defun tramp-crypt-do-encrypt-or-decrypt-file (op root infile outfile)
-  "Encrypt / decrypt file INFILE to OUTFILE according to crypted directory 
ROOT.
+  "Encrypt / decrypt file INFILE to OUTFILE according to encrypted directory 
ROOT.
 Both files must be local files.  OP must be `encrypt' or `decrypt'.
 If OP ist `decrypt', the basename of INFILE must be an encrypted file name.
 Raise an error if this fails."
@@ -474,12 +474,12 @@ Raise an error if this fails."
        (write-region nil nil outfile)))))
 
 (defsubst tramp-crypt-encrypt-file (root infile outfile)
-  "Encrypt file INFILE to OUTFILE according to crypted directory ROOT.
+  "Encrypt file INFILE to OUTFILE according to encrypted directory ROOT.
 See `tramp-crypt-do-encrypt-or-decrypt-file'."
   (tramp-crypt-do-encrypt-or-decrypt-file 'encrypt root infile outfile))
 
 (defsubst tramp-crypt-decrypt-file (root infile outfile)
-  "Decrypt file INFILE to OUTFILE according to crypted directory ROOT.
+  "Decrypt file INFILE to OUTFILE according to encrypted directory ROOT.
 See `tramp-crypt-do-encrypt-or-decrypt-file'."
   (tramp-crypt-do-encrypt-or-decrypt-file 'decrypt root infile outfile))
 
@@ -542,10 +542,10 @@ localname."
        (make-tramp-file-name
         :method tramp-crypt-method :user (user-login-name)
         :host (url-hexify-string dir))
-      (tramp-user-error nil "Not a crypted remote directory: \"%s\"" name))))
+      (tramp-user-error nil "Not an encrypted remote directory: \"%s\"" 
name))))
 
 (defun tramp-crypt-get-remote-dir (vec)
-  "Return the name of the crypted remote directory to be used for encfs."
+  "Return the name of the encrypted remote directory to be used for encfs."
   (url-unhex-string (tramp-file-name-host vec)))
 
 
@@ -554,7 +554,7 @@ localname."
 (defun tramp-crypt-handle-access-file (filename string)
   "Like `access-file' for Tramp files."
   (let* ((encrypt-filename (tramp-crypt-encrypt-file-name filename))
-        (encrypt-regexp (concat (regexp-quote encrypt-filename) "\\'"))
+        (encrypt-regexp (rx (literal encrypt-filename) eos))
         tramp-crypt-enabled)
     (condition-case err
        (access-file encrypt-filename string)
@@ -600,62 +600,61 @@ absolute file names."
            (delete-directory filename 'recursive)))
 
       (with-parsed-tramp-file-name (if t1 filename newname) nil
-       (unless (file-exists-p filename)
-         (tramp-error v 'file-missing filename))
-       (when (and (not ok-if-already-exists) (file-exists-p newname))
-         (tramp-error v 'file-already-exists newname))
-       (when (and (file-directory-p newname)
-                  (not (directory-name-p newname)))
-         (tramp-error v 'file-error "File is a directory %s" newname))
-
-       (with-tramp-progress-reporter
-           v 0 (format "%s %s to %s" msg-operation filename newname)
-         (if (and t1 t2 (string-equal t1 t2))
-             ;; Both files are on the same crypted remote directory.
-             (let (tramp-crypt-enabled)
-               (if (eq op 'copy)
-                   (copy-file
-                    encrypt-filename encrypt-newname ok-if-already-exists
-                    keep-date preserve-uid-gid preserve-extended-attributes)
-                 (rename-file
-                  encrypt-filename encrypt-newname ok-if-already-exists)))
-
-           (let* ((tmpdir (tramp-compat-make-temp-file filename 'dir))
-                  (tmpfile1
-                   (expand-file-name
-                    (file-name-nondirectory encrypt-filename) tmpdir))
-                  (tmpfile2
-                   (expand-file-name
-                    (file-name-nondirectory encrypt-newname) tmpdir))
-                  tramp-crypt-enabled)
-             (cond
-              ;; Source and target file are on a crypted remote directory.
-              ((and t1 t2)
-               (if (eq op 'copy)
-                   (copy-file
-                    encrypt-filename encrypt-newname ok-if-already-exists
-                    keep-date preserve-uid-gid preserve-extended-attributes)
-                 (rename-file
-                  encrypt-filename encrypt-newname ok-if-already-exists)))
-              ;; Source file is on a crypted remote directory.
-              (t1
-               (if (eq op 'copy)
-                   (copy-file
-                    encrypt-filename tmpfile1 t keep-date preserve-uid-gid
-                    preserve-extended-attributes)
-                 (rename-file encrypt-filename tmpfile1 t))
-               (tramp-crypt-decrypt-file t1 tmpfile1 tmpfile2)
-               (rename-file tmpfile2 newname ok-if-already-exists))
-              ;; Target file is on a crypted remote directory.
-              (t2
-               (if (eq op 'copy)
-                   (copy-file
-                    filename tmpfile1 t keep-date preserve-uid-gid
-                    preserve-extended-attributes)
-                 (rename-file filename tmpfile1 t))
-               (tramp-crypt-encrypt-file t2 tmpfile1 tmpfile2)
-               (rename-file tmpfile2 encrypt-newname ok-if-already-exists)))
-             (delete-directory tmpdir 'recursive))))))
+       (tramp-barf-if-file-missing v filename
+         (when (and (not ok-if-already-exists) (file-exists-p newname))
+           (tramp-error v 'file-already-exists newname))
+         (when (and (file-directory-p newname)
+                    (not (directory-name-p newname)))
+           (tramp-error v 'file-error "File is a directory %s" newname))
+
+         (with-tramp-progress-reporter
+             v 0 (format "%s %s to %s" msg-operation filename newname)
+           (if (and t1 t2 (string-equal t1 t2))
+               ;; Both files are on the same encrypted remote directory.
+               (let (tramp-crypt-enabled)
+                 (if (eq op 'copy)
+                     (copy-file
+                      encrypt-filename encrypt-newname ok-if-already-exists
+                      keep-date preserve-uid-gid preserve-extended-attributes)
+                   (rename-file
+                    encrypt-filename encrypt-newname ok-if-already-exists)))
+
+             (let* ((tmpdir (tramp-compat-make-temp-file filename 'dir))
+                    (tmpfile1
+                     (expand-file-name
+                      (file-name-nondirectory encrypt-filename) tmpdir))
+                    (tmpfile2
+                     (expand-file-name
+                      (file-name-nondirectory encrypt-newname) tmpdir))
+                    tramp-crypt-enabled)
+               (cond
+                ;; Source and target file are on an encrypted remote directory.
+                ((and t1 t2)
+                 (if (eq op 'copy)
+                     (copy-file
+                      encrypt-filename encrypt-newname ok-if-already-exists
+                      keep-date preserve-uid-gid preserve-extended-attributes)
+                   (rename-file
+                    encrypt-filename encrypt-newname ok-if-already-exists)))
+                ;; Source file is on an encrypted remote directory.
+                (t1
+                 (if (eq op 'copy)
+                     (copy-file
+                      encrypt-filename tmpfile1 t keep-date preserve-uid-gid
+                      preserve-extended-attributes)
+                   (rename-file encrypt-filename tmpfile1 t))
+                 (tramp-crypt-decrypt-file t1 tmpfile1 tmpfile2)
+                 (rename-file tmpfile2 newname ok-if-already-exists))
+                ;; Target file is on an encrypted remote directory.
+                (t2
+                 (if (eq op 'copy)
+                     (copy-file
+                      filename tmpfile1 t keep-date preserve-uid-gid
+                      preserve-extended-attributes)
+                   (rename-file filename tmpfile1 t))
+                 (tramp-crypt-encrypt-file t2 tmpfile1 tmpfile2)
+                 (rename-file tmpfile2 encrypt-newname ok-if-already-exists)))
+               (delete-directory tmpdir 'recursive)))))))
 
     (when (and t1 (eq op 'rename))
       (with-parsed-tramp-file-name filename v1
@@ -682,7 +681,7 @@ absolute file names."
      (list filename newname ok-if-already-exists keep-date
           preserve-uid-gid preserve-extended-attributes))))
 
-;; Crypted files won't be trashed.
+;; Encrypted files won't be trashed.
 (defun tramp-crypt-handle-delete-directory
     (directory &optional recursive _trash)
   "Like `delete-directory' for Tramp files."
@@ -691,7 +690,7 @@ absolute file names."
     (let (tramp-crypt-enabled)
       (delete-directory (tramp-crypt-encrypt-file-name directory) recursive))))
 
-;; Crypted files won't be trashed.
+;; Encrypted files won't be trashed.
 (defun tramp-crypt-handle-delete-file (filename &optional _trash)
   "Like `delete-file' for Tramp files."
   (with-parsed-tramp-file-name (expand-file-name filename) nil
@@ -702,36 +701,14 @@ absolute file names."
 (defun tramp-crypt-handle-directory-files
     (directory &optional full match nosort count)
   "Like `directory-files' for Tramp files."
-  (unless (file-exists-p directory)
-    (tramp-error (tramp-dissect-file-name directory) 'file-missing directory))
-  (when (file-directory-p directory)
-    (setq directory (file-name-as-directory (expand-file-name directory)))
-    (let* (tramp-crypt-enabled
-          (result
-           (directory-files (tramp-crypt-encrypt-file-name directory) 'full)))
-      (setq result
-           (mapcar (lambda (x) (tramp-crypt-decrypt-file-name x)) result))
-      (when match
-       (setq result
-             (delq
-              nil
-              (mapcar
-               (lambda (x)
-                 (when (string-match-p match (substring x (length directory)))
-                   x))
-               result))))
-      (unless full
-       (setq result
-             (mapcar
-              (lambda (x)
-                (replace-regexp-in-string
-                 (concat "^" (regexp-quote directory)) "" x))
-              result)))
-      (unless nosort
-        (setq result (sort result #'string<)))
-      (when (and (natnump count) (> count 0))
-       (setq result (nbutlast result (- (length result) count))))
-      result)))
+  (tramp-skeleton-directory-files directory full match nosort count
+    (let (tramp-crypt-enabled)
+      (mapcar
+       (lambda (x)
+        (replace-regexp-in-string
+         (rx bos (literal directory)) ""
+         (tramp-crypt-decrypt-file-name x)))
+       (directory-files (tramp-crypt-encrypt-file-name directory) 'full)))))
 
 (defun tramp-crypt-handle-file-attributes (filename &optional id-format)
   "Like `file-attributes' for Tramp files."
@@ -847,24 +824,21 @@ WILDCARD is not supported."
 
 (defun tramp-crypt-handle-set-file-modes (filename mode &optional flag)
   "Like `set-file-modes' for Tramp files."
-  (with-parsed-tramp-file-name filename nil
-    (tramp-flush-file-properties v localname)
+  (tramp-skeleton-set-file-modes-times-uid-gid filename
     (let (tramp-crypt-enabled)
       (tramp-compat-set-file-modes
        (tramp-crypt-encrypt-file-name filename) mode flag))))
 
 (defun tramp-crypt-handle-set-file-times (filename &optional time flag)
   "Like `set-file-times' for Tramp files."
-  (with-parsed-tramp-file-name filename nil
-    (tramp-flush-file-properties v localname)
+  (tramp-skeleton-set-file-modes-times-uid-gid filename
     (let (tramp-crypt-enabled)
       (tramp-compat-set-file-times
        (tramp-crypt-encrypt-file-name filename) time flag))))
 
 (defun tramp-crypt-handle-set-file-uid-gid (filename &optional uid gid)
   "Like `tramp-set-file-uid-gid' for Tramp files."
-  (with-parsed-tramp-file-name filename nil
-    (tramp-flush-file-properties v localname)
+  (tramp-skeleton-set-file-modes-times-uid-gid filename
     (let (tramp-crypt-enabled)
       (tramp-set-file-uid-gid
        (tramp-crypt-encrypt-file-name filename) uid gid))))
diff --git a/lisp/net/tramp-ftp.el b/lisp/net/tramp-ftp.el
index ff8caa570c..ad736256ca 100644
--- a/lisp/net/tramp-ftp.el
+++ b/lisp/net/tramp-ftp.el
@@ -97,9 +97,9 @@ present for backward compatibility."
 
  ;; Add some defaults for `tramp-default-method-alist'.
  (add-to-list 'tramp-default-method-alist
-             (list "\\`ftp\\." nil tramp-ftp-method))
+             (list (rx bos "ftp.") nil tramp-ftp-method))
  (add-to-list 'tramp-default-method-alist
-             (list nil "\\`\\(anonymous\\|ftp\\)\\'" tramp-ftp-method))
+             (list nil (rx bos (| "anonymous" "ftp") eos) tramp-ftp-method))
 
  ;; Add completion function for FTP method.
  (tramp-set-completion-function
@@ -125,7 +125,7 @@ pass to the OPERATION."
          ;; "ftp" method is used in the Tramp file name.  So we unset
          ;; those values.
          (ange-ftp-ftp-name-arg "")
-         (ange-ftp-ftp-name-res nil))
+         ange-ftp-ftp-name-res)
       (cond
        ;; If argument is a symlink, `file-directory-p' and
        ;; `file-exists-p' call the traversed file recursively.  So we
@@ -135,12 +135,21 @@ pass to the OPERATION."
        ;; completion.  We don't use `with-parsed-tramp-file-name',
        ;; because this returns another user but the one declared in
        ;; "~/.netrc".
+       ;; For file names which look like Tramp archive files like
+       ;; "/ftp:anonymous@ftp.gnu.org:/gnu/tramp/tramp-2.0.39.tar.gz",
+       ;; we must disable tramp-archive.el, because in
+       ;; `ange-ftp-get-files' this is "normalized" by
+       ;; `file-name-as-directory' with unwelcome side side-effects.
+       ;; This disables the file archive functionality, perhaps we
+       ;; could fix this otherwise.  (Bug#56078)
        ((memq operation '(file-directory-p file-exists-p))
-       (if (apply #'ange-ftp-hook-function operation args)
+       (cl-letf (((symbol-function #'tramp-archive-file-name-handler)
+                  (lambda (operation &rest args)
+                    (tramp-archive-run-real-handler operation args))))
+         (prog1 (apply #'ange-ftp-hook-function operation args)
            (let ((v (tramp-dissect-file-name (car args) t)))
              (setf (tramp-file-name-method v) tramp-ftp-method)
-             (tramp-set-connection-property v "started" t))
-         nil))
+             (tramp-set-connection-property v "started" t)))))
 
        ;; If the second argument of `copy-file' or `rename-file' is a
        ;; remote file name but via FTP, ange-ftp doesn't check this.
diff --git a/lisp/net/tramp-fuse.el b/lisp/net/tramp-fuse.el
index 20be74a79b..4b51af070a 100644
--- a/lisp/net/tramp-fuse.el
+++ b/lisp/net/tramp-fuse.el
@@ -51,43 +51,37 @@
   "Remove hidden files from FILES."
   (if tramp-fuse-remove-hidden-files
       (cl-remove-if
-       (lambda (x) (and (stringp x) (string-match-p "\\.fuse_hidden" x)))
+       (lambda (x) (and (stringp x) (string-match-p (rx ".fuse_hidden") x)))
        files)
     files))
 
 (defun tramp-fuse-handle-directory-files
     (directory &optional full match nosort count)
   "Like `directory-files' for Tramp files."
-  (unless (file-exists-p directory)
-    (tramp-error (tramp-dissect-file-name directory) 'file-missing directory))
-  (when (file-directory-p directory)
-    (setq directory (file-name-as-directory (expand-file-name directory)))
-    (with-parsed-tramp-file-name directory nil
-      (let ((result
-            (tramp-compat-directory-files
-             (tramp-fuse-local-file-name directory) full match nosort count)))
+  (let ((result
+        (tramp-skeleton-directory-files directory full match nosort count
+          ;; Some storage systems do not return "." and "..".
+          (delete-dups
+           (append
+            '("." "..")
+            (tramp-fuse-remove-hidden-files
+             (tramp-compat-directory-files
+              (tramp-fuse-local-file-name directory))))))))
+    (if full
        ;; Massage the result.
-       (when full
-         (let ((local (concat "^" (regexp-quote (tramp-fuse-mount-point v))))
-               (remote (directory-file-name
-                        (funcall
-                         (if (tramp-compat-file-name-quoted-p directory)
-                             #'tramp-compat-file-name-quote #'identity)
-                         (file-remote-p directory)))))
-           (setq result
-                 (mapcar
-                  (lambda (x) (replace-regexp-in-string local remote x))
-                  result))))
-       ;; Some storage systems do not return "." and "..".
-       (dolist (item '(".." "."))
-         (when (and (string-match-p (or match (regexp-quote item)) item)
-                    (not
-                     (member (if full (setq item (concat directory item)) item)
-                             result)))
-           (setq result (cons item result))))
-       ;; Return result.
-       (tramp-fuse-remove-hidden-files
-        (if nosort result (sort result #'string<)))))))
+       (let ((local (rx bol
+                        (literal
+                         (tramp-fuse-mount-point
+                          (tramp-dissect-file-name directory)))))
+             (remote (directory-file-name
+                      (funcall
+                       (if (tramp-compat-file-name-quoted-p directory)
+                           #'tramp-compat-file-name-quote #'identity)
+                       (file-remote-p directory)))))
+         (mapcar
+          (lambda (x) (replace-regexp-in-string local remote x))
+          result))
+      result)))
 
 (defun tramp-fuse-handle-file-attributes (filename &optional id-format)
   "Like `file-attributes' for Tramp files."
@@ -153,7 +147,7 @@
 
 (defun tramp-fuse-mount-point (vec)
   "Return local mount point of VEC."
-  (or (tramp-get-connection-property vec "mount-point" nil)
+  (or (tramp-get-connection-property vec "mount-point")
       (expand-file-name
        (concat
        tramp-temp-name-prefix
@@ -177,7 +171,7 @@ It has the same meaning as 
`remote-file-name-inhibit-cache'.")
   ;; cannot use `with-tramp-file-property', because we don't want to
   ;; cache a nil result.
   (let ((remote-file-name-inhibit-cache tramp-fuse-mount-timeout))
-    (or (tramp-get-file-property vec "/" "mounted" nil)
+    (or (tramp-get-file-property vec "/" "mounted")
         (let* ((default-directory tramp-compat-temporary-file-directory)
                (command (format "mount -t fuse.%s" (tramp-file-name-method 
vec)))
               (mount (shell-command-to-string command)))
@@ -185,8 +179,7 @@ It has the same meaning as 
`remote-file-name-inhibit-cache'.")
           (tramp-set-file-property
           vec "/" "mounted"
            (when (string-match
-                 (format
-                   "^\\(%s\\)\\s-" (regexp-quote (tramp-fuse-mount-spec vec)))
+                 (rx bol (group (literal (tramp-fuse-mount-spec vec))) space)
                  mount)
              (match-string 1 mount)))))))
 
diff --git a/lisp/net/tramp-gvfs.el b/lisp/net/tramp-gvfs.el
index fca3988b8d..9060f37ed5 100644
--- a/lisp/net/tramp-gvfs.el
+++ b/lisp/net/tramp-gvfs.el
@@ -87,7 +87,7 @@
 ;; For hostname completion, information is retrieved from the zeroconf
 ;; daemon (for the "afp", "dav", "davs", and "sftp" methods).  The
 ;; zeroconf daemon is pre-configured to discover services in the
-;; "local" domain.  If another domain shall be used for discovering
+;; "local" domain.  If another domain should be used for discovering
 ;; services, the user option `tramp-gvfs-zeroconf-domain' can be set
 ;; accordingly.
 
@@ -410,9 +410,9 @@ It has been changed in GVFS 1.14.")
 ;; </interface>
 
 (defconst tramp-goa-identity-regexp
-  (concat "^" "\\(" tramp-user-regexp "\\)?"
-         "@" "\\(" tramp-host-regexp "\\)?"
-         "\\(?:" ":""\\(" tramp-port-regexp "\\)" "\\)?")
+  (rx bol (? (group (regexp tramp-user-regexp)))
+      "@" (? (group (regexp tramp-host-regexp)))
+      (? ":" (group (regexp tramp-port-regexp))))
   "Regexp matching GNOME Online Accounts \"PresentationIdentity\" property.")
 
 (defconst tramp-goa-interface-mail "org.gnome.OnlineAccounts.Mail"
@@ -712,13 +712,13 @@ It has been changed in GVFS 1.14.")
 
 (eval-and-compile
   (defconst tramp-gvfs-file-attributes-with-gvfs-ls-regexp
-    (concat "[[:blank:]]" (regexp-opt tramp-gvfs-file-attributes t) 
"=\\(.+?\\)")
+    (rx blank (group (regexp (regexp-opt tramp-gvfs-file-attributes)))
+       "=" (group (+? nonl)))
     "Regexp to parse GVFS file attributes with `gvfs-ls'."))
 
 (defconst tramp-gvfs-file-attributes-with-gvfs-info-regexp
-  (concat "^[[:blank:]]*"
-         (regexp-opt tramp-gvfs-file-attributes t)
-         ":[[:blank:]]+\\(.*\\)$")
+  (rx bol (* blank) (group (regexp (regexp-opt tramp-gvfs-file-attributes)))
+      ":" (+ blank) (group (* nonl)) eol)
   "Regexp to parse GVFS file attributes with `gvfs-info'.")
 
 (defconst tramp-gvfs-file-system-attributes
@@ -728,16 +728,16 @@ It has been changed in GVFS 1.14.")
   "GVFS file system attributes.")
 
 (defconst tramp-gvfs-file-system-attributes-regexp
-  (concat "^[[:blank:]]*"
-         (regexp-opt tramp-gvfs-file-system-attributes t)
-         ":[[:blank:]]+\\(.*\\)$")
+  (rx bol (* blank)
+      (group (regexp (regexp-opt tramp-gvfs-file-system-attributes)))
+      ":" (+ blank) (group (* nonl)) eol)
   "Regexp to parse GVFS file system attributes with `gvfs-info'.")
 
 (defconst tramp-gvfs-nextcloud-default-prefix "/remote.php/webdav"
   "Default prefix for owncloud / nextcloud methods.")
 
 (defconst tramp-gvfs-nextcloud-default-prefix-regexp
-  (concat (regexp-quote tramp-gvfs-nextcloud-default-prefix) "$")
+  (rx (literal tramp-gvfs-nextcloud-default-prefix) eol)
   "Regexp of default prefix for owncloud / nextcloud methods.")
 
 
@@ -839,6 +839,8 @@ Operations not mentioned here will be handled by the 
default Emacs primitives.")
     (let ((method (tramp-file-name-method vec)))
       (and (stringp method) (member method tramp-gvfs-methods)))))
 
+(defvar tramp-gvfs-dbus-event-vector)
+
 ;;;###tramp-autoload
 (defun tramp-gvfs-file-name-handler (operation &rest args)
   "Invoke the GVFS related OPERATION and ARGS.
@@ -846,7 +848,11 @@ First arg specifies the OPERATION, second arg is a list of
 arguments to pass to the OPERATION."
   (unless tramp-gvfs-enabled
     (tramp-user-error nil "Package `tramp-gvfs' not supported"))
-  (if-let ((fn (assoc operation tramp-gvfs-file-name-handler-alist)))
+  (if-let ((filename (apply #'tramp-file-name-for-operation operation args))
+           (tramp-gvfs-dbus-event-vector
+            (and (tramp-tramp-file-p filename)
+                 (tramp-dissect-file-name filename)))
+           (fn (assoc operation tramp-gvfs-file-name-handler-alist)))
       (save-match-data (apply (cdr fn) args))
     (tramp-run-real-handler operation args)))
 
@@ -862,7 +868,7 @@ arguments to pass to the OPERATION."
 (defun tramp-gvfs-dbus-string-to-byte-array (string)
   "Like `dbus-string-to-byte-array' but add trailing \\0 if needed."
   (dbus-string-to-byte-array
-   (if (string-match-p "^(aya{sv})" tramp-gvfs-mountlocation-signature)
+   (if (string-match-p (rx bol "(aya{sv})") tramp-gvfs-mountlocation-signature)
        (concat string (string 0)) string)))
 
 (defun tramp-gvfs-dbus-byte-array-to-string (byte-array)
@@ -896,7 +902,7 @@ The call will be traced by Tramp with trace level 6."
   (let (result)
     (tramp-message vec 6 "%s" (cons func args))
     (setq result (apply func args))
-    (tramp-message vec 6 "%s" result(tramp-gvfs-stringify-dbus-message result))
+    (tramp-message vec 6 "%s" (tramp-gvfs-stringify-dbus-message result))
     result))
 
 (put #'tramp-dbus-function 'tramp-suppress-trace t)
@@ -936,7 +942,8 @@ The call will be traced by Tramp with trace level 6."
 (defvar tramp-gvfs-dbus-event-vector nil
   "Current Tramp file name to be used, as vector.
 It is needed when D-Bus signals or errors arrive, because there
-is no information where to trace the message.")
+is no information where to trace the message.
+The global value will always be nil; it is bound where needed.")
 
 (defun tramp-gvfs-dbus-event-error (event err)
   "Called when a D-Bus error message arrives, see 
`dbus-event-error-functions'."
@@ -953,6 +960,15 @@ is no information where to trace the message.")
 
 ;; File name primitives.
 
+(defun tramp-gvfs-info (filename &optional arg)
+  "Check FILENAME via `gvfs-info'.
+Set file property \"file-exists-p\" with the result."
+  (with-parsed-tramp-file-name filename nil
+    (tramp-set-file-property
+     v localname "file-exists-p"
+     (tramp-gvfs-send-command
+      v "gvfs-info" arg (tramp-gvfs-url-file-name filename)))))
+
 (defun tramp-gvfs-do-copy-or-rename-file
   (op filename newname &optional ok-if-already-exists keep-date
    preserve-uid-gid preserve-extended-attributes)
@@ -995,84 +1011,81 @@ file names."
          (msg-operation (if (eq op 'copy) "Copying" "Renaming")))
 
       (with-parsed-tramp-file-name (if t1 filename newname) nil
-       (unless (file-exists-p filename)
-         (tramp-error v 'file-missing filename))
-       (when (and (not ok-if-already-exists) (file-exists-p newname))
-         (tramp-error v 'file-already-exists newname))
-       (when (and (file-directory-p newname)
-                  (not (directory-name-p newname)))
-         (tramp-error v 'file-error "File is a directory %s" newname))
-
-       (cond
-        ;; We cannot rename volatile files, as used by Google-drive.
-        ((and (not equal-remote) volatile)
-         (prog1 (copy-file
-                 filename newname ok-if-already-exists keep-date
-                 preserve-uid-gid preserve-extended-attributes)
-           (delete-file filename)))
-
-        ;; We cannot copy or rename directly.
-        ((or (and equal-remote
-                  (tramp-get-connection-property v "direct-copy-failed" nil))
-             (and t1 (not (tramp-gvfs-file-name-p filename)))
-             (and t2 (not (tramp-gvfs-file-name-p newname))))
-         (let ((tmpfile (tramp-compat-make-temp-file filename)))
-           (if (eq op 'copy)
-               (copy-file
-                filename tmpfile t keep-date preserve-uid-gid
-                preserve-extended-attributes)
-             (rename-file filename tmpfile t))
-           (rename-file tmpfile newname ok-if-already-exists)))
-
-        ;; Direct action.
-        (t (with-tramp-progress-reporter
-               v 0 (format "%s %s to %s" msg-operation filename newname)
-             (unless
-                 (and (apply
-                       #'tramp-gvfs-send-command v gvfs-operation
-                       (append
-                        (and (eq op 'copy) (or keep-date preserve-uid-gid)
-                             '("--preserve"))
-                        (list
-                         (tramp-gvfs-url-file-name filename)
-                         (tramp-gvfs-url-file-name newname))))
-                      ;; Some backends do not return a proper error
-                      ;; code in case of direct copy/move.  Apply
-                      ;; sanity checks.
-                      (or (not equal-remote)
-                          (tramp-gvfs-send-command
-                           v "gvfs-info" (tramp-gvfs-url-file-name newname))
-                          (eq op 'copy)
-                          (not (tramp-gvfs-send-command
-                                v "gvfs-info"
-                                (tramp-gvfs-url-file-name filename)))))
-
-               (if (or (not equal-remote)
-                       (and equal-remote
-                            (tramp-get-connection-property
-                             v "direct-copy-failed" nil)))
-                   ;; Propagate the error.
-                   (with-current-buffer (tramp-get-connection-buffer v)
-                     (goto-char (point-min))
-                     (tramp-error-with-buffer
-                      nil v 'file-error
-                      "%s failed, see buffer `%s' for details."
-                      msg-operation (buffer-name)))
-
-                 ;; Some WebDAV server, like the one from QNAP, do
-                 ;; not support direct copy/move.  Try a fallback.
-                 (tramp-set-connection-property v "direct-copy-failed" t)
-                 (tramp-gvfs-do-copy-or-rename-file
-                  op filename newname ok-if-already-exists keep-date
-                  preserve-uid-gid preserve-extended-attributes))))
-
-           (when (and t1 (eq op 'rename))
-             (with-parsed-tramp-file-name filename nil
-               (tramp-flush-file-properties v localname)))
-
-           (when t2
-             (with-parsed-tramp-file-name newname nil
-               (tramp-flush-file-properties v localname)))))))))
+       (tramp-barf-if-file-missing v filename
+         (when (and (not ok-if-already-exists) (file-exists-p newname))
+           (tramp-error v 'file-already-exists newname))
+         (when (and (file-directory-p newname)
+                    (not (directory-name-p newname)))
+           (tramp-error v 'file-error "File is a directory %s" newname))
+
+         (cond
+          ;; We cannot rename volatile files, as used by Google-drive.
+          ((and (not equal-remote) volatile)
+           (prog1 (copy-file
+                   filename newname ok-if-already-exists keep-date
+                   preserve-uid-gid preserve-extended-attributes)
+             (delete-file filename)))
+
+          ;; We cannot copy or rename directly.
+          ((or (and equal-remote
+                    (tramp-get-connection-property v "direct-copy-failed"))
+               (and t1 (not (tramp-gvfs-file-name-p filename)))
+               (and t2 (not (tramp-gvfs-file-name-p newname))))
+           (let ((tmpfile (tramp-compat-make-temp-file filename)))
+             (if (eq op 'copy)
+                 (copy-file
+                  filename tmpfile t keep-date preserve-uid-gid
+                  preserve-extended-attributes)
+               (rename-file filename tmpfile t))
+             (rename-file tmpfile newname ok-if-already-exists)))
+
+          ;; Direct action.
+          (t (with-tramp-progress-reporter
+                 v 0 (format "%s %s to %s" msg-operation filename newname)
+               (unless
+                   (and (apply
+                         #'tramp-gvfs-send-command v gvfs-operation
+                         (append
+                          (and (eq op 'copy) (or keep-date preserve-uid-gid)
+                               '("--preserve"))
+                          (list
+                           (tramp-gvfs-url-file-name filename)
+                           (tramp-gvfs-url-file-name newname))))
+                        ;; Some backends do not return a proper error
+                        ;; code in case of direct copy/move.  Apply
+                        ;; sanity checks.
+                        (or (not equal-remote)
+                            (and
+                             (tramp-gvfs-info newname)
+                             (or (eq op 'copy)
+                                 (not (tramp-gvfs-info filename))))))
+
+                 (if (or (not equal-remote)
+                         (and equal-remote
+                              (tramp-get-connection-property
+                               v "direct-copy-failed")))
+                     ;; Propagate the error.
+                     (with-current-buffer (tramp-get-connection-buffer v)
+                       (goto-char (point-min))
+                       (tramp-error-with-buffer
+                        nil v 'file-error
+                        "%s failed, see buffer `%s' for details."
+                        msg-operation (buffer-name)))
+
+                   ;; Some WebDAV server, like the one from QNAP, do
+                   ;; not support direct copy/move.  Try a fallback.
+                   (tramp-set-connection-property v "direct-copy-failed" t)
+                   (tramp-gvfs-do-copy-or-rename-file
+                    op filename newname ok-if-already-exists keep-date
+                    preserve-uid-gid preserve-extended-attributes))))
+
+             (when (and t1 (eq op 'rename))
+               (with-parsed-tramp-file-name filename nil
+                 (tramp-flush-file-properties v localname)))
+
+             (when t2
+               (with-parsed-tramp-file-name newname nil
+                 (tramp-flush-file-properties v localname))))))))))
 
 (defun tramp-gvfs-handle-copy-file
   (filename newname &optional ok-if-already-exists keep-date
@@ -1105,8 +1118,9 @@ file names."
        (tramp-error
         v 'file-error "Couldn't delete non-empty %s" directory)))
 
-    (unless (tramp-gvfs-send-command
-            v "gvfs-rm" (tramp-gvfs-url-file-name directory))
+    (unless (and (tramp-gvfs-send-command
+                 v "gvfs-rm" (tramp-gvfs-url-file-name directory))
+                (not (tramp-gvfs-info directory)))
       ;; Propagate the error.
       (with-current-buffer (tramp-get-connection-buffer v)
        (goto-char (point-min))
@@ -1119,8 +1133,9 @@ file names."
     (tramp-flush-file-properties v localname)
     (if (and delete-by-moving-to-trash trash)
        (move-file-to-trash filename)
-      (unless (tramp-gvfs-send-command
-              v "gvfs-rm" (tramp-gvfs-url-file-name filename))
+      (unless (and (tramp-gvfs-send-command
+                   v "gvfs-rm" (tramp-gvfs-url-file-name filename))
+                  (not (tramp-gvfs-info filename)))
        ;; Propagate the error.
        (with-current-buffer (tramp-get-connection-buffer v)
          (goto-char (point-min))
@@ -1138,11 +1153,13 @@ file names."
     (setq name (tramp-compat-file-name-concat dir name)))
   ;; If NAME is not a Tramp file, run the real handler.
   (if (not (tramp-tramp-file-p name))
-      (tramp-run-real-handler #'expand-file-name (list name nil))
+      (tramp-run-real-handler #'expand-file-name (list name))
     ;; Dissect NAME.
     (with-parsed-tramp-file-name name nil
       ;; If there is a default location, expand tilde.
-      (when (string-match "\\`~\\([^/]*\\)\\(.*\\)\\'" localname)
+      (when (string-match
+            (rx bos "~" (group (* (not (any "/")))) (group (* nonl)) eos)
+             localname)
        (let ((uname (match-string 1 localname))
              (fname (match-string 2 localname))
              hname)
@@ -1152,26 +1169,28 @@ file names."
            (setq localname (concat hname fname)))))
       ;; Tilde expansion is not possible.
       (when (and (not tramp-tolerate-tilde)
-                (string-match-p "\\`\\(~[^/]*\\)\\(.*\\)\\'" localname))
+                (string-prefix-p "~" localname))
        (tramp-error v 'file-error "Cannot expand tilde in file `%s'" name))
       (unless (tramp-run-real-handler #'file-name-absolute-p (list localname))
        (setq localname (concat "/" localname)))
       ;; We do not pass "/..".
-      (if (string-match-p "^\\(afp\\|davs?\\|smb\\)$" method)
-         (when (string-match "^/[^/]+\\(/\\.\\./?\\)" localname)
+      (if (string-match-p (rx bos (| "afp" (: "dav" (? "s")) "smb") eos) 
method)
+         (when (string-match
+                (rx bos "/" (+ (not (any "/"))) (group "/.." (? "/")))
+                localname)
            (setq localname (replace-match "/" t t localname 1)))
-       (when (string-match "^/\\.\\./?" localname)
+       (when (string-match (rx bol "/.." (? "/")) localname)
          (setq localname (replace-match "/" t t localname))))
       ;; There might be a double slash.  Remove this.
       (while (string-match "//" localname)
        (setq localname (replace-match "/" t t localname)))
       ;; Do not keep "/..".
-      (when (string-match-p "^/\\.\\.?$" localname)
+      (when (string-match-p (rx bos "/" (** 1 2 ".") eos) localname)
        (setq localname "/"))
       ;; Do normal `expand-file-name' (this does "/./" and "/../"),
       ;; unless there are tilde characters in file name.
       (tramp-make-tramp-file-name
-       v (if (string-match-p "\\`\\(~[^/]*\\)\\(.*\\)\\'" localname)
+       v (if (string-prefix-p "~" localname)
             localname
           (tramp-run-real-handler #'expand-file-name (list localname)))))))
 
@@ -1193,20 +1212,20 @@ file names."
        (with-current-buffer (tramp-get-connection-buffer v)
          (goto-char (point-min))
          (while (looking-at
-                 (eval-when-compile
-                   (concat "^\\(.+\\)[[:blank:]]"
-                           "\\([[:digit:]]+\\)[[:blank:]]"
-                           "(\\(.+?\\))"
-                           tramp-gvfs-file-attributes-with-gvfs-ls-regexp)))
+                 (rx bol (group (+ nonl)) blank
+                     (group (+ digit)) blank
+                     "(" (group (+? nonl)) ")"
+                     (regexp tramp-gvfs-file-attributes-with-gvfs-ls-regexp)))
            (let ((item (list (cons "type" (match-string 3))
                              (cons "standard::size" (match-string 2))
                              (cons "name" (match-string 1)))))
              (goto-char (1+ (match-end 3)))
              (while (looking-at
-                     (concat
-                      tramp-gvfs-file-attributes-with-gvfs-ls-regexp
-                      "\\(" tramp-gvfs-file-attributes-with-gvfs-ls-regexp
-                      "\\|" "$" "\\)"))
+                     (rx (regexp 
tramp-gvfs-file-attributes-with-gvfs-ls-regexp)
+                         (group
+                          (| (regexp
+                              tramp-gvfs-file-attributes-with-gvfs-ls-regexp)
+                             eol))))
                (push (cons (match-string 1) (match-string 2)) item)
                (goto-char (match-end 2)))
              ;; Add display name as head.
@@ -1233,10 +1252,8 @@ If FILE-SYSTEM is non-nil, return file system 
attributes."
         (if file-system " system" "") localname)
        ;; Send command.
        (if file-system
-           (tramp-gvfs-send-command
-            v "gvfs-info" "--filesystem" (tramp-gvfs-url-file-name filename))
-         (tramp-gvfs-send-command
-          v "gvfs-info" (tramp-gvfs-url-file-name filename)))
+           (tramp-gvfs-info filename "--filesystem")
+         (tramp-gvfs-info filename))
        ;; Parse output.
        (with-current-buffer (tramp-get-connection-buffer v)
          (goto-char (point-min))
@@ -1253,8 +1270,10 @@ If FILE-SYSTEM is non-nil, return file system 
attributes."
   (setq filename (directory-file-name (expand-file-name filename)))
   (with-parsed-tramp-file-name filename nil
     (setq localname (tramp-compat-file-name-unquote localname))
-    (if (or (and (string-match-p "^\\(afp\\|davs?\\|smb\\)$" method)
-                (string-match-p "^/?\\([^/]+\\)$" localname))
+    (if (or (and (string-match-p
+                 (rx bol (| "afp" (: "dav" (? "s")) "smb") eol) method)
+                (string-match-p
+                 (rx bol (? "/") (+ (not (any "/"))) eol) localname))
            (string-equal localname "/"))
        (tramp-gvfs-get-root-attributes filename)
       (assoc
@@ -1284,7 +1303,7 @@ If FILE-SYSTEM is non-nil, return file system attributes."
              ;; Convert them to multibyte.
              (decode-coding-string
               (replace-regexp-in-string
-               "\\\\x\\([[:xdigit:]]\\{2\\}\\)"
+               (rx "\\x" (group (= 2 xdigit)))
                (lambda (x)
                  (unibyte-string (string-to-number (match-string 1 x) 16)))
                res-symlink-target)
@@ -1329,32 +1348,29 @@ If FILE-SYSTEM is non-nil, return file system 
attributes."
             (or (cdr (assoc "standard::size" attributes)) "0")))
       ;; ... file mode flags
       (setq res-filemodes
-           (let ((n (cdr (assoc "unix::mode" attributes))))
-             (if n
-                 (tramp-file-mode-from-int (string-to-number n))
-               (format
-                "%s%s%s%s------"
-                (if dirp "d" (if res-symlink-target "l" "-"))
-                (if (equal (cdr (assoc "access::can-read" attributes))
-                           "FALSE")
-                    "-" "r")
-                (if (equal (cdr (assoc "access::can-write" attributes))
-                           "FALSE")
-                    "-" "w")
-                (if (equal (cdr (assoc "access::can-execute" attributes))
-                           "FALSE")
-                    "-" "x")))))
+           (if-let ((n (cdr (assoc "unix::mode" attributes))))
+               (tramp-file-mode-from-int (string-to-number n))
+             (format
+              "%s%s%s%s------"
+              (if dirp "d" (if res-symlink-target "l" "-"))
+              (if (equal (cdr (assoc "access::can-read" attributes))
+                         "FALSE")
+                  "-" "r")
+              (if (equal (cdr (assoc "access::can-write" attributes))
+                         "FALSE")
+                  "-" "w")
+              (if (equal (cdr (assoc "access::can-execute" attributes))
+                         "FALSE")
+                  "-" "x"))))
       ;; ... inode and device
       (setq res-inode
-           (let ((n (cdr (assoc "unix::inode" attributes))))
-             (if n
-                 (string-to-number n)
-               (tramp-get-inode (tramp-dissect-file-name filename)))))
+           (if-let ((n (cdr (assoc "unix::inode" attributes))))
+               (string-to-number n)
+             (tramp-get-inode (tramp-dissect-file-name filename))))
       (setq res-device
-           (let ((n (cdr (assoc "unix::device" attributes))))
-             (if n
-                 (string-to-number n)
-               (tramp-get-device (tramp-dissect-file-name filename)))))
+           (if-let ((n (cdr (assoc "unix::device" attributes))))
+               (string-to-number n)
+             (tramp-get-device (tramp-dissect-file-name filename))))
 
       ;; Return data gathered.
       (list
@@ -1457,7 +1473,7 @@ If FILE-SYSTEM is non-nil, return file system attributes."
   (let* ((events (process-get proc 'events))
         (rest-string (process-get proc 'rest-string))
         (dd (tramp-get-default-directory (process-buffer proc)))
-        (ddu (regexp-quote (tramp-gvfs-url-file-name dd))))
+        (ddu (rx (literal (tramp-gvfs-url-file-name dd)))))
     (when rest-string
       (tramp-message proc 10 "Previous string:\n%s" rest-string))
     (tramp-message proc 6 "%S\n%s" proc string)
@@ -1471,15 +1487,15 @@ If FILE-SYSTEM is non-nil, return file system 
attributes."
                  "renamed to" "moved" string))
     ;; https://bugs.launchpad.net/bugs/1742946
     (when
-       (string-match-p "Monitoring not supported\\|No locations given" string)
+       (string-match-p
+        (rx (| "Monitoring not supported" "No locations given")) string)
       (delete-process proc))
 
     (while (string-match
-           (eval-when-compile
-             (concat "^.+:"
-                     "[[:space:]]\\(.+\\):"
-                     "[[:space:]]" (regexp-opt tramp-gio-events t)
-                     "\\([[:space:]]\\(.+\\)\\)?$"))
+           (rx bol (+ nonl) ":"
+               space (group (+ nonl)) ":"
+               space (group (regexp (regexp-opt tramp-gio-events)))
+               (? (group space (group (+ nonl)))) eol)
            string)
 
       (let ((file (match-string 1 string))
@@ -1489,11 +1505,11 @@ If FILE-SYSTEM is non-nil, return file system 
attributes."
        ;; File names are returned as URL paths.  We must convert them.
        (when (string-match ddu file)
          (setq file (replace-match dd nil nil file)))
-       (while (string-match-p "%\\([[:xdigit:]]\\{2\\}\\)" file)
+       (while (string-match-p (rx "%" (= 2 xdigit)) file)
          (setq file (url-unhex-string file)))
        (when (string-match ddu (or file1 ""))
          (setq file1 (replace-match dd nil nil file1)))
-       (while (string-match-p "%\\([[:xdigit:]]\\{2\\}\\)" (or file1 ""))
+       (while (string-match-p (rx "%" (= 2 xdigit)) (or file1 ""))
          (setq file1 (url-unhex-string file1)))
        ;; Remove watch when file or directory to be watched is deleted.
        (when (and (member action '(moved deleted))
@@ -1544,8 +1560,10 @@ If FILE-SYSTEM is non-nil, return file system 
attributes."
          (make-directory ldir parents))
        ;; Just do it.
        (or (when-let ((mkdir-succeeded
-                       (tramp-gvfs-send-command
-                        v "gvfs-mkdir" (tramp-gvfs-url-file-name dir))))
+                       (and
+                        (tramp-gvfs-send-command
+                         v "gvfs-mkdir" (tramp-gvfs-url-file-name dir))
+                        (tramp-gvfs-info dir))))
              (set-file-modes dir (default-file-modes))
              mkdir-succeeded)
            (and parents (file-directory-p dir))
@@ -1575,21 +1593,18 @@ If FILE-SYSTEM is non-nil, return file system 
attributes."
          (with-current-buffer (tramp-get-connection-buffer vec)
            (goto-char (point-min))
            (when (looking-at-p "gio: Operation not supported")
-             (tramp-set-connection-property vec key nil)))
-         nil))))
+             (tramp-set-connection-property vec key nil)))))))
 
 (defun tramp-gvfs-handle-set-file-modes (filename mode &optional flag)
   "Like `set-file-modes' for Tramp files."
-  (with-parsed-tramp-file-name filename nil
-    (tramp-flush-file-properties v localname)
+  (tramp-skeleton-set-file-modes-times-uid-gid filename
     (tramp-gvfs-set-attribute
      v (if (eq flag 'nofollow) "-nt" "-t") "uint32"
      (tramp-gvfs-url-file-name filename) "unix::mode" (number-to-string 
mode))))
 
 (defun tramp-gvfs-handle-set-file-times (filename &optional time flag)
   "Like `set-file-times' for Tramp files."
-  (with-parsed-tramp-file-name filename nil
-    (tramp-flush-file-properties v localname)
+  (tramp-skeleton-set-file-modes-times-uid-gid filename
     (tramp-gvfs-set-attribute
      v (if (eq flag 'nofollow) "-nt" "-t") "uint64"
      (tramp-gvfs-url-file-name filename) "time::modified"
@@ -1605,12 +1620,11 @@ If FILE-SYSTEM is non-nil, return file system 
attributes."
 If USER is a string, return its home directory instead of the
 user identified by VEC.  If there is no user specified in either
 VEC or USER, or if there is no home directory, return nil."
-  (let ((localname
-        (tramp-get-connection-property vec "default-location" nil))
+  (let ((localname (tramp-get-connection-property vec "default-location"))
        result)
     (cond
      ((zerop (length localname))
-      (tramp-get-connection-property (tramp-get-process vec) "share" nil))
+      (tramp-get-connection-property (tramp-get-process vec) "share"))
      ;; Google-drive.
      ((not (string-prefix-p "/" localname))
       (dolist (item
@@ -1624,27 +1638,26 @@ VEC or USER, or if there is no home directory, return 
nil."
 (defun tramp-gvfs-handle-get-remote-uid (vec id-format)
   "The uid of the remote connection VEC, in ID-FORMAT.
 ID-FORMAT valid values are `string' and `integer'."
+  ;; The result is cached in `tramp-get-remote-uid'.
   (if (equal id-format 'string)
       (tramp-file-name-user vec)
     (when-let ((localname
-               (tramp-get-connection-property
-                (tramp-get-process vec) "share" nil)))
+               (tramp-get-connection-property (tramp-get-process vec) 
"share")))
       (file-attribute-user-id
        (file-attributes (tramp-make-tramp-file-name vec localname) 
id-format)))))
 
 (defun tramp-gvfs-handle-get-remote-gid (vec id-format)
   "The gid of the remote connection VEC, in ID-FORMAT.
 ID-FORMAT valid values are `string' and `integer'."
+  ;; The result is cached in `tramp-get-remote-gid'.
   (when-let ((localname
-             (tramp-get-connection-property
-              (tramp-get-process vec) "share" nil)))
+             (tramp-get-connection-property (tramp-get-process vec) "share")))
     (file-attribute-group-id
      (file-attributes (tramp-make-tramp-file-name vec localname) id-format))))
 
 (defun tramp-gvfs-handle-set-file-uid-gid (filename &optional uid gid)
   "Like `tramp-set-file-uid-gid' for Tramp files."
-  (with-parsed-tramp-file-name filename nil
-    (tramp-flush-file-properties v localname)
+  (tramp-skeleton-set-file-modes-times-uid-gid filename
     (when (natnump uid)
       (tramp-gvfs-set-attribute
        v "-t" "uint32"
@@ -1675,7 +1688,7 @@ ID-FORMAT valid values are `string' and `integer'."
                  (concat (tramp-gvfs-get-remote-prefix v) localname)))
          (when (string-equal "mtp" method)
            (when-let
-               ((media (tramp-get-connection-property v "media-device" nil)))
+               ((media (tramp-get-connection-property v "media-device")))
              (setq method (tramp-media-device-method media)
                    host (tramp-media-device-host media)
                    port (tramp-media-device-port media))))
@@ -1712,14 +1725,15 @@ ID-FORMAT valid values are `string' and `integer'."
 (defun tramp-gvfs-file-name (object-path)
   "Retrieve file name from D-Bus OBJECT-PATH."
   (dbus-unescape-from-identifier
-   (replace-regexp-in-string "^.*/\\([^/]+\\)$" "\\1" object-path)))
+   (replace-regexp-in-string
+    (rx bol (* nonl) "/" (+ (not (any "/"))) eol) "\\1" object-path)))
 
 (defun tramp-gvfs-url-host (url)
   "Return the host name part of URL, a string.
 We cannot use `url-host', because `url-generic-parse-url' returns
 a downcased host name only."
   (and (stringp url)
-       (string-match "^[[:alnum:]]+://\\([^/:]+\\)" url)
+       (string-match (rx bol (+ alnum) "://" (group (+ (not (any "/:"))))) url)
        (match-string 1 url)))
 
 
@@ -1732,7 +1746,8 @@ a downcased host name only."
         (pw-prompt
          (format
           "%s for %s "
-          (if (string-match "\\([pP]assword\\|[pP]assphrase\\)" message)
+          (if (string-match
+               (rx (group (any "Pp") (| "assword" "assphrase"))) message)
               (capitalize (match-string 1 message))
             "Password")
           filename))
@@ -1750,7 +1765,7 @@ a downcased host name only."
            (setq domain (read-string "Domain name: ")))
 
          (tramp-message l 6 "%S %S %S %d" message user domain flags)
-         (unless (tramp-get-connection-property l "first-password-request" nil)
+         (unless (tramp-get-connection-property l "first-password-request")
            (tramp-clear-passwd l))
 
          (setq password (tramp-read-passwd
@@ -1795,7 +1810,8 @@ a downcased host name only."
                         (progn
                           (message "%s" message)
                           0)
-                      (with-tramp-connection-property (tramp-get-process v) 
message
+                      (with-tramp-connection-property
+                          (tramp-get-process v) message
                         ;; In theory, there can be several choices.
                         ;; Until now, there is only the question
                         ;; whether to accept an unknown host
@@ -1853,7 +1869,7 @@ Their full names are \"org.gtk.vfs.MountTracker.mounted\" 
and
                   (cadr (assoc "ssl" (cadr mount-spec)))))
             (uri (tramp-gvfs-dbus-byte-array-to-string
                   (cadr (assoc "uri" (cadr mount-spec))))))
-       (when (string-match "^\\(afp\\|smb\\)" method)
+       (when (string-match (rx bol (group (| "afp" "smb"))) method)
          (setq method (match-string 1 method)))
        (when (and (string-equal "dav" method) (string-equal "true" ssl))
          (setq method "davs"))
@@ -1872,14 +1888,13 @@ Their full names are 
\"org.gtk.vfs.MountTracker.mounted\" and
        (when (member method tramp-media-methods)
          ;; Ensure that media devices are cached.
          (tramp-get-media-devices nil)
-         (let ((v (tramp-get-connection-property
-                   (make-tramp-media-device
-                    :method method :host host :port port)
-                   "vector" nil)))
-           (when v
-             (setq method (tramp-file-name-method v)
-                   host (tramp-file-name-host v)
-                   port (tramp-file-name-port v)))))
+         (when-let ((v (tramp-get-connection-property
+                        (make-tramp-media-device
+                         :method method :host host :port port)
+                        "vector" nil)))
+           (setq method (tramp-file-name-method v)
+                 host (tramp-file-name-host v)
+                 port (tramp-file-name-port v))))
        (when (member method tramp-gvfs-methods)
          (let ((v (make-tramp-file-name
                    :method method :user user :domain domain
@@ -1888,7 +1903,7 @@ Their full names are \"org.gtk.vfs.MountTracker.mounted\" 
and
             v 6 "%s %s"
             signal-name (tramp-gvfs-stringify-dbus-message mount-info))
            (tramp-flush-file-property v "/" "list-mounts")
-           (if (string-equal (downcase signal-name) "unmounted")
+           (if (tramp-compat-string-equal-ignore-case signal-name "unmounted")
                (tramp-flush-file-properties v "/")
              ;; Set mountpoint and location.
              (tramp-set-file-property v "/" "fuse-mountpoint" fuse-mountpoint)
@@ -1917,15 +1932,14 @@ Their full names are 
\"org.gtk.vfs.MountTracker.mounted\" and
 (defun tramp-gvfs-connection-mounted-p (vec)
   "Check, whether the location is already mounted."
   (or
-   (tramp-get-file-property vec "/" "fuse-mountpoint" nil)
+   (tramp-get-file-property vec "/" "fuse-mountpoint")
    (catch 'mounted
      (dolist
         (elt
          (with-tramp-file-property vec "/" "list-mounts"
            (with-tramp-dbus-call-method vec t
              :session tramp-gvfs-service-daemon tramp-gvfs-path-mounttracker
-             tramp-gvfs-interface-mounttracker tramp-gvfs-listmounts))
-         nil)
+             tramp-gvfs-interface-mounttracker tramp-gvfs-listmounts)))
        ;; Jump over the first elements of the mount info.  Since there
        ;; were changes in the entries, we cannot access dedicated
        ;; elements.
@@ -1955,7 +1969,7 @@ Their full names are \"org.gtk.vfs.MountTracker.mounted\" 
and
                      (or
                       (cadr (assoc "share" (cadr mount-spec)))
                       (cadr (assoc "volume" (cadr mount-spec)))))))
-        (when (string-match "^\\(afp\\|smb\\)" method)
+        (when (string-match (rx bol (group (| "afp" "smb"))) method)
           (setq method (match-string 1 method)))
         (when (and (string-equal "dav" method) (string-equal "true" ssl))
           (setq method "davs"))
@@ -1974,21 +1988,20 @@ Their full names are 
\"org.gtk.vfs.MountTracker.mounted\" and
         (when (member method tramp-media-methods)
           ;; Ensure that media devices are cached.
           (tramp-get-media-devices vec)
-          (let ((v (tramp-get-connection-property
-                    (make-tramp-media-device
-                     :method method :host host :port port)
-                    "vector" nil)))
-            (when v
-              (setq method (tramp-file-name-method v)
-                    host (tramp-file-name-host v)
-                    port (tramp-file-name-port v)))))
+          (when-let ((v (tramp-get-connection-property
+                         (make-tramp-media-device
+                          :method method :host host :port port)
+                         "vector")))
+            (setq method (tramp-file-name-method v)
+                  host (tramp-file-name-host v)
+                  port (tramp-file-name-port v))))
         (when (and
                (string-equal method (tramp-file-name-method vec))
                (string-equal user (tramp-file-name-user vec))
                (string-equal domain (tramp-file-name-domain vec))
                (string-equal host (tramp-file-name-host vec))
                (string-equal port (tramp-file-name-port vec))
-               (string-match-p (concat "^/" (regexp-quote (or share "")))
+               (string-match-p (rx bol "/" (literal (or share "")))
                                (tramp-file-name-unquote-localname vec)))
           ;; Set mountpoint and location.
           (tramp-set-file-property vec "/" "fuse-mountpoint" fuse-mountpoint)
@@ -2014,7 +2027,7 @@ Their full names are \"org.gtk.vfs.MountTracker.mounted\" 
and
 (defun tramp-gvfs-mount-spec-entry (key value)
   "Construct a mount-spec entry to be used in a mount_spec.
 It was \"a(say)\", but has changed to \"a{sv})\"."
-  (if (string-match-p "^(aya{sv})" tramp-gvfs-mountlocation-signature)
+  (if (string-match-p (rx bol "(aya{sv})") tramp-gvfs-mountlocation-signature)
       (list :dict-entry key
            (list :variant (tramp-gvfs-dbus-string-to-byte-array value)))
     (list :struct key (tramp-gvfs-dbus-string-to-byte-array value))))
@@ -2032,9 +2045,11 @@ It was \"a(say)\", but has changed to \"a{sv})\"."
         (port (if media
                   (tramp-media-device-port media) (tramp-file-name-port vec)))
         (localname (tramp-file-name-unquote-localname vec))
-        (share (when (string-match "^/?\\([^/]+\\)" localname)
+        (share (when (string-match
+                      (rx bol (? "/") (group (+ (not (any "/"))))) localname)
                  (match-string 1 localname)))
-        (ssl (if (string-match-p "^davs\\|^nextcloud" method) "true" "false"))
+        (ssl (if (string-match-p (rx bol (| "davs" "nextcloud")) method)
+                 "true" "false"))
         (mount-spec
           `(:array
             ,@(cond
@@ -2042,7 +2057,7 @@ It was \"a(say)\", but has changed to \"a{sv})\"."
                 (list (tramp-gvfs-mount-spec-entry "type" "smb-share")
                       (tramp-gvfs-mount-spec-entry "server" host)
                       (tramp-gvfs-mount-spec-entry "share" share)))
-               ((string-match-p "^dav\\|^nextcloud" method)
+               ((string-match-p (rx bol (| "davs" "nextcloud")) method)
                 (list (tramp-gvfs-mount-spec-entry "type" "dav")
                       (tramp-gvfs-mount-spec-entry "host" host)
                       (tramp-gvfs-mount-spec-entry "ssl" ssl)))
@@ -2056,7 +2071,7 @@ It was \"a(say)\", but has changed to \"a{sv})\"."
                ((string-equal "nextcloud" method)
                 (list (tramp-gvfs-mount-spec-entry "type" "owncloud")
                       (tramp-gvfs-mount-spec-entry "host" host)))
-               ((string-match-p "^http" method)
+               ((string-match-p (rx bol "http") method)
                 (list (tramp-gvfs-mount-spec-entry "type" "http")
                       (tramp-gvfs-mount-spec-entry
                       "uri"
@@ -2073,8 +2088,8 @@ It was \"a(say)\", but has changed to \"a{sv})\"."
             ,@(when port
                 (list (tramp-gvfs-mount-spec-entry "port" port)))))
         (mount-pref
-          (if (and (string-match-p "^dav" method)
-                   (string-match "^/?[^/]+" localname))
+          (if (and (string-match-p (rx bol "dav") method)
+                   (string-match (rx bol (? "/") (+ (not (any "/")))) 
localname))
               (match-string 0 localname)
            (tramp-gvfs-get-remote-prefix vec))))
 
@@ -2135,10 +2150,6 @@ connection if a previous connection has died for some 
reason."
   (unless (tramp-connectable-p vec)
     (throw 'non-essential 'non-essential))
 
-  ;; We set the file name, in case there are incoming D-Bus signals or
-  ;; D-Bus errors.
-  (setq tramp-gvfs-dbus-event-vector vec)
-
   ;; For password handling, we need a process bound to the connection
   ;; buffer.  Therefore, we create a dummy process.  Maybe there is a
   ;; better solution?
@@ -2165,7 +2176,7 @@ connection if a previous connection has died for some 
reason."
                 (string-equal localname "/"))
        (tramp-user-error vec "Filename must contain an AFP volume"))
 
-      (when (and (string-match-p "davs?" method)
+      (when (and (string-match-p (rx "dav" (? "s")) method)
                 (string-equal localname "/"))
        (tramp-user-error vec "Filename must contain a WebDAV share"))
 
@@ -2215,7 +2226,7 @@ connection if a previous connection has died for some 
reason."
 
        ;; The call must be asynchronously, because of the "askPassword"
        ;; or "askQuestion" callbacks.
-       (if (string-match-p "(so)$" tramp-gvfs-mountlocation-signature)
+       (if (string-match-p (rx "(so)" eol) tramp-gvfs-mountlocation-signature)
            (with-tramp-dbus-call-method vec nil
              :session tramp-gvfs-service-daemon tramp-gvfs-path-mounttracker
              tramp-gvfs-interface-mounttracker tramp-gvfs-mountlocation
@@ -2241,7 +2252,7 @@ connection if a previous connection has died for some 
reason."
               (tramp-error
                vec 'file-error
                "Timeout reached mounting %s@%s using %s" user host method)))
-         (while (not (tramp-get-file-property vec "/" "fuse-mountpoint" nil))
+         (while (not (tramp-get-file-property vec "/" "fuse-mountpoint"))
            (read-event nil nil 0.1)))
 
        ;; If `tramp-gvfs-handler-askquestion' has returned "No", it
@@ -2379,11 +2390,11 @@ It checks for registered GNOME Online Accounts."
 (defun tramp-get-media-device (vec)
   "Transform VEC into a `tramp-media-device' structure.
 Check, that respective cache values do exist."
-  (if-let ((media (tramp-get-connection-property vec "media-device" nil))
-          (prop (tramp-get-connection-property media "vector" nil)))
+  (if-let ((media (tramp-get-connection-property vec "media-device"))
+          (prop (tramp-get-connection-property media "vector")))
       media
     (tramp-get-media-devices vec)
-    (tramp-get-connection-property vec "media-device" nil)))
+    (tramp-get-connection-property vec "media-device")))
 
 (defun tramp-get-media-devices (vec)
   "Retrieve media devices, and cache them.
@@ -2428,9 +2439,9 @@ It checks for mounted media devices."
    (lambda (key)
      (and (tramp-media-device-p key)
          (string-equal service (tramp-media-device-method key))
-         (tramp-get-connection-property key "vector" nil)
+         (tramp-get-connection-property key "vector")
          (list nil (tramp-file-name-host
-                    (tramp-get-connection-property key "vector" nil)))))
+                    (tramp-get-connection-property key "vector")))))
    (hash-table-keys tramp-cache-data)))
 
 
@@ -2445,7 +2456,7 @@ It checks for mounted media devices."
           (text (zeroconf-service-txt x))
           user)
        (when port
-        (setq host (format "%s%s%d" host tramp-prefix-port-regexp port)))
+        (setq host (format "%s%s%d" host tramp-prefix-port-format port)))
        ;; A user is marked in a TXT field like "u=guest".
        (while text
         (when (string-match "u=\\(.+\\)$" (car text))
@@ -2461,7 +2472,7 @@ This uses \"avahi-browse\" in case D-Bus is not enabled 
in Avahi."
         (ignore-errors
           (split-string
            (shell-command-to-string (format "avahi-browse -trkp %s" service))
-           "[\n\r]+" 'omit "^\\+;.*$"))))
+           (rx (+ (any "\r\n"))) 'omit (rx bol "+;" (* nonl) eol)))))
     (delete-dups
      (mapcar
       (lambda (x)
@@ -2471,7 +2482,7 @@ This uses \"avahi-browse\" in case D-Bus is not enabled 
in Avahi."
               user)
          ;; A user is marked in a TXT field like "u=guest".
          (while text
-           (when (string-match "u=\\(.+\\)$" (car text))
+           (when (string-match (rx "u=" (group (+ nonl)) eol) (car text))
              (setq user (match-string 1 (car text))))
            (setq text (cdr text)))
          (list user host)))
diff --git a/lisp/net/tramp-integration.el b/lisp/net/tramp-integration.el
index 5e51074c49..946f972502 100644
--- a/lisp/net/tramp-integration.el
+++ b/lisp/net/tramp-integration.el
@@ -85,7 +85,8 @@ special handling of `substitute-in-file-name'."
 
 (defun tramp-rfn-eshadow-update-overlay-regexp ()
   "An overlay covering the shadowed part of the filename."
-  (format "[^%s/~]*\\(/\\|~\\)" tramp-postfix-host-format))
+  (rx-to-string
+   `(: (* (not (any ,tramp-postfix-host-format "/~"))) (or "/" "~"))))
 
 (defun tramp-rfn-eshadow-update-overlay ()
   "Update `rfn-eshadow-overlay' to cover shadowed part of minibuffer input.
@@ -108,7 +109,7 @@ been set up by `rfn-eshadow-setup-minibuffer'."
                     end))
             (point-max))
            (let ((rfn-eshadow-overlay tramp-rfn-eshadow-overlay)
-                 (rfn-eshadow-update-overlay-hook nil)
+                 rfn-eshadow-update-overlay-hook
                  file-name-handler-alist)
              (move-overlay rfn-eshadow-overlay (point-max) (point-max))
              (rfn-eshadow-update-overlay))))))))
@@ -215,9 +216,13 @@ NAME must be equal to `tramp-current-connection'."
   ;; Create a pseudo mode `tramp-info-lookup-mode' for Tramp symbol lookup.
   (info-lookup-maybe-add-help
    :mode 'tramp-info-lookup-mode :topic 'symbol
-   :regexp "[^][()`'‘’,\" \t\n]+"
-   :doc-spec '(("(tramp)Function Index" nil "^ -+ .*: " "\\( \\|$\\)")
-              ("(tramp)Variable Index" nil "^ -+ .*: " "\\( \\|$\\)")))
+   :regexp (rx (+ (not (any "\t\n \"'(),[]`‘’"))))
+   :doc-spec '(("(tramp)Function Index" nil
+               (rx bol " " (+ "-") " " (* nonl) ": ")
+               (rx (group (| " " eol))))
+              ("(tramp)Variable Index" nil
+               (rx bol " " (+ "-") " " (* nonl) ": ")
+               (rx (group (| " " eol))))))
 
   (add-hook
    'tramp-integration-unload-hook
diff --git a/lisp/net/tramp-rclone.el b/lisp/net/tramp-rclone.el
index bbc7685131..435faf8329 100644
--- a/lisp/net/tramp-rclone.el
+++ b/lisp/net/tramp-rclone.el
@@ -186,7 +186,7 @@ arguments to pass to the OPERATION."
     (delq nil
          (mapcar
           (lambda (line)
-            (when (string-match "^\\(\\S-+\\):$" line)
+            (when (string-match (rx bol (group (+ (not space))) ":" eol) line)
               `(nil ,(match-string 1 line))))
           (tramp-process-lines nil tramp-rclone-program "listremotes")))))
 
@@ -225,46 +225,45 @@ file names."
          (msg-operation (if (eq op 'copy) "Copying" "Renaming")))
 
       (with-parsed-tramp-file-name (if t1 filename newname) nil
-       (unless (file-exists-p filename)
-         (tramp-error v 'file-missing filename))
-       (when (and (not ok-if-already-exists) (file-exists-p newname))
-         (tramp-error v 'file-already-exists newname))
-       (when (and (file-directory-p newname)
-                  (not (directory-name-p newname)))
-         (tramp-error v 'file-error "File is a directory %s" newname))
-
-       (if (or (and t1 (not (tramp-rclone-file-name-p filename)))
-               (and t2 (not (tramp-rclone-file-name-p newname))))
-
-           ;; We cannot copy or rename directly.
-           (let ((tmpfile (tramp-compat-make-temp-file filename)))
-             (if (eq op 'copy)
-                 (copy-file
-                  filename tmpfile t keep-date preserve-uid-gid
-                  preserve-extended-attributes)
-               (rename-file filename tmpfile t))
-             (rename-file tmpfile newname ok-if-already-exists))
-
-         ;; Direct action.
-         (with-tramp-progress-reporter
-             v 0 (format "%s %s to %s" msg-operation filename newname)
-           (unless (zerop
-                    (tramp-rclone-send-command
-                     v rclone-operation
-                     (tramp-rclone-remote-file-name filename)
-                     (tramp-rclone-remote-file-name newname)))
-             (tramp-error
-              v 'file-error
-              "Error %s `%s' `%s'" msg-operation filename newname)))
-
-         (when (and t1 (eq op 'rename))
-           (while (file-exists-p filename)
-             (with-parsed-tramp-file-name filename v1
-               (tramp-flush-file-properties v1 v1-localname))))
-
-         (when t2
-           (with-parsed-tramp-file-name newname v2
-             (tramp-flush-file-properties v2 v2-localname))))))))
+       (tramp-barf-if-file-missing v filename
+         (when (and (not ok-if-already-exists) (file-exists-p newname))
+           (tramp-error v 'file-already-exists newname))
+         (when (and (file-directory-p newname)
+                    (not (directory-name-p newname)))
+           (tramp-error v 'file-error "File is a directory %s" newname))
+
+         (if (or (and t1 (not (tramp-rclone-file-name-p filename)))
+                 (and t2 (not (tramp-rclone-file-name-p newname))))
+
+             ;; We cannot copy or rename directly.
+             (let ((tmpfile (tramp-compat-make-temp-file filename)))
+               (if (eq op 'copy)
+                   (copy-file
+                    filename tmpfile t keep-date preserve-uid-gid
+                    preserve-extended-attributes)
+                 (rename-file filename tmpfile t))
+               (rename-file tmpfile newname ok-if-already-exists))
+
+           ;; Direct action.
+           (with-tramp-progress-reporter
+               v 0 (format "%s %s to %s" msg-operation filename newname)
+             (unless (zerop
+                      (tramp-rclone-send-command
+                       v rclone-operation
+                       (tramp-rclone-remote-file-name filename)
+                       (tramp-rclone-remote-file-name newname)))
+               (tramp-error
+                v 'file-error
+                "Error %s `%s' `%s'" msg-operation filename newname)))
+
+           (when (and t1 (eq op 'rename))
+             (while (file-exists-p filename)
+               (with-parsed-tramp-file-name filename v1
+                 (tramp-flush-file-properties v1 v1-localname))))
+
+           (when t2
+             (with-parsed-tramp-file-name newname v2
+               (tramp-flush-file-properties v2 v2-localname)))))))))
 
 (defun tramp-rclone-handle-copy-file
   (filename newname &optional ok-if-already-exists keep-date
@@ -301,11 +300,11 @@ file names."
        (let (total used free)
          (goto-char (point-min))
          (while (not (eobp))
-           (when (looking-at "Total: [[:space:]]+\\([[:digit:]]+\\)")
+           (when (looking-at (rx "Total: " (+ space) (group (+ digit))))
              (setq total (string-to-number (match-string 1))))
-           (when (looking-at "Used: [[:space:]]+\\([[:digit:]]+\\)")
+           (when (looking-at (rx "Used: " (+ space) (group (+ digit))))
              (setq used (string-to-number (match-string 1))))
-           (when (looking-at "Free: [[:space:]]+\\([[:digit:]]+\\)")
+           (when (looking-at (rx "Free: " (+ space) (group (+ digit))))
              (setq free (string-to-number (match-string 1))))
            (forward-line))
          (when used
@@ -344,7 +343,7 @@ file names."
          (tramp-rclone-maybe-open-connection v)
          ;; TODO: This shall be handled by `expand-file-name'.
          (setq localname
-               (replace-regexp-in-string "^\\." "" (or localname "")))
+               (replace-regexp-in-string (rx bol ".") "" (or localname "")))
          (format "%s%s" (tramp-fuse-mounted-p v) localname)))
     ;; It is a local file name.
     filename))
diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el
index 8f8b81186b..2489ac9aec 100644
--- a/lisp/net/tramp-sh.el
+++ b/lisp/net/tramp-sh.el
@@ -81,10 +81,10 @@ the default storage location, e.g. \"$HOME/.sh_history\"."
                  (string :tag "Redirect to a file")))
 
 ;;;###tramp-autoload
-(defconst tramp-display-escape-sequence-regexp "\e[[:digit:];[]+m"
+(defconst tramp-display-escape-sequence-regexp (rx "\e" (+ (any ";[" digit)) 
"m")
   "Terminal control escape sequences for display attributes.")
 
-(defconst tramp-device-escape-sequence-regexp "\e[[:digit:][]+n"
+(defconst tramp-device-escape-sequence-regexp (rx "\e" (+ (any "[" digit)) "n")
   "Terminal control escape sequences for device status.")
 
 ;; ksh on OpenBSD 4.5 requires that $PS1 contains a `#' character for
@@ -410,19 +410,20 @@ The string is used in `tramp-methods'.")
                 (tramp-copy-keep-date       t)))
 
  (add-to-list 'tramp-default-method-alist
-             `(,tramp-local-host-regexp "\\`root\\'" "su"))
+             `(,tramp-local-host-regexp
+               ,(rx bos (literal tramp-root-id-string) eos) "su"))
 
  (add-to-list 'tramp-default-user-alist
-             `(,(concat "\\`" (regexp-opt '("su" "sudo" "doas" "ksu")) "\\'")
-               nil "root"))
+             `(,(rx bos (regexp (regexp-opt '("su" "sudo" "doas" "ksu"))) eos)
+               nil ,tramp-root-id-string))
  ;; Do not add "ssh" based methods, otherwise ~/.ssh/config would be ignored.
  ;; Do not add "plink" based methods, they ask interactively for the user.
  (add-to-list 'tramp-default-user-alist
-             `(,(concat
-                 "\\`"
-                 (regexp-opt
-                  '("rcp" "remcp" "rsh" "telnet" "nc" "krlogin" "fcp"))
-                 "\\'")
+             `(,(rx bos
+                    (regexp
+                     (regexp-opt
+                      '("rcp" "remcp" "rsh" "telnet" "nc" "krlogin" "fcp")))
+                    eos)
                nil ,(user-login-name))))
 
 ;;;###tramp-autoload
@@ -517,8 +518,8 @@ The string is used in `tramp-methods'.")
  (tramp-set-completion-function "fcp" tramp-completion-function-alist-ssh))
 
 (defcustom tramp-sh-extra-args
-  '(("/bash\\'" . "-noediting -norc -noprofile")
-    ("/zsh\\'" . "-f +Z -V"))
+  `((,(rx "/bash" eos) . "-noediting -norc -noprofile")
+    (,(rx "/zsh" eos) . "-f +Z -V"))
   "Alist specifying extra arguments to pass to the remote shell.
 Entries are (REGEXP . ARGS) where REGEXP is a regular expression
 matching the shell file name and ARGS is a string specifying the
@@ -666,14 +667,14 @@ else
 {
     $type = \"nil\"
 };
-$uid = ($ARGV[1] eq \"integer\") ? $stat[4] : \"\\\"\" . getpwuid($stat[4]) . 
\"\\\"\";
-$gid = ($ARGV[1] eq \"integer\") ? $stat[5] : \"\\\"\" . getgrgid($stat[5]) . 
\"\\\"\";
 printf(
-    \"(%%s %%u %%s %%s (%%u %%u) (%%u %%u) (%%u %%u) %%u %%u t %%u -1)\\n\",
+    \"(%%s %%u (%%s . %%u) (%%s . %%u) (%%u %%u) (%%u %%u) (%%u %%u) %%u %%u t 
%%u -1)\\n\",
     $type,
     $stat[3],
-    $uid,
-    $gid,
+    \"\\\"\" . getpwuid($stat[4]) . \"\\\"\",
+    $stat[4],
+    \"\\\"\" . getgrgid($stat[5]) . \"\\\"\",
+    $stat[5],
     $stat[8] >> 16 & 0xffff,
     $stat[8] & 0xffff,
     $stat[9] >> 16 & 0xffff,
@@ -683,12 +684,29 @@ printf(
     $stat[7],
     $stat[2],
     $stat[1]
-);' \"$1\" \"$2\" %n"
+);' \"$1\" %n"
   "Perl script to produce output suitable for use with `file-attributes'
 on the remote file system.
 Format specifiers are replaced by `tramp-expand-script', percent
 characters need to be doubled.")
 
+(defconst tramp-stat-file-attributes
+  (format
+   (concat
+    "(%%s -c"
+    " '((%s%%%%N%s) %%%%h (%s%%%%U%s . %%%%u) (%s%%%%G%s . %%%%g)"
+    " %%%%X %%%%Y %%%%Z %%%%s %s%%%%A%s t %%%%i -1)' \"$1\" %%n || echo nil) |"
+    " sed -e 's/\"/\\\\\"/g' -e 's/%s/\"/g'")
+    tramp-stat-marker tramp-stat-marker ; %%N
+    tramp-stat-marker tramp-stat-marker ; %%U
+    tramp-stat-marker tramp-stat-marker ; %%G
+    tramp-stat-marker tramp-stat-marker ; %%A
+    tramp-stat-quoted-marker)
+  "Shell function to produce output suitable for use with `file-attributes'
+on the remote file system.
+Format specifiers are replaced by `tramp-expand-script', percent
+characters need to be doubled.")
+
 (defconst tramp-perl-directory-files-and-attributes
   "%p -e '
 chdir($ARGV[0]) or printf(\"\\\"Cannot change to $ARGV[0]: $''!''\\\"\\n\"), 
exit();
@@ -715,16 +733,16 @@ for($i = 0; $i < $n; $i++)
     {
         $type = \"nil\"
     };
-    $uid = ($ARGV[1] eq \"integer\") ? $stat[4] : \"\\\"\" . 
getpwuid($stat[4]) . \"\\\"\";
-    $gid = ($ARGV[1] eq \"integer\") ? $stat[5] : \"\\\"\" . 
getgrgid($stat[5]) . \"\\\"\";
     $filename =~ s/\"/\\\\\"/g;
     printf(
-        \"(\\\"%%s\\\" %%s %%u %%s %%s (%%u %%u) (%%u %%u) (%%u %%u) %%u %%u t 
%%u -1)\\n\",
+        \"(\\\"%%s\\\" %%s %%u (%%s . %%u) (%%s . %%u) (%%u %%u) (%%u %%u) 
(%%u %%u) %%u %%u t %%u -1)\\n\",
         $filename,
         $type,
         $stat[3],
-        $uid,
-        $gid,
+        \"\\\"\" . getpwuid($stat[4]) . \"\\\"\",
+        $stat[4],
+        \"\\\"\" . getgrgid($stat[5]) . \"\\\"\",
+        $stat[5],
         $stat[8] >> 16 & 0xffff,
         $stat[8] & 0xffff,
         $stat[9] >> 16 & 0xffff,
@@ -735,12 +753,38 @@ for($i = 0; $i < $n; $i++)
         $stat[2],
         $stat[1]);
 }
-printf(\")\\n\");' \"$1\" \"$2\" %n"
+printf(\")\\n\");' \"$1\" %n"
   "Perl script implementing `directory-files-and-attributes' as Lisp `read'able
 output.
 Format specifiers are replaced by `tramp-expand-script', percent
 characters need to be doubled.")
 
+(defconst tramp-stat-directory-files-and-attributes
+  (format
+   (concat
+    ;; We must care about file names with spaces, or starting with
+    ;; "-"; this would confuse xargs.  "ls -aQ" might be a solution,
+    ;; but it does not work on all remote systems.  Therefore, we use
+    ;; \000 as file separator.  `tramp-sh--quoting-style-options' do
+    ;; not work for file names with spaces piped to "xargs".
+    ;; Apostrophes in the stat output are masked as
+    ;; `tramp-stat-marker', in order to make a proper shell escape of
+    ;; them in file names.
+    "cd \"$1\" && echo \"(\"; (%%l -a | tr '\\n\\r' '\\000\\000' |"
+    " xargs -0 %%s -c"
+    " '(%s%%%%n%s (%s%%%%N%s) %%%%h (%s%%%%U%s . %%%%u) (%s%%%%G%s . %%%%g) 
%%%%X %%%%Y %%%%Z %%%%s %s%%%%A%s t %%%%i -1)'"
+    " -- %%n | sed -e 's/\"/\\\\\"/g' -e 's/%s/\"/g'); echo \")\"")
+   tramp-stat-marker tramp-stat-marker ; %n
+   tramp-stat-marker tramp-stat-marker ; %N
+   tramp-stat-marker tramp-stat-marker ; %U
+   tramp-stat-marker tramp-stat-marker ; %G
+   tramp-stat-marker tramp-stat-marker ; %A
+   tramp-stat-quoted-marker)
+  "Shell function implementing `directory-files-and-attributes' as Lisp
+`read'able output.
+Format specifiers are replaced by `tramp-expand-script', percent
+characters need to be doubled.")
+
 ;; These two use base64 encoding.
 (defconst tramp-perl-encode-with-module
   "%p -MMIME::Base64 -0777 -ne 'print encode_base64($_)' %n"
@@ -1068,7 +1112,10 @@ component is used as the target of the symlink."
       (let ((non-essential t))
        (when (and (tramp-tramp-file-p target)
                   (tramp-file-name-equal-p v (tramp-dissect-file-name target)))
-         (setq target (tramp-file-local-name (expand-file-name target)))))
+         (setq target (tramp-file-local-name (expand-file-name target))))
+       ;; There could be a cyclic link.
+       (tramp-flush-file-properties
+        v (expand-file-name target (tramp-file-local-name default-directory))))
 
       ;; If TARGET is still remote, quote it.
       (if (tramp-tramp-file-p target)
@@ -1130,36 +1177,32 @@ component is used as the target of the symlink."
       (tramp-make-tramp-file-name
        v
        (with-tramp-file-property v localname "file-truename"
-        (let (result)                  ; result steps in reverse order
-          (tramp-message v 4 "Finding true name for `%s'" filename)
-          (cond
-           ;; Use GNU readlink --canonicalize-missing where available.
-           ((tramp-get-remote-readlink v)
-            (tramp-send-command-and-check
-             v
-             (format "%s --canonicalize-missing %s"
-                     (tramp-get-remote-readlink v)
-                     (tramp-shell-quote-argument localname)))
-            (with-current-buffer (tramp-get-connection-buffer v)
-              (goto-char (point-min))
-              (setq result (buffer-substring (point-min) (point-at-eol)))))
-
-           ;; Use Perl implementation.
-           ((and (tramp-get-remote-perl v)
-                 (tramp-get-connection-property v "perl-file-spec" nil)
-                 (tramp-get-connection-property v "perl-cwd-realpath" nil))
-            (tramp-maybe-send-script
-             v tramp-perl-file-truename "tramp_perl_file_truename")
-            (setq result
-                  (tramp-send-command-and-read
-                   v
-                   (format "tramp_perl_file_truename %s"
-                           (tramp-shell-quote-argument localname)))))
-
-           ;; Do it yourself.
-           (t (setq
-               result
-               (tramp-file-local-name (tramp-handle-file-truename filename)))))
+        (tramp-message v 4 "Finding true name for `%s'" filename)
+        (let ((result
+               (cond
+                ;; Use GNU readlink --canonicalize-missing where available.
+                ((tramp-get-remote-readlink v)
+                 (tramp-send-command-and-check
+                  v (format "%s --canonicalize-missing %s"
+                            (tramp-get-remote-readlink v)
+                            (tramp-shell-quote-argument localname)))
+                 (with-current-buffer (tramp-get-connection-buffer v)
+                   (goto-char (point-min))
+                   (buffer-substring (point-min) (line-end-position))))
+
+                ;; Use Perl implementation.
+                ((and (tramp-get-remote-perl v)
+                      (tramp-get-connection-property v "perl-file-spec")
+                      (tramp-get-connection-property v "perl-cwd-realpath"))
+                 (tramp-maybe-send-script
+                  v tramp-perl-file-truename "tramp_perl_file_truename")
+                 (tramp-send-command-and-read
+                  v (format "tramp_perl_file_truename %s"
+                            (tramp-shell-quote-argument localname))))
+
+                ;; Do it yourself.
+                (t (tramp-file-local-name
+                    (tramp-handle-file-truename filename))))))
 
           ;; Detect cycle.
           (when (and (file-symlink-p filename)
@@ -1184,37 +1227,28 @@ component is used as the target of the symlink."
   (when (tramp-connectable-p filename)
     (with-parsed-tramp-file-name filename nil
       (with-tramp-file-property v localname "file-exists-p"
-       (or (not (null (tramp-get-file-property
-                       v localname "file-attributes-integer" nil)))
-            (not (null (tramp-get-file-property
-                       v localname "file-attributes-string" nil)))
-           (tramp-send-command-and-check
-            v
-            (format
-             "%s %s"
-             (tramp-get-file-exists-command v)
-             (tramp-shell-quote-argument localname))))))))
+       (if (tramp-file-property-p v localname "file-attributes")
+           (not (null (tramp-get-file-property v localname "file-attributes")))
+         (tramp-send-command-and-check
+          v
+          (format
+           "%s %s"
+           (tramp-get-file-exists-command v)
+           (tramp-shell-quote-argument localname))))))))
 
 (defun tramp-sh-handle-file-attributes (filename &optional id-format)
   "Like `file-attributes' for Tramp files."
-  (unless id-format (setq id-format 'integer))
-  (ignore-errors
-    ;; Don't modify `last-coding-system-used' by accident.
-    (let ((last-coding-system-used last-coding-system-used))
-      (with-parsed-tramp-file-name (expand-file-name filename) nil
-       (with-tramp-file-property
-           v localname (format "file-attributes-%s" id-format)
-         (tramp-convert-file-attributes
-          v
-          (or
-           (cond
-            ((tramp-get-remote-stat v)
-             (tramp-do-file-attributes-with-stat v localname id-format))
-            ((tramp-get-remote-perl v)
-             (tramp-do-file-attributes-with-perl v localname id-format))
-            (t nil))
-           ;; The scripts could fail, for example with huge file size.
-           (tramp-do-file-attributes-with-ls v localname id-format))))))))
+  ;; The result is cached in `tramp-convert-file-attributes'.
+  ;; Don't modify `last-coding-system-used' by accident.
+  (let ((last-coding-system-used last-coding-system-used))
+    (with-parsed-tramp-file-name (expand-file-name filename) nil
+      (tramp-convert-file-attributes v localname id-format
+       (cond
+        ((tramp-get-remote-stat v)
+         (tramp-do-file-attributes-with-stat v localname))
+        ((tramp-get-remote-perl v)
+         (tramp-do-file-attributes-with-perl v localname))
+        (t (tramp-do-file-attributes-with-ls v localname)))))))
 
 (defconst tramp-sunos-unames (regexp-opt '("SunOS 5.10" "SunOS 5.11"))
   "Regexp to determine remote SunOS.")
@@ -1230,29 +1264,40 @@ component is used as the target of the symlink."
      (tramp-get-ls-command-with vec "-w"))
    ""))
 
-(defun tramp-do-file-attributes-with-ls (vec localname &optional id-format)
+(defun tramp-do-file-attributes-with-ls (vec localname)
   "Implement `file-attributes' for Tramp files using the ls(1) command."
   (let (symlinkp dirp
        res-inode res-filemodes res-numlinks
-       res-uid res-gid res-size res-symlink-target)
+       res-uid-string res-gid-string res-uid-integer res-gid-integer
+       res-size res-symlink-target)
     (tramp-message vec 5 "file attributes with ls: %s" localname)
     ;; We cannot send all three commands combined, it could exceed
     ;; NAME_MAX or PATH_MAX.  Happened on macOS, for example.
-    (when (or (tramp-send-command-and-check
-               vec
-               (format "%s %s"
-                       (tramp-get-file-exists-command vec)
-                       (tramp-shell-quote-argument localname)))
-              (tramp-send-command-and-check
-               vec
-               (format "%s -h %s"
-                       (tramp-get-test-command vec)
-                       (tramp-shell-quote-argument localname))))
+    (when (tramp-send-command-and-check
+           vec
+           (format "cd %s && (%s %s || %s -h %s)"
+                  (tramp-shell-quote-argument
+                   (tramp-run-real-handler
+                    #'file-name-directory (list localname)))
+                  (tramp-get-file-exists-command vec)
+                  (if (string-empty-p (file-name-nondirectory localname))
+                      "."
+                     (tramp-shell-quote-argument
+                     (file-name-nondirectory localname)))
+                   (tramp-get-test-command vec)
+                  (if (string-empty-p (file-name-nondirectory localname))
+                      "."
+                     (tramp-shell-quote-argument
+                     (file-name-nondirectory localname)))))
       (tramp-send-command
        vec
-       (format "%s %s %s %s"
+       (format "%s -ild %s %s; %s -lnd %s %s"
+               (tramp-get-ls-command vec)
+               ;; On systems which have no quoting style, file names
+               ;; with special characters could fail.
+               (tramp-sh--quoting-style-options vec)
+               (tramp-shell-quote-argument localname)
                (tramp-get-ls-command vec)
-               (if (eq id-format 'integer) "-ildn" "-ild")
                ;; On systems which have no quoting style, file names
                ;; with special characters could fail.
                (tramp-sh--quoting-style-options vec)
@@ -1268,17 +1313,16 @@ component is used as the target of the symlink."
           ;; ... number links
           (setq res-numlinks (read (current-buffer)))
           ;; ... uid and gid
-          (setq res-uid (read (current-buffer)))
-          (setq res-gid (read (current-buffer)))
-          (if (eq id-format 'integer)
-              (progn
-                (unless (numberp res-uid)
-                 (setq res-uid tramp-unknown-id-integer))
-                (unless (numberp res-gid)
-                 (setq res-gid tramp-unknown-id-integer)))
-            (progn
-              (unless (stringp res-uid) (setq res-uid (symbol-name res-uid)))
-              (unless (stringp res-gid) (setq res-gid (symbol-name res-gid)))))
+          (setq res-uid-string (read (current-buffer)))
+          (setq res-gid-string (read (current-buffer)))
+         (when (natnump res-uid-string)
+           (setq res-uid-string (number-to-string res-uid-string)))
+          (unless (stringp res-uid-string)
+           (setq res-uid-string (symbol-name res-uid-string)))
+         (when (natnump res-gid-string)
+           (setq res-gid-string (number-to-string res-gid-string)))
+          (unless (stringp res-gid-string)
+           (setq res-gid-string (symbol-name res-gid-string)))
           ;; ... size
           (setq res-size (read (current-buffer)))
           ;; From the file modes, figure out other stuff.
@@ -1290,8 +1334,21 @@ component is used as the target of the symlink."
             (setq res-symlink-target
                   (if (looking-at-p "\"")
                       (read (current-buffer))
-                    (buffer-substring (point) (point-at-eol)))))
-          ;; Return data gathered.
+                    (buffer-substring (point) (line-end-position)))))
+         (forward-line)
+          ;; ... file mode flags
+         (read (current-buffer))
+          ;; ... number links
+         (read (current-buffer))
+          ;; ... uid and gid
+          (setq res-uid-integer (read (current-buffer)))
+          (setq res-gid-integer (read (current-buffer)))
+          (unless (numberp res-uid-integer)
+           (setq res-uid-integer tramp-unknown-id-integer))
+          (unless (numberp res-gid-integer)
+           (setq res-gid-integer tramp-unknown-id-integer))
+
+         ;; Return data gathered.
           (list
            ;; 0. t for directory, string (name linked to) for symbolic
            ;; link, or nil.
@@ -1299,9 +1356,9 @@ component is used as the target of the symlink."
            ;; 1. Number of links to file.
            res-numlinks
            ;; 2. File uid.
-           res-uid
+           (cons res-uid-string res-uid-integer)
            ;; 3. File gid.
-           res-gid
+           (cons res-gid-string res-gid-integer)
            ;; 4. Last access time.
            ;; 5. Last modification time.
            ;; 6. Last status change time.
@@ -1318,42 +1375,23 @@ component is used as the target of the symlink."
            ;; 11. Device number.  Will be replaced by a virtual device number.
            -1))))))
 
-(defun tramp-do-file-attributes-with-perl
-  (vec localname &optional id-format)
+(defun tramp-do-file-attributes-with-perl (vec localname)
   "Implement `file-attributes' for Tramp files using a Perl script."
   (tramp-message vec 5 "file attributes with perl: %s" localname)
   (tramp-maybe-send-script
    vec tramp-perl-file-attributes "tramp_perl_file_attributes")
   (tramp-send-command-and-read
-   vec
-   (format "tramp_perl_file_attributes %s %s"
-          (tramp-shell-quote-argument localname) id-format)))
+   vec (format "tramp_perl_file_attributes %s"
+              (tramp-shell-quote-argument localname))))
 
-(defun tramp-do-file-attributes-with-stat
-  (vec localname &optional id-format)
+(defun tramp-do-file-attributes-with-stat (vec localname)
   "Implement `file-attributes' for Tramp files using stat(1) command."
   (tramp-message vec 5 "file attributes with stat: %s" localname)
+  (tramp-maybe-send-script
+   vec tramp-stat-file-attributes "tramp_stat_file_attributes")
   (tramp-send-command-and-read
-   vec
-   (format
-    (concat
-     ;; Apostrophes in the stat output are masked as
-     ;; `tramp-stat-marker', in order to make a proper shell escape of
-     ;; them in file names.
-     "(%s -c '((%s%%N%s) %%h %s %s %%X %%Y %%Z %%s %s%%A%s t %%i -1)' %s |"
-     " sed -e 's/\"/\\\\\"/g' -e 's/%s/\"/g')")
-    (tramp-get-remote-stat vec)
-    tramp-stat-marker tramp-stat-marker
-    (if (eq id-format 'integer)
-       "%u"
-      (eval-when-compile (concat tramp-stat-marker "%U" tramp-stat-marker)))
-    (if (eq id-format 'integer)
-       "%g"
-      (eval-when-compile (concat tramp-stat-marker "%G" tramp-stat-marker)))
-    tramp-stat-marker tramp-stat-marker
-    (tramp-shell-quote-argument localname)
-    tramp-stat-quoted-marker)
-   'noerror))
+   vec (format "tramp_stat_file_attributes %s"
+              (tramp-shell-quote-argument localname))))
 
 (defun tramp-sh-handle-set-visited-file-modtime (&optional time-list)
   "Like `set-visited-file-modtime' for Tramp files."
@@ -1378,7 +1416,7 @@ component is used as the target of the symlink."
               (format "%s -ild %s"
                       (tramp-get-ls-command v)
                       (tramp-shell-quote-argument localname)))
-             (setq attr (buffer-substring (point) (point-at-eol))))
+             (setq attr (buffer-substring (point) (line-end-position))))
            (tramp-set-file-property
             v localname "visited-file-modtime-ild" attr))
          (setq last-coding-system-used coding-system-used)
@@ -1422,7 +1460,7 @@ of."
                       (tramp-get-ls-command v)
                       (tramp-shell-quote-argument localname)))
              (with-current-buffer (tramp-get-buffer v)
-               (setq attr (buffer-substring (point) (point-at-eol))))
+               (setq attr (buffer-substring (point) (line-end-position))))
              (equal
               attr
               (tramp-get-file-property
@@ -1433,12 +1471,11 @@ of."
 
 (defun tramp-sh-handle-set-file-modes (filename mode &optional flag)
   "Like `set-file-modes' for Tramp files."
-  (with-parsed-tramp-file-name filename nil
-    ;; We need "chmod -h" when the flag is set.
-    (when (or (not (eq flag 'nofollow))
-             (not (file-symlink-p filename))
-             (tramp-get-remote-chmod-h v))
-      (tramp-flush-file-properties v localname)
+  ;; We need "chmod -h" when the flag is set.
+  (when (or (not (eq flag 'nofollow))
+           (not (file-symlink-p filename))
+           (tramp-get-remote-chmod-h (tramp-dissect-file-name filename)))
+    (tramp-skeleton-set-file-modes-times-uid-gid filename
       ;; FIXME: extract the proper text from chmod's stderr.
       (tramp-barf-unless-okay
        v
@@ -1450,9 +1487,8 @@ of."
 
 (defun tramp-sh-handle-set-file-times (filename &optional time flag)
   "Like `set-file-times' for Tramp files."
-  (with-parsed-tramp-file-name filename nil
+  (tramp-skeleton-set-file-modes-times-uid-gid filename
     (when (tramp-get-remote-touch v)
-      (tramp-flush-file-properties v localname)
       (let ((time
             (if (or (null time)
                     (tramp-compat-time-equal-p time tramp-time-doesnt-exist)
@@ -1463,7 +1499,7 @@ of."
         v (format
            "env TZ=UTC %s %s %s %s"
            (tramp-get-remote-touch v)
-           (if (tramp-get-connection-property v "touch-t" nil)
+           (if (tramp-get-connection-property v "touch-t")
                (format "-t %s" (format-time-string "%Y%m%d%H%M.%S" time t))
              "")
            (if (eq flag 'nofollow) "-h" "")
@@ -1481,11 +1517,12 @@ VEC or USER, or if there is no home directory, return 
nil."
               (concat "~" (or user (tramp-file-name-user vec))))))
     (with-current-buffer (tramp-get-buffer vec)
       (goto-char (point-min))
-      (buffer-substring (point) (point-at-eol)))))
+      (buffer-substring (point) (line-end-position)))))
 
 (defun tramp-sh-handle-get-remote-uid (vec id-format)
   "The uid of the remote connection VEC, in ID-FORMAT.
 ID-FORMAT valid values are `string' and `integer'."
+  ;; The result is cached in `tramp-get-remote-uid'.
   (ignore-errors
     (cond
      ((tramp-get-remote-id vec) (tramp-get-remote-uid-with-id vec id-format))
@@ -1496,6 +1533,7 @@ ID-FORMAT valid values are `string' and `integer'."
 (defun tramp-sh-handle-get-remote-gid (vec id-format)
   "The gid of the remote connection VEC, in ID-FORMAT.
 ID-FORMAT valid values are `string' and `integer'."
+  ;; The result is cached in `tramp-get-remote-gid'.
   (ignore-errors
     (cond
      ((tramp-get-remote-id vec) (tramp-get-remote-gid-with-id vec id-format))
@@ -1509,9 +1547,9 @@ ID-FORMAT valid values are `string' and `integer'."
   ;; another implementation, see `dired-do-chown'.  OTOH, it is mostly
   ;; working with su(do)? when it is needed, so it shall succeed in
   ;; the majority of cases.
-  ;; Don't modify `last-coding-system-used' by accident.
-  (let ((last-coding-system-used last-coding-system-used))
-    (with-parsed-tramp-file-name filename nil
+  (tramp-skeleton-set-file-modes-times-uid-gid filename
+    ;; Don't modify `last-coding-system-used' by accident.
+    (let ((last-coding-system-used last-coding-system-used))
       (if (and (zerop (user-uid)) (tramp-local-host-p v))
          ;; If we are root on the local host, we can do it directly.
          (tramp-set-file-uid-gid localname uid gid)
@@ -1534,8 +1572,10 @@ ID-FORMAT valid values are `string' and `integer'."
   (with-parsed-tramp-file-name filename nil
     (with-tramp-file-property v localname "file-selinux-context"
       (let ((context '(nil nil nil nil))
-           (regexp (concat "\\([[:alnum:]_]+\\):" "\\([[:alnum:]_]+\\):"
-                           "\\([[:alnum:]_]+\\):" "\\([[:alnum:]_]+\\)")))
+           (regexp (rx (group (+ (any "_" alnum))) ":"
+                       (group (+ (any "_" alnum))) ":"
+                       (group (+ (any "_" alnum))) ":"
+                       (group (+ (any "_" alnum))))))
        (when (and (tramp-remote-selinux-p v)
                   (tramp-send-command-and-check
                    v (format
@@ -1544,7 +1584,7 @@ ID-FORMAT valid values are `string' and `integer'."
                       (tramp-shell-quote-argument localname))))
          (with-current-buffer (tramp-get-connection-buffer v)
            (goto-char (point-min))
-           (when (re-search-forward regexp (point-at-eol) t)
+           (when (re-search-forward regexp (line-end-position) t)
              (setq context (list (match-string 1) (match-string 2)
                                  (match-string 3) (match-string 4))))))
        ;; Return the context.
@@ -1620,16 +1660,18 @@ ID-FORMAT valid values are `string' and `integer'."
     (with-tramp-file-property v localname "file-executable-p"
       ;; Examine `file-attributes' cache to see if request can be
       ;; satisfied without remote operation.
-      (or (tramp-check-cached-permissions v ?x)
-         (tramp-check-cached-permissions v ?s)
-         (tramp-run-test "-x" filename)))))
+      (if (tramp-file-property-p v localname "file-attributes")
+         (or (tramp-check-cached-permissions v ?x)
+             (tramp-check-cached-permissions v ?s))
+       (tramp-run-test "-x" filename)))))
 
 (defun tramp-sh-handle-file-readable-p (filename)
   "Like `file-readable-p' for Tramp files."
   (with-parsed-tramp-file-name filename nil
     (with-tramp-file-property v localname "file-readable-p"
-      (or (tramp-handle-file-readable-p filename)
-         (tramp-run-test "-r" filename)))))
+      (if (tramp-file-property-p v localname "file-attributes")
+         (tramp-handle-file-readable-p filename)
+       (tramp-run-test "-r" filename)))))
 
 ;; Functions implemented using the basic functions above.
 
@@ -1642,19 +1684,28 @@ ID-FORMAT valid values are `string' and `integer'."
     ;; be expected that this is always a directory.
     (or (zerop (length localname))
        (with-tramp-file-property v localname "file-directory-p"
-         (tramp-run-test "-d" filename)))))
+         (if-let
+             ((truename (tramp-get-file-property v localname "file-truename"))
+              (attr-p (tramp-file-property-p
+                       v (tramp-file-local-name truename) "file-attributes")))
+             (eq (file-attribute-type
+                  (tramp-get-file-property
+                   v (tramp-file-local-name truename) "file-attributes"))
+                 t)
+           (tramp-run-test "-d" filename))))))
 
 (defun tramp-sh-handle-file-writable-p (filename)
   "Like `file-writable-p' for Tramp files."
   (with-parsed-tramp-file-name filename nil
     (with-tramp-file-property v localname "file-writable-p"
       (if (file-exists-p filename)
-         ;; Examine `file-attributes' cache to see if request can be
-         ;; satisfied without remote operation.
-          (or (tramp-check-cached-permissions v ?w)
-             (tramp-run-test "-w" filename))
+         (if (tramp-file-property-p v localname "file-attributes")
+             ;; Examine `file-attributes' cache to see if request can
+             ;; be satisfied without remote operation.
+             (tramp-check-cached-permissions v ?w)
+           (tramp-run-test "-w" filename))
        ;; If file doesn't exist, check if directory is writable.
-       (and (tramp-run-test "-d" (file-name-directory filename))
+       (and (file-exists-p (file-name-directory filename))
             (tramp-run-test "-w" (file-name-directory filename)))))))
 
 (defun tramp-sh-handle-file-ownership-preserved-p (filename &optional group)
@@ -1674,7 +1725,7 @@ ID-FORMAT valid values are `string' and `integer'."
                 ;; On BSD-derived systems files always inherit the
                  ;; parent directory's group, so skip the group-gid
                  ;; test.
-                 (tramp-check-remote-uname v "BSD\\|DragonFly\\|Darwin")
+                 (tramp-check-remote-uname v (rx (| "BSD" "DragonFly" 
"Darwin")))
                 (= (file-attribute-group-id attributes)
                    (tramp-get-remote-gid v 'integer)))))))))
 
@@ -1683,51 +1734,18 @@ ID-FORMAT valid values are `string' and `integer'."
 (defun tramp-sh-handle-directory-files-and-attributes
   (directory &optional full match nosort id-format count)
   "Like `directory-files-and-attributes' for Tramp files."
-  (unless id-format (setq id-format 'integer))
-  (unless (file-exists-p directory)
-    (tramp-error (tramp-dissect-file-name directory) 'file-missing directory))
-  (when (file-directory-p directory)
-    (setq directory (expand-file-name directory))
-    (let* ((temp
-           (copy-tree
-            (with-parsed-tramp-file-name directory nil
-              (with-tramp-file-property
-                  v localname
-                  (format "directory-files-and-attributes-%s" id-format)
-                (mapcar
-                 (lambda (x)
-                   (cons (car x) (tramp-convert-file-attributes v (cdr x))))
-                 (cond
-                  ((tramp-get-remote-stat v)
-                   (tramp-do-directory-files-and-attributes-with-stat
-                    v localname id-format))
-                  ((tramp-get-remote-perl v)
-                   (tramp-do-directory-files-and-attributes-with-perl
-                    v localname id-format))
-                  (t nil)))))))
-          result item)
-
-      (while temp
-       (setq item (pop temp))
-       (when (or (null match) (string-match-p match (car item)))
-         (when full
-           (setcar item (expand-file-name (car item) directory)))
-         (push item result)))
-
-      (unless nosort
-       (setq result (sort result (lambda (x y) (string< (car x) (car y))))))
-
-      (when (and (natnump count) (> count 0))
-       (setq result (nbutlast result (- (length result) count))))
-
-      (or result
-         ;; The scripts could fail, for example with huge file size.
-         (tramp-handle-directory-files-and-attributes
-          directory full match nosort id-format count)))))
+  (tramp-skeleton-directory-files-and-attributes
+      directory full match nosort id-format count
+    (cond
+     ((tramp-get-remote-stat v)
+      (tramp-do-directory-files-and-attributes-with-stat
+       v localname))
+     ((tramp-get-remote-perl v)
+      (tramp-do-directory-files-and-attributes-with-perl
+       v localname)))))
 
 ;; FIXME: Fix function to work with count parameter.
-(defun tramp-do-directory-files-and-attributes-with-perl
-  (vec localname &optional id-format)
+(defun tramp-do-directory-files-and-attributes-with-perl (vec localname)
   "Implement `directory-files-and-attributes' for Tramp files using a Perl 
script."
   (tramp-message vec 5 "directory-files-and-attributes with perl: %s" 
localname)
   (tramp-maybe-send-script
@@ -1735,59 +1753,31 @@ ID-FORMAT valid values are `string' and `integer'."
    "tramp_perl_directory_files_and_attributes")
   (let ((object
         (tramp-send-command-and-read
-         vec
-         (format "tramp_perl_directory_files_and_attributes %s %s"
-                 (tramp-shell-quote-argument localname) id-format))))
+         vec (format "tramp_perl_directory_files_and_attributes %s"
+                     (tramp-shell-quote-argument localname)))))
     (when (stringp object) (tramp-error vec 'file-error object))
     object))
 
 ;; FIXME: Fix function to work with count parameter.
-(defun tramp-do-directory-files-and-attributes-with-stat
-  (vec localname &optional id-format)
+(defun tramp-do-directory-files-and-attributes-with-stat (vec localname)
   "Implement `directory-files-and-attributes' for Tramp files with stat(1) 
command."
   (tramp-message vec 5 "directory-files-and-attributes with stat: %s" 
localname)
+  (tramp-maybe-send-script
+   vec tramp-stat-directory-files-and-attributes
+   "tramp_stat_directory_files_and_attributes")
   (tramp-send-command-and-read
-   vec
-   (format
-    (concat
-     ;; We must care about file names with spaces, or starting with
-     ;; "-"; this would confuse xargs.  "ls -aQ" might be a solution,
-     ;; but it does not work on all remote systems.  Therefore, we use
-     ;; \000 as file separator.  `tramp-sh--quoting-style-options' do
-     ;; not work for file names with spaces piped to "xargs".
-     ;; Apostrophes in the stat output are masked as
-     ;; `tramp-stat-marker', in order to make a proper shell escape of
-     ;; them in file names.
-     "cd %s && echo \"(\"; (%s %s -a | tr '\\n\\r' '\\000\\000' | "
-     "xargs -0 %s -c "
-     "'(%s%%n%s (%s%%N%s) %%h %s %s %%X %%Y %%Z %%s %s%%A%s t %%i -1)' "
-     "-- 2>%s | sed -e 's/\"/\\\\\"/g' -e 's/%s/\"/g'); echo \")\"")
-    (tramp-shell-quote-argument localname)
-    (tramp-get-ls-command vec)
-    ;; On systems which have no quoting style, file names with special
-    ;; characters could fail.
-    (tramp-sh--quoting-style-options vec)
-    (tramp-get-remote-stat vec)
-    tramp-stat-marker tramp-stat-marker
-    tramp-stat-marker tramp-stat-marker
-    (if (eq id-format 'integer)
-       "%u"
-      (eval-when-compile (concat tramp-stat-marker "%U" tramp-stat-marker)))
-    (if (eq id-format 'integer)
-       "%g"
-      (eval-when-compile (concat tramp-stat-marker "%G" tramp-stat-marker)))
-    tramp-stat-marker tramp-stat-marker
-    (tramp-get-remote-null-device vec)
-    tramp-stat-quoted-marker)))
+   vec (format "tramp_stat_directory_files_and_attributes %s"
+              (tramp-shell-quote-argument localname))))
 
 ;; This function should return "foo/" for directories and "bar" for
 ;; files.
 (defun tramp-sh-handle-file-name-all-completions (filename directory)
   "Like `file-name-all-completions' for Tramp files."
-  (unless (tramp-compat-string-search "/" filename)
-    (all-completions
-     filename
-     (with-parsed-tramp-file-name (expand-file-name directory) nil
+  (with-parsed-tramp-file-name (expand-file-name directory) nil
+    (when (and (not (tramp-compat-string-search "/" filename))
+              (tramp-connectable-p v))
+      (all-completions
+       filename
        (with-tramp-file-property v localname "file-name-all-completions"
         (let (result)
           ;; Get a list of directories and files, including reliably
@@ -1821,7 +1811,7 @@ ID-FORMAT valid values are `string' and `integer'."
 
             ;; Check result code, found in last line of output.
             (forward-line -1)
-            (if (looking-at-p "^fail$")
+            (if (looking-at-p (rx bol "fail" eol))
                 (progn
                   ;; Grab error message from line before last line
                   ;; (it was put there by `cd 2>&1').
@@ -1829,12 +1819,12 @@ ID-FORMAT valid values are `string' and `integer'."
                   (tramp-error
                    v 'file-error
                    "tramp-sh-handle-file-name-all-completions: %s"
-                   (buffer-substring (point) (point-at-eol))))
+                   (buffer-substring (point) (line-end-position))))
               ;; For peace of mind, if buffer doesn't end in `fail'
               ;; then it should end in `ok'.  If neither are in the
               ;; buffer something went seriously wrong on the remote
               ;; side.
-              (unless (looking-at-p "^ok$")
+              (unless (looking-at-p (rx bol "ok" eol))
                 (tramp-error
                  v 'file-error
                  (concat "tramp-sh-handle-file-name-all-completions: "
@@ -1842,7 +1832,7 @@ ID-FORMAT valid values are `string' and `integer'."
                  (tramp-shell-quote-argument localname) (buffer-string))))
 
             (while (zerop (forward-line -1))
-              (push (buffer-substring (point) (point-at-eol)) result)))
+              (push (buffer-substring (point) (line-end-position)) result)))
           result))))))
 
 ;; cp, mv and ln
@@ -1900,59 +1890,62 @@ ID-FORMAT valid values are `string' and `integer'."
 (defun tramp-sh-handle-copy-directory
   (dirname newname &optional keep-date parents copy-contents)
   "Like `copy-directory' for Tramp files."
-  (let ((t1 (tramp-tramp-file-p dirname))
-       (t2 (tramp-tramp-file-p newname))
-       target)
-    (with-parsed-tramp-file-name (if t1 dirname newname) nil
-      (unless (file-exists-p dirname)
-       (tramp-error v 'file-missing dirname))
-
-      ;; `copy-directory-create-symlink' exists since Emacs 28.1.
-      (if (and (bound-and-true-p copy-directory-create-symlink)
-              (setq target (file-symlink-p dirname))
-              (tramp-equal-remote dirname newname))
-         (make-symbolic-link
-          target
-          (if (directory-name-p newname)
-              (concat newname (file-name-nondirectory dirname)) newname)
-          t)
-
-       (if (and (not copy-contents)
-                (tramp-get-method-parameter v 'tramp-copy-recursive)
-                ;; When DIRNAME and NEWNAME are remote, they must
-                ;; have the same method.
-                (or (null t1) (null t2)
-                    (string-equal
-                     (tramp-file-name-method (tramp-dissect-file-name dirname))
-                     (tramp-file-name-method
-                      (tramp-dissect-file-name newname)))))
-           ;; scp or rsync DTRT.
-           (progn
-             (when (and (file-directory-p newname)
-                        (not (directory-name-p newname)))
-               (tramp-error v 'file-already-exists newname))
-             (setq dirname (directory-file-name (expand-file-name dirname))
-                   newname (directory-file-name (expand-file-name newname)))
-             (when (and (file-directory-p newname)
-                        (not (string-equal (file-name-nondirectory dirname)
-                                           (file-name-nondirectory newname))))
-               (setq newname
-                     (expand-file-name
-                      (file-name-nondirectory dirname) newname)))
-             (unless (file-directory-p (file-name-directory newname))
-               (make-directory (file-name-directory newname) parents))
-             (tramp-do-copy-or-rename-file-out-of-band
-              'copy dirname newname 'ok-if-already-exists keep-date))
-
-         ;; We must do it file-wise.
-         (tramp-run-real-handler
-          #'copy-directory
-          (list dirname newname keep-date parents copy-contents))))
-
-      ;; When newname did exist, we have wrong cached values.
-      (when t2
-       (with-parsed-tramp-file-name newname nil
-         (tramp-flush-file-properties v localname))))))
+  (tramp-skeleton-copy-directory
+      dirname newname keep-date parents copy-contents
+    (let ((t1 (tramp-tramp-file-p dirname))
+         (t2 (tramp-tramp-file-p newname))
+         target)
+      (with-parsed-tramp-file-name (if t1 dirname newname) nil
+       (unless (file-exists-p dirname)
+         (tramp-error v 'file-missing dirname))
+
+       ;; `copy-directory-create-symlink' exists since Emacs 28.1.
+       (if (and (bound-and-true-p copy-directory-create-symlink)
+                (setq target (file-symlink-p dirname))
+                (tramp-equal-remote dirname newname))
+           (make-symbolic-link
+            target
+            (if (directory-name-p newname)
+                (concat newname (file-name-nondirectory dirname)) newname)
+            t)
+
+         (if (and (not copy-contents)
+                  (tramp-get-method-parameter v 'tramp-copy-recursive)
+                  ;; When DIRNAME and NEWNAME are remote, they must
+                  ;; have the same method.
+                  (or (null t1) (null t2)
+                      (string-equal
+                       (tramp-file-name-method
+                        (tramp-dissect-file-name dirname))
+                       (tramp-file-name-method
+                        (tramp-dissect-file-name newname)))))
+             ;; scp or rsync DTRT.
+             (progn
+               (when (and (file-directory-p newname)
+                          (not (directory-name-p newname)))
+                 (tramp-error v 'file-already-exists newname))
+               (setq dirname (directory-file-name (expand-file-name dirname))
+                     newname (directory-file-name (expand-file-name newname)))
+               (when (and (file-directory-p newname)
+                          (not (string-equal (file-name-nondirectory dirname)
+                                             (file-name-nondirectory 
newname))))
+                 (setq newname
+                       (expand-file-name
+                        (file-name-nondirectory dirname) newname)))
+               (unless (file-directory-p (file-name-directory newname))
+                 (make-directory (file-name-directory newname) parents))
+               (tramp-do-copy-or-rename-file-out-of-band
+                'copy dirname newname 'ok-if-already-exists keep-date))
+
+           ;; We must do it file-wise.
+           (tramp-run-real-handler
+            #'copy-directory
+            (list dirname newname keep-date parents copy-contents))))
+
+       ;; When newname did exist, we have wrong cached values.
+       (when t2
+         (with-parsed-tramp-file-name newname nil
+           (tramp-flush-file-properties v localname)))))))
 
 (defun tramp-sh-handle-rename-file
   (filename newname &optional ok-if-already-exists)
@@ -1997,98 +1990,101 @@ file names."
        (copy-directory filename newname keep-date t)
        (when (eq op 'rename) (delete-directory filename 'recursive)))
 
+    ;; FIXME: This should be optimized.  Computing `file-attributes'
+    ;; checks already, whether the file exists.
     (let ((t1 (tramp-tramp-file-p filename))
          (t2 (tramp-tramp-file-p newname))
          (length (file-attribute-size
                   (file-attributes (file-truename filename))))
-         (attributes (and preserve-extended-attributes
-                          (file-extended-attributes filename)))
          (msg-operation (if (eq op 'copy) "Copying" "Renaming")))
 
       (with-parsed-tramp-file-name (if t1 filename newname) nil
-       (unless (file-exists-p filename)
+       (unless length
          (tramp-error v 'file-missing filename))
-       (when (and (not ok-if-already-exists) (file-exists-p newname))
-         (tramp-error v 'file-already-exists newname))
-       (when (and (file-directory-p newname)
-                  (not (directory-name-p newname)))
-         (tramp-error v 'file-error "File is a directory %s" newname))
+       (tramp-barf-if-file-missing v filename
+         (when (and (not ok-if-already-exists) (file-exists-p newname))
+           (tramp-error v 'file-already-exists newname))
+         (when (and (file-directory-p newname)
+                    (not (directory-name-p newname)))
+           (tramp-error v 'file-error "File is a directory %s" newname))
 
-       (with-tramp-progress-reporter
-           v 0 (format "%s %s to %s" msg-operation filename newname)
+         (with-tramp-progress-reporter
+             v 0 (format "%s %s to %s" msg-operation filename newname)
 
-         (cond
-          ;; Both are Tramp files.
-          ((and t1 t2)
-           (with-parsed-tramp-file-name filename v1
-             (with-parsed-tramp-file-name newname v2
-               (cond
-                ;; Shortcut: if method, host, user are the same for
-                ;; both files, we invoke `cp' or `mv' on the remote
-                ;; host directly.
-                ((tramp-equal-remote filename newname)
-                 (tramp-do-copy-or-rename-file-directly
-                  op filename newname
-                  ok-if-already-exists keep-date preserve-uid-gid))
-
-                ;; Try out-of-band operation.
-                ((and
-                  (tramp-method-out-of-band-p v1 length)
-                  (tramp-method-out-of-band-p v2 length))
-                 (tramp-do-copy-or-rename-file-out-of-band
-                  op filename newname ok-if-already-exists keep-date))
-
-                ;; No shortcut was possible.  So we copy the file
-                ;; first.  If the operation was `rename', we go back
-                ;; and delete the original file (if the copy was
-                ;; successful).  The approach is simple-minded: we
-                ;; create a new buffer, insert the contents of the
-                ;; source file into it, then write out the buffer to
-                ;; the target file.  The advantage is that it doesn't
-                ;; matter which file name handlers are used for the
-                ;; source and target file.
-                (t
-                 (tramp-do-copy-or-rename-file-via-buffer
-                  op filename newname ok-if-already-exists keep-date))))))
-
-          ;; One file is a Tramp file, the other one is local.
-          ((or t1 t2)
            (cond
-            ;; Fast track on local machine.
-            ((tramp-local-host-p v)
-             (tramp-do-copy-or-rename-file-directly
-              op filename newname
-              ok-if-already-exists keep-date preserve-uid-gid))
-
-            ;; If the Tramp file has an out-of-band method, the
-            ;; corresponding copy-program can be invoked.
-            ((tramp-method-out-of-band-p v length)
-             (tramp-do-copy-or-rename-file-out-of-band
-              op filename newname ok-if-already-exists keep-date))
-
-            ;; Use the inline method via a Tramp buffer.
-            (t (tramp-do-copy-or-rename-file-via-buffer
-                op filename newname ok-if-already-exists keep-date))))
-
-          (t
-           ;; One of them must be a Tramp file.
-           (error "Tramp implementation says this cannot happen")))
-
-         ;; Handle `preserve-extended-attributes'.  We ignore possible
-         ;; errors, because ACL strings could be incompatible.
-         (when attributes
-           (ignore-errors
-             (set-file-extended-attributes newname attributes)))
-
-         ;; In case of `rename', we must flush the cache of the source file.
-         (when (and t1 (eq op 'rename))
-           (with-parsed-tramp-file-name filename v1
-             (tramp-flush-file-properties v1 v1-localname)))
-
-         ;; When newname did exist, we have wrong cached values.
-         (when t2
-           (with-parsed-tramp-file-name newname v2
-             (tramp-flush-file-properties v2 v2-localname))))))))
+            ;; Both are Tramp files.
+            ((and t1 t2)
+             (with-parsed-tramp-file-name filename v1
+               (with-parsed-tramp-file-name newname v2
+                 (cond
+                  ;; Shortcut: if method, host, user are the same for
+                  ;; both files, we invoke `cp' or `mv' on the remote
+                  ;; host directly.
+                  ((tramp-equal-remote filename newname)
+                   (tramp-do-copy-or-rename-file-directly
+                    op filename newname
+                    ok-if-already-exists keep-date preserve-uid-gid))
+
+                  ;; Try out-of-band operation.
+                  ((and
+                    (tramp-method-out-of-band-p v1 length)
+                    (tramp-method-out-of-band-p v2 length))
+                   (tramp-do-copy-or-rename-file-out-of-band
+                    op filename newname ok-if-already-exists keep-date))
+
+                  ;; No shortcut was possible.  So we copy the file
+                  ;; first.  If the operation was `rename', we go
+                  ;; back and delete the original file (if the copy
+                  ;; was successful).  The approach is simple-minded:
+                  ;; we create a new buffer, insert the contents of
+                  ;; the source file into it, then write out the
+                  ;; buffer to the target file.  The advantage is
+                  ;; that it doesn't matter which file name handlers
+                  ;; are used for the source and target file.
+                  (t
+                   (tramp-do-copy-or-rename-file-via-buffer
+                    op filename newname ok-if-already-exists keep-date))))))
+
+            ;; One file is a Tramp file, the other one is local.
+            ((or t1 t2)
+             (cond
+              ;; Fast track on local machine.
+              ((tramp-local-host-p v)
+               (tramp-do-copy-or-rename-file-directly
+                op filename newname
+                ok-if-already-exists keep-date preserve-uid-gid))
+
+              ;; If the Tramp file has an out-of-band method, the
+              ;; corresponding copy-program can be invoked.
+              ((tramp-method-out-of-band-p v length)
+               (tramp-do-copy-or-rename-file-out-of-band
+                op filename newname ok-if-already-exists keep-date))
+
+              ;; Use the inline method via a Tramp buffer.
+              (t (tramp-do-copy-or-rename-file-via-buffer
+                  op filename newname ok-if-already-exists keep-date))))
+
+            (t
+             ;; One of them must be a Tramp file.
+             (error "Tramp implementation says this cannot happen")))
+
+           ;; Handle `preserve-extended-attributes'.  We ignore
+           ;; possible errors, because ACL strings could be
+           ;; incompatible.
+           (when-let ((attributes (and preserve-extended-attributes
+                                       (file-extended-attributes filename))))
+             (ignore-errors
+               (set-file-extended-attributes newname attributes)))
+
+           ;; In case of `rename', we must flush the cache of the source file.
+           (when (and t1 (eq op 'rename))
+             (with-parsed-tramp-file-name filename v1
+               (tramp-flush-file-properties v1 v1-localname)))
+
+           ;; When newname did exist, we have wrong cached values.
+           (when t2
+             (with-parsed-tramp-file-name newname v2
+               (tramp-flush-file-properties v2 v2-localname)))))))))
 
 (defun tramp-do-copy-or-rename-file-via-buffer
     (op filename newname ok-if-already-exists keep-date)
@@ -2208,6 +2204,8 @@ the uid and gid from FILENAME."
                  (file-name-directory (concat prefix localname2)))
                 (or (file-directory-p (concat prefix localname2))
                     (file-writable-p (concat prefix localname2))))
+           (with-parsed-tramp-file-name prefix nil
+             (tramp-flush-file-properties v localname2))
            (tramp-do-copy-or-rename-file-directly
             op (concat prefix localname1) (concat prefix localname2)
             ok-if-already-exists keep-date preserve-uid-gid)
@@ -2350,7 +2348,7 @@ The method used must be an out-of-band method."
                  ?h (or (tramp-file-name-host v) "")
                  ?u (or (tramp-file-name-user v)
                         ;; There might be an interactive setting.
-                        (tramp-get-connection-property v "login-as" nil)
+                        (tramp-get-connection-property v "login-as")
                         "")
                  ;; For direct remote copying, the port must be the
                  ;; same for source and target.
@@ -2417,53 +2415,53 @@ The method used must be an out-of-band method."
 
       (with-temp-buffer
        (unwind-protect
-           ;; The default directory must be remote.
-           (let ((default-directory
-                  (file-name-directory (if v1 filename newname)))
-                 (process-environment (copy-sequence process-environment)))
-             ;; Set the transfer process properties.
-             (tramp-set-connection-property
-              v "process-name" (buffer-name (current-buffer)))
-             (tramp-set-connection-property
-              v "process-buffer" (current-buffer))
-             (when copy-env
-               (tramp-message
-                v 6 "%s=\"%s\""
-                (car copy-env) (string-join (cdr copy-env) " "))
-               (setenv (car copy-env) (string-join (cdr copy-env) " ")))
-             (setq
-              copy-args
-              (append
-               copy-args
-               (if remote-copy-program
-                   (list (if v1 (concat ">" target) (concat "<" source)))
-                 (list source target)))
-              ;; Use an asynchronous process.  By this, password can
-              ;; be handled.  We don't set a timeout, because the
-              ;; copying of large files can last longer than 60 secs.
-              p (let ((default-directory
-                       tramp-compat-temporary-file-directory))
-                  (apply
-                   #'start-process
-                   (tramp-get-connection-name v)
-                   (tramp-get-connection-buffer v)
-                   copy-program copy-args)))
-             (tramp-message v 6 "%s" (string-join (process-command p) " "))
-             (process-put p 'vector v)
-             (process-put p 'adjust-window-size-function #'ignore)
-             (set-process-query-on-exit-flag p nil)
-
-             ;; We must adapt `tramp-local-end-of-line' for sending
-             ;; the password.  Also, we indicate that perhaps several
-             ;; password prompts might appear.
-             (let ((tramp-local-end-of-line tramp-rsh-end-of-line)
-                   (tramp-password-prompt-not-unique (and v1 v2)))
-               (tramp-process-actions
-                p v nil tramp-actions-copy-out-of-band)))
-
-         ;; Reset the transfer process properties.
-         (tramp-flush-connection-property v "process-name")
-         (tramp-flush-connection-property v "process-buffer")
+           (with-tramp-saved-connection-properties
+               v '("process-name" "process-buffer")
+             ;; The default directory must be remote.
+             (let ((default-directory
+                    (file-name-directory (if v1 filename newname)))
+                   (process-environment (copy-sequence process-environment)))
+               ;; Set the transfer process properties.
+               (tramp-set-connection-property
+                v "process-name" (buffer-name (current-buffer)))
+               (tramp-set-connection-property
+                v "process-buffer" (current-buffer))
+               (when copy-env
+                 (tramp-message
+                  v 6 "%s=\"%s\""
+                  (car copy-env) (string-join (cdr copy-env) " "))
+                 (setenv (car copy-env) (string-join (cdr copy-env) " ")))
+               (setq
+                copy-args
+                (append
+                 copy-args
+                 (if remote-copy-program
+                     (list (if v1 (concat ">" target) (concat "<" source)))
+                   (list source target)))
+                ;; Use an asynchronous process.  By this, password
+                ;; can be handled.  We don't set a timeout, because
+                ;; the copying of large files can last longer than 60
+                ;; secs.
+                p (let ((default-directory
+                         tramp-compat-temporary-file-directory))
+                    (apply
+                     #'start-process
+                     (tramp-get-connection-name v)
+                     (tramp-get-connection-buffer v)
+                     copy-program copy-args)))
+               (tramp-message v 6 "%s" (string-join (process-command p) " "))
+               (process-put p 'vector v)
+               (process-put p 'adjust-window-size-function #'ignore)
+               (set-process-query-on-exit-flag p nil)
+
+               ;; We must adapt `tramp-local-end-of-line' for sending
+               ;; the password.  Also, we indicate that perhaps
+               ;; several password prompts might appear.
+               (let ((tramp-local-end-of-line tramp-rsh-end-of-line)
+                     (tramp-password-prompt-not-unique (and v1 v2)))
+                 (tramp-process-actions
+                  p v nil tramp-actions-copy-out-of-band))))
+
          ;; Clear the remote prompt.
          (when (and remote-copy-program
                     (not (tramp-send-command-and-check v nil)))
@@ -2521,12 +2519,12 @@ The method used must be an out-of-band method."
   "Like `delete-file' for Tramp files."
   (setq filename (expand-file-name filename))
   (with-parsed-tramp-file-name filename nil
-    (tramp-flush-file-properties v localname)
     (if (and delete-by-moving-to-trash trash)
        (move-file-to-trash filename)
       (tramp-barf-unless-okay
        v (format "rm -f %s" (tramp-shell-quote-argument localname))
-       "Couldn't delete %s" filename))))
+       "Couldn't delete %s" filename))
+    (tramp-flush-file-properties v localname)))
 
 ;; Dired.
 
@@ -2554,7 +2552,7 @@ The method used must be an out-of-band method."
               (with-tramp-progress-reporter
                    v 0 (format "Uncompressing %s" file)
                 (when (tramp-send-command-and-check
-                       v (if (string-match-p "%[io]" (nth 2 suffix))
+                       v (if (string-match-p (rx "%" (any "io")) (nth 2 
suffix))
                               (replace-regexp-in-string
                                "%i" (tramp-shell-quote-argument localname)
                                (nth 2 suffix))
@@ -2663,7 +2661,9 @@ The method used must be an out-of-band method."
        (save-restriction
          (narrow-to-region beg-marker end-marker)
          ;; Check for "--dired" output.
-         (when (re-search-backward "^//DIRED//\\s-+\\(.+\\)$" nil 'noerror)
+         (when (re-search-backward
+                (rx bol "//DIRED//" (+ space) (group (+ nonl)) eol)
+                nil 'noerror)
            (let ((beg (match-beginning 1))
                  (end (match-end 0)))
              ;; Now read the numeric positions of file names.
@@ -2735,7 +2735,7 @@ The method used must be an out-of-band method."
          ;; Try to insert the amount of free space.
          (goto-char (point-min))
          ;; First find the line to put it on.
-         (when (and (re-search-forward "^\\([[:space:]]*total\\)" nil t)
+         (when (and (re-search-forward (rx bol (group (* space) "total")) nil 
t)
                     ;; Emacs 29.1 or later.
                     (not (fboundp 'dired--insert-disk-space)))
            (when-let ((available (get-free-disk-space ".")))
@@ -2762,7 +2762,7 @@ the result will be a local, non-Tramp, file name."
   ;; by `file-name-absolute-p'.
   (if (and (eq system-type 'windows-nt)
           (string-match-p
-           (concat "^\\([[:alpha:]]:\\|" null-device "$\\)") name))
+           (rx bol (| (: alpha ":") (: (literal null-device) eol))) name))
       (tramp-run-real-handler #'expand-file-name (list name dir))
     ;; Unless NAME is absolute, concat DIR and NAME.
     (unless (file-name-absolute-p name)
@@ -2771,14 +2771,16 @@ the result will be a local, non-Tramp, file name."
     (with-parsed-tramp-file-name name nil
       ;; If connection is not established yet, run the real handler.
       (if (not (tramp-connectable-p v))
-         (tramp-run-real-handler #'expand-file-name (list name nil))
+         (tramp-run-real-handler #'expand-file-name (list name))
        (unless (tramp-run-real-handler #'file-name-absolute-p (list localname))
          (setq localname (concat "~/" localname)))
        ;; Tilde expansion if necessary.  This needs a shell which
        ;; groks tilde expansion!  The function `tramp-find-shell' is
        ;; supposed to find such a shell on the remote host.  Please
        ;; tell me about it when this doesn't work on your system.
-       (when (string-match "\\`~\\([^/]*\\)\\(.*\\)\\'" localname)
+       (when (string-match
+              (rx bos "~" (group (* (not (any "/")))) (group (* nonl)) eos)
+              localname)
          (let ((uname (match-string 1 localname))
                (fname (match-string 2 localname))
                hname)
@@ -2789,7 +2791,7 @@ the result will be a local, non-Tramp, file name."
            ;; appropriate either, because ssh and companions might
            ;; use a user name from the config file.
            (when (and (zerop (length uname))
-                      (string-match-p "\\`su\\(do\\)?\\'" method))
+                      (string-match-p (rx bos "su" (? "do") eos) method))
              (setq uname user))
            (when (setq hname (tramp-get-home-directory v uname))
              (setq localname (concat hname fname)))))
@@ -2798,7 +2800,7 @@ the result will be a local, non-Tramp, file name."
        (while (string-match "//" localname)
          (setq localname (replace-match "/" t t localname)))
        ;; Do not keep "/..".
-       (when (string-match-p "^/\\.\\.?$" localname)
+       (when (string-match-p (rx bos "/" (** 1 2 ".") eos) localname)
          (setq localname "/"))
        ;; Do normal `expand-file-name' (this does "/./" and "/../"),
        ;; unless there are tilde characters in file name.
@@ -2806,9 +2808,9 @@ the result will be a local, non-Tramp, file name."
        ;; would be problems with UNC shares or Cygwin mounts.
        (let ((default-directory tramp-compat-temporary-file-directory))
          (tramp-make-tramp-file-name
-          v (if (string-match-p "\\`\\(~[^/]*\\)\\(.*\\)\\'" localname)
-                localname
-              (tramp-drop-volume-letter
+          v (tramp-drop-volume-letter
+             (if (string-prefix-p "~" localname)
+                 localname
                (tramp-run-real-handler
                 #'expand-file-name (list localname))))))))))
 
@@ -2851,7 +2853,10 @@ implementation will be used."
            (signal 'wrong-type-argument (list #'symbolp coding)))
          (when (eq connection-type t)
            (setq connection-type 'pty))
-         (unless (memq connection-type '(nil pipe pty))
+         (unless (or (and (consp connection-type)
+                          (memq (car connection-type) '(nil pipe pty))
+                          (memq (cdr connection-type) '(nil pipe pty)))
+                     (memq connection-type '(nil pipe pty)))
            (signal 'wrong-type-argument (list #'symbolp connection-type)))
          (unless (or (null filter) (eq filter t) (functionp filter))
            (signal 'wrong-type-argument (list #'functionp filter)))
@@ -2885,11 +2890,12 @@ implementation will be used."
                 ;; command.
                 (heredoc (and (not (bufferp stderr))
                               (stringp program)
-                              (string-match-p "sh$" program)
+                              (string-match-p (rx "sh" eol) program)
                               (= (length args) 2)
                               (string-equal "-c" (car args))
                               ;; Don't if there is a quoted string.
-                              (not (string-match-p "'\\|\"" (cadr args)))
+                              (not
+                               (string-match-p (rx (any "'\"")) (cadr args)))
                               ;; Check, that /dev/tty is usable.
                               (tramp-get-remote-dev-tty v)))
                 ;; When PROGRAM is nil, we just provide a tty.
@@ -2976,94 +2982,103 @@ implementation will be used."
              (setq i (1+ i)
                    name1 (format "%s<%d>" name i)))
            (setq name name1)
-           ;; Set the new process properties.
-           (tramp-set-connection-property v "process-name" name)
-           (tramp-set-connection-property v "process-buffer" buffer)
 
-           (with-current-buffer (tramp-get-connection-buffer v)
-             (unwind-protect
-                 ;; We catch this event.  Otherwise, `make-process'
-                 ;; could be called on the local host.
-                 (save-excursion
-                   (save-restriction
-                     ;; Activate narrowing in order to save BUFFER
-                     ;; contents.  Clear also the modification time;
-                     ;; otherwise we might be interrupted by
-                     ;; `verify-visited-file-modtime'.
-                     (let ((buffer-undo-list t)
-                           (inhibit-read-only t)
-                           (mark (point-max))
-                           (coding-system-for-write
-                            (if (symbolp coding) coding (car coding)))
-                           (coding-system-for-read
-                            (if (symbolp coding) coding (cdr coding))))
-                       (clear-visited-file-modtime)
-                       (narrow-to-region (point-max) (point-max))
-                       (catch 'suppress
-                         ;; Set the pid of the remote shell.  This is
-                         ;; needed when sending signals remotely.
-                         (let ((pid (tramp-send-command-and-read v "echo $$")))
-                           (setq p (tramp-get-connection-process v))
-                           (process-put p 'remote-pid pid)
-                           (tramp-set-connection-property p "remote-pid" pid))
-                         ;; Disable carriage return to newline
-                         ;; translation.  This does not work on
-                         ;; macOS, see Bug#50748.
-                         (when (and (memq connection-type '(nil pipe))
-                                     (not (tramp-check-remote-uname v 
"Darwin")))
-                           (tramp-send-command v "stty -icrnl"))
-                         ;; `tramp-maybe-open-connection' and
-                         ;; `tramp-send-command-and-read' could have
-                         ;; trashed the connection buffer.  Remove this.
-                         (widen)
-                         (delete-region mark (point-max))
+           (with-tramp-saved-connection-properties
+               v '("process-name"  "process-buffer")
+             ;; Set the new process properties.
+             (tramp-set-connection-property v "process-name" name)
+             (tramp-set-connection-property v "process-buffer" buffer)
+             (with-current-buffer (tramp-get-connection-buffer v)
+               (unwind-protect
+                   ;; We catch this event.  Otherwise, `make-process'
+                   ;; could be called on the local host.
+                   (save-excursion
+                     (save-restriction
+                       ;; Activate narrowing in order to save BUFFER
+                       ;; contents.  Clear also the modification
+                       ;; time; otherwise we might be interrupted by
+                       ;; `verify-visited-file-modtime'.
+                       (let ((buffer-undo-list t)
+                             (inhibit-read-only t)
+                             (mark (point-max))
+                             (coding-system-for-write
+                              (if (symbolp coding) coding (car coding)))
+                             (coding-system-for-read
+                              (if (symbolp coding) coding (cdr coding))))
+                         (clear-visited-file-modtime)
                          (narrow-to-region (point-max) (point-max))
-                         ;; Now do it.
-                         (if command
-                             ;; Send the command.
-                             (tramp-send-command v command nil t) ; nooutput
-                           ;; Check, whether a pty is associated.
-                           (unless (process-get p 'remote-tty)
-                             (tramp-error
-                              v 'file-error
-                              "pty association is not supported for `%s'"
-                              name))))
-                       ;; Set sentinel and filter.
-                       (when sentinel
-                         (set-process-sentinel p sentinel))
-                       (when filter
-                         (set-process-filter p filter))
-                       (process-put p 'remote-command orig-command)
-                       (tramp-set-connection-property
-                        p "remote-command" orig-command)
-                       ;; Set query flag and process marker for this
-                       ;; process.  We ignore errors, because the
-                       ;; process could have finished already.
-                       (ignore-errors
-                         (set-process-query-on-exit-flag p (null noquery))
-                         (set-marker (process-mark p) (point)))
-                       ;; Kill stderr process and delete named pipe.
-                       (when (bufferp stderr)
-                         (add-function
-                          :after (process-sentinel p)
-                          (lambda (_proc _msg)
-                            (ignore-errors
-                              (while (accept-process-output
-                                      (get-buffer-process stderr) 0 nil t))
-                              (delete-process (get-buffer-process stderr)))
-                            (ignore-errors
-                              (delete-file remote-tmpstderr)))))
-                       ;; Return process.
-                       p)))
-
-               ;; Save exit.
-               (if (string-prefix-p tramp-temp-buffer-name (buffer-name))
-                   (ignore-errors
-                     (set-process-buffer p nil)
-                     (kill-buffer (current-buffer)))
-                 (set-buffer-modified-p bmp))
-               (tramp-flush-connection-property v "process-name")
-               (tramp-flush-connection-property v "process-buffer")))))))))
+                         (catch 'suppress
+                           ;; Set the pid of the remote shell.  This
+                           ;; is needed when sending signals
+                           ;; remotely.
+                           (let ((pid
+                                  (tramp-send-command-and-read v "echo $$")))
+                             (setq p (tramp-get-connection-process v))
+                             (process-put p 'remote-pid pid)
+                             (tramp-set-connection-property
+                              p "remote-pid" pid))
+                           ;; Disable carriage return to newline
+                           ;; translation.  This does not work on
+                           ;; macOS, see Bug#50748.
+                           (when (and (memq connection-type '(nil pipe))
+                                      (not
+                                       (tramp-check-remote-uname v "Darwin")))
+                             (tramp-send-command v "stty -icrnl"))
+                           ;; `tramp-maybe-open-connection' and
+                           ;; `tramp-send-command-and-read' could
+                           ;; have trashed the connection buffer.
+                           ;; Remove this.
+                           (widen)
+                           (delete-region mark (point-max))
+                           (narrow-to-region (point-max) (point-max))
+                           ;; Now do it.
+                           (if command
+                               ;; Send the command.
+                               (tramp-send-command v command nil t) ; nooutput
+                             ;; Check, whether a pty is associated.
+                             (unless (process-get p 'remote-tty)
+                               (tramp-error
+                                v 'file-error
+                                "pty association is not supported for `%s'"
+                                name))))
+                         ;; Set sentinel and filter.
+                         (when sentinel
+                           (set-process-sentinel p sentinel))
+                         (when filter
+                           (set-process-filter p filter))
+                         (process-put p 'remote-command orig-command)
+                         (tramp-set-connection-property
+                          p "remote-command" orig-command)
+                         ;; Set query flag and process marker for
+                         ;; this process.  We ignore errors, because
+                         ;; the process could have finished already.
+                         (ignore-errors
+                           (set-process-query-on-exit-flag p (null noquery))
+                           (set-marker (process-mark p) (point)))
+                         ;; We must flush them here already;
+                         ;; otherwise `delete-file' will fail.
+                         (tramp-flush-connection-property v "process-name")
+                         (tramp-flush-connection-property v "process-buffer")
+                         ;; Kill stderr process and delete named pipe.
+                         (when (bufferp stderr)
+                           (add-function
+                            :after (process-sentinel p)
+                            (lambda (_proc _msg)
+                              (ignore-errors
+                                (while (accept-process-output
+                                        (get-buffer-process stderr) 0 nil t))
+                                (delete-process (get-buffer-process stderr)))
+                              (ignore-errors
+                                (delete-file remote-tmpstderr)))))
+                         ;; Return process.
+                         p)))
+
+                 ;; Save exit.
+                 (if (string-prefix-p tramp-temp-buffer-name (buffer-name))
+                     (ignore-errors
+                       (set-process-buffer p nil)
+                       (kill-buffer (current-buffer)))
+                   (set-buffer-modified-p bmp)))))))))))
 
 (defun tramp-sh-get-signal-strings (vec)
   "Strings to return by `process-file' in case of signals."
@@ -3085,7 +3100,7 @@ implementation will be used."
       (let (signal-hook-function)
        (condition-case nil
            (dolist (sig (cdr signals))
-             (unless (string-match-p "^[[:alnum:]+-]+$" sig)
+             (unless (string-match-p (rx bol (+ (any "+-" alnum)) eol) sig)
                (error nil)))
          (error (setq signals '(0)))))
       (dotimes (i 128)
@@ -3093,7 +3108,7 @@ implementation will be used."
         (cond
          ;; Some predefined values, which aren't reported sometimes,
          ;; or would raise problems (all Stopped signals).
-         ((= i 0) 0)
+         ((zerop i) 0)
          ((string-equal (nth i signals) "HUP") "Hangup")
          ((string-equal (nth i signals) "INT") "Interrupt")
          ((string-equal (nth i signals) "QUIT") "Quit")
@@ -3116,8 +3131,9 @@ implementation will be used."
                       (tramp-shell-quote-argument (format "kill -%d $$" i))))
                     (with-current-buffer (tramp-get-connection-buffer vec)
                       (goto-char (point-min))
-                      (buffer-substring (point-at-bol) (point-at-eol)))))
-            (if (string-equal res "")
+                      (buffer-substring (line-beginning-position)
+                                        (line-end-position)))))
+            (if (string-empty-p res)
                 (format "Signal %d" i)
               res)))
         result))
@@ -3244,7 +3260,7 @@ implementation will be used."
       ;; because the remote process could have changed them.
       (when tmpinput (delete-file tmpinput))
       (when process-file-side-effects
-        (tramp-flush-directory-properties v ""))
+        (tramp-flush-directory-properties v "/"))
 
       ;; Return exit status.
       (if (equal ret -1)
@@ -3260,277 +3276,290 @@ implementation will be used."
 
 (defun tramp-sh-handle-file-local-copy (filename)
   "Like `file-local-copy' for Tramp files."
-  (with-parsed-tramp-file-name filename nil
-    (unless (file-exists-p (file-truename filename))
-      (tramp-error v 'file-missing filename))
+  (tramp-skeleton-file-local-copy filename
+    (if-let ((size (file-attribute-size (file-attributes filename))))
+       (let (rem-enc loc-dec)
 
-    (let* ((size (file-attribute-size
-                 (file-attributes (file-truename filename))))
-          (rem-enc (tramp-get-inline-coding v "remote-encoding" size))
-          (loc-dec (tramp-get-inline-coding v "local-decoding" size))
-          (tmpfile (tramp-compat-make-temp-file filename)))
+         (condition-case err
+             (cond
+              ;; Empty file.  Nothing to copy.
+              ((zerop size))
+
+              ;; `copy-file' handles direct copy and out-of-band methods.
+              ((or (tramp-local-host-p v)
+                   (tramp-method-out-of-band-p v size))
+               (copy-file filename tmpfile 'ok-if-already-exists 'keep-time))
+
+              ;; Use inline encoding for file transfer.
+              ((and (setq rem-enc
+                          (tramp-get-inline-coding v "remote-encoding" size))
+                    (setq loc-dec
+                          (tramp-get-inline-coding v "local-decoding" size)))
+               (with-tramp-progress-reporter
+                   v 3
+                   (format-message
+                    "Encoding remote file `%s' with `%s'" filename rem-enc)
+                 (tramp-barf-unless-okay
+                  v (format rem-enc (tramp-shell-quote-argument localname))
+                  "Encoding remote file failed"))
+
+               ;; Check error.  `rem-enc' could be a pipe, which
+               ;; doesn't flag the error in the first command.
+               (when (zerop (buffer-size (tramp-get-buffer v)))
+                 (tramp-error v 'file-error' "Encoding remote file failed"))
+
+               (with-tramp-progress-reporter
+                   v 3 (format-message
+                        "Decoding local file `%s' with `%s'" tmpfile loc-dec)
+                 (if (functionp loc-dec)
+                     ;; If local decoding is a function, we call it.
+                     ;; We must disable multibyte, because
+                     ;; `uudecode-decode-region' doesn't handle it
+                     ;; correctly.  Unset `file-name-handler-alist'.
+                     ;; Otherwise, epa-file gets confused.
+                     (let (file-name-handler-alist
+                           (coding-system-for-write 'binary)
+                           (default-directory
+                            tramp-compat-temporary-file-directory))
+                       (with-temp-file tmpfile
+                         (set-buffer-multibyte nil)
+                         (insert-buffer-substring (tramp-get-buffer v))
+                         (funcall loc-dec (point-min) (point-max))))
+
+                   ;; If tramp-decoding-function is not defined for
+                   ;; this method, we invoke tramp-decoding-command
+                   ;; instead.
+                   (let ((tmpfile2 (tramp-compat-make-temp-file filename)))
+                     ;; Unset `file-name-handler-alist'.  Otherwise,
+                     ;; epa-file gets confused.
+                     (let (file-name-handler-alist
+                           (coding-system-for-write 'binary))
+                       (with-current-buffer (tramp-get-buffer v)
+                         (write-region
+                          (point-min) (point-max) tmpfile2 nil 'no-message)))
+                     (unwind-protect
+                         (tramp-call-local-coding-command
+                          loc-dec tmpfile2 tmpfile)
+                       (delete-file tmpfile2)))))
+
+               ;; Set proper permissions.
+               (set-file-modes tmpfile (tramp-default-file-modes filename))
+               ;; Set local user ownership.
+               (tramp-set-file-uid-gid tmpfile))
+
+              ;; Oops, I don't know what to do.
+              (t (tramp-error
+                  v 'file-error "Wrong method specification for `%s'" method)))
 
-      (condition-case err
-         (cond
-          ;; `copy-file' handles direct copy and out-of-band methods.
-          ((or (tramp-local-host-p v)
-               (tramp-method-out-of-band-p v size))
-           (copy-file filename tmpfile 'ok-if-already-exists 'keep-time))
+           ;; Error handling.
+           ((error quit)
+            (delete-file tmpfile)
+            (signal (car err) (cdr err)))))
 
-          ;; Use inline encoding for file transfer.
-          (rem-enc
-           (with-tramp-progress-reporter
-               v 3
-               (format-message
-                "Encoding remote file `%s' with `%s'" filename rem-enc)
-             (tramp-barf-unless-okay
-              v (format rem-enc (tramp-shell-quote-argument localname))
-              "Encoding remote file failed"))
-
-           (with-tramp-progress-reporter
-               v 3 (format-message
-                    "Decoding local file `%s' with `%s'" tmpfile loc-dec)
-             (if (functionp loc-dec)
-                 ;; If local decoding is a function, we call it.  We
-                 ;; must disable multibyte, because
-                 ;; `uudecode-decode-region' doesn't handle it
-                 ;; correctly.  Unset `file-name-handler-alist'.
-                 ;; Otherwise, epa-file gets confused.
-                 (let (file-name-handler-alist
-                       (coding-system-for-write 'binary)
-                       (default-directory
-                         tramp-compat-temporary-file-directory))
-                   (with-temp-file tmpfile
-                     (set-buffer-multibyte nil)
-                     (insert-buffer-substring (tramp-get-buffer v))
-                     (funcall loc-dec (point-min) (point-max))))
-
-               ;; If tramp-decoding-function is not defined for this
-               ;; method, we invoke tramp-decoding-command instead.
-               (let ((tmpfile2 (tramp-compat-make-temp-file filename)))
-                 ;; Unset `file-name-handler-alist'.  Otherwise,
-                 ;; epa-file gets confused.
-                 (let (file-name-handler-alist
-                       (coding-system-for-write 'binary))
-                   (with-current-buffer (tramp-get-buffer v)
-                     (write-region
-                      (point-min) (point-max) tmpfile2 nil 'no-message)))
-                 (unwind-protect
-                     (tramp-call-local-coding-command
-                      loc-dec tmpfile2 tmpfile)
-                   (delete-file tmpfile2)))))
-
-           ;; Set proper permissions.
-           (set-file-modes tmpfile (tramp-default-file-modes filename))
-           ;; Set local user ownership.
-           (tramp-set-file-uid-gid tmpfile))
-
-          ;; Oops, I don't know what to do.
-          (t (tramp-error
-              v 'file-error "Wrong method specification for `%s'" method)))
-
-       ;; Error handling.
-       ((error quit)
-        (delete-file tmpfile)
-        (signal (car err) (cdr err))))
-
-      (run-hooks 'tramp-handle-file-local-copy-hook)
-      tmpfile)))
+      ;; Impossible to copy.  Trigger `file-missing' error.
+      (setq tmpfile nil))))
 
 (defun tramp-sh-handle-write-region
   (start end filename &optional append visit lockname mustbenew)
   "Like `write-region' for Tramp files."
   (tramp-skeleton-write-region start end filename append visit lockname 
mustbenew
-    (if (and (tramp-local-host-p v)
-            ;; `file-writable-p' calls `file-expand-file-name'.  We
-            ;; cannot use `tramp-run-real-handler' therefore.
-            (file-writable-p (file-name-directory localname))
-            (or (file-directory-p localname)
-                (file-writable-p localname)))
-       ;; Short track: if we are on the local host, we can run directly.
-       (let ((create-lockfiles (not file-locked)))
-         (write-region start end localname append 'no-message lockname))
-
-      (let* ((modes (tramp-default-file-modes
-                    filename (and (eq mustbenew 'excl) 'nofollow)))
-            ;; We use this to save the value of
-            ;; `last-coding-system-used' after writing the tmp file.
-            ;; At the end of the function, we set
-            ;; `last-coding-system-used' to this saved value.  This
-            ;; way, any intermediary coding systems used while
-            ;; talking to the remote shell or suchlike won't hose
-            ;; this variable.  This approach was snarfed from
-            ;; ange-ftp.el.
-            coding-system-used
-            ;; Write region into a tmp file.  This isn't really
-            ;; needed if we use an encoding function, but currently
-            ;; we use it always because this makes the logic simpler.
-            ;; We must also set `temporary-file-directory', because
-            ;; it could point to a remote directory.
-            (temporary-file-directory
-             tramp-compat-temporary-file-directory)
-            (tmpfile (or tramp-temp-buffer-file-name
-                         (tramp-compat-make-temp-file filename))))
-
-       ;; If `append' is non-nil, we copy the file locally, and let
-       ;; the native `write-region' implementation do the job.
-       (when (and append (file-exists-p filename))
-         (copy-file filename tmpfile 'ok))
-
-       ;; We say `no-message' here because we don't want the visited
-       ;; file modtime data to be clobbered from the temp file.  We
-       ;; call `set-visited-file-modtime' ourselves later on.  We
-       ;; must ensure that `file-coding-system-alist' matches
-       ;; `tmpfile'.
-       (let ((file-coding-system-alist
-              (tramp-find-file-name-coding-system-alist filename tmpfile))
-              create-lockfiles)
-         (condition-case err
-             (write-region start end tmpfile append 'no-message)
-           ((error quit)
-            (setq tramp-temp-buffer-file-name nil)
-            (delete-file tmpfile)
-            (signal (car err) (cdr err))))
-
-         ;; Now, `last-coding-system-used' has the right value.
-         ;; Remember it.
-         (setq coding-system-used last-coding-system-used))
-
-       ;; The permissions of the temporary file should be set.  If
-       ;; FILENAME does not exist (eq modes nil) it has been renamed
-       ;; to the backup file.  This case `save-buffer' handles
-       ;; permissions.  Ensure that it is still readable.
-       (when modes
-         (set-file-modes tmpfile (logior (or modes 0) #o0400)))
-
-       ;; This is a bit lengthy due to the different methods possible
-       ;; for file transfer.  First, we check whether the method uses
-       ;; an scp program.  If so, we call it.  Otherwise, both
-       ;; encoding and decoding command must be specified.  However,
-       ;; if the method _also_ specifies an encoding function, then
-       ;; that is used for encoding the contents of the tmp file.
-       (let* ((size (file-attribute-size (file-attributes tmpfile)))
-              (rem-dec (tramp-get-inline-coding v "remote-decoding" size))
-              (loc-enc (tramp-get-inline-coding v "local-encoding" size)))
-         (cond
-          ;; `copy-file' handles direct copy and out-of-band methods.
-          ((or (tramp-local-host-p v)
-               (tramp-method-out-of-band-p v size))
-           (if (and (not (stringp start))
-                    (= (or end (point-max)) (point-max))
-                    (= (or start (point-min)) (point-min))
-                    (tramp-get-method-parameter
-                     v 'tramp-copy-keep-tmpfile))
-               (progn
-                 (setq tramp-temp-buffer-file-name tmpfile)
-                 (condition-case err
-                     ;; We keep the local file for performance
-                     ;; reasons, useful for "rsync".
-                     (copy-file tmpfile filename t)
-                   ((error quit)
-                    (setq tramp-temp-buffer-file-name nil)
-                    (delete-file tmpfile)
-                    (signal (car err) (cdr err)))))
-             (setq tramp-temp-buffer-file-name nil)
-             ;; Don't rename, in order to keep context in SELinux.
+    ;; If `start' is the empty string, it is likely that a temporary
+    ;; file is created.  Do it directly.
+    (if (and (stringp start) (string-empty-p start))
+       (tramp-send-command
+        v (format "cat <%s >%s"
+                  (tramp-get-remote-null-device v)
+                  (tramp-shell-quote-argument localname)))
+
+      ;; Short track: if we are on the local host, we can run directly.
+      (if (and (tramp-local-host-p v)
+              ;; `file-writable-p' calls `file-expand-file-name'.  We
+              ;; cannot use `tramp-run-real-handler' therefore.
+              (file-writable-p (file-name-directory localname))
+              (or (file-directory-p localname)
+                  (file-writable-p localname)))
+         (let ((create-lockfiles (not file-locked)))
+           (write-region start end localname append 'no-message lockname))
+
+       (let* ((modes (tramp-default-file-modes
+                      filename (and (eq mustbenew 'excl) 'nofollow)))
+              ;; We use this to save the value of
+              ;; `last-coding-system-used' after writing the tmp
+              ;; file.  At the end of the function, we set
+              ;; `last-coding-system-used' to this saved value.  This
+              ;; way, any intermediary coding systems used while
+              ;; talking to the remote shell or suchlike won't hose
+              ;; this variable.  This approach was snarfed from
+              ;; ange-ftp.el.
+              coding-system-used
+              ;; Write region into a tmp file.  This isn't really
+              ;; needed if we use an encoding function, but currently
+              ;; we use it always because this makes the logic
+              ;; simpler.  We must also set
+              ;; `temporary-file-directory', because it could point
+              ;; to a remote directory.
+              (temporary-file-directory
+               tramp-compat-temporary-file-directory)
+              (tmpfile (or tramp-temp-buffer-file-name
+                           (tramp-compat-make-temp-file filename))))
+
+         ;; If `append' is non-nil, we copy the file locally, and let
+         ;; the native `write-region' implementation do the job.
+         (when (and append (file-exists-p filename))
+           (copy-file filename tmpfile 'ok))
+
+         ;; We say `no-message' here because we don't want the
+         ;; visited file modtime data to be clobbered from the temp
+         ;; file.  We call `set-visited-file-modtime' ourselves later
+         ;; on.  We must ensure that `file-coding-system-alist'
+         ;; matches `tmpfile'.
+         (let ((file-coding-system-alist
+                (tramp-find-file-name-coding-system-alist filename tmpfile))
+               create-lockfiles)
+           (condition-case err
+               (write-region start end tmpfile append 'no-message)
+             ((error quit)
+              (setq tramp-temp-buffer-file-name nil)
+              (delete-file tmpfile)
+              (signal (car err) (cdr err))))
+
+           ;; Now, `last-coding-system-used' has the right value.
+           ;; Remember it.
+           (setq coding-system-used last-coding-system-used))
+
+         ;; The permissions of the temporary file should be set.  If
+         ;; FILENAME does not exist (eq modes nil) it has been
+         ;; renamed to the backup file.  This case `save-buffer'
+         ;; handles permissions.  Ensure that it is still readable.
+         (when modes
+           (set-file-modes tmpfile (logior (or modes 0) #o0400)))
+
+         ;; This is a bit lengthy due to the different methods
+         ;; possible for file transfer.  First, we check whether the
+         ;; method uses an scp program.  If so, we call it.
+         ;; Otherwise, both encoding and decoding command must be
+         ;; specified.  However, if the method _also_ specifies an
+         ;; encoding function, then that is used for encoding the
+         ;; contents of the tmp file.
+         (let* ((size (file-attribute-size (file-attributes tmpfile)))
+                (rem-dec (tramp-get-inline-coding v "remote-decoding" size))
+                (loc-enc (tramp-get-inline-coding v "local-encoding" size)))
+           (cond
+            ;; `copy-file' handles direct copy and out-of-band methods.
+            ((or (tramp-local-host-p v)
+                 (tramp-method-out-of-band-p v size))
+             (if (and (not (stringp start))
+                      (= (or end (point-max)) (point-max))
+                      (= (or start (point-min)) (point-min))
+                      (tramp-get-method-parameter
+                       v 'tramp-copy-keep-tmpfile))
+                 (progn
+                   (setq tramp-temp-buffer-file-name tmpfile)
+                   (condition-case err
+                       ;; We keep the local file for performance
+                       ;; reasons, useful for "rsync".
+                       (copy-file tmpfile filename t)
+                     ((error quit)
+                      (setq tramp-temp-buffer-file-name nil)
+                      (delete-file tmpfile)
+                      (signal (car err) (cdr err)))))
+               (setq tramp-temp-buffer-file-name nil)
+               ;; Don't rename, in order to keep context in SELinux.
+               (unwind-protect
+                   (copy-file tmpfile filename t)
+                 (delete-file tmpfile))))
+
+            ;; Use inline file transfer.
+            (rem-dec
+             ;; Encode tmpfile.
              (unwind-protect
-                 (copy-file tmpfile filename t)
-               (delete-file tmpfile))))
-
-          ;; Use inline file transfer.
-          (rem-dec
-           ;; Encode tmpfile.
-           (unwind-protect
-               (with-temp-buffer
-                 (set-buffer-multibyte nil)
-                 ;; Use encoding function or command.
-                 (with-tramp-progress-reporter
-                     v 3 (format-message
-                          "Encoding local file `%s' using `%s'"
-                          tmpfile loc-enc)
-                   (if (functionp loc-enc)
-                       ;; The following `let' is a workaround for the
-                       ;; base64.el that comes with pgnus-0.84.  If
-                       ;; both of the following conditions are
-                       ;; satisfied, it tries to write to a local
-                       ;; file in default-directory, but at this
-                       ;; point, default-directory is remote.
-                       ;; (`call-process-region' can't write to
-                       ;; remote files, it seems.)  The file in
-                       ;; question is a tmp file anyway.
-                       (let ((coding-system-for-read 'binary)
-                             (default-directory
-                              tramp-compat-temporary-file-directory))
-                         (insert-file-contents-literally tmpfile)
-                         (funcall loc-enc (point-min) (point-max)))
-
-                     (unless (zerop (tramp-call-local-coding-command
-                                     loc-enc tmpfile t))
-                       (tramp-error
-                        v 'file-error
-                        (concat "Cannot write to `%s', "
-                                "local encoding command `%s' failed")
-                        filename loc-enc))))
-
-                 ;; Send buffer into remote decoding command which
-                 ;; writes to remote file.  Because this happens on
-                 ;; the remote host, we cannot use the function.
-                 (with-tramp-progress-reporter
-                     v 3 (format-message
-                          "Decoding remote file `%s' using `%s'"
-                          filename rem-dec)
-                   (goto-char (point-max))
-                   (unless (bolp) (newline))
-                   (tramp-send-command
-                    v
-                    (format
-                     (concat rem-dec " <<'%s'\n%s%s")
-                     (tramp-shell-quote-argument localname)
-                     tramp-end-of-heredoc
-                     (buffer-string)
-                     tramp-end-of-heredoc))
-                   (tramp-barf-unless-okay
-                    v nil
-                    "Couldn't write region to `%s', decode using `%s' failed"
-                    filename rem-dec)
-                   ;; When `file-precious-flag' is set, the region is
-                   ;; written to a temporary file.  Check that the
-                   ;; checksum is equal to that from the local tmpfile.
-                   (when file-precious-flag
-                     (erase-buffer)
-                     (and
-                      ;; cksum runs locally, if possible.
-                      (zerop (tramp-call-process v "cksum" tmpfile t))
-                      ;; cksum runs remotely.
-                      (tramp-send-command-and-check
-                       v
-                       (format
-                        "cksum <%s"
-                        (tramp-shell-quote-argument localname)))
-                      ;; ... they are different.
-                      (not
-                       (string-equal
-                        (buffer-string)
-                        (tramp-get-buffer-string (tramp-get-buffer v))))
-                      (tramp-error
-                       v 'file-error
-                       "Couldn't write region to `%s', decode using `%s' 
failed"
-                       filename rem-dec)))))
-
-             ;; Save exit.
-             (delete-file tmpfile)))
-
-          ;; That's not expected.
-          (t
-           (tramp-error
-            v 'file-error
-            (concat "Method `%s' should specify both encoding and "
-                    "decoding command or an scp program")
-            method))))
+                 (with-temp-buffer
+                   (set-buffer-multibyte nil)
+                   ;; Use encoding function or command.
+                   (with-tramp-progress-reporter
+                       v 3 (format-message
+                            "Encoding local file `%s' using `%s'"
+                            tmpfile loc-enc)
+                     (if (functionp loc-enc)
+                         ;; The following `let' is a workaround for
+                         ;; the base64.el that comes with pgnus-0.84.
+                         ;; If both of the following conditions are
+                         ;; satisfied, it tries to write to a local
+                         ;; file in default-directory, but at this
+                         ;; point, default-directory is remote.
+                         ;; (`call-process-region' can't write to
+                         ;; remote files, it seems.)  The file in
+                         ;; question is a tmp file anyway.
+                         (let ((coding-system-for-read 'binary)
+                               (default-directory
+                                tramp-compat-temporary-file-directory))
+                           (insert-file-contents-literally tmpfile)
+                           (funcall loc-enc (point-min) (point-max)))
+
+                       (unless (zerop (tramp-call-local-coding-command
+                                       loc-enc tmpfile t))
+                         (tramp-error
+                          v 'file-error
+                          (concat "Cannot write to `%s', "
+                                  "local encoding command `%s' failed")
+                          filename loc-enc))))
+
+                   ;; Send buffer into remote decoding command which
+                   ;; writes to remote file.  Because this happens on
+                   ;; the remote host, we cannot use the function.
+                   (with-tramp-progress-reporter
+                       v 3 (format-message
+                            "Decoding remote file `%s' using `%s'"
+                            filename rem-dec)
+                     (goto-char (point-max))
+                     (unless (bolp) (newline))
+                     (tramp-barf-unless-okay
+                      v  (format
+                          (concat rem-dec " <<'%s'\n%s%s")
+                          (tramp-shell-quote-argument localname)
+                          tramp-end-of-heredoc
+                          (buffer-string)
+                          tramp-end-of-heredoc)
+                      "Couldn't write region to `%s', decode using `%s' failed"
+                      filename rem-dec)
+                     ;; When `file-precious-flag' is set, the region
+                     ;; is written to a temporary file.  Check that
+                     ;; the checksum is equal to that from the local
+                     ;; tmpfile.
+                     (when file-precious-flag
+                       (erase-buffer)
+                       (and
+                        ;; cksum runs locally, if possible.
+                        (zerop (tramp-call-process v "cksum" tmpfile t))
+                        ;; cksum runs remotely.
+                        (tramp-send-command-and-check
+                         v (format
+                            "cksum <%s" (tramp-shell-quote-argument 
localname)))
+                        ;; ... they are different.
+                        (not
+                         (string-equal
+                          (buffer-string)
+                          (tramp-get-buffer-string (tramp-get-buffer v))))
+                        (tramp-error
+                         v 'file-error
+                         (concat "Couldn't write region to `%s',"
+                                 " decode using `%s' failed")
+                         filename rem-dec)))))
 
-       ;; Make `last-coding-system-used' have the right value.
-       (when coding-system-used
-         (setq last-coding-system-used coding-system-used))))))
+               ;; Save exit.
+               (delete-file tmpfile)))
+
+            ;; That's not expected.
+            (t
+             (tramp-error
+              v 'file-error
+              (concat "Method `%s' should specify both encoding and "
+                      "decoding command or an scp program")
+              method))))
+
+         ;; Make `last-coding-system-used' have the right value.
+         (when coding-system-used
+           (setq last-coding-system-used coding-system-used)))))))
 
 (defvar tramp-vc-registered-file-names nil
   "List used to collect file names, which are checked during `vc-registered'.")
@@ -3788,8 +3817,8 @@ Fall back to normal file name handler if no Tramp handler 
exists."
 
     (catch 'doesnt-work
       ;; https://bugs.launchpad.net/bugs/1742946
-      (when
-          (string-match-p "Monitoring not supported\\|No locations given" 
string)
+      (when (string-match-p
+            (rx (| "Monitoring not supported" "No locations given")) string)
         (delete-process proc)
         (throw 'doesnt-work nil))
 
@@ -3805,12 +3834,13 @@ Fall back to normal file name handler if no Tramp 
handler exists."
           (setq pos (match-end 0))
            (cond
             ((getenv "EMACS_EMBA_CI") 'GInotifyFileMonitor)
-            ((eq system-type 'cygwin) 'GPollFileMonitor)
-            (t nil)))
+            ((eq system-type 'cygwin) 'GPollFileMonitor)))
           ;; TODO: What happens, if several monitor names are reported?
-          ((string-match "\
-Supported arguments for GIO_USE_FILE_MONITOR environment variable:
-\\s-*\\([[:alpha:]]+\\) - 20" string)
+          ((string-match
+           (rx "Supported arguments for "
+               "GIO_USE_FILE_MONITOR environment variable:\n"
+               (* space) (group (+ alpha)) " - 20")
+           string)
           (setq pos (match-end 0))
            (intern
            (format "G%sFileMonitor" (capitalize (match-string 1 string)))))
@@ -3821,15 +3851,14 @@ Supported arguments for GIO_USE_FILE_MONITOR 
environment variable:
       (setq string (tramp-compat-string-replace "\n\n" "\n" string))
 
       (while (string-match
-             (eval-when-compile
-               (concat "^[^:]+:"
-                       "[[:space:]]\\([^:]+\\):"
-                       "[[:space:]]" (regexp-opt tramp-gio-events t)
-                       "\\([[:space:]]\\([^:]+\\)\\)?$"))
+             (rx bol (+ (not (any ":"))) ":" space
+                 (group (+ (not (any ":")))) ":" space
+                 (group (regexp (regexp-opt tramp-gio-events)))
+                 (? space (group (+ (not (any ":"))))) eol)
              string)
 
         (let* ((file (match-string 1 string))
-              (file1 (match-string 4 string))
+              (file1 (match-string 3 string))
               (object
                (list
                 proc
@@ -3849,7 +3878,7 @@ Supported arguments for GIO_USE_FILE_MONITOR environment 
variable:
             `(file-notify ,object file-notify-callback))))))
 
     ;; Save rest of the string.
-    (while (string-match "^\n" string)
+    (while (string-match (rx bol "\n") string)
       (setq string (replace-match "" nil nil string)))
     (when (zerop (length string)) (setq string nil))
     (when string (tramp-message proc 10 "Rest string:\n%s" string))
@@ -3862,9 +3891,8 @@ Supported arguments for GIO_USE_FILE_MONITOR environment 
variable:
     (dolist (line (split-string string "[\n\r]+" 'omit))
       ;; Check, whether there is a problem.
       (unless (string-match
-              (concat "^[^[:blank:]]+"
-                      "[[:blank:]]+\\([^[:blank:]]+\\)"
-                      "\\([[:blank:]]+\\([^\n\r]+\\)\\)?")
+              (rx bol (+ (not blank)) (+ blank) (group (+ (not blank)))
+                  (? (+ blank) (group (+ (not (any "\r\n"))))))
               line)
        (tramp-error proc 'file-notify-error line))
 
@@ -3876,7 +3904,7 @@ Supported arguments for GIO_USE_FILE_MONITOR environment 
variable:
                 (intern-soft
                  (tramp-compat-string-replace "_" "-" (downcase x))))
               (split-string (match-string 1 line) "," 'omit))
-             (or (match-string 3 line)
+             (or (match-string 2 line)
                  (file-name-nondirectory (process-get proc 'watch-name))))))
        ;; Usually, we would add an Emacs event now.  Unfortunately,
        ;; `unread-command-events' does not accept several events at
@@ -3900,10 +3928,10 @@ Supported arguments for GIO_USE_FILE_MONITOR 
environment variable:
          (goto-char (point-min))
          (forward-line)
          (when (looking-at
-                (concat "\\(?:^/[^[:space:]]*[[:space:]]\\)?"
-                        "[[:space:]]*\\([[:digit:]]+\\)"
-                        "[[:space:]]+\\([[:digit:]]+\\)"
-                        "[[:space:]]+\\([[:digit:]]+\\)"))
+                (rx (? bol "/" (* (not space)) space) (* space)
+                    (group (+ digit)) (+ space)
+                    (group (+ digit)) (+ space)
+                    (group (+ digit))))
            (mapcar
             (lambda (d)
               (* d (tramp-get-connection-property v "df-blocksize" 0)))
@@ -3918,40 +3946,58 @@ Supported arguments for GIO_USE_FILE_MONITOR 
environment variable:
 
 (defun tramp-expand-script (vec script)
   "Expand SCRIPT with remote files or commands.
-\"%a\", \"%h\", \"%o\" and \"%p\" format specifiers are replaced
-by the respective `awk', `hexdump', `od' and `perl' commands.
-\"%n\" is replaced by \"2>/dev/null\", and \"%t\" is replaced by
-a temporary file name.
-If VEC is nil, the respective local commands are used.
-If there is a format specifier which cannot be expanded, this
+\"%a\", \"%h\", \"%l\", \"%o\", \"%p\", \"%r\" and \"%s\" format
+specifiers are replaced by the respective `awk', `hexdump', `ls',
+`od', `perl', `readlink' and `stat' commands.  \"%n\" is replaced
+by \"2>/dev/null\", and \"%t\" is replaced by a temporary file
+name.  If VEC is nil, the respective local commands are used.  If
+there is a format specifier which cannot be expanded, this
 function returns nil."
-  (if (not (string-match-p "\\(^\\|[^%]\\)%[ahnopt]" script))
+  (if (not (string-match-p
+           (rx (| bol (not (any "%"))) "%" (any "ahlnoprst")) script))
       script
     (catch 'wont-work
-      (let ((awk (when (string-match-p "\\(^\\|[^%]\\)%a" script)
+      (let ((awk (when (string-match-p (rx (| bol (not (any "%"))) "%a") 
script)
                   (or
                    (if vec (tramp-get-remote-awk vec) (executable-find "awk"))
                    (throw 'wont-work nil))))
-           (hdmp (when (string-match-p "\\(^\\|[^%]\\)%h" script)
+           (hdmp (when (string-match-p (rx (| bol (not (any "%"))) "%h") 
script)
                    (or
                     (if vec (tramp-get-remote-hexdump vec)
                       (executable-find "hexdump"))
                     (throw 'wont-work nil))))
-           (dev (when (string-match-p "\\(^\\|[^%]\\)%n" script)
+           (dev (when (string-match-p (rx (| bol (not (any "%"))) "%n") script)
                   (or
                    (if vec (concat "2>" (tramp-get-remote-null-device vec))
                      (if (eq system-type 'windows-nt) ""
                        (concat "2>" null-device)))
                    (throw 'wont-work nil))))
-           (od (when (string-match-p "\\(^\\|[^%]\\)%o" script)
+           (ls (when (string-match-p (rx (| bol (not (any "%"))) "%l") script)
+                 (format "%s %s"
+                         (or (tramp-get-ls-command vec)
+                             (throw 'wont-work nil))
+                         (tramp-sh--quoting-style-options vec))))
+           (od (when (string-match-p (rx (| bol (not (any "%"))) "%o") script)
                  (or (if vec (tramp-get-remote-od vec) (executable-find "od"))
                      (throw 'wont-work nil))))
-           (perl (when (string-match-p "\\(^\\|[^%]\\)%p" script)
+           (perl (when (string-match-p (rx (| bol (not (any "%"))) "%p") 
script)
                    (or
                     (if vec
                         (tramp-get-remote-perl vec) (executable-find "perl"))
                     (throw 'wont-work nil))))
-           (tmp (when (string-match-p "\\(^\\|[^%]\\)%t" script)
+           (readlink (when (string-match-p
+                            (rx (| bol (not (any "%"))) "%r") script)
+                       (or
+                        (if vec
+                        (tramp-get-remote-readlink vec)
+                      (executable-find "readlink"))
+                    (throw 'wont-work nil))))
+           (stat (when (string-match-p (rx (| bol (not (any "%"))) "%s") 
script)
+                   (or
+                    (if vec
+                        (tramp-get-remote-stat vec) (executable-find "stat"))
+                    (throw 'wont-work nil))))
+           (tmp (when (string-match-p (rx (| bol (not (any "%"))) "%t") script)
                   (or
                    (if vec
                        (tramp-file-local-name (tramp-make-tramp-temp-name vec))
@@ -3959,7 +4005,9 @@ function returns nil."
                    (throw 'wont-work nil)))))
        (format-spec
         script
-        (format-spec-make ?a awk ?h hdmp ?n dev ?o od ?p perl ?t tmp))))))
+        (format-spec-make
+         ?a awk ?h hdmp ?l ls ?n dev ?o od ?p perl
+         ?r readlink ?s stat ?t tmp))))))
 
 (defun tramp-maybe-send-script (vec script name)
   "Define in remote shell function NAME implemented as SCRIPT.
@@ -3967,7 +4015,7 @@ Only send the definition if it has not already been done."
   ;; We cannot let-bind (tramp-get-connection-process vec) because it
   ;; might be nil.
   (let ((scripts (tramp-get-connection-property
-                 (tramp-get-connection-process vec) "scripts" nil)))
+                 (tramp-get-connection-process vec) "scripts")))
     (unless (member name scripts)
       (with-tramp-progress-reporter
          vec 5 (format-message "Sending script `%s'" name)
@@ -4022,7 +4070,7 @@ This function expects to be in the right *tramp* buffer."
       (unless (or ignore-path (tramp-check-remote-uname vec 
tramp-sunos-unames))
        (tramp-send-command vec (format "which \\%s | wc -w" progname))
        (goto-char (point-min))
-       (if (looking-at-p "^\\s-*1$")
+       (if (looking-at-p (rx bol (* space) "1" eol))
            (setq result (concat "\\" progname))))
       (unless result
        (when ignore-tilde
@@ -4049,7 +4097,7 @@ This function expects to be in the right *tramp* buffer."
        (when (search-backward "tramp_executable " nil t)
          (skip-chars-forward "^ ")
          (skip-chars-forward " ")
-         (setq result (buffer-substring (point) (point-at-eol)))))
+         (setq result (buffer-substring (point) (line-end-position)))))
     result)))
 
 ;; On hydra.nixos.org, the $PATH environment variable is too long to
@@ -4062,7 +4110,8 @@ whether it exists and if so, it is added to the 
environment
 variable PATH."
   (let ((command
         (format
-         "PATH=%s && export PATH" (string-join (tramp-get-remote-path vec) 
":")))
+         "PATH=%s && export PATH"
+         (string-join (tramp-get-remote-path vec) ":")))
        (pipe-buf
         (with-tramp-connection-property vec "pipe-buf"
           (tramp-send-command-and-read
@@ -4175,19 +4224,23 @@ file exists and nonzero exit status otherwise."
     ;; by some sh implementations (eg, bash when called as sh) on
     ;; startup; this way, we avoid the startup file clobbering $PS1.
     ;; $PROMPT_COMMAND is another way to set the prompt in /bin/bash,
-    ;; it must be discarded as well.  $HISTFILE is set according to
-    ;; `tramp-histfile-override'.  $TERM and $INSIDE_EMACS set here to
-    ;; ensure they have the correct values when the shell starts, not
-    ;; just processes run within the shell.  (Which processes include
-    ;; our initial probes to ensure the remote shell is usable.)
-    ;; For the time being, we assume that all shells interpret -i as
-    ;; interactive shell.  Must be the last argument, because (for
-    ;; example) bash expects long options first.
+    ;; it must be discarded as well.  Some ssh daemons (for example,
+    ;; on Android devices) do not acknowledge the $PS1 setting in
+    ;; that call, so we make a further sanity check.  (Bug#57044)
+    ;; $HISTFILE is set according to `tramp-histfile-override'.  $TERM
+    ;; and $INSIDE_EMACS set here to ensure they have the correct
+    ;; values when the shell starts, not just processes run within the
+    ;; shell.  (Which processes include our initial probes to ensure
+    ;; the remote shell is usable.)  For the time being, we assume
+    ;; that all shells interpret -i as interactive shell.  Must be the
+    ;; last argument, because (for example) bash expects long options
+    ;; first.
     (tramp-send-command
      vec (format
-         (concat
-          "exec env TERM='%s' INSIDE_EMACS='%s' "
-          "ENV=%s %s PROMPT_COMMAND='' PS1=%s PS2='' PS3='' %s %s -i")
+         (eval-when-compile
+           (concat
+            "exec env TERM='%s' INSIDE_EMACS='%s' "
+            "ENV=%s %s PROMPT_COMMAND='' PS1=%s PS2='' PS3='' %s %s -i"))
           tramp-terminal-type (tramp-inside-emacs)
           (or (getenv-internal "ENV" tramp-remote-process-environment) "")
          (if (stringp tramp-histfile-override)
@@ -4198,7 +4251,26 @@ file exists and nonzero exit status otherwise."
              ""))
          (tramp-shell-quote-argument tramp-end-of-output)
          shell (or (tramp-get-sh-extra-args shell) ""))
-     t)
+     t t)
+
+    ;; Sanity check.
+    (tramp-barf-if-no-shell-prompt
+     (tramp-get-connection-process vec) 60
+     "Couldn't find remote shell prompt for %s" shell)
+    (unless
+       (tramp-check-for-regexp
+        (tramp-get-connection-process vec) (rx (literal tramp-end-of-output)))
+      (tramp-wait-for-output (tramp-get-connection-process vec))
+      (tramp-message vec 5 "Setting shell prompt")
+      (tramp-send-command
+       vec (format "PS1=%s PS2='' PS3='' PROMPT_COMMAND=''"
+                  (tramp-shell-quote-argument tramp-end-of-output))
+       t t)
+      (tramp-barf-if-no-shell-prompt
+       (tramp-get-connection-process vec) 60
+       "Couldn't find remote shell prompt for %s" shell))
+    (tramp-wait-for-output (tramp-get-connection-process vec))
+
     ;; Check proper HISTFILE setting.  We give up when not working.
     (when (and (stringp tramp-histfile-override)
               (file-name-directory tramp-histfile-override))
@@ -4217,7 +4289,7 @@ file exists and nonzero exit status otherwise."
 (defun tramp-find-shell (vec)
   "Open a shell on the remote host which groks tilde expansion."
   ;; If we are in `make-process', we don't need another shell.
-  (unless (tramp-get-connection-property vec "process-name" nil)
+  (unless (tramp-get-connection-property vec "process-name")
     (with-current-buffer (tramp-get-buffer vec)
       (let ((default-shell (tramp-get-method-parameter vec 
'tramp-remote-shell))
            shell)
@@ -4225,8 +4297,11 @@ file exists and nonzero exit status otherwise."
              (with-tramp-connection-property vec "remote-shell"
                ;; CCC: "root" does not exist always, see my QNAP
                ;; TS-459.  Which check could we apply instead?
-               (tramp-send-command vec "echo ~root" t)
-               (if (or (string-match-p "^~root$" (buffer-string))
+               (tramp-send-command
+                vec (format "echo ~%s" tramp-root-id-string) t)
+               (if (or (string-match-p
+                        (rx bol "~" (literal tramp-root-id-string) eol)
+                        (buffer-string))
                        ;; The default shell (ksh93) of OpenSolaris
                        ;; and Solaris is buggy.  We've got reports
                        ;; for "SunOS 5.10" and "SunOS 5.11" so far.
@@ -4241,9 +4316,10 @@ file exists and nonzero exit status otherwise."
                            default-shell
                          (tramp-message
                           vec 2
-                          (concat
-                           "Couldn't find a remote shell which groks tilde "
-                           "expansion, using `%s'")
+                          (eval-when-compile
+                            (concat
+                             "Couldn't find a remote shell which groks tilde "
+                             "expansion, using `%s'"))
                           default-shell)))
 
                  default-shell)))
@@ -4264,8 +4340,9 @@ seconds.  If not, it produces an error message with the 
given ERROR-ARGS."
     (condition-case nil
        (tramp-wait-for-regexp
         proc timeout
-        (format
-         "\\(%s\\|%s\\)\\'" shell-prompt-pattern tramp-shell-prompt-pattern))
+        (rx (| (regexp shell-prompt-pattern)
+               (regexp tramp-shell-prompt-pattern))
+            eos))
       (error
        (delete-process proc)
        (apply #'tramp-error-with-buffer
@@ -4275,8 +4352,7 @@ seconds.  If not, it produces an error message with the 
given ERROR-ARGS."
   "Set up an interactive shell.
 Mainly sets the prompt and the echo correctly.  PROC is the shell
 process to set up.  VEC specifies the connection."
-  (let ((tramp-end-of-output tramp-initial-end-of-output)
-       (case-fold-search t))
+  (let ((case-fold-search t))
     (tramp-open-shell vec (tramp-get-method-parameter vec 'tramp-remote-shell))
     (tramp-message vec 5 "Setting up remote shell environment")
 
@@ -4303,22 +4379,15 @@ process to set up.  VEC specifies the connection."
        ;; width magic interferes with them.
        (tramp-send-command vec "stty icanon erase ^H cols 32767" t))))
 
-  (tramp-message vec 5 "Setting shell prompt")
-  (tramp-send-command
-   vec (format "PS1=%s PS2='' PS3='' PROMPT_COMMAND=''"
-              (tramp-shell-quote-argument tramp-end-of-output))
-   t)
-
   ;; Check whether the output of "uname -sr" has been changed.  If
   ;; yes, this is a strong indication that we must expire all
   ;; connection properties.  We start again with
   ;; `tramp-maybe-open-connection', it will be caught there.
   (tramp-message vec 5 "Checking system information")
-  (let* ((old-uname (tramp-get-connection-property vec "uname" nil))
+  (let* ((old-uname (tramp-get-connection-property vec "uname"))
         (uname
          ;; If we are in `make-process', we don't need to recompute.
-         (if (and old-uname
-                  (tramp-get-connection-property vec "process-name" nil))
+         (if (and old-uname (tramp-get-connection-property vec "process-name"))
              old-uname
            (tramp-set-connection-property
             vec "uname"
@@ -4342,7 +4411,8 @@ process to set up.  VEC specifies the connection."
                         (string-prefix-p "Darwin" uname)
                         (cons 'utf-8-hfs 'utf-8-hfs))
                    (and (memq 'utf-8 (coding-system-list))
-                        (string-match-p "utf-?8" (tramp-get-remote-locale vec))
+                        (string-match-p
+                         (rx "utf" (? "-") "8") (tramp-get-remote-locale vec))
                         (cons 'utf-8 'utf-8))
                    (process-coding-system proc)
                    (cons 'undecided 'undecided)))
@@ -4374,7 +4444,7 @@ process to set up.  VEC specifies the connection."
        (t
        (tramp-message
         vec 5 "Checking remote host type for `send-process-string' bug")
-       (if (string-match-p "FreeBSD\\|DragonFly" uname) 500 0))))
+       (if (string-match-p (rx (| "FreeBSD" "DragonFly")) uname) 500 0))))
 
     ;; Set remote PATH variable.
     (tramp-set-remote-path vec)
@@ -4406,7 +4476,7 @@ process to set up.  VEC specifies the connection."
       (tramp-send-command vec "set +H" t))
 
     ;; Disable tab expansion.
-    (if (string-match-p "BSD\\|DragonFly\\|Darwin" uname)
+    (if (string-match-p (rx (| "BSD" "DragonFly" "Darwin")) uname)
        (tramp-send-command vec "stty tabs" t)
       (tramp-send-command vec "stty tab0" t))
 
@@ -4434,7 +4504,7 @@ process to set up.  VEC specifies the connection."
                             (copy-sequence tramp-remote-process-environment))))
        (setq item (split-string item "=" 'omit))
        (setcdr item (string-join (cdr item) "="))
-       (if (and (stringp (cdr item)) (not (string-equal (cdr item) "")))
+       (if (and (stringp (cdr item)) (not (string-empty-p (cdr item))))
            (push (format "%s %s" (car item) (cdr item)) vars)
          (push (car item) unset)))
       (when vars
@@ -4632,7 +4702,7 @@ Goes through the list `tramp-local-coding-commands' and
 
                  (with-current-buffer (tramp-get-connection-buffer vec)
                    (goto-char (point-min))
-                   (unless (looking-at-p (regexp-quote magic))
+                   (unless (looking-at-p (rx (literal magic)))
                      (throw 'wont-work-remote nil)))
 
                  ;; `rem-enc' and `rem-dec' could be a string meanwhile.
@@ -4718,7 +4788,7 @@ Goes through the list `tramp-inline-compress-commands'."
                      nil t))
               (throw 'next nil))
            (goto-char (point-min))
-           (unless (looking-at-p (regexp-quote magic))
+           (unless (looking-at-p (rx (literal magic)))
              (throw 'next nil)))
           (tramp-message
           vec 5
@@ -4729,7 +4799,7 @@ Goes through the list `tramp-inline-compress-commands'."
            (throw 'next nil))
          (with-current-buffer (tramp-get-buffer vec)
            (goto-char (point-min))
-           (unless (looking-at-p (regexp-quote magic))
+           (unless (looking-at-p (rx (literal magic)))
              (throw 'next nil)))
          (setq found t)))
 
@@ -4818,7 +4888,7 @@ Goes through the list `tramp-inline-compress-commands'."
                (goto-char (point-min))
                (unless
                     (search-forward-regexp
-                     "\\(illegal\\|unknown\\) option -- T" nil t)
+                     (rx (| "illegal" "unknown") " option -- T") nil t)
                  (setq tramp-scp-strict-file-name-checking "-T")))))))
       tramp-scp-strict-file-name-checking)))
 
@@ -4845,7 +4915,7 @@ Goes through the list `tramp-inline-compress-commands'."
                (goto-char (point-min))
                (unless
                     (search-forward-regexp
-                     "\\(illegal\\|unknown\\) option -- O" nil t)
+                     (rx (| "illegal" "unknown") " option -- O") nil t)
                  (setq tramp-scp-force-scp-protocol "-O")))))))
       tramp-scp-force-scp-protocol)))
 
@@ -4868,7 +4938,7 @@ Goes through the list `tramp-inline-compress-commands'."
             (tramp-call-process vec1 "scp" nil t nil "-R")
             (goto-char (point-min))
             (not (search-forward-regexp
-                  "\\(illegal\\|unknown\\) option -- R" nil 'noerror)))))
+                  (rx (| "illegal" "unknown") " option -- R") nil 'noerror)))))
 
        ;; Check, that RemoteCommand is not used.
        (with-tramp-connection-property
@@ -4909,7 +4979,10 @@ Goes through the list `tramp-inline-compress-commands'."
                      (line-beginning-position) (line-end-position))
                     string
                     (and
-                     (string-match "^[^# ]+ \\S-+ \\(\\S-+\\)$" string)
+                     (string-match
+                      (rx bol (+ (not (any " #"))) " " (+ (not space)) " "
+                          (group (+ (not space))) eol)
+                      string)
                      (match-string 1 string))
                     found
                     (and string
@@ -4926,7 +4999,7 @@ Goes through the list `tramp-inline-compress-commands'."
   "Close the connection VEC after a session timeout.
 If there is just some editing, retry it after 5 seconds."
   (if (and (tramp-get-connection-property
-           (tramp-get-connection-process vec) "locked" nil)
+           (tramp-get-connection-process vec) "locked")
           (tramp-file-name-equal-p vec (car tramp-current-connection)))
       (progn
        (tramp-message
@@ -4945,7 +5018,7 @@ connection if a previous connection has died for some 
reason."
     (throw 'non-essential 'non-essential))
 
   (let ((p (tramp-get-connection-process vec))
-       (process-name (tramp-get-connection-property vec "process-name" nil))
+       (process-name (tramp-get-connection-property vec "process-name"))
        (process-environment (copy-sequence process-environment))
        (pos (with-current-buffer (tramp-get-connection-buffer vec) (point))))
 
@@ -5159,9 +5232,9 @@ connection if a previous connection has died for some 
reason."
                          previous-hop hop)))
 
                ;; Activate session timeout.
-               (when (tramp-get-connection-property p "session-timeout" nil)
+               (when (tramp-get-connection-property p "session-timeout")
                  (run-at-time
-                  (tramp-get-connection-property p "session-timeout" nil) nil
+                  (tramp-get-connection-property p "session-timeout") nil
                   #'tramp-timeout-session vec))
 
                ;; Make initial shell settings.
@@ -5183,7 +5256,7 @@ is meant to be used from `tramp-maybe-open-connection' 
only.  The
 function waits for output unless NOOUTPUT is set."
   (unless neveropen (tramp-maybe-open-connection vec))
   (let ((p (tramp-get-connection-process vec)))
-    (when (tramp-get-connection-property p "remote-echo" nil)
+    (when (tramp-get-connection-property p "remote-echo")
       ;; We mark the command string that it can be erased in the output buffer.
       (tramp-set-connection-property p "check-remote-echo" t)
       ;; If we put `tramp-echo-mark' after a trailing newline (which
@@ -5214,20 +5287,22 @@ function waits for output unless NOOUTPUT is set."
           ;; Busyboxes built with the EDITING_ASK_TERMINAL config
           ;; option send also escape sequences, which must be
           ;; ignored.
-          (regexp (format "[^#$\n]*%s\\(%s\\)?\r?$"
-                          (regexp-quote tramp-end-of-output)
-                          tramp-device-escape-sequence-regexp))
+          (regexp (rx (* (not (any "#$\n")))
+                      (literal tramp-end-of-output)
+                      (? (regexp tramp-device-escape-sequence-regexp))
+                      (? "\r") eol))
           ;; Sometimes, the commands do not return a newline but a
           ;; null byte before the shell prompt, for example "git
           ;; ls-files -c -z ...".
-          (regexp1 (format "\\(^\\|\000\\)%s" regexp))
+          (regexp1 (rx (| bol "\000") (regexp regexp)))
           (found (tramp-wait-for-regexp proc timeout regexp1)))
       (if found
          (let ((inhibit-read-only t))
            ;; A simple-minded busybox has sent " ^H" sequences.
            ;; Delete them.
            (goto-char (point-min))
-           (when (re-search-forward "^\\(.\b\\)+$" (point-at-eol) t)
+           (when (re-search-forward
+                  (rx bol (+ nonl "\b") eol) (line-end-position) t)
              (forward-line 1)
              (delete-region (point-min) (point)))
            ;; Delete the prompt.
@@ -5256,18 +5331,27 @@ executed in a subshell, ie surrounded by parentheses.  
If
 DONT-SUPPRESS-ERR is non-nil, stderr won't be sent to \"/dev/null\".
 Optional argument EXIT-STATUS, if non-nil, triggers the return of
 the exit status."
-  (tramp-send-command
-   vec
-   (concat (if subshell "( " "")
-          command
-          (if command
-               (if dont-suppress-err
-                   "; " (format " 2>%s; " (tramp-get-remote-null-device vec)))
-             "")
-          "echo tramp_exit_status $?"
-          (if subshell " )" "")))
+  (let (cmd data)
+    (if (and (stringp command)
+            (string-match
+             (rx (* nonl) "<<'" (literal tramp-end-of-heredoc) "'" (* nonl))
+             command))
+       (setq cmd (match-string 0 command)
+             data (substring command (match-end 0)))
+      (setq cmd command))
+    (tramp-send-command
+     vec
+     (concat (if subshell "( " "")
+            cmd
+            (if cmd
+                (if dont-suppress-err
+                     "; " (format " 2>%s; " (tramp-get-remote-null-device 
vec)))
+               "")
+            "echo tramp_exit_status $?"
+            (if subshell " )" "")
+            data)))
   (with-current-buffer (tramp-get-connection-buffer vec)
-    (unless (tramp-search-regexp "tramp_exit_status [[:digit:]]+")
+    (unless (tramp-search-regexp (rx "tramp_exit_status " (+ digit)))
       (tramp-error
        vec 'file-error "Couldn't find exit status of `%s'" command))
     (skip-chars-forward "^ ")
@@ -5312,7 +5396,7 @@ raises an error."
                     (unless noerror signal-hook-function)))
                (read (current-buffer)))
            ;; Error handling.
-           (when (re-search-forward "\\S-" (point-at-eol) t)
+           (when (re-search-forward (rx (not space)) (line-end-position) t)
              (error nil)))
        (error (unless noerror
                 (tramp-error
@@ -5320,94 +5404,6 @@ raises an error."
                  "`%s' does not return a valid Lisp expression: `%s'"
                  command (buffer-string))))))))
 
-;; FIXME: Move to tramp.el?
-;;;###tramp-autoload
-(defun tramp-convert-file-attributes (vec attr)
-  "Convert `file-attributes' ATTR generated by perl script, stat or ls.
-Convert file mode bits to string and set virtual device number.
-Return ATTR."
-  (when attr
-    (save-match-data
-      ;; Remove color escape sequences from symlink.
-      (when (stringp (car attr))
-       (while (string-match tramp-display-escape-sequence-regexp (car attr))
-         (setcar attr (replace-match "" nil nil (car attr)))))
-      ;; Convert uid and gid.  Use `tramp-unknown-id-integer' as
-      ;; indication of unusable value.
-      (when (and (numberp (nth 2 attr)) (< (nth 2 attr) 0))
-       (setcar (nthcdr 2 attr) tramp-unknown-id-integer))
-      (when (and (floatp (nth 2 attr))
-                (<= (nth 2 attr) most-positive-fixnum))
-       (setcar (nthcdr 2 attr) (round (nth 2 attr))))
-      (when (and (numberp (nth 3 attr)) (< (nth 3 attr) 0))
-       (setcar (nthcdr 3 attr) tramp-unknown-id-integer))
-      (when (and (floatp (nth 3 attr))
-                (<= (nth 3 attr) most-positive-fixnum))
-       (setcar (nthcdr 3 attr) (round (nth 3 attr))))
-      ;; Convert last access time.
-      (unless (listp (nth 4 attr))
-       (setcar (nthcdr 4 attr) (seconds-to-time (nth 4 attr))))
-      ;; Convert last modification time.
-      (unless (listp (nth 5 attr))
-       (setcar (nthcdr 5 attr) (seconds-to-time (nth 5 attr))))
-      ;; Convert last status change time.
-      (unless (listp (nth 6 attr))
-       (setcar (nthcdr 6 attr) (seconds-to-time (nth 6 attr))))
-      ;; Convert file size.
-      (when (< (nth 7 attr) 0)
-       (setcar (nthcdr 7 attr) -1))
-      (when (and (floatp (nth 7 attr))
-                (<= (nth 7 attr) most-positive-fixnum))
-       (setcar (nthcdr 7 attr) (round (nth 7 attr))))
-      ;; Convert file mode bits to string.
-      (unless (stringp (nth 8 attr))
-       (setcar (nthcdr 8 attr) (tramp-file-mode-from-int (nth 8 attr)))
-       (when (stringp (car attr))
-          (aset (nth 8 attr) 0 ?l)))
-      ;; Convert directory indication bit.
-      (when (string-prefix-p "d" (nth 8 attr))
-       (setcar attr t))
-      ;; Convert symlink from `tramp-do-file-attributes-with-stat'.
-      ;; Decode also multibyte string.
-      (when (consp (car attr))
-       (setcar attr
-               (and (stringp (caar attr))
-                    (string-match ".+ -> .\\(.+\\)." (caar attr))
-                    (decode-coding-string
-                     (match-string 1 (caar attr)) 'utf-8))))
-      ;; Set file's gid change bit.
-      (setcar (nthcdr 9 attr)
-              (if (numberp (nth 3 attr))
-                  (not (= (nth 3 attr)
-                          (tramp-get-remote-gid vec 'integer)))
-               (not (string-equal
-                      (nth 3 attr)
-                      (tramp-get-remote-gid vec 'string)))))
-      ;; Convert inode.
-      (when (floatp (nth 10 attr))
-       (setcar (nthcdr 10 attr)
-               (condition-case nil
-                    (let ((high (nth 10 attr))
-                          middle low)
-                      (if (<= high most-positive-fixnum)
-                          (floor high)
-                       ;; The low 16 bits.
-                       (setq low (mod high #x10000)
-                              high (/ high #x10000))
-                       (if (<= high most-positive-fixnum)
-                            (cons (floor high) (floor low))
-                          ;; The middle 24 bits.
-                          (setq middle (mod high #x1000000)
-                               high (/ high #x1000000))
-                          (cons (floor high)
-                               (cons (floor middle) (floor low))))))
-                  ;; Inodes can be incredible huge.  We must hide this.
-                  (error (tramp-get-inode vec)))))
-      ;; Set virtual device number.
-      (setcar (nthcdr 11 attr)
-              (tramp-get-device vec)))
-    attr))
-
 (defun tramp-shell-case-fold (string)
   "Convert STRING to shell glob pattern which ignores case."
   (mapconcat
@@ -5430,7 +5426,7 @@ Return ATTR."
     ;; This does not work for MS Windows scp, if there are characters
     ;; to be quoted.  OpenSSH 8 supports disabling of strict file name
     ;; checking in scp, we use it when available.
-    (unless (string-match-p "ftp$" method)
+    (unless (string-match-p (rx "ftp" eos) method)
       (setq localname (tramp-unquote-shell-quote-argument localname)))
     (cond
      ((tramp-get-method-parameter vec 'tramp-remote-copy-program)
@@ -5508,7 +5504,7 @@ Nonexistent directories are removed from spec."
                    (tramp-get-method-parameter vec 'tramp-remote-shell-args)
                    " ")
                   (tramp-shell-quote-argument tramp-end-of-heredoc))
-                 'noerror (regexp-quote tramp-end-of-heredoc))
+                 'noerror (rx (literal tramp-end-of-heredoc)))
                 (progn
                   (tramp-message
                    vec 2 "Could not retrieve `tramp-own-remote-path'")
@@ -5557,8 +5553,9 @@ Nonexistent directories are removed from spec."
       (with-current-buffer (tramp-get-connection-buffer vec)
        (while candidates
          (goto-char (point-min))
-         (if (string-match-p (format "^%s\r?$" (regexp-quote (car candidates)))
-                             (buffer-string))
+         (if (string-match-p
+              (rx bol (literal (car candidates))"%s" (? "\r") eol)
+              (buffer-string))
              (setq locale (car candidates)
                    candidates nil)
            (setq candidates (cdr candidates)))))
@@ -5583,10 +5580,14 @@ Nonexistent directories are removed from spec."
             ;; "--color=never" argument (for example on FreeBSD).
             (when (tramp-send-command-and-check
                    vec (format "%s -lnd /" result))
-              (when (tramp-send-command-and-check
-                     vec (format
-                          "%s --color=never -al %s"
-                           result (tramp-get-remote-null-device vec)))
+              (when (and (tramp-send-command-and-check
+                          vec (format
+                               "%s --color=never -al %s"
+                               result (tramp-get-remote-null-device vec)))
+                         (not (string-match-p
+                               "\e"
+                               (tramp-get-buffer-string
+                                (tramp-get-buffer vec)))))
                 (setq result (concat result " --color=never")))
               (throw 'ls-found result))
             (setq dl (cdr dl))))))
@@ -5632,7 +5633,7 @@ Nonexistent directories are removed from spec."
        vec (format "( %s / -nt / )" (tramp-get-test-command vec)))
        (with-current-buffer (tramp-get-buffer vec)
         (goto-char (point-min))
-        (when (looking-at-p (regexp-quote tramp-end-of-output))
+        (when (looking-at-p (rx (literal tramp-end-of-output)))
           (format "%s %%s -nt %%s" (tramp-get-test-command vec)))))
      (progn
        (tramp-send-command
@@ -5697,7 +5698,9 @@ Nonexistent directories are removed from spec."
                tmp (tramp-send-command-and-read
                     vec (format "%s -c '(\"%%N\" %%s)' /" result) 'noerror))
          (unless (and (listp tmp) (stringp (car tmp))
-                      (string-match-p "^[\"`‘„”«「]/[\"'’“”»」]$" (car tmp))
+                      (string-match-p
+                       (rx bol (any "\"`'‘„”«「") "/" (any "\"'’“”»」") eol)
+                       (car tmp))
                       (integerp (cadr tmp)))
            (setq result nil)))
        result))))
@@ -5789,18 +5792,25 @@ This command is returned only if 
`delete-by-moving-to-trash' is non-nil."
          (while (and dl (setq result (tramp-find-executable vec cmd dl t t)))
            ;; Check POSIX parameter.
            (when (tramp-send-command-and-check vec (format "%s -u" result))
+             (tramp-set-connection-property
+              vec "uid-integer"
+              (with-current-buffer (tramp-get-connection-buffer vec)
+                (goto-char (point-min))
+                (read (current-buffer))))
              (throw 'id-found result))
            (setq dl (cdr dl))))))))
 
 (defun tramp-get-remote-uid-with-id (vec id-format)
   "Implement `tramp-get-remote-uid' for Tramp files using `id'."
-  (tramp-send-command-and-read
-   vec
-   (format "%s -u%s %s"
-          (tramp-get-remote-id vec)
-          (if (equal id-format 'integer) "" "n")
-          (if (equal id-format 'integer)
-              "" "| sed -e s/^/\\\"/ -e s/\\$/\\\"/"))))
+  ;; `tramp-get-remote-id' sets already connection property "uid-integer".
+  (with-tramp-connection-property vec (format "uid-%s" id-format)
+    (tramp-send-command-and-read
+     vec
+     (format "%s -u%s %s"
+            (tramp-get-remote-id vec)
+            (if (equal id-format 'integer) "" "n")
+            (if (equal id-format 'integer)
+                "" "| sed -e s/^/\\\"/ -e s/\\$/\\\"/")))))
 
 (defun tramp-get-remote-uid-with-perl (vec id-format)
   "Implement `tramp-get-remote-uid' for Tramp files using a Perl script."
@@ -5817,7 +5827,6 @@ This command is returned only if 
`delete-by-moving-to-trash' is non-nil."
   (with-tramp-connection-property vec "python"
     (tramp-message vec 5 "Finding a suitable `python' command")
     (or (tramp-find-executable vec "python" (tramp-get-remote-path vec))
-        (tramp-find-executable vec "python2" (tramp-get-remote-path vec))
         (tramp-find-executable vec "python3" (tramp-get-remote-path vec)))))
 
 (defun tramp-get-remote-uid-with-python (vec id-format)
@@ -5950,7 +5959,7 @@ If no corresponding command is found, nil is returned."
             (> size tramp-inline-compress-start-size))
     (with-tramp-connection-property (tramp-get-process vec) prop
       (tramp-find-inline-compress vec)
-      (tramp-get-connection-property (tramp-get-process vec) prop nil))))
+      (tramp-get-connection-property (tramp-get-process vec) prop))))
 
 (defun tramp-get-inline-coding (vec prop size)
   "Return the coding command related to PROP.
@@ -5970,7 +5979,7 @@ function cell is returned to be applied on a buffer."
     (let ((coding
           (with-tramp-connection-property (tramp-get-process vec) prop
             (tramp-find-inline-encoding vec)
-            (tramp-get-connection-property (tramp-get-process vec) prop nil)))
+            (tramp-get-connection-property (tramp-get-process vec) prop)))
          (prop1 (if (tramp-compat-string-search "encoding" prop)
                     "inline-compress" "inline-decompress"))
          compress)
@@ -6133,5 +6142,4 @@ function cell is returned to be applied on a buffer."
 ;; * Support hostname canonicalization in ~/.ssh/config.
 ;;   <https://stackoverflow.com/questions/70205232/>
 
-
 ;;; tramp-sh.el ends here
diff --git a/lisp/net/tramp-smb.el b/lisp/net/tramp-smb.el
index 8037c89829..9e63d53262 100644
--- a/lisp/net/tramp-smb.el
+++ b/lisp/net/tramp-smb.el
@@ -53,7 +53,7 @@
 ;;;###tramp-autoload
 (tramp--with-startup
  (add-to-list 'tramp-default-user-alist
-             `(,(concat "\\`" tramp-smb-method "\\'") nil nil))
+             `(,(rx bos (literal tramp-smb-method) eos) nil nil))
 
  ;; Add completion function for SMB method.
  (tramp-set-completion-function
@@ -92,10 +92,15 @@ this variable \"client min protocol=NT1\"."
   "Version string of the SMB client.")
 
 (defconst tramp-smb-server-version
-  "Domain=\\[[^]]*\\] OS=\\[[^]]*\\] Server=\\[[^]]*\\]"
+  (rx "Domain=[" (* (not (any "]"))) "] "
+      "OS=[" (* (not (any "]"))) "] "
+      "Server=[" (* (not (any "]"))) "]")
   "Regexp of SMB server identification.")
 
-(defconst tramp-smb-prompt "^\\(smb:\\|PS\\) .+> \\|^\\s-+Server\\s-+Comment$"
+(defconst tramp-smb-prompt
+  (rx bol (| (: (| "smb:" "PS") " " (+ nonl) "> ")
+            (: (+ space) "Server"
+               (+ space) "Comment" eol)))
   "Regexp used as prompt in smbclient or powershell.")
 
 (defconst tramp-smb-wrong-passwd-regexp
@@ -105,66 +110,63 @@ this variable \"client min protocol=NT1\"."
   "Regexp for login error strings of SMB servers.")
 
 (defconst tramp-smb-errors
-  (mapconcat
-   #'identity
-   `(;; Connection error / timeout / unknown command.
-     "Connection\\( to \\S-+\\)? failed"
-     "Read from server failed, maybe it closed the connection"
-     "Call timed out: server did not respond"
-     "\\S-+: command not found"
-     "Server doesn't support UNIX CIFS calls"
-     ,(regexp-opt
-       '(;; Samba.
-        "ERRDOS"
-        "ERRHRD"
-        "ERRSRV"
-        "ERRbadfile"
-        "ERRbadpw"
-        "ERRfilexists"
-        "ERRnoaccess"
-        "ERRnomem"
-        "ERRnosuchshare"
-        ;; See /usr/include/samba-4.0/core/ntstatus.h.
-        ;; Windows 4.0 (Windows NT), Windows 5.0 (Windows 2000),
-        ;; Windows 5.1 (Windows XP), Windows 5.2 (Windows Server 2003),
-        ;; Windows 6.0 (Windows Vista), Windows 6.1 (Windows 7),
-        ;; Windows 6.3 (Windows Server 2012, Windows 10).
-        "NT_STATUS_ACCESS_DENIED"
-        "NT_STATUS_ACCOUNT_LOCKED_OUT"
-        "NT_STATUS_BAD_NETWORK_NAME"
-        "NT_STATUS_CANNOT_DELETE"
-        "NT_STATUS_CONNECTION_DISCONNECTED"
-        "NT_STATUS_CONNECTION_REFUSED"
-        "NT_STATUS_CONNECTION_RESET"
-        "NT_STATUS_DIRECTORY_NOT_EMPTY"
-        "NT_STATUS_DUPLICATE_NAME"
-        "NT_STATUS_FILE_IS_A_DIRECTORY"
-        "NT_STATUS_HOST_UNREACHABLE"
-        "NT_STATUS_IMAGE_ALREADY_LOADED"
-        "NT_STATUS_INVALID_LEVEL"
-        "NT_STATUS_INVALID_PARAMETER"
-        "NT_STATUS_INVALID_PARAMETER_MIX"
-        "NT_STATUS_IO_TIMEOUT"
-        "NT_STATUS_LOGON_FAILURE"
-        "NT_STATUS_NETWORK_ACCESS_DENIED"
-        "NT_STATUS_NOT_IMPLEMENTED"
-        "NT_STATUS_NO_LOGON_SERVERS"
-        "NT_STATUS_NO_SUCH_FILE"
-        "NT_STATUS_NO_SUCH_USER"
-        "NT_STATUS_NOT_A_DIRECTORY"
-        "NT_STATUS_NOT_SUPPORTED"
-        "NT_STATUS_OBJECT_NAME_COLLISION"
-        "NT_STATUS_OBJECT_NAME_INVALID"
-        "NT_STATUS_OBJECT_NAME_NOT_FOUND"
-        "NT_STATUS_OBJECT_PATH_SYNTAX_BAD"
-        "NT_STATUS_PASSWORD_MUST_CHANGE"
-        "NT_STATUS_RESOURCE_NAME_NOT_FOUND"
-        "NT_STATUS_REVISION_MISMATCH"
-        "NT_STATUS_SHARING_VIOLATION"
-        "NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE"
-        "NT_STATUS_UNSUCCESSFUL"
-        "NT_STATUS_WRONG_PASSWORD")))
-   "\\|")
+  (rx (| ;; Connection error / timeout / unknown command.
+       (: "Connection" (? " to " (+ (not space))) " failed")
+       "Read from server failed, maybe it closed the connection"
+       "Call timed out: server did not respond"
+       (: (+ (not space)) ": command not found")
+       "Server doesn't support UNIX CIFS calls"
+       (regexp (regexp-opt
+               '(;; Samba.
+                 "ERRDOS"
+                 "ERRHRD"
+                 "ERRSRV"
+                 "ERRbadfile"
+                 "ERRbadpw"
+                 "ERRfilexists"
+                 "ERRnoaccess"
+                 "ERRnomem"
+                 "ERRnosuchshare"
+                 ;; See /usr/include/samba-4.0/core/ntstatus.h.
+                 ;; Windows 4.0 (Windows NT), Windows 5.0 (Windows 2000),
+                 ;; Windows 5.1 (Windows XP), Windows 5.2 (Windows Server 
2003),
+                 ;; Windows 6.0 (Windows Vista), Windows 6.1 (Windows 7),
+                 ;; Windows 6.3 (Windows Server 2012, Windows 10).
+                 "NT_STATUS_ACCESS_DENIED"
+                 "NT_STATUS_ACCOUNT_LOCKED_OUT"
+                 "NT_STATUS_BAD_NETWORK_NAME"
+                 "NT_STATUS_CANNOT_DELETE"
+                 "NT_STATUS_CONNECTION_DISCONNECTED"
+                 "NT_STATUS_CONNECTION_REFUSED"
+                 "NT_STATUS_CONNECTION_RESET"
+                 "NT_STATUS_DIRECTORY_NOT_EMPTY"
+                 "NT_STATUS_DUPLICATE_NAME"
+                 "NT_STATUS_FILE_IS_A_DIRECTORY"
+                 "NT_STATUS_HOST_UNREACHABLE"
+                 "NT_STATUS_IMAGE_ALREADY_LOADED"
+                 "NT_STATUS_INVALID_LEVEL"
+                 "NT_STATUS_INVALID_PARAMETER"
+                 "NT_STATUS_INVALID_PARAMETER_MIX"
+                 "NT_STATUS_IO_TIMEOUT"
+                 "NT_STATUS_LOGON_FAILURE"
+                 "NT_STATUS_NETWORK_ACCESS_DENIED"
+                 "NT_STATUS_NOT_IMPLEMENTED"
+                 "NT_STATUS_NO_LOGON_SERVERS"
+                 "NT_STATUS_NO_SUCH_FILE"
+                 "NT_STATUS_NO_SUCH_USER"
+                 "NT_STATUS_NOT_A_DIRECTORY"
+                 "NT_STATUS_NOT_SUPPORTED"
+                 "NT_STATUS_OBJECT_NAME_COLLISION"
+                 "NT_STATUS_OBJECT_NAME_INVALID"
+                 "NT_STATUS_OBJECT_NAME_NOT_FOUND"
+                 "NT_STATUS_OBJECT_PATH_SYNTAX_BAD"
+                 "NT_STATUS_PASSWORD_MUST_CHANGE"
+                 "NT_STATUS_RESOURCE_NAME_NOT_FOUND"
+                 "NT_STATUS_REVISION_MISMATCH"
+                 "NT_STATUS_SHARING_VIOLATION"
+                 "NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE"
+                 "NT_STATUS_UNSUCCESSFUL"
+                 "NT_STATUS_WRONG_PASSWORD")))))
   "Regexp for possible error strings of SMB servers.
 Used instead of analyzing error codes of commands.")
 
@@ -232,7 +234,7 @@ See `tramp-actions-before-shell' for more info.")
     (delete-file . tramp-smb-handle-delete-file)
     ;; `diff-latest-backup-file' performed by default handler.
     (directory-file-name . tramp-handle-directory-file-name)
-    (directory-files . tramp-smb-handle-directory-files)
+    (directory-files . tramp-handle-directory-files)
     (directory-files-and-attributes
      . tramp-handle-directory-files-and-attributes)
     (dired-compress-file . ignore)
@@ -386,14 +388,13 @@ arguments to pass to the OPERATION."
       ;; We must also flush the cache of the directory, because
       ;; `file-attributes' reads the values from there.
       (tramp-flush-file-properties v2 v2-localname)
-      (unless
-         (tramp-smb-send-command
-          v1
-          (format
-           "%s \"%s\" \"%s\""
-           (if (tramp-smb-get-cifs-capabilities v1) "link" "hardlink")
-           (tramp-smb-get-localname v1)
-           (tramp-smb-get-localname v2)))
+      (unless (tramp-smb-send-command
+              v1
+              (format
+               "%s %s %s"
+               (if (tramp-smb-get-cifs-capabilities v1) "link" "hardlink")
+               (tramp-smb-shell-quote-localname v1)
+               (tramp-smb-shell-quote-localname v2)))
        (tramp-error
         v2 'file-error
         "error with add-name-to-file, see buffer `%s' for details"
@@ -417,175 +418,181 @@ arguments to pass to the OPERATION."
 (defun tramp-smb-handle-copy-directory
   (dirname newname &optional keep-date parents copy-contents)
   "Like `copy-directory' for Tramp files."
-  (let ((t1 (tramp-tramp-file-p dirname))
-       (t2 (tramp-tramp-file-p newname))
-       target)
-    (with-parsed-tramp-file-name (if t1 dirname newname) nil
-      (unless (file-exists-p dirname)
-       (tramp-error v 'file-missing dirname))
-
-      ;; `copy-directory-create-symlink' exists since Emacs 28.1.
-      (if (and (bound-and-true-p copy-directory-create-symlink)
-              (setq target (file-symlink-p dirname))
-              (tramp-equal-remote dirname newname))
-         (make-symbolic-link
-          target
-          (if (directory-name-p newname)
-              (concat newname (file-name-nondirectory dirname)) newname)
-          t)
-
-       (if copy-contents
-           ;; We must do it file-wise.
-           (tramp-run-real-handler
-            #'copy-directory
-            (list dirname newname keep-date parents copy-contents))
-
-         (setq dirname (expand-file-name dirname)
-               newname (expand-file-name newname))
-         (with-tramp-progress-reporter
-             v 0 (format "Copying %s to %s" dirname newname)
-           (unless (file-exists-p dirname)
-             (tramp-error v 'file-missing dirname))
-           (when (and (file-directory-p newname)
-                      (not (directory-name-p newname)))
-             (tramp-error v 'file-already-exists newname))
-           (cond
-            ;; We must use a local temporary directory.
-            ((and t1 t2)
-             (let ((tmpdir (tramp-compat-make-temp-name)))
-               (unwind-protect
-                   (progn
-                     (make-directory tmpdir)
-                     (copy-directory
-                      dirname (file-name-as-directory tmpdir)
-                      keep-date 'parents)
-                     (copy-directory
-                      (expand-file-name (file-name-nondirectory dirname) 
tmpdir)
-                      newname keep-date parents))
-                 (delete-directory tmpdir 'recursive))))
-
-            ;; We can copy recursively.
-            ;; TODO: Does not work reliably.
-            (nil ;(and (or t1 t2) (tramp-smb-get-cifs-capabilities v))
+  (tramp-skeleton-copy-directory
+      dirname newname keep-date parents copy-contents
+    (let ((t1 (tramp-tramp-file-p dirname))
+         (t2 (tramp-tramp-file-p newname))
+         target)
+      (with-parsed-tramp-file-name (if t1 dirname newname) nil
+       (unless (file-exists-p dirname)
+         (tramp-error v 'file-missing dirname))
+
+       ;; `copy-directory-create-symlink' exists since Emacs 28.1.
+       (if (and (bound-and-true-p copy-directory-create-symlink)
+                (setq target (file-symlink-p dirname))
+                (tramp-equal-remote dirname newname))
+           (make-symbolic-link
+            target
+            (if (directory-name-p newname)
+                (concat newname (file-name-nondirectory dirname)) newname)
+            t)
+
+         (if copy-contents
+             ;; We must do it file-wise.
+             (tramp-run-real-handler
+              #'copy-directory
+              (list dirname newname keep-date parents copy-contents))
+
+           (setq dirname (expand-file-name dirname)
+                 newname (expand-file-name newname))
+           (with-tramp-progress-reporter
+               v 0 (format "Copying %s to %s" dirname newname)
              (when (and (file-directory-p newname)
-                        (not (string-equal (file-name-nondirectory dirname)
-                                           (file-name-nondirectory newname))))
-               (setq newname
-                     (expand-file-name
-                      (file-name-nondirectory dirname) newname))
-               (if t2 (setq v (tramp-dissect-file-name newname))))
-             (if (not (file-directory-p newname))
-                 (make-directory newname parents))
-
-             (let* ((share (tramp-smb-get-share v))
-                    (localname (file-name-as-directory
-                                (tramp-compat-string-replace
-                                 "\\" "/" (tramp-smb-get-localname v))))
-                    (tmpdir    (tramp-compat-make-temp-name))
-                    (args      (list (concat "//" host "/" share) "-E"))
-                    (options   tramp-smb-options))
-
-               (if (not (zerop (length user)))
-                   (setq args (append args (list "-U" user)))
-                 (setq args (append args (list "-N"))))
-
-               (when domain (setq args (append args (list "-W" domain))))
-               (when port   (setq args (append args (list "-p" port))))
-               (when tramp-smb-conf
-                 (setq args (append args (list "-s" tramp-smb-conf))))
-               (while options
-                 (setq args
-                       (append args `("--option" ,(format "%s" (car options))))
-                       options (cdr options)))
-               (setq args
-                     (if t1
-                         ;; Source is remote.
+                        (not (directory-name-p newname)))
+               (tramp-error v 'file-already-exists newname))
+             (cond
+              ;; We must use a local temporary directory.
+              ((and t1 t2)
+               (let ((tmpdir (tramp-compat-make-temp-name)))
+                 (unwind-protect
+                     (progn
+                       (make-directory tmpdir)
+                       (copy-directory
+                        dirname (file-name-as-directory tmpdir)
+                        keep-date 'parents)
+                       (copy-directory
+                        (expand-file-name
+                         (file-name-nondirectory dirname) tmpdir)
+                        newname keep-date parents))
+                   (delete-directory tmpdir 'recursive))))
+
+              ;; We can copy recursively.
+              ;; FIXME: Does not work reliably.
+              (nil ;(and (or t1 t2) (tramp-smb-get-cifs-capabilities v))
+               (when (and (file-directory-p newname)
+                          (not (string-equal (file-name-nondirectory dirname)
+                                             (file-name-nondirectory 
newname))))
+                 (setq newname
+                       (expand-file-name
+                        (file-name-nondirectory dirname) newname))
+                 (if t2 (setq v (tramp-dissect-file-name newname))))
+               (if (not (file-directory-p newname))
+                   (make-directory newname parents))
+
+               (let* ((share (tramp-smb-get-share v))
+                      (localname (file-name-as-directory
+                                  (tramp-compat-string-replace
+                                   "\\" "/" (tramp-smb-get-localname v))))
+                      (tmpdir    (tramp-compat-make-temp-name))
+                      (args      (list (concat "//" host "/" share) "-E"))
+                      (options   tramp-smb-options))
+
+                 (if (not (zerop (length user)))
+                     (setq args (append args (list "-U" user)))
+                   (setq args (append args (list "-N"))))
+
+                 (when domain (setq args (append args (list "-W" domain))))
+                 (when port   (setq args (append args (list "-p" port))))
+                 (when tramp-smb-conf
+                   (setq args (append args (list "-s" tramp-smb-conf))))
+                 (while options
+                   (setq args
                          (append args
+                                 `("--option" ,(format "%s" (car options))))
+                         options (cdr options)))
+                 (setq args
+                       (if t1
+                           ;; Source is remote.
+                           (append args
+                                   (list "-D"
+                                         (tramp-unquote-shell-quote-argument
+                                          localname)
+                                         "-c"
+                                         (tramp-unquote-shell-quote-argument
+                                          "tar qc - *")
+                                         "|" "tar" "xfC" "-"
+                                         (tramp-unquote-shell-quote-argument
+                                          tmpdir)))
+                         ;; Target is remote.
+                         (append (list
+                                  "tar" "cfC" "-"
+                                  (tramp-unquote-shell-quote-argument dirname)
+                                  "." "|")
+                                 args
                                  (list "-D" (tramp-unquote-shell-quote-argument
                                              localname)
                                        "-c" (tramp-unquote-shell-quote-argument
-                                             "tar qc - *")
-                                       "|" "tar" "xfC" "-"
-                                       (tramp-unquote-shell-quote-argument
-                                        tmpdir)))
-                       ;; Target is remote.
-                       (append (list
-                                "tar" "cfC" "-"
-                                (tramp-unquote-shell-quote-argument dirname)
-                                "." "|")
-                               args
-                               (list "-D" (tramp-unquote-shell-quote-argument
-                                           localname)
-                                     "-c" (tramp-unquote-shell-quote-argument
-                                           "tar qx -")))))
-
-               (unwind-protect
-                   (with-temp-buffer
-                     ;; Set the transfer process properties.
-                     (tramp-set-connection-property
-                      v "process-name" (buffer-name (current-buffer)))
-                     (tramp-set-connection-property
-                      v "process-buffer" (current-buffer))
-
-                     (when t1
-                       ;; The smbclient tar command creates always
-                       ;; complete paths.  We must emulate the
-                       ;; directory structure, and symlink to the
-                       ;; real target.
-                       (make-directory
-                        (expand-file-name
-                         ".." (concat tmpdir localname))
-                        'parents)
-                       (make-symbolic-link
-                        newname
-                        (directory-file-name (concat tmpdir localname))))
-
-                     ;; Use an asynchronous processes.  By this,
-                     ;; password can be handled.
-                     (let* ((default-directory tmpdir)
-                            (p (apply
-                                #'start-process
-                                (tramp-get-connection-name v)
-                                (tramp-get-connection-buffer v)
-                                tramp-smb-program args)))
-
-                       (tramp-message
-                        v 6 "%s" (string-join (process-command p) " "))
-                       (process-put p 'vector v)
-                       (process-put p 'adjust-window-size-function #'ignore)
-                       (set-process-query-on-exit-flag p nil)
-                       (tramp-process-actions
-                        p v nil tramp-smb-actions-with-tar)
-
-                       (while (process-live-p p)
-                         (sleep-for 0.1))
-                       (tramp-message v 6 "\n%s" (buffer-string))))
-
-                 ;; Reset the transfer process properties.
-                 (tramp-flush-connection-property v "process-name")
-                 (tramp-flush-connection-property v "process-buffer")
-                 (when t1 (delete-directory tmpdir 'recursive))))
-
-             ;; Handle KEEP-DATE argument.
-             (when keep-date
-               (tramp-compat-set-file-times
-                newname
-                (file-attribute-modification-time (file-attributes dirname))
-                (unless ok-if-already-exists 'nofollow)))
-
-             ;; Set the mode.
-             (unless keep-date
-               (set-file-modes newname (tramp-default-file-modes dirname)))
-
-             ;; When newname did exist, we have wrong cached values.
-             (when t2
-               (with-parsed-tramp-file-name newname nil
-                 (tramp-flush-file-properties v localname))))
-
-            ;; We must do it file-wise.
-            (t
-             (tramp-run-real-handler
-              #'copy-directory (list dirname newname keep-date 
parents))))))))))
+                                             "tar qx -")))))
+
+                 (unwind-protect
+                     (with-tramp-saved-connection-properties
+                         v '("process-name" "process-buffer")
+                       (with-temp-buffer
+                         ;; Set the transfer process properties.
+                         (tramp-set-connection-property
+                          v "process-name" (buffer-name (current-buffer)))
+                         (tramp-set-connection-property
+                          v "process-buffer" (current-buffer))
+
+                         (when t1
+                           ;; The smbclient tar command creates
+                           ;; always complete paths.  We must emulate
+                           ;; the directory structure, and symlink to
+                           ;; the real target.
+                           (make-directory
+                            (expand-file-name
+                             ".." (concat tmpdir localname))
+                            'parents)
+                           (make-symbolic-link
+                            newname
+                            (directory-file-name (concat tmpdir localname))))
+
+                         ;; Use an asynchronous processes.  By this,
+                         ;; password can be handled.
+                         (let* ((default-directory tmpdir)
+                                (p (apply
+                                    #'start-process
+                                    (tramp-get-connection-name v)
+                                    (tramp-get-connection-buffer v)
+                                    tramp-smb-program args)))
+
+                           (tramp-message
+                            v 6 "%s" (string-join (process-command p) " "))
+                           (process-put p 'vector v)
+                           (process-put
+                            p 'adjust-window-size-function #'ignore)
+                           (set-process-query-on-exit-flag p nil)
+                           (tramp-process-actions
+                            p v nil tramp-smb-actions-with-tar)
+
+                           (while (process-live-p p)
+                             (sleep-for 0.1))
+                           (tramp-message v 6 "\n%s" (buffer-string)))))
+
+                   ;; Save exit.
+                   (when t1 (delete-directory tmpdir 'recursive))))
+
+               ;; Handle KEEP-DATE argument.
+               (when keep-date
+                 (tramp-compat-set-file-times
+                  newname
+                  (file-attribute-modification-time (file-attributes dirname))
+                  (unless ok-if-already-exists 'nofollow)))
+
+               ;; Set the mode.
+               (unless keep-date
+                 (set-file-modes newname (tramp-default-file-modes dirname)))
+
+               ;; When newname did exist, we have wrong cached values.
+               (when t2
+                 (with-parsed-tramp-file-name newname nil
+                   (tramp-flush-file-properties v localname))))
+
+              ;; We must do it file-wise.
+              (t
+               (tramp-run-real-handler
+                #'copy-directory
+                (list dirname newname keep-date parents)))))))))))
 
 (defun tramp-smb-handle-copy-file
   (filename newname &optional ok-if-already-exists keep-date
@@ -641,9 +648,9 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are 
completely ignored."
            (tramp-error
             v 'file-error "Target `%s' must contain a share name" newname))
          (unless (tramp-smb-send-command
-                  v (format "put \"%s\" \"%s\""
-                            (tramp-compat-file-name-unquote filename)
-                            (tramp-smb-get-localname v)))
+                  v (format "put %s %s"
+                            (tramp-smb-shell-quote-argument filename)
+                            (tramp-smb-shell-quote-localname v)))
            (tramp-error
             v 'file-error "Cannot copy `%s' to `%s'" filename newname)))))
 
@@ -672,10 +679,10 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are 
completely ignored."
       (tramp-flush-directory-properties v localname)
       (unless (tramp-smb-send-command
               v (format
-                 "%s \"%s\""
+                 "%s %s"
                  (if (tramp-smb-get-cifs-capabilities v)
                      "posix_rmdir" "rmdir")
-                 (tramp-smb-get-localname v)))
+                 (tramp-smb-shell-quote-localname v)))
        ;; Error.
        (with-current-buffer (tramp-get-connection-buffer v)
          (goto-char (point-min))
@@ -698,46 +705,15 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are 
completely ignored."
          (move-file-to-trash filename)
        (unless (tramp-smb-send-command
                 v (format
-                   "%s \"%s\""
+                   "%s %s"
                    (if (tramp-smb-get-cifs-capabilities v) "posix_unlink" "rm")
-                   (tramp-smb-get-localname v)))
+                   (tramp-smb-shell-quote-localname v)))
          ;; Error.
          (with-current-buffer (tramp-get-connection-buffer v)
            (goto-char (point-min))
            (search-forward-regexp tramp-smb-errors nil t)
            (tramp-error v 'file-error "%s `%s'" (match-string 0) 
filename)))))))
 
-(defun tramp-smb-handle-directory-files
-  (directory &optional full match nosort count)
-  "Like `directory-files' for Tramp files."
-  (unless (file-exists-p directory)
-    (tramp-error (tramp-dissect-file-name directory) 'file-missing directory))
-  (let ((result (mapcar #'directory-file-name
-                       (file-name-all-completions "" directory))))
-    ;; Discriminate with regexp.
-    (when match
-      (setq result
-           (delete nil
-                   (mapcar (lambda (x) (when (string-match-p match x) x))
-                           result))))
-
-    ;; Sort them if necessary.
-    (unless nosort
-      (setq result (sort result #'string-lessp)))
-
-    ;; Return count number of results.
-    (when (and (natnump count) (> count 0))
-      (setq result (nbutlast result (- (length result) count))))
-
-    ;; Prepend directory.
-    (when full
-      (setq result
-           (mapcar
-            (lambda (x) (format "%s/%s" (directory-file-name directory) x))
-            result)))
-
-    result))
-
 (defun tramp-smb-handle-expand-file-name (name &optional dir)
   "Like `expand-file-name' for Tramp files."
   ;; If DIR is not given, use DEFAULT-DIRECTORY or "/".
@@ -749,11 +725,13 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are 
completely ignored."
     (setq name (tramp-compat-file-name-concat dir name)))
   ;; If NAME is not a Tramp file, run the real handler.
   (if (not (tramp-tramp-file-p name))
-      (tramp-run-real-handler #'expand-file-name (list name nil))
+      (tramp-run-real-handler #'expand-file-name (list name))
     ;; Dissect NAME.
     (with-parsed-tramp-file-name name nil
       ;; Tilde expansion if necessary.
-      (when (string-match "\\`~\\([^/]*\\)\\(.*\\)\\'" localname)
+      (when (string-match
+            (rx bos "~" (group (* (not (any "/")))) (group (* nonl)) eos)
+            localname)
        (let ((uname (match-string 1 localname))
              (fname (match-string 2 localname))
              hname)
@@ -763,20 +741,24 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are 
completely ignored."
            (setq localname (concat hname fname)))))
       ;; Tilde expansion is not possible.
       (when (and (not tramp-tolerate-tilde)
-                (string-match-p "\\`\\(~[^/]*\\)\\(.*\\)\\'" localname))
+                (string-prefix-p "~" localname))
        (tramp-error v 'file-error "Cannot expand tilde in file `%s'" name))
       (unless (tramp-run-real-handler #'file-name-absolute-p (list localname))
        (setq localname (concat "/" localname)))
      ;; Do not keep "/..".
-      (when (string-match-p "^/\\.\\.?$" localname)
+      (when (string-match-p (rx bos "/" (** 1 2 ".") eos) localname)
        (setq localname "/"))
       ;; Do normal `expand-file-name' (this does "/./" and "/../"),
       ;; unless there are tilde characters in file name.
       (tramp-make-tramp-file-name
-       v (if (string-match-p "\\`\\(~[^/]*\\)\\(.*\\)\\'" localname)
+       v (if (string-prefix-p "~" localname)
             localname
           (tramp-run-real-handler #'expand-file-name (list localname)))))))
 
+(defun tramp-smb-remote-acl-p (_vec)
+  "Check, whether ACL is enabled on the remote host."
+  (and (stringp tramp-smb-acl-program) (executable-find 
tramp-smb-acl-program)))
+
 (defun tramp-smb-action-get-acl (proc vec)
   "Read ACL data from connection buffer."
   (unless (process-live-p proc)
@@ -787,10 +769,10 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are 
completely ignored."
       (widen)
       (tramp-message vec 10 "\n%s" (buffer-string))
       (goto-char (point-min))
-      (while (and (not (eobp)) (not (looking-at-p "^REVISION:")))
+      (while (and (not (eobp)) (not (looking-at-p (rx bol "REVISION:"))))
        (forward-line)
        (delete-region (point-min) (point)))
-      (while (and (not (eobp)) (looking-at-p "^.+:.+"))
+      (while (and (not (eobp)) (looking-at-p (rx bol (+ nonl) ":" (+ nonl))))
        (forward-line))
       (delete-region (point) (point-max))
       (throw 'tramp-action 'ok))))
@@ -800,7 +782,7 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are 
completely ignored."
   (ignore-errors
     (with-parsed-tramp-file-name filename nil
       (with-tramp-file-property v localname "file-acl"
-       (when (executable-find tramp-smb-acl-program)
+       (when (tramp-smb-remote-acl-p v)
          (let* ((share     (tramp-smb-get-share v))
                 (localname (tramp-compat-string-replace
                             "\\" "/" (tramp-smb-get-localname v)))
@@ -825,54 +807,49 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are 
completely ignored."
                                (concat "2>" (tramp-get-remote-null-device 
v)))))
 
            (unwind-protect
-               (with-temp-buffer
-                 ;; Set the transfer process properties.
-                 (tramp-set-connection-property
-                  v "process-name" (buffer-name (current-buffer)))
-                 (tramp-set-connection-property
-                  v "process-buffer" (current-buffer))
-
-                 ;; Use an asynchronous process.  By this, password can
-                 ;; be handled.
-                 (let ((p (apply
-                           #'start-process
-                           (tramp-get-connection-name v)
-                           (tramp-get-connection-buffer v)
-                           tramp-smb-acl-program args)))
-
-                   (tramp-message
-                    v 6 "%s" (string-join (process-command p) " "))
-                   (process-put p 'vector v)
-                   (process-put p 'adjust-window-size-function #'ignore)
-                   (set-process-query-on-exit-flag p nil)
-                   (tramp-process-actions p v nil tramp-smb-actions-get-acl)
-                   (when (> (point-max) (point-min))
-                     (substring-no-properties (buffer-string)))))
-
-             ;; Reset the transfer process properties.
-             (tramp-flush-connection-property v "process-name")
-             (tramp-flush-connection-property v "process-buffer"))))))))
+               (with-tramp-saved-connection-properties
+                   v '("process-name" "process-buffer")
+                 (with-temp-buffer
+                   ;; Set the transfer process properties.
+                   (tramp-set-connection-property
+                    v "process-name" (buffer-name (current-buffer)))
+                   (tramp-set-connection-property
+                    v "process-buffer" (current-buffer))
+
+                   ;; Use an asynchronous process.  By this, password
+                   ;; can be handled.
+                   (let ((p (apply
+                             #'start-process
+                             (tramp-get-connection-name v)
+                             (tramp-get-connection-buffer v)
+                             tramp-smb-acl-program args)))
+
+                     (tramp-message
+                      v 6 "%s" (string-join (process-command p) " "))
+                     (process-put p 'vector v)
+                     (process-put p 'adjust-window-size-function #'ignore)
+                     (set-process-query-on-exit-flag p nil)
+                     (tramp-process-actions p v nil tramp-smb-actions-get-acl)
+                     (when (> (point-max) (point-min))
+                       (substring-no-properties (buffer-string)))))))))))))
 
 (defun tramp-smb-handle-file-attributes (filename &optional id-format)
   "Like `file-attributes' for Tramp files."
-  (unless id-format (setq id-format 'integer))
-  (ignore-errors
-    (with-parsed-tramp-file-name filename nil
-      (with-tramp-file-property
-         v localname (format "file-attributes-%s" id-format)
+  ;; The result is cached in `tramp-convert-file-attributes'.
+  (with-parsed-tramp-file-name filename nil
+    (tramp-convert-file-attributes v localname id-format
+      (ignore-errors
        (if (tramp-smb-get-stat-capability v)
-           (tramp-smb-do-file-attributes-with-stat v id-format)
-         ;; Reading just the filename entry via "dir localname" is not
-         ;; possible, because when filename is a directory, some
-         ;; smbclient versions return the content of the directory, and
-         ;; other versions don't.  Therefore, the whole content of the
-         ;; upper directory is retrieved, and the entry of the filename
-         ;; is extracted from.
+           (tramp-smb-do-file-attributes-with-stat v)
+         ;; Reading just the filename entry via "dir localname" is
+         ;; not possible, because when filename is a directory, some
+         ;; smbclient versions return the content of the directory,
+         ;; and other versions don't.  Therefore, the whole content
+         ;; of the upper directory is retrieved, and the entry of the
+         ;; filename is extracted from.
          (let* ((entries (tramp-smb-get-file-entries
                           (file-name-directory filename)))
                 (entry (assoc (file-name-nondirectory filename) entries))
-                (uid (if (equal id-format 'string) "nobody" -1))
-                (gid (if (equal id-format 'string) "nogroup" -1))
                 (inode (tramp-get-inode v))
                 (device (tramp-get-device v)))
 
@@ -880,25 +857,27 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are 
completely ignored."
            (when entry
              (list (and (tramp-compat-string-search "d" (nth 1 entry))
                         t)              ;0 file type
-                   -1                   ;1 link count
-                   uid                  ;2 uid
-                   gid                  ;3 gid
+                   -1                   ;1 link count
+                   (cons
+                    tramp-unknown-id-string tramp-unknown-id-integer) ;2 uid
+                   (cons
+                    tramp-unknown-id-string tramp-unknown-id-integer) ;3 gid
                    tramp-time-dont-know ;4 atime
                    (nth 3 entry)        ;5 mtime
                    tramp-time-dont-know ;6 ctime
                    (nth 2 entry)        ;7 size
                    (nth 1 entry)        ;8 mode
-                   nil                  ;9 gid weird
-                   inode                ;10 inode number
+                   nil                  ;9 gid weird
+                   inode                ;10 inode number
                    device))))))))       ;11 file system number
 
-(defun tramp-smb-do-file-attributes-with-stat (vec &optional id-format)
+(defun tramp-smb-do-file-attributes-with-stat (vec)
   "Implement `file-attributes' for Tramp files using `stat' command."
   (tramp-message
    vec 5 "file attributes with stat: %s" (tramp-file-name-localname vec))
   (let* (size id link uid gid atime mtime ctime mode inode)
     (when (tramp-smb-send-command
-          vec (format "stat \"%s\"" (tramp-smb-get-localname vec)))
+          vec (format "stat %s" (tramp-smb-shell-quote-localname vec)))
 
       ;; Loop the listing.
       (with-current-buffer (tramp-get-connection-buffer vec)
@@ -907,31 +886,30 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are 
completely ignored."
          (while (not (eobp))
            (cond
             ((looking-at
-              (concat
-               "Size:\\s-+\\([[:digit:]]+\\)\\s-+"
-               "Blocks:\\s-+[[:digit:]]+\\s-+\\(\\w+\\)"))
+              (rx "Size:" (+ space) (group (+ digit)) (+ space)
+                  "Blocks:" (+ space) (+ digit) (+ space) (group (+ 
wordchar))))
              (setq size (string-to-number (match-string 1))
                    id (if (string-equal "directory" (match-string 2)) t
                         (if (string-equal "symbolic" (match-string 2)) ""))))
             ((looking-at
-              
"Inode:\\s-+\\([[:digit:]]+\\)\\s-+Links:\\s-+\\([[:digit:]]+\\)")
+              (rx "Inode:" (+ space) (group (+ digit)) (+ space)
+                  "Links:" (+ space) (group (+ digit))))
              (setq inode (string-to-number (match-string 1))
                    link (string-to-number (match-string 2))))
             ((looking-at
-              (concat
-               "Access:\\s-+([[:digit:]]+/\\(\\S-+\\))\\s-+"
-               "Uid:\\s-+\\([[:digit:]]+\\)\\s-+"
-               "Gid:\\s-+\\([[:digit:]]+\\)"))
+              (rx "Access:" (+ space)
+                  "(" (+ digit) "/" (group (+ (not space))) ")" (+ space)
+                  "Uid:" (+ space) (group (+ digit)) (+ whitespace)
+                  "Gid:" (+ space) (group (+ digit))))
              (setq mode (match-string 1)
-                   uid (if (equal id-format 'string) (match-string 2)
-                         (string-to-number (match-string 2)))
-                   gid (if (equal id-format 'string) (match-string 3)
-                         (string-to-number (match-string 3)))))
+                   uid (match-string 2)
+                   gid (match-string 3)))
             ((looking-at
-              (concat
-               "Access:\\s-+"
-               "\\([[:digit:]]+\\)-\\([[:digit:]]+\\)-\\([[:digit:]]+\\)\\s-+"
-               "\\([[:digit:]]+\\):\\([[:digit:]]+\\):\\([[:digit:]]+\\)"))
+              (rx "Access:" (+ space)
+                  (group (+ digit)) "-" (group (+ digit)) "-"
+                  (group (+ digit)) (+ space)
+                  (group (+ digit)) ":" (group (+ digit)) ":"
+                  (group (+ digit))))
              (setq atime
                    (encode-time
                     (string-to-number (match-string 6)) ;; sec
@@ -941,10 +919,11 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are 
completely ignored."
                     (string-to-number (match-string 2)) ;; month
                     (string-to-number (match-string 1))))) ;; year
             ((looking-at
-              (concat
-               "Modify:\\s-+"
-               "\\([[:digit:]]+\\)-\\([[:digit:]]+\\)-\\([[:digit:]]+\\)\\s-+"
-               "\\([[:digit:]]+\\):\\([[:digit:]]+\\):\\([[:digit:]]+\\)"))
+              (rx "Modify:" (+ space)
+                  (group (+ digit)) "-" (group (+ digit)) "-"
+                  (group (+ digit)) (+ space)
+                  (group (+ digit)) ":" (group (+ digit)) ":"
+                  (group (+ digit))))
              (setq mtime
                    (encode-time
                     (string-to-number (match-string 6)) ;; sec
@@ -954,10 +933,11 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are 
completely ignored."
                     (string-to-number (match-string 2)) ;; month
                     (string-to-number (match-string 1))))) ;; year
             ((looking-at
-              (concat
-               "Change:\\s-+"
-               "\\([[:digit:]]+\\)-\\([[:digit:]]+\\)-\\([[:digit:]]+\\)\\s-+"
-               "\\([[:digit:]]+\\):\\([[:digit:]]+\\):\\([[:digit:]]+\\)"))
+              (rx "Change:" (+ space)
+                  (group (+ digit)) "-" (group (+ digit)) "-"
+                  (group (+ digit)) (+ space)
+                  (group (+ digit)) ":" (group (+ digit)) ":"
+                  (group (+ digit))))
              (setq ctime
                    (encode-time
                     (string-to-number (match-string 6)) ;; sec
@@ -972,32 +952,31 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are 
completely ignored."
          (when (and (stringp id)
                     (tramp-smb-send-command
                      vec
-                     (format "readlink \"%s\"" (tramp-smb-get-localname vec))))
+                     (format
+                      "readlink %s" (tramp-smb-shell-quote-localname vec))))
            (goto-char (point-min))
-           (and (looking-at ".+ -> \\(.+\\)")
+           (and (looking-at (rx (+ nonl) " -> " (group (+ nonl))))
                 (setq id (match-string 1))))
 
          ;; Return the result.
          (when (or id link uid gid atime mtime ctime size mode inode)
-           (list id link uid gid atime mtime ctime size mode nil inode
-                 (tramp-get-device vec))))))))
+           (list id link (cons uid (string-to-number uid))
+                 (cons gid (string-to-number gid)) gid atime mtime ctime size
+                 mode nil inode (tramp-get-device vec))))))))
 
 (defun tramp-smb-handle-file-local-copy (filename)
   "Like `file-local-copy' for Tramp files."
-  (with-parsed-tramp-file-name (file-truename filename) nil
-    (unless (file-exists-p (file-truename filename))
-      (tramp-error v 'file-missing filename))
-    (let ((tmpfile (tramp-compat-make-temp-file filename)))
-      (with-tramp-progress-reporter
-         v 3 (format "Fetching %s to tmp file %s" filename tmpfile)
-       (unless (tramp-smb-send-command
-                v (format "get \"%s\" \"%s\""
-                          (tramp-smb-get-localname v) tmpfile))
-         ;; Oops, an error.  We shall cleanup.
-         (delete-file tmpfile)
-         (tramp-error
-          v 'file-error "Cannot make local copy of file `%s'" filename)))
-      tmpfile)))
+  (tramp-skeleton-file-local-copy filename
+    (with-tramp-progress-reporter
+       v 3 (format "Fetching %s to tmp file %s" filename tmpfile)
+      (unless (tramp-smb-send-command
+              v (format "get %s %s"
+                        (tramp-smb-shell-quote-localname v)
+                        (tramp-smb-shell-quote-argument tmpfile)))
+       ;; Oops, an error.  We shall cleanup.
+       (delete-file tmpfile)
+       (tramp-error
+        v 'file-error "Cannot make local copy of file `%s'" filename)))))
 
 ;; This function should return "foo/" for directories and "bar" for
 ;; files.
@@ -1025,20 +1004,20 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are 
completely ignored."
       (when (tramp-smb-get-share v)
        (tramp-message v 5 "file system info: %s" localname)
        (tramp-smb-send-command
-        v (format "du %s/*" (tramp-smb-get-localname v)))
+        v (format "du %s/*" (tramp-smb-shell-quote-localname v)))
        (with-current-buffer (tramp-get-connection-buffer v)
          (let (total avail blocksize)
            (goto-char (point-min))
            (forward-line)
            (when (looking-at
-                  (concat "[[:space:]]*\\([[:digit:]]+\\)"
-                          " blocks of size \\([[:digit:]]+\\)"
-                          "\\. \\([[:digit:]]+\\) blocks available"))
+                  (rx (* space) (group (+ digit))
+                      " blocks of size " (group (+ digit))
+                      ". " (group (+ digit)) " blocks available"))
              (setq blocksize (string-to-number (match-string 2))
                    total (* blocksize (string-to-number (match-string 1)))
                    avail (* blocksize (string-to-number (match-string 3)))))
            (forward-line)
-           (when (looking-at "Total number of bytes: \\([[:digit:]]+\\)")
+           (when (looking-at (rx "Total number of bytes: " (group (+ digit))))
              ;; The used number of bytes is not part of the result.
              ;; As side effect, we store it as file property.
              (tramp-set-file-property
@@ -1089,11 +1068,11 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are 
completely ignored."
                (/ (tramp-get-file-property v localname "used-bytes" 0) 1024))))
 
          (when wildcard
-           (string-match "\\." base)
+           (string-match (rx ".") base)
            (setq base (replace-match "\\\\." nil nil base))
-           (string-match "\\*" base)
+           (string-match (rx "*") base)
            (setq base (replace-match ".*" nil nil base))
-           (string-match "\\?" base)
+           (string-match (rx "?") base)
            (setq base (replace-match ".?" nil nil base)))
 
          ;; Filter entries.
@@ -1104,7 +1083,8 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are 
completely ignored."
                     ;; Check for matching entries.
                     (mapcar
                      (lambda (x)
-                       (when (string-match-p (format "^%s" base) (nth 0 x)) x))
+                       (when (string-match-p (rx bol (literal base)) (nth 0 x))
+                         x))
                      entries)
                   ;; We just need the only and only entry FILENAME.
                   (list (assoc base entries)))))
@@ -1215,18 +1195,17 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are 
completely ignored."
   (unless (file-name-absolute-p directory)
     (setq directory (expand-file-name directory default-directory)))
   (with-parsed-tramp-file-name directory nil
-    (let* ((file (tramp-smb-get-localname v)))
-      (when (file-directory-p (file-name-directory directory))
-       (tramp-smb-send-command
-        v
-        (if (tramp-smb-get-cifs-capabilities v)
-            (format "posix_mkdir \"%s\" %o" file (default-file-modes))
-          (format "mkdir \"%s\"" file)))
-       ;; 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 directory)
-       (tramp-error v 'file-error "Couldn't make directory %s" directory)))))
+    (when (file-directory-p (file-name-directory directory))
+      (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 directory)
+      (tramp-error v 'file-error "Couldn't make directory %s" directory))))
 
 (defun tramp-smb-handle-make-symbolic-link
   (target linkname &optional ok-if-already-exists)
@@ -1270,11 +1249,10 @@ component is used as the target of the symlink."
        ;; `file-attributes' reads the values from there.
        (tramp-flush-file-properties v localname)
 
-       (unless
-           (tramp-smb-send-command
-            v (format "symlink \"%s\" \"%s\""
-                      (tramp-compat-file-name-unquote target)
-                      (tramp-smb-get-localname v)))
+       (unless (tramp-smb-send-command
+                v (format "symlink %s %s"
+                          (tramp-smb-shell-quote-argument target)
+                          (tramp-smb-shell-quote-localname v)))
          (tramp-error
           v 'file-error
           "error with make-symbolic-link, see buffer `%s' for details"
@@ -1343,31 +1321,34 @@ component is used as the target of the symlink."
        (setq i (1+ i)
              name1 (format "%s<%d>" name i)))
 
-      ;; Set the new process properties.
-      (tramp-set-connection-property v "process-name" name1)
-      (tramp-set-connection-property
-       v "process-buffer"
-       (or outbuf (generate-new-buffer tramp-temp-buffer-name)))
-
       ;; Call it.
       (condition-case nil
-         (with-current-buffer (tramp-get-connection-buffer v)
-           ;; Preserve buffer contents.
-           (narrow-to-region (point-max) (point-max))
-           (tramp-smb-call-winexe v)
-           (when (tramp-smb-get-share v)
-             (tramp-smb-send-command
-              v (format "cd \"//%s%s\"" host (file-name-directory localname))))
-           (tramp-smb-send-command v command)
-           ;; Preserve command output.
-           (narrow-to-region (point-max) (point-max))
-           (let ((p (tramp-get-connection-process v)))
-             (tramp-smb-send-command v "exit $lasterrorcode")
-             (while (process-live-p p)
-               (sleep-for 0.1)
-               (setq ret (process-exit-status p))))
-           (delete-region (point-min) (point-max))
-           (widen))
+         (with-tramp-saved-connection-properties
+             v '("process-name" "process-buffer")
+           ;; Set the new process properties.
+           (tramp-set-connection-property v "process-name" name1)
+           (tramp-set-connection-property
+            v "process-buffer"
+            (or outbuf (generate-new-buffer tramp-temp-buffer-name)))
+           (with-current-buffer (tramp-get-connection-buffer v)
+             ;; Preserve buffer contents.
+             (narrow-to-region (point-max) (point-max))
+             (tramp-smb-call-winexe v)
+             (when (tramp-smb-get-share v)
+               (tramp-smb-send-command
+                v (format "cd //%s%s" host
+                          (tramp-smb-shell-quote-argument
+                           (file-name-directory localname)))))
+             (tramp-smb-send-command v command)
+             ;; Preserve command output.
+             (narrow-to-region (point-max) (point-max))
+             (let ((p (tramp-get-connection-process v)))
+               (tramp-smb-send-command v "exit $lasterrorcode")
+               (while (process-live-p p)
+                 (sleep-for 0.1)
+                 (setq ret (process-exit-status p))))
+             (delete-region (point-min) (point-max))
+             (widen)))
 
        ;; When the user did interrupt, we should do it also.  We use
        ;; return code -1 as marker.
@@ -1382,13 +1363,12 @@ component is used as the target of the symlink."
 
       ;; Cleanup.  We remove all file cache values for the connection,
       ;; because the remote process could have changed them.
-      (tramp-flush-connection-property v "process-name")
-      (tramp-flush-connection-property v "process-buffer")
       (when tmpinput (delete-file tmpinput))
+      ;; FIXME: Does connection-property "process-buffer" still exist?
       (unless outbuf
-       (kill-buffer (tramp-get-connection-property v "process-buffer" nil)))
+       (kill-buffer (tramp-get-connection-property v "process-buffer")))
       (when process-file-side-effects
-       (tramp-flush-directory-properties v ""))
+       (tramp-flush-directory-properties v "/"))
 
       ;; Return exit status.
       (if (equal ret -1)
@@ -1432,9 +1412,9 @@ component is used as the target of the symlink."
                 v2 'file-error
                 "Target `%s' must contain a share name" newname))
              (unless (tramp-smb-send-command
-                      v2 (format "rename \"%s\" \"%s\""
-                                 (tramp-smb-get-localname v1)
-                                 (tramp-smb-get-localname v2)))
+                      v2 (format "rename %s %s"
+                                 (tramp-smb-shell-quote-localname v1)
+                                 (tramp-smb-shell-quote-localname v2)))
                (tramp-error v2 'file-error "Cannot rename `%s'" filename))))
 
        ;; We must rename via copy.
@@ -1459,7 +1439,7 @@ component is used as the target of the symlink."
     (with-parsed-tramp-file-name filename nil
       (tramp-flush-file-property v localname "file-acl")
 
-      (when (and (stringp acl-string) (executable-find tramp-smb-acl-program))
+      (when (and (stringp acl-string) (tramp-smb-remote-acl-p v))
        (let* ((share     (tramp-smb-get-share v))
               (localname (tramp-compat-string-replace
                           "\\" "/" (tramp-smb-get-localname v)))
@@ -1487,52 +1467,53 @@ component is used as the target of the symlink."
                              "||" "echo" "tramp_exit_status" "1")))
 
          (unwind-protect
-             (with-temp-buffer
-               ;; Set the transfer process properties.
-               (tramp-set-connection-property
-                v "process-name" (buffer-name (current-buffer)))
-               (tramp-set-connection-property
-                v "process-buffer" (current-buffer))
-
-               ;; Use an asynchronous process.  By this, password can
-               ;; be handled.
-               (let ((p (apply
-                         #'start-process
-                         (tramp-get-connection-name v)
-                         (tramp-get-connection-buffer v)
-                         tramp-smb-acl-program args)))
-
-                 (tramp-message v 6 "%s" (string-join (process-command p) " "))
-                 (process-put p 'vector v)
-                 (process-put p 'adjust-window-size-function #'ignore)
-                 (set-process-query-on-exit-flag p nil)
-                 (tramp-process-actions p v nil tramp-smb-actions-set-acl)
-                 ;; This is meant for traces, and returning from the
-                 ;; function.  No error is propagated outside, due to
-                 ;; the `ignore-errors' closure.
-                 (unless (tramp-search-regexp "tramp_exit_status [[:digit:]]+")
-                   (tramp-error
-                    v 'file-error
-                    "Couldn't find exit status of `%s'" tramp-smb-acl-program))
-                 (skip-chars-forward "^ ")
-                 (when (zerop (read (current-buffer)))
-                   ;; Success.
-                   (tramp-set-file-property v localname "file-acl" acl-string)
-                   t)))
-
-           ;; Reset the transfer process properties.
-           (tramp-flush-connection-property v "process-name")
-           (tramp-flush-connection-property v "process-buffer")))))))
+             (with-tramp-saved-connection-properties
+                 v '("process-name" "process-buffer")
+               (with-temp-buffer
+                 ;; Set the transfer process properties.
+                 (tramp-set-connection-property
+                  v "process-name" (buffer-name (current-buffer)))
+                 (tramp-set-connection-property
+                  v "process-buffer" (current-buffer))
+
+                 ;; Use an asynchronous process.  By this, password
+                 ;; can be handled.
+                 (let ((p (apply
+                           #'start-process
+                           (tramp-get-connection-name v)
+                           (tramp-get-connection-buffer v)
+                           tramp-smb-acl-program args)))
+
+                   (tramp-message
+                    v 6 "%s" (string-join (process-command p) " "))
+                   (process-put p 'vector v)
+                   (process-put p 'adjust-window-size-function #'ignore)
+                   (set-process-query-on-exit-flag p nil)
+                   (tramp-process-actions p v nil tramp-smb-actions-set-acl)
+                   ;; This is meant for traces, and returning from
+                   ;; the function.  No error is propagated outside,
+                   ;; due to the `ignore-errors' closure.
+                   (unless
+                       (tramp-search-regexp (rx "tramp_exit_status " (+ 
digit)))
+                     (tramp-error
+                      v 'file-error
+                      "Couldn't find exit status of `%s'"
+                      tramp-smb-acl-program))
+                   (skip-chars-forward "^ ")
+                   (when (zerop (read (current-buffer)))
+                     ;; Success.
+                     (tramp-set-file-property v localname "file-acl" 
acl-string)
+                     t))))))))))
 
 (defun tramp-smb-handle-set-file-modes (filename mode &optional flag)
   "Like `set-file-modes' for Tramp files."
-  (with-parsed-tramp-file-name filename nil
-    ;; smbclient chmod does not support nofollow.
-    (unless (and (eq flag 'nofollow) (file-symlink-p filename))
+  ;; smbclient chmod does not support nofollow.
+  (unless (and (eq flag 'nofollow) (file-symlink-p filename))
+    (tramp-skeleton-set-file-modes-times-uid-gid filename
       (when (tramp-smb-get-cifs-capabilities v)
-       (tramp-flush-file-properties v localname)
        (unless (tramp-smb-send-command
-                v (format "chmod \"%s\" %o" (tramp-smb-get-localname v) mode))
+                v
+                (format "chmod %s %o" (tramp-smb-shell-quote-localname v) 
mode))
          (tramp-error
           v 'file-error "Error while changing file's mode %s" filename))))))
 
@@ -1553,44 +1534,47 @@ component is used as the target of the symlink."
           (i 0)
           p)
       (unwind-protect
-         (save-excursion
-           (save-restriction
-             (while (get-process name1)
-               ;; NAME must be unique as process name.
-               (setq i (1+ i)
-                     name1 (format "%s<%d>" name i)))
-             ;; Set the new process properties.
-             (tramp-set-connection-property v "process-name" name1)
-             (tramp-set-connection-property v "process-buffer" buffer)
-             ;; Activate narrowing in order to save BUFFER contents.
-             (with-current-buffer (tramp-get-connection-buffer v)
-               (let ((buffer-undo-list t))
-                 (narrow-to-region (point-max) (point-max))
-                 (tramp-smb-call-winexe v)
-                 (when (tramp-smb-get-share v)
-                   (tramp-smb-send-command
-                    v (format
-                       "cd \"//%s%s\""
-                       host (file-name-directory localname))))
-                 (tramp-message v 6 "(%s); exit" command)
-                 (tramp-send-string v command)))
-             (setq p (tramp-get-connection-process v))
-             (when program
-               (process-put p 'remote-command (cons program args))
-               (tramp-set-connection-property
-              p "remote-command" (cons program args)))
-             ;; Return value.
-             p))
+         (with-tramp-saved-connection-properties
+             v '("process-name" "process-buffer")
+           (save-excursion
+             (save-restriction
+               (while (get-process name1)
+                 ;; NAME must be unique as process name.
+                 (setq i (1+ i)
+                       name1 (format "%s<%d>" name i)))
+               ;; Set the new process properties.
+               (tramp-set-connection-property v "process-name" name1)
+               (tramp-set-connection-property v "process-buffer" buffer)
+               ;; Activate narrowing in order to save BUFFER contents.
+               (with-current-buffer (tramp-get-connection-buffer v)
+                 (let ((buffer-undo-list t))
+                   (narrow-to-region (point-max) (point-max))
+                   (tramp-smb-call-winexe v)
+                   (when (tramp-smb-get-share v)
+                     (tramp-smb-send-command
+                      v (format
+                         "cd //%s%s"
+                         host
+                         (tramp-smb-shell-quote-argument
+                          (file-name-directory localname)))))
+                   (tramp-message v 6 "(%s); exit" command)
+                   (tramp-send-string v command)))
+               (setq p (tramp-get-connection-process v))
+               (when program
+                 (process-put p 'remote-command (cons program args))
+                 (tramp-set-connection-property
+                  p "remote-command" (cons program args)))
+               ;; Return value.
+               p)))
 
        ;; Save exit.
+       ;; FIXME: Does `tramp-get-connection-buffer' return the proper value?
        (with-current-buffer (tramp-get-connection-buffer v)
          (if (tramp-compat-string-search tramp-temp-buffer-name (buffer-name))
              (progn
                (set-process-buffer (tramp-get-connection-process v) nil)
                (kill-buffer (current-buffer)))
-           (set-buffer-modified-p bmp)))
-       (tramp-flush-connection-property v "process-name")
-       (tramp-flush-connection-property v "process-buffer")))))
+           (set-buffer-modified-p bmp)))))))
 
 (defun tramp-smb-handle-substitute-in-file-name (filename)
   "Like `substitute-in-file-name' for Tramp files.
@@ -1601,7 +1585,8 @@ errors for shares like \"C$/\", which are common in 
Microsoft Windows."
       filename
     (with-parsed-tramp-file-name filename nil
       ;; Ignore in LOCALNAME everything before "//".
-      (when (and (stringp localname) (string-match ".+?/\\(/\\|~\\)" 
localname))
+      (when (and (stringp localname)
+                (string-match (rx (+? nonl) "/" (group (| "/" "~"))) 
localname))
        (setq filename
              (concat (file-remote-p filename)
                      (replace-match "\\1" nil nil localname)))))
@@ -1635,8 +1620,9 @@ VEC or USER, or if there is no home directory, return 
nil."
          v 3 (format "Moving tmp file %s to %s" tmpfile filename)
        (unwind-protect
            (unless (tramp-smb-send-command
-                    v (format "put %s \"%s\""
-                              tmpfile (tramp-smb-get-localname v)))
+                    v (format "put %s %s"
+                              (tramp-smb-shell-quote-argument tmpfile)
+                              (tramp-smb-shell-quote-localname v)))
              (tramp-error v 'file-error "Cannot write `%s'" filename))
          (delete-file tmpfile))))))
 
@@ -1646,7 +1632,8 @@ VEC or USER, or if there is no home directory, return 
nil."
   "Return the share name of LOCALNAME."
   (save-match-data
     (let ((localname (tramp-file-name-unquote-localname vec)))
-      (when (string-match "^/?\\([^/]+\\)/" localname)
+      (when (string-match
+            (rx bol (? "/") (group (+ (not (any "/")))) "/") localname)
        (match-string 1 localname)))))
 
 (defun tramp-smb-get-localname (vec)
@@ -1656,7 +1643,8 @@ If VEC has no cifs capabilities, exchange \"/\" by 
\"\\\\\"."
     (let ((localname (tramp-file-name-unquote-localname vec)))
       (setq
        localname
-       (if (string-match "^/?[^/]+\\(/.*\\)" localname)
+       (if (string-match
+           (rx bol (? "/") (+ (not (any "/"))) (group "/" (* nonl))) localname)
           ;; There is a share, separated by "/".
           (if (not (tramp-smb-get-cifs-capabilities vec))
               (mapconcat
@@ -1664,17 +1652,17 @@ If VEC has no cifs capabilities, exchange \"/\" by 
\"\\\\\"."
                (match-string 1 localname) "")
             (match-string 1 localname))
         ;; There is just a share.
-        (if (string-match "^/?\\([^/]+\\)$" localname)
+        (if (string-match
+             (rx bol (? "/") (group (+ (not (any "/")))) eol) localname)
             (match-string 1 localname)
           "")))
 
       ;; Sometimes we have discarded `substitute-in-file-name'.
-      (when (string-match "\\(\\$\\$\\)\\(/\\|$\\)" localname)
+      (when (string-match (rx (group "$$") (group (| "/" eol))) localname)
        (setq localname (replace-match "$" nil nil localname 1)))
 
-      ;; A period followed by a space, or trailing periods and spaces,
-      ;; are not supported.
-      (when (string-match-p "\\. \\|\\.$\\| $" localname)
+      ;; A trailing space is not supported.
+      (when (string-match-p (rx " " eol) localname)
        (tramp-error
         vec 'file-error
         "Invalid file name %s" (tramp-make-tramp-file-name vec localname)))
@@ -1695,7 +1683,7 @@ Result is a list of (LOCALNAME MODE SIZE MONTH DAY TIME 
YEAR)."
     (setq localname (or localname "/"))
     (with-tramp-file-property v localname "file-entries"
       (let* ((share (tramp-smb-get-share v))
-            (cache (tramp-get-connection-property v "share-cache" nil))
+            (cache (tramp-get-connection-property v "share-cache"))
             res entry)
 
        (if (and (not share) cache)
@@ -1705,7 +1693,7 @@ Result is a list of (LOCALNAME MODE SIZE MONTH DAY TIME 
YEAR)."
          ;; Read entries.
          (if share
              (tramp-smb-send-command
-              v (format "dir \"%s*\"" (tramp-smb-get-localname v)))
+              v (format "dir %s*" (tramp-smb-shell-quote-localname v)))
            ;; `tramp-smb-maybe-open-connection' lists also the share names.
            (tramp-smb-maybe-open-connection v))
 
@@ -1787,13 +1775,14 @@ If SHARE is result, entries are of type dir.  
Otherwise, shares
 are listed.  Result is the list (LOCALNAME MODE SIZE MTIME)."
 ;; We are called from `tramp-smb-get-file-entries', which sets the
 ;; current buffer.
-  (let ((line (buffer-substring (point) (point-at-eol)))
+  (let ((line (buffer-substring (point) (line-end-position)))
        localname mode size month day hour min sec year mtime)
 
     (if (not share)
 
        ;; Read share entries.
-       (when (string-match "^Disk|\\([^|]+\\)|" line)
+       (when (string-match
+              (rx bol "Disk|" (group (+ (not (any "|")))) "|") line)
          (setq localname (match-string 1 line)
                mode "dr-xr-xr-x"
                size 0))
@@ -1802,14 +1791,17 @@ are listed.  Result is the list (LOCALNAME MODE SIZE 
MTIME)."
       (cl-block nil
 
        ;; year.
-       (if (string-match "\\([[:digit:]]+\\)$" line)
+       (if (string-match (rx (group (+ digit)) eol) line)
            (setq year (string-to-number (match-string 1 line))
                  line (substring line 0 -5))
          (cl-return))
 
        ;; time.
        (if (string-match
-            "\\([[:digit:]]+\\):\\([[:digit:]]+\\):\\([[:digit:]]+\\)$" line)
+            (rx (group (+ digit)) ":"
+                (group (+ digit)) ":"
+                (group (+ digit)) eol)
+            line)
            (setq hour (string-to-number (match-string 1 line))
                  min  (string-to-number (match-string 2 line))
                  sec  (string-to-number (match-string 3 line))
@@ -1817,28 +1809,28 @@ are listed.  Result is the list (LOCALNAME MODE SIZE 
MTIME)."
          (cl-return))
 
        ;; day.
-       (if (string-match "\\([[:digit:]]+\\)$" line)
+       (if (string-match (rx (group (+ digit)) eol) line)
            (setq day  (string-to-number (match-string 1 line))
                  line (substring line 0 -3))
          (cl-return))
 
        ;; month.
-       (if (string-match "\\(\\w+\\)$" line)
+       (if (string-match (rx (group (+ wordchar)) eol) line)
            (setq month (match-string 1 line)
                  line  (substring line 0 -4))
          (cl-return))
 
        ;; weekday.
-       (if (string-match-p "\\(\\w+\\)$" line)
+       (if (string-match-p (rx (group (+ wordchar)) eol) line)
            (setq line (substring line 0 -5))
          (cl-return))
 
        ;; size.
-       (if (string-match "\\([[:digit:]]+\\)$" line)
+       (if (string-match (rx (group (+ digit)) eol) line)
            (let ((length (- (max 10 (1+ (length (match-string 1 line)))))))
              (setq size (string-to-number (match-string 1 line)))
              (when (string-match
-                    "\\([ACDEHNORrsSTV]+\\)" (substring line length))
+                    (rx (+ (any "ACDEHNORSTVrs"))) (substring line length))
                (setq length (+ length (match-end 0))))
              (setq line (substring line 0 length)))
          (cl-return))
@@ -1847,7 +1839,7 @@ are listed.  Result is the list (LOCALNAME MODE SIZE 
MTIME)."
        ;;       NONINDEXED, NORMAL, OFFLINE, READONLY,
        ;;       REPARSE_POINT, SPARSE, SYSTEM, TEMPORARY, VOLID.
 
-       (if (string-match "\\([ACDEHNORrsSTV]+\\)?$" line)
+       (if (string-match (rx (? (group (+ (any "ACDEHNORSTVrs")))) eol) line)
            (setq
             mode (or (match-string 1 line) "")
             mode (format
@@ -1862,7 +1854,11 @@ are listed.  Result is the list (LOCALNAME MODE SIZE 
MTIME)."
          (cl-return))
 
        ;; localname.
-       (if (string-match "^\\s-+\\(\\S-\\(.*\\S-\\)?\\)\\s-*$" line)
+       (if (string-match
+            (rx bol (+ space)
+                (group (not space) (? (group (* nonl) (not space))))
+                (* space) eol)
+            line)
            (setq localname (match-string 1 line))
          (cl-return))))
 
@@ -1901,7 +1897,8 @@ are listed.  Result is the list (LOCALNAME MODE SIZE 
MTIME)."
                (member
                 "pathnames"
                 (split-string
-                 (buffer-substring (point) (point-at-eol)) nil 'omit)))))))))
+                 (buffer-substring (point) (line-end-position))
+                 nil 'omit)))))))))
 
 (defun tramp-smb-get-stat-capability (vec)
   "Check whether the SMB server supports the `stat' command."
@@ -1909,7 +1906,7 @@ are listed.  Result is the list (LOCALNAME MODE SIZE 
MTIME)."
   (if (and (tramp-smb-get-share vec)
           (process-live-p (tramp-get-connection-process vec)))
       (with-tramp-connection-property (tramp-get-process vec) "stat-capability"
-       (tramp-smb-send-command vec "stat \"/\""))))
+       (tramp-smb-send-command vec "stat /"))))
 
 
 ;; Connection functions.
@@ -1951,7 +1948,7 @@ If ARGUMENT is non-nil, use it as argument for
          (setq tramp-smb-version (shell-command-to-string command))
          (tramp-message vec 6 command)
          (tramp-message vec 6 "\n%s" tramp-smb-version)
-         (if (string-match "[ \t\n\r]+\\'" tramp-smb-version)
+         (if (string-match (rx (+ (any " \t\n\r")) eos) tramp-smb-version)
              (setq tramp-smb-version
                    (replace-match "" nil nil tramp-smb-version))))
 
@@ -1959,7 +1956,7 @@ If ARGUMENT is non-nil, use it as argument for
                 tramp-smb-version
                 (tramp-get-connection-property
                  vec "smbclient-version" tramp-smb-version))
-         (tramp-flush-directory-properties vec "")
+         (tramp-flush-directory-properties vec "/")
          (tramp-flush-connection-properties vec))
 
        (tramp-set-connection-property
@@ -2024,7 +2021,7 @@ If ARGUMENT is non-nil, use it as argument for
                      (if (not (zerop (length user))) (concat user "@") "")
                      host (or share ""))
 
-           (let* ((coding-system-for-read nil)
+           (let* (coding-system-for-read
                   (process-connection-type tramp-process-connection-type)
                   (p (let ((default-directory
                              tramp-compat-temporary-file-directory)
@@ -2055,24 +2052,6 @@ If ARGUMENT is non-nil, use it as argument for
                         tramp-smb-actions-with-share
                       tramp-smb-actions-without-share))
 
-                   ;; Check server version.
-                   ;; FIXME: With recent smbclient versions, this
-                   ;; information isn't printed anymore.
-                   ;; (unless argument
-                   ;;   (with-current-buffer (tramp-get-connection-buffer vec)
-                   ;;  (goto-char (point-min))
-                   ;;  (search-forward-regexp tramp-smb-server-version nil t)
-                   ;;  (let ((smbserver-version (match-string 0)))
-                   ;;    (unless
-                   ;;        (string-equal
-                   ;;         smbserver-version
-                   ;;         (tramp-get-connection-property
-                   ;;          vec "smbserver-version" smbserver-version))
-                   ;;      (tramp-flush-directory-properties vec "")
-                   ;;      (tramp-flush-connection-properties vec))
-                   ;;    (tramp-set-connection-property
-                   ;;     vec "smbserver-version" smbserver-version))))
-
                    ;; Set chunksize to 1.  smbclient reads its input
                    ;; character by character; if we send the string
                    ;; at once, it is read painfully slow.
@@ -2169,6 +2148,10 @@ Removes smb prompt.  Returns nil if an error message has 
appeared."
   (let ((system-type 'ms-dos))
     (tramp-unquote-shell-quote-argument s)))
 
+(defun tramp-smb-shell-quote-localname (vec)
+  "Call `tramp-smb-shell-quote-argument' on localname of VEC."
+  (tramp-smb-shell-quote-argument (tramp-smb-get-localname vec)))
+
 (add-hook 'tramp-unload-hook
          (lambda ()
            (unload-feature 'tramp-smb 'force)))
diff --git a/lisp/net/tramp-sshfs.el b/lisp/net/tramp-sshfs.el
index 61bf165f30..31720a605e 100644
--- a/lisp/net/tramp-sshfs.el
+++ b/lisp/net/tramp-sshfs.el
@@ -215,7 +215,7 @@ arguments to pass to the OPERATION."
          (progn
            ;; Read the expression.
            (goto-char (point-min))
-           (buffer-substring (point) (point-at-eol)))
+           (buffer-substring (point) (line-end-position)))
          ":" 'omit))))
    ;; The equivalent to `exec-directory'.
    `(,(tramp-file-local-name (expand-file-name default-directory)))))
@@ -333,7 +333,7 @@ arguments to pass to the OPERATION."
        ;; them.
        (when tmpinput (delete-file tmpinput))
        (when process-file-side-effects
-          (tramp-flush-directory-properties v ""))))))
+          (tramp-flush-directory-properties v "/"))))))
 
 (defun tramp-sshfs-handle-rename-file
     (filename newname &optional ok-if-already-exists)
@@ -355,18 +355,15 @@ arguments to pass to the OPERATION."
 
 (defun tramp-sshfs-handle-set-file-modes (filename mode &optional flag)
   "Like `set-file-modes' for Tramp files."
-  (with-parsed-tramp-file-name filename nil
-    (unless (and (eq flag 'nofollow) (file-symlink-p filename))
-      (tramp-flush-file-properties v localname)
+  (unless (and (eq flag 'nofollow) (file-symlink-p filename))
+    (tramp-skeleton-set-file-modes-times-uid-gid filename
       (tramp-compat-set-file-modes
        (tramp-fuse-local-file-name filename) mode flag))))
 
 (defun tramp-sshfs-handle-set-file-times (filename &optional timestamp flag)
   "Like `set-file-times' for Tramp files."
-  (or (file-exists-p filename) (write-region "" nil filename nil 0))
-  (with-parsed-tramp-file-name filename nil
-    (unless (and (eq flag 'nofollow) (file-symlink-p filename))
-      (tramp-flush-file-properties v localname)
+  (unless (and (eq flag 'nofollow) (file-symlink-p filename))
+    (tramp-skeleton-set-file-modes-times-uid-gid filename
       (tramp-compat-set-file-times
        (tramp-fuse-local-file-name filename) timestamp flag))))
 
@@ -449,7 +446,7 @@ connection if a previous connection has died for some 
reason."
     (funcall orig-fun)))
 
 (add-function
- :around  (symbol-function #'shell-mode) #'tramp-sshfs-tolerate-tilde)
+ :around (symbol-function #'shell-mode) #'tramp-sshfs-tolerate-tilde)
 (add-hook 'tramp-sshfs-unload-hook
          (lambda ()
            (remove-function
diff --git a/lisp/net/tramp-sudoedit.el b/lisp/net/tramp-sudoedit.el
index 420a593644..893afcdbbe 100644
--- a/lisp/net/tramp-sudoedit.el
+++ b/lisp/net/tramp-sudoedit.el
@@ -48,7 +48,9 @@
                                   ("-p" "Password:") ("--")))
                (tramp-password-previous-hop t)))
 
- (add-to-list 'tramp-default-user-alist '("\\`sudoedit\\'" nil "root"))
+ (add-to-list 'tramp-default-user-alist
+             `(,(rx bos (literal tramp-sudoedit-method) eos)
+               nil ,tramp-root-id-string))
 
  (tramp-set-completion-function
   tramp-sudoedit-method tramp-completion-function-alist-su))
@@ -241,6 +243,8 @@ absolute file names."
        (copy-directory filename newname keep-date t)
        (when (eq op 'rename) (delete-directory filename 'recursive)))
 
+    ;; FIXME: This should be optimized.  Computing `file-attributes'
+    ;; checks already, whether the file exists.
     (let ((t1 (tramp-sudoedit-file-name-p filename))
          (t2 (tramp-sudoedit-file-name-p newname))
          (file-times (file-attribute-modification-time
@@ -256,62 +260,61 @@ absolute file names."
          (msg-operation (if (eq op 'copy) "Copying" "Renaming")))
 
       (with-parsed-tramp-file-name (if t1 filename newname) nil
-       (unless (file-exists-p filename)
-         (tramp-error v 'file-missing filename))
-       (when (and (not ok-if-already-exists) (file-exists-p newname))
-         (tramp-error v 'file-already-exists newname))
-       (when (and (file-directory-p newname)
-                  (not (directory-name-p newname)))
-         (tramp-error v 'file-error "File is a directory %s" newname))
-
-       (if (or (and (file-remote-p filename) (not t1))
-               (and (file-remote-p newname)  (not t2)))
-           ;; We cannot copy or rename directly.
-           (let ((tmpfile (tramp-compat-make-temp-file filename)))
-             (if (eq op 'copy)
-                 (copy-file filename tmpfile t)
-               (rename-file filename tmpfile t))
-             (rename-file tmpfile newname ok-if-already-exists))
-
-         ;; Direct action.
-         (with-tramp-progress-reporter
-             v 0 (format "%s %s to %s" msg-operation filename newname)
-           (unless (tramp-sudoedit-send-command
-                    v sudoedit-operation
-                    (tramp-unquote-file-local-name filename)
-                    (tramp-unquote-file-local-name newname))
-             (tramp-error
-              v 'file-error
-              "Error %s `%s' `%s'" msg-operation filename newname))))
-
-       ;; When `newname' is local, we must change the ownership to
-       ;; the local user.
-       (unless (file-remote-p newname)
-         (tramp-set-file-uid-gid
-          (concat (file-remote-p filename) newname)
-          (tramp-get-local-uid 'integer)
-          (tramp-get-local-gid 'integer)))
-
-       ;; Set the time and mode. Mask possible errors.
-       (when keep-date
-         (ignore-errors
-           (tramp-compat-set-file-times
-            newname file-times (unless ok-if-already-exists 'nofollow))
-           (set-file-modes newname file-modes)))
-
-       ;; Handle `preserve-extended-attributes'.  We ignore possible
-       ;; errors, because ACL strings could be incompatible.
-       (when attributes
-         (ignore-errors
-           (set-file-extended-attributes newname attributes)))
-
-       (when (and t1 (eq op 'rename))
-         (with-parsed-tramp-file-name filename v1
-           (tramp-flush-file-properties v1 v1-localname)))
-
-       (when t2
-         (with-parsed-tramp-file-name newname v2
-           (tramp-flush-file-properties v2 v2-localname)))))))
+       (tramp-barf-if-file-missing v filename
+         (when (and (not ok-if-already-exists) (file-exists-p newname))
+           (tramp-error v 'file-already-exists newname))
+         (when (and (file-directory-p newname)
+                    (not (directory-name-p newname)))
+           (tramp-error v 'file-error "File is a directory %s" newname))
+
+         (if (or (and (file-remote-p filename) (not t1))
+                 (and (file-remote-p newname)  (not t2)))
+             ;; We cannot copy or rename directly.
+             (let ((tmpfile (tramp-compat-make-temp-file filename)))
+               (if (eq op 'copy)
+                   (copy-file filename tmpfile t)
+                 (rename-file filename tmpfile t))
+               (rename-file tmpfile newname ok-if-already-exists))
+
+           ;; Direct action.
+           (with-tramp-progress-reporter
+               v 0 (format "%s %s to %s" msg-operation filename newname)
+             (unless (tramp-sudoedit-send-command
+                      v sudoedit-operation
+                      (tramp-unquote-file-local-name filename)
+                      (tramp-unquote-file-local-name newname))
+               (tramp-error
+                v 'file-error
+                "Error %s `%s' `%s'" msg-operation filename newname))))
+
+         ;; When `newname' is local, we must change the ownership to
+         ;; the local user.
+         (unless (file-remote-p newname)
+           (tramp-set-file-uid-gid
+            (concat (file-remote-p filename) newname)
+            (tramp-get-local-uid 'integer)
+            (tramp-get-local-gid 'integer)))
+
+         ;; Set the time and mode. Mask possible errors.
+         (when keep-date
+           (ignore-errors
+             (tramp-compat-set-file-times
+              newname file-times (unless ok-if-already-exists 'nofollow))
+             (set-file-modes newname file-modes)))
+
+         ;; Handle `preserve-extended-attributes'.  We ignore possible
+         ;; errors, because ACL strings could be incompatible.
+         (when attributes
+           (ignore-errors
+             (set-file-extended-attributes newname attributes)))
+
+         (when (and t1 (eq op 'rename))
+           (with-parsed-tramp-file-name filename v1
+             (tramp-flush-file-properties v1 v1-localname)))
+
+         (when t2
+           (with-parsed-tramp-file-name newname v2
+             (tramp-flush-file-properties v2 v2-localname))))))))
 
 (defun tramp-sudoedit-handle-copy-file
   (filename newname &optional ok-if-already-exists keep-date
@@ -372,7 +375,9 @@ the result will be a local, non-Tramp, file name."
       (setq localname "~"))
     (unless (file-name-absolute-p localname)
       (setq localname (format "~%s/%s" user localname)))
-    (when (string-match "\\`~\\([^/]*\\)\\(.*\\)\\'" localname)
+    (when (string-match
+          (rx bos "~" (group (* (not (any "/")))) (group (* nonl)) eos)
+          localname)
       (let ((uname (match-string 1 localname))
            (fname (match-string 2 localname))
            hname)
@@ -381,11 +386,11 @@ the result will be a local, non-Tramp, file name."
        (when (setq hname (tramp-get-home-directory v uname))
          (setq localname (concat hname fname)))))
     ;; Do not keep "/..".
-    (when (string-match-p "^/\\.\\.?$" localname)
+    (when (string-match-p (rx bos "/" (** 1 2 ".") eos) localname)
       (setq localname "/"))
     ;; Do normal `expand-file-name' (this does "~user/", "/./" and "/../").
     (tramp-make-tramp-file-name
-     v (if (string-match-p "\\`\\(~[^/]*\\)\\(.*\\)\\'" localname)
+     v (if (string-prefix-p "~" localname)
           localname
         (tramp-run-real-handler
          #'expand-file-name (list localname))))))
@@ -407,34 +412,30 @@ the result will be a local, non-Tramp, file name."
        ;; provided by `tramp-sudoedit-send-command-string'.  Add it.
        (and (stringp result) (concat result "\n"))))))
 
+(defconst tramp-sudoedit-file-attributes
+  (format
+   ;; Apostrophes in the stat output are masked as
+   ;; `tramp-stat-marker', in order to make a proper shell escape of
+   ;; them in file names.  They are replaced in
+   ;; `tramp-sudoedit-send-command-and-read'.
+   (concat "((%s%%N%s) %%h (%s%%U%s . %%u) (%s%%G%s . %%g)"
+          " %%X %%Y %%Z %%s %s%%A%s t %%i -1)")
+   tramp-stat-marker tramp-stat-marker  ; %%N
+   tramp-stat-marker tramp-stat-marker  ; %%U
+   tramp-stat-marker tramp-stat-marker  ; %%G
+   tramp-stat-marker tramp-stat-marker) ; %%A
+  "stat format string to produce output suitable for use with
+`file-attributes' on the remote file system.")
+
 (defun tramp-sudoedit-handle-file-attributes (filename &optional id-format)
   "Like `file-attributes' for Tramp files."
-  (unless id-format (setq id-format 'integer))
+  ;; The result is cached in `tramp-convert-file-attributes'.
   (with-parsed-tramp-file-name (expand-file-name filename) nil
-    (with-tramp-file-property
-       v localname (format "file-attributes-%s" id-format)
-      (tramp-message v 5 "file attributes: %s" localname)
-      (ignore-errors
-       (tramp-convert-file-attributes
-        v
-        (tramp-sudoedit-send-command-and-read
-         v "env" "QUOTING_STYLE=locale" "stat" "-c"
-         (format
-          ;; Apostrophes in the stat output are masked as
-          ;; `tramp-stat-marker', in order to make a proper shell
-          ;; escape of them in file names.
-          "((%s%%N%s) %%h %s %s %%X %%Y %%Z %%s %s%%A%s t %%i -1)"
-          tramp-stat-marker tramp-stat-marker
-          (if (eq id-format 'integer)
-              "%u"
-            (eval-when-compile
-              (concat tramp-stat-marker "%U" tramp-stat-marker)))
-          (if (eq id-format 'integer)
-              "%g"
-            (eval-when-compile
-              (concat tramp-stat-marker "%G" tramp-stat-marker)))
-          tramp-stat-marker tramp-stat-marker)
-         (tramp-compat-file-name-unquote localname)))))))
+    (tramp-convert-file-attributes v localname id-format
+      (tramp-sudoedit-send-command-and-read
+       v "env" "QUOTING_STYLE=locale" "stat" "-c"
+       tramp-sudoedit-file-attributes
+       (tramp-compat-file-name-unquote localname)))))
 
 (defun tramp-sudoedit-handle-file-executable-p (filename)
   "Like `file-executable-p' for Tramp files."
@@ -472,7 +473,7 @@ the result will be a local, non-Tramp, file name."
        (delq
         nil
         (mapcar
-         (lambda (l) (and (not (string-match-p "^[[:space:]]*$" l)) l))
+         (lambda (l) (and (not (string-match-p (rx bol (* space) eol) l)) l))
          (split-string
           (tramp-get-buffer-string (tramp-get-connection-buffer v))
           "\n" 'omit))))))))
@@ -487,10 +488,9 @@ the result will be a local, non-Tramp, file name."
 
 (defun tramp-sudoedit-handle-set-file-modes (filename mode &optional flag)
   "Like `set-file-modes' for Tramp files."
-  (with-parsed-tramp-file-name filename nil
-    ;; It is unlikely that "chmod -h" works.
-    (unless (and (eq flag 'nofollow) (file-symlink-p filename))
-      (tramp-flush-file-properties v localname)
+  ;; It is unlikely that "chmod -h" works.
+  (unless (and (eq flag 'nofollow) (file-symlink-p filename))
+    (tramp-skeleton-set-file-modes-times-uid-gid filename
       (unless (tramp-sudoedit-send-command
               v "chmod" (format "%o" mode)
               (tramp-compat-file-name-unquote localname))
@@ -507,15 +507,17 @@ the result will be a local, non-Tramp, file name."
   (with-parsed-tramp-file-name filename nil
     (with-tramp-file-property v localname "file-selinux-context"
       (let ((context '(nil nil nil nil))
-           (regexp (concat "\\([[:alnum:]_]+\\):" "\\([[:alnum:]_]+\\):"
-                           "\\([[:alnum:]_]+\\):" "\\([[:alnum:]_]+\\)")))
+           (regexp (rx (group (+ (any "_" alnum))) ":"
+                       (group (+ (any "_" alnum))) ":"
+                       (group (+ (any "_" alnum))) ":"
+                       (group (+ (any "_" alnum))))))
        (when (and (tramp-sudoedit-remote-selinux-p v)
                   (tramp-sudoedit-send-command
                    v "ls" "-d" "-Z"
                    (tramp-compat-file-name-unquote localname)))
          (with-current-buffer (tramp-get-connection-buffer v)
            (goto-char (point-min))
-           (when (re-search-forward regexp (point-at-eol) t)
+           (when (re-search-forward regexp (line-end-position) t)
              (setq context (list (match-string 1) (match-string 2)
                                  (match-string 3) (match-string 4))))))
        ;; Return the context.
@@ -533,9 +535,9 @@ the result will be a local, non-Tramp, file name."
          (goto-char (point-min))
          (forward-line)
          (when (looking-at
-                (concat "[[:space:]]*\\([[:digit:]]+\\)"
-                        "[[:space:]]+\\([[:digit:]]+\\)"
-                        "[[:space:]]+\\([[:digit:]]+\\)"))
+                (rx (* space) (group (+ digit))
+                    (+ space) (group (+ digit))
+                    (+ space) (group (+ digit))))
            (list (string-to-number (match-string 1))
                  ;; The second value is the used size.  We need the
                  ;; free size.
@@ -545,8 +547,7 @@ the result will be a local, non-Tramp, file name."
 
 (defun tramp-sudoedit-handle-set-file-times (filename &optional time flag)
   "Like `set-file-times' for Tramp files."
-  (with-parsed-tramp-file-name filename nil
-    (tramp-flush-file-properties v localname)
+  (tramp-skeleton-set-file-modes-times-uid-gid filename
     (let ((time
           (if (or (null time)
                   (tramp-compat-time-equal-p time tramp-time-doesnt-exist)
@@ -718,6 +719,7 @@ VEC or USER, or if there is no home directory, return nil."
 (defun tramp-sudoedit-handle-get-remote-uid (vec id-format)
   "The uid of the remote connection VEC, in ID-FORMAT.
 ID-FORMAT valid values are `string' and `integer'."
+  ;; The result is cached in `tramp-get-remote-uid'.
   (if (equal id-format 'integer)
       (tramp-sudoedit-send-command-and-read vec "id" "-u")
     (tramp-sudoedit-send-command-string vec "id" "-un")))
@@ -725,19 +727,20 @@ ID-FORMAT valid values are `string' and `integer'."
 (defun tramp-sudoedit-handle-get-remote-gid (vec id-format)
   "The gid of the remote connection VEC, in ID-FORMAT.
 ID-FORMAT valid values are `string' and `integer'."
+  ;; The result is cached in `tramp-get-remote-gid'.
   (if (equal id-format 'integer)
       (tramp-sudoedit-send-command-and-read vec "id" "-g")
     (tramp-sudoedit-send-command-string vec "id" "-gn")))
 
 (defun tramp-sudoedit-handle-set-file-uid-gid (filename &optional uid gid)
   "Like `tramp-set-file-uid-gid' for Tramp files."
-    (with-parsed-tramp-file-name filename nil
-      (tramp-sudoedit-send-command
-       v "chown"
-       (format "%d:%d"
-              (or uid (tramp-get-remote-uid v 'integer))
-              (or gid (tramp-get-remote-gid v 'integer)))
-       (tramp-unquote-file-local-name filename))))
+  (tramp-skeleton-set-file-modes-times-uid-gid filename
+    (tramp-sudoedit-send-command
+     v "chown"
+     (format "%d:%d"
+            (or uid (tramp-get-remote-uid v 'integer))
+            (or gid (tramp-get-remote-gid v 'integer)))
+     (tramp-unquote-file-local-name filename))))
 
 
 ;; Internal functions.
@@ -754,7 +757,7 @@ ID-FORMAT valid values are `string' and `integer'."
     (delete-region (point-min) (point))
     ;; Delete empty lines.
     (goto-char (point-min))
-    (while (and (not (eobp)) (= (point) (point-at-eol)))
+    (while (and (not (eobp)) (= (point) (line-end-position)))
       (forward-line))
     (delete-region (point-min) (point))
     (tramp-message vec 3 "Process has finished.")
@@ -843,7 +846,7 @@ In case there is no valid Lisp expression, it raises an 
error."
       (condition-case nil
          (prog1 (read (current-buffer))
            ;; Error handling.
-           (when (re-search-forward "\\S-" (point-at-eol) t)
+           (when (re-search-forward (rx (not space)) (line-end-position) t)
              (error nil)))
        (error (tramp-error
                vec 'file-error
@@ -857,7 +860,7 @@ In case there is no valid Lisp expression, it raises an 
error."
       (tramp-message vec 6 "\n%s" (buffer-string))
       (goto-char (point-max))
       ;(delete-blank-lines)
-      (while (looking-back "[ \t\n]+" nil 'greedy)
+      (while (looking-back (rx (+ (any " \t\n"))) nil 'greedy)
        (delete-region (match-beginning 0) (point)))
       (when (> (point-max) (point-min))
        (substring-no-properties (buffer-string))))))
diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el
index cee8897b4f..bb6eeaa741 100644
--- a/lisp/net/tramp.el
+++ b/lisp/net/tramp.el
@@ -64,7 +64,8 @@
 (declare-function netrc-parse "netrc")
 (defvar auto-save-file-name-transforms)
 
-;; Reload `tramp-compat' when we reload `tramp-autoloads' of the GNU ELPA 
package.
+;; Reload `tramp-compat' when we reload `tramp-autoloads' of the GNU
+;; ELPA package.
 ;;;###autoload (when (featurep 'tramp-compat)
 ;;;###autoload   (load "tramp-compat" 'noerror 'nomessage))
 
@@ -77,7 +78,8 @@
   :link '(custom-manual "(tramp)Top")
   :version "22.1")
 
-(eval-and-compile ;; So it's also available in tramp-loaddefs.el!
+;;;###tramp-autoload
+(progn
   (defvar tramp--startup-hook nil
     "Forms to be executed at the end of tramp.el.")
   (put 'tramp--startup-hook 'tramp-suppress-trace t)
@@ -95,6 +97,7 @@
 If it is set to nil, all remote file names are used literally."
   :type 'boolean)
 
+;;;###tramp-autoload
 (defcustom tramp-verbose 3
   "Verbosity level for Tramp messages.
 Any level x includes messages for all levels 1 .. x-1.  The levels are
@@ -106,8 +109,8 @@ Any level x includes messages for all levels 1 .. x-1.  The 
levels are
  4  activities
  5  internal
  6  sent and received strings
- 7  file caching
- 8  connection properties
+ 7  connection properties
+ 8  file caching
  9  test commands
 10  traces (huge)
 11  call traces (maintainer only)."
@@ -186,9 +189,11 @@ See the variable `tramp-encoding-shell' for more 
information."
 ;; Since Emacs 26.1, `system-name' can return nil at build time if
 ;; Emacs is compiled with "--no-build-details".  We do expect it to be
 ;; a string.  (Bug#44481, Bug#54294)
+;;;###tramp-autoload
 (defconst tramp-system-name (or (system-name) "")
   "The system name Tramp is running locally.")
 
+;;;###tramp-autoload
 (defvar tramp-methods nil
   "Alist of methods for remote files.
 This is a list of entries of the form (NAME PARAM1 PARAM2 ...).
@@ -259,6 +264,7 @@ pair of the form (KEY VALUE).  The following KEYs are 
defined:
       argument if it is supported.
     - \"%z\" is replaced by the `tramp-scp-direct-remote-copying'
       argument if it is supported.
+    - \"%d\" is replaced by the device detected by `tramp-adb-get-device'.
 
     The existence of `tramp-login-args', combined with the
     absence of `tramp-copy-args', is an indication that the
@@ -403,6 +409,7 @@ See `tramp-methods' for possibilities.
 Also see `tramp-default-method-alist'."
   :type 'string)
 
+;;;###tramp-autoload
 (defcustom tramp-default-method-alist nil
   ;; FIXME: This is not an "alist", because its elements are not of
   ;; the form (KEY . VAL) but (KEY1 KEY2 VAL).
@@ -432,6 +439,7 @@ It is nil by default; otherwise settings in configuration 
files like
 This variable is regarded as obsolete, and will be removed soon."
   :type '(choice (const nil) string))
 
+;;;###tramp-autoload
 (defcustom tramp-default-user-alist nil
   ;; FIXME: This is not an "alist", because its elements are not of
   ;; the form (KEY . VAL) but (KEY1 KEY2 VAL).
@@ -453,6 +461,7 @@ empty string for the method name."
 Useful for su and sudo methods mostly."
   :type 'string)
 
+;;;###tramp-autoload
 (defcustom tramp-default-host-alist nil
   ;; FIXME: This is not an "alist", because its elements are not of
   ;; the form (KEY . VAL) but (KEY1 KEY2 VAL).
@@ -506,10 +515,10 @@ interpreted as a regular expression which always matches."
 ;; <https://debbugs.gnu.org/cgi/bugreport.cgi?bug=38079#20>.
 (defcustom tramp-restricted-shell-hosts-alist
   (when (and (eq system-type 'windows-nt)
-             (not (string-match-p "sh$" tramp-encoding-shell)))
-    (list (format "\\`\\(%s\\|%s\\)\\'"
-                 (regexp-quote (downcase tramp-system-name))
-                 (regexp-quote (upcase tramp-system-name)))))
+             (not (string-match-p (rx "sh" eol) tramp-encoding-shell)))
+    (list (rx bos (group (| (literal (downcase tramp-system-name))
+                           (literal (upcase tramp-system-name))))
+             eos)))
   "List of hosts, which run a restricted shell.
 This is a list of regular expressions, which denote hosts running
 a restricted shell like \"rbash\".  Those hosts can be used as
@@ -518,15 +527,16 @@ host runs a restricted shell, it shall be added to this 
list, too."
   :version "27.1"
   :type '(repeat (regexp :tag "Host regexp")))
 
+;;;###tramp-autoload
 (defcustom tramp-local-host-regexp
-  (concat
-   "\\`"
-   (regexp-opt
-    (list "localhost" "localhost6" tramp-system-name "127.0.0.1" "::1") t)
-   "\\'")
+  (rx bos
+      (regexp (regexp-opt
+              `("localhost" "localhost4" "localhost6"
+                ,tramp-system-name "127.0.0.1" "::1")))
+      eos)
   "Host names which are regarded as local host.
 If the local host runs a chrooted environment, set this to nil."
-  :version "27.1"
+  :version "29.1"
   :type '(choice (const :tag "Chrooted environment" nil)
                 (regexp :tag "Host regexp")))
 
@@ -570,8 +580,9 @@ followed by an equal number of backspaces to erase them will
 usually suffice.")
 
 (defconst tramp-echoed-echo-mark-regexp
-  (format "%s\\(\b\\( \b\\)?\\)\\{%d\\}"
-         tramp-echo-mark-marker tramp-echo-mark-marker-length)
+  (rx-to-string
+   `(: ,tramp-echo-mark-marker
+       (= ,tramp-echo-mark-marker-length (group "\b" (? " \b")))))
   "Regexp which matches `tramp-echo-mark' as it gets echoed by \
 the remote shell.")
 
@@ -588,7 +599,7 @@ if you need to change this."
   :type 'string)
 
 (defcustom tramp-login-prompt-regexp
-  ".*\\(user\\|login\\)\\( .*\\)?: *"
+  (rx (* nonl) (group (| "user" "login")) (? (group " " (* nonl))) ":" (* " "))
   "Regexp matching login-like prompts.
 The regexp should match at end of buffer.
 
@@ -600,8 +611,11 @@ Sometimes the prompt is reported to look like \"login 
as:\"."
   ;; displayed at the beginning of the line (and Zsh uses it).
   ;; Allow also [] style prompts.  They can appear only during
   ;; connection initialization; Tramp redefines the prompt afterwards.
-  (concat "\\(?:^\\|\r\\)"
-         "[^]#$%>\n]*#?[]#$%>] *\\(\e\\[[[:digit:];]*[[:alpha:]] *\\)*")
+  (rx (| bol "\r")
+      (* (not (any "\n#$%>]")))
+      (? "#") (any "#$%>]") (* space)
+      ;; Escape characters.
+      (* "[" (* (any ";" digit)) alpha (* space)))
   "Regexp to match prompts from remote shell.
 Normally, Tramp expects you to configure `shell-prompt-pattern'
 correctly, but sometimes it happens that you are connecting to a
@@ -616,11 +630,13 @@ This regexp must match both `tramp-initial-end-of-output' 
and
   :type 'regexp)
 
 (defcustom tramp-password-prompt-regexp
-  (format "^.*\\(%s\\).*:\^@? *" (regexp-opt password-word-equivalents))
+  (rx bol (* nonl)
+      (group (regexp (regexp-opt password-word-equivalents)))
+      (* nonl) ":" (? "\^@") (* space))
   "Regexp matching password-like prompts.
 The regexp should match at end of buffer.
 
-This variable is, by default, initialised from
+This variable is, by default, initialized from
 `password-word-equivalents' when Tramp is loaded, and it is
 usually more convenient to add new passphrases to that variable
 instead of altering this variable.
@@ -630,36 +646,26 @@ The `sudo' program appears to insert a `^@' character 
into the prompt."
   :type 'regexp)
 
 (defcustom tramp-wrong-passwd-regexp
-  (concat "^.*"
-         ;; These strings should be on the last line
-         (regexp-opt '("Permission denied"
-                       "Login incorrect"
-                       "Login Incorrect"
-                       "Connection refused"
-                       "Connection closed"
-                       "Timeout, server not responding."
-                       "Sorry, try again."
-                       "Name or service not known"
-                       "Host key verification failed."
-                       "No supported authentication methods left to try!")
-                     t)
-         ".*"
-         "\\|"
-         "^.*\\("
-         ;; Here comes a list of regexes, separated by \\|
-         "Received signal [[:digit:]]+"
-         "\\).*")
+  (rx bol (* nonl)
+      (| "Permission denied"
+        "Login [Ii]ncorrect"
+        "Connection refused"
+        "Connection closed"
+        "Timeout, server not responding."
+        "Sorry, try again."
+        "Name or service not known"
+        "Host key verification failed."
+        "No supported authentication methods left to try!"
+        (: "Received signal " (+ digit)))
+      (* nonl))
   "Regexp matching a `login failed' message.
 The regexp should match at end of buffer."
   :type 'regexp)
 
 (defcustom tramp-yesno-prompt-regexp
-  (concat
-   (regexp-opt
-    '("Are you sure you want to continue connecting (yes/no)?"
-      "Are you sure you want to continue connecting (yes/no/[fingerprint])?")
-    t)
-   "\\s-*")
+  (rx "Are you sure you want to continue connecting (yes/no"
+      (? "/[fingerprint]") ")?"
+      (* space))
   "Regular expression matching all yes/no queries which need to be confirmed.
 The confirmation should be done with yes or no.
 The regexp should match at end of buffer.
@@ -667,17 +673,16 @@ See also `tramp-yn-prompt-regexp'."
   :type 'regexp)
 
 (defcustom tramp-yn-prompt-regexp
-  (concat
-   (regexp-opt '("Store key in cache? (y/n)"
-                "Update cached key? (y/n, Return cancels connection)")
-               t)
-   "\\s-*")
+  (rx (| "Store key in cache? (y/n)"
+        "Update cached key? (y/n, Return cancels connection)")
+      (* space))
   "Regular expression matching all y/n queries which need to be confirmed.
 The confirmation should be done with y or n.
 The regexp should match at end of buffer.
 See also `tramp-yesno-prompt-regexp'."
   :type 'regexp)
 
+;;;###tramp-autoload
 (defcustom tramp-terminal-type "dumb"
   "Value of TERM environment variable for logging in to remote host.
 Because Tramp wants to parse the output of the remote shell, it is easily
@@ -687,11 +692,10 @@ files conditionalize this setup based on the TERM 
environment variable."
   :type 'string)
 
 (defcustom tramp-terminal-prompt-regexp
-  (concat "\\("
-         "TERM = (.*)"
-         "\\|"
-         "Terminal type\\? \\[.*\\]"
-         "\\)\\s-*")
+  (rx (group
+       (| (: "TERM = (" (* nonl) ")")
+         (: "Terminal type? [" (* nonl) "]")))
+      (* space))
   "Regular expression matching all terminal setting prompts.
 The regexp should match at end of buffer.
 The answer will be provided by `tramp-action-terminal', which see."
@@ -702,7 +706,7 @@ The answer will be provided by `tramp-action-terminal', 
which see."
 ;; "-no-antispoof".  However, since we don't know which PuTTY
 ;; version is installed, we must react interactively.
 (defcustom tramp-antispoof-regexp
-  (regexp-quote "Access granted. Press Return to begin session. ")
+  (rx (literal "Access granted. Press Return to begin session. "))
   "Regular expression matching plink's anti-spoofing message.
 The regexp should match at end of buffer."
   :version "27.1"
@@ -712,42 +716,42 @@ The regexp should match at end of buffer."
 ;; with their finger.  We must tell it to the user.
 ;; Added in OpenSSH 8.2.  I've tested it with yubikey.
 (defcustom tramp-security-key-confirm-regexp
-  "^\r*Confirm user presence for key .*[\r\n]*"
+  (rx bol (* "\r") "Confirm user presence for key " (* nonl) (* (any "\r\n")))
   "Regular expression matching security key confirmation message.
 The regexp should match at end of buffer."
   :version "28.1"
   :type 'regexp)
 
 (defcustom tramp-security-key-confirmed-regexp
-  "^\r*User presence confirmed[\r\n]*"
+  (rx bol (* "\r") "User presence confirmed" (* (any "\r\n")))
   "Regular expression matching security key confirmation message.
 The regexp should match at end of buffer."
   :version "28.1"
   :type 'regexp)
 
 (defcustom tramp-security-key-timeout-regexp
-  "^\r*sign_and_send_pubkey: signing failed for .*[\r\n]*"
+  (rx bol (* "\r") "sign_and_send_pubkey: signing failed for "
+      (* nonl) (* (any "\r\n")))
   "Regular expression matching security key timeout message.
 The regexp should match at end of buffer."
   :version "28.1"
   :type 'regexp)
 
 (defcustom tramp-operation-not-permitted-regexp
-  (concat "\\(" "preserving times.*" "\\|" "set mode" "\\)" ":\\s-*"
-         (regexp-opt '("Operation not permitted") t))
+  (rx (| (: "preserving times" (* nonl)) "set mode") ":" (* space)
+      "Operation not permitted")
   "Regular expression matching keep-date problems in (s)cp operations.
 Copying has been performed successfully already, so this message can
 be ignored safely."
   :type 'regexp)
 
 (defcustom tramp-copy-failed-regexp
-  (concat "\\(.+: "
-          (regexp-opt '("Permission denied"
-                        "not a regular file"
-                        "is a directory"
-                        "No such file or directory")
-                      t)
-          "\\)\\s-*")
+  (rx (+ nonl) ": "
+      (| "No such file or directory"
+        "Permission denied"
+        "is a directory"
+        "not a regular file")
+      (* space))
   "Regular expression matching copy problems in (s)cp operations."
   :type 'regexp)
 
@@ -798,6 +802,23 @@ Customize.  See also `tramp-change-syntax'."
   :initialize #'custom-initialize-default
   :set #'tramp-set-syntax)
 
+(defvar tramp-prefix-format)
+(defvar tramp-prefix-regexp)
+(defvar tramp-method-regexp)
+(defvar tramp-postfix-method-format)
+(defvar tramp-postfix-method-regexp)
+(defvar tramp-prefix-ipv6-format)
+(defvar tramp-prefix-ipv6-regexp)
+(defvar tramp-postfix-ipv6-format)
+(defvar tramp-postfix-ipv6-regexp)
+(defvar tramp-postfix-host-format)
+(defvar tramp-postfix-host-regexp)
+(defvar tramp-remote-file-name-spec-regexp)
+(defvar tramp-file-name-structure)
+(defvar tramp-file-name-regexp)
+(defvar tramp-completion-method-regexp)
+(defvar tramp-completion-file-name-regexp)
+
 (defun tramp-set-syntax (symbol value)
   "Set SYMBOL to value VALUE.
 Used in user option `tramp-syntax'.  There are further variables
@@ -811,24 +832,25 @@ to be set, depending on VALUE."
   ;; Set the value:
   (set-default symbol value)
   ;; Reset the depending variables.
-  (with-no-warnings
-    (setq tramp-prefix-format (tramp-build-prefix-format)
-         tramp-prefix-regexp (tramp-build-prefix-regexp)
-         tramp-method-regexp (tramp-build-method-regexp)
-         tramp-postfix-method-format (tramp-build-postfix-method-format)
-         tramp-postfix-method-regexp (tramp-build-postfix-method-regexp)
-         tramp-prefix-ipv6-format (tramp-build-prefix-ipv6-format)
-         tramp-prefix-ipv6-regexp (tramp-build-prefix-ipv6-regexp)
-         tramp-postfix-ipv6-format (tramp-build-postfix-ipv6-format)
-         tramp-postfix-ipv6-regexp (tramp-build-postfix-ipv6-regexp)
-         tramp-postfix-host-format (tramp-build-postfix-host-format)
-         tramp-postfix-host-regexp (tramp-build-postfix-host-regexp)
-         tramp-remote-file-name-spec-regexp
-         (tramp-build-remote-file-name-spec-regexp)
-         tramp-file-name-structure (tramp-build-file-name-structure)
-         tramp-file-name-regexp (tramp-build-file-name-regexp)
-         tramp-completion-file-name-regexp
-          (tramp-build-completion-file-name-regexp)))
+  (setq tramp-prefix-format (tramp-build-prefix-format)
+       tramp-prefix-regexp (tramp-build-prefix-regexp)
+       tramp-method-regexp (tramp-build-method-regexp)
+       tramp-postfix-method-format (tramp-build-postfix-method-format)
+       tramp-postfix-method-regexp (tramp-build-postfix-method-regexp)
+       tramp-prefix-ipv6-format (tramp-build-prefix-ipv6-format)
+       tramp-prefix-ipv6-regexp (tramp-build-prefix-ipv6-regexp)
+       tramp-postfix-ipv6-format (tramp-build-postfix-ipv6-format)
+       tramp-postfix-ipv6-regexp (tramp-build-postfix-ipv6-regexp)
+       tramp-postfix-host-format (tramp-build-postfix-host-format)
+       tramp-postfix-host-regexp (tramp-build-postfix-host-regexp)
+       tramp-remote-file-name-spec-regexp
+       (tramp-build-remote-file-name-spec-regexp)
+       tramp-file-name-structure (tramp-build-file-name-structure)
+       tramp-file-name-regexp (tramp-build-file-name-regexp)
+       tramp-completion-method-regexp
+        (tramp-build-completion-method-regexp)
+       tramp-completion-file-name-regexp
+        (tramp-build-completion-file-name-regexp))
   ;; Rearrange file name handlers.
   (tramp-register-file-name-handlers))
 
@@ -861,30 +883,31 @@ Raise an error if it is invalid."
   "Return `tramp-prefix-format' according to `tramp-syntax'."
   (tramp-lookup-syntax tramp-prefix-format-alist))
 
-(defvar tramp-prefix-format nil ;Initialized when defining `tramp-syntax'!
+(defvar tramp-prefix-format nil ; Initialized when defining `tramp-syntax'!
   "String matching the very beginning of Tramp file names.
 Used in `tramp-make-tramp-file-name'.")
 
 (defun tramp-build-prefix-regexp ()
   "Return `tramp-prefix-regexp'."
-  (concat "^" (regexp-quote tramp-prefix-format)))
+  (rx bol (literal (tramp-build-prefix-format))))
 
-(defvar tramp-prefix-regexp nil ;Initialized when defining `tramp-syntax'!
+(defvar tramp-prefix-regexp nil ; Initialized when defining `tramp-syntax'!
   "Regexp matching the very beginning of Tramp file names.
 Should always start with \"^\".  Derived from `tramp-prefix-format'.")
 
 (defconst tramp-method-regexp-alist
-  '((default    . "[[:alnum:]-]+")
+  `((default . ,(rx (| (literal tramp-default-method-marker) (>= 2 alnum))))
     (simplified . "")
-    (separate   . "[[:alnum:]-]*"))
+    (separate
+     . ,(rx (? (| (literal tramp-default-method-marker) (>= 2 alnum))))))
   "Alist mapping Tramp syntax to regexps matching methods identifiers.")
 
 (defun tramp-build-method-regexp ()
   "Return `tramp-method-regexp' according to `tramp-syntax'."
   (tramp-lookup-syntax tramp-method-regexp-alist))
 
-(defvar tramp-method-regexp nil ;Initialized when defining `tramp-syntax'!
-  "Regexp matching methods identifiers.
+(defvar tramp-method-regexp nil ; Initialized when defining `tramp-syntax'!
+  "Regexp matching method identifiers.
 The `ftp' syntax does not support methods.")
 
 (defconst tramp-postfix-method-format-alist
@@ -897,47 +920,47 @@ The `ftp' syntax does not support methods.")
   "Return `tramp-postfix-method-format' according to `tramp-syntax'."
   (tramp-lookup-syntax tramp-postfix-method-format-alist))
 
-(defvar tramp-postfix-method-format nil ;Init'd when defining `tramp-syntax'!
+(defvar tramp-postfix-method-format nil ; Init'd when defining `tramp-syntax'!
   "String matching delimiter between method and user or host names.
 The `ftp' syntax does not support methods.
 Used in `tramp-make-tramp-file-name'.")
 
 (defun tramp-build-postfix-method-regexp ()
   "Return `tramp-postfix-method-regexp'."
-  (regexp-quote tramp-postfix-method-format))
+  (rx (literal (tramp-build-postfix-method-format))))
 
-(defvar tramp-postfix-method-regexp nil ;Init'd when defining `tramp-syntax'!
+(defvar tramp-postfix-method-regexp nil ; Init'd when defining `tramp-syntax'!
   "Regexp matching delimiter between method and user or host names.
 Derived from `tramp-postfix-method-format'.")
 
-(defconst tramp-user-regexp "[^/|: \t]+"
+(defconst tramp-user-regexp (rx (+ (not (any "/:|" space))))
   "Regexp matching user names.")
 
 (defconst tramp-prefix-domain-format "%"
   "String matching delimiter between user and domain names.")
 
-(defconst tramp-prefix-domain-regexp (regexp-quote tramp-prefix-domain-format)
+(defconst tramp-prefix-domain-regexp (rx (literal tramp-prefix-domain-format))
   "Regexp matching delimiter between user and domain names.
 Derived from `tramp-prefix-domain-format'.")
 
-(defconst tramp-domain-regexp "[[:alnum:]_.-]+"
+(defconst tramp-domain-regexp (rx (+ (any "._-" alnum)))
   "Regexp matching domain names.")
 
 (defconst tramp-user-with-domain-regexp
-  (concat "\\(" tramp-user-regexp "\\)"
-               tramp-prefix-domain-regexp
-         "\\(" tramp-domain-regexp "\\)")
+  (rx (group (regexp tramp-user-regexp))
+             (regexp tramp-prefix-domain-regexp)
+      (group (regexp tramp-domain-regexp)))
   "Regexp matching user names with domain names.")
 
 (defconst tramp-postfix-user-format "@"
   "String matching delimiter between user and host names.
 Used in `tramp-make-tramp-file-name'.")
 
-(defconst tramp-postfix-user-regexp (regexp-quote tramp-postfix-user-format)
+(defconst tramp-postfix-user-regexp (rx (literal tramp-postfix-user-format))
   "Regexp matching delimiter between user and host names.
 Derived from `tramp-postfix-user-format'.")
 
-(defconst tramp-host-regexp "[[:alnum:]_.%-]+"
+(defconst tramp-host-regexp (rx (+ (any "%._-" alnum)))
   "Regexp matching host names.")
 
 (defconst tramp-prefix-ipv6-format-alist
@@ -950,22 +973,22 @@ Derived from `tramp-postfix-user-format'.")
   "Return `tramp-prefix-ipv6-format' according to `tramp-syntax'."
   (tramp-lookup-syntax tramp-prefix-ipv6-format-alist))
 
-(defvar tramp-prefix-ipv6-format nil ;Initialized when defining `tramp-syntax'!
+(defvar tramp-prefix-ipv6-format nil ; Initialized when defining 
`tramp-syntax'!
   "String matching left hand side of IPv6 addresses.
 Used in `tramp-make-tramp-file-name'.")
 
 (defun tramp-build-prefix-ipv6-regexp ()
   "Return `tramp-prefix-ipv6-regexp'."
-  (regexp-quote tramp-prefix-ipv6-format))
+  (rx (literal tramp-prefix-ipv6-format)))
 
-(defvar tramp-prefix-ipv6-regexp nil ;Initialized when defining `tramp-syntax'!
+(defvar tramp-prefix-ipv6-regexp nil ; Initialized when defining 
`tramp-syntax'!
   "Regexp matching left hand side of IPv6 addresses.
 Derived from `tramp-prefix-ipv6-format'.")
 
 ;; The following regexp is a bit sloppy.  But it shall serve our
 ;; purposes.  It covers also IPv4 mapped IPv6 addresses, like in
 ;; "::ffff:192.168.0.1".
-(defconst tramp-ipv6-regexp "\\(?:[[:alnum:]]*:\\)+[[:alnum:].]+"
+(defconst tramp-ipv6-regexp (rx (+ (* alnum) ":") (* (any "." alnum)))
   "Regexp matching IPv6 addresses.")
 
 (defconst tramp-postfix-ipv6-format-alist
@@ -978,38 +1001,38 @@ Derived from `tramp-prefix-ipv6-format'.")
   "Return `tramp-postfix-ipv6-format' according to `tramp-syntax'."
   (tramp-lookup-syntax tramp-postfix-ipv6-format-alist))
 
-(defvar tramp-postfix-ipv6-format nil ;Initialized when defining 
`tramp-syntax'!
+(defvar tramp-postfix-ipv6-format nil ; Initialized when defining 
`tramp-syntax'!
   "String matching right hand side of IPv6 addresses.
 Used in `tramp-make-tramp-file-name'.")
 
 (defun tramp-build-postfix-ipv6-regexp ()
   "Return `tramp-postfix-ipv6-regexp'."
-  (regexp-quote tramp-postfix-ipv6-format))
+  (rx (literal tramp-postfix-ipv6-format)))
 
-(defvar tramp-postfix-ipv6-regexp nil ;Initialized when defining 
`tramp-syntax'!
+(defvar tramp-postfix-ipv6-regexp nil ; Initialized when defining 
`tramp-syntax'!
   "Regexp matching right hand side of IPv6 addresses.
 Derived from `tramp-postfix-ipv6-format'.")
 
 (defconst tramp-prefix-port-format "#"
   "String matching delimiter between host names and port numbers.")
 
-(defconst tramp-prefix-port-regexp (regexp-quote tramp-prefix-port-format)
+(defconst tramp-prefix-port-regexp (rx (literal tramp-prefix-port-format))
   "Regexp matching delimiter between host names and port numbers.
 Derived from `tramp-prefix-port-format'.")
 
-(defconst tramp-port-regexp "[[:digit:]]+"
+(defconst tramp-port-regexp (rx (+ digit))
   "Regexp matching port numbers.")
 
 (defconst tramp-host-with-port-regexp
-  (concat "\\(" tramp-host-regexp "\\)"
-               tramp-prefix-port-regexp
-         "\\(" tramp-port-regexp "\\)")
+  (rx (group (regexp tramp-host-regexp))
+             (regexp tramp-prefix-port-regexp)
+      (group (regexp tramp-port-regexp)))
   "Regexp matching host names with port numbers.")
 
 (defconst tramp-postfix-hop-format "|"
   "String matching delimiter after ad-hoc hop definitions.")
 
-(defconst tramp-postfix-hop-regexp (regexp-quote tramp-postfix-hop-format)
+(defconst tramp-postfix-hop-regexp (rx (literal tramp-postfix-hop-format))
   "Regexp matching delimiter after ad-hoc hop definitions.
 Derived from `tramp-postfix-hop-format'.")
 
@@ -1023,19 +1046,19 @@ Derived from `tramp-postfix-hop-format'.")
   "Return `tramp-postfix-host-format' according to `tramp-syntax'."
   (tramp-lookup-syntax tramp-postfix-host-format-alist))
 
-(defvar tramp-postfix-host-format nil ;Initialized when defining 
`tramp-syntax'!
+(defvar tramp-postfix-host-format nil ; Initialized when defining 
`tramp-syntax'!
   "String matching delimiter between host names and localnames.
 Used in `tramp-make-tramp-file-name'.")
 
 (defun tramp-build-postfix-host-regexp ()
   "Return `tramp-postfix-host-regexp'."
-  (regexp-quote tramp-postfix-host-format))
+  (rx (literal tramp-postfix-host-format)))
 
-(defvar tramp-postfix-host-regexp nil ;Initialized when defining 
`tramp-syntax'!
+(defvar tramp-postfix-host-regexp nil ; Initialized when defining 
`tramp-syntax'!
   "Regexp matching delimiter between host names and localnames.
 Derived from `tramp-postfix-host-format'.")
 
-(defconst tramp-localname-regexp "[^\n\r]*\\'"
+(defconst tramp-localname-regexp (rx (* (not (any "\r\n"))) eos)
   "Regexp matching localnames.")
 
 (defconst tramp-unknown-id-string "UNKNOWN"
@@ -1044,21 +1067,32 @@ Derived from `tramp-postfix-host-format'.")
 (defconst tramp-unknown-id-integer -1
   "Integer used to denote an unknown user or group.")
 
+;;;###tramp-autoload
+(defconst tramp-root-id-string "root"
+  "String used to denote the root user or group.")
+
+(defconst tramp-root-id-integer 0
+  "Integer used to denote the root user or group.")
+
 ;;; File name format:
 
 (defun tramp-build-remote-file-name-spec-regexp ()
   "Construct a regexp matching a Tramp file name for a Tramp syntax.
 It is expected, that `tramp-syntax' has the proper value."
-  (concat
-           "\\("   tramp-method-regexp "\\)" tramp-postfix-method-regexp
-   "\\(?:" "\\("   tramp-user-regexp   "\\)" tramp-postfix-user-regexp   "\\)?"
-   "\\("   "\\(?:" tramp-host-regexp   "\\|"
-                  tramp-prefix-ipv6-regexp  "\\(?:" tramp-ipv6-regexp "\\)?"
-                                            tramp-postfix-ipv6-regexp "\\)"
-          "\\(?:" tramp-prefix-port-regexp  tramp-port-regexp "\\)?" "\\)?"))
+  (rx ;; Method.
+      (group (regexp tramp-method-regexp)) (regexp tramp-postfix-method-regexp)
+      ;; Optional user.
+      (? (group (regexp tramp-user-regexp)) (regexp tramp-postfix-user-regexp))
+      ;; Optional host.
+      (? (group (| (regexp tramp-host-regexp)
+                   (: (regexp tramp-prefix-ipv6-regexp)
+                     (? (regexp tramp-ipv6-regexp))
+                     (regexp tramp-postfix-ipv6-regexp)))
+      ;; Optional port.
+      (? (regexp tramp-prefix-port-regexp) (regexp tramp-port-regexp))))))
 
 (defvar tramp-remote-file-name-spec-regexp
-   nil ;Initialized when defining `tramp-syntax'!
+  nil ; Initialized when defining `tramp-syntax'!
   "Regular expression matching a Tramp file name between prefix and postfix.")
 
 (defun tramp-build-file-name-structure ()
@@ -1066,15 +1100,15 @@ It is expected, that `tramp-syntax' has the proper 
value."
 It is expected, that `tramp-syntax' has the proper value.
 See `tramp-file-name-structure'."
   (list
-   (concat
-    tramp-prefix-regexp
-    "\\(" "\\(?:" tramp-remote-file-name-spec-regexp
-                  tramp-postfix-hop-regexp "\\)+" "\\)?"
-    tramp-remote-file-name-spec-regexp tramp-postfix-host-regexp
-    "\\(" tramp-localname-regexp "\\)")
+   (rx (regexp tramp-prefix-regexp)
+       (? (group (+ (regexp tramp-remote-file-name-spec-regexp)
+                   (regexp tramp-postfix-hop-regexp))))
+       (regexp tramp-remote-file-name-spec-regexp)
+       (regexp tramp-postfix-host-regexp)
+       (group (regexp tramp-localname-regexp)))
    5 6 7 8 1))
 
-(defvar tramp-file-name-structure nil ;Initialized when defining 
`tramp-syntax'!
+(defvar tramp-file-name-structure nil ; Initialized when defining 
`tramp-syntax'!
   "List detailing the Tramp file name structure.
 This is a list of six elements (REGEXP METHOD USER HOST FILE HOP).
 
@@ -1099,7 +1133,8 @@ See also `tramp-file-name-regexp'.")
   (car tramp-file-name-structure))
 
 ;;;###autoload
-(defconst tramp-initial-file-name-regexp "\\`/[^/:]+:[^/:]*:"
+(defconst tramp-initial-file-name-regexp
+  (rx bos "/" (+ (not (any "/:"))) ":" (* (not (any "/:"))) ":")
   "Value for `tramp-file-name-regexp' for autoload.
 It must match the initial `tramp-syntax' settings.")
 
@@ -1116,78 +1151,56 @@ initial value is overwritten by the car of 
`tramp-file-name-structure'.")
   :version "27.1"
   :type '(choice (const nil) regexp))
 
-(defconst tramp-completion-file-name-regexp-default
-  (concat
-   "\\`"
-   ;; `file-name-completion' uses absolute paths for matching.  This
-   ;; means that on W32 systems, something like "/ssh:host:~/path"
-   ;; becomes "c:/ssh:host:~/path".  See also `tramp-drop-volume-letter'.
-   (when (eq system-type 'windows-nt)
-       "\\(?:[[:alpha:]]:\\)?")
-   "/\\("
-   ;; Optional multi hop.
-   "\\([^/|:]+:[^/|:]*|\\)*"
-   ;; Last hop.
-   (if (memq system-type '(cygwin windows-nt))
-       ;; The method is either "-", or at least two characters.
-       "\\(-\\|[^/|:]\\{2,\\}\\)"
-     ;; At least one character for method.
-     "[^/|:]+")
-   ;; Method separator, user name and host name.
-   "\\(:[^/|:]*\\)?"
-   "\\)?\\'")
-  "Value for `tramp-completion-file-name-regexp' for default remoting.
-See `tramp-file-name-structure' for more explanations.
-
-On W32 systems, the volume letter must be ignored.")
-
-(defconst tramp-completion-file-name-regexp-simplified
-  (concat
-   "\\`"
-   ;; Allow the volume letter at the beginning of the path.  See the
-   ;; comment in `tramp-completion-file-name-regexp-default' for more
-   ;; details.
-   (when (eq system-type 'windows-nt)
-     "\\(?:[[:alpha:]]:\\)?")
-   "/\\("
-   ;; Optional multi hop.
-   "\\([^/|:]*|\\)*"
-   ;; Last hop.
-   (if (memq system-type '(cygwin windows-nt))
-       ;; At least two characters.
-       "[^/|:]\\{2,\\}"
-     ;; At least one character.
-     "[^/|:]+")
-   "\\)?\\'")
-  "Value for `tramp-completion-file-name-regexp' for simplified style remoting.
-See `tramp-file-name-structure' for more explanations.
-
-On W32 systems, the volume letter must be ignored.")
-
-(defconst tramp-completion-file-name-regexp-separate
-  (concat
-   "\\`"
-   ;; Allow the volume letter at the beginning of the path.  See the
-   ;; comment in `tramp-completion-file-name-regexp-default' for more
-   ;; details.
-   (when (eq system-type 'windows-nt)
-     "\\(?:[[:alpha:]]:\\)?")
-   "/\\(\\[[^]]*\\)?\\'")
-  "Value for `tramp-completion-file-name-regexp' for separate remoting.
-See `tramp-file-name-structure' for more explanations.")
-
-(defconst tramp-completion-file-name-regexp-alist
-  `((default    . ,tramp-completion-file-name-regexp-default)
-    (simplified . ,tramp-completion-file-name-regexp-simplified)
-    (separate   . ,tramp-completion-file-name-regexp-separate))
-  "Alist mapping incomplete Tramp file names.")
+(defconst tramp-volume-letter-regexp
+  (if (eq system-type 'windows-nt)
+      (rx bos alpha ":") "")
+  "Volume letter on MS Windows.")
+
+;; `tramp-method-regexp' needs at least two characters, in order to
+;; distinguish from volume letter.  This is in the way when completing.
+(defconst tramp-completion-method-regexp-alist
+  `((default    . ,(rx (| (literal tramp-default-method-marker) (+ alnum))))
+    (simplified . "")
+    (separate   . ,(rx (| (literal tramp-default-method-marker) (* alnum)))))
+  "Alist mapping Tramp syntax to regexps matching completion methods.")
+
+(defun tramp-build-completion-method-regexp ()
+  "Return `tramp-completion-method-regexp' according to `tramp-syntax'."
+  (tramp-lookup-syntax tramp-completion-method-regexp-alist))
+
+(defvar tramp-completion-method-regexp
+  nil ; Initialized when defining `tramp-syntax'!
+  "Regexp matching completion method identifiers.
+The `ftp' syntax does not support methods.")
 
 (defun tramp-build-completion-file-name-regexp ()
   "Return `tramp-completion-file-name-regexp' according to `tramp-syntax'."
-  (tramp-lookup-syntax tramp-completion-file-name-regexp-alist))
+  (if (eq tramp-syntax 'separate)
+      ;; FIXME: This shouldn't be necessary.
+      (rx bos "/" (? (group "[" (* (not (any "]"))))) eos)
+  (rx bos
+      ;; `file-name-completion' uses absolute paths for matching.
+      ;; This means that on W32 systems, something like
+      ;; "/ssh:host:~/path" becomes "c:/ssh:host:~/path".  See also
+      ;; `tramp-drop-volume-letter'.
+      (? (regexp tramp-volume-letter-regexp))
+      (regexp tramp-prefix-regexp)
+
+      ;; Optional multi hops.
+      (* (regexp tramp-remote-file-name-spec-regexp)
+         (regexp tramp-postfix-hop-regexp))
+
+      ;; Last hop.
+      (? (regexp tramp-completion-method-regexp)
+        ;; Method separator, user name and host name.
+        (? (regexp tramp-postfix-method-regexp)
+           ;; This is a little bit lax, but it serves.
+           (? (regexp tramp-host-regexp))))
+
+      eos)))
 
 (defvar tramp-completion-file-name-regexp
-   nil ;Initialized when defining `tramp-syntax'!
+   nil ; Initialized when defining `tramp-syntax'!
   "Regular expression matching file names handled by Tramp completion.
 This regexp should match partial Tramp file names only.
 
@@ -1200,14 +1213,8 @@ Also see `tramp-file-name-structure'.")
 
 ;;;###autoload
 (defconst tramp-autoload-file-name-regexp
-  (concat
-   "\\`/"
-   (if (memq system-type '(cygwin windows-nt))
-       ;; The method is either "-", or at least two characters.
-       "\\(-\\|[^/|:]\\{2,\\}\\)"
-     ;; At least one character for method.
-     "[^/|:]+")
-   ":")
+  ;; The method is either "-", or at least two characters.
+  (rx bos "/" (| "-" (>= 2 (not (any "/:|")))) ":")
   "Regular expression matching file names handled by Tramp autoload.
 It must match the initial `tramp-syntax' settings.  It should not
 match file names at root of the underlying local file system,
@@ -1383,7 +1390,8 @@ would require an immediate reread during filename 
completion, nil
 means to use always cached values for the directory contents."
   :type '(choice (const nil) (const t) integer))
 (make-obsolete-variable
- 'tramp-completion-reread-directory-timeout 'remote-file-name-inhibit-cache 
"27.2")
+ 'tramp-completion-reread-directory-timeout
+ 'remote-file-name-inhibit-cache "27.2")
 
 ;;; Internal Variables:
 
@@ -1413,6 +1421,7 @@ Operations not mentioned here will be handled by Tramp's 
file
 name handler functions, or the normal Emacs functions.")
 
 ;; Handlers for foreign methods, like FTP or SMB, shall be plugged here.
+;;;###autoload
 (defvar tramp-foreign-file-name-handler-alist nil
   "Alist of elements (FUNCTION . HANDLER) for foreign methods handled 
specially.
 If (FUNCTION FILENAME) returns non-nil, then all I/O on that file is done by
@@ -1427,9 +1436,11 @@ calling HANDLER.")
 ;; The basic structure for remote file names.  We must autoload it in
 ;; tramp-loaddefs.el, because some functions, which need it, wouldn't
 ;; work otherwise when unloading / reloading Tramp.  (Bug#50869)
+;;;###tramp-autoload(require 'cl-lib)
 ;;;###tramp-autoload
-(cl-defstruct (tramp-file-name (:type list) :named)
-  method user domain host port localname hop)
+(progn
+  (cl-defstruct (tramp-file-name (:type list) :named)
+    method user domain host port localname hop))
 
 (put #'tramp-file-name-method 'tramp-suppress-trace t)
 (put #'tramp-file-name-user 'tramp-suppress-trace t)
@@ -1472,13 +1483,22 @@ If nil, return `tramp-default-port'."
 
 (put #'tramp-file-name-port-or-default 'tramp-suppress-trace t)
 
-(defun tramp-file-name-unify (vec)
+;;;###tramp-autoload
+(defun tramp-file-name-unify (vec &optional localname)
   "Unify VEC by removing localname and hop from `tramp-file-name' structure.
+If LOCALNAME is a string, set it as localname.
 Objects returned by this function compare `equal' if they refer to the
 same connection.  Make a copy in order to avoid side effects."
   (when (tramp-file-name-p vec)
     (setq vec (copy-tramp-file-name vec))
-    (setf (tramp-file-name-localname vec) nil
+    (setf (tramp-file-name-localname vec)
+         (and (stringp localname)
+              ;; FIXME: This is a sanity check.  When this error
+              ;; doesn't happen for a while, it can be removed.
+              (or (file-name-absolute-p localname)
+                  (tramp-error
+                   vec 'file-error "File `%s' must be absolute" localname))
+              (tramp-compat-file-name-unquote (directory-file-name localname)))
          (tramp-file-name-hop vec) nil))
   vec)
 
@@ -1497,10 +1517,10 @@ If VEC is a vector, check first in connection 
properties.
 Afterwards, check in `tramp-methods'.  If the `tramp-methods'
 entry does not exist, return nil."
   (let ((hash-entry
-        (replace-regexp-in-string "^tramp-" "" (symbol-name param))))
+        (replace-regexp-in-string (rx bos "tramp-") "" (symbol-name param))))
     (if (tramp-connection-property-p vec hash-entry)
        ;; We use the cached property.
-       (tramp-get-connection-property vec hash-entry nil)
+       (tramp-get-connection-property vec hash-entry)
       ;; Use the static value from `tramp-methods'.
       (when-let ((methods-entry
                  (assoc
@@ -1512,14 +1532,12 @@ entry does not exist, return nil."
   "Return unquoted localname component of VEC."
   (tramp-compat-file-name-unquote (tramp-file-name-localname vec)))
 
+;;;###tramp-autoload
 (defun tramp-tramp-file-p (name)
   "Return t if NAME is a string with Tramp file name syntax."
   (and tramp-mode (stringp name)
        ;; No "/:" and "/c:".  This is not covered by `tramp-file-name-regexp'.
-       (not (string-match-p
-            (if (memq system-type '(cygwin windows-nt))
-                "^/[[:alpha:]]?:" "^/:")
-            name))
+       (not (string-match-p (rx bos "/" (? alpha) ":") name))
        ;; Excluded file names.
        (or (null tramp-ignored-file-name-regexp)
           (not (string-match-p tramp-ignored-file-name-regexp name)))
@@ -1533,6 +1551,7 @@ entry does not exist, return nil."
 ;; However, it is more performant than `file-local-name', and might be
 ;; useful where performance matters, like in operations over a bulk
 ;; list of file names.
+;;;###tramp-autoload
 (defun tramp-file-local-name (name)
   "Return the local name component of NAME.
 This function removes from NAME the specification of the remote
@@ -1556,7 +1575,7 @@ of `process-file', `start-file-process', or 
`shell-command'."
 This is METHOD, if non-nil.  Otherwise, do a lookup in
 `tramp-default-method-alist' and `tramp-default-method'."
   (when (and method
-            (or (string-equal method "")
+            (or (string-empty-p method)
                 (string-equal method tramp-default-method-marker)))
     (setq method nil))
   (let ((result
@@ -1624,6 +1643,7 @@ This is HOST, if non-nil.  Otherwise, do a lookup in
 
 (put #'tramp-find-host 'tramp-suppress-trace t)
 
+;;;###tramp-autoload
 (defun tramp-dissect-file-name (name &optional nodefault)
   "Return a `tramp-file-name' structure of NAME, a remote file name.
 The structure consists of method, user, domain, host, port,
@@ -1691,6 +1711,7 @@ default values are used."
 
 (put #'tramp-dissect-file-name 'tramp-suppress-trace t)
 
+;;;###tramp-autoload
 (defun tramp-ensure-dissected-file-name (vec-or-filename)
   "Return a `tramp-file-name' structure for VEC-OR-FILENAME.
 
@@ -1709,7 +1730,7 @@ See `tramp-dissect-file-name' for details."
   (let ((v (tramp-dissect-file-name
            (concat tramp-prefix-format
                    (replace-regexp-in-string
-                    (concat tramp-postfix-hop-regexp "$")
+                    (rx (regexp tramp-postfix-hop-regexp) eos)
                     tramp-postfix-host-format name))
            nodefault)))
     ;; Only some methods from tramp-sh.el do support multi-hops.
@@ -1733,6 +1754,7 @@ See `tramp-dissect-file-name' for details."
 
 (put #'tramp-buffer-name 'tramp-suppress-trace t)
 
+;;;###tramp-autoload
 (defun tramp-make-tramp-file-name (&rest args)
   "Construct a Tramp file name from ARGS.
 
@@ -1761,7 +1783,7 @@ the form (METHOD USER DOMAIN HOST PORT LOCALNAME 
&optional HOP)."
        ;; Assure that the hops are in `tramp-default-proxies-alist'.
        ;; In tramp-archive.el, the slot `hop' is used for the archive
        ;; file name.
-       (unless (string-equal method "archive")
+       (unless (string-equal method tramp-archive-method)
          (tramp-add-hops (car args)))))
 
      (t (setq method (nth 0 args)
@@ -1804,7 +1826,7 @@ the form (METHOD USER DOMAIN HOST PORT LOCALNAME 
&optional HOP)."
    (replace-regexp-in-string
     tramp-prefix-regexp ""
     (replace-regexp-in-string
-     (concat tramp-postfix-host-regexp "$") tramp-postfix-hop-format
+     (rx (regexp tramp-postfix-host-regexp) eos) tramp-postfix-hop-format
      (tramp-make-tramp-file-name vec 'noloc)))))
 
 (defun tramp-completion-make-tramp-file-name (method user host localname)
@@ -1836,25 +1858,26 @@ Unless DONT-CREATE, the buffer is created when it 
doesn't exist yet."
          ;; as indication, whether a connection is active.
          (tramp-set-connection-property
           vec "process-buffer"
-          (tramp-get-connection-property vec "process-buffer" nil))
+          (tramp-get-connection-property vec "process-buffer"))
          (setq buffer-undo-list t
                default-directory
                (tramp-make-tramp-file-name vec 'noloc))
          (current-buffer)))))
 
+;;;###tramp-autoload
 (defun tramp-get-connection-buffer (vec &optional dont-create)
   "Get the connection buffer to be used for VEC.
 Unless DONT-CREATE, the buffer is created when it doesn't exist yet.
 In case a second asynchronous communication has been started, it is different
 from `tramp-get-buffer'."
-  (or (tramp-get-connection-property vec "process-buffer" nil)
+  (or (tramp-get-connection-property vec "process-buffer")
       (tramp-get-buffer vec dont-create)))
 
 (defun tramp-get-connection-name (vec)
   "Get the connection name to be used for VEC.
 In case a second asynchronous communication has been started, it is different
 from the default one."
-  (or (tramp-get-connection-property vec "process-name" nil)
+  (or (tramp-get-connection-property vec "process-name")
       (tramp-buffer-name vec)))
 
 (defun tramp-get-process (vec-or-proc)
@@ -1898,8 +1921,7 @@ version, the function does nothing."
   "Return `default-directory' of BUFFER."
   (buffer-local-value 'default-directory buffer))
 
-(put #'tramp-get-default-directory 'tramp-suppress-trace t)
-
+;;;###tramp-autoload
 (defsubst tramp-get-buffer-string (&optional buffer)
   "Return contents of BUFFER.
 If BUFFER is not a buffer or a buffer name, return the contents
@@ -1907,8 +1929,6 @@ of `current-buffer'."
   (with-current-buffer (or buffer (current-buffer))
     (substring-no-properties (buffer-string))))
 
-(put #'tramp-get-buffer-string 'tramp-suppress-trace t)
-
 (defun tramp-debug-buffer-name (vec)
   "A name for the debug buffer for VEC."
   (let ((method (tramp-file-name-method vec))
@@ -1921,10 +1941,12 @@ of `current-buffer'."
 (put #'tramp-debug-buffer-name 'tramp-suppress-trace t)
 
 (defconst tramp-debug-outline-regexp
-  (concat
-   "[[:digit:]]+:[[:digit:]]+:[[:digit:]]+\\.[[:digit:]]+ " ;; Timestamp.
-   "\\(?:\\(#<thread .+>\\) \\)?" ;; Thread.
-   "[[:alnum:]-]+ (\\([[:digit:]]+\\)) #") ;; Function name, verbosity.
+  (rx ;; Timestamp.
+      (+ digit) ":" (+ digit) ":" (+ digit) "." (+ digit) " "
+      ;; Thread.
+      (? (group "#<thread " (+ nonl) ">") " ")
+       ;; Function name, verbosity.
+      (+ (any "-" alnum)) " (" (group (group (+ digit))) ") #")
   "Used for highlighting Tramp debug buffers in `outline-mode'.")
 
 (defconst tramp-debug-font-lock-keywords
@@ -1933,7 +1955,7 @@ of `current-buffer'."
   ;; Also, in `font-lock-defaults' you can specify a function name for
   ;; the "KEYWORDS" part, so font-lock calls it to get the actual keywords!
   '(list
-    (concat "^\\(?:" tramp-debug-outline-regexp "\\).+")
+    (rx bol (regexp tramp-debug-outline-regexp) (+ nonl))
     '(1 font-lock-warning-face t t)
     '(0 (outline-font-lock-face) keep t))
   "Used for highlighting Tramp debug buffers in `outline-mode'.")
@@ -1954,7 +1976,9 @@ The outline level is equal to the verbosity of the Tramp 
message."
   "A predicate for Tramp interactive commands.
 They are completed by \"M-x TAB\" only in Tramp debug buffers."
   (with-current-buffer buffer
-    (string-equal (buffer-substring 1 (min 10 (point-max))) ";; Emacs:")))
+    (string-equal
+     (buffer-substring (point-min) (min (+ (point-min) 10) (point-max)))
+     ";; Emacs:")))
 
 (put #'tramp-debug-buffer-command-completion-p 'tramp-suppress-trace t)
 
@@ -1981,6 +2005,7 @@ They are completed by \"M-x TAB\" only in Tramp debug 
buffers."
                   ,(eval tramp-debug-font-lock-keywords t)))
   ;; Do not edit the debug buffer.
   (use-local-map special-mode-map)
+  (set-buffer-modified-p nil)
   ;; For debugging purposes.
   (local-set-key "\M-n" 'clone-buffer)
   (add-hook 'clone-buffer-hook #'tramp-setup-debug-buffer nil 'local))
@@ -2017,6 +2042,7 @@ They are completed by \"M-x TAB\" only in Tramp debug 
buffers."
 (defvar tramp-trace-functions nil
   "A list of non-Tramp functions to be traced with `tramp-verbose' > 10.")
 
+;;;###tramp-autoload
 (defun tramp-debug-message (vec fmt-string &rest arguments)
   "Append message to debug buffer of VEC.
 Message is formatted with FMT-STRING as control string and the remaining
@@ -2090,10 +2116,12 @@ ARGUMENTS to actually emit the message (if applicable)."
 
 (put #'tramp-debug-message 'tramp-suppress-trace t)
 
+;;;###tramp-autoload
 (defvar tramp-inhibit-progress-reporter nil
   "Show Tramp progress reporter in the minibuffer.
 This variable is used to disable concurrent progress reporter messages.")
 
+;;;###tramp-autoload
 (defsubst tramp-message (vec-or-proc level fmt-string &rest arguments)
   "Emit a message depending on verbosity level.
 VEC-OR-PROC identifies the Tramp buffer to use.  It can be either a
@@ -2146,19 +2174,17 @@ applicable)."
                 (concat (format "(%d) # " level) fmt-string)
                 arguments))))))
 
-(put #'tramp-message 'tramp-suppress-trace t)
-
-(defsubst tramp-backtrace (&optional vec-or-proc)
+(defsubst tramp-backtrace (&optional vec-or-proc force)
   "Dump a backtrace into the debug buffer.
-If VEC-OR-PROC is nil, the buffer *debug tramp* is used.  This
-function is meant for debugging purposes."
-  (when (>= tramp-verbose 10)
-    (if vec-or-proc
-       (tramp-message
-        vec-or-proc 10 "\n%s" (with-output-to-string (backtrace)))
-      (with-output-to-temp-buffer "*debug tramp*" (backtrace)))))
-
-(put #'tramp-backtrace 'tramp-suppress-trace t)
+If VEC-OR-PROC is nil, the buffer *debug tramp* is used.  FORCE
+forces the backtrace even if `tramp-verbose' is less than 10.
+This function is meant for debugging purposes."
+  (let ((tramp-verbose (if force 10 tramp-verbose)))
+    (when (>= tramp-verbose 10)
+      (if vec-or-proc
+         (tramp-message
+          vec-or-proc 10 "\n%s" (with-output-to-string (backtrace)))
+       (with-output-to-temp-buffer "*debug tramp*" (backtrace))))))
 
 (defun tramp-error (vec-or-proc signal fmt-string &rest arguments)
   "Emit an error.
@@ -2227,8 +2253,6 @@ an input event arrives.  The other arguments are passed 
to `tramp-error'."
        (when (tramp-file-name-equal-p vec (car tramp-current-connection))
          (setcdr tramp-current-connection (current-time)))))))
 
-(put #'tramp-error-with-buffer 'tramp-suppress-trace t)
-
 ;; We must make it a defun, because it is used earlier already.
 (defun tramp-user-error (vec-or-proc fmt-string &rest arguments)
   "Signal a user error (or \"pilot error\")."
@@ -2265,7 +2289,21 @@ the resulting error message."
          (progn ,@body)
        (error (tramp-message ,vec-or-proc 3 ,format ,err) nil))))
 
-(put #'tramp-with-demoted-errors 'tramp-suppress-trace t)
+;; This macro shall optimize the cases where an `file-exists-p' call
+;; is invoked first.  Often, the file exists, so the remote command is
+;; superfluous.
+(defmacro tramp-barf-if-file-missing (vec filename &rest body)
+  "Execute BODY and return the result.
+In case if an error, raise a `file-missing' error if FILENAME
+does not exist, otherwise propagate the error."
+  (declare (indent 2) (debug (symbolp form body)))
+  (let ((err (make-symbol "err")))
+    `(condition-case ,err
+         (progn ,@body)
+       (error
+       (if (not (file-exists-p ,filename))
+           (tramp-error ,vec 'file-missing ,filename)
+         (signal (car ,err) (cdr ,err)))))))
 
 (defun tramp-test-message (fmt-string &rest arguments)
   "Emit a Tramp message according `default-directory'."
@@ -2348,7 +2386,7 @@ without a visible progress reporter."
             ;; running, and when there is a minimum level.
            (when-let ((pr (and (null tramp-inhibit-progress-reporter)
                                (<= ,level (min tramp-verbose 3))
-                               (make-progress-reporter ,message nil nil))))
+                               (make-progress-reporter ,message))))
              (run-at-time 3 0.1 #'tramp-progress-reporter-update pr))))
        (unwind-protect
            ;; Execute the body.
@@ -2362,35 +2400,6 @@ without a visible progress reporter."
          (if tm (cancel-timer tm))
          (tramp-message ,vec ,level "%s...%s" ,message cookie)))))
 
-(defmacro with-tramp-file-property (vec file property &rest body)
-  "Check in Tramp cache for PROPERTY, otherwise execute BODY and set cache.
-FILE must be a local file name on a connection identified via VEC."
-  (declare (indent 3) (debug t))
-  `(if (file-name-absolute-p ,file)
-       (let ((value (tramp-get-file-property
-                    ,vec ,file ,property tramp-cache-undefined)))
-        (when (eq value tramp-cache-undefined)
-          ;; We cannot pass @body as parameter to
-          ;; `tramp-set-file-property' because it mangles our debug
-          ;; messages.
-          (setq value (progn ,@body))
-          (tramp-set-file-property ,vec ,file ,property value))
-        value)
-     ,@body))
-
-(defmacro with-tramp-connection-property (key property &rest body)
-  "Check in Tramp for property PROPERTY, otherwise execute BODY and set."
-  (declare (indent 2) (debug t))
-  `(let ((value (tramp-get-connection-property
-                ,key ,property tramp-cache-undefined)))
-     (when (eq value tramp-cache-undefined)
-       ;; We cannot pass ,@body as parameter to
-       ;; `tramp-set-connection-property' because it mangles our debug
-       ;; messages.
-       (setq value (progn ,@body))
-       (tramp-set-connection-property ,key ,property value))
-     value))
-
 (defun tramp-drop-volume-letter (name)
   "Cut off unnecessary drive letter from file NAME.
 The functions `tramp-*-handle-expand-file-name' call `expand-file-name'
@@ -2400,15 +2409,19 @@ letter into the file name.  This function removes it."
   (save-match-data
     (let ((quoted (tramp-compat-file-name-quoted-p name 'top))
          (result (tramp-compat-file-name-unquote name 'top)))
-      (setq result (if (string-match "\\`[[:alpha:]]:/" result)
-                    (replace-match "/" nil t result) result))
+      (setq result
+           (if (string-match
+                (rx (regexp tramp-volume-letter-regexp) "/") result)
+               (replace-match "/" nil t result) result))
       (if quoted (tramp-compat-file-name-quote result 'top) result))))
 
 ;;; Config Manipulation Functions:
 
-(defconst tramp-dns-sd-service-regexp "^_[-[:alnum:]]+\\._tcp$"
+(defconst tramp-dns-sd-service-regexp
+  (rx bol "_" (+ (any "-" alnum)) "._tcp" eol)
   "DNS-SD service regexp.")
 
+;;;###tramp-autoload
 (defun tramp-set-completion-function (method function-list)
   "Set the list of completion functions for METHOD.
 FUNCTION-LIST is a list of entries of the form (FUNCTION FILE).
@@ -2508,7 +2521,7 @@ coding system might not be determined.  This function 
repairs it."
        ;; We found a matching entry in `file-coding-system-alist'.
        ;; So we add a similar entry, but with the temporary file name
        ;; as regexp.
-       (push (cons (regexp-quote tmpname) (cdr elt)) result)))))
+       (push (cons (rx (literal tmpname)) (cdr elt)) result)))))
 
 (defun tramp-run-real-handler (operation args)
   "Invoke normal file name handler for OPERATION.
@@ -2649,6 +2662,7 @@ Must be handled by the callers."
       res)))
 
 ;; Main function.
+;;;###autoload
 (defun tramp-file-name-handler (operation &rest args)
   "Invoke Tramp file name handler for OPERATION and ARGS.
 Fall back to normal file name handler if no Tramp file name handler exists."
@@ -2785,14 +2799,12 @@ This avoids problems during autoload, when `load-path' 
contains
 remote file names."
   ;; We expect all other Tramp files in the same directory as tramp.el.
   (let* ((dir (expand-file-name (file-name-directory (locate-library 
"tramp"))))
-        (files-regexp
-         (format
-          "^%s$"
-          (regexp-opt
-           (mapcar
-            #'file-name-sans-extension
-            (directory-files dir nil "\\`tramp.+\\.elc?\\'"))
-           'paren))))
+        (files (delete-dups
+                (mapcar
+                 #'file-name-sans-extension
+                 (directory-files
+                  dir nil (rx bos "tramp" (+ nonl) ".el" (? "c") eos)))))
+        (files-regexp (rx bol (: (regexp (regexp-opt files))) eol)))
     (mapatoms
      (lambda (atom)
        (when (and (functionp atom)
@@ -2844,6 +2856,7 @@ remote file names."
 
 (tramp--with-startup (tramp-register-file-name-handlers))
 
+;;;###tramp-autoload
 (defun tramp-register-foreign-file-name-handler
     (func handler &optional append)
   "Register (FUNC . HANDLER) in `tramp-foreign-file-name-handler-alist'.
@@ -2936,11 +2949,9 @@ not in completion mode."
 
     ;; Suppress hop from completion.
     (when (string-match
-          (concat
-           tramp-prefix-regexp
-           "\\(" "\\(" tramp-remote-file-name-spec-regexp
-                       tramp-postfix-hop-regexp
-           "\\)+" "\\)")
+          (rx (regexp tramp-prefix-regexp)
+              (group (+ (regexp tramp-remote-file-name-spec-regexp)
+                        (regexp tramp-postfix-hop-regexp))))
           fullname)
       (setq hop (match-string 1 fullname)
            fullname (replace-match "" nil nil fullname 1)))
@@ -3022,68 +3033,62 @@ not in completion mode."
 ;; ["x" nil "" nil]     ["x" nil "y" nil]    ["x" nil "y" ""]
 ;; ["x" "" nil nil]     ["x" "y" nil nil]
 
-;; "/x:y@""/[x/y@"      "/x:y@z" "/[x/y@z"   "/x:y@z:" "/[x/y@z]"
-;;["x" "y" nil nil]     ["x" "y" "z" nil]    ["x" "y" "z" ""]
+;; "/x:y@" "/[x/y@"     "/x:y@z" "/[x/y@z"   "/x:y@z:" "/[x/y@z]"
+;; ["x" "y" nil nil]    ["x" "y" "z" nil]    ["x" "y" "z" ""]
 (defun tramp-completion-dissect-file-name (name)
   "Return a list of `tramp-file-name' structures for NAME.
 They are collected by `tramp-completion-dissect-file-name1'."
-  (let* ((x-nil "\\|\\(\\)")
-        (tramp-completion-ipv6-regexp
-         (format
-          "[^%s]*"
-          (if (zerop (length tramp-postfix-ipv6-format))
-              tramp-postfix-host-format
-            tramp-postfix-ipv6-format)))
-        ;; "/method" "/[method"
+  (let* (;; "/method" "/[method"
         (tramp-completion-file-name-structure1
          (list
-          (concat
-           tramp-prefix-regexp
-           "\\(" tramp-method-regexp x-nil "\\)$")
+          (rx (regexp tramp-prefix-regexp)
+              (group (? (regexp tramp-completion-method-regexp))) eol)
           1 nil nil nil))
         ;; "/method:user" "/[method/user"
         (tramp-completion-file-name-structure2
          (list
-          (concat
-           tramp-prefix-regexp
-           "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
-           "\\(" tramp-user-regexp x-nil   "\\)$")
+          (rx (regexp tramp-prefix-regexp)
+              (group (regexp tramp-method-regexp))
+              (regexp tramp-postfix-method-regexp)
+              (group (? (regexp tramp-user-regexp))) eol)
           1 2 nil nil))
         ;; "/method:host" "/[method/host"
         (tramp-completion-file-name-structure3
          (list
-          (concat
-           tramp-prefix-regexp
-           "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
-           "\\(" tramp-host-regexp x-nil   "\\)$")
+          (rx (regexp tramp-prefix-regexp)
+              (group (regexp tramp-method-regexp))
+              (regexp tramp-postfix-method-regexp)
+              (group (? (regexp tramp-host-regexp))) eol)
           1 nil 2 nil))
         ;; "/method:[ipv6" "/[method/ipv6"
         (tramp-completion-file-name-structure4
          (list
-          (concat
-           tramp-prefix-regexp
-           "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
-           tramp-prefix-ipv6-regexp
-           "\\(" tramp-completion-ipv6-regexp x-nil "\\)$")
+          (rx (regexp tramp-prefix-regexp)
+              (group (regexp tramp-method-regexp))
+              (regexp tramp-postfix-method-regexp)
+              (regexp tramp-prefix-ipv6-regexp)
+              (group (? (regexp tramp-ipv6-regexp))) eol)
           1 nil 2 nil))
         ;; "/method:user@host" "/[method/user@host"
         (tramp-completion-file-name-structure5
          (list
-          (concat
-           tramp-prefix-regexp
-           "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
-           "\\(" tramp-user-regexp "\\)"   tramp-postfix-user-regexp
-           "\\(" tramp-host-regexp x-nil   "\\)$")
+          (rx (regexp tramp-prefix-regexp)
+              (group (regexp tramp-method-regexp))
+              (regexp tramp-postfix-method-regexp)
+              (group (regexp tramp-user-regexp))
+              (regexp tramp-postfix-user-regexp)
+              (group (? (regexp tramp-host-regexp))) eol)
           1 2 3 nil))
         ;; "/method:user@[ipv6" "/[method/user@ipv6"
         (tramp-completion-file-name-structure6
          (list
-          (concat
-           tramp-prefix-regexp
-           "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp
-           "\\(" tramp-user-regexp "\\)"   tramp-postfix-user-regexp
-           tramp-prefix-ipv6-regexp
-           "\\(" tramp-completion-ipv6-regexp x-nil "\\)$")
+          (rx (regexp tramp-prefix-regexp)
+              (group (regexp tramp-method-regexp))
+              (regexp tramp-postfix-method-regexp)
+              (group (regexp tramp-user-regexp))
+              (regexp tramp-postfix-user-regexp)
+              (regexp tramp-prefix-ipv6-regexp)
+              (group (? (regexp tramp-ipv6-regexp))) eol)
           1 2 3 nil)))
     (delq
      nil
@@ -3179,7 +3184,7 @@ for all methods.  Resulting data are derived from default 
settings."
    "Return a (user host) tuple allowed to access.
 User is always nil."
    (let (result)
-     (when (re-search-forward regexp (point-at-eol) t)
+     (when (re-search-forward regexp (line-end-position) t)
        (setq result (list nil (match-string match-level))))
      (or
       (> (skip-chars-forward skip-chars) 0)
@@ -3209,11 +3214,10 @@ Either user or host may be nil."
 Either user or host may be nil."
    (let (result
         (regexp
-         (concat
-          "^\\(" tramp-host-regexp "\\)"
-          "\\([ \t]+" "\\(" tramp-user-regexp "\\)" "\\)?")))
-     (when (re-search-forward regexp (point-at-eol) t)
-       (setq result (append (list (match-string 3) (match-string 1)))))
+         (rx bol (group (regexp tramp-host-regexp))
+             (? (+ space) (group (regexp tramp-user-regexp))))))
+     (when (re-search-forward regexp (line-end-position) t)
+       (setq result (append (list (match-string 2) (match-string 1)))))
      (forward-line 1)
      result))
 
@@ -3225,7 +3229,7 @@ User is always nil."
 (defun tramp-parse-shosts-group ()
    "Return a (user host) tuple allowed to access.
 User is always nil."
-   (tramp-parse-group (concat "^\\(" tramp-host-regexp "\\)") 1 ","))
+   (tramp-parse-group (rx bol (group (regexp tramp-host-regexp))) 1 ","))
 
 (defun tramp-parse-sconfig (filename)
   "Return a list of (user host) tuples allowed to access.
@@ -3236,9 +3240,10 @@ User is always nil."
    "Return a (user host) tuple allowed to access.
 User is always nil."
    (tramp-parse-group
-    (concat "\\(?:^[ \t]*Host\\)" "\\|" "\\(?:^.+\\)"
-           "\\|" "\\(" tramp-host-regexp "\\)")
-    1 " \t"))
+    (rx (| (: bol (* space) "Host")
+          (: bol (+ nonl)) ;; ???
+          (group (regexp tramp-host-regexp))))
+    1 (rx space)))
 
 ;; Generic function.
 (defun tramp-parse-shostkeys-sknownhosts (dirname regexp)
@@ -3250,21 +3255,24 @@ User is always nil."
         (files (and (file-directory-p dirname) (directory-files dirname))))
     (cl-loop
      for f in files
-     when (and (not (string-match "^\\.\\.?$" f)) (string-match regexp f))
+     when (and (not (string-match-p (rx bol (** 1 2 ".") eol) f))
+              (string-match regexp f))
      collect (list nil (match-string 1 f)))))
 
 (defun tramp-parse-shostkeys (dirname)
   "Return a list of (user host) tuples allowed to access.
 User is always nil."
   (tramp-parse-shostkeys-sknownhosts
-   dirname (concat "^key_[[:digit:]]+_\\(" tramp-host-regexp "\\)\\.pub$")))
+   dirname
+   (rx bol "key_" (+ digit) "_" (group (regexp tramp-host-regexp)) ".pub" 
eol)))
 
 (defun tramp-parse-sknownhosts (dirname)
   "Return a list of (user host) tuples allowed to access.
 User is always nil."
   (tramp-parse-shostkeys-sknownhosts
    dirname
-   (concat "^\\(" tramp-host-regexp "\\)\\.ssh-\\(dss\\|rsa\\)\\.pub$")))
+   (rx bol (group (regexp tramp-host-regexp))
+       ".ssh-" (| "dss" "rsa") ".pub" eol)))
 
 (defun tramp-parse-hosts (filename)
   "Return a list of (user host) tuples allowed to access.
@@ -3275,7 +3283,8 @@ User is always nil."
    "Return a (user host) tuple allowed to access.
 User is always nil."
    (tramp-parse-group
-    (concat "^\\(" tramp-ipv6-regexp "\\|" tramp-host-regexp "\\)") 1 " \t"))
+    (rx bol (group (| (regexp tramp-ipv6-regexp) (regexp tramp-host-regexp))))
+    1 (rx space)))
 
 (defun tramp-parse-passwd (filename)
   "Return a list of (user host) tuples allowed to access.
@@ -3293,8 +3302,8 @@ Host is always \"localhost\"."
    "Return a (user host) tuple allowed to access.
 Host is always \"localhost\"."
    (let (result
-        (regexp (concat "^\\(" tramp-user-regexp "\\):")))
-     (when (re-search-forward regexp (point-at-eol) t)
+        (regexp (rx bol (group (regexp tramp-user-regexp)) ":")))
+     (when (re-search-forward regexp (line-end-position) t)
        (setq result (list (match-string 1) "localhost")))
      (forward-line 1)
      result))
@@ -3315,7 +3324,8 @@ Host is always \"localhost\"."
    "Return a (group host) tuple allowed to access.
 Host is always \"localhost\"."
    (let (result
-        (split (split-string (buffer-substring (point) (point-at-eol)) ":")))
+        (split
+         (split-string (buffer-substring (point) (line-end-position)) ":")))
      (when (member (user-login-name) (split-string (nth 3 split) "," 'omit))
        (setq result (list (nth 0 split) "localhost")))
      (forward-line 1)
@@ -3324,14 +3334,11 @@ Host is always \"localhost\"."
 (defun tramp-parse-netrc (filename)
   "Return a list of (user host) tuples allowed to access.
 User may be nil."
-  ;; The declaration is not sufficient at runtime, because netrc.el is
-  ;; not autoloaded.
-  (autoload 'netrc-parse "netrc")
   (mapcar
    (lambda (item)
      (and (assoc "machine" item)
          `(,(cdr (assoc "login" item)) ,(cdr (assoc "machine" item)))))
-   (netrc-parse filename)))
+   (tramp-compat-auth-source-netrc-parse-all filename)))
 
 (defun tramp-parse-putty (registry-or-dirname)
   "Return a list of (user host) tuples allowed to access.
@@ -3346,20 +3353,34 @@ User is always nil."
                     (tramp-parse-putty-group registry-or-dirname)))))
     ;; UNIX case.
     (tramp-parse-shostkeys-sknownhosts
-     registry-or-dirname (concat "^\\(" tramp-host-regexp "\\)$"))))
+     registry-or-dirname (rx bol (group (regexp tramp-host-regexp)) eol))))
 
 (defun tramp-parse-putty-group (registry)
    "Return a (user host) tuple allowed to access.
 User is always nil."
    (let (result
-        (regexp (concat (regexp-quote registry) "\\\\\\(.+\\)")))
-     (when (re-search-forward regexp (point-at-eol) t)
+        (regexp (rx (literal registry) "\\" (group (+ nonl)))))
+     (when (re-search-forward regexp (line-end-position) t)
        (setq result (list nil (match-string 1))))
      (forward-line 1)
      result))
 
 ;;; Skeleton macros for file name handler functions.
 
+(defmacro tramp-skeleton-copy-directory
+  (directory _newname &optional _keep-date _parents _copy-contents &rest body)
+  "Skeleton for `tramp-*-handle-copy-directory'.
+BODY is the backend specific code."
+  (declare (indent 5) (debug t))
+  ;; `copy-directory' creates NEWNAME before running this check.  So
+  ;; we do it ourselves.  Therefore, we cannot also run
+  ;; `tramp-barf-if-file-missing'.
+  `(progn
+     (unless (file-exists-p ,directory)
+       (tramp-error
+       (tramp-dissect-file-name ,directory) 'file-missing ,directory))
+     ,@body))
+
 (defmacro tramp-skeleton-delete-directory (directory recursive trash &rest 
body)
   "Skeleton for `tramp-*-handle-delete-directory'.
 BODY is the backend specific code."
@@ -3375,7 +3396,116 @@ BODY is the backend specific code."
       ,@body)
     (tramp-flush-directory-properties v localname)))
 
-(put #'tramp-skeleton-delete-directory 'tramp-suppress-trace t)
+(defmacro tramp-skeleton-directory-files
+    (directory &optional full match nosort count &rest body)
+  "Skeleton for `tramp-*-handle-directory-files'.
+BODY is the backend specific code."
+  (declare (indent 5) (debug t))
+  `(or
+    (with-parsed-tramp-file-name ,directory nil
+      (tramp-barf-if-file-missing v ,directory
+       (when (file-directory-p ,directory)
+         (setq ,directory
+               (file-name-as-directory (expand-file-name ,directory)))
+         (let ((temp
+                (with-tramp-file-property v localname "directory-files" 
,@body))
+               result item)
+           (while temp
+             (setq item (directory-file-name (pop temp)))
+             (when (or (null ,match) (string-match-p ,match item))
+               (push (if ,full (concat ,directory item) item)
+                     result)))
+           (unless ,nosort
+              (setq result (sort result #'string<)))
+           (when (and (natnump ,count) (> ,count 0))
+             (setq result (tramp-compat-ntake ,count result)))
+           result))))
+
+    ;; Error handling.
+    (if (not (file-exists-p ,directory))
+       (tramp-error
+        (tramp-dissect-file-name ,directory) 'file-missing ,directory)
+      nil)))
+
+(defmacro tramp-skeleton-directory-files-and-attributes
+    (directory &optional full match nosort id-format count &rest body)
+  "Skeleton for `tramp-*-handle-directory-files-and-attributes'.
+BODY is the backend specific code."
+  (declare (indent 6) (debug t))
+  `(or
+    (with-parsed-tramp-file-name ,directory nil
+      (tramp-barf-if-file-missing v ,directory
+       (when (file-directory-p ,directory)
+         (let ((temp
+                (copy-tree
+                 (mapcar
+                  (lambda (x)
+                    (cons
+                     (car x)
+                     (tramp-convert-file-attributes
+                         v (expand-file-name (car x) localname)
+                         ,id-format (cdr x))))
+                  (with-tramp-file-property
+                      v localname "directory-files-and-attributes"
+                    ,@body))))
+               result item)
+
+           (while temp
+             (setq item (pop temp))
+             (when (or (null ,match) (string-match-p ,match (car item)))
+               (when ,full
+                 (setcar item (expand-file-name (car item) ,directory)))
+               (push item result)))
+
+           (unless ,nosort
+             (setq result
+                   (sort result (lambda (x y) (string< (car x) (car y))))))
+
+           (when (and (natnump ,count) (> ,count 0))
+             (setq result (tramp-compat-ntake ,count result)))
+
+           (or result
+               ;; The scripts could fail, for example with huge file size.
+               (tramp-handle-directory-files-and-attributes
+                ,directory ,full ,match ,nosort ,id-format ,count))))))
+
+    ;; Error handling.
+    (if (not (file-exists-p ,directory))
+       (tramp-error
+        (tramp-dissect-file-name ,directory) 'file-missing ,directory)
+      nil)))
+
+(defmacro tramp-skeleton-file-local-copy (filename &rest body)
+  "Skeleton for `tramp-*-handle-file-local-copy'.
+BODY is the backend specific code."
+  (declare (indent 1) (debug t))
+  `(with-parsed-tramp-file-name (file-truename ,filename) nil
+     (tramp-barf-if-file-missing v ,filename
+       (or
+       (let ((tmpfile (tramp-compat-make-temp-file ,filename)))
+         ,@body
+          (run-hooks 'tramp-handle-file-local-copy-hook)
+         tmpfile)
+
+       ;; Trigger the `file-missing' error.
+       (signal 'error nil)))))
+
+(defmacro tramp-skeleton-set-file-modes-times-uid-gid
+    (filename &rest body)
+  "Skeleton for `tramp-*-set-file-{modes,times,uid-gid}'.
+BODY is the backend specific code."
+  (declare (indent 1) (debug t))
+  `(with-parsed-tramp-file-name ,filename nil
+     (when (not (file-exists-p ,filename))
+       (tramp-error v 'file-missing ,filename))
+     (with-tramp-saved-file-properties
+        v localname
+        ;; We cannot add "file-attributes", "file-executable-p",
+        ;; "file-ownership-preserved-p", "file-readable-p",
+        ;; "file-writable-p".
+        '("file-directory-p" "file-exists-p" "file-symlinkp" "file-truename")
+       (tramp-flush-file-properties v localname))
+     ,@body))
 
 (defmacro tramp-skeleton-write-region
   (start end filename append visit lockname mustbenew &rest body)
@@ -3436,6 +3566,9 @@ BODY is the backend specific code."
           ;; We must also flush the cache of the directory, because
           ;; `file-attributes' reads the values from there.
           (tramp-flush-file-properties v localname)
+          ;; Set the "file-exists-p" file property, because it is
+          ;; likely that it is needed shortly after `write-region'.
+          (tramp-set-file-property v localname "file-exists-p" t)
 
           ;; We must protect `last-coding-system-used', now we have
           ;; set it to its correct value.
@@ -3449,8 +3582,8 @@ BODY is the backend specific code."
                  ;; `file-precious-flag' is set.
                  (or (file-attribute-modification-time file-attr)
                      (current-time)))
-                (unless (and (= (file-attribute-user-id file-attr) uid)
-                             (= (file-attribute-group-id file-attr) gid))
+                (when (and (= (file-attribute-user-id file-attr) uid)
+                           (= (file-attribute-group-id file-attr) gid))
                   (setq need-chown nil))))
 
             ;; Set the ownership.
@@ -3479,8 +3612,6 @@ BODY is the backend specific code."
             (tramp-message v 0 "Wrote %s" filename))
           (run-hooks 'tramp-handle-write-region-hook))))))
 
-(put #'tramp-skeleton-write-region 'tramp-suppress-trace t)
-
 ;;; Common file name handler functions for different backends:
 
 (defvar tramp-handle-file-local-copy-hook nil
@@ -3507,7 +3638,7 @@ Let-bind it when necessary.")
               ;; home directory.
              (tramp-get-home-directory vec)
             ;; Otherwise, just use the cached value.
-            (tramp-get-connection-property vec "~" nil))))
+            (tramp-get-connection-property vec "~"))))
     (when home-dir
       (setq home-dir
            (tramp-compat-funcall
@@ -3570,14 +3701,12 @@ Let-bind it when necessary.")
 (defun tramp-handle-copy-directory
   (directory newname &optional keep-date parents copy-contents)
   "Like `copy-directory' for Tramp files."
-  ;; `copy-directory' creates NEWNAME before running this check.  So
-  ;; we do it ourselves.
-  (unless (file-exists-p directory)
-    (tramp-error (tramp-dissect-file-name directory) 'file-missing directory))
-  ;; We must do it file-wise.
-  (tramp-run-real-handler
-   #'copy-directory
-   (list directory newname keep-date parents copy-contents)))
+  (tramp-skeleton-copy-directory
+      directory newname keep-date parents copy-contents
+   ;; We must do it file-wise.
+   (tramp-run-real-handler
+    #'copy-directory
+    (list directory newname keep-date parents copy-contents))))
 
 (defun tramp-handle-directory-file-name (directory)
   "Like `directory-file-name' for Tramp files."
@@ -3593,23 +3722,8 @@ Let-bind it when necessary.")
 
 (defun tramp-handle-directory-files (directory &optional full match nosort 
count)
   "Like `directory-files' for Tramp files."
-  (unless (file-exists-p directory)
-    (tramp-error (tramp-dissect-file-name directory) 'file-missing directory))
-  (when (file-directory-p directory)
-    (setq directory (file-name-as-directory (expand-file-name directory)))
-    (let ((temp (nreverse (file-name-all-completions "" directory)))
-         result item)
-
-      (while temp
-       (setq item (directory-file-name (pop temp)))
-       (when (or (null match) (string-match-p match item))
-         (push (if full (concat directory item) item)
-               result)))
-      (unless nosort
-        (setq result (sort result #'string<)))
-      (when (and (natnump count) (> count 0))
-       (setq result (nbutlast result (- (length result) count))))
-      result)))
+  (tramp-skeleton-directory-files directory full match nosort count
+    (nreverse (file-name-all-completions "" directory))))
 
 (defun tramp-handle-directory-files-and-attributes
   (directory &optional full match nosort id-format count)
@@ -3637,7 +3751,7 @@ Let-bind it when necessary.")
     (setq name (tramp-compat-file-name-concat dir name)))
   ;; If NAME is not a Tramp file, run the real handler.
   (if (not (tramp-tramp-file-p name))
-      (tramp-run-real-handler #'expand-file-name (list name nil))
+      (tramp-run-real-handler #'expand-file-name (list name))
     ;; Dissect NAME.
     (with-parsed-tramp-file-name name nil
       (unless (tramp-run-real-handler #'file-name-absolute-p (list localname))
@@ -3645,7 +3759,9 @@ Let-bind it when necessary.")
       ;; Expand tilde.  Usually, the methods applying this handler do
       ;; not support tilde expansion.  But users could declare a
       ;; respective connection property.  (Bug#53847)
-      (when (string-match "\\`~\\([^/]*\\)\\(.*\\)\\'" localname)
+      (when (string-match
+            (rx bos "~" (group (* (not (any "/")))) (group (* nonl)) eos)
+            localname)
        (let ((uname (match-string 1 localname))
              (fname (match-string 2 localname))
              hname)
@@ -3655,10 +3771,10 @@ Let-bind it when necessary.")
            (setq localname (concat hname fname)))))
       ;; Tilde expansion is not possible.
       (when (and (not tramp-tolerate-tilde)
-                (string-match-p "\\`\\(~[^/]*\\)\\(.*\\)\\'" localname))
+                (string-prefix-p "~" localname))
        (tramp-error v 'file-error "Cannot expand tilde in file `%s'" name))
       ;; Do not keep "/..".
-      (when (string-match-p "^/\\.\\.?$" localname)
+      (when (string-match-p (rx bos "/" (** 1 2 ".") eos) localname)
        (setq localname "/"))
       ;; Do normal `expand-file-name' (this does "/./" and "/../").
       ;; `default-directory' is bound, because on Windows there would
@@ -3666,7 +3782,7 @@ Let-bind it when necessary.")
       (let ((default-directory tramp-compat-temporary-file-directory))
        (tramp-make-tramp-file-name
         v (tramp-drop-volume-letter
-           (if (string-match-p "\\`\\(~[^/]*\\)\\(.*\\)\\'" localname)
+           (if (string-prefix-p "~" localname)
                localname
              (tramp-run-real-handler #'expand-file-name (list 
localname)))))))))
 
@@ -3677,7 +3793,10 @@ Let-bind it when necessary.")
 
 (defun tramp-handle-file-directory-p (filename)
   "Like `file-directory-p' for Tramp files."
-  (eq (file-attribute-type (file-attributes (file-truename filename))) t))
+  ;; `file-truename' could raise an error, for example due to a cyclic
+  ;; symlink.
+  (ignore-errors
+    (eq (file-attribute-type (file-attributes (file-truename filename))) t)))
 
 (defun tramp-handle-file-equal-p (filename1 filename2)
   "Like `file-equalp-p' for Tramp files."
@@ -3694,7 +3813,9 @@ Let-bind it when necessary.")
   ;; We don't want to run it when `non-essential' is t, or there is
   ;; no connection process yet.
   (when (tramp-connectable-p filename)
-    (not (null (file-attributes filename)))))
+    (with-parsed-tramp-file-name filename nil
+      (with-tramp-file-property v localname "file-exists-p"
+       (not (null (file-attributes filename)))))))
 
 (defun tramp-handle-file-in-directory-p (filename directory)
   "Like `file-in-directory-p' for Tramp files."
@@ -3707,12 +3828,8 @@ Let-bind it when necessary.")
 
 (defun tramp-handle-file-local-copy (filename)
   "Like `file-local-copy' for Tramp files."
-  (with-parsed-tramp-file-name filename nil
-    (unless (file-exists-p filename)
-      (tramp-error v 'file-missing filename))
-    (let ((tmpfile (tramp-compat-make-temp-file filename)))
-      (copy-file filename tmpfile 'ok-if-already-exists 'keep-time)
-      tmpfile)))
+  (tramp-skeleton-file-local-copy filename
+    (copy-file filename tmpfile 'ok-if-already-exists 'keep-time)))
 
 (defun tramp-handle-file-modes (filename &optional flag)
   "Like `file-modes' for Tramp files."
@@ -3764,7 +3881,7 @@ Let-bind it when necessary.")
                  ;; lower case letters.  This avoids us to create a
                  ;; temporary file.
                  (while (and (string-match-p
-                              "[[:lower:]]" (tramp-file-local-name candidate))
+                              (rx lower) (tramp-file-local-name candidate))
                              (not (file-exists-p candidate)))
                    (setq candidate
                          (directory-file-name
@@ -3772,7 +3889,7 @@ Let-bind it when necessary.")
                  ;; Nothing found, so we must use a temporary file
                  ;; for comparison.
                  (unless (string-match-p
-                          "[[:lower:]]" (tramp-file-local-name candidate))
+                          (rx lower) (tramp-file-local-name candidate))
                    (setq tmpfile
                          (let ((default-directory
                                 (file-name-directory filename)))
@@ -3807,7 +3924,8 @@ Let-bind it when necessary.")
           (and
            completion-ignored-extensions
            (string-match-p
-            (concat (regexp-opt completion-ignored-extensions 'paren) "$") x)
+            (rx (regexp (regexp-opt completion-ignored-extensions)) eos)
+            x)
            ;; We remember the hit.
            (push x hits-ignored-extensions))))))
      ;; No match.  So we try again for ignored files.
@@ -3849,7 +3967,8 @@ Let-bind it when necessary.")
          ;; links.
          (when-let ((symlink (file-symlink-p filename)))
            (and (stringp symlink)
-                (file-readable-p (concat (file-remote-p filename) 
symlink))))))))
+                (file-readable-p
+                 (concat (file-remote-p filename) symlink))))))))
 
 (defun tramp-handle-file-regular-p (filename)
   "Like `file-regular-p' for Tramp files."
@@ -3867,7 +3986,7 @@ Let-bind it when necessary.")
       (let* ((o (tramp-dissect-file-name filename))
             (p (tramp-get-connection-process o))
             (c (and (process-live-p p)
-                    (tramp-get-connection-property p "connected" nil))))
+                    (tramp-get-connection-property p "connected"))))
        ;; We expand the file name only, if there is already a connection.
        (with-parsed-tramp-file-name
            (if c (expand-file-name filename) filename) nil
@@ -3978,15 +4097,17 @@ Let-bind it when necessary.")
        (when (and (not tramp-allow-unsafe-temporary-files)
                   (not backup-inhibited)
                   (file-in-directory-p (car result) temporary-file-directory)
-                  (zerop (or (file-attribute-user-id
-                              (file-attributes filename 'integer))
-                             tramp-unknown-id-integer))
+                  (= (or (file-attribute-user-id
+                          (file-attributes filename 'integer))
+                         tramp-unknown-id-integer)
+                     tramp-root-id-integer)
                   (not (with-tramp-connection-property
                            (tramp-get-process v) "unsafe-temporary-file"
                          (yes-or-no-p
-                          (concat
-                           "Backup file on local temporary directory, "
-                           "do you want to continue?")))))
+                          (eval-when-compile
+                            (concat
+                             "Backup file on local temporary directory, "
+                             "do you want to continue?"))))))
          (tramp-error v 'file-error "Unsafe backup file name"))))))
 
 (defun tramp-handle-insert-directory
@@ -4015,12 +4136,13 @@ Let-bind it when necessary.")
            (goto-char (point-min))
            (while (setq start
                         (text-property-not-all
-                         (point) (point-at-eol) 'dired-filename t))
+                         (point) (line-end-position) 'dired-filename t))
              (delete-region
               start
-              (or (text-property-any start (point-at-eol) 'dired-filename t)
-                  (point-at-eol)))
-             (if (= (point-at-bol) (point-at-eol))
+              (or (text-property-any
+                   start (line-end-position) 'dired-filename t)
+                  (line-end-position)))
+             (if (= (line-beginning-position) (line-end-position))
                  ;; Empty line.
                  (delete-region (point) (progn (forward-line) (point)))
                (forward-line)))))))))
@@ -4033,13 +4155,10 @@ Let-bind it when necessary.")
   (let (result local-copy remote-copy)
     (with-parsed-tramp-file-name filename nil
       (unwind-protect
-         (if (not (file-exists-p filename))
-              (let ((tramp-verbose (if visit 0 tramp-verbose)))
-               (tramp-error v 'file-missing filename))
-
-           (with-tramp-progress-reporter
-               v 3 (format-message "Inserting `%s'" filename)
-             (condition-case err
+         (condition-case err
+             (tramp-barf-if-file-missing v filename
+               (with-tramp-progress-reporter
+                   v 3 (format-message "Inserting `%s'" filename)
                  (if (and (tramp-local-host-p v)
                           (let (file-name-handler-alist)
                             (file-readable-p localname)))
@@ -4052,7 +4171,7 @@ Let-bind it when necessary.")
 
                    ;; When we shall insert only a part of the file, we
                    ;; copy this part.  This works only for the shell file
-                   ;; name handlers.  It doesn't work for crypted files.
+                   ;; name handlers.  It doesn't work for encrypted files.
                    (when (and (or beg end)
                               (tramp-sh-file-name-handler-p v)
                               (null tramp-crypt-enabled))
@@ -4116,12 +4235,16 @@ Let-bind it when necessary.")
                            filename local-copy)))
                      (setq result
                            (insert-file-contents
-                            local-copy visit beg end replace))))
-               (error
-                (add-hook 'find-file-not-found-functions
-                          `(lambda () (signal ',(car err) ',(cdr err)))
-                          nil t)
-                (signal (car err) (cdr err))))))
+                            local-copy visit beg end replace))))))
+
+           (file-error
+            (let ((tramp-verbose (if visit 0 tramp-verbose)))
+              (tramp-error v 'file-missing filename)))
+           (error
+            (add-hook 'find-file-not-found-functions
+                      `(lambda () (signal ',(car err) ',(cdr err)))
+                      nil t)
+            (signal (car err) (cdr err))))
 
        ;; Save exit.
        (when visit
@@ -4141,15 +4264,13 @@ Let-bind it when necessary.")
 (defun tramp-ps-time ()
   "Read printed time oif \"ps\" in format \"[[DD-]hh:]mm:ss\".
 Return it as number of seconds.  Used in `tramp-process-attributes-ps-format'."
-  (search-forward-regexp "\\s-+")
-  (search-forward-regexp
-   (concat
-    "\\(?:" "\\(?:" "\\([0-9]+\\)-" "\\)?"
-                    "\\([0-9]+\\):" "\\)?"
-                    "\\([0-9]+\\):"
-                    ;; Seconds can also be a floating point number.
-                    "\\([0-9.]+\\)")
-   (line-end-position) 'noerror)
+  (search-forward-regexp (rx (+ space)))
+  (search-forward-regexp (rx (? (? (group (+ digit)) "-")
+                                  (group (+ digit)) ":")
+                                  (group (+ digit)) ":"
+                                  ;; Seconds can also be a floating point num.
+                                  (group (+ (any "." digit))))
+                        (line-end-position) 'noerror)
   (+ (* 24 60 60 (string-to-number (or (match-string 1) "0")))
         (* 60 60 (string-to-number (or (match-string 2) "0")))
            (* 60 (string-to-number (or (match-string 3) "0")))
@@ -4254,7 +4375,7 @@ It is not guaranteed, that all process attributes as 
described in
                 ;;  "%s" (buffer-substring (point) (line-end-position)))
                 (when (save-excursion
                         (search-forward-regexp
-                         "[[:digit:]]" (line-end-position) 'noerror))
+                        (rx digit) (line-end-position) 'noerror))
                   (setq res nil)
                   (dolist (elt tramp-process-attributes-ps-format)
                     (push
@@ -4263,18 +4384,18 @@ It is not guaranteed, that all process attributes as 
described in
                       (cond
                        ((eq (cdr elt) 'number) (read (current-buffer)))
                        ((eq (cdr elt) 'string)
-                        (search-forward-regexp "\\S-+")
+                        (search-forward-regexp (rx (+ (not space))))
                         (match-string 0))
                        ((numberp (cdr elt))
-                        (search-forward-regexp "\\s-+")
-                        (search-forward-regexp ".+" (+ (point) (cdr elt)))
+                        (search-forward-regexp (rx (+ space)))
+                        (search-forward-regexp
+                        (rx (+ nonl)) (+ (point) (cdr elt)))
                         (string-trim (match-string 0)))
                        ((fboundp (cdr elt))
                         (funcall (cdr elt)))
                        ((null (cdr elt))
-                        (search-forward-regexp "\\s-+")
-                        (buffer-substring (point) (line-end-position)))
-                       (t nil)))
+                        (search-forward-regexp (rx (+ whitespace)))
+                        (buffer-substring (point) (line-end-position)))))
                      res))
                   ;; `nice' could be `-'.
                   (setq res (rassq-delete-all '- res))
@@ -4300,7 +4421,7 @@ Return nil when there is no lockfile."
               (buffer-string))))))
 
 (defvar tramp-lock-pid nil
-  "A random nunber local for every connection.
+  "A random number local for every connection.
 Do not set it manually, it is used buffer-local in `tramp-get-lock-pid'.")
 
 (defun tramp-get-lock-pid (file)
@@ -4315,7 +4436,10 @@ Do not set it manually, it is used buffer-local in 
`tramp-get-lock-pid'.")
 
 (defconst tramp-lock-file-info-regexp
   ;; USER@HOST.PID[:BOOT_TIME]
-  "\\`\\(.+\\)@\\(.+\\)\\.\\([[:digit:]]+\\)\\(?::\\([[:digit:]]+\\)\\)?\\'"
+  (rx bos (group (+ nonl))
+      "@" (group (+ nonl))
+      "." (group (+ digit))
+      (? ":" (group (+ digit))) eos)
   "The format of a lock file.")
 
 (defun tramp-handle-file-locked-p (file)
@@ -4363,15 +4487,17 @@ Do not set it manually, it is used buffer-local in 
`tramp-get-lock-pid'.")
          (when (and (not tramp-allow-unsafe-temporary-files)
                     create-lockfiles
                     (file-in-directory-p lockname temporary-file-directory)
-                    (zerop (or (file-attribute-user-id
-                                (file-attributes file 'integer))
-                               tramp-unknown-id-integer))
+                    (= (or (file-attribute-user-id
+                            (file-attributes file 'integer))
+                           tramp-unknown-id-integer)
+                       tramp-root-id-integer)
                     (not (with-tramp-connection-property
                              (tramp-get-process v) "unsafe-temporary-file"
                            (yes-or-no-p
-                            (concat
-                             "Lock file on local temporary directory, "
-                             "do you want to continue?")))))
+                            (eval-when-compile
+                              (concat
+                               "Lock file on local temporary directory, "
+                               "do you want to continue?"))))))
            (tramp-error v 'file-error "Unsafe lock file name")))
 
        ;; Do the lock.
@@ -4410,7 +4536,7 @@ Do not set it manually, it is used buffer-local in 
`tramp-get-lock-pid'.")
       ;; The first condition is always true for absolute file names.
       ;; Included for safety's sake.
       (unless (or (file-name-directory file)
-                 (string-match-p "\\.elc?\\'" file))
+                 (string-match-p (rx ".el" (? "c") eos) file))
        (tramp-error
         v 'file-error
         "File `%s' does not include a `.el' or `.elc' suffix" file)))
@@ -4443,9 +4569,9 @@ Do not set it manually, it is used buffer-local in 
`tramp-get-lock-pid'.")
                     tramp-prefix-format proxy tramp-postfix-host-format))
             (entry
              (list (and (stringp host-port)
-                        (concat "^" (regexp-quote host-port) "$"))
+                        (rx bol (literal host-port) eol))
                    (and (stringp user-domain)
-                        (concat "^" (regexp-quote user-domain) "$"))
+                        (rx bol (literal user-domain) eol))
                    (propertize proxy 'tramp-ad-hoc t))))
        (tramp-message vec 5 "Add %S to `tramp-default-proxies-alist'" entry)
        ;; Add the hop.
@@ -4524,7 +4650,7 @@ Do not set it manually, it is used buffer-local in 
`tramp-get-lock-pid'.")
            (setq tramp-default-proxies-alist saved-tdpa)
            (tramp-user-error
             vec "Host name `%s' does not match `%s'" host previous-host))
-         (setq previous-host (concat "^" (regexp-quote host) "$")))))
+         (setq previous-host (rx bol (literal host) eol)))))
 
     ;; Result.
     target-alist))
@@ -4553,7 +4679,7 @@ substitution.  SPEC-LIST is a list of char/value pairs 
used for
     (and ;; The method supports it.
          (tramp-get-method-parameter v 'tramp-direct-async)
         ;; It has been indicated.
-         (tramp-get-connection-property v "direct-async-process" nil)
+         (tramp-get-connection-property v "direct-async-process")
         ;; There's no multi-hop.
         (or (not (tramp-multi-hop-p v))
             (= (length (tramp-compute-multi-hops v)) 1))
@@ -4590,7 +4716,10 @@ substitution.  SPEC-LIST is a list of char/value pairs 
used for
          (signal 'wrong-type-argument (list #'symbolp coding)))
        (when (eq connection-type t)
          (setq connection-type 'pty))
-       (unless (memq connection-type '(nil pipe pty))
+       (unless (or (and (consp connection-type)
+                        (memq (car connection-type) '(nil pipe pty))
+                        (memq (cdr connection-type) '(nil pipe pty)))
+                   (memq connection-type '(nil pipe pty)))
          (signal 'wrong-type-argument (list #'symbolp connection-type)))
        (unless (or (null filter) (eq filter t) (functionp filter))
          (signal 'wrong-type-argument (list #'functionp filter)))
@@ -4634,6 +4763,7 @@ substitution.  SPEC-LIST is a list of char/value pairs 
used for
          ;; is different between tramp-sh.el, and tramp-adb.el or
          ;; tramp-sshfs.el.
          (let* ((sh-file-name-handler-p (tramp-sh-file-name-handler-p v))
+                (adb-file-name-handler-p (tramp-adb-file-name-p v))
                 (login-program
                  (tramp-get-method-parameter v 'tramp-login-program))
                 ;; We don't create the temporary file.  In fact, it
@@ -4653,6 +4783,10 @@ substitution.  SPEC-LIST is a list of char/value pairs 
used for
                  (when sh-file-name-handler-p
                    (tramp-compat-funcall
                     'tramp-ssh-controlmaster-options v)))
+                (device
+                 (when adb-file-name-handler-p
+                   (tramp-compat-funcall
+                    'tramp-adb-get-device v)))
                 login-args p)
 
            ;; Replace `login-args' place holders.  Split
@@ -4669,7 +4803,7 @@ substitution.  SPEC-LIST is a list of char/value pairs 
used for
                 v 'tramp-login-args
                 ?h (or host "") ?u (or user "") ?p (or port "")
                 ?c (format-spec (or options "") (format-spec-make ?t tmpfile))
-                ?l ""))))
+                ?d (or device "") ?l ""))))
             p (make-process
                :name name :buffer buffer
                :command (append `(,login-program) login-args command)
@@ -4705,7 +4839,7 @@ support symbolic links."
 
 (defun tramp-handle-shell-command (command &optional output-buffer 
error-buffer)
   "Like `shell-command' for Tramp files."
-  (let* ((asynchronous (string-match-p "[ \t]*&[ \t]*\\'" command))
+  (let* ((asynchronous (string-match-p (rx (* space) "&" (* space) eos) 
command))
         (command (substring command 0 asynchronous))
         current-buffer-p
         (output-buffer-p output-buffer)
@@ -4807,11 +4941,7 @@ support symbolic links."
              ;; Run the process.
              (setq p (start-file-process-shell-command
                       (buffer-name output-buffer) buffer command))
-           ;; Insert error messages if they were separated.
-           (when error-file
-             (with-current-buffer error-buffer
-               (insert-file-contents-literally error-file)))
-           (if (process-live-p p)
+           (when (process-live-p p)
              ;; Display output.
              (with-current-buffer output-buffer
                (setq mode-line-process '(":%s"))
@@ -4827,14 +4957,18 @@ support symbolic links."
                       (insert-file-contents-literally
                        error-file nil nil nil 'replace))
                     (delete-file error-file))))
-               (display-buffer output-buffer '(nil (allow-no-window . t))))
+               (display-buffer output-buffer '(nil (allow-no-window . t)))))
 
-             (when error-file
-               (delete-file error-file)))))
+           ;; Insert error messages if they were separated.
+           (when (and error-file (not (process-live-p p)))
+             (with-current-buffer error-buffer
+               (insert-file-contents-literally error-file))
+             (delete-file error-file))))
 
+      ;; Synchronous case.
       (prog1
          ;; Run the process.
-         (process-file-shell-command command nil buffer nil)
+         (process-file-shell-command command nil buffer)
        ;; Insert error messages if they were separated.
        (when error-file
          (with-current-buffer error-buffer
@@ -4888,14 +5022,14 @@ BUFFER might be a list, in this case STDERR is 
separated."
       (let (process-environment)
        ;; Ignore in LOCALNAME everything before "//" or "/~".
        (when (stringp localname)
-         (if (string-match "//\\(/\\|~\\)" localname)
+         (if (string-match-p (rx "//" (| "/" "~")) localname)
              (setq filename
                     (replace-regexp-in-string
-                     "\\`/+" "/" (substitute-in-file-name localname)))
+                     (rx bos (+ "/")) "/" (substitute-in-file-name localname)))
            (setq filename
                  (concat (file-remote-p filename)
                          (replace-regexp-in-string
-                           "\\`/+" "/"
+                           (rx bos (+ "/")) "/"
                           ;; We must disable cygwin-mount file name
                           ;; handlers and alike.
                           (tramp-run-real-handler
@@ -5059,8 +5193,7 @@ of."
       ;; Sometimes, the process returns a new password request
       ;; immediately after rejecting the previous (wrong) one.
       (unless (or tramp-password-prompt-not-unique
-                 (tramp-get-connection-property
-                  vec "first-password-request" nil))
+                 (tramp-get-connection-property vec "first-password-request"))
        (tramp-clear-passwd vec))
       (goto-char (point-min))
       (tramp-check-for-regexp proc tramp-process-action-regexp)
@@ -5143,7 +5276,8 @@ Wait, until the connection buffer changes."
       (ignore set-message-function clear-message-function)
       (tramp-message vec 6 "\n%s" (buffer-string))
       (tramp-check-for-regexp proc tramp-process-action-regexp)
-      (with-temp-message (replace-regexp-in-string "[\r\n]" "" (match-string 
0))
+      (with-temp-message
+         (replace-regexp-in-string (rx (any "\r\n")) "" (match-string 0))
        ;; Hide message in buffer.
        (narrow-to-region (point-max) (point-max))
        ;; Wait for new output.
@@ -5185,8 +5319,7 @@ Wait, until the connection buffer changes."
                 (tramp-message vec 3 "Process has finished.")
                 (throw 'tramp-action 'ok))
             (tramp-message vec 3 "Process has died.")
-            (throw 'tramp-action 'out-of-band-failed))))
-       (t nil)))
+            (throw 'tramp-action 'out-of-band-failed))))))
 
 ;;; Functions for processing the actions:
 
@@ -5304,7 +5437,7 @@ performed successfully.  Any other value means an error."
   "Lock PROC for other communication, and run BODY.
 Mostly useful to protect BODY from being interrupted by timers."
   (declare (indent 1) (debug t))
-  `(if (tramp-get-connection-property ,proc "locked" nil)
+  `(if (tramp-get-connection-property ,proc "locked")
        ;; Be kind for older Emacsen.
        (if (member 'remote-file-error debug-ignored-errors)
           (throw 'non-essential 'non-essential)
@@ -5357,7 +5490,7 @@ Erase echoed commands if exists."
     ;; Check whether we need to remove echo output.  The max length of
     ;; the echo mark regexp is taken for search.  We restrict the
     ;; search for the second echo mark to PIPE_BUF characters.
-    (when (and (tramp-get-connection-property proc "check-remote-echo" nil)
+    (when (and (tramp-get-connection-property proc "check-remote-echo")
               (re-search-forward
                tramp-echoed-echo-mark-regexp
                (+ (point) (* 5 tramp-echo-mark-marker-length)) t))
@@ -5373,7 +5506,7 @@ Erase echoed commands if exists."
          (delete-region begin (point))
          (goto-char (point-min)))))
 
-    (when (or (not (tramp-get-connection-property proc "check-remote-echo" 
nil))
+    (when (or (not (tramp-get-connection-property proc "check-remote-echo"))
              ;; Sometimes, the echo string is suppressed on the remote side.
              (not (string-equal
                    (substring-no-properties
@@ -5435,7 +5568,7 @@ The STRING is expected to use Unix line-endings, but the 
lines sent to
 the remote host use line-endings as defined in the variable
 `tramp-rsh-end-of-line'.  The communication buffer is erased before sending."
   (let* ((p (tramp-get-connection-process vec))
-        (chunksize (tramp-get-connection-property p "chunksize" nil)))
+        (chunksize (tramp-get-connection-property p "chunksize")))
     (unless p
       (tramp-error
        vec 'file-error "Can't send string to remote host -- not logged in"))
@@ -5473,14 +5606,14 @@ the remote host use line-endings as defined in the 
variable
   (unless (process-live-p proc)
     (let ((vec (process-get proc 'vector))
          (buf (process-buffer proc))
-         (prompt (tramp-get-connection-property proc "prompt" nil)))
+         (prompt (tramp-get-connection-property proc "prompt")))
       (when vec
        (tramp-message vec 5 "Sentinel called: `%S' `%s'" proc event)
         (tramp-flush-connection-properties proc)
-        (tramp-flush-directory-properties vec ""))
+        (tramp-flush-directory-properties vec "/"))
       (when (buffer-live-p buf)
        (with-current-buffer buf
-          (when (and prompt (tramp-search-regexp (regexp-quote prompt)))
+          (when (and prompt (tramp-search-regexp (rx (literal prompt))))
            (delete-region (point) (point-max))))))))
 
 (defun tramp-get-inode (vec)
@@ -5684,7 +5817,7 @@ VEC is used for tracing."
          (while candidates
            (goto-char (point-min))
            (if (string-match-p
-                (format "^%s\r?$" (regexp-quote (car candidates)))
+                (rx bol (literal (car candidates)) (? "\r") eol)
                 (buffer-string))
                (setq locale (car candidates)
                      candidates nil)
@@ -5697,51 +5830,144 @@ VEC is used for tracing."
   "Check `file-attributes' caches for VEC.
 Return t if according to the cache access type ACCESS is known to
 be granted."
-  (let ((result nil)
-        (offset (cond
-                 ((eq ?r access) 1)
-                 ((eq ?w access) 2)
-                 ((eq ?x access) 3)
-                 ((eq ?s access) 3))))
-    (dolist (suffix '("string" "integer") result)
-      (setq
-       result
-       (or
-        result
-        (let ((file-attr
-              (or
-               (tramp-get-file-property
-                vec (tramp-file-name-localname vec)
-                (concat "file-attributes-" suffix) nil)
-               (file-attributes
-                (tramp-make-tramp-file-name vec) (intern suffix))))
-              (remote-uid (tramp-get-remote-uid vec (intern suffix)))
-              (remote-gid (tramp-get-remote-gid vec (intern suffix)))
-             (unknown-id
-              (if (string-equal suffix "string")
-                  tramp-unknown-id-string tramp-unknown-id-integer)))
-          (and
-           file-attr
-           (or
-            ;; Not a symlink.
-            (eq t (file-attribute-type file-attr))
-            (null (file-attribute-type file-attr)))
-           (or
-            ;; World accessible.
-            (eq access (aref (file-attribute-modes file-attr) (+ offset 6)))
-            ;; User accessible and owned by user.
-            (and
-             (eq access (aref (file-attribute-modes file-attr) offset))
-            (or (equal remote-uid unknown-id)
-                (equal remote-uid (file-attribute-user-id file-attr))
-                (equal unknown-id (file-attribute-user-id file-attr))))
-            ;; Group accessible and owned by user's principal group.
-            (and
-             (eq access
-                (aref (file-attribute-modes file-attr) (+ offset 3)))
-             (or (equal remote-gid unknown-id)
-                (equal remote-gid (file-attribute-group-id file-attr))
-                (equal unknown-id (file-attribute-group-id 
file-attr))))))))))))
+  (when-let ((offset (cond
+                      ((eq ?r access) 1)
+                      ((eq ?w access) 2)
+                      ((eq ?x access) 3)
+                      ((eq ?s access) 3)))
+            (file-attr (file-attributes (tramp-make-tramp-file-name vec)))
+            (remote-uid (tramp-get-remote-uid vec 'integer))
+            (remote-gid (tramp-get-remote-gid vec 'integer)))
+    (or
+     ;; Not a symlink.
+     (eq t (file-attribute-type file-attr))
+     (null (file-attribute-type file-attr)))
+    (or
+     ;; World accessible.
+     (eq access (aref (file-attribute-modes file-attr) (+ offset 6)))
+     ;; User accessible and owned by user.
+     (and
+      (eq access (aref (file-attribute-modes file-attr) offset))
+      (or (equal remote-uid tramp-root-id-integer)
+         (equal remote-uid tramp-unknown-id-integer)
+         (equal remote-uid (file-attribute-user-id file-attr))
+         (equal tramp-unknown-id-integer (file-attribute-user-id file-attr))))
+     ;; Group accessible and owned by user's principal group.
+     (and
+      (eq access
+         (aref (file-attribute-modes file-attr) (+ offset 3)))
+      (or (equal remote-gid tramp-root-id-integer)
+         (equal remote-gid tramp-unknown-id-integer)
+         (equal remote-gid (file-attribute-group-id file-attr))
+         (equal tramp-unknown-id-integer
+                (file-attribute-group-id file-attr)))))))
+
+(defmacro tramp-convert-file-attributes (vec localname id-format attr)
+  "Convert `file-attributes' ATTR generated Tramp backend functions.
+Convert file mode bits to string and set virtual device number.
+Set file uid and gid according to ID-FORMAT.  LOCALNAME is used
+to cache the result.  Return the modified ATTR."
+  (declare (indent 3) (debug t))
+  `(with-tramp-file-property
+       ,vec ,localname (format "file-attributes-%s" (or ,id-format 'integer))
+     (when-let
+        ((result
+          (with-tramp-file-property ,vec ,localname "file-attributes"
+            (when-let ((attr ,attr))
+              (save-match-data
+                ;; Remove color escape sequences from symlink.
+                (when (stringp (car attr))
+                  (while (string-match
+                          tramp-display-escape-sequence-regexp (car attr))
+                    (setcar attr (replace-match "" nil nil (car attr)))))
+                ;; Convert uid and gid.  Use `tramp-unknown-id-integer'
+                ;; as indication of unusable value.
+                (when (consp (nth 2 attr))
+                  (when (and (numberp (cdr (nth 2 attr)))
+                             (< (cdr (nth 2 attr)) 0))
+                    (setcdr (car (nthcdr 2 attr)) tramp-unknown-id-integer))
+                  (when (and (floatp (cdr (nth 2 attr)))
+                             (<= (cdr (nth 2 attr)) most-positive-fixnum))
+                    (setcdr (car (nthcdr 2 attr)) (round (cdr (nth 2 attr))))))
+                (when (consp (nth 3 attr))
+                  (when (and (numberp (cdr (nth 3 attr)))
+                             (< (cdr (nth 3 attr)) 0))
+                    (setcdr (car (nthcdr 3 attr)) tramp-unknown-id-integer))
+                  (when (and (floatp (cdr (nth 3 attr)))
+                             (<= (cdr (nth 3 attr)) most-positive-fixnum))
+                    (setcdr (car (nthcdr 3 attr)) (round (cdr (nth 3 attr))))))
+                ;; Convert last access time.
+                (unless (listp (nth 4 attr))
+                  (setcar (nthcdr 4 attr) (seconds-to-time (nth 4 attr))))
+                ;; Convert last modification time.
+                (unless (listp (nth 5 attr))
+                  (setcar (nthcdr 5 attr) (seconds-to-time (nth 5 attr))))
+                ;; Convert last status change time.
+                (unless (listp (nth 6 attr))
+                  (setcar (nthcdr 6 attr) (seconds-to-time (nth 6 attr))))
+                ;; Convert file size.
+                (when (< (nth 7 attr) 0)
+                  (setcar (nthcdr 7 attr) -1))
+                (when (and (floatp (nth 7 attr))
+                           (<= (nth 7 attr) most-positive-fixnum))
+                  (setcar (nthcdr 7 attr) (round (nth 7 attr))))
+                ;; Convert file mode bits to string.
+                (unless (stringp (nth 8 attr))
+                  (setcar (nthcdr 8 attr)
+                          (tramp-file-mode-from-int (nth 8 attr)))
+                  (when (stringp (car attr))
+                    (aset (nth 8 attr) 0 ?l)))
+                ;; Convert directory indication bit.
+                (when (string-prefix-p "d" (nth 8 attr))
+                  (setcar attr t))
+                ;; Convert symlink from `tramp-do-file-attributes-with-stat'.
+                ;; Decode also multibyte string.
+                (when (consp (car attr))
+                  (setcar attr
+                          (and (stringp (caar attr))
+                               (string-match
+                                (rx (+ nonl) " -> " nonl (group (+ nonl)) nonl)
+                                (caar attr))
+                               (decode-coding-string
+                                (match-string 1 (caar attr)) 'utf-8))))
+                ;; Set file's gid change bit.
+                (setcar
+                 (nthcdr 9 attr)
+                 (not (= (cdr (nth 3 attr))
+                         (or (tramp-get-remote-gid ,vec 'integer)
+                             tramp-unknown-id-integer))))
+                ;; Convert inode.
+                (when (floatp (nth 10 attr))
+                  (setcar (nthcdr 10 attr)
+                          (condition-case nil
+                              (let ((high (nth 10 attr))
+                                    middle low)
+                                (if (<= high most-positive-fixnum)
+                                    (floor high)
+                                  ;; The low 16 bits.
+                                  (setq low (mod high #x10000)
+                                        high (/ high #x10000))
+                                  (if (<= high most-positive-fixnum)
+                                      (cons (floor high) (floor low))
+                                    ;; The middle 24 bits.
+                                    (setq middle (mod high #x1000000)
+                                          high (/ high #x1000000))
+                                    (cons (floor high)
+                                          (cons (floor middle) (floor low))))))
+                            ;; Inodes can be incredible huge.  We
+                            ;; must hide this.
+                            (error (tramp-get-inode ,vec)))))
+                ;; Set virtual device number.
+                (setcar (nthcdr 11 attr)
+                        (tramp-get-device ,vec))
+                attr)))))
+
+       ;; Return normalized result.
+       (append (tramp-compat-take 2 result)
+              (if (eq ,id-format 'string)
+                  (list (car (nth 2 result)) (car (nth 3 result)))
+                (list (cdr (nth 2 result)) (cdr (nth 3 result))))
+              (nthcdr 4 result)))))
 
 (defun tramp-get-home-directory (vec &optional user)
   "The remote home directory for connection VEC as local file name.
@@ -5786,18 +6012,18 @@ This handles also chrooted environments, which are not 
regarded as local."
      ;; handlers.  `tramp-local-host-p' is also called for "smb" and
      ;; alike, where it must fail.
      (tramp-sh-file-name-handler-p vec)
-     ;; Direct actions aren't possible for crypted directories.
+     ;; Direct actions aren't possible for encrypted directories.
      (null tramp-crypt-enabled)
      ;; The local temp directory must be writable for the other user.
      (file-writable-p
       (tramp-make-tramp-file-name vec tramp-compat-temporary-file-directory))
      ;; On some systems, chown runs only for root.
      (or (zerop (user-uid))
-        (zerop (tramp-get-remote-uid vec 'integer))))))
+        (= (tramp-get-remote-uid vec 'integer) tramp-root-id-integer)))))
 
 (defun tramp-get-remote-tmpdir (vec)
   "Return directory for temporary files on the remote host identified by VEC."
-  (with-tramp-connection-property vec "tmpdir"
+  (with-tramp-connection-property (tramp-get-process vec) "remote-tmpdir"
     (let ((dir
           (tramp-make-tramp-file-name
            vec (or (tramp-get-method-parameter vec 'tramp-tmpdir) "/tmp"))))
@@ -5814,21 +6040,16 @@ This handles also chrooted environments, which are not 
regarded as local."
 (defun tramp-make-tramp-temp-file (vec)
   "Create a temporary file on the remote host identified by VEC.
 Return the local name of the temporary file."
-  (let (result)
-    (while (not result)
-      ;; `make-temp-file' would be the natural choice for
-      ;; implementation.  But it calls `write-region' internally,
-      ;; which also needs a temporary file - we would end in an
-      ;; infinite loop.
-      (setq result (tramp-make-tramp-temp-name vec))
-      (if (file-exists-p result)
-         (setq result nil)
-       ;; This creates the file by side effect.
-       (set-file-times result)
-       (set-file-modes result #o0700)))
-
-    ;; Return the local part.
-    (tramp-file-local-name result)))
+  (let (create-lockfiles)
+    (cl-letf (((symbol-function 'tramp-remote-acl-p) #'ignore)
+             ((symbol-function 'tramp-remote-selinux-p) #'ignore)
+             ((symbol-function 'tramp-smb-remote-acl-p) #'ignore)
+             ((symbol-function 'tramp-sudoedit-remote-acl-p) #'ignore)
+             ((symbol-function 'tramp-sudoedit-remote-selinux-p) #'ignore))
+      (tramp-file-local-name
+       (make-temp-file
+       (expand-file-name
+        tramp-temp-name-prefix (tramp-get-remote-tmpdir vec)))))))
 
 (defun tramp-delete-temp-file-function ()
   "Remove temporary files related to current buffer."
@@ -5884,15 +6105,17 @@ this file, if that variable is non-nil."
        (when (and (not tramp-allow-unsafe-temporary-files)
                   auto-save-default
                   (file-in-directory-p result temporary-file-directory)
-                  (zerop (or (file-attribute-user-id
-                              (file-attributes filename 'integer))
-                             tramp-unknown-id-integer))
+                  (= (or (file-attribute-user-id
+                          (file-attributes filename 'integer))
+                         tramp-unknown-id-integer)
+                     tramp-root-id-integer)
                   (not (with-tramp-connection-property
                            (tramp-get-process v) "unsafe-temporary-file"
                          (yes-or-no-p
-                          (concat
-                           "Autosave file on local temporary directory, "
-                           "do you want to continue?")))))
+                          (eval-when-compile
+                            (concat
+                             "Autosave file on local temporary directory, "
+                             "do you want to continue?"))))))
          (tramp-error v 'file-error "Unsafe autosave file name"))))))
 
 (defun tramp-subst-strs-in-string (alist string)
@@ -5903,7 +6126,7 @@ ALIST is of the form ((FROM . TO) ...)."
       (let* ((pr (car alist))
              (from (car pr))
              (to (cdr pr)))
-        (while (string-match (regexp-quote from) string)
+        (while (string-match (rx (literal from)) string)
           (setq string (replace-match to t t string)))
         (setq alist (cdr alist))))
     string))
@@ -6005,7 +6228,7 @@ verbosity of 6."
              (apply #'process-lines program args)
            (error
             (tramp-error vec (car err) (cdr err)))))
-    (tramp-message vec 6 "%s" result)
+    (tramp-message vec 6 "\n%s" (mapconcat #'identity result "\n"))
     result))
 
 (defun tramp-process-running-p (process-name)
@@ -6041,7 +6264,7 @@ Consults the auth-source package."
         (key (tramp-make-tramp-file-name vec 'noloc))
         (method (tramp-file-name-method vec))
         (user (or (tramp-file-name-user-domain vec)
-                  (tramp-get-connection-property key "login-as" nil)))
+                  (tramp-get-connection-property key "login-as")))
         (host (tramp-file-name-host-port vec))
         (pw-prompt
          (or prompt
@@ -6064,8 +6287,7 @@ Consults the auth-source package."
         (setq tramp-password-save-function nil)
         ;; See if auth-sources contains something useful.
         (ignore-errors
-          (and (tramp-get-connection-property
-                vec "first-password-request" nil)
+          (and (tramp-get-connection-property vec "first-password-request")
                ;; Try with Tramp's current method.  If there is no
                ;; user name, `:create' triggers to ask for.  We
                ;; suppress it.
diff --git a/lisp/net/trampver.el b/lisp/net/trampver.el
index 9a2f495eb8..2b39add20d 100644
--- a/lisp/net/trampver.el
+++ b/lisp/net/trampver.el
@@ -52,9 +52,9 @@
     ;; Suppress message from `emacs-repository-get-branch'.  We must
     ;; also handle out-of-tree builds.
     (let ((inhibit-message t)
-         (debug-on-error nil)
          (dir (or (locate-dominating-file (locate-library "tramp") ".git")
-                  source-directory)))
+                  source-directory))
+         debug-on-error)
       ;; `emacs-repository-get-branch' has been introduced with Emacs 27.1.
       (with-no-warnings
        (and (stringp dir) (file-directory-p dir)
@@ -67,9 +67,9 @@
     ;; Suppress message from `emacs-repository-get-version'.  We must
     ;; also handle out-of-tree builds.
     (let ((inhibit-message t)
-         (debug-on-error nil)
          (dir (or (locate-dominating-file (locate-library "tramp") ".git")
-                  source-directory)))
+                  source-directory))
+         debug-on-error)
       (and (stringp dir) (file-directory-p dir)
           (executable-find "git")
           (emacs-repository-get-version dir))))
@@ -104,7 +104,7 @@
          ("2.3.3" . "26.1") ("2.3.3.26.1" . "26.1") ("2.3.5.26.2" . "26.2")
          ("2.3.5.26.3" . "26.3")
          ("2.4.3.27.1" . "27.1") ("2.4.5.27.2" . "27.2")
-         ("2.5.2.28.1" . "28.1")))
+         ("2.5.2.28.1" . "28.1") ("2.5.3.28.2" . "28.2")))
 
 (add-hook 'tramp-unload-hook
          (lambda ()
diff --git a/lisp/net/webjump.el b/lisp/net/webjump.el
index b2ef47898c..9886a4c79d 100644
--- a/lisp/net/webjump.el
+++ b/lisp/net/webjump.el
@@ -79,6 +79,14 @@
   :prefix "webjump-"
   :group 'browse-url)
 
+(defcustom webjump-use-internal-browser nil
+  "Whether or not to force the use of an internal browser.
+If non-nil, WebJump will always use an internal browser (such as
+EWW or xwidget-webkit) to open web pages, as opposed to an
+external browser like IceCat."
+  :version "29.1"
+  :type 'boolean)
+
 (defconst webjump-sample-sites
   '(
     ;; FSF, not including Emacs-specific.
@@ -255,18 +263,32 @@ Please submit bug reports and other feedback to the 
author, Neil W. Van Dyke
                webjump-sites t))
         (name (car item))
         (expr (cdr item)))
-    (browse-url (webjump-url-fix
-                (cond ((not expr) "")
-                      ((stringp expr) expr)
-                      ((vectorp expr) (webjump-builtin expr name))
-                      ((listp expr) (eval expr t))
-                      ((symbolp expr)
-                       (if (fboundp expr)
-                           (funcall expr name)
-                         (error "WebJump URL function \"%s\" undefined"
-                                expr)))
-                      (t (error "WebJump URL expression for \"%s\" invalid"
-                                name)))))))
+    (if webjump-use-internal-browser
+        (browse-url-with-browser-kind
+         'internal (webjump-url-fix
+                    (cond ((not expr) "")
+                          ((stringp expr) expr)
+                          ((vectorp expr) (webjump-builtin expr name))
+                          ((listp expr) (eval expr t))
+                          ((symbolp expr)
+                           (if (fboundp expr)
+                               (funcall expr name)
+                             (error "WebJump URL function \"%s\" undefined"
+                                    expr)))
+                          (t (error "WebJump URL expression for \"%s\" invalid"
+                                    name)))))
+      (browse-url (webjump-url-fix
+                   (cond ((not expr) "")
+                         ((stringp expr) expr)
+                         ((vectorp expr) (webjump-builtin expr name))
+                         ((listp expr) (eval expr t))
+                         ((symbolp expr)
+                          (if (fboundp expr)
+                              (funcall expr name)
+                            (error "WebJump URL function \"%s\" undefined"
+                                   expr)))
+                         (t (error "WebJump URL expression for \"%s\" invalid"
+                                   name))))))))
 
 (defun webjump-builtin (expr name)
   (if (< (length expr) 1)
diff --git a/lisp/nxml/nxml-mode.el b/lisp/nxml/nxml-mode.el
index 171b7088c1..dfe5c369e2 100644
--- a/lisp/nxml/nxml-mode.el
+++ b/lisp/nxml/nxml-mode.el
@@ -369,31 +369,29 @@ and, if `nxml-char-ref-display-glyph-flag' is non-nil, a 
glyph
 corresponding to the referenced character following the character
 reference.")
 
-(defvar nxml-mode-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "\M-\C-u" 'nxml-backward-up-element)
-    (define-key map "\M-\C-d" 'nxml-down-element)
-    (define-key map "\M-\C-n" 'nxml-forward-element)
-    (define-key map "\M-\C-p" 'nxml-backward-element)
-    (define-key map "\M-{" 'nxml-backward-paragraph)
-    (define-key map "\M-}" 'nxml-forward-paragraph)
-    (define-key map "\M-h" 'nxml-mark-paragraph)
-    (define-key map "\C-c\C-f" 'nxml-finish-element)
-    (define-key map "\C-c]" 'nxml-finish-element)
-    (define-key map "\C-c/" 'nxml-finish-element)
-    (define-key map "\C-c\C-m" 'nxml-split-element)
-    (define-key map "\C-c\C-b" 'nxml-balanced-close-start-tag-block)
-    (define-key map "\C-c\C-i" 'nxml-balanced-close-start-tag-inline)
-    (define-key map "\C-c\C-x" 'nxml-insert-xml-declaration)
-    (define-key map "\C-c\C-d" 'nxml-dynamic-markup-word)
-    ;; u is for Unicode
-    (define-key map "\C-c\C-u" 'nxml-insert-named-char)
-    (define-key map "\C-c\C-o" nxml-outline-prefix-map)
-    (define-key map [S-mouse-2] 'nxml-mouse-hide-direct-text-content)
-    (define-key map "/" 'nxml-electric-slash)
-    (define-key map "\M-\t" 'completion-at-point)
-    map)
-  "Keymap for `nxml-mode'.")
+(defvar-keymap nxml-mode-map
+  :doc "Keymap for `nxml-mode'."
+  "C-M-u"   #'nxml-backward-up-element
+  "C-M-d"   #'nxml-down-element
+  "C-M-n"   #'nxml-forward-element
+  "C-M-p"   #'nxml-backward-element
+  "M-{"     #'nxml-backward-paragraph
+  "M-}"     #'nxml-forward-paragraph
+  "M-h"     #'nxml-mark-paragraph
+  "C-c C-f" #'nxml-finish-element
+  "C-c ]"   #'nxml-finish-element
+  "C-c /"   #'nxml-finish-element
+  "C-c C-m" #'nxml-split-element
+  "C-c C-b" #'nxml-balanced-close-start-tag-block
+  "C-c C-i" #'nxml-balanced-close-start-tag-inline
+  "C-c C-x" #'nxml-insert-xml-declaration
+  "C-c C-d" #'nxml-dynamic-markup-word
+  ;; u is for Unicode
+  "C-c C-u" #'nxml-insert-named-char
+  "C-c C-o" nxml-outline-prefix-map
+  "/"       #'nxml-electric-slash
+  "M-TAB"   #'completion-at-point
+  "S-<mouse-2>" #'nxml-mouse-hide-direct-text-content)
 
 (defvar nxml-font-lock-keywords
   '(nxml-fontify-matcher)
diff --git a/lisp/nxml/nxml-outln.el b/lisp/nxml/nxml-outln.el
index 928338a6af..1518122a79 100644
--- a/lisp/nxml/nxml-outln.el
+++ b/lisp/nxml/nxml-outln.el
@@ -129,20 +129,18 @@ See the variable `nxml-section-element-name-regexp' for 
more details."
 (defvar nxml-heading-scan-distance 1000
   "Maximum distance from section to scan for heading.")
 
-(defvar nxml-outline-prefix-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "\C-a" 'nxml-show-all)
-    (define-key map "\C-t" 'nxml-hide-all-text-content)
-    (define-key map "\C-r" 'nxml-refresh-outline)
-    (define-key map "\C-c" 'nxml-hide-direct-text-content)
-    (define-key map "\C-e" 'nxml-show-direct-text-content)
-    (define-key map "\C-d" 'nxml-hide-subheadings)
-    (define-key map "\C-s" 'nxml-show)
-    (define-key map "\C-k" 'nxml-show-subheadings)
-    (define-key map "\C-l" 'nxml-hide-text-content)
-    (define-key map "\C-i" 'nxml-show-direct-subheadings)
-    (define-key map "\C-o" 'nxml-hide-other)
-    map))
+(defvar-keymap nxml-outline-prefix-map
+  "C-a" #'nxml-show-all
+  "C-t" #'nxml-hide-all-text-content
+  "C-r" #'nxml-refresh-outline
+  "C-c" #'nxml-hide-direct-text-content
+  "C-e" #'nxml-show-direct-text-content
+  "C-d" #'nxml-hide-subheadings
+  "C-s" #'nxml-show
+  "C-k" #'nxml-show-subheadings
+  "C-l" #'nxml-hide-text-content
+  "C-i" #'nxml-show-direct-subheadings
+  "C-o" #'nxml-hide-other)
 
 ;;; Commands for changing visibility
 
@@ -693,11 +691,9 @@ non-transparent child section."
                         (nxml-highlighted-qname (xmltok-end-tag-qname))
                         nxml-highlighted-greater-than))))
 
-(defvar nxml-outline-show-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "\C-m" 'nxml-show-direct-text-content)
-    (define-key map [mouse-2] 'nxml-mouse-show-direct-text-content)
-    map))
+(defvar-keymap nxml-outline-show-map
+  "RET" #'nxml-show-direct-text-content
+  "<mouse-2>" #'nxml-mouse-show-direct-text-content)
 
 (defvar nxml-outline-show-help "mouse-2: show")
 
@@ -724,12 +720,10 @@ non-transparent child section."
 (put 'nxml-outline-display-heading 'evaporate t)
 (put 'nxml-outline-display-heading 'face 'nxml-heading)
 
-(defvar nxml-outline-hiding-tag-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map [mouse-1] 'nxml-mouse-show-direct-subheadings)
-    (define-key map [mouse-2] 'nxml-mouse-show-direct-text-content)
-    (define-key map "\C-m" 'nxml-show-direct-text-content)
-    map))
+(defvar-keymap nxml-outline-hiding-tag-map
+  "<mouse-1>" #'nxml-mouse-show-direct-subheadings
+  "<mouse-2>" #'nxml-mouse-show-direct-text-content
+  "RET" #'nxml-show-direct-text-content)
 
 (defvar nxml-outline-hiding-tag-help
   "mouse-1: show subheadings, mouse-2: show text content")
@@ -739,12 +733,10 @@ non-transparent child section."
 (put 'nxml-outline-display-hiding-tag 'keymap nxml-outline-hiding-tag-map)
 (put 'nxml-outline-display-hiding-tag 'help-echo nxml-outline-hiding-tag-help)
 
-(defvar nxml-outline-showing-tag-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map [mouse-1] 'nxml-mouse-hide-subheadings)
-    (define-key map [mouse-2] 'nxml-mouse-show-direct-text-content)
-    (define-key map "\C-m" 'nxml-show-direct-text-content)
-    map))
+(defvar-keymap nxml-outline-showing-tag-map
+  "<mouse-1>" #'nxml-mouse-hide-subheadings
+  "<mouse-2>" #'nxml-mouse-show-direct-text-content
+  "RET" #'nxml-show-direct-text-content)
 
 (defvar nxml-outline-showing-tag-help
   "mouse-1: hide subheadings, mouse-2: show text content")
diff --git a/lisp/nxml/nxml-parse.el b/lisp/nxml/nxml-parse.el
index ff9eda3fd2..56ba4480bf 100644
--- a/lisp/nxml/nxml-parse.el
+++ b/lisp/nxml/nxml-parse.el
@@ -246,7 +246,7 @@ same way as well-formedness error."
                    parsed-attributes)))
       (setq atts (cdr atts)))
     ;; We want to end up with the attributes followed by the
-    ;; the namespace attributes in the same order as
+    ;; namespace attributes in the same order as
     ;; xmltok-attributes and xmltok-namespace-attributes respectively.
     (when parsed-namespace-attributes
       (setq parsed-attributes
diff --git a/lisp/nxml/rng-dt.el b/lisp/nxml/rng-dt.el
index b88653f79e..0523e8132b 100644
--- a/lisp/nxml/rng-dt.el
+++ b/lisp/nxml/rng-dt.el
@@ -52,7 +52,7 @@ a datatype library.")
           (rng-dt-error "The string datatype does not take any parameters")))
        ((eq name 'token)
         (if (null params)
-            '(t rng-collapse-space)
+             '(t string-clean-whitespace)
           (rng-dt-error "The token datatype does not take any parameters")))
        (t
         (rng-dt-error "There is no built-in datatype %s" name))))
diff --git a/lisp/nxml/rng-loc.el b/lisp/nxml/rng-loc.el
index 0fa455cbb5..40332aacd5 100644
--- a/lisp/nxml/rng-loc.el
+++ b/lisp/nxml/rng-loc.el
@@ -354,7 +354,7 @@ NS is t if the document has a non-nil, but not otherwise 
known namespace."
   (or (cdr (assq 'uri props))
       (let ((type-id (cdr (assq 'typeId props))))
        (and type-id
-            (cons (rng-collapse-space type-id) nil)))))
+             (cons (string-clean-whitespace type-id) nil)))))
 
 (defun rng-possible-type-ids-using (file type-ids)
   (let ((rules (rng-get-parsed-schema-locating-file file))
@@ -366,7 +366,7 @@ NS is t if the document has a non-nil, but not otherwise 
known namespace."
             (let ((id (cdr (assq 'id (cdr rule)))))
               (when id
                 (setq type-ids
-                      (cons (rng-collapse-space id)
+                       (cons (string-clean-whitespace id)
                             type-ids)))))
            ((eq (car rule) 'include)
             (let ((uri (cdr (assq 'rules (cdr rule)))))
@@ -390,7 +390,7 @@ or nil."
       (cond ((and (eq (car rule) 'typeId)
                  (let ((id (assq 'id (cdr rule))))
                    (and id
-                        (string= (rng-collapse-space (cdr id)) type-id))))
+                         (string= (string-clean-whitespace (cdr id)) 
type-id))))
             (setq schema (rng-match-default-rule (cdr rule))))
            ((eq (car rule) 'include)
             (let ((uri (cdr (assq 'rules (cdr rule)))))
@@ -414,7 +414,7 @@ or nil."
             (setq rng-schema-locating-file-alist
                   (delq cached rng-schema-locating-file-alist)))
           nil)
-         ((and cached (equal (nth 1 cached) mtime))
+         ((and cached (time-equal-p (nth 1 cached) mtime))
           (nth 2 cached))
          (t
           (setq parsed (rng-parse-schema-locating-file file))
diff --git a/lisp/nxml/rng-match.el b/lisp/nxml/rng-match.el
index e767a9333b..f3549681f2 100644
--- a/lisp/nxml/rng-match.el
+++ b/lisp/nxml/rng-match.el
@@ -1154,7 +1154,7 @@ list may contain duplicates."
             (if (or (rng--ipattern-nullable
                      (rng-data-deriv child value))
                     (and (rng--ipattern-nullable child)
-                         (rng-blank-p value)))
+                          (string-blank-p value)))
                 (rng--ipattern-after ipattern)
               rng-not-allowed-ipattern)))
          ((eq type 'data)
diff --git a/lisp/nxml/rng-parse.el b/lisp/nxml/rng-parse.el
index 76cb94b144..1c08d77f56 100644
--- a/lisp/nxml/rng-parse.el
+++ b/lisp/nxml/rng-parse.el
@@ -62,7 +62,7 @@ be signaled in the same way as when it is not well-formed."
         (unless (rng-match-element-value (or text ""))
           (cons "Invalid data" (and text 'text))))
        ((and text
-             (not (rng-blank-p text))
+              (not (string-blank-p text))
              (not (rng-match-mixed-text)))
         (cons "Text not allowed" 'text))
        ((not start-tag)
diff --git a/lisp/nxml/rng-util.el b/lisp/nxml/rng-util.el
index 74f405410a..7ac6db25f4 100644
--- a/lisp/nxml/rng-util.el
+++ b/lisp/nxml/rng-util.el
@@ -36,8 +36,6 @@
 
 (defconst rng-builtin-datatypes-uri (rng-make-datatypes-uri ""))
 
-(defun rng-blank-p (str) (string-match "\\`[ \t\n\r]*\\'" str))
-
 (defun rng-substq (new old list)
   "Replace first member of LIST (if any) that is `eq' to OLD by NEW.
 LIST is not modified."
@@ -73,24 +71,15 @@ LIST is not modified."
                            s
                            t))
 
-(defun rng-collapse-space (string)
-  (setq string
-       (replace-regexp-in-string "[ \t\r\n]+" " " string t t))
-  (when (string-match "\\` " string)
-    (setq string (substring string 1)))
-  (when (string-match " \\'" string)
-    (setq string (substring string 0 -1)))
-  string)
-
 (define-error 'rng-error nil)
 
-;; Obsolete.
-
 (defun rng-uniquify-eq (list)
   (declare (obsolete seq-uniq "28.1"))
   (seq-uniq list #'eq))
 
 (define-obsolete-function-alias 'rng-uniquify-equal #'seq-uniq "28.1")
+(define-obsolete-function-alias 'rng-blank-p #'string-blank-p "29.1")
+(define-obsolete-function-alias 'rng-collapse-space #'string-clean-whitespace 
"29.1")
 
 (provide 'rng-util)
 
diff --git a/lisp/nxml/rng-valid.el b/lisp/nxml/rng-valid.el
index 56ff3b66c0..ad5c9c7a15 100644
--- a/lisp/nxml/rng-valid.el
+++ b/lisp/nxml/rng-valid.el
@@ -110,14 +110,14 @@
 
 (defcustom rng-state-cache-distance 2000
   "Distance in characters between each parsing and validation state cache."
-  :type 'integer)
+  :type 'natnum)
 
 (defcustom rng-validate-chunk-size 8000
   "Number of characters in a RELAX NG validation chunk.
 A validation chunk will be the smallest chunk that is at least this
 size and ends with a tag.  After validating a chunk, validation will
 continue only if Emacs is still idle."
-  :type 'integer)
+  :type 'natnum)
 
 (defcustom rng-validate-delay 1.5
   "Time in seconds that Emacs must be idle before starting a full validation.
@@ -1275,7 +1275,7 @@ Return nil at end of buffer, t otherwise."
 
 (defun rng-segment-blank-p (segment)
   (if (car segment)
-      (rng-blank-p (car segment))
+      (string-blank-p (car segment))
     (apply #'rng-region-blank-p
           (cdr segment))))
 
@@ -1303,7 +1303,7 @@ string between START and END."
        ((not (or (and whitespace
                       (or (eq whitespace t)
                           (if value
-                              (rng-blank-p value)
+                               (string-blank-p value)
                             (rng-region-blank-p start end))))
                  (rng-match-mixed-text)))
         (rng-mark-invalid "Text not allowed" start (or end (point))))))
diff --git a/lisp/obsolete/abbrevlist.el b/lisp/obsolete/abbrevlist.el
deleted file mode 100644
index ca508a1554..0000000000
--- a/lisp/obsolete/abbrevlist.el
+++ /dev/null
@@ -1,56 +0,0 @@
-;;; abbrevlist.el --- list one abbrev table alphabetically ordered  -*- 
lexical-binding: t; -*-
-
-;; Copyright (C) 1986, 1992, 2001-2022 Free Software Foundation, Inc.
-;; Suggested by a previous version by Gildea.
-
-;; Maintainer: emacs-devel@gnu.org
-;; Keywords: abbrev
-;; Package: emacs
-;; Obsolete-since: 24.1
-
-;; 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:
-
-;;;###autoload
-(defun list-one-abbrev-table (abbrev-table output-buffer)
-  "Display alphabetical listing of ABBREV-TABLE in buffer OUTPUT-BUFFER."
-  (with-output-to-temp-buffer output-buffer
-    (save-excursion
-      (let ((abbrev-list nil) (first-column 0))
-       (set-buffer standard-output)
-       (mapatoms
-         (function (lambda (abbrev)
-                     (setq abbrev-list (cons abbrev abbrev-list))))
-         abbrev-table)
-       (setq abbrev-list (sort abbrev-list #'string-lessp))
-       (while abbrev-list
-         (if (> (+ first-column 40) (window-width))
-             (progn
-               (insert "\n")
-               (setq first-column 0)))
-         (indent-to first-column)
-         (insert (symbol-name (car abbrev-list)))
-         (indent-to (+ first-column 8))
-         (insert (symbol-value (car abbrev-list)))
-         (setq first-column (+ first-column 40))
-         (setq abbrev-list (cdr abbrev-list)))))))
-
-(provide 'abbrevlist)
-
-;;; abbrevlist.el ends here
diff --git a/lisp/obsolete/assoc.el b/lisp/obsolete/assoc.el
deleted file mode 100644
index 76fcb4b78b..0000000000
--- a/lisp/obsolete/assoc.el
+++ /dev/null
@@ -1,140 +0,0 @@
-;;; assoc.el --- insert/delete functions on association lists  -*- 
lexical-binding: t -*-
-
-;; Copyright (C) 1996, 2001-2022 Free Software Foundation, Inc.
-
-;; Author: Barry A. Warsaw <bwarsaw@cen.com>
-;; Keywords: extensions
-;; Obsolete-since: 24.3
-
-;; 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:
-
-;; Association list utilities providing insertion, deletion, sorting
-;; fetching off key-value pairs in association lists.
-
-;;; Code:
-
-(defun asort (alist-symbol key)
-  "Move a specified key-value pair to the head of an alist.
-The alist is referenced by ALIST-SYMBOL.  Key-value pair to move to
-head is one matching KEY.  Returns the sorted list and doesn't affect
-the order of any other key-value pair.  Side effect sets alist to new
-sorted list."
-  (set alist-symbol
-       (sort (copy-alist (symbol-value alist-symbol))
-             (lambda (a _b) (equal (car a) key)))))
-
-
-(defun aelement (key value)
-  "Make a list of a cons cell containing car of KEY and cdr of VALUE.
-The returned list is suitable for concatenating with an existing
-alist, via `nconc'."
-  (list (cons key value)))
-
-
-(defun aheadsym (alist)
-  "Return the key symbol at the head of ALIST."
-  (car (car alist)))
-
-
-(defun anot-head-p (alist key)
-  "Find out if a specified key-value pair is not at the head of an alist.
-The alist to check is specified by ALIST and the key-value pair is the
-one matching the supplied KEY.  Returns nil if ALIST is nil, or if
-key-value pair is at the head of the alist.  Returns t if key-value
-pair is not at the head of alist.  ALIST is not altered."
-  (not (equal (aheadsym alist) key)))
-
-
-(defun aput (alist-symbol key &optional value)
-  "Insert a key-value pair into an alist.
-The alist is referenced by ALIST-SYMBOL.  The key-value pair is made
-from KEY and optionally, VALUE.  Returns the altered alist.
-
-If the key-value pair referenced by KEY can be found in the alist, and
-VALUE is supplied non-nil, then the value of KEY will be set to VALUE.
-If VALUE is not supplied, or is nil, the key-value pair will not be
-modified, but will be moved to the head of the alist.  If the key-value
-pair cannot be found in the alist, it will be inserted into the head
-of the alist (with value nil if VALUE is nil or not supplied)."
-  (let ((elem (aelement key value))
-        alist)
-    (asort alist-symbol key)
-    (setq alist (symbol-value alist-symbol))
-    (cond ((null alist) (set alist-symbol elem))
-         ((anot-head-p alist key) (set alist-symbol (nconc elem alist)))
-         (value (setcar alist (car elem)) alist)
-         (t alist))))
-
-
-(defun adelete (alist-symbol key)
-  "Delete a key-value pair from the alist.
-Alist is referenced by ALIST-SYMBOL and the key-value pair to remove
-is pair matching KEY.  Returns the altered alist."
-  (asort alist-symbol key)
-  (let ((alist (symbol-value alist-symbol)))
-    (cond ((null alist) nil)
-         ((anot-head-p alist key) alist)
-         (t (set alist-symbol (cdr alist))))))
-
-
-(defun aget (alist key &optional keynil-p)
-  "Return the value in ALIST that is associated with KEY.
-Optional KEYNIL-P describes what to do if the value associated with
-KEY is nil.  If KEYNIL-P is not supplied or is nil, and the value is
-nil, then KEY is returned.  If KEYNIL-P is non-nil, then nil would be
-returned.
-
-If no key-value pair matching KEY could be found in ALIST, or ALIST is
-nil then nil is returned.  ALIST is not altered."
-  (defvar assoc--copy)
-  (let ((assoc--copy (copy-alist alist)))
-    (cond ((null alist) nil)
-         ((progn (asort 'assoc--copy key) ; dynamic binding
-                 (anot-head-p assoc--copy key)) nil)
-         ((cdr (car assoc--copy)))
-         (keynil-p nil)
-         ((car (car assoc--copy)))
-         (t nil))))
-
-
-(defun amake (alist-symbol keylist &optional valuelist)
-  "Make an association list.
-The association list is attached to the alist referenced by
-ALIST-SYMBOL.  Each element in the KEYLIST becomes a key and is
-associated with the value in VALUELIST with the same index.  If
-VALUELIST is not supplied or is nil, then each key in KEYLIST is
-associated with nil.
-
-KEYLIST and VALUELIST should have the same number of elements, but
-this isn't enforced.  If VALUELIST is smaller than KEYLIST, remaining
-keys are associated with nil.  If VALUELIST is larger than KEYLIST,
-extra values are ignored.  Returns the created alist."
-  (let ((keycar (car keylist))
-        (keycdr (cdr keylist))
-        (valcar (car valuelist))
-        (valcdr (cdr valuelist)))
-    (cond ((null keycdr)
-          (aput alist-symbol keycar valcar))
-         (t
-          (amake alist-symbol keycdr valcdr)
-          (aput alist-symbol keycar valcar))))
-  (symbol-value alist-symbol))
-
-(provide 'assoc)
-
-;;; assoc.el ends here
diff --git a/lisp/obsolete/autoload.el b/lisp/obsolete/autoload.el
new file mode 100644
index 0000000000..680df739e0
--- /dev/null
+++ b/lisp/obsolete/autoload.el
@@ -0,0 +1,915 @@
+;;; autoload.el --- maintain autoloads in loaddefs.el  -*- lexical-binding: t 
-*-
+
+;; Copyright (C) 1991-1997, 2001-2022 Free Software Foundation, Inc.
+
+;; Author: Roland McGrath <roland@gnu.org>
+;; Keywords: maint
+;; Package: emacs
+;; Obsolete-since: 29.1
+
+;; 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 code helps GNU Emacs maintainers keep the loaddefs.el file up to
+;; date.  It interprets magic cookies of the form ";;;###autoload" in
+;; Lisp source files in various useful ways.  To learn more, read the
+;; source; if you're going to use this, you'd better be able to.
+
+;; The functions in this file have been superseded by loaddefs-gen.el.
+
+;; Note: When removing this file, also remove the references to
+;; `make-directory-autoloads' and `update-directory-autoloads' in
+;; subr.el.
+
+;;; Code:
+
+(require 'lisp-mode)                   ;for `doc-string-elt' properties.
+(require 'lisp-mnt)
+(require 'cl-lib)
+(require 'loaddefs-gen)
+
+;; This feels like it should be a defconst, but MH-E sets it to
+;; ";;;###mh-autoload" for the autoloads that are to go into mh-loaddefs.el.
+(defvar generate-autoload-cookie ";;;###autoload"
+  "Magic comment indicating the following form should be autoloaded.
+Used by \\[update-file-autoloads].  This string should be
+meaningless to Lisp (e.g., a comment).
+
+This string is used:
+
+\;;;###autoload
+\(defun function-to-be-autoloaded () ...)
+
+If this string appears alone on a line, the following form will be
+read and an autoload made for it.  If there is further text on the line,
+that text will be copied verbatim to `generated-autoload-file'.")
+
+(defvar autoload-excludes nil
+  "If non-nil, list of absolute file names not to scan for autoloads.")
+
+(defconst generate-autoload-section-header "\f\n;;;### "
+  "String that marks the form at the start of a new file's autoload section.")
+
+(defconst generate-autoload-section-trailer "\n;;;***\n"
+  "String which indicates the end of the section of autoloads for a file.")
+
+(defconst generate-autoload-section-continuation ";;;;;; "
+  "String to add on each continuation of the section header form.")
+
+;; In some ways it would be nicer to use a value that is recognizably
+;; not a time-value, eg t, but that can cause issues if an older Emacs
+;; that does not expect non-time-values loads the file.
+(defconst autoload--non-timestamp '(0 0 0 0)
+  "Value to insert when `autoload-timestamps' is nil.")
+
+(defvar autoload-timestamps nil                ; experimental, see bug#22213
+  "Non-nil means insert a timestamp for each input file into the output.
+We use these in incremental updates of the output file to decide
+if we need to rescan an input file.  If you set this to nil,
+then we use the timestamp of the output file instead.  As a result:
+ - for fixed inputs, the output will be the same every time
+ - incremental updates of the output file might not be correct if:
+   i) the timestamp of the output file cannot be trusted (at least
+     relative to that of the input files)
+   ii) any of the input files can be modified during the time it takes
+      to create the output
+   iii) only a subset of the input files are scanned
+   These issues are unlikely to happen in practice, and would arguably
+   represent bugs in the build system.  Item iii) will happen if you
+   use a command like `update-file-autoloads', though, since it only
+   checks a single input file.")
+
+(defvar autoload-modified-buffers)      ;Dynamically scoped var.
+
+(defalias 'make-autoload #'loaddefs-generate--make-autoload)
+
+;; Forms which have doc-strings which should be printed specially.
+;; A doc-string-elt property of ELT says that (nth ELT FORM) is
+;; the doc-string in FORM.
+;; Those properties are now set in lisp-mode.el.
+
+(defun autoload-find-generated-file (file)
+  "Visit the autoload file for the current buffer, and return its buffer."
+  (let ((enable-local-variables :safe)
+        (enable-local-eval nil)
+        (find-file-hook nil)
+        (delay-mode-hooks t))
+    ;; We used to use `raw-text' to read this file, but this causes
+    ;; problems when the file contains non-ASCII characters.
+    (with-current-buffer (find-file-noselect
+                          (autoload-ensure-file-writeable file))
+      (if (zerop (buffer-size)) (insert (autoload-rubric file nil t)))
+      (current-buffer))))
+
+(defun autoload-generated-file (outfile)
+  "Return OUTFILE as an absolute name.
+If `generated-autoload-file' is bound locally in the current
+buffer, that is used instead, and it is expanded using the
+default directory; otherwise, `source-directory'/lisp is used."
+  (expand-file-name (if (local-variable-p 'generated-autoload-file)
+                        generated-autoload-file
+                      outfile)
+                    ;; File-local settings of generated-autoload-file should
+                    ;; be interpreted relative to the file's location,
+                    ;; of course.
+                    (if (not (local-variable-p 'generated-autoload-file))
+                        (expand-file-name "lisp" source-directory))))
+
+(defun autoload-read-section-header ()
+  "Read a section header form.
+Since continuation lines have been marked as comments,
+we must copy the text of the form and remove those comment
+markers before we call `read'."
+  (save-match-data
+    (let ((beginning (point))
+         string)
+      (forward-line 1)
+      (while (looking-at generate-autoload-section-continuation)
+       (forward-line 1))
+      (setq string (buffer-substring beginning (point)))
+      (with-current-buffer (get-buffer-create " *autoload*")
+       (erase-buffer)
+       (insert string)
+       (goto-char (point-min))
+       (while (search-forward generate-autoload-section-continuation nil t)
+         (replace-match " "))
+       (goto-char (point-min))
+       (read (current-buffer))))))
+
+(defvar autoload-print-form-outbuf nil
+  "Buffer which gets the output of `autoload-print-form'.")
+
+(defun autoload-print-form (form)
+  "Print FORM such that `make-docfile' will find the docstrings.
+The variable `autoload-print-form-outbuf' specifies the buffer to
+put the output in."
+  (cond
+   ;; If the form is a sequence, recurse.
+   ((eq (car form) 'progn) (mapcar #'autoload-print-form (cdr form)))
+   ;; Symbols at the toplevel are meaningless.
+   ((symbolp form) nil)
+   (t
+    (let ((doc-string-elt (function-get (car-safe form) 'doc-string-elt))
+         (outbuf autoload-print-form-outbuf))
+      (if (and (numberp doc-string-elt) (stringp (nth doc-string-elt form)))
+         ;; We need to hack the printing because the
+         ;; doc-string must be printed specially for
+         ;; make-docfile (sigh).
+         (let* ((p (nthcdr (1- doc-string-elt) form))
+                (elt (cdr p)))
+           (setcdr p nil)
+           (princ "\n(" outbuf)
+           (let ((print-escape-newlines t)
+                 (print-escape-control-characters t)
+                  (print-quoted t)
+                 (print-escape-nonascii t))
+             (dolist (elt form)
+               (prin1 elt outbuf)
+               (princ " " outbuf)))
+           (princ "\"\\\n" outbuf)
+           (let ((begin (with-current-buffer outbuf (point))))
+             (princ (substring (prin1-to-string (car elt)) 1)
+                    outbuf)
+             ;; Insert a backslash before each ( that
+             ;; appears at the beginning of a line in
+             ;; the doc string.
+             (with-current-buffer outbuf
+               (save-excursion
+                 (while (re-search-backward "\n[[(]" begin t)
+                   (forward-char 1)
+                   (insert "\\"))))
+             (if (null (cdr elt))
+                 (princ ")" outbuf)
+               (princ " " outbuf)
+               (princ (substring (prin1-to-string (cdr elt)) 1)
+                      outbuf))
+             (terpri outbuf)))
+       (let ((print-escape-newlines t)
+             (print-escape-control-characters t)
+              (print-quoted t)
+             (print-escape-nonascii t))
+         (print form outbuf)))))))
+
+(defalias 'autoload-rubric #'loaddefs-generate--rubric)
+
+(defvar autoload-ensure-writable nil
+  "Non-nil means `autoload-find-generated-file' makes existing file writable.")
+;; Just in case someone tries to get you to overwrite a file that you
+;; don't want to.
+;;;###autoload
+(put 'autoload-ensure-writable 'risky-local-variable t)
+
+(defun autoload-ensure-file-writeable (file)
+  ;; Probably pointless, but replaces the old AUTOGEN_VCS in lisp/Makefile,
+  ;; which was designed to handle CVSREAD=1 and equivalent.
+  (and autoload-ensure-writable
+       (let ((modes (file-modes file)))
+        (if (and modes (zerop (logand modes #o0200)))
+             ;; Ignore any errors here, and let subsequent attempts
+             ;; to write the file raise any real error.
+             (ignore-errors (set-file-modes file (logior modes #o0200))))))
+  file)
+
+(defun autoload-insert-section-header (outbuf autoloads load-name file time)
+  "Insert into buffer OUTBUF the section-header line for FILE.
+The header line lists the file name, its \"load name\", its autoloads,
+and the time the FILE was last updated (the time is inserted only
+if `autoload-timestamps' is non-nil, otherwise a fixed fake time is inserted)."
+  ;; (cl-assert ;Make sure we don't insert it in the middle of another section.
+  ;;  (save-excursion
+  ;;    (or (not (re-search-backward
+  ;;              (concat "\\("
+  ;;                      (regexp-quote generate-autoload-section-header)
+  ;;                      "\\)\\|\\("
+  ;;                      (regexp-quote generate-autoload-section-trailer)
+  ;;                      "\\)")
+  ;;              nil t))
+  ;;        (match-end 2))))
+  (insert generate-autoload-section-header)
+  (prin1 `(autoloads ,autoloads ,load-name ,file ,time)
+        outbuf)
+  (terpri outbuf)
+  ;; Break that line at spaces, to avoid very long lines.
+  ;; Make each sub-line into a comment.
+  (with-current-buffer outbuf
+    (save-excursion
+      (forward-line -1)
+      (while (not (eolp))
+       (move-to-column 64)
+       (skip-chars-forward "^ \n")
+       (or (eolp)
+           (insert "\n" generate-autoload-section-continuation))))))
+
+(defun autoload-find-file (file)
+  "Fetch FILE and put it in a temp buffer.  Return the buffer."
+  ;; It is faster to avoid visiting the file.
+  (setq file (expand-file-name file))
+  (with-current-buffer (get-buffer-create " *autoload-file*")
+    (kill-all-local-variables)
+    (erase-buffer)
+    (setq buffer-undo-list t
+          buffer-read-only nil)
+    (delay-mode-hooks (emacs-lisp-mode))
+    (setq default-directory (file-name-directory file))
+    (insert-file-contents file nil)
+    (let ((enable-local-variables :safe)
+         (enable-local-eval nil))
+      (hack-local-variables))
+    (current-buffer)))
+
+(defalias 'autoload-file-load-name #'loaddefs-generate--file-load-name)
+
+(defun generate-file-autoloads (file)
+  "Insert at point a loaddefs autoload section for FILE.
+Autoloads are generated for defuns and defmacros in FILE
+marked by `generate-autoload-cookie' (which see).
+If FILE is being visited in a buffer, the contents of the buffer
+are used.
+Return non-nil in the case where no autoloads were added at point."
+  (interactive "fGenerate autoloads for file: ")
+  (let ((autoload-modified-buffers nil))
+    (autoload-generate-file-autoloads file (current-buffer) buffer-file-name)
+    autoload-modified-buffers))
+
+(defconst autoload-def-prefixes-max-entries 5
+  "Target length of the list of definition prefixes per file.
+If set too small, the prefixes will be too generic (i.e. they'll use little
+memory, we'll end up looking in too many files when we need a particular
+prefix), and if set too large, they will be too specific (i.e. they will
+cost more memory use).")
+
+(defconst autoload-def-prefixes-max-length 12
+  "Target size of definition prefixes.
+Don't try to split prefixes that are already longer than that.")
+
+(defalias 'autoload--make-defs-autoload #'loaddefs-generate--make-prefixes)
+
+(defun autoload--setup-output (otherbuf outbuf absfile load-name output-file)
+  (let ((outbuf
+         (or (if otherbuf
+                 ;; A file-local setting of
+                 ;; autoload-generated-file says we
+                 ;; should ignore OUTBUF.
+                 nil
+               outbuf)
+             (autoload-find-destination absfile load-name output-file)
+             ;; The file has autoload cookies, but they're
+             ;; already up-to-date. If OUTFILE is nil, the
+             ;; entries are in the expected OUTBUF,
+             ;; otherwise they're elsewhere.
+             (throw 'done otherbuf))))
+    (with-current-buffer outbuf
+      (point-marker))))
+
+(defun autoload--print-cookie-text (output-start load-name file)
+  (let ((standard-output (marker-buffer output-start)))
+     (search-forward generate-autoload-cookie)
+     (skip-chars-forward " \t")
+     (if (eolp)
+         (condition-case-unless-debug err
+             ;; Read the next form and make an autoload.
+             (let* ((form (prog1 (read (current-buffer))
+                            (or (bolp) (forward-line 1))))
+                    (autoload (make-autoload form load-name)))
+               (if autoload
+                   nil
+                 (setq autoload form))
+               (let ((autoload-print-form-outbuf
+                      standard-output))
+                 (autoload-print-form autoload)))
+           (error
+            (message "Autoload cookie error in %s:%s %S"
+                     file (count-lines (point-min) (point)) err)))
+
+       ;; Copy the rest of the line to the output.
+       (princ (buffer-substring
+               (progn
+                 ;; Back up over whitespace, to preserve it.
+                 (skip-chars-backward " \f\t")
+                 (if (= (char-after (1+ (point))) ? )
+                     ;; Eat one space.
+                     (forward-char 1))
+                 (point))
+              (progn (forward-line 1) (point)))))))
+
+(defvar autoload-builtin-package-versions nil)
+
+(defun autoload-generate-file-autoloads (file &optional outbuf outfile)
+  "Insert an autoload section for FILE in the appropriate buffer.
+Autoloads are generated for defuns and defmacros in FILE
+marked by `generate-autoload-cookie' (which see).
+
+If FILE is being visited in a buffer, the contents of the buffer are used.
+OUTBUF is the buffer in which the autoload statements should be inserted.
+
+If OUTBUF is nil, the output will go to OUTFILE, unless there's a
+buffer-local setting of `generated-autoload-file' in FILE.
+
+Return non-nil if and only if FILE adds no autoloads to OUTFILE
+\(or OUTBUF if OUTFILE is nil).  The actual return value is
+FILE's modification time."
+  ;; Include the file name in any error messages
+  (condition-case err
+      (let (load-name
+            (print-length nil)
+            (print-level nil)
+            (float-output-format nil)
+            (visited (get-file-buffer file))
+            (otherbuf nil)
+            (absfile (expand-file-name file))
+          (defs '())
+            ;; nil until we found a cookie.
+            output-start)
+        (when
+            (catch 'done
+              (with-current-buffer (or visited
+                                       ;; It is faster to avoid visiting the 
file.
+                                       (autoload-find-file file))
+                ;; Obey the no-update-autoloads file local variable.
+                (unless no-update-autoloads
+                  (or noninteractive (message "Generating autoloads for %s..." 
file))
+                  (setq load-name
+                        (if (stringp generated-autoload-load-name)
+                            generated-autoload-load-name
+                          (autoload-file-load-name absfile outfile)))
+                  ;; FIXME? Comparing file-names for equality with just equal
+                  ;; is fragile, eg if one has an automounter prefix and one
+                  ;; does not, but both refer to the same physical file.
+                  (when (and outfile
+                             (not outbuf)
+                             (not
+                              (if (memq system-type '(ms-dos windows-nt))
+                                  (equal (downcase outfile)
+                                         (downcase (autoload-generated-file
+                                                    outfile)))
+                                (equal outfile (autoload-generated-file
+                                                outfile)))))
+                    (setq otherbuf t))
+                  (save-excursion
+                    (save-restriction
+                      (widen)
+                      (when autoload-builtin-package-versions
+                        (let ((version (lm-header "version"))
+                              package)
+                          (and version
+                               (setq version (ignore-errors (version-to-list 
version)))
+                               (setq package (or (lm-header "package")
+                                                 (file-name-sans-extension
+                                                  (file-name-nondirectory 
file))))
+                               (setq output-start (autoload--setup-output
+                                                   otherbuf outbuf absfile
+                                                   load-name outfile))
+                               (let ((standard-output (marker-buffer 
output-start))
+                                     (print-quoted t))
+                                 (princ `(push (purecopy
+                                                ',(cons (intern package) 
version))
+                                               package--builtin-versions))
+                                 (princ "\n")))))
+
+                      ;; Do not insert autoload entries for excluded files.
+                      (unless (member absfile autoload-excludes)
+                        (goto-char (point-min))
+                        (while (not (eobp))
+                          (skip-chars-forward " \t\n\f")
+                          (cond
+                           ((looking-at (regexp-quote 
generate-autoload-cookie))
+                            ;; If not done yet, figure out where to insert 
this text.
+                            (unless output-start
+                              (setq output-start (autoload--setup-output
+                                                  otherbuf outbuf absfile
+                                                  load-name outfile)))
+                            (autoload--print-cookie-text output-start 
load-name file))
+                           ((= (following-char) ?\;)
+                            ;; Don't read the comment.
+                            (forward-line 1))
+                           (t
+                  ;; Avoid (defvar <foo>) by requiring a trailing space.
+                  ;; Also, ignore this prefix business
+                  ;; for ;;;###tramp-autoload and friends.
+                  (when (and (equal generate-autoload-cookie ";;;###autoload")
+                             (looking-at "(\\(def[^ ]+\\) ['(]*\\([^' 
()\"\n]+\\)[\n \t]")
+                             (not (member
+                                   (match-string 1)
+                                   autoload-ignored-definitions)))
+                    (push (match-string-no-properties 2) defs))
+                            (forward-sexp 1)
+                            (forward-line 1)))))))
+
+          (when (and autoload-compute-prefixes defs)
+            ;; This output needs to always go in the main loaddefs.el,
+            ;; regardless of generated-autoload-file.
+            ;; FIXME: the files that don't have autoload cookies but
+            ;; do have definitions end up listed twice in loaddefs.el:
+            ;; once for their register-definition-prefixes and once in
+            ;; the list of "files without any autoloads".
+            (let ((form (autoload--make-defs-autoload defs load-name)))
+              (cond
+               ((null form))             ;All defs obey the default rule, yay!
+               ((not otherbuf)
+                (unless output-start
+                  (setq output-start (autoload--setup-output
+                                      nil outbuf absfile load-name outfile)))
+                (let ((autoload-print-form-outbuf
+                       (marker-buffer output-start)))
+                  (autoload-print-form form)))
+               (t
+                (let* ((other-output-start
+                        ;; To force the output to go to the main loaddefs.el
+                        ;; rather than to generated-autoload-file,
+                        ;; there are two cases: if outbuf is non-nil,
+                        ;; then passing otherbuf=nil is enough, but if
+                        ;; outbuf is nil, that won't cut it, so we
+                        ;; locally bind generated-autoload-file.
+                        (autoload--setup-output nil outbuf absfile load-name
+                                                outfile))
+                       (autoload-print-form-outbuf
+                        (marker-buffer other-output-start)))
+                  (autoload-print-form form)
+                  (with-current-buffer (marker-buffer other-output-start)
+                    (save-excursion
+                      ;; Insert the section-header line which lists
+                      ;; the file name and which functions are in it, etc.
+                      (goto-char other-output-start)
+                      (let ((relfile (file-relative-name absfile)))
+                        (autoload-insert-section-header
+                         (marker-buffer other-output-start)
+                         "actual autoloads are elsewhere" load-name relfile
+                        (if autoload-timestamps
+                            (file-attribute-modification-time
+                             (file-attributes absfile))
+                          autoload--non-timestamp))
+                        (insert ";;; Generated autoloads from " relfile "\n")))
+                    (insert generate-autoload-section-trailer)))))))
+
+                  (when output-start
+                    (let ((secondary-autoloads-file-buf
+                           (if otherbuf (current-buffer))))
+                      (with-current-buffer (marker-buffer output-start)
+                        (cl-assert (> (point) output-start))
+                        (save-excursion
+                          ;; Insert the section-header line which lists the 
file name
+                          ;; and which functions are in it, etc.
+                          (goto-char output-start)
+                          (let ((relfile (file-relative-name absfile)))
+                            (autoload-insert-section-header
+                             (marker-buffer output-start)
+                             () load-name relfile
+                             (if secondary-autoloads-file-buf
+                                 ;; MD5 checksums are much better because they 
do not
+                                 ;; change unless the file changes (so they'll 
be
+                                 ;; equal on two different systems and will 
change
+                                 ;; less often than time-stamps, thus leading 
to fewer
+                                 ;; unneeded changes causing spurious 
conflicts), but
+                                 ;; using time-stamps is a very useful 
optimization,
+                                 ;; so we use time-stamps for the main 
autoloads file
+                                 ;; (loaddefs.el) where we have special ways to
+                                 ;; circumvent the "random change problem", 
and MD5
+                                 ;; checksum in secondary autoload files where 
we do
+                                 ;; not need the time-stamp optimization 
because it is
+                                 ;; already provided by the primary autoloads 
file.
+                                 (md5 secondary-autoloads-file-buf
+                                      ;; We'd really want to just use
+                                      ;; `emacs-internal' instead.
+                                      nil nil 'emacs-mule-unix)
+                               (if autoload-timestamps
+                                   (file-attribute-modification-time
+                                   (file-attributes relfile))
+                                 autoload--non-timestamp)))
+                            (insert ";;; Generated autoloads from " relfile 
"\n")))
+                        (insert generate-autoload-section-trailer))))
+                  (or noninteractive
+                      (message "Generating autoloads for %s...done" file)))
+                (or visited
+                    ;; We created this buffer, so we should kill it.
+                    (kill-buffer (current-buffer))))
+              (or (not output-start)
+                  ;; If the entries were added to some other buffer, then the 
file
+                  ;; doesn't add entries to OUTFILE.
+                  otherbuf))
+          (file-attribute-modification-time (file-attributes absfile))))
+    (error
+     ;; Probably unbalanced parens in forward-sexp. In that case, the
+     ;; condition is scan-error, and the signal data includes point
+     ;; where the error was found; we'd like to convert that to
+     ;; line:col, but line-number-at-pos gets the wrong line in batch
+     ;; mode for some reason.
+     ;;
+     ;; At least this gets the file name in the error message; the
+     ;; developer can use goto-char to get to the error position.
+     (error "%s:0:0: error: %s: %s" file (car err) (cdr err)))
+    ))
+
+;; For parallel builds, to stop another process reading a half-written file.
+(defun autoload--save-buffer ()
+  "Save current buffer to its file, atomically."
+  ;; Similar to byte-compile-file.
+  (let* ((version-control 'never)
+         (tempfile (make-temp-file buffer-file-name))
+        (default-modes (default-file-modes))
+        (temp-modes (logand default-modes #o600))
+        (desired-modes (logand default-modes
+                               (or (file-modes buffer-file-name) #o666)))
+         (kill-emacs-hook
+          (cons (lambda () (ignore-errors (delete-file tempfile)))
+                kill-emacs-hook)))
+    (unless (= temp-modes desired-modes)
+      (set-file-modes tempfile desired-modes 'nofollow))
+    (write-region (point-min) (point-max) tempfile nil 1)
+    (backup-buffer)
+    (rename-file tempfile buffer-file-name t))
+  (set-buffer-modified-p nil)
+  (set-visited-file-modtime)
+  (or noninteractive (message "Wrote %s" buffer-file-name)))
+
+(defun autoload-save-buffers ()
+  (while autoload-modified-buffers
+    (with-current-buffer (pop autoload-modified-buffers)
+      (autoload--save-buffer))))
+
+;; FIXME This command should be deprecated.
+;; See https://debbugs.gnu.org/22213#41
+;;;###autoload
+(defun update-file-autoloads (file &optional save-after outfile)
+  "Update the autoloads for FILE.
+If prefix arg SAVE-AFTER is non-nil, save the buffer too.
+
+If FILE binds `generated-autoload-file' as a file-local variable,
+autoloads are written into that file.  Otherwise, the autoloads
+file is determined by OUTFILE.  If called interactively, prompt
+for OUTFILE; if called from Lisp with OUTFILE nil, use the
+existing value of `generated-autoload-file'.
+
+Return FILE if there was no autoload cookie in it, else nil."
+  (interactive (list (read-file-name "Update autoloads for file: ")
+                    current-prefix-arg
+                    (read-file-name "Write autoload definitions to file: ")))
+  (setq outfile (or outfile generated-autoload-file))
+  (let* ((autoload-modified-buffers nil)
+        ;; We need this only if the output file handles more than one input.
+        ;; See https://debbugs.gnu.org/22213#38 and subsequent.
+        (autoload-timestamps t)
+         (no-autoloads (autoload-generate-file-autoloads
+                        file nil
+                        (if (local-variable-p 'generated-autoload-file)
+                            generated-autoload-file
+                          outfile))))
+    (if autoload-modified-buffers
+        (if save-after (autoload-save-buffers))
+      (if (called-interactively-p 'interactive)
+          (message "Autoload section for %s is up to date." file)))
+    (if no-autoloads file)))
+
+(defun autoload-find-destination (file load-name output-file)
+  "Find the destination point of the current buffer's autoloads.
+FILE is the file name of the current buffer.
+LOAD-NAME is the name as it appears in the output.
+Returns a buffer whose point is placed at the requested location.
+Returns nil if the file's autoloads are up-to-date, otherwise
+removes any prior now out-of-date autoload entries."
+  (catch 'up-to-date
+    (let* ((buf (current-buffer))
+           (existing-buffer (if buffer-file-name buf))
+           (output-file (autoload-generated-file output-file))
+           (output-time (if (file-exists-p output-file)
+                            (file-attribute-modification-time
+                            (file-attributes output-file))))
+           (found nil))
+      (with-current-buffer (autoload-find-generated-file output-file)
+        ;; This is to make generated-autoload-file have Unix EOLs, so
+        ;; that it is portable to all platforms.
+        (or (eq 0 (coding-system-eol-type buffer-file-coding-system))
+           (set-buffer-file-coding-system 'unix))
+        (or (> (buffer-size) 0)
+            (error "Autoloads file %s lacks boilerplate" buffer-file-name))
+        (or (file-writable-p buffer-file-name)
+            (error "Autoloads file %s is not writable" buffer-file-name))
+        (widen)
+        (goto-char (point-min))
+        ;; Look for the section for LOAD-NAME.
+        (while (and (not found)
+                    (search-forward generate-autoload-section-header nil t))
+          (let ((form (autoload-read-section-header)))
+            (cond ((string= (nth 2 form) load-name)
+                   ;; We found the section for this file.
+                   ;; Check if it is up to date.
+                   (let ((begin (match-beginning 0))
+                         (last-time (nth 4 form))
+                         (file-time (file-attribute-modification-time
+                                    (file-attributes file))))
+                     (if (and (or (null existing-buffer)
+                                  (not (buffer-modified-p existing-buffer)))
+                              (cond
+                               ;; FIXME? Arguably we should throw a
+                               ;; user error, or some kind of warning,
+                               ;; if we were called from update-file-autoloads,
+                               ;; which can update only a single input file.
+                               ;; It's not appropriate to use the output
+                               ;; file modtime in such a case,
+                               ;; if there are multiple input files
+                               ;; contributing to the output.
+                               ((and output-time
+                                    (member last-time
+                                            (list t autoload--non-timestamp)))
+                                (not (time-less-p output-time file-time)))
+                               ;; last-time is the time-stamp (specifying
+                               ;; the last time we looked at the file) and
+                               ;; the file hasn't been changed since.
+                               ((listp last-time)
+                                (not (time-less-p last-time file-time)))
+                               ;; last-time is an MD5 checksum instead.
+                               ((stringp last-time)
+                                (equal last-time
+                                      (md5 buf nil nil 'emacs-mule)))))
+                         (throw 'up-to-date nil)
+                       (autoload-remove-section begin)
+                       (setq found t))))
+                  ((string< load-name (nth 2 form))
+                   ;; We've come to a section alphabetically later than
+                   ;; LOAD-NAME.  We assume the file is in order and so
+                   ;; there must be no section for LOAD-NAME.  We will
+                   ;; insert one before the section here.
+                   (goto-char (match-beginning 0))
+                   (setq found t)))))
+        (or found
+            (progn
+              ;; No later sections in the file.  Put before the last page.
+              (goto-char (point-max))
+              (search-backward "\f" nil t)))
+        (unless (memq (current-buffer) autoload-modified-buffers)
+          (push (current-buffer) autoload-modified-buffers))
+        (current-buffer)))))
+
+(defun autoload-remove-section (begin)
+  (goto-char begin)
+  (search-forward generate-autoload-section-trailer)
+  (delete-region begin (point)))
+
+;;;###autoload
+(defun update-directory-autoloads (&rest dirs)
+  "Update autoload definitions for Lisp files in the directories DIRS.
+In an interactive call, you must give one argument, the name of a
+single directory.  In a call from Lisp, you can supply multiple
+directories as separate arguments, but this usage is discouraged.
+
+The function does NOT recursively descend into subdirectories of the
+directory or directories specified.
+
+In an interactive call, prompt for a default output file for the
+autoload definitions.  When called from Lisp, use the existing
+value of `generated-autoload-file'.  If any Lisp file binds
+`generated-autoload-file' as a file-local variable, write its
+autoloads into the specified file instead."
+  (declare (obsolete loaddefs-generate "29.1"))
+  (interactive "DUpdate autoloads from directory: ")
+  (make-directory-autoloads
+   dirs
+   (if (called-interactively-p 'interactive)
+       (read-file-name "Write autoload definitions to file: ")
+     generated-autoload-file)))
+
+;;;###autoload
+(defun make-directory-autoloads (dir output-file)
+  "Update autoload definitions for Lisp files in the directories DIRS.
+DIR can be either a single directory or a list of
+directories.  (The latter usage is discouraged.)
+
+The autoloads will be written to OUTPUT-FILE.  If any Lisp file
+binds `generated-autoload-file' as a file-local variable, write
+its autoloads into the specified file instead.
+
+The function does NOT recursively descend into subdirectories of the
+directory or directories specified."
+  (declare (obsolete loaddefs-generate "29.1"))
+  (interactive "DUpdate autoloads from directory: \nFWrite to file: ")
+  (let* ((files-re (let ((tmp nil))
+                    (dolist (suf (get-load-suffixes))
+                       ;; We don't use module-file-suffix below because
+                       ;; we don't want to depend on whether Emacs was
+                       ;; built with or without modules support, nor
+                       ;; what is the suffix for the underlying OS.
+                      (unless (string-match "\\.\\(elc\\|so\\|dll\\)" suf)
+                         (push suf tmp)))
+                     (concat "\\`[^=.].*" (regexp-opt tmp t) "\\'")))
+        (files (apply #'nconc
+                      (mapcar (lambda (d)
+                                (directory-files (expand-file-name d)
+                                                  t files-re))
+                              (if (consp dir) dir (list dir)))))
+         (done ())                      ;Files processed; to remove duplicates.
+         (changed nil)                  ;Non-nil if some change occurred.
+        (last-time)
+         ;; Files with no autoload cookies or whose autoloads go to other
+         ;; files because of file-local autoload-generated-file settings.
+        (no-autoloads nil)
+         ;; Ensure that we don't do odd things when putting the doc
+         ;; strings into the autoloads file.
+         (left-margin 0)
+         (autoload-modified-buffers nil)
+        (output-time
+         (and (file-exists-p output-file)
+              (file-attribute-modification-time
+                (file-attributes output-file)))))
+
+    (with-current-buffer (autoload-find-generated-file output-file)
+      (save-excursion
+       ;; Canonicalize file names and remove the autoload file itself.
+       (setq files (delete (file-relative-name buffer-file-name)
+                           (mapcar #'file-relative-name files)))
+
+       (goto-char (point-min))
+       (while (search-forward generate-autoload-section-header nil t)
+         (let* ((form (autoload-read-section-header))
+                (file (nth 3 form)))
+           (cond ((and (consp file) (stringp (car file)))
+                  ;; This is a list of files that have no autoload cookies.
+                  ;; There shouldn't be more than one such entry.
+                  ;; Remove the obsolete section.
+                  (autoload-remove-section (match-beginning 0))
+                  (setq last-time (nth 4 form))
+                  (if (member last-time (list t autoload--non-timestamp))
+                      (setq last-time output-time))
+                  (dolist (file file)
+                    (let ((file-time (file-attribute-modification-time
+                                      (file-attributes file))))
+                      (when (and file-time
+                                 (not (time-less-p last-time file-time)))
+                        ;; file unchanged
+                        (push file no-autoloads)
+                        (setq files (delete file files))))))
+                 ((not (stringp file)))
+                 ((or (not (file-exists-p file))
+                       ;; Remove duplicates as well, just in case.
+                       (member file done))
+                   ;; Remove the obsolete section.
+                   (setq changed t)
+                  (autoload-remove-section (match-beginning 0)))
+                 ((not (time-less-p (let ((oldtime (nth 4 form)))
+                                      (if (member oldtime
+                                                  (list
+                                                   t autoload--non-timestamp))
+                                          output-time
+                                        oldtime))
+                                     (file-attribute-modification-time
+                                     (file-attributes file))))
+                  ;; File hasn't changed.
+                  nil)
+                 (t
+                   (setq changed t)
+                   (autoload-remove-section (match-beginning 0))
+                   (if (autoload-generate-file-autoloads
+                        ;; Passing `current-buffer' makes it insert at point.
+                        file (current-buffer) buffer-file-name)
+                       (push file no-autoloads))))
+            (push file done)
+           (setq files (delete file files)))))
+      ;; Elements remaining in FILES have no existing autoload sections yet.
+      (let ((no-autoloads-time (or last-time '(0 0 0 0)))
+            (progress (make-progress-reporter
+                       (byte-compile-info
+                        (concat "Scraping files for "
+                                (file-relative-name output-file)))
+                       0 (length files) nil 10))
+            (file-count 0)
+            file-time)
+       (dolist (file files)
+          (progress-reporter-update progress (setq file-count (1+ file-count)))
+         (cond
+          ;; Passing nil as second argument forces
+          ;; autoload-generate-file-autoloads to look for the right
+          ;; spot where to insert each autoloads section.
+          ((setq file-time
+                 (autoload-generate-file-autoloads file nil buffer-file-name))
+           (push file no-autoloads)
+           (if (time-less-p no-autoloads-time file-time)
+               (setq no-autoloads-time file-time)))
+           (t (setq changed t))))
+        (progress-reporter-done progress)
+
+       (when no-autoloads
+         ;; Sort them for better readability.
+         (setq no-autoloads (sort no-autoloads 'string<))
+         ;; Add the `no-autoloads' section.
+         (goto-char (point-max))
+         (search-backward "\f" nil t)
+         (autoload-insert-section-header
+          (current-buffer) nil nil
+           ;; Filter out the other loaddefs files, because it makes
+           ;; the list unstable (and leads to spurious changes in
+           ;; ldefs-boot.el) since the loaddef files can be created in
+           ;; any order.
+           (seq-filter (lambda (file)
+                         (not (string-match-p "[/-]loaddefs.el" file)))
+                       no-autoloads)
+           (if autoload-timestamps
+              no-autoloads-time
+            autoload--non-timestamp))
+         (insert generate-autoload-section-trailer)))
+
+      ;; Don't modify the file if its content has not been changed, so `make'
+      ;; dependencies don't trigger unnecessarily.
+      (if (not changed)
+          (set-buffer-modified-p nil)
+        (autoload--save-buffer))
+
+      ;; In case autoload entries were added to other files because of
+      ;; file-local autoload-generated-file settings.
+      (autoload-save-buffers))))
+
+(defun batch-update-autoloads--summary (strings)
+  (let ((message ""))
+    (while strings
+      (when (> (length (concat message " " (car strings))) 64)
+        (byte-compile-info (concat message " ...") t "SCRAPE")
+        (setq message ""))
+      (setq message (if (zerop (length message))
+                        (car strings)
+                      (concat message " " (car strings))))
+      (setq strings (cdr strings)))
+    (when (> (length message) 0)
+      (byte-compile-info message t "SCRAPE"))))
+
+;;;###autoload
+(defun batch-update-autoloads ()
+  "Update loaddefs.el autoloads in batch mode.
+Calls `update-directory-autoloads' on the command line arguments.
+Definitions are written to `generated-autoload-file' (which
+should be non-nil)."
+  ;; For use during the Emacs build process only.
+  ;; Exclude those files that are preloaded on ALL platforms.
+  ;; These are the ones in loadup.el where "(load" is at the start
+  ;; of the line (crude, but it works).
+  (unless autoload-excludes
+    (let ((default-directory (file-name-directory generated-autoload-file))
+         file)
+      (when (file-readable-p "loadup.el")
+       (with-temp-buffer
+         (insert-file-contents "loadup.el")
+         (while (re-search-forward "^(load \"\\([^\"]+\\)\"" nil t)
+           (setq file (match-string 1))
+           (or (string-match "\\.el\\'" file)
+               (setq file (format "%s.el" file)))
+           (or (string-match "\\`site-" file)
+               (push (expand-file-name file) autoload-excludes)))))))
+  (let ((args command-line-args-left))
+    (batch-update-autoloads--summary args)
+    (setq command-line-args-left nil)
+    (with-suppressed-warnings ((obsolete make-directory-autoloads))
+      (make-directory-autoloads args generated-autoload-file))))
+
+(provide 'autoload)
+
+;;; autoload.el ends here
diff --git a/lisp/obsolete/complete.el b/lisp/obsolete/complete.el
deleted file mode 100644
index 1b4c39b159..0000000000
--- a/lisp/obsolete/complete.el
+++ /dev/null
@@ -1,1122 +0,0 @@
-;;; complete.el --- partial completion mechanism plus other goodies  -*- 
lexical-binding: t; -*-
-
-;; Copyright (C) 1990-1993, 1999-2022 Free Software Foundation, Inc.
-
-;; Author: Dave Gillespie <daveg@synaptics.com>
-;; Keywords: abbrev convenience
-;; Obsolete-since: 24.1
-;;
-;; Special thanks to Hallvard Furuseth for his many ideas and contributions.
-
-;; 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:
-
-;; Extended completion for the Emacs minibuffer.
-;;
-;; The basic idea is that the command name or other completable text is
-;; divided into words and each word is completed separately, so that
-;; "M-x p-b" expands to "M-x print-buffer".  If the entry is ambiguous
-;; each word is completed as much as possible and then the cursor is
-;; left at the first position where typing another letter will resolve
-;; the ambiguity.
-;;
-;; Word separators for this purpose are hyphen, space, and period.
-;; These would most likely occur in command names, Info menu items,
-;; and file names, respectively.  But all word separators are treated
-;; alike at all times.
-;;
-;; This completion package replaces the old-style completer's key
-;; bindings for TAB, SPC, RET, and `?'.  The old completer is still
-;; available on the Meta versions of those keys.  If you set
-;; PC-meta-flag to nil, the old completion keys will be left alone
-;; and the partial completer will use the Meta versions of the keys.
-
-
-;; Usage:  M-x partial-completion-mode.  During completable minibuffer entry,
-;;
-;;     TAB    means to do a partial completion;
-;;     SPC    means to do a partial complete-word;
-;;     RET    means to do a partial complete-and-exit;
-;;     ?      means to do a partial completion-help.
-;;
-;; If you set PC-meta-flag to nil, then TAB, SPC, RET, and ? perform
-;; original Emacs completions, and M-TAB etc. do partial completion.
-;; To do this, put the command,
-;;
-;;       (setq PC-meta-flag nil)
-;;
-;; in your .emacs file.  To load partial completion automatically, put
-;;
-;;       (partial-completion-mode t)
-;;
-;; in your .emacs file, too.  Things will be faster if you byte-compile
-;; this file when you install it.
-;;
-;; As an extra feature, in cases where RET would not normally
-;; complete (such as `C-x b'), the M-RET key will always do a partial
-;; complete-and-exit.  Thus `C-x b f.c RET' will select or create a
-;; buffer called "f.c", but `C-x b f.c M-RET' will select the existing
-;; buffer whose name matches that pattern (perhaps "filing.c").
-;; (PC-meta-flag does not affect this behavior; M-RET used to be
-;; undefined in this situation.)
-;;
-;; The regular M-TAB (lisp-complete-symbol) command also supports
-;; partial completion in this package.
-
-;; In addition, this package includes a feature for accessing include
-;; files.  For example, `C-x C-f <sys/time.h> RET' reads the file
-;; /usr/include/sys/time.h.  The variable PC-include-file-path is a
-;; list of directories in which to search for include files.  Completion
-;; is supported in include file names.
-
-
-;;; Code:
-
-(defgroup partial-completion nil
-  "Partial Completion of items."
-  :prefix "pc-"
-  :group 'minibuffer
-  :group 'convenience)
-
-(defcustom PC-first-char 'find-file
-  "Control how the first character of a string is to be interpreted.
-If nil, the first character of a string is not taken literally if it is a word
-delimiter, so that \".e\" matches \"*.e*\".
-If t, the first character of a string is always taken literally even if it is a
-word delimiter, so that \".e\" matches \".e*\".
-If non-nil and non-t, the first character is taken literally only for file name
-completion."
-  :type '(choice (const :tag "delimiter" nil)
-                (const :tag "literal" t)
-                (other :tag "find-file" find-file)))
-
-(defcustom PC-meta-flag t
-  "If non-nil, TAB means PC completion and M-TAB means normal completion.
-Otherwise, TAB means normal completion and M-TAB means Partial Completion."
-  :type 'boolean)
-
-(defcustom PC-word-delimiters "-_. "
-  "A string of characters treated as word delimiters for completion.
-Some arcane rules:
-If `]' is in this string, it must come first.
-If `^' is in this string, it must not come first.
-If `-' is in this string, it must come first or right after `]'.
-In other words, if S is this string, then `[S]' must be a valid Emacs regular
-expression (not containing character ranges like `a-z')."
-  :type 'string)
-
-(defcustom PC-include-file-path '("/usr/include" "/usr/local/include")
-  "A list of directories in which to look for include files.
-If nil, means use the colon-separated path in the variable $INCPATH instead."
-  :type '(repeat directory))
-
-(defcustom PC-disable-includes nil
-  "If non-nil, include-file support in \\[find-file] is disabled."
-  :type 'boolean)
-
-(defvar PC-default-bindings t
-  "If non-nil, default partial completion key bindings are suppressed.")
-
-(defvar PC-env-vars-alist nil
-  "A list of the environment variable names and values.")
-
-
-(defun PC-bindings (bind)
-  (let ((completion-map minibuffer-local-completion-map)
-       (must-match-map minibuffer-local-must-match-map))
-    (cond ((not bind)
-          ;; These bindings are the default bindings.  It would be better to
-          ;; restore the previous bindings.
-          (define-key read-expression-map "\e\t" #'completion-at-point)
-
-          (define-key completion-map "\t"      #'minibuffer-complete)
-          (define-key completion-map " "       #'minibuffer-complete-word)
-          (define-key completion-map "?"       #'minibuffer-completion-help)
-
-          (define-key must-match-map "\r"      #'minibuffer-complete-and-exit)
-          (define-key must-match-map "\n"      #'minibuffer-complete-and-exit)
-
-          (define-key global-map [remap lisp-complete-symbol]  nil))
-         (PC-default-bindings
-          (define-key read-expression-map "\e\t" #'PC-lisp-complete-symbol)
-
-          (define-key completion-map "\t"      #'PC-complete)
-          (define-key completion-map " "       #'PC-complete-word)
-          (define-key completion-map "?"       #'PC-completion-help)
-
-          (define-key completion-map "\e\t"    #'PC-complete)
-          (define-key completion-map "\e "     #'PC-complete-word)
-          (define-key completion-map "\e\r"    #'PC-force-complete-and-exit)
-          (define-key completion-map "\e\n"    #'PC-force-complete-and-exit)
-          (define-key completion-map "\e?"     #'PC-completion-help)
-
-          (define-key must-match-map "\r"      #'PC-complete-and-exit)
-          (define-key must-match-map "\n"      #'PC-complete-and-exit)
-
-          (define-key must-match-map "\e\r"    #'PC-complete-and-exit)
-          (define-key must-match-map "\e\n"    #'PC-complete-and-exit)
-
-          (define-key global-map [remap lisp-complete-symbol]  
#'PC-lisp-complete-symbol)))))
-
-(defvar PC-do-completion-end nil
-  "Internal variable used by `PC-do-completion'.")
-
-(make-variable-buffer-local 'PC-do-completion-end)
-
-(defvar PC-goto-end nil
-   "Internal variable set in `PC-do-completion', used in
-`choose-completion-string-functions'.")
-
-(make-variable-buffer-local 'PC-goto-end)
-
-;;;###autoload
-(define-minor-mode partial-completion-mode
-  "Toggle Partial Completion mode.
-
-When Partial Completion mode is enabled, TAB (or M-TAB if `PC-meta-flag' is
-nil) is enhanced so that if some string is divided into words and each word is
-delimited by a character in `PC-word-delimiters', partial words are completed
-as much as possible and `*' characters are treated likewise in file names.
-
-For example, M-x p-c-m expands to M-x partial-completion-mode since no other
-command begins with that sequence of characters, and
-\\[find-file] f_b.c TAB might complete to foo_bar.c if that file existed and no
-other file in that directory begins with that sequence of characters.
-
-Unless `PC-disable-includes' is non-nil, the `<...>' sequence is interpreted
-specially in \\[find-file].  For example,
-\\[find-file] <sys/time.h> RET finds the file `/usr/include/sys/time.h'.
-See also the variable `PC-include-file-path'.
-
-Partial Completion mode extends the meaning of `completion-auto-help' (which
-see), so that if it is neither nil nor t, Emacs shows the `*Completions*'
-buffer only on the second attempt to complete.  That is, if TAB finds nothing
-to complete, the first TAB just says \"Next char not unique\" and the
-second TAB brings up the `*Completions*' buffer."
-  :global t
-  ;; Deal with key bindings...
-  (PC-bindings partial-completion-mode)
-  ;; Deal with include file feature...
-  (cond ((not partial-completion-mode)
-        (remove-hook 'find-file-not-found-functions
-                     #'PC-look-for-include-file))
-       ((not PC-disable-includes)
-        (add-hook 'find-file-not-found-functions #'PC-look-for-include-file)))
-  ;; Adjust the completion selection in *Completion* buffers to the way
-  ;; we work.  The default minibuffer completion code only completes the
-  ;; text before point and leaves the text after point alone (new in
-  ;; Emacs-22).  In contrast we use the whole text and we even sometimes
-  ;; move point to a place before EOB, to indicate the first position where
-  ;; there's a difference, so when the user uses choose-completion, we have
-  ;; to trick choose-completion into replacing the whole minibuffer text
-  ;; rather than only the text before point.  --Stef
-  (funcall
-   (if partial-completion-mode #'add-hook #'remove-hook)
-   'choose-completion-string-functions
-   (lambda (_choice buffer &rest _)
-     ;; When completing M-: (lisp- ) with point before the ), it is
-     ;; not appropriate to go to point-max (unlike the filename case).
-     (if (and (not PC-goto-end)
-              (minibufferp buffer))
-         (goto-char (point-max))
-       ;; Need a similar hack for the non-minibuffer-case -- gm.
-       (when PC-do-completion-end
-         (goto-char PC-do-completion-end)
-         (setq PC-do-completion-end nil)))
-     (setq PC-goto-end nil)
-     nil))
-  ;; Build the env-completion and mapping table.
-  (when (and partial-completion-mode (null PC-env-vars-alist))
-    (setq PC-env-vars-alist
-          (mapcar (lambda (string)
-                    (let ((d (string-search "=" string)))
-                      (cons (concat "$" (substring string 0 d))
-                            (and d (substring string (1+ d))))))
-                  process-environment))))
-
-
-(defun PC-complete ()
-  "Like minibuffer-complete, but allows \"b--di\"-style abbreviations.
-For example, \"M-x b--di\" would match `byte-recompile-directory', or any
-name which consists of three or more words, the first beginning with \"b\"
-and the third beginning with \"di\".
-
-The pattern \"b--d\" is ambiguous for `byte-recompile-directory' and
-`beginning-of-defun', so this would produce a list of completions
-just like when normal Emacs completions are ambiguous.
-
-Word-delimiters for the purposes of Partial Completion are \"-\", \"_\",
-\".\", and SPC."
-  (interactive)
-  (if (PC-was-meta-key)
-      (minibuffer-complete)
-    ;; If the previous command was not this one,
-    ;; never scroll, always retry completion.
-    (or (eq last-command this-command)
-       (setq minibuffer-scroll-window nil))
-    (let ((window minibuffer-scroll-window))
-      ;; If there's a fresh completion window with a live buffer,
-      ;; and this command is repeated, scroll that window.
-      (if (and window (window-buffer window)
-              (buffer-name (window-buffer window)))
-         (with-current-buffer (window-buffer window)
-           (if (pos-visible-in-window-p (point-max) window)
-               (set-window-start window (point-min) nil)
-             (scroll-other-window)))
-       (PC-do-completion nil)))))
-
-
-(defun PC-complete-word ()
-  "Like `minibuffer-complete-word', but allows \"b--di\"-style abbreviations.
-See `PC-complete' for details.
-This can be bound to other keys, like `-' and `.', if you wish."
-  (interactive)
-  (if (eq (PC-was-meta-key) PC-meta-flag)
-      (if (eq last-command-event ? )
-         (minibuffer-complete-word)
-       (self-insert-command 1))
-    (self-insert-command 1)
-    (if (eobp)
-       (PC-do-completion 'word))))
-
-
-(defun PC-complete-space ()
-  "Like `minibuffer-complete-word', but allows \"b--di\"-style abbreviations.
-See `PC-complete' for details.
-This is suitable for binding to other keys which should act just like SPC."
-  (interactive)
-  (if (eq (PC-was-meta-key) PC-meta-flag)
-      (minibuffer-complete-word)
-    (insert " ")
-    (if (eobp)
-       (PC-do-completion 'word))))
-
-
-(defun PC-complete-and-exit ()
-  "Like `minibuffer-complete-and-exit', but allows \"b--di\"-style 
abbreviations.
-See `PC-complete' for details."
-  (interactive)
-  (if (eq (PC-was-meta-key) PC-meta-flag)
-      (minibuffer-complete-and-exit)
-    (PC-do-complete-and-exit)))
-
-(defun PC-force-complete-and-exit ()
-  "Like `minibuffer-complete-and-exit', but allows \"b--di\"-style 
abbreviations.
-See `PC-complete' for details."
-  (interactive)
-  (let ((minibuffer-completion-confirm nil))
-    (PC-do-complete-and-exit)))
-
-(defun PC-do-complete-and-exit ()
-  (cond
-   ((= (point-max) (minibuffer-prompt-end))
-    ;; Duplicate the "bug" that Info-menu relies on...
-    (exit-minibuffer))
-   ((eq minibuffer-completion-confirm 'confirm)
-    (if (or (eq last-command this-command)
-            (test-completion (field-string)
-                             minibuffer-completion-table
-                             minibuffer-completion-predicate))
-        (exit-minibuffer)
-      (PC-temp-minibuffer-message " [Confirm]")))
-   ((eq minibuffer-completion-confirm 'confirm-after-completion)
-    ;; Similar to the above, but only if trying to exit immediately
-    ;; after typing TAB (this catches most minibuffer typos).
-    (if (and (memq last-command minibuffer-confirm-exit-commands)
-            (not (test-completion (field-string)
-                                  minibuffer-completion-table
-                                  minibuffer-completion-predicate)))
-       (PC-temp-minibuffer-message " [Confirm]")
-      (exit-minibuffer)))
-   (t
-    (let ((flag (PC-do-completion 'exit)))
-      (and flag
-          (if (or (eq flag 'complete)
-                  (not minibuffer-completion-confirm))
-              (exit-minibuffer)
-            (PC-temp-minibuffer-message " [Confirm]")))))))
-
-
-(defun PC-completion-help ()
-  "Like `minibuffer-completion-help', but allows \"b--di\"-style abbreviations.
-See `PC-complete' for details."
-  (interactive)
-  (if (eq (PC-was-meta-key) PC-meta-flag)
-      (minibuffer-completion-help)
-    (PC-do-completion 'help)))
-
-(defun PC-was-meta-key ()
-  (or (/= (length (this-command-keys)) 1)
-      (let ((key (aref (this-command-keys) 0)))
-       (if (integerp key)
-           (>= key 128)
-         (not (null (memq 'meta (event-modifiers key))))))))
-
-
-(defvar PC-ignored-extensions 'empty-cache)
-(defvar PC-delims 'empty-cache)
-(defvar PC-ignored-regexp nil)
-(defvar PC-word-failed-flag nil)
-(defvar PC-delim-regex nil)
-(defvar PC-ndelims-regex nil)
-(defvar PC-delims-list nil)
-
-(defvar PC-completion-as-file-name-predicate
-  (lambda () minibuffer-completing-file-name)
-  "A function testing whether a minibuffer completion now will work 
filename-style.
-The function takes no arguments, and typically looks at the value
-of `minibuffer-completion-table' and the minibuffer contents.")
-
-;; Returns the sequence of non-delimiter characters that follow regexp in 
string.
-(defun PC-chunk-after (string regexp)
-  (if (not (string-match regexp string))
-      (let ((message "String %s didn't match regexp %s"))
-       (message message string regexp)
-       (error message string regexp)))
-  (let ((result (substring string (match-end 0))))
-    ;; result may contain multiple chunks
-    (if (string-match PC-delim-regex result)
-       (setq result (substring result 0 (match-beginning 0))))
-    result))
-
-(defun test-completion-ignore-case (str table pred)
-  "Like `test-completion', but ignores case when possible."
-  ;; Binding completion-ignore-case to nil ensures, for compatibility with
-  ;; standard completion, that the return value is exactly one of the
-  ;; possibilities.  Do this binding only if pred is nil, out of paranoia;
-  ;; perhaps it is safe even if pred is non-nil.
-  (if pred
-      (test-completion str table pred)
-    (let ((completion-ignore-case nil))
-      (test-completion str table pred))))
-
-;; The following function is an attempt to work around two problems:
-
-;; (1) When complete.el was written, (try-completion "" '(("") (""))) used to
-;; return the value "".  With a change from 2002-07-07 it returns t which 
caused
-;; `PC-lisp-complete-symbol' to fail with a "Wrong type argument: sequencep, t"
-;; error.  `PC-try-completion' returns STRING in this case.
-
-;; (2) (try-completion "" '((""))) returned t before the above-mentioned 
change.
-;; Since `PC-chop-word' operates on the return value of `try-completion' this
-;; case might have provoked a similar error as in (1).  `PC-try-completion'
-;; returns "" instead.  I don't know whether this is a real problem though.
-
-;; Since `PC-try-completion' is not a guaranteed to fix these bugs reliably, 
you
-;; should try to look at the following discussions when you encounter problems:
-;; - emacs-pretest-bug ("Partial Completion" starting 2007-02-23),
-;; - emacs-devel ("[address-of-OP: Partial completion]" starting 2007-02-24),
-;; - emacs-devel ("[address-of-OP: EVAL and mouse selection in *Completions*]"
-;;   starting 2007-03-05).
-(defun PC-try-completion (string alist &optional predicate)
-  "Like `try-completion' but return STRING instead of t."
-  (let ((result (try-completion string alist predicate)))
-    (if (eq result t) string result)))
-
-(defvar completion-base-size)
-
-;; TODO document MODE magic...
-(defun PC-do-completion (&optional mode beg end goto-end)
-  "Internal function to do the work of partial completion.
-Text to be completed lies between BEG and END.  Normally when
-replacing text in the minibuffer, this function replaces up to
-point-max (as is appropriate for completing a file name).  If
-GOTO-END is non-nil, however, it instead replaces up to END."
-  (or beg (setq beg (minibuffer-prompt-end)))
-  (or end (setq end (point-max)))
-  (let* ((table (if (eq minibuffer-completion-table 'read-file-name-internal)
-                    'PC-read-file-name-internal
-                    minibuffer-completion-table))
-        (pred minibuffer-completion-predicate)
-        (filename (funcall PC-completion-as-file-name-predicate))
-        (dirname nil) ; non-nil only if a filename is being completed
-        ;; The following used to be "(dirlength 0)" which caused the erasure of
-        ;; the entire buffer text before `point' when inserting a completion
-        ;; into a buffer.
-        dirlength
-        (str (buffer-substring beg end))
-        (incname (and filename (string-match "<\\([^\"<>]*\\)>?$" str)))
-        (ambig nil)
-        basestr origstr
-        env-on
-        regex
-        p offset
-         abbreviated
-        (poss nil)
-        helpposs
-        (case-fold-search completion-ignore-case))
-
-    ;; Check if buffer contents can already be considered complete
-    (if (and (eq mode 'exit)
-            (test-completion str table pred))
-       'complete
-
-      ;; Do substitutions in directory names
-      (and filename
-           (setq basestr (or (file-name-directory str) ""))
-           (setq dirlength (length basestr))
-          ;; Do substitutions in directory names
-           (setq p (substitute-in-file-name basestr))
-           (not (string-equal basestr p))
-           (setq str (concat p (file-name-nondirectory str)))
-           (progn
-            (delete-region beg end)
-            (insert str)
-            (setq end (+ beg (length str)))))
-
-      ;; Prepare various delimiter strings
-      (or (equal PC-word-delimiters PC-delims)
-         (setq PC-delims PC-word-delimiters
-               PC-delim-regex (concat "[" PC-delims "]")
-               PC-ndelims-regex (concat "[^" PC-delims "]*")
-               PC-delims-list (append PC-delims nil)))
-
-      ;; Add wildcards if necessary
-      (and filename
-           (let ((dir (file-name-directory str))
-                 (file (file-name-nondirectory str))
-                ;; The base dir for file-completion was passed in `predicate'.
-                (default-directory (if (stringp pred) (expand-file-name pred)
-                                      default-directory)))
-             (while (and (stringp dir) (not (file-directory-p dir)))
-               (setq dir (directory-file-name dir))
-               (setq file (concat (replace-regexp-in-string
-                                   PC-delim-regex "*\\&"
-                                   (file-name-nondirectory dir))
-                                  "*/" file))
-               (setq dir (file-name-directory dir)))
-             (setq origstr str str (concat dir file))))
-
-      ;; Look for wildcard expansions in directory name
-      (and filename
-          (string-match "\\*.*/" str)
-          (let ((pat str)
-                ;; The base dir for file-completion was passed in `predicate'.
-                (default-directory (if (stringp pred) (expand-file-name pred)
-                                      default-directory))
-                files)
-            (setq p (1+ (string-match "/[^/]*\\'" pat)))
-            (while (setq p (string-match PC-delim-regex pat p))
-              (setq pat (concat (substring pat 0 p)
-                                "*"
-                                (substring pat p))
-                    p (+ p 2)))
-            (setq files (file-expand-wildcards (concat pat "*")))
-            (if files
-                (let ((dir (file-name-directory (car files)))
-                      (p files))
-                  (while (and (setq p (cdr p))
-                              (equal dir (file-name-directory (car p)))))
-                  (if p
-                      (setq filename nil table nil
-                             pred (if (stringp pred) nil pred)
-                            ambig t)
-                    (delete-region beg end)
-                    (setq str (concat dir (file-name-nondirectory str)))
-                    (insert str)
-                    (setq end (+ beg (length str)))))
-              (if origstr
-                       ;; If the wildcards were introduced by us, it's
-                       ;; possible that PC-read-file-name-internal can
-                       ;; still find matches for the original string
-                       ;; even if we couldn't, so remove the added
-                       ;; wildcards.
-                   (setq str origstr)
-                (setq filename nil table nil
-                       pred (if (stringp pred) nil pred))))))
-
-      ;; Strip directory name if appropriate
-      (if filename
-         (if incname
-             (setq basestr (substring str incname)
-                   dirname (substring str 0 incname))
-           (setq basestr (file-name-nondirectory str)
-                 dirname (file-name-directory str))
-           ;; Make sure str is consistent with its directory and basename
-           ;; parts.  This is important on DOZe'NT systems when str only
-           ;; includes a drive letter, like in "d:".
-           (setq str (concat dirname basestr)))
-       (setq basestr str))
-
-      ;; Convert search pattern to a standard regular expression
-      (setq regex (regexp-quote basestr)
-           offset (if (and (> (length regex) 0)
-                           (not (eq (aref basestr 0) ?\*))
-                           (or (eq PC-first-char t)
-                               (and PC-first-char filename))) 1 0)
-           p offset)
-      (while (setq p (string-match PC-delim-regex regex p))
-       (if (eq (aref regex p) ? )
-           (setq regex (concat (substring regex 0 p)
-                               PC-ndelims-regex
-                               PC-delim-regex
-                               (substring regex (1+ p)))
-                 p (+ p (length PC-ndelims-regex) (length PC-delim-regex)))
-         (let ((bump (if (memq (aref regex p)
-                               '(?$ ?^ ?\. ?* ?+ ?? ?\[ ?\] ?\\))
-                         -1 0)))
-           (setq regex (concat (substring regex 0 (+ p bump))
-                               PC-ndelims-regex
-                               (substring regex (+ p bump)))
-                 p (+ p (length PC-ndelims-regex) 1)))))
-      (setq p 0)
-      (if filename
-         (while (setq p (string-search "\\*" regex p))
-           (setq regex (concat (substring regex 0 p)
-                               "[^/]*"
-                               (substring regex (+ p 2))))))
-      ;;(setq the-regex regex)
-      (setq regex (concat "\\`" regex))
-
-      (and (> (length basestr) 0)
-           (= (aref basestr 0) ?$)
-           (setq env-on t
-                 table PC-env-vars-alist
-                 pred nil))
-
-      ;; Find an initial list of possible completions
-        (unless (setq p (string-match (concat PC-delim-regex
-                                            (if filename "\\|\\*" ""))
-                                    str
-                                      (+ (length dirname) offset)))
-
-         ;; Minibuffer contains no hyphens -- simple case!
-          (setq poss (all-completions (if env-on basestr str)
-                                     table
-                                     pred))
-          (unless (or poss (string-equal str ""))
-            ;; Try completion as an abbreviation, e.g. "mvb" ->
-            ;; "m-v-b" -> "multiple-value-bind", but only for
-            ;; non-empty strings.
-            (setq origstr str
-                  abbreviated t)
-            (if filename
-                (cond
-                  ;; "alpha" or "/alpha" -> expand whole path.
-                  ((string-match "^/?\\([A-Za-z0-9]+\\)$" str)
-                   (setq
-                    basestr ""
-                    p nil
-                   poss (file-expand-wildcards
-                          (concat "/"
-                                  (mapconcat #'list (match-string 1 str) "*/")
-                                  "*"))
-                    beg (1- beg)))
-                  ;; Alphanumeric trailer -> expand trailing file
-                  ((string-match "^\\(.+/\\)\\([A-Za-z0-9]+\\)$" str)
-                   (setq regex (concat "\\`"
-                                        (mapconcat #'list
-                                                   (match-string 2 str)
-                                                   "[A-Za-z0-9]*[^A-Za-z0-9]"))
-                          p (1+ (length (match-string 1 str))))))
-             (setq regex (concat "\\`" (mapconcat (lambda (c)
-                                                    (regexp-quote (string c)))
-                                                  str "[^-]*-"))
-                   p 1))))
-        (when p
-       ;; Use all-completions to do an initial cull.  This is a big win,
-       ;; since all-completions is written in C!
-       (let ((compl (all-completions (if env-on
-                                         (file-name-nondirectory (substring 
str 0 p))
-                                       (substring str 0 p))
-                                      table
-                                      pred)))
-         (setq p compl)
-            (when (and compl abbreviated)
-              (if filename
-                  (progn
-                    (setq p nil)
-                    (dolist (x compl)
-                      (when (string-match regex x)
-                        (push x p)))
-                    (setq basestr (try-completion "" p)))
-                  (setq basestr (mapconcat #'list str "-"))
-                  (delete-region beg end)
-                  (setq end (+ beg (length basestr)))
-                  (insert basestr))))
-         (while p
-           (and (string-match regex (car p))
-                (progn
-                  (set-text-properties 0 (length (car p)) '() (car p))
-                  (setq poss (cons (car p) poss))))
-            (setq p (cdr p))))
-
-      ;; If table had duplicates, they can be here.
-      (delete-dups poss)
-
-      ;; Handle completion-ignored-extensions
-      (and filename
-           (not (eq mode 'help))
-           (let ((p2 poss))
-
-             ;; Build a regular expression representing the extensions list
-             (or (equal completion-ignored-extensions PC-ignored-extensions)
-                 (setq PC-ignored-regexp
-                       (concat "\\("
-                               (mapconcat
-                                #'regexp-quote
-                                (setq PC-ignored-extensions
-                                      completion-ignored-extensions)
-                                "\\|")
-                               "\\)\\'")))
-
-             ;; Check if there are any without an ignored extension.
-             ;; Also ignore `.' and `..'.
-             (setq p nil)
-             (while p2
-               (or (string-match PC-ignored-regexp (car p2))
-                   (string-match "\\(\\`\\|/\\)[.][.]?/?\\'" (car p2))
-                   (setq p (cons (car p2) p)))
-               (setq p2 (cdr p2)))
-
-             ;; If there are "good" names, use them
-             (and p (setq poss p))))
-
-      ;; Now we have a list of possible completions
-
-      (cond
-
-       ;; No valid completions found
-       ((null poss)
-       (if (and (eq mode 'word)
-                (not PC-word-failed-flag))
-           (let ((PC-word-failed-flag t))
-             (delete-char -1)
-             (PC-do-completion 'word))
-               (when abbreviated
-                 (delete-region beg end)
-                 (insert origstr))
-         (beep)
-         (PC-temp-minibuffer-message (if ambig
-                                         " [Ambiguous dir name]"
-                                       (if (eq mode 'help)
-                                           " [No completions]"
-                                         " [No match]")))
-         nil))
-
-       ;; More than one valid completion found
-       ((or (cdr (setq helpposs poss))
-           (memq mode '(help word)))
-
-       ;; Is the actual string one of the possible completions?
-       (setq p (and (not (eq mode 'help)) poss))
-       (while (and p
-                   (not (string-equal (car p) basestr)))
-         (setq p (cdr p)))
-       (and p (null mode)
-            (PC-temp-minibuffer-message " [Complete, but not unique]"))
-       (if (and p
-                (not (and (null mode)
-                          (eq this-command last-command))))
-           t
-
-         ;; If ambiguous, try for a partial completion
-         (let ((improved nil)
-               prefix
-               (pt nil)
-               (skip "\\`"))
-
-           ;; Check if next few letters are the same in all cases
-           (if (and (not (eq mode 'help))
-                    (setq prefix (PC-try-completion
-                                  (PC-chunk-after basestr skip) poss)))
-               (let ((first t) i)
-                 (if (eq mode 'word)
-                     (setq prefix (PC-chop-word prefix basestr)))
-                 (goto-char (+ beg (length dirname)))
-                 (while (and (progn
-                               (setq i 0) ; index into prefix string
-                               (while (< i (length prefix))
-                                 (if (and (< (point) end)
-                                           (or (eq (downcase (aref prefix i))
-                                                  (downcase (following-char)))
-                                              (and (looking-at " ")
-                                                   (memq (aref prefix i)
-                                                         PC-delims-list))))
-                                     ;; replace " " by the actual delimiter
-                                      ;; or input char by prefix char
-                                     (progn
-                                       (delete-char 1)
-                                       (insert (substring prefix i (1+ i))))
-                                   ;; insert a new character
-                                   (progn
-                                     (and filename (looking-at "\\*")
-                                          (progn
-                                            (delete-char 1)
-                                            (setq end (1- end))))
-                                     (setq improved t)
-                                     (insert (substring prefix i (1+ i)))
-                                     (setq end (1+ end))))
-                                 (setq i (1+ i)))
-                               (or pt (setq pt (point)))
-                               (looking-at PC-delim-regex))
-                             (setq skip (concat skip
-                                                (regexp-quote prefix)
-                                                PC-ndelims-regex)
-                                   prefix (PC-try-completion
-                                           (PC-chunk-after
-                                            ;; not basestr, because that does
-                                            ;; not reflect insertions
-                                            (buffer-substring
-                                             (+ beg (length dirname)) end)
-                                            skip)
-                                           (mapcar
-                                             (lambda (x)
-                                               (when (string-match skip x)
-                                                 (substring x (match-end 0))))
-                                            poss)))
-                             (or (> i 0) (> (length prefix) 0))
-                             (or (not (eq mode 'word))
-                                 (and first (> (length prefix) 0)
-                                      (setq first nil
-                                            prefix (substring prefix 0 1))))))
-                 (goto-char (if (eq mode 'word) end
-                              (or pt beg)))))
-
-           (if (and (eq mode 'word)
-                    (not PC-word-failed-flag))
-
-               (if improved
-
-                   ;; We changed it... would it be complete without the space?
-                   (if (test-completion (buffer-substring
-                                          (field-beginning) (1- end))
-                                         table pred)
-                       (delete-region (1- end) end)))
-
-             (if improved
-
-                 ;; We changed it... enough to be complete?
-                 (and (eq mode 'exit)
-                      (test-completion-ignore-case (field-string) table pred))
-
-               ;; If totally ambiguous, display a list of completions
-               (if (or (eq completion-auto-help t)
-                       (and completion-auto-help
-                            (eq last-command this-command))
-                       (eq mode 'help))
-                    (let ((prompt-end (minibuffer-prompt-end)))
-                      (with-output-to-temp-buffer "*Completions*"
-                        (display-completion-list (sort helpposs 
#'string-lessp))
-                        (setq PC-do-completion-end end
-                              PC-goto-end goto-end)
-                        (with-current-buffer standard-output
-                          ;; Record which part of the buffer we are completing
-                          ;; so that choosing a completion from the list
-                          ;; knows how much old text to replace.
-                          ;; This was briefly nil in the non-dirname case.
-                          ;; However, if one calls PC-lisp-complete-symbol
-                          ;; on "(ne-f" with point on the hyphen, PC offers
-                          ;; all completions starting with "(ne", some of
-                          ;; which do not match the "-f" part (maybe it
-                          ;; should not, but it does). In such cases,
-                          ;; completion gets confused trying to figure out
-                          ;; how much to replace, so we tell it explicitly
-                          ;; (ie, the number of chars in the buffer before 
beg).
-                          ;;
-                          ;; Note that choose-completion-string-functions
-                          ;; plays around with point.
-                          (with-suppressed-warnings ((obsolete
-                                                      completion-base-size))
-                            (setq completion-base-size
-                                  (if dirname
-                                      dirlength
-                                    (- beg prompt-end)))))))
-                             (PC-temp-minibuffer-message " [Next char not 
unique]"))
-                         ;; Expansion of filenames is not reversible,
-                         ;; so just keep the prefix.
-           (when (and abbreviated filename)
-             (delete-region (point) end))
-                         nil)))))
-
-       ;; Only one possible completion
-       (t
-       (if (and (equal basestr (car poss))
-                 (not (and env-on filename))
-                 (not abbreviated))
-           (if (null mode)
-               (PC-temp-minibuffer-message " [Sole completion]"))
-         (delete-region beg end)
-         (insert (format "%s"
-                         (if filename
-                             (substitute-in-file-name (concat dirname (car 
poss)))
-                           (car poss)))))
-       t)))))
-
-(defun PC-chop-word (new old)
-  (let ((i -1)
-       (j -1))
-    (while (and (setq i (string-match PC-delim-regex old (1+ i)))
-               (setq j (string-match PC-delim-regex new (1+ j)))))
-    (if (and j
-            (or (not PC-word-failed-flag)
-                (setq j (string-match PC-delim-regex new (1+ j)))))
-       (substring new 0 (1+ j))
-      new)))
-
-(defvar PC-not-minibuffer nil)
-
-(defun PC-temp-minibuffer-message (message)
-  "A Lisp version of `temp_minibuffer_message' from minibuf.c."
-  (cond (PC-not-minibuffer
-        (message "%s" message)
-        (sit-for 2)
-        (message ""))
-       ((fboundp 'temp-minibuffer-message)
-        (temp-minibuffer-message message))
-       (t
-        (let ((point-max (point-max)))
-          (save-excursion
-            (goto-char point-max)
-            (insert message))
-          (let ((inhibit-quit t))
-            (sit-for 2)
-            (delete-region point-max (point-max))
-            (when quit-flag
-              (setq quit-flag nil
-                    unread-command-events '(7))))))))
-
-;; Does not need to be buffer-local (?) because only used when one
-;; PC-l-c-s immediately follows another.
-(defvar PC-lisp-complete-end nil
-  "Internal variable used by `PC-lisp-complete-symbol'.")
-
-(defun PC-lisp-complete-symbol ()
-  "Perform completion on Lisp symbol preceding point.
-That symbol is compared against the symbols that exist
-and any additional characters determined by what is there
-are inserted.
-If the symbol starts just after an open-parenthesis,
-only symbols with function definitions are considered.
-Otherwise, all symbols with function definitions, values
-or properties are considered."
-  (interactive)
-  (let* ((end
-          (save-excursion
-            (with-syntax-table lisp-mode-syntax-table
-              (skip-syntax-forward "_w")
-              (point))))
-        (beg (save-excursion
-                (with-syntax-table lisp-mode-syntax-table
-                  (backward-sexp 1)
-                  (while (= (char-syntax (following-char)) ?\')
-                    (forward-char 1))
-                  (point))))
-        (minibuffer-completion-table obarray)
-        (minibuffer-completion-predicate
-         (if (eq (char-after (1- beg)) ?\()
-             'fboundp
-           (function (lambda (sym)
-                       (or (boundp sym) (fboundp sym)
-                           (symbol-plist sym))))))
-        (PC-not-minibuffer t))
-    ;; https://lists.gnu.org/r/emacs-devel/2007-03/msg01211.html
-    ;;
-    ;; This deals with cases like running PC-l-c-s on "M-: (n-f".
-    ;; The first call to PC-l-c-s expands this to "(ne-f", and moves
-    ;; point to the hyphen [1]. If one calls PC-l-c-s immediately after,
-    ;; then without the last-command check, one is offered all
-    ;; completions of "(ne", which is presumably not what one wants.
-    ;;
-    ;; This is arguably (at least, it seems to be the existing intended
-    ;; behavior) what one _does_ want if point has been explicitly
-    ;; positioned on the hyphen. Note that if PC-do-completion (qv) binds
-    ;; completion-base-size to nil, then completion does not replace the
-    ;; correct amount of text in such cases.
-    ;;
-    ;; Neither of these problems occur when using PC for filenames in the
-    ;; minibuffer, because in that case PC-do-completion is called without
-    ;; an explicit value for END, and so uses (point-max). This is fine for
-    ;; a filename, because the end of the filename must be at the end of
-    ;; the minibuffer. The same is not true for lisp symbols.
-    ;;
-    ;; [1] An alternate fix would be to not move point to the hyphen
-    ;; in such cases, but that would make the behavior different from
-    ;; that for filenames. It seems PC moves point to the site of the
-    ;; first difference between the possible completions.
-    ;;
-    ;; Alternatively alternatively, maybe end should be computed in
-    ;; the same way as beg. That would change the behavior though.
-    (if (equal last-command 'PC-lisp-complete-symbol)
-        (PC-do-completion nil beg PC-lisp-complete-end t)
-      (if PC-lisp-complete-end
-          (move-marker PC-lisp-complete-end end)
-        (setq PC-lisp-complete-end (copy-marker end t)))
-      (PC-do-completion nil beg end t))))
-
-(defun PC-complete-as-file-name ()
-   "Perform completion on file names preceding point.
- Environment vars are converted to their values."
-   (interactive)
-   (let* ((end (point))
-          (beg (if (re-search-backward "[^\\][ \t\n\"`'][^ \t\n\"`']"
-                                      (point-min) t)
-                   (+ (point) 2)
-                   (point-min)))
-          (minibuffer-completion-table 'PC-read-file-name-internal)
-          (minibuffer-completion-predicate nil)
-          (PC-not-minibuffer t))
-     (goto-char end)
-     (PC-do-completion nil beg end)))
-
-;; Facilities for loading C header files.  This is independent from the
-;; main completion code.  See also the variable `PC-include-file-path'
-;; at top of this file.
-
-(defun PC-look-for-include-file ()
-  (if (string-match "[\"<]\\([^\"<>]*\\)[\">]?$" (buffer-file-name))
-      (let ((name (substring (buffer-file-name)
-                            (match-beginning 1) (match-end 1)))
-           (punc (aref (buffer-file-name) (match-beginning 0)))
-           (path nil)
-           new-buf)
-       (kill-buffer (current-buffer))
-       (if (equal name "")
-           (with-current-buffer (car (buffer-list))
-             (save-excursion
-               (beginning-of-line)
-               (if (looking-at
-                    "[ \t]*#[ \t]*include[ \t]+[<\"]\\(.+\\)[>\"][ \t]*[\n/]")
-                   (setq name (buffer-substring (match-beginning 1)
-                                                (match-end 1))
-                         punc (char-after (1- (match-beginning 1))))
-                 ;; Suggested by Frank Siebenlist:
-                 (if (or (looking-at
-                          "[ \t]*([ \t]*load[ \t]+\"\\([^\"]+\\)\"")
-                         (looking-at
-                          "[ \t]*([ \t]*load-library[ \t]+\"\\([^\"]+\\)\"")
-                         (looking-at
-                          "[ \t]*([ \t]*require[ \t]+'\\([^\t )]+\\)[\t )]"))
-                     (progn
-                       (setq name (buffer-substring (match-beginning 1)
-                                                    (match-end 1))
-                             punc ?\<
-                             path load-path)
-                       (if (string-match "\\.elc$" name)
-                           (setq name (substring name 0 -1))
-                         (or (string-match "\\.el$" name)
-                             (setq name (concat name ".el")))))
-                   (error "Not on an #include line"))))))
-       (or (string-match "\\.[[:alnum:]]+$" name)
-           (setq name (concat name ".h")))
-       (if (eq punc ?\<)
-           (let ((path (or path (PC-include-file-path))))
-             (while (and path
-                         (not (file-exists-p
-                               (concat (file-name-as-directory (car path))
-                                       name))))
-               (setq path (cdr path)))
-             (if path
-                 (setq name (concat (file-name-as-directory (car path)) name))
-               (error "No such include file: <%s>" name)))
-         (let ((dir (with-current-buffer (car (buffer-list))
-                      default-directory)))
-           (if (file-exists-p (concat dir name))
-               (setq name (concat dir name))
-             (error "No such include file: `%s'" name))))
-       (setq new-buf (get-file-buffer name))
-       (if new-buf
-           ;; no need to verify last-modified time for this!
-           (set-buffer new-buf)
-         (set-buffer (create-file-buffer name))
-         (erase-buffer)
-         (insert-file-contents name t))
-       ;; Returning non-nil with the new buffer current
-       ;; is sufficient to tell find-file to use it.
-       t)
-    nil))
-
-(defun PC-include-file-path ()
-  (or PC-include-file-path
-      (let ((env (getenv "INCPATH"))
-           (path nil)
-           pos)
-       (or env (error "No include file path specified"))
-       (while (setq pos (string-match ":[^:]+$" env))
-         (setq path (cons (substring env (1+ pos)) path)
-               env (substring env 0 pos)))
-       path)))
-
-;; This is adapted from lib-complete.el, by Mike Williams.
-(defun PC-include-file-all-completions (file search-path &optional full)
-  "Return all completions for FILE in any directory on SEARCH-PATH.
-If optional third argument FULL is non-nil, returned pathnames should be
-absolute rather than relative to some directory on the SEARCH-PATH."
-  (setq search-path
-       (mapcar (lambda (dir)
-                 (if dir (file-name-as-directory dir) default-directory))
-               search-path))
-  (if (file-name-absolute-p file)
-      ;; It's an absolute file name, so don't need search-path
-      (progn
-       (setq file (expand-file-name file))
-       (file-name-all-completions
-        (file-name-nondirectory file) (file-name-directory file)))
-    (let ((subdir (file-name-directory file))
-         (ndfile (file-name-nondirectory file))
-         file-lists)
-      ;; Append subdirectory part to each element of search-path
-      (if subdir
-         (setq search-path
-               (mapcar (lambda (dir) (concat dir subdir))
-                       search-path)
-               file nil))
-      ;; Make list of completions in each directory on search-path
-      (while search-path
-       (let* ((dir (car search-path))
-              (subdir (if full dir subdir)))
-         (if (file-directory-p dir)
-             (progn
-               (setq file-lists
-                     (cons
-                      (mapcar (lambda (file) (concat subdir file))
-                              (file-name-all-completions ndfile
-                                                         (car search-path)))
-                      file-lists))))
-         (setq search-path (cdr search-path))))
-      ;; Compress out duplicates while building complete list (slloooow!)
-      (let ((sorted (sort (apply #'nconc file-lists)
-                         (lambda (x y) (not (string-lessp x y)))))
-           compressed)
-       (while sorted
-         (if (equal (car sorted) (car compressed)) nil
-           (setq compressed (cons (car sorted) compressed)))
-         (setq sorted (cdr sorted)))
-       compressed))))
-
-(defun PC-read-file-name-internal (string pred action)
-  "Extend `read-file-name-internal' to handle include files.
-This is only used by "
-  (if (string-match "<\\([^\"<>]*\\)>?\\'" string)
-      (let* ((name (match-string 1 string))
-            (str2 (substring string (match-beginning 0)))
-            (completion-table
-             (mapcar (lambda (x)
-                        (format (if (string-match "/\\'" x) "<%s" "<%s>") x))
-                     (PC-include-file-all-completions
-                      name (PC-include-file-path)))))
-        (cond
-         ((not completion-table) nil)
-         ((eq action 'lambda) (test-completion str2 completion-table nil))
-         ((eq action nil) (PC-try-completion str2 completion-table nil))
-         ((eq action t) (all-completions str2 completion-table nil))))
-    (read-file-name-internal string pred action)))
-
-
-(provide 'complete)
-
-;;; complete.el ends here
diff --git a/lisp/obsolete/cust-print.el b/lisp/obsolete/cust-print.el
deleted file mode 100644
index 80ded08654..0000000000
--- a/lisp/obsolete/cust-print.el
+++ /dev/null
@@ -1,674 +0,0 @@
-;;; cust-print.el --- handles print-level and print-circle  -*- 
lexical-binding: t; -*-
-
-;; Copyright (C) 1992, 2001-2022 Free Software Foundation, Inc.
-
-;; Author: Daniel LaLiberte <liberte@holonexus.org>
-;; Adapted-By: ESR
-;; Keywords: extensions
-;; Obsolete-since: 24.3
-
-;; LCD Archive Entry:
-;; cust-print|Daniel LaLiberte|liberte@holonexus.org
-;; |Handle print-level, print-circle and more.
-
-;; 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 package provides a general print handler for prin1 and princ
-;; that supports print-level and print-circle, and by the way,
-;; print-length since the standard routines are being replaced.  Also,
-;; to print custom types constructed from lists and vectors, use
-;; custom-print-list and custom-print-vector.  See the documentation
-;; strings of these variables for more details.
-
-;; If the results of your expressions contain circular references to
-;; other parts of the same structure, the standard Emacs print
-;; subroutines may fail to print with an untrappable error,
-;; "Apparently circular structure being printed".  If you only use cdr
-;; circular lists (where cdrs of lists point back; what is the right
-;; term here?), you can limit the length of printing with
-;; print-length.  But car circular lists and circular vectors generate
-;; the above mentioned error in Emacs version 18.  Version
-;; 19 supports print-level, but it is often useful to get a better
-;; print representation of circular and shared structures; the print-circle
-;; option may be used to print more concise representations.
-
-;; There are three main ways to use this package.  First, you may
-;; replace prin1, princ, and some subroutines that use them by calling
-;; install-custom-print so that any use of these functions in
-;; Lisp code will be affected; you can later reset with
-;; uninstall-custom-print.  Second, you may temporarily install
-;; these functions with the macro with-custom-print.  Third, you
-;; could call the custom routines directly, thus only affecting the
-;; printing that requires them.
-
-;; Note that subroutines which call print subroutines directly will
-;; not use the custom print functions.  In particular, the evaluation
-;; functions like eval-region call the print subroutines directly.
-;; Therefore, if you evaluate (aref circ-list 0), where circ-list is a
-;; circular list rather than an array, aref calls error directly which
-;; will jump to the top level instead of printing the circular list.
-
-;; Uninterned symbols are recognized when print-circle is non-nil,
-;; but they are not printed specially here.  Use the cl-packages package
-;; to print according to print-gensym.
-
-;; Obviously the right way to implement this custom-print facility is
-;; in C or with hooks into the standard printer.  Please volunteer
-;; since I don't have the time or need.  More CL-like printing
-;; capabilities could be added in the future.
-
-;; Implementation design: we want to use the same list and vector
-;; processing algorithm for all versions of prin1 and princ, since how
-;; the processing is done depends on print-length, print-level, and
-;; print-circle.  For circle printing, a preprocessing step is
-;; required before the final printing.  Thanks to Jamie Zawinski
-;; for motivation and algorithms.
-
-
-;;; Code:
-
-(defgroup cust-print nil
-  "Handles print-level and print-circle."
-  :prefix "print-"
-  :group 'lisp
-  :group 'extensions)
-
-;; If using cl-packages:
-
-'(defpackage "cust-print"
-   (:nicknames "CP" "custom-print")
-   (:use "el")
-   (:export
-    print-level
-    print-circle
-
-    custom-print-install
-    custom-print-uninstall
-    custom-print-installed-p
-    with-custom-print
-
-    custom-prin1
-    custom-princ
-    custom-prin1-to-string
-    custom-print
-    custom-format
-    custom-message
-    custom-error
-
-    custom-printers
-    add-custom-printer
-    ))
-
-'(in-package cust-print)
-
-;; Emacs 18 doesn't have defalias.
-;; Provide def for byte compiler.
-
-;; Variables:
-;;=========================================================
-
-;;(defvar print-length nil
-;;  "*Controls how many elements of a list, at each level, are printed.
-;;This is defined by emacs.")
-
-(defcustom print-level nil
-  "Controls how many levels deep a nested data object will print.
-
-If nil, printing proceeds recursively and may lead to
-max-lisp-eval-depth being exceeded or an error may occur:
-`Apparently circular structure being printed.'
-Also see `print-length' and `print-circle'.
-
-If non-nil, components at levels equal to or greater than `print-level'
-are printed simply as `#'.  The object to be printed is at level 0,
-and if the object is a list or vector, its top-level components are at
-level 1."
-  :type '(choice (const nil) integer))
-
-
-(defcustom print-circle nil
-  "Controls the printing of recursive structures.
-
-If nil, printing proceeds recursively and may lead to
-`max-lisp-eval-depth' being exceeded or an error may occur:
-\"Apparently circular structure being printed.\"  Also see
-`print-length' and `print-level'.
-
-If non-nil, shared substructures anywhere in the structure are printed
-with `#N=' before the first occurrence (in the order of the print
-representation) and `#N#' in place of each subsequent occurrence,
-where N is a positive decimal integer."
-  :type 'boolean)
-
-
-(defcustom custom-print-vectors nil
-  "Non-nil if printing of vectors should obey `print-level' and 
`print-length'."
-  :type 'boolean)
-
-
-;; Custom printers
-;;==========================================================
-
-(defvar custom-printers nil
-  ;; e.g. '((symbolp . pkg::print-symbol))
-  "An alist for custom printing of any type.
-Pairs are of the form (PREDICATE . PRINTER).  If PREDICATE is true
-for an object, then PRINTER is called with the object.
-PRINTER should print to `standard-output' using cust-print-original-princ
-if the standard printer is sufficient, or cust-print-prin for complex things.
-The PRINTER should return the object being printed.
-
-Don't modify this variable directly.  Use `add-custom-printer' and
-`delete-custom-printer'")
-;; Should cust-print-original-princ and cust-print-prin be exported symbols?
-;; Or should the standard printers functions be replaced by
-;; CP ones in Emacs Lisp so that CP internal functions need not be called?
-
-(defun add-custom-printer (pred printer)
-  "Add a pair of PREDICATE and PRINTER to `custom-printers'.
-Any pair that has the same PREDICATE is first removed."
-  (setq custom-printers (cons (cons pred printer)
-                             (delq (assq pred custom-printers)
-                                   custom-printers)))
-  ;; Rather than updating here, we could wait until cust-print-top-level is 
called.
-  (cust-print-update-custom-printers))
-
-(defun delete-custom-printer (pred)
-  "Delete the custom printer associated with PREDICATE."
-  (setq custom-printers (delq (assq pred custom-printers)
-                             custom-printers))
-  (cust-print-update-custom-printers))
-
-
-(defun cust-print-use-custom-printer (_object)
-  ;; Default function returns nil.
-  nil)
-
-(defun cust-print-update-custom-printers ()
-  ;; Modify the definition of cust-print-use-custom-printer
-  (defalias 'cust-print-use-custom-printer
-    ;; We don't really want to require the byte-compiler.
-    ;; (byte-compile
-    `(lambda (object)
-       (cond
-       ,@(mapcar (function
-                  (lambda (pair)
-                    `((,(car pair) object)
-                      (,(cdr pair) object))))
-                 custom-printers)
-       ;; Otherwise return nil.
-       (t nil)
-       ))
-    ;; )
-    ))
-
-
-;; Saving and restoring emacs printing routines.
-;;====================================================
-
-(defun cust-print-set-function-cell (symbol-pair)
-  (defalias (car symbol-pair)
-    (symbol-function (car (cdr symbol-pair)))))
-
-(defun cust-print-original-princ (_object &optional _stream) nil) ; dummy def
-
-;; Save emacs routines.
-(if (not (fboundp 'cust-print-original-prin1))
-    (mapc #'cust-print-set-function-cell
-         '((cust-print-original-prin1 prin1)
-           (cust-print-original-princ princ)
-           (cust-print-original-print print)
-           (cust-print-original-prin1-to-string prin1-to-string)
-           (cust-print-original-format format)
-           (cust-print-original-message message)
-           (cust-print-original-error error))))
-(declare-function cust-print-original-format "cust-print")
-(declare-function cust-print-original-message "cust-print")
-
-(defun custom-print-install ()
-  "Replace print functions with general, customizable, Lisp versions.
-The Emacs subroutines are saved away, and you can reinstall them
-by running `custom-print-uninstall'."
-  (interactive)
-  (mapc #'cust-print-set-function-cell
-       '((prin1 custom-prin1)
-         (princ custom-princ)
-         (print custom-print)
-         (prin1-to-string custom-prin1-to-string)
-         (format custom-format)
-         (message custom-message)
-         (error custom-error)
-         ))
-  t)
-
-(defun custom-print-uninstall ()
-  "Reset print functions to their Emacs subroutines."
-  (interactive)
-  (mapc #'cust-print-set-function-cell
-       '((prin1 cust-print-original-prin1)
-         (princ cust-print-original-princ)
-         (print cust-print-original-print)
-         (prin1-to-string cust-print-original-prin1-to-string)
-         (format cust-print-original-format)
-         (message cust-print-original-message)
-         (error cust-print-original-error)
-         ))
-  t)
-
-(defalias 'custom-print-funcs-installed-p #'custom-print-installed-p)
-(defun custom-print-installed-p ()
-  "Return t if custom-print is currently installed, nil otherwise."
-  (eq (symbol-function 'custom-prin1) (symbol-function 'prin1)))
-
-(defmacro with-custom-print (&rest body)
-  "Temporarily install the custom print package while executing BODY."
-  (declare (debug t))
-  `(unwind-protect
-       (progn
-        (custom-print-install)
-        ,@body)
-     (custom-print-uninstall)))
-(defalias 'with-custom-print-funcs #'with-custom-print)
-
-
-;; Lisp replacements for prin1 and princ, and for some subrs that use them
-;;===============================================================
-;; - so far only the printing and formatting subrs.
-
-(defun custom-prin1 (object &optional stream)
-  "Output the printed representation of OBJECT, any Lisp object.
-Quoting characters are printed when needed to make output that `read'
-can handle, whenever this is possible.
-Output stream is STREAM, or value of `standard-output' (which see).
-
-This is the custom-print replacement for the standard `prin1'.  It
-uses the appropriate printer depending on the values of `print-level'
-and `print-circle' (which see)."
-  (cust-print-top-level object stream 'cust-print-original-prin1))
-
-
-(defun custom-princ (object &optional stream)
-  "Output the printed representation of OBJECT, any Lisp object.
-No quoting characters are used; no delimiters are printed around
-the contents of strings.
-Output stream is STREAM, or value of `standard-output' (which see).
-
-This is the custom-print replacement for the standard `princ'."
-  (cust-print-top-level object stream 'cust-print-original-princ))
-
-
-(defun custom-prin1-to-string (object &optional noescape)
-  "Return a string containing the printed representation of OBJECT,
-any Lisp object.  Quoting characters are used when needed to make output
-that `read' can handle, whenever this is possible, unless the optional
-second argument NOESCAPE is non-nil.
-
-This is the custom-print replacement for the standard `prin1-to-string'."
-  (let ((buf (get-buffer-create " *custom-print-temp*")))
-    ;; We must erase the buffer before printing in case an error
-    ;; occurred during the last prin1-to-string and we are in debugger.
-    (with-current-buffer buf
-      (erase-buffer))
-    ;; We must be in the current-buffer when the print occurs.
-    (if noescape
-       (custom-princ object buf)
-      (custom-prin1 object buf))
-    (with-current-buffer buf
-      (buffer-string)
-      ;; We could erase the buffer again, but why bother?
-      )))
-
-
-(defun custom-print (object &optional stream)
-  "Output the printed representation of OBJECT, with newlines around it.
-Quoting characters are printed when needed to make output that `read'
-can handle, whenever this is possible.
-Output stream is STREAM, or value of `standard-output' (which see).
-
-This is the custom-print replacement for the standard `print'."
-  (cust-print-original-princ "\n" stream)
-  (custom-prin1 object stream)
-  (cust-print-original-princ "\n" stream))
-
-
-(defun custom-format (fmt &rest args)
-  "Format a string out of a control-string and arguments.
-The first argument is a control string.  It, and subsequent arguments
-substituted into it, become the value, which is a string.
-It may contain %s or %d or %c to substitute successive following arguments.
-%s means print an argument as a string, %d means print as number in decimal,
-%c means print a number as a single character.
-The argument used by %s must be a string or a symbol;
-the argument used by %d, %b, %o, %x or %c must be a number.
-
-This is the custom-print replacement for the standard `format'.  It
-calls the Emacs `format' after first making strings for list,
-vector, or symbol args.  The format specification for such args should
-be `%s' in any case, so a string argument will also work.  The string
-is generated with `custom-prin1-to-string', which quotes quotable
-characters."
-  (apply #'cust-print-original-format fmt
-        (mapcar (function (lambda (arg)
-                            (if (or (listp arg) (vectorp arg) (symbolp arg))
-                                (custom-prin1-to-string arg)
-                              arg)))
-                args)))
-
-
-(defun custom-message (fmt &rest args)
-  "Print a one-line message at the bottom of the screen.
-The first argument is a control string.
-It may contain %s or %d or %c to print successive following arguments.
-%s means print an argument as a string, %d means print as number in decimal,
-%c means print a number as a single character.
-The argument used by %s must be a string or a symbol;
-the argument used by %d or %c must be a number.
-
-This is the custom-print replacement for the standard `message'.
-See `custom-format' for the details."
-  ;; It doesn't work to princ the result of custom-format as in:
-  ;; (cust-print-original-princ (apply 'custom-format fmt args))
-  ;; because the echo area requires special handling
-  ;; to avoid duplicating the output.
-  ;; cust-print-original-message does it right.
-  (apply #'cust-print-original-message  fmt
-        (mapcar (function (lambda (arg)
-                            (if (or (listp arg) (vectorp arg) (symbolp arg))
-                                (custom-prin1-to-string arg)
-                              arg)))
-                args)))
-
-
-(defun custom-error (fmt &rest args)
-  "Signal an error, making error message by passing all args to `format'.
-
-This is the custom-print replacement for the standard `error'.
-See `custom-format' for the details."
-  (signal 'error (list (apply #'custom-format fmt args))))
-
-
-
-;; Support for custom prin1 and princ
-;;=========================================
-
-;; Defs to quiet byte-compiler.
-(defvar circle-table)
-(defvar cust-print-current-level)
-
-(defun cust-print-original-printer (_object) nil) ; One of the standard 
printers.
-(defun cust-print-low-level-prin (_object) nil)   ; Used internally.
-(defun cust-print-prin (_object) nil) ; Call this to print recursively.
-
-(defun cust-print-top-level (object stream emacs-printer)
-  ;; Set up for printing.
-  (let ((standard-output (or stream standard-output))
-       ;; circle-table will be non-nil if anything is circular.
-       (circle-table (and print-circle
-                          (cust-print-preprocess-circle-tree object)))
-       (cust-print-current-level (or print-level -1)))
-
-    (defalias 'cust-print-original-printer emacs-printer)
-    (defalias 'cust-print-low-level-prin
-      (cond
-       ((or custom-printers
-           circle-table
-           print-level                 ; comment out for version 19
-           ;; Emacs doesn't use print-level or print-length
-           ;; for vectors, but custom-print can.
-           (if custom-print-vectors
-               (or print-level print-length)))
-       'cust-print-print-object)
-       (t 'cust-print-original-printer)))
-    (defalias 'cust-print-prin
-      (if circle-table 'cust-print-print-circular 'cust-print-low-level-prin))
-
-    (cust-print-prin object)
-    object))
-
-
-(defun cust-print-print-object (object)
-  ;; Test object type and print accordingly.
-  ;; Could be called as either cust-print-low-level-prin or cust-print-prin.
-  (cond
-   ((null object) (cust-print-original-printer object))
-   ((cust-print-use-custom-printer object) object)
-   ((consp object) (cust-print-list object))
-   ((vectorp object) (cust-print-vector object))
-   ;; All other types, just print.
-   (t (cust-print-original-printer object))))
-
-
-(defun cust-print-print-circular (object)
-  ;; Printer for `prin1' and `princ' that handles circular structures.
-  ;; If OBJECT appears multiply, and has not yet been printed,
-  ;; prefix with label; if it has been printed, use `#N#' instead.
-  ;; Otherwise, print normally.
-  (let ((tag (assq object circle-table)))
-    (if tag
-       (let ((id (cdr tag)))
-         (if (> id 0)
-             (progn
-               ;; Already printed, so just print id.
-               (cust-print-original-princ "#")
-               (cust-print-original-princ id)
-               (cust-print-original-princ "#"))
-           ;; Not printed yet, so label with id and print object.
-           (setcdr tag (- id)) ; mark it as printed
-           (cust-print-original-princ "#")
-           (cust-print-original-princ (- id))
-           (cust-print-original-princ "=")
-           (cust-print-low-level-prin object)
-           ))
-      ;; Not repeated in structure.
-      (cust-print-low-level-prin object))))
-
-
-;;================================================
-;; List and vector processing for print functions.
-
-(defun cust-print-list (list)
-  ;; Print a list using print-length, print-level, and print-circle.
-  (if (= cust-print-current-level 0)
-      (cust-print-original-princ "#")
-    (let ((cust-print-current-level (1- cust-print-current-level)))
-      (cust-print-original-princ "(")
-      (let ((length (or print-length 0)))
-
-       ;; Print the first element always (even if length = 0).
-       (cust-print-prin (car list))
-       (setq list (cdr list))
-       (if list (cust-print-original-princ " "))
-       (setq length (1- length))
-
-       ;; Print the rest of the elements.
-       (while (and list (/= 0 length))
-         (if (and (listp list)
-                  (not (assq list circle-table)))
-             (progn
-               (cust-print-prin (car list))
-               (setq list (cdr list)))
-
-           ;; cdr is not a list, or it is in circle-table.
-           (cust-print-original-princ ". ")
-           (cust-print-prin list)
-           (setq list nil))
-
-         (setq length (1- length))
-         (if list (cust-print-original-princ " ")))
-
-       (if (and list (= length 0)) (cust-print-original-princ "..."))
-       (cust-print-original-princ ")"))))
-  list)
-
-
-(defun cust-print-vector (vector)
-  ;; Print a vector according to print-length, print-level, and print-circle.
-  (if (= cust-print-current-level 0)
-      (cust-print-original-princ "#")
-    (let ((cust-print-current-level (1- cust-print-current-level))
-         (i 0)
-         (len (length vector)))
-      (cust-print-original-princ "[")
-
-      (if print-length
-         (setq len (min print-length len)))
-      ;; Print the elements
-      (while (< i len)
-       (cust-print-prin (aref vector i))
-       (setq i (1+ i))
-       (if (< i (length vector)) (cust-print-original-princ " ")))
-
-      (if (< i (length vector)) (cust-print-original-princ "..."))
-      (cust-print-original-princ "]")
-      ))
-  vector)
-
-
-
-;; Circular structure preprocessing
-;;==================================
-
-(defun cust-print-preprocess-circle-tree (object)
-  ;; Fill up the table.
-  (let (;; Table of tags for each object in an object to be printed.
-       ;; A tag is of the form:
-       ;; ( <object> <nil-t-or-id-number> )
-       ;; The id-number is generated after the entire table has been computed.
-       ;; During walk through, the real circle-table lives in the cdr so we
-       ;; can use setcdr to add new elements instead of having to setq the
-       ;; variable sometimes (poor man's locf).
-       (circle-table (list nil)))
-    (cust-print-walk-circle-tree object)
-
-    ;; Reverse table so it is in the order that the objects will be printed.
-    ;; This pass could be avoided if we always added to the end of the
-    ;; table with setcdr in walk-circle-tree.
-    (setcdr circle-table (nreverse (cdr circle-table)))
-
-    ;; Walk through the table, assigning id-numbers to those
-    ;; objects which will be printed using #N= syntax.  Delete those
-    ;; objects which will be printed only once (to speed up assq later).
-    (let ((rest circle-table)
-         (id -1))
-      (while (cdr rest)
-       (let ((tag (car (cdr rest))))
-         (cond ((cdr tag)
-                (setcdr tag id)
-                (setq id (1- id))
-                (setq rest (cdr rest)))
-               ;; Else delete this object.
-               (t (setcdr rest (cdr (cdr rest))))))
-       ))
-    ;; Drop the car.
-    (cdr circle-table)
-    ))
-
-
-
-(defun cust-print-walk-circle-tree (object)
-  (let (read-equivalent-p tag)
-    (while object
-      (setq read-equivalent-p
-           (or (numberp object)
-               (and (symbolp object)
-                    ;; Check if it is uninterned.
-                    (eq object (intern-soft (symbol-name object)))))
-           tag (and (not read-equivalent-p)
-                    (assq object (cdr circle-table))))
-      (cond (tag
-            ;; Seen this object already, so note that.
-            (setcdr tag t))
-
-           ((not read-equivalent-p)
-            ;; Add a tag for this object.
-            (setcdr circle-table
-                    (cons (list object)
-                          (cdr circle-table)))))
-      (setq object
-           (cond
-            (tag ;; No need to descend since we have already.
-             nil)
-
-            ((consp object)
-             ;; Walk the car of the list recursively.
-             (cust-print-walk-circle-tree (car object))
-             ;; But walk the cdr with the above while loop
-             ;; to avoid problems with max-lisp-eval-depth.
-             ;; And it should be faster than recursion.
-             (cdr object))
-
-            ((vectorp object)
-             ;; Walk the vector.
-             (let ((i (length object))
-                   (j 0))
-               (while (< j i)
-                 (cust-print-walk-circle-tree (aref object j))
-                 (setq j (1+ j))))))))))
-
-
-;; Example.
-;;=======================================
-
-'(progn
-   (progn
-     ;; Create some circular structures.
-     (setq circ-sym (let ((x (make-symbol "FOO"))) (list x x)))
-     (setq circ-list (list 'a 'b (vector 1 2 3 4) 'd 'e 'f))
-     (setcar (nthcdr 3 circ-list) circ-list)
-     (aset (nth 2 circ-list) 2 circ-list)
-     (setq dotted-circ-list (list 'a 'b 'c))
-     (setcdr (cdr (cdr dotted-circ-list)) dotted-circ-list)
-     (setq circ-vector (vector 1 2 3 4 (list 'a 'b 'c 'd) 6 7))
-     (aset circ-vector 5 (make-symbol "-gensym-"))
-     (setcar (cdr (aref circ-vector 4)) (aref circ-vector 5))
-     nil)
-
-   (install-custom-print)
-   ;; (setq print-circle t)
-
-   (let ((print-circle t))
-     (or (equal (prin1-to-string circ-list) "#1=(a b [1 2 #1# 4] #1# e f)")
-         (error "Circular object with array printing")))
-
-   (let ((print-circle t))
-     (or (equal (prin1-to-string dotted-circ-list) "#1=(a b c . #1#)")
-         (error "Circular object with array printing")))
-
-   (let* ((print-circle t)
-         (x (list 'p 'q))
-         (y (list (list 'a 'b) x 'foo x)))
-     (setcdr (cdr (cdr (cdr y))) (cdr y))
-     (or (equal (prin1-to-string y) "((a b) . #1=(#2=(p q) foo #2# . #1#))"
-               )
-         (error "Circular list example from CL manual")))
-
-   (let ((print-circle nil))
-     ;; cl-packages.el is required to print uninterned symbols like #:FOO.
-     ;; (require 'cl-packages)
-     (or (equal (prin1-to-string circ-sym) "(#:FOO #:FOO)")
-         (error "Uninterned symbols in list")))
-   (let ((print-circle t))
-     (or (equal (prin1-to-string circ-sym) "(#1=FOO #1#)")
-         (error "Circular uninterned symbols in list")))
-
-   (uninstall-custom-print)
-   )
-
-(provide 'cust-print)
-
-;;; cust-print.el ends here
diff --git a/lisp/obsolete/eieio-compat.el b/lisp/obsolete/eieio-compat.el
index 8d8211b849..ead9352695 100644
--- a/lisp/obsolete/eieio-compat.el
+++ b/lisp/obsolete/eieio-compat.el
@@ -5,6 +5,7 @@
 ;; Author: Eric M. Ludlam <zappo@gnu.org>
 ;; Keywords: OO, lisp
 ;; Package: eieio
+;; Obsolete-since: 29.1
 
 ;; This file is part of GNU Emacs.
 
@@ -247,31 +248,11 @@ Summary:
   (message "next-method-p called outside of a primary or around method")
   nil)
 
-;;;###autoload
-(defun eieio-defmethod (method args)
-  "Obsolete work part of an old version of the `defmethod' macro."
-  (declare (obsolete cl-defmethod "24.1"))
-  (eval `(defmethod ,method ,@args))
-  method)
-
-;;;###autoload
-(defun eieio-defgeneric (method doc-string)
-  "Obsolete work part of an old version of the `defgeneric' macro."
-  (declare (obsolete cl-defgeneric "24.1"))
-  (eval `(defgeneric ,method (x) ,@(if doc-string `(,doc-string))))
-  ;; Return the method
-  'method)
-
 ;;;###autoload
 (defun eieio-defclass (cname superclasses slots options)
   (declare (obsolete eieio-defclass-internal "25.1"))
   (eval `(defclass ,cname ,superclasses ,slots ,@options)))
 
-
-;; Local Variables:
-;; generated-autoload-file: "eieio-loaddefs.el"
-;; End:
-
 (provide 'eieio-compat)
 
 ;;; eieio-compat.el ends here
diff --git a/lisp/obsolete/erc-hecomplete.el b/lisp/obsolete/erc-hecomplete.el
deleted file mode 100644
index 79ccf80440..0000000000
--- a/lisp/obsolete/erc-hecomplete.el
+++ /dev/null
@@ -1,218 +0,0 @@
-;;; erc-hecomplete.el --- Provides Nick name completion for ERC  -*- 
lexical-binding: t; -*-
-
-;; Copyright (C) 2001-2002, 2004, 2006-2022 Free Software Foundation,
-;; Inc.
-
-;; Author: Alex Schroeder <alex@gnu.org>
-;; URL: https://www.emacswiki.org/cgi-bin/wiki.pl?ErcCompletion
-;; Obsolete-since: 24.1
-
-;; This file is part of GNU Emacs.
-
-;; GNU Emacs is free software: you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; GNU Emacs is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; This file is considered obsolete.  It is recommended to use
-;; completion from erc-pcomplete instead.
-
-;; This file is based on hippie-expand, while the new file is based on
-;; pcomplete.
-
-;;; Code:
-
-(require 'erc)
-(require 'erc-match); for erc-pals
-(require 'hippie-exp); for the hippie expand stuff
-
-;;;###autoload (autoload 'erc-hecomplete-mode "erc-hecomplete" nil t)
-(define-erc-module hecomplete nil
-  "Complete nick at point."
-  ((add-hook 'erc-complete-functions #'erc-hecomplete))
-  ((remove-hook 'erc-complete-functions #'erc-hecomplete)))
-
-(defun erc-hecomplete ()
-  "Complete nick at point.
-See `erc-try-complete-nick' for more technical info.
-This function is obsolete, use `erc-pcomplete' instead."
-  (interactive)
-  (let ((hippie-expand-try-functions-list '(erc-try-complete-nick)))
-    (hippie-expand nil)))
-
-(defgroup erc-hecomplete nil
-  "Nick completion.  It is recommended to use `erc-pcomplete' instead."
-  :group 'erc)
-
-(defcustom erc-nick-completion 'all
-  "Determine how the list of nicks is determined during nick completion.
-See `erc-complete-nick' for information on how to activate this.
-
-pals:   Use `erc-pals'.
-all:    All channel members.
-
-You may also provide your own function that returns a list of completions.
-One example is `erc-nick-completion-exclude-myself',
-or you may use an arbitrary lisp expression."
-  :type '(choice (const :tag "List of pals" pals)
-                (const :tag "All channel members" all)
-                (const :tag "All channel members except yourself"
-                       erc-nick-completion-exclude-myself)
-                (repeat :tag "List" (string :tag "Nick"))
-                function
-                sexp))
-
-(defcustom erc-nick-completion-ignore-case t
-  "Non-nil means don't consider case significant in nick completion.
-Case will be automatically corrected when non-nil.
-For instance if you type \"dely TAB\" the word completes and changes to
-\"delYsid\"."
-  :type 'boolean)
-
-(defun erc-nick-completion-exclude-myself ()
-  "Get a list of all the channel members except you.
-
-This function returns a list of all the members in the channel, except
-your own nick.  This way if you're named foo and someone is called foobar,
-typing \"f o TAB\" will directly give you foobar.  Use this with
-`erc-nick-completion'."
-  (remove
-   (erc-current-nick)
-   (erc-get-channel-nickname-list)))
-
-(defcustom erc-nick-completion-postfix ": "
-  "When `erc-complete' is used in the first word after the prompt,
-add this string when a unique expansion was found."
-  :type 'string)
-
-(defun erc-command-list ()
-  "Return a list of strings of the defined user commands."
-  (let ((case-fold-search nil))
-    (mapcar (lambda (x)
-             (concat "/" (downcase (substring (symbol-name x) 8))))
-           (apropos-internal "erc-cmd-[A-Z]+"))))
-
-(defun erc-try-complete-nick (old)
-  "Complete nick at point.
-This is a function to put on `hippie-expand-try-functions-list'.
-Then use \\[hippie-expand] to expand nicks.
-The type of completion depends on `erc-nick-completion'."
-  (try-complete-erc-nick old (cond ((eq erc-nick-completion 'pals) erc-pals)
-                                  ((eq erc-nick-completion 'all)
-                                   (append
-                                    (erc-get-channel-nickname-list)
-                                    (erc-command-list)))
-                                  ((functionp erc-nick-completion)
-                                   (funcall erc-nick-completion))
-                                  (t erc-nick-completion))))
-
-(defvar try-complete-erc-nick-window-configuration nil
-  "The window configuration for `try-complete-erc-nick'.
-When called the first time, a window config is stored here,
-and when completion is done, the window config is restored
-from here.  See `try-complete-erc-nick-restore' and
-`try-complete-erc-nick'.")
-
-(defun try-complete-erc-nick-restore ()
-  "Restore window configuration."
-  (if (not try-complete-erc-nick-window-configuration)
-      (when (get-buffer "*Completions*")
-       (delete-windows-on "*Completions*"))
-    (set-window-configuration
-     try-complete-erc-nick-window-configuration)
-    (setq try-complete-erc-nick-window-configuration nil)))
-
-(defun try-complete-erc-nick (old completions)
-  "Try to complete current word depending on `erc-try-complete-nick'.
-The argument OLD has to be nil the first call of this function, and t
-for subsequent calls (for further possible completions of the same
-string).  It returns t if a new completion is found, nil otherwise.  The
-second argument COMPLETIONS is a list of completions to use.  Actually,
-it is only used when OLD is nil.  It will be copied to `he-expand-list'
-on the first call.  After that, it is no longer used.
-Window configurations are stored in
-`try-complete-erc-nick-window-configuration'."
-  (let (expansion
-       final
-       (alist (if (consp (car completions))
-                  completions
-                (mapcar (lambda (s)
-                          (if (and (erc-complete-at-prompt)
-                                   (and (not (= (length s) 0))
-                                        (not (eq (elt s 0) ?/))))
-                              (list (concat s erc-nick-completion-postfix))
-                            (list (concat s " "))))
-                        completions))) ; make alist if required
-       (completion-ignore-case erc-nick-completion-ignore-case))
-    (he-init-string (he-dabbrev-beg) (point))
-    ;; If there is a string to complete, complete it using alist.
-    ;; expansion is the possible expansion, or t.  If expansion is t
-    ;; or if expansion is the "real" thing, we are finished (final is
-    ;; t).  Take care -- expansion can also be nil!
-    (unless (string= he-search-string "")
-      (setq expansion (try-completion he-search-string alist)
-           final (or (eq t expansion)
-                     (and expansion
-                          (eq t (try-completion expansion alist))))))
-    (cond ((not expansion)
-          ;; There is no expansion at all.
-          (try-complete-erc-nick-restore)
-          (he-reset-string)
-          nil)
-         ((eq t expansion)
-          ;; The user already has the correct expansion.
-          (try-complete-erc-nick-restore)
-          (he-reset-string)
-          t)
-         ((and old (string= expansion he-search-string))
-          ;; This is the second time around and nothing changed,
-          ;; ie. the user tried to expand something incomplete
-          ;; without making a choice -- hitting TAB twice, for
-          ;; example.
-          (try-complete-erc-nick-restore)
-          (he-reset-string)
-          nil)
-         (final
-          ;; The user has found the correct expansion.
-          (try-complete-erc-nick-restore)
-          (he-substitute-string expansion)
-          t)
-         (t
-          ;; We found something but we are not finished.  Show a
-          ;; completions buffer.  Substitute what we found and return
-          ;; t.
-          (setq try-complete-erc-nick-window-configuration
-                (current-window-configuration))
-          (with-output-to-temp-buffer "*Completions*"
-            (display-completion-list (all-completions he-search-string alist)))
-          (he-substitute-string expansion)
-          t))))
-
-(defun erc-at-beginning-of-line-p (point &optional bol-func)
-  (save-excursion
-    (funcall (or bol-func
-                'erc-bol))
-    (equal point (point))))
-
-(defun erc-complete-at-prompt ()
-  "Return t if point is directly after `erc-prompt' when doing completion."
-  (erc-at-beginning-of-line-p (he-dabbrev-beg)))
-
-(provide 'erc-hecomplete)
-
-;;; erc-hecomplete.el ends here
-;;
-;; Local Variables:
-;; indent-tabs-mode: t
-;; tab-width: 8
-;; End:
diff --git a/lisp/obsolete/fast-lock.el b/lisp/obsolete/fast-lock.el
deleted file mode 100644
index 1614935f03..0000000000
--- a/lisp/obsolete/fast-lock.el
+++ /dev/null
@@ -1,730 +0,0 @@
-;;; fast-lock.el --- automagic text properties caching for fast Font Lock mode 
 -*- lexical-binding: t; -*-
-
-;; Copyright (C) 1994-1998, 2001-2022 Free Software Foundation, Inc.
-
-;; Author: Simon Marshall <simon@gnu.org>
-;; Maintainer: emacs-devel@gnu.org
-;; Keywords: faces files
-;; Version: 3.14
-;; Obsolete-since: 22.1
-
-;; 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:
-
-;; Fast Lock mode is a Font Lock support mode.
-;; It makes visiting a file in Font Lock mode faster by restoring its face text
-;; properties from automatically saved associated Font Lock cache files.
-;;
-;; See caveats and feedback below.
-;; See also the lazy-lock package.  (But don't use the two at the same time!)
-
-;; Installation:
-;;
-;; Put in your ~/.emacs:
-;;
-;; (setq font-lock-support-mode 'fast-lock-mode)
-;;
-;; Start up a new Emacs and use font-lock as usual (except that you can use the
-;; so-called "gaudier" fontification regexps on big files without frustration).
-;;
-;; When you visit a file (which has `font-lock-mode' enabled) that has a
-;; corresponding Font Lock cache file associated with it, the Font Lock cache
-;; will be loaded from that file instead of being generated by Font Lock code.
-
-;; Caveats:
-;;
-;; A cache will be saved when visiting a compressed file using crypt++, but not
-;; be read.  This is a "feature"/"consequence"/"bug" of crypt++.
-;;
-;; Version control packages are likely to stamp all over file modification
-;; times.  Therefore the act of checking out may invalidate a cache.
-
-;; History:
-;;
-;; 0.02--1.00:
-;; - Changed name from turbo-prop to fast-lock.  Automagic for font-lock only
-;; - Made `fast-lock-mode' a minor mode, like G. Dinesh Dutt's fss-mode
-;; 1.00--1.01:
-;; - Turn on `fast-lock-mode' only if `buffer-file-name' or `interactive-p'
-;; - Made `fast-lock-file-name' use `buffer-name' if `buffer-file-name' is nil
-;; - Moved save-all conditions to `fast-lock-save-cache'
-;; - Added `fast-lock-save-text-properties' to `kill-buffer-hook'
-;; 1.01--2.00: complete rewrite---not worth the space to document
-;; - Changed structure of text properties cache and threw out file mod checks
-;; 2.00--2.01:
-;; - Made `condition-case' forms understand `quit'.
-;; - Made `fast-lock' require `font-lock'
-;; - Made `fast-lock-cache-name' chase links (from Ben Liblit)
-;; 2.01--3.00:
-;; - Changed structure of cache to include `font-lock-keywords' (from rms)
-;; - Changed `fast-lock-cache-mechanisms' to `fast-lock-cache-directories'
-;; - Removed `fast-lock-read-others'
-;; - Made `fast-lock-read-cache' ignore cache owner
-;; - Made `fast-lock-save-cache-external' create cache directory
-;; - Made `fast-lock-save-cache-external' save `font-lock-keywords'
-;; - Made `fast-lock-cache-data' check `font-lock-keywords'
-;; 3.00--3.01: incorporated port of 2.00 to Lucid, made by Barry Warsaw
-;; - Package now provides itself
-;; - Lucid: Use `font-lock-any-extents-p' for `font-lock-any-properties-p'
-;; - Lucid: Use `list-faces' for `face-list'
-;; - Lucid: Added `set-text-properties'
-;; - Lucid: Made `turn-on-fast-lock' pass 1 not t to `fast-lock-mode'
-;; - Removed test for `fast-lock-mode' from `fast-lock-read-cache'
-;; - Lucid: Added Lucid-specific `fast-lock-get-face-properties'
-;; 3.01--3.02: now works with Lucid Emacs, thanks to Barry Warsaw
-;; - Made `fast-lock-cache-name' map ":" to ";" for OS/2 (from Serganova Vera)
-;; - Made `fast-lock-cache-name' use abbreviated file name (from Barry Warsaw)
-;; - Lucid: Separated handlers for `error' and `quit' for `condition-case'
-;; 3.02--3.03:
-;; - Changed `fast-lock-save-cache-external' to `fast-lock-save-cache-data'
-;; - Lucid: Added Lucid-specific `fast-lock-set-face-properties'
-;; 3.03--3.04:
-;; - Corrected `subrp' test of Lucid code
-;; - Replaced `font-lock-any-properties-p' with `text-property-not-all'
-;; - Lucid: Made `fast-lock-set-face-properties' put `text-prop' on extents
-;; - Made `fast-lock-cache-directories' a regexp alist (from Colin Rafferty)
-;; - Made `fast-lock-cache-directory' to return a usable cache file directory
-;; 3.04--3.05:
-;; - Lucid: Fix for XEmacs 19.11 `text-property-not-all'
-;; - Replaced `subrp' test of Lucid code with `emacs-version' `string-match'
-;; - Made `byte-compile-warnings' omit `unresolved' on compilation
-;; - Made `fast-lock-save-cache-data' use a buffer (from Rick Sladkey)
-;; - Reverted to old `fast-lock-get-face-properties' (from Rick Sladkey)
-;; 3.05--3.06: incorporated hack of 3.03, made by Jonathan Stigelman (Stig)
-;; - Reverted to 3.04 version of `fast-lock-get-face-properties'
-;; - XEmacs: Removed `list-faces' `defalias'
-;; - Made `fast-lock-mode' and `turn-on-fast-lock' succeed `autoload' cookies
-;; - Added `fast-lock-submit-bug-report'
-;; - Renamed `fast-lock-save-size' to `fast-lock-minimum-size'
-;; - Made `fast-lock-save-cache' output a message if no save ever attempted
-;; - Made `fast-lock-save-cache-data' output a message if save attempted
-;; - Made `fast-lock-cache-data' output a message if load attempted
-;; - Made `fast-lock-save-cache-data' do `condition-case' not `unwind-protect'
-;; - Made `fast-lock-save-cache' and `fast-lock-read-cache' return nothing
-;; - Made `fast-lock-save-cache' check `buffer-modified-p' (Stig)
-;; - Added `fast-lock-save-events'
-;; - Added `fast-lock-after-save-hook' to `after-save-hook' (Stig)
-;; - Added `fast-lock-kill-buffer-hook' to `kill-buffer-hook'
-;; - Changed `fast-lock-save-caches' to `fast-lock-kill-emacs-hook'
-;; - Added `fast-lock-kill-emacs-hook' to `kill-emacs-hook'
-;; - Made `fast-lock-save-cache' check `verify-visited-file-modtime' (Stig)
-;; - Made `visited-file-modtime' be the basis of the timestamp (Stig)
-;; - Made `fast-lock-save-cache-1' and `fast-lock-cache-data' use/reformat it
-;; - Added `fast-lock-cache-filename' to keep track of the cache file name
-;; - Added `fast-lock-after-fontify-buffer'
-;; - Added `fast-lock-save-faces' list of faces to save (idea from Stig/Tibor)
-;; - Made `fast-lock-get-face-properties' functions use it
-;; - XEmacs: Made `fast-lock-set-face-properties' do extents the Font Lock way
-;; - XEmacs: Removed fix for `text-property-not-all' (19.11 support dropped)
-;; - Made `fast-lock-mode' ensure `font-lock-mode' is on
-;; - Made `fast-lock-save-cache' do `cdr-safe' not `cdr' (from Dave Foster)
-;; - Made `fast-lock-save-cache' do `set-buffer' first (from Dave Foster)
-;; - Made `fast-lock-save-cache' loop until saved or quit (from Georg Nikodym)
-;; - Made `fast-lock-cache-data' check `buffer-modified-p'
-;; - Made `fast-lock-cache-data' do `font-lock-compile-keywords' if necessary
-;; - XEmacs: Made `font-lock-compile-keywords' `defalias'
-;; 3.06--3.07:
-;; - XEmacs: Add `fast-lock-after-fontify-buffer' to the Font Lock hook
-;; - Made `fast-lock-cache-name' explain the use of `directory-abbrev-alist'
-;; - Made `fast-lock-mode' use `buffer-file-truename' not `buffer-file-name'
-;; 3.07--3.08:
-;; - Made `fast-lock-read-cache' set `fast-lock-cache-filename'
-;; 3.08--3.09:
-;; - Made `fast-lock-save-cache' cope if `fast-lock-minimum-size' is a list
-;; - Made `fast-lock-mode' respect the value of `font-lock-inhibit-thing-lock'
-;; - Added `fast-lock-after-unfontify-buffer'
-;; 3.09--3.10:
-;; - Rewrite for Common Lisp macros
-;; - Made fast-lock.el barf on a crap 8+3 pseudo-OS (Eli Zaretskii help)
-;; - XEmacs: Made `add-minor-mode' succeed `autoload' cookie
-;; - XEmacs: Made `fast-lock-save-faces' default to `font-lock-face-list'
-;; - Made `fast-lock-save-cache' use `font-lock-value-in-major-mode'
-;; - Wrap with `save-buffer-state' (Ray Van Tassle report)
-;; - Made `fast-lock-mode' wrap `font-lock-support-mode'
-;; 3.10--3.11:
-;; - Made `fast-lock-get-face-properties' cope with face lists
-;; - Added `fast-lock-verbose'
-;; - XEmacs: Add `font-lock-value-in-major-mode' if necessary
-;; - Removed `fast-lock-submit-bug-report' and bade farewell
-;; 3.11--3.12:
-;; - Added Custom support (Hrvoje Nikšić help)
-;; - Made `save-buffer-state' wrap `inhibit-point-motion-hooks'
-;; - Made `fast-lock-cache-data' simplify calls of `font-lock-compile-keywords'
-;; 3.12--3.13:
-;; - Removed `byte-*' variables from `eval-when-compile' (Erik Naggum hint)
-;; - Changed structure of cache to include `font-lock-syntactic-keywords'
-;; - Made `fast-lock-save-cache-1' save syntactic fontification data
-;; - Made `fast-lock-cache-data' take syntactic fontification data
-;; - Added `fast-lock-get-syntactic-properties'
-;; - Renamed `fast-lock-set-face-properties' to `fast-lock-add-properties'
-;; - Made `fast-lock-add-properties' add syntactic and face fontification data
-;; 3.13--3.14:
-;; - Made `fast-lock-cache-name' cope with `windowsnt' (Geoff Voelker fix)
-;; - Made `fast-lock-verbose' use `other' widget (Andreas Schwab fix)
-;; - Used `with-temp-message' where possible to make messages temporary.
-
-;;; Code:
-
-(require 'font-lock)
-
-(declare-function msdos-long-file-names "msdos.c")
-
-;; Make sure fast-lock.el is supported.
-(if (and (eq system-type 'ms-dos) (not (msdos-long-file-names)))
-    (error "`fast-lock' was written for long file name systems"))
-
-(defvar font-lock-face-list)
-
-(eval-when-compile
- ;;
- ;; We use this to verify that a face should be saved.
- (defmacro fast-lock-save-facep (face)
-   "Return non-nil if FACE is one of `fast-lock-save-faces'."
-   `(or (null fast-lock-save-faces)
-     (if (symbolp ,face)
-         (memq ,face fast-lock-save-faces)
-         (let ((faces ,face))
-           (while (unless (memq (car faces) fast-lock-save-faces)
-                    (setq faces (cdr faces))))
-           faces)))))
-
-(defgroup fast-lock nil
-  "Font Lock support mode to cache fontification."
-  :load 'fast-lock
-  :group 'font-lock)
-
-(defvar fast-lock-mode nil)            ; Whether we are turned on.
-(defvar fast-lock-cache-timestamp nil) ; For saving/reading.
-(defvar fast-lock-cache-filename nil)  ; For deleting.
-
-;; User Variables:
-
-(defcustom fast-lock-minimum-size 25600
-  "Minimum size of a buffer for cached fontification.
-Only buffers more than this can have associated Font Lock cache files saved.
-If nil, means cache files are never created.
-If a list, each element should be a cons pair of the form (MAJOR-MODE . SIZE),
-where MAJOR-MODE is a symbol or t (meaning the default).  For example:
- ((c-mode . 25600) (c++-mode . 25600) (rmail-mode . 1048576))
-means that the minimum size is 25K for buffers in C or C++ modes, one megabyte
-for buffers in Rmail mode, and size is irrelevant otherwise."
-  :type '(choice (const :tag "none" nil)
-                (integer :tag "size")
-                (repeat :menu-tag "mode specific" :tag "mode specific"
-                        :value ((t . nil))
-                        (cons :tag "Instance"
-                              (radio :tag "Mode"
-                                     (const :tag "all" t)
-                                     (symbol :tag "name"))
-                              (radio :tag "Size"
-                                     (const :tag "none" nil)
-                                     (integer :tag "size"))))))
-
-(defcustom fast-lock-cache-directories '("~/.emacs-flc")
-; - `internal', keep each file's Font Lock cache file in the same file.
-; - `external', keep each file's Font Lock cache file in the same directory.
-  "Directories in which Font Lock cache files are saved and read.
-Each item should be either DIR or a cons pair of the form (REGEXP . DIR) where
-DIR is a directory name (relative or absolute) and REGEXP is a regexp.
-
-An attempt will be made to save or read Font Lock cache files using these items
-until one succeeds (i.e., until a readable or writable one is found).  If an
-item contains REGEXP, DIR is used only if the buffer file name matches REGEXP.
-For example:
-
- (let ((home (expand-file-name (abbreviate-file-name (file-truename \"~/\")))))
-   (list (cons (concat \"^\" (regexp-quote home)) \".\") \"~/.emacs-flc\"))
-    =>
- ((\"^/your/true/home/directory/\" . \".\") \"~/.emacs-flc\")
-
-would cause a file's current directory to be used if the file is under your
-home directory hierarchy, or otherwise the absolute directory `~/.emacs-flc'.
-For security reasons, it is not advisable to use the file's current directory
-to avoid the possibility of using the cache of another user."
-  :type '(repeat (radio (directory :tag "directory")
-                       (cons :tag "Matching"
-                             (regexp :tag "regexp")
-                             (directory :tag "directory")))))
-(put 'fast-lock-cache-directories 'risky-local-variable t)
-
-(defcustom fast-lock-save-events '(kill-buffer kill-emacs)
-  "Events under which caches will be saved.
-Valid events are `save-buffer', `kill-buffer' and `kill-emacs'.
-If concurrent editing sessions use the same associated cache file for a file's
-buffer, then you should add `save-buffer' to this list."
-  :type '(set (const :tag "buffer saving" save-buffer)
-             (const :tag "buffer killing" kill-buffer)
-             (const :tag "emacs killing" kill-emacs)))
-
-(defcustom fast-lock-save-others t
-  "If non-nil, save Font Lock cache files irrespective of file owner.
-If nil, means only buffer files known to be owned by you can have associated
-Font Lock cache files saved.  Ownership may be unknown for networked files."
-  :type 'boolean)
-
-(defcustom fast-lock-verbose font-lock-verbose
-  "If non-nil, means show status messages for cache processing.
-If a number, only buffers greater than this size have processing messages."
-  :type '(choice (const :tag "never" nil)
-                (other :tag "always" t)
-                (integer :tag "size")))
-
-(defvar fast-lock-save-faces nil
-  "Faces that will be saved in a Font Lock cache file.
-If nil, means information for all faces will be saved.")
-
-;; User Functions:
-
-;;;###autoload
-(defun fast-lock-mode (&optional arg)
-  "Toggle Fast Lock mode.
-With arg, turn Fast Lock mode on if and only if arg is positive and the buffer
-is associated with a file.  Enable it automatically in your `~/.emacs' by:
-
- (setq font-lock-support-mode \\='fast-lock-mode)
-
-If Fast Lock mode is enabled, and the current buffer does not contain any text
-properties, any associated Font Lock cache is used if its timestamp matches the
-buffer's file, and its `font-lock-keywords' match those that you are using.
-
-Font Lock caches may be saved:
-- When you save the file's buffer.
-- When you kill an unmodified file's buffer.
-- When you exit Emacs, for all unmodified or saved buffers.
-Depending on the value of `fast-lock-save-events'.
-See also the commands `fast-lock-read-cache' and `fast-lock-save-cache'.
-
-Use \\[font-lock-fontify-buffer] to fontify the buffer if the cache is bad.
-
-Various methods of control are provided for the Font Lock cache.  In general,
-see variable `fast-lock-cache-directories' and function `fast-lock-cache-name'.
-For saving, see variables `fast-lock-minimum-size', `fast-lock-save-events',
-`fast-lock-save-others' and `fast-lock-save-faces'."
-  (interactive "P")
-  ;; Only turn on if we are visiting a file.  We could use `buffer-file-name',
-  ;; but many packages temporarily wrap that to nil when doing their own thing.
-  (set (make-local-variable 'fast-lock-mode)
-       (and buffer-file-truename
-           (not (memq 'fast-lock-mode font-lock-inhibit-thing-lock))
-           (if arg (> (prefix-numeric-value arg) 0) (not fast-lock-mode))))
-  (if (and fast-lock-mode (not font-lock-mode))
-      ;; Turned on `fast-lock-mode' rather than `font-lock-mode'.
-      (progn
-        (message "Use font-lock-support-mode rather than calling 
fast-lock-mode")
-        (sit-for 2))
-    ;; Let's get down to business.
-    (set (make-local-variable 'fast-lock-cache-timestamp) nil)
-    (set (make-local-variable 'fast-lock-cache-filename) nil)
-    (when (and fast-lock-mode (not font-lock-fontified))
-      (fast-lock-read-cache))))
-
-(defun fast-lock-read-cache ()
-  "Read the Font Lock cache for the current buffer.
-
-The following criteria must be met for a Font Lock cache file to be read:
-- Fast Lock mode must be turned on in the buffer.
-- The buffer must not be modified.
-- The buffer's `font-lock-keywords' must match the cache's.
-- The buffer file's timestamp must match the cache's.
-- Criteria imposed by `fast-lock-cache-directories'.
-
-See `fast-lock-mode'."
-  (interactive)
-  (let ((directories fast-lock-cache-directories)
-       (modified (buffer-modified-p)) (inhibit-read-only t)
-       (fontified font-lock-fontified))
-    (set (make-local-variable 'font-lock-fontified) nil)
-    ;; Keep trying directories until fontification is turned off.
-    (while (and directories (not font-lock-fontified))
-      (let ((directory (fast-lock-cache-directory (car directories) nil)))
-       (condition-case nil
-           (when directory
-             (setq fast-lock-cache-filename (fast-lock-cache-name directory))
-             (when (file-readable-p fast-lock-cache-filename)
-               (load fast-lock-cache-filename t t t)))
-         (error nil) (quit nil))
-       (setq directories (cdr directories))))
-    ;; Unset `fast-lock-cache-filename', and restore `font-lock-fontified', if
-    ;; we don't use a cache.  (Note that `fast-lock-cache-data' sets the value
-    ;; of `fast-lock-cache-timestamp'.)
-    (set-buffer-modified-p modified)
-    (unless font-lock-fontified
-      (setq fast-lock-cache-filename nil font-lock-fontified fontified))))
-
-(defun fast-lock-save-cache (&optional buffer)
-  "Save the Font Lock cache of BUFFER or the current buffer.
-
-The following criteria must be met for a Font Lock cache file to be saved:
-- Fast Lock mode must be turned on in the buffer.
-- The event must be one of `fast-lock-save-events'.
-- The buffer must be at least `fast-lock-minimum-size' bytes long.
-- The buffer file must be owned by you, or `fast-lock-save-others' must be t.
-- The buffer must contain at least one `face' text property.
-- The buffer must not be modified.
-- The buffer file's timestamp must be the same as the file's on disk.
-- The on disk file's timestamp must be different than the buffer's cache.
-- Criteria imposed by `fast-lock-cache-directories'.
-
-See `fast-lock-mode'."
-  (interactive)
-  (save-excursion
-    (when buffer
-      (set-buffer buffer))
-    (let ((min-size (font-lock-value-in-major-mode fast-lock-minimum-size))
-         (file-timestamp (visited-file-modtime)) (saved nil))
-      (when (and fast-lock-mode
-            ;;
-            ;; "Only save if the buffer matches the file, the file has
-            ;; changed, and it was changed by the current emacs session."
-            ;;
-            ;; Only save if the buffer is not modified,
-            ;; (i.e., so we don't save for something not on disk)
-            (not (buffer-modified-p))
-            ;; and the file's timestamp is the same as the buffer's,
-            ;; (i.e., someone else hasn't written the file in the meantime)
-            (verify-visited-file-modtime (current-buffer))
-            ;; and the file's timestamp is different from the cache's.
-            ;; (i.e., a save has occurred since the cache was read)
-            (not (equal fast-lock-cache-timestamp file-timestamp))
-            ;;
-            ;; Only save if user's restrictions are satisfied.
-            (and min-size (>= (buffer-size) min-size))
-            (or fast-lock-save-others
-                (eq (user-uid) (file-attribute-user-id
-                                (file-attributes buffer-file-name))))
-            ;;
-            ;; Only save if there are `face' properties to save.
-            (text-property-not-all (point-min) (point-max) 'face nil))
-       ;;
-       ;; Try each directory until we manage to save or the user quits.
-       (let ((directories fast-lock-cache-directories))
-         (while (and directories (memq saved '(nil error)))
-           (let* ((dir (fast-lock-cache-directory (car directories) t))
-                  (file (and dir (fast-lock-cache-name dir))))
-             (when (and file (file-writable-p file))
-               (setq saved (fast-lock-save-cache-1 file file-timestamp)))
-             (setq directories (cdr directories)))))))))
-
-;;;###autoload
-(defun turn-on-fast-lock ()
-  "Unconditionally turn on Fast Lock mode."
-  (fast-lock-mode t))
-
-;;; API Functions:
-
-(defun fast-lock-after-fontify-buffer ()
-  ;; Delete the Font Lock cache file used to restore fontification, if any.
-  (when fast-lock-cache-filename
-    (if (file-writable-p fast-lock-cache-filename)
-       (delete-file fast-lock-cache-filename)
-      (message "File %s font lock cache cannot be deleted" (buffer-name))))
-  ;; Flag so that a cache will be saved later even if the file is never saved.
-  (setq fast-lock-cache-timestamp nil))
-
-(defalias 'fast-lock-after-unfontify-buffer #'ignore)
-
-;; Miscellaneous Functions:
-
-(defun fast-lock-save-cache-after-save-file ()
-  ;; Do `fast-lock-save-cache' if `save-buffer' is on `fast-lock-save-events'.
-  (when (memq 'save-buffer fast-lock-save-events)
-    (fast-lock-save-cache)))
-
-(defun fast-lock-save-cache-before-kill-buffer ()
-  ;; Do `fast-lock-save-cache' if `kill-buffer' is on `fast-lock-save-events'.
-  (when (memq 'kill-buffer fast-lock-save-events)
-    (fast-lock-save-cache)))
-
-(defun fast-lock-save-caches-before-kill-emacs ()
-  ;; Do `fast-lock-save-cache's if `kill-emacs' is on `fast-lock-save-events'.
-  (when (memq 'kill-emacs fast-lock-save-events)
-    (mapcar #'fast-lock-save-cache (buffer-list))))
-
-(defun fast-lock-cache-directory (directory create)
-  "Return usable directory based on DIRECTORY.
-Returns nil if the directory does not exist, or, if CREATE non-nil, cannot be
-created.  DIRECTORY may be a string or a cons pair of the form (REGEXP . DIR).
-See `fast-lock-cache-directories'."
-  (let ((dir
-        (cond ((not buffer-file-name)
-               ;; Should never be nil, but `crypt++' screws it up.
-               nil)
-              ((stringp directory)
-               ;; Just a directory.
-               directory)
-              (t
-               ;; A directory if the file name matches the regexp.
-               (let ((bufile (expand-file-name buffer-file-truename))
-                     (case-fold-search nil))
-                 (when (save-match-data (string-match (car directory) bufile))
-                   (cdr directory)))))))
-    (cond ((not dir)
-          nil)
-         ((file-accessible-directory-p dir)
-          dir)
-         (create
-          (condition-case nil
-              (progn (make-directory dir t) dir)
-            (error nil))))))
-
-;; If you are wondering why we only hash if the directory is not ".", rather
-;; than if `file-name-absolute-p', it is because if we just appended ".flc" for
-;; relative cache directories (that are not ".") then it is possible that more
-;; than one file would have the same cache name in that directory, if the luser
-;; made a link from one relative cache directory to another.  (Phew!)
-(defun fast-lock-cache-name (directory)
-  "Return full cache file name using caching DIRECTORY.
-If DIRECTORY is `.', the file name is the buffer file name appended with 
`.flc'.
-Otherwise, the file name is constructed from DIRECTORY and the buffer's true
-abbreviated file name, with all `/' characters in the name replaced with `#'
-characters, and appended with `.flc'.
-
-If the same file has different cache file names when edited on different
-machines, e.g., on one machine the cache file name has the prefix `#home',
-perhaps due to automount, try putting in your `~/.emacs' something like:
-
- (setq directory-abbrev-alist (cons \\='(\"^/home/\" . \"/\") 
directory-abbrev-alist))
-
-Emacs automagically removes the common `/tmp_mnt' automount prefix by default.
-
-See `fast-lock-cache-directory'."
-  (if (string-equal directory ".")
-      (concat buffer-file-name ".flc")
-    (let* ((bufile (expand-file-name buffer-file-truename))
-          (chars-alist
-           (if (memq system-type '(windows-nt cygwin))
-               '((?/ . (?#)) (?# . (?# ?#)) (?: . (?\;)) (?\; . (?\; ?\;)))
-             '((?/ . (?#)) (?# . (?# ?#)))))
-          (mapchars
-           (function (lambda (c) (or (cdr (assq c chars-alist)) (list c))))))
-      (concat
-       (file-name-as-directory (expand-file-name directory))
-       (mapconcat #'char-to-string (apply #'append (mapcar mapchars bufile)) 
"")
-       ".flc"))))
-
-;; Font Lock Cache Processing Functions:
-
-;; The version 3 format of the cache is:
-;;
-;; (fast-lock-cache-data VERSION TIMESTAMP
-;;  font-lock-syntactic-keywords SYNTACTIC-PROPERTIES
-;;  font-lock-keywords FACE-PROPERTIES)
-
-(defun fast-lock-save-cache-1 (file timestamp)
-  ;; Save the FILE with the TIMESTAMP plus fontification data.
-  ;; Returns non-nil if a save was attempted to a writable cache file.
-  (let ((tpbuf (generate-new-buffer " *fast-lock*"))
-       (verbose (if (numberp fast-lock-verbose)
-                    (> (buffer-size) fast-lock-verbose)
-                  fast-lock-verbose))
-       (saved t))
-    (with-temp-message
-       (when verbose
-         (format "Saving %s font lock cache..." (buffer-name)))
-      (condition-case nil
-         (save-excursion
-           (print (list 'fast-lock-cache-data 3
-                        (list 'quote timestamp)
-                        (list 'quote font-lock-syntactic-keywords)
-                        (list 'quote (fast-lock-get-syntactic-properties))
-                        (list 'quote font-lock-keywords)
-                        (list 'quote (fast-lock-get-face-properties)))
-                  tpbuf)
-           (set-buffer tpbuf)
-           (write-region (point-min) (point-max) file nil 'quietly)
-           (setq fast-lock-cache-timestamp timestamp
-                 fast-lock-cache-filename file))
-       (error (setq saved 'error)) (quit (setq saved 'quit)))
-      (kill-buffer tpbuf))
-    (cond ((eq saved 'quit)
-          (message "Saving %s font lock cache...quit" (buffer-name)))
-         ((eq saved 'error)
-          (message "Saving %s font lock cache...failed" (buffer-name))))
-    ;; We return non-nil regardless of whether a failure occurred.
-    saved))
-
-(defun fast-lock-cache-data (version timestamp
-                            syntactic-keywords syntactic-properties
-                            keywords face-properties
-                            &rest _ignored)
-  ;; Find value of syntactic keywords in case it is a symbol.
-  (setq font-lock-syntactic-keywords (font-lock-eval-keywords
-                                     font-lock-syntactic-keywords))
-  ;; Compile all keywords in case some are and some aren't.
-  (when font-lock-syntactic-keywords
-    (setq font-lock-syntactic-keywords (font-lock-compile-keywords
-                                       font-lock-syntactic-keywords t)))
-  (when syntactic-keywords
-    (setq syntactic-keywords (font-lock-compile-keywords syntactic-keywords 
t)))
-  (setq font-lock-keywords (font-lock-compile-keywords font-lock-keywords)
-       keywords (font-lock-compile-keywords keywords))
-  ;; Use the Font Lock cache SYNTACTIC-PROPERTIES and FACE-PROPERTIES if we're
-  ;; using cache VERSION format 3, the current buffer's file timestamp matches
-  ;; the TIMESTAMP, the current buffer's `font-lock-syntactic-keywords' are the
-  ;; same as SYNTACTIC-KEYWORDS, and the current buffer's `font-lock-keywords'
-  ;; are the same as KEYWORDS.
-  (let ((buf-timestamp (visited-file-modtime))
-       (verbose (if (numberp fast-lock-verbose)
-                    (> (buffer-size) fast-lock-verbose)
-                  fast-lock-verbose))
-       (loaded t))
-    (if (or (/= version 3)
-           (buffer-modified-p)
-           (not (equal timestamp buf-timestamp))
-           (not (equal syntactic-keywords font-lock-syntactic-keywords))
-           (not (equal keywords font-lock-keywords)))
-       (setq loaded nil)
-      (with-temp-message
-         (when verbose
-           (format "Loading %s font lock cache..." (buffer-name)))
-       (condition-case nil
-           (fast-lock-add-properties syntactic-properties face-properties)
-         (error (setq loaded 'error)) (quit (setq loaded 'quit))))
-      (cond ((eq loaded 'quit)
-            (message "Loading %s font lock cache...quit" (buffer-name)))
-           ((eq loaded 'error)
-            (message "Loading %s font lock cache...failed" (buffer-name)))))
-    (setq font-lock-fontified (eq loaded t)
-         fast-lock-cache-timestamp (and (eq loaded t) timestamp))))
-
-;; Text Properties Processing Functions:
-
-;; This is fast, but fails if adjacent characters have different `face' text
-;; properties.  Maybe that's why I dropped it in the first place?
-;(defun fast-lock-get-face-properties ()
-;  "Return a list of `face' text properties in the current buffer.
-;Each element of the list is of the form (VALUE START1 END1 START2 END2 ...)
-;where VALUE is a `face' property value and STARTx and ENDx are positions."
-;  (save-restriction
-;    (widen)
-;    (let ((start (text-property-not-all (point-min) (point-max) 'face nil))
-;        (limit (point-max)) end properties value cell)
-;      (while start
-;      (setq end (next-single-property-change start 'face nil limit)
-;            value (get-text-property start 'face))
-;      ;; Make, or add to existing, list of regions with same `face'.
-;      (if (setq cell (assq value properties))
-;          (setcdr cell (cons start (cons end (cdr cell))))
-;        (setq properties (cons (list value start end) properties)))
-;      (setq start (next-single-property-change end 'face)))
-;      properties)))
-
-;; This is slow, but copes if adjacent characters have different `face' text
-;; properties, but fails if they are lists.
-;(defun fast-lock-get-face-properties ()
-;  "Return a list of `face' text properties in the current buffer.
-;Each element of the list is of the form (VALUE START1 END1 START2 END2 ...)
-;where VALUE is a `face' property value and STARTx and ENDx are positions.
-;Only those `face' VALUEs in `fast-lock-save-faces' are returned."
-;  (save-restriction
-;    (widen)
-;    (let ((faces (or fast-lock-save-faces (face-list))) (limit (point-max))
-;        properties regions face start end)
-;      (while faces
-;      (setq face (car faces) faces (cdr faces) regions () end (point-min))
-;      ;; Make a list of start/end regions with `face' property face.
-;      (while (setq start (text-property-any end limit 'face face))
-;        (setq end (or (text-property-not-all start limit 'face face) limit)
-;              regions (cons start (cons end regions))))
-;      ;; Add `face' face's regions, if any, to properties.
-;      (when regions
-;        (push (cons face regions) properties)))
-;      properties)))
-
-(defun fast-lock-get-face-properties ()
-  "Return a list of `face' text properties in the current buffer.
-Each element of the list is of the form (VALUE START1 END1 START2 END2 ...)
-where VALUE is a `face' property value and STARTx and ENDx are positions."
-  (save-restriction
-    (widen)
-    (let ((start (text-property-not-all (point-min) (point-max) 'face nil))
-         end properties value cell)
-      (while start
-       (setq end (next-single-property-change start 'face nil (point-max))
-             value (get-text-property start 'face))
-       ;; Make, or add to existing, list of regions with same `face'.
-       (cond ((setq cell (assoc value properties))
-              (setcdr cell (cons start (cons end (cdr cell)))))
-             ((fast-lock-save-facep value)
-              (push (list value start end) properties)))
-       (setq start (text-property-not-all end (point-max) 'face nil)))
-      properties)))
-
-(defun fast-lock-get-syntactic-properties ()
-  "Return a list of `syntax-table' text properties in the current buffer.
-See `fast-lock-get-face-properties'."
-  (save-restriction
-    (widen)
-    (let ((start (text-property-not-all (point-min) (point-max) 'syntax-table
-                                       nil))
-         end properties value cell)
-      (while start
-       (setq end (next-single-property-change start 'syntax-table nil
-                                              (point-max))
-             value (get-text-property start 'syntax-table))
-       ;; Make, or add to existing, list of regions with same `syntax-table'.
-       (if (setq cell (assoc value properties))
-           (setcdr cell (cons start (cons end (cdr cell))))
-         (push (list value start end) properties))
-       (setq start (text-property-not-all end (point-max) 'syntax-table nil)))
-      properties)))
-
-(defun fast-lock-add-properties (syntactic-properties face-properties)
-  "Add `syntax-table' and `face' text properties to the current buffer.
-Any existing `syntax-table' and `face' text properties are removed first.
-See `fast-lock-get-face-properties'."
-  (with-silent-modifications
-    (let ((inhibit-point-motion-hooks t))
-      (save-restriction
-        (widen)
-        (font-lock-unfontify-region (point-min) (point-max))
-        ;;
-        ;; Set the `syntax-table' property for each start/end region.
-        (pcase-dolist (`(,plist . ,regions) syntactic-properties)
-         (while regions
-           (add-text-properties (nth 0 regions) (nth 1 regions) plist)
-           (setq regions (nthcdr 2 regions))))
-       ;;
-       ;; Set the `face' property for each start/end region.
-        (pcase-dolist (`(,plist . ,regions) face-properties)
-         (while regions
-           (add-text-properties (nth 0 regions) (nth 1 regions) plist)
-           (setq regions (nthcdr 2 regions))))))))
-
-
-;; Install ourselves:
-
-(add-hook 'after-save-hook #'fast-lock-save-cache-after-save-file)
-(add-hook 'kill-buffer-hook #'fast-lock-save-cache-before-kill-buffer)
-(unless noninteractive
-  (add-hook 'kill-emacs-hook #'fast-lock-save-caches-before-kill-emacs))
-
-;;;###autoload
-(when (fboundp 'add-minor-mode)
-  (defvar fast-lock-mode nil)
-  (add-minor-mode 'fast-lock-mode nil))
-;;;###dont-autoload
-(unless (assq 'fast-lock-mode minor-mode-alist)
-  (setq minor-mode-alist (append minor-mode-alist '((fast-lock-mode nil)))))
-
-(provide 'fast-lock)
-
-;;; fast-lock.el ends here
-
-;; Local Variables:
-;; byte-compile-warnings: (not obsolete)
-;; End:
diff --git a/lisp/obsolete/gs.el b/lisp/obsolete/gs.el
index 7bf324ceec..d5a8713129 100644
--- a/lisp/obsolete/gs.el
+++ b/lisp/obsolete/gs.el
@@ -144,7 +144,7 @@ image in pixels."
 
 (defun gs-set-ghostview-colors-window-prop (frame pixel-colors)
   "Set the `GHOSTVIEW_COLORS' environment variable depending on FRAME."
-  (let ((mode (cond ((x-display-color-p frame) "Color")
+  (let ((mode (cond ((display-color-p frame) "Color")
                    ((x-display-grayscale-p frame) "Grayscale")
                    (t "Monochrome"))))
     (x-change-window-property "GHOSTVIEW_COLORS"
diff --git a/lisp/obsolete/info-edit.el b/lisp/obsolete/info-edit.el
index 6c1be1078f..b9cb83ed97 100644
--- a/lisp/obsolete/info-edit.el
+++ b/lisp/obsolete/info-edit.el
@@ -33,7 +33,6 @@
 (make-obsolete-variable 'Info-edit-mode-hook
                        "editing Info nodes by hand is not recommended." "24.4")
 
-(define-obsolete-variable-alias 'Info-edit-map 'Info-edit-mode-map "24.1")
 (defvar Info-edit-mode-map (let ((map (make-sparse-keymap)))
                              (set-keymap-parent map text-mode-map)
                              (define-key map "\C-c\C-c" #'Info-cease-edit)
@@ -78,11 +77,12 @@ This feature will be removed in future.")
        (buffer-modified-p)
        (message "Tags may have changed.  Use Info-tagify if necessary")))
 
-(defvar ibuffer-help-buffer-modes)
-;; Moved here from definition of ibuffer-help-buffer-modes to make
-;; that variable customizable even though this code is obsolete.  See
-;; also Bug#30990.
-(add-to-list 'ibuffer-help-buffer-modes 'Info-edit-mode)
+(with-eval-after-load 'ibuffer
+  (defvar ibuffer-help-buffer-modes)
+  ;; Moved here from definition of ibuffer-help-buffer-modes to make
+  ;; that variable customizable even though this code is obsolete.  See
+  ;; also Bug#30990.
+  (add-to-list 'ibuffer-help-buffer-modes 'Info-edit-mode))
 
 (provide 'info-edit)
 
diff --git a/lisp/obsolete/lazy-lock.el b/lisp/obsolete/lazy-lock.el
deleted file mode 100644
index 5c35cb3212..0000000000
--- a/lisp/obsolete/lazy-lock.el
+++ /dev/null
@@ -1,1025 +0,0 @@
-;;; lazy-lock.el --- lazy demand-driven fontification for fast Font Lock mode  
-*- lexical-binding: t; -*-
-
-;; Copyright (C) 1994-1998, 2001-2022 Free Software Foundation, Inc.
-
-;; Author: Simon Marshall <simon@gnu.org>
-;; Maintainer: emacs-devel@gnu.org
-;; Keywords: faces files
-;; Version: 2.11
-;; Obsolete-since: 22.1
-
-;; 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:
-
-;; Purpose:
-;;
-;; Lazy Lock mode is a Font Lock support mode.
-;; It makes visiting buffers in Font Lock mode faster by making fontification
-;; be demand-driven, deferred and stealthy, so that fontification only occurs
-;; when, and where, necessary.
-;;
-;; See caveats and feedback below.
-;; See also the fast-lock package.  (But don't use them at the same time!)
-
-;; Installation:
-;;
-;; Put in your ~/.emacs:
-;;
-;; (setq font-lock-support-mode 'lazy-lock-mode)
-;;
-;; Start up a new Emacs and use font-lock as usual (except that you can use the
-;; so-called "gaudier" fontification regexps on big files without frustration).
-;;
-;; In a buffer (which has `font-lock-mode' enabled) which is at least
-;; `lazy-lock-minimum-size' characters long, buffer fontification will not
-;; occur and only the visible portion of the buffer will be fontified.  Motion
-;; around the buffer will fontify those visible portions not previously
-;; fontified.  If stealth fontification is enabled, buffer fontification will
-;; occur in invisible parts of the buffer after `lazy-lock-stealth-time'
-;; seconds of idle time.  If on-the-fly fontification is deferred, on-the-fly
-;; fontification will occur after `lazy-lock-defer-time' seconds of idle time.
-
-;; User-visible differences with version 1:
-;;
-;; - Version 2 can defer on-the-fly fontification.  Therefore you need not, and
-;; should not, use defer-lock.el with this version of lazy-lock.el.
-;;
-;; A number of variables have changed meaning:
-;;
-;; - A value of nil for the variable `lazy-lock-minimum-size' means never turn
-;; on demand-driven fontification.  In version 1 this meant always turn on
-;; demand-driven fontification.  If you really want demand-driven fontification
-;; regardless of buffer size, set this variable to 0.
-;;
-;; - The variable `lazy-lock-stealth-lines' cannot have a nil value.  In
-;; version 1 this meant use `window-height' as the maximum number of lines to
-;; fontify as a stealth chunk.  This makes no sense; stealth fontification is
-;; of a buffer, not a window.
-
-;; Implementation differences with version 1:
-;;
-;; - Version 1 of lazy-lock.el is a bit of a hack.  Version 1 demand-driven
-;; fontification, the core feature of lazy-lock.el, is implemented by placing a
-;; function on `post-command-hook'.  This function fontifies where necessary,
-;; i.e., where a window scroll has occurred.  However, there are a number of
-;; problems with using `post-command-hook':
-;;
-;; (a) As the name suggests, `post-command-hook' is run after every command,
-;;     i.e., frequently and regardless of whether scrolling has occurred.
-;; (b) Scrolling can occur during a command, when `post-command-hook' is not
-;;     run, i.e., it is not necessarily run after scrolling has occurred.
-;; (c) When `post-command-hook' is run, there is nothing to suggest where
-;;     scrolling might have occurred, i.e., which windows have scrolled.
-;;
-;; Thus lazy-lock.el's function is called almost as often as possible, usually
-;; when it need not be called, yet it is not always called when it is needed.
-;; Also, lazy-lock.el's function must check each window to see if a scroll has
-;; occurred there.  Worse still, lazy-lock.el's function must fontify a region
-;; twice as large as necessary to make sure the window is completely fontified.
-;; Basically, `post-command-hook' is completely inappropriate for lazy-lock.el.
-;;
-;; Ideally, we want to attach lazy-lock.el's function to a hook that is run
-;; only when scrolling occurs, e.g., `window-start' has changed, and tells us
-;; as much information as we need, i.e., the window and its new buffer region.
-;; Richard Stallman implemented a `window-scroll-functions' for Emacs 19.30.
-;; Functions on it are run when `window-start' has changed, and are supplied
-;; with the window and the window's new `window-start' position.  (It would be
-;; better if it also supplied the window's new `window-end' position, but that
-;; is calculated as part of the redisplay process, and the functions on
-;; `window-scroll-functions' are run before redisplay has finished.)  Thus, the
-;; hook deals with the above problems (a), (b) and (c).
-;;
-;; If only life was that easy.  Version 2 demand-driven fontification is mostly
-;; implemented by placing a function on `window-scroll-functions'.  However,
-;; not all scrolling occurs when `window-start' has changed.  A change in
-;; window size, e.g., via C-x 1, or a significant deletion, e.g., of a number
-;; of lines, causes text previously invisible (i.e., after `window-end') to
-;; become visible without changing `window-start'.  Arguably, these events are
-;; not scrolling events, but fontification must occur for lazy-lock.el to work.
-;; Hooks `window-size-change-functions' and `redisplay-end-trigger-functions'
-;; were added for these circumstances.
-;;
-;; (Ben Wing thinks these hooks are "horribly horribly kludgy", and implemented
-;; a `pre-idle-hook', a `mother-of-all-post-command-hooks', for XEmacs 19.14.
-;; He then hacked up a version 1 lazy-lock.el to use `pre-idle-hook' rather
-;; than `post-command-hook'.  Whereas functions on `post-command-hook' are
-;; called almost as often as possible, functions on `pre-idle-hook' really are
-;; called as often as possible, even when the mouse moves and, on some systems,
-;; while XEmacs is idle.  Thus, the hook deals with the above problem (b), but
-;; unfortunately it makes (a) worse and does not address (c) at all.
-;;
-;; I freely admit that `redisplay-end-trigger-functions' and, to a much lesser
-;; extent, `window-size-change-functions' are not pretty.  However, I feel that
-;; a `window-scroll-functions' feature is cleaner than a `pre-idle-hook', and
-;; the result is faster and smaller, less intrusive and more targeted, code.
-;; Since `pre-idle-hook' is pretty much like `post-command-hook', there is no
-;; point in making this version of lazy-lock.el work with it.  Anyway, that's
-;; Lit 30 of my humble opinion.
-;;
-;; - Version 1 stealth fontification is also implemented by placing a function
-;; on `post-command-hook'.  This function waits for a given amount of time,
-;; and, if Emacs remains idle, fontifies where necessary.  Again, there are a
-;; number of problems with using `post-command-hook':
-;;
-;; (a) Functions on `post-command-hook' are run sequentially, so this function
-;;     can interfere with other functions on the hook, and vice versa.
-;; (b) This function waits for a given amount of time, so it can interfere with
-;;     various features that are dealt with by Emacs after a command, e.g.,
-;;     region highlighting, asynchronous updating and keystroke echoing.
-;; (c) Fontification may be required during a command, when `post-command-hook'
-;;     is not run.  (Version 2 deferred fontification only.)
-;;
-;; Again, `post-command-hook' is completely inappropriate for lazy-lock.el.
-;; Richard Stallman and Morten Welinder implemented internal Timers and Idle
-;; Timers for Emacs 19.31.  Functions can be run independently at given times
-;; or after given amounts of idle time.  Thus, the feature deals with the above
-;; problems (a), (b) and (c).  Version 2 deferral and stealth are implemented
-;; by functions on Idle Timers.  (A function on XEmacs' `pre-idle-hook' is
-;; similar to an Emacs Idle Timer function with a fixed zero second timeout.)
-
-;; - Version 1 has the following problems (relative to version 2):
-;;
-;; (a) It is slow when it does its job.
-;; (b) It does not always do its job when it should.
-;; (c) It slows all interaction (when it doesn't need to do its job).
-;; (d) It interferes with other package functions on `post-command-hook'.
-;; (e) It interferes with Emacs things within the read-eval loop.
-;;
-;; Ben's hacked-up lazy-lock.el 1.14 almost solved (b) but made (c) worse.
-;;
-;; - Version 2 has the following additional features (relative to version 1):
-;;
-;; (a) It can defer fontification (both on-the-fly and on-scrolling).
-;; (b) It can fontify contextually (syntactically true on-the-fly).
-
-;; Caveats:
-;;
-;; Lazy Lock mode does not work efficiently with Outline mode.
-;; This is because when in Outline mode, although text may be not visible to
-;; you in the window, the text is visible to Emacs Lisp code (not surprisingly)
-;; and Lazy Lock fontifies it mercilessly.  Maybe it will be fixed one day.
-;;
-;; Because buffer text is not necessarily fontified, other packages that expect
-;; buffer text to be fontified in Font Lock mode either might not work as
-;; expected, or might not display buffer text as expected.  An example of the
-;; latter is `occur', which copies lines of buffer text into another buffer.
-;;
-;; In Emacs 19.30, Lazy Lock mode does not ensure that an existing buffer is
-;; fontified if it is made visible via a minibuffer-less command that replaces
-;; an existing window's buffer (e.g., via the Buffers menu).  Upgrade!
-;;
-;; In Emacs 19.30, Lazy Lock mode does not work well with Transient Mark mode
-;; or modes based on Comint mode (e.g., Shell mode), and also interferes with
-;; the echoing of keystrokes in the minibuffer.  This is because of the way
-;; deferral and stealth have to be implemented for Emacs 19.30.  Upgrade!
-;;
-;; Currently XEmacs does not have the features to support this version of
-;; lazy-lock.el.  Maybe it will one day.
-
-;; History:
-;;
-;; 1.15--2.00:
-;; - Rewrite for Emacs 19.30 and the features rms added to support lazy-lock.el
-;;   so that it could work correctly and efficiently.
-;; - Many thanks to those who reported bugs, fixed bugs, made suggestions or
-;;   otherwise contributed in the version 1 cycle; Jari Aalto, Kevin Broadey,
-;;   Ulrik Dickow, Bill Dubuque, Bob Glickstein, Boris Goldowsky,
-;;   Jonas Jarnestrom, David Karr, Michael Kifer, Erik Naggum, Rick Sladkey,
-;;   Jim Thompson, Ben Wing, Ilya Zakharevich, and Richard Stallman.
-;; 2.00--2.01:
-;; - Made `lazy-lock-fontify-after-command' always `sit-for' and so redisplay
-;; - Use `buffer-name' not `buffer-live-p' (Bill Dubuque hint)
-;; - Made `lazy-lock-install' do `add-to-list' not `setq' of `current-buffer'
-;; - Made `lazy-lock-fontify-after-install' loop over buffer list
-;; - Made `lazy-lock-arrange-before-change' to arrange `window-end' triggering
-;; - Made `lazy-lock-let-buffer-state' wrap both `befter-change-functions'
-;; - Made `lazy-lock-fontify-region' do `condition-case' (Hyman Rosen report)
-;; 2.01--2.02:
-;; - Use `buffer-live-p' as `buffer-name' can barf (Richard Stanton report)
-;; - Made `lazy-lock-install' set `font-lock-fontified' (Kevin Davidson report)
-;; - Made `lazy-lock-install' add hooks only if needed
-;; - Made `lazy-lock-unstall' add `font-lock-after-change-function' if needed
-;; 2.02--2.03:
-;; - Made `lazy-lock-fontify-region' do `condition-case' for `quit' too
-;; - Made `lazy-lock-mode' respect the value of `font-lock-inhibit-thing-lock'
-;; - Added `lazy-lock-after-unfontify-buffer'
-;; - Removed `lazy-lock-fontify-after-install' hack
-;; - Made `lazy-lock-fontify-after-scroll' not `set-buffer' to `window-buffer'
-;; - Made `lazy-lock-fontify-after-trigger' not `set-buffer' to `window-buffer'
-;; - Made `lazy-lock-fontify-after-idle' be interruptible (Scott Burson hint)
-;; 2.03--2.04:
-;; - Rewrite for Emacs 19.31 idle timers
-;; - Renamed `buffer-windows' to `get-buffer-window-list'
-;; - Removed `buffer-live-p'
-;; - Made `lazy-lock-defer-after-change' always save `current-buffer'
-;; - Made `lazy-lock-fontify-after-defer' just process buffers
-;; - Made `lazy-lock-install-hooks' add hooks correctly (Kevin Broadey report)
-;; - Made `lazy-lock-install' cope if `lazy-lock-defer-time' is a list
-;; 2.04--2.05:
-;; - Rewrite for Common Lisp macros
-;; - Added `do-while' macro
-;; - Renamed `lazy-lock-let-buffer-state' macro to `save-buffer-state'
-;; - Returned `lazy-lock-fontify-after-install' hack (Darren Hall hint)
-;; - Added `lazy-lock-defer-on-scrolling' functionality (Scott Byer hint)
-;; - Made `lazy-lock-mode' wrap `font-lock-support-mode'
-;; 2.05--2.06:
-;; - Made `lazy-lock-fontify-after-defer' swap correctly (Scott Byer report)
-;; 2.06--2.07:
-;; - Added `lazy-lock-stealth-load' functionality (Rob Hooft hint)
-;; - Made `lazy-lock-unstall' call `lazy-lock-fontify-region' if needed
-;; - Made `lazy-lock-mode' call `lazy-lock-unstall' only if needed
-;; - Made `lazy-lock-defer-after-scroll' do `set-window-redisplay-end-trigger'
-;; - Added `lazy-lock-defer-contextually' functionality
-;; - Added `lazy-lock-defer-on-the-fly' from `lazy-lock-defer-time'
-;; - Renamed `lazy-lock-defer-driven' to `lazy-lock-defer-on-scrolling'
-;; - Removed `lazy-lock-submit-bug-report' and bade farewell
-;; 2.07--2.08:
-;; - Made `lazy-lock-fontify-conservatively' fontify around `window-point'
-;; - Made `save-buffer-state' wrap `inhibit-point-motion-hooks'
-;; - Added Custom support
-;; 2.08--2.09:
-;; - Removed `byte-*' variables from `eval-when-compile' (Erik Naggum hint)
-;; - Made various wrapping `inhibit-point-motion-hooks' (Vinicius Latorre hint)
-;; - Made `lazy-lock-fontify-after-idle' wrap `minibuffer-auto-raise'
-;; - Made `lazy-lock-fontify-after-defer' paranoid about deferred buffers
-;; 2.09--2.10:
-;; - Use `window-end' UPDATE arg for Emacs 20.4 and later.
-;; - Made deferral `widen' before unfontifying (Dan Nicolaescu report)
-;; - Use `lazy-lock-fontify-after-visage' for hideshow.el (Dan Nicolaescu hint)
-;; - Use `other' widget where possible (Andreas Schwab fix)
-;; 2.10--2.11:
-;; - Used `with-temp-message' where possible to make messages temporary.
-
-;;; Code:
-
-(require 'font-lock)
-(eval-when-compile (require 'cl-lib))
-
-(eval-when-compile
- ;;
- ;; We use this for clarity and speed.  Naughty but nice.
- (defmacro do-while (test &rest body)
-   "(do-while TEST BODY...): eval BODY... and repeat if TEST yields non-nil.
-The order of execution is thus BODY, TEST, BODY, TEST and so on
-until TEST returns nil."
-   (declare (indent 1) (debug t))
-   `(while (progn ,@body ,test))))
-
-(defgroup lazy-lock nil
-  "Font Lock support mode to fontify lazily."
-  :group 'font-lock)
-
-(defvar lazy-lock-mode nil)                    ; Whether we are turned on.
-(defvar lazy-lock-buffers nil)                 ; For deferral.
-(defvar lazy-lock-timers (cons nil nil))       ; For deferral and stealth.
-
-;; User Variables:
-
-(defcustom lazy-lock-minimum-size 25600
-  "Minimum size of a buffer for demand-driven fontification.
-On-demand fontification occurs if the buffer size is greater than this value.
-If nil, means demand-driven fontification is never performed.
-If a list, each element should be a cons pair of the form (MAJOR-MODE . SIZE),
-where MAJOR-MODE is a symbol or t (meaning the default).  For example:
- ((c-mode . 25600) (c++-mode . 25600) (rmail-mode . 1048576))
-means that the minimum size is 25K for buffers in C or C++ modes, one megabyte
-for buffers in Rmail mode, and size is irrelevant otherwise.
-
-The value of this variable is used when Lazy Lock mode is turned on."
-  :type '(choice (const :tag "none" nil)
-                (integer :tag "size")
-                (repeat :menu-tag "mode specific" :tag "mode specific"
-                        :value ((t . nil))
-                        (cons :tag "Instance"
-                              (radio :tag "Mode"
-                                     (const :tag "all" t)
-                                     (symbol :tag "name"))
-                              (radio :tag "Size"
-                                     (const :tag "none" nil)
-                                     (integer :tag "size"))))))
-
-(defcustom lazy-lock-defer-on-the-fly t
-  "If non-nil, means fontification after a change should be deferred.
-If nil, means on-the-fly fontification is performed.  This means when changes
-occur in the buffer, those areas are immediately fontified.
-If a list, it should be a list of `major-mode' symbol names for which deferred
-fontification should occur.  The sense of the list is negated if it begins with
-`not'.  For example:
- (c-mode c++-mode)
-means that on-the-fly fontification is deferred for buffers in C and C++ modes
-only, and deferral does not occur otherwise.
-
-The value of this variable is used when Lazy Lock mode is turned on."
-  :type '(choice (const :tag "never" nil)
-                (const :tag "always" t)
-                (set :menu-tag "mode specific" :tag "modes"
-                     :value (not)
-                     (const :tag "Except" not)
-                     (repeat :inline t (symbol :tag "mode")))))
-
-(defcustom lazy-lock-defer-on-scrolling nil
-  "If non-nil, means fontification after a scroll should be deferred.
-If nil, means demand-driven fontification is performed.  This means when
-scrolling into unfontified areas of the buffer, those areas are immediately
-fontified.  Thus scrolling never presents unfontified areas.  However, since
-fontification occurs during scrolling, scrolling may be slow.
-If t, means defer-driven fontification is performed.  This means fontification
-of those areas is deferred.  Thus scrolling may present momentarily unfontified
-areas.  However, since fontification does not occur during scrolling, scrolling
-will be faster than demand-driven fontification.
-If any other value, e.g., `eventually', means demand-driven fontification is
-performed until the buffer is fontified, then buffer fontification becomes
-defer-driven.  Thus scrolling never presents unfontified areas until the buffer
-is first fontified, after which subsequent scrolling may present future buffer
-insertions momentarily unfontified.  However, since fontification does not
-occur during scrolling after the buffer is first fontified, scrolling will
-become faster.  (But, since contextual changes continually occur, such a value
-makes little sense if `lazy-lock-defer-contextually' is non-nil.)
-
-The value of this variable is used when Lazy Lock mode is turned on."
-  :type '(choice (const :tag "never" nil)
-                (const :tag "always" t)
-                (other :tag "eventually" eventually)))
-
-(defcustom lazy-lock-defer-contextually 'syntax-driven
-  "If non-nil, means deferred fontification should be syntactically true.
-If nil, means deferred fontification occurs only on those lines modified.  This
-means where modification on a line causes syntactic change on subsequent lines,
-those subsequent lines are not refontified to reflect their new context.
-If t, means deferred fontification occurs on those lines modified and all
-subsequent lines.  This means those subsequent lines are refontified to reflect
-their new syntactic context, either immediately or when scrolling into them.
-If any other value, e.g., `syntax-driven', means deferred syntactically true
-fontification occurs only if syntactic fontification is performed using the
-buffer mode's syntax table, i.e., only if `font-lock-keywords-only' is nil.
-
-The value of this variable is used when Lazy Lock mode is turned on."
-  :type '(choice (const :tag "never" nil)
-                (const :tag "always" t)
-                (other :tag "syntax-driven" syntax-driven)))
-
-(defcustom lazy-lock-defer-time 0.25
-  "Time in seconds to delay before beginning deferred fontification.
-Deferred fontification occurs if there is no input within this time.
-If nil, means fontification is never deferred, regardless of the values of the
-variables `lazy-lock-defer-on-the-fly', `lazy-lock-defer-on-scrolling' and
-`lazy-lock-defer-contextually'.
-
-The value of this variable is used when Lazy Lock mode is turned on."
-  :type '(choice (const :tag "never" nil)
-                (number :tag "seconds")))
-
-(defcustom lazy-lock-stealth-time 30
-  "Time in seconds to delay before beginning stealth fontification.
-Stealth fontification occurs if there is no input within this time.
-If nil, means stealth fontification is never performed.
-
-The value of this variable is used when Lazy Lock mode is turned on."
-  :type '(choice (const :tag "never" nil)
-                (number :tag "seconds")))
-
-(defcustom lazy-lock-stealth-lines (if font-lock-maximum-decoration 100 250)
-  "Maximum size of a chunk of stealth fontification.
-Each iteration of stealth fontification can fontify this number of lines.
-To speed up input response during stealth fontification, at the cost of stealth
-taking longer to fontify, you could reduce the value of this variable."
-  :type '(integer :tag "lines"))
-
-(defcustom lazy-lock-stealth-load
-  (if (condition-case nil (load-average) (error)) 200)
-  "Load in percentage above which stealth fontification is suspended.
-Stealth fontification pauses when the system short-term load average (as
-returned by the function `load-average' if supported) goes above this level,
-thus reducing the demand that stealth fontification makes on the system.
-If nil, means stealth fontification is never suspended.
-To reduce machine load during stealth fontification, at the cost of stealth
-taking longer to fontify, you could reduce the value of this variable.
-See also `lazy-lock-stealth-nice'."
-  :type (if (condition-case nil (load-average) (error))
-           '(choice (const :tag "never" nil)
-                    (integer :tag "load"))
-         '(const :format "%t: unsupported\n" nil)))
-
-(defcustom lazy-lock-stealth-nice 0.125
-  "Time in seconds to pause between chunks of stealth fontification.
-Each iteration of stealth fontification is separated by this amount of time,
-thus reducing the demand that stealth fontification makes on the system.
-If nil, means stealth fontification is never paused.
-To reduce machine load during stealth fontification, at the cost of stealth
-taking longer to fontify, you could increase the value of this variable.
-See also `lazy-lock-stealth-load'."
-  :type '(choice (const :tag "never" nil)
-                (number :tag "seconds")))
-
-(defcustom lazy-lock-stealth-verbose
-  (and (not lazy-lock-defer-contextually) (not (null font-lock-verbose)))
-  "If non-nil, means stealth fontification should show status messages."
-  :type 'boolean)
-
-;; User Functions:
-
-;;;###autoload
-(defun lazy-lock-mode (&optional arg)
-  "Toggle Lazy Lock mode.
-With arg, turn Lazy Lock mode on if and only if arg is positive.  Enable it
-automatically in your `~/.emacs' by:
-
- (setq font-lock-support-mode \\='lazy-lock-mode)
-
-For a newer font-lock support mode with similar functionality, see
-`jit-lock-mode'.  Eventually, Lazy Lock mode will be deprecated in
-JIT Lock's favor.
-
-When Lazy Lock mode is enabled, fontification can be lazy in a number of ways:
-
-- Demand-driven buffer fontification if `lazy-lock-minimum-size' is non-nil.
-  This means initial fontification does not occur if the buffer is greater than
-  `lazy-lock-minimum-size' characters in length.  Instead, fontification occurs
-  when necessary, such as when scrolling through the buffer would otherwise
-  reveal unfontified areas.  This is useful if buffer fontification is too slow
-  for large buffers.
-
-- Deferred scroll fontification if `lazy-lock-defer-on-scrolling' is non-nil.
-  This means demand-driven fontification does not occur as you scroll.
-  Instead, fontification is deferred until after `lazy-lock-defer-time' seconds
-  of Emacs idle time, while Emacs remains idle.  This is useful if
-  fontification is too slow to keep up with scrolling.
-
-- Deferred on-the-fly fontification if `lazy-lock-defer-on-the-fly' is non-nil.
-  This means on-the-fly fontification does not occur as you type.  Instead,
-  fontification is deferred until after `lazy-lock-defer-time' seconds of Emacs
-  idle time, while Emacs remains idle.  This is useful if fontification is too
-  slow to keep up with your typing.
-
-- Deferred context fontification if `lazy-lock-defer-contextually' is non-nil.
-  This means fontification updates the buffer corresponding to true syntactic
-  context, after `lazy-lock-defer-time' seconds of Emacs idle time, while Emacs
-  remains idle.  Otherwise, fontification occurs on modified lines only, and
-  subsequent lines can remain fontified corresponding to previous syntactic
-  contexts.  This is useful where strings or comments span lines.
-
-- Stealthy buffer fontification if `lazy-lock-stealth-time' is non-nil.
-  This means remaining unfontified areas of buffers are fontified if Emacs has
-  been idle for `lazy-lock-stealth-time' seconds, while Emacs remains idle.
-  This is useful if any buffer has any deferred fontification.
-
-Basic Font Lock mode on-the-fly fontification behavior fontifies modified
-lines only.  Thus, if `lazy-lock-defer-contextually' is non-nil, Lazy Lock mode
-on-the-fly fontification may fontify differently, albeit correctly.  In any
-event, to refontify some lines you can use \\[font-lock-fontify-block].
-
-Stealth fontification only occurs while the system remains unloaded.
-If the system load rises above `lazy-lock-stealth-load' percent, stealth
-fontification is suspended.  Stealth fontification intensity is controlled via
-the variable `lazy-lock-stealth-nice' and `lazy-lock-stealth-lines', and
-verbosity is controlled via the variable `lazy-lock-stealth-verbose'."
-  (interactive "P")
-  (let* ((was-on lazy-lock-mode)
-        (now-on (unless (memq 'lazy-lock-mode font-lock-inhibit-thing-lock)
-                  (if arg (> (prefix-numeric-value arg) 0) (not was-on)))))
-    (cond ((and now-on (not font-lock-mode))
-          ;; Turned on `lazy-lock-mode' rather than `font-lock-mode'.
-           (message "Use font-lock-support-mode rather than calling 
lazy-lock-mode")
-           (sit-for 2))
-         (now-on
-          ;; Turn ourselves on.
-          (set (make-local-variable 'lazy-lock-mode) t)
-          (lazy-lock-install))
-         (was-on
-          ;; Turn ourselves off.
-          (set (make-local-variable 'lazy-lock-mode) nil)
-          (lazy-lock-unstall)))))
-
-;;;###autoload
-(defun turn-on-lazy-lock ()
-  "Unconditionally turn on Lazy Lock mode."
-  (lazy-lock-mode t))
-
-(defun lazy-lock-install ()
-  (let ((min-size (font-lock-value-in-major-mode lazy-lock-minimum-size))
-       (defer-change (and lazy-lock-defer-time lazy-lock-defer-on-the-fly))
-       (defer-scroll (and lazy-lock-defer-time lazy-lock-defer-on-scrolling))
-       (defer-context (and lazy-lock-defer-time lazy-lock-defer-contextually
-                           (or (eq lazy-lock-defer-contextually t)
-                               (null font-lock-keywords-only)))))
-    ;;
-    ;; Tell Font Lock whether Lazy Lock will do fontification.
-    (make-local-variable 'font-lock-fontified)
-    (setq font-lock-fontified (and min-size (>= (buffer-size) min-size)))
-    ;;
-    ;; Add the text properties and fontify.
-    (if (not font-lock-fontified)
-       (lazy-lock-after-fontify-buffer)
-      ;; Make sure we fontify in any existing windows showing the buffer.
-      (let ((windows (get-buffer-window-list (current-buffer) 'nomini t)))
-       (lazy-lock-after-unfontify-buffer)
-       (while windows
-         (lazy-lock-fontify-conservatively (car windows))
-         (setq windows (cdr windows)))))
-    ;;
-    ;; Add the fontification hooks.
-    (lazy-lock-install-hooks
-     font-lock-fontified
-     (cond ((eq (car-safe defer-change) 'not)
-           (not (memq major-mode (cdr defer-change))))
-          ((listp defer-change)
-           (memq major-mode defer-change))
-          (t
-           defer-change))
-     (eq defer-scroll t)
-     defer-context)
-    ;;
-    ;; Add the fontification timers.
-    (lazy-lock-install-timers
-     (if (or defer-change defer-scroll defer-context) lazy-lock-defer-time)
-     lazy-lock-stealth-time)))
-
-(defun lazy-lock-install-hooks (fontifying
-                               defer-change defer-scroll defer-context)
-  ;;
-  ;; Add hook if lazy-lock.el is fontifying on scrolling or is deferring.
-  (when (or fontifying defer-change defer-scroll defer-context)
-    (add-hook 'window-scroll-functions (if defer-scroll
-                                          #'lazy-lock-defer-after-scroll
-                                        #'lazy-lock-fontify-after-scroll)
-             nil t))
-  ;;
-  ;; Add hook if lazy-lock.el is fontifying and is not deferring changes.
-  (when (and fontifying (not defer-change) (not defer-context))
-    (add-hook 'before-change-functions #'lazy-lock-arrange-before-change nil 
t))
-  ;;
-  ;; Replace Font Lock mode hook.
-  (remove-hook 'after-change-functions #'font-lock-after-change-function t)
-  (add-hook 'after-change-functions
-           (cond ((and defer-change defer-context)
-                  #'lazy-lock-defer-rest-after-change)
-                 (defer-change
-                  #'lazy-lock-defer-line-after-change)
-                 (defer-context
-                  #'lazy-lock-fontify-rest-after-change)
-                 (t
-                  #'lazy-lock-fontify-line-after-change))
-           nil t)
-  ;;
-  ;; Add package-specific hook.
-  (add-hook 'outline-view-change-hook #'lazy-lock-fontify-after-visage nil t)
-  (add-hook 'hs-hide-hook #'lazy-lock-fontify-after-visage nil t))
-
-(defun lazy-lock-install-timers (dtime stime)
-  ;; Schedule or re-schedule the deferral and stealth timers.
-  ;; The layout of `lazy-lock-timers' is:
-  ;;  ((DEFER-TIME . DEFER-TIMER) (STEALTH-TIME . STEALTH-TIMER)
-  ;; If an idle timeout has changed, cancel the existing idle timer (if there
-  ;; is one) and schedule a new one (if the new idle timeout is non-nil).
-  (unless (eq dtime (car (car lazy-lock-timers)))
-    (let ((defer (car lazy-lock-timers)))
-      (when (cdr defer)
-       (cancel-timer (cdr defer)))
-      (setcar lazy-lock-timers (cons dtime (and dtime
-             (run-with-idle-timer dtime t #'lazy-lock-fontify-after-defer))))))
-  (unless (eq stime (car (cdr lazy-lock-timers)))
-    (let ((stealth (cdr lazy-lock-timers)))
-      (when (cdr stealth)
-       (cancel-timer (cdr stealth)))
-      (setcdr lazy-lock-timers (cons stime (and stime
-             (run-with-idle-timer stime t #'lazy-lock-fontify-after-idle)))))))
-
-(defun lazy-lock-unstall ()
-  ;;
-  ;; If Font Lock mode is still enabled, make sure that the buffer is
-  ;; fontified, and reinstall its hook.  We must do this first.
-  (when font-lock-mode
-    (when (lazy-lock-unfontified-p)
-      (let ((verbose (if (numberp font-lock-verbose)
-                        (> (buffer-size) font-lock-verbose)
-                      font-lock-verbose)))
-       (with-temp-message
-           (when verbose
-             (format "Fontifying %s..." (buffer-name)))
-         ;; Make sure we fontify etc. in the whole buffer.
-         (save-restriction
-           (widen)
-           (lazy-lock-fontify-region (point-min) (point-max))))))
-    (add-hook 'after-change-functions #'font-lock-after-change-function nil t))
-  ;;
-  ;; Remove the text properties.
-  (lazy-lock-after-unfontify-buffer)
-  ;;
-  ;; Remove the fontification hooks.
-  (remove-hook 'window-scroll-functions #'lazy-lock-fontify-after-scroll t)
-  (remove-hook 'window-scroll-functions #'lazy-lock-defer-after-scroll t)
-  (remove-hook 'before-change-functions #'lazy-lock-arrange-before-change t)
-  (remove-hook 'after-change-functions #'lazy-lock-fontify-line-after-change t)
-  (remove-hook 'after-change-functions #'lazy-lock-fontify-rest-after-change t)
-  (remove-hook 'after-change-functions #'lazy-lock-defer-line-after-change t)
-  (remove-hook 'after-change-functions #'lazy-lock-defer-rest-after-change t)
-  (remove-hook 'outline-view-change-hook #'lazy-lock-fontify-after-visage t)
-  (remove-hook 'hs-hide-hook #'lazy-lock-fontify-after-visage t))
-
-;; Hook functions.
-
-;; Lazy Lock mode intervenes when (1) a previously invisible buffer region
-;; becomes visible, i.e., for demand- or defer-driven on-the-scroll
-;; fontification, (2) a buffer modification occurs, i.e., for defer-driven
-;; on-the-fly fontification, (3) Emacs becomes idle, i.e., for fontification of
-;; deferred fontification and stealth fontification, and (4) other special
-;; occasions.
-
-;; 1.  There are three ways whereby this can happen.
-;;
-;; (a) Scrolling the window, either explicitly (e.g., `scroll-up') or
-;;     implicitly (e.g., `search-forward').  Here, `window-start' changes.
-;;     Fontification occurs by adding `lazy-lock-fontify-after-scroll' (for
-;;     demand-driven fontification) or `lazy-lock-defer-after-scroll' (for
-;;     defer-driven fontification) to the hook `window-scroll-functions'.
-
-(defun lazy-lock-fontify-after-scroll (window window-start)
-  ;; Called from `window-scroll-functions'.
-  ;; Fontify WINDOW from WINDOW-START following the scroll.
-  (let ((inhibit-point-motion-hooks t))
-    (lazy-lock-fontify-region window-start (window-end window t)))
-  ;; A prior deletion that did not cause scrolling, followed by a scroll, would
-  ;; result in an unnecessary trigger after this if we did not cancel it now.
-  (set-window-redisplay-end-trigger window nil))
-
-(defun lazy-lock-defer-after-scroll (window _window-start)
-  ;; Called from `window-scroll-functions'.
-  ;; Defer fontification following the scroll.  Save the current buffer so that
-  ;; we subsequently fontify in all windows showing the buffer.
-  (unless (memq (current-buffer) lazy-lock-buffers)
-    (push (current-buffer) lazy-lock-buffers))
-  ;; A prior deletion that did not cause scrolling, followed by a scroll, would
-  ;; result in an unnecessary trigger after this if we did not cancel it now.
-  (set-window-redisplay-end-trigger window nil))
-
-;; (b) Resizing the window, either explicitly (e.g., `enlarge-window') or
-;;     implicitly (e.g., `delete-other-windows').  Here, `window-end' changes.
-;;     Fontification occurs by adding `lazy-lock-fontify-after-resize' to the
-;;     hook `window-size-change-functions'.
-
-(defun lazy-lock-fontify-after-resize (frame)
-  ;; Called from `window-size-change-functions'.
-  ;; Fontify windows in FRAME following the resize.  We cannot use
-  ;; `window-start' or `window-end' so we fontify conservatively.
-  (save-excursion
-    (save-selected-window
-      (select-frame frame)
-      (walk-windows (function (lambda (window)
-                      (set-buffer (window-buffer window))
-                      (when lazy-lock-mode
-                        (lazy-lock-fontify-conservatively window))
-                      (set-window-redisplay-end-trigger window nil)))
-                   'nomini frame))))
-
-;; (c) Deletion in the buffer.  Here, a `window-end' marker can become visible.
-;;     Fontification occurs by adding `lazy-lock-arrange-before-change' to
-;;     `before-change-functions' and `lazy-lock-fontify-after-trigger' to the
-;;     hook `redisplay-end-trigger-functions'.  Before every deletion, the
-;;     marker `window-redisplay-end-trigger' position is set to the soon-to-be
-;;     changed `window-end' position.  If the marker becomes visible,
-;;     `lazy-lock-fontify-after-trigger' gets called.  Ouch.  Note that we only
-;;     have to deal with this eventuality if there is no on-the-fly deferral.
-
-(defun lazy-lock-arrange-before-change (beg end)
-  ;; Called from `before-change-functions'.
-  ;; Arrange that if text becomes visible it will be fontified (if a deletion
-  ;; is pending, text might become visible at the bottom).
-  (unless (eq beg end)
-    (let ((windows (get-buffer-window-list (current-buffer) 'nomini t)) window)
-      (while windows
-       (setq window (car windows))
-       (unless (markerp (window-redisplay-end-trigger window))
-         (set-window-redisplay-end-trigger window (make-marker)))
-       (set-marker (window-redisplay-end-trigger window) (window-end window))
-       (setq windows (cdr windows))))))
-
-(defun lazy-lock-fontify-after-trigger (window trigger-point)
-  ;; Called from `redisplay-end-trigger-functions'.
-  ;; Fontify WINDOW from TRIGGER-POINT following the redisplay.
-  ;; We could probably just use `lazy-lock-fontify-after-scroll' without loss:
-  ;;  (inline (lazy-lock-fontify-after-scroll window (window-start window)))
-  (let ((inhibit-point-motion-hooks t))
-    (lazy-lock-fontify-region trigger-point (window-end window t))))
-
-;; 2.  Modified text must be marked as unfontified so it can be identified and
-;;     fontified later when Emacs is idle.  Deferral occurs by adding one of
-;;     `lazy-lock-fontify-*-after-change' (for on-the-fly fontification) or
-;;     `lazy-lock-defer-*-after-change' (for deferred fontification) to the
-;;     hook `after-change-functions'.
-
-(defalias 'lazy-lock-fontify-line-after-change
-  ;; Called from `after-change-functions'.
-  ;; Fontify the current change.
-  #'font-lock-after-change-function)
-
-(defun lazy-lock-fontify-rest-after-change (beg end old-len)
-  ;; Called from `after-change-functions'.
-  ;; Fontify the current change and defer fontification of the rest of the
-  ;; buffer.  Save the current buffer so that we subsequently fontify in all
-  ;; windows showing the buffer.
-  (lazy-lock-fontify-line-after-change beg end old-len)
-  (with-silent-modifications
-    (unless (memq (current-buffer) lazy-lock-buffers)
-      (push (current-buffer) lazy-lock-buffers))
-    (save-restriction
-      (widen)
-      (remove-text-properties end (point-max) '(lazy-lock nil)))))
-
-(defun lazy-lock-defer-line-after-change (beg end _old-len)
-  ;; Called from `after-change-functions'.
-  ;; Defer fontification of the current change.  Save the current buffer so
-  ;; that we subsequently fontify in all windows showing the buffer.
-  (with-silent-modifications
-    (unless (memq (current-buffer) lazy-lock-buffers)
-      (push (current-buffer) lazy-lock-buffers))
-    (remove-text-properties (max (1- beg) (point-min))
-                           (min (1+ end) (point-max))
-                           '(lazy-lock nil))))
-
-(defun lazy-lock-defer-rest-after-change (beg _end _old-len)
-  ;; Called from `after-change-functions'.
-  ;; Defer fontification of the rest of the buffer.  Save the current buffer so
-  ;; that we subsequently fontify in all windows showing the buffer.
-  (with-silent-modifications
-    (unless (memq (current-buffer) lazy-lock-buffers)
-      (push (current-buffer) lazy-lock-buffers))
-    (save-restriction
-      (widen)
-      (remove-text-properties (max (1- beg) (point-min))
-                             (point-max)
-                             '(lazy-lock nil)))))
-
-;; 3.  Deferred fontification and stealth fontification are done from these two
-;;     functions.  They are set up as Idle Timers.
-
-(defun lazy-lock-fontify-after-defer ()
-  ;; Called from `timer-idle-list'.
-  ;; Fontify all windows where deferral has occurred for its buffer.
-  (save-excursion
-    (while (and lazy-lock-buffers (not (input-pending-p)))
-      (let ((buffer (car lazy-lock-buffers)) windows)
-       ;; Paranoia: check that the buffer is still live and Lazy Lock mode on.
-       (when (buffer-live-p buffer)
-         (set-buffer buffer)
-         (when lazy-lock-mode
-           (setq windows (get-buffer-window-list buffer 'nomini t))
-           (while windows
-             (lazy-lock-fontify-window (car windows))
-             (setq windows (cdr windows)))))
-       (setq lazy-lock-buffers (cdr lazy-lock-buffers)))))
-  ;; Add hook if fontification should now be defer-driven in this buffer.
-  (when (and lazy-lock-mode lazy-lock-defer-on-scrolling
-            (memq #'lazy-lock-fontify-after-scroll window-scroll-functions)
-            (not (or (input-pending-p) (lazy-lock-unfontified-p))))
-    (remove-hook 'window-scroll-functions #'lazy-lock-fontify-after-scroll t)
-    (add-hook 'window-scroll-functions #'lazy-lock-defer-after-scroll nil t)))
-
-(defun lazy-lock-fontify-after-idle ()
-  ;; Called from `timer-idle-list'.
-  ;; Fontify all buffers that need it, stealthily while idle.
-  (unless (or executing-kbd-macro (window-minibuffer-p (selected-window)))
-    ;; Loop over all buffers, fontify stealthily for each if necessary.
-    (let ((buffers (buffer-list)) (continue t)
-         message message-log-max minibuffer-auto-raise)
-      (save-excursion
-       (do-while (and buffers continue)
-         (set-buffer (car buffers))
-         (if (not (and lazy-lock-mode (lazy-lock-unfontified-p)))
-             (setq continue (not (input-pending-p)))
-           ;; Fontify regions in this buffer while there is no input.
-           (with-temp-message
-               (when lazy-lock-stealth-verbose
-                 "Fontifying stealthily...")
-             (do-while (and (lazy-lock-unfontified-p) continue)
-               (if (and lazy-lock-stealth-load
-                        (> (car (load-average)) lazy-lock-stealth-load))
-                   ;; Wait a while before continuing with the loop.
-                   (progn
-                     (when message
-                       (message "Fontifying stealthily...suspended")
-                       (setq message nil))
-                     (setq continue (sit-for (or lazy-lock-stealth-time 30))))
-                 ;; Fontify a chunk.
-                 (when lazy-lock-stealth-verbose
-                   (if message
-                       (message "Fontifying stealthily... %2d%% of %s"
-                                (lazy-lock-percent-fontified) (buffer-name))
-                     (message "Fontifying stealthily...")
-                     (setq message t)))
-                 ;; Current buffer may have changed during `sit-for'.
-                 (set-buffer (car buffers))
-                 (lazy-lock-fontify-chunk)
-                 (setq continue (sit-for (or lazy-lock-stealth-nice 0)))))))
-         (setq buffers (cdr buffers)))))))
-
-;; 4.  Special circumstances.
-
-(defun lazy-lock-fontify-after-visage ()
-  ;; Called from `outline-view-change-hook' and `hs-hide-hook'.
-  ;; Fontify windows showing the current buffer, as its visibility has changed.
-  ;; This is a conspiracy hack between lazy-lock.el, outline.el and
-  ;; hideshow.el.
-  (let ((windows (get-buffer-window-list (current-buffer) 'nomini t)))
-    (while windows
-      (lazy-lock-fontify-conservatively (car windows))
-      (setq windows (cdr windows)))))
-
-(defun lazy-lock-after-fontify-buffer ()
-  ;; Called from `font-lock-after-fontify-buffer'.
-  ;; Mark the current buffer as fontified.
-  ;; This is a conspiracy hack between lazy-lock.el and font-lock.el.
-  (with-silent-modifications
-    (add-text-properties (point-min) (point-max) '(lazy-lock t))))
-
-(defun lazy-lock-after-unfontify-buffer ()
-  ;; Called from `font-lock-after-unfontify-buffer'.
-  ;; Mark the current buffer as unfontified.
-  ;; This is a conspiracy hack between lazy-lock.el and font-lock.el.
-  (with-silent-modifications
-    (remove-text-properties (point-min) (point-max) '(lazy-lock nil))))
-
-;; Fontification functions.
-
-;; If packages want to ensure that some region of the buffer is fontified, they
-;; should use this function.  For an example, see ps-print.el.
-(defun lazy-lock-fontify-region (beg end)
-  ;; Fontify between BEG and END, where necessary, in the current buffer.
-  (save-restriction
-    (widen)
-    (when (setq beg (text-property-any beg end 'lazy-lock nil))
-      (save-excursion
-       (with-silent-modifications
-         (let ((inhibit-point-motion-hooks t))
-           ;; Find successive unfontified regions between BEG and END.
-           (condition-case data
-               (do-while beg
-                 (let ((next (or (text-property-any beg end 'lazy-lock t)
-                                 end)))
-                   ;; Make sure the region end points are at beginning of line.
-                   (goto-char beg)
-                   (unless (bolp)
-                     (beginning-of-line)
-                     (setq beg (point)))
-                   (goto-char next)
-                   (unless (bolp)
-                     (forward-line)
-                     (setq next (point)))
-                   ;; Fontify the region, then flag it as fontified.
-                   (font-lock-fontify-region beg next)
-                   (add-text-properties beg next '(lazy-lock t))
-                   (setq beg (text-property-any next end 'lazy-lock nil))))
-             ((error quit) (message "Fontifying region...%s" data)))))))))
-
-(defun lazy-lock-fontify-chunk ()
-  ;; Fontify the nearest chunk, for stealth, in the current buffer.
-  (let ((inhibit-point-motion-hooks t))
-    (save-excursion
-      (save-restriction
-       (widen)
-       ;; Move to end of line in case the character at point is not fontified.
-       (end-of-line)
-       ;; Find where the previous (next) unfontified regions end (begin).
-       (let ((prev (previous-single-property-change (point) 'lazy-lock))
-             (next (text-property-any (point) (point-max) 'lazy-lock nil)))
-         ;; Fontify from the nearest unfontified position.
-         (if (or (null prev) (and next (< (- next (point)) (- (point) prev))))
-             ;; The next, or neither, region is the nearest not fontified.
-             (lazy-lock-fontify-region
-              (progn (goto-char (or next (point-min)))
-                     (beginning-of-line)
-                     (point))
-              (progn (goto-char (or next (point-min)))
-                     (forward-line lazy-lock-stealth-lines)
-                     (point)))
-           ;; The previous region is the nearest not fontified.
-           (lazy-lock-fontify-region
-            (progn (goto-char prev)
-                   (forward-line (- lazy-lock-stealth-lines))
-                   (point))
-            (progn (goto-char prev)
-                   (forward-line)
-                   (point)))))))))
-
-(defun lazy-lock-fontify-window (window)
-  ;; Fontify in WINDOW between `window-start' and `window-end'.
-  ;; We can only do this when we can use `window-start' and `window-end'.
-  (with-current-buffer (window-buffer window)
-    (lazy-lock-fontify-region (window-start window) (window-end window))))
-
-(defun lazy-lock-fontify-conservatively (window)
-  ;; Fontify in WINDOW conservatively around point.
-  ;; Where we cannot use `window-start' and `window-end' we do `window-height'
-  ;; lines around point.  That way we guarantee to have done enough.
-  (with-current-buffer (window-buffer window)
-    (let ((inhibit-point-motion-hooks t))
-      (lazy-lock-fontify-region
-       (save-excursion
-        (goto-char (window-point window))
-        (vertical-motion (- (window-height window)) window) (point))
-       (save-excursion
-        (goto-char (window-point window))
-        (vertical-motion (window-height window) window) (point))))))
-
-(defun lazy-lock-unfontified-p ()
-  ;; Return non-nil if there is anywhere still to be fontified.
-  (save-restriction
-    (widen)
-    (text-property-any (point-min) (point-max) 'lazy-lock nil)))
-
-(defun lazy-lock-percent-fontified ()
-  ;; Return the percentage (of characters) of the buffer that are fontified.
-  (save-restriction
-    (widen)
-    (let ((beg (point-min)) (size 0) next)
-      ;; Find where the next fontified region begins.
-      (while (setq beg (text-property-any beg (point-max) 'lazy-lock t))
-       (setq next (or (text-property-any beg (point-max) 'lazy-lock nil)
-                      (point-max)))
-       (cl-incf size (- next beg))
-       (setq beg next))
-      ;; Float because using integer multiplication will frequently overflow.
-      (truncate (* (/ (float size) (point-max)) 100)))))
-
-;; Version dependent workarounds and fixes.
-
-(when (consp lazy-lock-defer-time)
-  ;;
-  ;; In 2.06.04 and below, `lazy-lock-defer-time' could specify modes and time.
-  (with-output-to-temp-buffer "*Help*"
-    (princ "The value of the variable `lazy-lock-defer-time' was\n ")
-    (princ lazy-lock-defer-time)
-    (princ "\n")
-    (princ "This variable cannot now be a list of modes and time,\n")
-    (princ "so instead use ")
-    (princ (substitute-command-keys "\\[customize-option]"))
-    (princ " to modify the variables, or put the forms:\n")
-    (princ " (setq lazy-lock-defer-time ")
-    (princ (cdr lazy-lock-defer-time))
-    (princ ")\n")
-    (princ " (setq lazy-lock-defer-on-the-fly '")
-    (princ (car lazy-lock-defer-time))
-    (princ ")\n")
-    (princ "in your ~/.emacs.  ")
-    (princ "The above forms have been evaluated for this editor session,\n")
-    (princ "but you should use ")
-    (princ (substitute-command-keys "\\[customize-option]"))
-    (princ " or change your ~/.emacs now."))
-  (setq lazy-lock-defer-on-the-fly (car lazy-lock-defer-time)
-       lazy-lock-defer-time (cdr lazy-lock-defer-time)))
-
-(when (boundp 'lazy-lock-defer-driven)
-  ;;
-  ;; In 2.06.04 and below, `lazy-lock-defer-driven' was the variable name.
-  (with-output-to-temp-buffer "*Help*"
-    (princ "The value of the variable `lazy-lock-defer-driven' is set to ")
-    (if (memq lazy-lock-defer-driven '(nil t))
-       (princ lazy-lock-defer-driven)
-      (princ "`")
-      (princ lazy-lock-defer-driven)
-      (princ "'"))
-    (princ ".\n")
-    (princ "This variable is now called `lazy-lock-defer-on-scrolling',\n")
-    (princ "so instead use ")
-    (princ (substitute-command-keys "\\[customize-option]"))
-    (princ " to modify the variable, or put the form:\n")
-    (princ " (setq lazy-lock-defer-on-scrolling ")
-    (unless (memq lazy-lock-defer-driven '(nil t))
-      (princ "'"))
-    (princ lazy-lock-defer-driven)
-    (princ ")\n")
-    (princ "in your ~/.emacs.  ")
-    (princ "The above form has been evaluated for this editor session,\n")
-    (princ "but you should use ")
-    (princ (substitute-command-keys "\\[customize-option]"))
-    (princ " or change your ~/.emacs now."))
-  (setq lazy-lock-defer-on-scrolling lazy-lock-defer-driven))
-
-;; Install ourselves:
-
-(add-hook 'window-size-change-functions #'lazy-lock-fontify-after-resize)
-(add-hook 'redisplay-end-trigger-functions #'lazy-lock-fontify-after-trigger)
-
-(unless (assq 'lazy-lock-mode minor-mode-alist)
-  (setq minor-mode-alist (append minor-mode-alist '((lazy-lock-mode nil)))))
-
-(provide 'lazy-lock)
-
-;; Local Variables:
-;; byte-compile-warnings: (not obsolete)
-;; End:
-
-;;; lazy-lock.el ends here
diff --git a/lisp/obsolete/longlines.el b/lisp/obsolete/longlines.el
index 731f47794c..1e2ae698c6 100644
--- a/lisp/obsolete/longlines.el
+++ b/lisp/obsolete/longlines.el
@@ -73,6 +73,11 @@ You can also enable the display temporarily, using the 
command
 This is used when `longlines-show-hard-newlines' is on."
   :type 'string)
 
+(defcustom longlines-break-chars " ;,|"
+  "A bag of separator chars for longlines."
+  :version "29.1"
+  :type 'string)
+
 ;;; Internal variables
 
 (defvar longlines-wrap-beg nil)
@@ -115,7 +120,6 @@ newlines are indicated with a symbol."
         (add-to-list 'buffer-file-format 'longlines)
         (add-hook 'change-major-mode-hook #'longlines-mode-off nil t)
        (add-hook 'before-revert-hook #'longlines-before-revert-hook nil t)
-        (make-local-variable 'buffer-substring-filters)
         (make-local-variable 'longlines-auto-wrap)
        (set (make-local-variable 'isearch-search-fun-function)
             #'longlines-search-function)
@@ -123,7 +127,8 @@ newlines are indicated with a symbol."
             #'longlines-search-forward)
        (set (make-local-variable 'replace-re-search-function)
             #'longlines-re-search-forward)
-        (add-to-list 'buffer-substring-filters 'longlines-encode-string)
+        (add-function :filter-return (local 'filter-buffer-substring-function)
+                      #'longlines-encode-string)
         (when longlines-wrap-follows-window-size
          (let ((dw (if (and (integerp longlines-wrap-follows-window-size)
                             (>= longlines-wrap-follows-window-size 0)
@@ -140,7 +145,7 @@ newlines are indicated with a symbol."
              (inhibit-modification-hooks t)
               (mod (buffer-modified-p))
              buffer-file-name buffer-file-truename)
-          ;; Turning off undo is OK since (spaces + newlines) is
+          ;; Turning off undo is OK since (separators + newlines) is
           ;; conserved, except for a corner case in
           ;; longlines-wrap-lines that we'll never encounter from here
          (save-restriction
@@ -199,7 +204,8 @@ newlines are indicated with a symbol."
     (kill-local-variable 'replace-search-function)
     (kill-local-variable 'replace-re-search-function)
     (kill-local-variable 'require-final-newline)
-    (kill-local-variable 'buffer-substring-filters)
+    (remove-function (local 'filter-buffer-substring-function)
+                     #'longlines-encode-string)
     (kill-local-variable 'use-hard-newlines)))
 
 (defun longlines-mode-off ()
@@ -273,11 +279,8 @@ end of the buffer."
   "If the current line needs to be wrapped, wrap it and return nil.
 If wrapping is performed, point remains on the line.  If the line does
 not need to be wrapped, move point to the next line and return t."
-  (if (longlines-set-breakpoint)
+  (if (longlines-set-breakpoint fill-column)
       (progn (insert-before-markers-and-inherit ?\n)
-            (backward-char 1)
-             (delete-char -1)
-            (forward-char 1)
              nil)
     (if (longlines-merge-lines-p)
         (progn (end-of-line)
@@ -286,58 +289,60 @@ not need to be wrapped, move point to the next line and 
return t."
      ;; replace these two newlines by a single space.  Unfortunately,
      ;; this breaks the conservation of (spaces + newlines), so we
      ;; have to fiddle with longlines-wrap-point.
-              (if (or (prog1 (bolp) (forward-char 1)) (eolp))
-                  (progn
-                    (delete-char -1)
-                    (if (> longlines-wrap-point (point))
-                        (setq longlines-wrap-point
-                              (1- longlines-wrap-point))))
-                (insert-before-markers-and-inherit ?\s)
-                (backward-char 1)
-                (delete-char -1)
-                (forward-char 1))
+               (if (or (prog1 (bolp) (forward-char 1)) (eolp))
+                  (progn
+                    (delete-char -1)
+                    (if (> longlines-wrap-point (point))
+                        (setq longlines-wrap-point
+                              (1- longlines-wrap-point))))
+                (delete-char -1))
                nil)
       (forward-line 1)
       t)))
 
-(defun longlines-set-breakpoint ()
+(defun longlines-set-breakpoint (target-column)
   "Place point where we should break the current line, and return t.
 If the line should not be broken, return nil; point remains on the
 line."
-  (move-to-column fill-column)
-  (if (and (re-search-forward "[^ ]" (line-end-position) 1)
-           (> (current-column) fill-column))
-      ;; This line is too long.  Can we break it?
-      (or (longlines-find-break-backward)
-          (progn (move-to-column fill-column)
-                 (longlines-find-break-forward)))))
+  (move-to-column target-column)
+  (let ((non-break-re (format "[^%s]" longlines-break-chars)))
+    (if (and (re-search-forward non-break-re (line-end-position) t 1)
+             (> (current-column) target-column))
+        ;; This line is too long.  Can we break it?
+        (or (longlines-find-break-backward)
+            (progn (move-to-column target-column)
+                   (longlines-find-break-forward))))))
 
 (defun longlines-find-break-backward ()
   "Move point backward to the first available breakpoint and return t.
 If no breakpoint is found, return nil."
-  (and (search-backward " " (line-beginning-position) 1)
-       (save-excursion
-         (skip-chars-backward " " (line-beginning-position))
-         (null (bolp)))
-       (progn (forward-char 1)
-              (if (and fill-nobreak-predicate
-                       (run-hook-with-args-until-success
-                        'fill-nobreak-predicate))
-                  (progn (skip-chars-backward " " (line-beginning-position))
-                         (longlines-find-break-backward))
-                t))))
+  (let ((break-re (format "[%s]" longlines-break-chars)))
+    (when (and (re-search-backward break-re (line-beginning-position) t 1)
+               (save-excursion
+                 (skip-chars-backward longlines-break-chars
+                                      (line-beginning-position))
+                 (null (bolp))))
+      (forward-char 1)
+      (if (and fill-nobreak-predicate
+               (run-hook-with-args-until-success 'fill-nobreak-predicate))
+          (progn
+            (skip-chars-backward longlines-break-chars
+                                 (line-beginning-position))
+            (longlines-find-break-backward))
+        t))))
 
 (defun longlines-find-break-forward ()
   "Move point forward to the first available breakpoint and return t.
 If no break point is found, return nil."
-  (and (search-forward " " (line-end-position) 1)
-       (progn (skip-chars-forward " " (line-end-position))
-              (null (eolp)))
-       (if (and fill-nobreak-predicate
-                (run-hook-with-args-until-success
-                 'fill-nobreak-predicate))
-           (longlines-find-break-forward)
-         t)))
+  (let ((break-re (format "[%s]" longlines-break-chars)))
+    (and (re-search-forward break-re (line-end-position) t 1)
+         (progn
+           (skip-chars-forward longlines-break-chars (line-end-position))
+           (null (eolp)))
+         (if (and fill-nobreak-predicate
+                  (run-hook-with-args-until-success 'fill-nobreak-predicate))
+             (longlines-find-break-forward)
+           t))))
 
 (defun longlines-merge-lines-p ()
   "Return t if part of the next line can fit onto the current line.
@@ -348,12 +353,7 @@ Otherwise, return nil.  Text cannot be moved across hard 
newlines."
          (null (get-text-property (point) 'hard))
          (let ((space (- fill-column (current-column))))
            (forward-line 1)
-           (if (eq (char-after) ? )
-               t ; We can always merge some spaces
-             (<= (if (search-forward " " (line-end-position) 1)
-                     (current-column)
-                   (1+ (current-column)))
-                 space))))))
+           (longlines-set-breakpoint (max 0 (1- space)))))))
 
 (defun longlines-decode-region (&optional beg end)
   "Turn all newlines between BEG and END into hard newlines.
@@ -372,7 +372,7 @@ If BEG and END are nil, the point and mark are used."
   (longlines-decode-region (point-min) (point-max)))
 
 (defun longlines-encode-region (beg end &optional _buffer)
-  "Replace each soft newline between BEG and END with exactly one space.
+  "Remove each soft newline between BEG and END.
 Hard newlines are left intact.  The optional argument BUFFER exists for
 compatibility with `format-alist', and is ignored."
   (save-excursion
@@ -382,23 +382,28 @@ compatibility with `format-alist', and is ignored."
       (while (search-forward "\n" reg-max t)
        (let ((pos (match-beginning 0)))
          (unless (get-text-property pos 'hard)
-           (goto-char (1+ pos))
-           (insert-and-inherit " ")
-           (delete-region pos (1+ pos))
-            (remove-text-properties pos (1+ pos) '(hard nil)))))
+            (remove-text-properties pos (1+ pos) '(hard nil))
+            (delete-region pos (1+ pos)))))
       (set-buffer-modified-p mod)
       end)))
 
 (defun longlines-encode-string (string)
-  "Return a copy of STRING with each soft newline replaced by a space.
+  "Return a copy of STRING with each soft newline removed.
 Hard newlines are left intact."
-  (let* ((str (copy-sequence string))
-         (pos (string-search "\n" str)))
-    (while pos
-      (if (null (get-text-property pos 'hard str))
-          (aset str pos ? ))
-      (setq pos (string-search "\n" str (1+ pos))))
-    str))
+  (let ((start 0)
+        (result nil)
+        pos)
+    (while (setq pos (string-search "\n" string start))
+      (unless (= start pos)
+        (push (substring string start pos) result))
+      (when (get-text-property pos 'hard string)
+        (push (substring string pos (1+ pos)) result))
+      (setq start (1+ pos)))
+    (if (null result)
+        (copy-sequence string)
+      (unless (= start (length string))
+        (push (substring string start) result))
+      (apply #'concat (nreverse result)))))
 
 ;;; Auto wrap
 
diff --git a/lisp/obsolete/mailpost.el b/lisp/obsolete/mailpost.el
deleted file mode 100644
index 5b3a76e2f7..0000000000
--- a/lisp/obsolete/mailpost.el
+++ /dev/null
@@ -1,101 +0,0 @@
-;;; mailpost.el --- RMAIL coupler to /usr/uci/post mailer  -*- 
lexical-binding: t; -*-
-
-;; This is in the public domain
-;; since Delp distributed it in 1986 without a copyright notice.
-
-;; This file is part of GNU Emacs.
-
-;; Author: Gary Delp <delp@huey.Udel.Edu>
-;; Maintainer: emacs-devel@gnu.org
-;; Created: 13 Jan 1986
-;; Keywords: mail
-;; Obsolete-since: 24.3
-
-;;; Commentary:
-
-;; Yet another mail interface.  this for the rmail system to provide
-;;  the missing sendmail interface on systems without /usr/lib/sendmail,
-;;   but with /usr/uci/post.
-
-;;; Code:
-
-(require 'mailalias)
-(require 'sendmail)
-
-;; (setq send-mail-function 'post-mail-send-it)
-
-(defun post-mail-send-it ()
-  "The MH -post interface for `rmail-mail' to call.
-To use it, include \"(setq send-mail-function \\='post-mail-send-it)\" in
-site-init."
-  (let ((errbuf (if mail-interactive
-                   (generate-new-buffer " post-mail errors")
-                 0))
-       temfile
-       (tembuf (generate-new-buffer " post-mail temp"))
-       (case-fold-search nil)
-       delimline
-       (mailbuf (current-buffer)))
-    (unwind-protect
-       (with-current-buffer tembuf
-         (erase-buffer)
-         (insert-buffer-substring mailbuf)
-         (goto-char (point-max))
-         ;; require one newline at the end.
-         (or (= (preceding-char) ?\n)
-             (insert ?\n))
-         ;; Change header-delimiter to be what post-mail expects.
-         (mail-sendmail-undelimit-header)
-         (setq delimline (point-marker))
-         (if mail-aliases
-             (expand-mail-aliases (point-min) delimline))
-         (goto-char (point-min))
-         ;; ignore any blank lines in the header
-         (while (and (re-search-forward "\n\n\n*" delimline t)
-                     (< (point) delimline))
-           (replace-match "\n"))
-         ;; Find and handle any Fcc fields.
-         (let ((case-fold-search t))
-           (goto-char (point-min))
-           (if (re-search-forward "^Fcc:" delimline t)
-               (mail-do-fcc delimline))
-           ;; If there is a From and no Sender, put it a Sender.
-           (goto-char (point-min))
-           (and (re-search-forward "^From:"  delimline t)
-                (not (save-excursion
-                       (goto-char (point-min))
-                       (re-search-forward "^Sender:" delimline t)))
-                (progn
-                  (forward-line 1)
-                  (insert "Sender: " (user-login-name) "\n")))
-           ;; don't send out a blank subject line
-           (goto-char (point-min))
-           (if (re-search-forward "^Subject:[ \t]*\n" delimline t)
-               (replace-match ""))
-           (if mail-interactive
-               (with-current-buffer errbuf
-                 (erase-buffer))))
-         (with-file-modes 384 (setq temfile (make-temp-file ",rpost")))
-         (apply #'call-process
-                (append (list (if (boundp 'post-mail-program)
-                                  post-mail-program
-                                "/usr/uci/lib/mh/post")
-                              nil errbuf nil
-                              "-nofilter" "-msgid")
-                        (if mail-interactive '("-watch") '("-nowatch"))
-                        (list temfile)))
-         (if mail-interactive
-             (with-current-buffer errbuf
-               (goto-char (point-min))
-               (while (re-search-forward "\n\n* *" nil t)
-                 (replace-match "; "))
-               (if (not (zerop (buffer-size)))
-                   (error "Sending...failed to %s"
-                          (buffer-substring (point-min) (point-max)))))))
-      (kill-buffer tembuf)
-      (if (bufferp errbuf)
-         (switch-to-buffer errbuf)))))
-
-(provide 'mailpost)
-
-;;; mailpost.el ends here
diff --git a/lisp/obsolete/makesum.el b/lisp/obsolete/makesum.el
new file mode 100644
index 0000000000..3e343c9537
--- /dev/null
+++ b/lisp/obsolete/makesum.el
@@ -0,0 +1,107 @@
+;;; makesum.el --- generate key binding summary for Emacs  -*- 
lexical-binding:t -*-
+
+;; Copyright (C) 1985, 2001-2022 Free Software Foundation, Inc.
+
+;; Maintainer: emacs-devel@gnu.org
+;; Keywords: help
+;; Obsolete-since: 29.1
+
+;; 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:
+
+;; Displays a nice human-readable summary of all keybindings in a
+;; two-column format.
+
+;;; Code:
+
+;;;###autoload
+(defun make-command-summary ()
+  "Make a summary of current key bindings in the buffer *Summary*.
+Previous contents of that buffer are killed first."
+  (interactive)
+  ;; This puts a description of bindings in a buffer called *Help*.
+  (save-window-excursion
+   (describe-bindings))
+  (with-output-to-temp-buffer "*Summary*"
+    (save-excursion
+     (let ((cur-mode mode-name))
+       (set-buffer standard-output)
+       (erase-buffer)
+       (insert-buffer-substring "*Help*")
+       (goto-char (point-min))
+       (delete-region (point) (progn (forward-line 1) (point)))
+       (while (search-forward "         " nil t)
+        (replace-match "  "))
+       (goto-char (point-min))
+       (while (search-forward "-@ " nil t)
+        (replace-match "-SP"))
+       (goto-char (point-min))
+       (while (search-forward "  .. ~ " nil t)
+        (replace-match "SP .. ~"))
+       (goto-char (point-min))
+       (while (search-forward "C-?" nil t)
+        (replace-match "DEL"))
+       (goto-char (point-min))
+       (while (search-forward "C-i" nil t)
+        (replace-match "TAB"))
+       (goto-char (point-min))
+       (when (re-search-forward "^Local Bindings:" nil t)
+         (forward-char -1)
+         (insert " for " (format-mode-line cur-mode) " Mode")
+         (while (search-forward "??\n" nil t)
+           (delete-region (point)
+                          (progn
+                            (forward-line -1)
+                            (point)))))
+       (goto-char (point-min))
+       (insert "Emacs command summary\n")
+       ;; Delete "key    binding" and underlining of dashes.
+       (delete-region (point) (progn (forward-line 2) (point)))
+       (forward-line 1)                        ;Skip blank line
+       (while (not (eobp))
+        (let ((beg (point)))
+          (or (re-search-forward "^$" nil t)
+              (goto-char (point-max)))
+          (double-column beg (point))
+          (forward-line 1)))
+       (goto-char (point-min))))))
+
+(defun double-column (start end)
+  "Reformat buffer contents from START to END into two columns."
+  (interactive "r")
+  (let (half lines
+        (nlines (count-lines start end))
+       (from-end (- (point-max) end)))
+    (when (> nlines 1)
+      (setq half (/ (1+ nlines) 2))
+      (goto-char start)
+      (save-excursion
+       (forward-line half)
+       (dotimes (_ (- nlines half))
+         (push (buffer-substring (point) (line-end-position))
+               lines)
+        (delete-region (point) (progn (forward-line 1) (point)))))
+      (dolist (line (nreverse lines))
+        (end-of-line)
+       (indent-to 41)
+        (insert line)
+        (forward-line 1)))
+    (goto-char (- (point-max) from-end))))
+
+(provide 'makesum)
+
+;;; makesum.el ends here
diff --git a/lisp/obsolete/mh-compat.el b/lisp/obsolete/mh-compat.el
new file mode 100644
index 0000000000..a5be3bd742
--- /dev/null
+++ b/lisp/obsolete/mh-compat.el
@@ -0,0 +1,136 @@
+;;; mh-compat.el --- make MH-E compatible with various versions of Emacs  -*- 
lexical-binding: t; -*-
+
+;; Copyright (C) 2006-2022 Free Software Foundation, Inc.
+
+;; Author: Bill Wohler <wohler@newt.com>
+;; Keywords: mail
+;; See: mh-e.el
+;; Obsolete-since: 29.1
+
+;; 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:
+
+;; This is a good place to gather code that is used for compatibility
+;; between different versions of Emacs. Please document which versions
+;; of Emacs that the defsubst, defalias, or defmacro applies. That
+;; way, it's easy to occasionally go through this file and see which
+;; macros we can retire.
+
+;; Please use mh-gnus.el when providing compatibility with different
+;; versions of Gnus.
+
+;; Items are listed alphabetically.
+
+(eval-when-compile (require 'mh-acros))
+
+(define-obsolete-function-alias 'mh-require #'require "29.1")
+(define-obsolete-function-alias 'mh-assoc-string #'assoc-string "29.1")
+(define-obsolete-function-alias 'mh-cancel-timer #'cancel-timer "29.1")
+
+(define-obsolete-function-alias 'mh-display-color-cells
+  #'display-color-cells "29.1")
+
+(defmacro mh-display-completion-list (completions &optional common-substring)
+  "Display the list of COMPLETIONS.
+See documentation for `display-completion-list' for a description of the
+arguments COMPLETIONS.
+The optional argument COMMON-SUBSTRING, if non-nil, should be a string
+specifying a common substring for adding the faces
+`completions-first-difference' and `completions-common-part' to
+the completions."
+  (declare (obsolete nil "29.1"))
+  `(display-completion-list
+    (completion-hilit-commonality ,completions
+                                  ,(length common-substring) nil)))
+
+(define-obsolete-function-alias 'mh-face-foreground
+  #'face-foreground "29.1")
+
+(define-obsolete-function-alias 'mh-face-background
+  #'face-background "29.1")
+
+(define-obsolete-function-alias 'mh-font-lock-add-keywords
+  #'font-lock-add-keywords "29.1")
+
+;; Not preloaded in without-x builds.
+(declare-function image-load-path-for-library "image")
+(define-obsolete-function-alias 'mh-image-load-path-for-library
+  #'image-load-path-for-library "29.1")
+
+;; Not preloaded in without-x builds.
+(declare-function image-search-load-path "image")
+(define-obsolete-function-alias 'mh-image-search-load-path
+  #'image-search-load-path "29.1")
+
+(define-obsolete-function-alias 'mh-line-beginning-position
+  #'line-beginning-position "29.1")
+
+(define-obsolete-function-alias 'mh-line-end-position
+  #'line-end-position "29.1")
+
+(require 'mailabbrev)
+(define-obsolete-function-alias 'mh-mail-abbrev-make-syntax-table
+  #'mail-abbrev-make-syntax-table "29.1")
+
+(define-obsolete-function-alias 'mh-define-obsolete-variable-alias
+  #'define-obsolete-variable-alias "29.1")
+
+(define-obsolete-function-alias 'mh-make-obsolete-variable
+  #'make-obsolete-variable "29.1")
+
+(define-obsolete-function-alias 'mh-match-string-no-properties
+  #'match-string-no-properties "29.1")
+
+(define-obsolete-function-alias 'mh-replace-regexp-in-string
+  #'replace-regexp-in-string "29.1")
+
+(define-obsolete-function-alias 'mh-test-completion
+  #'test-completion "29.1")
+
+(defconst mh-url-unreserved-chars
+  '(
+    ?a ?b ?c ?d ?e ?f ?g ?h ?i ?j ?k ?l ?m ?n ?o ?p ?q ?r ?s ?t ?u ?v ?w ?x ?y 
?z
+       ?A ?B ?C ?D ?E ?F ?G ?H ?I ?J ?K ?L ?M ?N ?O ?P ?Q ?R ?S ?T ?U ?V ?W ?X 
?Y ?Z
+       ?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9
+       ?- ?_ ?. ?! ?~ ?* ?' ?\( ?\))
+  "A list of characters that are _NOT_ reserved in the URL spec.
+This is taken from RFC 2396.")
+(make-obsolete-variable 'mh-url-unreserved-chars 'url-unreserved-chars "29.1")
+
+(define-obsolete-function-alias 'mh-url-hexify-string
+  #'url-hexify-string "29.1")
+
+(define-obsolete-function-alias 'mh-view-mode-enter
+  #'view-mode-enter "29.1")
+
+(define-obsolete-function-alias 'mh-window-full-height-p
+  #'window-full-height-p "29.1")
+
+(defmacro mh-write-file-functions ()
+  "Return `write-file-functions'."
+  (declare (obsolete nil "29.1"))
+  ''write-file-functions)
+
+(provide 'mh-compat)
+
+;; Local Variables:
+;; sentence-end-double-space: nil
+;; End:
+
+;;; mh-compat.el ends here
diff --git a/lisp/obsolete/mouse-sel.el b/lisp/obsolete/mouse-sel.el
deleted file mode 100644
index 3eacac65fb..0000000000
--- a/lisp/obsolete/mouse-sel.el
+++ /dev/null
@@ -1,731 +0,0 @@
-;;; mouse-sel.el --- multi-click selection support  -*- lexical-binding: t; -*-
-
-;; Copyright (C) 1993-1995, 2001-2022 Free Software Foundation, Inc.
-
-;; Author: Mike Williams <mdub@bigfoot.com>
-;; Keywords: mouse
-;; Obsolete-since: 24.3
-
-;; 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 module provides multi-click mouse support for GNU Emacs versions
-;; 19.18 and later.  I've tried to make it behave more like standard X
-;; clients (eg. xterm) than the default Emacs 19 mouse selection handlers.
-;; Basically:
-;;
-;;   * Clicking mouse-1 starts (cancels) selection, dragging extends it.
-;;
-;;   * Clicking or dragging mouse-3 extends the selection as well.
-;;
-;;   * Double-clicking on word constituents selects words.
-;;     Double-clicking on symbol constituents selects symbols.
-;;     Double-clicking on quotes or parentheses selects sexps.
-;;     Double-clicking on whitespace selects whitespace.
-;;     Triple-clicking selects lines.
-;;     Quad-clicking selects paragraphs.
-;;
-;;   * Selecting sets the region & X primary selection, but does NOT affect
-;;     the kill-ring.  Because the mouse handlers set the primary selection
-;;     directly, mouse-sel sets the variables interprogram-cut-function
-;;     and interprogram-paste-function to nil.
-;;
-;;   * Clicking mouse-2 inserts the contents of the primary selection at
-;;     the mouse position (or point, if mouse-yank-at-point is non-nil).
-;;
-;;   * Pressing mouse-2 while selecting or extending copies selection
-;;     to the kill ring.  Pressing mouse-1 or mouse-3 kills it.
-;;
-;;   * Double-clicking mouse-3 also kills selection.
-;;
-;;   * M-mouse-1, M-mouse-2 & M-mouse-3 work similarly to mouse-1, mouse-2
-;;     & mouse-3, but operate on the X secondary selection rather than the
-;;     primary selection and region.
-;;
-;; This module requires my thingatpt.el module, which it uses to find the
-;; bounds of words, lines, sexps, etc.
-;;
-;; Thanks to KevinB@bartley.demon.co.uk for his useful input.
-;;
-;;--- Customization -------------------------------------------------------
-;;
-;; * You may want to use none or more of following:
-;;
-;;      ;; Enable region highlight
-;;      (transient-mark-mode 1)
-;;
-;;      ;; But only in the selected window
-;;      (setq highlight-nonselected-windows nil)
-;;
-;;      ;; Enable pending-delete
-;;      (delete-selection-mode 1)
-;;
-;; * You can control the way mouse-sel binds its keys by setting the value
-;;   of mouse-sel-default-bindings before loading mouse-sel.
-;;
-;;   (a) If mouse-sel-default-bindings = t (the default)
-;;
-;;       Mouse sets and insert selection
-;;        mouse-1              mouse-select
-;;        mouse-2              mouse-insert-selection
-;;        mouse-3              mouse-extend
-;;
-;;       Selection/kill-ring interaction is disabled
-;;         interprogram-cut-function   = nil
-;;         interprogram-paste-function = nil
-;;
-;;   (b) If mouse-sel-default-bindings = 'interprogram-cut-paste
-;;
-;;       Mouse sets selection, and pastes from kill-ring
-;;        mouse-1              mouse-select
-;;        mouse-2              mouse-insert-selection
-;;        mouse-3              mouse-extend
-;;      In this mode, mouse-insert-selection just calls mouse-yank-at-click.
-;;
-;;       Selection/kill-ring interaction is retained
-;;         interprogram-cut-function   = gui-select-text
-;;         interprogram-paste-function = gui-selection-value
-;;
-;;       What you lose is the ability to select some text in
-;;       delete-selection-mode and yank over the top of it.
-;;
-;;   (c) If mouse-sel-default-bindings = nil, no bindings are made.
-;;
-;; * By default, mouse-insert-selection (mouse-2) inserts the selection at
-;;   the mouse position.  You can tell it to insert at point instead with:
-;;
-;;     (setq mouse-yank-at-point t)
-;;
-;; * I like to leave point at the end of the region nearest to where the
-;;   mouse was, even though this makes region highlighting mis-leading (the
-;;   cursor makes it look like one extra character is selected).  You can
-;;   disable this behavior with:
-;;
-;;     (setq mouse-sel-leave-point-near-mouse nil)
-;;
-;; * By default, mouse-select cycles the click count after 4 clicks.  That
-;;   is, clicking mouse-1 five times has the same effect as clicking it
-;;   once, clicking six times has the same effect as clicking twice, etc.
-;;   Disable this behavior with:
-;;
-;;     (setq mouse-sel-cycle-clicks nil)
-;;
-;; * The variables mouse-sel-{set,get}-selection-function control how the
-;;   selection is handled.  Under X Windows, these variables default so
-;;   that the X primary selection is used.  Under other windowing systems,
-;;   alternate functions are used, which simply store the selection value
-;;   in a variable.
-
-;;; Code:
-
-(require 'mouse)
-(require 'thingatpt)
-
-;;=== User Variables ======================================================
-
-(defgroup mouse-sel nil
-  "Mouse selection enhancement."
-  :group 'mouse)
-
-(defcustom mouse-sel-leave-point-near-mouse t
-  "Leave point near last mouse position.
-If non-nil, \\[mouse-select] and \\[mouse-extend] will leave point at the end
-of the region nearest to where the mouse last was.
-If nil, point will always be placed at the beginning of the region."
-  :type 'boolean)
-
-(defcustom mouse-sel-cycle-clicks t
-  "If non-nil, \\[mouse-select] cycles the click-counts after 4 clicks."
-  :type 'boolean)
-
-(defcustom mouse-sel-default-bindings t
-  "Control mouse bindings."
-  :type '(choice (const :tag "none" nil)
-                (const :tag "cut and paste" interprogram-cut-paste)
-                (other :tag "default bindings" t)))
-
-;;=== Key bindings ========================================================
-
-(defconst mouse-sel-bound-events
-  '(;; Primary selection bindings.
-    ;;
-    ;; Bind keys to `ignore' instead of unsetting them because modes may
-    ;; bind `down-mouse-1', for instance, without binding `mouse-1'.
-    ;; If we unset `mouse-1', this leads to a bitch_at_user when the
-    ;; mouse goes up because no matching binding is found for that.
-    ([mouse-1]         . ignore)
-    ([drag-mouse-1]    . ignore)
-    ([mouse-3]         . ignore)
-    ([down-mouse-1]    . mouse-select)
-    ([down-mouse-3]    . mouse-extend)
-    ([mouse-2]         . mouse-insert-selection)
-    ;; Secondary selection bindings.
-    ([M-mouse-1]       . ignore)
-    ([M-drag-mouse-1]  . ignore)
-    ([M-mouse-3]       . ignore)
-    ([M-down-mouse-1]  . mouse-select-secondary)
-    ([M-mouse-2]       . mouse-insert-secondary)
-    ([M-down-mouse-3]  . mouse-extend-secondary))
-  "An alist of events that `mouse-sel-mode' binds.")
-
-;;=== User Command ========================================================
-
-(defvar mouse-sel-original-bindings nil)
-
-(defalias 'mouse-sel--ignore #'ignore)
-
-;;;###autoload
-(define-minor-mode mouse-sel-mode
-  "Toggle Mouse Sel mode.
-
-Mouse Sel mode is a global minor mode.  When enabled, mouse
-selection is enhanced in various ways:
-
-- Double-clicking on symbol constituents selects symbols.
-Double-clicking on quotes or parentheses selects sexps.
-Double-clicking on whitespace selects whitespace.
-Triple-clicking selects lines.
-Quad-clicking selects paragraphs.
-
-- Selecting sets the region & X primary selection, but does NOT affect
-the `kill-ring', nor do the kill-ring functions change the X selection.
-Because the mouse handlers set the primary selection directly,
-mouse-sel sets the variables `interprogram-cut-function' and
-`interprogram-paste-function' to nil.
-
-- Clicking mouse-2 inserts the contents of the primary selection at
-the mouse position (or point, if `mouse-yank-at-point' is non-nil).
-
-- mouse-2 while selecting or extending copies selection to the
-kill ring; mouse-1 or mouse-3 kills it."
-  :global t
-  (if mouse-sel-mode
-      (progn
-       ;; If mouse-2 has never been done by the user, initialize the
-       ;; `event-kind' property to ensure that `follow-link' clicks
-       ;; are interpreted correctly.
-       (put 'mouse-2 'event-kind 'mouse-click)
-       (add-hook 'x-lost-selection-functions #'mouse-sel-lost-selection-hook)
-       (when mouse-sel-default-bindings
-         ;; Save original bindings and replace them with new ones.
-         (setq mouse-sel-original-bindings
-               (mapcar (lambda (binding)
-                         (let ((event (car binding)))
-                           (prog1 (cons event (lookup-key global-map event))
-                             (global-set-key event (cdr binding)))))
-                       mouse-sel-bound-events))
-         ;; Update interprogram functions.
-         (unless (eq mouse-sel-default-bindings 'interprogram-cut-paste)
-           (add-function :override interprogram-cut-function
-                          #'mouse-sel--ignore)
-            (add-function :override interprogram-paste-function
-                          #'mouse-sel--ignore))))
-
-    ;; Restore original bindings
-    (remove-hook 'x-lost-selection-functions #'mouse-sel-lost-selection-hook)
-    (dolist (binding mouse-sel-original-bindings)
-      (global-set-key (car binding) (cdr binding)))
-    ;; Restore the old values of these variables,
-    ;; only if they were actually saved previously.
-    (remove-function interprogram-cut-function #'mouse-sel--ignore)
-    (remove-function interprogram-paste-function #'mouse-sel--ignore)))
-
-(make-obsolete 'mouse-sel-mode "use the normal mouse modes" "24.3")
-
-;;=== Internal Variables/Constants ========================================
-
-(defvar mouse-sel-primary-thing nil
-  "Type of PRIMARY selection in current buffer.")
-(make-variable-buffer-local 'mouse-sel-primary-thing)
-
-(defvar mouse-sel-secondary-thing nil
-  "Type of SECONDARY selection in current buffer.")
-(make-variable-buffer-local 'mouse-sel-secondary-thing)
-
-;; Ensure that secondary overlay is defined
-(unless (overlayp mouse-secondary-overlay)
-  (setq mouse-secondary-overlay (make-overlay 1 1))
-  (overlay-put mouse-secondary-overlay 'face 'secondary-selection))
-
-(defconst mouse-sel-primary-overlay
-  (let ((ol (make-overlay (point-min) (point-min))))
-    (delete-overlay ol)
-    (overlay-put ol 'face 'region)
-    ol)
-  "An overlay which records the current primary selection.
-This is used by Mouse Sel mode only.")
-
-(defconst mouse-sel-selection-alist
-  '((PRIMARY mouse-sel-primary-overlay mouse-sel-primary-thing)
-    (SECONDARY mouse-secondary-overlay mouse-sel-secondary-thing))
-  "Alist associating selections with variables.
-Each element is of the form:
-
-   (SELECTION-NAME OVERLAY-SYMBOL SELECTION-THING-SYMBOL)
-
-where   SELECTION-NAME          = name of selection
-        OVERLAY-SYMBOL          = name of variable containing overlay to use
-       SELECTION-THING-SYMBOL  = name of variable where the current selection
-                                 type for this selection should be stored.")
-
-(defvar mouse-sel-set-selection-function
-  (if (eq mouse-sel-default-bindings 'interprogram-cut-paste)
-      'gui-set-selection
-    (lambda (selection value)
-      (if (eq selection 'PRIMARY)
-         (gui-select-text value)
-       (gui-set-selection selection value))))
-  "Function to call to set selection.
-Called with two arguments:
-
-  SELECTION, the name of the selection concerned, and
-  VALUE, the text to store.
-
-This sets the selection, unless `mouse-sel-default-bindings'
-is `interprogram-cut-paste'.")
-
-
-(defvar mouse-sel-get-selection-function
-  (lambda (selection)
-    (if (eq selection 'PRIMARY)
-       (or (gui-selection-value)
-           (bound-and-true-p x-last-selected-text-primary)
-            gui--last-selected-text-primary)
-      (gui-get-selection selection)))
-  "Function to call to get the selection.
-Called with one argument:
-
-   SELECTION: the name of the selection concerned.")
-
-;;=== Support/access functions ============================================
-
-(defun mouse-sel-determine-selection-thing (nclicks)
-  "Determine what `thing' `mouse-sel' should operate on.
-The first argument is NCLICKS, is the number of consecutive
-mouse clicks at the same position.
-
-Double-clicking on word constituents selects words.
-Double-clicking on symbol constituents selects symbols.
-Double-clicking on quotes or parentheses selects sexps.
-Double-clicking on whitespace selects whitespace.
-Triple-clicking selects lines.
-Quad-clicking selects paragraphs.
-
-Feel free to re-define this function to support your own desired
-multi-click semantics."
-  (let* ((next-char (char-after (point)))
-        (char-syntax (if next-char (char-syntax next-char))))
-    (if mouse-sel-cycle-clicks
-       (setq nclicks (1+ (% (1- nclicks) 4))))
-    (cond
-     ((= nclicks 1) nil)
-     ((= nclicks 3) 'line)
-     ((>= nclicks 4) 'paragraph)
-     ((memq char-syntax '(?\( ?\) ?\" ?')) 'sexp)
-     ((memq next-char '(?\s ?\t ?\n)) 'whitespace)
-     ((eq char-syntax ?_) 'symbol)
-     ((eq char-syntax ?w) 'word))))
-
-(defun mouse-sel-set-selection (selection value)
-  "Set the specified SELECTION to VALUE."
-  (if mouse-sel-set-selection-function
-      (funcall mouse-sel-set-selection-function selection value)
-    (put 'mouse-sel-internal-selection selection value)))
-
-(defun mouse-sel-get-selection (selection)
-  "Get the value of the specified SELECTION."
-  (if mouse-sel-get-selection-function
-      (funcall mouse-sel-get-selection-function selection)
-    (get 'mouse-sel-internal-selection selection)))
-
-(defun mouse-sel-selection-overlay (selection)
-  "Return overlay corresponding to SELECTION."
-  (let ((symbol (nth 1 (assoc selection mouse-sel-selection-alist))))
-    (or symbol (error "No overlay corresponding to %s selection" selection))
-    (symbol-value symbol)))
-
-(defun mouse-sel-selection-thing (selection)
-  "Return overlay corresponding to SELECTION."
-  (let ((symbol (nth 2 (assoc selection mouse-sel-selection-alist))))
-    (or symbol (error "No symbol corresponding to %s selection" selection))
-    symbol))
-
-(defun mouse-sel-region-to-primary (orig-window)
-  "Convert region to PRIMARY overlay and deactivate region.
-Argument ORIG-WINDOW specifies the window the cursor was in when the
-originating command was issued, and is used to determine whether the
-region was visible or not."
-  (if transient-mark-mode
-      (let ((overlay (mouse-sel-selection-overlay 'PRIMARY)))
-       (cond
-        ((and mark-active
-              (or highlight-nonselected-windows
-                  (eq orig-window (selected-window))))
-         ;; Region was visible, so convert region to overlay
-         (move-overlay overlay (region-beginning) (region-end)
-                       (current-buffer)))
-        ((eq orig-window (selected-window))
-         ;; Point was visible, so set overlay at point
-         (move-overlay overlay (point) (point) (current-buffer)))
-        (t
-         ;; Nothing was visible, so remove overlay
-         (delete-overlay overlay)))
-       (setq mark-active nil))))
-
-(defun mouse-sel-primary-to-region (&optional direction)
-  "Convert PRIMARY overlay to region.
-Optional argument DIRECTION specifies the mouse drag direction: a value of
-1 indicates that the mouse was dragged left-to-right, otherwise it was
-dragged right-to-left."
-  (let* ((overlay (mouse-sel-selection-overlay 'PRIMARY))
-        (start (overlay-start overlay))
-        (end (overlay-end overlay)))
-    (if (eq start end)
-       (progn
-         (if start (goto-char start))
-         (deactivate-mark))
-      (if (and mouse-sel-leave-point-near-mouse (eq direction 1))
-         (progn
-           (goto-char end)
-           (push-mark start 'nomsg 'active))
-       (goto-char start)
-       (push-mark end 'nomsg 'active)))
-    (if transient-mark-mode (delete-overlay overlay))))
-
-(defmacro mouse-sel-eval-at-event-end (event &rest forms)
-  "Evaluate forms at mouse position.
-Move to the end position of EVENT, execute FORMS, and restore original
-point and window."
-  `(let ((posn (event-end ,event)))
-    (if posn (mouse-minibuffer-check ,event))
-    (if (and posn (not (windowp (posn-window posn))))
-        (error "Cursor not in text area of window"))
-    (let (orig-window orig-point-marker)
-      (setq orig-window (selected-window))
-      (if posn (select-window (posn-window posn)))
-      (setq orig-point-marker (point-marker))
-      (if (and posn (numberp (posn-point posn)))
-          (goto-char (posn-point posn)))
-      (unwind-protect
-           (progn
-             ,@forms)
-        (goto-char (marker-position orig-point-marker))
-        (move-marker orig-point-marker nil)
-        (select-window orig-window)))))
-
-(put 'mouse-sel-eval-at-event-end 'lisp-indent-hook 1)
-
-;;=== Select ==============================================================
-
-(defun mouse-select (event)
-  "Set region/selection using the mouse.
-
-Click sets point & mark to click position.
-Dragging extends region/selection.
-
-Multi-clicking selects word/lines/paragraphs, as determined by
-`mouse-sel-determine-selection-thing'.
-
-Clicking mouse-2 while selecting copies selected text to the kill-ring.
-Clicking mouse-1 or mouse-3 kills the selected text.
-
-This should be bound to a down-mouse event."
-  (interactive "@e")
-  (let (select)
-    (unwind-protect
-       (setq select (mouse-select-internal 'PRIMARY event))
-      (if (and select (listp select))
-         (push (cons 'mouse-2 (cdr event)) unread-command-events)
-       (mouse-sel-primary-to-region select)))))
-
-(defun mouse-select-secondary (event)
-  "Set secondary selection using the mouse.
-
-Click sets the start of the secondary selection to click position.
-Dragging extends the secondary selection.
-
-Multi-clicking selects word/lines/paragraphs, as determined by
-`mouse-sel-determine-selection-thing'.
-
-Clicking mouse-2 while selecting copies selected text to the kill-ring.
-Clicking mouse-1 or mouse-3 kills the selected text.
-
-This should be bound to a down-mouse event."
-  (interactive "e")
-  (mouse-select-internal 'SECONDARY event))
-
-(defun mouse-select-internal (selection event)
-  "Set SELECTION using the mouse, with EVENT as the initial down-event.
-Normally, this returns the direction in which the selection was
-made: a value of 1 indicates that the mouse was dragged
-left-to-right, otherwise it was dragged right-to-left.
-
-However, if `mouse-1-click-follows-link' is non-nil and the
-subsequent mouse events specify following a link, this returns
-the final mouse-event.  In that case, the selection is not set."
-  (mouse-sel-eval-at-event-end event
-    (let ((thing-symbol (mouse-sel-selection-thing selection))
-         (overlay (mouse-sel-selection-overlay selection)))
-      (set thing-symbol
-          (mouse-sel-determine-selection-thing (event-click-count event)))
-      (let ((object-bounds (bounds-of-thing-at-point
-                           (symbol-value thing-symbol))))
-       (if object-bounds
-           (progn
-             (move-overlay overlay
-                           (car object-bounds) (cdr object-bounds)
-                           (current-buffer)))
-         (move-overlay overlay (point) (point) (current-buffer)))))
-    (catch 'follow-link
-      (mouse-extend-internal selection event t))))
-
-;;=== Extend ==============================================================
-
-(defun mouse-extend (event)
-  "Extend region/selection using the mouse."
-  (interactive "e")
-  (let ((orig-window (selected-window))
-       direction)
-    (select-window (posn-window (event-end event)))
-    (unwind-protect
-       (progn
-         (mouse-sel-region-to-primary orig-window)
-         (setq direction (mouse-extend-internal 'PRIMARY event)))
-      (mouse-sel-primary-to-region direction))))
-
-(defun mouse-extend-secondary (event)
-  "Extend secondary selection using the mouse."
-  (interactive "e")
-  (save-window-excursion
-    (mouse-extend-internal 'SECONDARY event)))
-
-(defun mouse-extend-internal (selection &optional initial-event no-process)
-  "Extend specified SELECTION using the mouse.
-Track mouse-motion events, adjusting the SELECTION appropriately.
-Optional argument INITIAL-EVENT specifies an initial down-mouse event.
-Optional argument NO-PROCESS means not to process the initial
-event.
-
-See documentation for mouse-select-internal for more details."
-  (mouse-sel-eval-at-event-end initial-event
-    (let ((orig-cursor-type
-          (cdr (assoc 'cursor-type (frame-parameters (selected-frame))))))
-      (unwind-protect
-
-         (let* ((thing-symbol (mouse-sel-selection-thing selection))
-                (overlay (mouse-sel-selection-overlay selection))
-                (orig-window (selected-window))
-                (top (nth 1 (window-edges orig-window)))
-                (bottom (nth 3 (window-edges orig-window)))
-                (mark-active nil)      ; inhibit normal region highlight
-                (echo-keystrokes 0)    ; don't echo mouse events
-                min max
-                direction
-                event)
-
-           ;; Get current bounds of overlay
-           (if (eq (overlay-buffer overlay) (current-buffer))
-               (setq min (overlay-start overlay)
-                     max (overlay-end overlay))
-             (setq min (point)
-                   max min)
-             (set thing-symbol nil))
-
-
-           ;; Bar cursor
-           (if (fboundp 'modify-frame-parameters)
-               (modify-frame-parameters (selected-frame)
-                                        '((cursor-type . bar))))
-
-           ;; Handle dragging
-           (track-mouse
-
-             (while (if (and initial-event (not no-process))
-                        ;; Use initial event
-                        (prog1
-                            (setq event initial-event)
-                          (setq initial-event nil))
-                      (setq event (read-event))
-                      (and (consp event)
-                           (memq (car event) '(mouse-movement switch-frame))))
-
-               (let ((selection-thing (symbol-value thing-symbol))
-                     (end (event-end event)))
-
-                 (cond
-
-                  ;; Ignore any movement outside the frame
-                  ((eq (car-safe event) 'switch-frame) nil)
-                  ((and (posn-window end)
-                        (not (eq (let ((posn-w (posn-window end)))
-                                   (if (windowp posn-w)
-                                       (window-frame posn-w)
-                                     posn-w))
-                                 (window-frame orig-window)))) nil)
-
-                  ;; Different window, same frame
-                  ((not (eq (posn-window end) orig-window))
-                   (let ((end-row (cdr (cdr (mouse-position)))))
-                     (cond
-                      ((and end-row (not (bobp)) (< end-row top))
-                       (mouse-scroll-subr orig-window (- end-row top)
-                                          overlay max))
-                      ((and end-row (not (eobp)) (>= end-row bottom))
-                       (mouse-scroll-subr orig-window (1+ (- end-row bottom))
-                                          overlay min))
-                      )))
-
-                  ;; On the mode line
-                  ((eq (posn-point end) 'mode-line)
-                   (mouse-scroll-subr orig-window 1 overlay min))
-
-                  ;; In original window
-                  (t (goto-char (posn-point end)))
-
-                  )
-
-                 ;; Determine direction of drag
-                 (cond
-                  ((and (not direction) (not (eq min max)))
-                   (setq direction (if (< (point) (/ (+ min max) 2)) -1 1)))
-                  ((and (not (eq direction -1)) (<= (point) min))
-                   (setq direction -1))
-                  ((and (not (eq direction 1)) (>= (point) max))
-                   (setq direction 1)))
-
-                 (if (not selection-thing) nil
-
-                   ;; If dragging forward, goal is next character
-                   (if (and (eq direction 1) (not (eobp))) (forward-char 1))
-
-                   ;; Move to start/end of selected thing
-                   (let ((goal (point)))
-                     (goto-char (if (eq 1 direction) min max))
-                     (condition-case nil
-                         (progn
-                           (while (> (* direction (- goal (point))) 0)
-                             (forward-thing selection-thing direction))
-                           (let ((end (point)))
-                             (forward-thing selection-thing (- direction))
-                             (goto-char
-                              (if (> (* direction (- goal (point))) 0)
-                                  end (point)))))
-                       (error))))
-
-                 ;; Move overlay
-                 (move-overlay overlay
-                               (if (eq 1 direction) min (point))
-                               (if (eq -1 direction) max (point))
-                               (current-buffer))
-
-                 )))                   ; end track-mouse
-
-           ;; Detect follow-link events
-           (when (mouse-sel-follow-link-p initial-event event)
-             (throw 'follow-link event))
-
-           ;; Finish up after dragging
-           (let ((overlay-start (overlay-start overlay))
-                 (overlay-end (overlay-end overlay)))
-
-             ;; Set selection
-             (if (not (eq overlay-start overlay-end))
-                 (mouse-sel-set-selection
-                  selection
-                  (buffer-substring overlay-start overlay-end)))
-
-             ;; Handle copy/kill
-             (let (this-command)
-               (cond
-                ((eq (event-basic-type last-input-event) 'mouse-2)
-                 (copy-region-as-kill overlay-start overlay-end)
-                 (read-event) (read-event))
-                ((and (memq (event-basic-type last-input-event)
-                            '(mouse-1 mouse-3))
-                      (memq 'down (event-modifiers last-input-event)))
-                 (kill-region overlay-start overlay-end)
-                 (move-overlay overlay overlay-start overlay-start)
-                 (read-event) (read-event))
-                ((and (eq (event-basic-type last-input-event) 'mouse-3)
-                      (memq 'double (event-modifiers last-input-event)))
-                 (kill-region overlay-start overlay-end)
-                 (move-overlay overlay overlay-start overlay-start)))))
-
-           direction)
-
-       ;; Restore cursor
-       (if (fboundp 'modify-frame-parameters)
-           (modify-frame-parameters
-            (selected-frame) (list (cons 'cursor-type orig-cursor-type))))
-
-       ))))
-
-(defun mouse-sel-follow-link-p (initial final)
-  "Return t if we should follow a link, given INITIAL and FINAL mouse events.
-See `mouse-1-click-follows-link' for details.  Currently, Mouse
-Sel mode does not support using a `double' value to follow links
-using double-clicks."
-  (and initial final mouse-1-click-follows-link
-       (eq (car initial) 'down-mouse-1)
-       (mouse-on-link-p (event-start initial))
-       (= (posn-point (event-start initial))
-         (posn-point (event-end final)))
-       (= (event-click-count initial) 1)
-       (or (not (integerp mouse-1-click-follows-link))
-          (let ((t0 (posn-timestamp (event-start initial)))
-                (t1 (posn-timestamp (event-end final))))
-            (and (integerp t0) (integerp t1)
-                 (if (> mouse-1-click-follows-link 0)
-                     (<= (- t1 t0) mouse-1-click-follows-link)
-                   (< (- t0 t1) mouse-1-click-follows-link)))))))
-
-;;=== Paste ===============================================================
-
-(defun mouse-insert-selection (event arg)
-  "Insert the contents of the PRIMARY selection at mouse click.
-If `mouse-yank-at-point' is non-nil, insert at point instead."
-  (interactive "e\nP")
-  (if (eq mouse-sel-default-bindings 'interprogram-cut-paste)
-      (mouse-yank-at-click event arg)
-    (mouse-insert-selection-internal 'PRIMARY event)))
-
-(defun mouse-insert-secondary (event)
-  "Insert the contents of the SECONDARY selection at mouse click.
-If `mouse-yank-at-point' is non-nil, insert at point instead."
-  (interactive "e")
-  (mouse-insert-selection-internal 'SECONDARY event))
-
-(defun mouse-insert-selection-internal (selection event)
-  "Insert the contents of the named SELECTION at mouse click.
-If `mouse-yank-at-point' is non-nil, insert at point instead."
-  (unless mouse-yank-at-point
-    (mouse-set-point event))
-  (when mouse-sel-get-selection-function
-    (push-mark (point) 'nomsg)
-  (insert-for-yank
-   (or (funcall mouse-sel-get-selection-function selection) ""))))
-
-;;=== Handle loss of selections ===========================================
-
-(defun mouse-sel-lost-selection-hook (selection)
-  "Remove the overlay for a lost selection."
-  (let ((overlay (mouse-sel-selection-overlay selection)))
-    (delete-overlay overlay)))
-
-(provide 'mouse-sel)
-
-;;; mouse-sel.el ends here
diff --git a/lisp/obsolete/netrc.el b/lisp/obsolete/netrc.el
new file mode 100644
index 0000000000..0114dadbab
--- /dev/null
+++ b/lisp/obsolete/netrc.el
@@ -0,0 +1,245 @@
+;;; netrc.el --- .netrc parsing functionality  -*- lexical-binding: t -*-
+
+;; Copyright (C) 1996-2022 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Keywords: news
+;; Obsolete-since: 29.1
+;;
+;; Instead of using `netrc-parse', use `auth-source-netrc-parse-all'.
+;;
+;;  Modularized by Ted Zlatanov <tzz@lifelogs.com>
+;;  when it was part of Gnus.
+
+;; 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:
+
+;; Just the .netrc parsing functionality, abstracted so other packages
+;; besides Gnus can use it.
+
+;;; Code:
+
+;;;
+;;; .netrc and .authinfo rc parsing
+;;;
+
+(defgroup netrc nil
+ "Netrc configuration."
+ :group 'comm)
+
+(defcustom netrc-file "~/.authinfo"
+  "File where user credentials are stored."
+  :version "24.1"
+  :type 'file)
+
+(defvar netrc-services-file "/etc/services"
+  "The name of the services file.")
+
+(defvar netrc-cache nil)
+
+(defun netrc-parse (&optional file)
+  "Parse FILE and return a list of all entries in the file."
+  (declare (obsolete auth-source-netrc-parse-all "29.1"))
+  (interactive "fFile to Parse: ")
+  (unless file
+    (setq file netrc-file))
+  (if (listp file)
+      ;; We got already parsed contents; just return it.
+      file
+    (when (file-exists-p file)
+      (with-temp-buffer
+       (let ((tokens '("machine" "default" "login"
+                       "password" "account" "macdef" "force"
+                       "port"))
+             alist elem result pair)
+          (if (and netrc-cache
+                  (time-equal-p (car netrc-cache)
+                                (file-attribute-modification-time
+                                 (file-attributes file))))
+             (insert (base64-decode-string (rot13-string (cdr netrc-cache))))
+           (insert-file-contents file)
+           (when (string-match "\\.gpg\\'" file)
+             ;; Store the contents of the file heavily encrypted in memory.
+             (setq netrc-cache (cons (file-attribute-modification-time
+                                       (file-attributes file))
+                                     (rot13-string
+                                      (base64-encode-string
+                                       (buffer-string)))))))
+         (goto-char (point-min))
+         ;; Go through the file, line by line.
+         (while (not (eobp))
+            (narrow-to-region (point) (line-end-position))
+           ;; For each line, get the tokens and values.
+           (while (not (eobp))
+             (skip-chars-forward "\t ")
+             ;; Skip lines that begin with a "#".
+             (if (eq (char-after) ?#)
+                 (goto-char (point-max))
+               (unless (eobp)
+                 (setq elem
+                       (if (= (following-char) ?\")
+                           (read (current-buffer))
+                         (buffer-substring
+                          (point) (progn (skip-chars-forward "^\t ")
+                                         (point)))))
+                 (cond
+                  ((equal elem "macdef")
+                   ;; We skip past the macro definition.
+                   (widen)
+                   (while (and (zerop (forward-line 1))
+                               (looking-at "$")))
+                   (narrow-to-region (point) (point)))
+                  ((member elem tokens)
+                   ;; Tokens that don't have a following value are ignored,
+                   ;; except "default".
+                   (when (and pair (or (cdr pair)
+                                       (equal (car pair) "default")))
+                     (push pair alist))
+                   (setq pair (list elem)))
+                  (t
+                   ;; Values that haven't got a preceding token are ignored.
+                   (when pair
+                     (setcdr pair elem)
+                     (push pair alist)
+                     (setq pair nil)))))))
+           (when alist
+             (push (nreverse alist) result))
+           (setq alist nil
+                 pair nil)
+           (widen)
+           (forward-line 1))
+         (nreverse result))))))
+
+(defun netrc-machine (list machine &optional port defaultport)
+  "Return the netrc values from LIST for MACHINE or for the default entry.
+If PORT specified, only return entries with matching port tokens.
+Entries without port tokens default to DEFAULTPORT."
+  (let ((rest list)
+       result)
+    (while list
+      (when (equal (cdr (assoc "machine" (car list))) machine)
+       (push (car list) result))
+      (pop list))
+    (unless result
+      ;; No machine name matches, so we look for default entries.
+      (while rest
+       (when (assoc "default" (car rest))
+         (let ((elem (car rest)))
+           (setq elem (delete (assoc "default" elem) elem))
+           (push elem result)))
+       (pop rest)))
+    (when result
+      (setq result (nreverse result))
+      (if (not port)
+         (car result)
+       (while (and result
+                   (not (netrc-port-equal
+                         (or port defaultport "nntp")
+                         ;; when port is not given in the netrc file,
+                         ;; it should mean "any port"
+                         (or (netrc-get (car result) "port")
+                             defaultport port))))
+         (pop result))
+       (car result)))))
+
+(defun netrc-machine-user-or-password (mode authinfo-file-or-list machines 
ports defaults)
+  "Get the user name or password according to MODE from AUTHINFO-FILE-OR-LIST.
+Matches a machine from MACHINES and a port from PORTS, giving
+default ports DEFAULTS to `netrc-machine'.
+
+MODE can be \"login\" or \"password\", suitable for passing to
+`netrc-get'."
+  (let ((authinfo-list (if (stringp authinfo-file-or-list)
+                           (with-suppressed-warnings ((obsolete netrc-parse))
+                            (netrc-parse authinfo-file-or-list))
+                        authinfo-file-or-list))
+       (ports (or ports '(nil)))
+       (defaults (or defaults '(nil)))
+       info)
+    (if (listp mode)
+       (setq info
+             (mapcar
+              (lambda (mode-element)
+                (netrc-machine-user-or-password
+                 mode-element
+                 authinfo-list
+                 machines
+                 ports
+                 defaults))
+              mode))
+      (dolist (machine machines)
+       (dolist (default defaults)
+         (dolist (port ports)
+           (let ((alist (netrc-machine authinfo-list machine port default)))
+             (setq info (or (netrc-get alist mode) info)))))))
+    info))
+
+(defun netrc-get (alist type)
+  "Return the value of token TYPE from ALIST."
+  (cdr (assoc type alist)))
+
+(defun netrc-port-equal (port1 port2)
+  (when (numberp port1)
+    (setq port1 (or (netrc-find-service-name port1) port1)))
+  (when (numberp port2)
+    (setq port2 (or (netrc-find-service-name port2) port2)))
+  (equal port1 port2))
+
+(defun netrc-parse-services ()
+  (when (file-exists-p netrc-services-file)
+    (let ((services nil))
+      (with-temp-buffer
+       (insert-file-contents netrc-services-file)
+       (while (search-forward "#" nil t)
+          (delete-region (1- (point)) (line-end-position)))
+       (goto-char (point-min))
+       (while (re-search-forward
+               "^ *\\([^ \n\t]+\\)[ \t]+\\([0-9]+\\)/\\([^ \t\n]+\\)" nil t)
+         (push (list (match-string 1) (string-to-number (match-string 2))
+                     (intern (downcase (match-string 3))))
+               services))
+       (nreverse services)))))
+
+(defun netrc-find-service-name (number &optional type)
+  (let ((services (netrc-parse-services))
+       service)
+    (setq type (or type 'tcp))
+    (while (and (setq service (pop services))
+               (not (and (= number (cadr service))
+                         (eq type (car (cddr service)))))))
+    (car service)))
+
+;;;###autoload
+(defun netrc-credentials (machine &rest ports)
+  "Return a user name/password pair.
+Port specifications will be prioritized in the order they are
+listed in the PORTS list."
+  (let ((list (with-suppressed-warnings ((obsolete netrc-parse))
+                (netrc-parse)))
+       found)
+    (if (not ports)
+       (setq found (netrc-machine list machine))
+      (while (and ports
+                 (not found))
+       (setq found (netrc-machine list machine (pop ports)))))
+    (when found
+      (list (cdr (assoc "login" found))
+           (cdr (assoc "password" found))))))
+
+(provide 'netrc)
+
+;;; netrc.el ends here
diff --git a/lisp/obsolete/old-emacs-lock.el b/lisp/obsolete/old-emacs-lock.el
deleted file mode 100644
index 70123e7537..0000000000
--- a/lisp/obsolete/old-emacs-lock.el
+++ /dev/null
@@ -1,102 +0,0 @@
-;;; old-emacs-lock.el --- prevents you from exiting Emacs if a buffer is 
locked  -*- lexical-binding: t; -*-
-
-;; Copyright (C) 1994, 1997, 2001-2022 Free Software Foundation, Inc.
-
-;; Author: Tom Wurgler <twurgler@goodyear.com>
-;; Created: 12/8/94
-;; Keywords: extensions, processes
-;; Obsolete-since: 24.1
-
-;; 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 code sets a buffer-local variable to t if toggle-emacs-lock is run,
-;; then if the user attempts to exit Emacs, the locked buffer name will be
-;; displayed and the exit aborted.  This is just a way of protecting
-;; yourself from yourself.  For example, if you have a shell running a big
-;; program and exiting Emacs would abort that program, you may want to lock
-;; that buffer, then if you forget about it after a while, you won't
-;; accidentally exit Emacs.  To unlock the buffer, just goto the buffer and
-;; run toggle-emacs-lock again.
-
-;;; Code:
-
-(defvar emacs-lock-from-exiting nil
-  "Whether Emacs is locked to prevent exiting.  See `check-emacs-lock'.")
-(make-variable-buffer-local 'emacs-lock-from-exiting)
-
-(defvar emacs-lock-buffer-locked nil
-  "Whether a shell or telnet buffer was locked when its process was killed.")
-(make-variable-buffer-local 'emacs-lock-buffer-locked)
-(put 'emacs-lock-buffer-locked 'permanent-local t)
-
-(defun check-emacs-lock ()
-  "Check if variable `emacs-lock-from-exiting' is t for any buffer.
-If any locked buffer is found, signal error and display the buffer's name."
-  (save-excursion
-    (dolist (buffer (buffer-list))
-      (set-buffer buffer)
-      (when emacs-lock-from-exiting
-       (error "Emacs is locked from exit due to buffer: %s" (buffer-name))))))
-
-(defun toggle-emacs-lock ()
-  "Toggle `emacs-lock-from-exiting' for the current buffer.
-See `check-emacs-lock'."
-  (interactive)
-  (setq emacs-lock-from-exiting (not emacs-lock-from-exiting))
-  (if emacs-lock-from-exiting
-      (message "Buffer is now locked")
-    (message "Buffer is now unlocked")))
-
-(defun emacs-lock-check-buffer-lock ()
-  "Check if variable `emacs-lock-from-exiting' is t for a buffer.
-If the buffer is locked, signal error and display its name."
-  (when emacs-lock-from-exiting
-    (error "Buffer `%s' is locked, can't delete it" (buffer-name))))
-
-; These next defuns make it so if you exit a shell that is locked,  the lock
-; is shut off for that shell so you can exit Emacs.  Same for telnet.
-; Also, if a shell or a telnet buffer was locked and the process killed,
-; turn the lock back on again if the process is restarted.
-
-(defun emacs-lock-shell-sentinel ()
-  (set-process-sentinel
-   (get-buffer-process (buffer-name)) (function emacs-lock-clear-sentinel)))
-
-(defun emacs-lock-clear-sentinel (_proc _str)
-  (if emacs-lock-from-exiting
-      (progn
-       (setq emacs-lock-from-exiting nil)
-       (setq emacs-lock-buffer-locked t)
-       (message "Buffer is now unlocked"))
-    (setq emacs-lock-buffer-locked nil)))
-
-(defun emacs-lock-was-buffer-locked ()
-  (if emacs-lock-buffer-locked
-      (setq emacs-lock-from-exiting t)))
-
-(unless noninteractive
-  (add-hook 'kill-emacs-hook #'check-emacs-lock))
-(add-hook 'kill-buffer-hook #'emacs-lock-check-buffer-lock)
-(add-hook 'shell-mode-hook #'emacs-lock-was-buffer-locked)
-(add-hook 'shell-mode-hook #'emacs-lock-shell-sentinel)
-(add-hook 'telnet-mode-hook #'emacs-lock-was-buffer-locked)
-(add-hook 'telnet-mode-hook #'emacs-lock-shell-sentinel)
-
-(provide 'emacs-lock)
-
-;;; old-emacs-lock.el ends here
diff --git a/lisp/obsolete/patcomp.el b/lisp/obsolete/patcomp.el
deleted file mode 100644
index 2c35cb0700..0000000000
--- a/lisp/obsolete/patcomp.el
+++ /dev/null
@@ -1,24 +0,0 @@
-;;; patcomp.el --- used by patch files to update Emacs releases  -*- 
lexical-binding: t; -*-
-
-;; This file is part of GNU Emacs.
-
-;; Obsolete-since: 24.3
-
-;;; Commentary:
-
-;;; Code:
-
-(defun batch-byte-recompile-emacs ()
-  "Recompile the Emacs `lisp' directory.
-This is used after installing the patches for a new version."
-  (let ((load-path (list (expand-file-name "lisp"))))
-    (byte-recompile-directory "lisp")))
-
-(defun batch-byte-compile-emacs ()
-  "Compile new files installed in the Emacs `lisp' directory.
-This is used after installing the patches for a new version.
-It uses the command line arguments to specify the files to compile."
-  (let ((load-path (list (expand-file-name "lisp"))))
-    (batch-byte-compile)))
-
-;;; patcomp.el ends here
diff --git a/lisp/obsolete/pc-mode.el b/lisp/obsolete/pc-mode.el
deleted file mode 100644
index 4c4bfb5b9c..0000000000
--- a/lisp/obsolete/pc-mode.el
+++ /dev/null
@@ -1,56 +0,0 @@
-;;; pc-mode.el --- emulate certain key bindings used on PCs  -*- 
lexical-binding: t; -*-
-
-;; Copyright (C) 1995, 2001-2022 Free Software Foundation, Inc.
-
-;; Maintainer: emacs-devel@gnu.org
-;; Keywords: emulations
-;; Obsolete-since: 24.1
-
-;; 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:
-
-;;;###autoload
-(defun pc-bindings-mode ()
-  "Set up certain key bindings for PC compatibility.
-The keys affected are:
-Delete (and its variants) delete forward instead of backward.
-C-Backspace kills backward a word (as C-Delete normally would).
-M-Backspace does undo.
-Home and End move to beginning and end of line
-C-Home and C-End move to beginning and end of buffer.
-C-Escape does list-buffers."
-
-  (interactive)
-  (define-key function-key-map [delete] "\C-d")
-  (define-key function-key-map [M-delete] [?\M-d])
-  (define-key function-key-map [C-delete] [?\M-d])
-  (global-set-key [C-M-delete] #'kill-sexp)
-  (global-set-key [C-backspace] #'backward-kill-word)
-  (global-set-key [M-backspace] #'undo)
-
-  (global-set-key [C-escape] #'list-buffers)
-
-  (global-set-key [home] #'beginning-of-line)
-  (global-set-key [end] #'end-of-line)
-  (global-set-key [C-home] #'beginning-of-buffer)
-  (global-set-key [C-end] #'end-of-buffer))
-
-(provide 'pc-mode)
-
-;;; pc-mode.el ends here
diff --git a/lisp/obsolete/pc-select.el b/lisp/obsolete/pc-select.el
deleted file mode 100644
index 922358bcd6..0000000000
--- a/lisp/obsolete/pc-select.el
+++ /dev/null
@@ -1,410 +0,0 @@
-;;; pc-select.el --- emulate mark, cut, copy and paste from Motif  -*- 
lexical-binding: t; -*-
-;;;                 (or MAC GUI or MS-windoze (bah)) look-and-feel
-;;;                 including key bindings.
-
-;; Copyright (C) 1995-1997, 2000-2022 Free Software Foundation, Inc.
-
-;; Author: Michael Staats <michael@thp.Uni-Duisburg.DE>
-;; Keywords: convenience emulations
-;; Created: 26 Sep 1995
-;; Obsolete-since: 24.1
-
-;; 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 package emulates the mark, copy, cut and paste look-and-feel of motif
-;; programs (which is the same as the MAC gui and (sorry for that) MS-Windows).
-;; It modifies the keybindings of the cursor keys and the next, prior,
-;; home and end keys. They will modify mark-active.
-;; You can still get the old behavior of cursor moving with the
-;; control sequences C-f, C-b, etc.
-;; This package uses transient-mark-mode and
-;; delete-selection-mode.
-;;
-;; In addition to that all key-bindings from the pc-mode are
-;; done here too (as suggested by RMS).
-;;
-;; As I found out after I finished the first version, s-region.el tries
-;; to do the same.... But my code is a little more complete and using
-;; delete-selection-mode is very important for the look-and-feel.
-;; Pete Forman <pete.forman@airgun.wg.waii.com> provided some motif
-;; compliant keybindings which I added. I had to modify them a little
-;; to add the -mark and -nomark functionality of cursor moving.
-;;
-;; Credits:
-;; Many thanks to all who made comments.
-;; Thanks to RMS and Ralf Muschall <prm@rz.uni-jena.de> for criticism.
-;; Kevin Cutts <cutts@ukraine.corp.mot.com> added the beginning-of-buffer
-;; and end-of-buffer functions which I modified a little.
-;; David Biesack <sasdjb@unx.sas.com> suggested some more cleanup.
-;; Thanks to Pete Forman <pete.forman@airgun.wg.waii.com>
-;; for additional motif keybindings.
-;; Thanks to jvromans@squirrel.nl (Johan Vromans) for a bug report
-;; concerning setting of this-command.
-;; Dan Nicolaescu <done@ece.arizona.ro> suggested suppressing the
-;; scroll-up/scroll-down error.
-;; Eli Barzilay (eli@cs.bgu.ac.il) suggested the sexps functions and
-;; keybindings.
-;;
-;; Ok, some details about the idea of PC Selection mode:
-;;
-;;  o The standard keys for moving around (right, left, up, down, home, end,
-;;    prior, next, called "move-keys" from now on) will always de-activate
-;;    the mark.
-;;  o If you press "Shift" together with the "move-keys", the region
-;;    you pass along is activated
-;;  o You have the copy, cut and paste functions (as in many other programs)
-;;    which will operate on the active region
-;;    It was not possible to bind them to C-v, C-x and C-c for obvious
-;;    emacs reasons.
-;;    They will be bound according to the "old" behavior to S-delete (cut),
-;;    S-insert (paste) and C-insert (copy). These keys do the same in many
-;;    other programs.
-;;
-
-;;; Code:
-
-;; Customization:
-(defgroup pc-select nil
-  "Emulate pc bindings."
-  :prefix "pc-select"
-  :group 'emulations)
-
-(define-obsolete-variable-alias 'pc-select-override-scroll-error
-                                'scroll-error-top-bottom
-                                "24.1")
-(defcustom pc-select-override-scroll-error t
-  "Non-nil means don't generate error on scrolling past edge of buffer.
-This variable applies in PC Selection mode only.
-The scroll commands normally generate an error if you try to scroll
-past the top or bottom of the buffer.  This is annoying when selecting
-text with these commands.  If you set this variable to non-nil, these
-errors are suppressed."
-  :type 'boolean)
-
-(defcustom pc-select-selection-keys-only nil
-  "Non-nil means only bind the basic selection keys when started.
-Other keys that emulate pc-behavior will be untouched.
-This gives mostly Emacs-like behavior with only the selection keys enabled."
-  :type 'boolean)
-
-(defcustom pc-select-meta-moves-sexps nil
-  "Non-nil means move sexp-wise with Meta key, otherwise move word-wise."
-  :type 'boolean)
-
-(defcustom pc-selection-mode-hook nil
-  "The hook to run when PC Selection mode is toggled."
-  :type 'hook)
-
-(defvar pc-select-saved-settings-alist nil
-  "The values of the variables before PC Selection mode was toggled on.
-When PC Selection mode is toggled on, it sets quite a few variables
-for its own purposes.  This alist holds the original values of the
-variables PC Selection mode had set, so that these variables can be
-restored to their original values when PC Selection mode is toggled off.")
-
-(defvar pc-select-map nil
-  "The keymap used as the global map when PC Selection mode is on." )
-
-(defvar pc-select-saved-global-map nil
-  "The global map that was in effect when PC Selection mode was toggled on.")
-
-(defvar pc-select-key-bindings-alist nil
-  "This alist holds all the key bindings PC Selection mode sets.")
-
-(defvar pc-select-default-key-bindings nil
-  "These key bindings always get set by PC Selection mode.")
-
-(defvar pc-select-extra-key-bindings
-  ;; The following keybindings are for standard ISO keyboards
-  ;; as they are used with IBM compatible PCs, IBM RS/6000,
-  ;; MACs, many X-Stations and probably more.
-  '(;; Commented out since it's been standard at least since Emacs-21.
-    ;;([S-insert]  . yank)
-    ;;([C-insert]  . copy-region-as-kill)
-    ;;([S-delete]  . kill-region)
-
-    ;; The following bindings are useful on Sun Type 3 keyboards
-    ;; They implement the Get-Delete-Put (copy-cut-paste)
-    ;; functions from sunview on the L6, L8 and L10 keys
-    ;; Sam Steingold <sds@gnu.org> says that f16 is copy and f18 is paste.
-    ([f16]  . copy-region-as-kill)
-    ([f18]  . yank)
-    ([f20]  . kill-region)
-
-    ;; The following bindings are from Pete Forman.
-    ([f6] . other-window)              ; KNextPane     F6
-    ([C-delete] . kill-line)           ; KEraseEndLine cDel
-    ("\M-\d" . undo)                   ; KUndo         aBS
-
-    ;; The following binding is taken from pc-mode.el
-    ;; as suggested by RMS.
-    ;; I only used the one that is not covered above.
-    ([C-M-delete]  . kill-sexp)
-    ;; Next line proposed by Eli Barzilay
-    ([C-escape]    . electric-buffer-list))
-  "Key bindings to set only if `pc-select-selection-keys-only' is nil.")
-
-(defvar pc-select-meta-moves-sexps-key-bindings
-  '((([M-right]   . forward-sexp)
-     ([M-left]    . backward-sexp))
-    (([M-right]   . forward-word)
-     ([M-left]    . backward-word)))
-  "The list of key bindings controlled by `pc-select-meta-moves-sexp'.
-The bindings in the car of this list get installed if
-`pc-select-meta-moves-sexp' is t, the bindings in the cadr of this
-list get installed otherwise.")
-
-;; This is for tty.  We don't turn on normal-erase-is-backspace,
-;; but bind keys as pc-selection-mode did before
-;; normal-erase-is-backspace was invented, to keep us back
-;; compatible.
-(defvar pc-select-tty-key-bindings
-  '(([delete] . delete-char)           ; KDelete       Del
-   ([C-backspace] . backward-kill-word))
-  "The list of key bindings controlled by `pc-select-selection-keys-only'.
-These key bindings get installed when running in a tty, but only if
-`pc-select-selection-keys-only' is nil.")
-
-(defvar pc-select-old-M-delete-binding nil
-  "Holds the old mapping of [M-delete] in the `function-key-map'.
-This variable holds the value associated with [M-delete] in the
-`function-key-map' before PC Selection mode had changed that
-association.")
-
-;;;;
-;; misc
-;;;;
-
-(provide 'pc-select)
-
-(defun pc-select-define-keys (alist keymap)
-  "Make KEYMAP have the key bindings specified in ALIST."
-  (let ((lst alist))
-    (while lst
-      (define-key keymap (caar lst) (cdar lst))
-      (setq lst (cdr lst)))))
-
-(defun pc-select-restore-keys (alist keymap saved-map)
-  "Use ALIST to restore key bindings from SAVED-MAP into KEYMAP.
-Go through all the key bindings in ALIST, and, for each key
-binding, if KEYMAP and ALIST still agree on the key binding,
-restore the previous value of that key binding from SAVED-MAP."
-  (let ((lst alist))
-    (while lst
-      (when (equal (lookup-key keymap (caar lst)) (cdar lst))
-       (define-key keymap (caar lst) (lookup-key saved-map (caar lst))))
-      (setq lst (cdr lst)))))
-
-(defmacro pc-select-add-to-alist (alist var val)
-  "Ensure that ALIST contains the cons cell (VAR . VAL).
-If a cons cell whose car is VAR is already on the ALIST, update the
-cdr of that cell with VAL.  Otherwise, make a new cons cell
-\(VAR . VAL), and prepend it onto ALIST."
-  (let ((elt (make-symbol "elt")))
-    `(let ((,elt (assq ',var ,alist)))
-       (if ,elt
-          (setcdr ,elt ,val)
-        (setq ,alist (cons (cons ',var ,val) ,alist))))))
-
-(defmacro pc-select-save-and-set-var (var newval)
-  "Set VAR to NEWVAL; save the old value.
-The old value is saved on the `pc-select-saved-settings-alist'."
-  `(when (boundp ',var)
-     (pc-select-add-to-alist pc-select-saved-settings-alist ,var ,var)
-     (setq ,var ,newval)))
-
-(defmacro pc-select-save-and-set-mode (mode &optional arg mode-var)
-  "Call the function MODE; save the old value of the variable MODE.
-MODE is presumed to be a function which turns on a minor mode.  First,
-save the value of the variable MODE on `pc-select-saved-settings-alist'.
-Then, if ARG is specified, call MODE with ARG, otherwise call it with
-nil as an argument.  If MODE-VAR is specified, save the value of the
-variable MODE-VAR (instead of the value of the variable MODE) on
-`pc-select-saved-settings-alist'."
-  (unless mode-var (setq mode-var mode))
-  `(when (fboundp ',mode)
-     (pc-select-add-to-alist pc-select-saved-settings-alist
-                            ,mode-var ,mode-var)
-     (,mode ,arg)))
-
-(defmacro pc-select-restore-var (var)
-  "Restore the previous value of the variable VAR.
-Look up VAR's previous value in `pc-select-saved-settings-alist', and,
-if the value is found, set VAR to that value."
-  (let ((elt (make-symbol "elt")))
-    `(let ((,elt (assq ',var pc-select-saved-settings-alist)))
-       (unless (null ,elt)
-        (setq ,var (cdr ,elt))))))
-
-(defmacro pc-select-restore-mode (mode)
-  "Restore the previous state (either on or off) of the minor mode MODE.
-Look up the value of the variable MODE on `pc-select-saved-settings-alist'.
-If the value is non-nil, call the function MODE with an argument of
-1, otherwise call it with an argument of -1."
-  (let ((elt (make-symbol "elt")))
-    `(when (fboundp ',mode)
-       (let ((,elt (assq ',mode pc-select-saved-settings-alist)))
-        (unless (null ,elt)
-          (,mode (if (cdr ,elt) 1 -1)))))))
-
-
-;;;###autoload
-(define-minor-mode pc-selection-mode
-  "Change mark behavior to emulate Motif, Mac or MS-Windows cut and paste 
style.
-
-This mode enables Delete Selection mode and Transient Mark mode.
-
-The arrow keys (and others) are bound to new functions
-which modify the status of the mark.
-
-The ordinary arrow keys disable the mark.
-The shift-arrow keys move, leaving the mark behind.
-
-C-LEFT and C-RIGHT move back or forward one word, disabling the mark.
-S-C-LEFT and S-C-RIGHT move back or forward one word, leaving the mark behind.
-
-M-LEFT and M-RIGHT move back or forward one word or sexp, disabling the mark.
-S-M-LEFT and S-M-RIGHT move back or forward one word or sexp, leaving the mark
-behind.  To control whether these keys move word-wise or sexp-wise set the
-variable `pc-select-meta-moves-sexps' after loading pc-select.el but before
-turning PC Selection mode on.
-
-C-DOWN and C-UP move back or forward a paragraph, disabling the mark.
-S-C-DOWN and S-C-UP move back or forward a paragraph, leaving the mark behind.
-
-HOME moves to beginning of line, disabling the mark.
-S-HOME moves to beginning of line, leaving the mark behind.
-With Ctrl or Meta, these keys move to beginning of buffer instead.
-
-END moves to end of line, disabling the mark.
-S-END moves to end of line, leaving the mark behind.
-With Ctrl or Meta, these keys move to end of buffer instead.
-
-PRIOR or PAGE-UP scrolls and disables the mark.
-S-PRIOR or S-PAGE-UP scrolls and leaves the mark behind.
-
-S-DELETE kills the region (`kill-region').
-S-INSERT yanks text from the kill ring (`yank').
-C-INSERT copies the region into the kill ring (`copy-region-as-kill').
-
-In addition, certain other PC bindings are imitated (to avoid this, set
-the variable `pc-select-selection-keys-only' to t after loading pc-select.el
-but before calling PC Selection mode):
-
-  F6           other-window
-  DELETE       delete-char
-  C-DELETE     kill-line
-  M-DELETE     kill-word
-  C-M-DELETE   kill-sexp
-  C-BACKSPACE  backward-kill-word
-  M-BACKSPACE  undo"
-  ;; FIXME: bring pc-bindings-mode here ?
-  :global t
-
-  (if pc-selection-mode
-      (if (null pc-select-key-bindings-alist)
-         (progn
-           (setq pc-select-saved-global-map (copy-keymap (current-global-map)))
-           (setq pc-select-key-bindings-alist
-                 (append pc-select-default-key-bindings
-                         (if pc-select-selection-keys-only
-                             nil
-                           pc-select-extra-key-bindings)
-                         (if pc-select-meta-moves-sexps
-                             (car pc-select-meta-moves-sexps-key-bindings)
-                           (cadr pc-select-meta-moves-sexps-key-bindings))
-                         (if  (or pc-select-selection-keys-only
-                                  (eq window-system 'x)
-                                  (memq system-type '(ms-dos windows-nt)))
-                             nil
-                           pc-select-tty-key-bindings)))
-
-           (pc-select-define-keys pc-select-key-bindings-alist
-                                  (current-global-map))
-
-           (unless  (or pc-select-selection-keys-only
-                        (eq window-system 'x)
-                        (memq system-type '(ms-dos windows-nt)))
-             ;; it is not clear that we need the following line
-             ;; I hope it doesn't do too much harm to leave it in, though...
-             (setq pc-select-old-M-delete-binding
-                   (lookup-key function-key-map [M-delete]))
-             (define-key function-key-map  [M-delete] [?\M-d]))
-
-           (when (and (not pc-select-selection-keys-only)
-                      (or (eq window-system 'x)
-                          (memq system-type '(ms-dos windows-nt)))
-                      (fboundp 'normal-erase-is-backspace-mode))
-             (pc-select-save-and-set-mode normal-erase-is-backspace-mode 1
-                                          normal-erase-is-backspace))
-           ;; the original author also had this above:
-           ;; (setq-default normal-erase-is-backspace t)
-           ;; However, the documentation for the variable says that
-           ;; "setting it with setq has no effect", so I'm removing it.
-
-           (pc-select-save-and-set-var highlight-nonselected-windows nil)
-           (pc-select-save-and-set-var transient-mark-mode t)
-           (pc-select-save-and-set-var shift-select-mode t)
-           (pc-select-save-and-set-var mark-even-if-inactive t)
-           (pc-select-save-and-set-mode delete-selection-mode 1))
-       ;;else
-       ;; If the user turned on pc-selection-mode a second time
-       ;; do not clobber the values of the variables that were
-       ;; saved from before pc-selection mode was activated --
-       ;; just make sure the values are the way we like them.
-       (pc-select-define-keys pc-select-key-bindings-alist
-                              (current-global-map))
-       (unless  (or pc-select-selection-keys-only
-                    (eq window-system 'x)
-                    (memq system-type '(ms-dos windows-nt)))
-         ;; it is not clear that we need the following line
-         ;; I hope it doesn't do too much harm to leave it in, though...
-         (define-key function-key-map  [M-delete] [?\M-d]))
-       (when (and (not pc-select-selection-keys-only)
-                  (or (eq window-system 'x)
-                      (memq system-type '(ms-dos windows-nt)))
-                  (fboundp 'normal-erase-is-backspace-mode))
-         (normal-erase-is-backspace-mode 1))
-       (setq highlight-nonselected-windows nil)
-       (transient-mark-mode 1)
-       (setq mark-even-if-inactive t)
-       (delete-selection-mode 1))
-    ;;else
-    (when pc-select-key-bindings-alist
-      (when (and (not pc-select-selection-keys-only)
-                (or (eq window-system 'x)
-                    (memq system-type '(ms-dos windows-nt))))
-       (pc-select-restore-mode normal-erase-is-backspace-mode))
-
-      (pc-select-restore-keys
-       pc-select-key-bindings-alist (current-global-map)
-       pc-select-saved-global-map)
-
-      (pc-select-restore-var highlight-nonselected-windows)
-      (pc-select-restore-var transient-mark-mode)
-      (pc-select-restore-var shift-select-mode)
-      (pc-select-restore-var mark-even-if-inactive)
-      (pc-select-restore-mode delete-selection-mode)
-      (and pc-select-old-M-delete-binding
-          (define-key function-key-map [M-delete]
-            pc-select-old-M-delete-binding))
-      (setq pc-select-key-bindings-alist nil
-           pc-select-saved-settings-alist nil))))
-(make-obsolete 'pc-selection-mode 'delete-selection-mode "24.1")
-
-;;; pc-select.el ends here
diff --git a/lisp/obsolete/ps-def.el b/lisp/obsolete/ps-def.el
new file mode 100644
index 0000000000..0f7f7609ca
--- /dev/null
+++ b/lisp/obsolete/ps-def.el
@@ -0,0 +1,54 @@
+;;; ps-def.el --- Emacs definitions for ps-print -*- lexical-binding: t -*-
+
+;; Copyright (C) 2007-2022 Free Software Foundation, Inc.
+
+;; Author: Vinicius Jose Latorre <viniciusjl.gnu@gmail.com>
+;;     Kenichi Handa <handa@gnu.org> (multi-byte characters)
+;; Keywords: wp, print, PostScript
+;; URL: https://www.emacswiki.org/cgi-bin/wiki/ViniciusJoseLatorre
+;; Package: ps-print
+;; Obsolete-since: 29.1
+
+;; 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:
+
+;; See ps-print.el for documentation.
+
+;;; Code:
+
+
+;; Emacs Definitions
+
+(defun ps-mark-active-p ()
+  (declare (obsolete mark-active "29.1"))
+  mark-active)
+
+(defun ps-face-foreground-name (face)
+  (declare (obsolete face-foreground "29.1"))
+  (face-foreground face nil t))
+
+(defun ps-face-background-name (face)
+  (declare (obsolete face-background "29.1"))
+  (face-background face nil t))
+
+(define-obsolete-function-alias 'ps-frame-parameter #'frame-parameter "28.1")
+(define-obsolete-function-alias 'ps-color-device #'display-color-p "29.1")
+(define-obsolete-function-alias 'ps-color-values #'color-values "28.1")
+
+(provide 'ps-def)
+
+;;; ps-def.el ends here
diff --git a/lisp/obsolete/quickurl.el b/lisp/obsolete/quickurl.el
new file mode 100644
index 0000000000..5ac10323d1
--- /dev/null
+++ b/lisp/obsolete/quickurl.el
@@ -0,0 +1,524 @@
+;;; quickurl.el --- insert a URL based on text at point in buffer  -*- 
lexical-binding: t; -*-
+
+;; Copyright (C) 1999-2022 Free Software Foundation, Inc.
+
+;; Author: Dave Pearson <davep@davep.org>
+;; Created: 1999-05-28
+;; Keywords: hypermedia
+;; Obsolete-since: 29.1
+
+;; 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 package provides a simple method of inserting a URL based on the
+;; text at point in the current buffer.  This is part of an on-going effort
+;; to increase the information I provide people while reducing the amount
+;; of typing I need to do.  No-doubt there are undiscovered Emacs packages
+;; out there that do all of this and do it better, feel free to point me to
+;; them, in the mean time I'm having fun playing with Emacs Lisp.
+;;
+;; The URLs are stored in an external file as a list of either cons cells,
+;; or lists.  A cons cell entry looks like this:
+;;
+;;    (<Lookup> . <URL>)
+;;
+;; where <Lookup> is a string that acts as the keyword lookup and <URL> is
+;; the URL associated with it.  An example might be:
+;;
+;;    ("GNU" . "https://www.gnu.org/";)
+;;
+;; A list entry looks like:
+;;
+;;    (<Lookup> <URL> <Comment>)
+;;
+;; where <Lookup> and <URL> are the same as with the cons cell and <Comment>
+;; is any text you like that describes the URL.  This description will be
+;; used when presenting a list of URLS using `quickurl-list'.  An example
+;; might be:
+;;
+;;    ("FSF" "https://www.fsf.org/"; "The Free Software Foundation")
+;;
+;; Given the above, your quickurl file might look like:
+;;
+;; (("GNU"    . "https://www.gnu.org/";)
+;;  ("FSF"      "https://www.fsf.org/"; "The Free Software Foundation")
+;;  ("emacs"  . "https://www.emacs.org/";)
+;;  ("davep"    "http://www.davep.org/"; "Dave's homepage"))
+;;
+;; In case you're wondering about the mixture of cons cells and lists,
+;; quickurl started life using just the cons cells, there were no comments.
+;; URL comments are a later addition and so there is a mixture to keep
+;; backward compatibility with existing URL lists.
+;;
+;; The name and location of the file is up to you, the default name used by
+;; `quickurl' is stored in `quickurl-url-file'.
+;;
+;; quickurl is always available from:
+;;
+;;   <URL:http://www.davep.org/emacs/quickurl.el>
+
+;;; TODO:
+;;
+;; o The quickurl-browse-url* functions pretty much duplicate their non
+;;   browsing friends. It would feel better if a more generic solution could
+;;   be found.
+
+;;; Code:
+
+;; Things we need:
+
+(eval-when-compile (require 'cl-lib))
+(require 'thingatpt)
+(require 'pp)
+(require 'browse-url)
+
+;; Customize options.
+
+(defgroup quickurl nil
+  "Insert a URL based on text at point in buffer."
+  :version "21.1"
+  :group  'abbrev
+  :prefix "quickurl-")
+
+(defcustom quickurl-url-file
+  (locate-user-emacs-file "quickurls" ".quickurls")
+  "File that contains the URL list."
+  :version "24.4"                       ; added locate-user-emacs-file
+  :type  'file)
+
+(defcustom quickurl-format-function #'quickurl-format-url
+  "Function to format the URL before insertion into the current buffer."
+  :type  'function)
+
+(defcustom quickurl-sort-function #'quickurl-sort-urls
+  "Function to sort the URL list."
+  :type  'function)
+
+(defcustom quickurl-grab-lookup-function #'current-word
+  "Function to grab the thing to lookup."
+  :type  'function)
+
+(defun quickurl--assoc-function (key alist)
+  "Default function for `quickurl-assoc-function'."
+  (assoc-string key alist t))
+
+(defcustom quickurl-assoc-function #'quickurl--assoc-function
+  "Function to use for alist lookup into `quickurl-urls'."
+  :version "26.1"                 ; was the obsolete assoc-ignore-case
+  :type  'function)
+
+(defcustom quickurl-completion-ignore-case t
+  "Should `quickurl-ask' ignore case when doing the input lookup?"
+  :type  'boolean)
+
+(defcustom quickurl-prefix ";; -*- lisp -*-\n\n"
+  "Text to write to `quickurl-url-file' before writing the URL list."
+  :type  'string)
+
+(defcustom quickurl-postfix ""
+  "Text to write to `quickurl-url-file' after writing the URL list.
+
+See the constant `quickurl-reread-hook-postfix' for some example text that
+could be used here."
+  :type  'string)
+
+(defcustom quickurl-list-mode-hook nil
+  "Hooks for `quickurl-list-mode'."
+  :type  'hook)
+
+;; Constants.
+
+;;;###autoload
+(defconst quickurl-reread-hook-postfix
+    "
+;; Local Variables:
+;; eval: (progn (require 'quickurl) (add-hook 'write-file-functions (lambda () 
(quickurl-read) nil) nil t))
+;; End:
+"
+  "Example `quickurl-postfix' text that adds a local variable to the
+`quickurl-url-file' so that if you edit it by hand it will ensure that
+`quickurl-urls' is updated with the new URL list.
+
+To make use of this do something like:
+
+  (setq quickurl-postfix quickurl-reread-hook-postfix)
+
+in your init file (after loading/requiring quickurl).")
+
+;; Non-customize variables.
+
+(defvar quickurl-urls nil
+  "URL alist for use with `quickurl' and `quickurl-ask'.")
+
+(defvar-keymap quickurl-list-mode-map
+  :doc "Local keymap for a `quickurl-list-mode' buffer."
+  "a"   #'quickurl-list-add-url
+  "RET" #'quickurl-list-insert-url
+  "u"   #'quickurl-list-insert-naked-url
+  "SPC" #'quickurl-list-insert-with-lookup
+  "l"   #'quickurl-list-insert-lookup
+  "d"   #'quickurl-list-insert-with-desc
+  "C-g" #'quickurl-list-quit
+  "q"   #'quickurl-list-quit
+  "<mouse-2>" #'quickurl-list-mouse-select)
+
+(defvar quickurl-list-buffer-name "*quickurl-list*"
+  "Name for the URL listing buffer.")
+
+(defvar quickurl-list-last-buffer nil
+  "`current-buffer' when `quickurl-list' was called.")
+
+;; Functions for working with a URL entry.
+
+(defun quickurl-url-commented-p (url)
+  "Does the URL have a comment?"
+  (listp (cdr url)))
+
+(defun quickurl-make-url (keyword url &optional comment)
+  "Create a URL from KEYWORD, URL and (optionally) COMMENT."
+  (if (and comment (not (zerop (length comment))))
+      (list keyword url comment)
+    (cons keyword url)))
+
+(defalias 'quickurl-url-keyword #'car
+  "Return the keyword for the URL.
+\n\(fn URL)")
+
+(defun quickurl-url-url (url)
+  "Return the actual URL of the URL.
+
+Note that this function is a setfable place."
+  (declare (gv-setter (lambda (store)
+                        `(setf (if (quickurl-url-commented-p ,url)
+                                   (cadr ,url)
+                                 (cdr ,url))
+                               ,store))))
+  (if (quickurl-url-commented-p url)
+      (cadr url)
+    (cdr url)))
+
+(defun quickurl-url-comment (url)
+  "Get the comment from a URL.
+
+If the URL has no comment an empty string is returned.  Also note
+that this function is a setfable place."
+  (declare
+   (gv-setter (lambda (store)
+                `(if (quickurl-url-commented-p ,url)
+                     (if (zerop (length ,store))
+                         (setf (cdr ,url) (cadr ,url))
+                       (setf (nth 2 ,url) ,store))
+                   (unless (zerop (length ,store))
+                     (setf (cdr ,url) (list (cdr ,url) ,store)))))))
+  (if (quickurl-url-commented-p url)
+      (nth 2 url)
+    ""))
+
+(defun quickurl-url-description (url)
+  "Return a description for the URL.
+
+If the URL has a comment then this is returned, otherwise the keyword is
+returned."
+  (let ((desc (quickurl-url-comment url)))
+    (if (zerop (length desc))
+        (quickurl-url-keyword url)
+      desc)))
+
+;; Main code:
+
+(defun quickurl-format-url (url)
+  (format "<URL:%s>" (quickurl-url-url url)))
+
+(defun quickurl-sort-urls (list)
+  "Sort URLs in LIST according to their `quickurl-url-description'."
+  (sort list
+        (lambda (x y)
+          (string<
+           (downcase (quickurl-url-description x))
+           (downcase (quickurl-url-description y))))))
+
+(defun quickurl-read (&optional buffer)
+  "`read' the URL list from BUFFER into `quickurl-urls'.
+
+BUFFER, if nil, defaults to current buffer.
+Note that this function moves point to `point-min' before doing the `read'
+It also restores point after the `read'."
+  (save-excursion
+    (goto-char (point-min))
+    (setq quickurl-urls (funcall quickurl-sort-function
+                                 (read (or buffer (current-buffer)))))))
+
+(defun quickurl-load-urls ()
+  "Load the contents of `quickurl-url-file' into `quickurl-urls'."
+  (when (file-exists-p quickurl-url-file)
+    (with-temp-buffer
+      (insert-file-contents quickurl-url-file)
+      (quickurl-read))))
+
+(defun quickurl-save-urls ()
+  "Save the contents of `quickurl-urls' to `quickurl-url-file'."
+  (with-temp-buffer
+    (let ((standard-output (current-buffer))
+          (print-length nil))
+      (princ quickurl-prefix)
+      (pp quickurl-urls)
+      (princ quickurl-postfix)
+      (write-region (point-min) (point-max) quickurl-url-file nil 0))))
+
+(defun quickurl-find-url (lookup)
+  "Return URL associated with key LOOKUP.
+
+The lookup is done by looking in the alist `quickurl-urls' and the `cons'
+for the URL is returned.  The actual method used to look into the alist
+depends on the setting of the variable `quickurl-assoc-function'."
+  (funcall quickurl-assoc-function lookup quickurl-urls))
+
+(defun quickurl-insert (url &optional silent)
+  "Insert URL, formatted using `quickurl-format-function'.
+
+Also display a `message' saying what the URL was unless SILENT is non-nil."
+  (insert (funcall quickurl-format-function url))
+  (unless silent
+    (message "Found %s" (quickurl-url-url url))))
+
+;;;###autoload
+(defun quickurl (&optional lookup)
+  "Insert a URL based on LOOKUP.
+
+If not supplied LOOKUP is taken to be the word at point in the current
+buffer, this default action can be modified via
+`quickurl-grab-lookup-function'."
+  (interactive)
+  (when (or lookup
+            (setq lookup (funcall quickurl-grab-lookup-function)))
+    (quickurl-load-urls)
+    (let ((url (quickurl-find-url lookup)))
+      (if (null url)
+          (error "No URL associated with \"%s\"" lookup)
+        (when (looking-at "\\w")
+          (skip-syntax-forward "\\w"))
+        (insert " ")
+        (quickurl-insert url)))))
+
+;;;###autoload
+(defun quickurl-ask (lookup)
+  "Insert a URL, with `completing-read' prompt, based on LOOKUP."
+  (interactive
+   (list
+    (progn
+      (quickurl-load-urls)
+      (let ((completion-ignore-case quickurl-completion-ignore-case))
+        (completing-read "Lookup: " quickurl-urls nil t)))))
+  (let ((url (quickurl-find-url lookup)))
+    (when url
+      (quickurl-insert url))))
+
+(defun quickurl-grab-url ()
+  "Attempt to grab a word/URL pair from point in the current buffer.
+
+Point should be somewhere on the URL and the word is taken to be the thing
+that is returned from calling `quickurl-grab-lookup-function' once a
+`backward-word' has been issued at the start of the URL.
+
+It is assumed that the URL is either \"unguarded\" or is wrapped inside an
+<URL:...> wrapper."
+  (let ((url (thing-at-point 'url)))
+    (when url
+      (save-excursion
+        (beginning-of-thing 'url)
+        ;; `beginning-of-thing' doesn't take you to the start of a marked-up
+        ;; URL, only to the start of the URL within the "markup". So, we
+        ;; need to do a little more work to get to where we want to be.
+        (when (thing-at-point-looking-at thing-at-point-markedup-url-regexp)
+          (search-backward "<URL:"))
+        (backward-word-strictly 1)
+        (let ((word (funcall quickurl-grab-lookup-function)))
+          (when word
+            (quickurl-make-url
+             ;; The grab function may return the word with properties. I don't
+             ;; want the properties. I couldn't find a method of stripping
+             ;; them from a "string" so this will have to do. If you know of
+             ;; a better method of doing this I'd love to know.
+             (with-temp-buffer
+               (insert word)
+               (buffer-substring-no-properties (point-min) (point-max)))
+             url)))))))
+
+;;;###autoload
+(defun quickurl-add-url (word url comment)
+  "Allow the user to interactively add a new URL associated with WORD.
+
+See `quickurl-grab-url' for details on how the default word/URL combination
+is decided."
+  (interactive (let ((word-url (quickurl-grab-url)))
+                 (list (read-string "Word: "    (quickurl-url-keyword 
word-url))
+                       (read-string "URL: "     (quickurl-url-url word-url))
+                       (read-string "Comment: " (quickurl-url-comment 
word-url)))))
+  (if (zerop (length word))
+      (error "You must specify a WORD for lookup")
+    (quickurl-load-urls)
+    (let* ((current-url (quickurl-find-url word))
+           (add-it      (if current-url
+                            (if (called-interactively-p 'interactive)
+                                (y-or-n-p (format "\"%s\" exists, replace URL? 
" word))
+                              t)
+                          t)))
+      (when add-it
+        (if current-url
+            (progn
+              (setf (quickurl-url-url current-url) url)
+              (setf (quickurl-url-comment current-url) comment))
+          (push (quickurl-make-url word url comment) quickurl-urls))
+        (setq quickurl-urls (funcall quickurl-sort-function quickurl-urls))
+        (quickurl-save-urls)
+        (when (get-buffer quickurl-list-buffer-name)
+          (quickurl-list-populate-buffer))
+        (when (called-interactively-p 'interactive)
+          (message "Added %s" url))))))
+
+;;;###autoload
+(defun quickurl-browse-url (&optional lookup)
+  "Browse the URL associated with LOOKUP.
+
+If not supplied LOOKUP is taken to be the word at point in the
+current buffer, this default action can be modified via
+`quickurl-grab-lookup-function'."
+  (interactive)
+  (when (or lookup
+            (setq lookup (funcall quickurl-grab-lookup-function)))
+    (quickurl-load-urls)
+    (let ((url (quickurl-find-url lookup)))
+      (if url
+          (browse-url (quickurl-url-url url))
+        (error "No URL associated with \"%s\"" lookup)))))
+
+;;;###autoload
+(defun quickurl-browse-url-ask (lookup)
+  "Browse the URL, with `completing-read' prompt, associated with LOOKUP."
+  (interactive (list
+                (progn
+                  (quickurl-load-urls)
+                  (completing-read "Browse: " quickurl-urls nil t))))
+  (let ((url (quickurl-find-url lookup)))
+    (when url
+      (browse-url (quickurl-url-url url)))))
+
+;;;###autoload
+(defun quickurl-edit-urls ()
+  "Pull `quickurl-url-file' into a buffer for hand editing."
+  (interactive)
+  (find-file quickurl-url-file))
+
+;; quickurl-list mode.
+
+;;;###autoload
+(define-derived-mode quickurl-list-mode special-mode "Quickurl"
+  "A mode for browsing the quickurl URL list.
+
+The key bindings for `quickurl-list-mode' are:
+
+\\{quickurl-list-mode-map}"
+  (setq truncate-lines t))
+
+;;;###autoload
+(defun quickurl-list ()
+  "Display `quickurl-list' as a formatted list using `quickurl-list-mode'."
+  (interactive)
+  (quickurl-load-urls)
+  (unless (string= (buffer-name) quickurl-list-buffer-name)
+    (setq quickurl-list-last-buffer (current-buffer)))
+  (pop-to-buffer quickurl-list-buffer-name)
+  (quickurl-list-populate-buffer)
+  (quickurl-list-mode))
+
+(defun quickurl-list-populate-buffer ()
+  "Populate the `quickurl-list' buffer."
+  (with-current-buffer (get-buffer quickurl-list-buffer-name)
+    (let* ((sizes (or (cl-loop for url in quickurl-urls
+                               collect (length (quickurl-url-description url)))
+                      (list 20)))
+           (fmt (format "%%-%ds %%s\n" (apply #'max sizes)))
+           (inhibit-read-only t))
+      (erase-buffer)
+      (dolist (url quickurl-urls)
+        (let ((start (point)))
+          (insert (format fmt (quickurl-url-description url)
+                          (quickurl-url-url url)))
+          (add-text-properties
+           start (1- (point))
+           '(mouse-face highlight help-echo "mouse-2: insert this URL"))))
+      (goto-char (point-min)))))
+
+(defun quickurl-list-add-url (word url comment)
+  "Wrapper for `quickurl-add-url' that doesn't guess the parameters."
+  (interactive "sWord: \nsURL: \nsComment: ")
+  (quickurl-add-url word url comment))
+
+(defun quickurl-list-quit ()
+  "Kill the buffer named `quickurl-list-buffer-name'."
+  (interactive)
+  (quit-window t))
+
+(defun quickurl-list-mouse-select (event)
+  "Select the URL under the mouse click."
+  (interactive "e")
+  (goto-char (posn-point (event-end event)))
+  (quickurl-list-insert-url))
+
+(defun quickurl-list-insert (type)
+  "Insert the URL under cursor into `quickurl-list-last-buffer'.
+TYPE dictates what will be inserted, options are:
+  `url'         - Insert the URL as <URL:url>
+  `naked-url'   - Insert the URL with no formatting
+  `with-lookup' - Insert \"lookup <URL:url>\"
+  `with-desc'   - Insert \"description <URL:url>\"
+  `lookup'      - Insert the lookup for that URL"
+  (let ((url (nth (count-lines (point-min) (line-beginning-position))
+                  quickurl-urls)))
+    (if url
+        (with-current-buffer quickurl-list-last-buffer
+          (insert
+           (pcase type
+             ('url         (funcall quickurl-format-function url))
+             ('naked-url   (quickurl-url-url url))
+             ('with-lookup (format "%s <URL:%s>"
+                                   (quickurl-url-keyword url)
+                                   (quickurl-url-url url)))
+             ('with-desc   (format "%S <URL:%s>"
+                                   (quickurl-url-description url)
+                                   (quickurl-url-url url)))
+             ('lookup      (quickurl-url-keyword url)))))
+      (error "No URL details on that line"))
+    url))
+
+(defmacro quickurl-list-make-inserter (type)
+  "Macro to make a key-response function for use in `quickurl-list-mode-map'."
+  `(defun ,(intern (format "quickurl-list-insert-%S" type)) ()
+    ,(format "Insert the result of calling `quickurl-list-insert' with `%s'." 
type)
+    (interactive)
+    (when (quickurl-list-insert ',type)
+      (quickurl-list-quit))))
+
+(quickurl-list-make-inserter url)
+(quickurl-list-make-inserter naked-url)
+(quickurl-list-make-inserter with-lookup)
+(quickurl-list-make-inserter with-desc)
+(quickurl-list-make-inserter lookup)
+
+(provide 'quickurl)
+
+;;; quickurl.el ends here
diff --git a/lisp/obsolete/rcompile.el b/lisp/obsolete/rcompile.el
index fbfc0c6bbc..ceffb072cb 100644
--- a/lisp/obsolete/rcompile.el
+++ b/lisp/obsolete/rcompile.el
@@ -167,7 +167,7 @@ See \\[compile]."
     (compilation-start compile-command)
     ;; Set comint-file-name-prefix in the compilation buffer so
     ;; compilation-parse-errors will find referenced files by Tramp.
-    (with-current-buffer compilation-last-buffer
+    (with-current-buffer next-error-last-buffer
       (when (fboundp 'tramp-make-tramp-file-name)
        (set (make-local-variable 'comint-file-name-prefix)
             (funcall
diff --git a/lisp/obsolete/rlogin.el b/lisp/obsolete/rlogin.el
new file mode 100644
index 0000000000..6a06300ae3
--- /dev/null
+++ b/lisp/obsolete/rlogin.el
@@ -0,0 +1,307 @@
+;;; rlogin.el --- remote login interface  -*- lexical-binding:t -*-
+
+;; Copyright (C) 1992-2022 Free Software Foundation, Inc.
+
+;; Author: Noah Friedman <friedman@splode.com>
+;; Keywords: unix, comm
+;; Obsolete-since: 29.1
+
+;; 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 library is obsolete.
+;; See: https://debbugs.gnu.org/56461
+
+;; Support for remote logins using `rlogin'.
+;; This program is layered on top of shell.el; the code here only accounts
+;; for the variations needed to handle a remote process, e.g. directory
+;; tracking and the sending of some special characters.
+
+;; If you wish for rlogin mode to prompt you in the minibuffer for
+;; passwords when a password prompt appears, just enter
+;; M-x comint-send-invisible and type in your line (or tweak
+;; `comint-password-prompt-regexp' to match your password prompt).
+
+;;; Code:
+
+(require 'comint)
+(require 'shell)
+
+(defgroup rlogin nil
+  "Remote login interface."
+  :group 'processes
+  :group 'unix)
+
+(defcustom rlogin-program "ssh"
+  "Name of program to invoke remote login."
+  :version "24.4"                       ; rlogin -> ssh
+  :type 'string
+  :group 'rlogin)
+
+(defcustom rlogin-explicit-args '("-t" "-t")
+  "List of arguments to pass to `rlogin-program' on the command line."
+  :version "24.4"                       ; nil -> -t -t
+  :type '(repeat (string :tag "Argument"))
+  :group 'rlogin)
+
+(defcustom rlogin-mode-hook nil
+  "Hooks to run after setting current buffer to rlogin-mode."
+  :type 'hook
+  :group 'rlogin)
+
+(defcustom rlogin-process-connection-type
+  ;; Solaris 2.x `rlogin' will spew a bunch of ioctl error messages if
+  ;; stdin isn't a tty.
+  (and (string-match "rlogin" rlogin-program)
+       (string-match-p "-solaris2" system-configuration) t)
+  "If non-nil, use a pty for the local rlogin process.
+If nil, use a pipe (if pipes are supported on the local system).
+
+Generally it is better not to waste ptys on systems which have a static
+number of them.  On the other hand, some implementations of `rlogin' assume
+a pty is being used, and errors will result from using a pipe instead."
+  :set-after '(rlogin-program)
+  :type '(choice (const :tag "pipes" nil)
+                (other :tag "ptys" t))
+  :group 'rlogin)
+
+(defcustom rlogin-directory-tracking-mode 'local
+  "Control whether and how to do directory tracking in an rlogin buffer.
+
+nil means don't do directory tracking.
+
+t means do so using an ftp remote file name.
+
+Any other value means do directory tracking using local file names.
+This works only if the remote machine and the local one
+share the same directories (through NFS).  This is the default.
+
+This variable becomes local to a buffer when set in any fashion for it.
+
+It is better to use the function of the same name to change the behavior of
+directory tracking in an rlogin session once it has begun, rather than
+simply setting this variable, since the function does the necessary
+re-synching of directories."
+  :type '(choice (const :tag "off" nil)
+                (const :tag "ftp" t)
+                (other :tag "local" local))
+  :group 'rlogin)
+
+(make-variable-buffer-local 'rlogin-directory-tracking-mode)
+
+(defcustom rlogin-host nil
+  "The name of the default remote host.  This variable is buffer-local."
+  :type '(choice (const nil) string)
+  :group 'rlogin)
+
+(defcustom rlogin-remote-user nil
+  "The username used on the remote host.
+This variable is buffer-local and defaults to your local user name.
+If rlogin is invoked with the `-l' option to specify the remote username,
+this variable is set from that."
+  :type '(choice (const nil) string)
+  :group 'rlogin)
+
+(defvar-keymap rlogin-mode-map
+  :doc "Keymap for `rlogin-mode'."
+  :parent shell-mode-map
+  "C-c C-c"  #'rlogin-send-Ctrl-C
+  "C-c C-d"  #'rlogin-send-Ctrl-D
+  "C-c C-z"  #'rlogin-send-Ctrl-Z
+  "C-c C-\\" #'rlogin-send-Ctrl-backslash
+  "C-d"      #'rlogin-delchar-or-send-Ctrl-D
+  "TAB"      #'rlogin-tab-or-complete)
+
+
+(defvar rlogin-history nil)
+
+;;;###autoload
+(defun rlogin (input-args &optional buffer)
+  "Open a network login connection via `rlogin' with args INPUT-ARGS.
+INPUT-ARGS should start with a host name; it may also contain
+other arguments for `rlogin'.
+
+Input is sent line-at-a-time to the remote connection.
+
+Communication with the remote host is recorded in a buffer `*rlogin-HOST*'
+\(or `*rlogin-USER@HOST*' if the remote username differs).
+If a prefix argument is given and the buffer `*rlogin-HOST*' already exists,
+a new buffer with a different connection will be made.
+
+When called from a program, if the optional second argument BUFFER is
+a string or buffer, it specifies the buffer to use.
+
+The variable `rlogin-program' contains the name of the actual program to
+run.  It can be a relative or absolute path.
+
+The variable `rlogin-explicit-args' is a list of arguments to give to
+the rlogin when starting.  They are added after any arguments given in
+INPUT-ARGS.
+
+If the default value of `rlogin-directory-tracking-mode' is t, then the
+default directory in that buffer is set to a remote (FTP) file name to
+access your home directory on the remote machine.  Occasionally this causes
+an error, if you cannot access the home directory on that machine.  This
+error is harmless as long as you don't try to use that default directory.
+
+If `rlogin-directory-tracking-mode' is neither t nor nil, then the default
+directory is initially set up to your (local) home directory.
+This is useful if the remote machine and your local machine
+share the same files via NFS.  This is the default.
+
+If you wish to change directory tracking styles during a session, use the
+function `rlogin-directory-tracking-mode' rather than simply setting the
+variable."
+  (interactive (list
+               (read-from-minibuffer (format-message
+                                       "Arguments for `%s' (hostname first): "
+                                       (file-name-nondirectory rlogin-program))
+                                     nil nil nil 'rlogin-history)
+               current-prefix-arg))
+  (let* ((process-connection-type rlogin-process-connection-type)
+         (args (if rlogin-explicit-args
+                   (append (split-string input-args)
+                           rlogin-explicit-args)
+                 (split-string input-args)))
+         (host (let ((tail args))
+                 ;; Find first arg that doesn't look like an option.
+                 ;; This still loses for args that take values, feh.
+                 (while (and tail (= ?- (aref (car tail) 0)))
+                   (setq tail (cdr tail)))
+                 (car tail)))
+        (user (or (car (cdr (member "-l" args)))
+                   (user-login-name)))
+         (buffer-name (if (string= user (user-login-name))
+                          (format "*rlogin-%s*" host)
+                        (format "*rlogin-%s@%s*" user host))))
+    (cond ((null buffer))
+         ((stringp buffer)
+          (setq buffer-name buffer))
+          ((bufferp buffer)
+           (setq buffer-name (buffer-name buffer)))
+          ((numberp buffer)
+           (setq buffer-name (format "%s<%d>" buffer-name buffer)))
+          (t
+           (setq buffer-name (generate-new-buffer-name buffer-name))))
+    (setq buffer (get-buffer-create buffer-name))
+    (switch-to-buffer buffer-name)
+    (unless (comint-check-proc buffer-name)
+      (comint-exec buffer buffer-name rlogin-program nil args)
+      (rlogin-mode)
+      (setq-local rlogin-host host)
+      (setq-local rlogin-remote-user user)
+      (ignore-errors
+        (cond ((eq rlogin-directory-tracking-mode t)
+               ;; Do this here, rather than calling the tracking mode
+               ;; function, to avoid a gratuitous resync check; the default
+               ;; should be the user's home directory, be it local or remote.
+               (setq comint-file-name-prefix
+                     (concat "/-:" rlogin-remote-user "@" rlogin-host ":"))
+               (cd-absolute comint-file-name-prefix))
+              ((null rlogin-directory-tracking-mode))
+              (t
+               (cd-absolute (concat comint-file-name-prefix "~/"))))))))
+
+(put 'rlogin-mode 'mode-class 'special)
+
+(define-derived-mode rlogin-mode shell-mode "Rlogin"
+  (setq shell-dirtrackp rlogin-directory-tracking-mode)
+  (make-local-variable 'comint-file-name-prefix))
+
+(defun rlogin-directory-tracking-mode (&optional prefix)
+  "Do remote or local directory tracking, or disable entirely.
+
+If called with no prefix argument or a unspecified prefix argument (just
+`\\[universal-argument]' with no number) do remote directory tracking via
+ange-ftp.  If called as a function, give it no argument.
+
+If called with a negative prefix argument, disable directory tracking
+entirely.
+
+If called with a positive, numeric prefix argument, for example
+\\[universal-argument] 1 \\[rlogin-directory-tracking-mode],
+then do directory tracking but assume the remote filesystem is the same as
+the local system.  This only works in general if the remote machine and the
+local one share the same directories (e.g. through NFS)."
+  (interactive "P")
+  (cond
+   ((or (null prefix)
+        (consp prefix))
+    (setq rlogin-directory-tracking-mode t)
+    (setq shell-dirtrackp t)
+    (setq comint-file-name-prefix
+          (concat "/-:" rlogin-remote-user "@" rlogin-host ":")))
+   ((< prefix 0)
+    (setq rlogin-directory-tracking-mode nil)
+    (setq shell-dirtrackp nil))
+   (t
+    (setq rlogin-directory-tracking-mode 'local)
+    (setq comint-file-name-prefix "")
+    (setq shell-dirtrackp t)))
+  (cond
+   (shell-dirtrackp
+    (let* ((proc (get-buffer-process (current-buffer)))
+           (proc-mark (process-mark proc))
+           (current-input (buffer-substring proc-mark (point-max)))
+           (orig-point (point))
+           (offset (and (>= orig-point proc-mark)
+                        (- (point-max) orig-point))))
+      (unwind-protect
+          (progn
+            (delete-region proc-mark (point-max))
+            (goto-char (point-max))
+            (shell-resync-dirs))
+        (goto-char proc-mark)
+        (insert current-input)
+        (if offset
+            (goto-char (- (point-max) offset))
+          (goto-char orig-point)))))))
+
+
+(defun rlogin-send-Ctrl-C ()
+  (interactive)
+  (process-send-string nil "\C-c"))
+
+(defun rlogin-send-Ctrl-D ()
+  (interactive)
+  (process-send-string nil "\C-d"))
+
+(defun rlogin-send-Ctrl-Z ()
+  (interactive)
+  (process-send-string nil "\C-z"))
+
+(defun rlogin-send-Ctrl-backslash ()
+  (interactive)
+  (process-send-string nil "\C-\\"))
+
+(defun rlogin-delchar-or-send-Ctrl-D (arg)
+  "Delete ARG characters forward, or send a C-d to process if at end of 
buffer."
+  (interactive "p")
+  (if (eobp)
+      (rlogin-send-Ctrl-D)
+    (delete-char arg)))
+
+(defun rlogin-tab-or-complete ()
+  "Complete file name if doing directory tracking, or just insert TAB."
+  (interactive)
+  (if rlogin-directory-tracking-mode
+      (completion-at-point)
+    (insert "\C-i")))
+
+(provide 'rlogin)
+
+;;; rlogin.el ends here
diff --git a/lisp/obsolete/s-region.el b/lisp/obsolete/s-region.el
deleted file mode 100644
index 9dfc9831f4..0000000000
--- a/lisp/obsolete/s-region.el
+++ /dev/null
@@ -1,123 +0,0 @@
-;;; s-region.el --- set region using shift key  -*- lexical-binding: t; -*-
-
-;; Copyright (C) 1994-1995, 2001-2022 Free Software Foundation, Inc.
-
-;; Author: Morten Welinder <terra@diku.dk>
-;; Keywords: terminals
-;; Favorite-brand-of-beer: None, I hate beer.
-;; Obsolete-since: 24.1
-
-;; 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:
-
-;; Having loaded this code you can set the region by holding down the
-;; shift key and move the cursor to the other end of the region.  The
-;; functionality provided by this code is similar to that provided by
-;; the editors of Borland International's compilers for ms-dos.
-
-;; Currently, s-region-move may be bound only to events that are vectors
-;; of length one and whose last element is a symbol.  Also, the functions
-;; that are given this kind of overlay should be (interactive "p")
-;; functions.
-
-;; If the following keys are not already bound then...
-;; C-insert is bound to copy-region-as-kill
-;; S-delete is bound to kill-region
-;; S-insert is bound to yank
-
-;;; Code:
-
-(defvar s-region-overlay (make-overlay 1 1))
-(overlay-put s-region-overlay 'face 'region)
-(overlay-put s-region-overlay 'priority 1000000) ; for hilit19
-
-(defun s-region-unshift (key)
-  "Remove shift modifier from last keypress KEY and return that as a key."
-  (if (vectorp key)
-      (let ((last (aref key (1- (length key)))))
-       (if (symbolp last)
-           (let* ((keyname (symbol-name last))
-                  (pos (string-match "S-" keyname)))
-             (if pos
-                 ;; We skip all initial parts of the event assuming that
-                 ;; those are setting up the prefix argument to the command.
-                 (vector (intern (concat (substring keyname 0 pos)
-                                         (substring keyname (+ 2 pos)))))
-               (error "Non-shifted key: %S" key)))
-         (error "Key does not end in a symbol: %S" key)))
-    (error "Non-vector key: %S" key)))
-
-(defun s-region-move-p1 (&rest arg)
-  "This is an overlay function to point-moving keys that are interactive 
\"p\"."
-  (interactive "p")
-  (apply (function s-region-move) arg))
-
-(defun s-region-move-p2 (&rest arg)
-  "This is an overlay function to point-moving keys that are interactive 
\"P\"."
-  (interactive "P")
-  (apply (function s-region-move) arg))
-
-(defun s-region-move (&rest arg)
-  (if (if mark-active (not (equal last-command 's-region-move)) t)
-      (set-mark-command nil)
-    (message "")) ; delete the "Mark set" message
-  (setq this-command 's-region-move)
-  (apply (key-binding (s-region-unshift (this-command-keys))) arg)
-  (move-overlay s-region-overlay (mark) (point) (current-buffer))
-  (sit-for 1)
-  (delete-overlay s-region-overlay))
-
-(defun s-region-bind (keylist &optional map)
-  "Bind shifted keys in KEYLIST to `s-region-move-p1' or `s-region-move-p2'.
-Each key in KEYLIST is shifted and bound to one of the `s-region-move'
-functions provided it is already bound to some command or other.
-Optional second argument MAP specifies keymap to add binding to, defaulting
-to global keymap."
-  (let ((p2 (list 'scroll-up 'scroll-down
-                 'beginning-of-buffer 'end-of-buffer)))
-    (or map (setq map global-map))
-    (while keylist
-      (let* ((key (car keylist))
-            (binding (key-binding key)))
-       (if (commandp binding)
-           (define-key
-             map
-             (vector (intern (concat "S-" (symbol-name (aref key 0)))))
-             (cond ((memq binding p2)
-                    's-region-move-p2)
-                   (t 's-region-move-p1)))))
-      (setq keylist (cdr keylist)))))
-
-;; Single keys (plus modifiers) only!
-(s-region-bind
- (list [right] [left] [up] [down]
-       [C-left] [C-right] [C-up] [C-down]
-       [M-left] [M-right] [M-up] [M-down]
-       [next] [previous] [home] [end]
-       [C-next] [C-previous] [C-home] [C-end]
-       [M-next] [M-previous] [M-home] [M-end]))
-
-(or (global-key-binding [C-insert])
-    (global-set-key [C-insert] #'copy-region-as-kill))
-(or (global-key-binding [S-delete])
-    (global-set-key [S-delete] #'kill-region))
-(or (global-key-binding [S-insert])
-    (global-set-key [S-insert] #'yank))
-
-(provide 's-region)
-
-;;; s-region.el ends here
diff --git a/lisp/obsolete/sregex.el b/lisp/obsolete/sregex.el
deleted file mode 100644
index f8722f6129..0000000000
--- a/lisp/obsolete/sregex.el
+++ /dev/null
@@ -1,605 +0,0 @@
-;;; sregex.el --- symbolic regular expressions  -*- lexical-binding: t; -*-
-
-;; Copyright (C) 1997-1998, 2000-2022 Free Software Foundation, Inc.
-
-;; Author: Bob Glickstein <bobg+sregex@zanshin.com>
-;; Maintainer: emacs-devel@gnu.org
-;; Keywords: extensions
-;; Obsolete-since: 24.1
-
-;; 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 package allows you to write regular expressions using a
-;; totally new, Lisp-like syntax.
-
-;; A "symbolic regular expression" (sregex for short) is a Lisp form
-;; that, when evaluated, produces the string form of the specified
-;; regular expression.  Here's a simple example:
-
-;;   (sregexq (or "Bob" "Robert"))  =>  "Bob\\|Robert"
-
-;; As you can see, an sregex is specified by placing one or more
-;; special clauses in a call to `sregexq'.  The clause in this case is
-;; the `or' of two strings (not to be confused with the Lisp function
-;; `or').  The list of allowable clauses appears below.
-
-;; With sregex, it is never necessary to "escape" magic characters
-;; that are meant to be taken literally; that happens automatically.
-;; For example:
-
-;;   (sregexq "M*A*S*H")  =>  "M\\*A\\*S\\*H"
-
-;; It is also unnecessary to "group" parts of the expression together
-;; to overcome operator precedence; that also happens automatically.
-;; For example:
-
-;;   (sregexq (opt (or "Bob" "Robert")))  =>  "\\(?:Bob\\|Robert\\)?"
-
-;; It *is* possible to group parts of the expression in order to refer
-;; to them with numbered backreferences:
-
-;;   (sregexq (group (or "Go" "Run"))
-;;            ", Spot, "
-;;            (backref 1))             =>  "\\(Go\\|Run\\), Spot, \\1"
-
-;; `sregexq' is a macro.  Each time it is used, it constructs a simple
-;; Lisp expression that then invokes a moderately complex engine to
-;; interpret the sregex and render the string form.  Because of this,
-;; I don't recommend sprinkling calls to `sregexq' throughout your
-;; code, the way one normally does with string regexes (which are
-;; cheap to evaluate).  Instead, it's wiser to precompute the regexes
-;; you need wherever possible instead of repeatedly constructing the
-;; same ones over and over.  Example:
-
-;;    (let ((field-regex (sregexq (opt "resent-")
-;;                                (or "to" "cc" "bcc"))))
-;;      ...
-;;      (while ...
-;;        ...
-;;        (re-search-forward field-regex ...)
-;;        ...))
-
-;; The arguments to `sregexq' are automatically quoted, but the
-;; flipside of this is that it is not straightforward to include
-;; computed (i.e., non-constant) values in `sregexq' expressions.  So
-;; `sregex' is a function that is like `sregexq' but which does not
-;; automatically quote its values.  Literal sregex clauses must be
-;; explicitly quoted like so:
-
-;;   (sregex '(or "Bob" "Robert"))  =>  "Bob\\|Robert"
-
-;; but computed clauses can be included easily, allowing for the reuse
-;; of common clauses:
-
-;;  (let ((dotstar '(0+ any))
-;;        (whitespace '(1+ (syntax ?-)))
-;;        (digits '(1+ (char (?0 . ?9)))))
-;;    (sregex 'bol dotstar ":" whitespace digits))  =>  "^.*:\\s-+[0-9]+"
-
-;; To use this package in a Lisp program, simply (require 'sregex).
-
-;; Here are the clauses allowed in an `sregex' or `sregexq'
-;; expression:
-
-;; - a string
-;;   This stands for the literal string.  If it contains
-;;   metacharacters, they will be escaped in the resulting regex
-;;   (using `regexp-quote').
-
-;; - the symbol `any'
-;;   This stands for ".", a regex matching any character except
-;;   newline.
-
-;; - the symbol `bol'
-;;   Stands for "^", matching the empty string at the beginning of a line
-
-;; - the symbol `eol'
-;;   Stands for "$", matching the empty string at the end of a line
-
-;; - (group CLAUSE ...)
-;;   Groups the given CLAUSEs using "\\(" and "\\)".
-
-;; - (sequence CLAUSE ...)
-
-;;   Groups the given CLAUSEs; may or may not use "\\(?:" and "\\)".
-;;   Clauses grouped by `sequence' do not count for purposes of
-;;   numbering backreferences.  Use `sequence' in situations like
-;;   this:
-
-;;     (sregexq (or "dog" "cat"
-;;                  (sequence (opt "sea ") "monkey")))
-;;                                  =>  "dog\\|cat\\|\\(?:sea \\)?monkey"
-
-;;   where a single `or' alternate needs to contain multiple
-;;   subclauses.
-
-;; - (backref N)
-;;   Matches the same string previously matched by the Nth "group" in
-;;   the same sregex.  N is a positive integer.
-
-;; - (or CLAUSE ...)
-;;   Matches any one of the CLAUSEs by separating them with "\\|".
-
-;; - (0+ CLAUSE ...)
-;;   Concatenates the given CLAUSEs and matches zero or more
-;;   occurrences by appending "*".
-
-;; - (1+ CLAUSE ...)
-;;   Concatenates the given CLAUSEs and matches one or more
-;;   occurrences by appending "+".
-
-;; - (opt CLAUSE ...)
-;;   Concatenates the given CLAUSEs and matches zero or one occurrence
-;;   by appending "?".
-
-;; - (repeat MIN MAX CLAUSE ...)
-;;   Concatenates the given CLAUSEs and constructs a regex matching at
-;;   least MIN occurrences and at most MAX occurrences.  MIN must be a
-;;   non-negative integer.  MAX must be a non-negative integer greater
-;;   than or equal to MIN; or MAX can be nil to mean "infinity."
-
-;; - (char CHAR-CLAUSE ...)
-;;   Creates a "character class" matching one character from the given
-;;   set.  See below for how to construct a CHAR-CLAUSE.
-
-;; - (not-char CHAR-CLAUSE ...)
-;;   Creates a "character class" matching any one character not in the
-;;   given set.  See below for how to construct a CHAR-CLAUSE.
-
-;; - the symbol `bot'
-;;   Stands for "\\`", matching the empty string at the beginning of
-;;   text (beginning of a string or of a buffer).
-
-;; - the symbol `eot'
-;;   Stands for "\\'", matching the empty string at the end of text.
-
-;; - the symbol `point'
-;;   Stands for "\\=", matching the empty string at point.
-
-;; - the symbol `word-boundary'
-;;   Stands for "\\b", matching the empty string at the beginning or
-;;   end of a word.
-
-;; - the symbol `not-word-boundary'
-;;   Stands for "\\B", matching the empty string not at the beginning
-;;   or end of a word.
-
-;; - the symbol `bow'
-;;   Stands for "\\<", matching the empty string at the beginning of a
-;;   word.
-
-;; - the symbol `eow'
-;;   Stands for "\\>", matching the empty string at the end of a word.
-
-;; - the symbol `wordchar'
-;;   Stands for the regex "\\w", matching a word-constituent character
-;;   (as determined by the current syntax table)
-
-;; - the symbol `not-wordchar'
-;;   Stands for the regex "\\W", matching a non-word-constituent
-;;   character.
-
-;; - (syntax CODE)
-;;   Stands for the regex "\\sCODE", where CODE is a syntax table code
-;;   (a single character).  Matches any character with the requested
-;;   syntax.
-
-;; - (not-syntax CODE)
-;;   Stands for the regex "\\SCODE", where CODE is a syntax table code
-;;   (a single character).  Matches any character without the
-;;   requested syntax.
-
-;; - (regex REGEX)
-;;   This is a "trapdoor" for including ordinary regular expression
-;;   strings in the result.  Some regular expressions are clearer when
-;;   written the old way: "[a-z]" vs. (sregexq (char (?a . ?z))), for
-;;   instance.
-
-;; Each CHAR-CLAUSE that is passed to (char ...) and (not-char ...)
-;; has one of the following forms:
-
-;; - a character
-;;   Adds that character to the set.
-
-;; - a string
-;;   Adds all the characters in the string to the set.
-
-;; - A pair (MIN . MAX)
-;;   Where MIN and MAX are characters, adds the range of characters
-;;   from MIN through MAX to the set.
-
-;;; To do:
-
-;; An earlier version of this package could optionally translate the
-;; symbolic regex into other languages' syntaxes, e.g. Perl.  For
-;; instance, with Perl syntax selected, (sregexq (or "ab" "cd")) would
-;; yield "ab|cd" instead of "ab\\|cd".  It might be useful to restore
-;; such a facility.
-
-;; - handle multibyte chars in sregex--char-aux
-;; - add support for character classes ([:blank:], ...)
-;; - add support for non-greedy operators *? and +?
-;; - bug: (sregexq (opt (opt ?a))) returns "a??" which is a non-greedy "a?"
-
-;;; Code:
-
-(eval-when-compile (require 'cl-lib))
-
-;; Compatibility code for when we didn't have shy-groups
-(defvar sregex--current-sregex nil)
-(defun sregex-info () nil)
-(defmacro sregex-save-match-data (&rest forms) (cons 'save-match-data forms))
-(defun sregex-replace-match (r &optional f l str subexp _x)
-  (replace-match r f l str subexp))
-(defun sregex-match-string (c &optional i _x) (match-string c i))
-(defun sregex-match-string-no-properties (count &optional in-string _sregex)
-  (match-string-no-properties count in-string))
-(defun sregex-match-beginning (count &optional _sregex) (match-beginning 
count))
-(defun sregex-match-end (count &optional _sregex) (match-end count))
-(defun sregex-match-data (&optional _sregex) (match-data))
-(defun sregex-backref-num (n &optional _sregex) n)
-
-
-(defun sregex (&rest exps)
-  "Symbolic regular expression interpreter.
-This is exactly like `sregexq' (q.v.) except that it evaluates all its
-arguments, so literal sregex clauses must be quoted.  For example:
-
-  (sregex \\='(or \"Bob\" \"Robert\"))  =>  \"Bob\\\\|Robert\"
-
-An argument-evaluating sregex interpreter lets you reuse sregex
-subexpressions:
-
-  (let ((dotstar \\='(0+ any))
-        (whitespace \\='(1+ (syntax ?-)))
-        (digits \\='(1+ (char (?0 . ?9)))))
-    (sregex \\='bol dotstar \":\" whitespace digits))  =>  
\"^.*:\\\\s-+[0-9]+\""
-  (sregex--sequence exps nil))
-
-(defmacro sregexq (&rest exps)
-  "Symbolic regular expression interpreter.
-This macro allows you to specify a regular expression (regexp) in
-symbolic form, and converts it into the string form required by Emacs's
-regex functions such as `re-search-forward' and `looking-at'.  Here is
-a simple example:
-
-  (sregexq (or \"Bob\" \"Robert\"))  =>  \"Bob\\\\|Robert\"
-
-As you can see, an sregex is specified by placing one or more special
-clauses in a call to `sregexq'.  The clause in this case is the `or'
-of two strings (not to be confused with the Lisp function `or').  The
-list of allowable clauses appears below.
-
-With `sregex', it is never necessary to \"escape\" magic characters
-that are meant to be taken literally; that happens automatically.
-For example:
-
-  (sregexq \"M*A*S*H\")  =>  \"M\\\\*A\\\\*S\\\\*H\"
-
-It is also unnecessary to \"group\" parts of the expression together
-to overcome operator precedence; that also happens automatically.
-For example:
-
-  (sregexq (opt (or \"Bob\" \"Robert\")))  =>  \"\\\\(Bob\\\\|Robert\\\\)?\"
-
-It *is* possible to group parts of the expression in order to refer
-to them with numbered backreferences:
-
-  (sregexq (group (or \"Go\" \"Run\"))
-           \", Spot, \"
-           (backref 1))             =>  \"\\\\(Go\\\\|Run\\\\), Spot, \\\\1\"
-
-If `sregexq' needs to introduce its own grouping parentheses, it will
-automatically renumber your backreferences:
-
-  (sregexq (opt \"resent-\")
-           (group (or \"to\" \"cc\" \"bcc\"))
-           \": \"
-           (backref 1))  =>  \"\\\\(resent-\\\\)?\\\\(to\\\\|cc\\\\|bcc\\\\): 
\\\\2\"
-
-`sregexq' is a macro.  Each time it is used, it constructs a simple
-Lisp expression that then invokes a moderately complex engine to
-interpret the sregex and render the string form.  Because of this, I
-don't recommend sprinkling calls to `sregexq' throughout your code,
-the way one normally does with string regexes (which are cheap to
-evaluate).  Instead, it's wiser to precompute the regexes you need
-wherever possible instead of repeatedly constructing the same ones
-over and over.  Example:
-
-   (let ((field-regex (sregexq (opt \"resent-\")
-                               (or \"to\" \"cc\" \"bcc\"))))
-     ...
-     (while ...
-       ...
-       (re-search-forward field-regex ...)
-       ...))
-
-The arguments to `sregexq' are automatically quoted, but the
-flipside of this is that it is not straightforward to include
-computed (i.e., non-constant) values in `sregexq' expressions.  So
-`sregex' is a function that is like `sregexq' but which does not
-automatically quote its values.  Literal sregex clauses must be
-explicitly quoted like so:
-
-  (sregex \\='(or \"Bob\" \"Robert\"))  =>  \"Bob\\\\|Robert\"
-
-but computed clauses can be included easily, allowing for the reuse
-of common clauses:
-
-  (let ((dotstar \\='(0+ any))
-        (whitespace \\='(1+ (syntax ?-)))
-        (digits \\='(1+ (char (?0 . ?9)))))
-    (sregex \\='bol dotstar \":\" whitespace digits))  =>  
\"^.*:\\\\s-+[0-9]+\"
-
-Here are the clauses allowed in an `sregex' or `sregexq' expression:
-
-- a string
-  This stands for the literal string.  If it contains
-  metacharacters, they will be escaped in the resulting regex
-  (using `regexp-quote').
-
-- the symbol `any'
-  This stands for \".\", a regex matching any character except
-  newline.
-
-- the symbol `bol'
-  Stands for \"^\", matching the empty string at the beginning of a line
-
-- the symbol `eol'
-  Stands for \"$\", matching the empty string at the end of a line
-
-- (group CLAUSE ...)
-  Groups the given CLAUSEs using \"\\\\(\" and \"\\\\)\".
-
-- (sequence CLAUSE ...)
-
-  Groups the given CLAUSEs; may or may not use \"\\\\(\" and \"\\\\)\".
-  Clauses grouped by `sequence' do not count for purposes of
-  numbering backreferences.  Use `sequence' in situations like
-  this:
-
-    (sregexq (or \"dog\" \"cat\"
-                 (sequence (opt \"sea \") \"monkey\")))
-                                 =>  \"dog\\\\|cat\\\\|\\\\(?:sea 
\\\\)?monkey\"
-
-  where a single `or' alternate needs to contain multiple
-  subclauses.
-
-- (backref N)
-  Matches the same string previously matched by the Nth \"group\" in
-  the same sregex.  N is a positive integer.
-
-- (or CLAUSE ...)
-  Matches any one of the CLAUSEs by separating them with \"\\\\|\".
-
-- (0+ CLAUSE ...)
-  Concatenates the given CLAUSEs and matches zero or more
-  occurrences by appending \"*\".
-
-- (1+ CLAUSE ...)
-  Concatenates the given CLAUSEs and matches one or more
-  occurrences by appending \"+\".
-
-- (opt CLAUSE ...)
-  Concatenates the given CLAUSEs and matches zero or one occurrence
-  by appending \"?\".
-
-- (repeat MIN MAX CLAUSE ...)
-  Concatenates the given CLAUSEs and constructs a regex matching at
-  least MIN occurrences and at most MAX occurrences.  MIN must be a
-  non-negative integer.  MAX must be a non-negative integer greater
-  than or equal to MIN; or MAX can be nil to mean \"infinity.\"
-
-- (char CHAR-CLAUSE ...)
-  Creates a \"character class\" matching one character from the given
-  set.  See below for how to construct a CHAR-CLAUSE.
-
-- (not-char CHAR-CLAUSE ...)
-  Creates a \"character class\" matching any one character not in the
-  given set.  See below for how to construct a CHAR-CLAUSE.
-
-- the symbol `bot'
-  Stands for \"\\\\\\=`\", matching the empty string at the beginning of
-  text (beginning of a string or of a buffer).
-
-- the symbol `eot'
-  Stands for \"\\\\'\", matching the empty string at the end of text.
-
-- the symbol `point'
-  Stands for \"\\\\=\\=\", matching the empty string at point.
-
-- the symbol `word-boundary'
-  Stands for \"\\\\b\", matching the empty string at the beginning or
-  end of a word.
-
-- the symbol `not-word-boundary'
-  Stands for \"\\\\B\", matching the empty string not at the beginning
-  or end of a word.
-
-- the symbol `bow'
-  Stands for \"\\\\=\\<\", matching the empty string at the beginning of a
-  word.
-
-- the symbol `eow'
-  Stands for \"\\\\=\\>\", matching the empty string at the end of a word.
-
-- the symbol `wordchar'
-  Stands for the regex \"\\\\w\", matching a word-constituent character
-  (as determined by the current syntax table)
-
-- the symbol `not-wordchar'
-  Stands for the regex \"\\\\W\", matching a non-word-constituent
-  character.
-
-- (syntax CODE)
-  Stands for the regex \"\\\\sCODE\", where CODE is a syntax table code
-  (a single character).  Matches any character with the requested
-  syntax.
-
-- (not-syntax CODE)
-  Stands for the regex \"\\\\SCODE\", where CODE is a syntax table code
-  (a single character).  Matches any character without the
-  requested syntax.
-
-- (regex REGEX)
-  This is a \"trapdoor\" for including ordinary regular expression
-  strings in the result.  Some regular expressions are clearer when
-  written the old way: \"[a-z]\" vs. (sregexq (char (?a . ?z))), for
-  instance.
-
-Each CHAR-CLAUSE that is passed to (char ...) and (not-char ...)
-has one of the following forms:
-
-- a character
-  Adds that character to the set.
-
-- a string
-  Adds all the characters in the string to the set.
-
-- A pair (MIN . MAX)
-  Where MIN and MAX are characters, adds the range of characters
-  from MIN through MAX to the set."
-  `(apply 'sregex ',exps))
-
-(defun sregex--engine (exp combine)
-  (cond
-   ((stringp exp)
-    (if (and combine
-            (eq combine 'suffix)
-            (/= (length exp) 1))
-       (concat "\\(?:" (regexp-quote exp) "\\)")
-      (regexp-quote exp)))
-   ((symbolp exp)
-    (cl-ecase exp
-      (any ".")
-      (bol "^")
-      (eol "$")
-      (wordchar "\\w")
-      (not-wordchar "\\W")
-      (bot "\\`")
-      (eot "\\'")
-      (point "\\=")
-      (word-boundary "\\b")
-      (not-word-boundary "\\B")
-      (bow "\\<")
-      (eow "\\>")))
-   ((consp exp)
-    (funcall (intern (concat "sregex--"
-                            (symbol-name (car exp))))
-            (cdr exp)
-            combine))
-   (t (error "Invalid expression: %s" exp))))
-
-(defun sregex--sequence (exps combine)
-  (if (= (length exps) 1) (sregex--engine (car exps) combine)
-    (let ((re (mapconcat
-              (lambda (e) (sregex--engine e 'concat))
-              exps "")))
-      (if (eq combine 'suffix)
-          (concat "\\(?:" re "\\)")
-        re))))
-
-(defun sregex--or (exps combine)
-  (if (= (length exps) 1) (sregex--engine (car exps) combine)
-    (let ((re (mapconcat
-              (lambda (e) (sregex--engine e 'or))
-              exps "\\|")))
-      (if (not (eq combine 'or))
-          (concat "\\(?:" re "\\)")
-        re))))
-
-(defun sregex--group (exps _combine) (concat "\\(" (sregex--sequence exps nil) 
"\\)"))
-
-(defun sregex--backref (exps _combine) (concat "\\" (int-to-string (car 
exps))))
-(defun sregex--opt (exps _combine) (concat (sregex--sequence exps 'suffix) 
"?"))
-(defun sregex--0+ (exps _combine) (concat (sregex--sequence exps 'suffix) "*"))
-(defun sregex--1+ (exps _combine) (concat (sregex--sequence exps 'suffix) "+"))
-
-(defun sregex--char (exps _combine) (sregex--char-aux nil exps))
-(defun sregex--not-char (exps _combine) (sregex--char-aux t exps))
-
-(defun sregex--syntax (exps _combine) (format "\\s%c" (car exps)))
-(defun sregex--not-syntax (exps _combine) (format "\\S%c" (car exps)))
-
-(defun sregex--regex (exps combine)
-  (if combine (concat "\\(?:" (car exps) "\\)") (car exps)))
-
-(defun sregex--repeat (exps _combine)
-  (let* ((min (or (pop exps) 0))
-        (minstr (number-to-string min))
-        (max (pop exps)))
-    (concat (sregex--sequence exps 'suffix)
-           (concat "\\{" minstr ","
-                   (when max (number-to-string max)) "\\}"))))
-
-(defun sregex--char-range (start end)
-  (let ((startc (char-to-string start))
-       (endc (char-to-string end)))
-    (cond
-     ((> end (+ start 2)) (concat startc "-" endc))
-     ((> end (+ start 1)) (concat startc (char-to-string (1+ start)) endc))
-     ((> end start) (concat startc endc))
-     (t startc))))
-
-(defun sregex--char-aux (complement args)
-  ;; regex-opt does the same, we should join effort.
-  (let ((chars (make-bool-vector 256 nil))) ; Yeah, right!
-    (dolist (arg args)
-      (cond ((integerp arg) (aset chars arg t))
-           ((stringp arg) (mapc (lambda (c) (aset chars c t)) arg))
-           ((consp arg)
-            (let ((start (car arg))
-                  (end (cdr arg)))
-              (when (> start end)
-                (let ((tmp start)) (setq start end) (setq end tmp)))
-              ;; now start <= end
-              (let ((i start))
-                (while (<= i end)
-                  (aset chars i t)
-                  (setq i (1+ i))))))))
-    ;; now chars is a map of the characters in the class
-    (let ((caret (aref chars ?^))
-         (dash (aref chars ?-))
-         (class (if (aref chars ?\]) "]" "")))
-      (aset chars ?^ nil)
-      (aset chars ?- nil)
-      (aset chars ?\] nil)
-
-      (let (start end)
-       (dotimes (i 256)
-         (if (aref chars i)
-             (progn
-               (unless start (setq start i))
-               (setq end i)
-               (aset chars i nil))
-           (when start
-             (setq class (concat class (sregex--char-range start end)))
-             (setq start nil))))
-       (if start
-           (setq class (concat class (sregex--char-range start end)))))
-
-      (if (> (length class) 0)
-         (setq class (concat class (if caret "^") (if dash "-")))
-       (setq class (concat class (if dash "-") (if caret "^"))))
-      (if (and (not complement) (= (length class) 1))
-         (regexp-quote class)
-       (concat "[" (if complement "^") class "]")))))
-
-(provide 'sregex)
-
-;;; sregex.el ends here
diff --git a/lisp/obsolete/starttls.el b/lisp/obsolete/starttls.el
index 6f0685d3dd..2f1f0e9773 100644
--- a/lisp/obsolete/starttls.el
+++ b/lisp/obsolete/starttls.el
@@ -287,9 +287,6 @@ GnuTLS requires a port number."
                            starttls-gnutls-program
                          starttls-program))))
 
-(define-obsolete-function-alias 'starttls-any-program-available
-  #'starttls-available-p "24.1")
-
 (provide 'starttls)
 
 ;;; starttls.el ends here
diff --git a/lisp/obsolete/tpu-extras.el b/lisp/obsolete/tpu-extras.el
index 76338cdd24..d631c47705 100644
--- a/lisp/obsolete/tpu-extras.el
+++ b/lisp/obsolete/tpu-extras.el
@@ -292,7 +292,7 @@ Prefix argument serves as repeat count."
           (bottom (save-excursion (move-to-window-line bottom-margin) (point)))
           (far (save-excursion
                  (goto-char bottom)
-                 (point-at-bol (1- height)))))
+                 (line-beginning-position (1- height)))))
      ,@body))
 
 (defun tpu-paragraph (num)
diff --git a/lisp/obsolete/uce.el b/lisp/obsolete/uce.el
new file mode 100644
index 0000000000..2cbbf5dc65
--- /dev/null
+++ b/lisp/obsolete/uce.el
@@ -0,0 +1,401 @@
+;;; uce.el --- facilitate reply to unsolicited commercial email  -*- 
lexical-binding: t; -*-
+
+;; Copyright (C) 1996, 1998, 2000-2022 Free Software Foundation, Inc.
+
+;; Author: stanislav shalunov <shalunov@mccme.ru>
+;; Created: 10 Dec 1996
+;; Keywords: mail, uce, unsolicited commercial email
+;; Obsolete-since: 29.1
+
+;; 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 code in this file provides a semi-automatic means of replying
+;; to unsolicited commercial email (UCE) you might get.  Currently, it
+;; only works with Rmail and Gnus.  If you would like to make it work
+;; with other mail readers, see the mail-client dependent section of
+;; uce-reply-to-uce.  Please let me know about your changes so I can
+;; incorporate them.  I'd appreciate it.
+
+;; NOTE: We don't recommend using this feature; see the message in
+;; 'uce-reply-to-uce' for the reasons.
+
+;; The command uce-reply-to-uce, if called when the current message
+;; buffer is a UCE, will setup a reply *mail* buffer as follows.  It
+;; scans the full headers of the message for: 1) the normal return
+;; address of the sender (From, Reply-To lines), and puts these
+;; addresses into the To: header, along with abuse@offenders.host; 2)
+;; the mailhub that first saw this message, and adds the address of
+;; its postmaster into the To: header; and 3), finally, it looks at
+;; the Message-Id and adds the postmaster of that host to the list of
+;; addresses.
+
+;; Then, we add an "Errors-To: nobody@localhost" header, so that if
+;; some of these addresses are not actually correct, we will never see
+;; bounced mail.  Also, mail-self-blind and mail-archive-file-name
+;; take no effect: the ideology is that we don't want to save junk or
+;; replies to junk.
+
+;; Then we insert a template into the buffer (a customizable message
+;; that explains what has happened), customizable signature, and the
+;; original message with full headers and envelope for postmasters.
+;; Then the buffer is left for editing.
+
+;; The reason that the function uce-reply-to-uce is mail-client
+;; dependent is that we want the full headers of the original message,
+;; nothing stripped.  If we use the normal means of inserting the
+;; original message into the *mail* buffer, headers like Received:
+;; (not really headers, but envelope lines) will be stripped, while
+;; they bear valuable information for us and postmasters.  I do wish
+;; that there would be some portable way to write this function, but I
+;; am not aware of any.
+
+;; Usage:
+
+;; Place uce.el in your load-path (and optionally byte-compile it).
+;; Add the following line to your init file:
+;; (autoload 'uce-reply-to-uce "uce" "Reply to UCEs" t nil)
+;; If you want to use it with Gnus rather than Rmail:
+;; (setq uce-mail-reader 'gnus)
+
+;; Options:
+
+;; uce-message-text is a template that will be inserted into buffer.
+;; It has a reasonable default.  If you want to write some scarier
+;; one, please do so and send it to me.  Please keep it polite.
+
+;; uce-signature behaves just like mail-signature.  If nil, nothing is
+;; inserted, if t, file ~/.signature is used, if a string, its
+;; contents are inserted into buffer.
+
+;; uce-uce-separator is a line that separates your message from the
+;; UCE that you enclose.
+
+;; uce-subject-line will be used as the subject of the outgoing message.
+
+
+;;; Change Log:
+
+;; Dec 10, 1996 -- posted draft version to gnu.sources.emacs
+
+;; Dec 11, 1996 -- fixed some typos, and Francesco Potortì
+;; <F.Potorti@cnuce.cnr.it> pointed out that my use of defvar was
+;; weird, suggested fix, and added let form.
+
+;; Dec 17, 1996 -- made scanning for host names little bit more clever
+;; (obviously bogus stuff like localhost is now ignored).
+
+;; Nov 11, 1997 -- incorporated changes from Mikael Djurfeldt
+;; <mdj@nada.kth.se> to make uce.el work with Gnus.  Changed the text
+;; of message that is sent.
+
+;; Dec 3, 1997 -- changes from Gareth Jones <gdj1@gdjones.demon.co.uk>
+;; handling Received headers following some line like `From:'.
+
+;; Aug 16, 2000 -- changes from Detlev Zundel
+;; <detlev.zundel@stud.uni-karlsruhe.de> to make uce.el work with the
+;; latest Gnus.  Lars told him it should work for all versions of Gnus
+;; younger than three years.
+
+
+;;; Code:
+
+(defvar gnus-original-article-buffer)
+(defvar mail-reply-buffer)
+
+(require 'sendmail)
+;; Those sections of code which are dependent upon
+;; RMAIL are only evaluated if we have received a message with RMAIL...
+;;(require 'rmail)
+
+(defgroup uce nil
+  "Facilitate reply to unsolicited commercial email."
+  :prefix "uce-"
+  :group 'mail)
+
+(defcustom uce-mail-reader 'rmail
+  "A symbol indicating which mail reader you are using.
+Choose from: `gnus', `rmail'."
+  :type '(choice (const gnus) (const rmail))
+  :version "20.3")
+
+(defcustom uce-setup-hook nil
+  "Hook to run after UCE rant message is composed.
+This hook is run after `mail-setup-hook', which is run as well."
+  :type 'hook)
+
+(defcustom uce-message-text
+  "Recently, I have received an Unsolicited Commercial E-mail from you.
+I do not like UCE's and I would like to inform you that sending
+unsolicited messages to someone while he or she may have to pay for
+reading your message may be illegal.  Anyway, it is highly annoying
+and not welcome by anyone.  It is rude, after all.
+
+If you think that this is a good way to advertise your products or
+services you are mistaken.  Spamming will only make people hate you, not
+buy from you.
+
+If you have any list of people you send unsolicited commercial emails to,
+REMOVE me from such list immediately.  I suggest that you make this list
+just empty.
+
+       ----------------------------------------------------
+
+If you are not an administrator of any site and still have received
+this message then your email address is being abused by some spammer.
+They fake your address in From: or Reply-To: header.  In this case,
+you might want to show this message to your system administrator, and
+ask him/her to investigate this matter.
+
+Note to the postmaster(s): I append the text of UCE in question to
+this message; I would like to hear from you about action(s) taken.
+This message has been sent to postmasters at the host that is
+mentioned as original sender's host (I do realize that it may be
+faked, but I think that if your domain name is being abused this way
+you might want to learn about it, and take actions) and to the
+postmaster whose host was used as mail relay for this message.  If
+message was sent not by your user, could you please compare time when
+this message was sent (use time in Received: field of the envelope
+rather than Date: field) with your sendmail logs and see what host was
+using your sendmail at this moment of time.
+
+Thank you."
+
+  "This is the text that `uce-reply-to-uce' command will put in reply buffer.
+Some of spamming programs in use will be set up to read all incoming
+to spam address email, and will remove people who put the word `remove'
+on beginning of some line from the spamming list.  So, when you set it
+up, it might be a good idea to actually use this feature.
+
+Value nil means insert no text by default, lets you type it in."
+  :type '(choice (const nil) string))
+
+(defcustom uce-uce-separator
+  "----- original unsolicited commercial email follows -----"
+  "Line that will begin quoting of the UCE.
+Value nil means use no separator."
+  :type '(choice (const nil) string))
+
+(defcustom uce-signature mail-signature
+"Text to put as your signature after the note to UCE sender.
+Value nil means none, t means insert `~/.signature' file (if it happens
+to exist), if this variable is a string this string will be inserted
+as your signature."
+  :type '(choice (const nil) (const t) string))
+
+(defcustom uce-default-headers
+  "Errors-To: nobody@localhost\nPrecedence: bulk\n"
+  "Additional headers to use when responding to a UCE with 
\\[uce-reply-to-uce].
+These are mostly meant for headers that prevent delivery errors reporting."
+  :type '(choice (const nil) string))
+
+(defcustom uce-subject-line
+  "Spam alert: unsolicited commercial e-mail"
+  "Subject of the message that will be sent in response to a UCE."
+  :type 'string)
+
+;; End of user options.
+
+
+(defvar rmail-buffer)
+(declare-function rmail-msg-is-pruned "rmail" ())
+(declare-function mail-strip-quoted-names "mail-utils" (address))
+(declare-function rmail-maybe-set-message-counters "rmail" ())
+(declare-function rmail-toggle-header "rmail" (&optional arg))
+
+(defvar uce--usage-warning-displayed nil)
+
+;;;###autoload
+(defun uce-reply-to-uce (&optional _ignored)
+  "Compose a reply to unsolicited commercial email (UCE).
+Sets up a reply buffer addressed to: the sender, his postmaster,
+his abuse@ address, and the postmaster of the mail relay used.
+You might need to set `uce-mail-reader' before using this."
+  (interactive)
+  ;; Start of mail-client dependent section.
+  (let ((message-buffer
+        (cond ((eq uce-mail-reader 'gnus) gnus-original-article-buffer)
+              ((eq uce-mail-reader 'rmail) (bound-and-true-p rmail-buffer))
+              (t (error
+                  "Variable uce-mail-reader set to unrecognized value"))))
+       pruned)
+    (or (and message-buffer (get-buffer message-buffer))
+       (error "No mail buffer, cannot find UCE"))
+    (switch-to-buffer message-buffer)
+    ;; We need the message with headers pruned.
+    ;; Why?  All we do is get the from and reply-to headers.  ?
+    (and (eq uce-mail-reader 'rmail)
+        (not (setq pruned (rmail-msg-is-pruned)))
+        (rmail-toggle-header 1))
+    (let ((to (mail-strip-quoted-names (mail-fetch-field "from" t)))
+         (reply-to (mail-fetch-field "reply-to"))
+         temp)
+      ;; Initial setting of the list of recipients of our message; that's
+      ;; what they are pretending to be.
+      (setq to (if to
+                  (format "%s" (mail-strip-quoted-names to))
+                ""))
+      (if reply-to
+         (setq to (format "%s, %s" to (mail-strip-quoted-names reply-to))))
+      (let (first-at-sign end-of-hostname sender-host)
+       (setq first-at-sign (string-search "@" to)
+             end-of-hostname (string-match "[ ,>]" to first-at-sign)
+             sender-host (substring to first-at-sign end-of-hostname))
+       (if (string-search "." sender-host)
+           (setq to (format "%s, postmaster%s, abuse%s"
+                            to sender-host sender-host))))
+      (setq mail-send-actions nil)
+      (setq mail-reply-buffer nil)
+      (when (eq uce-mail-reader 'rmail)
+       (rmail-toggle-header 0)
+       (rmail-maybe-set-message-counters)) ; why?
+      (copy-region-as-kill (point-min) (point-max))
+      ;; Restore the initial header state we found.
+      (and pruned (rmail-toggle-header 1))
+      (switch-to-buffer "*mail*")
+      (erase-buffer)
+      (yank)
+      (goto-char (point-min))
+      ;; Delete any internal Rmail headers.
+      (when (eq uce-mail-reader 'rmail)
+       (search-forward "\n\n")
+       (while (re-search-backward "^X-RMAIL" nil t)
+         (delete-region (point) (line-beginning-position 2)))
+       (goto-char (point-min)))
+      ;; Now find the mail hub that first accepted this message.
+      ;; This should try to find the last Received: header.
+      ;; Sometimes there may be other headers in between Received: headers.
+      (cond ((eq uce-mail-reader 'gnus)
+            ;; Does Gnus always have Lines: in the end?
+            (re-search-forward "^Lines:")
+            (beginning-of-line))
+           ((eq uce-mail-reader 'rmail)
+            (search-forward "\n\n")))
+      (re-search-backward "^Received:")
+      ;; Is this always good?  It's the only thing I saw when I checked
+      ;; a few messages.
+      ;;(if (not (re-search-forward ": \\(from\\|by\\) " eol t))
+      (unless (re-search-forward "\\(from\\|by\\) " (line-end-position) 'move)
+       (if (looking-at "[ \t\n]+\\(from\\|by\\) ")
+           (goto-char (match-end 0))
+         (error "Failed to extract hub address")))
+      (setq temp (point))
+      (search-forward " ")
+      (forward-char -1)
+      ;; And add its postmaster to the list of addresses.
+      (if (string-search "." (buffer-substring temp (point)))
+         (setq to (format "%s, postmaster@%s"
+                          to (buffer-substring temp (point)))))
+      ;; Also look at the message-id, it helps *very* often.
+      (and (search-forward "\nMessage-Id: " nil t)
+          ;; Not all Message-Id:'s have an `@' sign.
+          (search-forward "@" (line-end-position) t)
+          (progn
+            (setq temp (point))
+            (search-forward ">")
+            (forward-char -1)
+            (if (string-search "." (buffer-substring temp (point)))
+                (setq to (format "%s, postmaster@%s"
+                                 to (buffer-substring temp (point)))))))
+      (when (eq uce-mail-reader 'gnus)
+       ;; Does Gnus always have Lines: in the end?
+       (re-search-forward "^Lines:")
+       (beginning-of-line)
+       (setq temp (point))
+       (search-forward "\n\n" nil t)
+       (forward-line -1)
+       (delete-region temp (point)))
+      ;; End of mail-client dependent section.
+      (auto-save-mode auto-save-default)
+      (mail-mode)
+      (goto-char (point-min))
+      (insert "To: ")
+      (save-excursion
+       (if to
+           (let ((fill-prefix "\t")
+                 (address-start (point)))
+             (insert to "\n")
+             (fill-region-as-paragraph address-start (point)))
+         (newline))
+       (insert "Subject: " uce-subject-line "\n")
+       (if uce-default-headers
+           (insert uce-default-headers))
+       (if mail-default-headers
+           (insert mail-default-headers))
+       (if mail-default-reply-to
+           (insert "Reply-To: " mail-default-reply-to "\n"))
+       (insert mail-header-separator "\n")
+       ;; Insert all our text.  Then go back to the place where we started.
+       (if to (setq to (point)))
+       ;; Text of ranting.
+       (if uce-message-text
+           (insert uce-message-text))
+       ;; Signature.
+       (cond ((eq uce-signature t)
+              (if (file-exists-p "~/.signature")
+                  (progn
+                    (insert "\n\n-- \n")
+                    (forward-char (cadr (insert-file-contents 
"~/.signature"))))))
+             (uce-signature
+              (insert "\n\n-- \n" uce-signature)))
+       ;; And text of the original message.
+       (if uce-uce-separator
+           (insert "\n\n" uce-uce-separator "\n"))
+       ;; If message doesn't end with a newline, insert it.
+       (goto-char (point-max))
+       (or (bolp) (newline)))
+      ;; And go back to the beginning of text.
+      (if to (goto-char to))
+      (or to (set-buffer-modified-p nil))
+      ;; Run hooks before we leave buffer for editing.  Reasonable usage
+      ;; might be to set up special key bindings, replace standard
+      ;; functions in mail-mode, etc.
+      (run-hooks 'mail-setup-hook 'uce-setup-hook)))
+  (unless uce--usage-warning-displayed
+    (setq uce--usage-warning-displayed t)
+    (pop-to-buffer (get-buffer-create "uce-reply-to-uce warning"))
+    (insert "\
+-- !!! NOTE !!! ---------------------------------------------
+
+Replying to spam is at best pointless, but most likely actively
+harmful.
+
+- You will confirm that your email address is valid, thus ensuring
+  you get more spam.
+
+- You will leak information and open yourself up for further
+  attack.  For example, they could use your \"geolocation\" to find
+  your home address and phone number.
+
+- The sender address is likely fake.
+
+- You help them refine their methods of spamming.
+
+Therefore, we strongly recommend that you do not use this package.
+Use a spam filter instead, or just delete the spam.
+
+-------------------------------------------------------------
+")))
+
+(defun uce-insert-ranting (&optional _ignored)
+  "Insert text of the usual reply to UCE into current buffer."
+  (interactive "P")
+  (insert uce-message-text))
+
+(provide 'uce)
+
+;;; uce.el ends here
diff --git a/lisp/obsolete/url-about.el b/lisp/obsolete/url-about.el
new file mode 100644
index 0000000000..608df3f2a5
--- /dev/null
+++ b/lisp/obsolete/url-about.el
@@ -0,0 +1,104 @@
+;;; url-about.el --- Show internal URLs  -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2001-2022 Free Software Foundation, Inc.
+
+;; Keywords: comm, data, processes, hypermedia
+;; Obsolete-since: 29.1
+
+;; 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 'url-util)
+(require 'url-parse)
+
+(defun url-probe-protocols ()
+  "Return a list of all potential URL schemes."
+  (or (get 'url-extension-protocols 'probed)
+      (mapc (lambda (s) (url-scheme-get-property s 'name))
+           (or (get 'url-extension-protocols 'schemes)
+               (let ((schemes '("info" "man" "rlogin" "telnet"
+                                "tn3270" "data" "snews")))
+                 (mapc (lambda (d)
+                         (mapc (lambda (f)
+                                 (if (string-match "url-\\(.*\\).el$" f)
+                                     (push (match-string 1 f) schemes)))
+                               (directory-files d nil "\\`url-.*\\.el\\'")))
+                        (seq-filter #'file-exists-p load-path))
+                 (put 'url-extension-protocols 'schemes schemes)
+                 schemes)))))
+
+(defvar url-scheme-registry)
+
+(defun url-about-protocols (_url)
+  (url-probe-protocols)
+  (insert "<html>\n"
+         " <head>\n"
+         "  <title>Supported Protocols</title>\n"
+         " </head>\n"
+         " <body>\n"
+          "  <h1>Supported Protocols - URL package in Emacs " emacs-version 
"</h1>\n"
+         "  <table width='100%' border='1'>\n"
+         "   <tr>\n"
+         "    <td>Protocol\n"
+         "    <td>Properties\n"
+         "    <td>Description\n"
+         "   </tr>\n")
+  (mapc (lambda (k)
+         (if (string= k "proxy")
+             ;; Ignore the proxy setting... its magic!
+             nil
+           (insert "   <tr>\n")
+           ;; The name of the protocol
+           (insert "    <td valign=top>" (or (url-scheme-get-property k 'name) 
k) "\n")
+
+           ;; Now the properties.  Currently just asynchronous
+           ;; status, default port number, and proxy status.
+           (insert "    <td valign=top>"
+                   (if (url-scheme-get-property k 'asynchronous-p) "As" "S")
+                   "ynchronous<br>\n"
+                   (if (url-scheme-get-property k 'default-port)
+                       (format "Default Port: %d<br>\n"
+                               (url-scheme-get-property k 'default-port))
+                     "")
+                   (if (assoc k url-proxy-services)
+                       (format "Proxy: %s<br>\n" (assoc k url-proxy-services)) 
""))
+           ;; Now the description...
+           (insert "    <td valign=top>"
+                   (or (url-scheme-get-property k 'description) "N/A"))))
+       (sort (let (x) (maphash (lambda (k _v) (push k x)) url-scheme-registry) 
x)
+             #'string-lessp))
+  (insert "  </table>\n"
+         " </body>\n"
+         "</html>\n"))
+
+(defun url-about (url)
+  "Show internal URLs."
+  (let* ((item (downcase (url-filename url)))
+        (func (intern (format "url-about-%s" item))))
+    (if (fboundp func)
+       (progn
+         (set-buffer (generate-new-buffer " *about-data*"))
+         (insert "Content-type: text/plain\n\n")
+         (funcall func url)
+         (current-buffer))
+      (error "URL does not know about `%s'" item))))
+
+(provide 'url-about)
+
+;;; url-about.el ends here
diff --git a/lisp/obsolete/url-dired.el b/lisp/obsolete/url-dired.el
new file mode 100644
index 0000000000..40057fb174
--- /dev/null
+++ b/lisp/obsolete/url-dired.el
@@ -0,0 +1,58 @@
+;;; url-dired.el --- URL Dired minor mode  -*- lexical-binding: t -*-
+
+;; Copyright (C) 1996-1999, 2004-2022 Free Software Foundation, Inc.
+
+;; Keywords: comm, files
+;; Obsolete-since: 29.1
+
+;; 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:
+
+(autoload 'dired-get-filename "dired")
+
+(defvar-keymap url-dired-minor-mode-map
+  :doc "Keymap used when browsing directories."
+  "RET"       #'url-dired-find-file
+  "<mouse-2>" #'url-dired-find-file-mouse)
+
+(defun url-dired-find-file ()
+  "In dired, visit the file or directory named on this line."
+  (interactive)
+  (let ((filename (dired-get-filename)))
+    (find-file filename)))
+
+(defun url-dired-find-file-mouse (event)
+  "In dired, visit the file or directory name you click on."
+  (interactive "@e")
+  (mouse-set-point event)
+  (url-dired-find-file))
+
+(define-minor-mode url-dired-minor-mode
+  "Minor mode for directory browsing."
+  :lighter " URL" :keymap url-dired-minor-mode-map)
+
+(defun url-find-file-dired (dir)
+  "\"Edit\" directory DIR, but with additional URL-friendly bindings."
+  (interactive "DURL Dired (directory): ")
+  (find-file dir)
+  (url-dired-minor-mode t))
+
+(provide 'url-dired)
+
+;;; url-dired.el ends here
diff --git a/lisp/org/ChangeLog.1 b/lisp/org/ChangeLog.1
index 7e08d1a3c9..836e1430df 100644
--- a/lisp/org/ChangeLog.1
+++ b/lisp/org/ChangeLog.1
@@ -4001,7 +4001,7 @@
        buffer.
        (org-agenda-ignore-drawer-properties): New option.
        (org-agenda-prepare-buffers):
-       Honour `org-agenda-ignore-drawer-properties'.
+       Honor `org-agenda-ignore-drawer-properties'.
 
        * org-clock.el (org-clock-goto): Recenter to thrd line
 
@@ -4134,7 +4134,7 @@
        (orgstruct-heading-prefix-regexp, orgstruct-setup-hook):
        New options.
        (orgstruct-initialized): New variable.
-       (org-get-local-variables): Honour state property.
+       (org-get-local-variables): Honor state property.
        (org-run-like-in-org-mode): Use `let' instead of `progv'.  Do not
        override variables with non-default values.
        (org-forward-heading-same-level): Do not skip to headlines on
diff --git a/lisp/org/ob-comint.el b/lisp/org/ob-comint.el
index 427aba3415..c99d6a8ba7 100644
--- a/lisp/org/ob-comint.el
+++ b/lisp/org/ob-comint.el
@@ -166,7 +166,7 @@ source block, and the name of the temp file.")
 (defvar-local org-babel-comint-async-chunk-callback nil
   "Callback function to clean Babel async output results before insertion.
 Its single argument is a string consisting of output from the
-comint process.  It should return a string that will be be passed
+comint process.  It should return a string that will be passed
 to `org-babel-insert-result'.")
 
 (defvar-local org-babel-comint-async-dangling nil
diff --git a/lisp/org/ob-core.el b/lisp/org/ob-core.el
index 04af84d2e4..41b7a2a971 100644
--- a/lisp/org/ob-core.el
+++ b/lisp/org/ob-core.el
@@ -136,8 +136,7 @@ used."
   :type 'string
   :safe (lambda (v)
          (and (stringp v)
-              (eq (compare-strings "RESULTS" nil nil v nil nil t)
-                  t))))
+              (string-equal-ignore-case "RESULTS" v))))
 
 (defcustom org-babel-noweb-wrap-start "<<"
   "String used to begin a noweb reference in a code block.
@@ -489,13 +488,13 @@ arguments, imagine you'd like to set the file name output 
of a
 latex source block to a sha1 of its contents.  We could achieve
 this with:
 
-(defun org-src-sha ()
-  (let ((elem (org-element-at-point)))
-    (concat (sha1 (org-element-property :value elem)) \".svg\")))
+  (defun org-src-sha ()
+    (let ((elem (org-element-at-point)))
+      (concat (sha1 (org-element-property :value elem)) \".svg\")))
 
-(setq org-babel-default-header-args:latex
-      `((:results . \"file link replace\")
-        (:file . (lambda () (org-src-sha)))))
+  (setq org-babel-default-header-args:latex
+        `((:results . \"file link replace\")
+          (:file . (lambda () (org-src-sha)))))
 
 Because the closure is evaluated with point at the source block,
 the call to `org-element-at-point' above will always retrieve
@@ -918,7 +917,7 @@ arguments and pop open the results in a preview buffer."
                       vals ""))))))
     (save-excursion
       (goto-char begin)
-      (goto-char (point-at-eol))
+      (goto-char (line-end-position))
       (unless (= (char-before (point)) ?\ ) (insert " "))
       (insert ":" header-arg) (when value (insert " " value)))))
 
@@ -1937,9 +1936,9 @@ region is not active then the point is demarcated."
              (let ((lang (nth 0 info))
                    (indent (make-string (current-indentation) ?\s)))
               (when (string-match "^[[:space:]]*$"
-                                  (buffer-substring (point-at-bol)
-                                                    (point-at-eol)))
-                (delete-region (point-at-bol) (point-at-eol)))
+                                   (buffer-substring (line-beginning-position)
+                                                     (line-end-position)))
+                 (delete-region (line-beginning-position) (line-end-position)))
                (insert (concat
                        (if (looking-at "^") "" "\n")
                        indent (if upper-case-p "#+END_SRC\n" "#+end_src\n")
@@ -2435,7 +2434,7 @@ INFO may provide the values of these header arguments (in 
the
                       ;; Escape contents from "export" wrap.  Wrap
                       ;; inline results within an export snippet with
                       ;; appropriate value.
-                      ((eq t (compare-strings type nil nil "export" nil nil t))
+                      ((string-equal-ignore-case type "export")
                        (let ((backend (pcase split
                                         (`(,_) "none")
                                         (`(,_ ,b . ,_) b))))
@@ -2446,14 +2445,14 @@ INFO may provide the values of these header arguments 
(in the
                                           backend) "@@)}}}")))
                       ;; Escape contents from "example" wrap.  Mark
                       ;; inline results as verbatim.
-                      ((eq t (compare-strings type nil nil "example" nil nil 
t))
+                      ((string-equal-ignore-case type "example")
                        (funcall wrap
                                 opening-line closing-line
                                 nil nil
                                 "{{{results(=" "=)}}}"))
                       ;; Escape contents from "src" wrap.  Mark
                       ;; inline results as inline source code.
-                      ((eq t (compare-strings type nil nil "src" nil nil t))
+                      ((string-equal-ignore-case type "src")
                        (let ((inline-open
                               (pcase split
                                 (`(,_)
diff --git a/lisp/org/ob-julia.el b/lisp/org/ob-julia.el
index 50a44bcf44..de69f25fc3 100644
--- a/lisp/org/ob-julia.el
+++ b/lisp/org/ob-julia.el
@@ -26,6 +26,9 @@
 ;; Org-Babel support for evaluating julia code
 ;;
 ;; Based on ob-R.el by Eric Schulte and Dan Davison.
+;;
+;; Session support requires the installation of the DataFrames and CSV
+;; Julia packages.
 
 ;;; Code:
 (require 'cl-lib)
@@ -62,6 +65,7 @@
 (defvar ess-current-process-name) ; dynamically scoped
 (defvar ess-local-process-name)   ; dynamically scoped
 (defvar ess-eval-visibly-p)       ; dynamically scoped
+(defvar ess-local-customize-alist); dynamically scoped
 (defun org-babel-edit-prep:julia (info)
   (let ((session (cdr (assq :session (nth 2 info)))))
     (when (and session
@@ -281,7 +285,8 @@ last statement in BODY, as elisp."
     (value
      (with-temp-buffer
        (insert (org-babel-chomp body))
-       (let ((ess-local-process-name
+       (let ((ess-local-customize-alist t)
+             (ess-local-process-name
              (process-name (get-buffer-process session)))
             (ess-eval-visibly-p nil))
         (ess-eval-buffer nil)))
diff --git a/lisp/org/ob-lilypond.el b/lisp/org/ob-lilypond.el
index 15538b5037..f1ea803ba3 100644
--- a/lisp/org/ob-lilypond.el
+++ b/lisp/org/ob-lilypond.el
@@ -36,6 +36,7 @@
 
 (declare-function org-show-all "org" (&optional types))
 
+;; FIXME: Doesn't this rather belong in lilypond-mode.el?
 (defalias 'lilypond-mode 'LilyPond-mode)
 
 (add-to-list 'org-babel-tangle-lang-exts '("LilyPond" . "ly"))
@@ -311,7 +312,7 @@ LINENO is the number of the erroneous line."
        (progn
          (goto-char (point-min))
          (forward-line (- lineNo 1))
-         (buffer-substring (point) (point-at-eol)))
+          (buffer-substring (point) (line-end-position)))
       nil)))
 
 (defun org-babel-lilypond-attempt-to-open-pdf (file-name &optional test)
diff --git a/lisp/org/ob-octave.el b/lisp/org/ob-octave.el
index bbbda5bb1e..9be8f5ad3e 100644
--- a/lisp/org/ob-octave.el
+++ b/lisp/org/ob-octave.el
@@ -255,7 +255,7 @@ This removes initial blank and comment lines and then calls
       (insert-file-contents file-name)
       (re-search-forward "^[ \t]*[^# \t]" nil t)
       (when (< (setq beg (point-min))
-              (setq end (point-at-bol)))
+               (setq end (line-beginning-position)))
        (delete-region beg end)))
     (org-babel-import-elisp-from-file temp-file '(16))))
 
diff --git a/lisp/org/ob-tangle.el b/lisp/org/ob-tangle.el
index 566258eba4..525d27bc07 100644
--- a/lisp/org/ob-tangle.el
+++ b/lisp/org/ob-tangle.el
@@ -581,7 +581,10 @@ which enable the original code blocks to be found."
          (error "Not in tangled code"))
         (setq body (buffer-substring body-start end)))
       ;; Go to the beginning of the relative block in Org file.
-      (org-link-open-from-string link)
+      ;; Explicitly allow fuzzy search even if user customized
+      ;; otherwise.
+      (let (org-link-search-must-match-exact-headline)
+        (org-link-open-from-string link))
       (setq target-buffer (current-buffer))
       (if (string-match "[^ \t\n\r]:\\([[:digit:]]+\\)" block-name)
           (let ((n (string-to-number (match-string 1 block-name))))
diff --git a/lisp/org/oc-basic.el b/lisp/org/oc-basic.el
index 775690f176..398d2e2d3f 100644
--- a/lisp/org/oc-basic.el
+++ b/lisp/org/oc-basic.el
@@ -73,6 +73,7 @@
 (require 'seq)
 
 (declare-function org-open-at-point "org" (&optional arg))
+(declare-function org-open-file "org" (path &optional in-emacs line search))
 
 (declare-function org-element-interpret-data "org-element" (data))
 (declare-function org-element-property "org-element" (property element))
@@ -189,7 +190,14 @@ Return a hash table with citation references as keys and 
fields alist as values.
                                 (cons 'year
                                       (cond
                                        ((consp date)
-                                        (caar date))
+                                         (let ((year (caar date)))
+                                           (cond
+                                             ((numberp year) (number-to-string 
year))
+                                             ((stringp year) year)
+                                             (t
+                                               (error
+                                                 "First element of CSL-JSON 
date-parts should be a number or string, got %s: %S"
+                                                 (type-of year) year)))))
                                        ((stringp date)
                                         (replace-regexp-in-string
                                           (rx
@@ -452,12 +460,13 @@ substitutes for the unknown key.  Finally, it may be the 
symbol
         (_
          (lambda ()
            (interactive)
-           (setf (buffer-substring beg end)
-                 (concat "@"
-                         (if (= 1 (length suggestions))
-                             (car suggestions)
-                           (completing-read "Did you mean: "
-                                            suggestions nil t))))))))
+           (goto-char beg)
+           (delete-region beg end)
+           (insert "@"
+                   (if (= 1 (length suggestions))
+                       (car suggestions)
+                     (completing-read "Did you mean: "
+                                      suggestions nil t)))))))
     (put-text-property beg end 'keymap km)))
 
 (defun org-cite-basic-activate (citation)
diff --git a/lisp/org/oc.el b/lisp/org/oc.el
index eb5f519cb6..c4cd0268c7 100644
--- a/lisp/org/oc.el
+++ b/lisp/org/oc.el
@@ -808,6 +808,8 @@ INFO is the export communication channel, as a property 
list."
   (or (plist-get info :citations)
       (letrec ((cites nil)
                (tree (plist-get info :parse-tree))
+               (definition-cache (make-hash-table :test #'equal))
+               (definition-list nil)
                (find-definition
                 ;; Find definition for standard reference LABEL.  At
                 ;; this point, it is impossible to rely on
@@ -816,11 +818,21 @@ INFO is the export communication channel, as a property 
list."
                 ;; un-processed citation objects.  So we use
                 ;; a simplified version of the function above.
                 (lambda (label)
-                  (org-element-map tree 'footnote-definition
-                    (lambda (d)
-                      (and (equal label (org-element-property :label d))
-                           (or (org-element-contents d) "")))
-                    info t)))
+                  (or (gethash label definition-cache)
+                      (org-element-map
+                          (or definition-list
+                              (setq definition-list
+                                    (org-element-map
+                                        tree
+                                        'footnote-definition
+                                      #'identity info)))
+                          'footnote-definition
+                        (lambda (d)
+                          (and (equal label (org-element-property :label d))
+                               (puthash label
+                                        (or (org-element-contents d) "")
+                                        definition-cache)))
+                        info t))))
                (search-cites
                 (lambda (data)
                   (org-element-map data '(citation footnote-reference)
@@ -834,7 +846,8 @@ INFO is the export communication channel, as a property 
list."
                         (_
                          (let ((label (org-element-property :label datum)))
                            (funcall search-cites
-                                    (funcall find-definition label))))))
+                                    (funcall find-definition label)))))
+                      nil)
                     info nil 'footnote-definition t))))
         (funcall search-cites tree)
         (let ((result (nreverse cites)))
diff --git a/lisp/org/ol-doi.el b/lisp/org/ol-doi.el
index 94585e4c3e..56239f65d4 100644
--- a/lisp/org/ol-doi.el
+++ b/lisp/org/ol-doi.el
@@ -44,7 +44,7 @@ PATH is a the path to search for, as a string."
   "Export a \"doi\" type link.
 PATH is the DOI name.  DESC is the description of the link, or
 nil.  BACKEND is a symbol representing the backend used for
-export.  INFO is a a plist containing the export parameters."
+export.  INFO is a plist containing the export parameters."
   (let ((uri (concat org-link-doi-server-url path)))
     (pcase backend
       (`html
diff --git a/lisp/org/ol-irc.el b/lisp/org/ol-irc.el
index ed8bad5a50..e36c44ff70 100644
--- a/lisp/org/ol-irc.el
+++ b/lisp/org/ol-irc.el
@@ -135,13 +135,13 @@ result is a cons of the filename and search string."
      ;; can we get a '::' part?
      (if (string= erc-line (erc-prompt))
         (progn
-          (goto-char (point-at-bol))
+           (goto-char (line-beginning-position))
           (when (search-backward-regexp "^[^   ]" nil t)
-            (buffer-substring-no-properties (point-at-bol)
-                                            (point-at-eol))))
+             (buffer-substring-no-properties (line-beginning-position)
+                                             (line-end-position))))
        (when (search-backward erc-line nil t)
-        (buffer-substring-no-properties (point-at-bol)
-                                        (point-at-eol)))))))
+         (buffer-substring-no-properties (line-beginning-position)
+                                         (line-end-position)))))))
 
 (defun org-irc-erc-store-link ()
   "Store a link to the IRC log file or the session itself.
@@ -151,7 +151,7 @@ the session itself."
   (require 'erc-log)
   (if org-irc-link-to-logs
       (let* ((erc-line (buffer-substring-no-properties
-                       (point-at-bol) (point-at-eol)))
+                        (line-beginning-position) (line-end-position)))
             (parsed-line (org-irc-erc-get-line-from-log erc-line)))
        (if (erc-logging-enabled nil)
            (progn
diff --git a/lisp/org/ol.el b/lisp/org/ol.el
index a03d85f618..4ad1f6d345 100644
--- a/lisp/org/ol.el
+++ b/lisp/org/ol.el
@@ -646,7 +646,7 @@ followed by another \"%[A-F0-9]{2}\" group."
                  (cons 6 128))))
          (when (>= val 192) (setq eat (car shift-xor)))
          (setq val (logxor val (cdr shift-xor)))
-         (setq sum (+ (lsh sum (car shift-xor)) val))
+         (setq sum (+ (ash sum (car shift-xor)) val))
          (when (> eat 0) (setq eat (- eat 1)))
          (cond
           ((= 0 eat)                   ;multi byte
@@ -937,7 +937,7 @@ characters that should be escaped."
 
 (defun org-link-decode (s)
   "Decode percent-encoded parts in string S.
-E.g. \"%C3%B6\" becomes the german o-Umlaut."
+E.g. \"%C3%B6\" becomes the German o-Umlaut."
   (replace-regexp-in-string "\\(%[0-9A-Za-z]\\{2\\}\\)+"
                            #'org-link--decode-compound s t t))
 
@@ -1481,7 +1481,7 @@ non-nil."
        (let ((end (region-end)))
          (goto-char (region-beginning))
          (set-mark (point))
-         (while (< (point-at-eol) end)
+          (while (< (line-end-position) end)
            (move-end-of-line 1) (activate-mark)
            (let (current-prefix-arg)
              (call-interactively 'org-store-link))
@@ -1580,14 +1580,6 @@ non-nil."
                              nil nil nil))))
          (org-link-store-props :type "calendar" :date cd)))
 
-       ((eq major-mode 'w3-mode)
-       (setq cpltxt (if (and (buffer-name)
-                             (not (string-match "Untitled" (buffer-name))))
-                        (buffer-name)
-                      (url-view-url t))
-             link (url-view-url t))
-       (org-link-store-props :type "w3" :url (url-view-url t)))
-
        ((eq major-mode 'image-mode)
        (setq cpltxt (concat "file:"
                             (abbreviate-file-name buffer-file-name))
diff --git a/lisp/org/org-agenda.el b/lisp/org/org-agenda.el
index a43b083d53..35f19cf03b 100644
--- a/lisp/org/org-agenda.el
+++ b/lisp/org/org-agenda.el
@@ -2113,7 +2113,7 @@ in that string.  If STRING is nil, it will be fetched 
from the beginning
 of the current line."
   (declare (debug t))
   (org-with-gensyms (marker)
-    `(let ((,marker (get-text-property (if ,string 0 (point-at-bol))
+    `(let ((,marker (get-text-property (if ,string 0 (line-beginning-position))
                                       'org-hd-marker ,string)))
        (with-current-buffer (marker-buffer ,marker)
         (save-excursion
@@ -3076,10 +3076,10 @@ s   Search for keywords                 M   Like m, but 
only TODO entries
          (when (eq rmheader t)
            (org-goto-line 1)
            (re-search-forward ":" nil t)
-           (delete-region (match-end 0) (point-at-eol))
+            (delete-region (match-end 0) (line-end-position))
            (forward-char 1)
            (looking-at "-+")
-           (delete-region (match-end 0) (point-at-eol))
+            (delete-region (match-end 0) (line-end-position))
            (move-marker header-end (match-end 0)))
          (goto-char header-end)
          (delete-region (point) (point-max))
@@ -3505,10 +3505,10 @@ This ensures the export commands can easily use it."
   "Mark the line at POS as an agenda structure header."
   (save-excursion
     (goto-char pos)
-    (put-text-property (point-at-bol) (point-at-eol)
+    (put-text-property (line-beginning-position) (line-end-position)
                       'org-agenda-structural-header t)
     (when org-agenda-title-append
-      (put-text-property (point-at-bol) (point-at-eol)
+      (put-text-property (line-beginning-position) (line-end-position)
                         'org-agenda-title-append org-agenda-title-append))))
 
 (defvar org-mobile-creating-agendas) ; defined in org-mobile.el
@@ -3715,7 +3715,7 @@ removed from the entry content.  Currently only 
`planning' is allowed here."
             (while (not (eobp))
               (unless (looking-at "[ \t]*$")
                 (move-to-column ind)
-                (delete-region (point-at-bol) (point)))
+                 (delete-region (line-beginning-position) (point)))
               (beginning-of-line 2))
 
             (run-hooks 'org-agenda-entry-text-cleanup-hook)
@@ -3987,7 +3987,7 @@ agenda display, configure `org-agenda-finalize-hook'."
              (goto-char (point-min))
              (while (equal (forward-line) 0)
                (when (setq mrk (get-text-property (point) 'org-hd-marker))
-                 (put-text-property (point-at-bol) (point-at-eol)
+                  (put-text-property (line-beginning-position) 
(line-end-position)
                                     'tags
                                     (org-with-point-at mrk
                                       (org-get-tags))))))))
@@ -4035,7 +4035,8 @@ agenda display, configure `org-agenda-finalize-hook'."
              (goto-char s)
              (when (equal (org-get-at-bol 'org-hd-marker)
                           org-clock-hd-marker)
-               (setq ov (make-overlay (point-at-bol) (1+ (point-at-eol))))
+                (setq ov (make-overlay (line-beginning-position)
+                                       (1+ (line-end-position))))
                (overlay-put ov 'type 'org-agenda-clocking)
                (overlay-put ov 'face 'org-agenda-clocking)
                (overlay-put ov 'help-echo
@@ -4066,7 +4067,7 @@ agenda display, configure `org-agenda-finalize-hook'."
              b (match-beginning 1)
              e (if (eq org-agenda-fontify-priorities 'cookies)
                    (1+ (match-end 2))
-                 (point-at-eol))
+                  (line-end-position))
              ov (make-overlay b e))
        (overlay-put
         ov 'face
@@ -4168,7 +4169,7 @@ A good way to set it is through options in 
`org-agenda-custom-commands'.")
   "Throw to `:skip' in places that should be skipped.
 Also moves point to the end of the skipped region, so that search can
 continue from there."
-  (let ((p (point-at-bol)) to)
+  (let ((p (line-beginning-position)) to)
     (when (or
           (save-excursion (goto-char p) (looking-at comment-start-skip))
           (and org-agenda-skip-archived-trees (not org-agenda-archives-mode)
@@ -4244,7 +4245,7 @@ This check for agenda markers in all agenda buffers 
currently active."
                             m org-agenda-entry-text-maxlines
                             org-agenda-entry-text-leaders))))
     (when (string-match "\\S-" txt)
-      (setq o (make-overlay (point-at-bol) (point-at-eol)))
+      (setq o (make-overlay (line-beginning-position) (line-end-position)))
       (overlay-put o 'evaporate t)
       (overlay-put o 'org-overlay-type 'agenda-entry-content)
       (overlay-put o 'after-string txt))))
@@ -4749,7 +4750,7 @@ is active."
                                  (forward-line -1)
                                  (org-back-to-heading t)))
                      (skip-chars-forward "* ")
-                     (setq beg (point-at-bol)
+                      (setq beg (line-beginning-position)
                            beg1 (point)
                            end (progn
                                  (outline-next-heading)
@@ -4764,8 +4765,8 @@ is active."
                        (goto-char beg)
                        (org-agenda-skip)
                        (setq str (buffer-substring-no-properties
-                                  (point-at-bol)
-                                  (if hdl-only (point-at-eol) end)))
+                                   (line-beginning-position)
+                                   (if hdl-only (line-end-position) end)))
                        (mapc (lambda (wr) (when (string-match wr str)
                                             (goto-char (1- end))
                                             (throw :skip t)))
@@ -4793,7 +4794,7 @@ is active."
                              txt (org-agenda-format-item
                                   ""
                                   (buffer-substring-no-properties
-                                   beg1 (point-at-eol))
+                                    beg1 (line-end-position))
                                   level category tags t))
                        (org-add-props txt props
                          'org-marker marker 'org-hd-marker marker
@@ -5335,7 +5336,7 @@ each date.  It also removes lines that contain only 
whitespace."
                           (abbreviate-file-name buffer-file-name))
                 "")
     'org-agenda-diary-link t
-    'org-marker (org-agenda-new-marker (point-at-bol))))
+    'org-marker (org-agenda-new-marker (line-beginning-position))))
 
 (defun org-diary-default-entry ()
   "Add a dummy entry to the diary.
@@ -5986,7 +5987,7 @@ then those holidays will be skipped."
              clockp (not (or closedp statep))
              state (and statep (match-string 2))
              category (org-get-category (match-beginning 0))
-             timestr (buffer-substring (match-beginning 0) (point-at-eol)))
+              timestr (buffer-substring (match-beginning 0) 
(line-end-position)))
        (when (string-match "\\]" timestr)
          ;; substring should only run to end of time stamp
          (setq rest (substring timestr (match-end 0))
@@ -6044,7 +6045,7 @@ then those holidays will be skipped."
            'type type 'date date
            'undone-face 'org-warning 'done-face 'org-agenda-done)
          (push txt ee))
-       (goto-char (point-at-eol))))
+        (goto-char (line-end-position))))
     (nreverse ee)))
 
 (defun org-agenda-show-clocking-issues ()
@@ -6081,7 +6082,7 @@ See also the user option 
`org-agenda-clock-consistency-checks'."
          (setq issue "No valid clock line") (throw 'next t))
        (org-with-point-at m
          (save-excursion
-           (goto-char (point-at-bol))
+            (goto-char (line-beginning-position))
            (unless (looking-at re)
              (error "No valid Clock line")
              (throw 'next t))
@@ -6127,7 +6128,7 @@ See also the user option 
`org-agenda-clock-consistency-checks'."
       (setq tlend (or te tlend) tlstart (or ts tlstart))
       (when issue
        ;; OK, there was some issue, add an overlay to show the issue
-       (setq ov (make-overlay (point-at-bol) (point-at-eol)))
+        (setq ov (make-overlay (line-beginning-position) (line-end-position)))
        (overlay-put ov 'before-string
                     (concat
                      (org-add-props
@@ -7147,7 +7148,10 @@ The optional argument TYPE tells the agenda type."
        (save-excursion
          (beginning-of-line 1)
          (setq re (org-get-at-bol 'org-todo-regexp))
-         (goto-char (or (text-property-any (point-at-bol) (point-at-eol) 
'org-heading t) (point)))
+          (goto-char (or (text-property-any (line-beginning-position)
+                                            (line-end-position)
+                                            'org-heading t)
+                         (point)))
          (when (looking-at (concat "[ \t]*\\.*\\(" re "\\) +"))
            (add-text-properties (match-beginning 0) (match-end 1)
                                 (list 'face (org-get-todo-face 1)))
@@ -7428,7 +7432,7 @@ subtree."
                        (point)
                        (if org-agenda-restriction-lock-highlight-subtree
                            (save-excursion (org-end-of-subtree t t) (point))
-                         (point-at-eol)))
+                          (line-end-position)))
          (move-marker org-agenda-restrict-begin (point))
          (move-marker org-agenda-restrict-end
                       (save-excursion (org-end-of-subtree t t)))
@@ -8254,8 +8258,8 @@ grouptags."
 (defun org-agenda-filter-hide-line (type)
   "If current line is TYPE, hide it in the agenda buffer."
   (let* (buffer-invisibility-spec
-        (beg (max (point-min) (1- (point-at-bol))))
-        (end (point-at-eol)))
+         (beg (max (point-min) (1- (line-beginning-position))))
+         (end (line-end-position)))
     (let ((inhibit-read-only t))
       (add-text-properties
        beg end `(invisible org-filtered org-filter-type ,type)))))
@@ -8887,7 +8891,7 @@ When called with a prefix argument, include all archive 
files as well."
   (interactive "p")
   (let ((col (current-column)))
     (dotimes (_ n)
-      (when (next-single-property-change (point-at-eol) 'org-marker)
+      (when (next-single-property-change (line-end-position) 'org-marker)
        (move-end-of-line 1)
        (goto-char (next-single-property-change (point) 'org-marker))))
     (org-move-to-column col))
@@ -8945,7 +8949,8 @@ When called with a prefix argument, include all archive 
files as well."
        (when (re-search-forward org-complex-heading-regexp nil t)
          (goto-char (match-beginning 4)))))
     (run-hooks 'org-agenda-after-show-hook)
-    (and highlight (org-highlight (point-at-bol) (point-at-eol)))))
+    (and highlight (org-highlight (line-beginning-position)
+                                  (line-end-position)))))
 
 (defvar org-agenda-after-show-hook nil
   "Normal hook run after an item has been shown from the agenda.
@@ -8968,7 +8973,7 @@ deletes the agenda entry and don't move to the next 
entry."
          (level (and (eq org-agenda-loop-over-headlines-in-active-region 
'start-level)
                      (org-get-at-bol 'level))))
       (while (< (point) mend)
-       (let ((ov (make-overlay (point) (point-at-eol))))
+        (let ((ov (make-overlay (point) (line-end-position))))
          (if (not (or all
                       (and match (looking-at-p match))
                       (eq level (org-get-at-bol 'level))))
@@ -9013,8 +9018,8 @@ Pass ARG, FORCE-ARG, DELETE and BODY to 
`org-agenda-do-in-region'."
           (if (and (derived-mode-p 'org-mode) (not (member type '("sexp"))))
               (setq dbeg (progn (org-back-to-heading t) (point))
                     dend (org-end-of-subtree t t))
-            (setq dbeg (point-at-bol)
-                  dend (min (point-max) (1+ (point-at-eol)))))
+             (setq dbeg (line-beginning-position)
+                   dend (min (point-max) (1+ (line-end-position)))))
           (goto-char dbeg)
           (while (re-search-forward "^[ \t]*\\S-" dend t) (setq n (1+ n)))))
        (when (or (eq t org-agenda-confirm-kill)
@@ -9113,7 +9118,8 @@ If this information is not given, the function uses the 
tree at point."
                     (>= p beg)
                     (< p end))
            (let ((inhibit-read-only t))
-             (delete-region (point-at-bol) (1+ (point-at-eol)))))
+              (delete-region (line-beginning-position)
+                             (1+ (line-end-position)))))
          (beginning-of-line 0))))))
 
 (defun org-agenda-refile (&optional goto rfloc no-update)
@@ -9162,7 +9168,8 @@ It also looks at the text of the entry itself."
   (let* ((marker (or (org-get-at-bol 'org-hd-marker)
                     (org-get-at-bol 'org-marker)))
         (buffer (and marker (marker-buffer marker)))
-        (prefix (buffer-substring (point-at-bol) (point-at-eol)))
+         (prefix (buffer-substring (line-beginning-position)
+                                   (line-end-position)))
         (lkall (and buffer (org-offer-links-in-entry
                             buffer marker arg prefix)))
         (lk0 (car lkall))
@@ -9295,7 +9302,7 @@ if it was hidden in the outline."
   (let ((win (selected-window)))
     (org-agenda-goto t)
     (org-back-to-heading)
-    (set-window-start (selected-window) (point-at-bol))
+    (set-window-start (selected-window) (line-beginning-position))
     (cond
      ((= more 0)
       (org-flag-subtree t)
@@ -9532,7 +9539,8 @@ If FORCE-TAGS is non-nil, the car of it returns the new 
tags."
                  (with-current-buffer (marker-buffer hdmarker)
                    (org-with-wide-buffer
                     (org-agenda-format-item extra newhead level cat tags 
dotime))))
-               ;; pl (text-property-any (point-at-bol) (point-at-eol) 
'org-heading t)
+                ;; pl (text-property-any (line-beginning-position)
+                ;;                       (line-end-position) 'org-heading t)
                undone-face (org-get-at-bol 'undone-face)
                done-face (org-get-at-bol 'done-face))
          (beginning-of-line 1)
@@ -9549,10 +9557,11 @@ If FORCE-TAGS is non-nil, the car of it returns the new 
tags."
              (replace-match new t t)
              (beginning-of-line)
              (when mark (move-overlay mark (point) (+ 2 (point)))))
-           (add-text-properties (point-at-bol) (point-at-eol) props)
+            (add-text-properties (line-beginning-position)
+                                 (line-end-position) props)
            (when fixface
              (add-text-properties
-              (point-at-bol) (point-at-eol)
+               (line-beginning-position) (line-end-position)
               (list 'face
                     (if org-last-todo-state-is-todo
                         undone-face done-face))))
@@ -9560,7 +9569,7 @@ If FORCE-TAGS is non-nil, the car of it returns the new 
tags."
            (beginning-of-line 1))
           (t (error "Line update did not work")))
          (save-restriction
-           (narrow-to-region (point-at-bol) (point-at-eol))
+            (narrow-to-region (line-beginning-position) (line-end-position))
            (org-agenda-finalize)))
        (beginning-of-line 0)))))
 
@@ -9791,7 +9800,8 @@ When called programmatically, FORCE-DIRECTION can be 
`set', `up',
            (setq arg (- today cdate))))
        (org-timestamp-change arg (or what 'day))
        (when (and (org-at-date-range-p)
-                  (re-search-backward org-tr-regexp-both (point-at-bol)))
+                   (re-search-backward org-tr-regexp-both
+                                       (line-beginning-position)))
          (let ((end org-last-changed-timestamp))
            (org-timestamp-change arg (or what 'day))
            (setq org-last-changed-timestamp
@@ -9846,7 +9856,7 @@ When called programmatically, FORCE-DIRECTION can be 
`set', `up',
               (length stamp))
            t)
           (add-text-properties
-          (1- (point)) (point-at-eol)
+           (1- (point)) (line-end-position)
           (list 'display (org-add-props stamp nil
                            'face '(secondary-selection default))))
          (beginning-of-line 1))
@@ -9990,13 +10000,13 @@ buffer, display it in another window."
     (if (equal (buffer-name) "*Calendar*")
        (setq d1 (calendar-cursor-to-date t)
              d2 (car calendar-mark-ring))
-      (setq dp1 (get-text-property (point-at-bol) 'day))
+      (setq dp1 (get-text-property (line-beginning-position) 'day))
       (unless dp1 (user-error "No date defined in current line"))
       (setq d1 (calendar-gregorian-from-absolute dp1)
            d2 (and (ignore-errors (mark))
                    (save-excursion
                      (goto-char (mark))
-                     (setq dp2 (get-text-property (point-at-bol) 'day)))
+                      (setq dp2 (get-text-property (line-beginning-position) 
'day)))
                    (calendar-gregorian-from-absolute dp2))))
     (message "Diary entry: [d]ay [a]nniversary [b]lock [j]ump to date tree")
     (setq char (read-char-exclusive))
@@ -10319,7 +10329,7 @@ This is a command that has to be installed in 
`calendar-mode-map'."
 
 (defun org-agenda-bulk-marked-p ()
   "Non-nil when current entry is marked for bulk action."
-  (eq (get-char-property (point-at-bol) 'type)
+  (eq (get-char-property (line-beginning-position) 'type)
       'org-marked-entry-overlay))
 
 (defun org-agenda-bulk-mark (&optional arg)
@@ -10344,7 +10354,8 @@ When ARG is greater than one mark ARG lines."
        (unless (org-agenda-bulk-marked-p)
          (unless m (user-error "Nothing to mark at point"))
          (push m org-agenda-bulk-marked-entries)
-         (setq ov (make-overlay (point-at-bol) (+ 2 (point-at-bol))))
+          (setq ov (make-overlay (line-beginning-position)
+                                 (+ 2 (line-beginning-position))))
          (org-overlay-display ov (concat org-agenda-bulk-mark-char " ")
                               (org-get-todo-face "TODO")
                               'evaporate)
@@ -10388,7 +10399,7 @@ When ARG is greater than one mark ARG lines."
       (org-agenda-bulk-unmark-all)
     (cond ((org-agenda-bulk-marked-p)
           (org-agenda-bulk-remove-overlays
-           (point-at-bol) (+ 2 (point-at-bol)))
+            (line-beginning-position) (+ 2 (line-beginning-position)))
           (setq org-agenda-bulk-marked-entries
                 (delete (org-get-at-bol 'org-hd-marker)
                         org-agenda-bulk-marked-entries))
@@ -10768,8 +10779,8 @@ tag and note")))))
     (message "Entry unflagged")))
 
 (defun org-agenda-get-any-marker (&optional pos)
-  (or (get-text-property (or pos (point-at-bol)) 'org-hd-marker)
-      (get-text-property (or pos (point-at-bol)) 'org-marker)))
+  (or (get-text-property (or pos (line-beginning-position)) 'org-hd-marker)
+      (get-text-property (or pos (line-beginning-position)) 'org-marker)))
 
 ;;; Appointment reminders
 
diff --git a/lisp/org/org-capture.el b/lisp/org/org-capture.el
index 2fd9a9c74d..abf4f9610e 100644
--- a/lisp/org/org-capture.el
+++ b/lisp/org/org-capture.el
@@ -1447,7 +1447,7 @@ Of course, if exact position has been required, just put 
it there."
                (if (org-at-table-p)
                    (save-excursion
                      (org-table-goto-line (nth 1 where))
-                     (point-at-bol))
+                      (line-beginning-position))
                  (point))))))
     (with-current-buffer (buffer-base-buffer (current-buffer))
       (org-with-point-at pos
diff --git a/lisp/org/org-clock.el b/lisp/org/org-clock.el
index fdc9818a5a..38e0826075 100644
--- a/lisp/org/org-clock.el
+++ b/lisp/org/org-clock.el
@@ -1317,7 +1317,7 @@ the default behavior."
       ;; Clock in at which position?
       (setq target-pos
            (if (and (eobp) (not (org-at-heading-p)))
-               (point-at-bol 0)
+                (line-beginning-position 0)
              (point)))
       (save-excursion
        (when (and selected-task (marker-buffer selected-task))
@@ -1666,7 +1666,7 @@ to, overriding the existing value of 
`org-clock-out-switch-to-state'."
              (setq ts (match-string 2))
            (if fail-quietly (throw 'exit nil) (error "Clock start time is 
gone")))
          (goto-char (match-end 0))
-         (delete-region (point) (point-at-eol))
+          (delete-region (point) (line-end-position))
          (insert "--")
          (setq te (org-insert-time-stamp (or at-time now) 'with-hm 'inactive))
          (setq s (org-time-convert-to-integer
@@ -1804,7 +1804,7 @@ Optional argument N tells to change by that many units."
     (goto-char org-clock-marker)
     (if (looking-back (concat "^[ \t]*" org-clock-string ".*")
                      (line-beginning-position))
-       (progn (delete-region (1- (point-at-bol)) (point-at-eol))
+        (progn (delete-region (1- (line-beginning-position)) 
(line-end-position))
               (org-remove-empty-drawer-at (point)))
       (message "Clock gone, cancel the timer anyway")
       (sit-for 2)))
@@ -1946,7 +1946,7 @@ PROPNAME lets you set a custom text property instead of 
:org-clock-minutes."
                               (aset ltimes l (+ (aref ltimes l) t1))))
                  (setq time (aref ltimes level))
                  (goto-char (match-beginning 0))
-                 (put-text-property (point) (point-at-eol)
+                  (put-text-property (point) (line-end-position)
                                     (or propname :org-clock-minutes) time)
                  (when headline-filter
                    (save-excursion
@@ -2114,7 +2114,7 @@ fontified, and then returned."
     (forward-line 2)
     (buffer-substring (point) (progn
                                (re-search-forward "^[ \t]*#\\+END" nil t)
-                               (point-at-bol)))))
+                                (line-beginning-position)))))
 
 ;;;###autoload
 (defun org-clock-report (&optional arg)
@@ -2390,7 +2390,7 @@ the currently selected interval size."
   (setq n (prefix-numeric-value n))
   (and (memq dir '(left down)) (setq n (- n)))
   (save-excursion
-    (goto-char (point-at-bol))
+    (goto-char (line-beginning-position))
     (if (not (looking-at "^[ \t]*#\\+BEGIN:[ \t]+clocktable\\>.*?:block[ 
\t]+\\(\\S-+\\)"))
        (user-error "Line needs a :block definition before this command works")
       (let* ((b (match-beginning 1)) (e (match-end 1))
@@ -3030,7 +3030,7 @@ Otherwise, return nil."
         ((not (match-end 2))
          (when (and (equal (marker-buffer org-clock-marker) (current-buffer))
                     (> org-clock-marker (point))
-                    (<= org-clock-marker (point-at-eol)))
+                     (<= org-clock-marker (line-end-position)))
            ;; The clock is running here
            (setq org-clock-start-time
                  (org-time-string-to-time (match-string 1)))
diff --git a/lisp/org/org-compat.el b/lisp/org/org-compat.el
index 3e394fbab1..15f0daa91a 100644
--- a/lisp/org/org-compat.el
+++ b/lisp/org/org-compat.el
@@ -113,6 +113,11 @@ the symbol of the calling function, for example."
 
 ;;; Emacs < 27.1 compatibility
 
+(if (version< emacs-version "27.1")
+    (defsubst org-replace-buffer-contents (source &optional _max-secs 
_max-costs)
+      (replace-buffer-contents source))
+  (defalias 'org-replace-buffer-contents #'replace-buffer-contents))
+
 (unless (fboundp 'proper-list-p)
   ;; `proper-list-p' was added in Emacs 27.1.  The function below is
   ;; taken from Emacs subr.el 200195e824b^.
@@ -929,6 +934,14 @@ Implements `define-error' for older emacsen."
     (put name 'error-conditions
          (copy-sequence (cons name (get 'error 'error-conditions))))))
 
+(unless (fboundp 'string-equal-ignore-case)
+  ;; From Emacs subr.el.
+  (defun string-equal-ignore-case (string1 string2)
+    "Like `string-equal', but case-insensitive.
+Upper-case and lower-case letters are treated as equal.
+Unibyte strings are converted to multibyte for comparison."
+    (eq t (compare-strings string1 0 nil string2 0 nil t))))
+
 (unless (fboundp 'string-suffix-p)
   ;; From Emacs subr.el.
   (defun string-suffix-p (suffix string  &optional ignore-case)
@@ -1015,7 +1028,7 @@ To get rid of the restriction, use 
`\\[org-agenda-remove-restriction-lock]'."
   (require 'org-agenda)
   (let (p m tp np dir txt)
     (cond
-     ((setq p (text-property-any (point-at-bol) (point-at-eol)
+     ((setq p (text-property-any (line-beginning-position) (line-end-position)
                                 'org-imenu t))
       (setq m (get-text-property p 'org-imenu-marker))
       (with-current-buffer (marker-buffer m)
@@ -1025,7 +1038,7 @@ To get rid of the restriction, use 
`\\[org-agenda-remove-restriction-lock]'."
                         (overlays-at (point))))
            (org-agenda-remove-restriction-lock 'noupdate)
          (org-agenda-set-restriction-lock 'subtree))))
-     ((setq p (text-property-any (point-at-bol) (point-at-eol)
+     ((setq p (text-property-any (line-beginning-position) (line-end-position)
                                 'speedbar-function 'speedbar-find-file))
       (setq tp (previous-single-property-change
                (1+ p) 'speedbar-function)
@@ -1042,7 +1055,7 @@ To get rid of the restriction, use 
`\\[org-agenda-remove-restriction-lock]'."
        (org-agenda-set-restriction-lock 'file)))
      (t (user-error "Don't know how to restrict Org mode agenda")))
     (move-overlay org-speedbar-restriction-lock-overlay
-                 (point-at-bol) (point-at-eol))
+                  (line-beginning-position) (line-end-position))
     (setq current-prefix-arg nil)
     (org-agenda-maybe-redo)))
 
@@ -1120,10 +1133,8 @@ ELEMENT is the element at point."
          (and log
               (let ((drawer (org-element-lineage element '(drawer))))
                 (and drawer
-                     (eq (compare-strings
-                          log nil nil
-                          (org-element-property :drawer-name drawer) nil nil t)
-                         t)))))
+                     (string-equal-ignore-case
+                      log (org-element-property :drawer-name drawer))))))
        nil)
        (t
        (cl-case (org-element-type element)
diff --git a/lisp/org/org-element.el b/lisp/org/org-element.el
index 9db1406b3f..4c018062af 100644
--- a/lisp/org/org-element.el
+++ b/lisp/org/org-element.el
@@ -2205,7 +2205,7 @@ CDR is a plist containing `:key', `:value', `:begin', 
`:end',
          (key (progn (looking-at "[ \t]*#\\+\\(\\S-*\\):")
                      (upcase (match-string-no-properties 1))))
          (value (org-trim (buffer-substring-no-properties
-                           (match-end 0) (point-at-eol))))
+                            (match-end 0) (line-end-position))))
          (pos-before-blank (progn (forward-line) (point)))
          (end (progn (skip-chars-forward " \r\t\n" limit)
                      (if (eobp) (point) (line-beginning-position)))))
@@ -4273,7 +4273,7 @@ This function assumes that current major mode is 
`org-mode'."
     (goto-char (point-min))
     (org-skip-whitespace)
     (org-element--parse-elements
-     (point-at-bol) (point-max)
+     (line-beginning-position) (point-max)
      ;; Start in `first-section' mode so text before the first
      ;; headline belongs to a section.
      'first-section nil granularity visible-only (list 'org-data nil))))
@@ -4391,6 +4391,7 @@ looking into captions:
                       ;; every element it encounters.
                       (and (not (eq category 'elements))
                            (setq category 'elements))))))))
+         (--ignore-list (plist-get info :ignore-list))
         --acc)
     (letrec ((--walk-tree
              (lambda (--data)
@@ -4400,7 +4401,7 @@ looking into captions:
                  (cond
                   ((not --data))
                   ;; Ignored element in an export context.
-                  ((and info (memq --data (plist-get info :ignore-list))))
+                  ((and info (memq --data --ignore-list)))
                   ;; List of elements or objects.
                   ((not --type) (mapc --walk-tree --data))
                   ;; Unconditionally enter parse trees.
@@ -6206,12 +6207,12 @@ end of ELEM-A."
           (end-A (save-excursion
                    (goto-char (org-element-property :end elem-A))
                    (skip-chars-backward " \r\t\n")
-                   (point-at-eol)))
+                    (line-end-position)))
           (beg-B (org-element-property :begin elem-B))
           (end-B (save-excursion
                    (goto-char (org-element-property :end elem-B))
                    (skip-chars-backward " \r\t\n")
-                   (point-at-eol)))
+                    (line-end-position)))
           ;; Store inner overlays responsible for visibility status.
           ;; We also need to store their boundaries as they will be
           ;; removed from buffer.
diff --git a/lisp/org/org-feed.el b/lisp/org/org-feed.el
index a5fea08882..c7b4bde0d2 100644
--- a/lisp/org/org-feed.el
+++ b/lisp/org/org-feed.el
@@ -406,7 +406,7 @@ it can be a list structured like an entry in 
`org-feed-alist'."
 
          ;; Write the new status
          ;; We do this only now, in case something goes wrong above, so
-         ;; that would would end up with a status that does not reflect
+          ;; that would end up with a status that does not reflect
          ;; which items truly have been handled
          (org-feed-write-status inbox-pos drawer status)
 
diff --git a/lisp/org/org-habit.el b/lisp/org/org-habit.el
index bc5175b163..3bf4307f4a 100644
--- a/lisp/org/org-habit.el
+++ b/lisp/org/org-habit.el
@@ -426,7 +426,7 @@ current time."
        (moment (org-time-subtract nil
                                   (* 3600 org-extend-today-until))))
     (save-excursion
-      (goto-char (if line (point-at-bol) (point-min)))
+      (goto-char (if line (line-beginning-position) (point-min)))
       (while (not (eobp))
        (let ((habit (get-text-property (point) 'org-habit-p))
               (invisible-prop (get-text-property (point) 'invisible)))
diff --git a/lisp/org/org-inlinetask.el b/lisp/org/org-inlinetask.el
index 581370bb53..2cbbf7f7ac 100644
--- a/lisp/org/org-inlinetask.el
+++ b/lisp/org/org-inlinetask.el
@@ -238,7 +238,7 @@ going below `org-inlinetask-min-level'."
          (setq beg (point))
          (replace-match down-task nil t nil 1)
          (org-inlinetask-goto-end)
-         (if (and (eobp) (looking-back "END\\s-*" (point-at-bol)))
+          (if (and (eobp) (looking-back "END\\s-*" (line-beginning-position)))
               (beginning-of-line)
             (forward-line -1))
          (unless (= (point) beg)
@@ -264,7 +264,7 @@ If the task has an end part, also demote it."
        (setq beg (point))
        (replace-match down-task nil t nil 1)
        (org-inlinetask-goto-end)
-        (if (and (eobp) (looking-back "END\\s-*" (point-at-bol)))
+        (if (and (eobp) (looking-back "END\\s-*" (line-beginning-position)))
             (beginning-of-line)
           (forward-line -1))
        (unless (= (point) beg)
@@ -312,7 +312,7 @@ If the task has an end part, also demote it."
               (if (bolp) (1- (point)) (point))))
        (start (save-excursion
                 (org-inlinetask-goto-beginning)
-                (point-at-eol))))
+                 (line-end-position))))
     (cond
      ;; Nothing to show/hide.
      ((= end start))
diff --git a/lisp/org/org-lint.el b/lisp/org/org-lint.el
index 83c2d08a90..6d8cf3f237 100644
--- a/lisp/org/org-lint.el
+++ b/lisp/org/org-lint.el
@@ -334,10 +334,8 @@ called with one argument, the key used for comparison."
    ast
    'node-property
    (lambda (property)
-     (and (eq (compare-strings "CUSTOM_ID" nil nil
-                              (org-element-property :key property) nil nil
-                              t)
-             t)
+     (and (string-equal-ignore-case
+           "CUSTOM_ID" (org-element-property :key property))
          (org-element-property :value property)))
    (lambda (property _) (org-element-property :begin property))
    (lambda (key) (format "Duplicate CUSTOM_ID property \"%s\"" key))))
diff --git a/lisp/org/org-list.el b/lisp/org/org-list.el
index da309f8c6d..978e36ed61 100644
--- a/lisp/org/org-list.el
+++ b/lisp/org/org-list.el
@@ -517,7 +517,7 @@ Contexts `block' and `invalid' refer to 
`org-list-forbidden-blocks'."
                   (and (not (looking-at beg-re))
                        (not (looking-at end-re))
                        (setq beg (and (re-search-backward beg-re lim-up t)
-                                      (1+ (point-at-eol))))
+                                       (1+ (line-end-position))))
                        (setq end (or (and (re-search-forward end-re lim-down t)
                                           (1- (match-beginning 0)))
                                      lim-down))
@@ -528,12 +528,12 @@ Contexts `block' and `invalid' refer to 
`org-list-forbidden-blocks'."
           (when (save-excursion
                   (and (not (looking-at block-re))
                        (setq beg (and (re-search-backward block-re lim-up t)
-                                      (1+ (point-at-eol))))
+                                       (1+ (line-end-position))))
                        (looking-at "^[ \t]*#\\+begin_\\(\\S-+\\)")
                        (setq type (downcase (match-string 1)))
                        (goto-char beg)
                        (setq end (or (and (re-search-forward block-re lim-down 
t)
-                                          (1- (point-at-bol)))
+                                           (1- (line-beginning-position)))
                                      lim-down))
                        (>= end pos)
                        (equal (downcase (match-string 1)) "end")))
@@ -547,7 +547,7 @@ Contexts `block' and `invalid' refer to 
`org-list-forbidden-blocks'."
                             (end-re (concat beg-re "END[ \t]*$")))
                        (and (not (looking-at "^\\*+"))
                             (setq beg (and (re-search-backward beg-re lim-up t)
-                                           (1+ (point-at-eol))))
+                                            (1+ (line-end-position))))
                             (not (looking-at end-re))
                             (setq end (and (re-search-forward end-re lim-down 
t)
                                            (1- (match-beginning 0))))
@@ -569,7 +569,7 @@ values are:
 6. position at item end.
 
 Thus the following list, where numbers in parens are
-point-at-bol:
+line-beginning-position:
 
 - [X] first item                             (1)
   1. sub-item 1                              (18)
@@ -617,7 +617,7 @@ Assume point is at an item."
            ;; Ensure list ends at the first blank line.
            (lambda ()
              (skip-chars-backward " \r\t\n")
-             (min (1+ (point-at-eol)) lim-down))))
+              (min (1+ (line-end-position)) lim-down))))
       ;; 1. Read list from starting item to its beginning, and save
       ;;    top item position and indentation in BEG-CELL.  Also store
       ;;    ending position of items in END-LST.
@@ -872,7 +872,7 @@ Point returned is at end of line."
   (save-excursion
     (goto-char (org-list-get-item-end item struct))
     (skip-chars-backward " \r\t\n")
-    (point-at-eol)))
+    (line-end-position)))
 
 (defun org-list-get-parent (item struct parents)
   "Return parent of ITEM or nil.
@@ -1182,7 +1182,7 @@ some heuristics to guess the result."
           (lambda ()
             ;; Count blank lines above beginning of line.
             (save-excursion
-              (count-lines (goto-char (point-at-bol))
+               (count-lines (goto-char (line-beginning-position))
                            (progn (skip-chars-backward " \r\t\n")
                                   (forward-line)
                                   (point)))))))
@@ -1287,7 +1287,7 @@ This function modifies STRUCT."
                 ;; must be removed, or they will be left, stacking up
                 ;; after the list.
                 (when (< item-end pos)
-                  (delete-region (1- item-end) (point-at-eol)))
+                   (delete-region (1- item-end) (line-end-position)))
                 (skip-chars-backward " \r\t\n")
                 ;; Cut position is after any blank on the line.
                 (save-excursion
@@ -1364,7 +1364,7 @@ STRUCT is the list structure."
                  (save-excursion
                    (goto-char item)
                    (skip-chars-backward " \r\t\n")
-                   (min (1+ (point-at-eol)) (point-max)))
+                    (min (1+ (line-end-position)) (point-max)))
                item)))
     ;; Remove item from buffer.
     (delete-region beg end)
@@ -1441,7 +1441,7 @@ This function returns, destructively, the new list 
structure."
                      (setq dest (org-list-get-list-end item struct prevs))
                      (save-excursion
                        (goto-char (org-list-get-last-item item struct prevs))
-                       (point-at-eol)))
+                        (line-end-position)))
                     ((and (stringp dest) (string-match-p "\\`[0-9]+\\'" dest))
                      (let* ((all (org-list-get-all-items item struct prevs))
                             (len (length all))
@@ -1453,7 +1453,7 @@ This function returns, destructively, the new list 
structure."
                          (save-excursion
                            (goto-char
                             (org-list-get-last-item item struct prevs))
-                           (point-at-eol)))))
+                            (line-end-position)))))
                     (t dest)))
         (org-M-RET-may-split-line nil)
         ;; Store inner overlays (to preserve visibility).
@@ -1880,7 +1880,7 @@ Initial position of cursor is restored after the changes."
                    (insert (concat new-box (unless counterp " "))))))
              ;; c.  Indent item to appropriate column.
              (unless (= new-ind old-ind)
-               (delete-region (goto-char (point-at-bol))
+                (delete-region (goto-char (line-beginning-position))
                               (progn (skip-chars-forward " \t") (point)))
                (indent-to new-ind))))))
     ;; 1. First get list of items and position endings.  We maintain
@@ -2010,7 +2010,7 @@ Sublists of the list are skipped.  Cursor is always at the
 beginning of the item."
   (let* ((struct (org-list-struct))
         (prevs (org-list-prevs-alist struct))
-        (item (copy-marker (point-at-bol)))
+         (item (copy-marker (line-beginning-position)))
         (all (org-list-get-all-items (marker-position item) struct prevs))
         (value init-value))
     (dolist (e (nreverse all))
@@ -2147,10 +2147,10 @@ the item, so this really moves item trees."
   (interactive)
   (unless (org-at-item-p) (error "Not at an item"))
   (let* ((col (current-column))
-        (item (point-at-bol))
+         (item (line-beginning-position))
         (struct (org-list-struct))
         (prevs (org-list-prevs-alist struct))
-        (next-item (org-list-get-next-item (point-at-bol) struct prevs)))
+         (next-item (org-list-get-next-item (line-beginning-position) struct 
prevs)))
     (unless (or next-item org-list-use-circular-motion)
       (user-error "Cannot move this item further down"))
     (if (not next-item)
@@ -2168,10 +2168,10 @@ the item, so this really moves item trees."
   (interactive)
   (unless (org-at-item-p) (error "Not at an item"))
   (let* ((col (current-column))
-        (item (point-at-bol))
+         (item (line-beginning-position))
         (struct (org-list-struct))
         (prevs (org-list-prevs-alist struct))
-        (prev-item (org-list-get-prev-item (point-at-bol) struct prevs)))
+         (prev-item (org-list-get-prev-item (line-beginning-position) struct 
prevs)))
     (unless (or prev-item org-list-use-circular-motion)
       (user-error "Cannot move this item further up"))
     (if (not prev-item)
@@ -2312,7 +2312,7 @@ is an integer, 0 means `-', 1 means `+' etc.  If WHICH is
           (old-struct (copy-tree struct))
           (cbox (org-list-get-checkbox cpos struct))
            (prevs (org-list-prevs-alist struct))
-          (start (org-list-get-list-begin (point-at-bol) struct prevs))
+           (start (org-list-get-list-begin (line-beginning-position) struct 
prevs))
           (new (unless (and cbox (equal arg '(4)) (equal start cpos))
                  "[ ]")))
       (dolist (pos (org-list-get-all-items
@@ -2372,7 +2372,7 @@ subtree, ignoring planning line and any drawer following 
it."
                (let ((limit (region-end)))
                  (goto-char (region-beginning))
                  (if (org-list-search-forward (org-item-beginning-re) limit t)
-                     (setq lim-up (point-at-bol))
+                      (setq lim-up (line-beginning-position))
                    (error "No item in region"))
                  (setq lim-down (copy-marker limit))))
               ((org-at-heading-p)
@@ -2381,14 +2381,14 @@ subtree, ignoring planning line and any drawer 
following it."
                (let ((limit (save-excursion (outline-next-heading) (point))))
                  (org-end-of-meta-data t)
                  (if (org-list-search-forward (org-item-beginning-re) limit t)
-                     (setq lim-up (point-at-bol))
+                      (setq lim-up (line-beginning-position))
                    (error "No item in subtree"))
                  (setq lim-down (copy-marker limit))))
               ;; Just one item: set SINGLEP flag.
               ((org-at-item-p)
                (setq singlep t)
-               (setq lim-up (point-at-bol)
-                     lim-down (copy-marker (point-at-eol))))
+                (setq lim-up (line-beginning-position)
+                      lim-down (copy-marker (line-end-position))))
               (t (error "Not at an item or heading, and no active region"))))
             ;; Determine the checkbox going to be applied to all items
             ;; within bounds.
@@ -2636,7 +2636,7 @@ Return t if successful."
           ;; Are we going to move the whole list?
           (specialp
            (and (not regionp)
-                (= top (point-at-bol))
+                 (= top (line-beginning-position))
                 (cdr (assq 'indent org-list-automatic-rules))
                 (if no-subtree
                     (user-error
@@ -2650,12 +2650,12 @@ Return t if successful."
            (progn
              (set-marker org-last-indent-begin-marker rbeg)
              (set-marker org-last-indent-end-marker rend))
-         (set-marker org-last-indent-begin-marker (point-at-bol))
+          (set-marker org-last-indent-begin-marker (line-beginning-position))
          (set-marker org-last-indent-end-marker
                      (cond
                       (specialp (org-list-get-bottom-point struct))
-                      (no-subtree (1+ (point-at-bol)))
-                      (t (org-list-get-item-end (point-at-bol) struct))))))
+                       (no-subtree (1+ (line-beginning-position)))
+                       (t (org-list-get-item-end (line-beginning-position) 
struct))))))
       (let* ((beg (marker-position org-last-indent-begin-marker))
             (end (marker-position org-last-indent-end-marker)))
        (cond
@@ -2893,8 +2893,8 @@ function is being called interactively."
   (let* ((case-func (if with-case 'identity 'downcase))
          (struct (org-list-struct))
          (prevs (org-list-prevs-alist struct))
-        (start (org-list-get-list-begin (point-at-bol) struct prevs))
-        (end (org-list-get-list-end (point-at-bol) struct prevs))
+         (start (org-list-get-list-begin (line-beginning-position) struct 
prevs))
+         (end (org-list-get-list-end (line-beginning-position) struct prevs))
         (sorting-type
          (or sorting-type
              (progn
@@ -2939,21 +2939,21 @@ function is being called interactively."
                   ((= dcst ?n)
                    (string-to-number
                     (org-sort-remove-invisible
-                     (buffer-substring (match-end 0) (point-at-eol)))))
+                      (buffer-substring (match-end 0) (line-end-position)))))
                   ((= dcst ?a)
                    (funcall case-func
                             (org-sort-remove-invisible
                              (buffer-substring
-                              (match-end 0) (point-at-eol)))))
+                               (match-end 0) (line-end-position)))))
                   ((= dcst ?t)
                    (cond
                     ;; If it is a timer list, convert timer to seconds
                     ((org-at-item-timer-p)
                      (org-timer-hms-to-secs (match-string 1)))
                     ((or (save-excursion
-                           (re-search-forward org-ts-regexp (point-at-eol) t))
+                            (re-search-forward org-ts-regexp 
(line-end-position) t))
                          (save-excursion (re-search-forward org-ts-regexp-both
-                                                            (point-at-eol) t)))
+                                                             
(line-end-position) t)))
                      (org-time-string-to-seconds (match-string 0)))
                     (t (float-time now))))
                   ((= dcst ?x) (or (and (stringp (match-string 1))
@@ -3026,14 +3026,14 @@ With a prefix argument ARG, change the region in a 
single item."
           (save-excursion
             (goto-char pos)
             (skip-chars-forward " \r\t\n")
-            (point-at-bol))))
+             (line-beginning-position))))
        beg end)
     ;; Determine boundaries of changes.
     (if (org-region-active-p)
        (setq beg (funcall skip-blanks (region-beginning))
              end (copy-marker (region-end)))
-      (setq beg (point-at-bol)
-           end (copy-marker (point-at-eol))))
+      (setq beg (line-beginning-position)
+            end (copy-marker (line-end-position))))
     ;; Depending on the starting line, choose an action on the text
     ;; between BEG and END.
     (org-with-limited-levels
diff --git a/lisp/org/org-macs.el b/lisp/org/org-macs.el
index bb0562dde0..cf0eb48f2d 100644
--- a/lisp/org/org-macs.el
+++ b/lisp/org/org-macs.el
@@ -1124,11 +1124,11 @@ the value in cadr."
 
 (defsubst org-get-at-bol (property)
   "Get text property PROPERTY at the beginning of line."
-  (get-text-property (point-at-bol) property))
+  (get-text-property (line-beginning-position) property))
 
 (defun org-get-at-eol (property n)
   "Get text property PROPERTY at the end of line less N characters."
-  (get-text-property (- (point-at-eol) n) property))
+  (get-text-property (- (line-end-position) n) property))
 
 (defun org-find-text-property-in-string (prop s)
   "Return the first non-nil value of property PROP in string S."
diff --git a/lisp/org/org-mobile.el b/lisp/org/org-mobile.el
index 5cfaa7fe0a..6f0a60125c 100644
--- a/lisp/org/org-mobile.el
+++ b/lisp/org/org-mobile.el
@@ -617,7 +617,7 @@ The table of checksums is written to the file 
mobile-checksums."
         ((looking-at "[ \t]*$")) ; keep empty lines
         ((looking-at "=+$")
          ;; remove underlining
-         (delete-region (point) (point-at-eol)))
+          (delete-region (point) (line-end-position)))
         ((get-text-property (point) 'org-agenda-structural-header)
          (setq in-date nil)
          (setq app (get-text-property (point) 'org-agenda-title-append))
@@ -637,14 +637,14 @@ The table of checksums is written to the file 
mobile-checksums."
                      (get-text-property (point) 'org-marker)))
          (setq sexp (member (get-text-property (point) 'type)
                             '("diary" "sexp")))
-         (if (setq pl (text-property-any (point) (point-at-eol) 'org-heading 
t))
+          (if (setq pl (text-property-any (point) (line-end-position) 
'org-heading t))
              (progn
                (setq prefix (org-trim (buffer-substring
                                        (point) pl))
                      line (org-trim (buffer-substring
                                      pl
-                                     (point-at-eol))))
-               (delete-region (point-at-bol) (point-at-eol))
+                                      (line-end-position))))
+                (delete-region (line-beginning-position) (line-end-position))
                (insert line "<before>" prefix "</before>")
                (beginning-of-line 1))
            (and (looking-at "[ \t]+") (replace-match "")))
@@ -857,7 +857,7 @@ If BEG and END are given, only do this in that region."
            (org-mobile-timestamp-buffer (marker-buffer id-pos))
            (push (marker-buffer id-pos) buf-list))
          (unless (markerp id-pos)
-           (goto-char (+ 2 (point-at-bol)))
+            (goto-char (+ 2 (line-beginning-position)))
            (if (stringp id-pos)
                (insert id-pos " ")
              (insert "BAD REFERENCE "))
@@ -1093,7 +1093,7 @@ be returned that indicates what went wrong."
       (org-archive-to-archive-sibling))
 
      ((eq what 'body)
-      (setq current (buffer-substring (min (1+ (point-at-eol)) (point-max))
+      (setq current (buffer-substring (min (1+ (line-end-position)) 
(point-max))
                                      (save-excursion (outline-next-heading)
                                                      (point))))
       (if (not (string-match "\\S-" current)) (setq current nil))
diff --git a/lisp/org/org-mouse.el b/lisp/org/org-mouse.el
index a590ff87f2..aa4c20050f 100644
--- a/lisp/org/org-mouse.el
+++ b/lisp/org/org-mouse.el
@@ -184,7 +184,7 @@ Changing this variable requires a restart of Emacs to get 
activated."
 (defun org-mouse-re-search-line (regexp)
   "Search the current line for a given regular expression."
   (beginning-of-line)
-  (re-search-forward regexp (point-at-eol) t))
+  (re-search-forward regexp (line-end-position) t))
 
 (defun org-mouse-end-headline ()
   "Go to the end of current headline (ignoring tags)."
@@ -574,7 +574,7 @@ This means, between the beginning of line and the point."
      (insert "+ "))
     (:end                              ; insert text here
      (skip-chars-backward " \t")
-     (kill-region (point) (point-at-eol))
+     (kill-region (point) (line-end-position))
      (unless (looking-back org-mouse-punctuation (line-beginning-position))
        (insert (concat org-mouse-punctuation " ")))))
   (insert text)
@@ -985,7 +985,7 @@ This means, between the beginning of line and the point."
 (defun org-mouse-do-remotely (command)
   ;;  (org-agenda-check-no-diary)
   (when (get-text-property (point) 'org-marker)
-    (let* ((anticol (- (point-at-eol) (point)))
+    (let* ((anticol (- (line-end-position) (point)))
           (marker (get-text-property (point) 'org-marker))
           (buffer (marker-buffer marker))
           (pos (marker-position marker))
@@ -1009,7 +1009,7 @@ This means, between the beginning of line and the point."
                     (org-flag-heading nil)))   ; show the next heading
              (org-back-to-heading)
              (setq marker (point-marker))
-             (goto-char (max (point-at-bol) (- (point-at-eol) anticol)))
+              (goto-char (max (line-beginning-position) (- (line-end-position) 
anticol)))
              (funcall command)
              (message "_cmd: %S" org-mouse-cmd)
              (message "this-command: %S" this-command)
diff --git a/lisp/org/org-plot.el b/lisp/org/org-plot.el
index 4507fbe7dd..1912f6762a 100644
--- a/lisp/org/org-plot.el
+++ b/lisp/org/org-plot.el
@@ -272,10 +272,10 @@ argument for the FUNCTION."
             for k in keys collect
             (cons k (funcall function (lookup k alist1) (lookup k alist2))))))
 
-(defun org--plot/item-frequencies (values &optional normalise)
+(defun org--plot/item-frequencies (values &optional normalize)
   "Return an alist indicating the frequency of values in VALUES list.
-When NORMALISE is non-nil, the count is divided by the number of values."
-  (let ((normaliser (if normalise (float (length values)) 1)))
+When NORMALIZE is non-nil, the count is divided by the number of values."
+  (let ((normaliser (if normalize (float (length values)) 1)))
     (cl-loop for (n . m) in (seq-group-by #'identity values)
             collect (cons n (/ (length m) normaliser)))))
 
@@ -621,8 +621,9 @@ manner suitable for prepending to a user-specified script."
   "Find any overlays for IMG-FILE in the current Org buffer, and refresh them."
   (dolist (img-overlay org-inline-image-overlays)
     (when (string= img-file (plist-get (cdr (overlay-get img-overlay 
'display)) :file))
-      (when (file-exists-p img-file)
-        (image-refresh (overlay-get img-overlay 'display))))))
+      (when (and (file-exists-p img-file)
+                 (fboundp 'image-flush))
+        (image-flush (overlay-get img-overlay 'display))))))
 
 ;;-----------------------------------------------------------------------------
 ;; facade functions
@@ -682,9 +683,10 @@ line directly before or after the table."
                                  (looking-at "[[:space:]]*#\\+"))
                        (setf params (org-plot/collect-options params))))
       ;; Dump table to datafile
-      (if-let ((dump-func (plist-get type :data-dump)))
-         (funcall dump-func table data-file num-cols params)
-       (org-plot/gnuplot-to-data table data-file params))
+      (let ((dump-func (plist-get type :data-dump)))
+        (if dump-func
+           (funcall dump-func table data-file num-cols params)
+         (org-plot/gnuplot-to-data table data-file params)))
       ;; Check type of ind column (timestamp? text?)
       (when (plist-get params :check-ind-type)
        (let* ((ind (1- (plist-get params :ind)))
diff --git a/lisp/org/org-refile.el b/lisp/org/org-refile.el
index 71d00a7a22..3b3344b270 100644
--- a/lisp/org/org-refile.el
+++ b/lisp/org/org-refile.el
@@ -465,9 +465,9 @@ prefix argument (`C-u C-u C-u C-c C-w')."
        (unless (or (org-kill-is-subtree-p
                     (buffer-substring region-start region-end))
                    (prog1 org-refile-active-region-within-subtree
-                     (let ((s (point-at-eol)))
+                      (let ((s (line-end-position)))
                        (org-toggle-heading)
-                       (setq region-end (+ (- (point-at-eol) s) region-end)))))
+                        (setq region-end (+ (- (line-end-position) s) 
region-end)))))
          (user-error "The region is not a (sequence of) subtree(s)")))
       (if (equal arg '(16))
          (org-refile-goto-last-stored)
diff --git a/lisp/org/org-src.el b/lisp/org/org-src.el
index 54f901252f..89d0c28a43 100644
--- a/lisp/org/org-src.el
+++ b/lisp/org/org-src.el
@@ -1235,7 +1235,7 @@ Throw an error if there is no such buffer."
                   (insert (with-current-buffer write-back-buf 
(buffer-string))))
          (save-restriction
            (narrow-to-region beg end)
-           (replace-buffer-contents write-back-buf 0.1 nil)
+           (org-replace-buffer-contents write-back-buf 0.1 nil)
            (goto-char (point-max))))
        (when (and expecting-bol (not (bolp))) (insert "\n")))
       (kill-buffer write-back-buf)
@@ -1283,7 +1283,7 @@ Throw an error if there is no such buffer."
                               (buffer-string))))
           (save-restriction
             (narrow-to-region beg end)
-            (replace-buffer-contents write-back-buf 0.1 nil)
+            (org-replace-buffer-contents write-back-buf 0.1 nil)
             (goto-char (point-max))))
         (when (and expecting-bol (not (bolp))) (insert "\n")))))
     (when write-back-buf (kill-buffer write-back-buf))
diff --git a/lisp/org/org-table.el b/lisp/org/org-table.el
index c301bc6af1..9b692d0973 100644
--- a/lisp/org/org-table.el
+++ b/lisp/org/org-table.el
@@ -486,7 +486,7 @@ This may be useful when columns have been shrunk."
                                    (looking-at-p 
".*|\\s-+<[rcl]?\\([0-9]+\\)?>"))
                           (move-beginning-of-line 2))
                         (line-beginning-position)))
-                 (end (save-excursion (goto-char beg) (point-at-eol))))
+                 (end (save-excursion (goto-char beg) (line-end-position))))
             (if (pos-visible-in-window-p beg)
                 (when (overlayp org-table-header-overlay)
                   (delete-overlay org-table-header-overlay))
@@ -825,7 +825,7 @@ SIZE is a string Columns x Rows like for example \"3x2\"."
         (line (concat (apply 'concat indent "|" (make-list columns "  |"))
                       "\n")))
     (if (string-match "^[ \t]*$" (buffer-substring-no-properties
-                                 (point-at-bol) (point)))
+                                  (line-beginning-position) (point)))
        (beginning-of-line 1)
       (newline))
     ;; (mapcar (lambda (x) (insert line)) (make-list rows t))
@@ -1087,7 +1087,7 @@ With numeric argument N, move N-1 fields backward first."
     (while (> n 1)
       (setq n (1- n))
       (org-table-previous-field))
-    (if (not (re-search-backward "|" (point-at-bol 0) t))
+    (if (not (re-search-backward "|" (line-beginning-position 0) t))
        (user-error "No more table fields before the current")
       (goto-char (match-end 0))
       (and (looking-at " ") (forward-char 1)))
@@ -1102,7 +1102,7 @@ With numeric argument N, move N-1 fields forward first."
     (while (> n 1)
       (setq n (1- n))
       (org-table-next-field))
-    (when (re-search-forward "|" (point-at-eol 1) t)
+    (when (re-search-forward "|" (line-end-position 1) t)
       (backward-char 1)
       (skip-chars-backward " ")
       (when (and (equal (char-before (point)) ?|) (equal (char-after (point)) 
?\s))
@@ -1159,7 +1159,7 @@ When ALIGN is set, also realign the table."
       (goto-char (org-table-begin))
       (while (and (re-search-forward org-table-dataline-regexp end t)
                  (setq cnt (1+ cnt))
-                 (< (point-at-eol) pos))))
+                  (< (line-end-position) pos))))
     cnt))
 
 (defun org-table-current-column ()
@@ -1322,7 +1322,7 @@ However, when FORCE is non-nil, create new columns if 
necessary."
   (beginning-of-line 1)
   (when (> n 0)
     (while (and (> (setq n (1- n)) -1)
-               (or (search-forward "|" (point-at-eol) t)
+                (or (search-forward "|" (line-end-position) t)
                    (and force
                         (progn (end-of-line 1)
                                (skip-chars-backward "^|")
@@ -1663,7 +1663,7 @@ With prefix ABOVE, insert above the current line."
     (org-table-align))
   (org-table-with-shrunk-columns
    (let ((line (org-table-clean-line
-               (buffer-substring (point-at-bol) (point-at-eol))))
+                (buffer-substring (line-beginning-position) 
(line-end-position))))
         (col (current-column)))
      (while (string-match "|\\( +\\)|" line)
        (setq line (replace-match
@@ -1712,7 +1712,8 @@ In particular, this does handle wide and invisible 
characters."
        (dline (and (not (org-match-line org-table-hline-regexp))
                    (org-table-current-dline))))
     (org-table-with-shrunk-columns
-     (kill-region (point-at-bol) (min (1+ (point-at-eol)) (point-max)))
+     (kill-region (line-beginning-position)
+                  (min (1+ (line-end-position)) (point-max)))
      (if (not (org-at-table-p)) (beginning-of-line 0))
      (org-move-to-column col)
      (when (and dline
@@ -2253,14 +2254,14 @@ For all numbers larger than LIMIT, shift them by DELTA."
                 (format "@%d\\$[0-9]+=.*?\\(::\\|$\\)" remove))))
            s n a)
        (when remove
-         (while (re-search-forward re2 (point-at-eol) t)
+          (while (re-search-forward re2 (line-end-position) t)
            (unless (save-match-data (org-in-regexp "remote([^)]+?)"))
              (if (equal (char-before (match-beginning 0)) ?.)
                  (user-error
                   "Change makes TBLFM term %s invalid, use undo to recover"
                   (match-string 0))
                (replace-match "")))))
-       (while (re-search-forward re (point-at-eol) t)
+        (while (re-search-forward re (line-end-position) t)
          (unless (save-match-data (org-in-regexp "remote([^)]+?)"))
            (setq s (match-string 1) n (string-to-number s))
            (cond
@@ -3789,8 +3790,9 @@ FACE, when non-nil, for the highlight."
     (let ((id 0) (ih 0) hline eol str ov)
       (goto-char (org-table-begin))
       (while (org-at-table-p)
-       (setq eol (point-at-eol))
-       (setq ov (make-overlay (point-at-bol) (1+ (point-at-bol))))
+        (setq eol (line-end-position))
+        (setq ov (make-overlay (line-beginning-position)
+                               (1+ (line-beginning-position))))
        (push ov org-table-coordinate-overlays)
        (setq hline (looking-at org-table-hline-regexp))
        (setq str (if hline (format "I*%-2d" (setq ih (1+ ih)))
@@ -4923,7 +4925,7 @@ When LOCAL is non-nil, show references for the table at 
point."
                  ((not local) nil)
                  (t (user-error "No reference at point")))
            match (and what (or match (match-string 0))))
-      (when (and  match (not (equal (match-beginning 0) (point-at-bol))))
+      (when (and  match (not (equal (match-beginning 0) 
(line-beginning-position))))
        (org-table-add-rectangle-overlay (match-beginning 0) (match-end 0)
                                         'secondary-selection))
       (add-hook 'before-change-functions
diff --git a/lisp/org/org-version.el b/lisp/org/org-version.el
index 6bdcb0afff..353d533c06 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.5.4"))
+   (let ((org-git-version "release_9.5.4-19-g4dff42"))
      org-git-version))
 
 (provide 'org-version)
diff --git a/lisp/org/org.el b/lisp/org/org.el
index 008230500d..9facbed04d 100644
--- a/lisp/org/org.el
+++ b/lisp/org/org.el
@@ -82,8 +82,8 @@
 (or (eq this-command 'eval-buffer)
     (condition-case nil
        (load (concat (file-name-directory load-file-name)
-                     "org-loaddefs.el")
-             nil t t t)
+                     "org-loaddefs")
+             nil t nil t)
       (error
        (message "WARNING: No org-loaddefs.el file could be found from where 
org.el is loaded.")
        (sit-for 3)
@@ -1357,7 +1357,7 @@ Possible values for the file identifier are:
                      to open [[file:document.pdf::5]] with evince at page 5.
 
  `directory'   Matches a directory
- `remote'      Matches a remote file, accessible through tramp or efs.
+ `remote'      Matches a remote file, accessible through tramp.
                Remote files most likely should be visited through Emacs
                because external applications cannot handle such paths.
 `auto-mode'    Matches files that are matched by any entry in 
`auto-mode-alist',
@@ -1694,7 +1694,7 @@ OK to kill that hidden subtree.  When nil, kill without 
remorse."
          (const :tag "Never kill a hidden subtree with C-k" error)))
 
 (defcustom org-special-ctrl-o t
-  "Non-nil means, make `C-o' insert a row in tables."
+  "Non-nil means, make `open-line' (\\[open-line]) insert a row in tables."
   :group 'org-edit-structure
   :type 'boolean)
 
@@ -3807,10 +3807,6 @@ This is needed for font-lock setup.")
 (declare-function dired-get-filename
                  "dired"
                  (&optional localp no-error-if-not-filep))
-(declare-function iswitchb-read-buffer
-                 "iswitchb"
-                 (prompt &optional
-                         default require-match _predicate start matches-set))
 (declare-function org-agenda-change-all-lines
                  "org-agenda"
                  (newhead hdmarker &optional fixface just-this))
@@ -3844,7 +3840,6 @@ This is needed for font-lock setup.")
 (defvar calc-embedded-open-formula)
 (defvar calc-embedded-open-mode)
 (defvar font-lock-unfontify-region-function)
-(defvar iswitchb-temp-buflist)
 (defvar org-agenda-tags-todo-honor-ignore-options)
 (defvar remember-data-file)
 (defvar texmathp-why)
@@ -5976,7 +5971,7 @@ and subscripts."
           (emph-p (get-text-property mpos 'org-emphasis))
           (link-p (get-text-property mpos 'mouse-face))
           (keyw-p (eq 'org-special-keyword (get-text-property mpos 'face))))
-      (goto-char (point-at-bol))
+      (goto-char (line-beginning-position))
       (setq table-p (looking-at-p org-table-dataline-regexp)
            comment-p (looking-at-p "^[ \t]*#[ +]"))
       (goto-char pos)
@@ -6448,7 +6443,7 @@ Use `\\[org-edit-special]' to edit table.el tables"))
                (and (memq org-cycle-emulate-tab '(white whitestart))
                     (save-excursion (beginning-of-line 1) (looking-at "[ 
\t]*"))
                     (or (and (eq org-cycle-emulate-tab 'white)
-                             (= (match-end 0) (point-at-eol)))
+                              (= (match-end 0) (line-end-position)))
                         (and (eq org-cycle-emulate-tab 'whitestart)
                              (>= (match-end 0) pos)))))
            (call-interactively (global-key-binding (kbd "TAB"))))
@@ -6503,7 +6498,7 @@ Use `\\[org-edit-special]' to edit table.el tables"))
          (progn
            (beginning-of-line)
            (setq struct (org-list-struct))
-           (setq eoh (point-at-eol))
+            (setq eoh (line-end-position))
            (setq eos (org-list-get-item-end-before-blank (point) struct))
            (setq has-children (org-list-has-child-p (point) struct)))
        (org-back-to-heading)
@@ -6550,7 +6545,7 @@ Use `\\[org-edit-special]' to edit table.el tables"))
       (unless (org-before-first-heading-p)
        (run-hook-with-args 'org-pre-cycle-hook 'children))
       (if (org-at-item-p)
-         (org-list-set-item-visibility (point-at-bol) struct 'children)
+          (org-list-set-item-visibility (line-beginning-position) struct 
'children)
        (org-show-entry)
        (org-with-limited-levels (org-show-children))
        (org-show-set-visibility 'tree)
@@ -6734,7 +6729,7 @@ This function is the default value of the hook 
`org-cycle-hook'."
                     (org-get-next-sibling)
                     (org-get-next-sibling))
                (if (org-at-heading-p)
-                   (point-at-eol)
+                    (line-end-position)
                  (point))))
         (level (looking-at "\\*+"))
         (re (when level (concat "^" (regexp-quote (match-string 0)) " "))))
@@ -7152,7 +7147,7 @@ This is a list with the following elements:
   "Get the entry text, after heading, entire subtree."
   (save-excursion
     (org-back-to-heading t)
-    (buffer-substring (point-at-bol 2) (org-end-of-subtree t))))
+    (buffer-substring (line-beginning-position 2) (org-end-of-subtree t))))
 
 (defun org-edit-headline (&optional heading)
   "Edit the current headline.
@@ -8407,7 +8402,7 @@ function is being called interactively."
                    (org-time-string-to-seconds (match-string 1))
                  (float-time now))))
             ((= dcst ?p)
-             (if (re-search-forward org-priority-regexp (point-at-eol) t)
+              (if (re-search-forward org-priority-regexp (line-end-position) t)
                  (string-to-char (match-string 2))
                org-priority-default))
             ((= dcst ?r)
@@ -9249,7 +9244,8 @@ If not found, stay at current position and return nil."
 (defun org-create-dblock (plist)
   "Create a dynamic block section, with parameters taken from PLIST.
 PLIST must contain a :name entry which is used as the name of the block."
-  (when (string-match "\\S-" (buffer-substring (point-at-bol) (point-at-eol)))
+  (when (string-match "\\S-" (buffer-substring (line-beginning-position)
+                                               (line-end-position)))
     (end-of-line 1)
     (newline))
   (let ((col (current-column))
@@ -9319,6 +9315,7 @@ TYPE is the dynamic block type, as a string."
   "List all defined dynamic block types."
   (mapcar #'car org-dynamic-block-alist))
 
+;;;###org-autoload
 (defun org-dynamic-block-define (type func)
   "Define dynamic block TYPE with FUNC.
 TYPE is a string.  FUNC is the function creating the dynamic
@@ -9912,7 +9909,8 @@ When called through ELisp, arg is also interpreted in the 
following way:
            (run-hooks 'org-after-todo-state-change-hook)
            (when (and arg (not (member org-state org-done-keywords)))
              (setq head (org-get-todo-sequence-head org-state)))
-           (put-text-property (point-at-bol) (point-at-eol) 'org-todo-head 
head)
+            (put-text-property (line-beginning-position)
+                               (line-end-position) 'org-todo-head head)
            ;; Do we need to trigger a repeat?
            (when now-done-p
              (when (boundp 'org-agenda-headline-snapshot-before-repeat)
@@ -10125,7 +10123,7 @@ all statistics cookies in the buffer."
              (beginning-of-line 1)
              (while (re-search-forward
                      "\\(\\(\\[[0-9]*%\\]\\)\\|\\(\\[[0-9]*/[0-9]*\\]\\)\\)"
-                     (point-at-eol) t)
+                      (line-end-position) t)
                (replace-match (if (match-end 2) "[100%]" "[0/0]") t t)))))
        (goto-char pos)
        (move-marker pos nil)))))
@@ -10172,7 +10170,7 @@ statistics everywhere."
                             (downcase (or (org-entry-get nil "COOKIE_DATA")
                                           "")))))
            (throw 'exit nil))
-         (while (re-search-forward box-re (point-at-eol) t)
+          (while (re-search-forward box-re (line-end-position) t)
            (setq cnt-all 0 cnt-done 0 cookie-present t)
            (setq is-percent (match-end 2) checkbox-beg (match-beginning 0))
            (save-match-data
@@ -10281,10 +10279,11 @@ right sequence."
   (let (p)
     (cond
      ((not kwd)
-      (or (get-text-property (point-at-bol) 'org-todo-head)
+      (or (get-text-property (line-beginning-position) 'org-todo-head)
          (progn
-           (setq p (next-single-property-change (point-at-bol) 'org-todo-head
-                                                nil (point-at-eol)))
+            (setq p (next-single-property-change (line-beginning-position)
+                                                 'org-todo-head
+                                                 nil (line-end-position)))
            (get-text-property p 'org-todo-head))))
      ((not (member kwd org-todo-keywords-1))
       (car org-todo-keywords-1))
@@ -10740,13 +10739,13 @@ nil."
       (outline-next-heading)
       (while (re-search-backward re beg t)
        (replace-match "")
-       (if (and (string-match "\\S-" (buffer-substring (point-at-bol) (point)))
+        (if (and (string-match "\\S-" (buffer-substring 
(line-beginning-position) (point)))
                 (equal (char-before) ?\ ))
            (backward-delete-char 1)
          (when (string-match "^[ \t]*$" (buffer-substring
-                                         (point-at-bol) (point-at-eol)))
-           (delete-region (point-at-bol)
-                          (min (point-max) (1+ (point-at-eol))))))))))
+                                          (line-beginning-position) 
(line-end-position)))
+            (delete-region (line-beginning-position)
+                           (min (point-max) (1+ (line-end-position))))))))))
 
 (defvar org-time-was-given) ; dynamically scoped parameter
 (defvar org-end-time-was-given) ; dynamically scoped parameter
@@ -12220,7 +12219,7 @@ Also insert END."
 (defun org-fast-tag-show-exit (flag)
   (save-excursion
     (org-goto-line 3)
-    (when (re-search-forward "[ \t]+Next change exits" (point-at-eol) t)
+    (when (re-search-forward "[ \t]+Next change exits" (line-end-position) t)
       (replace-match ""))
     (when flag
       (end-of-line 1)
@@ -12267,7 +12266,7 @@ Returns the new tags string, or nil to not change the 
current settings."
          (setq ov-start (match-beginning 1)
                ov-end (match-end 1)
                ov-prefix "")
-       (setq ov-start (1- (point-at-eol))
+        (setq ov-start (1- (line-end-position))
              ov-end (1+ ov-start))
        (skip-chars-forward "^\n\r")
        (setq ov-prefix
@@ -12426,7 +12425,7 @@ Returns the new tags string, or nil to not change the 
current settings."
                  (when (eq exit-after-next 'now) (throw 'exit t))
                  (goto-char (point-min))
                  (beginning-of-line 2)
-                 (delete-region (point) (point-at-eol))
+                  (delete-region (point) (line-end-position))
                  (org-fast-tag-insert "Current" current c-face)
                  (org-set-current-tags-overlay current ov-prefix)
                  (let ((tag-re (concat "\\[.\\] \\(" org-tag-re "\\)")))
@@ -14086,7 +14085,8 @@ user."
                            (max (point-min) (- (point) 4)) (point))
                           "    "))
          (insert " ")))
-      (let* ((ans (concat (buffer-substring (point-at-bol) (point-max))
+      (let* ((ans (concat (buffer-substring (line-beginning-position)
+                                            (point-max))
                          " " (or org-ans1 org-ans2)))
             (org-end-time-was-given nil)
             (f (org-read-date-analyze ans org-def org-defdecode))
@@ -14108,7 +14108,7 @@ user."
        (when org-read-date-analyze-futurep
          (setq txt (concat txt " (=>F)")))
        (setq org-read-date-overlay
-             (make-overlay (1- (point-at-eol)) (point-at-eol)))
+              (make-overlay (1- (line-end-position)) (line-end-position)))
        (org-overlay-display org-read-date-overlay txt 'secondary-selection)))))
 
 (defun org-read-date-analyze (ans def defdecode)
@@ -14658,8 +14658,8 @@ days in order to avoid rounding problems."
    (org-clock-update-time-maybe)
    (save-excursion
      (unless (org-at-date-range-p t)
-       (goto-char (point-at-bol))
-       (re-search-forward org-tr-regexp-both (point-at-eol) t))
+       (goto-char (line-beginning-position))
+       (re-search-forward org-tr-regexp-both (line-end-position) t))
      (unless (org-at-date-range-p t)
        (user-error "Not at a time-stamp range, and none found in current 
line")))
    (let* ((ts1 (match-string 1))
@@ -15723,7 +15723,8 @@ When a buffer is unmodified, it is just killed.  When 
modified, it is saved
                  (goto-char (point-min))
                  (while (re-search-forward rea nil t)
                    (when (org-at-heading-p t)
-                     (add-text-properties (point-at-bol) (org-end-of-subtree 
t) pa))))
+                      (add-text-properties (line-beginning-position)
+                                           (org-end-of-subtree t) pa))))
                (goto-char (point-min))
                (setq re (format "^\\*+ .*\\<%s\\>" org-comment-string))
                (while (re-search-forward re nil t)
@@ -16486,7 +16487,7 @@ INCLUDE-LINKED is passed to 
`org-display-inline-images'."
     (org-toggle-inline-images)))
 
 ;; For without-x builds.
-(declare-function image-refresh "image" (spec &optional frame))
+(declare-function image-flush "image" (spec &optional frame))
 
 (defcustom org-display-remote-inline-images 'skip
   "How to display remote inline images.
@@ -16627,7 +16628,7 @@ buffer boundaries with possible narrowing."
                                (org-element-property :begin link)
                                'org-image-overlay)))
                      (if (and (car-safe old) refresh)
-                         (image-refresh (overlay-get (cdr old) 'display))
+                          (image-flush (overlay-get (cdr old) 'display))
                        (let ((image (org--create-inline-image file width)))
                          (when image
                            (let ((ov (make-overlay
@@ -17235,14 +17236,14 @@ this function returns t, nil otherwise."
     (save-excursion
       (catch 'exit
        (unless (org-region-active-p)
-         (setq beg (point-at-bol))
+          (setq beg (line-beginning-position))
          (beginning-of-line 2)
          (while (and (not (eobp)) ;; this is like `next-line'
                      (get-char-property (1- (point)) 'invisible))
            (beginning-of-line 2))
          (setq end (point))
          (goto-char beg)
-         (goto-char (point-at-eol))
+          (goto-char (line-end-position))
          (setq end (max end (point)))
          (while (re-search-forward re end t)
            (when (get-char-property (match-beginning 0) 'invisible)
@@ -18164,7 +18165,7 @@ number of stars to add."
             (goto-char pos)
             (while (org-at-comment-p) (forward-line))
             (skip-chars-forward " \r\t\n")
-            (point-at-bol))))
+             (line-beginning-position))))
        beg end toggled)
     ;; Determine boundaries of changes.  If a universal prefix has
     ;; been given, put the list in a region.  If region ends at a bol,
@@ -18178,9 +18179,9 @@ number of stars to add."
        (setq beg (funcall skip-blanks (region-beginning))
              end (copy-marker (save-excursion
                                 (goto-char (region-end))
-                                (if (bolp) (point) (point-at-eol)))))
-      (setq beg (funcall skip-blanks (point-at-bol))
-           end (copy-marker (point-at-eol))))
+                                 (if (bolp) (point) (line-end-position)))))
+      (setq beg (funcall skip-blanks (line-beginning-position))
+            end (copy-marker (line-end-position))))
     ;; Ensure inline tasks don't count as headings.
     (org-with-limited-levels
      (save-excursion
@@ -18791,7 +18792,9 @@ and :keyword."
     ;; First the large context
     (cond
      ((org-at-heading-p t)
-      (push (list :headline (point-at-bol) (point-at-eol)) clist)
+      (push (list :headline (line-beginning-position)
+                  (line-end-position))
+            clist)
       (when (progn
              (beginning-of-line 1)
              (looking-at org-todo-line-tags-regexp))
@@ -18805,7 +18808,7 @@ and :keyword."
 
      ((org-at-item-p)
       (push (org-point-in-group p 2 :item-bullet) clist)
-      (push (list :item (point-at-bol)
+      (push (list :item (line-beginning-position)
                  (save-excursion (org-end-of-item) (point)))
            clist)
       (and (org-at-item-checkbox-p)
@@ -19202,7 +19205,7 @@ Also align node properties according to 
`org-property-format'."
                      (beginning-of-line 1)
                      (skip-chars-backward "\n")
                      (or (org-at-heading-p)
-                         (looking-back ":END:.*" (point-at-bol))))))
+                         (looking-back ":END:.*" (line-beginning-position))))))
     (let* ((element (save-excursion (beginning-of-line) 
(org-element-at-point)))
           (type (org-element-type element)))
       (cond ((and (memq type '(plain-list item))
@@ -19942,7 +19945,7 @@ major mode."
                (point))))
       (org-babel-do-in-edit-buffer (call-interactively 'comment-dwim))
     (beginning-of-line)
-    (if (looking-at "\\s-*$") (delete-region (point) (point-at-eol))
+    (if (looking-at "\\s-*$") (delete-region (point) (line-end-position))
       (open-line 1))
     (org-indent-line)
     (insert "# ")))
@@ -20435,7 +20438,7 @@ interactive command with similar behavior."
                    (and (looking-at "[ \t]*$")
                         (string-match
                          "\\`\\*+\\'"
-                         (buffer-substring (point-at-bol) (point)))))))
+                          (buffer-substring (line-beginning-position) 
(point)))))))
          swallowp)
       (cond
        ((and subtreep org-yank-folded-subtrees)
@@ -20468,7 +20471,7 @@ interactive command with similar behavior."
          (beginning-of-line 1)
          (push-mark beg 'nomsg)))
        ((and subtreep org-yank-adjusted-subtrees)
-       (let ((beg (point-at-bol)))
+        (let ((beg (line-beginning-position)))
          (org-paste-subtree nil nil 'for-yank)
          (push-mark beg 'nomsg)))
        (t
diff --git a/lisp/org/ox-ascii.el b/lisp/org/ox-ascii.el
index 38b2a5772c..76a1a71fab 100644
--- a/lisp/org/ox-ascii.el
+++ b/lisp/org/ox-ascii.el
@@ -948,12 +948,18 @@ channel."
         (when description
           (let ((dest (if (equal type "fuzzy")
                           (org-export-resolve-fuzzy-link link info)
-                        (org-export-resolve-id-link link info))))
-            (concat
-             (org-ascii--fill-string
-              (format "[%s] %s" anchor (org-ascii--describe-datum dest info))
-              width info)
-             "\n\n"))))
+                         ;; Ignore broken links.  On broken link,
+                         ;; `org-export-resolve-id-link' will throw an
+                         ;; error and we will return nil.
+                        (condition-case nil
+                             (org-export-resolve-id-link link info)
+                           (org-link-broken nil)))))
+             (when dest
+              (concat
+               (org-ascii--fill-string
+                (format "[%s] %s" anchor (org-ascii--describe-datum dest info))
+                width info)
+               "\n\n")))))
        ;; Do not add a link that cannot be resolved and doesn't have
        ;; any description: destination is already visible in the
        ;; paragraph.
diff --git a/lisp/org/ox-icalendar.el b/lisp/org/ox-icalendar.el
index a3fe31d7b8..7a62145076 100644
--- a/lisp/org/ox-icalendar.el
+++ b/lisp/org/ox-icalendar.el
@@ -276,14 +276,14 @@ re-read the iCalendar file.")
 ;;; Define Back-End
 
 (org-export-define-derived-backend 'icalendar 'ascii
-  :translate-alist '((clock . ignore)
-                    (footnote-definition . ignore)
-                    (footnote-reference . ignore)
+  :translate-alist '((clock . nil)
+                    (footnote-definition . nil)
+                    (footnote-reference . nil)
                     (headline . org-icalendar-entry)
                      (inner-template . org-icalendar-inner-template)
-                    (inlinetask . ignore)
-                    (planning . ignore)
-                    (section . ignore)
+                    (inlinetask . nil)
+                    (planning . nil)
+                    (section . nil)
                     (template . org-icalendar-template))
   :options-alist
   '((:exclude-tags
diff --git a/lisp/org/ox-md.el b/lisp/org/ox-md.el
index ad684d8033..3551e4184e 100644
--- a/lisp/org/ox-md.el
+++ b/lisp/org/ox-md.el
@@ -193,11 +193,11 @@ of contents can refer to headlines."
      ;; A link refers internally to HEADLINE.
      (org-element-map (plist-get info :parse-tree) 'link
        (lambda (link)
-        (eq headline
-            (pcase (org-element-property :type link)
-              ((or "custom-id" "id") (org-export-resolve-id-link link info))
-              ("fuzzy" (org-export-resolve-fuzzy-link link info))
-              (_ nil))))
+        (equal headline
+                ;; Ignore broken links.
+                (condition-case nil
+                    (org-export-resolve-id-link link info)
+                  (org-link-broken nil))))
        info t))))
 
 (defun org-md--headline-title (style level title &optional anchor tags)
diff --git a/lisp/org/ox.el b/lisp/org/ox.el
index 2a3edaa500..9a2a69b2c1 100644
--- a/lisp/org/ox.el
+++ b/lisp/org/ox.el
@@ -80,6 +80,7 @@
 (require 'org-element)
 (require 'org-macro)
 (require 'tabulated-list)
+(require 'subr-x)
 
 (declare-function org-src-coderef-format "org-src" (&optional element))
 (declare-function org-src-coderef-regexp "org-src" (fmt &optional label))
@@ -1908,8 +1909,10 @@ Return a string."
                           (org-element-property :archivedp data)))
                  (let ((transcoder (org-export-transcoder data info)))
                    (or (and (functionp transcoder)
-                            (broken-link-handler
-                             (funcall transcoder data nil info)))
+                             (if (eq type 'link)
+                                (broken-link-handler
+                                 (funcall transcoder data nil info))
+                               (funcall transcoder data nil info)))
                        ;; Export snippets never return a nil value so
                        ;; that white spaces following them are never
                        ;; ignored.
@@ -1923,28 +1926,34 @@ Return a string."
                              (and (not greaterp)
                                   (memq type org-element-recursive-objects)))
                             (contents
-                             (mapconcat
-                              (lambda (element) (org-export-data element info))
-                              (org-element-contents
-                               (if (or greaterp objectp) data
-                                 ;; Elements directly containing
-                                 ;; objects must have their indentation
-                                 ;; normalized first.
-                                 (org-element-normalize-contents
-                                  data
-                                  ;; When normalizing first paragraph
-                                  ;; of an item or
-                                  ;; a footnote-definition, ignore
-                                  ;; first line's indentation.
-                                  (and
-                                   (eq type 'paragraph)
-                                   (memq (org-element-type parent)
-                                         '(footnote-definition item))
-                                   (eq (car (org-element-contents parent))
-                                       data)
-                                   (eq (org-element-property :pre-blank parent)
-                                       0)))))
-                              "")))
+                              (let ((export-buffer (current-buffer)))
+                                (with-temp-buffer
+                                  (dolist (element (org-element-contents
+                                                   (if (or greaterp objectp) 
data
+                                                     ;; Elements directly 
containing
+                                                     ;; objects must have 
their indentation
+                                                     ;; normalized first.
+                                                     
(org-element-normalize-contents
+                                                      data
+                                                      ;; When normalizing 
first paragraph
+                                                      ;; of an item or
+                                                      ;; a 
footnote-definition, ignore
+                                                      ;; first line's 
indentation.
+                                                      (and
+                                                       (eq type 'paragraph)
+                                                       (memq (org-element-type 
parent)
+                                                             
'(footnote-definition item))
+                                                       (eq (car 
(org-element-contents parent))
+                                                           data)
+                                                       (eq 
(org-element-property :pre-blank parent)
+                                                           0))))))
+                                    (insert
+                                     ;; Use right local variable
+                                     ;; environment if there are, for
+                                     ;; example, #+BIND variables.
+                                     (with-current-buffer export-buffer
+                                       (org-export-data element info))))
+                                  (buffer-string)))))
                        (broken-link-handler
                         (funcall transcoder data
                                  (if (not greaterp) contents
@@ -2956,11 +2965,12 @@ Return code as a string."
                    (mapcar (lambda (o) (and (eq (nth 4 o) 'parse) (nth 1 o)))
                            (append (org-export-get-all-options backend)
                                    org-export-options-alist))))
-            tree)
+            tree modified-tick)
        ;; Update communication channel and get parse tree.  Buffer
        ;; isn't parsed directly.  Instead, all buffer modifications
        ;; and consequent parsing are undertaken in a temporary copy.
        (org-export-with-buffer-copy
+         (font-lock-mode -1)
         ;; Run first hook with current back-end's name as argument.
         (run-hook-with-args 'org-export-before-processing-hook
                             (org-export-backend-name backend))
@@ -2972,6 +2982,7 @@ Return code as a string."
         ;; potentially invasive changes.
         (org-set-regexps-and-options)
         (org-update-radio-target-regexp)
+         (setq modified-tick (buffer-chars-modified-tick))
         ;;  Possibly execute Babel code.  Re-run a macro expansion
         ;;  specifically for {{{results}}} since inline source blocks
         ;;  may have generated some more.  Refresh buffer properties
@@ -2979,8 +2990,10 @@ Return code as a string."
         (when org-export-use-babel
           (org-babel-exp-process-buffer)
           (org-macro-replace-all '(("results" . "$1")) parsed-keywords)
-          (org-set-regexps-and-options)
-          (org-update-radio-target-regexp))
+           (unless (eq modified-tick (buffer-chars-modified-tick))
+            (org-set-regexps-and-options)
+            (org-update-radio-target-regexp))
+           (setq modified-tick (buffer-chars-modified-tick)))
         ;; Run last hook with current back-end's name as argument.
         ;; Update buffer properties and radio targets one last time
         ;; before parsing.
@@ -2988,8 +3001,10 @@ Return code as a string."
         (save-excursion
           (run-hook-with-args 'org-export-before-parsing-hook
                               (org-export-backend-name backend)))
-        (org-set-regexps-and-options)
-        (org-update-radio-target-regexp)
+         (unless (eq modified-tick (buffer-chars-modified-tick))
+          (org-set-regexps-and-options)
+          (org-update-radio-target-regexp))
+         (setq modified-tick (buffer-chars-modified-tick))
         ;; Update communication channel with environment.
         (setq info
               (org-combine-plists
@@ -3748,28 +3763,33 @@ definition can be found, raise an error."
     (if (not label) (org-element-contents footnote-reference)
       (let ((cache (or (plist-get info :footnote-definition-cache)
                       (let ((hash (make-hash-table :test #'equal)))
+                         ;; Cache all the footnotes in document for
+                         ;; later search.
+                         (org-element-map (plist-get info :parse-tree)
+                             '(footnote-definition footnote-reference)
+                           (lambda (f)
+                            ;; Skip any standard footnote reference
+                            ;; since those cannot contain a
+                            ;; definition.
+                             (unless (eq (org-element-property :type f) 
'standard)
+                               (puthash
+                                (cons :element (org-element-property :label f))
+                                f
+                                hash)))
+                           info)
                         (plist-put info :footnote-definition-cache hash)
                         hash))))
        (or
         (gethash label cache)
         (puthash label
-                 (org-element-map (plist-get info :parse-tree)
-                     '(footnote-definition footnote-reference)
-                   (lambda (f)
-                     (cond
-                      ;; Skip any footnote with a different label.
-                      ;; Also skip any standard footnote reference
-                      ;; with the same label since those cannot
-                      ;; contain a definition.
-                      ((not (equal (org-element-property :label f) label)) nil)
-                      ((eq (org-element-property :type f) 'standard) nil)
-                      ((org-element-contents f))
-                      ;; Even if the contents are empty, we can not
-                      ;; return nil since that would eventually raise
-                      ;; the error.  Instead, return the equivalent
-                      ;; empty string.
-                      (t "")))
-                   info t)
+                  (let ((hashed (gethash (cons :element label) cache)))
+                    (when hashed
+                      (or (org-element-contents hashed)
+                         ;; Even if the contents are empty, we can not
+                         ;; return nil since that would eventually raise
+                         ;; the error.  Instead, return the equivalent
+                         ;; empty string.
+                          "")))
                  cache)
         (error "Definition not found for footnote %s" label))))))
 
@@ -4341,17 +4361,27 @@ significant."
   (let* ((search-cells (org-export-string-to-search-cell
                        (org-element-property :path link)))
         (link-cache (or (plist-get info :resolve-fuzzy-link-cache)
-                        (let ((table (make-hash-table :test #'eq)))
+                        (let ((table (make-hash-table :test #'equal)))
+                           ;; Cache all the element search cells.
+                           (org-element-map (plist-get info :parse-tree)
+                              (append pseudo-types '(target) 
org-element-all-elements)
+                            (lambda (datum)
+                              (dolist (cell (org-export-search-cells datum))
+                                (if (gethash cell table)
+                                     (push datum (gethash cell table))
+                                   (puthash cell (list datum) table)))))
                           (plist-put info :resolve-fuzzy-link-cache table)
                           table)))
         (cached (gethash search-cells link-cache 'not-found)))
     (if (not (eq cached 'not-found)) cached
       (let ((matches
-            (org-element-map (plist-get info :parse-tree)
-                (append pseudo-types '(target) org-element-all-elements)
-              (lambda (datum)
-                (and (org-export-match-search-cell-p datum search-cells)
-                     datum)))))
+             (let (result)
+               (dolist (search-cell search-cells)
+                 (setq result
+                       (nconc
+                        result
+                       (gethash search-cell link-cache))))
+               (delq nil result))))
        (unless matches
          (signal 'org-link-broken (list (org-element-property :path link))))
        (puthash
@@ -4378,15 +4408,27 @@ tree or a file name.  Assume LINK type is either \"id\" 
or
 \"custom-id\".  Throw an error if no match is found."
   (let ((id (org-element-property :path link)))
     ;; First check if id is within the current parse tree.
-    (or (org-element-map (plist-get info :parse-tree) 'headline
-         (lambda (headline)
-           (when (or (equal (org-element-property :ID headline) id)
-                     (equal (org-element-property :CUSTOM_ID headline) id))
-             headline))
-         info 'first-match)
-       ;; Otherwise, look for external files.
-       (cdr (assoc id (plist-get info :id-alist)))
-       (signal 'org-link-broken (list id)))))
+    (or (let ((local-ids (or (plist-get info :id-local-cache)
+                             (let ((table (make-hash-table :test #'equal)))
+                               (org-element-map
+                                   (plist-get info :parse-tree)
+                                   'headline
+                                 (lambda (headline)
+                                   (let ((id (org-element-property :ID 
headline))
+                                         (custom-id (org-element-property 
:CUSTOM_ID headline)))
+                                     (when id
+                                       (unless (gethash id table)
+                                         (puthash id headline table)))
+                                     (when custom-id
+                                       (unless (gethash custom-id table)
+                                         (puthash custom-id headline table)))))
+                                 info)
+                               (plist-put info :id-local-cache table)
+                               table))))
+          (gethash id local-ids))
+        ;; Otherwise, look for external files.
+        (cdr (assoc id (plist-get info :id-alist)))
+        (signal 'org-link-broken (list id)))))
 
 (defun org-export-resolve-radio-link (link info)
   "Return radio-target object referenced as LINK destination.
@@ -4395,15 +4437,12 @@ INFO is a plist used as a communication channel.
 
 Return value can be a radio-target object or nil.  Assume LINK
 has type \"radio\"."
-  (let ((path (replace-regexp-in-string
-              "[ \r\t\n]+" " " (org-element-property :path link))))
+  (let ((path (string-clean-whitespace (org-element-property :path link))))
     (org-element-map (plist-get info :parse-tree) 'radio-target
       (lambda (radio)
-       (and (eq (compare-strings
-                 (replace-regexp-in-string
-                  "[ \r\t\n]+" " " (org-element-property :value radio))
-                 nil nil path nil nil t)
-                t)
+       (and (string-equal-ignore-case
+             (string-clean-whitespace (org-element-property :value radio))
+              path)
             radio))
       info 'first-match)))
 
@@ -6440,7 +6479,7 @@ to send the output file through additional processing, 
e.g,
     (let ((outfile (org-export-output-file-name \".tex\" subtreep)))
       (org-export-to-file \\='latex outfile
         async subtreep visible-only body-only ext-plist
-        #'org-latex-compile)))
+        #\\='org-latex-compile)))
 
 When expressed as an anonymous function, using `lambda',
 POST-PROCESS needs to be quoted.
diff --git a/lisp/outline.el b/lisp/outline.el
index 7fd43195cc..3250b62f1e 100644
--- a/lisp/outline.el
+++ b/lisp/outline.el
@@ -1,7 +1,6 @@
 ;;; outline.el --- outline mode commands for Emacs  -*- lexical-binding: t; -*-
 
-;; Copyright (C) 1986, 1993-1995, 1997, 2000-2022 Free Software
-;; Foundation, Inc.
+;; Copyright (C) 1986-2022 Free Software Foundation, Inc.
 
 ;; Maintainer: emacs-devel@gnu.org
 ;; Keywords: outlines
@@ -36,6 +35,7 @@
 ;;; Code:
 
 (eval-when-compile (require 'cl-lib))
+(require 'icons)
 
 (defgroup outlines nil
   "Support for hierarchical outlining."
@@ -182,7 +182,7 @@ in the file it applies to.")
 This option controls, in Outline minor mode, where on a heading typing
 the key sequences bound to visibility-cycling commands like `outline-cycle'
 and `outline-cycle-buffer' will invoke those commands.  By default, you can
-invoke these commands by typing `TAB' and `S-TAB' anywhere on a heading line,
+invoke these commands by typing \\`TAB' and \\`S-TAB' anywhere on a heading 
line,
 but customizing this option can make those bindings be in effect only at
 specific positions on the heading, like only at the line's beginning or
 line's end.  This allows these keys to be bound to their usual commands,
@@ -281,23 +281,33 @@ This option is only in effect when 
`outline-minor-mode-cycle' is non-nil."
   [outline-1 outline-2 outline-3 outline-4
    outline-5 outline-6 outline-7 outline-8])
 
-(defcustom outline-minor-mode-use-buttons nil
-  "If non-nil, use clickable buttons on the headings.
-Note that this feature is not meant to be used in editing
-buffers (yet) -- that will be amended in a future version.
+(defcustom outline-minor-mode-use-buttons '(derived-mode . help-mode)
+  "Whether to display clickable buttons on the headings.
+The value should be a `buffer-match-p' condition.
 
-The `outline-minor-mode-buttons' variable specifies how the
-buttons should look."
-  :type 'boolean
+These buttons can be used to hide and show the body under the heading.
+Note that this feature is not meant to be used in editing
+buffers (yet) -- that will be amended in a future version."
+  ;; FIXME -- is there a `buffer-match-p' defcustom type somewhere?
+  :type 'sexp
   :safe #'booleanp
   :version "29.1")
 
-(defcustom outline-minor-mode-buttons
-  '(("▶️" "🔽" outline--valid-emoji-p)
-    ("▶" "▼" outline--valid-char-p))
-  "List of close/open pairs to use if using buttons."
-  :type 'sexp
-  :version "29.1")
+(define-icon outline-open button
+  '((emoji "🔽")
+    (symbol " ▼ ")
+    (text " open "))
+  "Icon used for buttons for opening a section in outline buffers."
+  :version "29.1"
+  :help-echo "Open this section")
+
+(define-icon outline-close button
+  '((emoji "▶️")
+    (symbol " ▶ ")
+    (text " close "))
+  "Icon used for buttons for closing a section in outline buffers."
+  :version "29.1"
+  :help-echo "Close this section")
 
 
 (defvar outline-level #'outline-level
@@ -317,6 +327,7 @@ data reflects the `outline-regexp'.")
 
 (defvar outline-view-change-hook nil
   "Normal hook to be run after outline visibility changes.")
+(make-obsolete-variable 'outline-view-change-hook nil "29.1")
 
 (defvar outline-mode-hook nil
   "This hook is run when outline mode starts.")
@@ -381,9 +392,9 @@ After that, changing the prefix key requires manipulating 
keymaps."
 
 (defcustom outline-minor-mode-cycle nil
   "Enable visibility-cycling commands on headings in `outline-minor-mode'.
-If enabled, typing `TAB' on a heading line cycles the visibility
+If enabled, typing \\`TAB' on a heading line cycles the visibility
 state of that heading's body between `hide all', `headings only'
-and `show all' (`outline-cycle'), and typing `S-TAB' on a heading
+and `show all' (`outline-cycle'), and typing \\`S-TAB' on a heading
 line likewise cycles the visibility state of the whole buffer
 \(`outline-cycle-buffer').
 Typing these keys anywhere outside heading lines invokes their default
@@ -424,7 +435,7 @@ outline font-lock faces to those of major mode."
                          (goto-char (match-beginning 0))
                          (not (get-text-property (point) 'face))))
             (overlay-put overlay 'face (outline-font-lock-face)))
-          (when outline-minor-mode-use-buttons
+          (when (and (outline--use-buttons-p) (outline-on-heading-p))
             (outline--insert-open-button)))
         (goto-char (match-end 0))))))
 
@@ -441,11 +452,10 @@ See the command `outline-mode' for more information on 
this mode."
   (if outline-minor-mode
       (progn
         (when outline-minor-mode-highlight
-          (if (and global-font-lock-mode (font-lock-specified-p major-mode))
-              (progn
-                (font-lock-add-keywords nil outline-font-lock-keywords t)
-                (font-lock-flush))
-            (outline-minor-mode-highlight-buffer)))
+          (when (and global-font-lock-mode (font-lock-specified-p major-mode))
+            (font-lock-add-keywords nil outline-font-lock-keywords t)
+            (font-lock-flush))
+          (outline-minor-mode-highlight-buffer))
        ;; Turn off this mode if we change major modes.
        (add-hook 'change-major-mode-hook
                  (lambda () (outline-minor-mode -1))
@@ -465,6 +475,10 @@ See the command `outline-mode' for more information on 
this mode."
     ;; When turning off outline mode, get rid of any outline hiding.
     (outline-show-all)))
 
+(defun outline--use-buttons-p ()
+  (and outline-minor-mode
+       (buffer-match-p outline-minor-mode-use-buttons (current-buffer))))
+
 (defvar-local outline-heading-alist ()
   "Alist associating a heading for every possible level.
 Each entry is of the form (HEADING . LEVEL).
@@ -847,7 +861,6 @@ If FLAG is nil then text is shown, while if FLAG is t the 
text is hidden."
                   (or outline-isearch-open-invisible-function
                       #'outline-isearch-open-invisible))))
   (outline--fix-up-all-buttons from to)
-  ;; Seems only used by lazy-lock.  I.e. obsolete.
   (run-hooks 'outline-view-change-hook))
 
 (defun outline-reveal-toggle-invisible (o hidep)
@@ -969,26 +982,10 @@ If non-nil, EVENT should be a mouse event."
   (interactive (list last-nonmenu-event))
   (when (mouse-event-p event)
     (mouse-set-point event))
-  (when (and outline-minor-mode-use-buttons outline-minor-mode)
+  (when (outline--use-buttons-p)
     (outline--insert-close-button))
   (outline-flag-subtree t))
 
-(defun outline--make-button (type)
-  (cl-loop for (close open test) in outline-minor-mode-buttons
-           when (and (funcall test close) (funcall test open))
-           return (concat (if (eq type 'close)
-                              close
-                            open)
-                          " " (buffer-substring (point) (1+ (point))))))
-
-(defun outline--valid-emoji-p (string)
-  (when-let ((font (and (display-multi-font-p)
-                        (car (internal-char-font nil ?😀)))))
-    (font-has-char-p font (aref string 0))))
-
-(defun outline--valid-char-p (string)
-  (char-displayable-p (aref string 0)))
-
 (defun outline--make-button-overlay (type)
   (let ((o (seq-find (lambda (o)
                        (overlay-get o 'outline-button))
@@ -998,35 +995,56 @@ If non-nil, EVENT should be a mouse event."
       (overlay-put o 'follow-link 'mouse-face)
       (overlay-put o 'mouse-face 'highlight)
       (overlay-put o 'outline-button t))
-    (overlay-put o 'display (outline--make-button type))
+    (let ((icon
+           (icon-elements (if (eq type 'close) 'outline-close 'outline-open)))
+          (inhibit-read-only t))
+      ;; In editing buffers we use overlays only, but in other buffers
+      ;; we use a mix of text properties, text and overlays to make
+      ;; movement commands work more logically.
+      (when (derived-mode-p 'special-mode)
+        (put-text-property (point) (1+ (point)) 'face (plist-get icon 'face)))
+      (when-let ((image (plist-get icon 'image)))
+        (overlay-put o 'display image))
+      (overlay-put o 'display (plist-get icon 'string))
+      (overlay-put o 'face (plist-get icon 'face)))
     o))
 
 (defun outline--insert-open-button ()
-  (save-excursion
-    (beginning-of-line)
-    (let ((o (outline--make-button-overlay 'open)))
-      (overlay-put o 'help-echo "Click to hide")
-      (overlay-put o 'keymap
-                   (define-keymap
-                     "RET" #'outline-hide-subtree
-                     "<mouse-2>" #'outline-hide-subtree)))))
+  (with-silent-modifications
+    (save-excursion
+        (beginning-of-line)
+        (when (derived-mode-p 'special-mode)
+          (let ((inhibit-read-only t))
+            (insert "  ")
+            (beginning-of-line)))
+        (let ((o (outline--make-button-overlay 'open)))
+          (overlay-put o 'help-echo "Click to hide")
+          (overlay-put o 'keymap
+                       (define-keymap
+                         "RET" #'outline-hide-subtree
+                         "<mouse-2>" #'outline-hide-subtree))))))
 
 (defun outline--insert-close-button ()
-  (save-excursion
-    (beginning-of-line)
-    (let ((o (outline--make-button-overlay 'close)))
-      (overlay-put o 'help-echo "Click to show")
-      (overlay-put o 'keymap
-                   (define-keymap
-                     "RET" #'outline-show-subtree
-                     "<mouse-2>" #'outline-show-subtree)))))
+  (with-silent-modifications
+    (save-excursion
+        (beginning-of-line)
+        (when (derived-mode-p 'special-mode)
+          (let ((inhibit-read-only t))
+            (insert "  ")
+            (beginning-of-line)))
+        (let ((o (outline--make-button-overlay 'close)))
+          (overlay-put o 'help-echo "Click to show")
+          (overlay-put o 'keymap
+                       (define-keymap
+                         "RET" #'outline-show-subtree
+                         "<mouse-2>" #'outline-show-subtree))))))
 
 (defun outline--fix-up-all-buttons (&optional from to)
   (when from
     (save-excursion
       (goto-char from)
       (setq from (line-beginning-position))))
-  (when outline-minor-mode-use-buttons
+  (when (outline--use-buttons-p)
     (outline-map-region
      (lambda ()
        ;; `outline--cycle-state' will fail if we're in a totally
@@ -1057,7 +1075,7 @@ If non-nil, EVENT should be a mouse event."
   (interactive (list last-nonmenu-event))
   (when (mouse-event-p event)
     (mouse-set-point event))
-  (when (and outline-minor-mode-use-buttons outline-minor-mode)
+  (when (outline--use-buttons-p)
     (outline--insert-open-button))
   (outline-flag-subtree nil))
 
diff --git a/lisp/paren.el b/lisp/paren.el
index 4c268dbf77..d7580de9a9 100644
--- a/lisp/paren.el
+++ b/lisp/paren.el
@@ -149,7 +149,8 @@ use `show-paren-local-mode'."
 ;;;###autoload
 (define-minor-mode show-paren-local-mode
   "Toggle `show-paren-mode' only in this buffer."
-  :variable (buffer-local-value 'show-paren-mode (current-buffer))
+  :variable ( show-paren-mode .
+              (lambda (val) (setq-local show-paren-mode val)))
   (cond
    ((eq show-paren-mode (default-value 'show-paren-mode))
     (unless show-paren-mode
diff --git a/lisp/pcmpl-unix.el b/lisp/pcmpl-unix.el
index 0074722be7..8774f091c8 100644
--- a/lisp/pcmpl-unix.el
+++ b/lisp/pcmpl-unix.el
@@ -197,6 +197,10 @@ Uses both `pcmpl-ssh-config-file' and 
`pcmpl-ssh-known-hosts-file'."
   (pcomplete-opt "1246AaCfgKkMNnqsTtVvXxYbcDeFiLlmOopRSw")
   (pcomplete-here (pcmpl-ssh-hosts)))
 
+;;;###autoload
+(defalias 'pcomplete/rsh    #'pcomplete/ssh)
+(defalias 'pcomplete/rlogin #'pcomplete/ssh)
+
 ;;;###autoload
 (defun pcomplete/scp ()
   "Completion rules for the `scp' command.
@@ -229,22 +233,12 @@ Includes files as well as host names followed by a colon."
 (defalias 'pcomplete/ftp    'pcmpl-unix-complete-hostname)
 (defalias 'pcomplete/ncftp  'pcmpl-unix-complete-hostname)
 (defalias 'pcomplete/ping   'pcmpl-unix-complete-hostname)
-(defalias 'pcomplete/rlogin 'pcmpl-unix-complete-hostname)
 
 ;;;###autoload
 (defun pcomplete/telnet ()
   (pcomplete-opt "xl(pcmpl-unix-user-names)")
   (pcmpl-unix-complete-hostname))
 
-;;;###autoload
-(defun pcomplete/rsh ()
-  "Complete `rsh', which, after the user and hostname, is like xargs."
-  (pcomplete-opt "l(pcmpl-unix-user-names)")
-  (pcmpl-unix-complete-hostname)
-  (pcomplete-here (funcall pcomplete-command-completion-function))
-  (funcall (or (pcomplete-find-completion-function (pcomplete-arg 1))
-               pcomplete-default-completion-function)))
-
 (provide 'pcmpl-unix)
 
 ;;; pcmpl-unix.el ends here
diff --git a/lisp/pgtk-dnd.el b/lisp/pgtk-dnd.el
new file mode 100644
index 0000000000..b37bf9ba60
--- /dev/null
+++ b/lisp/pgtk-dnd.el
@@ -0,0 +1,410 @@
+;;; pgtk-dnd.el --- drag and drop support for GDK -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+
+;; Maintainer: emacs-devel@gnu.org
+;; Keywords: window, drag, drop
+;; Package: emacs
+
+;; Significant portions taken from x-dnd.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:
+
+;; This file provides the receiving side of the GDK drag and drop
+;; mechanism.
+
+;;; Code:
+
+(require 'dnd)
+
+;;; Customizable variables
+(defcustom pgtk-dnd-test-function #'pgtk-dnd-default-test-function
+  "The function drag and drop uses to determine if to accept or reject a drop.
+The function takes three arguments, WINDOW, ACTION and TYPES.
+WINDOW is where the mouse is when the function is called.  WINDOW
+may be a frame if the mouse isn't over a real window (i.e. menu
+bar, tool bar or scroll bar).  ACTION is the suggested action
+from the drag and drop source, one of the symbols move, copy,
+link or ask.  TYPES is a vector of available types for the drop.
+
+Each element of TYPE should either be a string (containing the
+name of the type's X atom), or a symbol, whose name will be used.
+
+The function shall return nil to reject the drop or a cons with
+two values, the wanted action as car and the wanted type as cdr.
+The wanted action can be copy, move, link, ask or private.
+
+The default value for this variable is `pgtk-dnd-default-test-function'."
+  :version "22.1"
+  :type 'symbol
+  :group 'pgtk)
+
+(defcustom pgtk-dnd-types-alist
+  `((,(purecopy "text/uri-list") . pgtk-dnd-handle-uri-list)
+    (,(purecopy "FILE_NAME") . pgtk-dnd-handle-file-name)
+    (,(purecopy "UTF8_STRING") . pgtk-dnd-insert-utf8-text)
+    (,(purecopy "text/plain;charset=UTF-8") . pgtk-dnd-insert-utf8-text)
+    (,(purecopy "text/plain;charset=utf-8") . pgtk-dnd-insert-utf8-text)
+    (,(purecopy "text/plain") . dnd-insert-text)
+    (,(purecopy "COMPOUND_TEXT") . pgtk-dnd-insert-ctext)
+    (,(purecopy "STRING") . dnd-insert-text)
+    (,(purecopy "TEXT")   . dnd-insert-text))
+  "Which function to call to handle a drop of that type.
+If the type for the drop is not present, or the function is nil,
+the drop is rejected.  The function takes three arguments, WINDOW, ACTION
+and DATA.  WINDOW is where the drop occurred, ACTION is the action for
+this drop (copy, move, link, private or ask) as determined by a previous
+call to `pgtk-dnd-test-function'.  DATA is the drop data.
+The function shall return the action used (copy, move, link or private)
+if drop is successful, nil if not."
+  :version "22.1"
+  :type 'alist
+  :group 'pgtk)
+
+(defcustom pgtk-dnd-known-types
+  (mapcar 'purecopy '("text/uri-list"
+                      "FILE_NAME"
+                      "UTF8_STRING"
+                      "text/plain;charset=UTF-8"
+                      "text/plain;charset=utf-8"
+                      "text/plain"
+                      "COMPOUND_TEXT"
+                      "STRING"
+                      "TEXT"))
+  "The types accepted by default for dropped data.
+The types are chosen in the order they appear in the list."
+  :version "22.1"
+  :type '(repeat string)
+  :group 'pgtk)
+
+;; Internal variables
+
+(defvar pgtk-dnd-current-state nil
+  "The current state for a drop.
+This is an alist with one entry for each display.  The value for each display
+is a vector that contains the state for drag and drop for that display.
+Elements in the vector are:
+Last buffer drag was in,
+last window drag was in,
+types available for drop,
+the action suggested by the source,
+the type we want for the drop,
+the action we want for the drop,
+any protocol specific data.")
+
+(declare-function pgtk-get-selection-internal "pgtkselect.c")
+(declare-function pgtk-register-dnd-targets "pgtkselect.c")
+
+(defvar pgtk-dnd-empty-state [nil nil nil nil nil nil nil])
+
+(defun pgtk-dnd-init-frame (&optional frame)
+  "Setup drag and drop for FRAME (i.e. create appropriate properties)."
+  (when (eq 'pgtk (window-system frame))
+    (pgtk-register-dnd-targets frame pgtk-dnd-known-types)))
+
+(defun pgtk-dnd-get-state-cons-for-frame (frame-or-window)
+  "Return the entry in `pgtk-dnd-current-state' for a frame or window."
+  (let* ((frame (if (framep frame-or-window) frame-or-window
+                 (window-frame frame-or-window)))
+        (display (frame-parameter frame 'display)))
+    (if (not (assoc display pgtk-dnd-current-state))
+       (push (cons display (copy-sequence pgtk-dnd-empty-state))
+             pgtk-dnd-current-state))
+    (assoc display pgtk-dnd-current-state)))
+
+(defun pgtk-dnd-get-state-for-frame (frame-or-window)
+  "Return the state in `pgtk-dnd-current-state' for a frame or window."
+  (cdr (pgtk-dnd-get-state-cons-for-frame frame-or-window)))
+
+(defun pgtk-dnd-default-test-function (_window _action types)
+  "The default test function for drag and drop.
+WINDOW is where the mouse is when this function is called.  It may be
+a frame if the mouse is over the menu bar, scroll bar or tool bar.
+ACTION is the suggested action from the source, and TYPES are the
+types the drop data can have.  This function only accepts drops with
+types in `pgtk-dnd-known-types'.  It always returns the action `copy'."
+  (let ((type (pgtk-dnd-choose-type types)))
+    (when type (cons 'copy type))))
+
+(defun pgtk-dnd-current-type (frame-or-window)
+  "Return the type we want the DND data to be in for the current drop.
+FRAME-OR-WINDOW is the frame or window that the mouse is over."
+  (aref (pgtk-dnd-get-state-for-frame frame-or-window) 4))
+
+(defun pgtk-dnd-forget-drop (frame-or-window)
+  "Remove all state for the last drop.
+FRAME-OR-WINDOW is the frame or window that the mouse is over."
+  (setcdr (pgtk-dnd-get-state-cons-for-frame frame-or-window)
+         (copy-sequence pgtk-dnd-empty-state)))
+
+(defun pgtk-dnd-maybe-call-test-function (window action)
+  "Call `pgtk-dnd-test-function' if something has changed.
+WINDOW is the window the mouse is over.  ACTION is the suggested
+action from the source.  If nothing has changed, return the last
+action and type we got from `pgtk-dnd-test-function'."
+  (let ((buffer (when (window-live-p window)
+                 (window-buffer window)))
+       (current-state (pgtk-dnd-get-state-for-frame window)))
+    (unless (and (equal buffer (aref current-state 0))
+                 (equal window (aref current-state 1))
+                 (equal action (aref current-state 3)))
+      (save-current-buffer
+       (when buffer (set-buffer buffer))
+       (let* ((action-type (funcall pgtk-dnd-test-function
+                                    window
+                                    action
+                                    (aref current-state 2)))
+              (handler (cdr (assoc (cdr action-type) pgtk-dnd-types-alist))))
+         ;; Ignore action-type if we have no handler.
+         (setq current-state
+               (pgtk-dnd-save-state window
+                                 action
+                                 (when handler action-type)))))))
+  (let ((current-state (pgtk-dnd-get-state-for-frame window)))
+    (cons (aref current-state 5)
+         (aref current-state 4))))
+
+(defun pgtk-dnd-save-state (window action action-type &optional types 
extra-data)
+  "Save the state of the current drag and drop.
+WINDOW is the window the mouse is over.  ACTION is the action suggested
+by the source.  ACTION-TYPE is the result of calling `pgtk-dnd-test-function'.
+If given, TYPES are the types for the drop data that the source supports.
+EXTRA-DATA is data needed for a specific protocol."
+  (let ((current-state (pgtk-dnd-get-state-for-frame window)))
+    (aset current-state 5 (car action-type))
+    (aset current-state 4 (cdr action-type))
+    (aset current-state 3 action)
+    (when types (aset current-state 2 types))
+    (when extra-data (aset current-state 6 extra-data))
+    (aset current-state 1 window)
+    (aset current-state 0 (and (window-live-p window) (window-buffer window)))
+    (setcdr (pgtk-dnd-get-state-cons-for-frame window) current-state)))
+
+
+(defun pgtk-dnd-handle-moz-url (window action data)
+  "Handle one item of type text/x-moz-url.
+WINDOW is the window where the drop happened.  ACTION is ignored.
+DATA is the moz-url, which is formatted as two strings separated by \\r\\n.
+The first string is the URL, the second string is the title of that URL.
+DATA is encoded in utf-16.  Decode the URL and call 
`pgtk-dnd-handle-uri-list'."
+  ;; Mozilla and applications based on it use text/unicode, but it is
+  ;; impossible to tell if it is le or be.  Use what the machine Emacs
+  ;; runs on uses.  This loses if dropping between machines
+  ;; with different endian-ness, but it is the best we can do.
+  (let* ((coding (if (eq (byteorder) ?B) 'utf-16be 'utf-16le))
+        (string (decode-coding-string data coding))
+        (strings (split-string string "[\r\n]" t))
+        ;; Can one drop more than one moz-url ??  Assume not.
+        (url (car strings)))
+    (pgtk-dnd-handle-uri-list window action url)))
+
+(defun pgtk-dnd-insert-utf8-text (window action text)
+  "Decode the UTF-8 text and insert it at point.
+TEXT is the text as a string, WINDOW is the window where the drop happened."
+  (dnd-insert-text window action (decode-coding-string text 'utf-8)))
+
+(defun pgtk-dnd-insert-utf16-text (window action text)
+  "Decode the UTF-16 text and insert it at point.
+TEXT is the text as a string, WINDOW is the window where the drop happened."
+  ;; See comment in pgtk-dnd-handle-moz-url about coding.
+  (let ((coding (if (eq (byteorder) ?B) 'utf-16be 'utf-16le)))
+    (dnd-insert-text window action (decode-coding-string text coding))))
+
+(defun pgtk-dnd-insert-ctext (window action text)
+  "Decode the compound text and insert it at point.
+TEXT is the text as a string, WINDOW is the window where the drop happened."
+  (dnd-insert-text window action
+                  (decode-coding-string text
+                                        'compound-text-with-extensions)))
+
+(defun pgtk-dnd-handle-uri-list (window action string)
+  "Split an uri-list into separate URIs and call `dnd-handle-one-url'.
+WINDOW is the window where the drop happened.
+STRING is the uri-list as a string.  The URIs are separated by \\r\\n."
+  (let ((uri-list (split-string string "[\0\r\n]" t))
+       retval)
+    (dolist (bf uri-list)
+      ;; If one URL is handled, treat as if the whole drop succeeded.
+      (let ((did-action (dnd-handle-one-url window action bf)))
+       (when did-action (setq retval did-action))))
+    retval))
+
+(defun pgtk-dnd-handle-file-name (window action string)
+  "Convert file names to URLs and call `dnd-handle-one-url'.
+WINDOW is the window where the drop happened.
+STRING is the file names as a string, separated by nulls."
+  (let ((uri-list (split-string string "[\0\r\n]" t))
+       (coding (or file-name-coding-system
+                   default-file-name-coding-system))
+       retval)
+    (dolist (bf uri-list)
+      ;; If one URL is handled, treat as if the whole drop succeeded.
+      (if coding (setq bf (encode-coding-string bf coding)))
+      (let* ((file-uri (concat "file://"
+                              (mapconcat 'url-hexify-string
+                                         (split-string bf "/") "/")))
+            (did-action (dnd-handle-one-url window action file-uri)))
+       (when did-action (setq retval did-action))))
+    retval))
+
+
+(defun pgtk-dnd-choose-type (types &optional known-types)
+  "Choose which type we want to receive for the drop.
+TYPES are the types the source of the drop offers, a vector of type names
+as strings or symbols.  Select among the types in `pgtk-dnd-known-types' or
+KNOWN-TYPES if given, and return that type name.
+If no suitable type is found, return nil."
+  (let* ((known-list (or known-types pgtk-dnd-known-types))
+        (first-known-type (car known-list))
+        (types-array types)
+        (found (when first-known-type
+                 (catch 'done
+                   (dotimes (i (length types-array))
+                     (let* ((type (aref types-array i))
+                            (typename (if (symbolp type)
+                                          (symbol-name type) type)))
+                       (when (equal first-known-type typename)
+                         (throw 'done first-known-type))))
+                   nil))))
+
+    (if (and (not found) (cdr known-list))
+       (pgtk-dnd-choose-type types (cdr known-list))
+      found)))
+
+(defun pgtk-dnd-drop-data (event frame window data type)
+  "Drop one data item onto a frame.
+EVENT is the client message for the drop, FRAME is the frame the drop
+occurred on.  WINDOW is the window of FRAME where the drop happened.
+DATA is the data received from the source, and type is the type for DATA,
+see `pgtk-dnd-types-alist').
+
+Returns the action used (move, copy, link, private) if drop was successful,
+nil if not."
+  (let* ((type-info (assoc type pgtk-dnd-types-alist))
+        (handler (cdr type-info))
+        (state (pgtk-dnd-get-state-for-frame frame))
+        (action (aref state 5))
+        (w (posn-window (event-start event))))
+    (when handler
+      (if (and (window-live-p w)
+              (not (window-minibuffer-p w))
+              (not (window-dedicated-p w)))
+         ;; If dropping in an ordinary window which we could use,
+         ;; let dnd-open-file-other-window specify what to do.
+         (progn
+           (when (and (not mouse-yank-at-point)
+                       ;; If dropping on top of the mode line, insert
+                       ;; the text at point instead.
+                       (posn-point (event-start event)))
+             (goto-char (posn-point (event-start event))))
+           (funcall handler window action data))
+       ;; If we can't display the file here,
+       ;; make a new window for it.
+       (let ((dnd-open-file-other-window t))
+         (select-frame frame)
+         (funcall handler window action data))))))
+
+(defun pgtk-dnd-handle-drag-n-drop-event (event)
+  "Receive drag and drop events (X client messages).
+Currently XDND, Motif and old KDE 1.x protocols are recognized."
+  (interactive "e")
+  (let* ((client-message (car (cdr (cdr event))))
+        (window (posn-window (event-start event)))
+         (frame (if (framep window)
+                    window
+                  (window-frame window))))
+    (pgtk-dnd-handle-gdk event frame window client-message)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;  GDK protocol.
+
+(declare-function pgtk-update-drop-status "pgtkselect.c")
+(declare-function pgtk-drop-finish "pgtkselect.c")
+
+(defvar pgtk-dnd-clear-data-on-motion nil
+  "Whether or not to obtain the new list of targets upon the next drag motion.
+For more details, see the function `pgtk-dnd-handle-gdk'.")
+
+(defun pgtk-dnd-handle-gdk (event frame window client-message)
+  "Handle drag-n-drop EVENT on FRAME.
+WINDOW should be the window the event happened on top of.
+CLIENT-MESSAGE is the detailed description of the drag-and-drop
+message."
+  (cond
+   ;; We can't handle `drag-leave' immediately, since that signal is
+   ;; also sent right before `drag-drop', and there is no reliable way
+   ;; to distinguish a signal sent because the source left from one
+   ;; sent prior to a drop.  Instead, set a flag that tells Emacs to
+   ;; clear the drag-and-drop state if anything other than a drop is
+   ;; received.
+   ((not client-message) ; drag-leave
+    (setq pgtk-dnd-clear-data-on-motion t))
+   ((eq (car client-message) 'lambda) ; drag-motion
+    (let ((state (pgtk-dnd-get-state-for-frame frame)))
+      (unless (and (aref state 0) ;; This is actually an entry.
+                   (not pgtk-dnd-clear-data-on-motion))
+        (setq pgtk-dnd-clear-data-on-motion nil)
+        ;; Forget the drop first, or else the list of targets will not
+        ;; be cleared if it is nil.
+        (pgtk-dnd-forget-drop window)
+        (pgtk-dnd-save-state window nil nil
+                             (pgtk-get-selection-internal
+                              (nth 1 client-message) 'TARGETS)
+                             t)
+        (setq state (pgtk-dnd-get-state-for-frame frame)))
+      (let* ((action (nth 3 client-message))
+             (time (nth 2 client-message))
+             (action-type (pgtk-dnd-maybe-call-test-function window
+                                                             action)))
+        ;; Get the selection contents now.  GdkWaylandSelection
+        ;; becomes unavailable immediately after `drag-drop' is sent.
+        (let* ((current-type (pgtk-dnd-current-type window))
+               (current-action-type (car-safe (aref state 6))))
+          (when (and current-type
+                     (not (equal current-action-type action-type)))
+            (aset state 6 (cons action-type
+                                (pgtk-get-selection-internal
+                                 (nth 1 client-message)
+                                 (intern current-type))))))
+        (pgtk-update-drop-status (car action-type) time)
+        (dnd-handle-movement (event-start event)))))
+   ((eq (car client-message) 'quote) ; drag-drop
+    (let* ((state (pgtk-dnd-get-state-for-frame frame))
+           (timestamp (nth 2 client-message))
+           (value (and (pgtk-dnd-current-type window)
+                       (or (cdr-safe (aref state 6))
+                           (pgtk-get-selection-internal
+                            (nth 1 client-message)
+                            (intern (pgtk-dnd-current-type window))
+                            timestamp))))
+           action)
+      (unwind-protect
+          (setq action (when value
+                         (condition-case info
+                            (pgtk-dnd-drop-data
+                              event frame window value
+                             (pgtk-dnd-current-type window))
+                          (error
+                           (message "Error: %s" info)
+                           nil))))
+        (pgtk-drop-finish action timestamp (eq action 'move))
+        (pgtk-dnd-forget-drop window))))))
+
+(provide 'pgtk-dnd)
+
+;;; pgtk-dnd.el ends here
diff --git a/lisp/pixel-scroll.el b/lisp/pixel-scroll.el
index fc7e680c26..167cb4fabe 100644
--- a/lisp/pixel-scroll.el
+++ b/lisp/pixel-scroll.el
@@ -570,11 +570,12 @@ the height of the current window."
                                  (window-header-line-height)
                                  (- max-y delta))))
          (point (posn-point posn))
-         (up-point (save-excursion
-                     (goto-char point)
-                     (vertical-motion (- (1+ scroll-margin)))
-                     (point))))
-    (when (> (point) up-point)
+         (up-point (and point
+                        (save-excursion
+                          (goto-char point)
+                          (vertical-motion (- (1+ scroll-margin)))
+                          (point)))))
+    (when (and point (> (point) up-point))
       (when (let ((pos-visible (pos-visible-in-window-p up-point nil t)))
               (or (eq (length pos-visible) 2)
                   (when-let* ((posn (posn-at-point up-point))
@@ -665,10 +666,11 @@ window being scrolled by DELTA pixels with an animation."
   "Scroll the current window up by DELTA pixels."
   (let ((max-height (- (window-text-height nil t)
                        (frame-char-height))))
-    (while (> delta max-height)
-      (pixel-scroll-precision-scroll-up-page max-height)
-      (setq delta (- delta max-height)))
-    (pixel-scroll-precision-scroll-up-page delta)))
+    (when (> max-height 0)
+      (while (> delta max-height)
+        (pixel-scroll-precision-scroll-up-page max-height)
+        (setq delta (- delta max-height)))
+      (pixel-scroll-precision-scroll-up-page delta))))
 
 ;; FIXME: This doesn't _always_ work when there's an image above the
 ;; current line that is taller than the window, and scrolling can
@@ -759,6 +761,10 @@ It is a vector of the form [ VELOCITY TIME SIGN ]."
   (interactive "e")
   (when pixel-scroll-precision-use-momentum
     (let ((window (mwheel-event-window event))
+          ;; The animations are smoother if the GC threshold is
+          ;; reduced for the duration of the animation.
+          (gc-cons-threshold (min most-positive-fixnum
+                                  (* gc-cons-threshold 3)))
           (state nil))
       (when (framep window)
         (setq window (frame-selected-window window)))
@@ -767,43 +773,43 @@ It is a vector of the form [ VELOCITY TIME SIGN ]."
                  (listp (aref state 0)))
         (condition-case nil
             (while-no-input
-              (unwind-protect (progn
-                                (aset state 0 (pixel-scroll-calculate-velocity 
state))
-                                (when (> (abs (aref state 0))
-                                         
pixel-scroll-precision-momentum-min-velocity)
-                                  (let* ((velocity (aref state 0))
-                                         (original-velocity velocity)
-                                         (time-spent 0))
-                                    (if (> velocity 0)
-                                        (while (and (> velocity 0)
-                                                    (<= time-spent
-                                                        
pixel-scroll-precision-momentum-seconds))
-                                          (when (> (round velocity) 0)
-                                            (with-selected-window window
-                                              
(pixel-scroll-precision-scroll-up (round velocity))))
-                                          (setq velocity (- velocity
-                                                            (/ 
original-velocity
-                                                               (/ 
pixel-scroll-precision-momentum-seconds
-                                                                  
pixel-scroll-precision-momentum-tick))))
-                                          (redisplay t)
-                                          (sit-for 
pixel-scroll-precision-momentum-tick)
-                                          (setq time-spent (+ time-spent
-                                                              
pixel-scroll-precision-momentum-tick))))
-                                    (while (and (< velocity 0)
-                                                (<= time-spent
-                                                    
pixel-scroll-precision-momentum-seconds))
-                                      (when (> (round (abs velocity)) 0)
-                                        (with-selected-window window
-                                          (pixel-scroll-precision-scroll-down 
(round
-                                                                               
(abs velocity)))))
-                                      (setq velocity (+ velocity
-                                                        (/ (abs 
original-velocity)
-                                                           (/ 
pixel-scroll-precision-momentum-seconds
-                                                              
pixel-scroll-precision-momentum-tick))))
-                                      (redisplay t)
-                                      (sit-for 
pixel-scroll-precision-momentum-tick)
-                                      (setq time-spent (+ time-spent
-                                                          
pixel-scroll-precision-momentum-tick))))))
+              (unwind-protect
+                  (progn
+                    (aset state 0 (pixel-scroll-calculate-velocity state))
+                    (when (> (abs (aref state 0))
+                             pixel-scroll-precision-momentum-min-velocity)
+                      (let* ((velocity (aref state 0))
+                             (original-velocity velocity)
+                             (time-spent 0))
+                        (if (> velocity 0)
+                            (while (and (> velocity 0)
+                                        (<= time-spent
+                                            
pixel-scroll-precision-momentum-seconds))
+                              (when (> (round velocity) 0)
+                                (with-selected-window window
+                                  (pixel-scroll-precision-scroll-up (round 
velocity))))
+                              (setq velocity (- velocity
+                                                (/ original-velocity
+                                                   (/ 
pixel-scroll-precision-momentum-seconds
+                                                      
pixel-scroll-precision-momentum-tick))))
+                              (sit-for pixel-scroll-precision-momentum-tick)
+                              (setq time-spent (+ time-spent
+                                                  
pixel-scroll-precision-momentum-tick))))
+                        (while (and (< velocity 0)
+                                    (<= time-spent
+                                        
pixel-scroll-precision-momentum-seconds))
+                          (when (> (round (abs velocity)) 0)
+                            (with-selected-window window
+                              (pixel-scroll-precision-scroll-down (round
+                                                                   (abs 
velocity)))))
+                          (setq velocity (+ velocity
+                                            (/ (abs original-velocity)
+                                               (/ 
pixel-scroll-precision-momentum-seconds
+                                                  
pixel-scroll-precision-momentum-tick))))
+                          (redisplay t)
+                          (sit-for pixel-scroll-precision-momentum-tick)
+                          (setq time-spent (+ time-spent
+                                              
pixel-scroll-precision-momentum-tick))))))
                 (aset state 0 (make-ring 30))
                 (aset state 1 nil)))
           (beginning-of-buffer
diff --git a/lisp/play/5x5.el b/lisp/play/5x5.el
index 8fe72ddf59..fb944f4d76 100644
--- a/lisp/play/5x5.el
+++ b/lisp/play/5x5.el
@@ -82,13 +82,6 @@
 
 ;; Non-customize variables.
 
-(defmacro 5x5-defvar-local (var value doc)
-  "Define VAR to VALUE with documentation DOC and make it buffer local."
-  (declare (obsolete defvar-local "28.1"))
-  `(progn
-     (defvar ,var ,value ,doc)
-     (make-variable-buffer-local (quote ,var))))
-
 (defvar-local 5x5-grid nil
   "5x5 grid contents.")
 
@@ -930,14 +923,15 @@ lest."
 
 ;; Support functions
 
-(define-obsolete-function-alias '5x5-xor 'xor "27.1")
-
 (defun 5x5-y-or-n-p (prompt)
   "5x5 wrapper for `y-or-n-p' which respects the `5x5-hassle-me' setting."
   (if 5x5-hassle-me
       (y-or-n-p prompt)
     t))
 
+(define-obsolete-function-alias '5x5-xor #'xor "27.1")
+(define-obsolete-function-alias '5x5-defvar-local #'defvar-local "28.1")
+
 (provide '5x5)
 
 ;;; 5x5.el ends here
diff --git a/lisp/play/bubbles.el b/lisp/play/bubbles.el
index 93fbc3b51b..808fc82d19 100644
--- a/lisp/play/bubbles.el
+++ b/lisp/play/bubbles.el
@@ -30,6 +30,8 @@
 ;; Bubbles is an implementation of the "Same Game", similar to "Same
 ;; GNOME" and many others, see <https://en.wikipedia.org/wiki/SameGame>.
 
+;;; Code:
+
 ;; ======================================================================
 
 ;;; History:
@@ -70,8 +72,6 @@
 
 ;; ======================================================================
 
-;;; Code:
-
 (require 'gamegrid)
 
 ;; User options
@@ -812,7 +812,7 @@ static char * dot3d_xpm[] = {
 (defvar-keymap bubbles-mode-map
   :doc "Mode map for `bubbles'."
   :name 'bubbles-mode-map
-  "q"   #'bubbles-quit
+  "q"   #'quit-window
   "C-j" #'bubbles-plop
   "SPC" #'bubbles-plop
   "C-m" #'bubbles-plop
@@ -871,7 +871,7 @@ static char * dot3d_xpm[] = {
     ["Save all settings" bubbles-save-settings]
     "---"
     ["New game" bubbles]
-    ["Quit" bubbles-quit]))
+    ["Quit" quit-window]))
 
 ;; bind menu to mouse
 (define-key bubbles-mode-map [down-mouse-3] bubbles-menu)
@@ -910,6 +910,7 @@ columns on its right towards the left.
 
 (defun bubbles-quit ()
   "Quit Bubbles."
+  (declare (obsolete quit-window "29.1"))
   (interactive nil bubbles-mode)
   (message "bubbles-quit")
   (bury-buffer))
diff --git a/lisp/play/cookie1.el b/lisp/play/cookie1.el
index fcdd2a7ce9..7ede8e358a 100644
--- a/lisp/play/cookie1.el
+++ b/lisp/play/cookie1.el
@@ -123,7 +123,8 @@ Emit STARTMSG and ENDMSG before and after.  Cache the 
result; second
 and subsequent calls on the same file won't go to disk."
   (setq phrase-file (cookie-check-file phrase-file))
   (let ((sym (intern-soft phrase-file cookie-cache)))
-    (and sym (not (equal (symbol-function sym)
+    (and sym (not (time-equal-p
+                        (symbol-function sym)
                         (file-attribute-modification-time
                           (file-attributes phrase-file))))
         (yes-or-no-p (concat phrase-file
diff --git a/lisp/play/decipher.el b/lisp/play/decipher.el
index bb3369de5f..c9bd8ea9fe 100644
--- a/lisp/play/decipher.el
+++ b/lisp/play/decipher.el
@@ -445,7 +445,7 @@ The most useful commands are:
       (let ((font-lock-fontify-region-function #'ignore))
         ;; insert-and-inherit will pick the right face automatically
         (while (search-forward-regexp "^:" nil t)
-          (setq bound (point-at-eol))
+          (setq bound (line-end-position))
           (while (search-forward cipher-string bound 'end)
             (decipher-insert plain-char)))))))
 
diff --git a/lisp/play/doctor.el b/lisp/play/doctor.el
index b93d768cbe..f87068e113 100644
--- a/lisp/play/doctor.el
+++ b/lisp/play/doctor.el
@@ -1,7 +1,6 @@
 ;;; doctor.el --- psychological help for frustrated users  -*- 
lexical-binding: t -*-
 
-;; Copyright (C) 1985, 1987, 1994, 1996, 2000-2022 Free Software
-;; Foundation, Inc.
+;; Copyright (C) 1985-2022 Free Software Foundation, Inc.
 
 ;; Maintainer: emacs-devel@gnu.org
 ;; Keywords: games
@@ -136,14 +135,14 @@ Like Text mode with Auto Fill mode
 except that RET when point is after a newline, or LFD at any time,
 reads the sentence before point, and prints the Doctor's answer."
   :interactive nil
-  (make-doctor-variables)
+  (doctor-make-variables)
   (turn-on-auto-fill)
   (doctor-type '(i am the psychotherapist \.
                 (doc$ doctor--please) (doc$ doctor--describe) your (doc$ 
doctor--problems) \.
                 each time you are finished talking\, type \R\E\T twice \.))
   (insert "\n"))
 
-(defun make-doctor-variables ()
+(defun doctor-make-variables ()
   (setq-local doctor--typos
               (mapcar (lambda (x)
                         (put (car x) 'doctor-correction  (cadr x))
@@ -1577,13 +1576,14 @@ Hack on previous word, setting global variable 
DOCTOR-OWNER to correct result."
                       (equal doctor-found 'killing))
                   (memq 'yourself doctor-sent)))
         (setq doctor--suicide-flag t)
-        (doctor-type '(If you are really suicidal\, you might
-                          want to contact the Samaritans via
-                          E-mail: jo@samaritans.org or\, at your option\,
-                          anonymous E-mail: samaritans@anon.twwells.com\ \.
-                           or find a Befrienders crisis center at
-                           https://www.befrienders.org/\ \.
-                          (doc$ doctor--please) (doc$ doctor--continue) \.)))
+         (doctor-type '( If you are really suicidal\, you might
+                         want to contact the Samaritans via
+                         e-mail: jo@samaritans.org \.
+                         or find a Befrienders crisis center at
+                         https://www.befrienders.org/\ \.
+                         you can also find other suicide crisis lines at
+                         
https://en.wikipedia.org/wiki/List_of_suicide_crisis_lines \.
+                         (doc$ doctor--please) (doc$ doctor--continue) \.)))
        (t (doctor-type (doc$ doctor--deathlst)))))
 
 (defun doctor-foul ()
@@ -1619,6 +1619,8 @@ Hack on previous word, setting global variable 
DOCTOR-OWNER to correct result."
 
 (defun doctor-chat () (doctor-type (doc$ doctor--chatlst)))
 
+(define-obsolete-function-alias 'make-doctor-variables #'doctor-make-variables 
"29.1")
+
 (provide 'doctor)
 
 ;;; doctor.el ends here
diff --git a/lisp/play/dunnet.el b/lisp/play/dunnet.el
index b859176bb4..94392901be 100644
--- a/lisp/play/dunnet.el
+++ b/lisp/play/dunnet.el
@@ -2324,7 +2324,7 @@ Also prints current score to let user know he has scored."
 ;;;;
 
 (define-key dun-mode-map "\r" 'dun-parse)
-(defvar dungeon-batch-map (make-keymap))
+(defvar-keymap dungeon-batch-map :full t)
 (let (n)
   (setq n 32)
   (while (< 0 (setq n (- n 1)))
diff --git a/lisp/play/fortune.el b/lisp/play/fortune.el
index 3bc51f6d68..0973f2bc5f 100644
--- a/lisp/play/fortune.el
+++ b/lisp/play/fortune.el
@@ -1,6 +1,6 @@
 ;;; fortune.el --- use fortune to create signatures  -*- lexical-binding: t -*-
 
-;; Copyright (C) 1999, 2001-2022 Free Software Foundation, Inc.
+;; Copyright (C) 1999-2022 Free Software Foundation, Inc.
 
 ;; Author: Holger Schauer <Holger.Schauer@gmx.de>
 ;; Keywords: games utils mail
@@ -21,38 +21,48 @@
 ;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 ;;; Commentary:
+
 ;; This utility allows you to automatically cut regions to a fortune
 ;; file.  In case that the region stems from an article buffer (mail or
 ;; news), it will try to automatically determine the author of the
-;; fortune.  It will also allow you to compile your fortune-database
+;; fortune.  It will also allow you to compile your fortune database
 ;; as well as providing a function to extract a fortune for use as your
 ;; signature.
+;;
 ;; Of course, it can simply display a fortune, too.
 ;; Use prefix arguments to specify different fortune databases.
-
+;;
 ;;; Installation:
-
-;; Please check the customize settings -- you will at least have to
-;; modify the values of `fortune-dir' and `fortune-file'.
-
+;;
+;; Please type `M-x customize-group RET fortune RET' -- you will at
+;; least have to modify the user options `fortune-dir' and
+;; `fortune-file'.
+;;
 ;; I then use this in my .gnus:
-;;(message "Making new signature: %s" (fortune-to-signature "~/fortunes/"))
+;;
+;;     (message "Making new signature: %s"
+;;              (fortune-to-signature "~/fortunes/"))
+;;
 ;; This automagically creates a new signature when starting up Gnus.
-;; Note that the call to fortune-to-signature specifies a directory in which
-;; several fortune-files and their databases are stored.
-
-;; If you like to get a new signature for every message, you can also hook
-;; it into message-mode:
-;; (add-hook 'message-setup-hook 'fortune-to-signature)
-;; This time no fortune-file is specified, so fortune-to-signature would use
-;; the default-file as specified by fortune-file.
-
-;; I have also this in my .gnus:
-;;(add-hook 'gnus-article-mode-hook
-;;       (lambda ()
-;;          (define-key gnus-article-mode-map "i" 'fortune-from-region)))
+;; Note that the call to `fortune-to-signature' specifies a directory
+;; in which several fortune files and their databases are stored.
+;;
+;; To get a new signature for every message, you can hook it into
+;; `message-mode':
+;;
+;;     (add-hook 'message-setup-hook #'fortune-to-signature)
+;;
+;; This time no fortune file is specified, so `fortune-to-signature'
+;; would use the default file as specified by `fortune-file'.
+;;
+;; I also have this in my .gnus:
+;;
+;;     (add-hook 'gnus-article-mode-hook
+;;               (lambda ()
+;;                 (define-key gnus-article-mode-map "i" 
#'fortune-from-region)))
+;;
 ;; which allows marking a region and then pressing "i" so that the marked
-;; region will be automatically added to my favorite fortune-file.
+;; region will be automatically added to my favorite fortune file.
 
 ;;; Code:
 
@@ -166,7 +176,7 @@ If INTERACTIVE is non-nil, don't compile the fortune file 
afterwards."
          (fortune-compile file)))))
 
 (defun fortune-ask-file ()
-  "Asks the user for a file-name."
+  "Ask the user for the file name of the fortune file."
   (expand-file-name
    (read-file-name
     "Fortune file to use: "
diff --git a/lisp/play/gamegrid.el b/lisp/play/gamegrid.el
index 55c9244f2e..8cff67c5bc 100644
--- a/lisp/play/gamegrid.el
+++ b/lisp/play/gamegrid.el
@@ -1,6 +1,6 @@
 ;;; gamegrid.el --- library for implementing grid-based games on Emacs  -*- 
lexical-binding:t -*-
 
-;; Copyright (C) 1997-1998, 2001-2022 Free Software Foundation, Inc.
+;; Copyright (C) 1997-2022 Free Software Foundation, Inc.
 
 ;; Author: Glynn Clements <glynn@sensei.co.uk>
 ;; Old-Version: 1.02
@@ -72,7 +72,7 @@ directory will be used.")
 (defvar gamegrid-mono-x-face nil)
 (defvar gamegrid-mono-tty-face nil)
 
-(defvar gamegrid-glyph-height-mm 7.0
+(defvar gamegrid-glyph-height-mm 5.0
   "Desired glyph height in mm.")
 
 ;; ;;;;;;;;;;;;; glyph generation ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -80,12 +80,24 @@ directory will be used.")
 (defun gamegrid-calculate-glyph-size ()
   "Calculate appropriate glyph size in pixels based on display resolution.
 Return a multiple of 8 no less than 16."
-  (if (and (display-pixel-height) (display-mm-height))
-      (let* ((y-pitch (/ (display-pixel-height) (float (display-mm-height))))
-             (pixels (* y-pitch gamegrid-glyph-height-mm))
-             (rounded (* (floor (/ (+ pixels 4) 8)) 8)))
-        (max 16 rounded))
-    16))
+  (let (atts
+        y-pitch)
+    (dolist (mon (display-monitor-attributes-list))
+      (when-let ((frames (alist-get 'frames mon))
+                 (match (memq (selected-frame) frames)))
+        (setq atts mon)))
+    (setq y-pitch (cond
+                   (atts
+                    (/ (nth 4 (assq 'geometry atts))
+                       (nth 2 (assq 'mm-size atts))
+                       (or (cdr (assq 'scale-factor atts)) 1.0)))
+                   ((and (display-pixel-height) (display-mm-height))
+                    (/ (display-pixel-height) (float (display-mm-height))))))
+    (if y-pitch
+        (let* ((pixels (* y-pitch gamegrid-glyph-height-mm))
+               (rounded (* (floor (/ (+ pixels 4) 8)) 8)))
+          (max 16 rounded))
+      16)))
 
 ;; Example of glyph in XPM format:
 ;;
@@ -251,7 +263,7 @@ format."
   (set-face-foreground face color)
   (set-face-background face color)
   (gamegrid-set-font face)
-  (set-face-background-pixmap face nil))
+  (set-face-stipple face nil))
 
 (defun gamegrid-make-mono-tty-face ()
   (let ((face (make-face 'gamegrid-mono-tty-face)))
@@ -335,8 +347,11 @@ format."
           (gamegrid-match-spec-list (cdr spec-list)))))
 
 (defun gamegrid-make-glyph (data-spec-list color-spec-list)
+  ;; image.el is not preloaded in --without-x builds.
+  (defvar image-scaling-factor)
   (let ((data (gamegrid-match-spec-list data-spec-list))
-       (color (gamegrid-match-spec-list color-spec-list)))
+       (color (gamegrid-match-spec-list color-spec-list))
+        (image-scaling-factor 1.0))
     (cond ((characterp data)
           (vector data))
          ((eq data 'colorize)
@@ -458,6 +473,7 @@ convert to an Emacs image-spec instead")
     ;; Adjust the height of the default face to the height of the
     ;; images. Unlike XEmacs, Emacs doesn't allow making the default
     ;; face buffer-local; so we do this with an overlay.
+    ;; FIXME: This is not correct.  See face-remap.el.
     (when (eq gamegrid-display-mode 'glyph)
       (overlay-put (make-overlay (point-min) (point-max))
                   'face gamegrid-face))
diff --git a/lisp/play/gomoku.el b/lisp/play/gomoku.el
index f8822c30db..fee242be98 100644
--- a/lisp/play/gomoku.el
+++ b/lisp/play/gomoku.el
@@ -161,11 +161,12 @@ SHOULD be at least 2 (MUST BE at least 1).")
   "For making font-lock use the winner's face for the line.")
 
 (defface gomoku-O
-    '((((class color)) (:foreground "red" :weight bold)))
+  '((((class color)) :foreground "red" :weight bold))
   "Face to use for Emacs's O.")
 
 (defface gomoku-X
-    '((((class color)) (:foreground "green" :weight bold)))
+  '((((background light)) :foreground "blue" :weight bold)
+    (((class color)) :foreground "green" :weight bold))
   "Face to use for your X.")
 
 (defvar gomoku-font-lock-keywords
diff --git a/lisp/play/hanoi.el b/lisp/play/hanoi.el
index 227dd790af..58fb82b6ed 100644
--- a/lisp/play/hanoi.el
+++ b/lisp/play/hanoi.el
@@ -73,7 +73,7 @@
   "Non-nil means that hanoi poles are oriented horizontally."
   :type 'boolean)
 
-(defcustom hanoi-move-period 1.0
+(defcustom hanoi-move-period 1
   "Time, in seconds, for each pole-to-pole move of a ring.
 If nil, move rings as fast as possible while displaying all
 intermediate positions."
@@ -112,35 +112,32 @@ intermediate positions."
             (prefix-numeric-value current-prefix-arg))))
   (if (< nrings 0)
       (error "Negative number of rings"))
-  (hanoi-internal nrings (make-list nrings 0) (float-time)))
+  (hanoi-internal nrings (make-list nrings 0) (time-convert nil 'integer)))
 
 ;;;###autoload
 (defun hanoi-unix ()
-  "Towers of Hanoi, UNIX doomsday version.
-Displays 32-ring towers that have been progressing at one move per
-second since 1970-01-01 00:00:00 GMT.
+  "Towers of Hanoi, 32-bit UNIX doomsday version.
+Display 32-ring towers that have been progressing at one move per
+second since 1970-01-01 00:00:00 UTC.
 
 Repent before ring 31 moves."
   (interactive)
-  (let* ((start (ftruncate (float-time)))
-        (bits (cl-loop repeat 32
-                        for x = (/ start (expt 2.0 31)) then (* x 2.0)
-                        collect (truncate (mod x 2.0))))
-        (hanoi-move-period 1.0))
+  (let* ((start (time-convert nil 'integer))
+        (bits (nreverse (cl-loop repeat 32
+                                 for x = start then (ash x -1)
+                                 collect (logand x 1))))
+        (hanoi-move-period 1))
     (hanoi-internal 32 bits start)))
 
 ;;;###autoload
 (defun hanoi-unix-64 ()
-  "Like `hanoi-unix', but pretend to have a 64-bit clock.
-This is, necessarily (as of Emacs 20.3), a crock.  When the
-`current-time' interface is made s2G-compliant, hanoi.el will need
-to be updated."
+  "Like `hanoi-unix', but with a 64-bit clock."
   (interactive)
-  (let* ((start (ftruncate (float-time)))
-        (bits (cl-loop repeat 64
-                        for x = (/ start (expt 2.0 63)) then (* x 2.0)
-                        collect (truncate (mod x 2.0))))
-        (hanoi-move-period 1.0))
+  (let* ((start (time-convert nil 'integer))
+        (bits (nreverse (cl-loop repeat 64
+                                 for x = start then (ash x -1)
+                                 collect (logand x 1))))
+        (hanoi-move-period 1))
     (hanoi-internal 64 bits start)))
 
 (defun hanoi-internal (nrings bits start-time)
@@ -378,9 +375,10 @@ BITS must be of length nrings.  Start at START-TIME."
                    (/ (- tick flyward-ticks fly-ticks)
                       ticks-per-pole-step))))))))
     (if hanoi-move-period
-       (cl-loop for elapsed = (- (float-time) start-time)
-                 while (< elapsed hanoi-move-period)
-                 with tick-period = (/ (float hanoi-move-period) total-ticks)
+       (cl-loop for elapsed = (float-time (time-subtract nil start-time))
+                while (time-less-p elapsed hanoi-move-period)
+                with tick-period = (/ (float-time hanoi-move-period)
+                                      total-ticks)
                 for tick = (ceiling elapsed tick-period) do
                  (hanoi-ring-to-pos ring (funcall tick-to-pos tick))
                  (hanoi-sit-for (- (* tick tick-period) elapsed)))
@@ -389,7 +387,7 @@ BITS must be of length nrings.  Start at START-TIME."
                (hanoi-sit-for 0)))
     ;; Always make last move to keep pole and ring data consistent
     (hanoi-ring-to-pos ring (car to))
-    (if hanoi-move-period (+ start-time hanoi-move-period))))
+    (if hanoi-move-period (time-add start-time hanoi-move-period))))
 
 ;; update display and pause, quitting with a pithy comment if the user
 ;; hits a key.
diff --git a/lisp/play/mpuz.el b/lisp/play/mpuz.el
index 1cacf01a20..177b6eecf0 100644
--- a/lisp/play/mpuz.el
+++ b/lisp/play/mpuz.el
@@ -156,7 +156,7 @@ You may abort a game by typing 
\\<mpuz-mode-map>\\[mpuz-offer-abort]."
 
 
 ;; A puzzle also uses a board displaying a multiplication.
-;; Every digit appears in the board, crypted or not.
+;; Every digit appears in the board, encrypted or not.
 ;;------------------------------------------------------
 (defvar mpuz-board (make-vector 10 nil)
   "The board associates to any digit the list of squares where it appears.")
diff --git a/lisp/play/spook.el b/lisp/play/spook.el
index f2bdba1c2a..ccff2e75b0 100644
--- a/lisp/play/spook.el
+++ b/lisp/play/spook.el
@@ -49,7 +49,7 @@
 
 (defcustom spook-phrase-default-count 15
   "Default number of phrases to insert."
-  :type 'integer)
+  :type 'natnum)
 
 ;;;###autoload
 (defun spook ()
diff --git a/lisp/play/tetris.el b/lisp/play/tetris.el
index 8ce2453c75..a6bfea81ee 100644
--- a/lisp/play/tetris.el
+++ b/lisp/play/tetris.el
@@ -95,27 +95,34 @@ If the return value is a number, it is used as the timer 
period."
 
 (defcustom tetris-buffer-width 30
   "Width of used portion of buffer."
-  :type 'number)
+  :type 'natnum)
 
 (defcustom tetris-buffer-height 22
   "Height of used portion of buffer."
-  :type 'number)
+  :type 'natnum)
 
 (defcustom tetris-width 10
   "Width of playing area."
-  :type 'number)
+  :type 'natnum)
 
 (defcustom tetris-height 20
   "Height of playing area."
-  :type 'number)
+  :type 'natnum)
 
 (defcustom tetris-top-left-x 3
   "X position of top left of playing area."
-  :type 'number)
+  :type 'natnum)
 
 (defcustom tetris-top-left-y 1
   "Y position of top left of playing area."
-  :type 'number)
+  :type 'natnum)
+
+(defcustom tetris-allow-repetitions t
+  "If non-nil, use a random selection for each shape.
+If nil, put the shapes into a bag and select without putting
+back (until empty, when the bag is repopulated."
+  :type 'boolean
+  :version "29.1")
 
 (defvar tetris-next-x (+ (* 2 tetris-top-left-x) tetris-width)
   "X position of next shape.")
@@ -233,6 +240,7 @@ each one of its four blocks.")
 (defvar-local tetris-pos-x 0)
 (defvar-local tetris-pos-y 0)
 (defvar-local tetris-paused nil)
+(defvar-local tetris--bag nil)
 
 ;; ;;;;;;;;;;;;; keymaps ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
@@ -341,10 +349,23 @@ each one of its four blocks.")
   (let ((period (tetris-get-tick-period)))
     (if period (gamegrid-set-timer period))))
 
+(defun tetris--shuffle (sequence)
+  (cl-loop for i from (length sequence) downto 2
+           do (cl-rotatef (elt sequence (random i))
+                          (elt sequence (1- i))))
+  sequence)
+
+(defun tetris--seven-bag ()
+  (when (not tetris--bag)
+    (setq tetris--bag (tetris--shuffle (list 0 1 2 3 4 5 6))))
+  (pop tetris--bag))
+
 (defun tetris-new-shape ()
   (setq tetris-shape tetris-next-shape)
   (setq tetris-rot 0)
-  (setq tetris-next-shape (random 7))
+  (setq tetris-next-shape (if tetris-allow-repetitions
+                              (random 7)
+                            (tetris--seven-bag)))
   (setq tetris-pos-x (/ (- tetris-width (tetris-shape-width)) 2))
   (setq tetris-pos-y 0)
   (if (tetris-test-shape)
diff --git a/lisp/plstore.el b/lisp/plstore.el
index b37d39ce1b..de3f828016 100644
--- a/lisp/plstore.el
+++ b/lisp/plstore.el
@@ -107,6 +107,7 @@ symmetric encryption will be used."
   :type '(choice (const nil) (repeat :tag "Recipient(s)" string))
   :group 'plstore)
 
+;;;###autoload
 (put 'plstore-encrypt-to 'safe-local-variable
      (lambda (val)
        (or (stringp val)
diff --git a/lisp/printing.el b/lisp/printing.el
index b9bc3581c4..d10de24e03 100644
--- a/lisp/printing.el
+++ b/lisp/printing.el
@@ -4,16 +4,9 @@
 
 ;; Author: Vinicius Jose Latorre <viniciusjl.gnu@gmail.com>
 ;; Keywords: wp, print, PostScript
-;; Version: 6.9.3
+;; Old-Version: 6.9.3
 ;; URL: https://www.emacswiki.org/cgi-bin/wiki/ViniciusJoseLatorre
 
-(defconst pr-version "6.9.3"
-  "printing.el, v 6.9.3 <2007/12/09 vinicius>
-
-Please send all bug fixes and enhancements to
-       bug-gnu-emacs@gnu.org and Vinicius Jose Latorre 
<viniciusjl.gnu@gmail.com>
-")
-
 ;; This file is part of GNU Emacs.
 
 ;; GNU Emacs is free software: you can redistribute it and/or modify
@@ -63,10 +56,6 @@ Please send all bug fixes and enhancements to
 ;; spool and to despool PostScript buffer.  So, `printing' provides an
 ;; interface to ps-print package and it also provides some extra stuff.
 ;;
-;; To download the latest ps-print package see
-;; `https://www.emacswiki.org/cgi-bin/wiki/PsPrintPackage'.
-;; Please, see README file for ps-print installation instructions.
-;;
 ;; `printing' was inspired by:
 ;;
 ;;    print-nt.el            Frederic Corne <frederic.corne@erli.fr>
@@ -942,11 +931,6 @@ Please send all bug fixes and enhancements to
 ;;
 ;; Below are some URL where you can find good utilities.
 ;;
-;; * For `printing' package:
-;;
-;;    printing `https://www.emacswiki.org/cgi-bin/emacs/download/printing.el'
-;;    ps-print `https://www.emacswiki.org/cgi-bin/wiki/PsPrintPackage'
-;;
 ;; * For GNU or Unix system:
 ;;
 ;;    gs, gv         
`https://www.gnu.org/software/ghostscript/ghostscript.html'
@@ -1015,10 +999,6 @@ Please send all bug fixes and enhancements to
 (require 'lpr)
 (require 'ps-print)
 
-(and (string< ps-print-version "6.6.4")
-     (error "`printing' requires `ps-print' package version 6.6.4 or later"))
-
-
 (defconst pr-cygwin-system
   (and lpr-windows-system (getenv "OSTYPE")
        (string-match "cygwin" (getenv "OSTYPE"))))
@@ -2782,7 +2762,7 @@ See `pr-ps-printer-alist'.")
       ["4-up"     (pr-ps-buffer-preview 4   t) t]
       ["Other..." (pr-ps-buffer-preview nil t)
        :keys "\\[pr-ps-buffer-preview]"])
-     ("Region" :active (and (not pr-spool-p) (ps-mark-active-p))
+     ("Region" :active (and (not pr-spool-p) mark-active)
       ["1-up"     (pr-ps-region-preview 1   t) t]
       ["2-up"     (pr-ps-region-preview 2   t) t]
       ["4-up"     (pr-ps-region-preview 4   t) t]
@@ -2837,7 +2817,7 @@ See `pr-ps-printer-alist'.")
       ["4-up"     (pr-ps-buffer-ps-print 4   t) t]
       ["Other..." (pr-ps-buffer-ps-print nil t)
        :keys "\\[pr-ps-buffer-ps-print]"])
-     ("Region" :active (ps-mark-active-p)
+     ("Region" :active mark-active
       ["1-up"     (pr-ps-region-ps-print 1   t) t]
       ["2-up"     (pr-ps-region-ps-print 2   t) t]
       ["4-up"     (pr-ps-region-ps-print 4   t) t]
@@ -2887,12 +2867,12 @@ See `pr-ps-printer-alist'.")
      "Replace non-printing chars with printable representations."
      ["Directory" pr-printify-directory t]
      ["Buffer"    pr-printify-buffer    t]
-     ["Region"    pr-printify-region    (ps-mark-active-p)])
+     ["Region"    pr-printify-region    mark-active])
     ("Print" :included (pr-visible-p 'text)
      :help "Send text to printer"
      ["Directory" pr-txt-directory t]
      ["Buffer"    pr-txt-buffer    t]
-     ["Region"    pr-txt-region    (ps-mark-active-p)]
+     ["Region"    pr-txt-region    mark-active]
      ["Mode"      pr-txt-mode      (pr-mode-alist-p)])
     ["Text Printers" pr-update-menus
      :active pr-txt-printer-alist :included (pr-visible-p 'text)
@@ -3007,9 +2987,7 @@ Calls `pr-update-menus' to adjust menus."
 
 
 (defconst pr-help-message
-  (concat "printing.el version " pr-version
-         "    ps-print.el version " ps-print-version
-         "\n\n
+  "\
 Menu Layout
 -----------
 
@@ -3062,7 +3040,7 @@ A. Interface:
 
 I. PostScript printing:
 
-   1. You can generate a PostScript file (if you type C-u before activating
+   1. You can generate a PostScript file (if you type \\[universal-argument] 
before activating
       menu) or PostScript temporary file for a directory, a buffer, a region
       or a major mode, choosing 1-up, 2-up, 4-up or any other n-up printing;
       after file generation, ghostview is activated using the file generated
@@ -3102,7 +3080,7 @@ I. PostScript printing:
              `pr-ps-utility-alist'.
 
    2. Operate the same way as option 1, but it sends directly the PostScript
-      code (or put in a file, if you've typed C-u) or it uses ghostscript to
+      code (or put in a file, if you've typed \\[universal-argument]) or it 
uses ghostscript to
       print the PostScript file generated.  It depends on option 18, if it's
       turned on, it uses ghostscript; otherwise, it sends directly to
       printer.  If spooling is on (option 16), the PostScript code is saved
@@ -3111,7 +3089,7 @@ I. PostScript printing:
       Instead of printing each buffer, region or major mode at once, you can
       save temporarily the PostScript code generated in a buffer and print it
       later.  The option `Despool...' despools the PostScript spooling buffer
-      directly on a printer.  If you type C-u before choosing this option,
+      directly on a printer.  If you type \\[universal-argument] before 
choosing this option,
       the PostScript code generated is saved in a file instead of sending it to
       the printer.  To spool the PostScript code generated you need to turn on
       option 16.  This option is enabled if spooling is on (option 16).
@@ -3215,14 +3193,12 @@ VI. Customization:
    23. Show current settings for `printing', `ps-print' or `lpr'.
 
    24. Quick help for printing menu layout.
-")
+"
   "Printing help message.")
 
 
 (defconst pr-interface-help-message
-  (concat "printing.el version " pr-version
-         "    ps-print.el version " ps-print-version
-         "\n\n
+  "\
 The printing interface buffer has the same functionality as the printing menu.
 The major difference is that the states (like sending PostScript generated to a
 file, n-up printing, etc.) are set and saved between printing buffer
@@ -3449,7 +3425,7 @@ The printing interface buffer has the following sections:
 
    Quick help for printing interface buffer and printing menu layout.  You can
    also quit the printing interface buffer or kill all printing help buffer.
-")
+"
   "Printing buffer interface help message.")
 
 
@@ -4207,7 +4183,8 @@ bottom."
 (defun pr-help (&rest _ignore)
   "Help for the printing package."
   (interactive)
-  (pr-show-setup pr-help-message "*Printing Help*"))
+  (pr-show-setup (substitute-command-keys pr-help-message)
+                 "*Printing Help*"))
 
 
 ;;;###autoload
@@ -4402,7 +4379,6 @@ Or choose the menu option Printing/Show 
Settings/printing."
     (mapconcat
      #'ps-print-quote
      (list
-      (concat "\n;;; printing.el version " pr-version "\n")
       ";; internal vars"
       (ps-comment-string "emacs-version       " emacs-version)
       (ps-comment-string "pr-txt-command      " pr-txt-command)
@@ -5061,7 +5037,8 @@ If menu binding was not done, calls `pr-menu-bind'."
 
 (defun pr-show-setup (settings buffer-name)
   (with-output-to-temp-buffer buffer-name
-    (princ settings)
+    (with-current-buffer buffer-name
+      (insert settings))
     (help-print-return-message)))
 
 
@@ -5585,7 +5562,7 @@ COMMAND.exe, COMMAND.bat and COMMAND.com in this order."
 (defun pr-create-interface ()
   "Create the front end for printing package."
   (setq pr-i-buffer (buffer-name (current-buffer))
-       pr-i-region (ps-mark-active-p)
+        pr-i-region mark-active
        pr-i-mode   (pr-mode-alist-p)
        pr-i-window-configuration (current-window-configuration))
 
@@ -5597,9 +5574,6 @@ COMMAND.exe, COMMAND.bat and COMMAND.com in this order."
   (switch-to-buffer (get-buffer-create pr-buffer-name))
 
   ;; header
-  (let ((versions (concat "printing v" pr-version
-                         "    ps-print v" ps-print-version)))
-    (widget-insert (make-string (- 79 (length versions)) ?\ ) versions))
   (pr-insert-italic "\nCurrent Directory : " 1)
   (pr-insert-italic default-directory)
 
@@ -5651,11 +5625,11 @@ COMMAND.exe, COMMAND.bat and COMMAND.com in this order."
                    (nreverse choices))
                  " Buffer : " nil
                  (lambda ()
-                    (pr-interface-save
-                     (setq pr-i-region (ps-mark-active-p)
-                           pr-i-mode   (pr-mode-alist-p)))
-                    (pr-update-checkbox 'pr-i-region)
-                    (pr-update-checkbox 'pr-i-mode)))
+                    (pr-interface-save
+                     (setq pr-i-region mark-active
+                           pr-i-mode   (pr-mode-alist-p)))
+                    (pr-update-checkbox 'pr-i-region)
+                    (pr-update-checkbox 'pr-i-mode)))
   ;;    1a. Buffer: Region
   (put 'pr-i-region 'pr-widget
        (pr-insert-checkbox
@@ -5663,7 +5637,7 @@ COMMAND.exe, COMMAND.bat and COMMAND.com in this order."
        'pr-i-region
         (lambda (widget &rest _ignore)
           (let ((region-p (pr-interface-save
-                           (ps-mark-active-p))))
+                           mark-active)))
             (cond ((null (widget-value widget)) ; widget is nil
                    (setq pr-i-region nil))
                   (region-p            ; widget is true and there is a region
@@ -6213,6 +6187,12 @@ COMMAND.exe, COMMAND.bat and COMMAND.com in this order."
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
+(defconst pr-version "6.9.3"
+  "printing.el, v 6.9.3 <2007/12/09 vinicius>
+
+Please send all bug fixes and enhancements to
+   bug-gnu-emacs@gnu.org and Vinicius Jose Latorre <viniciusjl.gnu@gmail.com>")
+(make-obsolete-variable 'pr-version 'emacs-version "29.1")
 
 (provide 'printing)
 
diff --git a/lisp/profiler.el b/lisp/profiler.el
index 94c24c62aa..8670e5786a 100644
--- a/lisp/profiler.el
+++ b/lisp/profiler.el
@@ -38,7 +38,7 @@
 
 (defcustom profiler-sampling-interval 1000000
   "Default sampling interval in nanoseconds."
-  :type 'integer
+  :type 'natnum
   :group 'profiler)
 
 
diff --git a/lisp/progmodes/antlr-mode.el b/lisp/progmodes/antlr-mode.el
index d6e2ab8a87..5002a3bbfa 100644
--- a/lisp/progmodes/antlr-mode.el
+++ b/lisp/progmodes/antlr-mode.el
@@ -66,8 +66,6 @@
 
 ;;; Installation:
 
-;; This file requires Emacs-20.3, XEmacs-20.4 or higher and package cc-mode.
-
 ;; If antlr-mode is not part of your distribution, put this file into your
 ;; load-path and the following into your init file:
 ;;   (autoload 'antlr-mode "antlr-mode" nil t)
@@ -75,9 +73,6 @@
 ;;   (add-hook 'speedbar-load-hook  ; would be too late in antlr-mode.el
 ;;            (lambda () (speedbar-add-supported-extension ".g")))
 
-;; I strongly recommend to use font-lock with a support mode like
-;; jit-lock (Emacs) / lazy-shot (XEmacs).
-
 ;; To customize, use menu item "Antlr" -> "Customize Antlr".
 
 ;;; Code:
@@ -894,7 +889,7 @@ Used for `antlr-slow-syntactic-context'.")
 
 
 ;;;===========================================================================
-;;;  Syntax functions -- Emacs vs XEmacs dependent, part 1
+;;;  Syntax functions
 ;;;===========================================================================
 
 ;;;===========================================================================
@@ -2431,8 +2426,6 @@ the default language."
        comment-start-skip "/\\*+ *\\|// *")
   ;; various -----------------------------------------------------------------
   (set (make-local-variable 'font-lock-defaults) antlr-font-lock-defaults)
-  (when (featurep 'xemacs)
-    (easy-menu-add antlr-mode-menu))
   (set (make-local-variable 'imenu-create-index-function)
        #'antlr-imenu-create-index-function)
   (set (make-local-variable 'imenu-generic-expression) t) ; fool stupid test
diff --git a/lisp/progmodes/autoconf.el b/lisp/progmodes/autoconf.el
index d0acd36f4b..fd8bf1f7ec 100644
--- a/lisp/progmodes/autoconf.el
+++ b/lisp/progmodes/autoconf.el
@@ -35,7 +35,7 @@
 
 ;;; Code:
 
-(defvar autoconf-mode-map (make-sparse-keymap))
+(defvar-keymap autoconf-mode-map)
 
 (defvar autoconf-mode-hook nil
   "Hook run by `autoconf-mode'.")
diff --git a/lisp/progmodes/bug-reference.el b/lisp/progmodes/bug-reference.el
index d3626dbaf0..5143af7dde 100644
--- a/lisp/progmodes/bug-reference.el
+++ b/lisp/progmodes/bug-reference.el
@@ -140,7 +140,7 @@ to the highlighted and clickable region."
                  t)))
         ;; All groups 2..10 are within bounds.
         (cons m-b1 m-e1)
-      ;; The regexp doesn't fulfil the contract of
+      ;; The regexp doesn't fulfill the contract of
       ;; bug-reference-bug-regexp, so fall back to the old behavior.
       (unless (member bug-reference-bug-regexp
                       bug-reference--nonconforming-regexps)
diff --git a/lisp/progmodes/cc-awk.el b/lisp/progmodes/cc-awk.el
index 9ea1557391..57750a2b39 100644
--- a/lisp/progmodes/cc-awk.el
+++ b/lisp/progmodes/cc-awk.el
@@ -887,7 +887,7 @@
 ;; subsequent use of movement functions, etc.  However, it seems that if font
 ;; lock _is_ enabled, we can always leave it to do the job.
 (defvar c-awk-old-ByLL 0)
-(make-variable-buffer-local 'c-awk-old-Byll)
+(make-variable-buffer-local 'c-awk-old-ByLL)
 ;; Just beyond logical line following the region which is about to be changed.
 ;; Set in c-awk-record-region-clear-NL and used in c-awk-after-change.
 
diff --git a/lisp/progmodes/cc-cmds.el b/lisp/progmodes/cc-cmds.el
index e9cc63709e..38e9d6011d 100644
--- a/lisp/progmodes/cc-cmds.el
+++ b/lisp/progmodes/cc-cmds.el
@@ -328,9 +328,6 @@ after special characters such as brace, comma, semi-colon, 
and colon."
   (c-update-modeline)
   (c-keep-region-active))
 
-(defalias 'c-toggle-auto-state 'c-toggle-auto-newline)
-(make-obsolete 'c-toggle-auto-state 'c-toggle-auto-newline "22.1")
-
 (defun c-toggle-hungry-state (&optional arg)
   "Toggle hungry-delete-key feature.
 Optional numeric ARG, if supplied, turns on hungry-delete when
@@ -2115,13 +2112,12 @@ with a brace block."
          (c-forward-syntactic-ws)
          (when (eq (char-after) ?\")
            (forward-sexp 1)
+           (c-forward-syntactic-ws)
            (c-forward-token-2))        ; over the comma and following WS.
-         (buffer-substring-no-properties
-          (point)
-          (progn
-            (c-forward-token-2)
-            (c-backward-syntactic-ws)
-            (point))))
+         (setq pos (point))
+         (and (zerop (c-forward-token-2))
+              (progn (c-backward-syntactic-ws) t)
+              (buffer-substring-no-properties pos (point))))
 
         ((and (c-major-mode-is 'objc-mode) (looking-at "[-+]\\s-*("))     ; 
Objective-C method
          ;; Move to the beginning of the method name.
diff --git a/lisp/progmodes/cc-defs.el b/lisp/progmodes/cc-defs.el
index 9edaf46534..f867625480 100644
--- a/lisp/progmodes/cc-defs.el
+++ b/lisp/progmodes/cc-defs.el
@@ -425,23 +425,6 @@ to it is returned.  This function does not modify the 
point or the mark."
 
 (defvar lookup-syntax-properties)       ;XEmacs.
 
-(eval-and-compile
-  ;; Constant to decide at compilation time whether to use category
-  ;; properties.  Currently (2010-03) they're available only on GNU Emacs.
-  (defconst c-use-category
-    (with-temp-buffer
-      (let ((parse-sexp-lookup-properties t)
-           (lookup-syntax-properties t))
-        (set-syntax-table (make-syntax-table))
-        (insert "<()>")
-        (put-text-property (point-min) (1+ (point-min))
-                          'category 'c-<-as-paren-syntax)
-        (put-text-property (+ 3 (point-min)) (+ 4 (point-min))
-                          'category 'c->-as-paren-syntax)
-        (goto-char (point-min))
-        (forward-sexp)
-        (= (point) (+ 4 (point-min)))))))
-
 (defmacro c-is-escaped (pos)
   ;; Are there an odd number of backslashes before POS?
   (declare (debug t))
@@ -811,15 +794,16 @@ right side of it."
               `(c-safe (scan-lists ,from ,count ,depth)))))
     (if limit
        `(save-restriction
-          (when ,limit
-            ,(if (numberp count)
-                 (if (< count 0)
-                     `(narrow-to-region ,limit (point-max))
-                   `(narrow-to-region (point-min) ,limit))
-               `(if (< ,count 0)
-                    (narrow-to-region ,limit (point-max))
-                  (narrow-to-region (point-min) ,limit))))
-          ,res)
+          (let ((-limit- ,limit))
+            (when -limit-
+              ,(if (numberp count)
+                   (if (< count 0)
+                       `(narrow-to-region -limit- (point-max))
+                     `(narrow-to-region (point-min) -limit-))
+                 `(if (< ,count 0)
+                      (narrow-to-region -limit- (point-max))
+                    (narrow-to-region (point-min) -limit-))))
+            ,res))
       res)))
 
 
@@ -1147,11 +1131,13 @@ MODE is either a mode symbol or a list of mode symbols."
                               (cc-bytecomp-fboundp 'delete-extent)
                               (cc-bytecomp-fboundp 'map-extents))))
 
-(defconst c-<-as-paren-syntax '(4 . ?>))
-(put 'c-<-as-paren-syntax 'syntax-table c-<-as-paren-syntax)
+(eval-and-compile
+  (defconst c-<-as-paren-syntax '(4 . ?>))
+  (put 'c-<-as-paren-syntax 'syntax-table c-<-as-paren-syntax))
 
-(defconst c->-as-paren-syntax '(5 . ?<))
-(put 'c->-as-paren-syntax 'syntax-table c->-as-paren-syntax)
+(eval-and-compile
+  (defconst c->-as-paren-syntax '(5 . ?<))
+  (put 'c->-as-paren-syntax 'syntax-table c->-as-paren-syntax))
 
 ;; `c-put-char-property' is complex enough in XEmacs and Emacs < 21 to
 ;; make it a function.
@@ -1210,6 +1196,26 @@ MODE is either a mode symbol or a list of mode symbols."
           `((setq c-syntax-table-hwm (min c-syntax-table-hwm -pos-))))
        (put-text-property -pos- (1+ -pos-) ',property ,value))))
 
+(eval-and-compile
+  ;; Constant to decide at compilation time whether to use category
+  ;; properties.  Currently (2010-03) they're available only on GNU
+  ;; Emacs.  This defconst must follow the declarations of
+  ;; `c-<-as-paren-syntax' and `c->-as-paren-syntax'.
+  (defconst c-use-category
+    (eval-when-compile
+      (with-temp-buffer
+       (let ((parse-sexp-lookup-properties t)
+             (lookup-syntax-properties t))
+          (set-syntax-table (make-syntax-table))
+          (insert "<()>")
+          (put-text-property (point-min) (1+ (point-min))
+                            'category 'c-<-as-paren-syntax)
+          (put-text-property (+ 3 (point-min)) (+ 4 (point-min))
+                            'category 'c->-as-paren-syntax)
+          (goto-char (point-min))
+          (forward-sexp)
+          (= (point) (+ 4 (point-min))))))))
+
 (defmacro c-get-char-property (pos property)
   ;; Get the value of the given property on the character at POS if
   ;; it's been put there by `c-put-char-property'.  PROPERTY is
@@ -1646,7 +1652,7 @@ with value CHAR in the region [FROM to)."
   ;; toggle the property in all template brackets simultaneously and
   ;; cheaply.  We use this, for instance, in `c-parse-state'.
   (declare (debug t))
-  (if c-use-category
+  (if (eval-when-compile c-use-category)
       `(c-put-char-property ,pos 'category 'c-<-as-paren-syntax)
     `(c-put-char-property ,pos 'syntax-table c-<-as-paren-syntax)))
 
@@ -1661,7 +1667,7 @@ with value CHAR in the region [FROM to)."
   ;; toggle the property in all template brackets simultaneously and
   ;; cheaply.  We use this, for instance, in `c-parse-state'.
   (declare (debug t))
-  (if c-use-category
+  (if (eval-when-compile c-use-category)
       `(c-put-char-property ,pos 'category 'c->-as-paren-syntax)
     `(c-put-char-property ,pos 'syntax-table c->-as-paren-syntax)))
 
@@ -1675,7 +1681,9 @@ with value CHAR in the region [FROM to)."
   ;; toggle the property in all template brackets simultaneously and
   ;; cheaply.  We use this, for instance, in `c-parse-state'.
   (declare (debug t))
-  `(c-clear-char-property ,pos ,(if c-use-category ''category ''syntax-table)))
+  `(c-clear-char-property ,pos ,(if (eval-when-compile c-use-category)
+                                   ''category
+                                 ''syntax-table)))
 
 (defsubst c-suppress-<->-as-parens ()
   ;; Suppress the syntactic effect of all marked < and > as parens.  Note
@@ -1755,7 +1763,7 @@ with value CHAR in the region [FROM to)."
 
 (defmacro c-sc-scan-lists (from count depth)
   (declare (debug t))
-  (if c-use-category
+  (if (eval-when-compile c-use-category)
       `(scan-lists ,from ,count ,depth)
     (cond
      ((and (eq count 1) (eq depth 1))
@@ -1803,7 +1811,7 @@ with value CHAR in the region [FROM to)."
 (defmacro c-sc-parse-partial-sexp (from to &optional targetdepth stopbefore
                                        oldstate)
   (declare (debug t))
-  (if c-use-category
+  (if (eval-when-compile c-use-category)
       `(parse-partial-sexp ,from ,to ,targetdepth ,stopbefore ,oldstate)
     `(c-sc-parse-partial-sexp-no-category ,from ,to ,targetdepth ,stopbefore
                                          ,oldstate)))
@@ -2063,8 +2071,8 @@ non-nil, a caret is prepended to invert the set."
     str))
 
 ;; Leftovers from (X)Emacs 19 compatibility.
-(defalias 'c-regexp-opt 'regexp-opt)
-(defalias 'c-regexp-opt-depth 'regexp-opt-depth)
+(define-obsolete-function-alias 'c-regexp-opt #'regexp-opt "29.1")
+(define-obsolete-function-alias 'c-regexp-opt-depth #'regexp-opt-depth "29.1")
 
 
 ;; Figure out what features this Emacs has
diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el
index 8794a527f8..b2d1f15d39 100644
--- a/lisp/progmodes/cc-engine.el
+++ b/lisp/progmodes/cc-engine.el
@@ -1239,7 +1239,7 @@ comment at the start of cc-engine.el for more info."
                           (not comma-delimited)
                           (not (c-looking-at-inexpr-block lim nil t))
                           (save-excursion
-                            (c-backward-token-2 1 t nil)
+                            (c-backward-token-2 1 t nil) ; Don't test the value
                             (not (looking-at "=\\([^=]\\|$\\)")))
                           (or
                            (not c-opt-block-decls-with-vars-key)
@@ -1672,9 +1672,13 @@ comment at the start of cc-engine.el for more info."
 Return the result of `forward-comment' if it gets called, nil otherwise."
   `(if (not comment-end-can-be-escaped)
        (forward-comment -1)
-     (when (and (< (skip-syntax-backward " >") 0)
-               (eq (char-after) ?\n))
-       (forward-char))
+     (let ((dist (skip-syntax-backward " >")))
+       (when (and
+             (< dist 0)
+             (progn
+               (skip-syntax-forward " " (- (point) dist 1))
+               (eq (char-after) ?\n)))
+        (forward-char)))
      (cond
       ((and (eq (char-before) ?\n)
            (eq (char-before (1- (point))) ?\\))
@@ -6837,7 +6841,7 @@ comment at the start of cc-engine.el for more info."
   (let ((type (c-syntactic-content from to c-recognize-<>-arglists)))
     (unless (gethash type c-found-types)
       (puthash type t c-found-types)
-      (when (and (not c-record-found-types) ; Only call 
`c-fontify-new-fount-type'
+      (when (and (not c-record-found-types) ; Only call 
`c-fontify-new-found-type'
                                        ; when we haven't "bound" c-found-types
                                        ; to itself in c-forward-<>-arglist.
                 (eq (string-match c-symbol-key type) 0)
@@ -8289,9 +8293,10 @@ multi-line strings (but not C++, for example)."
 (defun c-forward-noise-clause ()
   ;; Point is at a c-noise-macro-with-parens-names macro identifier.  Go
   ;; forward over this name, any parenthesis expression which follows it, and
-  ;; any syntactic WS, ending up at the next token.  If there is an unbalanced
-  ;; paren expression, leave point at it.  Always Return t.
-  (c-forward-token-2)
+  ;; any syntactic WS, ending up at the next token or EOB.  If there is an
+  ;; unbalanced paren expression, leave point at it.  Always Return t.
+  (or (zerop (c-forward-token-2))
+      (goto-char (point-max)))
   (if (and (eq (char-after) ?\()
           (c-go-list-forward))
       (c-forward-syntactic-ws))
@@ -9454,7 +9459,8 @@ point unchanged and return nil."
 
 (defun c-forward-declarator (&optional limit accept-anon)
   ;; Assuming point is at the start of a declarator, move forward over it,
-  ;; leaving point at the next token after it (e.g. a ) or a ; or a ,).
+  ;; leaving point at the next token after it (e.g. a ) or a ; or a ,), or at
+  ;; end of buffer if there is no such token.
   ;;
   ;; Return a list (ID-START ID-END BRACKETS-AFTER-ID GOT-INIT DECORATED),
   ;; where ID-START and ID-END are the bounds of the declarator's identifier,
@@ -9494,44 +9500,44 @@ point unchanged and return nil."
           ;; of the while.  These are, e.g. "*" in "int *foo" or "(" and
           ;; "*" in "int (*foo) (void)" (Note similar code in
           ;; `c-forward-decl-or-cast-1'.)
-             (while
-                 (cond
-                  ((looking-at c-decl-hangon-key)
-                   (c-forward-keyword-clause 1))
-                  ((and c-opt-cpp-prefix
-                        (looking-at c-noise-macro-with-parens-name-re))
-                   (c-forward-noise-clause))
-                  ((and (looking-at c-type-decl-prefix-key)
-                        (if (and (c-major-mode-is 'c++-mode)
-                                 (match-beginning 4)) ; Was 3 - 2021-01-01
-                            ;; If the third submatch matches in C++ then
-                            ;; we're looking at an identifier that's a
-                            ;; prefix only if it specifies a member pointer.
-                            (progn
-                              (setq id-start (point))
-                              (c-forward-name)
-                              (if (save-match-data
-                                    (looking-at "\\(::\\)"))
-                                  ;; We only check for a trailing "::" and
-                                  ;; let the "*" that should follow be
-                                  ;; matched in the next round.
-                                  t
-                                ;; It turned out to be the real identifier,
-                                ;; so flag that and stop.
-                                (setq got-identifier t)
-                                nil))
-                          t))
-                   (if (save-match-data
-                         (looking-at c-type-decl-operator-prefix-key))
-                       (setq decorated t))
-                   (if (eq (char-after) ?\()
-                       (progn
-                         (setq paren-depth (1+ paren-depth))
-                         (forward-char))
-                     (goto-char (or (match-end 1)
-                                    (match-end 2))))
-                   (c-forward-syntactic-ws)
-                   t)))
+          (while
+              (cond
+               ((looking-at c-decl-hangon-key)
+                (c-forward-keyword-clause 1))
+               ((and c-opt-cpp-prefix
+                     (looking-at c-noise-macro-with-parens-name-re))
+                (c-forward-noise-clause))
+               ((and (looking-at c-type-decl-prefix-key)
+                     (if (and (c-major-mode-is 'c++-mode)
+                              (match-beginning 4)) ; Was 3 - 2021-01-01
+                         ;; If the third submatch matches in C++ then
+                         ;; we're looking at an identifier that's a
+                         ;; prefix only if it specifies a member pointer.
+                         (progn
+                           (setq id-start (point))
+                           (c-forward-name)
+                           (if (save-match-data
+                                 (looking-at "\\(::\\)"))
+                               ;; We only check for a trailing "::" and
+                               ;; let the "*" that should follow be
+                               ;; matched in the next round.
+                               t
+                             ;; It turned out to be the real identifier,
+                             ;; so flag that and stop.
+                             (setq got-identifier t)
+                             nil))
+                       t))
+                (if (save-match-data
+                      (looking-at c-type-decl-operator-prefix-key))
+                    (setq decorated t))
+                (if (eq (char-after) ?\()
+                    (progn
+                      (setq paren-depth (1+ paren-depth))
+                      (forward-char))
+                  (goto-char (or (match-end 1)
+                                 (match-end 2))))
+                (c-forward-syntactic-ws)
+                t)))
 
           ;; If we haven't passed the identifier already, do it now.
           (unless got-identifier
@@ -9552,7 +9558,8 @@ point unchanged and return nil."
         (or (= paren-depth 0)
             (c-safe (goto-char (scan-lists (point) 1 paren-depth))))
 
-        (<= (point) limit)
+        (or (eq (point) (point-max))   ; No token after identifier.
+            (< (point) limit))
 
         ;; Skip over any trailing bit, such as "__attribute__".
         (progn
@@ -10566,8 +10573,8 @@ This function might do hidden buffer changes."
                        backup-maybe-typeless
                        (when c-recognize-typeless-decls
                          (or (not got-suffix)
-                             (not (looking-at
-                                   c-after-suffixed-type-maybe-decl-key))))))
+                             (looking-at
+                              c-after-suffixed-type-maybe-decl-key)))))
               ;; Got an empty paren pair and a preceding type that probably
               ;; really is the identifier.  Shift the type backwards to make
               ;; the last one the identifier.  This is analogous to the
diff --git a/lisp/progmodes/cc-fonts.el b/lisp/progmodes/cc-fonts.el
index 15e3beb837..12bb3d3751 100644
--- a/lisp/progmodes/cc-fonts.el
+++ b/lisp/progmodes/cc-fonts.el
@@ -285,6 +285,7 @@
     (byte-compile
      `(lambda (limit)
        (let (res)
+         (c-skip-comments-and-strings limit)
          (while (and (setq res (re-search-forward ,regexp limit t))
                      (progn
                        (goto-char (match-beginning 0))
@@ -300,43 +301,45 @@
     ;; with HIGHLIGHTS, a list of highlighters as specified on page
     ;; "Search-based Fontification" in the elisp manual.  If CHECK-POINT
     ;; is non-nil, we will check (< (point) limit) in the main loop.
-    `(while
-        ,(if check-point
-             `(and (< (point) limit)
-                   (re-search-forward ,regexp limit t))
-           `(re-search-forward ,regexp limit t))
-       (unless (progn
-                (goto-char (match-beginning 0))
-                (c-skip-comments-and-strings limit))
-        (goto-char (match-end 0))
-        ,@(mapcar
-           (lambda (highlight)
-             (if (integerp (car highlight))
-                 ;; e.g. highlight is (1 font-lock-type-face t)
-                 (progn
-                   (unless (eq (nth 2 highlight) t)
-                     (error
-                      "The override flag must currently be t in %s"
-                      highlight))
-                   (when (nth 3 highlight)
-                     (error
-                      "The laxmatch flag may currently not be set in %s"
-                      highlight))
-                   `(save-match-data
-                      (c-put-font-lock-face
-                       (match-beginning ,(car highlight))
-                       (match-end ,(car highlight))
-                       ,(elt highlight 1))))
-               ;; highlight is an "ANCHORED HIGHLIGHTER" of the form
-               ;; (ANCHORED-MATCHER PRE-FORM POST-FORM SUBEXP-HIGHLIGHTERS...)
-               (when (nth 3 highlight)
-                 (error "Match highlights currently not supported in %s"
+    `(progn
+       (c-skip-comments-and-strings limit)
+       (while
+          ,(if check-point
+               `(and (< (point) limit)
+                     (re-search-forward ,regexp limit t))
+             `(re-search-forward ,regexp limit t))
+        (unless (progn
+                  (goto-char (match-beginning 0))
+                  (c-skip-comments-and-strings limit))
+          (goto-char (match-end 0))
+          ,@(mapcar
+             (lambda (highlight)
+               (if (integerp (car highlight))
+                   ;; e.g. highlight is (1 font-lock-type-face t)
+                   (progn
+                     (unless (eq (nth 2 highlight) t)
+                       (error
+                        "The override flag must currently be t in %s"
+                        highlight))
+                     (when (nth 3 highlight)
+                       (error
+                        "The laxmatch flag may currently not be set in %s"
                         highlight))
-               `(progn
-                  ,(nth 1 highlight)
-                  (save-match-data ,(car highlight))
-                  ,(nth 2 highlight))))
-           highlights))))
+                     `(save-match-data
+                        (c-put-font-lock-face
+                         (match-beginning ,(car highlight))
+                         (match-end ,(car highlight))
+                         ,(elt highlight 1))))
+                 ;; highlight is an "ANCHORED HIGHLIGHTER" of the form
+                 ;; (ANCHORED-MATCHER PRE-FORM POST-FORM 
SUBEXP-HIGHLIGHTERS...)
+                 (when (nth 3 highlight)
+                   (error "Match highlights currently not supported in %s"
+                          highlight))
+                 `(progn
+                    ,(nth 1 highlight)
+                    (save-match-data ,(car highlight))
+                    ,(nth 2 highlight))))
+             highlights)))))
 
   (defun c-make-font-lock-search-function (regexp &rest highlights)
     ;; This function makes a byte compiled function that works much like
@@ -416,6 +419,8 @@
     ;; lambda more easily.
     (byte-compile
      `(lambda (limit)
+       (let ((lit-start (c-literal-start)))
+         (when lit-start (goto-char lit-start)))
        (let ( ;; The font-lock package in Emacs is known to clobber
              ;; `parse-sexp-lookup-properties' (when it exists).
              (parse-sexp-lookup-properties
@@ -935,7 +940,8 @@ casts and declarations are fontified.  Used on level 2 and 
higher."
                        '(c-decl-arg-start
                          c-decl-end
                          c-decl-id-start
-                         c-decl-type-start)))
+                         c-decl-type-start
+                         c-not-decl)))
             (1- (point))
           pos)
         limit 'c-type)))
@@ -1820,7 +1826,7 @@ casts and declarations are fontified.  Used on level 2 
and higher."
   ;; font-lock-keyword-face.  It always returns NIL to inhibit this and
   ;; prevent a repeat invocation.  See elisp/lispref page "Search-based
   ;; Fontification".
-  (let (mode capture-default id-start id-end declaration sub-begin sub-end)
+  (let (mode capture-default id-start id-end declaration sub-begin sub-end tem)
     (while (and (< (point) limit)
                (search-forward "[" limit t))
       (when (progn (backward-char)
@@ -1832,15 +1838,18 @@ casts and declarations are fontified.  Used on level 2 
and higher."
                        (char-after)))
        ;; Is the first element of the list a bare "=" or "&"?
        (when mode
-         (forward-char)
-         (c-forward-syntactic-ws)
-         (if (memq (char-after) '(?, ?\]))
-             (progn
-               (setq capture-default mode)
-               (when (eq (char-after) ?,)
-                 (forward-char)
-                 (c-forward-syntactic-ws)))
-           (c-backward-token-2)))
+         (setq tem nil)
+         (save-excursion
+           (forward-char)
+           (c-forward-syntactic-ws)
+           (if (memq (char-after) '(?, ?\]))
+               (progn
+                 (setq capture-default mode)
+                 (when (eq (char-after) ?,)
+                   (forward-char)
+                   (c-forward-syntactic-ws))
+                 (setq tem (point)))))
+         (if tem (goto-char tem)))
 
        ;; Go round the following loop once per captured item.  We use "\\s)"
        ;; rather than "\\]" here to avoid infinite looping in this situation:
diff --git a/lisp/progmodes/cc-langs.el b/lisp/progmodes/cc-langs.el
index 68070cd058..068b4a65b2 100644
--- a/lisp/progmodes/cc-langs.el
+++ b/lisp/progmodes/cc-langs.el
@@ -403,7 +403,7 @@ The syntax tables aren't stored directly since they're 
quite large."
   t  (if (c-lang-const c-recognize-<>-arglists)
      `(lambda ()
        ;(if (c-lang-const c-recognize-<>-arglists)
-       (let ((table (funcall ,(c-lang-const c-make-mode-syntax-table))))
+       (let ((table (funcall ',(c-lang-const c-make-mode-syntax-table))))
          (modify-syntax-entry ?\( "." table)
          (modify-syntax-entry ?\) "." table)
          (modify-syntax-entry ?\[ "." table)
@@ -458,12 +458,14 @@ so that all identifiers are recognized as words.")
        c-before-change-check-<>-operators
        c-truncate-bs-cache
        c-before-change-check-unbalanced-strings
-       c-parse-quotes-before-change)
+       c-parse-quotes-before-change
+       c-before-change-fix-comment-escapes)
   (c objc) '(c-extend-region-for-CPP
             c-depropertize-CPP
             c-truncate-bs-cache
             c-before-change-check-unbalanced-strings
-            c-parse-quotes-before-change)
+            c-parse-quotes-before-change
+            c-before-change-fix-comment-escapes)
   java '(c-parse-quotes-before-change
         c-before-change-check-unbalanced-strings
         c-before-change-check-<>-operators)
@@ -500,6 +502,7 @@ parameters \(point-min) and \(point-max).")
       c-after-change-mark-abnormal-strings
       c-change-expand-fl-region)
   (c objc) '(c-depropertize-new-text
+            c-after-change-fix-comment-escapes
             c-after-change-escape-NL-in-string
             c-parse-quotes-after-change
             c-after-change-mark-abnormal-strings
@@ -507,6 +510,7 @@ parameters \(point-min) and \(point-max).")
             c-neutralize-syntax-in-CPP
             c-change-expand-fl-region)
   c++ '(c-depropertize-new-text
+       c-after-change-fix-comment-escapes
        c-after-change-escape-NL-in-string
        c-after-change-unmark-ml-strings
        c-parse-quotes-after-change
@@ -846,7 +850,7 @@ This is of the form that fits inside [ ] in a regexp."
   "Regexp matching identifiers and keywords (with submatch 0).  Assumed
 to match if `c-symbol-start' matches on the same position."
   t    (concat (c-lang-const c-symbol-start)
-              "[" (c-lang-const c-symbol-chars) "]*")
+              "[" (c-lang-const c-symbol-chars) "]\\{,1000\\}")
   pike (concat
        ;; Use the value from C here since the operator backquote is
        ;; covered by the other alternative.
@@ -4274,7 +4278,7 @@ This macro is expanded at compile time to a form tailored 
for the mode
 in question, so MODE must be a constant.  Therefore MODE is not
 evaluated and should not be quoted."
   (declare (debug nil))
-  `(funcall ,(c-make-init-lang-vars-fun mode)))
+  `(funcall #',(c-make-init-lang-vars-fun mode)))
 
 
 (cc-provide 'cc-langs)
diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el
index ae96cdbd2f..9327dbf775 100644
--- a/lisp/progmodes/cc-mode.el
+++ b/lisp/progmodes/cc-mode.el
@@ -1518,7 +1518,12 @@ Note that the style variables are always made local to 
the buffer."
 
       ;; Move to end of logical line (as it will be after the change, or as it
       ;; was before unescaping a NL.)
-      (re-search-forward "\\(?:\\\\\\(?:.\\|\n\\)\\|[^\\\n\r]\\)*" nil t)
+      (while
+         (progn (end-of-line)
+                (and
+                 (eq (char-before) ?\\)
+                 (not (eobp))))
+       (forward-line))
       ;; We're at an EOLL or point-max.
       (if (equal (c-get-char-property (point) 'syntax-table) '(15))
          (if (memq (char-after) '(?\n ?\r))
@@ -1636,8 +1641,12 @@ Note that the style variables are always made local to 
the buffer."
                  (min (1+ end) ; 1+, if we're inside an escaped NL.
                       (point-max))
                end))
-            (re-search-forward "\\(?:\\\\\\(?:.\\|\n\\)\\|[^\\\n\r]\\)*"
-                               nil t)
+            (while
+                (progn (end-of-line)
+                       (and
+                        (eq (char-before) ?\\)
+                        (not (eobp))))
+              (forward-line))
             (point))
           c-new-END))
         s)
@@ -1979,6 +1988,87 @@ Note that this is a strict tail, so won't match, e.g. 
\"0x....\".")
 (defvar c-new-id-is-type nil)
 (make-variable-buffer-local 'c-new-id-is-type)
 
+(defun c-before-change-fix-comment-escapes (beg end)
+  "Remove punctuation syntax-table text properties from C/C++ comment markers.
+This is to handle the rare case of two or more backslashes at an
+end of line in a // comment or the equally rare case of a
+backslash preceding the terminator of a /* comment, as \\*/.
+
+This function is used solely as a member of
+`c-get-state-before-change-functions', where it should appear
+late in that variable, and it must be used only together with
+`c-after-change-fix-comment-escapes'.
+
+Note that the function currently only handles comments beginning
+with // and /*, not more generic line and block comments."
+  (c-save-buffer-state (end-state)
+    (setq end-state (c-full-pp-to-literal end))
+    (when (memq (cadr end-state) '(c c++))
+      (goto-char (max (- beg 2) (point-min)))
+      (if (eq (cadr end-state) 'c)
+         (when (search-forward "\\*/"
+                               (or (cdr (caddr end-state)) (point-max)) t)
+           (c-clear-char-property (match-beginning 0) 'syntax-table)
+           (c-truncate-lit-pos-cache (match-beginning 0)))
+       (while (search-forward "\\\\\n"
+                              (or (cdr (caddr end-state)) (point-max)) t)
+         (c-clear-char-property (match-beginning 0) 'syntax-table)
+         (c-truncate-lit-pos-cache (match-beginning 0)))))))
+
+(defun c-after-change-fix-comment-escapes (beg end _old-len)
+  "Apply punctuation syntax-table text properties to C/C++ comment markers.
+This is to handle the rare case of two or more backslashes at an
+end of line in a // comment or the equally rare case of a
+backslash preceding the terminator of a /* comment, as \\*/.
+
+This function is used solely as a member of
+`c-before-font-lock-functions', where it should appear early in
+that variable, and it must be used only together with
+`c-before-change-fix-comment-escapes'.
+
+Note that the function currently only handles comments beginning
+with // and /*, not more generic line and block comments."
+  (c-save-buffer-state (state)
+    ;; We cannot use `c-full-pp-to-literal' in this function, since the
+    ;; `syntax-table' text properties after point are not yet in a consistent
+    ;; state.
+    (setq state (c-semi-pp-to-literal beg))
+    (goto-char (if (memq (cadr state) '(c c++))
+                  (caddr state)
+                (max (- beg 2) (point-min))))
+    (while
+       (re-search-forward "\\\\\\(\\(\\\\\n\\)\\|\\(\\*/\\)\\)"
+                          (min (+ end 2) (point-max)) t)
+      (setq state (c-semi-pp-to-literal (match-beginning 0)))
+      (when (cond
+            ((eq (cadr state) 'c)
+             (match-beginning 3))
+            ((eq (cadr state) 'c++)
+             (match-beginning 2)))
+       (c-put-char-property (match-beginning 0) 'syntax-table '(1))
+       (c-truncate-lit-pos-cache (match-beginning 0))))
+
+    (goto-char end)
+    (setq state (c-semi-pp-to-literal (point)))
+    (cond
+     ((eq (cadr state) 'c)
+      (when (search-forward "*/" nil t)
+       (when (eq (char-before (match-beginning 0)) ?\\)
+         (c-put-char-property (1- (match-beginning 0)) 'syntax-table '(1))
+         (c-truncate-lit-pos-cache (1- (match-beginning 0))))))
+     ((eq (cadr state) 'c++)
+      (while
+         (progn
+           (end-of-line)
+           (and (eq (char-before) ?\\)
+                (progn
+                  (when (eq (char-before (1- (point))) ?\\)
+                    (c-put-char-property (- (point) 2) 'syntax-table '(1))
+                    (c-truncate-lit-pos-cache (1- (point))))
+                  t)
+                (not (eobp))))
+       (forward-char))))))
+
 (defun c-update-new-id (end)
   ;; Note the bounds of any identifier that END is in or just after, in
   ;; `c-new-id-start' and `c-new-id-end'.  Otherwise set these variables to
@@ -1990,7 +2080,6 @@ Note that this is a strict tail, so won't match, e.g. 
\"0x....\".")
            c-new-id-end (and id-beg
                              (progn (c-end-of-current-token) (point)))))))
 
-
 (defun c-post-command ()
   ;; If point was inside of a new identifier and no longer is, record that
   ;; fact.
@@ -2351,49 +2440,59 @@ Note that this is a strict tail, so won't match, e.g. 
\"0x....\".")
       (and (/= new-pos pos) new-pos))))
 
 (defun c-fl-decl-end (pos)
-  ;; If POS is inside a declarator, return the end of the token that follows
-  ;; the declarator, otherwise return nil.  POS being in a literal does not
-  ;; count as being in a declarator (on pragmatic grounds).  POINT is not
-  ;; preserved.
+  ;; If POS is inside a declarator, return the position of the end of the
+  ;; paren pair that terminates it, or of the end of the token that follows
+  ;; the declarator, otherwise return nil.  If there is no such token, the end
+  ;; of the last token in the buffer is used.  POS being in a literal is now
+  ;; (2022-07) handled correctly.  POINT is not preserved.
   (goto-char pos)
   (let ((lit-start (c-literal-start))
        (lim (c-determine-limit 1000))
        enclosing-attribute pos1)
-    (unless lit-start
-      (c-backward-syntactic-ws
-       lim)
-      (when (setq enclosing-attribute (c-enclosing-c++-attribute))
-       (goto-char (car enclosing-attribute))) ; Only happens in C++ Mode.
-      (when (setq pos1 (c-on-identifier))
-       (goto-char pos1)
-       (let ((lim (save-excursion
-                    (and (c-beginning-of-macro)
-                         (progn (c-end-of-macro) (point))))))
-         (and (c-forward-declarator lim)
-              (if (eq (char-after) ?\()
-                  (and
-                   (c-go-list-forward nil lim)
-                   (progn (c-forward-syntactic-ws lim)
-                          (not (eobp)))
-                   (progn
-                     (if (looking-at c-symbol-char-key)
-                         ;; Deal with baz (foo((bar)) type var), where
-                         ;; foo((bar)) is not semantically valid.  The result
-                         ;; must be after var).
-                         (and
-                          (goto-char pos)
-                          (setq pos1 (c-on-identifier))
-                          (goto-char pos1)
-                          (progn
-                            (c-backward-syntactic-ws lim)
-                            (eq (char-before) ?\())
-                          (c-fl-decl-end (1- (point))))
-                       (c-backward-syntactic-ws lim)
-                       (point))))
-                (and (progn (c-forward-syntactic-ws lim)
-                            (not (eobp)))
+    (if lit-start
+       (goto-char lit-start))
+    (c-backward-syntactic-ws lim)
+    (when (setq enclosing-attribute (c-enclosing-c++-attribute))
+      (goto-char (car enclosing-attribute)) ; Only happens in C++ Mode.
+      (c-backward-syntactic-ws lim))
+    (while (and (> (point) lim)
+               (memq (char-before) '(?\[ ?\()))
+      (backward-char)
+      (c-backward-syntactic-ws lim))
+    (when (setq pos1 (c-on-identifier))
+      (goto-char pos1)
+      (let ((lim (save-excursion
+                  (and (c-beginning-of-macro)
+                       (progn (c-end-of-macro) (point))))))
+       (and (c-forward-declarator lim)
+            (if (and (eq (char-after) ?\()
+                     (c-go-list-forward nil lim))
+                (and
+                 (progn (c-forward-syntactic-ws lim)
+                        (not (eobp)))
+                 (progn
+                   (if (looking-at c-symbol-char-key)
+                       ;; Deal with baz (foo((bar)) type var), where
+                       ;; foo((bar)) is not semantically valid.  The result
+                       ;; must be after var).
+                       (and
+                        (goto-char pos)
+                        (setq pos1 (c-on-identifier))
+                        (goto-char pos1)
+                        (progn
+                          (c-backward-syntactic-ws lim)
+                          (eq (char-before) ?\())
+                        (c-fl-decl-end (1- (point))))
                      (c-backward-syntactic-ws lim)
-                     (point)))))))))
+                     (point))))
+              (if (progn (c-forward-syntactic-ws lim)
+                         (not (eobp)))
+                  (c-forward-over-token)
+                (let ((lit-start (c-literal-start)))
+                  (when lit-start
+                      (goto-char lit-start))
+                  (c-backward-syntactic-ws)))
+              (and (>= (point) pos) (point))))))))
 
 (defun c-change-expand-fl-region (_beg _end _old-len)
   ;; Expand the region (c-new-BEG c-new-END) to an after-change font-lock
diff --git a/lisp/progmodes/cfengine.el b/lisp/progmodes/cfengine.el
index 00348ac0bb..7d7e926538 100644
--- a/lisp/progmodes/cfengine.el
+++ b/lisp/progmodes/cfengine.el
@@ -793,14 +793,6 @@ bundle agent rcfiles
                       (cdr (assq 'functions cfengine3-fallback-syntax)))
               'symbols))
 
-(defcustom cfengine-mode-abbrevs nil
-  "Abbrevs for CFEngine2 mode."
-  :type '(repeat (list (string :tag "Name")
-                      (string :tag "Expansion")
-                      (choice  :tag "Hook" (const nil) function))))
-
-(make-obsolete-variable 'cfengine-mode-abbrevs 'edit-abbrevs "24.1")
-
 ;; Taken from the doc for pre-release 2.1.
 (eval-and-compile
   (defconst cfengine2-actions
@@ -1194,7 +1186,7 @@ Intended as the value of `indent-line-function'."
                  (skip-syntax-forward "w_")
                  (when (search-backward-regexp
                         cfengine-mode-syntax-functions-regex
-                        (point-at-bol)
+                        (line-beginning-position)
                         t)
                    (match-string 1)))))
         (and w (assq (intern w) flist))))))
@@ -1293,7 +1285,7 @@ see.  Use it by enabling `eldoc-mode'."
   "Return completions for function name around or before point."
   (let* ((bounds (save-excursion
                    (let ((p (point)))
-                     (skip-syntax-backward "w_" (point-at-bol))
+                     (skip-syntax-backward "w_" (line-beginning-position))
                      (list (point) p))))
          (syntax (cfengine3-make-syntax-cache))
          (flist (assq 'functions syntax)))
@@ -1409,7 +1401,6 @@ to the action header."
   (setq-local outline-regexp "[ \t]*\\(\\sw\\|\\s_\\)+:+")
   (setq-local outline-level #'cfengine2-outline-level)
   (setq-local fill-paragraph-function #'cfengine-fill-paragraph)
-  (define-abbrev-table 'cfengine2-mode-abbrev-table cfengine-mode-abbrevs)
   (setq font-lock-defaults
         '(cfengine2-font-lock-keywords nil nil nil beginning-of-line))
   ;; Fixme: set the args of functions in evaluated classes to string
diff --git a/lisp/progmodes/compile.el b/lisp/progmodes/compile.el
index d28fce9dbd..5ce80e0657 100644
--- a/lisp/progmodes/compile.el
+++ b/lisp/progmodes/compile.el
@@ -276,7 +276,16 @@ of[ \t]+\"?\\([a-zA-Z]?:?[^\":\n]+\\)\"?:" 3 2 nil (1))
           "): ")
      3 4 5 (1 . 2))
 
-    (iar
+    (gradle-android
+     ,(rx bol (* " ") "ERROR:"
+          (group-n 1                    ; file
+                   (+ (not (in ":\n"))))
+          ":"
+          (group-n 2 (+ digit))         ; line
+          ": ")
+     1 2)
+
+   (iar
      
"^\"\\(.*\\)\",\\([0-9]+\\)\\s-+\\(?:Error\\|Warnin\\(g\\)\\)\\[[0-9]+\\]:"
      1 2 nil (3))
 
@@ -359,66 +368,73 @@ of[ \t]+\"?\\([a-zA-Z]?:?[^\":\n]+\\)\"?:" 3 2 nil (1))
      ": \\*\\*\\* \\[\\(\\(.+?\\):\\([0-9]+\\): .+\\)\\]" 2 3 nil 0 1)
 
     (gnu
+     ;; The `gnu' message syntax is
+     ;;   [PROGRAM:]FILE:LINE[-ENDLINE]:[COL[-ENDCOL]:] MESSAGE
+     ;; or
+     ;;   [PROGRAM:]FILE:LINE[.COL][-ENDLINE[.ENDCOL]]: MESSAGE
      ,(rx
        bol
-       ;; Match an optional program name in the format
-       ;;     PROGRAM:SOURCE-FILE-NAME:LINENO: MESSAGE
-       ;; which is used for non-interactive programs other than
-       ;; compilers (e.g. the "jade:" entry in compilation.txt).
+       ;; Match an optional program name which is used for
+       ;; non-interactive programs other than compilers (e.g. the
+       ;; "jade:" entry in compilation.txt).
        (? (| (: alpha (+ (in ?. ?- alnum)) ":" (? " "))
              ;; Skip indentation generated by GCC's -fanalyzer.
              (: (+ " ") "|")))
 
        ;; File name group.
        (group-n 1
-                ;; Avoid matching the file name as a program in the pattern
-                ;; above by disallow file names entirely composed of digits.
-                (: (regexp "[0-9]*[^0-9\n]")
-                   ;; This rule says that a file name can be composed
-                   ;; of any non-newline char, but it also rules out
-                   ;; some valid but unlikely cases, such as a
-                   ;; trailing space or a space followed by a -, or a
-                   ;; colon followed by a space.
-                   (*? (| (regexp "[^\n :]")
-                          (regexp " [^-/\n]")
-                          (regexp ":[^ \n]")))))
-       (regexp ": ?")
+         ;; Avoid matching the file name as a program in the pattern
+         ;; above by disallowing file names entirely composed of digits.
+         ;; Do not allow file names beginning with a space.
+         (| (not (in "0-9" "\n\t "))
+            (: (+ (in "0-9"))
+               (not (in "0-9" "\n"))))
+         ;; A file name can be composed of any non-newline char, but
+         ;; rule out some valid but unlikely cases, such as a trailing
+         ;; space or a space followed by a -, or a colon followed by a
+         ;; space.
+         (*? (| (not (in "\n :"))
+                (: " " (not (in ?- "/\n")))
+                (: ":" (not (in " \n"))))))
+       ":" (? " ")
 
        ;; Line number group.
-       (group-n 2 (regexp "[0-9]+"))
+       (group-n 2 (+ (in "0-9")))
        (? (| (: "-"
-                (group-n 4 (regexp "[0-9]+"))            ; ending line
-                (? "." (group-n 5 (regexp "[0-9]+"))))   ; ending column
+                (group-n 4 (+ (in "0-9")))               ; ending line
+                (? "." (group-n 5 (+ (in "0-9")))))      ; ending column
              (: (in ".:")
-                (group-n 3 (regexp "[0-9]+"))            ; starting column
+                (group-n 3 (+ (in "0-9")))               ; starting column
                 (? "-"
-                   (? (group-n 4 (regexp "[0-9]+")) ".") ; ending line
-                   (group-n 5 (regexp "[0-9]+"))))))     ; ending column
+                   (? (group-n 4 (+ (in "0-9"))) ".")    ; ending line
+                   (group-n 5 (+ (in "0-9")))))))        ; ending column
        ":"
        (| (: (* " ")
              (group-n 6 (| "FutureWarning"
                            "RuntimeWarning"
-                           "Warning"
-                           "warning"
+                           "Warning" "warning"
                            "W:")))
           (: (* " ")
-             (group-n 7 (| (regexp "[Ii]nfo\\(?:\\>\\|rmationa?l?\\)")
-                           "I:"
-                           (: "[ skipping " (+ nonl) " ]")
-                           "instantiated from"
-                           "required from"
-                           (regexp "[Nn]ote"))))
+             (group-n 7
+               (| (| "Info" "info"
+                     "Information" "information"
+                     "Informational" "informational"
+                     "I:"
+                     "instantiated from"
+                     "required from"
+                     "Note" "note")
+                  (: "[ skipping " (+ nonl) " ]"))))
           (: (* " ")
-             (regexp "[Ee]rror"))
+             (| "Error" "error"))
 
           ;; Avoid matching time stamps on the form "HH:MM:SS" where
           ;; MM is interpreted as a line number by trying to rule out
           ;; messages where the text after the line number starts with
           ;; a 2-digit number.
-          (: (regexp "[0-9]?")
-             (| (regexp "[^0-9\n]")
+          (: (? (in "0-9"))
+             (| (not (in "0-9\n"))
                 eol))
-          (regexp "[0-9][0-9][0-9]")))
+          (: (in "0-9") (in "0-9") (in "0-9"))))
      1 (2 . 4) (3 . 5) (6 . 7))
 
     (cucumber
@@ -844,7 +860,7 @@ You might also use mode hooks to specify it in certain 
modes, like this:
 
 It's often useful to leave a space at the end of the value."
   :type 'string)
-;;;###autoload(put 'compile-command 'safe-local-variable (lambda (a) (and 
(stringp a) (or (not (boundp 'compilation-read-command)) 
compilation-read-command))))
+;;;###autoload(put 'compile-command 'safe-local-variable (lambda (a) (and 
(stringp a) (if (boundp 'compilation-read-command) compilation-read-command 
t))))
 
 ;;;###autoload
 (defcustom compilation-disable-input nil
@@ -963,11 +979,6 @@ Faces `compilation-error-face', `compilation-warning-face',
 (defvar compilation-leave-directory-face 'font-lock-builtin-face
   "Face name to use for leaving directory messages.")
 
-;; Used for compatibility with the old compile.el.
-(defvar compilation-parse-errors-function nil)
-(make-obsolete-variable 'compilation-parse-errors-function
-                       'compilation-error-regexp-alist "24.1")
-
 (defcustom compilation-auto-jump-to-first-error nil
   "If non-nil, automatically jump to the first error during compilation."
   :type '(choice (const :tag "Never" nil)
@@ -1243,7 +1254,7 @@ POS and RES.")
 ;; Return a property list with all meta information on this error location.
 
 (defun compilation-error-properties (file line end-line col end-col type fmt
-                                     rule)
+                                          rule)
   (unless (text-property-not-all (match-beginning 0) (point)
                                  'compilation-message nil)
     (if file
@@ -1503,34 +1514,28 @@ RULE is the name (symbol) of the rule used or nil if 
anonymous.
             (and proc (memq (process-status proc) '(run open))))
       (setq end (line-beginning-position))))
   (compilation--remove-properties start end)
-  (if compilation-parse-errors-function
-      ;; An old package!  Try the compatibility code.
-      (progn
-        (goto-char start)
-        (compilation--compat-parse-errors end))
-
-    ;; compilation-directory-matcher is the only part that really needs to be
-    ;; parsed sequentially.  So we could split it out, handle directories
-    ;; like syntax-propertize, and the rest as font-lock-keywords.  But since
-    ;; we want to have it work even when font-lock is off, we'd then need to
-    ;; use our own compilation-parsed text-property to keep track of the parts
-    ;; that have already been parsed.
-    (goto-char start)
-    (while (re-search-forward (car compilation-directory-matcher)
-                              end t)
-      (compilation--flush-directory-cache (match-beginning 0) (match-end 0))
-      (when compilation-debug
-        (font-lock-append-text-property
-         (match-beginning 0) (match-end 0)
-         'compilation-debug
-         (vector 'directory compilation-directory-matcher)))
-      (dolist (elt (cdr compilation-directory-matcher))
-        (add-text-properties (match-beginning (car elt))
-                             (match-end (car elt))
-                             (compilation-directory-properties
-                              (car elt) (cdr elt)))))
-
-    (compilation-parse-errors start end)))
+  ;; compilation-directory-matcher is the only part that really needs to be
+  ;; parsed sequentially.  So we could split it out, handle directories
+  ;; like syntax-propertize, and the rest as font-lock-keywords.  But since
+  ;; we want to have it work even when font-lock is off, we'd then need to
+  ;; use our own compilation-parsed text-property to keep track of the parts
+  ;; that have already been parsed.
+  (goto-char start)
+  (while (re-search-forward (car compilation-directory-matcher)
+                            end t)
+    (compilation--flush-directory-cache (match-beginning 0) (match-end 0))
+    (when compilation-debug
+      (font-lock-append-text-property
+       (match-beginning 0) (match-end 0)
+       'compilation-debug
+       (vector 'directory compilation-directory-matcher)))
+    (dolist (elt (cdr compilation-directory-matcher))
+      (add-text-properties (match-beginning (car elt))
+                           (match-end (car elt))
+                           (compilation-directory-properties
+                            (car elt) (cdr elt)))))
+
+  (compilation-parse-errors start end))
 
 (defun compilation--note-type (type)
   "Note that a new message with severity TYPE was seen.
@@ -1787,6 +1792,7 @@ Otherwise, construct a buffer name from NAME-OF-MODE."
                #'compilation--default-buffer-name)
            name-of-mode))
 
+;;;###autoload
 (defun compilation--default-buffer-name (name-of-mode)
   (cond ((or (eq major-mode (intern-soft name-of-mode))
              (eq major-mode (intern-soft (concat name-of-mode "-mode"))))
@@ -2459,22 +2465,23 @@ commands of Compilation major mode are available.  See
 (defun compilation-sentinel (proc msg)
   "Sentinel for compilation buffers."
   (if (memq (process-status proc) '(exit signal))
-      (let ((buffer (process-buffer proc)))
-       (if (null (buffer-name buffer))
-           ;; buffer killed
-           (set-process-buffer proc nil)
-         (with-current-buffer buffer
-           ;; Write something in the compilation buffer
-           ;; and hack its mode line.
-           (compilation-handle-exit (process-status proc)
-                                    (process-exit-status proc)
-                                    msg)
-           ;; Since the buffer and mode line will show that the
-           ;; process is dead, we can delete it now.  Otherwise it
-           ;; will stay around until M-x list-processes.
-           (delete-process proc)))
+      (unwind-protect
+          (let ((buffer (process-buffer proc)))
+            (if (null (buffer-name buffer))
+                ;; buffer killed
+                (set-process-buffer proc nil)
+              (with-current-buffer buffer
+                ;; Write something in the compilation buffer
+                ;; and hack its mode line.
+                (compilation-handle-exit (process-status proc)
+                                         (process-exit-status proc)
+                                         msg))))
         (setq compilation-in-progress (delq proc compilation-in-progress))
-        (compilation--update-in-progress-mode-line))))
+        (compilation--update-in-progress-mode-line)
+        ;; Since the buffer and mode line will show that the
+        ;; process is dead, we can delete it now.  Otherwise it
+        ;; will stay around until M-x list-processes.
+        (delete-process proc))))
 
 (defun compilation-filter (proc string)
   "Process filter for compilation buffers.
@@ -3243,73 +3250,11 @@ TRUE-DIRNAME is the `file-truename' of DIRNAME, if 
given."
                (if (eq v fs) (remhash k compilation-locs)))
              compilation-locs)))
 
-;;; Compatibility with the old compile.el.
-
-(defvaralias 'compilation-last-buffer 'next-error-last-buffer)
-(defvar compilation-parsing-end (make-marker))
-(defvar compilation-error-list nil)
-(defvar compilation-old-error-list nil)
-
-(defun compilation--compat-parse-errors (limit)
-  (when compilation-parse-errors-function
-    ;; FIXME: We should remove the rest of the compilation keywords
-    ;; but we can't do that from here because font-lock is using
-    ;; the value right now.  --Stef
-    (save-excursion
-      (setq compilation-error-list nil)
-      ;; Reset compilation-parsing-end each time because font-lock
-      ;; might force us the re-parse many times (typically because
-      ;; some code adds some text-property to the output that we
-      ;; already parsed).  You might say "why reparse", well:
-      ;; because font-lock has just removed the `compilation-message' property
-      ;; so have to do it all over again.
-      (if compilation-parsing-end
-         (set-marker compilation-parsing-end (point))
-       (setq compilation-parsing-end (point-marker)))
-      (condition-case nil
-         ;; Ignore any error: we're calling this function earlier than
-         ;; in the old compile.el so things might not all be setup yet.
-         (funcall compilation-parse-errors-function limit nil)
-       (error nil))
-      (dolist (err (if (listp compilation-error-list) compilation-error-list))
-       (let* ((src (car err))
-              (dst (cdr err))
-              (loc (cond ((markerp dst)
-                           (cons nil
-                                 (compilation--make-cdrloc nil nil dst)))
-                         ((consp dst)
-                           (cons (nth 2 dst)
-                                 (compilation--make-cdrloc
-                                  (nth 1 dst)
-                                  (cons (cdar dst) (caar dst))
-                                  nil))))))
-         (when loc
-           (goto-char src)
-           ;; (put-text-property src (line-end-position)
-            ;;                    'font-lock-face 'font-lock-warning-face)
-           (put-text-property src (line-end-position)
-                              'compilation-message
-                               (compilation--make-message loc 2 nil nil)))))))
-  (goto-char limit)
-  nil)
-
-;; Beware! this is not only compatibility code.  New code also uses it.  --Stef
 (defun compilation-forget-errors ()
   ;; In case we hit the same file/line specs, we want to recompute a new
   ;; marker for them, so flush our cache.
   (clrhash compilation-locs)
   (setq compilation-gcpro nil)
-  ;; FIXME: the old code reset the directory-stack, so maybe we should
-  ;; put a `directory change' marker of some sort, but where?  -stef
-  ;;
-  ;; FIXME: The old code moved compilation-current-error (which was
-  ;; virtually represented by a mix of compilation-parsing-end and
-  ;; compilation-error-list) to point-min, but that was only meaningful for
-  ;; the internal uses of compilation-forget-errors: all calls from external
-  ;; packages seem to be followed by a move of compilation-parsing-end to
-  ;; something equivalent to point-max.  So we heuristically move
-  ;; compilation-current-error to point-max (since the external package
-  ;; won't know that it should do it).  --Stef
   (setq compilation-current-error nil)
   (let* ((proc (get-buffer-process (current-buffer)))
         (mark (if proc (process-mark proc)))
@@ -3328,6 +3273,10 @@ TRUE-DIRNAME is the `file-truename' of DIRNAME, if 
given."
               (or compilation-auto-jump-to-first-error
                   (eq compilation-scroll-output 'first-error))))
 
+(define-obsolete-variable-alias 'compilation-last-buffer
+  ;; Sadly, we forgot to declare this obsolete back then :-(
+  'next-error-last-buffer "29.1 (tho really since 22.1)")
+
 (provide 'compile)
 
 ;;; compile.el ends here
diff --git a/lisp/progmodes/cperl-mode.el b/lisp/progmodes/cperl-mode.el
index e571cee83c..a3995e2969 100644
--- a/lisp/progmodes/cperl-mode.el
+++ b/lisp/progmodes/cperl-mode.el
@@ -1,6 +1,6 @@
 ;;; cperl-mode.el --- Perl code editing commands for Emacs  -*- 
lexical-binding:t -*-
 
-;; Copyright (C) 1985-1987, 1991-2022 Free Software Foundation, Inc.
+;; Copyright (C) 1985-2022 Free Software Foundation, Inc.
 
 ;; Author: Ilya Zakharevich
 ;;     Bob Olson
@@ -28,26 +28,14 @@
 
 ;;; Commentary:
 
-;; This version of the file contains support for the syntax added by
-;; the MooseX::Declare CPAN module, as well as Perl 5.10 keyword
-;; support.
-
-;; The latest version is available from
-;; https://github.com/jrockway/cperl-mode
-;;
-;; (perhaps in the moosex-declare branch)
-
 ;; You can either fine-tune the bells and whistles of this mode or
-;; bulk enable them by putting
+;; bulk enable them by putting this in your Init file:
 
-;; (setq cperl-hairy t)
-
-;; in your .emacs file.  (Emacs rulers do not consider it politically
-;; correct to make whistles enabled by default.)
+;;     (setq cperl-hairy t)
 
 ;; DO NOT FORGET to read micro-docs (available from `Perl' menu)   <<<<<<
-;; or as help on variables `cperl-tips', `cperl-problems',         <<<<<<
-;; `cperl-praise', `cperl-speed'.                                 <<<<<<
+;; or as help on variables `cperl-tips', `cperl-praise',           <<<<<<
+;; `cperl-speed'.                                                  <<<<<<
 ;;
 ;; Or search for "Short extra-docs" further down in this file for
 ;; details on how to use `cperl-mode' instead of `perl-mode' and lots
@@ -55,19 +43,18 @@
 
 ;; The mode information (on C-h m) provides some customization help.
 
-;; Faces used now: three faces for first-class and second-class keywords
+;; Faces used: three faces for first-class and second-class keywords
 ;; and control flow words, one for each: comments, string, labels,
 ;; functions definitions and packages, arrays, hashes, and variable
-;; definitions.  If you do not see all these faces, your font-lock does
-;; not define them, so you need to define them manually.
+;; definitions.
 
-;; This mode supports font-lock, imenu and mode-compile.  In the
-;; hairy version font-lock is on, but you should activate imenu
-;; yourself (note that mode-compile is not standard yet).  Well, you
-;; can use imenu from keyboard anyway (M-g i), but it is better
-;; to bind it like that:
+;; This mode supports imenu.  You can use imenu from the keyboard
+;; (M-g i), but you might prefer binding it like this:
+;;
+;;     (define-key global-map [M-S-down-mouse-3] #'imenu)
 
-;; (define-key global-map [M-S-down-mouse-3] 'imenu)
+;; This version supports the syntax added by the MooseX::Declare CPAN
+;; module, as well as Perl 5.10 keyword support.
 
 ;;; Code:
 
@@ -103,7 +90,7 @@
   (let (answer)
     (while list
       (or answer
-         (if (or (x-color-defined-p (car list))
+          (if (or (color-defined-p (car list))
                  (null (cdr list)))
              (setq answer (car list))))
       (setq list (cdr list)))
@@ -891,8 +878,9 @@ In regular expressions (including character classes):
 (and (vectorp cperl-del-back-ch) (= (length cperl-del-back-ch) 1)
      (setq cperl-del-back-ch (aref cperl-del-back-ch 0)))
 
-(defun cperl-putback-char (c)          ; Emacs 19
-  (push c unread-command-events))       ; Avoid undefined warning
+(defun cperl-putback-char (c)
+  (declare (obsolete nil "29.1"))
+  (push c unread-command-events))
 
 (defsubst cperl-put-do-not-fontify (from to &optional post)
   ;; If POST, do not do it with postponed fontification
@@ -1123,8 +1111,7 @@ Unless KEEP, removes the old indentation."
               (get-text-property (point) 'syntax-type))
             '(here-doc pod))]
      "----"
-     ["CPerl pretty print (experimental)" cperl-ps-print
-      (fboundp 'ps-extend-face-list)]
+     ["CPerl pretty print (experimental)" cperl-ps-print]
      "----"
      ["Syntaxify region" cperl-find-pods-heres-region
       (use-region-p)]
@@ -1137,15 +1124,6 @@ Unless KEEP, removes the old indentation."
      ["Class Hierarchy from TAGS" cperl-tags-hier-init t]
      ;;["Update classes" (cperl-tags-hier-init t) tags-table-list]
      ("Tags"
-      ;; ["Create tags for current file" cperl-etags t]
-      ;; ["Add tags for current file" (cperl-etags t) t]
-      ;; ["Create tags for Perl files in directory" (cperl-etags nil t) t]
-      ;; ["Add tags for Perl files in directory" (cperl-etags t t) t]
-      ;; ["Create tags for Perl files in (sub)directories"
-      ;;  (cperl-etags nil 'recursive) t]
-      ;; ["Add tags for Perl files in (sub)directories"
-      ;;  (cperl-etags t 'recursive) t])
-      ;; ;;? cperl-write-tags (&optional file erase recurse dir inbuffer)
       ["Create tags for current file" (cperl-write-tags nil t) t]
       ["Add tags for current file" (cperl-write-tags) t]
       ["Create tags for Perl files in directory"
@@ -1158,6 +1136,8 @@ Unless KEEP, removes the old indentation."
        (cperl-write-tags nil nil t t) t]))
     ("Perl docs"
      ["Define word at point" imenu-go-find-at-position
+      ;; This is from imenu-go.el.  I can't find it on any ELPA
+      ;; archive, so I'm not sure if it's still in use or not.
       (fboundp 'imenu-go-find-at-position)]
      ["Help on function" cperl-info-on-command t]
      ["Help on function at point" cperl-info-on-current-command t]
@@ -1322,7 +1302,7 @@ name, and one for the discovery of a following BLOCK.")
                ,cperl--ws+-rx
                (group-n 2 ,cperl--normal-identifier-rx))
     "A regular expression to detect a subroutine start.
-Contains three groups: One one to distinguish lexical from
+Contains three groups: One to distinguish lexical from
 \"normal\" subroutines, for the keyword \"sub\", and one for the
 subroutine name.")
 
@@ -1893,25 +1873,6 @@ or as help on variables `cperl-tips', `cperl-problems',
          (cperl-make-indent comment-column 1) ; Indent min 1
          c)))))
 
-;;(defun cperl-comment-indent-fallback ()
-;;  "Is called if the standard comment-search procedure fails.
-;;Point is at start of real comment."
-;;  (let ((c (current-column)) target cnt prevc)
-;;    (if (= c comment-column) nil
-;;      (setq cnt (skip-chars-backward " \t"))
-;;      (setq target (max (1+ (setq prevc
-;;                          (current-column))) ; Else indent at comment column
-;;                comment-column))
-;;      (if (= c comment-column) nil
-;;     (delete-backward-char cnt)
-;;     (while (< prevc target)
-;;       (insert "\t")
-;;       (setq prevc (current-column)))
-;;     (if (> prevc target) (progn (delete-char -1) (setq prevc 
(current-column))))
-;;     (while (< prevc target)
-;;       (insert " ")
-;;       (setq prevc (current-column)))))))
-
 (defun cperl-indent-for-comment ()
   "Substitute for `indent-for-comment' in CPerl."
   (interactive)
@@ -2120,7 +2081,7 @@ Affected by `cperl-electric-parens'."
   "Insert a construction appropriate after a keyword.
 Help message may be switched off by setting `cperl-message-electric-keyword'
 to nil."
-  (let ((beg (point-at-bol))
+  (let ((beg (line-beginning-position))
        (dollar (and (eq last-command-event ?$)
                     (eq this-command 'self-insert-command)))
        (delete (and (memq last-command-event '(?\s ?\n ?\t ?\f))
@@ -2183,7 +2144,7 @@ to nil."
                   (delete-char -1)
                   (delete-char 1))))
           (if delete
-              (cperl-putback-char cperl-del-back-ch))
+               (push cperl-del-back-ch unread-command-events))
           (if cperl-message-electric-keyword
               (message "Precede char by C-q to avoid expansion"))))))
 
@@ -2257,13 +2218,13 @@ to nil."
                 (end-of-line)
                 (setq really-delete t)))
           (if (and delete really-delete)
-              (cperl-putback-char cperl-del-back-ch))))))
+               (push cperl-del-back-ch unread-command-events))))))
 
 (defun cperl-electric-else ()
   "Insert a construction appropriate after a keyword.
 Help message may be switched off by setting `cperl-message-electric-keyword'
 to nil."
-  (let ((beg (point-at-bol)))
+  (let ((beg (line-beginning-position)))
     (and (save-excursion
            (skip-chars-backward "[:alpha:]")
           (cperl-after-expr-p nil "{;:"))
@@ -2294,7 +2255,7 @@ to nil."
           (cperl-indent-line)
           (forward-line -1)
           (cperl-indent-line)
-          (cperl-putback-char cperl-del-back-ch)
+           (push cperl-del-back-ch unread-command-events)
           (setq this-command 'cperl-electric-else)
           (if cperl-message-electric-keyword
               (message "Precede char by C-q to avoid expansion"))))))
@@ -2303,8 +2264,8 @@ to nil."
   "Go to end of line, open a new line and indent appropriately.
 If in POD, insert appropriate lines."
   (interactive)
-  (let ((beg (point-at-bol))
-       (end (point-at-eol))
+  (let ((beg (line-beginning-position))
+        (end (line-end-position))
        (pos (point)) start over cut res)
     (if (and                           ; Check if we need to split:
                                        ; i.e., on a boundary and inside "{...}"
@@ -2382,8 +2343,8 @@ If in POD, insert appropriate lines."
                   (forward-paragraph -1)
                   (forward-word-strictly 1)
                   (setq pos (point))
-                  (setq cut (buffer-substring (point) (point-at-eol)))
-                  (delete-char (- (point-at-eol) (point)))
+                   (setq cut (buffer-substring (point) (line-end-position)))
+                   (delete-char (- (line-end-position) (point)))
                   (setq res (expand-abbrev))
                   (save-excursion
                     (goto-char pos)
@@ -2862,7 +2823,7 @@ Will not look before LIM."
                                        (point-max)))) ; do not loop if no 
syntaxification
                                  ;; label:
                                  (t
-                                  (setq colon-line-end (point-at-eol))
+                                   (setq colon-line-end (line-end-position))
                                   (search-forward ":"))))
                          ;; We are at beginning of code (NOT label or comment)
                          ;; First, the following code counts
@@ -2905,7 +2866,7 @@ Will not look before LIM."
                                    (looking-at (concat cperl-sub-regexp 
"\\>"))))
                             (setq p (nth 1 ; start of innermost containing list
                                          (parse-partial-sexp
-                                          (point-at-bol)
+                                           (line-beginning-position)
                                           (point)))))
                            (progn
                              (goto-char (1+ p)) ; enclosing block on the same 
line
@@ -3148,7 +3109,7 @@ comment."
 Returns true if comment is found.  In POD will not move the point."
   ;; If the line is inside other syntax groups (qq-style strings, HERE-docs)
   ;; then looks for literal # or end-of-line.
-  (let (state stop-in cpoint (lim (point-at-eol)) pr e)
+  (let (state stop-in cpoint (lim (line-end-position)) pr e)
     (or cperl-font-locking
        (cperl-update-syntaxification lim))
     (beginning-of-line)
@@ -4059,7 +4020,8 @@ recursive calls in starting lines of here-documents."
                             "")
                      tb (match-beginning 0))
                (setq argument nil)
-               (put-text-property (point-at-bol) b 'first-format-line 't)
+                (put-text-property (line-beginning-position)
+                                   b 'first-format-line 't)
                (if cperl-pod-here-fontify
                    (while (and (eq (forward-line) 0)
                                (not (looking-at "^[.;]$")))
@@ -5035,7 +4997,7 @@ If `cperl-indent-region-fix-constructs', will improve 
spacing on
 conditional/loop constructs."
   (interactive)
   (save-excursion
-    (let ((tmp-end (point-at-eol)) top done)
+    (let ((tmp-end (line-end-position)) top done)
       (save-excursion
        (beginning-of-line)
        (while (null done)
@@ -5085,9 +5047,9 @@ conditional/loop constructs."
                           "\\<\\(else\\|elsif\\|continue\\)\\>"))
                  (progn
                    (goto-char (match-end 0))
-                   (setq tmp-end (point-at-eol)))
+                    (setq tmp-end (line-end-position)))
                (setq done t))))
-         (setq tmp-end (point-at-eol)))
+          (setq tmp-end (line-end-position)))
        (goto-char tmp-end)
        (setq tmp-end (point-marker)))
       (if cperl-indent-region-fix-constructs
@@ -5100,7 +5062,7 @@ Returns some position at the last line."
   (interactive)
   (or end
       (setq end (point-max)))
-  (let ((ee (point-at-eol))
+  (let ((ee (line-end-position))
        (cperl-indent-region-fix-constructs
         (or cperl-indent-region-fix-constructs 1))
        p pp ml have-brace ret)
@@ -5276,7 +5238,7 @@ Returns some position at the last line."
                                (if (cperl-indent-line parse-data)
                                    (setq ret (cperl-fix-line-spacing end 
parse-data)))))))))))
        (beginning-of-line)
-       (setq p (point) pp (point-at-eol)) ; May be different from ee.
+        (setq p (point) pp (line-end-position)) ; May be different from ee.
        ;; Now check whether there is a hanging `}'
        ;; Looking at:
        ;; } blah
@@ -6035,7 +5997,7 @@ default function."
                cperl-font-lock-keywords-2 (append
                                           t-font-lock-keywords-1
                                           cperl-font-lock-keywords-1)))
-       (if (fboundp 'ps-print-buffer) (cperl-ps-print-init))
+        (cperl-ps-print-init)
        (setq cperl-faces-init t))
     (error (message "cperl-init-faces (ignored): %s" errs))))
 
@@ -7161,13 +7123,6 @@ One may build such TAGS files from CPerl mode menu."
               (sort root-packages (default-value 'imenu-sort-function)))
            root-packages))))
 
-;;(x-popup-menu t
-;;   '(keymap "Name1"
-;;         ("Ret1" "aa")
-;;         ("Head1" "ab"
-;;          keymap "Name2"
-;;          ("Tail1" "x") ("Tail2" "y"))))
-
 (defun cperl-list-fold (list name limit)
   (let (list1 list2 elt1 (num 0))
     (if (<= (length list) limit) list
@@ -7328,7 +7283,7 @@ Currently it is tuned to C and Perl syntax."
   ;; Get to the something meaningful
   (or (eobp) (eolp) (forward-char 1))
   (re-search-backward "[-[:alnum:]_:!&*+,./<=>?\\^|~$%@]"
-                     (point-at-bol)
+                      (line-beginning-position)
                      'to-beg)
   ;;  (cond
   ;;   ((or (eobp) (looking-at "[][ \t\n{}();,]")) ; Not at a symbol
@@ -8420,10 +8375,12 @@ the appropriate statement modifier."
   (interactive)
   (cperl-perldoc (cperl-word-at-point)))
 
-(defcustom pod2man-program "pod2man"
+(define-obsolete-variable-alias 'pod2man-program 'cperl-pod2man-program "29.1")
+(defcustom cperl-pod2man-program "pod2man"
   "File name for `pod2man'."
   :type 'file
-  :group 'cperl)
+  :group 'cperl
+  :version "29.1")
 
 ;; By Nick Roberts <Nick.Roberts@src.bae.co.uk> (with changes)
 (defun cperl-pod-to-manpage ()
@@ -8442,7 +8399,6 @@ the appropriate statement modifier."
                         (format (cperl-pod2man-build-command) pod2man-args))
          'Man-bgproc-sentinel)))))
 
-;; Updated version by him too
 (defun cperl-build-manpage ()
   "Create a virtual manpage in Emacs from the POD in the file."
   (interactive)
@@ -8579,8 +8535,8 @@ POS defaults to the point."
   (let ((p (cperl-get-here-doc-region pos)))
     (or p (error "Not inside a HERE document"))
     (narrow-to-region (car p) (cdr p))
-    (message
-     "When you are finished with narrow editing, type C-x n w")))
+    (message (substitute-command-keys
+              "When you are finished with narrow editing, type \\[widen]"))))
 
 (defun cperl-select-this-pod-or-here-doc (&optional pos)
   "Select the HERE-DOC (or POD section) at POS.
diff --git a/lisp/progmodes/cwarn.el b/lisp/progmodes/cwarn.el
index 971e3f6174..03469b9f55 100644
--- a/lisp/progmodes/cwarn.el
+++ b/lisp/progmodes/cwarn.el
@@ -180,9 +180,6 @@ C++ modes are included."
   (cwarn-font-lock-keywords cwarn-mode)
   (font-lock-flush))
 
-;;;###autoload
-(define-obsolete-function-alias 'turn-on-cwarn-mode 'cwarn-mode "24.1")
-
 ;;}}}
 ;;{{{ Help functions
 
diff --git a/lisp/progmodes/ebnf2ps.el b/lisp/progmodes/ebnf2ps.el
index 96cbcba9be..6e42da2d54 100644
--- a/lisp/progmodes/ebnf2ps.el
+++ b/lisp/progmodes/ebnf2ps.el
@@ -4,7 +4,7 @@
 
 ;; Author: Vinicius Jose Latorre <viniciusjl.gnu@gmail.com>
 ;; Keywords: wp, ebnf, PostScript
-;; Version: 4.4
+;; Old-Version: 4.4
 ;; URL: https://www.emacswiki.org/cgi-bin/wiki/ViniciusJoseLatorre
 
 ;; This file is part of GNU Emacs.
@@ -22,16 +22,6 @@
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
-(defconst ebnf-version "4.4"
-  "ebnf2ps.el, v 4.4 <2007/02/12 vinicius>
-
-Vinicius's last change version.  When reporting bugs, please also
-report the version of Emacs, if any, that ebnf2ps was running with.
-
-Please send all bug fixes and enhancements to
-       Vinicius Jose Latorre <viniciusjl.gnu@gmail.com>.")
-
-
 ;;; Commentary:
 
 ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -45,20 +35,12 @@ Please send all bug fixes and enhancements to
 ;;
 ;;        (require 'ebnf2ps)
 ;;
-;; ebnf2ps uses ps-print package (version 5.2.3 or later), so see ps-print to
+;; ebnf2ps uses ps-print package (bundled with Emacs), so see ps-print to
 ;; know how to set options like landscape printing, page headings, margins,
 ;; etc.
 ;;
-;; NOTE: ps-print zebra stripes and line number options doesn't have effect on
-;;       ebnf2ps, they behave as it's turned off.
-;;
-;; For good performance, be sure to byte-compile ebnf2ps.el, e.g.
-;;
-;;    M-x byte-compile-file <give the path to ebnf2ps.el when prompted>
-;;
-;; This will generate ebnf2ps.elc, which will be loaded instead of ebnf2ps.el.
-;;
-;; ebnf2ps was tested with GNU Emacs 20.4.1.
+;; NOTE: ps-print zebra stripes and line number options don't have an
+;;       effect on ebnf2ps, they behave as if it's turned off.
 ;;
 ;;
 ;; Using ebnf2ps
@@ -1154,9 +1136,6 @@ Please send all bug fixes and enhancements to
 (require 'ps-print)
 (eval-when-compile (require 'cl-lib))
 
-(and (string< ps-print-version "5.2.3")
-     (error "`ebnf2ps' requires `ps-print' package version 5.2.3 or later"))
-
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; User Variables:
@@ -2037,7 +2016,6 @@ It must be a float between 0.0 (top) and 1.0 (bottom)."
   :group 'ebnf2ps)
 
 
-;; Printing color requires x-color-values.
 (defcustom ebnf-color-p t
   "Non-nil means use color."
   :type 'boolean
@@ -2456,8 +2434,6 @@ See also `ebnf-syntax-buffer'."
   "Return the current ebnf2ps setup."
   (format
    "
-;;; ebnf2ps.el version %s
-
 ;;; Emacs version %S
 
 \(setq ebnf-special-show-delimiter      %S
@@ -2526,7 +2502,6 @@ See also `ebnf-syntax-buffer'."
 
 ;;; ebnf2ps.el - end of settings
 "
-   ebnf-version
    emacs-version
    ebnf-special-show-delimiter
    (ps-print-quote ebnf-special-font)
@@ -2959,7 +2934,7 @@ See section \"Actions in Comments\" in ebnf2ps 
documentation.")
 
 
 (defvar ebnf-eps-file-alist nil
-"Alist associating file name with EPS header and footer.
+  "Alist associating file name with EPS header and footer.
 
 Each element has the following form:
 
@@ -4524,7 +4499,7 @@ end
 
 (defun ebnf-generate-eps (tree)
   (let* ((ebnf-tree tree)
-         (ps-color-p           (and ebnf-color-p (ps-color-device)))
+         (ps-color-p           (and ebnf-color-p (display-color-p)))
         (ps-print-color-scale (if ps-color-p
                                   (float (car (color-values "white")))
                                 1.0))
@@ -4626,7 +4601,7 @@ end
 
 (defun ebnf-generate (tree)
   (let* ((ebnf-tree tree)
-         (ps-color-p           (and ebnf-color-p (ps-color-device)))
+         (ps-color-p           (and ebnf-color-p (display-color-p)))
         (ps-print-color-scale (if ps-color-p
                                   (float (car (color-values "white")))
                                 1.0))
@@ -5243,11 +5218,7 @@ killed after process termination."
         (not (search-forward "& ebnf2ps v"
                              (line-end-position)
                              t))
-        (progn
-          ;; adjust creator comment
-          (end-of-line)
-          ;; (backward-char)
-          (insert " & ebnf2ps v" ebnf-version)
+         (progn
           ;; insert ebnf settings & engine
           (goto-char (point-max))
           (search-backward "\n%%EndProlog\n")
@@ -5273,7 +5244,7 @@ killed after process termination."
        (format "%d %d" (1+ ebnf-eps-upper-x) (1+ ebnf-eps-upper-y))
        "\n%%Title: " filename
        "\n%%CreationDate: " (format-time-string "%T %b %d %Y")
-       "\n%%Creator: " (user-full-name) " (using ebnf2ps v" ebnf-version ")"
+       "\n%%Creator: " (user-full-name) " (using GNU Emacs " emacs-version ")"
        "\n%%DocumentNeededResources: font "
        (or ebnf-fonts-required
           (setq ebnf-fonts-required
@@ -6351,6 +6322,15 @@ killed after process termination."
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
+(defconst ebnf-version "4.4"
+  "ebnf2ps.el, v 4.4 <2007/02/12 vinicius>
+
+Vinicius's last change version.  When reporting bugs, please also
+report the version of Emacs, if any, that ebnf2ps was running with.
+
+Please send all bug fixes and enhancements to
+  bug-gnu-emacs@gnu.org and Vinicius Jose Latorre <viniciusjl.gnu@gmail.com>.")
+(make-obsolete-variable 'ebnf-version 'emacs-version "29.1")
 
 (provide 'ebnf2ps)
 
diff --git a/lisp/progmodes/ebrowse.el b/lisp/progmodes/ebrowse.el
index 16069f75ae..16b2f3ff50 100644
--- a/lisp/progmodes/ebrowse.el
+++ b/lisp/progmodes/ebrowse.el
@@ -996,7 +996,7 @@ if for some reason a circle is in the inheritance graph."
 Each line corresponds to a class in a class tree.
 Letters do not insert themselves, they are commands.
 File operations in the tree buffer work on class tree data structures.
-E.g.\\[save-buffer] writes the tree to the file it was loaded from.
+E.g. \\[save-buffer] writes the tree to the file it was loaded from.
 
 Tree mode key bindings:
 \\{ebrowse-tree-mode-map}"
diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el
index 5989e1161b..4ada27a1ac 100644
--- a/lisp/progmodes/elisp-mode.el
+++ b/lisp/progmodes/elisp-mode.el
@@ -31,6 +31,7 @@
 (require 'cl-generic)
 (require 'lisp-mode)
 (eval-when-compile (require 'cl-lib))
+(eval-when-compile (require 'subr-x))
 
 (define-abbrev-table 'emacs-lisp-mode-abbrev-table ()
   "Abbrev table for Emacs Lisp mode.
@@ -51,6 +52,9 @@ All commands in `lisp-mode-shared-map' are inherited by this 
map."
   :parent lisp-mode-shared-map
   "M-TAB" #'completion-at-point
   "C-M-x" #'eval-defun
+  "C-c C-e" #'elisp-eval-buffer
+  "C-c C-f" #'elisp-byte-compile-file
+  "C-c C-b" #'elisp-byte-compile-buffer
   "C-M-q" #'indent-pp-sexp)
 
 (easy-menu-define emacs-lisp-mode-menu emacs-lisp-mode-map
@@ -379,7 +383,9 @@ be used instead.
                      (setq sexp nil))
                     (`(lambda ,args . ,body)
                      (elisp--local-variables-1
-                      (append (remq '&optional (remq '&rest args)) vars)
+                      (let ((args (if (listp args) args)))
+                        ;; FIXME: Exit the loop if witness is in args.
+                        (append (remq '&optional (remq '&rest args)) vars))
                       (car (last body))))
                     (`(condition-case ,_ ,e) (elisp--local-variables-1 vars e))
                     (`(condition-case ,v ,_ . ,catches)
@@ -1226,6 +1232,8 @@ All commands in `lisp-mode-shared-map' are inherited by 
this map."
   :parent lisp-mode-shared-map
   "C-M-x" #'eval-defun
   "C-M-q" #'indent-pp-sexp
+  "C-c C-e" #'elisp-eval-buffer
+  "C-c C-b" #'elisp-byte-compile-buffer
   "M-TAB" #'completion-at-point
   "C-j"   #'eval-print-last-sexp)
 
@@ -1638,6 +1646,7 @@ Return the result of evaluation."
   ;; printing, not while evaluating.
   (defvar elisp--eval-defun-result)
   (let ((debug-on-error eval-expression-debug-on-error)
+        (edebugging edebug-all-defs)
         elisp--eval-defun-result)
     (save-excursion
       ;; Arrange for eval-region to "read" the (possibly) altered form.
@@ -1662,8 +1671,9 @@ Return the result of evaluation."
                          (elisp--eval-defun-1
                           (macroexpand form)))))
              (print-length eval-expression-print-length)
-             (print-level eval-expression-print-level))
-          (eval-region beg end standard-output
+             (print-level eval-expression-print-level)
+              (should-print (if (not edebugging) standard-output)))
+          (eval-region beg end should-print
                        (lambda (_ignore)
                          ;; Skipping to the end of the specified region
                          ;; will make eval-region return.
@@ -1678,7 +1688,10 @@ Return the result of evaluation."
     elisp--eval-defun-result))
 
 (defun eval-defun (edebug-it)
-  "Evaluate the top-level form containing point, or after point.
+  "Evaluate the top-level form containing point.
+If point isn't in a top-level form, evaluate the first top-level
+form after point.  If there is no top-level form after point,
+eval the first preceeding top-level form.
 
 If the current defun is actually a call to `defvar' or `defcustom',
 evaluating it this way resets the variable using its initial value
@@ -1743,7 +1756,7 @@ which see."
 (defalias 'elisp-eldoc-documentation-function 'elisp--documentation-one-liner
   "Return Elisp documentation for the thing at point as one-line string.
 This is meant as a backward compatibility aide to the \"old\"
-Elisp eldoc behaviour.  Consider variable docstrings and function
+Elisp eldoc behavior.  Consider variable docstrings and function
 signatures only, in this order.  If none applies, returns nil.
 Changes to `eldoc-documentation-functions' and
 `eldoc-documentation-strategy' are _not_ reflected here.  As such
@@ -1890,7 +1903,7 @@ or elsewhere, return a 1-line docstring."
           ;; go to the arg after `&rest'.
           (if (and key-have-value
                    (save-excursion
-                     (not (re-search-forward ":.*" (point-at-eol) t)))
+                     (not (re-search-forward ":.*" (line-end-position) t)))
                    (string-match "&rest \\([^ ()]*\\)" args))
               (setq index nil ; Skip next block based on positional args.
                     start (match-beginning 1)
@@ -2190,6 +2203,67 @@ Runs in a batch-mode Emacs.  Interactively use variable
     (terpri)
     (pp collected)))
 
+(defun elisp-eval-buffer ()
+  "Evaluate the forms in the current buffer."
+  (interactive)
+  (eval-buffer)
+  (message "Evaluated the %s buffer" (buffer-name)))
+
+(defun elisp-byte-compile-file (&optional load)
+  "Byte compile the file the current buffer is visiting.
+If LOAD is non-nil, load the resulting .elc file.  When called
+interactively, this is the prefix argument."
+  (interactive "P")
+  (unless buffer-file-name
+    (error "This buffer is not visiting a file"))
+  (byte-compile-file buffer-file-name)
+  (when load
+    (load (funcall byte-compile-dest-file-function buffer-file-name))))
+
+(defun elisp-byte-compile-buffer (&optional load)
+  "Byte compile the current buffer, but don't write a file.
+If LOAD is non-nil, load byte-compiled data.  When called
+interactively, this is the prefix argument."
+  (interactive "P")
+  (let ((bfn buffer-file-name)
+        file elc)
+    (require 'bytecomp)
+    (unwind-protect
+        (progn
+          (setq file (make-temp-file "compile" nil ".el")
+                elc (funcall byte-compile-dest-file-function file))
+          (write-region (point-min) (point-max) file nil 'silent)
+          (let ((set-message-function
+                 (lambda (message)
+                   (when (string-match-p "\\`Wrote " message)
+                     'ignore)))
+                (byte-compile-log-warning-function
+                 (lambda (string position &optional fill level)
+                   (if bfn
+                       ;; Massage the warnings to that they point to
+                       ;; this file, not the one in /tmp.
+                       (let ((byte-compile-current-file bfn)
+                             (byte-compile-root-dir (file-name-directory bfn)))
+                         (byte-compile--log-warning-for-byte-compile
+                          string position fill level))
+                     ;; We don't have a file name, so the warnings
+                     ;; will point to a file that doesn't exist.  This
+                     ;; should be fixed in some way.
+                     (byte-compile--log-warning-for-byte-compile
+                      string position fill level)))))
+            (byte-compile-file file))
+          (when (and bfn (get-buffer "*Compile-Log*"))
+            (with-current-buffer "*Compile-Log*"
+              (setq default-directory (file-name-directory bfn))))
+          (if load
+              (load elc)
+            (message "Byte-compiled the current buffer")))
+      (when file
+        (when (file-exists-p file)
+          (delete-file file))
+        (when (file-exists-p elc)
+          (delete-file elc))))))
+
 
 (put 'read-symbol-shorthands 'safe-local-variable #'consp)
 
diff --git a/lisp/progmodes/etags.el b/lisp/progmodes/etags.el
index 7766694edf..db2c8efbd4 100644
--- a/lisp/progmodes/etags.el
+++ b/lisp/progmodes/etags.el
@@ -1144,7 +1144,7 @@ error message."
              ;; Naive match found.  Qualify the match.
              (and (funcall (car order) pattern)
                   ;; Make sure it is not a previous qualified match.
-                  (not (member (set-marker match-marker (point-at-bol))
+                   (not (member (set-marker match-marker 
(line-beginning-position))
                                tag-lines-already-matched))
                   (throw 'qualified-match-found nil))
              (if next-line-after-failure-p
@@ -1314,11 +1314,11 @@ buffer-local values of tags table format variables."
 
       ;; Find the end of the tag and record the whole tag text.
       (search-forward "\177")
-      (setq tag-text (buffer-substring (1- (point)) (point-at-bol)))
+      (setq tag-text (buffer-substring (1- (point)) (line-beginning-position)))
       ;; If use-explicit is non-nil and explicit tag is present, use it as 
part of
       ;; return value. Else just skip it.
       (setq explicit-start (point))
-      (when (and (search-forward "\001" (point-at-bol 2) t)
+      (when (and (search-forward "\001" (line-beginning-position 2) t)
                 use-explicit)
        (setq tag-text (buffer-substring explicit-start (1- (point)))))
 
@@ -1705,7 +1705,7 @@ Point should be just after a string that matches TAG."
 ;;;###autoload
 (defalias 'next-file 'tags-next-file)
 (make-obsolete 'next-file
-               "use tags-next-file or fileloop-initialize and 
fileloop-next-file instead" "27.1")
+               "use `tags-next-file' or `fileloop-initialize' and 
`fileloop-next-file' instead" "27.1")
 ;;;###autoload
 (defun tags-next-file (&optional initialize novisit)
   "Select next file among files in current tags table.
diff --git a/lisp/progmodes/f90.el b/lisp/progmodes/f90.el
index dcd74f0369..443281c4f0 100644
--- a/lisp/progmodes/f90.el
+++ b/lisp/progmodes/f90.el
@@ -116,12 +116,11 @@
 ;;    non-nil, the line numbers are never touched.
 ;; 2) Multi-; statements like "do i=1,20 ; j=j+i ; end do" are not handled
 ;;    correctly, but I imagine them to be rare.
-;; 3) Regexps for hilit19 are no longer supported.
-;; 4) For FIXED FORMAT code, use fortran mode.
-;; 5) Preprocessor directives, i.e., lines starting with # are left-justified
+;; 3) For FIXED FORMAT code, use fortran mode.
+;; 4) Preprocessor directives, i.e., lines starting with # are left-justified
 ;;    and are untouched by all case-changing commands.  There is, at present, 
no
 ;;    mechanism for treating multi-line directives (continued by \ ).
-;; 6) f77 do-loops do 10 i=.. ; ; 10 continue are not correctly indented.
+;; 5) f77 do-loops do 10 i=.. ; ; 10 continue are not correctly indented.
 ;;    You are urged to use f90-do loops (with labels if you wish).
 
 ;; List of user commands
diff --git a/lisp/progmodes/flymake-proc.el b/lisp/progmodes/flymake-proc.el
index 4ab16831bc..249ae9dff2 100644
--- a/lisp/progmodes/flymake-proc.el
+++ b/lisp/progmodes/flymake-proc.el
@@ -399,10 +399,7 @@ instead of reading master file from disk."
                    (not (string-match (format "\\.%s\\'" source-file-extension)
                                       inc-name))
                    (setq inc-name (concat inc-name "." source-file-extension)))
-              (when (eq t (compare-strings
-                           source-file-nondir nil nil
-                           inc-name (- (length inc-name)
-                                       (length source-file-nondir)) nil))
+              (when (string-suffix-p source-file-nondir inc-name)
                 (flymake-log 3 "inc-name=%s" inc-name)
                 (when (flymake-proc--check-include source-file-name inc-name
                                                    include-dirs)
diff --git a/lisp/progmodes/flymake.el b/lisp/progmodes/flymake.el
index 0b7958e52f..15ee5cb7d5 100644
--- a/lisp/progmodes/flymake.el
+++ b/lisp/progmodes/flymake.el
@@ -1678,9 +1678,9 @@ the file they refer to is visited and `flymake-mode' is 
turned on
 in the resulting buffer.
 
 Flymake backends that somehow gain sporadic information about
-diagnostics in neighbouring files may freely modify this variable
+diagnostics in neighboring files may freely modify this variable
 by adding or removing entries to for those files.  If the
-information about those neighbouring files is acquired repeatedly
+information about those neighboring files is acquired repeatedly
 and reliably, it may be more sensible to report them as
 \"foreign\" diagnostics instead.
 
diff --git a/lisp/progmodes/fortran.el b/lisp/progmodes/fortran.el
index 786c5ae804..58d7a2026e 100644
--- a/lisp/progmodes/fortran.el
+++ b/lisp/progmodes/fortran.el
@@ -1117,7 +1117,7 @@ Auto-indent does not happen if a numeric ARG is used."
                  (eq ?\t (char-after (line-beginning-position)))
                  (not (or (eq last-command 'fortran-indent-line)
                           (eq last-command
-                              'fortran-indent-new-line))))
+                              'reindent-then-newline-and-indent))))
             (save-excursion
               (re-search-backward "[^ \t0-9]"
                                   (line-beginning-position)
@@ -1586,10 +1586,6 @@ Return point or nil."
         (if (< (current-column) cfi)
             (move-to-column cfi)))))
 
-;; Historically this was a separate function which advertised itself
-;; as reindenting but only did so where `most likely to be necessary'.
-(defalias 'fortran-indent-new-line 'reindent-then-newline-and-indent)
-
 (defun fortran-indent-subprogram ()
   "Properly indent the Fortran subprogram containing point."
   (interactive "*")
@@ -1926,9 +1922,6 @@ If ALL is nil, only match comments that start in column > 
0."
           ;; Result.
           (nth 3 parse-state))))))
 
-;; From old version.
-(defalias 'fortran-auto-fill-mode 'auto-fill-mode)
-
 (defun fortran-fill ()
   "Fill the current line at an appropriate point(s)."
   (let* ((auto-fill-function #'fortran-auto-fill)
@@ -2215,6 +2208,9 @@ arg DO-SPACE prevents stripping the whitespace."
      :active   (not (lookup-key (current-local-map) [menu-bar index]))
      :help "Add an index menu to the menu-bar"]))
 
+(define-obsolete-function-alias 'fortran-indent-new-line 
#'reindent-then-newline-and-indent "29.1")
+(define-obsolete-function-alias 'fortran-auto-fill-mode #'auto-fill-mode 
"29.1")
+
 (provide 'fortran)
 
 ;;; fortran.el ends here
diff --git a/lisp/progmodes/gdb-mi.el b/lisp/progmodes/gdb-mi.el
index 79ef6101e9..bab80719db 100644
--- a/lisp/progmodes/gdb-mi.el
+++ b/lisp/progmodes/gdb-mi.el
@@ -92,6 +92,7 @@
 (require 'cl-seq)
 (require 'bindat)
 (eval-when-compile (require 'pcase))
+(require 'subr-x)   ; `string-pad'
 
 (declare-function speedbar-change-initial-expansion-list
                   "speedbar" (new-default))
@@ -126,9 +127,9 @@ Possible value: main, $rsp, x+3.")
   "Address of memory display.")
 (defvar-local gdb-memory-last-address nil
   "Last successfully accessed memory address.")
-(defvar        gdb-memory-next-page nil
+(defvar gdb-memory-next-page nil
   "Address of next memory page for program memory buffer.")
-(defvar        gdb-memory-prev-page nil
+(defvar gdb-memory-prev-page nil
   "Address of previous memory page for program memory buffer.")
 (defvar-local gdb--memory-display-warning nil
   "Display warning on memory header if t.
@@ -684,7 +685,7 @@ Note that this variable only takes effect when variable
 Until there are such number of source windows on screen, GDB
 tries to open a new window when visiting a new source file; after
 that GDB starts to reuse existing source windows."
-  :type 'number
+  :type 'natnum
   :group 'gdb
   :version "28.1")
 
@@ -2112,7 +2113,7 @@ is running."
            (not (null gdb-running-threads-count))
            (> gdb-running-threads-count 0))))
 
-;; GUD displays the selected GDB frame.  This might might not be the current
+;; GUD displays the selected GDB frame.  This might not be the current
 ;; GDB frame (after up, down etc).  If no GDB frame is visible but the last
 ;; visited breakpoint is, use that window.
 (defun gdb-display-source-buffer (buffer)
@@ -2511,9 +2512,8 @@ means to decode using the coding-system set for the GDB 
process."
   ;; Record transactions if logging is enabled.
   (when gdb-enable-debug
     (push (cons 'recv string) gdb-debug-log)
-    (if (and gdb-debug-log-max
-            (> (length gdb-debug-log) gdb-debug-log-max))
-       (setcdr (nthcdr (1- gdb-debug-log-max) gdb-debug-log) nil)))
+    (when gdb-debug-log-max
+      (setq gdb-debug-log (ntake gdb-debug-log-max gdb-debug-log))))
 
   ;; Recall the left over gud-marker-acc from last time.
   (setq gud-marker-acc (concat gud-marker-acc string))
@@ -2817,7 +2817,7 @@ END-CHAR is the ending delimiter; will stop at 
end-of-buffer otherwise."
               pieces)
         (forward-char))
        (t
-        (warn "Unrecognised escape char: %c" (following-char))))
+        (warn "Unrecognized escape char: %c" (following-char))))
       (setq start (point)))
     (push (buffer-substring start (1- (point))) pieces)
     (let ((s (apply #'concat (nreverse pieces))))
@@ -2943,7 +2943,7 @@ Return position where LINE begins."
        start-posn)))
 
 (defun gdb-pad-string (string padding)
-  (format (concat "%" (number-to-string padding) "s") string))
+  (string-pad string (abs padding) nil (natnump padding)))
 
 ;; gdb-table struct is a way to programmatically construct simple
 ;; tables. It help to reliably align columns of data in GDB buffers
@@ -2961,8 +2961,7 @@ When non-nil, PROPERTIES will be added to the whole row 
when
 calling `gdb-table-string'."
   (let ((rows (gdb-table-rows table))
         (row-properties (gdb-table-row-properties table))
-        (column-sizes (gdb-table-column-sizes table))
-        (right-align (gdb-table-right-align table)))
+        (column-sizes (gdb-table-column-sizes table)))
     (when (not column-sizes)
       (setf (gdb-table-column-sizes table)
             (make-list (length row) 0)))
@@ -2972,9 +2971,7 @@ calling `gdb-table-string'."
           (append row-properties (list properties)))
     (setf (gdb-table-column-sizes table)
           (cl-mapcar (lambda (x s)
-                         (let ((new-x
-                                (max (abs x) (string-width (or s "")))))
-                           (if right-align new-x (- new-x))))
+                       (max (abs x) (string-width (or s ""))))
                        (gdb-table-column-sizes table)
                        row))
     ;; Avoid trailing whitespace at eol
@@ -2985,13 +2982,16 @@ calling `gdb-table-string'."
   "Return TABLE as a string with columns separated with SEP."
   (let ((column-sizes (gdb-table-column-sizes table)))
     (mapconcat
-     'identity
+     #'identity
      (cl-mapcar
       (lambda (row properties)
-        (apply 'propertize
-               (mapconcat 'identity
-                          (cl-mapcar (lambda (s x) (gdb-pad-string s x))
-                                       row column-sizes)
+        (apply #'propertize
+               (mapconcat #'identity
+                          (cl-mapcar (lambda (s x)
+                                       (string-pad
+                                        s x nil
+                                        (not (gdb-table-right-align table))))
+                                     row column-sizes)
                           sep)
                properties))
       (gdb-table-rows table)
@@ -3688,10 +3688,11 @@ in `gdb-memory-format'."
           (dolist (row memory)
             (insert (concat (gdb-mi--field row 'addr) ":"))
             (dolist (column (gdb-mi--field row 'data))
-              (insert (gdb-pad-string column
-                                      (+ 2 (gdb-memory-column-width
-                                            gdb-memory-unit
-                                            gdb-memory-format)))))
+              (insert (string-pad column
+                                  (+ 2 (gdb-memory-column-width
+                                        gdb-memory-unit
+                                        gdb-memory-format))
+                                  nil t)))
             (newline)))
       ;; Show last page instead of empty buffer when out of bounds
       (when gdb-memory-last-address
diff --git a/lisp/progmodes/glasses.el b/lisp/progmodes/glasses.el
index f760ccf368..c7b0587336 100644
--- a/lisp/progmodes/glasses.el
+++ b/lisp/progmodes/glasses.el
@@ -243,7 +243,8 @@ CATEGORY is the overlay category.  If it is nil, use the 
`glasses' category."
        (when glasses-separate-parentheses-p
          (goto-char beg)
          (while (re-search-forward "[a-zA-Z]_*\\((\\)" end t)
-           (unless (glasses-parenthesis-exception-p (point-at-bol) (match-end 
1))
+            (unless (glasses-parenthesis-exception-p (line-beginning-position)
+                                                     (match-end 1))
              (glasses-make-overlay (match-beginning 1) (match-end 1)
                                    'glasses-parenthesis))))))))
 
@@ -282,7 +283,8 @@ recognized according to the current value of the variable 
`glasses-separator'."
        (when glasses-separate-parentheses-p
          (goto-char (point-min))
          (while (re-search-forward "[a-zA-Z]_*\\( \\)(" nil t)
-           (unless (glasses-parenthesis-exception-p (point-at-bol) (1+ 
(match-end 1)))
+            (unless (glasses-parenthesis-exception-p (line-beginning-position)
+                                                     (1+ (match-end 1)))
              (replace-match "" t nil nil 1)))))))
   ;; nil must be returned to allow use in write file hooks
   nil)
diff --git a/lisp/progmodes/grep.el b/lisp/progmodes/grep.el
index a3ef90f397..2446e86abb 100644
--- a/lisp/progmodes/grep.el
+++ b/lisp/progmodes/grep.el
@@ -66,6 +66,7 @@ SYMBOL should be one of `grep-command', `grep-template',
                 integer)
   :version "22.1")
 
+;;;###autoload
 (defcustom grep-highlight-matches 'auto-detect
   "Use special markers to highlight grep matches.
 
@@ -125,11 +126,22 @@ include it when specifying `grep-command'.
 
 In interactive usage, the actual value of this variable is set up
 by `grep-compute-defaults'; to change the default value, use
-\\[customize] or call the function `grep-apply-setting'."
+\\[customize] or call the function `grep-apply-setting'.
+
+Also see `grep-command-position'."
   :type '(choice string
                 (const :tag "Not Set" nil))
   :set #'grep-apply-setting)
 
+(defcustom grep-command-position nil
+  "Where to put point when prompting for a grep command.
+This controls the placement of point in the minibuffer when Emacs
+prompts for the grep command.  If nil, put point at the end of
+the suggested command.  If non-nil, this should be the one-based
+position in the minibuffer where to place point."
+  :type '(choice (const :tag "At the end" nil)
+                 natnum))
+
 (defcustom grep-template nil
   "The default command to run for \\[lgrep].
 The following place holders should be present in the string:
@@ -345,13 +357,14 @@ See `compilation-error-screen-columns'."
 
 (defalias 'kill-grep #'kill-compilation)
 
-;; override compilation-last-buffer
+;; override next-error-last-buffer
 (defvar grep-last-buffer nil
   "The most recent grep buffer.
 A grep buffer becomes most recent when you select Grep mode in it.
 Notice that using \\[next-error] or \\[compile-goto-error] modifies
-`compilation-last-buffer' rather than `grep-last-buffer'.")
+`next-error-last-buffer' rather than `grep-last-buffer'.")
 
+;;;###autoload
 (defvar grep-match-face        'match
   "Face name to use for grep matches.")
 
@@ -885,6 +898,14 @@ The value depends on `grep-command', `grep-template',
   (setq-local compilation-disable-input t)
   (setq-local compilation-error-screen-columns
               grep-error-screen-columns)
+  ;; We normally use a nul byte to separate the file name from the
+  ;; contents, but display it as ":".  That's fine, but when yanking
+  ;; to other buffers, it's annoying to have the nul byte there.
+  (unless kill-transform-function
+    (setq-local kill-transform-function #'identity))
+  (add-function :filter-return (local 'kill-transform-function)
+                (lambda (string)
+                  (string-replace "\0" ":" string)))
   (add-hook 'compilation-filter-hook #'grep-filter nil t))
 
 (defun grep--save-buffers ()
@@ -921,10 +942,15 @@ list is empty)."
    (progn
      (grep-compute-defaults)
      (let ((default (grep-default-command)))
-       (list (read-shell-command "Run grep (like this): "
-                                 (if current-prefix-arg default grep-command)
-                                 'grep-history
-                                 (if current-prefix-arg nil default))))))
+       (list (read-shell-command
+              "Run grep (like this): "
+              (if current-prefix-arg
+                  default
+                (if grep-command-position
+                    (cons grep-command grep-command-position)
+                  grep-command))
+              'grep-history
+              (if current-prefix-arg nil default))))))
   ;; If called non-interactively, also compute the defaults if we
   ;; haven't already.
   (when (eq grep-highlight-matches 'auto-detect)
@@ -1210,7 +1236,7 @@ to specify a command to run.
 If CONFIRM is non-nil, the user will be given an opportunity to edit the
 command before it's run.
 
-Interactively, the user can use the `M-c' command while entering
+Interactively, the user can use the \\`M-c' command while entering
 the regexp to indicate whether the grep should be case sensitive
 or not."
   (interactive
diff --git a/lisp/progmodes/gud.el b/lisp/progmodes/gud.el
index 26fecf9c9f..ccc5720575 100644
--- a/lisp/progmodes/gud.el
+++ b/lisp/progmodes/gud.el
@@ -334,7 +334,7 @@ Used to gray out relevant toolbar icons.")
                                     (">" . gud-down)))
       (define-key map key cmd))
     map)
-  "Keymap to repeat `gud-gdb' stepping instructions `C-x C-a C-n n n'.
+  "Keymap to repeat `gud-gdb' stepping instructions \\`C-x C-a C-n n n'.
 Used in `repeat-mode'.")
 
 (defun gud-set-repeat-map-property (keymap-symbol)
@@ -1054,7 +1054,7 @@ SKIP is the number of chars to skip on each line, it 
defaults to 0."
                                     ("l" . gud-refresh)))
       (define-key map key cmd))
     map)
-  "Keymap to repeat `sdb' stepping instructions `C-x C-a C-n n n'.
+  "Keymap to repeat `sdb' stepping instructions \\`C-x C-a C-n n n'.
 Used in `repeat-mode'.")
 
 (defun gud-sdb-marker-filter (string)
@@ -1301,7 +1301,7 @@ whereby $stopformat=1 produces an output format 
compatible with
               gud-irix-p)
       (define-key map "f" 'gud-finish))
     map)
-  "Keymap to repeat `dbx' stepping instructions `C-x C-a C-n n n'.
+  "Keymap to repeat `dbx' stepping instructions \\`C-x C-a C-n n n'.
 Used in `repeat-mode'.")
 
 ;; The process filter is also somewhat
@@ -1476,7 +1476,7 @@ and source-file directory for your debugger."
                                     (">" . gud-down)))
       (define-key map key cmd))
     map)
-  "Keymap to repeat `xdb' stepping instructions `C-x C-a C-n n n'.
+  "Keymap to repeat `xdb' stepping instructions \\`C-x C-a C-n n n'.
 Used in `repeat-mode'.")
 
 (defcustom gud-xdb-directories nil
@@ -1564,7 +1564,7 @@ directories if your program contains sources from more 
than one directory."
                                     ("l" . gud-refresh)))
       (define-key map key cmd))
     map)
-  "Keymap to repeat `perldb' stepping instructions `C-x C-a C-n n n'.
+  "Keymap to repeat `perldb' stepping instructions \\`C-x C-a C-n n n'.
 Used in `repeat-mode'.")
 
 (defun gud-perldb-massage-args (_file args)
@@ -1577,16 +1577,17 @@ into one that invokes an Emacs-enabled debugging 
session.
         (seen-e nil)
         (shift (lambda () (push (pop args) new-args))))
 
-    ;; Pass all switches and -e scripts through.
+    ;; Pass all switches and -E/-e scripts through.
     (while (and args
                (string-match "^-" (car args))
                (not (equal "-" (car args)))
                (not (equal "--" (car args))))
-      (when (equal "-e" (car args))
+      (when (or (equal "-E" (car args)) (equal "-e" (car args)))
        ;; -e goes with the next arg, so shift one extra.
-       (or (funcall shift)
-           ;; -e as the last arg is an error in Perl.
-           (error "No code specified for -e"))
+       (funcall shift)
+       (or args
+           ;; -E (or -e) as the last arg is an error in Perl.
+           (error "No code specified for %s" (car new-args)))
        (setq seen-e t))
       (funcall shift))
 
@@ -1697,7 +1698,7 @@ The directory containing the perl program becomes the 
initial
 working directory and source-file directory for your debugger."
   (interactive
    (list (gud-query-cmdline 'perldb
-                           (concat (or (buffer-file-name) "-e 0") " "))))
+                           (concat (or (buffer-file-name) "-E 0") " "))))
 
   (gud-common-init command-line 'gud-perldb-massage-args
                   'gud-perldb-marker-filter)
@@ -1754,7 +1755,7 @@ working directory and source-file directory for your 
debugger."
                                     (">" . gud-down)))
       (define-key map key cmd))
     map)
-  "Keymap to repeat `pdb' stepping instructions `C-x C-a C-n n n'.
+  "Keymap to repeat `pdb' stepping instructions \\`C-x C-a C-n n n'.
 Used in `repeat-mode'.")
 
 ;; There's no guarantee that Emacs will hand the filter the entire
@@ -1871,7 +1872,7 @@ directory and source-file directory for your debugger."
                                     (">" . gud-down)))
       (define-key map key cmd))
     map)
-  "Keymap to repeat `guiler' stepping instructions `C-x C-a C-n n n'.
+  "Keymap to repeat `guiler' stepping instructions \\`C-x C-a C-n n n'.
 Used in `repeat-mode'.")
 
 (defun gud-guiler-marker-filter (string)
@@ -2398,7 +2399,7 @@ extension EXTN.  Normally EXTN is given as the regular 
expression
                                     ("l" . gud-refresh)))
       (define-key map key cmd))
     map)
-  "Keymap to repeat `jdb' stepping instructions `C-x C-a C-n n n'.
+  "Keymap to repeat `jdb' stepping instructions \\`C-x C-a C-n n n'.
 Used in `repeat-mode'.")
 
 (defun gud-jdb-find-source-using-classpath (p)
@@ -3694,7 +3695,6 @@ With arg, dereference expr if ARG is positive, otherwise 
do not dereference."
   (message "Dereferencing is now %s."
           (if gud-tooltip-dereference "on" "off")))
 
-(defvar tooltip-use-echo-area)
 (declare-function tooltip-show "tooltip" (text &optional use-echo-area))
 (declare-function tooltip-strip-prompt "tooltip" (process output))
 
@@ -3708,8 +3708,7 @@ With arg, dereference expr if ARG is positive, otherwise 
do not dereference."
   "Process debugger output and show it in a tooltip window."
   (remove-function (process-filter process) #'gud-tooltip-process-output)
   (tooltip-show (tooltip-strip-prompt process output)
-               (or gud-tooltip-echo-area tooltip-use-echo-area
-                    (not tooltip-mode))))
+                (or gud-tooltip-echo-area (not tooltip-mode))))
 
 (defun gud-tooltip-print-command (expr)
   "Return a suitable command to print the expression EXPR."
@@ -3753,8 +3752,7 @@ This function must return nil if it doesn't handle EVENT."
                    (unless (null define-elt)
                      (tooltip-show
                       (cdr define-elt)
-                      (or gud-tooltip-echo-area tooltip-use-echo-area
-                           (not tooltip-mode)))
+                       (or gud-tooltip-echo-area (not tooltip-mode)))
                      expr))))
            (when gud-tooltip-dereference
              (setq expr (concat "*" expr)))
diff --git a/lisp/progmodes/hideif.el b/lisp/progmodes/hideif.el
index ba2c573748..d09e1f4cdf 100644
--- a/lisp/progmodes/hideif.el
+++ b/lisp/progmodes/hideif.el
@@ -109,7 +109,7 @@
 ;;
 ;; Extensively modified by Luke Lee in 2013 to support complete C expression
 ;; evaluation and argumented macro expansion; C++11, C++14, C++17, GCC
-;; extension literals and gcc/clang matching behaviours are supported in 2021.
+;; extension literals and gcc/clang matching behaviors are supported in 2021.
 ;; Various floating point types and operations are also supported but the
 ;; actual precision is limited by the Emacs internal floating representation,
 ;; which is the C data type "double" or IEEE binary64 format.
@@ -2521,8 +2521,7 @@ Turn off hiding by calling `show-ifdefs'."
             (or hide-ifdef-read-only hif-outside-read-only))
       (and hide-ifdef-verbose
            (message "Hiding done, %.1f seconds elapsed"
-                    (float-time (time-subtract (current-time)
-                                               hide-start-time)))))))
+                   (float-time (time-subtract nil hide-start-time)))))))
 
 
 (defun show-ifdefs (&optional start end)
diff --git a/lisp/progmodes/hideshow.el b/lisp/progmodes/hideshow.el
index f574ec84fb..c0796fc2ee 100644
--- a/lisp/progmodes/hideshow.el
+++ b/lisp/progmodes/hideshow.el
@@ -267,7 +267,9 @@ This has effect only if `search-invisible' is set to 
`open'."
     ))
   "Alist for initializing the hideshow variables for different modes.
 Each element has the form
-  (MODE START END COMMENT-START FORWARD-SEXP-FUNC ADJUST-BEG-FUNC).
+  (MODE START END COMMENT-START FORWARD-SEXP-FUNC ADJUST-BEG-FUNC
+   FIND-BLOCK-BEGINNING-FUNC FIND-NEXT-BLOCK-FUNC
+   LOOKING-AT-BLOCK-START-P-FUNC).
 
 If non-nil, hideshow will use these values as regexps to define blocks
 and comments, respectively for major mode MODE.
@@ -288,6 +290,15 @@ cases, FORWARD-SEXP-FUNC specifies another function to use 
instead.
 See the documentation for `hs-adjust-block-beginning' to see what is the
 use of ADJUST-BEG-FUNC.
 
+See the documentation for `hs-find-block-beginning-func' to see
+what is the use of FIND-BLOCK-BEGINNING-FUNC.
+
+See the documentation for `hs-find-next-block-func' to see what
+is the use of FIND-NEXT-BLOCK-FUNC.
+
+See the documentation for `hs-looking-at-block-start-p-func' to
+see what is the use of LOOKING-AT-BLOCK-START-P-FUNC.
+
 If any of the elements is left nil or omitted, hideshow tries to guess
 appropriate values.  The regexps should not contain leading or trailing
 whitespace.  Case does not matter.")
@@ -433,6 +444,39 @@ It should not move the point.
 
 See `hs-c-like-adjust-block-beginning' for an example of using this.")
 
+(defvar-local hs-find-block-beginning-func #'hs-find-block-beginning
+  "Function used to do `hs-find-block-beginning'.
+It should reposition point at the beginning of the current block
+and return point, or nil if original point was not in a block.
+
+Specifying this function is necessary for languages such as
+Python, where regexp search and `syntax-ppss' check is not enough
+to find the beginning of the current block.")
+
+(defvar-local hs-find-next-block-func #'hs-find-next-block
+  "Function used to do `hs-find-next-block'.
+It should reposition point at next block start.
+
+It is called with three arguments REGEXP, MAXP, and COMMENTS.
+REGEXP is a regexp representing block start.  When block start is
+found, `match-data' should be set using REGEXP.  MAXP is a buffer
+position that bounds the search.  When COMMENTS is nil, comments
+should be skipped.  When COMMENTS is not nil, REGEXP matches not
+only beginning of a block but also beginning of a comment.  In
+this case, the function should find nearest block or comment.
+
+Specifying this function is necessary for languages such as
+Python, where regexp search is not enough to find the beginning
+of the next block.")
+
+(defvar-local hs-looking-at-block-start-p-func #'hs-looking-at-block-start-p
+  "Function used to do `hs-looking-at-block-start-p'.
+It should return non-nil if the point is at the block start.
+
+Specifying this function is necessary for languages such as
+Python, where `looking-at' and `syntax-ppss' check is not enough
+to check if the point is at the block start.")
+
 (defvar hs-headline nil
   "Text of the line where a hidden block begins, set during isearch.
 You can display this in the mode line by adding the symbol `hs-headline'
@@ -565,7 +609,7 @@ The block beginning is adjusted by 
`hs-adjust-block-beginning'
 and then further adjusted to be at the end of the line."
   (if comment-reg
       (hs-hide-comment-region (car comment-reg) (cadr comment-reg) end)
-    (when (hs-looking-at-block-start-p)
+    (when (funcall hs-looking-at-block-start-p-func)
       (let ((mdata (match-data t))
             (header-end (match-end 0))
             p q ov)
@@ -672,7 +716,14 @@ function; and adjust-block-beginning function."
                                                      0 (1- (match-end 0)))
                                         c-start-regexp)))
               hs-forward-sexp-func (or (nth 4 lookup) #'forward-sexp)
-              hs-adjust-block-beginning (or (nth 5 lookup) #'identity)))
+              hs-adjust-block-beginning (or (nth 5 lookup) #'identity)
+              hs-find-block-beginning-func (or (nth 6 lookup)
+                                               #'hs-find-block-beginning)
+              hs-find-next-block-func (or (nth 7 lookup)
+                                          #'hs-find-next-block)
+              hs-looking-at-block-start-p-func
+              (or (nth 8 lookup)
+                  #'hs-looking-at-block-start-p)))
     (setq hs-minor-mode nil)
     (error "%s Mode doesn't support Hideshow Minor Mode"
            (format-mode-line mode-name))))
@@ -683,7 +734,7 @@ Return point, or nil if original point was not in a block."
   (let ((done nil)
         (here (point)))
     ;; look if current line is block start
-    (if (hs-looking-at-block-start-p)
+    (if (funcall hs-looking-at-block-start-p-func)
         (point)
       ;; look backward for the start of a block that contains the cursor
       (while (and (re-search-backward hs-block-start-regexp nil t)
@@ -698,19 +749,25 @@ Return point, or nil if original point was not in a 
block."
         (goto-char here)
         nil))))
 
+(defun hs-find-next-block (regexp maxp comments)
+  "Reposition point at next block-start.
+Skip comments if COMMENTS is nil, and search for REGEXP in
+region (point MAXP)."
+  (when (not comments)
+    (forward-comment (point-max)))
+  (and (< (point) maxp)
+       (re-search-forward regexp maxp t)))
+
 (defun hs-hide-level-recursive (arg minp maxp)
   "Recursively hide blocks ARG levels below point in region (MINP MAXP)."
-  (when (hs-find-block-beginning)
+  (when (funcall hs-find-block-beginning-func)
     (setq minp (1+ (point)))
     (funcall hs-forward-sexp-func 1)
     (setq maxp (1- (point))))
   (unless hs-allow-nesting
     (hs-discard-overlays minp maxp))
   (goto-char minp)
-  (while (progn
-           (forward-comment (buffer-size))
-           (and (< (point) maxp)
-                (re-search-forward hs-block-start-regexp maxp t)))
+  (while (funcall hs-find-next-block-func hs-block-start-regexp maxp nil)
     (when (save-match-data
            (not (nth 8 (syntax-ppss)))) ; not inside comments or strings
       (if (> arg 1)
@@ -747,8 +804,8 @@ and `case-fold-search' are both t."
           (goto-char (nth 0 c-reg))
         (end-of-line)
         (when (and (not c-reg)
-                   (hs-find-block-beginning)
-                  (hs-looking-at-block-start-p))
+                   (funcall hs-find-block-beginning-func)
+                  (funcall hs-looking-at-block-start-p-func))
           ;; point is inside a block
           (goto-char (match-end 0)))))
     (end-of-line)
@@ -790,10 +847,8 @@ If `hs-hide-comments-when-hiding-all' is non-nil, also 
hide the comments."
                                    hs-c-start-regexp
                                    "\\)")
                          ""))))
-       (while (progn
-                (unless hs-hide-comments-when-hiding-all
-                  (forward-comment (point-max)))
-                (re-search-forward re (point-max) t))
+       (while (funcall hs-find-next-block-func re (point-max)
+                       hs-hide-comments-when-hiding-all)
          (if (match-beginning 1)
              ;; We have found a block beginning.
              (progn
@@ -838,8 +893,8 @@ Upon completion, point is repositioned and the normal hook
                       (<= (count-lines (car c-reg) (nth 1 c-reg)) 1)))
        (message "(not enough comment lines to hide)"))
       ((or c-reg
-          (hs-looking-at-block-start-p)
-           (hs-find-block-beginning))
+          (funcall hs-looking-at-block-start-p-func)
+           (funcall hs-find-block-beginning-func))
        (hs-hide-block-at-point end c-reg)
        (run-hooks 'hs-hide-hook))))))
 
@@ -868,9 +923,9 @@ See documentation for functions `hs-hide-block' and 
`run-hooks'."
              (when (car c-reg)
                (setq p (car c-reg)
                      q (cadr c-reg))))
-            ((and (hs-find-block-beginning)
+            ((and (funcall hs-find-block-beginning-func)
                   ;; ugh, fresh match-data
-                  (hs-looking-at-block-start-p))
+                  (funcall hs-looking-at-block-start-p-func))
              (setq p (point)
                    q (progn (hs-forward-sexp (match-data t) 1) (point)))))
       (when (and p q)
diff --git a/lisp/progmodes/icon.el b/lisp/progmodes/icon.el
index ec281f3a49..2da0fb1677 100644
--- a/lisp/progmodes/icon.el
+++ b/lisp/progmodes/icon.el
@@ -163,8 +163,6 @@ with no args, if that value is non-nil."
               '((icon-font-lock-keywords
                  icon-font-lock-keywords-1 icon-font-lock-keywords-2)
                 nil nil ((?_ . "w")) beginning-of-defun
-                ;; Obsoleted by Emacs 19.35 parse-partial-sexp's COMMENTSTOP.
-                ;;(font-lock-comment-start-regexp . "#")
                 (font-lock-mark-block-function . mark-defun)))
   ;; imenu support
   (setq-local imenu-generic-expression icon-imenu-generic-expression)
diff --git a/lisp/progmodes/idlw-shell.el b/lisp/progmodes/idlw-shell.el
index b606352136..63f032b7b3 100644
--- a/lisp/progmodes/idlw-shell.el
+++ b/lisp/progmodes/idlw-shell.el
@@ -231,7 +231,7 @@ because these are used as separators by IDL."
 
 (defcustom idlwave-shell-graphics-window-size '(500 400)
   "Size of IDL graphics windows popped up by special IDLWAVE command.
-The command is `C-c C-d C-f' and accepts as a prefix the window nr.
+The command is \\`C-c C-d C-f' and accepts as a prefix the window nr.
 A command like `WINDOW,N,xsize=XX,ysize=YY' is sent to IDL."
   :group 'idlwave-shell-general-setup
   :type '(list
@@ -844,7 +844,7 @@ IDL has currently stepped.")
    ---------
    A complete set of commands for compiling and debugging IDL programs
    is available from the menu.  Also keybindings starting with a
-   `C-c C-d' prefix are available for most commands in the *idl* buffer
+   \\`C-c C-d' prefix are available for most commands in the *idl* buffer
    and also in source buffers.  The best place to learn about the
    keybindings is again the menu.
 
@@ -1381,7 +1381,7 @@ Otherwise just move the line.  Move down unless UP is 
non-nil."
         (arg (if up arg (- arg))))
     (if (eq t idlwave-shell-arrows-do-history) (goto-char proc-pos))
     (if (and idlwave-shell-arrows-do-history
-            (>= (1+ (point-at-eol)) proc-pos))
+             (>= (1+ (line-end-position)) proc-pos))
        (comint-previous-input arg)
       (forward-line (- arg)))))
 
@@ -2130,7 +2130,7 @@ args of an executive .run, .rnew or .compile."
 
 (defun idlwave-shell-filename-string ()
   "Return t if in a string and after what could be a file name."
-  (let ((limit (point-at-bol)))
+  (let ((limit (line-beginning-position)))
     (save-excursion
       ;; Skip backwards over file name chars
       (skip-chars-backward idlwave-shell-file-name-chars limit)
@@ -2139,7 +2139,7 @@ args of an executive .run, .rnew or .compile."
 
 (defun idlwave-shell-batch-command ()
   "Return t if we're in a batch command statement like \"@foo\"."
-  (let ((limit (point-at-bol)))
+  (let ((limit (line-beginning-position)))
     (save-excursion
       ;; Skip backwards over filename
       (skip-chars-backward idlwave-shell-file-name-chars limit)
@@ -2317,7 +2317,7 @@ matter what the settings of that variable."
                                    idlwave-shell-electric-stop-line-face
                                  idlwave-shell-stop-line-face))
                  (move-overlay idlwave-shell-stop-line-overlay
-                               (point) (point-at-eol)
+                                (point) (line-end-position)
                                (current-buffer)))
              ;; use the arrow instead, but only if marking is wanted.
              (if idlwave-shell-mark-stop-line
@@ -2510,7 +2510,7 @@ If in the IDL shell buffer, returns 
`idlwave-shell-pc-frame'."
     (list (idlwave-shell-file-name (buffer-file-name))
           (save-restriction
             (widen)
-           (1+ (count-lines 1 (point-at-bol)))))))
+            (1+ (count-lines 1 (line-beginning-position)))))))
 
 (defun idlwave-shell-current-module ()
   "Return the name of the module for the current file.
@@ -3528,7 +3528,7 @@ Existing overlays are recycled, in order to minimize 
consumption."
       (while (setq bp (pop bp-list))
        (save-excursion
          (idlwave-shell-goto-frame (car bp))
-         (let* ((end (point-at-eol))
+          (let* ((end (line-end-position))
                 (beg (progn (beginning-of-line 1) (point)))
                 (condition (idlwave-shell-bp-get bp 'condition))
                 (count (idlwave-shell-bp-get bp 'count))
@@ -3851,7 +3851,7 @@ of the form:
                   (append
                    ;; compiled procedures
                    (progn
-                     (narrow-to-region cpro (point-at-bol))
+                     (narrow-to-region cpro (line-beginning-position))
                      (goto-char (point-min))
                      (idlwave-shell-sources-grep))
                    ;; compiled functions
diff --git a/lisp/progmodes/idlwave.el b/lisp/progmodes/idlwave.el
index edb53793e6..81f74dc1fa 100644
--- a/lisp/progmodes/idlwave.el
+++ b/lisp/progmodes/idlwave.el
@@ -1001,9 +1001,9 @@ Obsolete, if the IDL Assistant is being used for help."
   "List of modifiers to be used for the debugging commands.
 Will be used to bind debugging commands in the shell buffer and in all
 source buffers.  These are additional convenience bindings, the debugging
-commands are always available with the `C-c C-d' prefix.
+commands are always available with the \\`C-c C-d' prefix.
 If you set this to (control shift), this means setting a breakpoint will
-be on `C-S-b', compiling a source file on `C-S-c' etc.  Possible modifiers
+be on \\`C-S-b', compiling a source file on \\`C-S-c' etc.  Possible modifiers
 are `control', `meta', `super', `hyper', `alt', and `shift'."
   :group 'idlwave-shell-general-setup
   :type '(set :tag "Specify modifiers"
@@ -2004,7 +2004,7 @@ Returns non-nil if abbrev is left expanded."
 Moves to end of line if there is no comment delimiter.
 Ignores comment delimiters in strings.
 Returns point if comment found and nil otherwise."
-  (let ((eos (point-at-eol))
+  (let ((eos (line-end-position))
         (data (match-data))
         found)
     ;; Look for first comment delimiter not in a string
@@ -2054,7 +2054,7 @@ Also checks if the correct END statement has been used."
   ;;(backward-char 1)
   (let* ((pos (point-marker))
         (last-abbrev-marker (copy-marker last-abbrev-location))
-        (eol-pos (point-at-eol))
+         (eol-pos (line-end-position))
         begin-pos end-pos end end1 )
     (if idlwave-reindent-end  (idlwave-indent-line))
     (setq last-abbrev-location (marker-position last-abbrev-marker))
@@ -3202,7 +3202,7 @@ ignored."
         (beginning-of-line)
         (setq bcl (point))
         (re-search-forward (concat "^[ \t]*" comment-start "+")
-                          (point-at-eol) t)
+                           (line-end-position) t)
         ;; Get the comment leader on the line and its length
         (setq pre (current-column))
         ;; the comment leader is the indentation plus exactly the
@@ -3210,7 +3210,8 @@ ignored."
         (setq fill-prefix-reg
               (concat
                (setq fill-prefix
-                     (regexp-quote (buffer-substring (point-at-bol) (point))))
+                     (regexp-quote (buffer-substring (line-beginning-position)
+                                                     (point))))
                "[^;]"))
 
         ;; Mark the beginning and end of the paragraph
@@ -3247,7 +3248,7 @@ ignored."
         ;; In the following while statements, after one iteration
         ;; point will be at the beginning of a line in which case
         ;; the while will not be executed for the
-        ;; the first paragraph line and thus will not affect the
+        ;; first paragraph line and thus will not affect the
         ;; indentation.
         ;;
         ;; First check to see if indentation is based on hanging indent.
@@ -3264,7 +3265,7 @@ ignored."
               (setq indent hang)
               (beginning-of-line)
               (while (> (point) start)
-                (re-search-forward comment-start-skip (point-at-eol) t)
+                (re-search-forward comment-start-skip (line-end-position) t)
                 (if (> (setq diff (- indent (current-column))) 0)
                     (progn
                       (if (>= here (point))
@@ -3286,7 +3287,7 @@ ignored."
             (setq indent
                   (min indent
                        (progn
-                         (re-search-forward comment-start-skip (point-at-eol) 
t)
+                         (re-search-forward comment-start-skip 
(line-end-position) t)
                          (current-column))))
             (forward-line -1)))
         (setq fill-prefix (concat fill-prefix
@@ -3296,7 +3297,7 @@ ignored."
         (setq first-indent
               (max
                (progn
-                 (re-search-forward comment-start-skip (point-at-eol) t)
+                 (re-search-forward comment-start-skip (line-end-position) t)
                  (current-column))
                indent))
 
@@ -3334,11 +3335,11 @@ If not found returns nil."
   (if idlwave-use-last-hang-indent
       (save-excursion
         (end-of-line)
-        (if (re-search-backward idlwave-hang-indent-regexp (point-at-bol) t)
+        (if (re-search-backward idlwave-hang-indent-regexp 
(line-beginning-position) t)
             (+ (current-column) (length idlwave-hang-indent-regexp))))
     (save-excursion
       (beginning-of-line)
-      (if (re-search-forward idlwave-hang-indent-regexp (point-at-eol) t)
+      (if (re-search-forward idlwave-hang-indent-regexp (line-end-position) t)
           (current-column)))))
 
 (defun idlwave-auto-fill ()
@@ -3386,7 +3387,7 @@ if `idlwave-auto-fill-split-string' is non-nil."
                      ;; Remove whitespace between comment delimiter and
                      ;; text, insert spaces for appropriate indentation.
                      (beginning-of-line)
-                     (re-search-forward comment-start-skip (point-at-eol) t)
+                      (re-search-forward comment-start-skip 
(line-end-position) t)
                      (delete-horizontal-space)
                      (idlwave-indent-to indent)
                      (goto-char (- (point-max) here)))))
@@ -3548,7 +3549,7 @@ constants - a double quote followed by an octal digit."
     ;; Because single and double quotes can quote each other we must
     ;; search for the string start from the beginning of line.
     (let* ((start (point))
-           (eol (point-at-eol))
+           (eol (line-end-position))
            (bq (progn (beginning-of-line) (point)))
            (endq (point))
            (data (match-data))
@@ -3626,7 +3627,7 @@ unless the optional second argument NOINDENT is non-nil."
           (setq s1 (downcase s1) s2 (downcase s2)))
          (idlwave-abbrev-change-case
           (setq s1 (upcase s1) s2 (upcase s2))))
-    (let ((beg (point-at-bol))
+    (let ((beg (line-beginning-position))
          end)
       (if (not (looking-at "\\s-*\n"))
          (open-line 1))
@@ -7528,7 +7529,7 @@ associated TAG, if any."
        (setq cl (pop sclasses))
        (let ((tags (idlwave-class-tags cl)))
         (while tags
-          (if (eq t (compare-strings tag 0 nil (car tags) 0 nil t))
+          (if (string-equal-ignore-case tag (car tags))
             (throw 'exit cl))
           (setq tags (cdr tags))))))))
 
@@ -8421,7 +8422,7 @@ was pressed."
 (defun idlwave-list-shell-load-path-shadows (&optional _arg)
   "List the load path shadows of all routines compiled under the shell.
 This is very useful for checking an IDL application.  Just compile the
-application, do RESOLVE_ALL, and `C-c C-i' to compile all referenced
+application, do RESOLVE_ALL, and \\`C-c C-i' to compile all referenced
 routines and update IDLWAVE internal info.  Then check for shadowing
 with this command."
   (interactive)
@@ -8811,7 +8812,7 @@ to reset the variable `idlwave-true-path-alist' to nil."
 
 ;; ----------------------------------------------------------------------------
 ;;
-;; Additions for use with imenu.el and func-menu.el
+;; Additions for use with imenu.el
 ;; (pop-up a list of IDL units in the current file).
 ;;
 
@@ -8835,16 +8836,7 @@ Assumes that point is at the beginning of the unit as 
found by
      "[a-zA-Z_][a-zA-Z0-9$_]+\\(::[a-zA-Z_][a-zA-Z0-9$_]+\\)?")
     (buffer-substring-no-properties begin (point))))
 
-(defalias 'idlwave-function-menu
-  (condition-case nil
-      (progn
-       (require 'func-menu)
-       'function-menu)
-    (error (condition-case nil
-              (progn
-                (require 'imenu)
-                'imenu)
-            (error nil)))))
+(define-obsolete-function-alias 'idlwave-function-menu #'imenu "29.1")
 
 (defun idlwave-edit-in-idlde ()
   "Edit the current file in IDL Development environment."
@@ -8864,7 +8856,7 @@ Assumes that point is at the beginning of the unit as 
found by
 ;; Menus - using easymenu.el
 (defvar idlwave-mode-menu-def
   '("IDLWAVE"
-    ["PRO/FUNC menu" idlwave-function-menu t]
+    ["PRO/FUNC menu" imenu t]
     ("Motion"
      ["Subprogram Start" idlwave-beginning-of-subprogram t]
      ["Subprogram End" idlwave-end-of-subprogram t]
diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el
index eb2a1e4fcc..b920ef6c2c 100644
--- a/lisp/progmodes/js.el
+++ b/lisp/progmodes/js.el
@@ -307,9 +307,6 @@ Match group 1 is the name of the macro.")
 (defconst js--font-lock-keywords-2
   (append js--font-lock-keywords-1
           (list (list js--keyword-re 1 font-lock-keyword-face)
-                (list "\\_<for\\_>"
-                      "\\s-+\\(each\\)\\_>" nil nil
-                      (list 1 'font-lock-keyword-face))
                 (cons js--basic-type-re font-lock-type-face)
                 (cons js--constant-re font-lock-constant-face)))
   "Level two font lock keywords for `js-mode'.")
@@ -815,7 +812,7 @@ point at BOB."
                (setq str-terminator ?/))
              (re-search-forward
               (concat "\\([^\\]\\|^\\)" (string str-terminator))
-              (point-at-eol) t))
+              (line-end-position) t))
             ((nth 7 parse)
              (forward-line))
             ((or (nth 4 parse)
@@ -1686,7 +1683,7 @@ point of view of font-lock.  It applies highlighting 
directly with
            (insert "=")
            (goto-char (match-beginning 2)))
        (setq js--tmp-location nil)
-       (goto-char (point-at-eol)))
+       (goto-char (line-end-position)))
      (when js--tmp-location
        (save-excursion
          (goto-char js--tmp-location)
@@ -1830,22 +1827,23 @@ context."
 (defun js--class-decl-matcher (limit)
   "Font lock function used by `js-mode'.
 This performs fontification according to `js--class-styles'."
-  (cl-loop initially (js--ensure-cache limit)
-           while (re-search-forward js--quick-match-re limit t)
-           for orig-end = (match-end 0)
-           do (goto-char (match-beginning 0))
-           if (cl-loop for style in js--class-styles
-                       for decl-re = (plist-get style :class-decl)
-                       if (and (memq (plist-get style :framework)
-                                     js-enabled-frameworks)
-                               (memq (js-syntactic-context)
-                                     (plist-get style :contexts))
-                               decl-re
-                               (looking-at decl-re))
-                       do (goto-char (match-end 0))
-                       and return t)
-           return t
-           else do (goto-char orig-end)))
+  (when js-enabled-frameworks
+    (cl-loop initially (js--ensure-cache limit)
+             while (re-search-forward js--quick-match-re limit t)
+             for orig-end = (match-end 0)
+             do (goto-char (match-beginning 0))
+             if (cl-loop for style in js--class-styles
+                         for decl-re = (plist-get style :class-decl)
+                         if (and (memq (plist-get style :framework)
+                                       js-enabled-frameworks)
+                                 (memq (js-syntactic-context)
+                                       (plist-get style :contexts))
+                                 decl-re
+                                 (looking-at decl-re))
+                         do (goto-char (match-end 0))
+                         and return t)
+             return t
+             else do (goto-char orig-end))))
 
 (defconst js--font-lock-keywords
   '(js--font-lock-keywords-3 js--font-lock-keywords-1
@@ -2508,14 +2506,14 @@ the same column as the current line."
              (looking-at "[ \t\n]*}"))
            (save-excursion
              (backward-list) (forward-symbol -1) (looking-at "\\_<do\\_>"))
-         (js--re-search-backward "\\_<do\\_>" (point-at-bol) t)
+          (js--re-search-backward "\\_<do\\_>" (line-beginning-position) t)
          (or (looking-at "\\_<do\\_>")
              (let ((saved-indent (current-indentation)))
                (while (and (js--re-search-backward "^\\s-*\\_<" nil t)
                            (/= (current-indentation) saved-indent)))
                (and (looking-at "\\s-*\\_<do\\_>")
                     (not (js--re-search-forward
-                          "\\_<while\\_>" (point-at-eol) t))
+                           "\\_<while\\_>" (line-end-position) t))
                     (= (current-indentation) saved-indent)))))))))
 
 
@@ -2527,7 +2525,7 @@ nil."
   (save-excursion
     (back-to-indentation)
     (when (save-excursion
-            (and (not (eq (point-at-bol) (point-min)))
+            (and (not (eq (line-beginning-position) (point-min)))
                  (not (looking-at "[{]"))
                  (js--re-search-backward "[[:graph:]]" nil t)
                  (progn
@@ -2548,8 +2546,8 @@ nil."
     (c-get-syntactic-indentation (list (cons symbol anchor)))))
 
 (defun js--same-line (pos)
-  (and (>= pos (point-at-bol))
-       (<= pos (point-at-eol))))
+  (and (>= pos (line-beginning-position))
+       (<= pos (line-end-position))))
 
 (defun js--multi-line-declaration-indentation ()
   "Helper function for `js--proper-indentation'.
@@ -2923,7 +2921,7 @@ return nil."
   "Indent the current line as JavaScript."
   (interactive)
   (let* ((parse-status
-          (save-excursion (syntax-ppss (point-at-bol))))
+          (save-excursion (syntax-ppss (line-beginning-position))))
          (offset (- (point) (save-excursion (back-to-indentation) (point)))))
     (unless (nth 3 parse-status)
       (indent-line-to (js--proper-indentation parse-status))
@@ -3490,6 +3488,13 @@ This function is intended for use in 
`after-change-functions'."
   ;;(syntax-propertize (point-max))
   )
 
+;;;###autoload
+(define-derived-mode js-json-mode js-mode "JSON"
+  (setq-local js-enabled-frameworks nil)
+  ;; Speed up `syntax-ppss': JSON files can be big but can't hold
+  ;; regexp matchers nor #! thingies (and `js-enabled-frameworks' is nil).
+  (setq-local syntax-propertize-function #'ignore))
+
 ;; Since we made JSX support available and automatically-enabled in
 ;; the base `js-mode' (for ease of use), now `js-jsx-mode' simply
 ;; serves as one other interface to unconditionally enable JSX in
diff --git a/lisp/progmodes/make-mode.el b/lisp/progmodes/make-mode.el
index 91307f6c09..cbbcf1c2b7 100644
--- a/lisp/progmodes/make-mode.el
+++ b/lisp/progmodes/make-mode.el
@@ -220,8 +220,8 @@ to MODIFY A FILE WITHOUT YOUR CONFIRMATION when \"it seems 
necessary\"."
   "List of special targets.
 You will be offered to complete on one of those in the minibuffer whenever
 you enter a \".\" at the beginning of a line in `makefile-mode'."
-  :type '(repeat string))
-(put 'makefile-special-targets-list 'risky-local-variable t)
+  :type '(repeat string)
+  :risky t)
 
 (defcustom makefile-runtime-macros-list
   '(("@") ("&") (">") ("<") ("*") ("^") ("+") ("?") ("%") ("$"))
@@ -1170,7 +1170,6 @@ and adds all qualifying names to the list of known 
targets."
                       (goto-char (match-end 0))
                     (insert suffix))))))))
 
-(define-obsolete-function-alias 'makefile-complete 'completion-at-point "24.1")
 
 
 ;; Backslashification.  Stolen from cc-mode.el.
diff --git a/lisp/progmodes/meta-mode.el b/lisp/progmodes/meta-mode.el
index 5aaa277431..00bab00a0d 100644
--- a/lisp/progmodes/meta-mode.el
+++ b/lisp/progmodes/meta-mode.el
@@ -108,30 +108,27 @@
             (macro-keywords-2
              "\\(primarydef\\|secondarydef\\|tertiarydef\\)")
             (args-keywords
-             (eval-when-compile
-               (regexp-opt
-                '("expr" "suffix" "text" "primary" "secondary" "tertiary")
-                t)))
+             (regexp-opt
+              '("expr" "suffix" "text" "primary" "secondary" "tertiary")
+              t))
             (type-keywords
-             (eval-when-compile
-              (regexp-opt
-               '("boolean" "color" "numeric" "pair" "path" "pen" "picture"
-                 "string" "transform" "newinternal")
-               t)))
+             (regexp-opt
+              '("boolean" "color" "numeric" "pair" "path" "pen" "picture"
+                "string" "transform" "newinternal")
+              t))
             (syntactic-keywords
-             (eval-when-compile
-              (regexp-opt
-               '("for" "forever" "forsuffixes" "endfor"
-                 "step" "until" "upto" "downto" "thru" "within"
-                 "iff" "if" "elseif" "else" "fi" "exitif" "exitunless"
-                 "let" "def" "vardef" "enddef" "mode_def"
-                 "true" "false" "known" "unknown" "and" "or" "not"
-                 "save" "interim" "inner" "outer" "relax"
-                 "begingroup" "endgroup" "expandafter" "scantokens"
-                 "generate" "input" "endinput" "end" "bye"
-                 "message" "errmessage" "errhelp" "special" "numspecial"
-                 "readstring" "readfrom" "write")
-               t)))
+             (regexp-opt
+              '("for" "forever" "forsuffixes" "endfor"
+                "step" "until" "upto" "downto" "thru" "within"
+                "iff" "if" "elseif" "else" "fi" "exitif" "exitunless"
+                "let" "def" "vardef" "enddef" "mode_def"
+                "true" "false" "known" "unknown" "and" "or" "not"
+                "save" "interim" "inner" "outer" "relax"
+                "begingroup" "endgroup" "expandafter" "scantokens"
+                "generate" "input" "endinput" "end" "bye"
+                "message" "errmessage" "errhelp" "special" "numspecial"
+                "readstring" "readfrom" "write")
+              t))
             )
         (list
          ;; embedded TeX code in btex ... etex
@@ -159,14 +156,14 @@
          (cons (concat "\\<" type-keywords "\\>"
                        "\\([ \t\f]+\\(\\sw+\\)\\)*")
                '((1 font-lock-type-face)
-                 (font-lock-match-meta-declaration-item-and-skip-to-next
+                 (meta-font-lock-match-declaration-item-and-skip-to-next
                   (goto-char (match-end 1)) nil
                   (1 font-lock-variable-name-face nil t))))
          ;; argument declarations: expr, suffix, text, ...
          (cons (concat "\\<" args-keywords "\\>"
                        "\\([ \t\f]+\\(\\sw+\\|\\s_+\\)\\)*")
                '((1 font-lock-type-face)
-                 (font-lock-match-meta-declaration-item-and-skip-to-next
+                 (meta-font-lock-match-declaration-item-and-skip-to-next
                   (goto-char (match-end 1)) nil
                   (1 font-lock-variable-name-face nil t))))
          ;; special case of arguments: expr x of y
@@ -196,8 +193,7 @@
      ))
   "Default expressions to highlight in Metafont or MetaPost mode.")
 
-
-(defun font-lock-match-meta-declaration-item-and-skip-to-next (limit)
+(defun meta-font-lock-match-declaration-item-and-skip-to-next (limit)
   ;; Match and move over Metafont/MetaPost declaration item after point.
   ;;
   ;; The expected syntax of an item is either "word" or "symbol",
@@ -441,8 +437,6 @@ If the list was changed, sort the list and remove 
duplicates first."
                    (insert close)))))))
       (nth 1 entry))))
 
-(define-obsolete-function-alias 'meta-complete-symbol
-  'completion-at-point "24.1")
 
 ;;; Indentation.
 
@@ -526,7 +520,7 @@ If the list was changed, sort the list and remove 
duplicates first."
            (looking-at meta-ignore-comment-regexp))
       (current-indentation))
      ;; Beginning of buffer.
-     ((eq (point-at-bol) (point-min))
+     ((eq (line-beginning-position) (point-min))
       0)
      ;; Backindent at end of environments.
      ((meta-indent-looking-at-code
@@ -564,14 +558,14 @@ If the list was changed, sort the list and remove 
duplicates first."
     (end-of-line)
     ;; Skip backward the comments.
     (let ((point-not-in-string (point)))
-      (while (search-backward comment-start (point-at-bol) t)
+      (while (search-backward comment-start (line-beginning-position) t)
        (unless (meta-indent-in-string-p)
          (setq point-not-in-string (point))))
       (goto-char point-not-in-string))
     ;; Search for the end of the previous expression.
-    (if (search-backward ";" (point-at-bol) t)
+    (if (search-backward ";" (line-beginning-position) t)
        (progn (while (and (meta-indent-in-string-p)
-                          (search-backward ";" (point-at-bol) t)))
+                           (search-backward ";" (line-beginning-position) t)))
               (if (= (char-after) ?\;)
                   (forward-char)
                 (beginning-of-line)))
@@ -806,14 +800,8 @@ The environment marked is the one that contains point or 
follows point."
     st)
   "Syntax table used in Metafont or MetaPost mode.")
 
-(define-obsolete-variable-alias 'meta-mode-map 'meta-common-mode-map "24.1")
 (defvar meta-common-mode-map
   (let ((map (make-sparse-keymap)))
-    ;; Comment Paragraphs:
-    ;; (define-key map "\M-a"      'backward-sentence)
-    ;; (define-key map "\M-e"      'forward-sentence)
-    ;; (define-key map "\M-h"      'mark-paragraph)
-    ;; (define-key map "\M-q"      'fill-paragraph)
     ;; Navigation:
     (define-key map "\M-\C-a"   'meta-beginning-of-defun)
     (define-key map "\M-\C-e"   'meta-end-of-defun)
@@ -830,10 +818,6 @@ The environment marked is the one that contains point or 
follows point."
     (define-key map "\C-c:"     'meta-uncomment-region)
     ;; Symbol Completion:
     (define-key map "\M-\t"     'completion-at-point)
-    ;; Shell Commands:
-    ;; (define-key map "\C-c\C-c"  'meta-command-file)
-    ;; (define-key map "\C-c\C-k"  'meta-kill-job)
-    ;; (define-key map "\C-c\C-l"  'meta-recenter-output)
     map)
   "Keymap used in Metafont or MetaPost mode.")
 
@@ -858,10 +842,6 @@ The environment marked is the one that contains point or 
follows point."
         :active mark-active]
        "--"
        ["Complete Symbol"               completion-at-point t]
-;      "--"
-;      ["Command on Buffer"             meta-command-file t]
-;      ["Kill Job"                      meta-kill-job t]
-;      ["Recenter Output Buffer"        meta-recenter-output-buffer t]
        ))
 
 
@@ -942,6 +922,10 @@ The environment marked is the one that contains point or 
follows point."
               (list (list "\\<\\(\\sw+\\)" 1 'meta-symbol-list)
                     (list "" 'ispell-complete-word))))
 
+(define-obsolete-function-alias
+  'font-lock-match-meta-declaration-item-and-skip-to-next
+  #'meta-font-lock-match-declaration-item-and-skip-to-next "29.1")
+
 (provide 'meta-mode)
 (run-hooks 'meta-mode-load-hook)
 
diff --git a/lisp/progmodes/modula2.el b/lisp/progmodes/modula2.el
index a8d644dba0..e668570ba1 100644
--- a/lisp/progmodes/modula2.el
+++ b/lisp/progmodes/modula2.el
@@ -101,9 +101,8 @@
 
 (defcustom m2-indent 5
   "This variable gives the indentation in Modula-2 mode."
-  :type 'integer)
-(put 'm2-indent 'safe-local-variable
-     (lambda (v) (or (null v) (integerp v))))
+  :type 'integer
+  :safe (lambda (v) (or (null v) (integerp v))))
 
 (defconst m2-smie-grammar
   ;; An official definition can be found as "M2R10.pdf".  This grammar does
diff --git a/lisp/progmodes/octave.el b/lisp/progmodes/octave.el
index 7b7c675873..721dfa51ad 100644
--- a/lisp/progmodes/octave.el
+++ b/lisp/progmodes/octave.el
@@ -197,8 +197,8 @@ newline or semicolon after an else or end keyword."
 
 (defcustom octave-block-offset 2
   "Extra indentation applied to statements in Octave block structures."
-  :type 'integer)
-(put 'octave-block-offset 'safe-local-variable 'integerp)
+  :type 'integer
+  :safe #'integerp)
 
 (defvar octave-block-comment-start
   (concat (make-string 2 octave-comment-char) " ")
diff --git a/lisp/progmodes/opascal.el b/lisp/progmodes/opascal.el
index 4ab9b4a996..5ed719b5a7 100644
--- a/lisp/progmodes/opascal.el
+++ b/lisp/progmodes/opascal.el
@@ -29,7 +29,6 @@
 ;; .pas (and .dpr and .dpk) files.  Emacs, by default, will otherwise
 ;; enter Pascal mode.  For example:
 ;;
-;; (autoload 'opascal-mode "opascal")
 ;; (add-to-list 'auto-mode-alist
 ;;              '("\\.\\(pas\\|dpr\\|dpk\\)\\'" . opascal-mode))
 
@@ -1641,10 +1640,10 @@ An error is raised if not in a comment."
 (defun opascal-new-comment-line ()
   "If in a // comment, do a newline, indented such that one is still in the
 comment block.  If not in a // comment, just does a normal newline."
-  (interactive)
   (declare
    (obsolete "use comment-indent-new-line with comment-multi-line instead"
              "27.1"))
+  (interactive)
   (let ((comment (opascal-current-token)))
     (if (not (eq 'comment-single-line (opascal-token-kind comment)))
         ;; Not in a // comment. Just do the normal newline.
diff --git a/lisp/progmodes/pascal.el b/lisp/progmodes/pascal.el
index 351ea6e3a9..9786b1aa45 100644
--- a/lisp/progmodes/pascal.el
+++ b/lisp/progmodes/pascal.el
@@ -239,14 +239,6 @@ will do all lineups."
              (const :tag "Declarations" declaration)
               (const :tag "Case statements" case)))
 
-(defvar pascal-toggle-completions nil
-  "If non-nil, `pascal-complete-word' tries all possible completions.
-Repeated use of \\[pascal-complete-word] then shows all
-completions in turn, instead of displaying a list of all possible
-completions.")
-(make-obsolete-variable 'pascal-toggle-completions
-                        'completion-cycle-threshold "24.1")
-
 (defcustom pascal-type-keywords
   '("array" "file" "packed" "char" "integer" "real" "string" "record")
   "Keywords for types used when completing a word in a declaration or parmlist.
@@ -282,7 +274,7 @@ are handled in another way, and should not be added to this 
list."
     (while (and (> nest 0)
                (re-search-forward
                 "[:=]\\|\\(\\<record\\>\\)\\|\\(\\<end\\>\\)"
-                (point-at-eol 2) t))
+                 (line-end-position 2) t))
       (cond ((match-beginning 1) (setq nest (1+ nest)))
            ((match-beginning 2) (setq nest (1- nest)))
            ((looking-at "[^(\n]+)") (setq nest 0))))))
@@ -291,7 +283,8 @@ are handled in another way, and should not be added to this 
list."
 (defun pascal-declaration-beg ()
   (let ((nest 1))
     (while (and (> nest 0)
-               (re-search-backward 
"[:=]\\|\\<\\(type\\|var\\|label\\|const\\)\\>\\|\\(\\<record\\>\\)\\|\\(\\<end\\>\\)"
 (point-at-bol 0) t))
+                (re-search-backward 
"[:=]\\|\\<\\(type\\|var\\|label\\|const\\)\\>\\|\\(\\<record\\>\\)\\|\\(\\<end\\>\\)"
+                                    (line-beginning-position 0) t))
       (cond ((match-beginning 1) (setq nest 0))
            ((match-beginning 2) (setq nest (1- nest)))
            ((match-beginning 3) (setq nest (1+ nest)))))
@@ -299,7 +292,7 @@ are handled in another way, and should not be added to this 
list."
 
 
 (defsubst pascal-within-string ()
-  (nth 3 (parse-partial-sexp (point-at-bol) (point))))
+  (nth 3 (parse-partial-sexp (line-beginning-position) (point))))
 
 
 ;;;###autoload
@@ -396,7 +389,7 @@ See also the user variables `pascal-type-keywords', 
`pascal-start-keywords' and
             (forward-char 1)
             (delete-horizontal-space))
            ((and (looking-at "(\\*\\|\\*[^)]")
-                 (not (save-excursion (search-forward "*)" (point-at-eol) t))))
+                  (not (save-excursion (search-forward "*)" 
(line-end-position) t))))
             (setq setstar t))))
     ;; If last line was a star comment line then this one shall be too.
     (if (null setstar)
@@ -715,7 +708,7 @@ on the line which ends a function or procedure named NAME."
     (if (and (looking-at "\\<end;")
             (not (save-excursion
                    (end-of-line)
-                   (search-backward "{" (point-at-bol) t))))
+                    (search-backward "{" (line-beginning-position) t))))
        (let ((type (car (pascal-calculate-indent))))
          (if (eq type 'declaration)
              ()
@@ -987,7 +980,7 @@ indent of the current line in parameterlist."
           (stpos (progn (goto-char (scan-lists (point) -1 1)) (point)))
           (stcol (1+ (current-column)))
           (edpos (progn (pascal-declaration-end)
-                        (search-backward ")" (point-at-bol) t)
+                         (search-backward ")" (line-beginning-position) t)
                         (point)))
           (usevar (re-search-backward "\\<var\\>" stpos t)))
       (if arg (progn
@@ -1034,7 +1027,7 @@ indent of the current line in parameterlist."
        (setq pascal--extra-indent (pascal-get-lineup-indent stpos edpos 
lineup))
        (goto-char stpos)
        (while (and (<= (point) edpos) (not (eobp)))
-         (if (search-forward lineup (point-at-eol) 'move)
+          (if (search-forward lineup (line-end-position) 'move)
              (forward-char -1))
          (delete-horizontal-space)
          (indent-to pascal--extra-indent)
@@ -1061,7 +1054,7 @@ indent of the current line in parameterlist."
       (goto-char b)
       ;; Get rightmost position
       (while (< (point) e)
-       (and (re-search-forward reg (min e (point-at-eol 2)) 'move)
+        (and (re-search-forward reg (min e (line-end-position 2)) 'move)
             (cond ((match-beginning 1)
                    ;; Skip record blocks
                    (pascal-declaration-end))
@@ -1125,7 +1118,7 @@ indent of the current line in parameterlist."
 
       ;; Search through all reachable functions
       (while (pascal-beg-of-defun)
-        (if (re-search-forward pascal-str (point-at-eol) t)
+        (if (re-search-forward pascal-str (line-end-position) t)
             (progn (setq match (buffer-substring (match-beginning 2)
                                                  (match-end 2)))
                    (push match pascal-all)))
@@ -1142,17 +1135,17 @@ indent of the current line in parameterlist."
        match)
     ;; Traverse lines
     (while (< (point) end)
-      (if (re-search-forward "[:=]" (point-at-eol) t)
+      (if (re-search-forward "[:=]" (line-end-position) t)
          ;; Traverse current line
          (while (and (re-search-backward
                       (concat "\\((\\|\\<\\(var\\|type\\|const\\)\\>\\)\\|"
                               pascal-symbol-re)
-                      (point-at-bol) t)
+                       (line-beginning-position) t)
                      (not (match-end 1)))
            (setq match (buffer-substring (match-beginning 0) (match-end 0)))
            (if (string-match (concat "\\<" pascal-str) match)
                 (push match pascal-all))))
-      (if (re-search-forward "\\<record\\>" (point-at-eol) t)
+      (if (re-search-forward "\\<record\\>" (line-end-position) t)
          (pascal-declaration-end)
        (forward-line 1)))
 
@@ -1195,7 +1188,7 @@ indent of the current line in parameterlist."
           (if (> start (prog1 (save-excursion (pascal-end-of-defun)
                                               (point))))
               ()                        ; Declarations not reachable
-            (if (search-forward "(" (point-at-eol) t)
+            (if (search-forward "(" (line-end-position) t)
                 ;; Check parameterlist
                 ;; FIXME: pascal-get-completion-decl doesn't understand
                 ;; the var declarations in parameter lists :-(
@@ -1253,7 +1246,7 @@ indent of the current line in parameterlist."
                 (or (eq state 'declaration) (eq state 'paramlist)
                     (and (eq state 'defun)
                          (save-excursion
-                           (re-search-backward ")[ \t]*:" (point-at-bol) t))))
+                           (re-search-backward ")[ \t]*:" 
(line-beginning-position) t))))
                 (save-excursion
                   (if (or (eq state 'paramlist) (eq state 'defun))
                       (pascal-beg-of-defun))
@@ -1297,13 +1290,6 @@ indent of the current line in parameterlist."
     (when (> e b)
       (list b e #'pascal-completion))))
 
-(define-obsolete-function-alias 'pascal-complete-word
-  'completion-at-point "24.1")
-
-(define-obsolete-function-alias 'pascal-show-completions
-  'completion-help-at-point "24.1")
-
-
 (defun pascal-get-default-symbol ()
   "Return symbol around current point as a string."
   (save-excursion
diff --git a/lisp/progmodes/perl-mode.el b/lisp/progmodes/perl-mode.el
index 92b47ce88f..70cb460568 100644
--- a/lisp/progmodes/perl-mode.el
+++ b/lisp/progmodes/perl-mode.el
@@ -1120,7 +1120,6 @@ Returns (parse-state) if line starts inside a string."
         (t (forward-char -1) (forward-comment (- (point))) t)))))
 
 ;; note: this may be slower than the c-mode version, but I can understand it.
-(defalias 'indent-perl-exp 'perl-indent-exp)
 (defun perl-indent-exp ()
   "Indent each line of the Perl grouping following point."
   (interactive)
@@ -1220,7 +1219,6 @@ With argument, repeat that many times; negative args move 
backward."
              (goto-char (point-min)))))
       (setq arg (1+ arg)))))
 
-(defalias 'mark-perl-function 'perl-mark-function)
 (defun perl-mark-function ()
   "Put mark at end of Perl function, point at beginning."
   (interactive)
@@ -1230,6 +1228,9 @@ With argument, repeat that many times; negative args move 
backward."
   (perl-beginning-of-function)
   (backward-paragraph))
 
+(define-obsolete-function-alias 'indent-perl-exp #'perl-indent-exp "29.1")
+(define-obsolete-function-alias 'mark-perl-function #'perl-mark-function 
"29.1")
+
 (provide 'perl-mode)
 
 ;;; perl-mode.el ends here
diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el
index f4d6742ed8..30f51704dc 100644
--- a/lisp/progmodes/project.el
+++ b/lisp/progmodes/project.el
@@ -1221,22 +1221,18 @@ displayed."
   (display-buffer-other-frame buffer-or-name))
 
 (defcustom project-kill-buffer-conditions
-  `(buffer-file-name    ; All file-visiting buffers are included.
+  '(buffer-file-name    ; All file-visiting buffers are included.
     ;; Most of the temp buffers in the background:
-    ,(lambda (buf)
-       (not (eq (buffer-local-value 'major-mode buf)
-                'fundamental-mode)))
+    (major-mode . fundamental-mode)
     ;; non-text buffer such as xref, occur, vc, log, ...
-    (and (major-mode . special-mode)
-         ,(lambda (buf)
-            (not (eq (buffer-local-value 'major-mode buf)
-                     'help-mode))))
-    (major-mode . compilation-mode)
-    (major-mode . dired-mode)
-    (major-mode . diff-mode)
-    (major-mode . comint-mode)
-    (major-mode . eshell-mode)
-    (major-mode . change-log-mode))
+    (and (derived-mode . special-mode)
+         (not (major-mode . help-mode)))
+    (derived-mode . compilation-mode)
+    (derived-mode . dired-mode)
+    (derived-mode . diff-mode)
+    (derived-mode . comint-mode)
+    (derived-mode . eshell-mode)
+    (derived-mode . change-log-mode))
   "List of conditions to kill buffers related to a project.
 This list is used by `project-kill-buffers'.
 Each condition is either:
@@ -1246,11 +1242,9 @@ Each condition is either:
 - a cons-cell, where the car describes how to interpret the cdr.
   The car can be one of the following:
   * `major-mode': the buffer is killed if the buffer's major
-    mode is derived from the major mode denoted by the cons-cell's
-    cdr.
+    mode is eq to the cons-cell's cdr.
   * `derived-mode': the buffer is killed if the buffer's major
-    mode is eq to the cons-cell's cdr (this is deprecated and will
-    result in a warning if used).
+    mode is derived from the major mode in the cons-cell's cdr.
   * `not': the cdr is interpreted as a negation of a condition.
   * `and': the cdr is a list of recursive conditions, that all have
     to be met.
@@ -1308,15 +1302,12 @@ form of CONDITIONS."
       (when (cond
              ((stringp c)
               (string-match-p c (buffer-name buf)))
-             ((symbolp c)
+             ((functionp c)
               (funcall c buf))
-             ((eq (car-safe c) 'derived-mode)
-              (warn "The use of `derived-mode' in \
-`project--buffer-check' is deprecated.")
-              (provided-mode-derived-p
-               (buffer-local-value 'major-mode buf)
-               (cdr c)))
              ((eq (car-safe c) 'major-mode)
+              (eq (buffer-local-value 'major-mode buf)
+                  (cdr c)))
+             ((eq (car-safe c) 'derived-mode)
               (provided-mode-derived-p
                (buffer-local-value 'major-mode buf)
                (cdr c)))
diff --git a/lisp/progmodes/prolog.el b/lisp/progmodes/prolog.el
index 9598209f5e..f8edc2b1f7 100644
--- a/lisp/progmodes/prolog.el
+++ b/lisp/progmodes/prolog.el
@@ -84,14 +84,6 @@
 ;; You can also customize the variable
 ;; `prolog-program-name' (in the group `prolog-inferior') and provide
 ;; a full path for your Prolog system (swi, scitus, etc.).
-;;
-;; Note: I (Stefan, the current maintainer) work under XEmacs.  Future
-;;   developments will thus be biased towards XEmacs (OK, I admit it,
-;;   I am biased towards XEmacs in general), though I will do my best
-;;   to keep the GNU Emacs compatibility.  So if you work under Emacs
-;;   and see something that does not work do drop me a line, as I have
-;;   a smaller chance to notice this kind of bugs otherwise.
-;  [The above comment dates from 2011.]
 
 ;; Changelog:
 
@@ -742,14 +734,6 @@ Relevant only when `prolog-imenu-flag' is non-nil."
   :group 'prolog-other
   :type 'boolean)
 
-(defcustom prolog-char-quote-workaround nil
-  "If non-nil, declare 0 as a quote character to handle 0'<char>.
-This is really kludgy, and unneeded (i.e. obsolete) in Emacs>=24."
-  :version "24.1"
-  :group 'prolog-other
-  :type 'boolean)
-(make-obsolete-variable 'prolog-char-quote-workaround nil "24.1")
-
 
 ;;-------------------------------------------------------------------
 ;; Internal variables
@@ -1303,7 +1287,7 @@ To find out what version of Prolog mode you are running, 
enter
         (t t)))
 
 ;; This statement was missing in Emacs 24.1, 24.2, 24.3.
-(define-obsolete-function-alias 'switch-to-prolog 'run-prolog "24.1")
+(define-obsolete-function-alias 'switch-to-prolog 'run-prolog "24.1") ; "24.4" 
; for grep
 ;;;###autoload
 (defun run-prolog (arg)
   "Run an inferior Prolog process, input and output via buffer *prolog*.
@@ -1628,8 +1612,6 @@ Used for temporary files.")
 (defvar prolog-consult-compile-real-file nil
   "The file name of the buffer to compile/consult.")
 
-(defvar compilation-parse-errors-function)
-
 (defun prolog-consult-compile (compilep file &optional first-line)
   "Consult/compile FILE.
 If COMPILEP is non-nil, perform compilation, otherwise perform CONSULTING.
@@ -1655,14 +1637,14 @@ This function must be called from the source code 
buffer."
       ;; Setting up font-locking for this buffer
       (setq-local font-lock-defaults
                   '(prolog-font-lock-keywords nil nil ((?_ . "w"))))
-      (if (eq prolog-system 'sicstus)
-          ;; FIXME: This looks really problematic: not only is this using
-          ;; the old compilation-parse-errors-function, but
-          ;; prolog-parse-sicstus-compilation-errors only accepts one argument
-          ;; whereas compile.el calls it with 2 (and did so at least since
-          ;; Emacs-20).
-          (setq-local compilation-parse-errors-function
-                      'prolog-parse-sicstus-compilation-errors))
+      ;; (if (eq prolog-system 'sicstus)
+      ;;     ;; FIXME: This looks really problematic: not only is this using
+      ;;     ;; the old compilation-parse-errors-function, but
+      ;;     ;; prolog-parse-sicstus-compilation-errors only accepts one
+      ;;     ;; argument whereas compile.el calls it with 2 (and did so at
+      ;;     ;; least since Emacs-20).
+      ;;     (setq-local compilation-parse-errors-function
+      ;;                 #'prolog-parse-sicstus-compilation-errors))
       (setq buffer-read-only nil)
       (insert command-string "\n"))
     (display-buffer buffer)
@@ -1693,40 +1675,41 @@ This function must be called from the source code 
buffer."
 
 (defvar compilation-error-list)
 
-(defun prolog-parse-sicstus-compilation-errors (limit)
-  "Parse the prolog compilation buffer for errors.
-Argument LIMIT is a buffer position limiting searching.
-For use with the `compilation-parse-errors-function' variable."
-  (setq compilation-error-list nil)
-  (message "Parsing SICStus error messages...")
-  (let (filepath dir file errorline)
-    (while
-        (re-search-backward
-         "{\\([a-zA-Z ]* ERROR\\|Warning\\):.* in line[s ]*\\([0-9]+\\)"
-         limit t)
-      (setq errorline (string-to-number (match-string 2)))
-      (save-excursion
-        (re-search-backward
-         "{\\(consulting\\|compiling\\|processing\\) \\(.*\\)\\.\\.\\.}"
-         limit t)
-        (setq filepath (match-string 2)))
-
-      ;; ###### Does this work with SICStus under Windows
-      ;; (i.e. backslashes and stuff?)
-      (if (string-match "\\(.*/\\)\\([^/]*\\)$" filepath)
-          (progn
-            (setq dir (match-string 1 filepath))
-            (setq file (match-string 2 filepath))))
-
-      (setq compilation-error-list
-            (cons
-             (cons (save-excursion
-                     (beginning-of-line)
-                     (point-marker))
-                   (list (list file dir) errorline))
-             compilation-error-list)
-            ))
-    ))
+;; FIXME: This has been obsolete since Emacs-20!
+;; (defun prolog-parse-sicstus-compilation-errors (limit)
+;;   "Parse the prolog compilation buffer for errors.
+;; Argument LIMIT is a buffer position limiting searching.
+;; For use with the `compilation-parse-errors-function' variable."
+;;   (setq compilation-error-list nil)
+;;   (message "Parsing SICStus error messages...")
+;;   (let (filepath dir file errorline)
+;;     (while
+;;         (re-search-backward
+;;          "{\\([a-zA-Z ]* ERROR\\|Warning\\):.* in line[s ]*\\([0-9]+\\)"
+;;          limit t)
+;;       (setq errorline (string-to-number (match-string 2)))
+;;       (save-excursion
+;;         (re-search-backward
+;;          "{\\(consulting\\|compiling\\|processing\\) \\(.*\\)\\.\\.\\.}"
+;;          limit t)
+;;         (setq filepath (match-string 2)))
+
+;;       ;; ###### Does this work with SICStus under Windows
+;;       ;; (i.e. backslashes and stuff?)
+;;       (if (string-match "\\(.*/\\)\\([^/]*\\)$" filepath)
+;;           (progn
+;;             (setq dir (match-string 1 filepath))
+;;             (setq file (match-string 2 filepath))))
+
+;;       (setq compilation-error-list
+;;             (cons
+;;              (cons (save-excursion
+;;                      (beginning-of-line)
+;;                      (point-marker))
+;;                    (list (list file dir) errorline))
+;;              compilation-error-list)
+;;             ))
+;;     ))
 
 (defun prolog-consult-compile-filter (process output)
   "Filter function for Prolog compilation PROCESS.
@@ -2299,12 +2282,12 @@ between them)."
             (backward-paragraph)
             (unless (bobp) (forward-line))
             (if (string-match "^/\\*[^a-zA-Z]*$" (thing-at-point 'line))
-                (narrow-to-region (point-at-eol) (point-max))))
+                (narrow-to-region (line-end-position) (point-max))))
           (save-excursion
             (forward-paragraph)
             (forward-line -1)
             (if (string-match "^[^a-zA-Z]*\\*/$" (thing-at-point 'line))
-                (narrow-to-region (point-min) (point-at-bol))))
+                (narrow-to-region (point-min) (line-beginning-position))))
           (let ((fill-prefix (prolog-guess-fill-prefix)))
             (fill-paragraph nil))))
       )))
diff --git a/lisp/progmodes/ps-mode.el b/lisp/progmodes/ps-mode.el
index 7c9aee2b2a..89482d86ce 100644
--- a/lisp/progmodes/ps-mode.el
+++ b/lisp/progmodes/ps-mode.el
@@ -34,7 +34,6 @@
 
 ;;; Code:
 
-(defconst ps-mode-version "1.1i, 17 May 2008")
 (defconst ps-mode-maintainer-address
   "Peter Kleiweg <p.c.j.kleiweg@rug.nl>, bug-gnu-emacs@gnu.org")
 
@@ -519,7 +518,7 @@ Typing \\<ps-run-mode-map>\\[ps-run-goto-error] when the 
cursor is at the number
 (defun ps-mode-show-version ()
   "Show current version of PostScript mode."
   (interactive)
-  (message " *** PostScript Mode (ps-mode) Version %s *** " ps-mode-version))
+  (message " *** PostScript Mode (ps-mode) in GNU Emacs %s *** " 
emacs-version))
 
 ;; From reporter.el
 (defvar reporter-prompt-for-summary-p)
@@ -534,7 +533,7 @@ Typing \\<ps-run-mode-map>\\[ps-run-goto-error] when the 
cursor is at the number
                                        ps-run-font-lock-keywords-2)))
       (reporter-submit-bug-report
        ps-mode-maintainer-address
-       (format "ps-mode.el %s [%s]" ps-mode-version system-type)
+       (format "ps-mode.el %s [%s]" emacs-version system-type)
        '(ps-mode-tab
         ps-mode-paper-size
         ps-mode-print-function
@@ -1094,6 +1093,9 @@ Use line numbers if `ps-run-error-line-numbers' is not 
nil."
 ;;
 (add-hook 'kill-emacs-hook #'ps-run-cleanup)
 
+(defconst ps-mode-version "1.1i, 17 May 2008")
+(make-obsolete-variable 'ps-mode-version 'emacs-version "29.1")
+
 (provide 'ps-mode)
 
 ;;; ps-mode.el ends here
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index c2483436fe..d3ffc2db2c 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -248,7 +248,6 @@
 (eval-when-compile (require 'subr-x))   ;For `string-empty-p'.
 
 ;; Avoid compiler warnings
-(defvar view-return-to-alist)
 (defvar compilation-error-regexp-alist)
 (defvar outline-heading-end-regexp)
 
@@ -360,6 +359,7 @@
   "Python mode specialized rx macro.
 This variant of `rx' supports common Python named REGEXPS."
   `(rx-let ((sp-bsnl (or space (and ?\\ ?\n)))
+            (sp-nl (or space (and (? ?\\) ?\n)))
             (block-start       (seq symbol-start
                                     (or "def" "class" "if" "elif" "else" "try"
                                         "except" "finally" "for" "while" "with"
@@ -428,7 +428,19 @@ This variant of `rx' supports common Python named REGEXPS."
                                  (: "vim:" (* space) "set" (+ space)
                                     "fileencoding" (* space) ?= (* space)
                                     (group-n 1 (+ (or word ?-)))
-                                    (* space) ":")))))
+                                    (* space) ":"))))
+            (bytes-escape-sequence
+             (seq (not "\\")
+                  (group (or "\\\\" "\\'" "\\a" "\\b" "\\f"
+                             "\\n" "\\r" "\\t" "\\v"
+                             (seq "\\" (** 1 3 (in "0-7")))
+                             (seq "\\x" hex hex)))))
+            (string-escape-sequence
+             (or bytes-escape-sequence
+                 (seq (not "\\")
+                      (or (group-n 1 "\\u" (= 4 hex))
+                          (group-n 1 "\\U" (= 8 hex))
+                          (group-n 1 "\\N{" (*? anychar) "}"))))))
      (rx ,@regexps)))
 
 
@@ -540,10 +552,41 @@ the {...} holes that appear within f-strings."
         (goto-char (min limit (1+ send)))
         (setq ppss (syntax-ppss))))))
 
+(defconst python--not-raw-bytes-literal-start-regexp
+  (rx (or bos (not alnum)) (or "b" "B") (or "\"" "\"\"\"" "'" "'''") eos)
+  "A regular expression matching the start of a not-raw bytes literal.")
+
+(defconst python--not-raw-string-literal-start-regexp
+  (rx bos (or
+           ;; Multi-line string literals
+           (seq (? (? (not alnum)) (or "u" "U" "F" "f")) (or "\"\"\"" "'''"))
+           (seq (? anychar) (not alnum) (or "\"\"\"" "'''"))
+           ;; Single line string literals
+           (seq (? (** 0 2 anychar) (not alnum)) (or "u" "U" "F" "f") (or "'" 
"\""))
+           (seq (? (** 0 3 anychar) (not (any "'\"" alnum))) (or "'" "\"")))
+      eos)
+  "A regular expression matching the start of a not-raw string literal.")
+
+(defun python--string-bytes-literal-matcher (regexp start-regexp)
+  "Match REGEXP within a string or bytes literal whose start matches 
START-REGEXP."
+  (lambda (limit)
+    (cl-loop for result = (re-search-forward regexp limit t)
+             for result-valid = (and
+                                 result
+                                 (when-let* ((pos (nth 8 (syntax-ppss)))
+                                             (before-quote
+                                              (buffer-substring-no-properties
+                                               (max (- pos 4) (point-min))
+                                               (min (+ pos 1) (point-max)))))
+                                   (backward-char)
+                                   (string-match-p start-regexp before-quote)))
+             until (or (not result) result-valid)
+             finally return (and result-valid result))))
+
 (defvar python-font-lock-keywords-level-1
-  `((,(python-rx symbol-start "def" (1+ space) (group symbol-name))
+  `((,(python-rx symbol-start "def" (1+ sp-bsnl) (group symbol-name))
      (1 font-lock-function-name-face))
-    (,(python-rx symbol-start "class" (1+ space) (group symbol-name))
+    (,(python-rx symbol-start "class" (1+ sp-bsnl) (group symbol-name))
      (1 font-lock-type-face)))
   "Font lock keywords to use in `python-mode' for level 1 decoration.
 
@@ -683,12 +726,12 @@ sign in chained assignment."
     ;;   [*a] = 5, 6
     ;; are handled separately below
     (,(python-font-lock-assignment-matcher
-        (python-rx (? (or "[" "(") (* space))
-                   grouped-assignment-target (* space) ?, (* space)
-                   (* assignment-target (* space) ?, (* space))
-                   (? assignment-target (* space))
-                   (? ?, (* space))
-                   (? (or ")" "]") (* space))
+        (python-rx (? (or "[" "(") (* sp-nl))
+                   grouped-assignment-target (* sp-nl) ?, (* sp-nl)
+                   (* assignment-target (* sp-nl) ?, (* sp-nl))
+                   (? assignment-target (* sp-nl))
+                   (? ?, (* sp-nl))
+                   (? (or ")" "]") (* sp-bsnl))
                    (group assignment-operator)))
      (1 font-lock-variable-name-face)
      (,(python-rx grouped-assignment-target)
@@ -703,21 +746,39 @@ sign in chained assignment."
     ;;   c: Collection = {1, 2, 3}
     ;;   d: Mapping[int, str] = {1: 'bar', 2: 'baz'}
     (,(python-font-lock-assignment-matcher
-        (python-rx grouped-assignment-target (* space)
-                   (? ?: (* space) (+ not-simple-operator) (* space))
-                   assignment-operator))
+       (python-rx (or line-start ?\;) (* sp-bsnl)
+                  grouped-assignment-target (* sp-bsnl)
+                  (? ?: (* sp-bsnl) (+ not-simple-operator) (* sp-bsnl))
+                  assignment-operator))
      (1 font-lock-variable-name-face))
     ;; special cases
     ;;   (a) = 5
     ;;   [a] = 5,
     ;;   [*a] = 5, 6
     (,(python-font-lock-assignment-matcher
-       (python-rx (or line-start ?\; ?=) (* space)
-                  (or "[" "(") (* space)
-                  grouped-assignment-target (* space)
-                  (or ")" "]") (* space)
+       (python-rx (or line-start ?\; ?=) (* sp-bsnl)
+                  (or "[" "(") (* sp-nl)
+                  grouped-assignment-target (* sp-nl)
+                  (or ")" "]") (* sp-bsnl)
                   assignment-operator))
-     (1 font-lock-variable-name-face)))
+     (1 font-lock-variable-name-face))
+    ;; escape sequences within bytes literals
+    ;;   "\\" "\'" "\a" "\b" "\f" "\n" "\r" "\t" "\v"
+    ;;   "\ooo" character with octal value ooo
+    ;;   "\xhh" character with hex value hh
+    (,(python--string-bytes-literal-matcher
+       (python-rx bytes-escape-sequence)
+       python--not-raw-bytes-literal-start-regexp)
+     (1 font-lock-constant-face t))
+    ;; escape sequences within string literals, the same as appear in bytes
+    ;; literals in addition to:
+    ;;   "\uxxxx" Character with 16-bit hex value xxxx
+    ;;   "\Uxxxxxxxx" Character with 32-bit hex value xxxxxxxx
+    ;;   "\N{name}" Character named name in the Unicode database
+    (,(python--string-bytes-literal-matcher
+       (python-rx string-escape-sequence)
+       python--not-raw-string-literal-start-regexp)
+     (1 'font-lock-constant-face t)))
   "Font lock keywords to use in `python-mode' for maximum decoration.
 
 This decoration level includes everything in
@@ -737,6 +798,18 @@ decorators, exceptions, and assignments.")
 Which one will be chosen depends on the value of
 `font-lock-maximum-decoration'.")
 
+(defun python-font-lock-extend-region (beg end _old-len)
+  "Extend font-lock region given by BEG and END to statement boundaries."
+  (save-excursion
+    (save-match-data
+      (goto-char beg)
+      (python-nav-beginning-of-statement)
+      (setq beg (point))
+      (goto-char end)
+      (python-nav-end-of-statement)
+      (setq end (point))
+      (cons beg end))))
+
 
 (defconst python-syntax-propertize-function
   (syntax-propertize-rules
@@ -1165,8 +1238,14 @@ possibilities can be narrowed to specific indentation 
points."
          ;; Add one indentation level.
          (goto-char start)
          (+ (current-indentation) python-indent-offset))
+        (`(:after-backslash-block-continuation . ,start)
+         (goto-char start)
+         (let ((column (current-column)))
+           (if (= column (+ (current-indentation) python-indent-offset))
+               ;; Add one level to avoid same indent as next logical line.
+               (+ column python-indent-offset)
+             column)))
         (`(,(or :inside-paren
-                :after-backslash-block-continuation
                 :after-backslash-dotted-continuation) . ,start)
          ;; Use the column given by the context.
          (goto-char start)
@@ -1445,6 +1524,10 @@ marks the next defun after the ones already marked."
 The name of the defun should be grouped so it can be retrieved
 via `match-string'.")
 
+(defvar python-nav-beginning-of-block-regexp
+  (python-rx line-start (* space) block-start)
+  "Regexp matching block start.")
+
 (defun python-nav--beginning-of-defun (&optional arg)
   "Internal implementation of `python-nav-beginning-of-defun'.
 With positive ARG search backwards, else search forwards."
@@ -1455,26 +1538,40 @@ With positive ARG search backwards, else search 
forwards."
          (line-beg-pos (line-beginning-position))
          (line-content-start (+ line-beg-pos (current-indentation)))
          (pos (point-marker))
+         (min-indentation (if (python-info-current-line-empty-p)
+                              most-positive-fixnum
+                            (current-indentation)))
          (body-indentation
           (and (> arg 0)
-               (save-excursion
-                 (while (and
-                         (not (python-info-looking-at-beginning-of-defun))
-                         (python-nav-backward-block)))
-                 (or (and (python-info-looking-at-beginning-of-defun)
-                          (+ (current-indentation) python-indent-offset))
-                     0))))
+               (or (and (python-info-looking-at-beginning-of-defun nil t)
+                        (+ (save-excursion
+                             (python-nav-beginning-of-statement)
+                             (current-indentation))
+                           python-indent-offset))
+                   (save-excursion
+                     (while
+                         (and
+                          (python-nav-backward-block)
+                          (or (not (python-info-looking-at-beginning-of-defun))
+                              (>= (current-indentation) min-indentation))
+                          (setq min-indentation
+                                (min min-indentation (current-indentation)))))
+                     (or (and (python-info-looking-at-beginning-of-defun)
+                              (+ (current-indentation) python-indent-offset))
+                         0)))))
          (found
           (progn
-            (when (and (python-info-looking-at-beginning-of-defun)
+            (when (and (python-info-looking-at-beginning-of-defun nil t)
                        (or (< arg 0)
                            ;; If looking at beginning of defun, and if
                            ;; pos is > line-content-start, ensure a
                            ;; backward re search match this defun by
                            ;; going to end of line before calling
                            ;; re-search-fn bug#40563
-                           (and (> arg 0) (> pos line-content-start))))
-              (end-of-line 1))
+                           (and (> arg 0)
+                                (or (python-info-continuation-line-p)
+                                    (> pos line-content-start)))))
+              (python-nav-end-of-statement))
 
             (while (and (funcall re-search-fn
                                  python-nav-beginning-of-defun-regexp nil t)
@@ -1484,14 +1581,18 @@ With positive ARG search backwards, else search 
forwards."
                             (and (> arg 0)
                                  (not (= (current-indentation) 0))
                                  (>= (current-indentation) 
body-indentation)))))
-            (and (python-info-looking-at-beginning-of-defun)
+            (and (python-info-looking-at-beginning-of-defun nil t)
                  (or (not (= (line-number-at-pos pos)
                              (line-number-at-pos)))
                      (and (>= (point) line-beg-pos)
                           (<= (point) line-content-start)
                           (> pos line-content-start)))))))
     (if found
-        (or (beginning-of-line 1) t)
+        (progn
+          (when (< arg 0)
+            (python-nav-beginning-of-statement))
+          (beginning-of-line 1)
+          t)
       (and (goto-char pos) nil))))
 
 (defun python-nav-beginning-of-defun (&optional arg)
@@ -1630,11 +1731,15 @@ of the statement."
     (while (and (or noend (goto-char (line-end-position)))
                 (not (eobp))
                 (cond ((setq string-start (python-syntax-context 'string))
-                       ;; The assertion can only fail if syntax table
+                       ;; The condition can be nil if syntax table
                        ;; text properties and the `syntax-ppss' cache
                        ;; are somehow out of whack.  This has been
                        ;; observed when using `syntax-ppss' during
                        ;; narrowing.
+                       ;; It can also fail in cases where the buffer is in
+                       ;; the process of being modified, e.g. when creating
+                       ;; a string with `electric-pair-mode' disabled such
+                       ;; that there can be an unmatched single quote
                        (when (>= string-start last-string-end)
                          (goto-char string-start)
                          (if (python-syntax-context 'paren)
@@ -1688,16 +1793,16 @@ backward to previous statement."
   "Move to start of current block."
   (interactive "^")
   (let ((starting-pos (point)))
+    ;; Go to first line beginning a statement
+    (while (and (not (bobp))
+                (or (and (python-nav-beginning-of-statement) nil)
+                    (python-info-current-line-comment-p)
+                    (python-info-current-line-empty-p)))
+      (forward-line -1))
     (if (progn
           (python-nav-beginning-of-statement)
           (looking-at (python-rx block-start)))
         (point-marker)
-      ;; Go to first line beginning a statement
-      (while (and (not (bobp))
-                  (or (and (python-nav-beginning-of-statement) nil)
-                      (python-info-current-line-comment-p)
-                      (python-info-current-line-empty-p)))
-        (forward-line -1))
       (let ((block-matching-indent
              (- (current-indentation) python-indent-offset)))
         (while
@@ -1717,7 +1822,10 @@ backward to previous statement."
       (while (and (forward-line 1)
                   (not (eobp))
                   (or (and (> (current-indentation) block-indentation)
-                           (or (python-nav-end-of-statement) t))
+                           (let ((start (point)))
+                             (python-nav-end-of-statement)
+                             ;; must move forward otherwise infinite loop
+                             (> (point) start)))
                       (python-info-current-line-comment-p)
                       (python-info-current-line-empty-p))))
       (python-util-forward-comment -1)
@@ -1738,7 +1846,8 @@ backward to previous block."
   (or arg (setq arg 1))
   (let ((block-start-regexp
          (python-rx line-start (* whitespace) block-start))
-        (starting-pos (point)))
+        (starting-pos (point))
+        (orig-arg arg))
     (while (> arg 0)
       (python-nav-end-of-statement)
       (while (and
@@ -1752,7 +1861,8 @@ backward to previous block."
               (python-syntax-context-type)))
       (setq arg (1+ arg)))
     (python-nav-beginning-of-statement)
-    (if (not (looking-at (python-rx block-start)))
+    (if (or (and (> orig-arg 0) (< (point) starting-pos))
+            (not (looking-at (python-rx block-start))))
         (and (goto-char starting-pos) nil)
       (and (not (= (point) starting-pos)) (point-marker)))))
 
@@ -3091,7 +3201,8 @@ of `error' with a user-friendly message."
   (or (python-shell-get-process)
       (if interactivep
           (user-error
-           "Start a Python process first with `M-x run-python' or `%s'"
+           (substitute-command-keys
+            "Start a Python process first with \\`M-x run-python' or `%s'")
            ;; Get the binding.
            (key-description
             (where-is-internal
@@ -4455,6 +4566,11 @@ the if condition."
                       (not (python-syntax-comment-or-string-p))
                       python-skeleton-autoinsert)))
 
+(defun python--completion-predicate (_ buffer)
+  (provided-mode-derived-p
+   (buffer-local-value 'major-mode buffer)
+   'python-mode))
+
 (defmacro python-skeleton-define (name doc &rest skel)
   "Define a `python-mode' skeleton using NAME DOC and SKEL.
 The skeleton will be bound to python-skeleton-NAME and will
@@ -4463,6 +4579,7 @@ be added to `python-mode-skeleton-abbrev-table'."
   (let* ((name (symbol-name name))
          (function-name (intern (concat "python-skeleton-" name))))
     `(progn
+       (put ',function-name 'completion-predicate 
#'python--completion-predicate)
        (define-abbrev python-mode-skeleton-abbrev-table
          ,name "" ',function-name :system t)
        (setq python-skeleton-available
@@ -4488,13 +4605,15 @@ The skeleton will be bound to python-skeleton-NAME."
       (setq skel
             `(< ,(format "%s:" name) \n \n
                 > _ \n)))
-    `(define-skeleton ,function-name
-       ,(or doc
-            (format "Auxiliary skeleton for %s statement." name))
-       nil
-       (unless (y-or-n-p ,msg)
-         (signal 'quit t))
-       ,@skel)))
+    `(progn
+       (put ',function-name 'completion-predicate #'ignore)
+       (define-skeleton ,function-name
+         ,(or doc
+              (format "Auxiliary skeleton for %s statement." name))
+         nil
+         (unless (y-or-n-p ,msg)
+           (signal 'quit t))
+         ,@skel))))
 
 (python-define-auxiliary-skeleton else)
 
@@ -4617,11 +4736,12 @@ def __FFAP_get_module_path(objstr):
 ;;; Code check
 
 (defcustom python-check-command
-  (or (executable-find "pyflakes")
-      (executable-find "epylint")
-      "install pyflakes, pylint or something else")
+  (cond ((executable-find "pyflakes") "pyflakes")
+        ((executable-find "epylint") "epylint")
+        (t "pyflakes"))
   "Command used to check a Python file."
-  :type 'string)
+  :type 'string
+  :version "29.1")
 
 (defcustom python-check-buffer-name
   "*Python check: %s*"
@@ -4800,9 +4920,37 @@ Interactively, prompt for symbol."
 (defun python-hideshow-forward-sexp-function (_arg)
   "Python specific `forward-sexp' function for `hs-minor-mode'.
 Argument ARG is ignored."
-  (python-nav-end-of-defun)
-  (unless (python-info-current-line-empty-p)
-    (backward-char)))
+  (python-nav-end-of-block))
+
+(defun python-hideshow-find-next-block (regexp maxp comments)
+  "Python specific `hs-find-next-block' function for `hs-minor-mode'.
+Call `python-nav-forward-block' to find next block and check if
+block-start ends within MAXP.  If COMMENTS is not nil, comments
+are also searched.  REGEXP is passed to `looking-at' to set
+`match-data'."
+  (let* ((next-block (save-excursion
+                       (or (and
+                            (python-info-looking-at-beginning-of-block)
+                            (re-search-forward
+                             (python-rx block-start) maxp t))
+                           (and (python-nav-forward-block)
+                                (< (point) maxp)
+                                (re-search-forward
+                                 (python-rx block-start) maxp t))
+                           (1+ maxp))))
+         (next-comment
+          (or (when comments
+                (save-excursion
+                  (cl-loop while (re-search-forward "#" maxp t)
+                           if (python-syntax-context 'comment)
+                           return (point))))
+              (1+ maxp)))
+         (next-block-or-comment (min next-block next-comment)))
+    (when (<= next-block-or-comment maxp)
+      (goto-char next-block-or-comment)
+      (save-excursion
+        (beginning-of-line)
+        (looking-at regexp)))))
 
 
 ;;; Imenu
@@ -5146,7 +5294,8 @@ likely an invalid python file."
                                  (while (and (< (point) cur-line)
                                              (setq no-back-indent
                                                    (or (> 
(current-indentation) indentation)
-                                                       
(python-info-current-line-empty-p))))
+                                                       
(python-info-current-line-empty-p)
+                                                       
(python-info-current-line-comment-p))))
                                    (forward-line)))
                                no-back-indent)))
                   (setq collected-indentations
@@ -5286,13 +5435,28 @@ operator."
       (forward-line -1)
       (python-info-assignment-statement-p t))))
 
-(defun python-info-looking-at-beginning-of-defun (&optional syntax-ppss)
-  "Check if point is at `beginning-of-defun' using SYNTAX-PPSS."
+(defun python-info-looking-at-beginning-of-defun (&optional syntax-ppss
+                                                            check-statement)
+  "Check if point is at `beginning-of-defun' using SYNTAX-PPSS.
+When CHECK-STATEMENT is non-nil, the current statement is checked
+instead of the current physical line."
   (and (not (python-syntax-context-type (or syntax-ppss (syntax-ppss))))
        (save-excursion
+         (when check-statement
+           (python-nav-beginning-of-statement))
          (beginning-of-line 1)
          (looking-at python-nav-beginning-of-defun-regexp))))
 
+(defun python-info-looking-at-beginning-of-block ()
+  "Check if point is at the beginning of block."
+  (let ((pos (point)))
+    (save-excursion
+      (python-nav-beginning-of-statement)
+      (beginning-of-line)
+      (and
+       (<= (point) pos (+ (point) (current-indentation)))
+       (looking-at python-nav-beginning-of-block-regexp)))))
+
 (defun python-info-current-line-comment-p ()
   "Return non-nil if current line is a comment line."
   (char-equal
@@ -5534,9 +5698,13 @@ returned as is."
 This is a non empty list of strings, the checker tool possibly followed by
 required arguments.  Once launched it will receive the Python source to be
 checked as its standard input.
-To use `flake8' you would set this to (\"flake8\" \"-\")."
+To use `flake8' you would set this to (\"flake8\" \"-\").
+To use `pylint' you would set this to (\"pylint\" \"--from-stdin\" \"stdin\")."
   :version "26.1"
-  :type '(repeat string))
+  :type '(choice (const :tag "Pyflakes" ("pyflakes"))
+                 (const :tag "Flake8" ("flake8" "-"))
+                 (const :tag "Pylint" ("pylint" "--from-stdin" "stdin"))
+                 (repeat :tag "Custom command" string)))
 
 ;; The default regexp accommodates for older pyflakes, which did not
 ;; report the column number, and at the same time it's compatible with
@@ -5544,7 +5712,7 @@ To use `flake8' you would set this to (\"flake8\" \"-\")."
 ;; TYPE
 (defcustom python-flymake-command-output-pattern
   (list
-   "^\\(?:<?stdin>?\\):\\(?1:[0-9]+\\):\\(?:\\(?2:[0-9]+\\):\\)? \\(?3:.*\\)$"
+   "^\\(?:<?stdin>?\\):\\(?1:[0-9]+\\):\\(?:\\(?2:[0-9]+\\):?\\)? \\(?3:.*\\)$"
    1 2 nil 3)
   "Specify how to parse the output of `python-flymake-command'.
 The value has the form (REGEXP LINE COLUMN TYPE MESSAGE): if
@@ -5556,7 +5724,6 @@ MESSAGE'th gives the message text itself.
 If COLUMN or TYPE are nil or that index didn't match, that
 information is not present on the matched line and a default will
 be used."
-  :version "26.1"
   :type '(list regexp
                (integer :tag "Line's index")
                (choice
@@ -5565,7 +5732,8 @@ be used."
                (choice
                 (const :tag "No type" nil)
                 (integer :tag "Type's index"))
-               (integer :tag "Message's index")))
+               (integer :tag "Message's index"))
+  :version "29.1")
 
 (defcustom python-flymake-msg-alist
   '(("\\(^redefinition\\|.*unused.*\\|used$\\)" . :warning))
@@ -5687,7 +5855,9 @@ REPORT-FN is Flymake's callback function."
               `(,python-font-lock-keywords
                 nil nil nil nil
                 (font-lock-syntactic-face-function
-                 . python-font-lock-syntactic-face-function)))
+                 . python-font-lock-syntactic-face-function)
+                (font-lock-extend-after-change-region-function
+                 . python-font-lock-extend-region)))
 
   (setq-local syntax-propertize-function
               python-syntax-propertize-function)
@@ -5742,17 +5912,19 @@ REPORT-FN is Flymake's callback function."
 
   (add-to-list
    'hs-special-modes-alist
-   '(python-mode
-     "\\s-*\\_<\\(?:def\\|class\\)\\_>"
+   `(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))
+     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-heading-end-regexp ":[^\n]*\n")
   (setq-local outline-level
               (lambda ()
                 "`outline-level' function for Python mode."
@@ -5769,11 +5941,60 @@ REPORT-FN is Flymake's callback function."
 
   (add-hook 'flymake-diagnostic-functions #'python-flymake nil t))
 
+;;; Completion predicates for M-x
+;; Commands that only make sense when editing Python code
+(dolist (sym '(python-check
+               python-fill-paragraph
+               python-indent-dedent-line
+               python-indent-dedent-line-backspace
+               python-indent-guess-indent-offset
+               python-indent-shift-left
+               python-indent-shift-right
+               python-mark-defun
+               python-nav-backward-block
+               python-nav-backward-defun
+               python-nav-backward-sexp
+               python-nav-backward-sexp-safe
+               python-nav-backward-statement
+               python-nav-backward-up-list
+               python-nav-beginning-of-block
+               python-nav-beginning-of-statement
+               python-nav-end-of-block
+               python-nav-end-of-defun
+               python-nav-end-of-statement
+               python-nav-forward-block
+               python-nav-forward-defun
+               python-nav-forward-sexp
+               python-nav-forward-sexp-safe
+               python-nav-forward-statement
+               python-nav-if-name-main
+               python-nav-up-list
+               python-shell-send-buffer
+               python-shell-send-defun
+               python-shell-send-statement))
+  (put sym 'completion-predicate #'python--completion-predicate))
+
+(defun python-shell--completion-predicate (_ buffer)
+  (provided-mode-derived-p
+   (buffer-local-value 'major-mode buffer)
+   'python-mode 'inferior-python-mode))
+
+;; Commands that only make sense in the Python shell or when editing
+;; Python code.
+(dolist (sym '(python-describe-at-point
+               python-eldoc-at-point
+               python-shell-completion-native-toggle
+               python-shell-completion-native-turn-off
+               python-shell-completion-native-turn-on
+               python-shell-completion-native-turn-on-maybe
+               python-shell-font-lock-cleanup-buffer
+               python-shell-font-lock-toggle
+               python-shell-font-lock-turn-off
+               python-shell-font-lock-turn-on
+               python-shell-package-enable
+               python-shell-completion-complete-or-indent  ))
+  (put sym 'completion-predicate #'python-shell--completion-predicate))
 
 (provide 'python)
 
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-
 ;;; python.el ends here
diff --git a/lisp/progmodes/ruby-mode.el b/lisp/progmodes/ruby-mode.el
index a197724634..955daa393c 100644
--- a/lisp/progmodes/ruby-mode.el
+++ b/lisp/progmodes/ruby-mode.el
@@ -1147,7 +1147,7 @@ delimiter."
           (setq re (regexp-quote (or (match-string 4) (match-string 2))))
           (if (match-beginning 1) (setq re (concat "\\s *" re)))
           (let* ((id-end (goto-char (match-end 0)))
-                 (line-end-position (point-at-eol))
+                 (line-end-position (line-end-position))
                  (state (list in-string nest depth pcol indent)))
             ;; parse the rest of the line
             (while (and (> line-end-position (point))
@@ -1924,7 +1924,7 @@ It will be properly highlighted even when the call omits 
parens.")
                         (save-excursion
                           (forward-char -1)
                           (looking-back ruby-syntax-before-regexp-re
-                                        (point-at-bol))))
+                                        (line-beginning-position))))
                    ;; End of regexp.  We don't match the whole
                    ;; regexp at once because it can have
                    ;; string interpolation inside, or span
@@ -2457,6 +2457,13 @@ If there is no Rubocop config file, Rubocop will be 
passed a flag
   (setq-local beginning-of-defun-function #'ruby-beginning-of-defun)
   (setq-local end-of-defun-function #'ruby-end-of-defun)
 
+  ;; `outline-regexp' contains the first part of `ruby-indent-beg-re'
+  (setq-local outline-regexp (concat "^\\s *"
+                                     (regexp-opt '("class" "module" "def"))
+                                     "\\_>"))
+  (setq-local outline-level (lambda () (1+ (/ (current-indentation)
+                                              ruby-indent-level))))
+
   (add-hook 'after-save-hook #'ruby-mode-set-encoding nil 'local)
   (add-hook 'electric-indent-functions #'ruby--electric-indent-p nil 'local)
   (add-hook 'flymake-diagnostic-functions #'ruby-flymake-auto nil 'local)
diff --git a/lisp/progmodes/scheme.el b/lisp/progmodes/scheme.el
index 9b24c2155d..e0453c3b2f 100644
--- a/lisp/progmodes/scheme.el
+++ b/lisp/progmodes/scheme.el
@@ -388,12 +388,18 @@ See `run-hooks'."
     st))
 
 (put 'lambda 'scheme-doc-string-elt 2)
+(put 'lambda* 'scheme-doc-string-elt 2)
 ;; Docstring's pos in a `define' depends on whether it's a var or fun def.
 (put 'define 'scheme-doc-string-elt
      (lambda ()
        ;; The function is called with point right after "define".
        (forward-comment (point-max))
        (if (eq (char-after) ?\() 2 0)))
+(put 'define* 'scheme-doc-string-elt 2)
+(put 'case-lambda 'scheme-doc-string-elt 1)
+(put 'case-lambda* 'scheme-doc-string-elt 1)
+(put 'define-syntax-rule 'scheme-doc-string-elt 2)
+(put 'syntax-rules 'scheme-doc-string-elt 2)
 
 (defun scheme-syntax-propertize (beg end)
   (goto-char beg)
diff --git a/lisp/progmodes/sh-script.el b/lisp/progmodes/sh-script.el
index 75758fd39a..be9f325d93 100644
--- a/lisp/progmodes/sh-script.el
+++ b/lisp/progmodes/sh-script.el
@@ -1156,8 +1156,8 @@ Can be set to a number, or to nil which means leave it as 
is."
   "The default indentation increment.
 This value is used for the `+' and `-' symbols in an indentation variable."
   :type 'integer
+  :safe #'integerp
   :group 'sh-indentation)
-(put 'sh-basic-offset 'safe-local-variable 'integerp)
 
 (defcustom sh-indent-comment t
   "How a comment line is to be indented.
@@ -1926,9 +1926,9 @@ With t, you get the latter as long as that would indent 
the continuation line
 deeper than the initial line."
   :version "25.1"
   :type '(choice
-          (const nil :tag "Never")
-          (const t   :tag "Only if needed to make it deeper")
-          (const always :tag "Always"))
+          (const :value nil    :tag "Never")
+          (const :value t      :tag "Only if needed to make it deeper")
+          (const :value always :tag "Always"))
   :group 'sh-indentation)
 
 (defun sh-smie--continuation-start-indent ()
@@ -2410,6 +2410,8 @@ Lines containing only comments are considered empty."
 The working directory is that of the buffer, and only environment variables
 are already set which is why you can mark a header within the script.
 
+The executed subshell is `sh-shell-file'.
+
 With a positive prefix ARG, instead of sending region, define header from
 beginning of buffer to point.  With a negative prefix ARG, instead of sending
 region, clear header."
@@ -2417,17 +2419,18 @@ region, clear header."
   (if flag
       (setq sh-header-marker (if (> (prefix-numeric-value flag) 0)
                                 (point-marker)))
-    (if sh-header-marker
-       (save-excursion
-         (let (buffer-undo-list)
-           (goto-char sh-header-marker)
-           (append-to-buffer (current-buffer) start end)
-           (shell-command-on-region (point-min)
-                                    (setq end (+ sh-header-marker
-                                                 (- end start)))
-                                    sh-shell-file)
-           (delete-region sh-header-marker end)))
-      (shell-command-on-region start end (concat sh-shell-file " -")))))
+    (let ((shell-file-name sh-shell-file))
+      (if sh-header-marker
+         (save-excursion
+           (let (buffer-undo-list)
+             (goto-char sh-header-marker)
+             (append-to-buffer (current-buffer) start end)
+             (shell-command-on-region (point-min)
+                                      (setq end (+ sh-header-marker
+                                                   (- end start)))
+                                      sh-shell-file)
+             (delete-region sh-header-marker end)))
+        (shell-command-on-region start end (concat sh-shell-file " -"))))))
 
 
 (defun sh-remember-variable (var)
diff --git a/lisp/progmodes/sql.el b/lisp/progmodes/sql.el
index 8d25986090..b950f93f2a 100644
--- a/lisp/progmodes/sql.el
+++ b/lisp/progmodes/sql.el
@@ -274,8 +274,8 @@ file.  Since that is a plaintext file, this could be 
dangerous."
 (defcustom sql-port 0
   "Default port for connecting to a MySQL or Postgres server."
   :version "24.1"
-  :type 'number
-  :safe 'numberp)
+  :type 'natnum
+  :safe 'natnump)
 
 (defcustom sql-default-directory nil
   "Default directory for SQL processes."
@@ -4161,28 +4161,33 @@ must tell Emacs.  Here's how to do that in your init 
file:
   (setq-local sql-contains-names t)
   (setq-local escaped-string-quote "'")
   (setq-local syntax-propertize-function
-              (syntax-propertize-rules
-               ;; Handle escaped apostrophes within strings.
-               ("''"
-                (0
-                 (if (save-excursion (nth 3 (syntax-ppss (match-beginning 0))))
-                    (string-to-syntax ".")
-                   (forward-char -1)
-                   nil)))
-               ;; Propertize rules to not have /- and -* start comments.
-               ("\\(/-\\)" (1 "."))
-               ("\\(-\\*\\)"
-                (1
-                 (if (save-excursion
-                       (not (ppss-comment-depth
-                             (syntax-ppss (match-beginning 1)))))
-                     ;; If we're outside a comment, we don't let -*
-                     ;; start a comment.
-                    (string-to-syntax ".")
-                   ;; Inside a comment, ignore it to avoid -*/ not
-                   ;; being interpreted as a comment end.
-                   (forward-char -1)
-                   nil)))))
+              (eval
+               '(syntax-propertize-rules
+                 ;; Handle escaped apostrophes within strings.
+                 ((if (eq sql-product 'mysql)
+                      "\\\\'"
+                    "''")
+                  (0
+                   (if (save-excursion
+                         (nth 3 (syntax-ppss (match-beginning 0))))
+                      (string-to-syntax ".")
+                     (forward-char -1)
+                     nil)))
+                 ;; Propertize rules to not have /- and -* start comments.
+                 ("\\(/-\\)" (1 "."))
+                 ("\\(-\\*\\)"
+                  (1
+                   (if (save-excursion
+                         (not (ppss-comment-depth
+                               (syntax-ppss (match-beginning 1)))))
+                       ;; If we're outside a comment, we don't let -*
+                       ;; start a comment.
+                      (string-to-syntax ".")
+                     ;; Inside a comment, ignore it to avoid -*/ not
+                     ;; being interpreted as a comment end.
+                     (forward-char -1)
+                     nil))))
+               t))
   ;; Set syntax and font-face highlighting
   ;; Catch changes to sql-product and highlight accordingly
   (sql-set-product (or sql-product 'ansi)) ; Fixes bug#13591
diff --git a/lisp/progmodes/tcl.el b/lisp/progmodes/tcl.el
index 8c179879ce..7dae14f9e0 100644
--- a/lisp/progmodes/tcl.el
+++ b/lisp/progmodes/tcl.el
@@ -120,13 +120,13 @@
 
 (defcustom tcl-indent-level 4
   "Indentation of Tcl statements with respect to containing block."
-  :type 'integer)
-(put 'tcl-indent-level 'safe-local-variable #'integerp)
+  :type 'integer
+  :safe #'integerp)
 
 (defcustom tcl-continued-indent-level 4
   "Indentation of continuation line relative to first line of command."
-  :type 'integer)
-(put 'tcl-continued-indent-level 'safe-local-variable #'integerp)
+  :type 'integer
+  :safe #'integerp)
 
 (defcustom tcl-auto-newline nil
   "Non-nil means automatically newline before and after braces you insert."
diff --git a/lisp/progmodes/verilog-mode.el b/lisp/progmodes/verilog-mode.el
index 31d50a1882..fa799a0fb3 100644
--- a/lisp/progmodes/verilog-mode.el
+++ b/lisp/progmodes/verilog-mode.el
@@ -1824,7 +1824,7 @@ If set will become buffer local.")
 ;;
 
 (defsubst verilog-within-string ()
-  (nth 3 (parse-partial-sexp (point-at-bol) (point))))
+  (nth 3 (parse-partial-sexp (line-beginning-position) (point))))
 
 (defsubst verilog-string-match-fold (regexp string &optional start)
   "Like `string-match', but use `verilog-case-fold'.
@@ -1927,7 +1927,7 @@ This speeds up complicated regexp matches."
                (search-forward substr bound noerror))
       (save-excursion
        (beginning-of-line)
-       (setq done (re-search-forward regexp (point-at-eol) noerror)))
+        (setq done (re-search-forward regexp (line-end-position) noerror)))
       (unless (and (<= (match-beginning 0) (point))
                   (>= (match-end 0) (point)))
        (setq done nil)))
@@ -1947,7 +1947,7 @@ This speeds up complicated regexp matches."
                (search-backward substr bound noerror))
       (save-excursion
        (end-of-line)
-       (setq done (re-search-backward regexp (point-at-bol) noerror)))
+        (setq done (re-search-backward regexp (line-beginning-position) 
noerror)))
       (unless (and (<= (match-beginning 0) (point))
                   (>= (match-end 0) (point)))
        (setq done nil)))
@@ -4908,7 +4908,7 @@ primitive or interface named NAME."
        (or  kill-existing-comment
            (not (save-excursion
                   (end-of-line)
-                  (search-backward "//" (point-at-bol) t)))))
+                   (search-backward "//" (line-beginning-position) t)))))
       (let ((nest 1) b e
            m
            (else (if (match-end 2) "!" " ")))
@@ -4961,7 +4961,7 @@ primitive or interface named NAME."
           (or kill-existing-comment
               (not (save-excursion
                      (end-of-line)
-                     (search-backward "//" (point-at-bol) t)))))
+                      (search-backward "//" (line-beginning-position) t)))))
       (let ((type (car indent-str)))
        (unless (eq type 'declaration)
           (unless (looking-at (concat "\\(" verilog-end-block-ordered-re "\\)[ 
\t]*:"))  ; ignore named ends
@@ -5458,9 +5458,11 @@ For example:
 becomes:
         // surefire lint_line_off UDDONX"
   (interactive)
-  (let ((buff (if (boundp 'next-error-last-buffer)
+  (let ((buff (if (boundp 'next-error-last-buffer) ;Added to Emacs-22.1
                   next-error-last-buffer
-                compilation-last-buffer)))
+                (verilog--suppressed-warnings
+                    ((obsolete compilation-last-buffer))
+                  compilation-last-buffer))))
     (when (buffer-live-p buff)
       (save-excursion
         (switch-to-buffer buff)
@@ -5501,7 +5503,7 @@ becomes:
                 (cond
                  ((looking-at "// surefire lint_off_line ")
                   (goto-char (match-end 0))
-                  (let ((lim (point-at-eol)))
+                  (let ((lim (line-end-position)))
                     (if (re-search-forward code lim 'move)
                         (throw 'already t)
                       (insert (concat " " code)))))
@@ -9956,7 +9958,7 @@ Use DEFAULT-DIR to anchor paths if non-nil."
               (verilog-point-text) filename))
       (goto-char (point-min))
       (while (not (eobp))
-       (setq line (buffer-substring (point) (point-at-eol)))
+        (setq line (buffer-substring (point) (line-end-position)))
        (forward-line 1)
        (when (string-match "//" line)
          (setq line (substring line 0 (match-beginning 0))))
@@ -10878,10 +10880,10 @@ This repairs those mis-inserted by an AUTOARG."
             (setq out (replace-match
                        (concat (match-string 1 out)
                                (if (equal (match-string 3 out) ">>")
-                                   (int-to-string (lsh (string-to-number 
(match-string 2 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 (lsh (string-to-number 
(match-string 2 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))
@@ -14756,7 +14758,7 @@ Clicking on the middle-mouse button loads them in a 
buffer (as in dired)."
         (verilog-save-scan-cache
          (let (end-point)
            (goto-char end)
-           (setq end-point (point-at-eol))
+            (setq end-point (line-end-position))
            (goto-char beg)
            (beginning-of-line)  ; scan entire line
            ;; delete overlays existing on this line
diff --git a/lisp/progmodes/vhdl-mode.el b/lisp/progmodes/vhdl-mode.el
index 39c5eb453b..b763da3fbc 100644
--- a/lisp/progmodes/vhdl-mode.el
+++ b/lisp/progmodes/vhdl-mode.el
@@ -7707,7 +7707,7 @@ non-nil, indentation is done before aligning."
        (save-excursion
         (goto-char begin)
         (let (element
-              (eol (point-at-eol)))
+               (eol (line-end-position)))
           (setq element (nth 0 copy))
           (when (and (or (and (listp (car element))
                               (memq major-mode (car element)))
@@ -7733,7 +7733,7 @@ space is inserted after the token in MATCH."
       ;; Determine the greatest whitespace distance to the alignment
       ;; character
       (goto-char begin)
-      (setq eol (point-at-eol)
+      (setq eol (line-end-position)
            bol (setq begin (progn (beginning-of-line) (point))))
       (while (< bol end)
        (save-excursion
@@ -7750,13 +7750,13 @@ space is inserted after the token in MATCH."
              (setq max distance))))
        (forward-line)
        (setq bol (point)
-             eol (point-at-eol))
+              eol (line-end-position))
        (setq lines (1+ lines)))
       ;; Now insert enough maxs to push each assignment operator to
       ;; the same column.  We need to use 'lines' as a counter, since
       ;; the location of the mark may change
       (goto-char (setq bol begin))
-      (setq eol (point-at-eol))
+      (setq eol (line-end-position))
       (while (> lines 0)
        (when (and (vhdl-re-search-forward match eol t)
                   (save-excursion
@@ -7776,7 +7776,7 @@ space is inserted after the token in MATCH."
        (beginning-of-line)
        (forward-line)
        (setq bol (point)
-             eol (point-at-eol))
+              eol (line-end-position))
        (setq lines (1- lines))))))
 
 (defun vhdl-align-region-groups (beg end &optional spacing
@@ -8647,7 +8647,7 @@ buffer."
           (forward-char)
           (vhdl-forward-syntactic-ws))
         (goto-char end)
-        (when (> pos (point-at-eol))
+         (when (> pos (line-end-position))
           (error "ERROR:  Not within a generic/port clause"))
         ;; delete closing parenthesis on separate line (not supported style)
         (when (save-excursion (beginning-of-line) (looking-at "^\\s-*);"))
@@ -12838,7 +12838,7 @@ expressions (e.g. for index ranges of types and 
signals)."
   "Return the line number of the line containing point."
   (save-restriction
     (widen)
-    (1+ (count-lines (point-min) (point-at-bol)))))
+    (1+ (count-lines (point-min) (line-beginning-position)))))
 
 (defun vhdl-line-kill-entire (&optional arg)
   "Delete entire line."
@@ -12855,7 +12855,7 @@ expressions (e.g. for index ranges of types and 
signals)."
   "Copy current line."
   (interactive "p")
   (save-excursion
-    (let ((position (point-at-bol)))
+    (let ((position (line-beginning-position)))
       (forward-line (or arg 1))
       (copy-region-as-kill position (point)))))
 
@@ -14958,8 +14958,8 @@ otherwise use cached data."
 
 (defun vhdl-speedbar-insert-hierarchy ( ent-alist-arg conf-alist-arg
                                         package-alist ent-inst-list depth)
-  "Insert hierarchy of ENT-ALIST, CONF-ALIST, and PACKAGE-ALIST."
-  (if (not (or ent-alist conf-alist package-alist))
+  "Insert hierarchy of ENT-ALIST-ARG, CONF-ALIST-ARG, and PACKAGE-ALIST."
+  (if (not (or ent-alist-arg conf-alist-arg package-alist))
       (vhdl-speedbar-make-title-line "No VHDL design units!" depth)
     (let ((ent-alist ent-alist-arg)
           (conf-alist conf-alist-arg)
@@ -16752,7 +16752,7 @@ current project/directory."
   (let ((ent-alist ent-alist-arg)
        (conf-alist conf-alist-arg)
        (margin (current-indentation))
-       (beg (point-at-bol))
+        (beg (line-beginning-position))
        ent-entry inst-entry inst-path inst-prev-path tmp-alist) ;; cons-key
     ;; insert block configuration (for architecture)
     (vhdl-insert-keyword "FOR ") (insert arch-name "\n")
diff --git a/lisp/progmodes/which-func.el b/lisp/progmodes/which-func.el
index 3c8d4f43db..4fe4edc164 100644
--- a/lisp/progmodes/which-func.el
+++ b/lisp/progmodes/which-func.el
@@ -61,6 +61,9 @@
 
 ;;; Code:
 
+;; So that we can use the edebug spec in `lisp-current-defun-name'.
+(require 'edebug)
+
 ;; Variables for customization
 ;; ---------------------------
 ;;
@@ -234,9 +237,6 @@ It creates the Imenu index for the buffer, if necessary."
         (setq which-func-mode nil)
         (error "Error in which-func-update: %S" info))))))
 
-;;;###autoload
-(define-obsolete-function-alias 'which-func-mode 'which-function-mode "24.1")
-
 (defvar which-func-update-timer nil)
 
 (unless (or (assq 'which-func-mode mode-line-misc-info)
diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el
index 683589d71c..a7e372c2ac 100644
--- a/lisp/progmodes/xref.el
+++ b/lisp/progmodes/xref.el
@@ -1,7 +1,7 @@
 ;;; xref.el --- Cross-referencing commands              -*-lexical-binding:t-*-
 
 ;; Copyright (C) 2014-2022 Free Software Foundation, Inc.
-;; Version: 1.4.1
+;; Version: 1.5.0
 ;; Package-Requires: ((emacs "26.1"))
 
 ;; This is a GNU ELPA :core package.  Avoid functionality that is not
@@ -645,9 +645,15 @@ SELECT is `quit', also quit the *xref* window."
              (xref-buffer (current-buffer)))
         (cond (select
                (if (eq select 'quit) (quit-window nil nil))
-               (select-window
-                (with-current-buffer xref-buffer
-                  (xref--show-pos-in-buf marker buf))))
+               (let* ((old-frame (selected-frame))
+                      (window (with-current-buffer xref-buffer
+                                (xref--show-pos-in-buf marker buf)))
+                      (frame (window-frame window)))
+                 ;; If we chose another frame, make sure it gets input
+                 ;; focus.
+                 (unless (eq frame old-frame)
+                   (select-frame-set-input-focus frame))
+                 (select-window window)))
               (t
                (save-selected-window
                  (xref--with-dedicated-window
@@ -1758,6 +1764,12 @@ utility function used by commands like 
`dired-do-find-regexp' and
   :version "28.1"
   :package-version '(xref . "1.0.4"))
 
+(defmacro xref--with-connection-local-variables (&rest body)
+  (declare (debug t))
+  (if (>= emacs-major-version 27)
+      `(with-connection-local-variables ,@body)
+    `(progn ,@body)))
+
 ;;;###autoload
 (defun xref-matches-in-files (regexp files)
   "Find all matches for REGEXP in FILES.
@@ -1804,18 +1816,20 @@ to control which program to use when looking for 
matches."
         (insert (mapconcat #'identity files "\0"))
         (setq default-directory dir)
         (setq status
-              (xref--process-file-region (point-min)
-                                         (point-max)
-                                         shell-file-name
-                                         output
-                                         nil
-                                         shell-command-switch
-                                         command)))
+              (xref--with-connection-local-variables
+               (xref--process-file-region (point-min)
+                                          (point-max)
+                                          shell-file-name
+                                          output
+                                          nil
+                                          shell-command-switch
+                                          command))))
       (goto-char (point-min))
       (when (and (/= (point-min) (point-max))
                  (not (looking-at grep-re))
                  ;; TODO: Show these matches as well somehow?
-                 (not (looking-at "Binary file .* matches")))
+                 ;; Matching both Grep's and Ripgrep 13's messages.
+                 (not (looking-at ".*[bB]inary file.* matches")))
         (user-error "Search failed with status %d: %s" status
                     (buffer-substring (point-min) (line-end-position))))
       (while (re-search-forward grep-re nil t)
diff --git a/lisp/progmodes/xscheme.el b/lisp/progmodes/xscheme.el
index 6e21131e4a..4fb543a3bf 100644
--- a/lisp/progmodes/xscheme.el
+++ b/lisp/progmodes/xscheme.el
@@ -1,7 +1,6 @@
 ;;; xscheme.el --- run MIT Scheme under Emacs        -*- lexical-binding: t; 
-*-
 
-;; Copyright (C) 1986-1987, 1989-1990, 2001-2022 Free Software
-;; Foundation, Inc.
+;; Copyright (C) 1986-2022 Free Software Foundation, Inc.
 
 ;; Maintainer: emacs-devel@gnu.org
 ;; Keywords: languages, lisp
@@ -71,7 +70,9 @@ by the scheme process, so additional control-g's are to be 
ignored.")
 (defvar xscheme-string-receiver nil
   "Procedure to send the string argument from the scheme process.")
 
-(defconst default-xscheme-runlight
+(define-obsolete-variable-alias 'default-xscheme-runlight
+  'xscheme-default-runlight "29.1")
+(defconst xscheme-default-runlight
   '(": " xscheme-runlight-string)
   "Default global (shared) xscheme-runlight mode line format.")
 
@@ -240,7 +241,7 @@ With argument, asks for a command line."
    (list (read-buffer "Scheme interaction buffer: "
                      xscheme-buffer-name
                      t)))
-  (let ((process-name (verify-xscheme-buffer buffer-name nil)))
+  (let ((process-name (xscheme-verify-buffer buffer-name nil)))
     (setq-default xscheme-buffer-name buffer-name)
     (setq-default xscheme-process-name process-name)
     (setq-default xscheme-runlight-string
@@ -248,8 +249,8 @@ With argument, asks for a command line."
                     xscheme-runlight-string))
     (setq-default xscheme-runlight
                  (if (eq (process-status process-name) 'run)
-                     default-xscheme-runlight
-                     ""))))
+                      xscheme-default-runlight
+                    ""))))
 
 (defun local-set-scheme-interaction-buffer (buffer-name)
   "Set the scheme interaction buffer for the current buffer."
@@ -257,7 +258,7 @@ With argument, asks for a command line."
    (list (read-buffer "Scheme interaction buffer: "
                      xscheme-buffer-name
                      t)))
-  (let ((process-name (verify-xscheme-buffer buffer-name t)))
+  (let ((process-name (xscheme-verify-buffer buffer-name t)))
     (setq-local xscheme-buffer-name buffer-name)
     (setq-local xscheme-process-name process-name)
     (setq-local xscheme-runlight
@@ -273,7 +274,7 @@ With argument, asks for a command line."
   (kill-local-variable 'xscheme-process-name)
   (kill-local-variable 'xscheme-runlight))
 
-(defun verify-xscheme-buffer (buffer-name localp)
+(defun xscheme-verify-buffer (buffer-name localp)
   (if (and localp (xscheme-process-buffer-current-p))
       (error "Cannot change the interaction buffer of an interaction buffer"))
   (let* ((buffer (get-buffer buffer-name))
@@ -921,8 +922,8 @@ the remaining input.")
        (setq scheme-mode-line-process '(": " xscheme-runlight-string))
        (xscheme-mode-line-initialize name)
        (if (equal name (default-value 'xscheme-buffer-name))
-           (setq-default xscheme-runlight default-xscheme-runlight))))
-  (if (or (eq xscheme-runlight default-xscheme-runlight)
+            (setq-default xscheme-runlight xscheme-default-runlight))))
+  (if (or (eq xscheme-runlight xscheme-default-runlight)
          (equal xscheme-runlight ""))
       (setq xscheme-runlight (list ": " 'xscheme-buffer-name ": " "?")))
   (rplaca (nthcdr 3 xscheme-runlight)
@@ -1180,6 +1181,8 @@ the remaining input.")
                     (if (nth 2 state) 'many 'one)))))
        (set-syntax-table old-syntax-table)))))
 
+(define-obsolete-function-alias 'verify-xscheme-buffer #'xscheme-verify-buffer 
"29.1")
+
 (provide 'xscheme)
 
 ;;; xscheme.el ends here
diff --git a/lisp/ps-def.el b/lisp/ps-def.el
deleted file mode 100644
index 8c5187ca8b..0000000000
--- a/lisp/ps-def.el
+++ /dev/null
@@ -1,134 +0,0 @@
-;;; ps-def.el --- Emacs definitions for ps-print -*- lexical-binding: t -*-
-
-;; Copyright (C) 2007-2022 Free Software Foundation, Inc.
-
-;; Author: Vinicius Jose Latorre <viniciusjl.gnu@gmail.com>
-;;     Kenichi Handa <handa@gnu.org> (multi-byte characters)
-;; Keywords: wp, print, PostScript
-;; URL: https://www.emacswiki.org/cgi-bin/wiki/ViniciusJoseLatorre
-;; Package: ps-print
-
-;; 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:
-
-;; See ps-print.el for documentation.
-
-;;; Code:
-
-(declare-function ps-plot-with-face "ps-print" (from to face))
-(declare-function ps-plot-string    "ps-print" (string))
-
-(defvar ps-bold-faces)                  ; in ps-print.el
-(defvar ps-italic-faces)
-
-
-
-
-;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Emacs Definitions
-
-
-(defun ps-mark-active-p ()
-  mark-active)
-
-
-(defun ps-face-foreground-name (face)
-  (face-foreground face nil t))
-
-
-(defun ps-face-background-name (face)
-  (face-background face nil t))
-
-
-(define-obsolete-function-alias 'ps-frame-parameter #'frame-parameter "28.1")
-
-;; Return t if the device (which can be changed during an emacs session) can
-;; handle colors.
-(defun ps-color-device ()
-  (color-values "Green"))
-
-(define-obsolete-function-alias 'ps-color-values #'color-values "28.1")
-
-
-(defun ps-face-bold-p (face)
-  (or (face-bold-p face)
-      (memq face ps-bold-faces)))
-
-
-(defun ps-face-italic-p (face)
-  (or (face-italic-p face)
-      (memq face ps-italic-faces)))
-
-
-(defun ps-face-strikeout-p (face)
-  (eq (face-attribute face :strike-through) t))
-
-
-(defun ps-face-overline-p (face)
-  (eq (face-attribute face :overline) t))
-
-
-(defun ps-face-box-p (face)
-  (not (memq (face-attribute face :box) '(nil unspecified))))
-
-
-;; Emacs understands the %f format; we'll use it to limit color RGB values
-;; to three decimals to cut down some on the size of the PostScript output.
-(defvar ps-color-format "%0.3f %0.3f %0.3f")
-(defvar ps-float-format "%0.3f ")
-
-
-(defun ps-generate-postscript-with-faces1 (from to)
-  ;; Generate some PostScript.
-  (let ((face 'default)
-       (position to)
-       ;; Emacs
-       (property-change from)
-       (overlay-change from)
-       before-string after-string)
-    (while (< from to)
-      (and (< property-change to)  ; Don't search for property change
-                                       ; unless previous search succeeded.
-          (setq property-change (next-property-change from nil to)))
-      (and (< overlay-change to)   ; Don't search for overlay change
-                                       ; unless previous search succeeded.
-          (setq overlay-change (min (next-overlay-change from)
-                                    to)))
-      (setq position (min property-change overlay-change)
-           before-string nil
-           after-string nil)
-      (setq face
-           (cond ((invisible-p from)
-                  'emacs--invisible--face)
-                 ((get-char-property from 'face))
-                 (t 'default)))
-      ;; Plot up to this record.
-      (and before-string
-          (ps-plot-string before-string))
-      (ps-plot-with-face from position face)
-      (and after-string
-          (ps-plot-string after-string))
-      (setq from position))
-    (ps-plot-with-face from to face)))
-
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-(provide 'ps-def)
-
-;;; ps-def.el ends here
diff --git a/lisp/ps-print.el b/lisp/ps-print.el
index 8df5204fa1..d67c34e11a 100644
--- a/lisp/ps-print.el
+++ b/lisp/ps-print.el
@@ -8,21 +8,9 @@
 ;;     Kenichi Handa <handa@gnu.org> (multi-byte characters)
 ;; Maintainer: Vinicius Jose Latorre <viniciusjl.gnu@gmail.com>
 ;; Keywords: wp, print, PostScript
-;; Version: 7.3.5
+;; Old-Version: 7.3.5
 ;; URL: https://www.emacswiki.org/cgi-bin/wiki/ViniciusJoseLatorre
 
-(eval-when-compile (require 'cl-lib))
-
-(defconst ps-print-version "7.3.5"
-  "ps-print.el, v 7.3.5 <2009/12/23 vinicius>
-
-Vinicius's last change version -- this file may have been edited as part of
-Emacs without changes to the version number.  When reporting bugs, please also
-report the version of Emacs, if any, that ps-print was distributed with.
-
-Please send all bug fixes and enhancements to
-       bug-gnu-emacs@gnu.org and Vinicius Jose Latorre 
<viniciusjl.gnu@gmail.com>.")
-
 ;; This file is part of GNU Emacs.
 
 ;; GNU Emacs is free software: you can redistribute it and/or modify
@@ -1320,11 +1308,11 @@ Please send all bug fixes and enhancements to
 ;; Known bugs and limitations of ps-print
 ;; --------------------------------------
 ;;
-;; Automatic font-attribute detection doesn't work well, especially with
-;; hilit19 and older versions of get-create-face.  Users having problems with
-;; auto-font detection should use the lists `ps-italic-faces', `ps-bold-faces'
-;; and `ps-underlined-faces' and/or turn off automatic detection by setting
-;; `ps-auto-font-detect' to nil.
+;; Automatic font-attribute detection doesn't work well.  Users having
+;; problems with auto-font detection should use the lists
+;; `ps-italic-faces', `ps-bold-faces' and `ps-underlined-faces' and/or
+;; turn off automatic detection by setting `ps-auto-font-detect' to
+;; nil.
 ;;
 ;; Still too slow; could use some hand-optimization.
 ;;
@@ -1450,11 +1438,8 @@ Please send all bug fixes and enhancements to
 
 ;;; Code:
 
-
 (require 'lpr)
-
-;; Load Emacs definitions
-(require 'ps-def)
+(eval-when-compile (require 'cl-lib))
 
 ;; autoloads for secondary file
 (require 'ps-print-loaddefs)
@@ -2930,9 +2915,8 @@ Either a float or a cons of floats (LANDSCAPE-SIZE . 
PORTRAIT-SIZE)."
 
 ;;; Colors
 
-;; Printing color requires x-color-values.
 ;;;###autoload
-(defcustom ps-print-color-p (fboundp 'x-color-values)
+(defcustom ps-print-color-p t
   "Specify how buffer's text color is printed.
 
 Valid values are:
@@ -3601,7 +3585,6 @@ The table depends on the current ps-print setup."
     (mapconcat
      #'ps-print-quote
      (list
-      (concat "\n;;; (Emacs) ps-print version " ps-print-version "\n")
       ";; internal vars"
       (ps-comment-string "emacs-version     " emacs-version)
       (ps-comment-string "lpr-windows-system" lpr-windows-system)
@@ -4510,7 +4493,7 @@ page-height == ((floor print-height ((th + ls) * zh)) * 
((th + ls) * zh)) - th
 
 
 (defun ps-print-preprint-region (prefix)
-  (or (ps-mark-active-p)
+  (or mark-active
       (error "The mark is not set now"))
   (list (point) (mark) (ps-print-preprint prefix)))
 
@@ -4733,6 +4716,10 @@ page-height == ((floor print-height ((th + ls) * zh)) * 
((th + ls) * zh)) - th
 (defun ps-output-boolean (name bool)
   (ps-output (format "/%s %s def\n" name (if bool "true" "false"))))
 
+;; Limit color RGB values to three decimals to cut down some on the
+;; size of the PostScript output.
+(defvar ps-color-format "%0.3f %0.3f %0.3f")
+(defvar ps-float-format "%0.3f ")
 
 (defun ps-output-frame-properties (name alist)
   (ps-output "/" name " ["
@@ -5348,7 +5335,7 @@ XSTART YSTART are the relative position for the first 
page in a sheet.")
      ps-adobe-tag
      "%%Title: " (buffer-name)         ; Take job name from name of
                                        ; first buffer printed
-     "\n%%Creator: ps-print v" ps-print-version
+     "\n%%Creator: GNU Emacs " emacs-version
      "\n%%For: " (user-full-name)       ;FIXME: may need encoding!
      "\n%%CreationDate: " (format-time-string "%T %b %d %Y") ;FIXME: encoding!
      "\n%%Orientation: "
@@ -5749,7 +5736,7 @@ XSTART YSTART are the relative position for the first 
page in a sheet.")
        ;; Set the color scale.  We do it here instead of in the defvar so
        ;; that ps-print can be dumped into emacs.  This expression can't be
        ;; evaluated at dump-time because X isn't initialized.
-       ps-color-p            (and ps-print-color-p (ps-color-device))
+        ps-color-p            (and ps-print-color-p (display-color-p))
        ps-print-color-scale  (if ps-color-p
                                  (float (car (color-values "white")))
                                1.0)
@@ -5762,7 +5749,7 @@ XSTART YSTART are the relative position for the first 
page in a sheet.")
                                ((eq ps-default-bg 'frame-parameter)
                                 (frame-parameter nil 'background-color))
                                ((eq ps-default-bg t)
-                                (ps-face-background-name 'default))
+                                 (face-background 'default nil t))
                                (t
                                 ps-default-bg))
                               "unspecified-bg"
@@ -5776,7 +5763,7 @@ XSTART YSTART are the relative position for the first 
page in a sheet.")
                                ((eq ps-default-fg 'frame-parameter)
                                 (frame-parameter nil 'foreground-color))
                                ((eq ps-default-fg t)
-                                (ps-face-foreground-name 'default))
+                                 (face-foreground 'default nil t))
                                (t
                                 ps-default-fg))
                               "unspecified-fg"
@@ -6312,6 +6299,22 @@ If FACE is not a valid face name, use default face."
       (setq ps-print-face-alist (cons face-map ps-print-face-alist)))
     face-map))
 
+(defun ps-face-bold-p (face)
+  (or (face-bold-p face)
+      (memq face ps-bold-faces)))
+
+(defun ps-face-italic-p (face)
+  (or (face-italic-p face)
+      (memq face ps-italic-faces)))
+
+(defun ps-face-strikeout-p (face)
+  (eq (face-attribute face :strike-through) t))
+
+(defun ps-face-overline-p (face)
+  (eq (face-attribute face :overline) t))
+
+(defun ps-face-box-p (face)
+  (not (memq (face-attribute face :box) '(nil unspecified))))
 
 (defun ps-screen-to-bit-face (face)
   (cons face
@@ -6321,20 +6324,41 @@ If FACE is not a valid face name, use default face."
                        (if (ps-face-strikeout-p face)  8 0)  ; strikeout
                        (if (ps-face-overline-p face)  16 0)  ; overline
                        (if (ps-face-box-p face)       64 0)) ; box
-               (ps-face-foreground-name face)
-               (ps-face-background-name face))))
-
-
-(declare-function jit-lock-fontify-now "jit-lock" (&optional start end))
-(declare-function lazy-lock-fontify-region "lazy-lock" (beg end))
+                (face-foreground face nil t)
+                (face-background face nil t))))
 
-;; to avoid compilation gripes
-(defun ps-print-ensure-fontified (start end)
-  (cond ((and (boundp 'jit-lock-mode) (symbol-value 'jit-lock-mode))
-        (jit-lock-fontify-now start end))
-       ((and (boundp 'lazy-lock-mode) (symbol-value 'lazy-lock-mode))
-        (lazy-lock-fontify-region start end))))
 
+(defun ps-generate-postscript-with-faces1 (from to)
+  ;; Generate some PostScript.
+  (let ((face 'default)
+        (position to)
+        (property-change from)
+        (overlay-change from)
+        before-string after-string)
+    (while (< from to)
+      (and (< property-change to)       ; Don't search for property change
+                                        ; unless previous search succeeded.
+           (setq property-change (next-property-change from nil to)))
+      (and (< overlay-change to)        ; Don't search for overlay change
+                                        ; unless previous search succeeded.
+           (setq overlay-change (min (next-overlay-change from)
+                                     to)))
+      (setq position (min property-change overlay-change)
+            before-string nil
+            after-string nil)
+      (setq face
+            (cond ((invisible-p from)
+                   'emacs--invisible--face)
+                  ((get-char-property from 'face))
+                  (t 'default)))
+      ;; Plot up to this record.
+      (and before-string
+           (ps-plot-string before-string))
+      (ps-plot-with-face from position face)
+      (and after-string
+           (ps-plot-string after-string))
+      (setq from position))
+    (ps-plot-with-face from to face)))
 
 (defun ps-generate-postscript-with-faces (from to)
   ;; Some initialization...
@@ -6355,7 +6379,7 @@ If FACE is not a valid face name, use default face."
   ;; Generate some PostScript.
   (save-restriction
     (narrow-to-region from to)
-    (ps-print-ensure-fontified from to)
+    (font-lock-ensure from to)
     (deactivate-mark)                   ;bug#16866.
     (ps-generate-postscript-with-faces1 from to)))
 
@@ -6415,7 +6439,7 @@ If FACE is not a valid face name, use default face."
                (ps-end-job needs-begin-file)
 
                ;; Setting this variable tells the unwind form that the
-               ;; the PostScript was generated without error.
+               ;; PostScript was generated without error.
                (setq completed-safely t))
 
            ;; Unwind form: If some bad mojo occurred while generating
@@ -6512,6 +6536,19 @@ If FACE is not a valid face name, use default face."
 (unless noninteractive
   (add-hook 'kill-emacs-query-functions #'ps-kill-emacs-check))
 
+(defconst ps-print-version "7.3.5"
+  "ps-print.el, v 7.3.5 <2009/12/23 vinicius>
+
+Vinicius's last change version -- this file may have been edited as part of
+Emacs without changes to the version number.  When reporting bugs, please also
+report the version of Emacs, if any, that ps-print was distributed with.
+
+Please send all bug fixes and enhancements to
+  bug-gnu-emacs@gnu.org and Vinicius Jose Latorre <viniciusjl.gnu@gmail.com>.")
+(make-obsolete-variable 'ps-print-version 'emacs-version "29.1")
+
+(define-obsolete-function-alias 'ps-print-ensure-fontified #'font-lock-ensure 
"29.1")
+
 (provide 'ps-print)
 
 ;;; ps-print.el ends here
diff --git a/lisp/recentf.el b/lisp/recentf.el
index 2de9831154..b80ee3dd7d 100644
--- a/lisp/recentf.el
+++ b/lisp/recentf.el
@@ -1,4 +1,4 @@
-;;; recentf.el --- setup a menu of recently opened files  -*- lexical-binding: 
t -*-
+;;; recentf.el --- keep track of recently opened files  -*- lexical-binding: t 
-*-
 
 ;; Copyright (C) 1999-2022 Free Software Foundation, Inc.
 
@@ -23,13 +23,22 @@
 
 ;;; Commentary:
 
-;; This package maintains a menu for visiting files that were operated
-;; on recently.  When enabled a new "Open Recent" submenu is
-;; displayed in the "File" menu.  The recent files list is
-;; automatically saved across Emacs sessions.
+;; This package maintains a list of recently opened files and makes it
+;; easy to visit them.  The recent files list is automatically saved
+;; across Emacs sessions.
+
+;; There are three ways to access recent files:
+;;
+;; (1) `M-x recentf-open' prompts for a recently opened file.
+;;
+;; (2) When this mode is enabled, a new "Open Recent" submenu is
+;;     displayed in the "File" menu.
+;;
+;; (3) `M-x recentf-open-files' lists recently visited files in a
+;;     buffer.
 
 ;; You can customize the number of recent files displayed, the
-;; location of the menu and others options.  Type:
+;; location of the menu and other options.  Type:
 ;;
 ;;     M-x customize-group RET recentf RET
 
@@ -45,16 +54,17 @@
 ;;; Internal data
 ;;
 (defvar recentf-list nil
-  "List of recently opened files.")
+  "List of recently opened files for `recentf-mode'.")
 
-(defsubst recentf-enabled-p ()
-  "Return non-nil if recentf mode is currently enabled."
+(defun recentf-enabled-p ()
+  "Return non-nil if `recentf-mode' is currently enabled."
   (memq 'recentf-save-list kill-emacs-hook))
+
 
 ;;; Customization
 ;;
 (defgroup recentf nil
-  "Maintain a menu of recently opened files."
+  "Maintain a list of recently opened files."
   :version "21.1"
   :group 'files)
 
@@ -159,7 +169,7 @@ If nil add it at end of menu (see also 
`easy-menu-add-item')."
                  (const :tag "Last" nil))
   :set 'recentf-menu-customization-changed)
 
-(defcustom recentf-menu-action 'find-file
+(defcustom recentf-menu-action #'find-file
   "Function to invoke with a filename item of the recentf menu.
 The default is to call `find-file' to edit the selected file."
   :group 'recentf
@@ -168,7 +178,7 @@ The default is to call `find-file' to edit the selected 
file."
 (defcustom recentf-max-menu-items 10
   "Maximum number of items in the recentf menu."
   :group 'recentf
-  :type 'integer)
+  :type 'natnum)
 
 (defcustom recentf-menu-filter nil
   "Function used to filter files displayed in the recentf menu.
@@ -237,6 +247,8 @@ This item will replace the \"More...\" item."
 
 (defcustom recentf-auto-cleanup 'mode
   "Define when to automatically cleanup the recent list.
+That is, remove duplicates, non-kept, and excluded files.
+
 The following values can be set:
 
 - `mode'
@@ -284,7 +296,7 @@ If `file-name-history' is not empty, do nothing."
 (make-obsolete-variable 'recentf-load-hook
                         "use `with-eval-after-load' instead." "28.1")
 
-(defcustom recentf-filename-handlers nil
+(defcustom recentf-filename-handlers '(abbreviate-file-name)
   "Functions to post process recent file names.
 They are successively passed a file name to transform it."
   :group 'recentf
@@ -294,7 +306,8 @@ They are successively passed a file name to transform it."
            (choice
             (const file-truename)
             (const abbreviate-file-name)
-            (function :tag "Other function")))))
+            (function :tag "Other function"))))
+  :version "29.1")
 
 (defcustom recentf-show-file-shortcuts-flag t
   "Non-nil means to show \"[N]\" for the Nth item up to 10.
@@ -309,14 +322,14 @@ used as shortcuts to open the Nth file."
   (memq system-type '(windows-nt cygwin))
   "Non-nil if recentf searches and matches should ignore case.")
 
-(defsubst recentf-string-equal (s1 s2)
+(defun recentf-string-equal (s1 s2)
   "Return non-nil if strings S1 and S2 have identical contents.
 Ignore case if `recentf-case-fold-search' is non-nil."
   (if recentf-case-fold-search
       (string-equal (downcase s1) (downcase s2))
     (string-equal s1 s2)))
 
-(defsubst recentf-string-lessp (s1 s2)
+(defun recentf-string-lessp (s1 s2)
   "Return non-nil if string S1 is less than S2 in lexicographic order.
 Ignore case if `recentf-case-fold-search' is non-nil."
   (if recentf-case-fold-search
@@ -371,7 +384,7 @@ See also the option `recentf-auto-cleanup'.")
 
 ;;; File functions
 ;;
-(defsubst recentf-push (filename)
+(defun recentf-push (filename)
   "Push FILENAME into the recent list, if it isn't there yet.
 If it is there yet, move it at the beginning of the list.
 If `recentf-case-fold-search' is non-nil, ignore case when comparing
@@ -394,7 +407,7 @@ returned nil."
         (error nil))
       name))
 
-(defsubst recentf-expand-file-name (name)
+(defun recentf-expand-file-name (name)
   "Convert file NAME to absolute, and canonicalize it.
 NAME is first passed to the function `expand-file-name', then to
 `recentf-filename-handlers' to post process it."
@@ -435,7 +448,7 @@ That is, if it matches any of the `recentf-keep' checks."
             checks (cdr checks)))
     keepit))
 
-(defsubst recentf-add-file (filename)
+(defun recentf-add-file (filename)
   "Add or move FILENAME at the beginning of the recent list.
 Does nothing if the name satisfies any of the `recentf-exclude'
 regexps or predicates."
@@ -443,7 +456,7 @@ regexps or predicates."
   (when (recentf-include-p filename)
     (recentf-push filename)))
 
-(defsubst recentf-remove-if-non-kept (filename)
+(defun recentf-remove-if-non-kept (filename)
   "Remove FILENAME from the recent list, if file is not kept.
 Return non-nil if FILENAME has been removed."
   (unless (recentf-keep-p filename)
@@ -461,10 +474,30 @@ Return non-nil if F1 is less than F2."
         (recentf-string-lessp (file-name-nondirectory f1)
                               (file-name-nondirectory f2))
       (recentf-string-lessp d1 d2))))
+
+
+;;; Open files
+;;
+
+;;;###autoload
+(defun recentf-open (file)
+  "Prompt for FILE in `recentf-list' and visit it.
+Enable `recentf-mode' if it isn't already."
+  (interactive
+   (list
+    (progn (unless recentf-mode (recentf-mode 1))
+           (completing-read (format-prompt "Open recent file" nil)
+                            recentf-list nil t))))
+  (when file
+    (funcall recentf-menu-action file)))
+
+;;;###autoload
+(defalias 'recentf 'recentf-open)
+
 
 ;;; Menu building
 ;;
-(defsubst recentf-digit-shortcut-command-name (n)
+(defun recentf-digit-shortcut-command-name (n)
   "Return a command name to open the Nth most recent file.
 See also the command `recentf-open-most-recent-file'."
   (intern (format "recentf-open-most-recent-file-%d" n)))
@@ -476,10 +509,10 @@ See also the command `recentf-open-most-recent-file'."
         ;; Define a shortcut command.
         (defalias cmd
           `(lambda ()
-             (interactive)
+             (interactive nil recentf-dialog-mode)
              (recentf-open-most-recent-file ,k)))
         ;; Bind it to a digit key.
-        (define-key km (vector (+ k ?0)) cmd)))
+        (keymap-set km (format "%d" k) cmd)))
     km)
   "Digit shortcuts keymap.")
 
@@ -510,10 +543,6 @@ If non-nil it must contain a list of valid menu-items to 
be appended
 to the recent file list part of the menu.  Before calling a menu
 filter function this variable is reset to nil.")
 
-(defsubst recentf-elements (n)
-  "Return a list of the first N elements of the recent list."
-  (seq-take recentf-list n))
-
 (defsubst recentf-make-menu-element (menu-item menu-value)
   "Create a new menu-element.
 A menu element is a pair (MENU-ITEM . MENU-VALUE), where MENU-ITEM is
@@ -553,7 +582,7 @@ This a menu element (FILE . FILE)."
   "Return a list of the first N default menu elements from the recent list.
 See also `recentf-make-default-menu-element'."
   (mapcar #'recentf-make-default-menu-element
-          (recentf-elements n)))
+          (seq-take recentf-list n)))
 
 (defun recentf-apply-menu-filter (filter l)
   "Apply function FILTER to the list of menu-elements L.
@@ -650,7 +679,7 @@ Return nil if file NAME is not one of the ten more recent."
                 :help (concat "Open " value)
                 :active t)))))
 
-(defsubst recentf-menu-bar ()
+(defun recentf-menu-bar ()
   "Return the keymap of the global menu bar."
   (lookup-key global-map [menu-bar]))
 
@@ -670,7 +699,7 @@ Return nil if file NAME is not one of the ten more recent."
 
 ;;; Predefined menu filters
 ;;
-(defsubst recentf-sort-ascending (l)
+(defun recentf-sort-ascending (l)
   "Sort the list of menu elements L in ascending order.
 The MENU-ITEM part of each menu element is compared."
   (sort (copy-sequence l)
@@ -679,7 +708,7 @@ The MENU-ITEM part of each menu element is compared."
            (recentf-menu-element-item e1)
            (recentf-menu-element-item e2)))))
 
-(defsubst recentf-sort-descending (l)
+(defun recentf-sort-descending (l)
   "Sort the list of menu elements L in descending order.
 The MENU-ITEM part of each menu element is compared."
   (sort (copy-sequence l)
@@ -688,7 +717,7 @@ The MENU-ITEM part of each menu element is compared."
            (recentf-menu-element-item e2)
            (recentf-menu-element-item e1)))))
 
-(defsubst recentf-sort-basenames-ascending (l)
+(defun recentf-sort-basenames-ascending (l)
   "Sort the list of menu elements L in ascending order.
 Only filenames sans directory are compared."
   (sort (copy-sequence l)
@@ -697,7 +726,7 @@ Only filenames sans directory are compared."
            (file-name-nondirectory (recentf-menu-element-value e1))
            (file-name-nondirectory (recentf-menu-element-value e2))))))
 
-(defsubst recentf-sort-basenames-descending (l)
+(defun recentf-sort-basenames-descending (l)
   "Sort the list of menu elements L in descending order.
 Only filenames sans directory are compared."
   (sort (copy-sequence l)
@@ -706,7 +735,7 @@ Only filenames sans directory are compared."
            (file-name-nondirectory (recentf-menu-element-value e2))
            (file-name-nondirectory (recentf-menu-element-value e1))))))
 
-(defsubst recentf-sort-directories-ascending (l)
+(defun recentf-sort-directories-ascending (l)
   "Sort the list of menu elements L in ascending order.
 Compares directories then filenames to order the list."
   (sort (copy-sequence l)
@@ -715,7 +744,7 @@ Compares directories then filenames to order the list."
            (recentf-menu-element-value e1)
            (recentf-menu-element-value e2)))))
 
-(defsubst recentf-sort-directories-descending (l)
+(defun recentf-sort-directories-descending (l)
   "Sort the list of menu elements L in descending order.
 Compares directories then filenames to order the list."
   (sort (copy-sequence l)
@@ -743,14 +772,14 @@ optional argument NO-DIR is non-nil, or its directory 
otherwise."
         (setq name (format "%s(%s)" name sufx)))
       (push (recentf-make-menu-element name full) filtered-list))))
 
-(defsubst recentf-show-basenames-ascending (l)
+(defun recentf-show-basenames-ascending (l)
   "Filter the list of menu elements L to show filenames sans directory.
 Filenames are sorted in ascending order.
 This filter combines the `recentf-sort-basenames-ascending' and
 `recentf-show-basenames' filters."
   (recentf-show-basenames (recentf-sort-basenames-ascending l)))
 
-(defsubst recentf-show-basenames-descending (l)
+(defun recentf-show-basenames-descending (l)
   "Filter the list of menu elements L to show filenames sans directory.
 Filenames are sorted in descending order.
 This filter combines the `recentf-sort-basenames-descending' and
@@ -808,7 +837,7 @@ corresponding sub-menu items are displayed in the main 
recent files
 menu or in the `recentf-arrange-by-rule-others' sub-menu if
 defined."
   :group 'recentf-filters
-  :type 'number)
+  :type 'natnum)
 
 (defcustom recentf-arrange-by-rule-subfilter nil
   "Function called by a rule based filter to filter sub-menu elements.
@@ -1037,7 +1066,7 @@ That is, remove a non kept file from the recent list."
 (defun recentf-cancel-dialog (&rest _ignore)
   "Cancel the current dialog.
 IGNORE arguments."
-  (interactive)
+  (interactive nil recentf-dialog-mode)
   (kill-buffer (current-buffer))
   (message "Dialog canceled"))
 
@@ -1055,19 +1084,20 @@ Go to the beginning of buffer if not found."
     (error
      (goto-char (point-min)))))
 
-(defvar recentf-dialog-mode-map
-  (let ((km (copy-keymap recentf--shortcuts-keymap)))
-    (set-keymap-parent km widget-keymap)
-    (define-key km "q" #'recentf-cancel-dialog)
-    (define-key km "n" #'next-line)
-    (define-key km "p" #'previous-line)
-    km)
-  "Keymap used in recentf dialogs.")
+(defvar-keymap recentf-dialog-mode-map
+  :doc "Keymap used in recentf dialogs."
+  :parent (make-composed-keymap recentf--shortcuts-keymap widget-keymap)
+  "q"       #'recentf-cancel-dialog
+  "n"       #'next-line
+  "p"       #'previous-line
+  "C-c C-c" #'recentf-edit-list-validate
+  "C-c C-k" #'recentf-cancel-dialog)
 
 (define-derived-mode recentf-dialog-mode nil "recentf-dialog"
   "Major mode of recentf dialogs.
 
 \\{recentf-dialog-mode-map}"
+  :interactive nil
   :syntax-table nil
   :abbrev-table nil
   (setq truncate-lines t))
@@ -1104,6 +1134,7 @@ IGNORE other arguments."
 (defun recentf-edit-list-validate (&rest _ignore)
   "Process the recent list when the edit list dialog is committed.
 IGNORE arguments."
+  (interactive nil recentf-dialog-mode)
   (if recentf-edit-list
       (let ((i 0))
         (dolist (e recentf-edit-list)
@@ -1123,8 +1154,8 @@ IGNORE arguments."
     (widget-insert
      (format-message
       (substitute-command-keys
-       "Click on OK to delete selected files from the recent list.
-Click on Cancel or type \\[recentf-cancel-dialog] to cancel.\n")))
+       "Click on \"OK\" or type \\[recentf-edit-list-validate] to delete 
selected files from the recent list.
+Click on \"Cancel\" or type \\[recentf-cancel-dialog] to cancel.\n")))
     ;; Insert the list of files as checkboxes
     (dolist (item recentf-list)
       (widget-create 'checkbox
@@ -1337,12 +1368,18 @@ That is, remove duplicates, non-kept, and excluded 
files."
 
 ;;; The minor mode
 ;;
-(defvar recentf-mode-map (make-sparse-keymap)
-  "Keymap to use in recentf mode.")
+(defvar-keymap recentf-mode-map
+  :doc "Keymap to use in `recentf-mode'.")
 
 ;;;###autoload
 (define-minor-mode recentf-mode
-  "Toggle \"Open Recent\" menu (Recentf mode).
+  "Toggle keeping track of opened files (Recentf mode).
+This mode maintains a list of recently opened files and makes it
+easy to visit them.  The recent files list is automatically saved
+across Emacs sessions.
+
+You can use `recentf-open' or `recentf-open-files' to visit
+files.
 
 When Recentf mode is enabled, a \"Open Recent\" submenu is
 displayed in the \"File\" menu, containing a list of files that
@@ -1379,6 +1416,11 @@ buffers you switch to a lot, you can say something like 
the following:
 
 (define-obsolete-function-alias 'recentf-trunc-list #'seq-take "28.1")
 
+(defun recentf-elements (n)
+  "Return a list of the first N elements of the recent list."
+  (declare (obsolete "use `(seq-take recentf-list n)'." "29.1"))
+  (seq-take recentf-list n))
+
 (provide 'recentf)
 
 (run-hooks 'recentf-load-hook)
diff --git a/lisp/rect.el b/lisp/rect.el
index e717d2ac7e..e1d79da962 100644
--- a/lisp/rect.el
+++ b/lisp/rect.el
@@ -218,7 +218,7 @@ The returned value has the form of (WIDTH . HEIGHT)."
                          (point)))))
 
 (defun delete-extract-rectangle-line (startcol endcol lines fill)
-  (let ((pt (point-at-eol)))
+  (let ((pt (line-end-position)))
     (if (< (move-to-column startcol (if fill t 'coerce)) startcol)
        (setcdr lines (cons (spaces-string (- endcol startcol))
                            (cdr lines)))
@@ -397,17 +397,17 @@ no text on the right side of the rectangle."
 (defun open-rectangle-line (startcol endcol fill)
   (when (= (move-to-column startcol (if fill t 'coerce)) startcol)
     (unless (and (not fill)
-                (= (point) (point-at-eol)))
+                 (= (point) (line-end-position)))
       (indent-to endcol))))
 
 (defun delete-whitespace-rectangle-line (startcol _endcol fill)
   (when (= (move-to-column startcol (if fill t 'coerce)) startcol)
-    (unless (= (point) (point-at-eol))
-      (delete-region (point) (progn (skip-syntax-forward " " (point-at-eol))
+    (unless (= (point) (line-end-position))
+      (delete-region (point) (progn (skip-syntax-forward " " 
(line-end-position))
                                    (point))))))
 
 ;;;###autoload
-(defalias 'close-rectangle 'delete-whitespace-rectangle) ;; Old name
+(define-obsolete-function-alias 'close-rectangle #'delete-whitespace-rectangle 
"29.1")
 
 ;;;###autoload
 (defun delete-whitespace-rectangle (start end &optional fill)
@@ -536,7 +536,7 @@ Called from a program, takes three args; START, END and 
STRING."
    (apply-on-rectangle 'string-rectangle-line start end string t)))
 
 ;;;###autoload
-(defalias 'replace-rectangle 'string-rectangle)
+(define-obsolete-function-alias 'replace-rectangle #'string-rectangle "29.1")
 
 ;;;###autoload
 (defun string-insert-rectangle (start end string)
@@ -568,7 +568,7 @@ rectangle which were empty."
   (apply-on-rectangle 'clear-rectangle-line start end fill))
 
 (defun clear-rectangle-line (startcol endcol fill)
-  (let ((pt (point-at-eol)))
+  (let ((pt (line-end-position)))
     (when (= (move-to-column startcol (if fill t 'coerce)) startcol)
       (if (and (not fill)
               (<= (save-excursion (goto-char pt) (current-column)) endcol))
@@ -634,18 +634,17 @@ with a prefix argument, prompt for START-AT and FORMAT."
 (add-function :around region-insert-function
               #'rectangle--insert-region)
 
-(defvar rectangle-mark-mode-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map [?\C-o] 'open-rectangle)
-    (define-key map [?\C-t] 'string-rectangle)
-    (define-key map [remap exchange-point-and-mark]
-      'rectangle-exchange-point-and-mark)
-    (dolist (cmd '(right-char left-char forward-char backward-char
-                   next-line previous-line))
-      (define-key map (vector 'remap cmd)
-        (intern (format "rectangle-%s" cmd))))
-    map)
-  "Keymap used while marking a rectangular region.")
+(defvar-keymap rectangle-mark-mode-map
+  :doc "Keymap used while marking a rectangular region."
+  "C-o" #'open-rectangle
+  "C-t" #'string-rectangle
+  "<remap> <exchange-point-and-mark>" #'rectangle-exchange-point-and-mark
+  "<remap> <right-char>"              #'rectangle-right-char
+  "<remap> <left-char>"               #'rectangle-left-char
+  "<remap> <forward-char>"            #'rectangle-forward-char
+  "<remap> <backward-char>"           #'rectangle-backward-char
+  "<remap> <next-line>"               #'rectangle-next-line
+  "<remap> <previous-line>"           #'rectangle-previous-line)
 
 ;;;###autoload
 (define-minor-mode rectangle-mark-mode
@@ -931,6 +930,27 @@ Ignores `line-move-visual'."
     (mapc #'delete-overlay (nthcdr 5 rol))
     (setcar (cdr rol) nil)))
 
+(defun rectangle--duplicate-right (n)
+  "Duplicate the rectangular region N times on the right-hand side."
+  (let ((cols (rectangle--pos-cols (point) (mark))))
+    (apply-on-rectangle
+     (lambda (startcol endcol)
+       (let ((lines (list nil)))
+         (extract-rectangle-line startcol endcol lines)
+         (move-to-column endcol t)
+         (dotimes (_ n)
+           (insert (cadr lines)))))
+     (region-beginning) (region-end))
+    ;; Recompute the rectangle state; no crutches should be needed now.
+    (let ((p (point))
+          (m (mark)))
+      (rectangle--reset-crutches)
+      (goto-char m)
+      (move-to-column (cdr cols) t)
+      (set-mark (point))
+      (goto-char p)
+      (move-to-column (car cols) t))))
+
 (provide 'rect)
 
 ;;; rect.el ends here
diff --git a/lisp/repeat.el b/lisp/repeat.el
index ea4e3d0bd8..a32f3a4c50 100644
--- a/lisp/repeat.el
+++ b/lisp/repeat.el
@@ -368,8 +368,8 @@ When non-nil and the last typed key (with or without 
modifiers)
 doesn't exist in the keymap attached by the `repeat-map' property,
 then don't activate that keymap for the next command.  So only the
 same keys among repeatable keys are allowed in the repeating sequence.
-For example, with a non-nil value, only `C-x u u' repeats undo,
-whereas `C-/ u' doesn't.
+For example, with a non-nil value, only \\`C-x u u' repeats undo,
+whereas \\`C-/ u' doesn't.
 
 You can also set the property `repeat-check-key' on the command symbol.
 This property can override the value of this variable.
@@ -418,7 +418,7 @@ See `describe-repeat-maps' for a list of all repeatable 
commands."
                                    (and (commandp s)
                                         (get s 'repeat-map)
                                         (push (get s 'repeat-map) keymaps))))))
-      (message "Repeat mode is enabled for %d commands and %d keymaps; see 
`describe-repeat-maps'."
+      (message "Repeat mode is enabled for %d commands and %d keymaps; see 
`describe-repeat-maps'"
                (length commands)
                (length (delete-dups keymaps))))))
 
@@ -500,14 +500,17 @@ See `describe-repeat-maps' for a list of all repeatable 
commands."
 (defun repeat-echo-message-string (keymap)
   "Return a string with a list of repeating keys."
   (let (keys)
-    (map-keymap (lambda (key _) (push key keys)) keymap)
+    (map-keymap (lambda (key cmd) (and cmd (push key keys))) keymap)
     (format-message "Repeat with %s%s"
                     (mapconcat (lambda (key)
-                                 (key-description (vector key)))
+                                 (substitute-command-keys
+                                  (format "\\`%s'"
+                                          (key-description (vector key)))))
                                keys ", ")
                     (if repeat-exit-key
-                        (format ", or exit with %s"
-                                (key-description repeat-exit-key))
+                        (substitute-command-keys
+                         (format ", or exit with \\`%s'"
+                                 (key-description repeat-exit-key)))
                       ""))))
 
 (defun repeat-echo-message (keymap)
@@ -557,21 +560,28 @@ Used in `repeat-mode'."
                          (push s (alist-get (get s 'repeat-map) keymaps)))))
       (with-help-window (help-buffer)
         (with-current-buffer standard-output
-          (princ "A list of keymaps used by commands with the symbol property 
`repeat-map'.\n\n")
-
-          (dolist (keymap (sort keymaps (lambda (a b) (string-lessp (car a) 
(car b)))))
-            (princ (format-message "`%s' keymap is repeatable by these 
commands:\n"
-                                   (car keymap)))
-            (dolist (command (sort (cdr keymap) 'string-lessp))
+          (insert "A list of keymaps used by commands with the symbol property 
`repeat-map'.\n\n")
+
+          (dolist (keymap (sort keymaps (lambda (a b)
+                                          (when (and (symbolp (car a))
+                                                     (symbolp (car b)))
+                                            (string-lessp (car a) (car b))))))
+            (insert (format-message
+                     "`%s' keymap is repeatable by these commands:\n"
+                     (car keymap)))
+            (dolist (command (sort (cdr keymap) #'string-lessp))
               (let* ((info (help-fns--analyze-function command))
-                     (map (list (symbol-value (car keymap))))
+                     (map (list (if (symbolp (car keymap))
+                                    (symbol-value (car keymap))
+                                  (car keymap))))
                      (desc (mapconcat (lambda (key)
-                                        (format-message "`%s'" 
(key-description key)))
+                                        (propertize (key-description key)
+                                                    'face 'help-key-binding))
                                       (or (where-is-internal command map)
                                           (where-is-internal (nth 3 info) map))
                                       ", ")))
-                (princ (format-message " `%s' (bound to %s)\n" command desc))))
-            (princ "\n")))))))
+                (insert (format-message " `%s' (bound to %s)\n" command 
desc))))
+            (insert "\n")))))))
 
 (provide 'repeat)
 
diff --git a/lisp/replace.el b/lisp/replace.el
index c5c24c7a36..2bb9c1b90d 100644
--- a/lisp/replace.el
+++ b/lisp/replace.el
@@ -30,6 +30,7 @@
 
 (require 'text-mode)
 (eval-when-compile (require 'cl-lib))
+(eval-when-compile (require 'subr-x))
 
 (defcustom case-replace t
   "Non-nil means `query-replace' should preserve case in replacements."
@@ -156,7 +157,7 @@ is highlighted lazily using isearch lazy highlighting (see
 
 (defvar replace-count 0
   "Number of replacements done so far.
-See `replace-regexp' and `query-replace-regexp-eval'.")
+See `replace-regexp'.")
 
 (defun query-replace-descr (string)
   (setq string (copy-sequence string))
@@ -414,7 +415,7 @@ word boundaries.  A negative prefix arg means replace 
backward.
 Use \\<minibuffer-local-map>\\[next-history-element] \
 to pull the last incremental search string to the minibuffer
 that reads FROM-STRING, or invoke replacements from
-incremental search with a key sequence like `C-s C-s M-%'
+incremental search with a key sequence like \\`C-s C-s M-%'
 to use its current search string as the string to replace.
 
 Matching is independent of case if both `case-fold-search'
@@ -471,8 +472,8 @@ To customize possible responses, change the bindings in 
`query-replace-map'."
 (defun query-replace-regexp (regexp to-string &optional delimited start end 
backward region-noncontiguous-p)
   "Replace some things after point matching REGEXP with TO-STRING.
 As each match is found, the user must type a character saying
-what to do with it.  Type SPC or `y' to replace the match,
-DEL or `n' to skip and go to the next match.  For more directions,
+what to do with it.  Type \\`SPC' or \\`y' to replace the match,
+\\`DEL' or \\`n' to skip and go to the next match.  For more directions,
 type \\[help-command] at that time.
 
 In Transient Mark mode, if the mark is active, operate on the contents
@@ -480,12 +481,12 @@ of the region.  Otherwise, operate from point to the end 
of the buffer's
 accessible portion.
 
 When invoked interactively, matching a newline with `\\n' will not work;
-use `C-q C-j' instead.  To match a tab character (`\\t'), just press `TAB'.
+use \\`C-q C-j' instead.  To match a tab character (`\\t'), just press \\`TAB'.
 
 Use \\<minibuffer-local-map>\\[next-history-element] \
 to pull the last incremental search regexp to the minibuffer
 that reads REGEXP, or invoke replacements from
-incremental search with a key sequence like `C-M-s C-M-s C-M-%'
+incremental search with a key sequence like \\`C-M-s C-M-s C-M-%'
 to use its current search regexp as the regexp to replace.
 
 Matching is independent of case if both `case-fold-search'
@@ -562,84 +563,6 @@ REGION-NONCONTIGUOUS-P are passed to `perform-replace' 
(which see)."
 
 (define-key esc-map [?\C-%] 'query-replace-regexp)
 
-(defun query-replace-regexp-eval (regexp to-expr &optional delimited start end 
region-noncontiguous-p)
-  "Replace some things after point matching REGEXP with the result of TO-EXPR.
-
-Interactive use of this function is deprecated in favor of the
-`\\,' feature of `query-replace-regexp'.  For non-interactive use, a loop
-using `search-forward-regexp' and `replace-match' is preferred.
-
-As each match is found, the user must type a character saying
-what to do with it.  Type SPC or `y' to replace the match,
-DEL or `n' to skip and go to the next match.  For more directions,
-type \\[help-command] at that time.
-
-TO-EXPR is a Lisp expression evaluated to compute each replacement.  It may
-reference `replace-count' to get the number of replacements already made.
-If the result of TO-EXPR is not a string, it is converted to one using
-`prin1-to-string' with the NOESCAPE argument (which see).
-
-For convenience, when entering TO-EXPR interactively, you can use `\\&'
-to stand for whatever matched the whole of REGEXP, and `\\N' (where
-N is a digit) to stand for whatever matched the Nth `\\(...\\)' (1-based)
-in REGEXP.
-
-Use `\\#&' or `\\#N' if you want a number instead of a string.
-In interactive use, `\\#' in itself stands for `replace-count'.
-
-In Transient Mark mode, if the mark is active, operate on the contents
-of the region.  Otherwise, operate from point to the end of the buffer's
-accessible portion.
-
-Use \\<minibuffer-local-map>\\[next-history-element] \
-to pull the last incremental search regexp to the minibuffer
-that reads REGEXP.
-
-Preserves case in each replacement if `case-replace' and `case-fold-search'
-are non-nil and REGEXP has no uppercase letters.
-
-Ignore read-only matches if `query-replace-skip-read-only' is non-nil,
-ignore hidden matches if `search-invisible' is nil, and ignore more
-matches using `isearch-filter-predicate'.
-
-If `replace-regexp-lax-whitespace' is non-nil, a space or spaces in the regexp
-to be replaced will match a sequence of whitespace chars defined by the
-regexp in `search-whitespace-regexp'.
-
-This function is not affected by `replace-char-fold'.
-
-Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace
-only matches that are surrounded by word boundaries.
-Fourth and fifth arg START and END specify the region to operate on.
-
-Arguments REGEXP, DELIMITED, START, END, and REGION-NONCONTIGUOUS-P
-are passed to `perform-replace' (which see)."
-  (declare (obsolete "use the `\\,' feature of `query-replace-regexp'
-for interactive calls, and `search-forward-regexp'/`replace-match'
-for Lisp calls." "22.1"))
-  (interactive
-   (progn
-     (barf-if-buffer-read-only)
-     (let* ((from
-            ;; Let-bind the history var to disable the "foo -> bar"
-            ;; default.  Maybe we shouldn't disable this default, but
-            ;; for now I'll leave it off.  --Stef
-            (let ((query-replace-defaults nil))
-              (query-replace-read-from "Query replace regexp" t)))
-           (to (list (read-from-minibuffer
-                      (format "Query replace regexp %s with eval: "
-                              (query-replace-descr from))
-                      nil nil t query-replace-to-history-variable from t))))
-       ;; We make TO a list because replace-match-string-symbols requires one,
-       ;; and the user might enter a single token.
-       (replace-match-string-symbols to)
-       (list from (car to) current-prefix-arg
-            (if (use-region-p) (region-beginning))
-            (if (use-region-p) (region-end))
-            (if (use-region-p) (region-noncontiguous-p))))))
-  (perform-replace regexp (cons #'replace-eval-replacement to-expr)
-                  t 'literal delimited nil nil start end nil 
region-noncontiguous-p))
-
 (defun map-query-replace-regexp (regexp to-strings &optional n start end 
region-noncontiguous-p)
   "Replace some matches for REGEXP with various strings, in rotation.
 The second argument TO-STRINGS contains the replacement strings, separated
@@ -741,7 +664,10 @@ which will run faster and will not set the mark or print 
anything.
 \(You may need a more complex loop if FROM-STRING can match the null string
 and TO-STRING is also null.)"
   (declare (interactive-only
-           "use `search-forward' and `replace-match' instead."))
+           "use `search-forward' and `replace-match' instead.")
+           (interactive-args
+           (start (use-region-beginning))
+           (end (use-region-end))))
   (interactive
    (let ((common
          (query-replace-read-args
@@ -753,8 +679,7 @@ and TO-STRING is also null.)"
                   (if (use-region-p) " in region" ""))
           nil)))
      (list (nth 0 common) (nth 1 common) (nth 2 common)
-          (if (use-region-p) (region-beginning))
-          (if (use-region-p) (region-end))
+          (use-region-beginning) (use-region-end)
           (nth 3 common)
           (if (use-region-p) (region-noncontiguous-p)))))
   (perform-replace from-string to-string nil nil delimited nil nil start end 
backward region-noncontiguous-p))
@@ -894,6 +819,23 @@ by this function to the end of values available via
    (regexp-quote (or (car search-ring) ""))
    (car (symbol-value query-replace-from-history-variable))))
 
+(defvar-keymap read-regexp-map
+  :parent minibuffer-local-map
+  "M-c" #'read-regexp-toggle-case-folding)
+
+(defvar read-regexp--case-fold nil)
+
+(defun read-regexp-toggle-case-folding ()
+  (interactive)
+  (setq read-regexp--case-fold
+        (if (or (eq read-regexp--case-fold 'fold)
+                (and read-regexp--case-fold
+                     (not (eq read-regexp--case-fold 'inhibit-fold))))
+            'inhibit-fold
+          'fold))
+  (minibuffer-message "Case folding is now %s"
+                      (if (eq read-regexp--case-fold 'fold) "on" "off")))
+
 (defun read-regexp (prompt &optional defaults history)
   "Read and return a regular expression as a string.
 Prompt with the string PROMPT.  If PROMPT ends in \":\" (followed by
@@ -930,11 +872,14 @@ in \":\", followed by optional whitespace), DEFAULT is 
added to the prompt.
 The optional argument HISTORY is a symbol to use for the history list.
 If nil, use `regexp-history'.
 
-If the user has used the `M-c' command to specify case
+If the user has used the 
\\<read-regexp-map>\\[read-regexp-toggle-case-folding] command to specify case
 sensitivity, the returned string will have a text property named
 `case-fold' that has a value of either `fold' or
 `inhibit-fold'.  (It's up to the caller of `read-regexp' to
-respect this or not; see `read-regexp-case-fold-search'.)"
+respect this or not; see `read-regexp-case-fold-search'.)
+
+This command uses the `read-regexp-map' keymap while reading the
+regexp from the user."
   (let* ((defaults
           (if (and defaults (symbolp defaults))
               (cond
@@ -950,29 +895,15 @@ respect this or not; see `read-regexp-case-fold-search'.)"
         (suggestions (delete-dups (delq nil (delete "" suggestions))))
         ;; Do not automatically add default to the history for empty input.
         (history-add-new-input nil)
-         (case-fold case-fold-search)
+         ;; `read-regexp--case-fold' dynamically bound and may be
+         ;; altered by `M-c'.
+         (read-regexp--case-fold case-fold-search)
         (input (read-from-minibuffer
                  (if (string-match-p ":[ \t]*\\'" prompt)
                      prompt
                    (format-prompt prompt (and (length> default 0)
                                               (query-replace-descr default))))
-                nil
-                 (define-keymap
-                   :parent minibuffer-local-map
-                   "M-c" (lambda ()
-                           (interactive)
-                           (setq case-fold
-                                 (if (or (eq case-fold 'fold)
-                                         (and case-fold
-                                              (not (eq case-fold
-                                                       'inhibit-fold))))
-                                     'inhibit-fold
-                                   'fold))
-                           (minibuffer-message
-                            "Case folding is now %s"
-                            (if (eq case-fold 'fold)
-                                "on"
-                              "off"))))
+                nil read-regexp-map
                  nil (or history 'regexp-history) suggestions t))
          (result (if (equal input "")
                     ;; Return the default value when the user enters
@@ -982,9 +913,9 @@ respect this or not; see `read-regexp-case-fold-search'.)"
     (when result
       (add-to-history (or history 'regexp-history) result))
     (if (and result
-             (or (eq case-fold 'fold)
-                 (eq case-fold 'inhibit-fold)))
-        (propertize result 'case-fold case-fold)
+             (or (eq read-regexp--case-fold 'fold)
+                 (eq read-regexp--case-fold 'inhibit-fold)))
+        (propertize result 'case-fold read-regexp--case-fold)
       (or result input))))
 
 (defun read-regexp-case-fold-search (regexp)
@@ -2430,9 +2361,8 @@ See also `multi-occur'."
       (if (>= (+ prev-line (length prev-after-lines))
              (- curr-line (length before-lines)))
          (setq prev-after-lines
-               (butlast prev-after-lines
-                        (- (length prev-after-lines)
-                           (- curr-line prev-line (length before-lines) 1))))
+                (take (- curr-line prev-line (length before-lines) 1)
+                      prev-after-lines))
        ;; Separate non-overlapping context lines with a dashed line.
        (setq separator "-------\n")))
 
@@ -2713,10 +2643,9 @@ with three arguments, as if it were `search-forward'.")
 
 (defvar replace-re-search-function nil
   "Function to use when searching for regexps to replace.
-It is used by `query-replace-regexp', `replace-regexp',
-`query-replace-regexp-eval', and `map-query-replace-regexp'.
-It is called with three arguments, as if it were
-`re-search-forward'.")
+It is used by `query-replace-regexp', `replace-regexp', and
+`map-query-replace-regexp'.  It is called with three arguments,
+as if it were `re-search-forward'.")
 
 (defvar replace-regexp-function nil
   "Function to convert the FROM string of query-replace commands to a regexp.
@@ -2814,7 +2743,9 @@ to a regexp that is actually used for the search.")
            (isearch-case-fold-search case-fold)
            (isearch-forward (not backward))
            (isearch-other-end match-beg)
-           (isearch-error nil))
+           (isearch-error nil)
+           (isearch-lazy-count nil)
+           (lazy-highlight-buffer nil))
        (isearch-lazy-highlight-new-loop range-beg range-end))))
 
 (defun replace-dehighlight ()
diff --git a/lisp/ruler-mode.el b/lisp/ruler-mode.el
index f0efc20f03..0b18697cea 100644
--- a/lisp/ruler-mode.el
+++ b/lisp/ruler-mode.el
@@ -509,36 +509,21 @@ START-EVENT is the mouse click event."
   (setq ruler-mode-show-tab-stops (not ruler-mode-show-tab-stops))
   (force-mode-line-update))
 
-(defvar ruler-mode-map
-  (let ((km (make-sparse-keymap)))
-    (define-key km [header-line down-mouse-1]
-      #'ignore)
-    (define-key km [header-line down-mouse-3]
-      #'ignore)
-    (define-key km [header-line down-mouse-2]
-      #'ruler-mode-mouse-grab-any-column)
-    (define-key km [header-line (shift down-mouse-1)]
-      #'ruler-mode-mouse-set-left-margin)
-    (define-key km [header-line (shift down-mouse-3)]
-      #'ruler-mode-mouse-set-right-margin)
-    (define-key km [header-line (control down-mouse-1)]
-      #'ruler-mode-mouse-add-tab-stop)
-    (define-key km [header-line (control down-mouse-3)]
-      #'ruler-mode-mouse-del-tab-stop)
-    (define-key km [header-line (control down-mouse-2)]
-      #'ruler-mode-toggle-show-tab-stops)
-    (define-key km [header-line (shift mouse-1)]
-      #'ignore)
-    (define-key km [header-line (shift mouse-3)]
-      #'ignore)
-    (define-key km [header-line (control mouse-1)]
-      #'ignore)
-    (define-key km [header-line (control mouse-3)]
-      #'ignore)
-    (define-key km [header-line (control mouse-2)]
-      #'ignore)
-    km)
-  "Keymap for ruler minor mode.")
+(defvar-keymap ruler-mode-map
+  :doc "Keymap for `ruler-mode'."
+  "<header-line> <down-mouse-1>"   #'ignore
+  "<header-line> <down-mouse-3>"   #'ignore
+  "<header-line> <down-mouse-2>"   #'ruler-mode-mouse-grab-any-column
+  "<header-line> S-<down-mouse-1>" #'ruler-mode-mouse-set-left-margin
+  "<header-line> S-<down-mouse-3>" #'ruler-mode-mouse-set-right-margin
+  "<header-line> C-<down-mouse-1>" #'ruler-mode-mouse-add-tab-stop
+  "<header-line> C-<down-mouse-3>" #'ruler-mode-mouse-del-tab-stop
+  "<header-line> C-<down-mouse-2>" #'ruler-mode-toggle-show-tab-stops
+  "<header-line> S-<mouse-1>"      #'ignore
+  "<header-line> S-<mouse-3>"      #'ignore
+  "<header-line> C-<mouse-1>"      #'ignore
+  "<header-line> C-<mouse-3>"      #'ignore
+  "<header-line> C-<mouse-2>"      #'ignore)
 
 (defvar ruler-mode-header-line-format-old nil
   "Hold previous value of `header-line-format'.")
diff --git a/lisp/savehist.el b/lisp/savehist.el
index 172acaa4e8..8924c8dde2 100644
--- a/lisp/savehist.el
+++ b/lisp/savehist.el
@@ -97,7 +97,8 @@ This is decimal, not octal.  The default is 384 (0600 in 
octal).
 Set to nil to use the default permissions that Emacs uses, typically
 mandated by umask.  The default is a bit more restrictive to protect
 the user's privacy."
-  :type 'integer)
+  :type '(choice (natnum :tag "Specify")
+                 (const :tag "Use default" :value nil)))
 
 (defcustom savehist-autosave-interval (* 5 60)
   "The interval between autosaves of minibuffer history.
diff --git a/lisp/saveplace.el b/lisp/saveplace.el
index a23454b0bb..4b13331312 100644
--- a/lisp/saveplace.el
+++ b/lisp/saveplace.el
@@ -191,7 +191,7 @@ file names."
   ;; First check to make sure alist has been loaded in from the master
   ;; file.  If not, do so, then feel free to modify the alist.  It
   ;; will be saved again when Emacs is killed.
-  (or save-place-loaded (load-save-place-alist-from-file))
+  (or save-place-loaded (save-place-load-alist-from-file))
   (let* ((directory (and (derived-mode-p 'dired-mode)
                          (boundp 'dired-subdir-alist)
                         dired-subdir-alist
@@ -278,7 +278,7 @@ may have changed) back to `save-place-alist'."
          (file-error (message "Saving places: can't write %s" file)))
         (kill-buffer (current-buffer))))))
 
-(defun load-save-place-alist-from-file ()
+(defun save-place-load-alist-from-file ()
   (if (not save-place-loaded)
       (progn
         (setq save-place-loaded t)
@@ -346,8 +346,13 @@ may have changed) back to `save-place-alist'."
          (save-place-to-alist))
        (setq buf-list (cdr buf-list))))))
 
+(defvar save-place-after-find-file-hook nil
+  "Hook run at the end of `save-place-find-file-hook'.")
+
 (defun save-place-find-file-hook ()
-  (or save-place-loaded (load-save-place-alist-from-file))
+  "Function added to `find-file-hook' by `save-place-mode'.
+It runs the hook `save-place-after-find-file-hook'."
+  (or save-place-loaded (save-place-load-alist-from-file))
   (let ((cell (assoc buffer-file-name save-place-alist)))
     (if cell
        (progn
@@ -355,13 +360,14 @@ may have changed) back to `save-place-alist'."
              (and (integerp (cdr cell))
                   (goto-char (cdr cell))))
           ;; and make sure it will be saved again for later
-          (setq save-place-mode t)))))
+          (setq save-place-mode t))))
+  (run-hooks 'save-place-after-find-file-hook))
 
 (declare-function dired-goto-file "dired" (file))
 
 (defun save-place-dired-hook ()
   "Position the point in a Dired buffer."
-  (or save-place-loaded (load-save-place-alist-from-file))
+  (or save-place-loaded (save-place-load-alist-from-file))
   (let* ((directory (and (derived-mode-p 'dired-mode)
                          (boundp 'dired-subdir-alist)
                         dired-subdir-alist
@@ -390,5 +396,8 @@ may have changed) back to `save-place-alist'."
   (if save-place-loaded
       (save-place-alist-to-file)))
 
+(define-obsolete-function-alias 'load-save-place-alist-from-file
+  #'save-place-load-alist-from-file "29.1")
+
 (provide 'saveplace)
 ;;; saveplace.el ends here
diff --git a/lisp/select.el b/lisp/select.el
index 127a6a5c61..5b9cca80a3 100644
--- a/lisp/select.el
+++ b/lisp/select.el
@@ -85,9 +85,6 @@ other programs (X Windows clients or MS Windows programs).  
But, if this
 variable is set, it is used for the next communication only.
 After the communication, this variable is set to nil.")
 
-;; Only declared obsolete in 23.3.
-(define-obsolete-function-alias 'x-selection 'x-get-selection "at least 19.34")
-
 (define-obsolete-variable-alias 'x-select-enable-clipboard
   'select-enable-clipboard "25.1")
 (defcustom select-enable-clipboard t
@@ -112,20 +109,28 @@ E.g. it doesn't exist under MS-Windows."
 ;; We keep track of the last selection here, so we can check the
 ;; current selection against it, and avoid passing back with
 ;; gui-selection-value the same text we previously killed or
-;; yanked. We track both
-;; separately in case another X application only sets one of them
-;; we aren't fooled by the PRIMARY or CLIPBOARD selection staying the same.
+;; yanked. We track both separately in case another X application only
+;; sets one of them we aren't fooled by the PRIMARY or CLIPBOARD
+;; selection staying the same.
 
 (defvar gui--last-selected-text-clipboard nil
   "The value of the CLIPBOARD selection last seen.")
+
 (defvar gui--last-selected-text-primary nil
   "The value of the PRIMARY selection last seen.")
 
 (defvar gui--last-selection-timestamp-clipboard nil
   "The timestamp of the CLIPBOARD selection last seen.")
+
 (defvar gui--last-selection-timestamp-primary nil
   "The timestamp of the PRIMARY selection last seen.")
 
+(defvar gui-last-cut-in-clipboard nil
+  "Whether or not the last call to `interprogram-cut-function' owned 
CLIPBOARD.")
+
+(defvar gui-last-cut-in-primary nil
+  "Whether or not the last call to `interprogram-cut-function' owned PRIMARY.")
+
 (defun gui--set-last-clipboard-selection (text)
   "Save last clipboard selection.
 Save the selected text, passed as argument, and for window
@@ -182,7 +187,10 @@ MS-Windows does not have a \"primary\" selection."
     ;; should not be reset by cut (Bug#16382).
     (setq saved-region-selection text)
     (gui-set-selection 'CLIPBOARD text)
-    (gui--set-last-clipboard-selection text)))
+    (gui--set-last-clipboard-selection text))
+  ;; Record which selections we now have ownership over.
+  (setq gui-last-cut-in-clipboard select-enable-clipboard
+        gui-last-cut-in-primary select-enable-primary))
 (define-obsolete-function-alias 'x-select-text 'gui-select-text "25.1")
 
 (defcustom x-select-request-type nil
@@ -218,13 +226,13 @@ decided by `x-select-request-type'.  The return value is 
already
 decoded.  If `gui-get-selection' signals an error, return nil."
   ;; The doc string of `interprogram-paste-function' says to return
   ;; nil if no other program has provided text to paste.
-  (unless (and
-           ;; `gui-backend-selection-owner-p' might be unreliable on
-           ;; some other window systems.
-           (memq window-system '(x haiku))
-           (eq type 'CLIPBOARD)
-           ;; Should we unify this with gui--clipboard-selection-unchanged-p?
-           (gui-backend-selection-owner-p type))
+  (unless (and gui-last-cut-in-clipboard
+               ;; `gui-backend-selection-owner-p' might be unreliable on
+               ;; some other window systems.
+               (memq window-system '(x haiku))
+               (eq type 'CLIPBOARD)
+               ;; Should we unify this with 
gui--clipboard-selection-unchanged-p?
+               (gui-backend-selection-owner-p type))
     (let ((request-type (if (memq window-system '(x pgtk haiku))
                             (or x-select-request-type
                                 '(UTF8_STRING COMPOUND_TEXT STRING 
text/plain\;charset=utf-8))
@@ -254,7 +262,15 @@ decoded.  If `gui-get-selection' signals an error, return 
nil."
              ;; (bug#53894) for further discussion about this DWIM
              ;; action, and possible ways to make this check less
              ;; fragile, if so desired.
-             (unless (gui--clipboard-selection-unchanged-p text)
+
+             ;; Don't check the "newness" of CLIPBOARD if the last
+             ;; call to `gui-select-text' didn't cause us to become
+             ;; its owner.  This lets the user yank text killed by
+             ;; `clipboard-kill-region' with `clipboard-yank' without
+             ;; interference from text killed by other means when
+             ;; `select-enable-clipboard' is nil.
+             (unless (and gui-last-cut-in-clipboard
+                          (gui--clipboard-selection-unchanged-p text))
                (gui--set-last-clipboard-selection text)
                text))))
         (primary-text
@@ -264,7 +280,8 @@ decoded.  If `gui-get-selection' signals an error, return 
nil."
              ;; Check the PRIMARY selection for 'newness', is it different
              ;; from what we remembered them to be last time we did a
              ;; cut/paste operation.
-             (unless (gui--primary-selection-unchanged-p text)
+             (unless (and gui-last-cut-in-primary
+                          (gui--primary-selection-unchanged-p text))
                (gui--set-last-primary-selection text)
                text)))))
 
@@ -455,6 +472,73 @@ are not available to other programs."
       (symbolp data)
       (integerp data)))
 
+
+;; Minor mode to make losing ownership of PRIMARY behave more like
+;; other X programs.
+
+(defvar lost-selection-last-region-buffer nil
+  "The last buffer from which the region was selected.")
+
+(defun lost-selection-post-select-region-function (_text)
+  "Handle the region being selected into PRIMARY.
+If the current buffer is different from the last buffer,
+deactivate the mark in every other buffer.
+TEXT is ignored."
+  (when (not (eq lost-selection-last-region-buffer
+                 (current-buffer)))
+    (dolist (buffer (buffer-list))
+      (unless (or (string-match-p "^ "
+                                  (buffer-name buffer))
+                  (eq buffer (current-buffer)))
+        (with-current-buffer buffer
+          (deactivate-mark t))))
+    (setq lost-selection-last-region-buffer (current-buffer))))
+
+(defun lost-selection-function (selection)
+  "Handle losing of ownership of SELECTION.
+If SELECTION is `PRIMARY', deactivate the mark in every
+non-temporary buffer."
+  (let ((select-active-regions nil))
+    (when (eq selection 'PRIMARY)
+      (dolist (buffer (buffer-list))
+        (unless (string-match-p "^ "
+                                (buffer-name buffer))
+          (with-current-buffer buffer
+            (deactivate-mark t)))))))
+
+(define-minor-mode lost-selection-mode
+  "Toggle `lost-selection-mode'.
+
+When this is enabled, selecting some text in another program will
+cause the mark to be deactivated in all buffers, mimicking the
+behavior of most X Windows programs.
+
+Selecting text in a buffer that ends up changing the primary
+selection will also cause the mark to be deactivated in all other
+buffers."
+  :global t
+  :group 'x
+  (if lost-selection-mode
+      (progn
+        (cond ((featurep 'x) (add-hook 'x-lost-selection-functions
+                                       #'lost-selection-function))
+              ((featurep 'pgtk) (add-hook 'pgtk-lost-selection-functions
+                                          #'lost-selection-function))
+              ((featurep 'haiku) (add-hook 'haiku-lost-selection-functions
+                                           #'lost-selection-function)))
+        (add-hook 'post-select-region-hook
+                  #'lost-selection-post-select-region-function))
+    (cond ((featurep 'x) (remove-hook 'x-lost-selection-functions
+                                      #'lost-selection-function))
+          ((featurep 'pgtk) (remove-hook 'pgtk-lost-selection-functions
+                                         #'lost-selection-function))
+          ((featurep 'haiku) (remove-hook 'haiku-lost-selection-functions
+                                          #'lost-selection-function)))
+    (remove-hook 'post-select-region-hook
+                 #'lost-selection-post-select-region-function)
+    (setq lost-selection-last-region-buffer nil)))
+
+
 ;; Functions to convert the selection into various other selection types.
 ;; Every selection type that Emacs handles is implemented this way, except
 ;; for TIMESTAMP, which is a special case.
@@ -589,9 +673,12 @@ two markers or an overlay.  Otherwise, it is nil."
   (let ((str (cond ((stringp value) value)
                   ((setq value (xselect--selection-bounds value))
                    (with-current-buffer (nth 2 value)
-                     (buffer-substring (nth 0 value)
-                                       (nth 1 value)))))))
-    (xselect--encode-string type str t)))
+                      (when (and (>= (nth 0 value) (point-min))
+                                 (<= (nth 1 value) (point-max)))
+                       (buffer-substring (nth 0 value)
+                                          (nth 1 value))))))))
+    (when str
+      (xselect--encode-string type str t))))
 
 (defun xselect-convert-to-length (_selection _type value)
   (let ((len (cond ((stringp value)
@@ -721,16 +808,18 @@ This function returns the string \"emacs\"."
   (user-real-login-name))
 
 (defun xselect-convert-to-text-uri-list (_selection _type value)
-  (if (stringp value)
-      (xselect--encode-string 'TEXT
-                              (concat (url-encode-url value) "\n"))
-    (when (vectorp value)
-      (with-temp-buffer
-        (cl-loop for tem across value
-                 do (progn
-                      (insert (url-encode-url tem))
-                      (insert "\n")))
-        (xselect--encode-string 'TEXT (buffer-string))))))
+  (let ((string
+         (if (stringp value)
+             (xselect--encode-string 'TEXT
+                                     (concat (url-encode-url value) "\n"))
+           (when (vectorp value)
+             (with-temp-buffer
+               (cl-loop for tem across value
+                        do (progn
+                             (insert (url-encode-url tem))
+                             (insert "\n")))
+               (xselect--encode-string 'TEXT (buffer-string)))))))
+    (cons 'text/uri-list (cdr string))))
 
 (defun xselect-convert-to-xm-file (selection _type value)
   (when (and (stringp value)
@@ -740,7 +829,8 @@ This function returns the string \"emacs\"."
                             (concat value [0]))))
 
 (defun xselect-uri-list-available-p (selection _type value)
-  "Return whether or not `text/uri-list' is a valid target for SELECTION.
+  "Return non-nil if `text/uri-list' is a valid target for SELECTION.
+Return nil otherwise.
 VALUE is the local selection value of SELECTION."
   (and (eq selection 'XdndSelection)
        (or (stringp value)
@@ -750,13 +840,20 @@ VALUE is the local selection value of SELECTION."
   "")
 
 (defun xselect-dt-netfile-available-p (selection _type value)
-  "Return whether or not `_DT_NETFILE' is a valid target for SELECTION.
+  "Return non-nil if `_DT_NETFILE' is a valid target for SELECTION.
+Return nil otherwise.
 VALUE is SELECTION's local selection value."
   (and (eq selection 'XdndSelection)
        (stringp value)
        (file-exists-p value)
        (not (file-remote-p value))))
 
+(defun xselect-dnd-target-available-p (selection _type _value)
+  "Return non-nil if TYPE is a valid target for SELECTION.
+Return nil otherwise.
+VALUE is SELECTION's local selection value."
+  (eq selection 'XdndSelection))
+
 (defun xselect-tt-net-file (file)
   "Get the canonical ToolTalk filename for FILE.
 FILE must be a local file, or otherwise the conversion will fail.
@@ -801,7 +898,8 @@ VALUE should be SELECTION's local value."
        (text/plain\;charset=utf-8 . xselect-convert-to-string)
         (text/uri-list . (xselect-uri-list-available-p
                           . xselect-convert-to-text-uri-list))
-        (text/x-xdnd-username . xselect-convert-to-username)
+        (text/x-xdnd-username . (xselect-dnd-target-available-p
+                                 . xselect-convert-to-username))
         (FILE . (xselect-uri-list-available-p
                  . xselect-convert-to-xm-file))
        (TARGETS . xselect-convert-to-targets)
@@ -820,8 +918,10 @@ VALUE should be SELECTION's local value."
        (INTEGER . xselect-convert-to-integer)
        (SAVE_TARGETS . xselect-convert-to-save-targets)
        (_EMACS_INTERNAL . xselect-convert-to-identity)
-        (XmTRANSFER_SUCCESS . xselect-convert-xm-special)
-        (XmTRANSFER_FAILURE . xselect-convert-xm-special)
+        (XmTRANSFER_SUCCESS . (xselect-dnd-target-available-p
+                               . xselect-convert-xm-special))
+        (XmTRANSFER_FAILURE . (xselect-dnd-target-available-p
+                               . xselect-convert-xm-special))
         (_DT_NETFILE . (xselect-dt-netfile-available-p
                         . xselect-convert-to-dt-netfile))))
 
diff --git a/lisp/server.el b/lisp/server.el
index 8f47a99a31..dd7bccaf33 100644
--- a/lisp/server.el
+++ b/lisp/server.el
@@ -544,7 +544,8 @@ Creates the directory if necessary and makes sure:
   (setq dir (directory-file-name dir))
   (let ((attrs (file-attributes dir 'integer)))
     (unless attrs
-      (cl-letf (((default-file-modes) ?\700)) (make-directory dir t))
+      (with-file-modes ?\700
+        (make-directory dir t))
       (setq attrs (file-attributes dir 'integer)))
 
     ;; Check that it's safe for use.
@@ -691,7 +692,7 @@ server or call `\\[server-force-delete]' to forcibly 
disconnect it."))
        (server-ensure-safe-dir server-dir)
        (when server-process
          (server-log (message "Restarting server")))
-       (cl-letf (((default-file-modes) ?\700))
+        (with-file-modes ?\700
          (add-hook 'suspend-tty-functions #'server-handle-suspend-tty)
          (add-hook 'delete-frame-functions #'server-handle-delete-frame)
          (add-hook 'kill-emacs-query-functions
@@ -1314,7 +1315,8 @@ The following commands are accepted by the client:
                                                       frame-parameters))
                   ;; When resuming on a tty, tty-name is nil.
                   (tty-name
-                   (server-create-tty-frame tty-name tty-type proc))
+                   (server-create-tty-frame tty-name tty-type proc
+                                             frame-parameters))
 
                    ;; If there won't be a current frame to use, fall
                    ;; back to trying to create a new one.
diff --git a/lisp/ses.el b/lisp/ses.el
index ba965ff8a5..a5fd1774dd 100644
--- a/lisp/ses.el
+++ b/lisp/ses.el
@@ -3807,7 +3807,7 @@ function is redefined."
         (default (and cur-printer (ses--locprn-def cur-printer)))
         create-printer)
     (cond
-     ;; cancelled operation => do nothing
+     ;; canceled operation => do nothing
      ((eq definition t))
      ;; no change => do nothing
      ((and cur-printer (equal definition default)))
diff --git a/lisp/shell.el b/lisp/shell.el
index 8bcc578406..85225b128a 100644
--- a/lisp/shell.el
+++ b/lisp/shell.el
@@ -440,12 +440,11 @@ Useful for shells like zsh that has this feature."
        (push (point) begins)
         (let ((arg ()))
           (while (looking-at
-                  (eval-when-compile
-                    (concat
-                     "\\(?:[^\s\t\n\\\"';]+"
-                     "\\|'\\([^']*\\)'?"
-                     "\\|\"\\(\\(?:[^\"\\]\\|\\\\.\\)*\\)\"?"
-                     "\\|\\\\\\(\\(?:.\\|\n\\)?\\)\\)")))
+                  (concat
+                   "\\(?:[^\s\t\n\\\"';]+"
+                   "\\|'\\([^']*\\)'?"
+                   "\\|\"\\(\\(?:[^\"\\]\\|\\\\.\\)*\\)\"?"
+                   "\\|\\\\\\(\\(?:.\\|\n\\)?\\)\\)"))
             (goto-char (match-end 0))
             (cond
              ((match-beginning 3)       ;Backslash escape.
diff --git a/lisp/simple.el b/lisp/simple.el
index 99c951b24b..ceb29b1e30 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -1402,15 +1402,17 @@ instead of deleted."
   :version "24.1")
 
 (setq region-extract-function
-  (lambda (method)
-    (when (region-beginning)
-      (cond
-       ((eq method 'bounds)
-        (list (cons (region-beginning) (region-end))))
-       ((eq method 'delete-only)
-        (delete-region (region-beginning) (region-end)))
-       (t
-        (filter-buffer-substring (region-beginning) (region-end) method))))))
+      (lambda (method)
+        ;; This call either signals an error (if there is no region)
+        ;; or returns a number.
+        (let ((beg (region-beginning)))
+          (cond
+           ((eq method 'bounds)
+            (list (cons beg (region-end))))
+           ((eq method 'delete-only)
+            (delete-region beg (region-end)))
+           (t
+            (filter-buffer-substring beg (region-end) method))))))
 
 (defvar region-insert-function
   (lambda (lines)
@@ -1507,9 +1509,22 @@ the actual saved text might be different from what was 
killed."
            (while (> n 0)
              ;; 'find-composition' will return (FROM TO ....) or nil.
              (setq cmp (find-composition pos))
-             (if cmp
-                 (setq pos (cadr cmp))
-               (setq pos (1+ pos)))
+             (setq pos
+                   (if cmp
+                       (let ((from (car cmp))
+                             (to (cadr cmp)))
+                         (cond
+                          ((= (length cmp) 2) ; static composition
+                           to)
+                          ;; TO can be at POS, in which case we want
+                          ;; to make sure we advance at least by 1
+                          ;; character.
+                          ((<= to pos)
+                           (1+ pos))
+                          (t
+                           (lgstring-glyph-boundary (nth 2 cmp)
+                                                    from (1+ pos)))))
+                     (1+ pos)))
              (setq n (1- n)))
            (delete-char (- pos start) killflag)))
 
@@ -1719,8 +1734,6 @@ from Lisp."
             words (if (= words 1) "" "s")
             chars (if (= chars 1) "" "s"))))
 
-(define-obsolete-function-alias 'count-lines-region 'count-words-region "24.1")
-
 (defun what-line ()
   "Print the current buffer line number and narrowed line number of point."
   (interactive)
@@ -1907,17 +1920,19 @@ in *Help* buffer.  See also the command 
`describe-char'."
                   bidi-fixer encoding-msg pos total percent col hscroll))))))
 
 ;; Initialize read-expression-map.  It is defined at C level.
-(defvar read-expression-map
-  (let ((m (make-sparse-keymap)))
-    (define-key m "\M-\t" 'completion-at-point)
-    ;; Might as well bind TAB to completion, since inserting a TAB char is
-    ;; much too rarely useful.
-    (define-key m "\t" 'completion-at-point)
-    (define-key m "\r" 'read--expression-try-read)
-    (define-key m "\n" 'read--expression-try-read)
-    (define-key m "\M-g\M-c" 'read-expression-switch-to-completions)
-    (set-keymap-parent m minibuffer-local-map)
-    m))
+(defvar-keymap read-expression-map
+  :parent minibuffer-local-map
+  "C-M-i" #'completion-at-point
+  ;; Might as well bind TAB to completion, since inserting a TAB char is
+  ;; much too rarely useful.
+  "TAB" #'completion-at-point
+  "M-g M-c" #'read-expression-switch-to-completions)
+
+(defvar-keymap read--expression-map
+  :doc "Keymap used by `read--expression'."
+  :parent read-expression-map
+  "RET" #'read--expression-try-read
+  "C-j" #'read--expression-try-read)
 
 (defun read-minibuffer (prompt &optional initial-contents)
   "Return a Lisp object read using the minibuffer, unevaluated.
@@ -1938,10 +1953,6 @@ Such arguments are used as in `read-from-minibuffer'.)"
   ;; Used for interactive spec `X'.
   (eval (read--expression prompt initial-contents)))
 
-(defvar minibuffer-completing-symbol nil
-  "Non-nil means completing a Lisp symbol in the minibuffer.")
-(make-obsolete-variable 'minibuffer-completing-symbol nil "24.1" 'get)
-
 (defvar minibuffer-default nil
   "The current default value or list of default values in the minibuffer.
 The functions `read-from-minibuffer' and `completing-read' bind
@@ -2002,20 +2013,19 @@ display the result of expression evaluation."
 
 PROMPT and optional argument INITIAL-CONTENTS do the same as in
 function `read-from-minibuffer'."
-  (let ((minibuffer-completing-symbol t))
-    (minibuffer-with-setup-hook
-        (lambda ()
-          ;; FIXME: instead of just applying the syntax table, maybe
-          ;; use a special major mode tailored to reading Lisp
-          ;; expressions from the minibuffer? (`emacs-lisp-mode'
-          ;; doesn't preserve the necessary keybindings.)
-          (set-syntax-table emacs-lisp-mode-syntax-table)
-          (add-hook 'completion-at-point-functions
-                    #'elisp-completion-at-point nil t)
-          (run-hooks 'eval-expression-minibuffer-setup-hook))
-      (read-from-minibuffer prompt initial-contents
-                            read-expression-map t
-                            'read-expression-history))))
+  (minibuffer-with-setup-hook
+      (lambda ()
+        ;; FIXME: instead of just applying the syntax table, maybe
+        ;; use a special major mode tailored to reading Lisp
+        ;; expressions from the minibuffer? (`emacs-lisp-mode'
+        ;; doesn't preserve the necessary keybindings.)
+        (set-syntax-table emacs-lisp-mode-syntax-table)
+        (add-hook 'completion-at-point-functions
+                  #'elisp-completion-at-point nil t)
+        (run-hooks 'eval-expression-minibuffer-setup-hook))
+    (read-from-minibuffer prompt initial-contents
+                          read--expression-map t
+                          'read-expression-history)))
 
 (defun read--expression-try-read ()
   "Try to read an Emacs Lisp expression in the minibuffer.
@@ -2198,7 +2208,7 @@ to get different commands to edit and resubmit."
 If it's nil, include all the commands.
 If it's a function, it will be called with two parameters: the
 symbol of the command and a buffer.  The predicate should return
-non-nil if the command should be present when doing `M-x TAB'
+non-nil if the command should be present when doing \\`M-x TAB'
 in that buffer."
   :version "28.1"
   :group 'completion
@@ -2207,9 +2217,64 @@ in that buffer."
                         command-completion-default-include-p)
                  (function :tag "Other function")))
 
-(defun read-extended-command ()
-  "Read command name to invoke in `execute-extended-command'.
-This function uses the `read-extended-command-predicate' user option."
+(defun execute-extended-command-cycle ()
+  "Choose the next version of the extended command predicates.
+See `extended-command-versions'."
+  (interactive)
+  (throw 'cycle
+         (cons (minibuffer-contents)
+               (- (point) (minibuffer-prompt-end)))))
+
+(defvar extended-command-versions
+  (list (list "M-x " (lambda () read-extended-command-predicate))
+        (list "M-X " #'command-completion--command-for-this-buffer-function))
+  "Alist of prompts and what the extended command predicate should be.
+This is used by the 
\\<minibuffer-local-must-match-map>\\[execute-extended-command-cycle] command 
when reading an extended command.")
+
+(defvar-keymap read-extended-command-mode-map
+  :doc "Local keymap added to the current map when reading an extended 
command."
+  "M-X" #'execute-extended-command-cycle)
+
+(define-minor-mode read-extended-command-mode
+  "Minor mode used for completion in `read-extended-command'.")
+
+(defun read-extended-command (&optional prompt)
+  "Read command name to invoke via `execute-extended-command'.
+Use `read-extended-command-predicate' to determine which commands
+to include among completion candidates.
+
+This function activates the `read-extended-command-mode' minor
+mode when reading the command name."
+  (let ((default-predicate read-extended-command-predicate)
+        (read-extended-command-predicate read-extended-command-predicate)
+        already-typed ret)
+    ;; If we have a prompt (which is the name of the version of the
+    ;; command), then set up the predicate from
+    ;; `extended-command-versions'.
+    (if (not prompt)
+        (setq prompt (caar extended-command-versions))
+      (setq read-extended-command-predicate
+            (funcall (cadr (assoc prompt extended-command-versions)))))
+    ;; Normally this will only execute once.
+    (while (not (stringp ret))
+      (when (consp (setq ret (catch 'cycle
+                               (read-extended-command-1 prompt
+                                                        already-typed))))
+        ;; But if the user hit `M-X', then we `throw'ed out to that
+        ;; `catch', and we cycle to the next setting.
+        (let ((next (or (cadr (memq (assoc prompt extended-command-versions)
+                                    extended-command-versions))
+                        ;; Last one; cycle back to the first.
+                        (car extended-command-versions))))
+          ;; Restore the user's default predicate.
+          (setq read-extended-command-predicate default-predicate)
+          ;; Then calculate the next.
+          (setq prompt (car next)
+                read-extended-command-predicate (funcall (cadr next))
+                already-typed ret))))
+    ret))
+
+(defun read-extended-command-1 (prompt initial-input)
   (let ((buffer (current-buffer)))
     (minibuffer-with-setup-hook
         (lambda ()
@@ -2218,6 +2283,8 @@ This function uses the `read-extended-command-predicate' 
user option."
                       (setq execute-extended-command--last-typed
                             (minibuffer-contents)))
                     nil 'local)
+          ;; This is so that we define the `M-X' toggling command.
+          (read-extended-command-mode)
           (setq-local minibuffer-default-add-function
                      (lambda ()
                        ;; Get a command name at point in the original buffer
@@ -2234,8 +2301,8 @@ This function uses the `read-extended-command-predicate' 
user option."
                              (cons def (delete def all))
                            all)))))
       ;; Read a string, completing from and restricting to the set of
-      ;; all defined commands.  Don't provide any initial input.
-      ;; Save the command read on the extended-command history list.
+      ;; all defined commands.  Save the command read on the
+      ;; extended-command history list.
       (completing-read
        (concat (cond
                ((eq current-prefix-arg '-) "- ")
@@ -2253,9 +2320,7 @@ This function uses the `read-extended-command-predicate' 
user option."
               ;; but actually a prompt other than "M-x" would be confusing,
               ;; because "M-x" is a well-known prompt to read a command
               ;; and it serves as a shorthand for "Extended command: ".
-               (if (memq 'shift (event-modifiers last-command-event))
-                  "M-X "
-                "M-x "))
+               (or prompt "M-x "))
        (lambda (string pred action)
          (if (and suggest-key-bindings (eq action 'metadata))
             '(metadata
@@ -2294,12 +2359,12 @@ This function uses the 
`read-extended-command-predicate' user option."
                          (funcall read-extended-command-predicate sym buffer)
                        (error (message "read-extended-command-predicate: %s: 
%s"
                                        sym (error-message-string err))))))))
-       t nil 'extended-command-history))))
+       t initial-input 'extended-command-history))))
 
 (defun command-completion-using-modes-p (symbol buffer)
   "Say whether SYMBOL has been marked as a mode-specific command in BUFFER."
   ;; Check the modes.
-  (let ((modes (command-modes symbol)))
+  (when-let ((modes (command-modes symbol)))
     ;; Common fast case: Just a single mode.
     (if (null (cdr modes))
         (or (provided-mode-derived-p
@@ -2525,27 +2590,37 @@ minor modes), as well as commands bound in the active 
local key
 maps."
   (declare (interactive-only command-execute))
   (interactive
-   (let* ((execute-extended-command--last-typed nil)
-          (keymaps
-           ;; The major mode's keymap and any active minor modes.
-           (nconc
-            (and (current-local-map) (list (current-local-map)))
-            (mapcar
-             #'cdr
-             (seq-filter
-              (lambda (elem)
-                (symbol-value (car elem)))
-              minor-mode-map-alist))))
-          (read-extended-command-predicate
-           (lambda (symbol buffer)
-             (or (command-completion-using-modes-p symbol buffer)
-                 (where-is-internal symbol keymaps)))))
+   (let ((execute-extended-command--last-typed nil))
      (list current-prefix-arg
-           (read-extended-command)
+           (read-extended-command "M-X ")
            execute-extended-command--last-typed)))
   (with-suppressed-warnings ((interactive-only execute-extended-command))
     (execute-extended-command prefixarg command-name typed)))
 
+(defun command-completion--command-for-this-buffer-function ()
+  (let ((keymaps
+         ;; The major mode's keymap and any active minor modes.
+         (nconc
+          (and (current-local-map) (list (current-local-map)))
+          (mapcar
+           #'cdr
+           (seq-filter
+            (lambda (elem)
+              (symbol-value (car elem)))
+            minor-mode-map-alist)))))
+    (lambda (symbol buffer)
+      (or (command-completion-using-modes-p symbol buffer)
+          ;; Include commands that are bound in a keymap in the
+          ;; current buffer.
+          (and (where-is-internal symbol keymaps)
+               ;; But not if they have a command predicate that
+               ;; says that they shouldn't.  (This is the case
+               ;; for `ignore' and `undefined' and similar
+               ;; commands commonly found in keymaps.)
+               (or (null (get symbol 'completion-predicate))
+                   (funcall (get symbol 'completion-predicate)
+                            symbol buffer)))))))
+
 (cl-defgeneric function-documentation (function)
   "Extract the raw docstring info from FUNCTION.
 FUNCTION is expected to be a function value rather than, say, a mere symbol.
@@ -2641,12 +2716,15 @@ don't clear it."
          (t
           ;; Pass `cmd' rather than `final', for the backtrace's sake.
           (prog1 (call-interactively cmd record-flag keys)
-            (when (and (symbolp cmd)
-                       (get cmd 'byte-obsolete-info)
-                       (not (get cmd 'command-execute-obsolete-warned)))
+            (when-let ((info
+                        (and (symbolp cmd)
+                             (not (get cmd 'command-execute-obsolete-warned))
+                             (get cmd 'byte-obsolete-info))))
               (put cmd 'command-execute-obsolete-warned t)
               (message "%s" (macroexp--obsolete-warning
-                             cmd (get cmd 'byte-obsolete-info) 
"command"))))))))))
+                             cmd info "command"
+                             (help--key-description-fontified
+                              (where-is-internal (car info) nil t))))))))))))
 
 (defun command-execute--query (command)
   "Query the user whether to run COMMAND."
@@ -3460,12 +3538,19 @@ Return what remains of the list."
            ;; If this records an obsolete save
            ;; (not matching the actual disk file)
            ;; then don't mark unmodified.
-           (when (or (equal time (visited-file-modtime))
-                     (and (consp time)
-                          (equal (list (car time) (cdr time))
-                                 (visited-file-modtime))))
-             (unlock-buffer)
-             (set-buffer-modified-p nil)))
+           (let ((visited-file-time (visited-file-modtime)))
+             ;; Indirect buffers don't have a visited file, so their
+             ;; file-modtime can be bogus.  In that case, use the
+             ;; modtime of the base buffer instead.
+             (if (and (numberp visited-file-time)
+                      (= visited-file-time 0)
+                      (buffer-base-buffer))
+                 (setq visited-file-time
+                      (with-current-buffer (buffer-base-buffer)
+                        (visited-file-modtime))))
+            (when (time-equal-p time visited-file-time)
+               (unlock-buffer)
+               (set-buffer-modified-p nil))))
           ;; Element (nil PROP VAL BEG . END) is property change.
           (`(nil . ,(or `(,prop ,val ,beg . ,end) pcase--dontcare))
            (when (or (> (point-min) beg) (< (point-max) end))
@@ -5284,17 +5369,6 @@ that `filter-buffer-substring' received.  It should 
return the
 buffer substring between BEG and END, after filtering.  If DELETE is
 non-nil, it should delete the text between BEG and END from the buffer.")
 
-(defvar buffer-substring-filters nil
-  "List of filter functions for `buffer-substring--filter'.
-Each function must accept a single argument, a string, and return a string.
-The buffer substring is passed to the first function in the list,
-and the return value of each function is passed to the next.
-As a special convention, point is set to the start of the buffer text
-being operated on (i.e., the first argument of `buffer-substring--filter')
-before these functions are called.")
-(make-obsolete-variable 'buffer-substring-filters
-                        'filter-buffer-substring-function "24.1")
-
 (defun filter-buffer-substring (beg end &optional delete)
   "Return the buffer substring between BEG and END, after filtering.
 If DELETE is non-nil, delete the text between BEG and END from the buffer.
@@ -5315,20 +5389,15 @@ that are special to a buffer, and should not be copied 
into other buffers."
   "Default function to use for `filter-buffer-substring-function'.
 Its arguments and return value are as specified for `filter-buffer-substring'.
 Also respects the obsolete wrapper hook `filter-buffer-substring-functions'
-\(see `with-wrapper-hook' for details about wrapper hooks),
-and the abnormal hook `buffer-substring-filters'.
+(see `with-wrapper-hook' for details about wrapper hooks).
 No filtering is done unless a hook says to."
   (subr--with-wrapper-hook-no-warnings
     filter-buffer-substring-functions (beg end delete)
     (cond
-     ((or delete buffer-substring-filters)
+     (delete
       (save-excursion
         (goto-char beg)
-        (let ((string (if delete (delete-and-extract-region beg end)
-                        (buffer-substring beg end))))
-          (dolist (filter buffer-substring-filters)
-            (setq string (funcall filter string)))
-          string)))
+        (delete-and-extract-region beg end)))
      (t
       (buffer-substring beg end)))))
 
@@ -5391,7 +5460,7 @@ ring directly.")
 
 (defcustom kill-ring-max 120
   "Maximum length of kill ring before oldest elements are thrown away."
-  :type 'integer
+  :type 'natnum
   :group 'killing
   :version "29.1")
 
@@ -6667,7 +6736,8 @@ If Transient Mark mode is disabled, this function 
normally does
 nothing; but if FORCE is non-nil, it deactivates the mark anyway.
 
 Deactivating the mark sets `mark-active' to nil, updates the
-primary selection according to `select-active-regions', and runs
+primary selection according to `select-active-regions' (unless
+`deactivate-mark' is `dont-save'), and runs
 `deactivate-mark-hook'.
 
 If Transient Mark mode was temporarily enabled, reset the value
@@ -6678,6 +6748,7 @@ run `deactivate-mark-hook'."
     (when (and (if (eq select-active-regions 'only)
                   (eq (car-safe transient-mark-mode) 'only)
                 select-active-regions)
+               (not (eq deactivate-mark 'dont-save))
               (region-active-p)
               (display-selections-p))
       ;; The var `saved-region-selection', if non-nil, is the text in
@@ -6799,6 +6870,14 @@ point otherwise."
   :version "23.1"
   :group 'editing-basics)
 
+(defun use-region-beginning ()
+  "Return the start of the region if `use-region-p'."
+  (and (use-region-p) (region-beginning)))
+
+(defun use-region-end ()
+  "Return the end of the region if `use-region-p'."
+  (and (use-region-p) (region-end)))
+
 (defun use-region-p ()
   "Return t if the region is active and it is appropriate to act on it.
 This is used by commands that act specially on the region under
@@ -6809,7 +6888,11 @@ mark is active; furthermore, if 
`use-empty-active-region' is nil,
 the region must not be empty.  Otherwise, the return value is nil.
 
 For some commands, it may be appropriate to ignore the value of
-`use-empty-active-region'; in that case, use `region-active-p'."
+`use-empty-active-region'; in that case, use `region-active-p'.
+
+Also see the convenience functions `use-region-beginning' and
+`use-region-end', which may be handy when writing `interactive'
+specs."
   (and (region-active-p)
        (or use-empty-active-region (> (region-end) (region-beginning)))
        t))
@@ -6961,7 +7044,7 @@ is set to the buffer displayed in that window.")
 
 (defcustom mark-ring-max 16
   "Maximum size of mark ring.  Start discarding off end if gets this big."
-  :type 'integer
+  :type 'natnum
   :group 'editing-basics)
 
 (defvar global-mark-ring nil
@@ -6970,7 +7053,7 @@ is set to the buffer displayed in that window.")
 (defcustom global-mark-ring-max 16
   "Maximum size of global mark ring.  \
 Start discarding off end if gets this big."
-  :type 'integer
+  :type 'natnum
   :group 'editing-basics)
 
 (defun pop-to-mark-command ()
@@ -7216,7 +7299,7 @@ or \"mark.*active\" at the prompt."
 
 (define-minor-mode indent-tabs-mode
   "Toggle whether indentation can insert TAB characters."
-  :global t :group 'indent :variable indent-tabs-mode)
+  :group 'indent)
 
 (defvar widen-automatically t
   "Non-nil means it is ok for commands to call `widen' when they want to.
@@ -7614,11 +7697,23 @@ not vscroll."
                 ;; But don't vscroll in a keyboard macro.
                 (not defining-kbd-macro)
                 (not executing-kbd-macro)
+                 ;; Lines are not truncated...
+                 (not
+                  (and
+                   (or truncate-lines (truncated-partial-width-window-p))
+                   ;; ...or if lines are truncated, this buffer
+                   ;; doesn't have very long lines.
+                   (long-line-optimizations-p)))
                 (line-move-partial arg noerror))
       (set-window-vscroll nil 0 t)
       (if (and line-move-visual
               ;; Display-based column are incompatible with goal-column.
               (not goal-column)
+               ;; Lines aren't truncated.
+               (not
+                (and
+                 (or truncate-lines (truncated-partial-width-window-p))
+                 (long-line-optimizations-p)))
               ;; When the text in the window is scrolled to the left,
               ;; display-based motion doesn't make sense (because each
               ;; logical line occupies exactly one screen line).
@@ -7878,7 +7973,7 @@ If NOERROR, don't signal an error if we can't move that 
many lines."
 
        ;; Move to the desired column.
         (if (and line-move-visual
-                 (not (or truncate-lines truncate-partial-width-windows)))
+                 (not (or truncate-lines (truncated-partial-width-window-p))))
             ;; Under line-move-visual, goal-column should be
             ;; interpreted in units of the frame's canonical character
             ;; width, which is exactly what vertical-motion does.
@@ -8055,10 +8150,11 @@ For motion by visual lines, see 
`beginning-of-visual-line'."
          (line-move (1- arg) t)))
 
     ;; Move to beginning-of-line, ignoring fields and invisible text.
-    (skip-chars-backward "^\n")
-    (while (and (not (bobp)) (invisible-p (1- (point))))
-      (goto-char (previous-char-property-change (point)))
-      (skip-chars-backward "^\n"))
+    (let ((inhibit-field-text-motion t))
+      (goto-char (line-beginning-position))
+      (while (and (not (bobp)) (invisible-p (1- (point))))
+        (goto-char (previous-char-property-change (point)))
+        (goto-char (line-beginning-position))))
 
     ;; Now find first visible char in the line.
     (while (and (< (point) orig) (invisible-p (point)))
@@ -8544,10 +8640,10 @@ constitute a word."
 (defcustom fill-prefix nil
   "String for filling to insert at front of new line, or nil for none."
   :type '(choice (const :tag "None" nil)
-                string)
+                 string)
+  :safe #'string-or-null-p
   :group 'fill)
 (make-variable-buffer-local 'fill-prefix)
-(put 'fill-prefix 'safe-local-variable 'string-or-null-p)
 
 (defcustom auto-fill-inhibit-regexp nil
   "Regexp to match lines that should not be auto-filled."
@@ -8872,7 +8968,19 @@ presented."
   :global t :group 'mode-line)
 
 (define-minor-mode auto-save-mode
-  "Toggle auto-saving in the current buffer (Auto Save mode)."
+  "Toggle auto-saving in the current buffer (Auto Save mode).
+
+When this mode is enabled, Emacs periodically saves each file-visiting
+buffer in a separate \"auto-save file\".  This is a safety measure to
+prevent you from losing more than a limited amount of work if the
+system crashes.
+
+Auto-saving does not alter the file visited by the buffer: the visited
+file is changed only when you request saving it explicitly (such as
+with \\[save-buffer]).  If you want to save the buffer into its
+visited files automatically, use \\[auto-save-visited-mode]).
+
+For more details, see Info node `(emacs) Auto Save'."
   :variable ((and buffer-auto-save-file-name
                   ;; If auto-save is off because buffer has shrunk,
                   ;; then toggling should turn it on.
@@ -10282,8 +10390,15 @@ command works by setting the variable 
`buffer-read-only', which
 does not affect read-only regions caused by text properties.  To
 ignore read-only status in a Lisp program (whether due to text
 properties or buffer state), bind `inhibit-read-only' temporarily
-to a non-nil value."
+to a non-nil value.
+
+Reverting a buffer will keep the read-only status set by using
+this command."
   :variable buffer-read-only
+  ;; We're saving this value here so that we can restore the
+  ;; readedness state after reverting the buffer to the value that's
+  ;; been explicitly set by the user.
+  (setq-local read-only-mode--state buffer-read-only)
   (cond
    ((and (not buffer-read-only) view-mode)
     (View-exit-and-edit)
@@ -10551,6 +10666,49 @@ If the buffer doesn't exist, create it first."
   (interactive)
   (pop-to-buffer-same-window (get-scratch-buffer-create)))
 
+(defun kill-buffer--possibly-save (buffer)
+  (let ((response
+         (cadr
+          (read-multiple-choice
+           (format "Buffer %s modified; kill anyway?"
+                   (buffer-name))
+           '((?y "yes" "kill buffer without saving")
+             (?n "no" "exit without doing anything")
+             (?s "save and then kill" "save the buffer and then kill it"))
+           nil nil (not use-short-answers)))))
+    (if (equal response "no")
+        nil
+      (unless (equal response "yes")
+        (with-current-buffer buffer
+          (save-buffer)))
+      t)))
+
+(defsubst string-empty-p (string)
+  "Check whether STRING is empty."
+  (string= string ""))
+
+(defun read-signal-name ()
+  "Read a signal number or name."
+  (let ((value
+         (completing-read "Signal code or name: "
+                          (signal-names)
+                          nil
+                          (lambda (value)
+                            (or (string-match "\\`[0-9]+\\'" value)
+                                (member value (signal-names)))))))
+    (if (string-match "\\`[0-9]+\\'" value)
+        (string-to-number value)
+      (intern (concat "sig" (downcase value))))))
+
+(defun lax-plist-get (plist prop)
+  "Extract a value from a property list, comparing with `equal'."
+  (declare (obsolete plist-get "29.1"))
+  (plist-get plist prop #'equal))
+
+(defun lax-plist-put (plist prop val)
+  "Change value in PLIST of PROP to VAL, comparing with `equal'."
+  (declare (obsolete plist-put "29.1"))
+  (plist-put plist prop val #'equal))
 
 
 (provide 'simple)
diff --git a/lisp/so-long.el b/lisp/so-long.el
index a2b4282ad6..75201fefca 100644
--- a/lisp/so-long.el
+++ b/lisp/so-long.el
@@ -38,7 +38,7 @@
 ;; compacted into the smallest file size possible, which often entails removing
 ;; newlines should they not be strictly necessary).  This can result in lines
 ;; which are many thousands of characters long, and most programming modes
-;; simply aren't optimised (remotely) for this scenario, so performance can
+;; simply aren't optimized (remotely) for this scenario, so performance can
 ;; suffer significantly.
 ;;
 ;; When so-long detects such a file, it calls the command `so-long', which
@@ -90,7 +90,7 @@
 ;; * Overview of modes and commands
 ;; --------------------------------
 ;; - `global-so-long-mode' - A global minor mode which enables the automated
-;;    behaviour, causing the user's preferred action to be invoked whenever a
+;;    behavior, causing the user's preferred action to be invoked whenever a
 ;;    newly-visited file contains excessively long lines.
 ;; - `so-long-mode' - A major mode, and the default action.
 ;; - `so-long-minor-mode' - A minor mode version of the major mode, and an
@@ -111,7 +111,7 @@
 ;;
 ;; On rare occasions you may choose to manually invoke the `so-long' command,
 ;; which invokes your preferred `so-long-action' (exactly as the automatic
-;; behaviour would do if it had detected long lines).  You might use this if a
+;; behavior would do if it had detected long lines).  You might use this if a
 ;; problematic file did not meet your configured criteria, and you wished to
 ;; trigger the performance improvements manually.
 ;;
@@ -120,7 +120,7 @@
 ;; available to `so-long' but, like any other mode, they can be invoked 
directly
 ;; if you have a need to do that (see also "Other ways of using so-long" 
below).
 ;;
-;; If the behaviour ever triggers when you did not want it to, you can use the
+;; If the behavior ever triggers when you did not want it to, you can use the
 ;; `so-long-revert' command to restore the buffer to its original state.
 
 ;; * Basic configuration
@@ -199,7 +199,7 @@
 ;;
 ;; Note that `so-long-minor-modes' is not useful for other global minor modes
 ;; (as distinguished from globalized minor modes), but in some cases it will be
-;; possible to inhibit or otherwise counter-act the behaviour of a global mode
+;; possible to inhibit or otherwise counter-act the behavior of a global mode
 ;; by overriding variables, or by employing hooks (see below).  You would need
 ;; to inspect the code for a given global mode (on a case by case basis) to
 ;; determine whether it's possible to inhibit it for a single buffer -- and if
@@ -211,7 +211,7 @@
 ;; If `so-long-action' is set to either `so-long-mode' or `so-long-minor-mode',
 ;; the buffer-local value for each variable in the list is set to the 
associated
 ;; value in the alist.  Use this to enforce values which will improve
-;; performance or otherwise avoid undesirable behaviours.  If `so-long-revert'
+;; performance or otherwise avoid undesirable behaviors.  If `so-long-revert'
 ;; is called, then the original values are restored.
 
 ;; * Retaining minor modes and settings when switching to `so-long-mode'
@@ -273,7 +273,7 @@
 ;; `so-long-mode', completely bypassing the automated decision process.
 ;; Refer to M-: (info "(emacs) Specifying File Variables") RET
 ;;
-;; If so-long itself causes problems, disable the automated behaviour with
+;; If so-long itself causes problems, disable the automated behavior with
 ;; M-- M-x global-so-long-mode, or M-: (global-so-long-mode 0)
 
 ;; * Example configuration
@@ -313,7 +313,7 @@
 ;;   (add-hook 'js-mode-hook 'my-js-mode-hook)
 ;;
 ;;   (defun my-js-mode-hook ()
-;;     "Custom `js-mode' behaviours."
+;;     "Custom `js-mode' behaviors."
 ;;     (setq-local so-long-max-lines 100)
 ;;     (setq-local so-long-threshold 1000))
 ;;
@@ -327,7 +327,7 @@
 ;;   (add-hook 'nxml-mode-hook 'my-nxml-mode-hook)
 ;;
 ;;   (defun my-nxml-mode-hook ()
-;;     "Custom `nxml-mode' behaviours."
+;;     "Custom `nxml-mode' behaviors."
 ;;     (require 'so-long)
 ;;     (setq-local so-long-variable-overrides
 ;;                 (remove '(bidi-inhibit-bpa . t) 
so-long-variable-overrides)))
@@ -380,7 +380,7 @@
 ;; meaning you would need to add to `safe-local-variable-values' in order to
 ;; avoid being queried about them.
 ;;
-;; Finally, the `so-long-predicate' user option enables the automated behaviour
+;; Finally, the `so-long-predicate' user option enables the automated behavior
 ;; to be determined by a custom function, if greater control is needed.
 
 ;; * Implementation notes
@@ -397,7 +397,7 @@
 
 ;; * Caveats
 ;; ---------
-;; The variables affecting the automated behaviour of this library (such as
+;; The variables affecting the automated behavior of this library (such as
 ;; `so-long-action') can be used as file- or dir-local values in Emacs 26+, but
 ;; not in previous versions of Emacs.  This is on account of improvements made
 ;; to `normal-mode' in 26.1, which altered the execution order with respect to
@@ -412,7 +412,7 @@
 ;;
 ;; 1.1.2 - Use `so-long-mode-line-active' face on `mode-name' in 
`so-long-mode'.
 ;; 1.1.1 - Identical to 1.1, but fixing an incorrect GNU ELPA release.
-;; 1.1   - Utilise `buffer-line-statistics' in Emacs 28+, with the new
+;; 1.1   - Utilize `buffer-line-statistics' in Emacs 28+, with the new
 ;;         `so-long-predicate' function `so-long-statistics-excessive-p'.
 ;;       - Increase `so-long-threshold' from 250 to 10,000.
 ;;       - Increase `so-long-max-lines' from 5 to 500.
@@ -449,7 +449,7 @@
 ;;       - Added sgml-mode and nxml-mode to `so-long-target-modes'.
 ;; 0.7.4 - Refactored the handling of `whitespace-mode'.
 ;; 0.7.3 - Added customization group `so-long' with user options.
-;;       - Added `so-long-original-values' to generalise the storage and
+;;       - Added `so-long-original-values' to generalize the storage and
 ;;         restoration of values from the original mode upon `so-long-revert'.
 ;;       - Added `so-long-revert-hook'.
 ;; 0.7.2 - Remember the original major mode even with M-x `so-long-mode'.
@@ -462,7 +462,7 @@
 ;; 0.6   - Added `so-long-minor-modes' and `so-long-hook'.
 ;; 0.5   - Renamed library to "so-long.el".
 ;;       - Added explicit `so-long-enable' command to activate our advice.
-;; 0.4   - Amended/documented behaviour with file-local 'mode' variables.
+;; 0.4   - Amended/documented behavior with file-local 'mode' variables.
 ;; 0.3   - Defer to a file-local 'mode' variable.
 ;; 0.2   - Initial release to EmacsWiki.
 ;; 0.1   - Experimental.
@@ -490,7 +490,7 @@
   ;; automatically."; however `so-long--ensure-enabled' may forcibly re-enable
   ;; it contrary to the user's expectations, so for the present this should be
   ;; considered internal-use only (with `global-so-long-mode' the interface
-  ;; for enabling or disabling the automated behaviour).  FIXME: Establish a
+  ;; for enabling or disabling the automated behavior).  FIXME: Establish a
   ;; way to support the original use-case, or rename to `so-long--enabled'.
   "Internal use.  Non-nil when any `so-long' functionality has been used.")
 
@@ -586,7 +586,7 @@ files would prevent Emacs from handling them correctly."
 (defcustom so-long-invisible-buffer-function #'so-long-deferred
   "Function called in place of `so-long' when the buffer is not displayed.
 
-This affects the behaviour of `global-so-long-mode'.
+This affects the behavior of `global-so-long-mode'.
 
 We treat invisible buffers differently from displayed buffers because, in
 cases where a library is using a buffer for behind-the-scenes processing,
@@ -618,7 +618,7 @@ the mentioned options might interfere with some intended 
processing."
                                'so-long-detected-long-line-p)
   "Function called after `set-auto-mode' to decide whether action is needed.
 
-This affects the behaviour of `global-so-long-mode'.
+This affects the behavior of `global-so-long-mode'.
 
 Only called if the major mode is a member of `so-long-target-modes'.
 
@@ -642,7 +642,7 @@ Note that `so-long-statistics-excessive-p' requires Emacs 
28.1 or later."
 (defun so-long--action-type ()
   "Generate a :type for `so-long-action' based on `so-long-action-alist'."
   ;; :type seemingly cannot be a form to be evaluated on demand, so we
-  ;; endeavour to keep it up-to-date with `so-long-action-alist' by
+  ;; endeavor to keep it up-to-date with `so-long-action-alist' by
   ;; calling this from `so-long--action-alist-setter'.
   `(radio ,@(mapcar (lambda (x) (list 'const :tag (cadr x) (car x)))
                     (assq-delete-all nil so-long-action-alist))
@@ -684,8 +684,8 @@ subsequently called."
                                   (function :tag "Action")
                                   (function :tag "Revert")))
   :set #'so-long--action-alist-setter
+  :risky t
   :package-version '(so-long . "1.0"))
-(put 'so-long-action-alist 'risky-local-variable t)
 
 (defcustom so-long-action 'so-long-mode
   "The action taken by `so-long' when long lines are detected.
@@ -703,7 +703,7 @@ will be automatically processed; but custom actions can 
also do these things.
 The value `longlines-mode' causes that minor mode to be enabled.  See
 longlines.el for more details.
 
-Each action likewise determines the behaviour of `so-long-revert'.
+Each action likewise determines the behavior of `so-long-revert'.
 
 If the value is nil, or not defined in `so-long-action-alist', then no action
 will be taken."
@@ -753,7 +753,7 @@ If ACTION-ARG is provided, it is used in place of 
`so-long-action'."
 (defcustom so-long-file-local-mode-function 'so-long-mode-downgrade
   "Function to call during `set-auto-mode' when a file-local mode is set.
 
-This affects the behaviour of `global-so-long-mode'.
+This affects the behavior of `global-so-long-mode'.
 
 The specified function will be called with a single argument, being the
 file-local mode which was established.
@@ -855,7 +855,7 @@ By default this happens if `so-long-action' is set to 
either `so-long-mode'
 or `so-long-minor-mode'.  If `so-long-revert' is subsequently invoked, then the
 disabled modes are re-enabled by calling them with the numeric argument 1.
 
-`so-long-hook' can be used where more custom behaviour is desired.
+`so-long-hook' can be used where more custom behavior is desired.
 
 Please submit bug reports to recommend additional modes for this list, whether
 they are in Emacs core, GNU ELPA, or elsewhere."
@@ -1312,7 +1312,7 @@ This minor mode is a standard `so-long-action' option."
   (if so-long-minor-mode ;; We are enabling the mode.
       (progn
         ;; Housekeeping.  `so-long-minor-mode' might be invoked directly rather
-        ;; than via `so-long', so replicate the necessary behaviours.  The 
minor
+        ;; than via `so-long', so replicate the necessary behaviors.  The minor
         ;; mode also cares about whether `so-long' was already active, as we do
         ;; not want to remember values which were (potentially) overridden
         ;; already.
@@ -1387,9 +1387,9 @@ values), despite potential performance issues, type 
\\[so-long-revert].
 Use \\[so-long-commentary] for more information.
 
 Use \\[so-long-customize] to open the customization group `so-long' to
-configure the behaviour."
+configure the behavior."
   ;; Housekeeping.  `so-long-mode' might be invoked directly rather than via
-  ;; `so-long', so replicate the necessary behaviours.  We could use this same
+  ;; `so-long', so replicate the necessary behaviors.  We could use this same
   ;; test in `so-long-after-change-major-mode' to run `so-long-hook', but 
that's
   ;; not so obviously the right thing to do, so I've omitted it for now.
   (unless so-long--calling
@@ -1435,7 +1435,7 @@ configure the behaviour."
 This advice acts before `so-long-mode', with the previous mode still active."
   (unless (derived-mode-p 'so-long-mode)
     ;; Housekeeping.  `so-long-mode' might be invoked directly rather than
-    ;; via `so-long', so replicate the necessary behaviours.
+    ;; via `so-long', so replicate the necessary behaviors.
     (unless so-long--calling
       (so-long-remember-all :reset))
     ;; Remember the original major mode, regardless.
@@ -1549,7 +1549,7 @@ This is the `so-long-revert-function' for `so-long-mode'."
     ;; Emacs 26+ has already called `hack-local-variables' (during
     ;; `run-mode-hooks'; provided there was a `buffer-file-name'), but for 
older
     ;; versions we need to call it here.  In Emacs 26+ the revised 
'HANDLE-MODE'
-    ;; argument is set to `no-mode' (being the non-nil-and-non-t behaviour),
+    ;; argument is set to `no-mode' (being the non-nil-and-non-t behavior),
     ;; which we mimic here by binding `so-long--hack-local-variables-no-mode',
     ;; in order to prevent a local 'mode' variable from clobbering the major
     ;; mode we have just called.
@@ -1590,7 +1590,7 @@ because we do not want to downgrade the major mode in 
that scenario."
     ;; Act only if `so-long-mode' would be enabled by the current action.
     (when (and (symbolp (so-long-function))
                (provided-mode-derived-p (so-long-function) 'so-long-mode))
-      ;; Downgrade from `so-long-mode' to the `so-long-minor-mode' behaviour.
+      ;; Downgrade from `so-long-mode' to the `so-long-minor-mode' behavior.
       (setq so-long-function 'turn-on-so-long-minor-mode
             so-long-revert-function 'turn-off-so-long-minor-mode))))
 
@@ -1610,7 +1610,7 @@ and cannot be conveniently intercepted, so we are forced 
to replicate it here.
 
 This special-case code will ultimately be removed from Emacs, as it exists to
 deal with a deprecated feature; but until then we need to replicate it in order
-to inhibit our own behaviour in the presence of a header comment `mode'
+to inhibit our own behavior in the presence of a header comment `mode'
 declaration.
 
 If a file-local mode is detected in the header comment, then we call the
@@ -1747,7 +1747,7 @@ by testing the value against `major-mode'; but as we may 
have changed the
 major mode to `so-long-mode' by this point, that protection is insufficient
 and so we need to perform our own test.
 
-We likewise need to support an equivalent of the `no-mode' behaviour in 26.1+
+We likewise need to support an equivalent of the `no-mode' behavior in 26.1+
 to ensure that `so-long-mode-revert' will not restore a file-local mode again
 after it has already reverted to the original mode.
 
@@ -1895,7 +1895,7 @@ When such files are detected by `so-long-predicate', we 
invoke the selected
 Use \\[so-long-commentary] for more information.
 
 Use \\[so-long-customize] to open the customization group `so-long' to
-configure the behaviour."
+configure the behavior."
   :global t
   :group 'so-long
   (if global-so-long-mode
diff --git a/lisp/speedbar.el b/lisp/speedbar.el
index b12cf3d9c2..e74d6fd80a 100644
--- a/lisp/speedbar.el
+++ b/lisp/speedbar.el
@@ -703,8 +703,6 @@ If you want to change this while speedbar is active, either 
use
 (defvar speedbar-update-flag-disable nil
   "Permanently disable changing of the update flag.")
 
-(define-obsolete-variable-alias
-  'speedbar-syntax-table 'speedbar-mode-syntax-table "24.1")
 (defvar speedbar-mode-syntax-table
   (let ((st (make-syntax-table)))
     ;; Turn off paren matching around here.
@@ -719,8 +717,6 @@ If you want to change this while speedbar is active, either 
use
     st)
   "Syntax-table used on the speedbar.")
 
-
-(define-obsolete-variable-alias 'speedbar-key-map 'speedbar-mode-map "24.1")
 (defvar speedbar-mode-map
   (let ((map (make-keymap)))
     (suppress-keymap map t)
@@ -934,7 +930,8 @@ supported at a time.
   ;; reset the selection variable
   (setq speedbar-last-selected-file nil)
   (unless (display-graphic-p)
-    (message "Use `M-x speedbar-get-focus' to see the speedbar window")))
+    (message (substitute-command-keys
+              "Use \\[speedbar-get-focus] to see the speedbar window"))))
 
 (defun speedbar-frame-reposition-smartly ()
   "Reposition the speedbar frame to be next to the attached frame."
@@ -2792,15 +2789,7 @@ to add more types of version control systems."
             (not (or (and (featurep 'ange-ftp)
                           (string-match
                            (car (symbol-value 'ange-ftp-name-format))
-                           (expand-file-name default-directory)))
-                     ;; efs support: Bob Weiner
-                     (and (featurep 'efs)
-                          (string-match
-                           (let ((reg (symbol-value 'efs-directory-regexp)))
-                             (if (stringp reg)
-                                 reg
-                               (car reg)))
-                           (expand-file-name default-directory))))))
+                            (expand-file-name default-directory))))))
        (setq speedbar-vc-to-do-point 0))
     (if (numberp speedbar-vc-to-do-point)
        (progn
diff --git a/lisp/sqlite-mode.el b/lisp/sqlite-mode.el
index 66e2e487d9..fb2ceab383 100644
--- a/lisp/sqlite-mode.el
+++ b/lisp/sqlite-mode.el
@@ -24,6 +24,7 @@
 ;;; Code:
 
 (require 'cl-lib)
+(eval-when-compile (require 'subr-x))
 
 (declare-function sqlite-execute "sqlite.c")
 (declare-function sqlite-more-p "sqlite.c")
diff --git a/lisp/startup.el b/lisp/startup.el
index 4b42cd236c..b0fbf7a34c 100644
--- a/lisp/startup.el
+++ b/lisp/startup.el
@@ -800,10 +800,13 @@ It is the default value of the variable `top-level'."
          ;; face-font-rescale-alist into account.  For such
          ;; situations, we ought to have a way to find all font
          ;; objects and regenerate them; currently we do not.  As a
-         ;; workaround, we specifically reset te default face's :font
-         ;; attribute here.  See bug#1785.
-         (unless (eq face-font-rescale-alist
-                     old-face-font-rescale-alist)
+         ;; workaround, we specifically reset the default face's :font
+         ;; attribute here, if it was rescaled.  See bug#1785.
+         (when (and (display-multi-font-p)
+                     (not (eq face-font-rescale-alist
+                             old-face-font-rescale-alist))
+                     (assoc (font-xlfd-name (face-attribute 'default :font))
+                            face-font-rescale-alist #'string-match-p))
            (set-face-attribute 'default nil :font (font-spec)))
 
          ;; Modify the initial frame based on what .emacs puts into
@@ -2796,7 +2799,8 @@ nil default-directory" name)
           ;; `nondisplayed-buffers-p' is true if there exist buffers
           ;; in `displayable-buffers' that were not displayed to the
           ;; user.
-          (nondisplayed-buffers-p nil))
+          (nondisplayed-buffers-p nil)
+          (old-face-font-rescale-alist face-font-rescale-alist))
       (when (> displayable-buffers-len 0)
         (switch-to-buffer (car displayable-buffers)))
       (cond
@@ -2840,6 +2844,15 @@ nil default-directory" name)
         ;; before doing any output.
         (run-hooks 'emacs-startup-hook 'term-setup-hook)
 
+        ;; See the commentary in `normal-top-level' for why we do
+        ;; this.
+       (when (and (display-multi-font-p)
+                   (not (eq face-font-rescale-alist
+                           old-face-font-rescale-alist))
+                   (assoc (font-xlfd-name (face-attribute 'default :font))
+                          face-font-rescale-alist #'string-match-p))
+         (set-face-attribute 'default nil :font (font-spec)))
+
         ;; It's important to notice the user settings before we
         ;; display the startup message; otherwise, the settings
         ;; won't take effect until the user gives the first
diff --git a/lisp/strokes.el b/lisp/strokes.el
index 5402ebf1e1..d7a9539316 100644
--- a/lisp/strokes.el
+++ b/lisp/strokes.el
@@ -252,7 +252,7 @@ WARNING: Changing the value of this variable will gravely 
affect the
          figure out what it should be based on your needs and on how
          quick the particular platform(s) you're operating on, and
          only then start programming in your custom strokes."
-  :type 'integer)
+  :type 'natnum)
 
 (defcustom strokes-file (locate-user-emacs-file "strokes" ".strokes")
   "File containing saved strokes for Strokes mode."
@@ -1031,8 +1031,6 @@ o Strokes are a bit computer-dependent in that they 
depend somewhat on
     (help-mode)
     (help-print-return-message)))
 
-(define-obsolete-function-alias 'strokes-report-bug #'report-emacs-bug "24.1")
-
 (defun strokes-window-configuration-changed-p ()
   "Non-nil if the `strokes-window-configuration' frame properties changed.
 This is based on the last time `strokes-window-configuration' was updated."
diff --git a/lisp/subr.el b/lisp/subr.el
index 50ae357a13..36f5e2fee4 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -524,7 +524,14 @@ was called."
   "Return VALUE with its bits shifted left by COUNT.
 If COUNT is negative, shifting is actually to the right.
 In this case, if VALUE is a negative fixnum treat it as unsigned,
-i.e., subtract 2 * `most-negative-fixnum' from VALUE before shifting it."
+i.e., subtract 2 * `most-negative-fixnum' from VALUE before shifting it.
+
+This function is provided for compatibility.  In new code, use `ash'
+instead."
+  (declare (compiler-macro
+            (lambda (form)
+              (macroexp-warn-and-return "avoid `lsh'; use `ash' instead"
+                                        form '(suspicious lsh) t form))))
   (when (and (< value 0) (< count 0))
     (when (< value most-negative-fixnum)
       (signal 'args-out-of-range (list value count)))
@@ -540,12 +547,12 @@ i.e., subtract 2 * `most-negative-fixnum' from VALUE 
before shifting it."
 ;; you may want to amend the other, too.
 (defun internal--compiler-macro-cXXr (form x)
   (let* ((head (car form))
-         (n (symbol-name (car form)))
+         (n (symbol-name head))
          (i (- (length n) 2)))
     (if (not (string-match "c[ad]+r\\'" n))
         (if (and (fboundp head) (symbolp (symbol-function head)))
-            (internal--compiler-macro-cXXr (cons (symbol-function head) (cdr 
form))
-                                     x)
+            (internal--compiler-macro-cXXr
+             (cons (symbol-function head) (cdr form)) x)
           (error "Compiler macro for cXXr applied to non-cXXr form"))
       (while (> i (match-beginning 0))
         (setq x (list (if (eq (aref n i) ?a) 'car 'cdr) x))
@@ -707,11 +714,14 @@ If N is bigger than the length of LIST, return LIST."
 
 (defun butlast (list &optional n)
   "Return a copy of LIST with the last N elements removed.
-If N is omitted or nil, the last element is removed from the
-copy."
+If N is omitted or nil, return a copy of LIST without its last element.
+If N is zero or negative, return LIST."
   (declare (side-effect-free t))
-  (if (and n (<= n 0)) list
-    (nbutlast (copy-sequence list) n)))
+  (unless n
+    (setq n 1))
+  (if (<= n 0)
+      list
+    (take (- (length list) n) list)))
 
 (defun nbutlast (list &optional n)
   "Modify LIST to remove the last N elements.
@@ -723,11 +733,6 @@ If N is omitted or nil, remove the last element."
           (if (> n 0) (setcdr (nthcdr (- (1- m) n) list) nil))
           list))))
 
-;; The function's definition was moved to fns.c,
-;; but it's easier to set properties here.
-(put 'proper-list-p 'pure t)
-(put 'proper-list-p 'side-effect-free 'error-free)
-
 (defun delete-dups (list)
   "Destructively remove `equal' duplicates from LIST.
 Store the result in LIST and return it.  LIST must be a proper list.
@@ -858,7 +863,7 @@ Non-strings in LIST are ignored."
   (declare (side-effect-free t))
   (while (and list
              (not (and (stringp (car list))
-                       (eq t (compare-strings elt 0 nil (car list) 0 nil t)))))
+                       (string-equal-ignore-case elt (car list)))))
     (setq list (cdr list)))
   list)
 
@@ -964,7 +969,7 @@ side-effects, and the argument LIST is not modified."
 (defun kbd (keys)
   "Convert KEYS to the internal Emacs key representation.
 KEYS should be a string in the format returned by commands such
-as `C-h k' (`describe-key').
+as \\[describe-key] (`describe-key').
 
 This is the same format used for saving keyboard macros (see
 `edmacro-mode').
@@ -1542,21 +1547,21 @@ the `click' modifier."
         ;; sure the symbol has already been parsed.
        (cdr (internal-event-symbol-parse-modifiers type))
       (let ((list nil)
-           (char (logand type (lognot (logior ?\M-\^@ ?\C-\^@ ?\S-\^@
-                                              ?\H-\^@ ?\s-\^@ ?\A-\^@)))))
-       (if (not (zerop (logand type ?\M-\^@)))
+           (char (logand type (lognot (logior ?\M-\0 ?\C-\0 ?\S-\0
+                                              ?\H-\0 ?\s-\0 ?\A-\0)))))
+       (if (not (zerop (logand type ?\M-\0)))
            (push 'meta list))
-       (if (or (not (zerop (logand type ?\C-\^@)))
+       (if (or (not (zerop (logand type ?\C-\0)))
                (< char 32))
            (push 'control list))
-       (if (or (not (zerop (logand type ?\S-\^@)))
+       (if (or (not (zerop (logand type ?\S-\0)))
                (/= char (downcase char)))
            (push 'shift list))
-       (or (zerop (logand type ?\H-\^@))
+       (or (zerop (logand type ?\H-\0))
            (push 'hyper list))
-       (or (zerop (logand type ?\s-\^@))
+       (or (zerop (logand type ?\s-\0))
            (push 'super list))
-       (or (zerop (logand type ?\A-\^@))
+       (or (zerop (logand type ?\A-\0))
            (push 'alt list))
        list))))
 
@@ -1570,7 +1575,7 @@ in the current Emacs session, then this function may 
return nil."
       (setq event (car event)))
   (if (symbolp event)
       (car (get event 'event-symbol-elements))
-    (let* ((base (logand event (1- ?\A-\^@)))
+    (let* ((base (logand event (1- ?\A-\0)))
           (uncontrolled (if (< base 32) (logior base 64) base)))
       ;; There are some numbers that are invalid characters and
       ;; cause `downcase' to get an error.
@@ -1852,15 +1857,11 @@ be a list of the form returned by `event-start' and 
`event-end'."
 (set-advertised-calling-convention 'redirect-frame-focus '(frame focus-frame) 
"24.3")
 (set-advertised-calling-convention 'libxml-parse-xml-region '(start end 
&optional base-url) "27.1")
 (set-advertised-calling-convention 'libxml-parse-html-region '(start end 
&optional base-url) "27.1")
+(set-advertised-calling-convention 'time-convert '(time form) "29.1")
 
 ;;;; Obsolescence declarations for variables, and aliases.
 
-(make-obsolete-variable 'redisplay-end-trigger-functions 'jit-lock-register 
"23.1")
-(make-obsolete-variable 'deferred-action-list 'post-command-hook "24.1")
-(make-obsolete-variable 'deferred-action-function 'post-command-hook "24.1")
 (make-obsolete-variable 'redisplay-dont-pause nil "24.5")
-(make-obsolete 'window-redisplay-end-trigger nil "23.1")
-(make-obsolete 'set-window-redisplay-end-trigger nil "23.1")
 (make-obsolete-variable 'operating-system-release nil "28.1")
 (make-obsolete-variable 'inhibit-changing-match-data 'save-match-data "29.1")
 
@@ -1883,12 +1884,6 @@ be a list of the form returned by `event-start' and 
`event-end'."
 (make-obsolete-variable 'load-dangerous-libraries
                         "no longer used." "27.1")
 
-(defvar inhibit--record-char nil
-  "Obsolete variable.
-This was used internally by quail.el and keyboard.c in Emacs 27.
-It does nothing in Emacs 28.")
-(make-obsolete-variable 'inhibit--record-char nil "28.1")
-
 (define-obsolete-function-alias 'compare-window-configurations
   #'window-configuration-equal-p "29.1")
 
@@ -1916,12 +1911,18 @@ It does nothing in Emacs 28.")
 (defalias 'store-match-data #'set-match-data)
 (defalias 'chmod #'set-file-modes)
 (defalias 'mkdir #'make-directory)
-;; These are the XEmacs names:
-(defalias 'point-at-eol #'line-end-position)
-(defalias 'point-at-bol #'line-beginning-position)
 
-(define-obsolete-function-alias 'user-original-login-name
-  #'user-login-name "28.1")
+;; These were the XEmacs names, now obsolete:
+(define-obsolete-function-alias 'point-at-eol #'line-end-position "29.1")
+(define-obsolete-function-alias 'point-at-bol #'line-beginning-position "29.1")
+(define-obsolete-function-alias 'user-original-login-name #'user-login-name 
"28.1")
+
+;; These are in obsolete/autoload.el, but are commonly used by
+;; third-party scripts that assume that they exist without requiring
+;; autoload.  These should be removed when obsolete/autoload.el is
+;; removed.
+(autoload 'make-directory-autoloads "autoload" nil t)
+(autoload 'update-directory-autoloads "autoload" nil t)
 
 
 ;;;; Hook manipulation functions.
@@ -2706,18 +2707,44 @@ This is to `put' what `defalias' is to `fset'."
         (setcdr ps (cons symbol (cdr ps))))))
   (put symbol prop val))
 
-(defun symbol-file (symbol &optional type)
+(defvar comp-native-version-dir)
+(defvar native-comp-eln-load-path)
+(declare-function subr-native-elisp-p "data.c")
+(declare-function native-comp-unit-file "data.c")
+(declare-function subr-native-comp-unit "data.c")
+(declare-function comp-el-to-eln-rel-filename "comp.c")
+
+(defun locate-eln-file (eln-file)
+  "Locate a natively-compiled ELN-FILE by searching its load path.
+This function looks in directories named by `native-comp-eln-load-path'."
+  (or (locate-file-internal (concat comp-native-version-dir "/" eln-file)
+                  native-comp-eln-load-path)
+      (locate-file-internal
+       ;; Preloaded *.eln files live in the preloaded/ subdirectory of
+       ;; the last entry in `native-comp-eln-load-path'.
+       (concat comp-native-version-dir "/preloaded/" eln-file)
+       (last native-comp-eln-load-path))))
+
+(defun symbol-file (symbol &optional type native-p)
   "Return the name of the file that defined SYMBOL.
 The value is normally an absolute file name.  It can also be nil,
 if the definition is not associated with any file.  If SYMBOL
 specifies an autoloaded function, the value can be a relative
 file name without extension.
 
-If TYPE is nil, then any kind of definition is acceptable.  If
-TYPE is `defun', `defvar', or `defface', that specifies function
+If TYPE is nil, then any kind of SYMBOL's definition is acceptable.
+If TYPE is `defun', `defvar', or `defface', that specifies function
 definition, variable definition, or face definition only.
 Otherwise TYPE is assumed to be a symbol property.
 
+If NATIVE-P is non-nil, and SYMBOL was loaded from a .eln file,
+this function will return the absolute file name of that .eln file,
+if found.  Note that if the .eln file is older than its source .el
+file, Emacs won't load such an outdated .eln file, and this function
+will not return it.  If the .eln file couldn't be found, or is
+outdated, the function returns the corresponding .elc or .el file
+instead.
+
 This function only works for symbols defined in Lisp files.  For
 symbols that are defined in C files, use `help-C-file-name'
 instead."
@@ -2725,24 +2752,59 @@ instead."
           (symbolp symbol)
           (autoloadp (symbol-function symbol)))
       (nth 1 (symbol-function symbol))
-    (catch 'found
-      (pcase-dolist (`(,file . ,elems) load-history)
-       (when (if type
-                 (if (eq type 'defvar)
-                     ;; Variables are present just as their names.
-                     (member symbol elems)
-                   ;; Many other types are represented as (TYPE . NAME).
-                   (or (member (cons type symbol) elems)
-                        (memq symbol (alist-get type
-                                                (alist-get 'define-symbol-props
-                                                           elems)))))
-               ;; We accept all types, so look for variable def
-               ;; and then for any other kind.
-               (or (member symbol elems)
-                    (let ((match (rassq symbol elems)))
-                     (and match
-                          (not (eq 'require (car match)))))))
-          (throw 'found file))))))
+    (if (and native-p (or (null type) (eq type 'defun))
+            (symbolp symbol)
+            (native-comp-available-p)
+            ;; If it's a defun, we have a shortcut.
+            (subr-native-elisp-p (symbol-function symbol)))
+       ;; native-comp-unit-file returns unnormalized file names.
+       (expand-file-name (native-comp-unit-file (subr-native-comp-unit
+                                                 (symbol-function symbol))))
+      (let ((elc-file
+            (catch 'found
+              (pcase-dolist (`(,file . ,elems) load-history)
+                (when (if type
+                          (if (eq type 'defvar)
+                              ;; Variables are present just as their
+                              ;; names.
+                              (member symbol elems)
+                            ;; Many other types are represented as
+                            ;; (TYPE . NAME).
+                            (or (member (cons type symbol) elems)
+                                (memq
+                                 symbol
+                                 (alist-get type
+                                            (alist-get 'define-symbol-props
+                                                       elems)))))
+                        ;; We accept all types, so look for variable def
+                        ;; and then for any other kind.
+                        (or (member symbol elems)
+                            (let ((match (rassq symbol elems)))
+                              (and match
+                                   (not (eq 'require (car match)))))))
+                  (throw 'found file))))))
+       ;; If they asked for the .eln file, try to find it.
+       (or (and elc-file
+                native-p
+                (native-comp-available-p)
+                (let* ((sans-ext (file-name-sans-extension elc-file))
+                       (el-file
+                        (and (fboundp 'zlib-available-p)
+                             (zlib-available-p)
+                             (concat sans-ext ".el.gz")))
+                       (el-file-backup (concat sans-ext ".el")))
+                  (or (and el-file (file-exists-p el-file))
+                      (and (file-exists-p el-file-backup)
+                           (setq el-file el-file-backup))
+                      (setq el-file nil))
+                  (when (stringp el-file)
+                    (let ((eln-file (locate-eln-file
+                                     (comp-el-to-eln-rel-filename el-file))))
+                      ;; Emacs will not load an outdated .eln file,
+                      ;; so we mimic this behavior here.
+                      (if (file-newer-than-file-p eln-file el-file)
+                          eln-file)))))
+           elc-file)))))
 
 (declare-function read-library-name "find-func" nil)
 
@@ -3048,6 +3110,7 @@ by doing (clear-string STRING)."
             (use-local-map read-passwd-map)
             (setq-local inhibit-modification-hooks nil) ;bug#15501.
            (setq-local show-paren-mode nil)            ;bug#16091.
+            (setq-local inhibit--record-char t)
             (add-hook 'post-command-hook #'read-password--hide-password nil t))
         (unwind-protect
             (let ((enable-recursive-minibuffers t)
@@ -3313,9 +3376,7 @@ while calling this function, then pressing `help-char'
 causes it to evaluate `help-form' and display the result.
 There is no need to explicitly add `help-char' to CHARS;
 `help-char' is bound automatically to `help-form-show'."
-  (defvar empty-history)
-  (let* ((empty-history '())
-         (map (if (consp chars)
+  (let* ((map (if (consp chars)
                   (or (gethash (list help-form (cons help-char chars))
                                read-char-from-minibuffer-map-hash)
                       (let ((map (make-sparse-keymap))
@@ -3342,9 +3403,7 @@ There is no need to explicitly add `help-char' to CHARS;
                 read-char-from-minibuffer-map))
          ;; Protect this-command when called from pre-command-hook (bug#45029)
          (this-command this-command)
-         (result
-          (read-from-minibuffer prompt nil map nil
-                                (or history 'empty-history)))
+         (result (read-from-minibuffer prompt nil map nil (or history t)))
          (char
           (if (> (length result) 0)
               ;; We have a string (with one character), so return the first 
one.
@@ -3489,8 +3548,11 @@ like) while `y-or-n-p' is running)."
                                   (format "(y, n or %s) "
                                          (key-description
                                            (vector help-char)))
-                                  "(y or n) "
-                                  )))))))
+                                "(y or n) "))))))
+        ;; Preserve the actual command that eventually called
+        ;; `y-or-n-p' (otherwise `repeat' will be repeating
+        ;; `exit-minibuffer').
+        (real-this-command real-this-command))
     (cond
      (noninteractive
       (setq prompt (funcall padded prompt))
@@ -3542,9 +3604,7 @@ like) while `y-or-n-p' is running)."
         (discard-input)))
      (t
       (setq prompt (funcall padded prompt))
-      (defvar empty-history)
-      (let* ((empty-history '())
-             (enable-recursive-minibuffers t)
+      (let* ((enable-recursive-minibuffers t)
              (msg help-form)
              (keymap (let ((map (make-composed-keymap
                                  y-or-n-p-map query-replace-map)))
@@ -3561,7 +3621,7 @@ like) while `y-or-n-p' is running)."
              (this-command this-command)
              (str (read-from-minibuffer
                    prompt nil keymap nil
-                   (or y-or-n-p-history-variable 'empty-history))))
+                   (or y-or-n-p-history-variable t))))
         (setq answer (if (member str '("y" "Y")) 'act 'skip)))))
     (let ((ret (eq answer 'act)))
       (unless noninteractive
@@ -4011,6 +4071,11 @@ Otherwise, return nil."
       (setq object (indirect-function object)))
   (and (subrp object) (eq (cdr (subr-arity object)) 'unevalled)))
 
+(defun plistp (object)
+  "Non-nil if and only if OBJECT is a valid plist."
+  (let ((len (proper-list-p object)))
+    (and len (zerop (% len 2)))))
+
 (defun macrop (object)
   "Non-nil if and only if OBJECT is a macro."
   (let ((def (indirect-function object)))
@@ -4018,6 +4083,12 @@ Otherwise, return nil."
       (or (eq 'macro (car def))
           (and (autoloadp def) (memq (nth 4 def) '(macro t)))))))
 
+(defun compiled-function-p (object)
+  "Return non-nil if OBJECT is a function that has been compiled.
+Does not distinguish between functions implemented in machine code
+or byte-code."
+  (or (subrp object) (byte-code-function-p object)))
+
 (defun field-at-pos (pos)
   "Return the field at position POS, taking stickiness etc into account."
   (let ((raw-field (get-char-property (field-beginning pos) 'field)))
@@ -4707,9 +4778,6 @@ even if this catches the signal."
                    ,@(cdr handler)))
                handlers)))
 
-(define-obsolete-function-alias 'condition-case-no-debug
-  'condition-case-unless-debug "24.1")
-
 (defmacro with-demoted-errors (format &rest body)
   "Run BODY and demote any errors to simple messages.
 FORMAT is a string passed to `message' to format any error message.
@@ -5300,10 +5368,18 @@ and replace a sub-expression, e.g.
       (setq matches (cons (substring string start l) matches)) ; leftover
       (apply #'concat (nreverse matches)))))
 
+(defsubst string-equal-ignore-case (string1 string2)
+  "Like `string-equal', but case-insensitive.
+Upper-case and lower-case letters are treated as equal.
+Unibyte strings are converted to multibyte for comparison."
+  (declare (pure t) (side-effect-free t))
+  (eq t (compare-strings string1 0 nil string2 0 nil t)))
+
 (defun string-prefix-p (prefix string &optional ignore-case)
   "Return non-nil if PREFIX is a prefix of STRING.
 If IGNORE-CASE is non-nil, the comparison is done without paying attention
 to case differences."
+  (declare (pure t) (side-effect-free t))
   (let ((prefix-length (length prefix)))
     (if (> prefix-length (length string)) nil
       (eq t (compare-strings prefix 0 prefix-length string
@@ -5313,6 +5389,7 @@ to case differences."
   "Return non-nil if SUFFIX is a suffix of STRING.
 If IGNORE-CASE is non-nil, the comparison is done without paying
 attention to case differences."
+  (declare (pure t) (side-effect-free t))
   (let ((start-pos (- (length string) (length suffix))))
     (and (>= start-pos 0)
          (eq t (compare-strings suffix nil nil
@@ -6013,7 +6090,16 @@ To test whether a function can be called interactively, 
use
 (define-obsolete-function-alias
   'set-temporary-overlay-map #'set-transient-map "24.4")
 
-(defun set-transient-map (map &optional keep-pred on-exit)
+(defvar set-transient-map-timeout nil
+  "Timeout in seconds for deactivation of a transient keymap.
+If this is a number, it specifies the amount of idle time
+after which to deactivate the keymap set by `set-transient-map',
+thus overriding the value of the TIMEOUT argument to that function.")
+
+(defvar set-transient-map-timer nil
+  "Timer for `set-transient-map-timeout'.")
+
+(defun set-transient-map (map &optional keep-pred on-exit message timeout)
   "Set MAP as a temporary keymap taking precedence over other keymaps.
 Normally, MAP is used only once, to look up the very next key.
 However, if the optional argument KEEP-PRED is t, MAP stays
@@ -6024,24 +6110,52 @@ if it returns non-nil, then MAP stays active.
 Optional arg ON-EXIT, if non-nil, specifies a function that is
 called, with no arguments, after MAP is deactivated.
 
-This uses `overriding-terminal-local-map', which takes precedence over all
-other keymaps.  As usual, if no match for a key is found in MAP, the normal
-key lookup sequence then continues.
+Optional arg MESSAGE, if non-nil, requests display of an informative
+message after activating the transient map.  If MESSAGE is a string,
+it specifies the format string for the message to display, and the %k
+specifier in the string is replaced with the list of keys from the
+transient map.  Any other non-nil value of MESSAGE means to use the
+message format string \"Repeat with %k\".  Upon deactivating the map,
+the displayed message will be cleared out.
+
+Optional arg TIMEOUT, if non-nil, should be a number specifying the
+number of seconds of idle time after which the map is deactivated.
+The variable `set-transient-map-timeout', if non-nil, overrides the
+value of TIMEOUT.
+
+This function uses `overriding-terminal-local-map', which takes precedence
+over all other keymaps.  As usual, if no match for a key is found in MAP,
+the normal key lookup sequence then continues.
 
 This returns an \"exit function\", which can be called with no argument
 to deactivate this transient map, regardless of KEEP-PRED."
-  (let* ((clearfun (make-symbol "clear-transient-map"))
+  (let* ((timeout (or set-transient-map-timeout timeout))
+         (message
+          (when message
+            (let (keys)
+              (map-keymap (lambda (key cmd) (and cmd (push key keys))) map)
+              (format-spec (if (stringp message) message "Repeat with %k")
+                           `((?k . ,(mapconcat
+                                     (lambda (key)
+                                       (substitute-command-keys
+                                        (format "\\`%s'"
+                                                (key-description (vector 
key)))))
+                                     keys ", ")))))))
+         (clearfun (make-symbol "clear-transient-map"))
          (exitfun
           (lambda ()
             (internal-pop-keymap map 'overriding-terminal-local-map)
             (remove-hook 'pre-command-hook clearfun)
+            ;; Clear the prompt after exiting.
+            (when message (message ""))
+            (when set-transient-map-timer (cancel-timer 
set-transient-map-timer))
             (when on-exit (funcall on-exit)))))
     ;; Don't use letrec, because equal (in add/remove-hook) could get trapped
     ;; in a cycle. (bug#46326)
     (fset clearfun
           (lambda ()
             (with-demoted-errors "set-transient-map PCH: %S"
-              (unless (cond
+              (if (cond
                        ((null keep-pred) nil)
                        ((and (not (eq map (cadr 
overriding-terminal-local-map)))
                              (memq map (cddr overriding-terminal-local-map)))
@@ -6066,9 +6180,15 @@ to deactivate this transient map, regardless of 
KEEP-PRED."
                           ;; nil and so is `mc`.
                           (and mc (eq this-command mc))))
                        (t (funcall keep-pred)))
+                  ;; Repeat the message for the next command.
+                  (when message (message "%s" message))
                 (funcall exitfun)))))
     (add-hook 'pre-command-hook clearfun)
     (internal-push-keymap map 'overriding-terminal-local-map)
+    (when timeout
+      (when set-transient-map-timer (cancel-timer set-transient-map-timer))
+      (setq set-transient-map-timer (run-with-idle-timer timeout nil exitfun)))
+    (when message (message "%s" message))
     exitfun))
 
 ;;;; Progress reporters.
@@ -6531,7 +6651,7 @@ Also, \"-GIT\", \"-CVS\" and \"-NNN\" are treated as 
snapshot versions."
   (version-list-= (version-to-list v1) (version-to-list v2)))
 
 (defvar package--builtin-versions
-  ;; Mostly populated by loaddefs.el via autoload-builtin-package-versions.
+  ;; Mostly populated by loaddefs.el.
   (purecopy `((emacs . ,(version-to-list emacs-version))))
   "Alist giving the version of each versioned builtin package.
 I.e. each element of the list is of the form (NAME . VERSION) where
@@ -6774,7 +6894,7 @@ This means that OBJECT can be printed out and then read 
back
 again by the Lisp reader.  This function returns nil if OBJECT is
 unreadable, and the printed representation (from `prin1') of
 OBJECT if it is readable."
-  (declare (side-effect-free t))
+  (declare (side-effect-free error-free))
   (catch 'unreadable
     (let ((print-unreadable-function
            (lambda (_object _escape)
@@ -6783,10 +6903,7 @@ OBJECT if it is readable."
 
 (defun delete-line ()
   "Delete the current line."
-  (delete-region (line-beginning-position)
-                 (progn
-                   (forward-line 1)
-                   (point))))
+  (delete-region (pos-bol) (pos-bol 2)))
 
 (defun ensure-empty-lines (&optional lines)
   "Ensure that there are LINES number of empty lines before point.
@@ -6850,14 +6967,18 @@ lines."
 (defun buffer-match-p (condition buffer-or-name &optional arg)
   "Return non-nil if BUFFER-OR-NAME matches CONDITION.
 CONDITION is either:
+- the symbol t, to always match,
+- the symbol nil, which never matches,
 - a regular expression, to match a buffer name,
 - a predicate function that takes a buffer object and ARG as
   arguments, and returns non-nil if the buffer matches,
 - a cons-cell, where the car describes how to interpret the cdr.
   The car can be one of the following:
-  * `major-mode': the buffer matches if the buffer's major
-    mode is derived from the major mode denoted by the cons-cell's
-    cdr
+  * `derived-mode': the buffer matches if the buffer's major mode
+    is derived from the major mode in the cons-cell's cdr.
+  * `major-mode': the buffer matches if the buffer's major mode
+    is eq to the cons-cell's cdr.  Prefer using `derived-mode'
+    instead when both can work.
   * `not': the cdr is interpreted as a negation of a condition.
   * `and': the cdr is a list of recursive conditions, that all have
     to be met.
@@ -6870,6 +6991,7 @@ CONDITION is either:
           (catch 'match
             (dolist (condition conditions)
               (when (cond
+                     ((eq condition t))
                      ((stringp condition)
                       (string-match-p condition (buffer-name buffer)))
                      ((functionp condition)
@@ -6877,6 +6999,10 @@ CONDITION is either:
                           (funcall condition buffer)
                         (funcall condition buffer arg)))
                      ((eq (car-safe condition) 'major-mode)
+                      (eq
+                       (buffer-local-value 'major-mode buffer)
+                       (cdr condition)))
+                     ((eq (car-safe condition) 'derived-mode)
                       (provided-mode-derived-p
                        (buffer-local-value 'major-mode buffer)
                        (cdr condition)))
@@ -6906,4 +7032,16 @@ CONDITION."
         (push buf bufs)))
     bufs))
 
+(defmacro with-memoization (place &rest code)
+  "Return the value of CODE and stash it in PLACE.
+If PLACE's value is non-nil, then don't bother evaluating CODE
+and return the value found in PLACE instead."
+  (declare (indent 1) (debug (gv-place body)))
+  (gv-letplace (getter setter) place
+    `(or ,getter
+         ,(macroexp-let2 nil val (macroexp-progn code)
+            `(progn
+               ,(funcall setter val)
+               ,val)))))
+
 ;;; subr.el ends here
diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el
index 705b072501..cf5ae09a24 100644
--- a/lisp/tab-bar.el
+++ b/lisp/tab-bar.el
@@ -200,7 +200,9 @@ a list of frames to update."
                          (t frames))))
     ;; Loop over all frames and update `tab-bar-lines'
     (dolist (frame frame-lst)
-      (unless (frame-parameter frame 'tab-bar-lines-keep-state)
+      (unless (or (frame-parameter frame 'tab-bar-lines-keep-state)
+                  (and (eq auto-resize-tab-bars 'grow-only)
+                       (> (frame-parameter frame 'tab-bar-lines) 1)))
         (set-frame-parameter frame 'tab-bar-lines
                              (tab-bar--tab-bar-lines-for-frame frame)))))
   ;; Update `default-frame-alist'
@@ -371,31 +373,28 @@ at the mouse-down event to the position at mouse-up 
event."
       (tab-bar-move-tab-to
        (if (null to) (1+ (tab-bar--current-tab-index)) to) from))))
 
-(defvar tab-bar-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map [down-mouse-1] 'tab-bar-mouse-down-1)
-    (define-key map [drag-mouse-1] 'tab-bar-mouse-move-tab)
-    (define-key map [mouse-1]      'tab-bar-mouse-1)
-    (define-key map [down-mouse-2] 'tab-bar-mouse-close-tab)
-    (define-key map [mouse-2]      'ignore)
-    (define-key map [down-mouse-3] 'tab-bar-mouse-context-menu)
-
-    (define-key map [mouse-4]     'tab-previous)
-    (define-key map [mouse-5]     'tab-next)
-    (define-key map [wheel-up]    'tab-previous)
-    (define-key map [wheel-down]  'tab-next)
-    (define-key map [wheel-left]  'tab-previous)
-    (define-key map [wheel-right] 'tab-next)
-
-    (define-key map [S-mouse-4]     'tab-bar-move-tab-backward)
-    (define-key map [S-mouse-5]     'tab-bar-move-tab)
-    (define-key map [S-wheel-up]    'tab-bar-move-tab-backward)
-    (define-key map [S-wheel-down]  'tab-bar-move-tab)
-    (define-key map [S-wheel-left]  'tab-bar-move-tab-backward)
-    (define-key map [S-wheel-right] 'tab-bar-move-tab)
-
-    map)
-  "Keymap for the commands used on the tab bar.")
+(defvar-keymap tab-bar-map
+  :doc "Keymap for the commands used on the tab bar."
+  "<down-mouse-1>"  #'tab-bar-mouse-down-1
+  "<drag-mouse-1>"  #'tab-bar-mouse-move-tab
+  "<mouse-1>"       #'tab-bar-mouse-1
+  "<down-mouse-2>"  #'tab-bar-mouse-close-tab
+  "<mouse-2>"       #'ignore
+  "<down-mouse-3>"  #'tab-bar-mouse-context-menu
+
+  "<mouse-4>"       #'tab-previous
+  "<mouse-5>"       #'tab-next
+  "<wheel-up>"      #'tab-previous
+  "<wheel-down>"    #'tab-next
+  "<wheel-left>"    #'tab-previous
+  "<wheel-right>"   #'tab-next
+
+  "S-<mouse-4>"     #'tab-bar-move-tab-backward
+  "S-<mouse-5>"     #'tab-bar-move-tab
+  "S-<wheel-up>"    #'tab-bar-move-tab-backward
+  "S-<wheel-down>"  #'tab-bar-move-tab
+  "S-<wheel-left>"  #'tab-bar-move-tab-backward
+  "S-<wheel-right>" #'tab-bar-move-tab)
 
 (global-set-key [tab-bar]
                 `(menu-item ,(purecopy "tab bar") ignore
@@ -618,7 +617,7 @@ Also add the number of windows in the window configuration."
   "Maximum length of the tab name from the current buffer.
 Effective when `tab-bar-tab-name-function' is customized
 to `tab-bar-tab-name-truncated'."
-  :type 'integer
+  :type 'natnum
   :group 'tab-bar
   :version "27.1")
 
@@ -2006,26 +2005,25 @@ For more information, see the function `tab-switcher'."
 
 (defvar-local tab-switcher-column 3)
 
-(defvar tab-switcher-mode-map
-  (let ((map (make-keymap)))
-    (suppress-keymap map t)
-    (define-key map "q"    'quit-window)
-    (define-key map "\C-m" 'tab-switcher-select)
-    (define-key map "d"    'tab-switcher-delete)
-    (define-key map "k"    'tab-switcher-delete)
-    (define-key map "\C-d" 'tab-switcher-delete-backwards)
-    (define-key map "\C-k" 'tab-switcher-delete)
-    (define-key map "x"    'tab-switcher-execute)
-    (define-key map " "    'tab-switcher-next-line)
-    (define-key map "n"    'tab-switcher-next-line)
-    (define-key map "p"    'tab-switcher-prev-line)
-    (define-key map "\177" 'tab-switcher-backup-unmark)
-    (define-key map "?"    'describe-mode)
-    (define-key map "u"    'tab-switcher-unmark)
-    (define-key map [mouse-2] 'tab-switcher-mouse-select)
-    (define-key map [follow-link] 'mouse-face)
-    map)
-  "Local keymap for `tab-switcher-mode' buffers.")
+(defvar-keymap tab-switcher-mode-map
+  :doc "Local keymap for `tab-switcher-mode' buffers."
+  :full t
+  :suppress t
+  "q"   #'quit-window
+  "RET" #'tab-switcher-select
+  "d"   #'tab-switcher-delete
+  "k"   #'tab-switcher-delete
+  "C-d" #'tab-switcher-delete-backwards
+  "C-k" #'tab-switcher-delete
+  "x"   #'tab-switcher-execute
+  "SPC" #'tab-switcher-next-line
+  "n"   #'tab-switcher-next-line
+  "p"   #'tab-switcher-prev-line
+  "DEL" #'tab-switcher-backup-unmark
+  "?"   #'describe-mode
+  "u"   #'tab-switcher-unmark
+  "<mouse-2>"     #'tab-switcher-mouse-select
+  "<follow-link>" 'mouse-face)
 
 (define-derived-mode tab-switcher-mode nil "Window Configurations"
   "Major mode for selecting a window configuration.
@@ -2401,42 +2399,38 @@ When `switch-to-buffer-obey-display-actions' is non-nil,
 (defalias 'tab-group           'tab-bar-change-tab-group)
 (defalias 'tab-list            'tab-switcher)
 
-(define-key tab-prefix-map "n" 'tab-duplicate)
-(define-key tab-prefix-map "N" 'tab-new-to)
-(define-key tab-prefix-map "2" 'tab-new)
-(define-key tab-prefix-map "1" 'tab-close-other)
-(define-key tab-prefix-map "0" 'tab-close)
-(define-key tab-prefix-map "u" 'tab-undo)
-(define-key tab-prefix-map "o" 'tab-next)
-(define-key tab-prefix-map "O" 'tab-previous)
-(define-key tab-prefix-map "m" 'tab-move)
-(define-key tab-prefix-map "M" 'tab-move-to)
-(define-key tab-prefix-map "G" 'tab-group)
-(define-key tab-prefix-map "r" 'tab-rename)
-(define-key tab-prefix-map "\r" 'tab-switch)
-(define-key tab-prefix-map "b" 'switch-to-buffer-other-tab)
-(define-key tab-prefix-map "f" 'find-file-other-tab)
-(define-key tab-prefix-map "\C-f" 'find-file-other-tab)
-(define-key tab-prefix-map "\C-r" 'find-file-read-only-other-tab)
-(define-key tab-prefix-map "t" 'other-tab-prefix)
-
-(defvar tab-bar-switch-repeat-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "o" 'tab-next)
-    (define-key map "O" 'tab-previous)
-    map)
-  "Keymap to repeat tab switch key sequences `C-x t o o O'.
-Used in `repeat-mode'.")
+(keymap-set tab-prefix-map "n"   #'tab-duplicate)
+(keymap-set tab-prefix-map "N"   #'tab-new-to)
+(keymap-set tab-prefix-map "2"   #'tab-new)
+(keymap-set tab-prefix-map "1"   #'tab-close-other)
+(keymap-set tab-prefix-map "0"   #'tab-close)
+(keymap-set tab-prefix-map "u"   #'tab-undo)
+(keymap-set tab-prefix-map "o"   #'tab-next)
+(keymap-set tab-prefix-map "O"   #'tab-previous)
+(keymap-set tab-prefix-map "m"   #'tab-move)
+(keymap-set tab-prefix-map "M"   #'tab-move-to)
+(keymap-set tab-prefix-map "G"   #'tab-group)
+(keymap-set tab-prefix-map "r"   #'tab-rename)
+(keymap-set tab-prefix-map "RET" #'tab-switch)
+(keymap-set tab-prefix-map "b"   #'switch-to-buffer-other-tab)
+(keymap-set tab-prefix-map "f"   #'find-file-other-tab)
+(keymap-set tab-prefix-map "C-f" #'find-file-other-tab)
+(keymap-set tab-prefix-map "C-r" #'find-file-read-only-other-tab)
+(keymap-set tab-prefix-map "t"   #'other-tab-prefix)
+
+(defvar-keymap tab-bar-switch-repeat-map
+  :doc "Keymap to repeat tab switch key sequences \\`C-x t o o O'.
+Used in `repeat-mode'."
+  "o" #'tab-next
+  "O" #'tab-previous)
 (put 'tab-next 'repeat-map 'tab-bar-switch-repeat-map)
 (put 'tab-previous 'repeat-map 'tab-bar-switch-repeat-map)
 
-(defvar tab-bar-move-repeat-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "m" 'tab-move)
-    (define-key map "M" 'tab-bar-move-tab-backward)
-    map)
-  "Keymap to repeat tab move key sequences `C-x t m m M'.
-Used in `repeat-mode'.")
+(defvar-keymap tab-bar-move-repeat-map
+  :doc "Keymap to repeat tab move key sequences \\`C-x t m m M'.
+Used in `repeat-mode'."
+  "m" #'tab-move
+  "M" #'tab-bar-move-tab-backward)
 (put 'tab-move 'repeat-map 'tab-bar-move-repeat-map)
 (put 'tab-bar-move-tab-backward 'repeat-map 'tab-bar-move-repeat-map)
 
diff --git a/lisp/tab-line.el b/lisp/tab-line.el
index 80b0aabd77..3e3b4c9559 100644
--- a/lisp/tab-line.el
+++ b/lisp/tab-line.el
@@ -288,7 +288,7 @@ variable `tab-line-tab-name-function'."
   "Maximum length of the tab name from the current buffer.
 Effective when `tab-line-tab-name-function' is customized
 to `tab-line-tab-name-truncated-buffer'."
-  :type 'integer
+  :type 'natnum
   :group 'tab-line
   :version "27.1")
 
diff --git a/lisp/tar-mode.el b/lisp/tar-mode.el
index ed48b56842..20ad6e1e46 100644
--- a/lisp/tar-mode.el
+++ b/lisp/tar-mode.el
@@ -604,44 +604,42 @@ For instance, if mode is #o700, then it produces 
`rwx------'."
       (goto-char (point-min))
       (restore-buffer-modified-p modified))))
 
-(defvar tar-mode-map
-  (let ((map (make-keymap)))
-    (suppress-keymap map)
-    (define-key map " " 'tar-next-line)
-    (define-key map "C" 'tar-copy)
-    (define-key map "d" 'tar-flag-deleted)
-    (define-key map "\^D" 'tar-flag-deleted)
-    (define-key map "e" 'tar-extract)
-    (define-key map "f" 'tar-extract)
-    (define-key map "\C-m" 'tar-extract)
-    (define-key map [mouse-2] 'tar-mouse-extract)
-    (define-key map "g" 'revert-buffer)
-    (define-key map "n" 'tar-next-line)
-    (define-key map "\^N" 'tar-next-line)
-    (define-key map [down] 'tar-next-line)
-    (define-key map "o" 'tar-extract-other-window)
-    (define-key map "p" 'tar-previous-line)
-    (define-key map "\^P" 'tar-previous-line)
-    (define-key map [up] 'tar-previous-line)
-    (define-key map "I" 'tar-new-entry)
-    (define-key map "R" 'tar-rename-entry)
-    (define-key map "u" 'tar-unflag)
-    (define-key map "v" 'tar-view)
-    (define-key map "w" 'woman-tar-extract-file)
-    (define-key map "x" 'tar-expunge)
-    (define-key map "\177" 'tar-unflag-backwards)
-    (define-key map "E" 'tar-extract-other-window)
-    (define-key map "M" 'tar-chmod-entry)
-    (define-key map "G" 'tar-chgrp-entry)
-    (define-key map "O" 'tar-chown-entry)
-    ;; Let mouse-1 follow the link.
-    (define-key map [follow-link] 'mouse-face)
-
-    ;; Get rid of the Edit menu bar item to save space.
-    (define-key map [menu-bar edit] 'undefined)
-
-    map)
-  "Local keymap for Tar mode listings.")
+(defvar-keymap tar-mode-map
+  :doc "Local keymap for Tar mode listings."
+  :full t :suppress t
+  "SPC"    #'tar-next-line
+  "C"      #'tar-copy
+  "d"      #'tar-flag-deleted
+  "C-d"    #'tar-flag-deleted
+  "e"      #'tar-extract
+  "f"      #'tar-extract
+  "RET"    #'tar-extract
+  "g"      #'revert-buffer
+  "n"      #'tar-next-line
+  "C-n"    #'tar-next-line
+  "<down>" #'tar-next-line
+  "o"      #'tar-extract-other-window
+  "p"      #'tar-previous-line
+  "C-p"    #'tar-previous-line
+  "<up>"   #'tar-previous-line
+  "I"      #'tar-new-entry
+  "R"      #'tar-rename-entry
+  "u"      #'tar-unflag
+  "v"      #'tar-view
+  "w"      #'woman-tar-extract-file
+  "x"      #'tar-expunge
+  "DEL"    #'tar-unflag-backwards
+  "E"      #'tar-extract-other-window
+  "M"      #'tar-chmod-entry
+  "G"      #'tar-chgrp-entry
+  "O"      #'tar-chown-entry
+
+  ;; Let mouse-1 follow the link.
+  "<follow-link>" 'mouse-face
+  "<mouse-2>"     #'tar-mouse-extract
+
+  ;; Get rid of the Edit menu bar item to save space.
+  "<menu-bar> <edit>" #'undefined)
 
 (easy-menu-define tar-mode-immediate-menu tar-mode-map
   "Immediate menu for Tar mode."
@@ -1331,6 +1329,8 @@ to make your changes permanent."
       (error "This buffer has no superior tar file buffer"))
   (if (not (and (boundp 'tar-superior-descriptor) tar-superior-descriptor))
       (error "This buffer doesn't have an index into its superior tar file!"))
+  (unless (buffer-live-p tar-superior-buffer)
+    (error "The tar buffer no longer exists; can't save"))
   (let ((subfile (current-buffer))
         (coding buffer-file-coding-system)
         (descriptor tar-superior-descriptor)
@@ -1377,7 +1377,7 @@ to make your changes permanent."
          ;; Maybe update the datestamp.
          (when tar-update-datestamp
            (tar-alter-one-field tar-time-offset
-                                (concat (tar-octal-time (current-time)) " "))))
+                                (concat (tar-octal-time nil) " "))))
         ;; After doing the insertion, add any necessary final padding.
         (tar-pad-to-blocksize))
       (set-buffer-modified-p t)         ; mark the tar file as modified
diff --git a/lisp/term.el b/lisp/term.el
index f81cbf7293..797fb18074 100644
--- a/lisp/term.el
+++ b/lisp/term.el
@@ -78,7 +78,7 @@
 ;; directory/username/host tracking: the only drawback is that you will
 ;; have to modify your shell start-up script.  It's worth it, believe me :).
 ;;
-;; When you rlogin/su/telnet and the account you access has a modified
+;; When you ssh/sudo/su and the account you access has a modified
 ;; startup script, you will be able to access the remote files as usual
 ;; with C-x C-f, if it's needed you will have to enter a password,
 ;; otherwise the file should get loaded straight away.
@@ -915,7 +915,7 @@ Term buffers are truncated from the top to be no greater 
than this number.
 Notice that a setting of 0 means \"don't truncate anything\".  This variable
 is buffer-local."
   :group 'term
-  :type 'integer
+  :type 'natnum
   :version "27.1")
 
 (defcustom term-bind-function-keys nil
@@ -1052,11 +1052,10 @@ underlying shell."
   "Change `term-escape-char' and keymaps that depend on it."
   (when term-escape-char
     ;; Undo previous term-set-escape-char.
-    (define-key term-raw-map term-escape-char 'term-send-raw))
+    (define-key term-raw-map term-escape-char 'term-send-raw)
+    (define-key term-raw-escape-map term-escape-char nil t))
   (setq term-escape-char (if (vectorp key) key (vector key)))
   (define-key term-raw-map term-escape-char term-raw-escape-map)
-  ;; FIXME: If we later call term-set-escape-char again with another key,
-  ;; we should undo this binding.
   (define-key term-raw-escape-map term-escape-char 'term-send-raw))
 
 (term-set-escape-char (or term-escape-char ?\C-c))
@@ -1446,10 +1445,7 @@ Entry to this mode runs the hooks on `term-mode-hook'."
 (defun term-char-mode ()
   "Switch to char (\"raw\") sub-mode of term mode.
 Each character you type is sent directly to the inferior without
-intervention from Emacs, except for the escape character (usually C-c).
-
-This command will send existing partial lines to the terminal
-process."
+intervention from Emacs, except for the escape character (usually C-c)."
   (interactive)
   ;; FIXME: Emit message? Cfr ilisp-raw-message
   (when (term-in-line-mode)
@@ -1468,10 +1464,10 @@ process."
       (when (> (point) pmark)
        (unwind-protect
            (progn
-             (add-function :override term-input-sender #'term-send-string)
+             (add-function :override (local 'term-input-sender) 
#'term-send-string)
              (end-of-line)
              (term-send-input))
-         (remove-function term-input-sender #'term-send-string))))
+         (remove-function (local 'term-input-sender) #'term-send-string))))
     (term-update-mode-line)))
 
 (defun term-line-mode  ()
@@ -2477,7 +2473,7 @@ Checks if STRING contains a password prompt as defined by
   "Long inputs send to term processes are broken up into chunks of this size.
 If your process is choking on big inputs, try lowering the value."
   :group 'term
-  :type 'integer)
+  :type 'natnum)
 
 (defun term-send-string (proc str)
   "Send to PROC the contents of STR as input.
@@ -2866,13 +2862,13 @@ See `term-prompt-regexp'."
 
 (defun term-move-to-column (column)
   (setq term-current-column column)
-  (let ((point-at-eol (line-end-position)))
+  (let ((line-end-position (line-end-position)))
     (move-to-column term-current-column t)
     ;; If move-to-column extends the current line it will use the face
     ;; from the last character on the line, set the face for the chars
     ;; to default.
-    (when (> (point) point-at-eol)
-      (put-text-property point-at-eol (point) 'font-lock-face 'default))))
+    (when (> (point) line-end-position)
+      (put-text-property line-end-position (point) 'font-lock-face 'default))))
 
 ;; Move DELTA column right (or left if delta < 0 limiting at column 0).
 (defun term-move-columns (delta)
@@ -4377,7 +4373,7 @@ the process.  Any more args are arguments to PROGRAM."
 (defun ansi-term (program &optional new-buffer-name)
   "Start a terminal-emulator in a new buffer.
 This is almost the same as `term' apart from always creating a new buffer,
-and `C-x' being marked as a `term-escape-char'."
+and \\`C-x' being marked as a `term-escape-char'."
   (interactive (list (read-from-minibuffer "Run program: "
                                           (or explicit-shell-file-name
                                               (getenv "ESHELL")
diff --git a/lisp/term/common-win.el b/lisp/term/common-win.el
index 6f1e322aba..f7faba9cb7 100644
--- a/lisp/term/common-win.el
+++ b/lisp/term/common-win.el
@@ -59,20 +59,19 @@
        (setq system-key-alist
              (list
               ;; These are special "keys" used to pass events from C to lisp.
-              (cons  1 'ns-power-off)
-              (cons  2 'ns-open-file)
-              (cons  3 'ns-open-temp-file)
-              (cons  4 'ns-drag-file)
-              (cons  5 'ns-drag-color)
-              (cons  6 'ns-drag-text)
-              (cons  8 'ns-open-file-line)
-;;;           (cons  9 'ns-insert-working-text)
-;;;           (cons 10 'ns-delete-working-text)
-              (cons 11 'ns-spi-service-call)
-              (cons 12 'ns-new-frame)
-              (cons 13 'ns-toggle-toolbar)
-              (cons 14 'ns-show-prefs)
-              ))))
+              (cons  1 (make-non-key-event 'ns-power-off))
+              (cons  2 (make-non-key-event 'ns-open-file))
+              (cons  3 (make-non-key-event 'ns-open-temp-file))
+              (cons  4 (make-non-key-event 'ns-drag-file))
+              (cons  5 (make-non-key-event 'ns-drag-color))
+              (cons  6 (make-non-key-event 'ns-drag-text))
+              (cons  8 (make-non-key-event 'ns-open-file-line))
+;;;           (cons  9 (make-non-key-event 'ns-insert-working-text))
+;;;           (cons 10 (make-non-key-event 'ns-delete-working-text))
+              (cons 11 (make-non-key-event 'ns-spi-service-call))
+              (cons 12 (make-non-key-event 'ns-new-frame))
+              (cons 13 (make-non-key-event 'ns-toggle-toolbar))
+              (cons 14 (make-non-key-event 'ns-show-prefs))))))
     (set-terminal-parameter frame 'x-setup-function-keys t)))
 
 (defvar x-invocation-args)
diff --git a/lisp/term/haiku-win.el b/lisp/term/haiku-win.el
index 5443904a73..a16169d477 100644
--- a/lisp/term/haiku-win.el
+++ b/lisp/term/haiku-win.el
@@ -24,6 +24,7 @@
 ;;; Code:
 
 (eval-when-compile (require 'cl-lib))
+(eval-when-compile (require 'subr-x))
 (unless (featurep 'haiku)
   (error "%s: Loading haiku-win without having Haiku"
          invocation-name))
@@ -173,6 +174,31 @@ VALUE as a unibyte string, or nil if VALUE was not a 
string."
                                           (insert "\n")))
                             (buffer-string))))))
 
+(eval-and-compile
+  (defun haiku-get-numeric-enum (name)
+    "Return the numeric value of the system enumerator NAME."
+    (or (get name 'haiku-numeric-enum)
+        (let ((value 0)
+              (offset 0)
+              (string (symbol-name name)))
+          (cl-loop for octet across string
+                   do (progn
+                        (when (or (< octet 0)
+                                  (> octet 255))
+                          (error "Out of range octet: %d" octet))
+                        (setq value
+                              (logior value
+                                      (ash octet
+                                           (- (* (1- (length string)) 8)
+                                              offset))))
+                        (setq offset (+ offset 8))))
+          (prog1 value
+            (put name 'haiku-enumerator-id value))))))
+
+(defmacro haiku-numeric-enum (name)
+  "Expand to the numeric value NAME as a system identifier."
+  (haiku-get-numeric-enum name))
+
 (declare-function x-open-connection "haikufns.c")
 (declare-function x-handle-args "common-win")
 (declare-function haiku-selection-data "haikuselect.c")
@@ -180,6 +206,7 @@ VALUE as a unibyte string, or nil if VALUE was not a 
string."
 (declare-function haiku-selection-owner-p "haikuselect.c")
 (declare-function haiku-put-resource "haikufns.c")
 (declare-function haiku-drag-message "haikuselect.c")
+(declare-function haiku-selection-timestamp "haikuselect.c")
 
 (defun haiku--handle-x-command-line-resources (command-line-resources)
   "Handle command line X resources specified with the option `-xrm'.
@@ -223,7 +250,7 @@ If TYPE is nil, return \"text/plain\"."
   "Find the types of data available from CLIPBOARD.
 CLIPBOARD should be the symbol `PRIMARY', `SECONDARY' or
 `CLIPBOARD'.  Return the available types as a list of strings."
-  (mapcar #'car (haiku-selection-data clipboard nil)))
+  (delq 'type (mapcar #'car (haiku-selection-data clipboard nil))))
 
 (defun haiku-select-encode-xstring (_selection value)
   "Convert VALUE to a system message association.
@@ -236,7 +263,7 @@ under the type `text/plain;charset=iso-8859-1'."
                       (buffer-substring (nth 0 bounds)
                                         (nth 1 bounds)))))))
   (when (and (stringp value) (not (string-empty-p value)))
-    (list "text/plain;charset=iso-8859-1" 1296649541
+    (list "text/plain;charset=iso-8859-1" (haiku-numeric-enum MIME)
           (encode-coding-string value 'iso-latin-1))))
 
 (defun haiku-select-encode-utf-8-string (_selection value)
@@ -250,7 +277,7 @@ VALUE will be encoded as UTF-8 and stored under the type
                       (buffer-substring (nth 0 bounds)
                                         (nth 1 bounds)))))))
   (when (and (stringp value) (not (string-empty-p value)))
-    (list "text/plain" 1296649541
+    (list "text/plain" (haiku-numeric-enum MIME)
           (encode-coding-string value 'utf-8-unix))))
 
 (defun haiku-select-encode-file-name (_selection value)
@@ -262,12 +289,19 @@ or a pair of markers) and turns it into a file system 
reference."
 
 (cl-defmethod gui-backend-get-selection (type data-type
                                               &context (window-system haiku))
-  (if (eq data-type 'TARGETS)
-      (apply #'vector (mapcar #'intern
-                              (haiku-selection-targets type)))
-    (if (eq type 'XdndSelection)
-        haiku-dnd-selection-value
-      (haiku-selection-data type (haiku--selection-type-to-mime data-type)))))
+  (cond
+   ((eq data-type 'TARGETS)
+    (apply #'vector (mapcar #'intern
+                            (haiku-selection-targets type))))
+   ;; The timestamp here is really the number of times a program has
+   ;; put data into the selection.  But it always increases, so it
+   ;; makes sense if one imagines that time is frozen until
+   ;; immediately before that happens.
+   ((eq data-type 'TIMESTAMP)
+    (haiku-selection-timestamp type))
+   ((eq type 'XdndSelection) haiku-dnd-selection-value)
+   (t (haiku-selection-data type
+                            (haiku--selection-type-to-mime data-type)))))
 
 (cl-defmethod gui-backend-set-selection (type value
                                               &context (window-system haiku))
@@ -303,6 +337,21 @@ or a pair of markers) and turns it into a file system 
reference."
                                  (file-name-nondirectory default-filename)))
     (error "x-file-dialog on a tty frame")))
 
+(defun haiku-parse-drag-actions (message)
+  "Given the drag-and-drop message MESSAGE, retrieve the desired action."
+  (let ((actions (cddr (assoc "be:actions" message)))
+        (sorted nil))
+    (dolist (action (list (haiku-numeric-enum DDCP)
+                          (haiku-numeric-enum DDMV)
+                          (haiku-numeric-enum DDLN)))
+      (when (member action actions)
+        (push sorted action)))
+    (cond
+     ((eql (car sorted) (haiku-numeric-enum DDCP)) 'copy)
+     ((eql (car sorted) (haiku-numeric-enum DDMV)) 'move)
+     ((eql (car sorted) (haiku-numeric-enum DDLN)) 'link)
+     (t 'private))))
+
 (defun haiku-drag-and-drop (event)
   "Handle specified drag-n-drop EVENT."
   (interactive "e")
@@ -310,34 +359,35 @@ or a pair of markers) and turns it into a file system 
reference."
         (window (posn-window (event-start event))))
     (if (eq string 'lambda) ; This means the mouse moved.
         (dnd-handle-movement (event-start event))
-      (cond
-       ;; Don't allow dropping on something other than the text area.
-       ;; It does nothing and doesn't work with text anyway.
-       ((posn-area (event-start event)))
-       ((assoc "refs" string)
-        (with-selected-window window
-          (dolist (filename (cddr (assoc "refs" string)))
-            (dnd-handle-one-url window 'private
-                                (concat "file:" filename)))))
-       ((assoc "text/uri-list" string)
-        (dolist (text (cddr (assoc "text/uri-list" string)))
-          (let ((uri-list (split-string text "[\0\r\n]" t)))
-            (dolist (bf uri-list)
-              (dnd-handle-one-url window 'private bf)))))
-       ((assoc "text/plain" string)
-        (with-selected-window window
-          (dolist (text (cddr (assoc "text/plain" string)))
-            (unless mouse-yank-at-point
-              (goto-char (posn-point (event-start event))))
-            (dnd-insert-text window 'private
-                             (if (multibyte-string-p text)
-                                 text
-                               (decode-coding-string text 'undecided))))))
-       ((not (eq (cdr (assq 'type string))
-                 3003)) ; Type of the placeholder message Emacs uses
-                        ; to cancel a drop on C-g.
-        (message "Don't know how to drop any of: %s"
-                 (mapcar #'car string)))))))
+      (let ((action (haiku-parse-drag-actions string)))
+        (cond
+         ;; Don't allow dropping on something other than the text area.
+         ;; It does nothing and doesn't work with text anyway.
+         ((posn-area (event-start event)))
+         ((assoc "refs" string)
+          (with-selected-window window
+            (dolist (filename (cddr (assoc "refs" string)))
+              (dnd-handle-one-url window action
+                                  (concat "file:" filename)))))
+         ((assoc "text/uri-list" string)
+          (dolist (text (cddr (assoc "text/uri-list" string)))
+            (let ((uri-list (split-string text "[\0\r\n]" t)))
+              (dolist (bf uri-list)
+                (dnd-handle-one-url window action bf)))))
+         ((assoc "text/plain" string)
+          (with-selected-window window
+            (dolist (text (cddr (assoc "text/plain" string)))
+              (unless mouse-yank-at-point
+                (goto-char (posn-point (event-start event))))
+              (dnd-insert-text window action
+                               (if (multibyte-string-p text)
+                                   text
+                                 (decode-coding-string text 'undecided))))))
+         ((not (eq (cdr (assq 'type string))
+                   3003)) ; Type of the placeholder message Emacs uses
+                          ; to cancel a drop on C-g.
+          (message "Don't know how to drop any of: %s"
+                   (mapcar #'car string))))))))
 
 (define-key special-event-map [drag-n-drop] 'haiku-drag-and-drop)
 
@@ -359,8 +409,7 @@ take effect on menu items until the menu bar is updated 
again."
     (when (car mouse-position)
       (dnd-handle-movement (posn-at-x-y (cadr mouse-position)
                                         (cddr mouse-position)
-                                        (car mouse-position)))
-      (redisplay))))
+                                        (car mouse-position))))))
 
 (setq haiku-drag-track-function #'haiku-dnd-drag-handler)
 
@@ -392,7 +441,7 @@ take effect on menu items until the menu bar is updated 
again."
                   ;; Add B_MIME_TYPE to the message if the type was not
                   ;; previously specified, or the type if it was.
                   (push (or (get-text-property 0 'type maybe-string)
-                            1296649541)
+                            (haiku-numeric-enum MIME))
                         (alist-get (car selection-result) message
                                    nil nil #'equal))))
               (if (not (consp (cadr selection-result)))
@@ -410,7 +459,119 @@ take effect on menu items until the menu bar is updated 
again."
                           message allow-current-frame
                           follow-tooltip))))
 
-(add-variable-watcher 'use-system-tooltips #'haiku-use-system-tooltips-watcher)
+(add-variable-watcher 'use-system-tooltips
+                      #'haiku-use-system-tooltips-watcher)
+
+(defvar haiku-dnd-wheel-count nil
+  "Cons used to determine how many times the wheel has been turned.
+The car is just that; cdr is the timestamp of the last wheel
+movement.")
+
+(defvar haiku-last-wheel-direction nil
+  "Cons of two elements describing the direction the wheel last turned.
+The car is whether or not the movement was horizontal.
+The cdr is whether or not the movement was upwards or leftwards.")
+
+(defun haiku-note-wheel-click (timestamp)
+  "Note that the mouse wheel was moved at TIMESTAMP during drag-and-drop.
+Return the number of clicks that were made in quick succession."
+  (if (not (integerp double-click-time))
+      1
+    (let ((cell haiku-dnd-wheel-count))
+      (unless cell
+        (setq cell (cons 0 timestamp))
+        (setq haiku-dnd-wheel-count cell))
+      (when (< (cdr cell) (- timestamp double-click-time))
+        (setcar cell 0))
+      (setcar cell (1+ (car cell)))
+      (setcdr cell timestamp)
+      (car cell))))
+
+(defvar haiku-drag-wheel-function)
+
+(defun haiku-dnd-modifier-mask (mods)
+  "Return the internal modifier mask for the Emacs modifier state MODS.
+MODS is a single symbol, or a list of symbols such as `shift' or
+`control'."
+  (let ((mask 0))
+    (unless (consp mods)
+      (setq mods (list mods)))
+    (dolist (modifier mods)
+      (cond ((eq modifier 'shift)
+             (setq mask (logior mask ?\S-\0)))
+            ((eq modifier 'control)
+             (setq mask (logior mask ?\C-\0)))
+            ((eq modifier 'meta)
+             (setq mask (logior mask ?\M-\0)))
+            ((eq modifier 'hyper)
+             (setq mask (logior mask ?\H-\0)))
+            ((eq modifier 'super)
+             (setq mask (logior mask ?\s-\0)))
+            ((eq modifier 'alt)
+             (setq mask (logior mask ?\A-\0)))))
+    mask))
+
+(defun haiku-dnd-wheel-modifier-type (flags)
+  "Return the modifier type of an internal modifier mask.
+FLAGS is the internal modifier mask of a turn of the mouse wheel."
+  (let ((modifiers (logior ?\M-\0 ?\C-\0 ?\S-\0
+                          ?\H-\0 ?\s-\0 ?\A-\0)))
+    (catch 'type
+      (dolist (modifier mouse-wheel-scroll-amount)
+        (when (and (consp modifier)
+                   (eq (haiku-dnd-modifier-mask (car modifier))
+                       (logand flags modifiers)))
+          (throw 'type (cdr modifier))))
+      nil)))
+
+(defun haiku-handle-drag-wheel (frame x y horizontal up modifiers)
+  "Handle wheel movement during drag-and-drop.
+FRAME is the frame on top of which the wheel moved.
+X and Y are the frame-relative coordinates of the wheel movement.
+HORIZONTAL is whether or not the wheel movement was horizontal.
+UP is whether or not the wheel moved up (or left).
+MODIFIERS is the internal modifier mask of the wheel movement."
+  (when (not (equal haiku-last-wheel-direction
+                    (cons horizontal up)))
+    (setq haiku-last-wheel-direction
+          (cons horizontal up))
+    (when (consp haiku-dnd-wheel-count)
+      (setcar haiku-dnd-wheel-count 0)))
+  (let ((type (haiku-dnd-wheel-modifier-type modifiers))
+        (function (cond
+                   ((and (not horizontal) (not up))
+                    mwheel-scroll-up-function)
+                   ((not horizontal)
+                    mwheel-scroll-down-function)
+                   ((not up) (if mouse-wheel-flip-direction
+                                 mwheel-scroll-right-function
+                               mwheel-scroll-left-function))
+                   (t (if mouse-wheel-flip-direction
+                          mwheel-scroll-left-function
+                        mwheel-scroll-right-function))))
+        (timestamp (time-convert nil 1000))
+        (amt 1))
+    (cond ((and (eq type 'hscroll)
+                (not horizontal))
+           (setq function (if (not up)
+                              mwheel-scroll-left-function
+                            mwheel-scroll-right-function)))
+          ((and (eq type 'global-text-scale))
+           (setq function 'global-text-scale-adjust
+                 amt (if up 1 -1)))
+          ((and (eq type 'text-scale))
+           (setq function 'text-scale-adjust
+                 amt (if up 1 -1))))
+    (when function
+      (let ((posn (posn-at-x-y x y frame)))
+        (when (windowp (posn-window posn))
+          (with-selected-window (posn-window posn)
+            (funcall function
+                     (* amt
+                        (or (and (not mouse-wheel-progressive-speed) 1)
+                            (haiku-note-wheel-click (car timestamp)))))))))))
+
+(setq haiku-drag-wheel-function #'haiku-handle-drag-wheel)
 
 
 ;;;; Session management.
diff --git a/lisp/term/ns-win.el b/lisp/term/ns-win.el
index 84c5b087b9..82b6281eb6 100644
--- a/lisp/term/ns-win.el
+++ b/lisp/term/ns-win.el
@@ -97,8 +97,6 @@ The properties returned may include `top', `left', `height', 
and `width'."
 
 ;;;; Keyboard mapping.
 
-(define-obsolete-variable-alias 'ns-alternatives-map 'x-alternatives-map 
"24.1")
-
 ;; Here are some Nextstep-like bindings for command key sequences.
 (define-key global-map [?\s-,] 'customize)
 (define-key global-map [?\s-'] 'next-window-any-frame)
@@ -437,13 +435,14 @@ Lines are highlighted according to `ns-input-line'."
 ;; nsterm.m
 
 (declare-function ns-read-file-name "nsfns.m"
-                 (prompt &optional dir mustmatch init dir_only_p))
+                 (prompt &optional dir mustmatch init dir-only-p))
 
 ;;;; File handling.
 
-(defun x-file-dialog (prompt dir default_filename mustmatch only_dir_p)
+(defun x-file-dialog (prompt dir &optional default-filename
+                             mustmatch only-dir-p)
   "SKIP: real doc in xfns.c."
-  (ns-read-file-name prompt dir mustmatch default_filename only_dir_p))
+  (ns-read-file-name prompt dir mustmatch default-filename only-dir-p))
 
 (defun ns-open-file-using-panel ()
   "Pop up open-file panel, and load the result in a buffer."
@@ -682,10 +681,6 @@ See the documentation of 
`create-fontset-from-fontset-spec' for the format.")
 
 ;;;; Pasteboard support.
 
-(define-obsolete-function-alias 'ns-store-cut-buffer-internal
-  'gui-set-selection "24.1")
-
-
 (defun ns-copy-including-secondary ()
   (interactive)
   (call-interactively 'kill-ring-save)
diff --git a/lisp/term/pgtk-win.el b/lisp/term/pgtk-win.el
index 8abea3edba..b93e259d82 100644
--- a/lisp/term/pgtk-win.el
+++ b/lisp/term/pgtk-win.el
@@ -38,6 +38,7 @@
 (require 'menu-bar)
 (require 'fontset)
 (require 'dnd)
+(require 'pgtk-dnd)
 
 (defvar x-invocation-args)
 (defvar x-command-line-resources)
@@ -228,7 +229,7 @@ EVENT is a `preedit-text-event'."
   '(
     ("etc/images/new" . ("document-new" "gtk-new"))
     ("etc/images/open" . ("document-open" "gtk-open"))
-    ("etc/images/diropen" . "n:system-file-manager")
+    ("etc/images/diropen" . "gtk-directory")
     ("etc/images/close" . ("window-close" "gtk-close"))
     ("etc/images/save" . ("document-save" "gtk-save"))
     ("etc/images/saveas" . ("document-save-as" "gtk-save-as"))
@@ -389,6 +390,10 @@ Users should not call this function; see `device-class' 
instead."
 
 (defvaralias 'x-gtk-use-system-tooltips 'use-system-tooltips)
 
+
+(define-key special-event-map [drag-n-drop] 
#'pgtk-dnd-handle-drag-n-drop-event)
+(add-hook 'after-make-frame-functions #'pgtk-dnd-init-frame)
+
 (provide 'pgtk-win)
 (provide 'term/pgtk-win)
 
diff --git a/lisp/term/w32-win.el b/lisp/term/w32-win.el
index 7eaa604776..993f1d4320 100644
--- a/lisp/term/w32-win.el
+++ b/lisp/term/w32-win.el
@@ -81,7 +81,6 @@
                   (&optional frame exclude-proportional))
 
 (defvar w32-color-map) ;; defined in w32fns.c
-(make-obsolete 'w32-default-color-map nil "24.1")
 
 (declare-function w32-send-sys-command "w32fns.c")
 (declare-function set-message-beep "w32fns.c")
diff --git a/lisp/term/x-win.el b/lisp/term/x-win.el
index 1f29b24ef2..38266baa96 100644
--- a/lisp/term/x-win.el
+++ b/lisp/term/x-win.el
@@ -1171,9 +1171,6 @@ as returned by `x-server-vendor'."
 
 ;;;; Selections
 
-(define-obsolete-function-alias 'x-cut-buffer-or-selection-value
-  'x-selection-value "24.1")
-
 ;; Arrange for the kill and yank functions to set and check the clipboard.
 
 (defun x-clipboard-yank ()
@@ -1182,8 +1179,12 @@ as returned by `x-server-vendor'."
   (interactive "*")
   (let ((clipboard-text (gui--selection-value-internal 'CLIPBOARD))
        (select-enable-clipboard t))
-    (if (and clipboard-text (> (length clipboard-text) 0))
-       (kill-new clipboard-text))
+    (when (and clipboard-text (> (length clipboard-text) 0))
+      ;; Avoid asserting ownership of CLIPBOARD, which will cause
+      ;; `gui-selection-value' to return nil in the future.
+      ;; (bug#56273)
+      (let ((select-enable-clipboard nil))
+        (kill-new clipboard-text)))
     (yank)))
 
 (declare-function accelerate-menu "xmenu.c" (&optional frame) t)
@@ -1291,14 +1292,6 @@ This returns an error if any Emacs frames are X frames."
                    (cons (cons 'width (cdr (assq 'width parsed)))
                          default-frame-alist))))))
 
-  ;; Check the reverseVideo resource.
-  (let ((case-fold-search t))
-    (let ((rv (x-get-resource "reverseVideo" "ReverseVideo")))
-      (if (and rv
-              (string-match "^\\(true\\|yes\\|on\\)$" rv))
-         (setq default-frame-alist
-               (cons '(reverse . t) default-frame-alist)))))
-
   ;; Set x-selection-timeout, measured in milliseconds.
   (let ((res-selection-timeout (x-get-resource "selectionTimeout"
                                               "SelectionTimeout")))
@@ -1374,7 +1367,8 @@ This returns an error if any Emacs frames are X frames."
 (cl-defmethod gui-backend-get-selection (selection-symbol target-type
                                          &context (window-system x)
                                          &optional time-stamp terminal)
-  (x-get-selection-internal selection-symbol target-type time-stamp terminal))
+  (x-get-selection-internal selection-symbol target-type
+                            time-stamp terminal))
 
 ;; Initiate drag and drop
 (add-hook 'after-make-frame-functions 'x-dnd-init-frame)
@@ -1386,7 +1380,7 @@ This returns an error if any Emacs frames are X frames."
   '(
     ("etc/images/new" . ("document-new" "gtk-new"))
     ("etc/images/open" . ("document-open" "gtk-open"))
-    ("etc/images/diropen" . "n:system-file-manager")
+    ("etc/images/diropen" . "gtk-directory")
     ("etc/images/close" . ("window-close" "gtk-close"))
     ("etc/images/save" . ("document-save" "gtk-save"))
     ("etc/images/saveas" . ("document-save-as" "gtk-save-as"))
@@ -1574,8 +1568,7 @@ frames on all displays."
 
 (defun x-dnd-movement (_frame position)
   "Handle movement to POSITION during drag-and-drop."
-  (dnd-handle-movement position)
-  (redisplay))
+  (dnd-handle-movement position))
 
 (defun x-device-class (name)
   "Return the device class of NAME.
diff --git a/lisp/term/xterm.el b/lisp/term/xterm.el
index a7e257f41c..08e38c9a05 100644
--- a/lisp/term/xterm.el
+++ b/lisp/term/xterm.el
@@ -66,7 +66,7 @@ If you select a region larger than this size, it won't be 
copied to your system
 clipboard.  Since clipboard data is base 64 encoded, the actual number of
 string bytes that can be copied is 3/4 of this value."
   :version "25.1"
-  :type 'integer)
+  :type 'natnum)
 
 (defcustom xterm-set-window-title nil
   "Whether Emacs should set window titles to an Emacs frame in an XTerm."
diff --git a/lisp/textmodes/artist.el b/lisp/textmodes/artist.el
index ff4311c3ac..2cf9ded04b 100644
--- a/lisp/textmodes/artist.el
+++ b/lisp/textmodes/artist.el
@@ -46,8 +46,8 @@
 ;;
 ;; * Rubber-banding: When drawing lines you can interactively see the
 ;;   result while holding the mouse button down and moving the mouse.  If
-;;   your machine is not fast enough (a 386 is a bit to slow, but a
-;;   pentium is well enough), you can turn this feature off.  You will
+;;   your machine is not fast enough (a 386 is a bit too slow, but a
+;;   Pentium is good enough), you can turn this feature off.  You will
 ;;   then see 1's and 2's which mark the 1st and 2nd endpoint of the line
 ;;   you are drawing.
 ;;
@@ -75,10 +75,10 @@
 ;; * Flood-filling: You can fill any area with a certain character by
 ;;   flood-filling.
 ;;
-;; * Cut copy and paste: You can cut, copy and paste rectangular
+;; * Cut, copy and paste: You can cut, copy and paste rectangular
 ;;   regions.  Artist also interfaces with the rect package (this can be
 ;;   turned off if it causes you any trouble) so anything you cut in
-;;   artist can be yanked with C-x r y and vice versa.
+;;   artist can be yanked with `C-x r y' and vice versa.
 ;;
 ;; * Drawing with keys: Everything you can do with the mouse, you can
 ;;   also do without the mouse.
@@ -86,7 +86,7 @@
 ;; * Arrows: After having drawn a (straight) line or a (straight)
 ;;   poly-line, you can set arrows on the line-ends by typing < or >.
 ;;
-;; * Aspect-ratio: You can set the variable artist-aspect-ratio to
+;; * Aspect-ratio: You can set the user option `artist-aspect-ratio' to
 ;;   reflect the height-width ratio for the font you are using.  Squares
 ;;   and circles are then drawn square/round.  Note, that once your
 ;;   ascii-file is shown with font with a different height-width ratio,
@@ -95,7 +95,7 @@
 ;; * Picture mode compatibility: Artist is picture mode compatible (this
 ;;   can be turned off).
 ;;
-;; See the documentation for the function artist-mode for a detailed
+;; See the documentation for the function `artist-mode' for a detailed
 ;; description on how to use artist.
 ;;
 ;;
@@ -119,8 +119,8 @@
 ;;; Known bugs:
 
 ;; It is not possible to change between shifted and unshifted operation
-;; while drawing with the mouse. (See the comment in the function
-;; artist-shift-has-changed for further details.)
+;; while drawing with the mouse.  (See the comment in the function
+;; `artist-shift-has-changed' for further details.)
 
 
 ;;; ChangeLog:
@@ -149,9 +149,9 @@
 ;;
 ;; 1.2.1       15-Nov-2000
 ;; New:                Documentation fixes.
-;; Bugfix:     Sets next-line-add-newlines to t while in artist-mode.
+;; Bugfix:     Set `next-line-add-newlines' to t while in `artist-mode'.
 ;;             Drawing with keys was confusing without this fix, if
-;;             next-line-add-newlines was set to nil.
+;;             `next-line-add-newlines' was set to nil.
 ;;             Thanks to Tatsuo Furukawa <tatsuo@kobe.hp.com> for this.
 ;;
 ;; 1.2         22-Oct-2000
@@ -184,7 +184,6 @@
 
 ;; Variables
 
-(defconst artist-version "1.2.6")
 (defconst artist-maintainer-address "tab@lysator.liu.se, 
bug-gnu-emacs@gnu.org")
 
 (defvar x-pointer-crosshair)
@@ -463,7 +462,7 @@ This variable is initialized by the 
`artist-make-prev-next-op-alist' function.")
 (if artist-picture-compatibility
     (require 'picture))
 
-;; Variables that are made local in artist-mode-init
+;; Variables that are made local in `artist-mode-init'
 (defvar artist-key-is-drawing nil)
 (defvar artist-key-endpoint1 nil)
 (defvar artist-key-poly-point-list nil)
@@ -475,60 +474,57 @@ This variable is initialized by the 
`artist-make-prev-next-op-alist' function.")
 (defvar artist-arrow-point-1 nil)
 (defvar artist-arrow-point-2 nil)
 
-(defvar artist-mode-map
-  (let ((map (make-sparse-keymap)))
-    (setq artist-mode-map (make-sparse-keymap))
-    (define-key map [down-mouse-1] 'artist-down-mouse-1)
-    (define-key map [S-down-mouse-1] 'artist-down-mouse-1)
-    (define-key map [down-mouse-2] 'artist-mouse-choose-operation)
-    (define-key map [S-down-mouse-2] 'artist-mouse-choose-operation)
-    (define-key map [down-mouse-3] 'artist-down-mouse-3)
-    (define-key map [S-down-mouse-3] 'artist-down-mouse-3)
-    (define-key map [C-mouse-4] 'artist-select-prev-op-in-list)
-    (define-key map [C-mouse-5] 'artist-select-next-op-in-list)
-    (define-key map "\r" 'artist-key-set-point) ; return
-    (define-key map [up] 'artist-previous-line)
-    (define-key map "\C-p" 'artist-previous-line)
-    (define-key map [down] 'artist-next-line)
-    (define-key map "\C-n" 'artist-next-line)
-    (define-key map [left] 'artist-backward-char)
-    (define-key map "\C-b" 'artist-backward-char)
-    (define-key map [right] 'artist-forward-char)
-    (define-key map "\C-f" 'artist-forward-char)
-    (define-key map "<" 'artist-toggle-first-arrow)
-    (define-key map ">" 'artist-toggle-second-arrow)
-    (define-key map "\C-c\C-a\C-e" 'artist-select-erase-char)
-    (define-key map "\C-c\C-a\C-f" 'artist-select-fill-char)
-    (define-key map "\C-c\C-a\C-l" 'artist-select-line-char)
-    (define-key map "\C-c\C-a\C-o" 'artist-select-operation)
-    (define-key map "\C-c\C-a\C-r" 'artist-toggle-rubber-banding)
-    (define-key map "\C-c\C-a\C-t" 'artist-toggle-trim-line-endings)
-    (define-key map "\C-c\C-a\C-s" 'artist-toggle-borderless-shapes)
-    (define-key map "\C-c\C-c"     'artist-mode-off)
-    (define-key map "\C-c\C-al"    'artist-select-op-line)
-    (define-key map "\C-c\C-aL"    'artist-select-op-straight-line)
-    (define-key map "\C-c\C-ar"    'artist-select-op-rectangle)
-    (define-key map "\C-c\C-aR"    'artist-select-op-square)
-    (define-key map "\C-c\C-as"    'artist-select-op-square)
-    (define-key map "\C-c\C-ap"    'artist-select-op-poly-line)
-    (define-key map "\C-c\C-aP"    'artist-select-op-straight-poly-line)
-    (define-key map "\C-c\C-ae"    'artist-select-op-ellipse)
-    (define-key map "\C-c\C-ac"    'artist-select-op-circle)
-    (define-key map "\C-c\C-at"    'artist-select-op-text-see-thru)
-    (define-key map "\C-c\C-aT"    'artist-select-op-text-overwrite)
-    (define-key map "\C-c\C-aS"    'artist-select-op-spray-can)
-    (define-key map "\C-c\C-az"    'artist-select-op-spray-set-size)
-    (define-key map "\C-c\C-a\C-d" 'artist-select-op-erase-char)
-    (define-key map "\C-c\C-aE"    'artist-select-op-erase-rectangle)
-    (define-key map "\C-c\C-av"    'artist-select-op-vaporize-line)
-    (define-key map "\C-c\C-aV"    'artist-select-op-vaporize-lines)
-    (define-key map "\C-c\C-a\C-k" 'artist-select-op-cut-rectangle)
-    (define-key map "\C-c\C-a\M-w" 'artist-select-op-copy-rectangle)
-    (define-key map "\C-c\C-a\C-y" 'artist-select-op-paste)
-    (define-key map "\C-c\C-af"    'artist-select-op-flood-fill)
-    (define-key map "\C-c\C-a\C-b" 'artist-submit-bug-report)
-    map)
-  "Keymap for `artist-mode'.")
+(defvar-keymap artist-mode-map
+  :doc "Keymap for `artist-mode'."
+  "<down-mouse-1>"   #'artist-down-mouse-1
+  "S-<down-mouse-1>" #'artist-down-mouse-1
+  "<down-mouse-2>"   #'artist-mouse-choose-operation
+  "S-<down-mouse-2>" #'artist-mouse-choose-operation
+  "<down-mouse-3>"   #'artist-down-mouse-3
+  "S-<down-mouse-3>" #'artist-down-mouse-3
+  "C-<mouse-4>"      #'artist-select-prev-op-in-list
+  "C-<mouse-5>"      #'artist-select-next-op-in-list
+  "RET"              #'artist-key-set-point ; return
+  "<up>"             #'artist-previous-line
+  "C-p"              #'artist-previous-line
+  "<down>"           #'artist-next-line
+  "C-n"              #'artist-next-line
+  "<left>"           #'artist-backward-char
+  "C-b"              #'artist-backward-char
+  "<right>"          #'artist-forward-char
+  "C-f"              #'artist-forward-char
+  "<"                #'artist-toggle-first-arrow
+  ">"                #'artist-toggle-second-arrow
+  "C-c C-a C-e"      #'artist-select-erase-char
+  "C-c C-a C-f"      #'artist-select-fill-char
+  "C-c C-a C-l"      #'artist-select-line-char
+  "C-c C-a C-o"      #'artist-select-operation
+  "C-c C-a C-r"      #'artist-toggle-rubber-banding
+  "C-c C-a C-t"      #'artist-toggle-trim-line-endings
+  "C-c C-a C-s"      #'artist-toggle-borderless-shapes
+  "C-c C-c"          #'artist-mode-off
+  "C-c C-a l"        #'artist-select-op-line
+  "C-c C-a L"        #'artist-select-op-straight-line
+  "C-c C-a r"        #'artist-select-op-rectangle
+  "C-c C-a R"        #'artist-select-op-square
+  "C-c C-a s"        #'artist-select-op-square
+  "C-c C-a p"        #'artist-select-op-poly-line
+  "C-c C-a P"        #'artist-select-op-straight-poly-line
+  "C-c C-a e"        #'artist-select-op-ellipse
+  "C-c C-a c"        #'artist-select-op-circle
+  "C-c C-a t"        #'artist-select-op-text-see-thru
+  "C-c C-a T"        #'artist-select-op-text-overwrite
+  "C-c C-a S"        #'artist-select-op-spray-can
+  "C-c C-a z"        #'artist-select-op-spray-set-size
+  "C-c C-a C-d"      #'artist-select-op-erase-char
+  "C-c C-a E"        #'artist-select-op-erase-rectangle
+  "C-c C-a v"        #'artist-select-op-vaporize-line
+  "C-c C-a V"        #'artist-select-op-vaporize-lines
+  "C-c C-a C-k"      #'artist-select-op-cut-rectangle
+  "C-c C-a M-w"      #'artist-select-op-copy-rectangle
+  "C-c C-a C-y"      #'artist-select-op-paste
+  "C-c C-a f"        #'artist-select-op-flood-fill
+  "C-c C-a C-b"      #'artist-submit-bug-report)
 
 (easy-menu-define artist-menu-map artist-mode-map
   "Menu for `artist-mode'."
@@ -1335,25 +1331,25 @@ Variables
  This is a brief overview of the different variables.  For more info,
  see the documentation for the variables (type \\[describe-variable] 
<variable> RET).
 
- artist-rubber-banding         Interactively do rubber-banding or not
- artist-first-char             What to set at first/second point...
- artist-second-char            ...when not rubber-banding
- artist-interface-with-rect    If cut/copy/paste should interface with rect
- artist-arrows                 The arrows to use when drawing arrows
- artist-aspect-ratio           Character height-to-width for squares
- artist-trim-line-endings      Trimming of line endings
- artist-flood-fill-right-border        Right border when flood-filling
- artist-flood-fill-show-incrementally  Update display while filling
- artist-pointer-shape          Pointer shape to use while drawing
- artist-ellipse-left-char      Character to use for narrow ellipses
- artist-ellipse-right-char     Character to use for narrow ellipses
- artist-borderless-shapes       If shapes should have borders
- artist-picture-compatibility   Whether or not to be picture mode compatible
- artist-vaporize-fuzziness      Tolerance when recognizing lines
- artist-spray-interval          Seconds between repeated sprayings
- artist-spray-radius            Size of the spray-area
- artist-spray-chars             The spray-\"color\"
- artist-spray-new-chars         Initial spray-\"color\"
+ `artist-rubber-banding'              Interactively do rubber-banding or not
+ `artist-first-char'                  What to set at first/second point...
+ `artist-second-char'                 ...when not rubber-banding
+ `artist-interface-with-rect'         Should cut/copy/paste interface with rect
+ `artist-arrows'                      The arrows to use when drawing arrows
+ `artist-aspect-ratio'                Character height-to-width for squares
+ `artist-trim-line-endings'           Trimming of line endings
+ `artist-flood-fill-right-border'     Right border when flood-filling
+ `artist-flood-fill-show-incrementally'  Update display while filling
+ `artist-pointer-shape'               Pointer shape to use while drawing
+ `artist-ellipse-left-char'           Character to use for narrow ellipses
+ `artist-ellipse-right-char'          Character to use for narrow ellipses
+ `artist-borderless-shapes'           If shapes should have borders
+ `artist-picture-compatibility'       Picture mode compatibility on or off
+ `artist-vaporize-fuzziness'          Tolerance when recognizing lines
+ `artist-spray-interval'              Seconds between repeated sprayings
+ `artist-spray-radius'                Size of the spray-area
+ `artist-spray-chars'                 The spray-\"color\"
+ `artist-spray-new-char'              Initial spray-\"color\"
 
 Hooks
 
@@ -5364,7 +5360,7 @@ The event, EV, is the mouse event."
                (setq vars (delq x vars)))) vars)
        (reporter-submit-bug-report
         artist-maintainer-address
-        (concat "artist.el " artist-version)
+         (concat "artist.el in Emacs " emacs-version)
         vars
         nil nil
         (concat "Hello Tomas,\n\n"
@@ -5372,6 +5368,9 @@ The event, EV, is the mouse event."
 
 (define-obsolete-function-alias 'artist-uniq #'seq-uniq "28.1")
 
+(defconst artist-version "1.2.6")
+(make-obsolete-variable 'artist-version 'emacs-version "29.1")
+
 (provide 'artist)
 
 
diff --git a/lisp/textmodes/bib-mode.el b/lisp/textmodes/bib-mode.el
index 6168fed6c8..af49464d1e 100644
--- a/lisp/textmodes/bib-mode.el
+++ b/lisp/textmodes/bib-mode.el
@@ -24,12 +24,10 @@
 
 ;;; Commentary:
 
-;;   GNU Emacs code to help maintain databases compatible with (troff)
-;;   refer and lookbib.  The file bib-file should be set to your
-;;   bibliography file.  Keys are automagically inserted as you type,
-;;   and appropriate keys are presented for various kinds of entries.
-
-;; FIXME: Fix the namespace use of this library.
+;; GNU Emacs code to help maintain databases compatible with (troff)
+;; refer and lookbib.  The file `bib-file' should be set to your
+;; bibliography file.  Keys are automagically inserted as you type,
+;; and appropriate keys are presented for various kinds of entries.
 
 ;;; Code:
 
@@ -40,23 +38,23 @@
   :group 'text)
 
 (defcustom bib-file "~/my-bibliography.bib"
-  "Default name of file used by `addbib'."
+  "Default name of file used by `bib-add'."
   :type 'file)
 
-(defcustom unread-bib-file "~/to-be-read.bib"
-   "Default name of file used by `unread-bib' in Bib mode."
-   :type 'file)
+(define-obsolete-variable-alias 'unread-bib-file 'bib-unread-file "29.1")
+(defcustom bib-unread-file "~/to-be-read.bib"
+  "Default name of file used by `bib-unread' in Bib mode."
+  :type 'file
+  :version "29.1")
 
-(defvar bib-mode-map
-  (let ((map (make-sparse-keymap)))
-    (set-keymap-parent map text-mode-map)
-    (define-key map "\C-M" #'return-key-bib)
-    (define-key map "\C-c\C-u" #'unread-bib)
-    (define-key map "\C-c\C-@" #'mark-bib)
-    (define-key map "\e`" #'abbrev-mode)
-    map))
+(defvar-keymap bib-mode-map
+  :parent text-mode-map
+  "RET"     #'bib-return-key
+  "C-c C-u" #'bib-unread
+  "C-c C-@" #'bib-mark
+  "M-`"     #'abbrev-mode)
 
-(defun addbib ()
+(defun bib-add ()
    "Set up editor to add to troff bibliography file specified
 by global variable `bib-file'.  See description of `bib-mode'."
    (interactive)
@@ -87,10 +85,10 @@ R eport number or `phd thesis' or `masters thesis' or 
`draft' or
 W here can be found locally (login name, or ailib, etc.)
 X comments (not used in indexing)
 
-\\[unread-bib] appends current entry to a different file (for example,
+\\[bib-unread] appends current entry to a different file (for example,
 a file of papers to be read in the future), given by the value of the
-variable `unread-bib-file'.
-\\[mark-bib] marks current or previous entry.
+variable `bib-unread-file'.
+\\[bib-mark] marks current or previous entry.
 Abbreviations are saved in `bib-mode-abbrev-table'.
 Hook can be stored in `bib-mode-hook'.
 Field keys given by variable `bib-assoc'.
@@ -142,7 +140,7 @@ with the cdr.")
 
 (defconst bib-capitalized-fields "%[AETCBIJR]")
 
-(defun return-key-bib ()
+(defun bib-return-key ()
   "Magic when user hits return, used by `bib-mode'."
   (interactive)
   (if (eolp)
@@ -172,7 +170,7 @@ with the cdr.")
       (insert new-key))
     (newline)))
 
-(defun mark-bib ()
+(defun bib-mark ()
    "Set mark at beginning of current or previous bib entry, point at end."
    (interactive)
    (beginning-of-line nil)
@@ -185,14 +183,14 @@ with the cdr.")
    (forward-line 1)
    (beginning-of-line nil))
 
-(defun unread-bib ()
-   "Append current or previous entry to file of unread papers
-named by variable `unread-bib-file'."
-   (interactive)
-   (mark-bib)
-   (if (get-file-buffer unread-bib-file)
-      (append-to-buffer (get-file-buffer unread-bib-file) (mark) (point))
-      (append-to-file (mark) (point) unread-bib-file)))
+(defun bib-unread ()
+  "Append current or previous entry to file of unread papers
+named by variable `bib-unread-file'."
+  (interactive)
+  (bib-mark)
+  (if (get-file-buffer bib-unread-file)
+      (append-to-buffer (get-file-buffer bib-unread-file) (mark) (point))
+    (append-to-file (mark) (point) bib-unread-file)))
 
 
 (defvar bib-capitalize-title-stop-words
@@ -226,14 +224,17 @@ named by variable `unread-bib-file'."
               ))
         (set-syntax-table orig-syntax-table))))
 
-
 (defun bib-capitalize-title (s)
-   "Like `capitalize', but don't capitalize stop words, except the first."
-   (with-current-buffer (get-buffer-create "$$$Scratch$$$")
-     (erase-buffer)
-     (insert s)
-     (bib-capitalize-title-region (point-min) (point-max))
-     (buffer-string)))
+  "Like `capitalize', but don't capitalize stop words, except the first."
+  (with-temp-buffer
+    (insert s)
+    (bib-capitalize-title-region (point-min) (point-max))
+    (buffer-string)))
+
+(define-obsolete-function-alias 'addbib #'bib-add "29.1")
+(define-obsolete-function-alias 'return-key-bib #'bib-return-key "29.1")
+(define-obsolete-function-alias 'mark-bib #'bib-mark "29.1")
+(define-obsolete-function-alias 'unread-bib #'bib-unread "29.1")
 
 (provide 'bib-mode)
 
diff --git a/lisp/textmodes/bibtex.el b/lisp/textmodes/bibtex.el
index 544e0da827..8135d40d26 100644
--- a/lisp/textmodes/bibtex.el
+++ b/lisp/textmodes/bibtex.el
@@ -316,8 +316,6 @@ If parsing fails, try to set this variable to nil."
                                        (option (choice :tag "Alternative" 
:value nil
                                                        (const nil) 
integer)))))))
 
-(define-obsolete-variable-alias 'bibtex-entry-field-alist
-  'bibtex-BibTeX-entry-alist "24.1")
 (defcustom bibtex-BibTeX-entry-alist
   '(("Article" "Article in Journal"
      (("author")
@@ -2217,6 +2215,7 @@ Point must be at beginning of preamble.  Do not move 
point."
 
 (defsubst bibtex-string= (str1 str2)
   "Return t if STR1 and STR2 are equal, ignoring case."
+  (declare (obsolete string-equal-ignore-case "29.1"))
   (eq t (compare-strings str1 0 nil str2 0 nil t)))
 
 (defun bibtex-delete-whitespace ()
@@ -2659,7 +2658,7 @@ Formats current entry according to variable 
`bibtex-entry-format'."
 
                     ;; update page dashes
                     (if (and (memq 'page-dashes format)
-                             (bibtex-string= field-name "pages")
+                             (string-equal-ignore-case field-name "pages")
                              (progn (goto-char beg-text)
                                     (looking-at
                                      "\\([\"{][0-9]+\\)[ \t\n]*--?[ 
\t\n]*\\([0-9]+[\"}]\\)")))
@@ -2712,7 +2711,7 @@ Formats current entry according to variable 
`bibtex-entry-format'."
                     ;; use book title of crossref'd entry
                     (if (and (memq 'inherit-booktitle format)
                              empty-field
-                             (bibtex-string= field-name "booktitle")
+                             (string-equal-ignore-case field-name "booktitle")
                              crossref-key)
                         (let ((title (save-excursion
                                        (save-restriction
@@ -3505,7 +3504,7 @@ If NO-BUTTON is non-nil do not generate buttons."
           (let ((lst bibtex-generate-url-list) url)
             (while (and (not found) (setq url (car (pop lst))))
               (goto-char start)
-              (setq found (and (bibtex-string= name (car url))
+              (setq found (and (string-equal-ignore-case name (car url))
                                (re-search-forward (cdr url) end t))))))
       (unless found (goto-char end)))
     (if (and found (not no-button))
@@ -3661,7 +3660,11 @@ if that value is non-nil.
                                         ?\s)))))
     (if (and buffer-file-name enable-local-variables)
         (add-hook 'hack-local-variables-hook fun nil t)
-      (funcall fun))))
+      (funcall fun)))
+  ;; We may be using the mode programmatically to extract data, and we
+  ;; then need this to be set up first so that sexp-based movement
+  ;; commands don't bug out.
+  (font-lock-set-defaults))
 
 (defun bibtex-entry-alist (dialect)
   "Return entry-alist for DIALECT."
@@ -3673,14 +3676,6 @@ if that value is non-nil.
     (if (not (consp (nth 1 (car entry-alist))))
         ;; new format
         entry-alist
-      ;; Convert old format of `bibtex-entry-field-alist'
-      (unless (get var 'entry-list-format)
-        (put var 'entry-list-format "pre-24")
-        (message "Old format of `%s' (pre GNU Emacs 24).
-Please convert to the new format."
-                 (if (eq (indirect-variable 'bibtex-entry-field-alist) var)
-                     'bibtex-entry-field-alist var))
-        (sit-for 3))
       (let (lst)
         (dolist (entry entry-alist)
           (let ((fl (nth 1 entry)) req xref opt)
@@ -3960,7 +3955,7 @@ entry (for example, the year parts of the keys)."
        (goto-char (1- (match-beginning 0)))
        (bibtex-beginning-of-entry)
        (if (and (looking-at bibtex-entry-head)
-                 (bibtex-string= type (bibtex-type-in-head))
+                 (string-equal-ignore-case type (bibtex-type-in-head))
                  ;; In case we found ourselves :-(
                  (not (equal key (setq tmp (bibtex-key-in-head)))))
          (setq other-key tmp
@@ -3969,7 +3964,7 @@ entry (for example, the year parts of the keys)."
        (bibtex-end-of-entry)
        (bibtex-skip-to-valid-entry)
        (if (and (looking-at bibtex-entry-head)
-                 (bibtex-string= type (bibtex-type-in-head))
+                 (string-equal-ignore-case type (bibtex-type-in-head))
                  ;; In case we found ourselves :-(
                  (not (equal key (setq tmp (bibtex-key-in-head))))
                  (or (not other-key)
@@ -4010,9 +4005,9 @@ interactive calls."
   (interactive (list nil t))
   (unless field (setq field (car (bibtex-find-text-internal nil nil comma))))
   (if (string-search "@" field)
-      (cond ((bibtex-string= field "@string")
+      (cond ((string-equal-ignore-case field "@string")
              (message "String definition"))
-            ((bibtex-string= field "@preamble")
+            ((string-equal-ignore-case field "@preamble")
              (message "Preamble definition"))
             (t (message "Entry key")))
     (let* ((case-fold-search t)
@@ -4594,7 +4589,7 @@ Return t if test was successful, nil otherwise."
                         bounds field idx)
                    (while (setq bounds (bibtex-parse-field))
                      (let ((field-name (bibtex-name-in-field bounds)))
-                       (if (and (bibtex-string= field-name "month")
+                       (if (and (string-equal-ignore-case field-name "month")
                                 ;; Check only abbreviated month fields.
                                 (let ((month (bibtex-text-in-field-bounds 
bounds)))
                                   (not (or (string-match "\\`[\"{].+[\"}]\\'" 
month)
@@ -4675,7 +4670,7 @@ Return t if test was successful, nil otherwise."
             (while (re-search-forward bibtex-entry-head nil t)
               (setq entry-type (bibtex-type-in-head)
                     key (bibtex-key-in-head))
-              (if (or (and strings (bibtex-string= entry-type "string"))
+              (if (or (and strings (string-equal-ignore-case entry-type 
"string"))
                       (assoc-string entry-type bibtex-entry-alist t))
                   (if (member key key-list)
                       (push (format-message
@@ -5052,10 +5047,10 @@ At end of the cleaning process, the functions in
               (user-error "Not inside a BibTeX entry")))
         (entry-type (bibtex-type-in-head))
         (key (bibtex-key-in-head)))
-    (cond ((bibtex-string= entry-type "preamble")
+    (cond ((string-equal-ignore-case entry-type "preamble")
            ;; (bibtex-format-preamble)
            (user-error "No clean up of @Preamble entries"))
-          ((bibtex-string= entry-type "string")
+          ((string-equal-ignore-case entry-type "string")
            (setq entry-type 'string))
           ;; (bibtex-format-string)
           (t (bibtex-format-entry)))
@@ -5318,7 +5313,6 @@ entries from minibuffer."
     (goto-char (point-max))
     (message "Buffer is now parsable.  Please save it.")))
 
-(define-obsolete-function-alias 'bibtex-complete #'completion-at-point "24.1")
 (defun bibtex-completion-at-point-function ()
   (let ((pnt (point))
         (case-fold-search t)
@@ -5333,10 +5327,10 @@ entries from minibuffer."
                (>= pnt (bibtex-start-of-text-in-field bounds))
                (<= pnt (bibtex-end-of-text-in-field bounds)))
           (setq name (bibtex-name-in-field bounds t)
-                compl (cond ((bibtex-string= name "crossref")
+                compl (cond ((string-equal-ignore-case name "crossref")
                              ;; point is in crossref field
                              'crossref-key)
-                            ((bibtex-string= name "month")
+                            ((string-equal-ignore-case name "month")
                              ;; point is in month field
                              bibtex-predefined-month-strings)
                             ;; point is in other field
@@ -5495,7 +5489,7 @@ Return the URL or nil if none can be generated."
             (while (and (not url) (setq scheme (pop lst)))
               ;; Verify the match of `bibtex-font-lock-url' by
               ;; comparing with TEXT.
-              (when (and (bibtex-string= (caar scheme) name)
+              (when (and (string-equal-ignore-case (caar scheme) name)
                          (string-match (cdar scheme) text))
                 (setq url t scheme (cdr scheme)))))))
 
diff --git a/lisp/textmodes/conf-mode.el b/lisp/textmodes/conf-mode.el
index f940de3ff4..c3c9af5a83 100644
--- a/lisp/textmodes/conf-mode.el
+++ b/lisp/textmodes/conf-mode.el
@@ -139,11 +139,9 @@ not align (only setting space according to 
`conf-assignment-space')."
   "Syntax table in use in Unix style `conf-mode' buffers.")
 
 (defvar conf-javaprop-mode-syntax-table
-  (let ((table (make-syntax-table conf-unix-mode-syntax-table)))
-    (modify-syntax-entry ?/  ". 124" table)
-    (modify-syntax-entry ?*  ". 23b" table)
-    table)
+  (make-syntax-table conf-unix-mode-syntax-table)
   "Syntax table in use in Java properties buffers.")
+(make-obsolete-variable 'conf-javaprop-mode-syntax-table nil "29.1")
 
 (defvar conf-ppd-mode-syntax-table
   (let ((table (make-syntax-table conf-mode-syntax-table)))
@@ -470,13 +468,9 @@ PersistMoniker=file://Folder.htt"
 ;;;###autoload
 (define-derived-mode conf-javaprop-mode conf-mode "Conf[JavaProp]"
   "Conf Mode starter for Java properties files.
-Comments start with `#' but are also recognized with `//' or
-between `/*' and `*/'.
-For details see `conf-mode'.  Example:
+Comments start with `#'.  Example:
 
 # Conf mode font-locks this right with \\[conf-javaprop-mode] (Java properties)
-// another kind of comment
-/* yet another */
 
 name:value
 name=value
@@ -487,7 +481,6 @@ x.2.y.1.z.2.zz ="
   (conf-mode-initialize "#" 'conf-javaprop-font-lock-keywords)
   (setq-local conf-assignment-column conf-javaprop-assignment-column)
   (setq-local conf-assignment-regexp ".+?\\([ \t]*[=: \t][ \t]*\\|$\\)")
-  (setq-local comment-start-skip "\\(?:#+\\|/[/*]+\\)\\s *")
   (setq-local imenu-generic-expression
              '(("Parameters" "^[ \t]*\\(.+?\\)[=: \t]" 1))))
 
diff --git a/lisp/textmodes/css-mode.el b/lisp/textmodes/css-mode.el
index a2a7774aba..d2a35bd550 100644
--- a/lisp/textmodes/css-mode.el
+++ b/lisp/textmodes/css-mode.el
@@ -1711,7 +1711,7 @@ be used to fill comments.
     ;; comment.
     (when (save-excursion
             (beginning-of-line)
-            (comment-search-forward (point-at-eol) t))
+            (comment-search-forward (line-end-position) t))
       (goto-char (match-end 0)))
     (let ((ppss (syntax-ppss))
           (eol (line-end-position)))
diff --git a/lisp/textmodes/dns-mode.el b/lisp/textmodes/dns-mode.el
index 42d547504c..86da09c216 100644
--- a/lisp/textmodes/dns-mode.el
+++ b/lisp/textmodes/dns-mode.el
@@ -1,6 +1,6 @@
 ;;; dns-mode.el --- a mode for viewing/editing Domain Name System master files 
 -*- lexical-binding: t -*-
 
-;; Copyright (C) 2000-2001, 2004-2022 Free Software Foundation, Inc.
+;; Copyright (C) 2000-2022 Free Software Foundation, Inc.
 
 ;; Author: Simon Josefsson <simon@josefsson.org>
 ;; Keywords: DNS master zone file SOA comm
@@ -22,11 +22,11 @@
 
 ;;; Commentary:
 
-;; Use M-x dns-mode RET to invoke in master files.
+;; Use `M-x dns-mode' to invoke in master files.
 ;;
-;; C-c C-s  Increment SOA serial.
-;;          Understands YYYYMMDDNN, Unix time, and serial number formats,
-;;          and complains if it fail to find SOA serial.
+;; `C-c C-s'  Increment SOA serial.
+;;            Understands YYYYMMDDNN, Unix time, and serial number
+;;            formats, and complains if it fail to find SOA serial.
 
 ;;; References:
 
@@ -37,12 +37,6 @@
 ;;             Transport Layer Security (TLS) Protocol: TLSA"
 ;; RFC 6844, "DNS Certification Authority Authorization (CAA) Resource Record"
 
-;;; Release history:
-
-;; 2004-09-11  Posted on gnu.emacs.sources.
-;; 2004-09-13  Ported to XEmacs.
-;; 2004-09-14  Installed in Emacs CVS.
-
 ;;; Code:
 
 (eval-when-compile (require 'cl-lib))
@@ -142,12 +136,10 @@ manually with \\[dns-mode-soa-increment-serial]."
 
 ;; Keymap.
 
-(defvar dns-mode-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "\C-c\C-s" #'dns-mode-soa-increment-serial)
-    (define-key map "\C-c\C-e" #'dns-mode-ipv6-to-nibbles)
-    map)
-  "Keymap for DNS master file mode.")
+(defvar-keymap dns-mode-map
+  :doc "Keymap for DNS master file mode."
+  "C-c C-s" #'dns-mode-soa-increment-serial
+  "C-c C-e" #'dns-mode-ipv6-to-nibbles)
 
 ;; Menu.
 
diff --git a/lisp/textmodes/emacs-authors-mode.el 
b/lisp/textmodes/emacs-authors-mode.el
new file mode 100644
index 0000000000..866822c103
--- /dev/null
+++ b/lisp/textmodes/emacs-authors-mode.el
@@ -0,0 +1,145 @@
+;;; emacs-authors-mode.el --- font-locking for etc/AUTHORS  -*- 
lexical-binding: t -*-
+
+;; Copyright (C) 2021-2022 Free Software Foundation, Inc.
+
+;; Author: Stefan Kangas <stefankangas@gmail.com>
+;; Keywords: internal
+
+;; 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:
+
+;; Major mode to display the etc/AUTHORS file from the Emacs
+;; distribution.  Provides some basic font locking and not much else.
+
+;;; Code:
+
+(require 'subr-x)    ; `emacs-etc--hide-local-variables'
+
+(defgroup emacs-authors-mode nil
+  "Display the \"etc/AUTHORS\" file from the Emacs distribution."
+  :version "29.1"
+  :group 'internal)
+
+(defface emacs-authors-default
+  '((t :inherit variable-pitch))
+  "Default face used to display the \"etc/AUTHORS\" file.
+See also `emacs-authors-mode'."
+  :version "29.1")
+
+(defface emacs-authors-author
+  '((((class color) (min-colors 88) (background light))
+     :foreground "midnight blue"
+     :weight bold :height 1.05
+     :inherit variable-pitch)
+    (((class color) (min-colors 88) (background dark))
+     :foreground "cyan"
+     :weight bold :height 1.05
+     :inherit variable-pitch)
+    (((supports :weight bold) (supports :height 1.05))
+     :weight bold :height 1.05
+     :inherit variable-pitch)
+    (((supports :weight bold))
+     :weight bold :inherit variable-pitch)
+    (t :inherit variable-pitch))
+  "Face used for the author in the \"etc/AUTHORS\" file.
+See also `emacs-authors-mode'."
+  :version "29.1")
+
+(defface emacs-authors-descriptor
+  '((((class color) (min-colors 88) (background light))
+     :foreground "sienna" :inherit variable-pitch)
+    (((class color) (min-colors 88) (background dark))
+     :foreground "peru" :inherit variable-pitch)
+    (t :inherit variable-pitch))
+  "Face used for the description text in the \"etc/AUTHORS\" file.
+See also `emacs-authors-mode'."
+  :version "29.1")
+
+(defface emacs-authors-other-files
+  '((t :inherit emacs-authors-descriptor))
+  "Face used for the \"other files\" text in the \"etc/AUTHORS\" file.
+See also `emacs-authors-mode'."
+  :version "29.1")
+
+(defconst emacs-authors--author-re
+  (rx bol (group (not (any blank "\n")) (+? (not (any ":" "\n")))) ":")
+  "Regexp matching an author in \"etc/AUTHORS\".")
+
+(defvar emacs-authors-mode-font-lock-keywords
+  `((,emacs-authors--author-re
+     1 'emacs-authors-author)
+    (,(rx (or "wrote"
+              (seq (? "and ") (or "co-wrote" "changed"))))
+     0 'emacs-authors-descriptor)
+    (,(rx "and " (+ digit) " other files")
+     0 'emacs-authors-other-files)
+    (,(rx bol (not space) (+ not-newline) eol)
+     0 'emacs-authors-default)))
+
+(defun emacs-authors-next-author (&optional arg)
+  "Move point to the next author in \"etc/AUTHORS\".
+With a prefix arg ARG, move point that many authors forward."
+  (interactive "p" emacs-authors-mode)
+  (if (< 0 arg)
+      (progn
+        (when (looking-at emacs-authors--author-re)
+          (forward-line 1))
+        (re-search-forward emacs-authors--author-re nil t arg))
+    (when (looking-at emacs-authors--author-re)
+      (forward-line -1))
+    (re-search-backward emacs-authors--author-re nil t (abs arg)))
+  (goto-char (line-beginning-position)))
+
+(defun emacs-authors-prev-author (&optional arg)
+  "Move point to the previous author in \"etc/AUTHORS\".
+With a prefix arg ARG, move point that many authors backward."
+  (interactive "p" emacs-authors-mode)
+  (emacs-authors-next-author (- arg)))
+
+(defvar emacs-authors-imenu-generic-expression
+  `((nil ,(rx bol (group (+ (not ":"))) ": "
+              (or "wrote" "co-wrote" "changed")
+              " ")
+         1)))
+
+(define-obsolete-variable-alias 'etc-authors-mode-map 'emacs-authors-mode-map 
"29.1")
+(defvar-keymap emacs-authors-mode-map
+  :doc "Keymap for `emacs-authors-mode'."
+  "n" #'emacs-authors-next-author
+  "p" #'emacs-authors-prev-author)
+
+;;;###autoload
+(define-derived-mode emacs-authors-mode special-mode "Authors View"
+  "Major mode for viewing \"etc/AUTHORS\" from the Emacs distribution.
+Provides some basic font locking and not much else."
+  (setq-local font-lock-defaults
+              '(emacs-authors-mode-font-lock-keywords nil nil ((?_ . "w"))))
+  (setq font-lock-multiline nil)
+  (setq imenu-generic-expression emacs-authors-imenu-generic-expression)
+  (emacs-etc--hide-local-variables))
+
+(define-obsolete-face-alias 'etc-authors-default 'emacs-authors-default "29.1")
+(define-obsolete-face-alias 'etc-authors-author 'emacs-authors-author "29.1")
+(define-obsolete-face-alias 'etc-authors-descriptor 'emacs-authors-descriptor 
"29.1")
+(define-obsolete-face-alias 'etc-authors-other-files 
'emacs-authors-other-files "29.1")
+(define-obsolete-function-alias 'etc-authors-next-author 
#'emacs-authors-next-author "29.1")
+(define-obsolete-function-alias 'etc-authors-prev-author 
#'emacs-authors-prev-author "29.1")
+;;;###autoload
+(define-obsolete-function-alias 'etc-authors-mode #'emacs-authors-mode "29.1")
+
+(provide 'emacs-authors-mode)
+;;; emacs-authors-mode.el ends here
diff --git a/lisp/textmodes/emacs-news-mode.el 
b/lisp/textmodes/emacs-news-mode.el
index fdb3cb8628..022e17c934 100644
--- a/lisp/textmodes/emacs-news-mode.el
+++ b/lisp/textmodes/emacs-news-mode.el
@@ -24,6 +24,8 @@
 ;;; Code:
 
 (eval-when-compile (require 'cl-lib))
+(require 'outline)
+(require 'subr-x)    ; `emacs-etc--hide-local-variables'
 
 (defgroup emacs-news-mode nil
   "Major mode for editing and viewing the Emacs NEWS file."
@@ -39,12 +41,31 @@
   "Face used for displaying the \"does not need documentation\" tag."
   :version "29.1")
 
+(defvar-keymap emacs-news-common-map
+  ;; Navigation like `org-mode'/`outline-minor-mode'.
+  "C-c C-f" #'outline-forward-same-level
+  "C-c C-b" #'outline-backward-same-level
+  "C-c C-n" #'outline-next-visible-heading
+  "C-c C-p" #'outline-previous-visible-heading
+  "C-c C-u" #'outline-up-heading)
+
 (defvar-keymap emacs-news-mode-map
+  :parent emacs-news-common-map
   "C-c C-s" #'emacs-news-next-untagged-entry
   "C-c C-r" #'emacs-news-previous-untagged-entry
+  "C-c C-t" #'emacs-news-toggle-tag
   "C-c C-g" #'emacs-news-goto-section
-  "C-c C-f" #'emacs-news-find-heading
-  "C-c C-n" #'emacs-news-count-untagged-entries)
+  "C-c C-j" #'emacs-news-find-heading
+  "C-c C-e" #'emacs-news-count-untagged-entries
+  "C-x C-q" #'emacs-news-view-mode
+  "<remap> <open-line>" #'emacs-news-open-line)
+
+(defvar emacs-news-view-mode-map
+  ;; This is defined this way instead of inheriting because we're
+  ;; deriving the mode from `special-mode' and want the keys from there.
+  (let ((map (copy-keymap emacs-news-common-map)))
+    (keymap-set map "C-x C-q" #'emacs-news-mode)
+    map))
 
 (defvar emacs-news-mode-font-lock-keywords
   `(("^---$" 0 'emacs-news-does-not-need-documentation)
@@ -52,17 +73,21 @@
 
 (defun emacs-news--mode-common ()
   (setq-local font-lock-defaults '(emacs-news-mode-font-lock-keywords t))
-  (setq-local outline-regexp "\\*+ "
+  (setq-local outline-regexp "\\(:? +\\)?\\(\\*+\\) "
               outline-minor-mode-cycle t
-              ;; We subtract one from the level, because we have a
-              ;; space after the asterisks.
-              outline-level (lambda () (1- (length (match-string 0))))
+              outline-level (lambda () (length (match-string 2)))
               outline-minor-mode-highlight 'append)
-  (outline-minor-mode))
+  (outline-minor-mode)
+  (emacs-etc--hide-local-variables))
 
 ;;;###autoload
 (define-derived-mode emacs-news-mode text-mode "NEWS"
   "Major mode for editing the Emacs NEWS file."
+  ;; Disable buttons.
+  (button-mode nil)
+  ;; And make the buffer writable.  This is used when toggling
+  ;; emacs-news-mode.
+  (setq buffer-read-only nil)
   (setq-local fill-paragraph-function #'emacs-news--fill-paragraph)
   (emacs-news--mode-common))
 
@@ -148,6 +173,26 @@ untagged NEWS entry."
   (interactive nil emacs-news-mode)
   (emacs-news-next-untagged-entry t))
 
+(defun emacs-news-toggle-tag ()
+  "Toggle documentation tag of current headline in the Emacs NEWS file."
+  (interactive nil emacs-news-mode)
+  (save-excursion
+    (goto-char (line-beginning-position))
+    (cond ((or (looking-at (rx bol (or "---" "+++") eol)))
+           (forward-line 2))
+          ((or (looking-at (rx bol "*** ")))
+           (forward-line 1)))
+    (outline-previous-visible-heading 1)
+    (forward-line -1)
+    (cond ((not (looking-at (rx bol (or "---" "+++") eol)))
+           (insert "\n---"))
+          ((looking-at (rx bol "---" eol))
+           (delete-char 3)
+           (insert "+++"))
+          ((looking-at (rx bol "+++" eol))
+           (delete-char 4))
+          (t (user-error "Invalid headline tag; can't toggle")))))
+
 (defun emacs-news-count-untagged-entries ()
   "Say how many untagged entries there are in the current NEWS buffer."
   (interactive nil emacs-news-mode)
@@ -219,6 +264,16 @@ untagged NEWS entry."
   (when (re-search-forward (concat "^*+ " (regexp-quote heading)) nil t)
     (beginning-of-line)))
 
+(defun emacs-news-open-line (n)
+  "Open a new line in a NEWS file.
+This is like `open-line', but skips any temporary NEWS-style
+documentation marks on the previous line."
+  (interactive "*p" emacs-news-mode)
+  (when (save-excursion (forward-line -1)
+                        (looking-at (rx bol (or "---" "+++") eol)))
+    (forward-line -1))
+  (open-line n))
+
 (provide 'emacs-news-mode)
 
 ;;; emacs-news-mode.el ends here
diff --git a/lisp/textmodes/etc-authors-mode.el 
b/lisp/textmodes/etc-authors-mode.el
deleted file mode 100644
index 7eabdd4c2b..0000000000
--- a/lisp/textmodes/etc-authors-mode.el
+++ /dev/null
@@ -1,133 +0,0 @@
-;;; etc-authors-mode.el --- font-locking for etc/AUTHORS  -*- lexical-binding: 
t -*-
-
-;; Copyright (C) 2021-2022 Free Software Foundation, Inc.
-
-;; Author: Stefan Kangas <stefan@marxist.se>
-;; Keywords: internal
-
-;; 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:
-
-;; Major mode to display the etc/AUTHORS file from the Emacs
-;; distribution.  Provides some basic font locking and not much else.
-
-;;; Code:
-
-(defgroup etc-authors-mode nil
-  "Display the \"etc/AUTHORS\" file from the Emacs distribution."
-  :version "28.1"
-  :group 'internal)
-
-(defface etc-authors-default '((t :inherit variable-pitch))
-  "Default face used to display the \"etc/AUTHORS\" file.
-See also `etc-authors-mode'."
-  :version "28.1")
-
-(defface etc-authors-author '((((class color) (min-colors 88) (background 
light))
-                    :foreground "midnight blue"
-                    :weight bold :height 1.05
-                    :inherit variable-pitch)
-                   (((class color) (min-colors 88) (background dark))
-                    :foreground "cyan"
-                    :weight bold :height 1.05
-                    :inherit variable-pitch)
-                   (((supports :weight bold) (supports :height 1.05))
-                    :weight bold :height 1.05
-                    :inherit variable-pitch)
-                   (((supports :weight bold))
-                    :weight bold :inherit variable-pitch)
-                   (t :inherit variable-pitch))
-  "Face used for the author in the \"etc/AUTHORS\" file.
-See also `etc-authors-mode'."
-  :version "28.1")
-
-(defface etc-authors-descriptor '((((class color) (min-colors 88) (background 
light))
-                        :foreground "sienna" :inherit variable-pitch)
-                       (((class color) (min-colors 88) (background dark))
-                        :foreground "peru" :inherit variable-pitch)
-                       (t :inherit variable-pitch))
-  "Face used for the description text in the \"etc/AUTHORS\" file.
-See also `etc-authors-mode'."
-  :version "28.1")
-
-(defface etc-authors-other-files '((t :inherit etc-authors-descriptor))
-  "Face used for the \"other files\" text in the \"etc/AUTHORS\" file.
-See also `etc-authors-mode'."
-  :version "28.1")
-
-(defconst etc-authors--author-re
-  (rx bol (group (not (any blank "\n")) (+? (not (any ":" "\n")))) ":")
-  "Regexp matching an author in \"etc/AUTHORS\".")
-
-(defvar etc-authors-mode-font-lock-keywords
-  `((,etc-authors--author-re
-     1 'etc-authors-author)
-    (,(rx (or "wrote"
-              (seq (? "and ") (or "co-wrote" "changed"))))
-     0 'etc-authors-descriptor)
-    (,(rx "and " (+ digit) " other files")
-     0 'etc-authors-other-files)
-    (,(rx bol (not space) (+ not-newline) eol)
-     0 'etc-authors-default)))
-
-(defun etc-authors-mode--hide-local-variables ()
-  "Hide local variables in \"etc/AUTHORS\".  Used by `etc-authors-mode'."
-  (narrow-to-region (point-min)
-                    (save-excursion
-                      (goto-char (point-min))
-                      ;; Obfuscate to avoid this being interpreted
-                      ;; as a local variable section itself.
-                      (if (re-search-forward "^Local\sVariables:$" nil t)
-                          (progn (forward-line -1) (point))
-                        (point-max)))))
-
-(defun etc-authors-next-author (&optional arg)
-  "Move point to the next author in \"etc/AUTHORS\".
-With a prefix arg ARG, move point that many authors forward."
-  (interactive "p" etc-authors-mode)
-  (if (< 0 arg)
-      (progn
-        (when (looking-at etc-authors--author-re)
-          (forward-line 1))
-        (re-search-forward etc-authors--author-re nil t arg))
-    (when (looking-at etc-authors--author-re)
-          (forward-line -1))
-    (re-search-backward etc-authors--author-re nil t (abs arg)))
-  (goto-char (line-beginning-position)))
-
-(defun etc-authors-prev-author (&optional arg)
-  "Move point to the previous author in \"etc/AUTHORS\".
-With a prefix arg ARG, move point that many authors backward."
-  (interactive "p" etc-authors-mode)
-  (etc-authors-next-author (- arg)))
-
-(defvar-keymap etc-authors-mode-map
-  :doc "Keymap for `etc-authors-mode'."
-  "n" #'etc-authors-next-author
-  "p" #'etc-authors-prev-author)
-
-;;;###autoload
-(define-derived-mode etc-authors-mode special-mode "Authors View"
-  "Major mode for viewing \"etc/AUTHORS\" from the Emacs distribution.
-Provides some basic font locking and not much else."
-  (setq-local font-lock-defaults
-              '(etc-authors-mode-font-lock-keywords nil nil ((?_ . "w"))))
-  (setq font-lock-multiline nil)
-  (etc-authors-mode--hide-local-variables))
-
-(provide 'etc-authors-mode)
-;;; etc-authors-mode.el ends here
diff --git a/lisp/textmodes/fill.el b/lisp/textmodes/fill.el
index 88a8395c88..23ba1a24f1 100644
--- a/lisp/textmodes/fill.el
+++ b/lisp/textmodes/fill.el
@@ -46,8 +46,8 @@ A value of nil means that any change in indentation starts a 
new paragraph."
 
 (defcustom colon-double-space nil
   "Non-nil means put two spaces after a colon when filling."
-  :type 'boolean)
-(put 'colon-double-space 'safe-local-variable #'booleanp)
+  :type 'boolean
+  :safe #'booleanp)
 
 (defcustom fill-separate-heterogeneous-words-with-space nil
   "Non-nil means to use a space to separate words of a different kind.
diff --git a/lisp/textmodes/flyspell.el b/lisp/textmodes/flyspell.el
index 2c5e30fecd..a893bc7b9c 100644
--- a/lisp/textmodes/flyspell.el
+++ b/lisp/textmodes/flyspell.el
@@ -854,6 +854,9 @@ Mostly we check word delimiters."
        ((get this-command 'flyspell-deplacement)
        (not (eq flyspell-previous-command this-command)))
        ((get this-command 'flyspell-delayed)
+        ;; In case we're using `delete-selection-mode', make the
+        ;; region be updated immediately.
+        (deactivate-mark)
        ;; The current command is not delayed, that
        ;; is that we must check the word now.
        (and (not unread-command-events)
@@ -1550,7 +1553,7 @@ The buffer to mark them in is 
`flyspell-large-region-buffer'."
       (goto-char (point-min))
       ;; Localwords parsing copied from ispell.el.
       (while (search-forward ispell-words-keyword nil t)
-       (let ((end (point-at-eol))
+        (let ((end (line-end-position))
              string)
          ;; buffer-local words separated by a space, and can contain
          ;; any character other than a space.  Not rigorous enough.
@@ -1711,25 +1714,32 @@ of a misspelled word removed when you've corrected it."
 ;;*---------------------------------------------------------------------*/
 ;;*    flyspell-goto-next-error ...                                     */
 ;;*---------------------------------------------------------------------*/
-(defun flyspell-goto-next-error ()
-  "Go to the next previously detected error.
+(defun flyspell-goto-next-error (&optional previous)
+  "Go to the next error.
+If PREVIOUS (interactively, the prefix), go to the previous error
+instead.
+
 In general FLYSPELL-GOTO-NEXT-ERROR must be used after
 FLYSPELL-BUFFER."
-  (interactive)
+  (interactive "P")
   (let ((pos (point))
-       (max (point-max)))
-    (if (and (eq (current-buffer) flyspell-old-buffer-error)
-            (eq pos flyspell-old-pos-error))
-       (progn
-         (if (= flyspell-old-pos-error max)
-             ;; goto beginning of buffer
+       (max (if previous (point-min) (point-max))))
+    (when (and (eq (current-buffer) flyspell-old-buffer-error)
+              (eq pos flyspell-old-pos-error))
+      (if previous
+          (if (= flyspell-old-pos-error max)
              (progn
-               (message "Restarting from beginning of buffer")
-               (goto-char (point-min)))
-           (forward-word 1))
-         (setq pos (point))))
-    ;; seek the next error
-    (while (and (< pos max)
+               (message "Restarting from end of the buffer")
+               (goto-char (point-max)))
+           (forward-word -1))
+        (if (= flyspell-old-pos-error max)
+           (progn
+             (message "Restarting from beginning of buffer")
+             (goto-char (point-min)))
+         (forward-word 1)))
+      (setq pos (point)))
+    ;; Seek the next error.
+    (while (and (/= pos max)
                (let ((ovs (overlays-at pos))
                      (r '()))
                  (while (and (not r) (consp ovs))
@@ -1737,13 +1747,15 @@ FLYSPELL-BUFFER."
                        (setq r t)
                      (setq ovs (cdr ovs))))
                  (not r)))
-      (setq pos (1+ pos)))
-    ;; save the current location for next invocation
-    (setq flyspell-old-pos-error pos)
-    (setq flyspell-old-buffer-error (current-buffer))
+      (setq pos (if previous (1- pos) (1+ pos))))
     (goto-char pos)
-    (if (= pos max)
-       (message "No more miss-spelled word!"))))
+    (when previous
+      (forward-word -1))
+    ;; Save the current location for next invocation.
+    (setq flyspell-old-pos-error (point))
+    (setq flyspell-old-buffer-error (current-buffer))
+    (when (= (point) max)
+      (message "No more miss-spelled words"))))
 
 ;;*---------------------------------------------------------------------*/
 ;;*    flyspell-overlay-p ...                                           */
diff --git a/lisp/textmodes/ispell.el b/lisp/textmodes/ispell.el
index 1810d7bcae..8e63368809 100644
--- a/lisp/textmodes/ispell.el
+++ b/lisp/textmodes/ispell.el
@@ -1062,12 +1062,14 @@ calls it only when invoked interactively."
   (cl-pushnew (list dict '()) ispell-dictionary-alist :test #'equal)
   (ispell-hunspell-fill-dictionary-entry dict))
 
-(defun ispell-find-hunspell-dictionaries ()
+(defun ispell-find-hunspell-dictionaries (&optional dictionary)
   "Look for installed Hunspell dictionaries.
 Will initialize `ispell-hunspell-dictionary-alist' according
 to dictionaries found, and will remove aliases from the list
 in `ispell-dicts-name2locale-equivs-alist' if an explicit
-dictionary from that list was found."
+dictionary from that list was found.
+
+If DICTIONARY, check for that dictionary explicitly."
   (let ((hunspell-found-dicts
          (seq-filter
           (lambda (str)
@@ -1081,23 +1083,20 @@ dictionary from that list was found."
             (file-name-absolute-p str))
           (split-string
            (with-temp-buffer
-             (ispell-call-process ispell-program-name
-                            nil
-                            t
-                            nil
-                            "-D"
-                            ;; Use -a to prevent Hunspell from
-                            ;; trying to initialize its
-                            ;; curses/termcap UI, which causes it
-                            ;; to crash or fail to start in some
-                            ;; MS-Windows ports.
-                            "-a"
-                            ;; Hunspell 1.7.0 (and later?) won't
-                            ;; show LOADED DICTIONARY unless
-                            ;; there's at least one file argument
-                            ;; on the command line.  So we feed
-                            ;; it with the null device.
-                            null-device)
+             (apply #'ispell-call-process
+                    ispell-program-name nil t nil
+                    `("-D"
+                      ,@(and dictionary (list "-d" dictionary))
+                      ;; Use -a to prevent Hunspell from trying to
+                      ;; initialize its curses/termcap UI, which
+                      ;; causes it to crash or fail to start in some
+                      ;; MS-Windows ports.
+                      "-a"
+                      ;; Hunspell 1.7.0 (and later?) won't show LOADED
+                      ;; DICTIONARY unless there's at least one file
+                      ;; argument on the command line.  So we feed it
+                      ;; with the null device.
+                      ,null-device))
              (buffer-string))
            "[\n\r]+"
            t)))
@@ -1164,12 +1163,20 @@ dictionary from that list was found."
     ;; Parse and set values for default dictionary.
     (setq hunspell-default-dict (or hunspell-multi-dict
                                    (car hunspell-default-dict)))
+    ;; If we didn't find a dictionary based on the environment (i.e.,
+    ;; the locale and the DICTIONARY variable), try again if
+    ;; `ispell-dictionary' is set.
+    (when (and (not hunspell-default-dict)
+               (not dictionary)
+               ispell-dictionary)
+      (setq hunspell-default-dict
+            (ispell-find-hunspell-dictionaries ispell-dictionary)))
     ;; If hunspell-default-dict is nil, ispell-parse-hunspell-affix-file
     ;; will barf with an error message that doesn't help users figure
     ;; out what is wrong.  Produce an error message that points to the
     ;; root cause of the problem.
-    (or hunspell-default-dict
-        (error "Can't find Hunspell dictionary with a .aff affix file"))
+    (unless hunspell-default-dict
+      (error "Can't find Hunspell dictionary with a .aff affix file"))
     (setq hunspell-default-dict-entry
          (ispell-parse-hunspell-affix-file hunspell-default-dict))
     ;; Create an alist of found dicts with only names, except for default dict.
@@ -1179,7 +1186,8 @@ dictionary from that list was found."
       (cl-pushnew (if (string= dict hunspell-default-dict)
                       hunspell-default-dict-entry
                     (list dict))
-                  ispell-hunspell-dictionary-alist :test #'equal))))
+                  ispell-hunspell-dictionary-alist :test #'equal))
+    hunspell-default-dict))
 
 ;; Make ispell.el work better with enchant.
 
@@ -2615,15 +2623,18 @@ Optional REFRESH will unhighlighted then highlight, 
using block cursor
        (text (buffer-substring-no-properties start end))
                                        ; Save highlight region.
        (inhibit-quit t)                ; inhibit interrupt processing here.
-       (buffer-undo-list t))           ; don't clutter the undo list.
+       (buffer-undo-list t)            ; don't clutter the undo list.
+        (end1 (if (markerp end) (marker-position end) end)))
     (goto-char end)
     (delete-region start end)
-    (insert-char ?  (- end start))     ; minimize amount of redisplay
+    (insert-char ?  (- end1 start))    ; minimize amount of redisplay
     (sit-for 0)                                ; update display
     (if highlight (setq inverse-video (not inverse-video))) ; toggle video
-    (delete-region start end)          ; delete whitespace
+    (delete-region start end1)         ; delete whitespace
     (insert text)                      ; insert text in inverse video.
     (sit-for 0)                                ; update display showing 
inverse video.
+    (if (markerp end)
+        (set-marker end end1))          ; restore marker position
     (if (not highlight)
        (goto-char end)
       (setq inverse-video (not inverse-video)) ; toggle video
@@ -3143,7 +3154,7 @@ ispell-region: Search for first region to skip after 
(ispell-begin-skip-region-r
                                       (min skip-region-start ispell-region-end)
                                     (marker-position ispell-region-end))))
                (let* ((ispell-start (point))
-                      (ispell-end (min (point-at-eol) reg-end))
+                       (ispell-end (min (line-end-position) reg-end))
                       ;; See if line must be prefixed by comment string to let 
ispell know this is
                       ;; part of a comment string.  This is only supported in 
some modes.
                       ;; In particular, this is not supported in autoconf mode 
where adding the
@@ -3156,7 +3167,8 @@ ispell-region: Search for first region to skip after 
(ispell-begin-skip-region-r
                                ispell-start ispell-end add-comment)))
                  (ispell-print-if-debug
                    "ispell-region: string pos (%s->%s), eol: %s, [in-comment]: 
[%s], [add-comment]: [%s], [string]: [%s]\n"
-                   ispell-start ispell-end (point-at-eol) in-comment 
add-comment string)
+                   ispell-start ispell-end (line-end-position)
+                   in-comment add-comment string)
                  (if add-comment               ; account for comment chars 
added
                      (setq ispell-start (- ispell-start (length add-comment))
                            ;; Reset `in-comment' (and indirectly 
`add-comment') for new line
@@ -4093,7 +4105,7 @@ Includes LaTeX/Nroff modes and extended character mode."
     (goto-char (point-max))
     ;; Uses last occurrence of ispell-parsing-keyword
     (if (search-backward ispell-parsing-keyword nil t)
-       (let ((end (point-at-eol))
+        (let ((end (line-end-position))
              string)
          (search-forward ispell-parsing-keyword)
          (while (re-search-forward " *\\([^ \"]+\\)" end t)
@@ -4129,7 +4141,7 @@ Both should not be used to define a buffer-local 
dictionary."
        (if (search-backward ispell-dictionary-keyword nil t)
            (progn
              (search-forward ispell-dictionary-keyword)
-             (setq end (point-at-eol))
+              (setq end (line-end-position))
              (if (re-search-forward " *\\([^ \"]+\\)" end t)
                  (setq ispell-local-dictionary
                        (match-string-no-properties 1))))))
@@ -4137,7 +4149,7 @@ Both should not be used to define a buffer-local 
dictionary."
       (if (search-backward ispell-pdict-keyword nil t)
          (progn
            (search-forward ispell-pdict-keyword)
-           (setq end (point-at-eol))
+            (setq end (line-end-position))
            (if (re-search-forward " *\\([^ \"]+\\)" end t)
                (setq ispell-local-pdict
                      (match-string-no-properties 1)))))))
@@ -4166,7 +4178,7 @@ Both should not be used to define a buffer-local 
dictionary."
     (while (search-forward ispell-words-keyword nil t)
       (or ispell-buffer-local-name
          (setq ispell-buffer-local-name (buffer-name)))
-      (let ((end (point-at-eol))
+      (let ((end (line-end-position))
            (ispell-casechars (ispell-get-casechars))
            string)
        ;; buffer-local words separated by a space, and can contain
@@ -4232,17 +4244,10 @@ Both should not be used to define a buffer-local 
dictionary."
 
 ;;; LOCAL VARIABLES AND BUFFER-LOCAL VALUE EXAMPLES.
 
-;; Local Variable options:
-;; mode: name(-mode)
-;; eval: expression
-;; local-variable: value
-
 ;; The following sets the buffer local dictionary to `american' English
 ;; and spell checks only comments.
 
 ;; Local Variables:
-;; mode: emacs-lisp
-;; comment-column: 40
 ;; ispell-check-comments: exclusive
 ;; ispell-local-dictionary: "american"
 ;; End:
diff --git a/lisp/textmodes/nroff-mode.el b/lisp/textmodes/nroff-mode.el
index 435423d31e..4d1de18b2c 100644
--- a/lisp/textmodes/nroff-mode.el
+++ b/lisp/textmodes/nroff-mode.el
@@ -1,7 +1,6 @@
 ;;; nroff-mode.el --- GNU Emacs major mode for editing nroff source  -*- 
lexical-binding: t -*-
 
-;; Copyright (C) 1985-1986, 1994-1995, 1997, 2001-2022 Free Software
-;; Foundation, Inc.
+;; Copyright (C) 1985-2022 Free Software Foundation, Inc.
 
 ;; Maintainer: emacs-devel@gnu.org
 ;; Keywords: wp
@@ -45,16 +44,14 @@
   "Non-nil means automatically closing requests when you insert an open."
   :type 'boolean)
 
-(defvar nroff-mode-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "\t"  #'tab-to-tab-stop)
-    (define-key map "\e?" #'nroff-count-text-lines)
-    (define-key map "\n"  #'nroff-electric-newline)
-    (define-key map "\en" #'nroff-forward-text-line)
-    (define-key map "\ep" #'nroff-backward-text-line)
-    (define-key map "\C-c\C-c" #'nroff-view)
-    map)
-  "Major mode keymap for `nroff-mode'.")
+(defvar-keymap nroff-mode-map
+  :doc "Major mode keymap for `nroff-mode'."
+  "TAB"     #'tab-to-tab-stop
+  "M-?"     #'nroff-count-text-lines
+  "C-j"     #'nroff-electric-newline
+  "M-n"     #'nroff-forward-text-line
+  "M-p"     #'nroff-backward-text-line
+  "C-c C-c" #'nroff-view)
 
 (easy-menu-define nroff-mode-menu nroff-mode-map
   "Menu for `nroff-mode'."
@@ -160,8 +157,6 @@ closing requests for requests that are used in matched 
pairs."
     (skip-chars-forward ".H ")
     (string-to-number (buffer-substring (point) (+ 1 (point))))))
 
-;; Compute how much to indent a comment in nroff/troff source.
-;; By mit-erl!gildea April 86
 (defun nroff-comment-indent ()
   "Compute indent for an nroff/troff comment.
 Puts a full-stop before comments on a line by themselves."
diff --git a/lisp/textmodes/page-ext.el b/lisp/textmodes/page-ext.el
index 24149f9afb..6b71f26e4f 100644
--- a/lisp/textmodes/page-ext.el
+++ b/lisp/textmodes/page-ext.el
@@ -515,13 +515,12 @@ resets the page-delimiter to the original value."
 (defvar pages-buffer-original-position)
 (defvar pages-buffer-original-page)
 
-(defun pages-directory
-  (pages-list-all-headers-p count-lines-p &optional regexp)
+(defun pages-directory (pages-list-all-headers-p count-lines-p &optional 
regexp)
   "Display a directory of the page headers in a temporary buffer.
 A header is the first non-blank line after the `page-delimiter'.
-\\[pages-directory-mode]
+\\<pages-directory-mode-map>
 You may move point to one of the lines in the temporary buffer,
-then use \\<pages-directory-goto> to go to the same line in the pages buffer.
+then use \\[pages-directory-goto] to go to the same line in the pages buffer.
 
 In interactive use:
 
@@ -587,7 +586,9 @@ directory for only the accessible portion of the buffer."
         (pages-directory-mode)
         (setq buffer-read-only nil)
         (insert
-         "==== Pages Directory: use `C-c C-c' to go to page under cursor. 
====" ?\n)
+         (substitute-command-keys
+          "==== Pages Directory: use \\<pages-directory-mode-map>\
+\\[pages-directory-goto] to go to page under cursor. ====") "\n")
         (setq pages-buffer pages-target-buffer)
         (setq pages-pos-list nil))
 
@@ -772,7 +773,9 @@ directory."
           (goto-char (point-min))
           (delete-region (point) (line-end-position))
           (insert
-           "=== Address List Directory: use `C-c C-c' to go to page under 
cursor. ===")
+           (substitute-command-keys
+            "=== Address List Directory: use \\<pages-directory-mode-map>\
+\\[pages-directory-goto] to go to page under cursor. ==="))
           (set-buffer-modified-p nil)
           ))
     (error "No addresses file found!")))
diff --git a/lisp/textmodes/paragraphs.el b/lisp/textmodes/paragraphs.el
index 98eb494823..cd726ad477 100644
--- a/lisp/textmodes/paragraphs.el
+++ b/lisp/textmodes/paragraphs.el
@@ -96,8 +96,8 @@ lines that start paragraphs from lines that separate them.
 
 If the variable `use-hard-newlines' is non-nil, then only lines following a
 hard newline are considered to match."
-  :type 'regexp)
-(put 'paragraph-start 'safe-local-variable #'stringp)
+  :type 'regexp
+  :safe #'stringp)
 
 ;; paragraph-start requires a hard newline, but paragraph-separate does not:
 ;; It is assumed that paragraph-separate is distinctive enough to be believed
@@ -113,8 +113,8 @@ This is matched against the text at the left margin, which 
is not necessarily
 the beginning of the line, so it should not use \"^\" as an anchor.  This
 ensures that the paragraph functions will work equally within a region of
 text indented by a margin setting."
-  :type 'regexp)
-(put 'paragraph-separate 'safe-local-variable #'stringp)
+  :type 'regexp
+  :safe #'stringp)
 
 (defcustom sentence-end-double-space t
   "Non-nil means a single space does not end a sentence.
@@ -125,8 +125,8 @@ This value is used by the function `sentence-end' to 
construct the
 regexp describing the end of a sentence, when the value of the variable
 `sentence-end' is nil.  See Info node `(elisp)Standard Regexps'."
   :type 'boolean
+  :safe #'booleanp
   :group 'fill)
-(put 'sentence-end-double-space 'safe-local-variable #'booleanp)
 
 (defcustom sentence-end-without-period nil
   "Non-nil means a sentence will end without a period.
@@ -137,8 +137,8 @@ This value is used by the function `sentence-end' to 
construct the
 regexp describing the end of a sentence, when the value of the variable
 `sentence-end' is nil.  See Info node `(elisp)Standard Regexps'."
   :type 'boolean
+  :safe #'booleanp
   :group 'fill)
-(put 'sentence-end-without-period 'safe-local-variable #'booleanp)
 
 (defcustom sentence-end-without-space
   "。.?!"
@@ -147,8 +147,8 @@ regexp describing the end of a sentence, when the value of 
the variable
 This value is used by the function `sentence-end' to construct the
 regexp describing the end of a sentence, when the value of the variable
 `sentence-end' is nil.  See Info node `(elisp)Standard Regexps'."
-  :type 'string)
-(put 'sentence-end-without-space 'safe-local-variable #'stringp)
+  :type 'string
+  :safe  #'stringp)
 
 (defcustom sentence-end nil
   "Regexp describing the end of a sentence.
@@ -158,14 +158,14 @@ All paragraph boundaries also end sentences, regardless.
 The value nil means to use the default value defined by the
 function `sentence-end'.  You should always use this function
 to obtain the value of this variable."
-  :type '(choice regexp (const :tag "Use default value" nil)))
-(put 'sentence-end 'safe-local-variable #'string-or-null-p)
+  :type '(choice regexp (const :tag "Use default value" nil))
+  :safe #'string-or-null-p)
 
 (defcustom sentence-end-base "[.?!…‽][]\"'”’)}»›]*"
   "Regexp matching the basic end of a sentence, not including following space."
   :type 'regexp
+  :safe #'stringp
   :version "25.1")
-(put 'sentence-end-base 'safe-local-variable #'stringp)
 
 (defun sentence-end ()
   "Return the regexp describing the end of a sentence.
@@ -192,14 +192,14 @@ in between.  See Info node `(elisp)Standard Regexps'."
 
 (defcustom page-delimiter "^\014"
   "Regexp describing line-beginnings that separate pages."
-  :type 'regexp)
-(put 'page-delimiter 'safe-local-variable #'stringp)
+  :type 'regexp
+  :safe #'stringp)
 
 (defcustom paragraph-ignore-fill-prefix nil
   "Non-nil means the paragraph commands are not affected by `fill-prefix'.
 This is desirable in modes where blank lines are the paragraph delimiters."
-  :type 'boolean)
-(put 'paragraph-ignore-fill-prefix 'safe-local-variable #'booleanp)
+  :type 'boolean
+  :safe #'booleanp)
 
 ;; Silence the compiler.
 (defun forward-paragraph (&optional arg)
diff --git a/lisp/textmodes/picture.el b/lisp/textmodes/picture.el
index 17d9483f68..e8c1e6b14f 100644
--- a/lisp/textmodes/picture.el
+++ b/lisp/textmodes/picture.el
@@ -641,7 +641,6 @@ Leaves the region surrounding the rectangle."
     (define-key map [remap move-end-of-line] 'picture-end-of-line)
     (define-key map [remap mouse-set-point] 'picture-mouse-set-point)
     (define-key map "\C-c\C-d" 'picture-delete-char)
-    (define-key map "\e\t" 'picture-toggle-tab-state)
     (define-key map "\t" 'picture-tab)
     (define-key map "\e\t" 'picture-tab-search)
     (define-key map "\C-c\t" 'picture-set-tab-stops)
diff --git a/lisp/textmodes/refbib.el b/lisp/textmodes/refbib.el
index ba1deca47d..203a0fdbb7 100644
--- a/lisp/textmodes/refbib.el
+++ b/lisp/textmodes/refbib.el
@@ -163,12 +163,11 @@ This is in addition to the 
`r2b-capitalize-title-stop-words'.")
 
 
 (defun r2b-capitalize-title (s)
-   "Like `capitalize', but don't capitalize stop words, except the first."
-   (with-current-buffer (get-buffer-create "$$$Scratch$$$")
-     (erase-buffer)
-     (insert s)
-     (r2b-capitalize-title-region (point-min) (point-max))
-     (buffer-string)))
+  "Like `capitalize', but don't capitalize stop words, except the first."
+  (with-temp-buffer
+    (insert s)
+    (r2b-capitalize-title-region (point-min) (point-max))
+    (buffer-string)))
 
 ;*********************************************************
 (defun r2b-reset ()
diff --git a/lisp/textmodes/reftex-cite.el b/lisp/textmodes/reftex-cite.el
index 26b14ebc79..f3f95627af 100644
--- a/lisp/textmodes/reftex-cite.el
+++ b/lisp/textmodes/reftex-cite.el
@@ -1116,10 +1116,10 @@ recommended for follow mode.  It works OK for 
individual lookups."
         (setq bibtype (reftex-bib-or-thebib))
         (cond
          ((eq bibtype 'bib)
-;        ((assq 'bib (symbol-value reftex-docstruct-symbol))
+          ;; ((assq 'bib (symbol-value reftex-docstruct-symbol))
           (setq bibfile-list (reftex-get-bibfile-list)))
          ((eq bibtype 'thebib)
-;        ((assq 'thebib (symbol-value reftex-docstruct-symbol))
+          ;; ((assq 'thebib (symbol-value reftex-docstruct-symbol))
           (setq bibfile-list
                 (reftex-uniquify
                  (mapcar #'cdr
@@ -1142,8 +1142,35 @@ recommended for follow mode.  It works OK for individual 
lookups."
 
 ;;; Global BibTeX file
 (defun reftex-all-used-citation-keys ()
+  "Return a list of all citation keys used in document."
   (reftex-access-scan-info)
-  (let ((files (reftex-all-document-files)) file keys kk k)
+  ;; FIXME: multicites macros provided by biblatex
+  ;; are not covered in this function.
+  (let ((files (reftex-all-document-files))
+        (re (concat "\\\\"
+                    "\\(?:"
+                    ;; biblatex volcite macros take these args:
+                    ;; \volcite[prenote]{volume}[pages]{key}
+                    ;; so cater for the first 3 args:
+                    (regexp-opt '("volcite"  "Volcite"
+                                  "pvolcite" "Pvolcite"
+                                  "fvolcite" "ftvolcite"
+                                  "svolcite" "Svolcite"
+                                  "tvolcite" "Tvolcite"
+                                  "avolcite" "Avolcite"))
+                    "\\(?:\\[[^]]*\\]\\)?"
+                    "{[^}]*}"
+                    "\\(?:\\[[^]]*\\]\\)?"
+                    "\\|"
+                    ;; Other cite macros usually go like:
+                    ;; \cite[prenote][postnote]{key}
+                    ;; so cater for the optional args:
+                    "\\(?:bibentry\\|[a-zA-Z]*[Cc]ite[a-zA-Z*]*\\)"
+                    "\\(?:\\[[^]]*\\]\\)\\{0,2\\}"
+                    "\\)"
+                    ;; Now match the key:
+                    "{\\([^}]+\\)}"))
+        file keys kk k)
     (save-current-buffer
       (while (setq file (pop files))
         (set-buffer (reftex-get-file-buffer-force file 'mark))
@@ -1151,14 +1178,17 @@ recommended for follow mode.  It works OK for 
individual lookups."
           (save-restriction
             (widen)
             (goto-char (point-min))
-            (while (re-search-forward 
"\\(?:^\\|\\=\\)[^%\n\r]*?\\\\\\(bibentry\\|[a-zA-Z]*cite[a-zA-Z]*\\)\\(\\[[^]]*\\]\\)?{\\([^}]+\\)}"
 nil t)
-              (setq kk (match-string-no-properties 3))
-              (while (string-match "%.*\n?" kk)
-                (setq kk (replace-match "" t t kk)))
-              (setq kk (split-string kk "[, \t\r\n]+"))
-              (while (setq k (pop kk))
-                (or (member k keys)
-                    (setq keys (cons k keys)))))))))
+            (while (re-search-forward re nil t)
+              ;; Make sure we're not inside a comment:
+              (unless (save-match-data
+                        (nth 4 (syntax-ppss)))
+                (setq kk (match-string-no-properties 1))
+                (while (string-match "%.*\n?" kk)
+                  (setq kk (replace-match "" t t kk)))
+                (setq kk (split-string kk "[, \t\r\n]+"))
+                (while (setq k (pop kk))
+                  (or (member k keys)
+                      (setq keys (cons k keys))))))))))
     (reftex-kill-temporary-buffers)
     keys))
 
diff --git a/lisp/textmodes/reftex-index.el b/lisp/textmodes/reftex-index.el
index 734f82aba3..075ad666b3 100644
--- a/lisp/textmodes/reftex-index.el
+++ b/lisp/textmodes/reftex-index.el
@@ -269,18 +269,14 @@ will prompt for other arguments."
     (and newtag (cdr cell) (not (member newtag (cdr cell)))
          (push newtag (cdr cell)))))
 
-(define-obsolete-variable-alias
-  'reftex-index-map 'reftex-index-mode-map "24.1")
 (defvar reftex-index-mode-map
   (let ((map (make-sparse-keymap)))
     ;; Index map
     (define-key map [(mouse-2)] #'reftex-index-mouse-goto-line-and-hide)
     (define-key map [follow-link] 'mouse-face)
 
-    (substitute-key-definition
-     #'next-line #'reftex-index-next map global-map)
-    (substitute-key-definition
-     #'previous-line #'reftex-index-previous map global-map)
+    (define-key map [remap next-line] #'reftex-index-next)
+    (define-key map [remap previous-line] #'reftex-index-previous)
 
     (define-key map "n" #'reftex-index-next)
     (define-key map "p" #'reftex-index-previous)
@@ -1198,8 +1194,6 @@ This gets refreshed in every phrases command.")
   '((reftex-index-phrases-font-lock-keywords)
     nil t nil beginning-of-line)
   "Font lock defaults for `reftex-index-phrases-mode'.")
-(define-obsolete-variable-alias
-  'reftex-index-phrases-map 'reftex-index-phrases-mode-map "24.1")
 (defvar reftex-index-phrases-mode-map
   (let ((map (make-sparse-keymap)))
     ;; Keybindings and Menu for phrases buffer
@@ -1272,10 +1266,11 @@ This gets refreshed in every phrases command.")
 ;;;###autoload
 (defun reftex-index-phrase-selection-or-word (arg)
   "Add current selection or word at point to the phrases buffer.
+\\<reftex-index-phrases-mode-map>
 When you are in transient-mark-mode and the region is active, the
 selection will be used - otherwise the word at point.
 You get a chance to edit the entry in the phrases buffer - finish with
-`C-c C-c'."
+\\[reftex-index-phrases-save-and-return]."
   (interactive "P")
   (set-marker reftex-index-return-marker (point))
   (reftex-index-selection-or-word arg 'phrase)
@@ -1373,7 +1368,7 @@ If the buffer is non-empty, delete the old header first."
 ;;;###autoload
 (define-derived-mode reftex-index-phrases-mode fundamental-mode "Phrases"
   "Major mode for managing the Index phrases of a LaTeX document.
-This buffer was created with RefTeX.
+This buffer was created with RefTeX. \\<reftex-index-phrases-mode-map>
 
 To insert new phrases, use
  - `C-c \\' in the LaTeX document to copy selection or word
@@ -1684,8 +1679,8 @@ this function repeatedly."
 (defun reftex-index-phrases-set-macro-key ()
   "Change the macro key for the current line.
 Prompts for a macro key and insert is at the beginning of the line.
-If you reply with SPACE, the macro keyn will be removed, so that the
-default macro will be used.  If you reply with `RET', just prints
+If you reply with \\`SPC', the macro key will be removed, so that the
+default macro will be used.  If you reply with \\`RET', just prints
 information about the currently selected macro."
   (interactive)
   (reftex-index-phrases-parse-header)
diff --git a/lisp/textmodes/reftex-ref.el b/lisp/textmodes/reftex-ref.el
index 3fe7a79a27..fead734be7 100644
--- a/lisp/textmodes/reftex-ref.el
+++ b/lisp/textmodes/reftex-ref.el
@@ -294,14 +294,12 @@ also applies `reftex-translate-to-ascii-function' to the 
string."
 
 (defun reftex-latin1-to-ascii (string)
   ;; Translate the upper 128 chars in the Latin-1 charset to ASCII equivalents
-  (let ((tab "@@@@@@@@@@@@@@@@@@'@@@@@@@@@@@@@ 
icLxY|S\"ca<--R-o|23'uq..1o>423?AAAAAAACEEEEIIIIDNOOOOOXOUUUUYP3aaaaaaaceeeeiiiidnooooo:ouuuuypy")
-        (emacsp (not (featurep 'xemacs))))
+  (let ((tab "@@@@@@@@@@@@@@@@@@'@@@@@@@@@@@@@ 
icLxY|S\"ca<--R-o|23'uq..1o>423?AAAAAAACEEEEIIIIDNOOOOOXOUUUUYP3aaaaaaaceeeeiiiidnooooo:ouuuuypy"))
     (mapconcat
      (lambda (c)
        (cond ((and (> c 127) (< c 256))                 ; 8 bit Latin-1
               (char-to-string (aref tab (- c 128))))
-             ((and emacsp                               ; Not for XEmacs
-                   (> c 2175) (< c 2304))               ; Mule Latin-1
+             ((and (> c 2175) (< c 2304))               ; Mule Latin-1
               (char-to-string (aref tab (- c 2176))))
              (t (char-to-string c))))
      string "")))
diff --git a/lisp/textmodes/reftex-sel.el b/lisp/textmodes/reftex-sel.el
index d77411483f..80c01948e5 100644
--- a/lisp/textmodes/reftex-sel.el
+++ b/lisp/textmodes/reftex-sel.el
@@ -33,14 +33,10 @@
 (defvar reftex-select-shared-map
   (let ((map (make-sparse-keymap)))
     (set-keymap-parent map special-mode-map)
-    (substitute-key-definition
-     #'next-line #'reftex-select-next                      map global-map)
-    (substitute-key-definition
-     #'previous-line #'reftex-select-previous              map global-map)
-    (substitute-key-definition
-     #'keyboard-quit #'reftex-select-keyboard-quit         map global-map)
-    (substitute-key-definition
-     #'newline #'reftex-select-accept                      map global-map)
+    (define-key map [remap next-line] #'reftex-select-next)
+    (define-key map [remap previous-line] #'reftex-select-previous)
+    (define-key map [remap keyboard-quit] #'reftex-select-keyboard-quit)
+    (define-key map [remap newline] #'reftex-select-accept)
 
     (define-key map " " #'reftex-select-callback)
     (define-key map "n" #'reftex-select-next)
@@ -59,8 +55,6 @@
     (define-key map [follow-link] 'mouse-face)
     map))
 
-(define-obsolete-variable-alias
-  'reftex-select-label-map 'reftex-select-label-mode-map "24.1")
 (defvar reftex-select-label-mode-map
   (let ((map (make-sparse-keymap)))
     (set-keymap-parent map reftex-select-shared-map)
@@ -109,8 +103,6 @@ During a selection process, these are the local bindings.
   ;; We do not set a local map - reftex-select-item does this.
   )
 
-(define-obsolete-variable-alias
-  'reftex-select-bib-map 'reftex-select-bib-mode-map "24.1")
 (defvar reftex-select-bib-mode-map
   (let ((map (make-sparse-keymap)))
     (set-keymap-parent map reftex-select-shared-map)
diff --git a/lisp/textmodes/reftex-toc.el b/lisp/textmodes/reftex-toc.el
index f6f72cec4f..a7f3a9452a 100644
--- a/lisp/textmodes/reftex-toc.el
+++ b/lisp/textmodes/reftex-toc.el
@@ -28,17 +28,14 @@
 (require 'reftex)
 ;;;
 
-(define-obsolete-variable-alias 'reftex-toc-map 'reftex-toc-mode-map "24.1")
 (defvar reftex-toc-mode-map
   (let ((map (make-sparse-keymap)))
 
     (define-key map [(mouse-2)] #'reftex-toc-mouse-goto-line-and-hide)
     (define-key map [follow-link] 'mouse-face)
 
-    (substitute-key-definition
-     'next-line 'reftex-toc-next map global-map)
-    (substitute-key-definition
-     'previous-line 'reftex-toc-previous map global-map)
+    (define-key map [remap next-line] #'reftex-toc-next)
+    (define-key map [remap previous-line] #'reftex-toc-previous)
 
     (define-key map "n" #'reftex-toc-next)
     (define-key map "p" #'reftex-toc-previous)
@@ -157,22 +154,22 @@ Here are all local bindings.
 (defconst reftex-toc-help
 "                      AVAILABLE KEYS IN TOC BUFFER
                       ============================
-n / p      next-line / previous-line
-SPC        Show the corresponding location of the LaTeX document.
-TAB        Goto the location and keep the TOC window.
-RET        Goto the location and hide the TOC window (also on mouse-2).
-< / >      Promote / Demote section, or all sections in region.
-C-c >      Display Index. With prefix arg, restrict index to current section.
-q / k      Hide/Kill *toc* buffer, return to position of reftex-toc command.
-l i c F    Toggle display of  [l]abels,  [i]ndex,  [c]ontext,  [F]ile borders.
-t          Change maximum toc depth (e.g. `3 t' hides levels greater than 3).
-f / g      Toggle follow mode / Refresh *toc* buffer.
-a / d      Toggle auto recenter / Toggle dedicated frame
-r / C-u r  Reparse the LaTeX document     / Reparse entire LaTeX document.
-.          In other window, show position from where `reftex-toc' was called.
-M-%        Global search and replace to rename label at point.
-x          Switch to TOC of external document (with LaTeX package `xr').
-z          Jump to a specific section (e.g. '3 z' goes to section 3).")
+\\`n' / \\`p'      `next-line' / `previous-line'
+\\`SPC'        Show the corresponding location of the LaTeX document.
+\\`TAB'        Goto the location and keep the TOC window.
+\\`RET'        Goto the location and hide the TOC window (also on `mouse-2').
+\\`<' / \\`>'      Promote / Demote section, or all sections in region.
+\\`C-c >'      Display Index. With prefix arg, restrict index to current 
section.
+\\`q' / \\`k'      Hide/Kill *toc* buffer, return to position of reftex-toc 
command.
+\\`l' \\`i' \\`c' \\`F'    Toggle display of  [l]abels,  [i]ndex,  [c]ontext,  
[F]ile borders.
+\\`t'          Change maximum toc depth (e.g. `3 t' hides levels greater than 
3).
+\\`f' / \\`g'      Toggle follow mode / Refresh *toc* buffer.
+\\`a' / \\`d'      Toggle auto recenter / Toggle dedicated frame
+\\`r' / \\`C-u r'  Reparse the LaTeX document     / Reparse entire LaTeX 
document.
+\\`.'          In other window, show position from where `reftex-toc' was 
called.
+\\`M-%'        Global search and replace to rename label at point.
+\\`x'          Switch to TOC of external document (with LaTeX package `xr').
+\\`z'          Jump to a specific section (e.g. \\`3 z' goes to section 3).")
 
 (defvar reftex--rebuilding-toc nil)
 
@@ -394,7 +391,9 @@ SPC=view TAB=goto RET=goto+hide [q]uit [r]escan [l]abels 
[f]ollow [x]r [?]Help
                 (frame-parameter  frame 'name))
               "RefTeX TOC Frame")))
     (if (and res error)
-        (error "This frame is view-only.  Use `C-c =' to create TOC window for 
commands"))
+        (error (substitute-command-keys
+                "This frame is view-only.  Use \\[reftex-toc] \
+to create TOC window for commands")))
     res))
 
 (defun reftex-toc-show-help ()
@@ -402,7 +401,9 @@ SPC=view TAB=goto RET=goto+hide [q]uit [r]escan [l]abels 
[f]ollow [x]r [?]Help
   (interactive)
   (reftex-toc-dframe-p nil 'error)
   (with-output-to-temp-buffer "*RefTeX Help*"
-    (princ reftex-toc-help))
+    (let ((help (substitute-command-keys reftex-toc-help)))
+      (with-current-buffer standard-output
+        (insert help))))
   (reftex-enlarge-to-fit "*RefTeX Help*" t)
   ;; If follow mode is active, arrange to delay it one command
   (if reftex-toc-follow-mode
diff --git a/lisp/textmodes/reftex-vars.el b/lisp/textmodes/reftex-vars.el
index f9f09825fa..ee94cc5d69 100644
--- a/lisp/textmodes/reftex-vars.el
+++ b/lisp/textmodes/reftex-vars.el
@@ -100,7 +100,7 @@
      (("lstlisting" ?l "lst:" "~\\ref{%s}" nil (regexp "[Ll]isting"))))
 
     (minted    "The minted package"
-     (("minted" ?l "lst:" "~\\ref{%s}" nil (regexp "[Ll]isting"))))
+     (("listing" ?l "lst:" "~\\ref{%s}" nil (regexp "[Ll]isting"))))
 
     ;; The LaTeX core stuff
     (LaTeX       "LaTeX default environments"
diff --git a/lisp/textmodes/remember.el b/lisp/textmodes/remember.el
index e72f86f7db..c7a9f20ea2 100644
--- a/lisp/textmodes/remember.el
+++ b/lisp/textmodes/remember.el
@@ -129,8 +129,6 @@
 ;; To map the primary remember function to the keystroke F8, do the
 ;; following.
 ;;
-;;   (autoload 'remember "remember" nil t)
-;;
 ;;   (define-key global-map [f8] 'remember)
 ;;
 ;; * Feedback
@@ -296,7 +294,8 @@ With a prefix or a visible region, use the region as 
INITIAL."
         (insert "\n\n" annotation))
       (setq remember-initial-contents nil)
       (goto-char (point-min)))
-    (message "Use C-c C-c to remember the data.")))
+    (message (substitute-command-keys
+              "Use \\[remember-finalize] to remember the data"))))
 
 ;;;###autoload
 (defun remember-other-frame (&optional initial)
@@ -557,7 +556,7 @@ If this is nil, then `diary-file' will be used instead."
     map)
   "Keymap used in `remember-mode'.")
 
-(define-derived-mode remember-mode indented-text-mode "Remember"
+(define-derived-mode remember-mode text-mode "Remember"
   "Major mode for output from \\[remember].
 This buffer is used to collect data that you want to remember.
 \\<remember-mode-map>
diff --git a/lisp/textmodes/rst.el b/lisp/textmodes/rst.el
index 6a91cef1d9..c0d4dc68af 100644
--- a/lisp/textmodes/rst.el
+++ b/lisp/textmodes/rst.el
@@ -48,10 +48,10 @@
 ;; the contents of this package and how to use it.
 ;;
 ;; For more information about reStructuredText, see
-;; http://docutils.sourceforge.net/rst.html
+;; https://docutils.sourceforge.io/rst.html
 ;;
 ;; For full details on how to use the contents of this file, see
-;; http://docutils.sourceforge.net/docs/user/emacs.html
+;; https://docutils.sourceforge.io/docs/user/emacs.html
 ;;
 ;; There are a number of convenient key bindings provided by rst-mode.  For the
 ;; bindings, try C-c C-h when in rst-mode.  There are also many variables that
@@ -72,7 +72,7 @@
 ;;; DOWNLOAD
 
 ;; The latest release of this file lies in the docutils source code repository:
-;;   
http://docutils.svn.sourceforge.net/svnroot/docutils/trunk/docutils/tools/editors/emacs/rst.el
+;;   
https://sourceforge.net/p/docutils/code/HEAD/tree/trunk/docutils/tools/editors/emacs/rst.el
 
 ;;; INSTALLATION
 
@@ -81,7 +81,7 @@
 ;;   (require 'rst)
 ;;
 ;; If you are using `.txt' as a standard extension for reST files as
-;; 
http://docutils.sourceforge.net/FAQ.html#what-s-the-standard-filename-extension-for-a-restructuredtext-file
+;; 
https://docutils.sourceforge.io/FAQ.html#what-s-the-standard-filename-extension-for-a-restructuredtext-file
 ;; suggests you may use one of the `Local Variables in Files' mechanism Emacs
 ;; provides to set the major mode automatically.  For instance you may use::
 ;;
@@ -274,7 +274,7 @@ in parentheses follows the development revision and the 
time stamp.")
 (defgroup rst nil "Support for reStructuredText documents."
   :group 'text
   :version "23.1"
-  :link '(url-link "http://docutils.sourceforge.net/rst.html";))
+  :link '(url-link "https://docutils.sourceforge.io/rst.html";))
 
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -522,7 +522,7 @@ argument list for `rst-re'.")
 
 (defvar rst-re-alist) ; Forward declare to use it in `rst-re'.
 
-;; FIXME: Use `sregex' or `rx' instead of re-inventing the wheel.
+;; FIXME: Use `rx' instead of re-inventing the wheel.
 (rst-testcover-add-compose 'rst-re)
 (defun rst-re (&rest args)
   ;; testcover: ok.
@@ -2153,8 +2153,8 @@ around the cursor.  Then the following cases are 
distinguished.
            (end-of-line))
          nil)))))
 
-;; Maintain an alias for compatibility.
-(defalias 'rst-adjust-section-title 'rst-adjust)
+(define-obsolete-function-alias 'rst-adjust-section-title
+  #'rst-adjust "29.1")
 
 (defun rst-adjust-region (demote)
   ;; testcover: ok.
@@ -2205,8 +2205,8 @@ Hierarchy is displayed in a temporary buffer."
          (insert "\n")
          (cl-incf level))))))
 
-;; Maintain an alias for backward compatibility.
-(defalias 'rst-display-adornments-hierarchy 'rst-display-hdr-hierarchy)
+(define-obsolete-function-alias 'rst-display-adornments-hierarchy
+  #'rst-display-hdr-hierarchy "29.1")
 
 ;; FIXME: Should accept an argument giving the hierarchy level to start with
 ;;        instead of the top of the hierarchy.
@@ -2231,8 +2231,8 @@ in order to adapt it to our preferred style."
        (goto-char marker) nil)
       (rst-update-section (nth level (rst-Hdr-preferred-adornments))))))
 
-;; Maintain an alias for compatibility.
-(defalias 'rst-straighten-adornments 'rst-straighten-sections)
+(define-obsolete-function-alias 'rst-straighten-adornments
+  #'rst-straighten-sections "29.1")
 
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -2858,8 +2858,8 @@ file-write hook to always make it up-to-date 
automatically."
 ;;         ;; Disable undo for the write file hook.
 ;;         (let ((buffer-undo-list t)) (rst-toc-update) ))
 
-;; Maintain an alias for compatibility.
-(defalias 'rst-toc-insert-update 'rst-toc-update)
+(define-obsolete-function-alias 'rst-toc-insert-update
+  #'rst-toc-update "29.1")
 
 (defconst rst-toc-buffer-name "*Table of Contents*"
   "Name of the Table of Contents buffer.")
@@ -2893,8 +2893,8 @@ selecting a section title moves the cursor to that 
section."
     (setq rst-toc-mode-return-wincfg wincfg)
     (goto-char (or target-pos (point-min)))))
 
-;; Maintain an alias for compatibility.
-(defalias 'rst-goto-section 'rst-toc-follow-link)
+(define-obsolete-function-alias 'rst-goto-section
+  #'rst-toc-follow-link "29.1")
 
 (defun rst-toc-follow-link (link-buf link-pnt kill)
   ;; testcover: ok.
@@ -2919,8 +2919,8 @@ error if there is no working link at the given position."
     ;;        the adornment is always completely visible.
     (recenter 5)))
 
-;; Maintain an alias for compatibility.
-(defalias 'rst-toc-mode-goto-section 'rst-toc-mode-follow-link-kill)
+(define-obsolete-function-alias 'rst-toc-mode-goto-section
+  #'rst-toc-mode-follow-link-kill "29.1")
 
 ;; FIXME: Cursor before or behind the list must be handled properly; before the
 ;;        list should jump to the top and behind the list to the last normal
@@ -2931,8 +2931,8 @@ error if there is no working link at the given position."
   (interactive)
   (rst-toc-follow-link (current-buffer) (point) t))
 
-;; Maintain an alias for compatibility.
-(defalias 'rst-toc-mode-mouse-goto 'rst-toc-mouse-follow-link)
+(define-obsolete-function-alias 'rst-toc-mode-mouse-goto
+  #'rst-toc-mouse-follow-link "29.1")
 
 (defun rst-toc-mouse-follow-link (event kill)
   ;; testcover: uncovered.
@@ -2942,8 +2942,8 @@ EVENT is the input event.  Kill TOC buffer if KILL."
   (rst-toc-follow-link (window-buffer (posn-window (event-end event)))
                       (posn-point (event-end event)) kill))
 
-;; Maintain an alias for compatibility.
-(defalias 'rst-toc-mode-mouse-goto-kill 'rst-toc-mode-mouse-follow-link-kill)
+(define-obsolete-function-alias 'rst-toc-mode-mouse-goto-kill
+  #'rst-toc-mode-mouse-follow-link-kill "29.1")
 
 (defun rst-toc-mode-mouse-follow-link-kill (event)
   ;; testcover: uncovered.
@@ -2952,8 +2952,8 @@ EVENT is the input event."
   (interactive "e")
   (rst-toc-mouse-follow-link event t))
 
-;; Maintain an alias for compatibility.
-(defalias 'rst-toc-quit-window 'rst-toc-mode-return)
+(define-obsolete-function-alias 'rst-toc-quit-window
+  #'rst-toc-mode-return "29.1")
 
 (defun rst-toc-mode-return (kill)
   ;; testcover: ok.
@@ -3569,8 +3569,6 @@ Region is from BEG to END.  With WITH-EMPTY prefix empty 
lines too."
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Font lock
 
-;; FIXME: The obsolete variables need to disappear.
-
 ;; The following versions have been done inside Emacs and should not be
 ;; replaced by `:package-version' attributes until a change.
 
@@ -3584,125 +3582,46 @@ Region is from BEG to END.  With WITH-EMPTY prefix 
empty lines too."
   :version "24.1"
   :group 'rst-faces)
 
-(defcustom rst-block-face 'rst-block
-  "All syntax marking up a special block."
-  :version "24.1"
-  :group 'rst-faces
-  :type '(face))
-(make-obsolete-variable 'rst-block-face
-                        "customize the face `rst-block' instead."
-                        "24.1")
-
 (defface rst-external '((t :inherit font-lock-type-face))
   "Face used for field names and interpreted text."
   :version "24.1"
   :group 'rst-faces)
 
-(defcustom rst-external-face 'rst-external
-  "Field names and interpreted text."
-  :version "24.1"
-  :group 'rst-faces
-  :type '(face))
-(make-obsolete-variable 'rst-external-face
-                        "customize the face `rst-external' instead."
-                        "24.1")
-
 (defface rst-definition '((t :inherit font-lock-function-name-face))
   "Face used for all other defining constructs."
   :version "24.1"
   :group 'rst-faces)
 
-(defcustom rst-definition-face 'rst-definition
-  "All other defining constructs."
-  :version "24.1"
-  :group 'rst-faces
-  :type '(face))
-(make-obsolete-variable 'rst-definition-face
-                        "customize the face `rst-definition' instead."
-                        "24.1")
-
 (defface rst-directive '((t :inherit font-lock-builtin-face))
   "Face used for directives and roles."
   :version "24.1"
   :group 'rst-faces)
 
-(defcustom rst-directive-face 'rst-directive
-  "Directives and roles."
-  :group 'rst-faces
-  :type '(face))
-(make-obsolete-variable 'rst-directive-face
-                        "customize the face `rst-directive' instead."
-                        "24.1")
-
 (defface rst-comment '((t :inherit font-lock-comment-face))
   "Face used for comments."
   :version "24.1"
   :group 'rst-faces)
 
-(defcustom rst-comment-face 'rst-comment
-  "Comments."
-  :version "24.1"
-  :group 'rst-faces
-  :type '(face))
-(make-obsolete-variable 'rst-comment-face
-                        "customize the face `rst-comment' instead."
-                        "24.1")
-
 (defface rst-emphasis1 '((t :inherit italic))
   "Face used for simple emphasis."
   :version "24.1"
   :group 'rst-faces)
 
-(defcustom rst-emphasis1-face 'rst-emphasis1
-  "Simple emphasis."
-  :version "24.1"
-  :group 'rst-faces
-  :type '(face))
-(make-obsolete-variable 'rst-emphasis1-face
-                        "customize the face `rst-emphasis1' instead."
-                        "24.1")
-
 (defface rst-emphasis2 '((t :inherit bold))
   "Face used for double emphasis."
   :version "24.1"
   :group 'rst-faces)
 
-(defcustom rst-emphasis2-face 'rst-emphasis2
-  "Double emphasis."
-  :group 'rst-faces
-  :type '(face))
-(make-obsolete-variable 'rst-emphasis2-face
-                        "customize the face `rst-emphasis2' instead."
-                        "24.1")
-
 (defface rst-literal '((t :inherit font-lock-string-face))
   "Face used for literal text."
   :version "24.1"
   :group 'rst-faces)
 
-(defcustom rst-literal-face 'rst-literal
-  "Literal text."
-  :version "24.1"
-  :group 'rst-faces
-  :type '(face))
-(make-obsolete-variable 'rst-literal-face
-                        "customize the face `rst-literal' instead."
-                        "24.1")
-
 (defface rst-reference '((t :inherit font-lock-variable-name-face))
   "Face used for references to a definition."
   :version "24.1"
   :group 'rst-faces)
 
-(defcustom rst-reference-face 'rst-reference
-  "References to a definition."
-  :version "24.1"
-  :group 'rst-faces
-  :type '(face))
-(make-obsolete-variable 'rst-reference-face
-                        "customize the face `rst-reference' instead."
-                        "24.1")
-
 (defface rst-transition '((t :inherit font-lock-keyword-face))
   "Face used for a transition."
   :package-version '(rst . "1.3.0")
@@ -3786,7 +3705,7 @@ of your own."
 
 (defvar rst-font-lock-keywords
   ;; The reST-links in the comments below all relate to sections in
-  ;; http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html.
+  ;; https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html.
   `(;; FIXME: Block markup is not recognized in blocks after explicit markup
     ;;        start.
 
@@ -3794,23 +3713,23 @@ of your own."
     ;; `Bullet Lists`_
     ;; FIXME: A bullet directly after a field name is not recognized.
     (,(rst-re 'lin-beg '(:grp bul-sta))
-     1 rst-block-face)
+     1 'rst-block)
     ;; `Enumerated Lists`_
     (,(rst-re 'lin-beg '(:grp enmany-sta))
-     1 rst-block-face)
+     1 'rst-block)
     ;; `Definition Lists`_
     ;; FIXME: missing.
     ;; `Field Lists`_
     (,(rst-re 'lin-beg '(:grp fld-tag) 'bli-sfx)
-     1 rst-external-face)
+     1 'rst-external)
     ;; `Option Lists`_
     (,(rst-re 'lin-beg '(:grp opt-tag (:shy optsep-tag opt-tag) "*")
              '(:alt "$" (:seq hws-prt "\\{2\\}")))
-     1 rst-block-face)
+     1 'rst-block)
     ;; `Line Blocks`_
     ;; Only for lines containing no more bar - to distinguish from tables.
     (,(rst-re 'lin-beg '(:grp "|" bli-sfx) "[^|\n]*$")
-     1 rst-block-face)
+     1 'rst-block)
 
     ;; `Tables`_
     ;; FIXME: missing
@@ -3818,22 +3737,22 @@ of your own."
     ;; All the `Explicit Markup Blocks`_
     ;; `Footnotes`_ / `Citations`_
     (,(rst-re 'lin-beg 'fnc-sta-2)
-     (1 rst-definition-face)
-     (2 rst-definition-face))
+     (1 'rst-definition)
+     (2 'rst-definition))
     ;; `Directives`_ / `Substitution Definitions`_
     (,(rst-re 'lin-beg 'dir-sta-3)
-     (1 rst-directive-face)
-     (2 rst-definition-face)
-     (3 rst-directive-face))
+     (1 'rst-directive)
+     (2 'rst-definition)
+     (3 'rst-directive))
     ;; `Hyperlink Targets`_
     (,(rst-re 'lin-beg
              '(:grp exm-sta "_" (:alt
                                  (:seq "`" ilcbkqdef-tag "`")
                                  (:seq (:alt "[^:\\\n]" "\\\\.") "+")) ":")
              'bli-sfx)
-     1 rst-definition-face)
+     1 'rst-definition)
     (,(rst-re 'lin-beg '(:grp "__") 'bli-sfx)
-     1 rst-definition-face)
+     1 'rst-definition)
 
     ;; All `Inline Markup`_
     ;; Most of them may be multiline though this is uninteresting.
@@ -3841,16 +3760,16 @@ of your own."
     ;; FIXME: Condition 5 preventing fontification of e.g. "*" not implemented
     ;;        `Strong Emphasis`_.
     (,(rst-re 'ilm-pfx '(:grp "\\*\\*" ilcast-tag "\\*\\*") 'ilm-sfx)
-     1 rst-emphasis2-face)
+     1 'rst-emphasis2)
     ;; `Emphasis`_
     (,(rst-re 'ilm-pfx '(:grp "\\*" ilcast-tag "\\*") 'ilm-sfx)
-     1 rst-emphasis1-face)
+     1 'rst-emphasis1)
     ;; `Inline Literals`_
     (,(rst-re 'ilm-pfx '(:grp "``" ilcbkq-tag "``") 'ilm-sfx)
-     1 rst-literal-face)
+     1 'rst-literal)
     ;; `Inline Internal Targets`_
     (,(rst-re 'ilm-pfx '(:grp "_`" ilcbkq-tag "`") 'ilm-sfx)
-     1 rst-definition-face)
+     1 'rst-definition)
     ;; `Hyperlink References`_
     ;; FIXME: `Embedded URIs and Aliases`_ not considered.
     ;; FIXME: Directly adjacent marked up words are not fontified correctly
@@ -3858,28 +3777,28 @@ of your own."
     (,(rst-re 'ilm-pfx '(:grp (:alt (:seq "`" ilcbkq-tag "`")
                                    (:seq "\\sw" (:alt "\\sw" "-") "+\\sw"))
                              "__?") 'ilm-sfx)
-     1 rst-reference-face)
+     1 'rst-reference)
     ;; `Interpreted Text`_
     (,(rst-re 'ilm-pfx '(:grp (:shy ":" sym-tag ":") "?")
              '(:grp "`" ilcbkq-tag "`")
              '(:grp (:shy ":" sym-tag ":") "?") 'ilm-sfx)
-     (1 rst-directive-face)
-     (2 rst-external-face)
-     (3 rst-directive-face))
+     (1 'rst-directive)
+     (2 'rst-external)
+     (3 'rst-directive))
     ;; `Footnote References`_ / `Citation References`_
     (,(rst-re 'ilm-pfx '(:grp fnc-tag "_") 'ilm-sfx)
-     1 rst-reference-face)
+     1 'rst-reference)
     ;; `Substitution References`_
     ;; FIXME: References substitutions like |this|_ or |this|__ are not
     ;;        fontified correctly.
     (,(rst-re 'ilm-pfx '(:grp sub-tag) 'ilm-sfx)
-     1 rst-reference-face)
+     1 'rst-reference)
     ;; `Standalone Hyperlinks`_
     ;; FIXME: This takes it easy by using a whitespace as delimiter.
     (,(rst-re 'ilm-pfx '(:grp uri-tag ":\\S +") 'ilm-sfx)
-     1 rst-definition-face)
+     1 'rst-definition)
     (,(rst-re 'ilm-pfx '(:grp sym-tag "@" sym-tag ) 'ilm-sfx)
-     1 rst-definition-face)
+     1 'rst-definition)
 
     ;; Do all block fontification as late as possible so 'append works.
 
@@ -3906,18 +3825,18 @@ of your own."
     ;; `Comments`_
     ;; This is multiline.
     (,(rst-re 'lin-beg 'cmt-sta-1)
-     (1 rst-comment-face)
+     (1 'rst-comment)
      (rst-font-lock-find-unindented-line-match
       (rst-font-lock-find-unindented-line-limit (match-end 1))
       nil
-      (0 rst-comment-face append)))
+      (0 'rst-comment append)))
     (,(rst-re 'lin-beg '(:grp exm-tag) '(:grp hws-tag) "$")
-     (1 rst-comment-face)
-     (2 rst-comment-face)
+     (1'rst-comment)
+     (2'rst-comment)
      (rst-font-lock-find-unindented-line-match
       (rst-font-lock-find-unindented-line-limit 'next)
       nil
-      (0 rst-comment-face append)))
+      (0 'rst-comment append)))
 
     ;; FIXME: This is not rendered as comment::
     ;;        .. .. list-table::
@@ -3941,11 +3860,11 @@ of your own."
     ;; `Indented Literal Blocks`_
     ;; This is multiline.
     (,(rst-re 'lin-beg 'lit-sta-2)
-     (2 rst-block-face)
+     (2 'rst-block)
      (rst-font-lock-find-unindented-line-match
       (rst-font-lock-find-unindented-line-limit t)
       nil
-      (0 rst-literal-face append)))
+      (0 'rst-literal append)))
 
     ;; FIXME: `Quoted Literal Blocks`_ missing.
     ;; This is multiline.
@@ -3972,8 +3891,8 @@ of your own."
     ;;
     ;;   Indentation is not required for doctest blocks.
     (,(rst-re 'lin-beg '(:grp (:alt ">>>" ell-tag)) '(:grp ".+"))
-     (1 rst-block-face)
-     (2 rst-literal-face)))
+     (1 'rst-block)
+     (2 'rst-literal)))
   "Keywords to highlight in rst mode.")
 
 (defvar font-lock-beg)
@@ -4402,7 +4321,7 @@ buffer, if the region is not selected."
 
 ;; FIXME: Add `rst-compile-html-preview'.
 
-;; FIXME: Add support for `restview` (http://mg.pov.lt/restview/). May be a
+;; FIXME: Add support for `restview` (https://mg.pov.lt/restview/). May be a
 ;;        more general facility for calling commands on a reST file would make
 ;;        sense.
 
diff --git a/lisp/textmodes/sgml-mode.el b/lisp/textmodes/sgml-mode.el
index b49541f47d..7d691430ec 100644
--- a/lisp/textmodes/sgml-mode.el
+++ b/lisp/textmodes/sgml-mode.el
@@ -480,8 +480,8 @@ The attribute alist is made up as
 ATTRIBUTERULE is a list of optionally t (no value when no input) followed by
 an optional alist of possible values."
   :type '(repeat (cons (string :tag "Tag Name")
-                      (repeat :tag "Tag Rule" sexp))))
-(put 'sgml-tag-alist 'risky-local-variable t)
+                       (repeat :tag "Tag Rule" sexp)))
+  :risky t)
 
 (defcustom sgml-tag-help
   '(("!" . "Empty declaration for comment")
@@ -600,12 +600,11 @@ Do \\[describe-key] on the following bindings to discover 
what they do.
   (setq-local tildify-foreach-region-function
               (apply-partially
                'tildify-foreach-ignore-environments
-               `((,(eval-when-compile
-                     (concat
-                      "<\\("
-                      (regexp-opt '("pre" "dfn" "code" "samp" "kbd" "var"
-                                    "PRE" "DFN" "CODE" "SAMP" "KBD" "VAR"))
-                      "\\)\\>[^>]*>"))
+               `((,(concat
+                    "<\\("
+                    (regexp-opt '("pre" "dfn" "code" "samp" "kbd" "var"
+                                  "PRE" "DFN" "CODE" "SAMP" "KBD" "VAR"))
+                    "\\)\\>[^>]*>")
                   . ("</" 1 ">"))
                  ("<! *--" . "-- *>")
                  ("<" . ">"))))
@@ -1537,8 +1536,7 @@ not the case, the first tag returned is the one inside 
which we are."
            ;; [ Well, actually it depends, but we don't have the info about
            ;; when it doesn't and when it does.   --Stef ]
            (setq ignore nil)))
-        ((eq t (compare-strings (sgml-tag-name tag-info) nil nil
-                                (car stack) nil nil t))
+        ((string-equal-ignore-case (sgml-tag-name tag-info) (car stack))
          (setq stack (cdr stack)))
         (t
          ;; The open and close tags don't match.
@@ -1550,9 +1548,8 @@ not the case, the first tag returned is the one inside 
which we are."
                  ;; but it's a bad assumption when tags *are* closed but
                  ;; not properly nested.
                  (while (and (cdr tmp)
-                             (not (eq t (compare-strings
-                                         (sgml-tag-name tag-info) nil nil
-                                         (cadr tmp) nil nil t))))
+                             (not (string-equal-ignore-case
+                                   (sgml-tag-name tag-info) (cadr tmp))))
                    (setq tmp (cdr tmp)))
                  (if (cdr tmp) (setcdr tmp (cddr tmp)))))
            (message "Unmatched tags <%s> and </%s>"
@@ -1702,9 +1699,8 @@ LCON is the lexical context, if any."
            (there (point)))
        ;; Ignore previous unclosed start-tag in context.
        (while (and context unclosed
-                  (eq t (compare-strings
-                         (sgml-tag-name (car context)) nil nil
-                         unclosed nil nil t)))
+                  (string-equal-ignore-case
+                   (sgml-tag-name (car context)) unclosed))
         (setq context (cdr context)))
        ;; Indent to reflect nesting.
        (cond
@@ -1917,7 +1913,7 @@ This takes effect when first loading the library.")
         (valign '(("top") ("middle") ("bottom") ("baseline")))
         (rel '(("next") ("previous") ("parent") ("subdocument") ("made")))
         (href '("href" ("ftp:") ("file:") ("finger:") ("gopher:") ("http:")
-                ("mailto:";) ("news:";) ("rlogin:") ("telnet:") ("tn3270:")
+                 ("https:") ("mailto:";) ("news:";) ("rlogin:") ("telnet:") 
("tn3270:")
                 ("wais:") ("/cgi-bin/")))
         (name '("name"))
         (link `(,href
@@ -2409,6 +2405,7 @@ To work around that, do:
              (lambda () (char-before (match-end 0))))
   (setq-local add-log-current-defun-function #'html-current-defun-name)
   (setq-local sentence-end-base "[.?!][]\"'”)}]*\\(<[^>]*>\\)*")
+  (add-hook 'completion-at-point-functions 'html-mode--complete-at-point nil t)
 
   (when (fboundp 'libxml-parse-html-region)
     (defvar css-class-list-function)
@@ -2434,6 +2431,36 @@ To work around that, do:
   ;; (setq imenu-sort-function nil) ; sorting the menu defeats the purpose
   )
 
+(defun html-mode--complete-at-point ()
+  ;; Complete a tag like <colg etc.
+  (or
+   (when-let ((tag (save-excursion
+                     (and (looking-back "<\\([^ \t\n]*\\)"
+                                        (line-beginning-position))
+                          (match-string 1)))))
+     (list (match-beginning 1) (point)
+           (mapcar #'car html-tag-alist)))
+   ;; Complete params like <colgroup ali etc.
+   (when-let ((tag (save-excursion (sgml-beginning-of-tag)))
+              (params (seq-filter #'consp (cdr (assoc tag html-tag-alist))))
+              (param (save-excursion
+                       (and (looking-back "[ \t\n]\\([^= \t\n]*\\)"
+                                          (line-beginning-position))
+                            (match-string 1)))))
+     (list (match-beginning 1) (point)
+           (mapcar #'car params)))
+   ;; Complete param values like <colgroup align=mi etc.
+   (when-let ((tag (save-excursion (sgml-beginning-of-tag)))
+              (params (seq-filter #'consp (cdr (assoc tag html-tag-alist))))
+              (param (save-excursion
+                       (and (looking-back
+                             "[ \t\n]\\([^= \t\n]+\\)=\\([^= \t\n]*\\)"
+                             (line-beginning-position))
+                            (match-string 1))))
+              (values (cdr (assoc param params))))
+     (list (match-beginning 2) (point)
+           (mapcar #'car values)))))
+
 (defun html-mode--html-yank-handler (_type html)
   (save-restriction
     (insert html)
diff --git a/lisp/textmodes/tex-mode.el b/lisp/textmodes/tex-mode.el
index 473643bb48..e6c0f8c28c 100644
--- a/lisp/textmodes/tex-mode.el
+++ b/lisp/textmodes/tex-mode.el
@@ -248,9 +248,9 @@ Normally set to either `plain-tex-mode' or `latex-mode'."
 (defcustom tex-fontify-script t
   "If non-nil, fontify subscript and superscript strings."
   :type 'boolean
+  :safe #'booleanp
   :group 'tex
   :version "23.1")
-(put 'tex-fontify-script 'safe-local-variable #'booleanp)
 
 (defcustom tex-font-script-display '(-0.2 0.2)
   "How much to lower and raise subscript and superscript content.
@@ -983,14 +983,13 @@ Inherits `shell-mode-map' with a few additions.")
       (when (and slash (not comment))
        (setq mode
              (if (looking-at
-                  (eval-when-compile
-                    (concat
-                     (regexp-opt '("documentstyle" "documentclass"
-                                   "begin" "subsection" "section"
-                                   "part" "chapter" "newcommand"
-                                   "renewcommand" "RequirePackage")
-                                 'words)
-                     "\\|NeedsTeXFormat{LaTeX")))
+                  (concat
+                   (regexp-opt '("documentstyle" "documentclass"
+                                 "begin" "subsection" "section"
+                                 "part" "chapter" "newcommand"
+                                 "renewcommand" "RequirePackage")
+                               'words)
+                   "\\|NeedsTeXFormat{LaTeX"))
                  (if (and (looking-at
                            
"document\\(style\\|class\\)\\(\\[.*\\]\\)?{slides}")
                           ;; SliTeX is almost never used any more nowadays.
@@ -1242,11 +1241,10 @@ Entering SliTeX mode runs the hook `text-mode-hook', 
then the hook
               (apply-partially
                #'tildify-foreach-ignore-environments
                `(("\\\\\\\\" . "") ; do not remove this
-                 (,(eval-when-compile
-                     (concat "\\\\begin{\\("
-                             (regexp-opt '("verbatim" "math" "displaymath"
-                                           "equation" "eqnarray" "eqnarray*"))
-                             "\\)}"))
+                 (,(concat "\\\\begin{\\("
+                           (regexp-opt '("verbatim" "math" "displaymath"
+                                         "equation" "eqnarray" "eqnarray*"))
+                           "\\)}")
                   . ("\\\\end{" 1 "}"))
                  ("\\\\verb\\*?\\(.\\)" . (1))
                  ("\\$\\$?" . (0))
@@ -2126,11 +2124,10 @@ If NOT-ALL is non-nil, save the `.dvi' file."
 (defvar tex-compile-history nil)
 
 (defvar tex-input-files-re
-  (eval-when-compile
-    (concat "\\." (regexp-opt '("tex" "texi" "texinfo"
-                               "bbl" "ind" "sty" "cls") t)
-           ;; Include files with no dots (for directories).
-           "\\'\\|\\`[^.]+\\'")))
+  (concat "\\." (regexp-opt '("tex" "texi" "texinfo"
+                             "bbl" "ind" "sty" "cls") t)
+         ;; Include files with no dots (for directories).
+         "\\'\\|\\`[^.]+\\'"))
 
 (defcustom tex-use-reftex t
   "If non-nil, use RefTeX's list of files to determine what command to use."
@@ -2499,10 +2496,8 @@ Only applies the FSPEC to the args part of FORMAT."
     (let (shell-dirtrack-verbose)
       (tex-send-command tex-shell-cd-command dir)))
   (with-current-buffer (process-buffer (tex-send-command cmd))
-    (setq compilation-last-buffer (current-buffer))
-    (compilation-forget-errors)
-    ;; Don't parse previous compilations.
-    (set-marker compilation-parsing-end (1- (point-max))))
+    (setq next-error-last-buffer (current-buffer))
+    (compilation-forget-errors))
   (tex-display-shell)
   (setq tex-last-buffer-texed (current-buffer)))
 
diff --git a/lisp/textmodes/texinfo.el b/lisp/textmodes/texinfo.el
index 5d6f5deae1..98672f42b3 100644
--- a/lisp/textmodes/texinfo.el
+++ b/lisp/textmodes/texinfo.el
@@ -235,9 +235,6 @@ Subexpression 1 is what goes into the corresponding `@end' 
statement.")
   (define-key keymap "\C-c\C-t\C-r"    #'texinfo-tex-region)
   (define-key keymap "\C-c\C-t\C-b"    #'texinfo-tex-buffer))
 
-;; Mode documentation displays commands in reverse order
-;; from how they are listed in the texinfo-mode-map.
-
 (defvar texinfo-mode-map
   (let ((map (make-sparse-keymap)))
 
@@ -401,7 +398,7 @@ REPORT-FN is the callback function."
                                      source beg end type msg)
                             into diags
                             finally (funcall report-fn diags)))
-                       (flymake-log :warning "Cancelling obsolete check %s"
+                       (flymake-log :warning "Canceling obsolete check %s"
                                     proc))
                    (kill-buffer (process-buffer proc)))))))
       (process-send-region texinfo--flymake-proc (point-min) (point-max))
@@ -782,10 +779,10 @@ braces."
   nil
   (cond
    ;; parenthesis
-   ((looking-back "([^)]*" (point-at-bol 0))
+   ((looking-back "([^)]*" (line-beginning-position 0))
     "@pxref{")
    ;; beginning of sentence or buffer
-   ((or (looking-back (sentence-end) (point-at-bol 0))
+   ((or (looking-back (sentence-end) (line-beginning-position 0))
         (= (point) (point-min)))
     "@xref{")
    ;; bol or eol
@@ -793,7 +790,7 @@ braces."
     "@ref{")
    ;; inside word
    ((not (eq (char-syntax (char-after)) ? ))
-    (skip-syntax-backward "^ " (point-at-bol))
+    (skip-syntax-backward "^ " (line-beginning-position))
     "@ref{")
    ;; everything else
    (t
diff --git a/lisp/textmodes/texnfo-upd.el b/lisp/textmodes/texnfo-upd.el
index 5b468dc808..e44aa06e3d 100644
--- a/lisp/textmodes/texnfo-upd.el
+++ b/lisp/textmodes/texnfo-upd.el
@@ -1367,7 +1367,7 @@ left at the end of the node line."
            ;; There may be an @chapter or other such command between
            ;; the top node line and the next node line, as a title
            ;; for an `ifinfo' section. This @chapter command must
-           ;; must be skipped.  So the procedure is to search for
+           ;; be skipped.  So the procedure is to search for
            ;; the next `@node' line, and then copy its name.
            (if (re-search-forward "^@node" nil t)
                (progn
diff --git a/lisp/textmodes/text-mode.el b/lisp/textmodes/text-mode.el
index 076f8dd98f..9e8f3747c5 100644
--- a/lisp/textmodes/text-mode.el
+++ b/lisp/textmodes/text-mode.el
@@ -67,13 +67,11 @@
     st)
   "Syntax table used while in `text-mode'.")
 
-(defvar text-mode-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "\e\t" #'ispell-complete-word)
-    map)
-  "Keymap for `text-mode'.
-Many other modes, such as `mail-mode', `outline-mode' and `indented-text-mode',
-inherit all the commands defined in this map.")
+(defvar-keymap text-mode-map
+  :doc "Keymap for `text-mode'.
+Many other modes, such as `mail-mode' and `outline-mode', inherit
+all the commands defined in this map."
+  "C-M-i" #'ispell-complete-word)
 
 (easy-menu-define text-mode-menu text-mode-map
   "Menu for `text-mode'."
@@ -164,8 +162,6 @@ Turning on Paragraph-Indent minor mode runs the normal hook
     (remove-function (local 'indent-line-function)
                      #'indent-to-left-margin)))
 
-(defalias 'indented-text-mode #'text-mode)
-
 ;; This can be made a no-op once all modes that use text-mode-hook
 ;; are "derived" from text-mode.  (As of 2015/04, and probably well before,
 ;; the only one I can find that doesn't so derive is rmail-edit-mode.)
@@ -245,6 +241,8 @@ The argument NLINES says how many lines to center."
           (setq nlines (1+ nlines))
           (forward-line -1)))))
 
+(define-obsolete-function-alias 'indented-text-mode #'text-mode "29.1")
+
 (provide 'text-mode)
 
 ;;; text-mode.el ends here
diff --git a/lisp/textmodes/tildify.el b/lisp/textmodes/tildify.el
index 9dcfb10d6d..2a7ad295ab 100644
--- a/lisp/textmodes/tildify.el
+++ b/lisp/textmodes/tildify.el
@@ -494,9 +494,8 @@ variable will be set to the representation."
       (if (not (string-equal " " (or space tildify-space-string)))
           (when space
             (setq tildify-space-string space))
-        (message (eval-when-compile
-                   (concat "Hard space is a single space character, tildify-"
-                           "mode won't have any effect, disabling.")))
+        (message (concat "Hard space is a single space character, tildify-"
+                         "mode won't have any effect, disabling."))
         (setq tildify-mode nil))))
   (if tildify-mode
       (add-hook 'post-self-insert-hook #'tildify-space nil t)
diff --git a/lisp/thingatpt.el b/lisp/thingatpt.el
index b3dca5890f..462f87d3c1 100644
--- a/lisp/thingatpt.el
+++ b/lisp/thingatpt.el
@@ -74,7 +74,7 @@ question.
 
 \"things\" include `symbol', `list', `sexp', `defun', `filename',
 `existing-filename', `url', `email', `uuid', `word', `sentence',
-`whitespace', `line', and `page'.")
+`whitespace', `line', `face' and `page'.")
 
 ;; Basic movement
 
@@ -166,7 +166,7 @@ positions of the thing found."
 THING should be a symbol specifying a type of syntactic entity.
 Possibilities include `symbol', `list', `sexp', `defun',
 `filename', `existing-filename', `url', `email', `uuid', `word',
-`sentence', `whitespace', `line', `number', and `page'.
+`sentence', `whitespace', `line', `number', `face' and `page'.
 
 When the optional argument NO-PROPERTIES is non-nil,
 strip text properties from the return value.
@@ -361,6 +361,15 @@ E.g.:
 
 (put 'existing-filename 'thing-at-point 'thing-at-point-file-at-point)
 
+;; Faces
+
+(defun thing-at-point-face-at-point (&optional _lax _bounds)
+  "Return the name of the face at point as a symbol."
+  (when-let ((face (thing-at-point 'symbol)))
+    (and (facep face) (intern face))))
+
+(put 'face 'thing-at-point 'thing-at-point-face-at-point)
+
 ;;  URIs
 
 (defvar thing-at-point-beginning-of-url-regexp nil
@@ -391,6 +400,8 @@ If nil, construct the regexp from 
`thing-at-point-uri-schemes'.")
     "telnet://" "tftp://"; "tip://" "tn3270://" "udp://" "urn:"
     "uuid:" "vemmi://"  "webcal://" "xri://" "xmlrpc.beep://"
     "xmlrpc.beeps://" "z39.50r://" "z39.50s://" "xmpp:"
+    ;; Unofficial
+    "gemini://"
     ;; Compatibility
     "fax:" "man:" "mms://" "mmsh://" "modem:" "prospero:" "snews:";
     "wais://")
diff --git a/lisp/thumbs.el b/lisp/thumbs.el
index 3bf08dd6a5..0b3d36d6e3 100644
--- a/lisp/thumbs.el
+++ b/lisp/thumbs.el
@@ -73,16 +73,16 @@
 
 (defcustom thumbs-per-line 4
   "Number of thumbnails per line to show in directory."
-  :type 'integer)
+  :type 'natnum)
 
 (defcustom thumbs-max-image-number 16
- "Maximum number of images initially displayed in thumbs buffer."
-  :type 'integer)
+  "Maximum number of images initially displayed in thumbs buffer."
+  :type 'natnum)
 
 (defcustom thumbs-thumbsdir-max-size 50000000
   "Maximum size for thumbnails directory.
-When it reaches that size (in bytes), a warning is sent."
-  :type 'integer)
+When it reaches that size (in bytes), a warning is displayed."
+  :type 'natnum)
 
 ;; Unfortunately Windows XP has a program called CONVERT.EXE in
 ;; C:/WINDOWS/SYSTEM32/ for partitioning NTFS systems.  So Emacs
@@ -106,12 +106,12 @@ This must be the ImageMagick \"convert\" utility."
 
 (defcustom thumbs-relief 5
   "Size of button-like border around thumbnails."
-  :type 'integer)
+  :type 'natnum)
 
 (defcustom thumbs-margin 2
   "Size of the margin around thumbnails.
 This is where you see the cursor."
-  :type 'integer)
+  :type 'natnum)
 
 (defcustom thumbs-thumbsdir-auto-clean t
   "If set, delete older file in the thumbnails directory.
@@ -121,7 +121,7 @@ than `thumbs-thumbsdir-max-size'."
 
 (defcustom thumbs-image-resizing-step 10
   "Step by which to resize image as a percentage."
-  :type 'integer)
+  :type 'natnum)
 
 (defcustom thumbs-temp-dir temporary-file-directory
   "Temporary directory to use.
@@ -215,16 +215,17 @@ FILEIN is the input file,
 FILEOUT is the output file,
 ACTION is the command to send to convert.
 Optional arguments are:
-ARG any arguments to the ACTION command,
+ARG if non-nil, the argument of the ACTION command,
 OUTPUT-FORMAT is the file format to output (default is jpeg),
 ACTION-PREFIX is the symbol to place before the ACTION command
               (defaults to `-' but can sometimes be `+')."
-  (call-process thumbs-conversion-program nil nil nil
-               (or action-prefix "-")
-               action
-               (or arg "")
-               filein
-               (format "%s:%s" (or output-format "jpeg") fileout)))
+  (let ((action-param (concat (or action-prefix "-") action))
+       (fileout-param (format "%s:%s" (or output-format "jpeg") fileout)))
+    (if arg
+       (call-process thumbs-conversion-program nil nil nil
+                     action-param arg filein fileout-param)
+      (call-process thumbs-conversion-program nil nil nil
+                   action-param filein fileout-param))))
 
 (defun thumbs-new-image-size (s increment)
   "New image (a cons of width x height)."
@@ -293,6 +294,7 @@ smaller according to whether INCREMENT is 1 or -1."
     tn))
 
 (declare-function image-size "image.c" (spec &optional pixels frame))
+(declare-function image-supported-file-p "image" (file))
 
 (defun thumbs-file-size (img)
   (let ((i (image-size
@@ -610,7 +612,7 @@ ACTION and ARG should be a valid convert command."
     (thumbs-call-convert (or old thumbs-current-image-filename)
                         tmp
                         action
-                        (or arg ""))
+                        arg)
     (save-excursion
       (thumbs-insert-image tmp 'jpeg 0))
     (setq thumbs-current-tmp-filename tmp)))
@@ -703,27 +705,25 @@ ACTION and ARG should be a valid convert command."
 
 ;; thumbs-mode
 
-(defvar thumbs-mode-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map [return] 'thumbs-find-image-at-point)
-    (define-key map [mouse-2] 'thumbs-mouse-find-image)
-    (define-key map [(meta return)] 'thumbs-find-image-at-point-other-window)
-    (define-key map [(control return)] 
'thumbs-set-image-at-point-to-root-window)
-    (define-key map [delete] 'thumbs-delete-images)
-    (define-key map [right] 'thumbs-forward-char)
-    (define-key map [left] 'thumbs-backward-char)
-    (define-key map [up] 'thumbs-backward-line)
-    (define-key map [down] 'thumbs-forward-line)
-    (define-key map "+" 'thumbs-show-more-images)
-    (define-key map "d" 'thumbs-dired)
-    (define-key map "m" 'thumbs-mark)
-    (define-key map "u" 'thumbs-unmark)
-    (define-key map "R" 'thumbs-rename-images)
-    (define-key map "x" 'thumbs-delete-images)
-    (define-key map "s" 'thumbs-show-name)
-    (define-key map "q" 'thumbs-kill-buffer)
-    map)
-  "Keymap for `thumbs-mode'.")
+(defvar-keymap thumbs-mode-map
+  :doc "Keymap for `thumbs-mode'."
+  "<return>"   #'thumbs-find-image-at-point
+  "<mouse-2>"  #'thumbs-mouse-find-image
+  "M-<return>" #'thumbs-find-image-at-point-other-window
+  "C-<return>" #'thumbs-set-image-at-point-to-root-window
+  "<delete>"   #'thumbs-delete-images
+  "<right>"    #'thumbs-forward-char
+  "<left>"     #'thumbs-backward-char
+  "<up>"       #'thumbs-backward-line
+  "<down>"     #'thumbs-forward-line
+  "+"          #'thumbs-show-more-images
+  "d"          #'thumbs-dired
+  "m"          #'thumbs-mark
+  "u"          #'thumbs-unmark
+  "R"          #'thumbs-rename-images
+  "x"          #'thumbs-delete-images
+  "s"          #'thumbs-show-name
+  "q"          #'thumbs-kill-buffer)
 
 (put 'thumbs-mode 'mode-class 'special)
 (define-derived-mode thumbs-mode
@@ -731,22 +731,20 @@ ACTION and ARG should be a valid convert command."
   "Preview images in a thumbnails buffer."
   (setq buffer-read-only t))
 
-(defvar thumbs-view-image-mode-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map [prior] 'thumbs-previous-image)
-    (define-key map [next] 'thumbs-next-image)
-    (define-key map "^" 'thumbs-display-thumbs-buffer)
-    (define-key map "-" 'thumbs-shrink-image)
-    (define-key map "+" 'thumbs-enlarge-image)
-    (define-key map "<" 'thumbs-rotate-left)
-    (define-key map ">" 'thumbs-rotate-right)
-    (define-key map "e" 'thumbs-emboss-image)
-    (define-key map "r" 'thumbs-resize-image)
-    (define-key map "s" 'thumbs-save-current-image)
-    (define-key map "q" 'thumbs-kill-buffer)
-    (define-key map "w" 'thumbs-set-root)
-    map)
-  "Keymap for `thumbs-view-image-mode'.")
+(defvar-keymap thumbs-view-image-mode-map
+  :doc "Keymap for `thumbs-view-image-mode'."
+  "<prior>" #'thumbs-previous-image
+  "<next>"  #'thumbs-next-image
+  "^"       #'thumbs-display-thumbs-buffer
+  "-"       #'thumbs-shrink-image
+  "+"       #'thumbs-enlarge-image
+  "<"       #'thumbs-rotate-left
+  ">"       #'thumbs-rotate-right
+  "e"       #'thumbs-emboss-image
+  "r"       #'thumbs-resize-image
+  "s"       #'thumbs-save-current-image
+  "q"       #'thumbs-kill-buffer
+  "w"       #'thumbs-set-root)
 
 ;; thumbs-view-image-mode
 (put 'thumbs-view-image-mode 'mode-class 'special)
diff --git a/lisp/time.el b/lisp/time.el
index cd985bfb28..e7066cae7a 100644
--- a/lisp/time.el
+++ b/lisp/time.el
@@ -93,7 +93,7 @@ Non-nil means \\[display-time] should display day and date as 
well as time."
 
 (defcustom display-time-interval 60
   "Seconds between updates of time in the mode line."
-  :type 'integer)
+  :type 'natnum)
 
 (defcustom display-time-24hr-format nil
   "Non-nil indicates time should be displayed as hh:mm, 0 <= hh <= 23.
@@ -519,7 +519,7 @@ If the value is t instead of an alist, use the value of
 
 (defcustom world-clock-timer-second 60
   "Interval in seconds for updating the `world-clock' buffer."
-  :type 'integer
+  :type 'natnum
   :version "28.1")
 
 (defface world-clock-label
diff --git a/lisp/tool-bar.el b/lisp/tool-bar.el
index 82b458e010..b1f7a70e33 100644
--- a/lisp/tool-bar.el
+++ b/lisp/tool-bar.el
@@ -75,8 +75,8 @@ See `tool-bar-mode' for more information."
       (tool-bar-mode (if (> (frame-parameter nil 'tool-bar-lines) 0) 0 1))
     (tool-bar-mode arg)))
 
-(defvar tool-bar-map (make-sparse-keymap)
-  "Keymap for the tool bar.
+(defvar-keymap tool-bar-map
+  :doc "Keymap for the tool bar.
 
 To override the global tool bar, define this variable
 buffer-locally and add the items you want to it with
diff --git a/lisp/tooltip.el b/lisp/tooltip.el
index 3e9c16a445..95cb1cc62c 100644
--- a/lisp/tooltip.el
+++ b/lisp/tooltip.el
@@ -140,15 +140,6 @@ When using the GTK toolkit, this face will only be used if
   :group 'tooltip
   :group 'basic-faces)
 
-(defcustom tooltip-use-echo-area nil
-  "Use the echo area instead of tooltip frames for help and GUD tooltips.
-This variable is obsolete; instead of setting it to t, disable
-`tooltip-mode' (which has a similar effect)."
-  :type 'boolean)
-
-(make-obsolete-variable 'tooltip-use-echo-area
-                       "disable Tooltip mode instead" "24.1" 'set)
-
 (defcustom tooltip-resize-echo-area nil
   "If non-nil, using the echo area for tooltips will resize the echo area.
 By default, when the echo area is used for displaying tooltips,
@@ -427,7 +418,7 @@ This is installed on the hook `tooltip-functions', which
 is run when the timer with id `tooltip-timeout-id' fires.
 Value is non-nil if this function handled the tip."
   (when (stringp tooltip-help-message)
-    (tooltip-show tooltip-help-message tooltip-use-echo-area)
+    (tooltip-show tooltip-help-message (not tooltip-mode))
     t))
 
 (provide 'tooltip)
diff --git a/lisp/transient.el b/lisp/transient.el
index d329bbdbcd..a415858970 100644
--- a/lisp/transient.el
+++ b/lisp/transient.el
@@ -1,16 +1,18 @@
-;;; transient.el --- Transient commands          -*- lexical-binding: t; -*-
+;;; transient.el --- Transient commands  -*- lexical-binding:t -*-
 
 ;; Copyright (C) 2018-2022 Free Software Foundation, Inc.
 
 ;; Author: Jonas Bernoulli <jonas@bernoul.li>
-;; Homepage: https://github.com/magit/transient
-;; Keywords: bindings
+;; URL: https://github.com/magit/transient
+;; Keywords: extensions
 
-;; Package-Requires: ((emacs "25.1"))
 ;; Package-Version: 0.3.7
+;; Package-Requires: ((emacs "26.1"))
 
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 
+;; 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,
@@ -24,8 +26,6 @@
 ;; You should have received a copy of the GNU General Public License
 ;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-;; This file is part of GNU Emacs.
-
 ;;; Commentary:
 
 ;; Taking inspiration from prefix keys and prefix arguments, Transient
@@ -58,14 +58,14 @@
 (require 'format-spec)
 (require 'seq)
 
-(eval-when-compile
-  (require 'subr-x))
+(eval-when-compile (require 'subr-x))
 
-(declare-function info "info")
-(declare-function Man-find-section "man")
-(declare-function Man-next-section "man")
-(declare-function Man-getpage-in-background "man")
+(declare-function info "info" (&optional file-or-node buffer))
+(declare-function Man-find-section "man" (section))
+(declare-function Man-next-section "man" (n))
+(declare-function Man-getpage-in-background "man" (topic))
 
+(defvar display-line-numbers) ; since Emacs 26.1
 (defvar Man-notify-method)
 
 (define-obsolete-function-alias 'define-transient-command
@@ -77,6 +77,8 @@
 (define-obsolete-function-alias 'define-infix-argument
   #'transient-define-argument "Transient 0.3.0")
 
+(define-obsolete-variable-alias 'transient--source-buffer
+  'transient--original-buffer "Transient 0.2.0")
 (define-obsolete-variable-alias 'current-transient-prefix
   'transient-current-prefix "Transient 0.3.0")
 (define-obsolete-variable-alias 'current-transient-command
@@ -107,21 +109,20 @@
 
 (defcustom transient-show-popup t
   "Whether to show the current transient in a popup buffer.
-
+\\<transient-map>
 - If t, then show the popup as soon as a transient prefix command
   is invoked.
 
 - If nil, then do not show the popup unless the user explicitly
-  requests it, by pressing an incomplete prefix key sequence.
+  requests it, by pressing \\[transient-show] or a prefix key.
 
 - If a number, then delay displaying the popup and instead show
   a brief one-line summary.  If zero or negative, then suppress
   even showing that summary and display the pressed key only.
 
   Show the popup when the user explicitly requests it by pressing
-  an incomplete prefix key sequence.  Unless zero, then also show
-  the popup after that many seconds of inactivity (using the
-  absolute value)."
+  \\[transient-show] or a prefix key.  Unless zero, then also show the popup
+  after that many seconds of inactivity (using the absolute value)."
   :package-version '(transient . "0.1.0")
   :group 'transient
   :type '(choice (const  :tag "instantly" t)
@@ -129,20 +130,32 @@
                  (const  :tag "on demand (no summary)" 0)
                  (number :tag "after delay" 1)))
 
-(defcustom transient-enable-popup-navigation nil
+(defcustom transient-enable-popup-navigation t
   "Whether navigation commands are enabled in the transient popup.
 
 While a transient is active the transient popup buffer is not the
 current buffer, making it necessary to use dedicated commands to
-act on that buffer itself.  If this non-nil, then the following
-features are available:
-
-- \"<up>\" moves the cursor to the previous suffix.
-  \"<down>\" moves the cursor to the next suffix.
-  \"RET\" invokes the suffix the cursor is on.
-- \"<mouse-1>\" invokes the clicked on suffix.
-- \"C-s\" and \"C-r\" start isearch in the popup buffer."
-  :package-version '(transient . "0.2.0")
+act on that buffer itself.  If this is non-nil, then the following
+bindings are available:
+
+\\<transient-popup-navigation-map>\
+- \\[transient-backward-button] moves the cursor to the previous suffix.
+- \\[transient-forward-button] moves the cursor to the next suffix.
+- \\[transient-push-button] invokes the suffix the cursor is on.
+\\<transient-button-map>\
+- \\`<mouse-1>' and \\`<mouse-2>' invoke the clicked on suffix.
+\\<transient-popup-navigation-map>\
+- \\[transient-isearch-backward]\
+ and \\[transient-isearch-forward] start isearch in the popup buffer.
+
+\\`<mouse-1>' and \\`<mouse-2>' are bound in `transient-push-button'.
+All other bindings are in `transient-popup-navigation-map'.
+
+By default \\`M-RET' is bound to `transient-push-button', instead of
+\\`RET', because if a transient allows the invocation of non-suffixes
+then it is likely that you would want \\`RET' to do what it would do
+if no transient were active."
+  :package-version '(transient . "0.4.0")
   :group 'transient
   :type 'boolean)
 
@@ -244,9 +257,9 @@ arguments.  When this option is non-nil, then the key 
binding
 for infix argument are highlighted when only a long argument
 \(e.g. \"--verbose\") is specified but no shor-thand (e.g \"-v\").
 In the rare case that a short-hand is specified but does not
-match the key binding, then it is highlighed differently.
+match the key binding, then it is highlighted differently.
 
-The highlighting is done using using `transient-mismatched-key'
+The highlighting is done using `transient-mismatched-key'
 and `transient-nonstandard-key'."
   :package-version '(transient . "0.1.0")
   :group 'transient
@@ -317,13 +330,32 @@ used."
   :group 'transient
   :type 'boolean)
 
+(defcustom transient-align-variable-pitch nil
+  "Whether to align columns pixel-wise in the popup buffer.
+
+If this is non-nil, then columns are aligned pixel-wise to
+support variable-pitch fonts.  Keys are not aligned, so you
+should use a fixed-pitch font for the `transient-key' face.
+Other key faces inherit from that face unless a theme is
+used that breaks that relationship.
+
+This option is intended for users who use a variable-pitch
+font for the `default' face.
+
+Also see `transient-force-fixed-pitch'."
+  :package-version '(transient . "0.4.0")
+  :group 'transient
+  :type 'boolean)
+
 (defcustom transient-force-fixed-pitch nil
   "Whether to force use of monospaced font in the popup buffer.
 
 Even if you use a proportional font for the `default' face,
 you might still want to use a monospaced font in transient's
 popup buffer.  Setting this option to t causes `default' to
-be remapped to `fixed-pitch' in that buffer."
+be remapped to `fixed-pitch' in that buffer.
+
+Also see `transient-align-variable-pitch'."
   :package-version '(transient . "0.2.0")
   :group 'transient
   :type 'boolean)
@@ -337,6 +369,12 @@ text and might otherwise have to scroll in two dimensions."
   :group 'transient
   :type 'boolean)
 
+(defcustom transient-hide-during-minibuffer-read nil
+  "Whether to hide the transient buffer while reading in the minibuffer."
+  :package-version '(transient . "0.4.0")
+  :group 'transient
+  :type 'boolean)
+
 (defconst transient--default-child-level 1)
 
 (defconst transient--default-prefix-level 4)
@@ -375,21 +413,21 @@ give you as many additional suffixes as you hoped.)"
                  (const :tag "7 - most suffixes" 7)))
 
 (defcustom transient-levels-file
-  (locate-user-emacs-file (convert-standard-filename "transient/levels.el"))
+  (locate-user-emacs-file "transient/levels.el")
   "File used to save levels of transients and their suffixes."
   :package-version '(transient . "0.1.0")
   :group 'transient
   :type 'file)
 
 (defcustom transient-values-file
-  (locate-user-emacs-file (convert-standard-filename "transient/values.el"))
+  (locate-user-emacs-file "transient/values.el")
   "File used to save values of transients."
   :package-version '(transient . "0.1.0")
   :group 'transient
   :type 'file)
 
 (defcustom transient-history-file
-  (locate-user-emacs-file (convert-standard-filename "transient/history.el"))
+  (locate-user-emacs-file "transient/history.el")
   "File used to save history of transients and their infixes."
   :package-version '(transient . "0.1.0")
   :group 'transient
@@ -445,7 +483,7 @@ give you as many additional suffixes as you hoped.)"
   "Face used for the infix for which the value is being read."
   :group 'transient-faces)
 
-(defface transient-unreachable-key '((t :inherit shadow))
+(defface transient-unreachable-key '((t :inherit (transient-key shadow)))
   "Face used for keys unreachable from the current prefix sequence."
   :group 'transient-faces)
 
@@ -524,6 +562,15 @@ These faces are only used if `transient-semantic-coloring'
   "Face used for teal prefixes."
   :group 'transient-color-faces)
 
+(defface transient-purple
+  '((t :inherit transient-key :foreground "#a020f0"))
+  "Face used for purple prefixes.
+
+This is an addition to the colors supported by Hydra.  It is
+used by suffixes that quit the current prefix but return to
+the previous prefix."
+  :group 'transient-color-faces)
+
 ;;; Persistence
 
 (defun transient--read-file-contents (file)
@@ -784,6 +831,7 @@ elements themselves.")
 
 ;;; Define
 
+;;;###autoload
 (defmacro transient-define-prefix (name arglist &rest args)
   "Define NAME as a transient prefix command.
 
@@ -824,11 +872,11 @@ to the setup function:
   (transient-setup \\='NAME nil nil :scope SCOPE)
 
 \(fn NAME ARGLIST [DOCSTRING] [KEYWORD VALUE]... GROUP... [BODY...])"
-  (declare (debug (&define name lambda-list
-                           [&optional lambda-doc]
-                           [&rest keywordp sexp]
-                           [&rest vectorp]
-                           [&optional ("interactive" interactive) def-body]))
+  (declare (debug ( &define name lambda-list
+                    [&optional lambda-doc]
+                    [&rest keywordp sexp]
+                    [&rest vectorp]
+                    [&optional ("interactive" interactive) def-body]))
            (indent defun)
            (doc-string 3))
   (pcase-let ((`(,class ,slots ,suffixes ,docstr ,body)
@@ -865,11 +913,11 @@ ARGLIST.  The infix arguments are usually accessed by 
using
 `transient-args' inside `interactive'.
 
 \(fn NAME ARGLIST [DOCSTRING] [KEYWORD VALUE]... BODY...)"
-  (declare (debug (&define name lambda-list
-                           [&optional lambda-doc]
-                           [&rest keywordp sexp]
-                           ("interactive" interactive)
-                           def-body))
+  (declare (debug ( &define name lambda-list
+                    [&optional lambda-doc]
+                    [&rest keywordp sexp]
+                    ("interactive" interactive)
+                    def-body))
            (indent defun)
            (doc-string 3))
   (pcase-let ((`(,class ,slots ,_ ,docstr ,body)
@@ -911,14 +959,14 @@ functions.  Different infix commands behave differently 
because
 the concrete methods are different for different infix command
 classes.  In rare case the above command function might not be
 suitable, even if you define your own infix command class.  In
-that case you have to use `transient-suffix-command' to define
+that case you have to use `transient-define-suffix' to define
 the infix command and use t as the value of the `:transient'
 keyword.
 
 \(fn NAME ARGLIST [DOCSTRING] [KEYWORD VALUE]...)"
-  (declare (debug (&define name lambda-list
-                           [&optional lambda-doc]
-                           [&rest keywordp sexp]))
+  (declare (debug ( &define name lambda-list
+                    [&optional lambda-doc]
+                    [&rest keywordp sexp]))
            (indent defun)
            (doc-string 3))
   (pcase-let ((`(,class ,slots ,_ ,docstr ,_)
@@ -926,6 +974,7 @@ keyword.
     `(progn
        (defalias ',name ,(transient--default-infix-command))
        (put ',name 'interactive-only t)
+       (put ',name 'command-modes (list 'not-a-mode))
        (put ',name 'function-documentation ,docstr)
        (put ',name 'transient--suffix
             (,(or class 'transient-switch) :command ',name ,@slots)))))
@@ -951,8 +1000,9 @@ example, sets a variable use `transient-define-infix' 
instead.
           (push k keys)
           (push v keys))))
     (while (let ((arg (car args)))
-             (or (vectorp arg)
-                 (and arg (symbolp arg))))
+             (if (vectorp arg)
+                 (setcar args (eval (cdr (backquote-process arg))))
+               (and arg (symbolp arg))))
       (push (pop args) suffixes))
     (list (if (eq (car-safe class) 'quote)
               (cadr class)
@@ -970,8 +1020,8 @@ example, sets a variable use `transient-define-infix' 
instead.
                             (vectorp (car value))))
                    (cl-mapcan (lambda (s) (transient--parse-child prefix s)) 
value)
                  (transient--parse-child prefix value))))
-    (vector  (when-let ((c (transient--parse-group  prefix spec))) (list c)))
-    (list    (when-let ((c (transient--parse-suffix prefix spec))) (list c)))
+    (vector  (and-let* ((c (transient--parse-group  prefix spec))) (list c)))
+    (list    (and-let* ((c (transient--parse-suffix prefix spec))) (list c)))
     (string  (list spec))))
 
 (defun transient--parse-group (prefix spec)
@@ -1091,7 +1141,7 @@ example, sets a variable use `transient-define-infix' 
instead.
 
 ;;; Edit
 
-(defun transient--insert-suffix (prefix loc suffix action)
+(defun transient--insert-suffix (prefix loc suffix action &optional keep-other)
   (let* ((suf (cl-etypecase suffix
                 (vector (transient--parse-group  prefix suffix))
                 (list   (transient--parse-suffix prefix suffix))
@@ -1109,25 +1159,18 @@ example, sets a variable use `transient-define-infix' 
instead.
                suffix prefix loc
                "suffixes and groups cannot be siblings"))
      (t
-      (when (and (listp suffix)
-                 (listp elt))
-        ;; Both suffixes are key bindings; not heading strings.
-        (let ((key (transient--spec-key suf)))
-          (if (equal (transient--kbd key)
-                     (transient--kbd (transient--spec-key elt)))
-              ;; We must keep `mem' until after we have inserted
-              ;; behind it, which `transient-remove-suffix' does
-              ;; not allow us to do.
-              (let ((spred (transient--suffix-predicate suf))
-                    (epred (transient--suffix-predicate elt)))
-                ;; If both suffixes have a predicate and they
-                ;; are not identical, then there is a high
-                ;; probability that we want to keep both.
-                (when (or (not spred)
-                          (not epred)
-                          (equal spred epred))
-                  (setq action 'replace)))
-            (transient-remove-suffix prefix key))))
+      (when-let* ((bindingp (listp suf))
+                  (key (transient--spec-key suf))
+                  (conflict (car (transient--layout-member key prefix)))
+                  (conflictp
+                   (and (not (and (eq action 'replace)
+                                  (eq conflict elt)))
+                        (or (not keep-other)
+                            (eq (plist-get (nth 2 suf) :command)
+                                (plist-get (nth 2 conflict) :command)))
+                        (equal (transient--suffix-predicate suf)
+                               (transient--suffix-predicate conflict)))))
+        (transient-remove-suffix prefix key))
       (cl-ecase action
         (insert  (setcdr mem (cons elt (cdr mem)))
                  (setcar mem suf))
@@ -1135,7 +1178,7 @@ example, sets a variable use `transient-define-infix' 
instead.
         (replace (setcar mem suf)))))))
 
 ;;;###autoload
-(defun transient-insert-suffix (prefix loc suffix)
+(defun transient-insert-suffix (prefix loc suffix &optional keep-other)
   "Insert a SUFFIX into PREFIX before LOC.
 PREFIX is a prefix command, a symbol.
 SUFFIX is a suffix command or a group specification (of
@@ -1143,12 +1186,14 @@ SUFFIX is a suffix command or a group specification (of
 LOC is a command, a key vector, a key description (a string
   as returned by `key-description'), or a coordination list
   (whose last element may also be a command or key).
+Remove a conflicting binding unless optional KEEP-OTHER is
+  non-nil.
 See info node `(transient)Modifying Existing Transients'."
   (declare (indent defun))
-  (transient--insert-suffix prefix loc suffix 'insert))
+  (transient--insert-suffix prefix loc suffix 'insert keep-other))
 
 ;;;###autoload
-(defun transient-append-suffix (prefix loc suffix)
+(defun transient-append-suffix (prefix loc suffix &optional keep-other)
   "Insert a SUFFIX into PREFIX after LOC.
 PREFIX is a prefix command, a symbol.
 SUFFIX is a suffix command or a group specification (of
@@ -1156,9 +1201,11 @@ SUFFIX is a suffix command or a group specification (of
 LOC is a command, a key vector, a key description (a string
   as returned by `key-description'), or a coordination list
   (whose last element may also be a command or key).
+Remove a conflicting binding unless optional KEEP-OTHER is
+  non-nil.
 See info node `(transient)Modifying Existing Transients'."
   (declare (indent defun))
-  (transient--insert-suffix prefix loc suffix 'append))
+  (transient--insert-suffix prefix loc suffix 'append keep-other))
 
 ;;;###autoload
 (defun transient-replace-suffix (prefix loc suffix)
@@ -1268,7 +1315,7 @@ See info node `(transient)Modifying Existing Transients'."
          (plist-get plist :command)))))
 
 (defun transient--command-key (cmd)
-  (when-let ((obj (get cmd 'transient--suffix)))
+  (and-let* ((obj (get cmd 'transient--suffix)))
     (cond ((slot-boundp obj 'key)
            (oref obj key))
           ((slot-exists-p obj 'shortarg)
@@ -1289,7 +1336,7 @@ This is an object representing that transient, use
 (defvar transient-current-command nil
   "The transient from which this suffix command was invoked.
 This is a symbol representing that transient, use
-`current-transient-object' to get the respective object.")
+`transient-current-prefix' to get the respective object.")
 
 (defvar transient-current-suffixes nil
   "The suffixes of the transient from which this suffix command was invoked.
@@ -1319,6 +1366,8 @@ variable instead.")
 
 (defvar transient--stack nil)
 
+(defvar transient--minibuffer-depth 0)
+
 (defvar transient--buffer-name " *transient*"
   "Name of the transient buffer.")
 
@@ -1329,9 +1378,6 @@ variable instead.")
   "The window that was selected before the transient was invoked.
 Usually it remains selected while the transient is active.")
 
-(define-obsolete-variable-alias 'transient--source-buffer
-  'transient--original-buffer "Transient 0.2.0")
-
 (defvar transient--original-buffer nil
   "The buffer that was current before the transient was invoked.
 Usually it remains current while the transient is active.")
@@ -1340,6 +1386,17 @@ Usually it remains current while the transient is 
active.")
 
 (defvar transient--history nil)
 
+(defvar transient--abort-commands
+  '(abort-minibuffers                   ; (minibuffer-quit-recursive-edit)
+    abort-recursive-edit                ; (throw 'exit t)
+    exit-recursive-edit                 ; (throw 'exit nil)
+    keyboard-escape-quit                ; dwim
+    keyboard-quit                       ; (signal 'quit nil)
+    minibuffer-keyboard-quit            ; (abort-minibuffers)
+    minibuffer-quit-recursive-edit      ; (throw 'exit (lambda ()
+                                        ;      (signal 'minibuffer-quit nil)))
+    top-level))                         ; (throw 'top-level nil)
+
 (defvar transient--scroll-commands
   '(transient-scroll-up
     transient-scroll-down
@@ -1391,11 +1448,12 @@ probably use this instead:
           transient-current-prefix)
       (cl-find-if (lambda (obj)
                     (eq (transient--suffix-command obj)
-                        (or command this-original-command)))
+                        (or command this-command)))
                   (or transient--suffixes
                       transient-current-suffixes))
-    (when-let ((obj (get (or command this-command) 'transient--suffix))
-               (obj (clone obj)))
+    (when-let* ((obj (get (or command this-command) 'transient--suffix))
+                (obj (clone obj)))
+      ;; Cannot use and-let* because of debbugs#31840.
       (transient-init-scope obj)
       (transient-init-value obj)
       obj)))
@@ -1499,13 +1557,15 @@ to `transient-predicate-map'.  Also see 
`transient-base-map'.")
      'transient--layout
      (cl-mapcan
       (lambda (s) (transient--parse-child 'transient-common-commands s))
-      '([:hide (lambda ()
-                 (and (not (memq (car transient--redisplay-key)
-                                 transient--common-command-prefixes))
-                      (not transient-show-common-commands)))
+      `([:hide ,(lambda ()
+                  (and (not (memq (car (bound-and-true-p
+                                        transient--redisplay-key))
+                                  transient--common-command-prefixes))
+                       (not transient-show-common-commands)))
          ["Value commands"
           ("C-x s  " "Set"            transient-set)
           ("C-x C-s" "Save"           transient-save)
+          ("C-x C-k" "Reset"          transient-reset)
           ("C-x p  " "Previous value" transient-history-prev)
           ("C-x n  " "Next value"     transient-history-next)]
          ["Sticky commands"
@@ -1516,22 +1576,41 @@ to `transient-predicate-map'.  Also see 
`transient-base-map'.")
           ("C-z" "Suspend transient stack"  transient-suspend)]
          ["Customize"
           ("C-x t" transient-toggle-common
-           :description (lambda ()
-                          (if transient-show-common-commands
-                              "Hide common commands"
-                            "Show common permanently")))
+           :description ,(lambda ()
+                           (if transient-show-common-commands
+                               "Hide common commands"
+                             "Show common permanently")))
           ("C-x l" "Show/hide suffixes" transient-set-level)]])))
 
+(defvar transient-popup-navigation-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map (kbd "<down-mouse-1>") #'transient-noop)
+    (define-key map (kbd "<up>")   #'transient-backward-button)
+    (define-key map (kbd "<down>") #'transient-forward-button)
+    (define-key map (kbd "C-r")    #'transient-isearch-backward)
+    (define-key map (kbd "C-s")    #'transient-isearch-forward)
+    (define-key map (kbd "M-RET")  #'transient-push-button)
+    map)
+  "One of the keymaps used when popup navigation is enabled.
+See `transient-enable-popup-navigation'.")
+
+(defvar transient-button-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map (kbd "<mouse-1>") #'transient-push-button)
+    (define-key map (kbd "<mouse-2>") #'transient-push-button)
+    map)
+  "One of the keymaps used when popup navigation is enabled.
+See `transient-enable-popup-navigation'.")
+
 (defvar transient-predicate-map
   (let ((map (make-sparse-keymap)))
-    (define-key map [handle-switch-frame]     #'transient--do-suspend)
     (define-key map [transient-suspend]       #'transient--do-suspend)
     (define-key map [transient-help]          #'transient--do-stay)
     (define-key map [transient-set-level]     #'transient--do-stay)
     (define-key map [transient-history-prev]  #'transient--do-stay)
     (define-key map [transient-history-next]  #'transient--do-stay)
     (define-key map [universal-argument]      #'transient--do-stay)
-    (define-key map [negative-argument]       #'transient--do-stay)
+    (define-key map [negative-argument]       #'transient--do-minus)
     (define-key map [digit-argument]          #'transient--do-stay)
     (define-key map [transient-quit-all]      #'transient--do-quit-all)
     (define-key map [transient-quit-one]      #'transient--do-quit-one)
@@ -1541,6 +1620,7 @@ to `transient-predicate-map'.  Also see 
`transient-base-map'.")
     (define-key map [transient-toggle-common] #'transient--do-stay)
     (define-key map [transient-set]           #'transient--do-call)
     (define-key map [transient-save]          #'transient--do-call)
+    (define-key map [transient-reset]         #'transient--do-call)
     (define-key map [describe-key-briefly]    #'transient--do-stay)
     (define-key map [describe-key]            #'transient--do-stay)
     (define-key map [transient-scroll-up]     #'transient--do-stay)
@@ -1549,11 +1629,16 @@ to `transient-predicate-map'.  Also see 
`transient-base-map'.")
     (define-key map [scroll-bar-toolkit-scroll]   #'transient--do-stay)
     (define-key map [transient-noop]              #'transient--do-noop)
     (define-key map [transient-mouse-push-button] #'transient--do-move)
-    (define-key map [transient-push-button]       #'transient--do-move)
+    (define-key map [transient-push-button]       #'transient--do-push-button)
     (define-key map [transient-backward-button]   #'transient--do-move)
     (define-key map [transient-forward-button]    #'transient--do-move)
     (define-key map [transient-isearch-backward]  #'transient--do-move)
     (define-key map [transient-isearch-forward]   #'transient--do-move)
+    ;; If a valid but incomplete prefix sequence is followed by
+    ;; an unbound key, then Emacs calls the `undefined' command
+    ;; but does not set `this-command', `this-original-command'
+    ;; or `real-this-command' accordingly.  Instead they are nil.
+    (define-key map [nil] #'transient--do-warn)
     map)
   "Base keymap used to map common commands to their transient behavior.
 
@@ -1573,22 +1658,24 @@ For transient commands that are bound in individual 
transients,
 the transient behavior is specified using the `:transient' slot
 of the corresponding object.")
 
-(defvar transient-popup-navigation-map)
-
 (defvar transient--transient-map nil)
 (defvar transient--predicate-map nil)
 (defvar transient--redisplay-map nil)
 (defvar transient--redisplay-key nil)
 
-(defun transient--push-keymap (map)
-  (transient--debug "   push %s%s" map (if (symbol-value map) "" " VOID"))
-  (with-demoted-errors "transient--push-keymap: %S"
-    (internal-push-keymap (symbol-value map) 'overriding-terminal-local-map)))
+(defun transient--push-keymap (var)
+  (let ((map (symbol-value var)))
+    (transient--debug "     push %s%s" var (if map "" " VOID"))
+    (when map
+      (with-demoted-errors "transient--push-keymap: %S"
+        (internal-push-keymap map 'overriding-terminal-local-map)))))
 
-(defun transient--pop-keymap (map)
-  (transient--debug "   pop  %s%s" map (if (symbol-value map) "" " VOID"))
-  (with-demoted-errors "transient--pop-keymap: %S"
-    (internal-pop-keymap (symbol-value map) 'overriding-terminal-local-map)))
+(defun transient--pop-keymap (var)
+  (let ((map (symbol-value var)))
+    (transient--debug "     pop  %s%s" var (if map "" " VOID"))
+    (when map
+      (with-demoted-errors "transient--pop-keymap: %S"
+        (internal-pop-keymap map 'overriding-terminal-local-map)))))
 
 (defun transient--make-transient-map ()
   (let ((map (make-sparse-keymap)))
@@ -1613,17 +1700,27 @@ of the corresponding object.")
                      (string-trim key)
                      cmd conflict)))
           (define-key map kbd cmd))))
+    (when-let ((b (lookup-key map "-"))) (define-key map [kp-subtract] b))
+    (when-let ((b (lookup-key map "="))) (define-key map [kp-equal] b))
+    (when-let ((b (lookup-key map "+"))) (define-key map [kp-add] b))
     (when transient-enable-popup-navigation
-      (setq map
-            (make-composed-keymap (list map transient-popup-navigation-map))))
+      ;; `transient--make-redisplay-map' maps only over bindings that are
+      ;; directly in the base keymap, so that cannot be a composed keymap.
+      (set-keymap-parent
+       map (make-composed-keymap
+            (keymap-parent map)
+            transient-popup-navigation-map)))
     map))
 
 (defun transient--make-predicate-map ()
   (let ((map (make-sparse-keymap)))
     (set-keymap-parent map transient-predicate-map)
+    (when (memq (oref transient--prefix transient-non-suffix)
+                '(nil transient--do-warn transient--do-noop))
+      (define-key map [handle-switch-frame] #'transient--do-suspend))
     (dolist (obj transient--suffixes)
       (let* ((cmd (oref obj command))
-             (sub-prefix (and (symbolp cmd) (get cmd 'transient--prefix)))
+             (sub-prefix (and (symbolp cmd) (get cmd 'transient--prefix) t))
              (sym (transient--suffix-symbol cmd)))
         (cond
          ((oref obj inapt)
@@ -1631,13 +1728,14 @@ of the corresponding object.")
          ((slot-boundp obj 'transient)
           (define-key map (vector sym)
             (let ((do (oref obj transient)))
-              (pcase do
-                (`t (cond (sub-prefix #'transient--do-replace)
-                          ((cl-typep obj 'transient-infix)
-                           #'transient--do-stay)
-                          (t #'transient--do-call)))
-                (`nil 'transient--do-exit)
-                (_ do)))))
+              (pcase (list do sub-prefix)
+                ('(t     t) #'transient--do-recurse)
+                ('(t   nil) (if (cl-typep obj 'transient-infix)
+                                #'transient--do-stay
+                              #'transient--do-call))
+                ('(nil   t) #'transient--do-replace)
+                ('(nil nil) #'transient--do-exit)
+                (_          do)))))
          ((not (lookup-key transient-predicate-map (vector sym)))
           (define-key map (vector sym)
             (if sub-prefix
@@ -1673,7 +1771,10 @@ of the corresponding object.")
          (define-key topmap (vconcat transient--redisplay-key (list key))
            #'transient-update)))
      (if transient--redisplay-key
-         (lookup-key transient--transient-map (vconcat 
transient--redisplay-key))
+         (let ((key (vconcat transient--redisplay-key)))
+           (or (lookup-key transient--transient-map key)
+               (and-let* ((regular (lookup-key local-function-key-map key)))
+                 (lookup-key transient--transient-map (vconcat regular)))))
        transient--transient-map))
     topmap))
 
@@ -1690,8 +1791,6 @@ be nil and PARAMS may be (but usually is not) used to set 
e.g. the
 This function is also called internally in which case LAYOUT and
 EDIT may be non-nil."
   (transient--debug 'setup)
-  (when (> (minibuffer-depth) 0)
-    (user-error "Cannot invoke transient %s while minibuffer is active" name))
   (transient--with-emergency-exit
     (cond
      ((not name)
@@ -1719,6 +1818,7 @@ EDIT may be non-nil."
     (setq transient--redisplay-map (transient--make-redisplay-map))
     (setq transient--original-window (selected-window))
     (setq transient--original-buffer (current-buffer))
+    (setq transient--minibuffer-depth (minibuffer-depth))
     (transient--redisplay)
     (transient--init-transient)
     (transient--suspend-which-key-mode)))
@@ -1744,6 +1844,7 @@ value.  Otherwise return CHILDREN as is."
                       :level (or (alist-get t (alist-get name 
transient-levels))
                                  transient-default-level)
                       params))))
+    (transient--setup-recursion obj)
     (transient-init-value obj)
     obj))
 
@@ -1757,13 +1858,13 @@ value.  Otherwise return CHILDREN as is."
 
 (defun transient--flatten-suffixes (layout)
   (cl-labels ((s (def)
-                 (cond
-                  ((stringp def) nil)
-                  ((listp def) (cl-mapcan #'s def))
-                  ((transient-group--eieio-childp def)
-                   (cl-mapcan #'s (oref def suffixes)))
-                  ((transient-suffix--eieio-childp def)
-                   (list def)))))
+                (cond
+                 ((stringp def) nil)
+                 ((listp def) (cl-mapcan #'s def))
+                 ((transient-group--eieio-childp def)
+                  (cl-mapcan #'s (oref def suffixes)))
+                 ((transient-suffix--eieio-childp def)
+                  (list def)))))
     (cl-mapcan #'s layout)))
 
 (defun transient--init-child (levels spec)
@@ -1774,14 +1875,14 @@ value.  Otherwise return CHILDREN as is."
 
 (defun transient--init-group (levels spec)
   (pcase-let ((`(,level ,class ,args ,children) (append spec nil)))
-    (when (transient--use-level-p level)
-      (let ((obj (apply class :level level args)))
-        (when (transient--use-suffix-p obj)
-          (when-let ((suffixes
-                      (cl-mapcan (lambda (c) (transient--init-child levels c))
-                                 (transient-setup-children obj children))))
-            (oset obj suffixes suffixes)
-            (list obj)))))))
+    (when-let* ((- (transient--use-level-p level))
+                (obj (apply class :level level args))
+                (- (transient--use-suffix-p obj))
+                (suffixes (cl-mapcan (lambda (c) (transient--init-child levels 
c))
+                                     (transient-setup-children obj children))))
+      ;; Cannot use and-let* because of debbugs#31840.
+      (oset obj suffixes suffixes)
+      (list obj))))
 
 (defun transient--init-suffix (levels spec)
   (pcase-let* ((`(,level ,class ,args) spec)
@@ -1877,7 +1978,7 @@ value.  Otherwise return CHILDREN as is."
 (defun transient--suffix-predicate (spec)
   (let ((plist (nth 2 spec)))
     (seq-some (lambda (prop)
-                (when-let ((pred (plist-get plist prop)))
+                (and-let* ((pred (plist-get plist prop)))
                   (list prop pred)))
               '( :if :if-not
                  :if-nil :if-non-nil
@@ -1894,11 +1995,8 @@ value.  Otherwise return CHILDREN as is."
   (transient--debug 'init-transient)
   (transient--push-keymap 'transient--transient-map)
   (transient--push-keymap 'transient--redisplay-map)
-  (add-hook 'pre-command-hook      #'transient--pre-command)
-  (add-hook 'minibuffer-setup-hook #'transient--minibuffer-setup)
-  (add-hook 'minibuffer-exit-hook  #'transient--minibuffer-exit)
-  (add-hook 'post-command-hook     #'transient--post-command)
-  (advice-add 'abort-recursive-edit :after #'transient--minibuffer-exit)
+  (add-hook 'pre-command-hook  #'transient--pre-command)
+  (add-hook 'post-command-hook #'transient--post-command)
   (when transient--exitp
     ;; This prefix command was invoked as the suffix of another.
     ;; Prevent `transient--post-command' from removing the hooks
@@ -1907,46 +2005,62 @@ value.  Otherwise return CHILDREN as is."
 
 (defun transient--pre-command ()
   (transient--debug 'pre-command)
-  (cond
-   ((memq this-command '(transient-update transient-quit-seq))
-    (transient--pop-keymap 'transient--redisplay-map))
-   ((and transient--helpp
-         (not (memq this-command '(transient-quit-one
-                                   transient-quit-all))))
+  (transient--with-emergency-exit
+    ;; The use of `overriding-terminal-local-map' does not prevent the
+    ;; lookup of command remappings in the overridden maps, which can
+    ;; lead to a suffix being remapped to a non-suffix.  We have to undo
+    ;; the remapping in that case.  However, remapping a non-suffix to
+    ;; another should remain possible.
+    (when (and (transient--get-predicate-for this-original-command 'suffix)
+               (not (transient--get-predicate-for this-command 'suffix)))
+      (setq this-command this-original-command))
     (cond
-     ((transient-help)
-      (transient--do-suspend)
-      (setq this-command 'transient-suspend)
-      (transient--pre-exit))
-     ((not (transient--edebug-command-p))
-      (setq this-command 'transient-undefined))))
-   ((and transient--editp
-         (transient-suffix-object)
-         (not (memq this-command '(transient-quit-one
-                                   transient-quit-all
-                                   transient-help))))
-    (setq this-command 'transient-set-level))
-   (t
-    (setq transient--exitp nil)
-    (when (eq (if-let ((fn (transient--get-predicate-for
-                            this-original-command)))
-                  (let ((action (funcall fn)))
-                    (when (eq action transient--exit)
-                      (setq transient--exitp (or transient--exitp t)))
-                    action)
-                (if (let ((keys (this-command-keys-vector)))
-                      (eq (aref keys (1- (length keys))) ?\C-g))
-                    (setq this-command 'transient-noop)
-                  (unless (transient--edebug-command-p)
-                    (setq this-command 'transient-undefined)))
-                transient--stay)
-              transient--exit)
-      (transient--pre-exit)))))
-
-(defun transient--get-predicate-for (cmd)
-  (or (lookup-key transient--predicate-map
-                  (vector (transient--suffix-symbol cmd)))
-      (oref transient--prefix transient-non-suffix)))
+     ((memq this-command '(transient-update transient-quit-seq))
+      (transient--pop-keymap 'transient--redisplay-map))
+     ((and transient--helpp
+           (not (memq this-command '(transient-quit-one
+                                     transient-quit-all))))
+      (cond
+       ((transient-help)
+        (transient--do-suspend)
+        (setq this-command 'transient-suspend)
+        (transient--pre-exit))
+       ((not (transient--edebug-command-p))
+        (setq this-command 'transient-undefined))))
+     ((and transient--editp
+           (transient-suffix-object)
+           (not (memq this-command '(transient-quit-one
+                                     transient-quit-all
+                                     transient-help))))
+      (setq this-command 'transient-set-level))
+     (t
+      (setq transient--exitp nil)
+      (when (eq (transient--do-pre-command) transient--exit)
+        (transient--pre-exit))))))
+
+(defun transient--do-pre-command ()
+  (if-let ((fn (transient--get-predicate-for this-command)))
+      (let ((action (funcall fn)))
+        (when (eq action transient--exit)
+          (setq transient--exitp (or transient--exitp t)))
+        action)
+    (if (let ((keys (this-command-keys-vector)))
+          (eq (aref keys (1- (length keys))) ?\C-g))
+        (setq this-command 'transient-noop)
+      (unless (transient--edebug-command-p)
+        (setq this-command 'transient-undefined)))
+    transient--stay))
+
+(defun transient--get-predicate-for (cmd &optional suffix-only)
+  (or (ignore-errors
+        (lookup-key transient--predicate-map
+                    (vector (transient--suffix-symbol cmd))))
+      (and (not suffix-only)
+           (let ((pred (oref transient--prefix transient-non-suffix)))
+             (pcase pred
+               ('t   #'transient--do-stay)
+               ('nil #'transient--do-warn)
+               (_    pred))))))
 
 (defun transient--pre-exit ()
   (transient--debug 'pre-exit)
@@ -1954,7 +2068,6 @@ value.  Otherwise return CHILDREN as is."
   (transient--timer-cancel)
   (transient--pop-keymap 'transient--transient-map)
   (transient--pop-keymap 'transient--redisplay-map)
-  (remove-hook 'pre-command-hook #'transient--pre-command)
   (unless transient--showp
     (let ((message-log-max nil))
       (message "")))
@@ -1962,7 +2075,6 @@ value.  Otherwise return CHILDREN as is."
   (setq transient--predicate-map nil)
   (setq transient--redisplay-map nil)
   (setq transient--redisplay-key nil)
-  (setq transient--showp nil)
   (setq transient--helpp nil)
   (setq transient--editp nil)
   (setq transient--prefix nil)
@@ -1974,12 +2086,17 @@ value.  Otherwise return CHILDREN as is."
 
 (defun transient--delete-window ()
   (when (window-live-p transient--window)
-    (let ((buf (window-buffer transient--window)))
+    (let ((remain-in-minibuffer-window
+           (and (minibuffer-selected-window)
+                (selected-window)))
+          (buf (window-buffer transient--window)))
       ;; Only delete the window if it never showed another buffer.
       (unless (eq (car (window-parameter transient--window 'quit-restore)) 
'other)
         (with-demoted-errors "Error while exiting transient: %S"
           (delete-window transient--window)))
-      (kill-buffer buf))))
+      (kill-buffer buf)
+      (when remain-in-minibuffer-window
+        (select-window remain-in-minibuffer-window)))))
 
 (defun transient--export ()
   (setq transient-current-prefix transient--prefix)
@@ -1987,80 +2104,155 @@ value.  Otherwise return CHILDREN as is."
   (setq transient-current-suffixes transient--suffixes)
   (transient--history-push transient--prefix))
 
-(defun transient--minibuffer-setup ()
-  (transient--debug 'minibuffer-setup)
-  (unless (> (minibuffer-depth) 1)
-    (unless transient--exitp
-      (transient--pop-keymap 'transient--transient-map)
-      (transient--pop-keymap 'transient--redisplay-map)
-      (remove-hook 'pre-command-hook #'transient--pre-command))
-    (remove-hook 'post-command-hook #'transient--post-command)))
-
-(defun transient--minibuffer-exit ()
-  (transient--debug 'minibuffer-exit)
-  (unless (> (minibuffer-depth) 1)
-    (unless transient--exitp
-      (transient--push-keymap 'transient--transient-map)
-      (transient--push-keymap 'transient--redisplay-map)
-      (add-hook 'pre-command-hook #'transient--pre-command))
-    (add-hook 'post-command-hook #'transient--post-command)))
-
-(defun transient--suspend-override (&optional minibuffer-hooks)
+(defun transient--suspend-override (&optional nohide)
   (transient--debug 'suspend-override)
+  (transient--timer-cancel)
+  (cond ((and (not nohide) transient-hide-during-minibuffer-read)
+         (transient--delete-window))
+        ((and transient--prefix transient--redisplay-key)
+         (setq transient--redisplay-key nil)
+         (when transient--showp
+           (transient--show))))
   (transient--pop-keymap 'transient--transient-map)
   (transient--pop-keymap 'transient--redisplay-map)
   (remove-hook 'pre-command-hook  #'transient--pre-command)
-  (remove-hook 'post-command-hook #'transient--post-command)
-  (when minibuffer-hooks
-    (remove-hook   'minibuffer-setup-hook #'transient--minibuffer-setup)
-    (remove-hook   'minibuffer-exit-hook  #'transient--minibuffer-exit)
-    (advice-remove 'abort-recursive-edit  #'transient--minibuffer-exit)))
+  (remove-hook 'post-command-hook #'transient--post-command))
 
-(defun transient--resume-override (&optional minibuffer-hooks)
+(defun transient--resume-override ()
   (transient--debug 'resume-override)
+  (when (and transient--showp transient-hide-during-minibuffer-read)
+    (transient--show))
   (transient--push-keymap 'transient--transient-map)
   (transient--push-keymap 'transient--redisplay-map)
   (add-hook 'pre-command-hook  #'transient--pre-command)
-  (add-hook 'post-command-hook #'transient--post-command)
-  (when minibuffer-hooks
-    (add-hook   'minibuffer-setup-hook #'transient--minibuffer-setup)
-    (add-hook   'minibuffer-exit-hook  #'transient--minibuffer-exit)
-    (advice-add 'abort-recursive-edit :after #'transient--minibuffer-exit)))
+  (add-hook 'post-command-hook #'transient--post-command))
+
+(defmacro transient--with-suspended-override (&rest body)
+  (let ((depth (make-symbol "depth"))
+        (setup (make-symbol "setup"))
+        (exit  (make-symbol "exit")))
+    `(if (and transient--transient-map
+              (memq transient--transient-map
+                    overriding-terminal-local-map))
+         (let ((,depth (1+ (minibuffer-depth))) ,setup ,exit)
+           (setq ,setup
+                 (lambda () "@transient--with-suspended-override"
+                   (transient--debug 'minibuffer-setup)
+                   (remove-hook 'minibuffer-setup-hook ,setup)
+                   (transient--suspend-override)))
+           (setq ,exit
+                 (lambda () "@transient--with-suspended-override"
+                   (transient--debug 'minibuffer-exit)
+                   (when (= (minibuffer-depth) ,depth)
+                     (transient--resume-override))))
+           (unwind-protect
+               (progn
+                 (add-hook 'minibuffer-setup-hook ,setup)
+                 (add-hook 'minibuffer-exit-hook ,exit)
+                 ,@body)
+             (remove-hook 'minibuffer-setup-hook ,setup)
+             (remove-hook 'minibuffer-exit-hook ,exit)))
+       ,@body)))
+
+(defun transient--post-command-hook ()
+  (run-hooks 'transient--post-command-hook))
+
+(add-hook 'post-command-hook #'transient--post-command-hook)
+
+(defun transient--delay-post-command (&optional abort-only)
+  (transient--debug 'delay-post-command)
+  (let ((depth (minibuffer-depth))
+        (command this-command)
+        (delayed (if transient--exitp
+                     (apply-partially #'transient--post-exit this-command)
+                   #'transient--resume-override))
+        post-command abort-minibuffer)
+    (unless abort-only
+      (setq post-command
+            (lambda () "@transient--delay-post-command"
+              (let ((act (and (not (eq (this-command-keys-vector) []))
+                              (or (eq this-command command)
+                                  ;; `execute-extended-command' was
+                                  ;; used to call another command
+                                  ;; that also uses the minibuffer.
+                                  (equal
+                                   (string-to-multibyte (this-command-keys))
+                                   (format "\M-x%s\r" this-command))))))
+                (transient--debug 'post-command-hook "act: %s" act)
+                (when act
+                  (remove-hook 'transient--post-command-hook post-command)
+                  (remove-hook 'minibuffer-exit-hook abort-minibuffer)
+                  (funcall delayed)))))
+      (add-hook 'transient--post-command-hook post-command))
+    (setq abort-minibuffer
+          (lambda () "@transient--delay-post-command"
+            (let ((act (and (or (memq this-command transient--abort-commands)
+                                (equal (this-command-keys) ""))
+                            (= (minibuffer-depth) depth))))
+              (transient--debug
+               'abort-minibuffer
+               "mini: %s|%s, act %s" (minibuffer-depth) depth act)
+              (when act
+                (remove-hook 'transient--post-command-hook post-command)
+                (remove-hook 'minibuffer-exit-hook abort-minibuffer)
+                (funcall delayed)))))
+    (add-hook 'minibuffer-exit-hook abort-minibuffer)))
 
 (defun transient--post-command ()
   (transient--debug 'post-command)
-  (unless this-command
-    (transient--debug "-- force pre-exit from post-command")
-    (message "Quit transient!")
-    (transient--pre-exit)
-    (setq transient--exitp t))
-  (if transient--exitp
-      (progn
-        (unless (and (eq transient--exitp 'replace)
-                     (or transient--prefix
-                         ;; The current command could act as a prefix,
-                         ;; but decided not to call `transient-setup'.
-                         (prog1 nil (transient--stack-zap))))
-          (remove-hook   'minibuffer-setup-hook #'transient--minibuffer-setup)
-          (remove-hook   'minibuffer-exit-hook  #'transient--minibuffer-exit)
-          (advice-remove 'abort-recursive-edit  #'transient--minibuffer-exit)
-          (remove-hook   'post-command-hook     #'transient--post-command))
-        (setq transient-current-prefix nil)
-        (setq transient-current-command nil)
-        (setq transient-current-suffixes nil)
-        (let ((resume (and transient--stack
-                           (not (memq transient--exitp '(replace suspend))))))
-          (setq transient--exitp nil)
-          (setq transient--helpp nil)
-          (setq transient--editp nil)
-          (run-hooks 'transient-exit-hook)
-          (when resume
-            (transient--stack-pop))))
-    (transient--pop-keymap 'transient--redisplay-map)
-    (setq transient--redisplay-map (transient--make-redisplay-map))
-    (transient--push-keymap 'transient--redisplay-map)
-    (unless (eq this-command (oref transient--prefix command))
-      (transient--redisplay))))
+  (transient--with-emergency-exit
+    (cond
+     ((and (eq (this-command-keys-vector) [])
+           (= (minibuffer-depth)
+              (1+ transient--minibuffer-depth)))
+      (transient--suspend-override)
+      (transient--delay-post-command (eq transient--exitp 'replace)))
+     (transient--exitp
+      (transient--post-exit))
+     ((eq this-command (oref transient--prefix command)))
+     (t
+      (let ((old transient--redisplay-map)
+            (new (transient--make-redisplay-map)))
+        (unless (equal old new)
+          (transient--pop-keymap 'transient--redisplay-map)
+          (setq transient--redisplay-map new)
+          (transient--push-keymap 'transient--redisplay-map)))
+      (transient--redisplay)))))
+
+(defun transient--post-exit (&optional command)
+  (transient--debug 'post-exit)
+  (unless (and (eq transient--exitp 'replace)
+               (or transient--prefix
+                   ;; The current command could act as a prefix,
+                   ;; but decided not to call `transient-setup',
+                   ;; or it is prevented from doing so because it
+                   ;; uses the minibuffer and the user aborted
+                   ;; that.
+                   (prog1 nil
+                     (if (let ((obj (transient-suffix-object command)))
+                           (and (slot-boundp obj 'transient)
+                                (oref obj transient)))
+                         ;; This sub-prefix is a transient suffix;
+                         ;; go back to outer prefix, by calling
+                         ;; `transient--stack-pop' further down.
+                         (setq transient--exitp nil)
+                       (transient--stack-zap)))))
+    (remove-hook 'pre-command-hook  #'transient--pre-command)
+    (remove-hook 'post-command-hook #'transient--post-command))
+  (setq transient-current-prefix nil)
+  (setq transient-current-command nil)
+  (setq transient-current-suffixes nil)
+  (let ((resume (and transient--stack
+                     (not (memq transient--exitp '(replace suspend))))))
+    (unless (or resume (eq transient--exitp 'replace))
+      (setq transient--showp nil))
+    (setq transient--exitp nil)
+    (setq transient--helpp nil)
+    (setq transient--editp nil)
+    (setq transient--minibuffer-depth 0)
+    (run-hooks 'transient-exit-hook)
+    (when resume
+      (transient--stack-pop))))
 
 (defun transient--stack-push ()
   (transient--debug 'stack-push)
@@ -2082,7 +2274,14 @@ value.  Otherwise return CHILDREN as is."
 (defun transient--redisplay ()
   (if (or (eq transient-show-popup t)
           transient--showp)
-      (unless (memq this-command transient--scroll-commands)
+      (unless
+          (or (memq this-command transient--scroll-commands)
+              (and (or (memq this-command '(mouse-drag-region
+                                            mouse-set-region))
+                       (equal (key-description (this-command-keys-vector))
+                              "<mouse-movement>"))
+                   (and (eq (current-buffer)
+                            (get-buffer transient--buffer-name)))))
         (transient--show))
     (when (and (numberp transient-show-popup)
                (not (zerop transient-show-popup))
@@ -2106,14 +2305,22 @@ value.  Otherwise return CHILDREN as is."
 
 (defun transient--debug (arg &rest args)
   (when transient--debug
-    (if (symbolp arg)
-        (message "-- %-16s (cmd: %s, event: %S, exit: %s)"
-                 arg
-                 (or (transient--suffix-symbol this-command)
-                     (list this-command this-original-command last-command))
-                 (key-description (this-command-keys-vector))
-                 transient--exitp)
-      (apply #'message arg args))))
+    (let ((inhibit-message (not (eq transient--debug 'message))))
+      (if (symbolp arg)
+          (message "-- %-18s (cmd: %s, event: %S, exit: %s%s)"
+                   arg
+                   (or (ignore-errors (transient--suffix-symbol this-command))
+                       (if (byte-code-function-p this-command)
+                           "#[...]"
+                         this-command))
+                   (key-description (this-command-keys-vector))
+                   transient--exitp
+                   (cond ((stringp (car args))
+                          (concat ", " (apply #'format args)))
+                         (args
+                          (concat ", " (apply (car args) (cdr args))))
+                         (t "")))
+        (apply #'message arg args)))))
 
 (defun transient--emergency-exit ()
   "Exit the current transient command after an error occurred.
@@ -2124,7 +2331,7 @@ nil) then do nothing."
     (setq transient--stack nil)
     (setq transient--exitp t)
     (transient--pre-exit)
-    (transient--post-command)))
+    (transient--post-exit)))
 
 ;;; Pre-Commands
 
@@ -2152,12 +2359,49 @@ nil) then do nothing."
   (transient--export)
   transient--stay)
 
+(defun transient--do-return ()
+  "Call the command after exporting variables and return to parent prefix.
+If there is no parent prefix, then behave like `transient--do-exit'."
+  (if (not transient--stack)
+      (transient--do-exit)
+    (transient--export)
+    transient--exit))
+
 (defun transient--do-exit ()
   "Call the command after exporting variables and exit the transient."
   (transient--export)
   (transient--stack-zap)
   transient--exit)
 
+(defun transient--do-push-button ()
+  "Call the command represented by the activated button.
+Use that command's pre-command to determine transient behavior."
+  (if (and (mouse-event-p last-command-event)
+           (not (eq (posn-window (event-start last-command-event))
+                    transient--window)))
+      transient--stay
+    (setq this-command
+          (with-selected-window transient--window
+            (get-text-property (if (mouse-event-p last-command-event)
+                                   (posn-point (event-start 
last-command-event))
+                                 (point))
+                               'command)))
+    (transient--do-pre-command)))
+
+(defun transient--do-recurse ()
+  "Call the transient prefix command, preparing for return to active transient.
+If there is no parent prefix, then just call the command."
+  (transient--do-replace))
+
+(defun transient--setup-recursion (prefix-obj)
+  (when transient--stack
+    (let ((command (oref prefix-obj command)))
+      (when-let ((suffix-obj (transient-suffix-object command)))
+        (when (and (slot-boundp suffix-obj 'transient)
+                   (memq (oref suffix-obj transient)
+                         (list t #'transient--do-recurse)))
+          (oset prefix-obj transient-suffix 'transient--do-return))))))
+
 (defun transient--do-replace ()
   "Call the transient prefix command, replacing the active transient."
   (transient--export)
@@ -2195,17 +2439,28 @@ to `transient--do-warn'."
     (setq this-command 'transient-popup-navigation-help))
   transient--stay)
 
+(defun transient--do-minus ()
+  "Call `negative-argument' or pivot to `transient-update'.
+If `negative-argument' is invoked using \"-\" then preserve the
+prefix argument and pivot to `transient-update'."
+  (when (equal (this-command-keys) "-")
+    (setq this-command 'transient-update))
+  transient--stay)
+
 (put 'transient--do-stay       'transient-color 'transient-red)
 (put 'transient--do-noop       'transient-color 'transient-red)
 (put 'transient--do-warn       'transient-color 'transient-red)
 (put 'transient--do-warn-inapt 'transient-color 'transient-red)
 (put 'transient--do-call       'transient-color 'transient-red)
+(put 'transient--do-return     'transient-color 'transient-purple)
 (put 'transient--do-exit       'transient-color 'transient-blue)
+(put 'transient--do-recurse    'transient-color 'transient-red)
 (put 'transient--do-replace    'transient-color 'transient-blue)
 (put 'transient--do-suspend    'transient-color 'transient-blue)
 (put 'transient--do-quit-one   'transient-color 'transient-blue)
 (put 'transient--do-quit-all   'transient-color 'transient-blue)
 (put 'transient--do-move       'transient-color 'transient-red)
+(put 'transient--do-minus      'transient-color 'transient-red)
 
 ;;; Commands
 
@@ -2231,6 +2486,8 @@ to `transient--do-warn'."
                        'face 'font-lock-warning-face)
            (propertize "C-g" 'face 'transient-key)
            (propertize "?"   'face 'transient-key)
+           ;; `this-command' is `transient--undefined' or similar at this
+           ;; point.  Show the command the user actually tried to invoke.
            (propertize (symbol-name (transient--suffix-symbol
                                      this-original-command))
                        'face 'font-lock-warning-face))
@@ -2271,7 +2528,9 @@ transient is active."
 
 (defun transient-update ()
   "Redraw the transient's state in the popup buffer."
-  (interactive))
+  (interactive)
+  (when (equal this-original-command 'negative-argument)
+    (setq prefix-arg current-prefix-arg)))
 
 (defun transient-show ()
   "Show the transient's state in the popup buffer."
@@ -2336,7 +2595,8 @@ transient is active."
         (oset (transient-suffix-object command) level level))
       (setf (alist-get sym alist) level)
       (setf (alist-get prefix transient-levels) alist))
-    (transient-save-levels))
+    (transient-save-levels)
+    (transient--show))
    (t
     (transient-undefined))))
 
@@ -2350,6 +2610,11 @@ transient is active."
   (interactive)
   (transient-save-value (or transient--prefix transient-current-prefix)))
 
+(defun transient-reset ()
+  "Clear the set and saved values of the active transient."
+  (interactive)
+  (transient-reset-value (or transient--prefix transient-current-prefix)))
+
 (defun transient-history-next ()
   "Switch to the next value used for the active transient."
   (interactive)
@@ -2391,6 +2656,10 @@ around `scroll-down-command' (which see)."
   (with-selected-window transient--window
     (scroll-down-command arg)))
 
+(defun transient-push-button ()
+  "Invoke the suffix command represented by this button."
+  (interactive))
+
 (defun transient-resume ()
   "Resume a previously suspended stack of transients."
   (interactive)
@@ -2460,12 +2729,7 @@ Otherwise call the primary method according to object's 
class."
     (oset obj value
           (if-let ((saved (assq (oref obj command) transient-values)))
               (cdr saved)
-            (if-let ((default (and (slot-boundp obj 'default-value)
-                                   (oref obj default-value))))
-                (if (functionp default)
-                    (funcall default)
-                  default)
-              nil)))))
+            (transient-default-value obj)))))
 
 (cl-defmethod transient-init-value ((obj transient-argument))
   (oset obj value
@@ -2473,6 +2737,7 @@ Otherwise call the primary method according to object's 
class."
               (argument (and (slot-boundp obj 'argument)
                              (oref obj argument)))
               (multi-value (oref obj multi-value))
+              (case-fold-search nil)
               (regexp (if (slot-exists-p obj 'argument-regexp)
                           (oref obj argument-regexp)
                         (format "\\`%s\\(.*\\)" (oref obj argument)))))
@@ -2491,6 +2756,20 @@ Otherwise call the primary method according to object's 
class."
         (car (member (oref obj argument)
                      (oref transient--prefix value)))))
 
+;;;; Default
+
+(cl-defgeneric transient-default-value (_)
+  "Return the default value."
+  nil)
+
+(cl-defmethod transient-default-value ((obj transient-prefix))
+  (if-let ((default (and (slot-boundp obj 'default-value)
+                         (oref obj default-value))))
+      (if (functionp default)
+          (funcall default)
+        default)
+    nil))
+
 ;;;; Read
 
 (cl-defgeneric transient-infix-read (obj)
@@ -2511,13 +2790,24 @@ on the previous value.")
 (cl-defmethod transient-infix-read :around ((obj transient-infix))
   "Highlight the infix in the popup buffer.
 
-Also arrange for the transient to be exited in case of an error
-because otherwise Emacs would get stuck in an inconsistent state,
-which might make it necessary to kill it from the outside."
+This also wraps the call to `cl-call-next-method' with two
+macros.
+
+`transient--with-suspended-override' is necessary to allow
+reading user input using the minibuffer.
+
+`transient--with-emergency-exit' arranges for the transient to
+be exited in case of an error because otherwise Emacs would get
+stuck in an inconsistent state, which might make it necessary to
+kill it from the outside.
+
+If you replace this method, then you must make sure to always use
+the latter macro and most likely also the former."
   (let ((transient--active-infix obj))
     (transient--show))
   (transient--with-emergency-exit
-    (cl-call-next-method obj)))
+    (transient--with-suspended-override
+     (cl-call-next-method obj))))
 
 (cl-defmethod transient-infix-read ((obj transient-infix))
   "Read a value while taking care of history.
@@ -2541,7 +2831,7 @@ it\", in which case it is pointless to preserve history.)"
              (not always-read)
              transient--prefix)
         (oset obj value nil)
-      (let* ((overriding-terminal-local-map nil)
+      (let* ((enable-recursive-minibuffers t)
              (reader (oref obj reader))
              (prompt (transient-prompt obj))
              (value (if multi-value (mapconcat #'identity value ",") value))
@@ -2677,11 +2967,11 @@ prompt."
         (if (stringp prompt)
             prompt
           "(BUG: no prompt): "))
-    (or (when-let ((arg (and (slot-boundp obj 'argument) (oref obj argument))))
+    (or (and-let* ((arg (and (slot-boundp obj 'argument) (oref obj argument))))
           (if (and (stringp arg) (string-suffix-p "=" arg))
               arg
             (concat arg ": ")))
-        (when-let ((var (and (slot-boundp obj 'variable) (oref obj variable))))
+        (and-let* ((var (and (slot-boundp obj 'variable) (oref obj variable))))
           (and (stringp var)
                (concat var ": ")))
         "(BUG: no prompt): ")))
@@ -2719,12 +3009,18 @@ prompt."
                 (transient-infix-set obj nil)))))
       (cl-call-next-method obj value))))
 
+(cl-defgeneric transient-set-value (obj)
+  "Set the value of the transient prefix OBJ.")
+
 (cl-defmethod transient-set-value ((obj transient-prefix))
   (oset (oref obj prototype) value (transient-get-value))
   (transient--history-push obj))
 
 ;;;; Save
 
+(cl-defgeneric transient-save-value (obj)
+  "Save the value of the transient prefix OBJ.")
+
 (cl-defmethod transient-save-value ((obj transient-prefix))
   (let ((value (transient-get-value)))
     (oset (oref obj prototype) value value)
@@ -2732,6 +3028,20 @@ prompt."
     (transient-save-values))
   (transient--history-push obj))
 
+;;;; Reset
+
+(cl-defgeneric transient-reset-value (obj)
+  "Clear the set and saved values of the transient prefix OBJ.")
+
+(cl-defmethod transient-reset-value ((obj transient-prefix))
+  (let ((value (transient-default-value obj)))
+    (oset obj value value)
+    (oset (oref obj prototype) value value)
+    (setf (alist-get (oref obj command) transient-values nil 'remove) nil)
+    (transient-save-values))
+  (transient--history-push obj)
+  (mapc #'transient-init-value transient--suffixes))
+
 ;;;; Get
 
 (defun transient-args (prefix)
@@ -2759,7 +3069,7 @@ the set, saved or default value for PREFIX."
                transient-current-suffixes)))
 
 (defun transient--get-wrapped-value (obj)
-  (when-let ((value (transient-infix-value obj)))
+  (and-let* ((value (transient-infix-value obj)))
     (cl-ecase (and (slot-exists-p obj 'multi-value)
                    (oref obj multi-value))
       ((nil)    (list value))
@@ -2797,7 +3107,7 @@ does nothing." nil)
 
 (cl-defmethod transient-infix-value ((obj transient-option))
   "Return ARGUMENT and VALUE as a unit or nil if the latter is nil."
-  (when-let ((value (oref obj value)))
+  (and-let* ((value (oref obj value)))
     (let ((arg (oref obj argument)))
       (cl-ecase (oref obj multi-value)
         ((nil)    (concat arg value))
@@ -2820,9 +3130,10 @@ contribute to the value of the transient."
 For a switch return a boolean.  For an option return the value as
 a string, using the empty string for the empty value, or nil if
 the option does not appear in ARGS."
-  (if (string-match-p "=\\'" arg)
+  (if (string-suffix-p "=" arg)
       (save-match-data
-        (when-let ((match (let ((re (format "\\`%s\\(?:=\\(.+\\)\\)?\\'"
+        (and-let* ((match (let ((case-fold-search nil)
+                                (re (format "\\`%s\\(?:=\\(.+\\)\\)?\\'"
                                             (substring arg 0 -1))))
                             (cl-find-if (lambda (a)
                                           (and (stringp a)
@@ -2905,6 +3216,7 @@ have a history of their own.")
       (setq window-size-fixed t)
       (when (bound-and-true-p tab-line-format)
         (setq tab-line-format nil))
+      (setq header-line-format nil)
       (setq mode-line-format (if (eq transient-mode-line-format 'line)
                                  nil
                                transient-mode-line-format))
@@ -2938,9 +3250,9 @@ have a history of their own.")
         (goto-char (point-min))
         (when transient-enable-popup-navigation
           (transient--goto-button focus))
-        (magit--fit-window-to-buffer transient--window)))))
+        (transient--fit-window-to-buffer transient--window)))))
 
-(defun magit--fit-window-to-buffer (window)
+(defun transient--fit-window-to-buffer (window)
   (let ((window-resize-pixelwise t)
         (window-size-fixed nil))
     (if (eq (car (window-parameter window 'quit-restore)) 'other)
@@ -2962,13 +3274,18 @@ have a history of their own.")
       (when groups
         (insert ?\n)))))
 
+(defvar transient--max-group-level 1)
+
 (cl-defgeneric transient--insert-group (group)
   "Format GROUP and its elements and insert the result.")
 
-(cl-defmethod transient--insert-group :before ((group transient-group))
+(cl-defmethod transient--insert-group :around ((group transient-group))
   "Insert GROUP's description, if any."
   (when-let ((desc (transient-format-description group)))
-    (insert desc ?\n)))
+    (insert desc ?\n))
+  (let ((transient--max-group-level
+         (max (oref group level) transient--max-group-level)))
+    (cl-call-next-method group)))
 
 (cl-defmethod transient--insert-group ((group transient-row))
   (transient--maybe-pad-keys group)
@@ -2993,9 +3310,10 @@ have a history of their own.")
              (let ((rows (mapcar #'transient-format (oref column suffixes))))
                (when-let ((desc (transient-format-description column)))
                  (push desc rows))
-               rows))
+               (flatten-tree rows)))
            (oref group suffixes)))
-         (vp (oref transient--prefix variable-pitch))
+         (vp (or (oref transient--prefix variable-pitch)
+                 transient-align-variable-pitch))
          (rs (apply #'max (mapcar #'length columns)))
          (cs (length columns))
          (cw (mapcar (lambda (col)
@@ -3095,7 +3413,7 @@ Optional support for popup buttons is also implemented 
here."
       (add-face-text-property 0 (length str) 'transient-inapt-suffix nil str))
     (if transient-enable-popup-navigation
         (make-text-button str nil
-                          'type 'transient-button
+                          'type 'transient
                           'command (transient--suffix-command obj))
       str)))
 
@@ -3128,27 +3446,33 @@ Optional support for popup buttons is also implemented 
here."
         (let ((len (length transient--redisplay-key))
               (seq (cl-coerce (edmacro-parse-keys key t) 'list)))
           (cond
-           ((equal (seq-take seq len) transient--redisplay-key)
+           ((member (seq-take seq len)
+                    (list transient--redisplay-key
+                          (thread-last transient--redisplay-key
+                            (cl-substitute ?- 'kp-subtract)
+                            (cl-substitute ?= 'kp-equal)
+                            (cl-substitute ?+ 'kp-add))))
             (let ((pre (key-description (vconcat (seq-take seq len))))
                   (suf (key-description (vconcat (seq-drop seq len)))))
-              (setq pre (replace-regexp-in-string "RET" "C-m" pre t))
-              (setq pre (replace-regexp-in-string "TAB" "C-i" pre t))
-              (setq suf (replace-regexp-in-string "RET" "C-m" suf t))
-              (setq suf (replace-regexp-in-string "TAB" "C-i" suf t))
+              (setq pre (string-replace "RET" "C-m" pre))
+              (setq pre (string-replace "TAB" "C-i" pre))
+              (setq suf (string-replace "RET" "C-m" suf))
+              (setq suf (string-replace "TAB" "C-i" suf))
               ;; We use e.g. "-k" instead of the more correct "- k",
               ;; because the former is prettier.  If we did that in
               ;; the definition, then we want to drop the space that
               ;; is reinserted above.  False-positives are possible
               ;; for silly bindings like "-C-c C-c".
-              (unless (string-match-p " " key)
-                (setq pre (replace-regexp-in-string " " "" pre))
-                (setq suf (replace-regexp-in-string " " "" suf)))
-              (concat (propertize pre 'face 'default)
+              (unless (string-search " " key)
+                (setq pre (string-replace " " "" pre))
+                (setq suf (string-replace " " "" suf)))
+              (concat (propertize pre 'face 'transient-unreachable-key)
                       (and (string-prefix-p (concat pre " ") key) " ")
                       (transient--colorize-key suf cmd)
                       (save-excursion
-                        (when (string-match " +\\'" key)
-                          (match-string 0 key))))))
+                        (and (string-match " +\\'" key)
+                             (propertize (match-string 0 key)
+                                         'face 'fixed-pitch))))))
            ((transient--lookup-key transient-sticky-map (kbd key))
             (transient--colorize-key key cmd))
            (t
@@ -3179,7 +3503,7 @@ Optional support for popup buttons is also implemented 
here."
   "The `description' slot may be a function, in which case that is
 called inside the correct buffer (see `transient-insert-group')
 and its value is returned to the caller."
-  (when-let ((desc (oref obj description)))
+  (and-let* ((desc (oref obj description)))
     (if (functionp desc)
         (with-current-buffer transient--original-buffer
           (funcall desc))
@@ -3189,7 +3513,7 @@ and its value is returned to the caller."
   "Format the description by calling the next method.  If the result
 doesn't use the `face' property at all, then apply the face
 `transient-heading' to the complete string."
-  (when-let ((desc (cl-call-next-method obj)))
+  (and-let* ((desc (cl-call-next-method obj)))
     (if (text-property-not-all 0 (length desc) 'face nil desc)
         desc
       (propertize desc 'face 'transient-heading))))
@@ -3207,7 +3531,8 @@ If the OBJ's `key' is currently unreachable, then apply 
the face
     (cond ((transient--key-unreachable-p obj)
            (propertize desc 'face 'transient-unreachable))
           ((and transient-highlight-higher-levels
-                (> (oref obj level) transient--default-prefix-level))
+                (> (max (oref obj level) transient--max-group-level)
+                   transient--default-prefix-level))
            (add-face-text-property
             0 (length desc) 'transient-higher-level nil desc)
            desc)
@@ -3343,9 +3668,24 @@ manpage, then try to jump to the correct location."
   (transient--describe-function cmd))
 
 (defun transient--describe-function (fn)
-  (describe-function fn)
+  (describe-function (if (symbolp fn) fn 'transient--anonymous-infix-argument))
   (select-window (get-buffer-window (help-buffer))))
 
+(defun transient--anonymous-infix-argument ()
+  "Cannot show any documentation for this anonymous infix command.
+
+The infix command in question was defined anonymously, i.e.,
+it was define when the prefix command that it belongs to was
+defined, which means that it gets no docstring and also that
+no symbol is bound to it.
+
+When you request help for an infix command, then we usually
+show the respective man-page and jump to the location where
+the respective argument is being described.
+
+Because the containing prefix command does not specify any
+man-page, we cannot do that in this case.  Sorry about that.")
+
 (defun transient--show-manual (manual)
   (info manual))
 
@@ -3453,8 +3793,14 @@ resumes the suspended transient.")
 (define-minor-mode transient-resume-mode
   "Auxiliary minor-mode used to resume a transient after viewing help.")
 
-;;; Compatibility
-;;;; Popup Navigation
+(defun transient-toggle-debug ()
+  "Toggle debugging statements for transient commands."
+  (interactive)
+  (setq transient--debug (not transient--debug))
+  (message "Debugging transient %s"
+           (if transient--debug "enabled" "disabled")))
+
+;;; Popup Navigation
 
 (defun transient-popup-navigation-help ()
   "Inform the user how to enable popup navigation commands."
@@ -3462,39 +3808,9 @@ resumes the suspended transient.")
   (message "This command is only available if `%s' is non-nil"
            'transient-enable-popup-navigation))
 
-(define-button-type 'transient-button
+(define-button-type 'transient
   'face nil
-  'action (lambda (button)
-            (let ((command (button-get button 'command)))
-              ;; Yes, I know that this is wrong(tm).
-              ;; Unfortunately it is also necessary.
-              (setq this-original-command command)
-              (transient--pre-command)
-              (call-interactively command))))
-
-(defvar transient-popup-navigation-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map (kbd "<down-mouse-1>") #'transient-noop)
-    (define-key map (kbd "<mouse-1>") #'transient-mouse-push-button)
-    (define-key map (kbd "RET")       #'transient-push-button)
-    (define-key map (kbd "<up>")      #'transient-backward-button)
-    (define-key map (kbd "C-p")       #'transient-backward-button)
-    (define-key map (kbd "<down>")    #'transient-forward-button)
-    (define-key map (kbd "C-n")       #'transient-forward-button)
-    (define-key map (kbd "C-r")       #'transient-isearch-backward)
-    (define-key map (kbd "C-s")       #'transient-isearch-forward)
-    map))
-
-(defun transient-mouse-push-button (&optional pos)
-  "Invoke the suffix the user clicks on."
-  (interactive (list last-command-event))
-  (push-button pos))
-
-(defun transient-push-button ()
-  "Invoke the selected suffix command."
-  (interactive)
-  (with-selected-window transient--window
-    (push-button)))
+  'keymap transient-button-map)
 
 (defun transient-backward-button (n)
   "Move to the previous button in the transient popup buffer.
@@ -3529,6 +3845,7 @@ See `forward-button' for information about N."
           beg (next-single-property-change
                beg 'face nil (line-end-position))))))
 
+;;; Compatibility
 ;;;; Popup Isearch
 
 (defvar transient--isearch-mode-map
@@ -3577,7 +3894,7 @@ search instead."
 
 (defun transient--isearch-setup ()
   (select-window transient--window)
-  (transient--suspend-override))
+  (transient--suspend-override t))
 
 (defun transient--isearch-exit ()
   (select-window transient--original-window)
@@ -3606,11 +3923,12 @@ search instead."
                        'transient-red
                      'transient-blue))))
     (pcase (list suffix nonsuf)
-      (`(transient-red  disallow)       'transient-amaranth)
-      (`(transient-blue disallow)       'transient-teal)
-      (`(transient-red  transient-red)  'transient-pink)
-      (`(transient-red  transient-blue) 'transient-red)
-      (`(transient-blue transient-blue) 'transient-blue))))
+      (`(transient-purple ,_)           'transient-purple)
+      ('(transient-red  disallow)       'transient-amaranth)
+      ('(transient-blue disallow)       'transient-teal)
+      ('(transient-red  transient-red)  'transient-pink)
+      ('(transient-red  transient-blue) 'transient-red)
+      ('(transient-blue transient-blue) 'transient-blue))))
 
 ;;;; Edebug
 
@@ -3620,7 +3938,7 @@ search instead."
       (funcall fn arg-mode)
     (transient--suspend-override t)
     (funcall fn arg-mode)
-    (transient--resume-override t)))
+    (transient--resume-override)))
 
 (advice-add 'edebug--recursive-edit :around 
#'transient--edebug--recursive-edit)
 
@@ -3638,6 +3956,18 @@ search instead."
 
 ;;;; Miscellaneous
 
+(cl-pushnew (list nil (concat "^\\s-*("
+                              (eval-when-compile
+                                (regexp-opt
+                                 '("transient-define-prefix"
+                                   "transient-define-suffix"
+                                   "transient-define-infix"
+                                   "transient-define-argument")
+                                 t))
+                              "\\s-+\\(" lisp-mode-symbol-regexp "\\)")
+                  2)
+            lisp-imenu-generic-expression :test #'equal)
+
 (declare-function which-key-mode "which-key" (&optional arg))
 
 (defun transient--suspend-which-key-mode ()
@@ -3740,7 +4070,7 @@ we stop there."
            (oset obj value value)))
 
 (cl-defmethod transient-format-description ((obj transient-lisp-variable))
-  (or (oref obj description)
+  (or (cl-call-next-method obj)
       (symbol-name (oref obj variable))))
 
 (cl-defmethod transient-format-value ((obj transient-lisp-variable))
diff --git a/lisp/type-break.el b/lisp/type-break.el
index 267facccc4..bb6382cfe9 100644
--- a/lisp/type-break.el
+++ b/lisp/type-break.el
@@ -46,11 +46,6 @@
 ;; in the mode line instead, do M-x type-break-mode-line-message-mode
 ;; or set the variable of the same name to t.
 
-;; This program can truly cons up a storm because of all the calls to
-;; `current-time' (which always returns fresh conses).  I'm dismayed by
-;; this, but I think the health of my hands is far more important than a
-;; few pages of virtual memory.
-
 ;; This package was inspired by Roland McGrath's hanoi-break.el.
 ;; Several people contributed feedback and ideas, including
 ;;      Roland McGrath <roland@gnu.org>
@@ -69,7 +64,7 @@
 
 (defcustom type-break-interval (* 60 60)
   "Number of seconds between scheduled typing breaks."
-  :type 'integer
+  :type 'natnum
   :group 'type-break)
 
 (defcustom type-break-good-rest-interval (/ type-break-interval 6)
@@ -82,7 +77,7 @@ rest from typing, then the next typing break is simply 
rescheduled for later.
 If a break is interrupted before this much time elapses, the user will be
 asked whether or not really to interrupt the break."
   :set-after '(type-break-interval)
-  :type 'integer
+  :type 'natnum
   :group 'type-break)
 
 (defcustom type-break-good-break-interval nil
@@ -148,7 +143,7 @@ To avoid being queried at all, set `type-break-query-mode' 
to nil."
   "Number of seconds between queries to take a break, if put off.
 The user will continue to be prompted at this interval until he or she
 finally submits to taking a typing break."
-  :type 'integer
+  :type 'natnum
   :group 'type-break)
 
 (defcustom type-break-time-warning-intervals '(300 120 60 30)
@@ -171,7 +166,7 @@ will occur."
   "Number of keystrokes for which warnings should be repeated.
 That is, for each of this many keystrokes the warning is redisplayed
 in the echo area to make sure it's really seen."
-  :type 'integer
+  :type 'natnum
   :group 'type-break)
 
 (defcustom type-break-time-stamp-format "[%H:%M] "
@@ -263,7 +258,7 @@ It will be either \"seconds\" or \"keystrokes\".")
 (defvar type-break-keystroke-count 0)
 (defvar type-break-time-last-break nil)
 (defvar type-break-time-next-break nil)
-(defvar type-break-time-last-command (current-time))
+(defvar type-break-time-last-command (time-convert nil 'integer))
 (defvar type-break-current-time-warning-interval nil)
 (defvar type-break-current-keystroke-warning-interval nil)
 (defvar type-break-time-warning-count 0)
@@ -362,7 +357,7 @@ problems."
 
     (setq type-break-time-last-break
           (or (type-break-get-previous-time)
-              (current-time)))
+             (time-convert nil 'integer)))
 
     ;; Schedule according to break time from session file.
     (type-break-schedule
@@ -381,7 +376,7 @@ problems."
              (setq type-break-interval-start type-break-time-last-break)
              (- type-break-interval diff))
          ;; Schedule from now.
-         (setq type-break-interval-start (current-time))
+        (setq type-break-interval-start (time-convert nil 'integer))
          (type-break-file-time type-break-interval-start)
          type-break-interval))
      type-break-interval-start
@@ -456,7 +451,7 @@ the variable of the same name."
              ;; file saving is left to auto-save
              ))))))
 
-(defun timep (time)
+(defun type-break-timep (time)
   "If TIME is a Lisp time value then return TIME, else return nil."
   (condition-case nil
       (and (float-time time) time)
@@ -480,7 +475,7 @@ the variable of the same name."
 Return nil if the file is missing or if the time is not a Lisp time value."
   (let ((file (type-break-choose-file)))
     (if file
-        (timep ;; returns expected format, else nil
+        (type-break-timep ;; returns expected format, else nil
          (with-current-buffer (find-file-noselect file 'nowarn)
           (condition-case nil
               (save-excursion
@@ -525,7 +520,7 @@ as per the function `type-break-schedule'."
   ;; remove any query scheduled during interactive invocation
   (remove-hook 'type-break-post-command-hook 'type-break-do-query)
   (let ((continue t)
-        (start-time (current-time)))
+       (start-time (time-convert nil 'integer)))
     (setq type-break-time-last-break start-time)
     (while continue
       (save-window-excursion
@@ -676,9 +671,9 @@ keystroke threshold has been exceeded."
                 (progn
                   (type-break-keystroke-reset)
                   (type-break-mode-line-countdown-or-break nil)
-                  (setq type-break-time-last-break (current-time))
+                 (setq type-break-time-last-break (time-convert nil 'integer))
                   (type-break-schedule)))
-           (setq type-break-time-last-command (current-time))))
+          (setq type-break-time-last-command (time-convert nil 'integer))))
 
     (and type-break-keystroke-threshold
          (let ((keys (this-command-keys)))
@@ -943,14 +938,13 @@ FRAC should be the inverse of the fractional value; for 
example, a value of
 
 ;;; misc functions
 
-;; Compute the difference, in seconds, between a and b, two structures
-;; similar to those returned by `current-time'.
+;; Compute the difference, in seconds, between a and b, two time values.
 (defun type-break-time-difference (a b)
   (round (float-time (time-subtract b a))))
 
 ;; Return a time value that is the sum of the time-value arguments.
 (defun type-break-time-sum (&rest tmlist)
-  (let ((sum '(0 0)))
+  (let ((sum 0))
     (dolist (tem tmlist)
       (setq sum (time-add sum tem)))
     sum))
@@ -967,7 +961,7 @@ FRAC should be the inverse of the fractional value; for 
example, a value of
      (t (format "%d seconds" secs)))))
 
 (defun type-break-keystroke-reset ()
-  (setq type-break-interval-start (current-time)) ; not a keystroke
+  (setq type-break-interval-start (time-convert nil 'integer))
   (setq type-break-keystroke-count 0)
   (setq type-break-keystroke-warning-count 0)
   (setq type-break-current-keystroke-warning-interval
@@ -1149,6 +1143,8 @@ With optional non-nil ALL, force redisplay of all 
mode-lines."
        (and (get-buffer buffer-name)
             (kill-buffer buffer-name))))))
 
+(define-obsolete-function-alias 'timep 'type-break-timep "29.1")
+
 
 (provide 'type-break)
 
diff --git a/lisp/uniquify.el b/lisp/uniquify.el
index 2ef1f04f70..74655e299a 100644
--- a/lisp/uniquify.el
+++ b/lisp/uniquify.el
@@ -109,8 +109,8 @@ BASE and EXTRA-STRINGS where BASE is a string and 
EXTRA-STRINGS
 is a list of strings.  For example the current implementation for
 post-forward-angle-brackets could be:
 
-(defun my-post-forward-angle-brackets (base extra-string)
-  (concat base \"<\" (mapconcat #'identity extra-string \"/\") \">\"))
+  (defun my-post-forward-angle-brackets (base extra-string)
+    (concat base \"<\" (mapconcat #\\='identity extra-string \"/\") \">\"))
 
 The \"mumble\" part may be stripped as well, depending on the
 setting of `uniquify-strip-common-suffix'.  For more options that
@@ -128,7 +128,6 @@ you can set, browse the `uniquify' custom group."
   "If non-nil, rerationalize buffer names after a buffer has been killed."
   :type 'boolean)
 
-;; The default value matches certain Gnus buffers.
 (defcustom uniquify-ignore-buffers-re nil
   "Regular expression matching buffer names that should not be uniquified.
 For instance, set this to \"^draft-[0-9]+$\" to avoid having uniquify rename
diff --git a/lisp/url/url-about.el b/lisp/url/url-about.el
deleted file mode 100644
index 3943cae9e5..0000000000
--- a/lisp/url/url-about.el
+++ /dev/null
@@ -1,103 +0,0 @@
-;;; url-about.el --- Show internal URLs  -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2001, 2004-2022 Free Software Foundation, Inc.
-
-;; Keywords: comm, data, processes, hypermedia
-
-;; 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 'url-util)
-(require 'url-parse)
-
-(defun url-probe-protocols ()
-  "Return a list of all potential URL schemes."
-  (or (get 'url-extension-protocols 'probed)
-      (mapc (lambda (s) (url-scheme-get-property s 'name))
-           (or (get 'url-extension-protocols 'schemes)
-               (let ((schemes '("info" "man" "rlogin" "telnet"
-                                "tn3270" "data" "snews")))
-                 (mapc (lambda (d)
-                         (mapc (lambda (f)
-                                 (if (string-match "url-\\(.*\\).el$" f)
-                                     (push (match-string 1 f) schemes)))
-                               (directory-files d nil "\\`url-.*\\.el\\'")))
-                       load-path)
-                 (put 'url-extension-protocols 'schemes schemes)
-                 schemes)))))
-
-(defvar url-scheme-registry)
-
-(defun url-about-protocols (_url)
-  (url-probe-protocols)
-  (insert "<html>\n"
-         " <head>\n"
-         "  <title>Supported Protocols</title>\n"
-         " </head>\n"
-         " <body>\n"
-          "  <h1>Supported Protocols - URL package in Emacs " emacs-version 
"</h1>\n"
-         "  <table width='100%' border='1'>\n"
-         "   <tr>\n"
-         "    <td>Protocol\n"
-         "    <td>Properties\n"
-         "    <td>Description\n"
-         "   </tr>\n")
-  (mapc (lambda (k)
-         (if (string= k "proxy")
-             ;; Ignore the proxy setting... its magic!
-             nil
-           (insert "   <tr>\n")
-           ;; The name of the protocol
-           (insert "    <td valign=top>" (or (url-scheme-get-property k 'name) 
k) "\n")
-
-           ;; Now the properties.  Currently just asynchronous
-           ;; status, default port number, and proxy status.
-           (insert "    <td valign=top>"
-                   (if (url-scheme-get-property k 'asynchronous-p) "As" "S")
-                   "ynchronous<br>\n"
-                   (if (url-scheme-get-property k 'default-port)
-                       (format "Default Port: %d<br>\n"
-                               (url-scheme-get-property k 'default-port))
-                     "")
-                   (if (assoc k url-proxy-services)
-                       (format "Proxy: %s<br>\n" (assoc k url-proxy-services)) 
""))
-           ;; Now the description...
-           (insert "    <td valign=top>"
-                   (or (url-scheme-get-property k 'description) "N/A"))))
-       (sort (let (x) (maphash (lambda (k _v) (push k x)) url-scheme-registry) 
x)
-             #'string-lessp))
-  (insert "  </table>\n"
-         " </body>\n"
-         "</html>\n"))
-
-(defun url-about (url)
-  "Show internal URLs."
-  (let* ((item (downcase (url-filename url)))
-        (func (intern (format "url-about-%s" item))))
-    (if (fboundp func)
-       (progn
-         (set-buffer (generate-new-buffer " *about-data*"))
-         (insert "Content-type: text/plain\n\n")
-         (funcall func url)
-         (current-buffer))
-      (error "URL does not know about `%s'" item))))
-
-(provide 'url-about)
-
-;;; url-about.el ends here
diff --git a/lisp/url/url-cache.el b/lisp/url/url-cache.el
index 3e69227124..db8c121cf0 100644
--- a/lisp/url/url-cache.el
+++ b/lisp/url/url-cache.el
@@ -37,7 +37,7 @@
   "Default maximum time in seconds before cache files expire.
 Used by the function `url-cache-expired'."
   :version "24.1"
-  :type 'integer
+  :type 'natnum
   :group 'url-cache)
 
 ;; Cache manager
diff --git a/lisp/url/url-cookie.el b/lisp/url/url-cookie.el
index 15c78512c6..0709cdd3fa 100644
--- a/lisp/url/url-cookie.el
+++ b/lisp/url/url-cookie.el
@@ -360,7 +360,7 @@ to run the `url-cookie-setup-save-timer' function manually."
          (set-default var val)
          (if (bound-and-true-p url-setup-done)
              (url-cookie-setup-save-timer)))
-  :type 'integer
+  :type 'natnum
   :group 'url-cookie)
 
 (defun url-cookie-setup-save-timer ()
diff --git a/lisp/url/url-dired.el b/lisp/url/url-dired.el
deleted file mode 100644
index e2c23a8b6d..0000000000
--- a/lisp/url/url-dired.el
+++ /dev/null
@@ -1,57 +0,0 @@
-;;; url-dired.el --- URL Dired minor mode  -*- lexical-binding: t -*-
-
-;; Copyright (C) 1996-1999, 2004-2022 Free Software Foundation, Inc.
-
-;; Keywords: comm, files
-
-;; 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:
-
-(autoload 'dired-get-filename "dired")
-
-(defvar-keymap url-dired-minor-mode-map
-  :doc "Keymap used when browsing directories."
-  "C-m"       #'url-dired-find-file
-  "<mouse-2>" #'url-dired-find-file-mouse)
-
-(defun url-dired-find-file ()
-  "In dired, visit the file or directory named on this line."
-  (interactive)
-  (let ((filename (dired-get-filename)))
-    (find-file filename)))
-
-(defun url-dired-find-file-mouse (event)
-  "In dired, visit the file or directory name you click on."
-  (interactive "@e")
-  (mouse-set-point event)
-  (url-dired-find-file))
-
-(define-minor-mode url-dired-minor-mode
-  "Minor mode for directory browsing."
-  :lighter " URL" :keymap url-dired-minor-mode-map)
-
-(defun url-find-file-dired (dir)
-  "\"Edit\" directory DIR, but with additional URL-friendly bindings."
-  (interactive "DURL Dired (directory): ")
-  (find-file dir)
-  (url-dired-minor-mode t))
-
-(provide 'url-dired)
-
-;;; url-dired.el ends here
diff --git a/lisp/url/url-file.el b/lisp/url/url-file.el
index 3863ac9914..a72b2e67a6 100644
--- a/lisp/url/url-file.el
+++ b/lisp/url/url-file.el
@@ -26,7 +26,6 @@
 (require 'mailcap)
 (require 'url-vars)
 (require 'url-parse)
-(require 'url-dired)
 (declare-function mm-disable-multibyte "mm-util" ())
 
 (defvar url-allow-non-local-files nil
@@ -42,10 +41,10 @@ src=\"/ssh:host...\"> element, which can be disturbing.")
 (defun url-file-find-possibly-compressed-file (fname &rest _)
   "Find the exact file referenced by `fname'.
 This tries the common compression extensions, because things like
-ange-ftp and efs are not quite smart enough to realize when a server
-can do automatic decompression for them, and won't find `foo' if
-`foo.gz' exists, even though the FTP server would happily serve it up
-to them."
+ange-ftp is not quite smart enough to realize when a server can
+do automatic decompression for them, and won't find `foo' if
+`foo.gz' exists, even though the FTP server would happily serve
+it up to them."
   (let ((scratch nil)
        (compressed-extensions '("" ".gz" ".z" ".Z" ".bz2" ".xz"))
        (found nil))
@@ -174,7 +173,7 @@ to them."
 
     (if (file-directory-p filename)
        ;; A directory is done the same whether we are local or remote
-       (url-find-file-dired filename)
+       (find-file filename)
       (with-current-buffer
          (setq buffer (generate-new-buffer " *url-file*"))
         (require 'mm-util)
diff --git a/lisp/url/url-history.el b/lisp/url/url-history.el
index cb4814afca..058e601301 100644
--- a/lisp/url/url-history.el
+++ b/lisp/url/url-history.el
@@ -63,7 +63,7 @@ to run the `url-history-setup-save-timer' function manually."
          (set-default var val)
          (if (bound-and-true-p url-setup-done)
              (url-history-setup-save-timer)))
-  :type 'integer
+  :type 'natnum
   :group 'url-history)
 
 (defvar url-history-timer nil)
diff --git a/lisp/url/url-http.el b/lisp/url/url-http.el
index 4e5d017036..94ef156108 100644
--- a/lisp/url/url-http.el
+++ b/lisp/url/url-http.el
@@ -471,9 +471,7 @@ Return the number of characters removed."
           t ;; Instruct caller to signal an error.  Bug#50511
         ;; Find strongest supported auth.
         (dolist (this-auth auths)
-          (setq this-auth (url-eat-trailing-space
-                           (url-strip-leading-spaces
-                            this-auth)))
+          (setq this-auth (string-trim this-auth))
           (let* ((this-type
                   (downcase (if (string-match "[ \t]" this-auth)
                                 (substring this-auth 0 (match-beginning 0))
@@ -709,7 +707,7 @@ should be shown to the user."
            ;; gives the URI of the proxy.  The recipient is expected
            ;; to repeat this single request via the proxy.  305
            ;; responses MUST only be generated by origin servers.
-           (error "Redirection thru a proxy server not supported: %s"
+           (error "Redirection through a proxy server not supported: %s"
                   redirect-uri))
           (_
            ;; Treat everything like '300'
@@ -1048,19 +1046,15 @@ More sophisticated percentage downloaded, etc.
 Also does minimal parsing of HTTP headers and will actually cause
 the callback to be triggered."
   (if url-http-content-type
-      (url-display-percentage
+      (url-display-message
        "Reading [%s]... %s of %s (%d%%)"
-       (url-percentage (- nd url-http-end-of-headers)
-                      url-http-content-length)
        url-http-content-type
        (funcall byte-count-to-string-function (- nd url-http-end-of-headers))
        (funcall byte-count-to-string-function url-http-content-length)
        (url-percentage (- nd url-http-end-of-headers)
                       url-http-content-length))
-    (url-display-percentage
+    (url-display-message
      "Reading... %s of %s (%d%%)"
-     (url-percentage (- nd url-http-end-of-headers)
-                    url-http-content-length)
      (funcall byte-count-to-string-function (- nd url-http-end-of-headers))
      (funcall byte-count-to-string-function url-http-content-length)
      (url-percentage (- nd url-http-end-of-headers)
@@ -1069,7 +1063,6 @@ the callback to be triggered."
   (if (> (- nd url-http-end-of-headers) url-http-content-length)
       (progn
        ;; Found the end of the document!  Wheee!
-       (url-display-percentage nil nil)
        (url-lazy-message "Reading... done.")
        (if (url-http-parse-headers)
            (url-http-activate-callback)))))
@@ -1099,13 +1092,6 @@ the end of the document."
         ;; one after-change-function call.
         (while read-next-chunk
          (setq no-initial-crlf (= 0 url-http-chunked-counter))
-         (if url-http-content-type
-             (url-display-percentage nil
-                                     "Reading [%s]... chunk #%d"
-                                     url-http-content-type 
url-http-chunked-counter)
-           (url-display-percentage nil
-                                   "Reading... chunk #%d"
-                                   url-http-chunked-counter))
          (url-http-debug "Reading chunk %d (%d %d %d)"
                          url-http-chunked-counter st nd length)
          (setq regexp (if no-initial-crlf
@@ -1163,7 +1149,6 @@ the end of the document."
                    ;; Found the end of the document!  Wheee!
                    (url-http-debug "Saw end of stream chunk!")
                    (setq read-next-chunk nil)
-                   (url-display-percentage nil nil)
                    ;; Every chunk, even the last 0-length one, is
                    ;; terminated by CRLF.  Skip it.
                    (if (not (looking-at "\r?\n"))
diff --git a/lisp/url/url-privacy.el b/lisp/url/url-privacy.el
index f897248fe4..36ccbe2adc 100644
--- a/lisp/url/url-privacy.el
+++ b/lisp/url/url-privacy.el
@@ -41,9 +41,16 @@
          nil)
         ;; First, we handle the inseparable OS/Windowing system
         ;; combinations
-        ((eq system-type 'windows-nt) "Windows-NT; 32bit")
+        ((memq system-type '(windows-nt cygwin))
+          (concat "MS-Windows; "
+                  (if (string-match-p "\\`x86_64" system-configuration)
+                      "64bit"
+                    "32bit")
+                  "; "
+                  (cond ((eq window-system 'w32) "w32")
+                        ((eq window-system 'x) "X11")
+                        (t "TTY"))))
         ((eq system-type 'ms-dos) "MS-DOS; 32bit")
-        ((memq (or window-system 'tty) '(win32 w32)) "Windows; 32bit")
         (t
          (pcase (or window-system 'tty)
            ('x "X11")
diff --git a/lisp/url/url-queue.el b/lisp/url/url-queue.el
index b2e24607e1..cf45a7f681 100644
--- a/lisp/url/url-queue.el
+++ b/lisp/url/url-queue.el
@@ -36,13 +36,13 @@
 (defcustom url-queue-parallel-processes 6
   "The number of concurrent processes."
   :version "24.1"
-  :type 'integer
+  :type 'natnum
   :group 'url)
 
 (defcustom url-queue-timeout 5
   "How long to let a job live once it's started (in seconds)."
   :version "24.1"
-  :type 'integer
+  :type 'natnum
   :group 'url)
 
 ;;; Internal variables.
diff --git a/lisp/url/url-tramp.el b/lisp/url/url-tramp.el
index 30c1961407..c414a025a1 100644
--- a/lisp/url/url-tramp.el
+++ b/lisp/url/url-tramp.el
@@ -44,36 +44,40 @@ In case URL is not convertible, nil is returned."
          (port
           (and obj (natnump (url-portspec obj))
                (number-to-string (url-portspec obj)))))
-    (when (and obj (member (url-type obj) url-tramp-protocols))
-      (when (url-password obj)
-       (password-cache-add
-        (tramp-make-tramp-file-name
-          (make-tramp-file-name
-          :method (url-type obj) :user (url-user obj)
-           :host (url-host obj)))
-        (url-password obj)))
-      (tramp-make-tramp-file-name
-       (make-tramp-file-name
-        :method (url-type obj) :user (url-user obj)
-        :host (url-host obj) :port port :localname (url-filename obj))))))
+    (if (and obj (member (url-type obj) url-tramp-protocols))
+        (progn
+          (when (url-password obj)
+           (password-cache-add
+            (tramp-make-tramp-file-name
+              (make-tramp-file-name
+              :method (url-type obj) :user (url-user obj)
+               :host (url-host obj)))
+            (url-password obj)))
+          (tramp-make-tramp-file-name
+           (make-tramp-file-name
+            :method (url-type obj) :user (url-user obj)
+            :host (url-host obj) :port port :localname (url-filename obj))))
+      url)))
 
 (defun url-tramp-convert-tramp-to-url (file)
   "Convert FILE, a Tramp file name, to a URL.
 In case FILE is not convertible, nil is returned."
-  (let* ((obj (ignore-errors (tramp-dissect-file-name file)))
+  (let* ((obj (and (tramp-tramp-file-p file)
+                   (ignore-errors (tramp-dissect-file-name file))))
          (port
           (and obj (stringp (tramp-file-name-port obj))
                (string-to-number (tramp-file-name-port obj)))))
-    (when (and obj (member (tramp-file-name-method obj) url-tramp-protocols))
-      (url-recreate-url
-       (url-parse-make-urlobj
-       (tramp-file-name-method obj)
-       (tramp-file-name-user obj)
-       nil ; password.
-       (tramp-file-name-host obj)
-       port
-       (tramp-file-name-localname obj)
-       nil nil t))))) ; target attributes fullness.
+    (if (and obj (member (tramp-file-name-method obj) url-tramp-protocols))
+        (url-recreate-url
+         (url-parse-make-urlobj
+         (tramp-file-name-method obj)
+         (tramp-file-name-user obj)
+         nil ; password.
+         (tramp-file-name-host obj)
+         port
+         (tramp-file-name-localname obj)
+         nil nil t)) ; target attributes fullness.
+      file)))
 
 ;;;###autoload
 (defun url-tramp-file-handler (operation &rest args)
diff --git a/lisp/url/url-util.el b/lisp/url/url-util.el
index fc84d45176..147a643c9f 100644
--- a/lisp/url/url-util.el
+++ b/lisp/url/url-util.el
@@ -27,8 +27,6 @@
 
 (require 'url-parse)
 (require 'url-vars)
-(autoload 'timezone-parse-date "timezone")
-(autoload 'timezone-make-date-arpa-standard "timezone")
 (autoload 'mail-header-extract "mailheader")
 
 (defvar url-parse-args-syntax-table
@@ -180,39 +178,28 @@ Will not do anything if `url-show-status' is nil."
   (format-time-string "%a, %d %b %Y %T GMT" specified-time t)))
 
 ;;;###autoload
-(defun url-eat-trailing-space (x)
-  "Remove spaces/tabs at the end of a string."
-  (let ((y (1- (length x)))
-       (skip-chars (list ?  ?\t ?\n)))
-    (while (and (>= y 0) (memq (aref x y) skip-chars))
-      (setq y (1- y)))
-    (substring x 0 (1+ y))))
+(define-obsolete-function-alias 'url-eat-trailing-space
+  #'string-trim-right "29.1")
 
 ;;;###autoload
-(defun url-strip-leading-spaces (x)
-  "Remove spaces at the front of a string."
-  (let ((y (1- (length x)))
-       (z 0)
-       (skip-chars (list ?  ?\t ?\n)))
-    (while (and (<= z y) (memq (aref x z) skip-chars))
-      (setq z (1+ z)))
-    (substring x z nil)))
-
+(define-obsolete-function-alias 'url-strip-leading-spaces
+  #'string-trim-left "29.1")
 
 (define-obsolete-function-alias 'url-pretty-length
   'file-size-human-readable "24.4")
 
 ;;;###autoload
-(defun url-display-percentage (fmt perc &rest args)
+(defun url-display-message (fmt &rest args)
+  "Like `message', but do nothing if `url-show-status' is nil."
   (when (and url-show-status
-            (or (null url-current-object)
-                (not (url-silent url-current-object))))
-    (if (null fmt)
-       (if (fboundp 'clear-progress-display)
-           (clear-progress-display))
-      (if (and (fboundp 'progress-display) perc)
-         (apply 'progress-display fmt perc args)
-       (apply 'message fmt args)))))
+             (not (and url-current-object (url-silent url-current-object)))
+             fmt)
+    (apply #'message fmt args)))
+
+;;;###autoload
+(defun url-display-percentage (fmt _perc &rest args)
+  (declare (obsolete url-display-message "29.1"))
+  (url-display-message fmt args))
 
 ;;;###autoload
 (defun url-percentage (x y)
diff --git a/lisp/url/url-vars.el b/lisp/url/url-vars.el
index 1012525568..859a5c75ed 100644
--- a/lisp/url/url-vars.el
+++ b/lisp/url/url-vars.el
@@ -205,7 +205,8 @@ from the ACCESS_proxy environment variables."
 
 (defvar url-mime-separator-chars (append "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                                         "abcdefghijklmnopqrstuvwxyz"
-                                        "0123456789'()+_,-./=?")
+                                        "0123456789'()+_,-./=?"
+                                        nil)
   "Characters allowable in a MIME multipart separator.")
 
 (defcustom url-bad-port-list
@@ -297,7 +298,7 @@ get the first available language (as opposed to the 
default)."
 (defcustom url-max-password-attempts 5
   "Maximum number of times a password will be prompted for.
 Applies when a protected document is denied by the server."
-  :type 'integer
+  :type 'natnum
   :group 'url)
 
 (defcustom url-show-status t
@@ -330,7 +331,7 @@ undefined."
 (defcustom url-max-redirections 30
   "The maximum number of redirection requests to honor in a HTTP connection.
 A negative number means to honor an unlimited number of redirection requests."
-  :type 'integer
+  :type 'natnum
   :group 'url)
 
 (defcustom url-confirmation-func 'y-or-n-p
diff --git a/lisp/url/url.el b/lisp/url/url.el
index 4592f0f2e7..d08ff04eda 100644
--- a/lisp/url/url.el
+++ b/lisp/url/url.el
@@ -158,7 +158,7 @@ If URL is a multibyte string, it will be encoded as utf-8 
and
 URL-encoded before it's used."
   ;; XXX: There is code in Emacs that does dynamic binding
   ;; of the following variables around url-retrieve:
-  ;; url-standalone-mode, url-gateway-unplugged, w3-honor-stylesheets,
+  ;; url-standalone-mode, url-gateway-unplugged,
   ;; url-confirmation-func, url-cookie-multiple-line,
   ;; url-cookie-{{,secure-}storage,confirmation}
   ;; url-standalone-mode and url-gateway-unplugged should work as
diff --git a/lisp/vc/add-log.el b/lisp/vc/add-log.el
index beaad2e835..d710578fff 100644
--- a/lisp/vc/add-log.el
+++ b/lisp/vc/add-log.el
@@ -568,14 +568,12 @@ Compatibility function for \\[next-error] invocations."
        ;; Select window displaying source file.
        (select-window change-log-find-window)))))
 
-(defvar change-log-mode-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map [?\C-c ?\C-p] #'add-log-edit-prev-comment)
-    (define-key map [?\C-c ?\C-n] #'add-log-edit-next-comment)
-    (define-key map [?\C-c ?\C-f] #'change-log-find-file)
-    (define-key map [?\C-c ?\C-c] #'change-log-goto-source)
-    map)
-  "Keymap for Change Log major mode.")
+(defvar-keymap change-log-mode-map
+  :doc "Keymap for Change Log major mode."
+  "C-c C-p" #'add-log-edit-prev-comment
+  "C-c C-n" #'add-log-edit-next-comment
+  "C-c C-f" #'change-log-find-file
+  "C-c C-c" #'change-log-goto-source)
 
 (easy-menu-define change-log-mode-menu change-log-mode-map
   "Menu for Change Log major mode."
@@ -789,10 +787,9 @@ Optional arg BUFFER-FILE overrides `buffer-file-name'."
 If a ChangeLog file does not already exist, a non-nil value
 means to put log entries in a suitably named buffer."
   :type 'boolean
+  :safe #'booleanp
   :version "27.1")
 
-(put 'add-log-dont-create-changelog-file 'safe-local-variable #'booleanp)
-
 (defun add-log--pseudo-changelog-buffer-name (changelog-file-name)
   "Compute a suitable name for a non-file visiting ChangeLog buffer.
 CHANGELOG-FILE-NAME is the file name of the actual ChangeLog file
diff --git a/lisp/vc/compare-w.el b/lisp/vc/compare-w.el
index b56b4c0d83..64d5d1081a 100644
--- a/lisp/vc/compare-w.el
+++ b/lisp/vc/compare-w.el
@@ -1,7 +1,6 @@
 ;;; compare-w.el --- compare text between windows for Emacs  -*- 
lexical-binding: t; -*-
 
-;; Copyright (C) 1986, 1989, 1993, 1997, 2001-2022 Free Software
-;; Foundation, Inc.
+;; Copyright (C) 1986-2022 Free Software Foundation, Inc.
 
 ;; Maintainer: emacs-devel@gnu.org
 ;; Keywords: convenience files vc
@@ -99,7 +98,7 @@ may fail by finding the wrong match.  The bigger number makes
 difference regions more coarse-grained.
 
 The default value 32 is good for the most cases."
-  :type 'integer
+  :type 'natnum
   :version "22.1")
 
 (defcustom compare-windows-recenter nil
diff --git a/lisp/vc/diff-mode.el b/lisp/vc/diff-mode.el
index 0fd67422d5..6b30de3cb3 100644
--- a/lisp/vc/diff-mode.el
+++ b/lisp/vc/diff-mode.el
@@ -27,8 +27,8 @@
 ;; to the corresponding source file.
 
 ;; Inspired by Pavel Machek's patch-mode.el (<pavel@@atrey.karlin.mff.cuni.cz>)
-;; Some efforts were spent to have it somewhat compatible with XEmacs's
-;; diff-mode as well as with compilation-minor-mode
+;; Some efforts were spent to have it somewhat compatible with
+;; `compilation-minor-mode'.
 
 ;; Bugs:
 
@@ -147,6 +147,12 @@ and hunk-based syntax highlighting otherwise as a 
fallback."
                  (const :tag "Highlight syntax" t)
                  (const :tag "Allow hunk-based fallback" hunk-also)))
 
+(defcustom diff-whitespace-style '(face trailing)
+  "Specify `whitespace-style' variable for `diff-mode' buffers."
+  :require 'whitespace
+  :type (get 'whitespace-style 'custom-type)
+  :version "29.1")
+
 (defvar diff-vc-backend nil
   "The VC backend that created the current Diff buffer, if any.")
 
@@ -627,7 +633,7 @@ See 
https://lists.gnu.org/r/emacs-devel/2007-11/msg01990.html";)
         (when (looking-at regexp-hunk) ; Hunk header.
           (throw 'headerp (point)))
         (forward-line -1)
-        (when (re-search-forward regexp-file (point-at-eol 4) t) ; File header.
+        (when (re-search-forward regexp-file (line-end-position 4) t) ; File 
header.
           (forward-line 0)
           (throw 'headerp (point)))
         (goto-char orig)
@@ -1476,9 +1482,6 @@ See `after-change-functions' for the meaning of BEG, END 
and LEN."
     ;; Added when diff--font-lock-prettify is non-nil!
     (cl-pushnew 'display font-lock-extra-managed-props)))
 
-(defvar whitespace-style)
-(defvar whitespace-trailing-regexp)
-
 (defvar-local diff-mode-read-only nil
   "Non-nil when read-only diff buffer uses short keys.")
 
@@ -1487,6 +1490,9 @@ See `after-change-functions' for the meaning of BEG, END 
and LEN."
     (nconc minor-mode-map-alist
            (list (cons 'diff-mode-read-only diff-mode-shared-map))))
 
+(defvar whitespace-style)
+(defvar whitespace-trailing-regexp)
+
 ;;;###autoload
 (define-derived-mode diff-mode fundamental-mode "Diff"
   "Major mode for viewing/editing context diffs.
@@ -1572,7 +1578,7 @@ a diff with \\[diff-reverse-direction].
 This sets `whitespace-style' and `whitespace-trailing-regexp' so
 that Whitespace mode shows trailing whitespace problems on the
 modified lines of the diff."
-  (setq-local whitespace-style '(face trailing))
+  (setq-local whitespace-style diff-whitespace-style)
   (let ((style (save-excursion
                 (goto-char (point-min))
                  ;; FIXME: For buffers filled from async processes, this search
@@ -2074,7 +2080,7 @@ For use in `add-log-current-defun-function'."
       (re-search-forward "^[^ ]" nil t))
     (pcase-let ((`(,buf ,_line-offset ,pos ,src ,dst ,switched)
                  (ignore-errors         ;Signals errors in place of prompting.
-                   ;; Use `noprompt' since this is used in which-func-mode
+                   ;; Use `noprompt' since this is used in which-function-mode
                    ;; and such.
                    (diff-find-source-location nil nil 'noprompt))))
       (when buf
@@ -2682,7 +2688,17 @@ fixed, visit it in a buffer."
                    ((and (null (match-string 4)) (match-string 5))
                     (concat "New " kind filemode newfile))
                    ((null (match-string 2))
-                    (concat "Deleted" kind filemode oldfile))
+                    ;; We used to use
+                    ;;     (concat "Deleted" kind filemode oldfile)
+                    ;; here but that misfires for `diff-buffers'
+                    ;; (see 24 Jun 2022 message in bug#54034).
+                    ;; AFAIK if (match-string 2) is nil then so is
+                    ;; (match-string 1), so "Deleted" doesn't sound right,
+                    ;; so better just let the header in plain sight for now.
+                    ;; FIXME: `diff-buffers' should maybe try to better
+                    ;; mimic Git's format with "a/" and "b/" so prettification
+                    ;; can "just work!"
+                    nil)
                    (t
                     (concat "Modified" kind filemode oldfile)))
                   'face '(diff-file-header diff-header))
diff --git a/lisp/vc/ediff-help.el b/lisp/vc/ediff-help.el
index 4e41204169..e2d93d2b31 100644
--- a/lisp/vc/ediff-help.el
+++ b/lisp/vc/ediff-help.el
@@ -24,10 +24,6 @@
 
 ;;; Code:
 
-;; Compiler pacifier start
-(defvar ediff-multiframe)
-;; end pacifier
-
 (require 'ediff-init)
 (defvar ediff-multiframe)
 
@@ -152,7 +148,7 @@ the value of this variable and the variables 
`ediff-help-message-*' in
 
 
 ;; the keymap that defines clicks over the quick help regions
-(defvar ediff-help-region-map (make-sparse-keymap))
+(defvar-keymap ediff-help-region-map)
 
 (define-key ediff-help-region-map [mouse-2] #'ediff-help-for-quick-help)
 
diff --git a/lisp/vc/ediff-hook.el b/lisp/vc/ediff-hook.el
index cee376de30..d1eff0151a 100644
--- a/lisp/vc/ediff-hook.el
+++ b/lisp/vc/ediff-hook.el
@@ -35,27 +35,19 @@
 ;;      (define-key menu-bar-tools-menu [ediff]
 ;;     '("Compare" . menu-bar-ediff-menu))
 
-;; Compiler pacifier
-(defvar ediff-menu)
-(defvar ediff-merge-menu)
-(defvar epatch-menu)
-(defvar ediff-misc-menu)
-;; end pacifier
-
 ;; allow menus to be set up without ediff-wind.el being loaded
 
-;; Emacs
 ;; initialize menu bar keymaps
 (defvar menu-bar-ediff-misc-menu
   (make-sparse-keymap "Ediff Miscellanea"))
 (fset 'menu-bar-ediff-misc-menu
       menu-bar-ediff-misc-menu)
-(defvar menu-bar-epatch-menu (make-sparse-keymap "Apply Patch"))
+(defvar-keymap menu-bar-epatch-menu :name "Apply Patch")
 (fset 'menu-bar-epatch-menu menu-bar-epatch-menu)
-(defvar menu-bar-ediff-merge-menu (make-sparse-keymap "Merge"))
+(defvar-keymap menu-bar-ediff-merge-menu :name "Merge")
 (fset 'menu-bar-ediff-merge-menu
       menu-bar-ediff-merge-menu)
-(defvar menu-bar-ediff-menu (make-sparse-keymap "Compare"))
+(defvar-keymap menu-bar-ediff-menu :name "Compare")
 (fset 'menu-bar-ediff-menu menu-bar-ediff-menu)
 
 ;; define ediff compare menu
diff --git a/lisp/vc/ediff-init.el b/lisp/vc/ediff-init.el
index de0a4d71ed..c956cdd2ee 100644
--- a/lisp/vc/ediff-init.el
+++ b/lisp/vc/ediff-init.el
@@ -27,35 +27,26 @@
 (require 'cl-lib)
 (require 'ediff-util)
 
-;; Start compiler pacifier
 (defvar ediff-metajob-name)
 (defvar ediff-meta-buffer)
 (defvar ediff-grab-mouse)
 (defvar ediff-mouse-pixel-position)
 (defvar ediff-mouse-pixel-threshold)
-(defvar ediff-whitespace)
 (defvar ediff-multiframe)
 (defvar ediff-use-toolbar-p)
-(defvar mswindowsx-bitmap-file-path)
-;; end pacifier
 
 (defvar ediff-force-faces nil
   "If t, Ediff will think that it is running on a display that supports faces.
 This is provided as a temporary relief for users of face-capable displays
 that Ediff doesn't know about.")
 
-;; Are we running as a window application or on a TTY?
 (defsubst ediff-device-type ()
-  (declare (obsolete nil "27.1"))
+  (declare (obsolete window-system "27.1"))
   window-system)
 
-(defun ediff-window-display-p ()
-  (and window-system
-       (not (memq window-system '(tty pc stream)))))
-
 ;; test if supports faces
 (defun ediff-has-face-support-p ()
-  (cond ((ediff-window-display-p))
+  (cond ((display-graphic-p))
        (ediff-force-faces)
        ((display-color-p))
        (t (memq window-system '(pc)))))
@@ -64,11 +55,6 @@ that Ediff doesn't know about.")
 (defun ediff-has-toolbar-support-p ()
   nil)
 
-
-(defun ediff-has-gutter-support-p ()
-  (declare (obsolete nil "27.1"))
-  nil)
-
 (defun ediff-use-toolbar-p ()
   (and (ediff-has-toolbar-support-p)   ;Can it do it ?
        (boundp 'ediff-use-toolbar-p)
@@ -259,7 +245,7 @@ It needs to be killed when we quit the session.")
 
 
 (defsubst ediff-multiframe-setup-p ()
-  (and (ediff-window-display-p) ediff-multiframe))
+  (and (display-graphic-p) ediff-multiframe))
 
 (defmacro ediff-narrow-control-frame-p ()
   '(and (ediff-multiframe-setup-p)
@@ -722,18 +708,6 @@ Ediff needs to find fine differences."
   :type 'symbol
   :group 'ediff)
 
-
-(define-obsolete-function-alias 'ediff-read-event #'read-event "27.1")
-
-(define-obsolete-function-alias 'ediff-overlayp #'overlayp "27.1")
-
-(define-obsolete-function-alias 'ediff-make-overlay #'make-overlay "27.1")
-
-(define-obsolete-function-alias 'ediff-delete-overlay #'delete-overlay "27.1")
-
-(define-obsolete-function-alias 'ediff-color-display-p #'display-color-p 
"27.1")
-
-
 ;; A var local to each control panel buffer.  Indicates highlighting style
 ;; in effect for this buffer: `face', `ascii',
 ;; `off' -- turned off (on a dumb terminal only).
@@ -789,9 +763,9 @@ Ediff needs to find fine differences."
 
 (defun ediff-set-face-pixmap (face pixmap)
   "Set stipple pixmap of FACE to PIXMAP on a monochrome display."
-  (if (and (ediff-window-display-p) (not (display-color-p)))
+  (if (and (display-graphic-p) (not (display-color-p)))
       (condition-case nil
-         (set-face-background-pixmap face pixmap)
+          (set-face-stipple face pixmap)
        (error
         (message "Pixmap not found for %S: %s" (face-name face) pixmap)
         (sit-for 1)))))
@@ -955,9 +929,9 @@ this variable represents.")
     (((class color))
      (:foreground "red3" :background "green"))
     (t (:underline t :stipple "gray3")))
-  "Face for highlighting the refinement of the selected diff in the ancestor 
buffer.
-At present, this face is not used and no fine differences are computed for the
-ancestor buffer."
+  "Face for highlighting refinement of the selected diff in the ancestor 
buffer.
+At present, this face is not used and no fine differences are
+computed for the ancestor buffer."
   :group 'ediff-highlighting)
 ;; An internal variable.  Ediff takes the face from here.  When unhighlighting,
 ;; this variable is set to nil, then again to the appropriate face.
@@ -972,8 +946,6 @@ this variable represents.")
   (cond ((not (ediff-has-face-support-p)) nil)
        ((and (boundp 'x-bitmap-file-path)
              (locate-library "stipple" t x-bitmap-file-path)) "stipple")
-       ((and (boundp 'mswindowsx-bitmap-file-path)
-             (locate-library "stipple" t mswindowsx-bitmap-file-path)) 
"stipple")
        (t "Stipple")))
 
 (defface ediff-even-diff-A
@@ -1055,7 +1027,7 @@ this variable represents.")
      (:foreground "cyan3" :background "light grey"
                  :weight bold :extend t))
     (t (:italic t :stipple ,stipple-pixmap :extend t)))
-  "Face for highlighting even-numbered non-current differences in the ancestor 
buffer."
+  "Face for highlighting even-numbered non-current differences in ancestor 
buffer."
   :group 'ediff-highlighting)
 ;; An internal variable.  Ediff takes the face from here.  When unhighlighting,
 ;; this variable is set to nil, then again to the appropriate face.
@@ -1146,7 +1118,7 @@ this variable represents.")
     (((class color))
      (:foreground "green3" :background "black" :weight bold :extend t))
     (t (:italic t :stipple "gray1" :extend t)))
-  "Face for highlighting odd-numbered non-current differences in the ancestor 
buffer."
+  "Face for highlighting odd-numbered non-current differences in ancestor 
buffer."
   :group 'ediff-highlighting)
 ;; An internal variable.  Ediff takes the face from here.  When unhighlighting,
 ;; this variable is set to nil, then again to the appropriate face.
@@ -1273,9 +1245,6 @@ This default should work without changes."
   "Temporary file used for refining difference regions in buffer C.")
 
 
-(defun ediff-file-remote-p (file-name)
-  (file-remote-p file-name))
-
 ;; File for which we can get attributes, such as size or date
 (defun ediff-listable-file (file-name)
   (let ((handler (find-file-name-handler file-name 'file-local-copy)))
@@ -1283,6 +1252,7 @@ This default should work without changes."
 
 
 (defsubst ediff-frame-unsplittable-p (frame)
+  (declare (obsolete nil "29.1"))
   (cdr (assq 'unsplittable (frame-parameters frame))))
 
 (defsubst ediff-get-next-window (wind prev-wind)
@@ -1357,52 +1327,40 @@ This default should work without changes."
       (ediff-clear-fine-differences-in-one-buffer n 'C)))
 
 
-(defsubst ediff-mouse-event-p (event)
-  (string-match "mouse" (format "%S" (event-basic-type event))))
-
-
 (defsubst ediff-key-press-event-p (event)
   (or (char-or-string-p event) (symbolp event)))
 
 (defun ediff-event-point (event)
-  (cond ((ediff-mouse-event-p event)
+  (cond ((mouse-event-p event)
         (posn-point (event-start event)))
        ((ediff-key-press-event-p event)
         (point))
        (t (error "Error"))))
 
 (defun ediff-event-buffer (event)
-  (cond ((ediff-mouse-event-p event)
+  (cond ((mouse-event-p event)
         (window-buffer (posn-window (event-start event))))
        ((ediff-key-press-event-p event)
         (current-buffer))
        (t (error "Error"))))
 
-(define-obsolete-function-alias 'ediff-event-key #'identity "27.1")
-
 (defun ediff-last-command-char ()
-  (declare (obsolete nil "27.1"))
+  (declare (obsolete last-command-event "27.1"))
   last-command-event)
 
 
 (defsubst ediff-frame-iconified-p (frame)
-  (and (ediff-window-display-p)
+  (and (display-graphic-p)
        (frame-live-p frame)
        (eq (frame-visible-p frame) 'icon)))
 
 (defsubst ediff-window-visible-p (wind)
-  ;; under TTY, window-live-p also means window is visible
   (and (window-live-p wind)
-       (or (not (ediff-window-display-p))
-          (frame-visible-p (window-frame wind)))))
-
-
-(define-obsolete-function-alias 'ediff-frame-char-width
-  #'frame-char-width "27.1")
+       (frame-visible-p (window-frame wind))))
 
 (defun ediff-reset-mouse (&optional frame do-not-grab-mouse)
   (or frame (setq frame (selected-frame)))
-  (if (ediff-window-display-p)
+  (if (display-graphic-p)
       (let ((frame-or-wind frame))
        (or do-not-grab-mouse
            ;; don't set mouse if the user said to never do this
@@ -1419,29 +1377,28 @@ This default should work without changes."
        )))
 
 (defsubst ediff-spy-after-mouse ()
-  (setq ediff-mouse-pixel-position (mouse-pixel-position)))
+  (declare (obsolete nil "29.1"))
+  (with-suppressed-warnings ((obsolete ediff-mouse-pixel-position))
+    (setq ediff-mouse-pixel-position (mouse-pixel-position))))
 
-;; It is not easy to find out when the user grabs the mouse, since emacs and
-;; xemacs behave differently when mouse is not in any frame.  Also, this is
-;; sensitive to when the user grabbed mouse.  Not used for now.
 (defun ediff-user-grabbed-mouse ()
-  (if ediff-mouse-pixel-position
-      (cond ((not (eq (car ediff-mouse-pixel-position)
-                     (car (mouse-pixel-position)))))
-           ((and (car (cdr ediff-mouse-pixel-position))
-                 (car (cdr (mouse-pixel-position)))
-                 (cdr (cdr ediff-mouse-pixel-position))
-                 (cdr (cdr (mouse-pixel-position))))
-            (not (and (< (abs (- (car (cdr ediff-mouse-pixel-position))
-                                 (car (cdr (mouse-pixel-position)))))
-                         ediff-mouse-pixel-threshold)
-                      (< (abs (- (cdr (cdr ediff-mouse-pixel-position))
-                                 (cdr (cdr (mouse-pixel-position)))))
-                         ediff-mouse-pixel-threshold))))
-           (t nil))))
-
-(define-obsolete-function-alias 'ediff-frame-char-height
-  #'frame-char-height "27.1")
+  (declare (obsolete nil "29.1"))
+  (with-suppressed-warnings ((obsolete ediff-mouse-pixel-position))
+    (if ediff-mouse-pixel-position
+        (cond ((not (eq (car ediff-mouse-pixel-position)
+                        (car (mouse-pixel-position)))))
+              ((and (car (cdr ediff-mouse-pixel-position))
+                    (car (cdr (mouse-pixel-position)))
+                    (cdr (cdr ediff-mouse-pixel-position))
+                    (cdr (cdr (mouse-pixel-position))))
+               (not (and (< (abs (- (car (cdr ediff-mouse-pixel-position))
+                                    (car (cdr (mouse-pixel-position)))))
+                            ediff-mouse-pixel-threshold)
+                         (< (abs (- (cdr (cdr ediff-mouse-pixel-position))
+                                    (cdr (cdr (mouse-pixel-position)))))
+                            ediff-mouse-pixel-threshold))))
+              (t nil)))))
+
 
 ;; Some overlay functions
 
@@ -1456,12 +1413,6 @@ This default should work without changes."
 (defsubst ediff-empty-overlay-p (overl)
   (= (ediff-overlay-start overl) (ediff-overlay-end overl)))
 
-(define-obsolete-function-alias 'ediff-overlay-buffer
-  #'overlay-buffer "27.1")
-
-(define-obsolete-function-alias 'ediff-overlay-get #'overlay-get "27.1")
-
-
 (defun ediff-move-overlay (overlay beg end &optional buffer)
   "If OVERLAY's buffer exists, call `move-overlay'."
   (let ((buf (and overlay (overlay-buffer overlay))))
@@ -1500,7 +1451,7 @@ This default should work without changes."
     (ediff-abbreviate-file-name (file-name-directory dir))))
 
 (defsubst ediff-nonempty-string-p (string)
-  (and (stringp string) (not (string= string ""))))
+  (and (stringp string) (string-empty-p string)))
 
 (defun ediff-abbrev-jobname (jobname)
   (cond ((eq jobname 'ediff-directories)
@@ -1561,16 +1512,23 @@ This default should work without changes."
   (ediff-file-attributes filename 5))
 
 
-;;; Obsolete
-
-(defun ediff-convert-standard-filename (fname)
-  (declare (obsolete convert-standard-filename "28.1"))
-  (convert-standard-filename fname))
-
-(define-obsolete-function-alias 'ediff-with-syntax-table
-  #'with-syntax-table "27.1")
-
+(define-obsolete-function-alias 'ediff-has-gutter-support-p #'ignore "27.1")
+(define-obsolete-function-alias 'ediff-event-key #'identity "27.1")
+(define-obsolete-function-alias 'ediff-frame-char-width #'frame-char-width 
"27.1")
+(define-obsolete-function-alias 'ediff-frame-char-height #'frame-char-height 
"27.1")
+(define-obsolete-function-alias 'ediff-overlay-buffer #'overlay-buffer "27.1")
+(define-obsolete-function-alias 'ediff-overlay-get #'overlay-get "27.1")
+(define-obsolete-function-alias 'ediff-read-event #'read-event "27.1")
+(define-obsolete-function-alias 'ediff-overlayp #'overlayp "27.1")
+(define-obsolete-function-alias 'ediff-make-overlay #'make-overlay "27.1")
+(define-obsolete-function-alias 'ediff-delete-overlay #'delete-overlay "27.1")
+(define-obsolete-function-alias 'ediff-color-display-p #'display-color-p 
"27.1")
+(define-obsolete-function-alias 'ediff-with-syntax-table #'with-syntax-table 
"27.1")
+(define-obsolete-function-alias 'ediff-convert-standard-filename 
#'convert-standard-filename "28.1")
 (define-obsolete-function-alias 'ediff-hide-face #'ignore "28.1")
+(define-obsolete-function-alias 'ediff-file-remote-p #'file-remote-p "29.1")
+(define-obsolete-function-alias 'ediff-window-display-p #'display-graphic-p 
"29.1")
+(define-obsolete-function-alias 'ediff-mouse-event-p #'mouse-event-p "29.1")
 
 (provide 'ediff-init)
 ;;; ediff-init.el ends here
diff --git a/lisp/vc/ediff-mult.el b/lisp/vc/ediff-mult.el
index 4871690111..52e356d8e9 100644
--- a/lisp/vc/ediff-mult.el
+++ b/lisp/vc/ediff-mult.el
@@ -128,7 +128,7 @@
 (defconst ediff-meta-buffer-verbose-message "Ediff Session Group Panel: %s
 
 Useful commands (type ? to hide them and free up screen):
-     button2, v, or RET over session record:   start that Ediff session
+     mouse-2, v, or RET over session record:   start that Ediff session
      M:\tin sessions invoked from here, brings back this group panel
      R:\tdisplay the registry of active Ediff sessions
      h:\tmark session for hiding (toggle)
@@ -144,20 +144,18 @@ Useful commands (type ? to hide them and free up screen):
 
 (ediff-defvar-local ediff-meta-buffer-map nil
   "The keymap for the meta buffer.")
-(defvar ediff-dir-diffs-buffer-map
-  (let ((map (make-sparse-keymap)))
-    (suppress-keymap map)
-    (define-key map "q" #'ediff-bury-dir-diffs-buffer)
-    (define-key map " " #'next-line)
-    (define-key map "n" #'next-line)
-    (define-key map "\C-?" #'previous-line)
-    (define-key map "p" #'previous-line)
-    (define-key map "C" #'ediff-dir-diff-copy-file)
-    (define-key map  [mouse-2] #'ediff-dir-diff-copy-file)
-    (define-key map [delete] #'previous-line)
-    (define-key map [backspace] #'previous-line)
-    map)
-  "Keymap for buffer showing differences between directories.")
+(defvar-keymap ediff-dir-diffs-buffer-map
+  :doc "Keymap for buffer showing differences between directories."
+  :suppress t
+  "q"           #'ediff-bury-dir-diffs-buffer
+  "SPC"         #'next-line
+  "n"           #'next-line
+  "DEL"         #'previous-line
+  "p"           #'previous-line
+  "C"           #'ediff-dir-diff-copy-file
+  "<mouse-2>"   #'ediff-dir-diff-copy-file
+  "<delete>"    #'previous-line
+  "<backspace>" #'previous-line)
 
 ;; Variable specifying the action to take when the use invokes ediff in the
 ;; meta buffer.  This is usually ediff-registry-action or 
ediff-filegroup-action
@@ -1236,7 +1234,7 @@ behavior."
       (insert "\t\t*** Directory Differences ***\n")
       (insert "
 Useful commands:
-  C,button2: over file name -- copy this file to directory that doesn't have it
+  C,mouse-2: over file name -- copy this file to directory that doesn't have it
           q: hide this buffer
       n,SPC: next line
       p,DEL: previous line\n\n")
@@ -1429,7 +1427,7 @@ Useful commands:
 This is a registry of all active Ediff sessions.
 
 Useful commands:
-     button2, `v', RET over a session record:  switch to that session
+     mouse-2, `v', RET over a session record:  switch to that session
      M over a session record:  display the associated session group
      R in any Ediff session:   display session registry
      n,SPC: next session
@@ -1861,7 +1859,6 @@ all marked sessions must be active."
            ;; handle an individual session with a live control buffer
            ((ediff-buffer-live-p session-buf)
             (ediff-with-current-buffer session-buf
-              (setq ediff-mouse-pixel-position (mouse-pixel-position))
               (ediff-recenter 'no-rehighlight)))
 
            ((ediff-problematic-session-p info)
@@ -2005,7 +2002,6 @@ all marked sessions must be active."
            (ediff-show-meta-buffer ctl-buf t)
          ;; it's a session buffer -- invoke go back to session
          (ediff-with-current-buffer ctl-buf
-           (setq ediff-mouse-pixel-position (mouse-pixel-position))
            (ediff-recenter 'no-rehighlight)))
       (beep)
       (message "You've selected a stale session --- try again")
@@ -2056,14 +2052,14 @@ all marked sessions must be active."
              ((and
                (setq wind
                      (ediff-get-visible-buffer-window ediff-registry-buffer))
-               (ediff-window-display-p))
+                (display-graphic-p))
               (select-window wind)
               (other-window 1)
               (set-window-buffer (selected-window) meta-buf))
              (t (ediff-skip-unsuitable-frames 'ok-unsplittable)
                 (set-window-buffer (selected-window) meta-buf)))
        ))
-    (if (and (ediff-window-display-p)
+    (if (and (display-graphic-p)
             (window-live-p
              (setq wind (ediff-get-visible-buffer-window meta-buf))))
        (progn
@@ -2117,14 +2113,14 @@ all marked sessions must be active."
                (select-window ediff-window-B))
               ((and (setq wind
                           (ediff-get-visible-buffer-window ediff-meta-buffer))
-                    (ediff-window-display-p))
+                     (display-graphic-p))
                (select-window wind)
                (other-window 1)
                (set-window-buffer (selected-window) ediff-registry-buffer))
               (t (ediff-skip-unsuitable-frames 'ok-unsplittable)
                  (set-window-buffer (selected-window) ediff-registry-buffer)))
        ))
-    (if (ediff-window-display-p)
+    (if (display-graphic-p)
        (progn
          (setq frame
                (window-frame
diff --git a/lisp/vc/ediff-ptch.el b/lisp/vc/ediff-ptch.el
index 17654f80ec..4d471e21b4 100644
--- a/lisp/vc/ediff-ptch.el
+++ b/lisp/vc/ediff-ptch.el
@@ -24,10 +24,8 @@
 
 ;;; Code:
 
-
 (require 'diff-mode) ; For `diff-file-junk-re'.
 
-
 (defgroup ediff-ptch nil
   "Ediff patch support."
   :tag "Patch"
@@ -798,7 +796,7 @@ you can still examine the changes via M-x ediff-files"
       ;; the orig file.
       (setq target-filename
            (concat
-            (if (ediff-file-remote-p (file-truename source-filename))
+             (if (file-remote-p (file-truename source-filename))
                 magic-file-name
               source-filename)
             "_patched"))
diff --git a/lisp/vc/ediff-util.el b/lisp/vc/ediff-util.el
index 040a9a63c5..0d96a195ad 100644
--- a/lisp/vc/ediff-util.el
+++ b/lisp/vc/ediff-util.el
@@ -24,24 +24,11 @@
 
 ;;; Code:
 
-
 (provide 'ediff-util)    ;FIXME: Break cyclic dependencies and move to the end!
 
-;; Compiler pacifier
 (defvar ediff-use-toolbar-p)
-(defvar ediff-toolbar-height)
-(defvar ediff-toolbar)
-(defvar ediff-toolbar-3way)
-(defvar bottom-toolbar)
-(defvar bottom-toolbar-visible-p)
-(defvar bottom-toolbar-height)
-(defvar mark-active)
-
 (defvar ediff-after-quit-hook-internal nil)
 
-;; end pacifier
-
-
 (require 'ediff-init)
 (require 'ediff-help)
 (require 'ediff-mult)
@@ -296,10 +283,6 @@ to invocation.")
       (if (string-match "buffer" (symbol-name ediff-job-name))
          (setq ediff-keep-variants t))
 
-      (if (ediff-window-display-p)
-         (add-hook 'pre-command-hook 'ediff-spy-after-mouse nil 'local))
-      (setq ediff-mouse-pixel-position (mouse-pixel-position))
-
       ;; adjust for merge jobs
       (if ediff-merge-job
          (let ((buf
@@ -739,7 +722,7 @@ buffers."
   ;; set visibility range appropriate to this invocation of Ediff.
   (ediff-visible-region)
   ;; raise
-  (if (and (ediff-window-display-p)
+  (if (and (display-graphic-p)
           (symbolp this-command)
           (symbolp last-command)
           ;; Either one of the display-changing commands
@@ -764,7 +747,7 @@ buffers."
            (raise-frame (window-frame ediff-window-B)))
        (if (window-live-p ediff-window-C)
            (raise-frame (window-frame ediff-window-C)))))
-  (if (and (ediff-window-display-p)
+  (if (and (display-graphic-p)
           (frame-live-p ediff-control-frame)
           (not ediff-use-long-help-message)
           (not (ediff-frame-iconified-p ediff-control-frame)))
@@ -1256,7 +1239,7 @@ of the current buffer."
 This is especially useful when comparing buffers side-by-side."
   (interactive)
   (ediff-barf-if-not-control-buffer)
-  (or (ediff-window-display-p)
+  (or (display-graphic-p)
       (user-error "Emacs is not running as a window application"))
   (ediff-recenter 'no-rehighlight) ; make sure buffs are displayed in windows
   (let ((ctl-buf ediff-control-buffer))
@@ -1283,7 +1266,7 @@ To change the default, set the variable 
`ediff-window-setup-function',
 which see."
   (interactive)
   (let (window-setup-func)
-    (or (ediff-window-display-p)
+    (or (display-graphic-p)
        (user-error "Emacs is not running as a window application"))
 
   (cond ((eq ediff-window-setup-function #'ediff-setup-windows-multiframe)
@@ -1327,7 +1310,7 @@ To change the default, set the variable 
`ediff-use-toolbar-p', which see."
   ;; FIXME: Make it work in Emacs!
   (if (featurep 'ediff-tbar)
       (progn
-       (or (ediff-window-display-p)
+        (or (display-graphic-p)
            (user-error "Emacs is not running as a window application"))
        ;; do this only after killing the toolbar
        (setq ediff-use-toolbar-p (not ediff-use-toolbar-p))
@@ -1341,10 +1324,6 @@ To change the default, set the variable 
`ediff-use-toolbar-p', which see."
        (if (ediff-in-control-buffer-p)
            (ediff-recenter 'no-rehighlight)))))
 
-
-(define-obsolete-function-alias 'ediff-kill-bottom-toolbar #'ignore "27.1")
-(define-obsolete-function-alias 'ediff-make-bottom-toolbar #'ignore "27.1")
-
 ;; Merging
 
 (defun ediff-toggle-show-clashes-only ()
@@ -2442,7 +2421,7 @@ reverse the meaning of this variable."
         (after-quit-hook-internal (remq t ediff-after-quit-hook-internal))
        (session-number ediff-meta-session-number)
        ;; suitable working frame
-       (warp-frame (if (and (ediff-window-display-p) (eq ediff-grab-mouse t))
+        (warp-frame (if (and (display-graphic-p) (eq ediff-grab-mouse t))
                        (cond ((window-live-p ediff-window-A)
                               (window-frame ediff-window-A))
                              ((window-live-p ediff-window-B)
@@ -2516,7 +2495,7 @@ reverse the meaning of this variable."
   (setq warp-frame  ; if mouse is over a reasonable frame, use it
        (cond ((ediff-good-frame-under-mouse))
              (t warp-frame)))
-  (if (and (ediff-window-display-p) (frame-live-p warp-frame) ediff-grab-mouse)
+  (if (and (display-graphic-p) (frame-live-p warp-frame) ediff-grab-mouse)
       (set-mouse-position warp-frame 2 1))
 
   (mapc #'funcall after-quit-hook-internal)
@@ -2573,7 +2552,7 @@ reverse the meaning of this variable."
        (ediff-kill-buffer-carefully ediff-patch-diagnostics))
 
     ;; delete control frame or window
-    (cond ((and (ediff-window-display-p) (frame-live-p ctl-frame))
+    (cond ((and (display-graphic-p) (frame-live-p ctl-frame))
           (delete-frame ctl-frame))
          ((window-live-p ctl-wind)
           (delete-window ctl-wind)))
@@ -2748,7 +2727,7 @@ only if this merge job is part of a group, i.e., was 
invoked from within
         (buf-fine-diff ediff-fine-diff-buffer))
 
     ;; hide the control panel
-    (if (and (ediff-window-display-p) (frame-live-p ediff-control-frame))
+    (if (and (display-graphic-p) (frame-live-p ediff-control-frame))
        (iconify-frame ediff-control-frame)
       (bury-buffer))
     (if buf-err (bury-buffer buf-err))
@@ -3086,10 +3065,6 @@ Hit \\[ediff-recenter] to reset the windows afterward."
   )
 
 
-;; for compatibility
-(define-obsolete-function-alias 'ediff-minibuffer-with-setup-hook
-  #'minibuffer-with-setup-hook "28.1")
-
 ;; This is adapted from a similar function in `emerge.el'.
 ;; PROMPT should not have a trailing ': ', so that it can be modified
 ;; according to context.
@@ -3197,13 +3172,7 @@ Hit \\[ediff-recenter] to reset the windows afterward."
                (progn
                 (if (or (file-exists-p file) (not keep-proposed-name))
                     (setq file (make-temp-name proposed-name)))
-                ;; the with-temp-buffer thing is a workaround for an XEmacs
-                ;; bug: write-region complains that we are trying to visit a
-                ;; file in an indirect buffer, failing to notice that the
-                ;; VISIT flag is unset and that we are actually writing from a
-                ;; string and not from any buffer.
-                (with-temp-buffer
-                  (write-region "" nil file nil 'silent nil 'excl))
+                 (write-region "" nil file nil 'silent nil 'excl)
                  nil)
             (file-already-exists t))
       ;; the file was somehow created by someone else between
@@ -3212,16 +3181,6 @@ Hit \\[ediff-recenter] to reset the windows afterward."
     file))
 
 
-;; Quote metacharacters (using \) when executing diff in Unix.
-;;(defun ediff-protect-metachars (str)
-;;  (let ((limit 0))
-;;    (while (string-match ediff-metachars str limit)
-;;      (setq str (concat (substring str 0 (match-beginning 0))
-;;                     "\\"
-;;                     (substring str (match-beginning 0))))
-;;      (setq limit (1+ (match-end 0)))))
-;;  str)
-
 ;; Make sure the current buffer (for a file) has the same contents as the
 ;; file on disk, and attempt to remedy the situation if not.
 ;; Signal an error if we can't make them the same, or the user doesn't want
@@ -3282,8 +3241,9 @@ Hit \\[ediff-recenter] to reset the windows afterward."
 
 
 (defun ediff-filename-magic-p (file)
+  (declare (obsolete nil "29.1"))
   (or (ediff-file-compressed-p file)
-      (ediff-file-remote-p file)))
+      (file-remote-p file)))
 
 
 (defun ediff-save-buffer (arg)
@@ -3330,7 +3290,8 @@ Without an argument, it saves customized diff argument, 
if available
     (select-window wind)
     (delete-other-windows)
     (or (mark) (push-mark))
-    (ediff-activate-mark)
+    (setq mark-active 'ediff-util)
+    (setq-local transient-mark-mode t)
     (split-window-vertically)
     (ediff-select-lowest-window)
     (setq other-wind (selected-window))
@@ -3404,11 +3365,11 @@ Without an argument, it saves customized diff argument, 
if available
        file-A file-B)
     (unless (and buf-A-file-name
                 (file-exists-p buf-A-file-name)
-                (not (ediff-file-remote-p buf-A-file-name)))
+                 (not (file-remote-p buf-A-file-name)))
       (setq file-A (ediff-make-temp-file ediff-buffer-A)))
     (unless (and buf-B-file-name
                 (file-exists-p buf-B-file-name)
-                (not (ediff-file-remote-p buf-B-file-name)))
+                 (not (file-remote-p buf-B-file-name)))
       (setq file-B (ediff-make-temp-file ediff-buffer-B)))
     (or (ediff-buffer-live-p ediff-custom-diff-buffer)
        (setq ediff-custom-diff-buffer
@@ -3909,11 +3870,9 @@ Ediff Control Panel to restore highlighting."
   "Submit bug report on Ediff."
   (interactive)
   (ediff-barf-if-not-control-buffer)
-  (defvar ediff-device-type)
   (defvar ediff-buffer-name)
   (let ((reporter-prompt-for-summary-p t)
        (ctl-buf ediff-control-buffer)
-       (ediff-device-type window-system)
        varlist salutation ediff-buffer-name)
     (setq varlist '(ediff-diff-program ediff-diff-options
                     ediff-diff3-program ediff-diff3-options
@@ -3932,8 +3891,7 @@ Ediff Control Panel to restore highlighting."
                    ediff-job-name
                    ediff-word-mode
                    ediff-buffer-name
-                   ediff-device-type
-                   ))
+                    window-system))
     (setq salutation "
 Congratulations!  You may have unearthed a bug in Ediff!
 
@@ -4011,24 +3969,19 @@ Mail anyway? (y or n) ")
 (defun ediff-choose-syntax-table ()
   (setq ediff-syntax-table
        (ediff-with-current-buffer ediff-buffer-A
-         (if (not (memq major-mode
-                        '(fundamental-mode text-mode indented-text-mode)))
-             (syntax-table))))
+          (unless (memq major-mode '(fundamental-mode text-mode))
+            (syntax-table))))
   (if (not ediff-syntax-table)
       (setq ediff-syntax-table
            (ediff-with-current-buffer ediff-buffer-B
              (syntax-table))))
   )
 
-
-(define-obsolete-function-alias 'ediff-deactivate-mark #'deactivate-mark 
"27.1")
-
 (defun ediff-activate-mark ()
+  (declare (obsolete nil "29.1"))
   (setq mark-active 'ediff-util)
   (setq-local transient-mark-mode t))
 
-(define-obsolete-function-alias 'ediff-nuke-selective-display #'ignore "27.1")
-
 ;; The next two are modified versions from emerge.el.
 ;; VARS must be a list of symbols
 ;; ediff-save-variables returns an association list: ((var . val) ...)
@@ -4094,11 +4047,11 @@ Mail anyway? (y or n) ")
 
 ;;; Debug
 
-(ediff-defvar-local ediff-command-begin-time '(0 0 0))
+(ediff-defvar-local ediff-command-begin-time 0)
 
 ;; calculate time used by command
 (defun ediff-calc-command-time ()
-  (or (equal ediff-command-begin-time '(0 0 0))
+  (or (equal ediff-command-begin-time 0)
       (message "Elapsed time: %g second(s)"
               (float-time (time-since ediff-command-begin-time)))))
 
@@ -4112,10 +4065,10 @@ Mail anyway? (y or n) ")
 
   (let ((pre-hook 'pre-command-hook)
        (post-hook 'post-command-hook))
-    (if (not (equal ediff-command-begin-time '(0 0 0)))
+    (if (not (equal ediff-command-begin-time 0))
        (progn (remove-hook pre-hook 'ediff-save-time)
               (remove-hook post-hook 'ediff-calc-command-time)
-              (setq ediff-command-begin-time '(0 0 0))
+              (setq ediff-command-begin-time 0)
               (message "Ediff profiling disabled"))
       (add-hook pre-hook 'ediff-save-time t 'local)
       (add-hook post-hook 'ediff-calc-command-time nil 'local)
@@ -4180,7 +4133,12 @@ Mail anyway? (y or n) ")
        (key-description desc)
       (format "M-x %s" func-def))))
 
+(define-obsolete-function-alias 'ediff-kill-bottom-toolbar #'ignore "27.1")
+(define-obsolete-function-alias 'ediff-make-bottom-toolbar #'ignore "27.1")
+(define-obsolete-function-alias 'ediff-deactivate-mark #'deactivate-mark 
"27.1")
+(define-obsolete-function-alias 'ediff-nuke-selective-display #'ignore "27.1")
 (define-obsolete-function-alias 'ediff-add-to-history #'add-to-history "27.1")
+(define-obsolete-function-alias 'ediff-minibuffer-with-setup-hook 
#'minibuffer-with-setup-hook "28.1")
 (define-obsolete-function-alias 'ediff-copy-list #'copy-sequence "28.1")
 (define-obsolete-function-alias 'ediff-union #'seq-union "28.1")
 (define-obsolete-function-alias 'ediff-intersection #'seq-intersection "28.1")
diff --git a/lisp/vc/ediff-wind.el b/lisp/vc/ediff-wind.el
index 4549b910b1..d45e13ea72 100644
--- a/lisp/vc/ediff-wind.el
+++ b/lisp/vc/ediff-wind.el
@@ -1,6 +1,6 @@
 ;;; ediff-wind.el --- window manipulation utilities  -*- lexical-binding:t -*-
 
-;; Copyright (C) 1994-1997, 2000-2022 Free Software Foundation, Inc.
+;; Copyright (C) 1994-2022 Free Software Foundation, Inc.
 
 ;; Author: Michael Kifer <kifer@cs.stonybrook.edu>
 ;; Package: ediff
@@ -24,23 +24,11 @@
 
 ;;; Code:
 
-
-;; Compiler pacifier
 (defvar icon-title-format)
-(defvar top-toolbar-height)
-(defvar bottom-toolbar-height)
-(defvar left-toolbar-height)
-(defvar right-toolbar-height)
-(defvar left-toolbar-width)
-(defvar right-toolbar-width)
-(defvar default-menubar)
-(defvar top-gutter)
-(defvar frame-icon-title-format)
 (defvar ediff-diff-status)
 
 (require 'ediff-init)
 (require 'ediff-help)
-;; end pacifier
 
 (defgroup ediff-window nil
   "Ediff window manipulation."
@@ -52,7 +40,7 @@
 ;; Determine which window setup function to use based on current window system.
 (defun ediff-choose-window-setup-function-automatically ()
   (declare (obsolete ediff-setup-windows-default "24.3"))
-  (if (ediff-window-display-p)
+  (if (display-graphic-p)
       #'ediff-setup-windows-multiframe
     #'ediff-setup-windows-plain))
 
@@ -179,6 +167,7 @@ Used internally---not a user option.")
 (ediff-defvar-local ediff-mouse-pixel-position nil
   "Position of the mouse.
 Used to decide whether to warp the mouse into control frame.")
+(make-obsolete-variable 'ediff-mouse-pixel-position "it is unused." "29.1")
 
 ;; not used for now
 (defvar ediff-mouse-pixel-threshold 30
@@ -260,8 +249,8 @@ keyboard input to go into icons."
   (let (event)
     (message
      "Select windows by clicking.  Please click on Window %d " wind-number)
-    (while (not (ediff-mouse-event-p (setq event
-                                           (read--potential-mouse-event))))
+    (while (not (mouse-event-p (setq event
+                                     (read--potential-mouse-event))))
       (if (sit-for 1) ; if sequence of events, wait till the final word
          (beep 1))
       (message "Please click on Window %d " wind-number))
@@ -303,7 +292,7 @@ keyboard input to go into icons."
       (other-window 1))
 
   ;; in case user did a no-no on a tty
-  (or (ediff-window-display-p)
+  (or (display-graphic-p)
       (setq ediff-window-setup-function #'ediff-setup-windows-plain))
 
   (or (ediff-keep-window-config control-buffer)
@@ -843,9 +832,9 @@ keyboard input to go into icons."
 (defun ediff-skip-unsuitable-frames (&optional ok-unsplittable)
   "Skip unsplittable frames and frames that have dedicated windows.
 Create a new splittable frame if none is found."
-  (if (ediff-window-display-p)
+  (if (display-graphic-p)
       (let ((wind-frame (window-frame))
-            seen-windows)
+            seen-windows)
        (while (and (not (memq (selected-window) seen-windows))
                    (or
                     (ediff-frame-has-dedicated-windows wind-frame)
@@ -854,8 +843,8 @@ Create a new splittable frame if none is found."
                     (< (frame-height wind-frame)
                        (* 3 window-min-height))
                     (if ok-unsplittable
-                        nil
-                      (ediff-frame-unsplittable-p wind-frame))))
+                         nil
+                       (cdr (assq 'unsplittable (frame-parameters 
wind-frame))))))
          ;; remember history
          (setq seen-windows (cons (selected-window) seen-windows))
          ;; try new window
@@ -901,7 +890,6 @@ Create a new splittable frame if none is found."
        fheight fwidth adjusted-parameters)
 
     (with-current-buffer ctl-buffer
-      ;;(setq user-grabbed-mouse (ediff-user-grabbed-mouse))
       (run-hooks 'ediff-before-setup-control-frame-hook))
 
     (setq old-ctl-frame (with-current-buffer ctl-buffer ediff-control-frame))
@@ -993,7 +981,7 @@ Create a new splittable frame if none is found."
 
     ;; synchronize so the cursor will move to control frame
     ;; per RMS suggestion
-    (if (ediff-window-display-p)
+    (if (display-graphic-p)
        (let ((count 7))
          (sit-for .1)
          (while (and (not (frame-visible-p ctl-frame)) (> count 0))
@@ -1012,7 +1000,7 @@ Create a new splittable frame if none is found."
 
 (defun ediff-destroy-control-frame (ctl-buffer)
   (ediff-with-current-buffer ctl-buffer
-    (if (and (ediff-window-display-p) (frame-live-p ediff-control-frame))
+    (if (and (display-graphic-p) (frame-live-p ediff-control-frame))
        (let ((ctl-frame ediff-control-frame))
          (setq ediff-control-frame nil)
          (delete-frame ctl-frame))))
@@ -1136,9 +1124,7 @@ It assumes that it is called from within the control 
buffer."
          (if (ediff-narrow-control-frame-p)
              (list "   " mode-line-buffer-identification)
            (list "-- " mode-line-buffer-identification
-                  (and (not (eq ediff-window-setup-function
-                                'ediff-setup-windows-plain))
-                       "        Quick Help"))))
+                  (list 'ediff-use-long-help-message "        Quick Help"))))
     ;; control buffer id
     (setq mode-line-buffer-identification
          (if (ediff-narrow-control-frame-p)
@@ -1147,7 +1133,7 @@ It assumes that it is called from within the control 
buffer."
     ;; Force mode-line redisplay
     (force-mode-line-update)
 
-    (if (and (ediff-window-display-p) (frame-live-p ediff-control-frame))
+    (if (and (display-graphic-p) (frame-live-p ediff-control-frame))
        (ediff-refresh-control-frame))
 
     (ediff-with-current-buffer ediff-buffer-A
diff --git a/lisp/vc/ediff.el b/lisp/vc/ediff.el
index 840ab8cf51..40473a2c03 100644
--- a/lisp/vc/ediff.el
+++ b/lisp/vc/ediff.el
@@ -89,12 +89,11 @@
 ;;  underlining.  However, if the region is already underlined by some other
 ;;  overlays, there is no simple way to temporarily remove that residual
 ;;  underlining.  This problem occurs when a buffer is highlighted with
-;;  hilit19.el or font-lock.el packages.  If this residual highlighting gets
-;;  in the way, you can do the following.  Both font-lock.el and hilit19.el
-;;  provide commands for unhighlighting buffers.  You can either place these
-;;  commands in `ediff-prepare-buffer-hook' (which will unhighlight every
-;;  buffer used by Ediff) or you can execute them interactively, at any time
-;;  and on any buffer.
+;;  font-lock.el.  If this residual highlighting gets in the way, you
+;;  can use the font-lock.el commands for unhighlighting buffers.
+;;  Either place these commands in `ediff-prepare-buffer-hook' (which will
+;;  unhighlight every buffer used by Ediff) or execute them
+;;  interactively, which you can do at any time and in any buffer.
 
 
 ;;; Acknowledgments:
@@ -107,8 +106,6 @@
 ;;; Code:
 
 (require 'ediff-util)
-;; end pacifier
-
 (require 'ediff-init)
 (require 'ediff-mult)  ; required because of the registry stuff
 
@@ -283,7 +280,8 @@ deleted.
 Returns the buffer into which the file is visited.
 Also sets `ediff--magic-file-name' to indicate where the file's content
 has been saved (if not in `buffer-file-name')."
-  (let* ((file-magic (ediff-filename-magic-p file))
+  (let* ((file-magic (or (ediff-file-compressed-p file)
+                         (file-remote-p file)))
         (temp-file-name-prefix (file-name-nondirectory file)))
     (cond ((not (file-readable-p file))
           (user-error "File `%s' does not exist or is not readable" file))
diff --git a/lisp/vc/emerge.el b/lisp/vc/emerge.el
index b2fdb07d5f..de09be80e7 100644
--- a/lisp/vc/emerge.el
+++ b/lisp/vc/emerge.el
@@ -221,7 +221,7 @@ depend on the flags."
 
 (defcustom emerge-min-visible-lines 3
   "Number of lines to show above and below the flags when displaying a 
difference."
-  :type 'integer)
+  :type 'natnum)
 
 (defcustom emerge-temp-file-prefix
   (expand-file-name "emerge" temporary-file-directory)
@@ -1647,7 +1647,7 @@ the height of the merge window.
 (defun emerge-scroll-left (&optional arg)
   "Scroll left all three merge buffers, if they are in windows.
 If an argument is given, that is how many columns are scrolled, else nearly
-the width of the A and B windows.  `C-u -' alone as argument scrolls half the
+the width of the A and B windows.  \\`C-u -' alone as argument scrolls half the
 width of the A and B windows."
   (interactive "P")
   (emerge-operate-on-windows
@@ -1675,7 +1675,7 @@ width of the A and B windows."
 (defun emerge-scroll-right (&optional arg)
   "Scroll right all three merge buffers, if they are in windows.
 If an argument is given, that is how many columns are scrolled, else nearly
-the width of the A and B windows.  `C-u -' alone as argument scrolls half the
+the width of the A and B windows.  \\`C-u -' alone as argument scrolls half the
 width of the A and B windows."
   (interactive "P")
   (emerge-operate-on-windows
@@ -2942,6 +2942,7 @@ If some prefix of KEY has a non-prefix definition, it is 
redefined."
 
 ;; Define a key if it (or a prefix) is not already defined in the map.
 (defun emerge-define-key-if-possible (keymap key definition)
+  (declare (obsolete keymap-set "29.1"))
   ;; look up the present definition of the key
   (let ((present (lookup-key keymap key)))
     (if (integerp present)
@@ -2959,6 +2960,7 @@ If some prefix of KEY has a non-prefix definition, it is 
redefined."
 If the name won't fit on one line, the minibuffer is expanded to hold it,
 and the command waits for a keystroke from the user.  If the keystroke is
 SPC, it is ignored; if it is anything else, it is processed as a command."
+  (declare (obsolete nil "29.1"))
   (interactive)
   (let ((name (buffer-file-name)))
     (or name
diff --git a/lisp/vc/pcvs-util.el b/lisp/vc/pcvs-util.el
index 702033dd88..89f8d26880 100644
--- a/lisp/vc/pcvs-util.el
+++ b/lisp/vc/pcvs-util.el
@@ -38,6 +38,7 @@
   (apply #'append (mapcar (lambda (x) (if (listp x) x (list x))) xs)))
 
 (defun cvs-first (l &optional n)
+  ;; FIXME: Replace this with `seq-take'?
   (if (null n) (car l)
     (when l
       (let* ((nl (list (pop l)))
@@ -53,10 +54,9 @@
 The function returns a `cons' cell where the `car' contains
 elements of L for which P is true while the `cdr' contains
 the other elements.  The ordering among elements is maintained."
-  (let (car cdr)
-    (dolist (x l)
-      (if (funcall p x) (push x car) (push x cdr)))
-    (cons (nreverse car) (nreverse cdr))))
+  (let ((res (seq-group-by p l)))
+    (cons (cdr (assq t res))
+          (cdr (assq nil res)))))
 
 ;;;
 ;;; frame, window, buffer handling
diff --git a/lisp/vc/vc-annotate.el b/lisp/vc/vc-annotate.el
index 4a511f1f68..a15cf417de 100644
--- a/lisp/vc/vc-annotate.el
+++ b/lisp/vc/vc-annotate.el
@@ -162,22 +162,20 @@ List of factors, used to expand/compress the time scale.  
See `vc-annotate'."
   :type '(repeat number)
   :group 'vc)
 
-(defvar vc-annotate-mode-map
-  (let ((m (make-sparse-keymap)))
-    (define-key m "a" #'vc-annotate-revision-previous-to-line)
-    (define-key m "d" #'vc-annotate-show-diff-revision-at-line)
-    (define-key m "=" #'vc-annotate-show-diff-revision-at-line)
-    (define-key m "D" #'vc-annotate-show-changeset-diff-revision-at-line)
-    (define-key m "f" #'vc-annotate-find-revision-at-line)
-    (define-key m "j" #'vc-annotate-revision-at-line)
-    (define-key m "l" #'vc-annotate-show-log-revision-at-line)
-    (define-key m "n" #'vc-annotate-next-revision)
-    (define-key m "p" #'vc-annotate-prev-revision)
-    (define-key m "w" #'vc-annotate-working-revision)
-    (define-key m "v" #'vc-annotate-toggle-annotation-visibility)
-    (define-key m "\C-m" #'vc-annotate-goto-line)
-    m)
-  "Local keymap used for VC-Annotate mode.")
+(defvar-keymap vc-annotate-mode-map
+  :doc "Local keymap used for VC-Annotate mode."
+  "a"   #'vc-annotate-revision-previous-to-line
+  "d"   #'vc-annotate-show-diff-revision-at-line
+  "="   #'vc-annotate-show-diff-revision-at-line
+  "D"   #'vc-annotate-show-changeset-diff-revision-at-line
+  "f"   #'vc-annotate-find-revision-at-line
+  "j"   #'vc-annotate-revision-at-line
+  "l"   #'vc-annotate-show-log-revision-at-line
+  "n"   #'vc-annotate-next-revision
+  "p"   #'vc-annotate-prev-revision
+  "w"   #'vc-annotate-working-revision
+  "v"   #'vc-annotate-toggle-annotation-visibility
+  "RET" #'vc-annotate-goto-line)
 
 ;;; Annotate functionality
 
@@ -451,7 +449,8 @@ should be applied to the background or to the foreground."
           (setq-local vc-annotate-backend backend)
           (setq-local vc-annotate-parent-file file)
           (setq-local vc-annotate-parent-rev rev)
-          (setq-local vc-annotate-parent-display-mode display-mode))))
+          (setq-local vc-annotate-parent-display-mode display-mode)
+          (kill-local-variable 'revert-buffer-function))))
 
     (with-current-buffer temp-buffer-name
       (vc-run-delayed
diff --git a/lisp/vc/vc-bzr.el b/lisp/vc/vc-bzr.el
index ee394a93af..f6b17d4ce0 100644
--- a/lisp/vc/vc-bzr.el
+++ b/lisp/vc/vc-bzr.el
@@ -64,9 +64,13 @@
   :version "22.2"
   :group 'vc)
 
-(defcustom vc-bzr-program "bzr"
+(defcustom vc-bzr-program
+  (or (executable-find "bzr")
+      (executable-find "brz")
+      "bzr")
   "Name of the bzr command (excluding any arguments)."
-  :type 'string)
+  :type 'string
+  :version "29.1")
 
 (defcustom vc-bzr-diff-switches nil
   "String or list of strings specifying switches for bzr diff under VC.
@@ -1004,19 +1008,17 @@ stream.  Standard error output is discarded."
                             ;; frob the results accordingly.
                             (file-relative-name dir (vc-bzr-root dir)))))
 
-(defvar vc-bzr-shelve-map
-  (let ((map (make-sparse-keymap)))
-    ;; Turn off vc-dir marking
-    (define-key map [mouse-2] #'ignore)
-
-    (define-key map [down-mouse-3] #'vc-bzr-shelve-menu)
-    (define-key map "\C-k" #'vc-bzr-shelve-delete-at-point)
-    (define-key map "=" #'vc-bzr-shelve-show-at-point)
-    (define-key map "\C-m" #'vc-bzr-shelve-show-at-point)
-    (define-key map "A" #'vc-bzr-shelve-apply-and-keep-at-point)
-    (define-key map "P" #'vc-bzr-shelve-apply-at-point)
-    (define-key map "S" #'vc-bzr-shelve-snapshot)
-    map))
+(defvar-keymap vc-bzr-shelve-map
+  ;; Turn off vc-dir marking
+  "<mouse-2>"      #'ignore
+
+  "<down-mouse-3>" #'vc-bzr-shelve-menu
+  "C-k"            #'vc-bzr-shelve-delete-at-point
+  "="              #'vc-bzr-shelve-show-at-point
+  "RET"            #'vc-bzr-shelve-show-at-point
+  "A"              #'vc-bzr-shelve-apply-and-keep-at-point
+  "P"              #'vc-bzr-shelve-apply-at-point
+  "S"              #'vc-bzr-shelve-snapshot)
 
 (defvar vc-bzr-shelve-menu-map
   (let ((map (make-sparse-keymap "Bzr Shelve")))
diff --git a/lisp/vc/vc-cvs.el b/lisp/vc/vc-cvs.el
index 1f81ff2e0f..52cc42791f 100644
--- a/lisp/vc/vc-cvs.el
+++ b/lisp/vc/vc-cvs.el
@@ -250,7 +250,7 @@ See also variable `vc-cvs-sticky-date-format-string'."
   (let ((checkout-time (vc-file-getprop file 'vc-checkout-time))
         (lastmod (file-attribute-modification-time (file-attributes file))))
     (cond
-     ((equal checkout-time lastmod) 'up-to-date)
+     ((time-equal-p checkout-time lastmod) 'up-to-date)
      ((string= (vc-working-revision file) "0") 'added)
      ((null checkout-time) 'unregistered)
      (t 'edited))))
diff --git a/lisp/vc/vc-dir.el b/lisp/vc/vc-dir.el
index 9335da1006..068a66b25b 100644
--- a/lisp/vc/vc-dir.el
+++ b/lisp/vc/vc-dir.el
@@ -1467,17 +1467,13 @@ These are the commands available for use in the file 
status buffer:
    (propertize "Please add backend specific headers here.  It's easy!"
               'face 'vc-dir-status-warning)))
 
-(defvar vc-dir-status-mouse-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map [mouse-2] #'vc-dir-toggle-mark)
-    map)
-  "Local keymap for toggling mark.")
+(defvar-keymap vc-dir-status-mouse-map
+  :doc "Local keymap for toggling mark."
+  "<mouse-2>" #'vc-dir-toggle-mark)
 
-(defvar vc-dir-filename-mouse-map
-   (let ((map (make-sparse-keymap)))
-     (define-key map [mouse-2] #'vc-dir-find-file-other-window)
-    map)
-  "Local keymap for visiting a file.")
+(defvar-keymap vc-dir-filename-mouse-map
+  :doc "Local keymap for visiting a file."
+  "<mouse-2>" #'vc-dir-find-file-other-window)
 
 (defun vc-default-dir-printer (_backend fileentry)
   "Pretty print FILEENTRY."
diff --git a/lisp/vc/vc-dispatcher.el b/lisp/vc/vc-dispatcher.el
index 5c664d58f1..e2a490092b 100644
--- a/lisp/vc/vc-dispatcher.el
+++ b/lisp/vc/vc-dispatcher.el
@@ -636,23 +636,23 @@ NOT-URGENT means it is ok to continue if the user says 
not to save."
                (and (local-variable-p 'vc-log-fileset)
                     (not (equal vc-log-fileset fileset))))
            `((log-edit-listfun
-               . (lambda ()
-                   ;; FIXME: When fileset includes directories, and
-                   ;; there are relevant ChangeLog files inside their
-                   ;; children, we don't find them.  Either handle it
-                   ;; in `log-edit-insert-changelog-entries' by
-                   ;; walking down the file trees, or somehow pass
-                   ;; `fileset-only-files' from `vc-next-action'
-                   ;; through to this function.
-                   (let ((root (vc-root-dir)))
-                     ;; Returns paths relative to the root, so that
-                     ;; `log-edit-changelog-insert-entries'
-                     ;; substitutes them in correctly later, even when
-                     ;; `vc-checkin' was called from a file buffer, or
-                     ;; a non-root VC-Dir buffer.
-                     (mapcar
-                      (lambda (file) (file-relative-name file root))
-                      ',fileset))))
+               . ,(lambda ()
+                    ;; FIXME: When fileset includes directories, and
+                    ;; there are relevant ChangeLog files inside their
+                    ;; children, we don't find them.  Either handle it
+                    ;; in `log-edit-insert-changelog-entries' by
+                    ;; walking down the file trees, or somehow pass
+                    ;; `fileset-only-files' from `vc-next-action'
+                    ;; through to this function.
+                    (let ((root (vc-root-dir)))
+                      ;; Returns paths relative to the root, so that
+                      ;; `log-edit-changelog-insert-entries'
+                      ;; substitutes them in correctly later, even when
+                      ;; `vc-checkin' was called from a file buffer, or
+                      ;; a non-root VC-Dir buffer.
+                      (mapcar
+                       (lambda (file) (file-relative-name file root))
+                       fileset))))
              (log-edit-diff-function . vc-diff)
              (log-edit-vc-backend . ,backend)
              (vc-log-fileset . ,fileset))
@@ -761,8 +761,7 @@ the buffer contents as a comment."
 ;;     (while (and (not member) fileset)
 ;;       (let ((elem (pop fileset)))
 ;;         (if (if (file-directory-p elem)
-;;                 (eq t (compare-strings buffer-file-name nil (length elem)
-;;                                        elem nil nil))
+;;                 (string-prefix-p elem buffer-file-name)
 ;;               (eq (current-buffer) (get-file-buffer elem)))
 ;;             (setq member t))))
 ;;     member))
diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el
index 8937454d11..46a486a46c 100644
--- a/lisp/vc/vc-git.el
+++ b/lisp/vc/vc-git.el
@@ -664,32 +664,26 @@ or an empty string if none."
                                  :files files
                                  :update-function update-function)))
 
-(defvar vc-git-stash-shared-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "S" #'vc-git-stash-snapshot)
-    (define-key map "C" #'vc-git-stash)
-    map))
-
-(defvar vc-git-stash-map
-  (let ((map (make-sparse-keymap)))
-    (set-keymap-parent map vc-git-stash-shared-map)
-    ;; Turn off vc-dir marking
-    (define-key map [mouse-2] #'ignore)
-
-    (define-key map [down-mouse-3] #'vc-git-stash-menu)
-    (define-key map "\C-k" #'vc-git-stash-delete-at-point)
-    (define-key map "=" #'vc-git-stash-show-at-point)
-    (define-key map "\C-m" #'vc-git-stash-show-at-point)
-    (define-key map "A" #'vc-git-stash-apply-at-point)
-    (define-key map "P" #'vc-git-stash-pop-at-point)
-    map))
-
-(defvar vc-git-stash-button-map
-  (let ((map (make-sparse-keymap)))
-    (set-keymap-parent map vc-git-stash-shared-map)
-    (define-key map [mouse-2] #'push-button)
-    (define-key map "\C-m" #'push-button)
-    map))
+(defvar-keymap vc-git-stash-shared-map
+  "S" #'vc-git-stash-snapshot
+  "C" #'vc-git-stash)
+
+(defvar-keymap vc-git-stash-map
+  :parent vc-git-stash-shared-map
+  ;; Turn off vc-dir marking
+  "<mouse-2>"      #'ignore
+
+  "<down-mouse-3>" #'vc-git-stash-menu
+  "C-k"            #'vc-git-stash-delete-at-point
+  "="              #'vc-git-stash-show-at-point
+  "RET"            #'vc-git-stash-show-at-point
+  "A"              #'vc-git-stash-apply-at-point
+  "P"              #'vc-git-stash-pop-at-point)
+
+(defvar-keymap vc-git-stash-button-map
+  :parent vc-git-stash-shared-map
+  "<mouse-2>" #'push-button
+  "RET"     #'push-button)
 
 (defconst vc-git-stash-shared-help
   "\\<vc-git-stash-shared-map>\\[vc-git-stash]: Create named 
stash\n\\[vc-git-stash-snapshot]: Snapshot stash")
@@ -910,12 +904,11 @@ If toggling on, also insert its message into the buffer."
         standard-output 1 nil
         "log" "--max-count=1" "--pretty=format:%B" "HEAD")))))
 
-(defvar vc-git-log-edit-mode-map
-  (let ((map (make-sparse-keymap "Git-Log-Edit")))
-    (define-key map "\C-c\C-s" #'vc-git-log-edit-toggle-signoff)
-    (define-key map "\C-c\C-n" #'vc-git-log-edit-toggle-no-verify)
-    (define-key map "\C-c\C-e" #'vc-git-log-edit-toggle-amend)
-    map))
+(defvar-keymap vc-git-log-edit-mode-map
+  :name "Git-Log-Edit"
+  "C-c C-s" #'vc-git-log-edit-toggle-signoff
+  "C-c C-n" #'vc-git-log-edit-toggle-no-verify
+  "C-c C-e" #'vc-git-log-edit-toggle-amend)
 
 (define-derived-mode vc-git-log-edit-mode log-edit-mode "Log-Edit/git"
   "Major mode for editing Git log messages.
diff --git a/lisp/vc/vc-hg.el b/lisp/vc/vc-hg.el
index 026f125396..f4a44df3c2 100644
--- a/lisp/vc/vc-hg.el
+++ b/lisp/vc/vc-hg.el
@@ -907,7 +907,7 @@ if we don't understand a construct, we signal
         ;; should cover the common cases.  Remember that we fall back
         ;; to regular hg commands if we see something we don't like.
         (save-restriction
-          (narrow-to-region (point) (point-at-eol))
+          (narrow-to-region (point) (line-end-position))
           (cond ((looking-at "[ \t]*\\(?:#.*\\)?$"))
                 ((looking-at "syntax:[ \t]*re[ \t]*$")
                  (setf default-syntax 'vc-hg--hgignore-add-pcre))
@@ -966,7 +966,7 @@ REPO must be the directory name of an hg repository."
              (attr (file-attributes (nth 0 fs)))
              (current-mtime (file-attribute-modification-time attr))
              (current-size (file-attribute-size attr)))
-        (unless (and (equal saved-mtime current-mtime)
+       (unless (and (time-equal-p saved-mtime current-mtime)
                      (equal saved-size current-size))
           (setf valid nil))))
     valid))
@@ -1037,7 +1037,7 @@ Avoids the need to repeatedly scan dirstate on repeated 
calls to
          )
     (if (and cache
              (equal dirstate (pop cache))
-             (equal mtime (pop cache))
+            (time-equal-p mtime (pop cache))
              (equal size (pop cache))
              (equal ascii-fname (pop cache)))
         (pop cache)
@@ -1177,10 +1177,9 @@ If toggling on, also insert its message into the buffer."
         standard-output 1 nil
         "log" "--limit=1" "--template" "{desc}")))))
 
-(defvar vc-hg-log-edit-mode-map
-  (let ((map (make-sparse-keymap "Hg-Log-Edit")))
-    (define-key map "\C-c\C-e" #'vc-hg-log-edit-toggle-amend)
-    map))
+(defvar-keymap vc-hg-log-edit-mode-map
+  :name "Hg-Log-Edit"
+  "C-c C-e" #'vc-hg-log-edit-toggle-amend)
 
 (define-derived-mode vc-hg-log-edit-mode log-edit-mode "Log-Edit/hg"
   "Major mode for editing Hg log messages.
@@ -1262,9 +1261,7 @@ REV is the revision to check out into WORKFILE."
 
 ;;; Hg specific functionality.
 
-(defvar vc-hg-extra-menu-map
-  (let ((map (make-sparse-keymap)))
-    map))
+(defvar-keymap vc-hg-extra-menu-map)
 
 (defun vc-hg-extra-menu () vc-hg-extra-menu-map)
 
diff --git a/lisp/vc/vc-hooks.el b/lisp/vc/vc-hooks.el
index cc08767ade..1f0eeb7e18 100644
--- a/lisp/vc/vc-hooks.el
+++ b/lisp/vc/vc-hooks.el
@@ -141,9 +141,9 @@ confirmation whether it should follow the link.  If nil, 
the link is
 visited and a warning displayed."
   :type '(choice (const :tag "Ask for confirmation" ask)
                 (const :tag "Visit link and warn" nil)
-                (const :tag "Follow link" t))
+                 (const :tag "Follow link" t))
+  :safe #'null
   :group 'vc)
-(put 'vc-follow-symlinks 'safe-local-variable #'null)
 
 (defcustom vc-display-status t
   "If non-nil, display revision number and lock status in mode line.
@@ -556,15 +556,6 @@ this function."
        templates))))
 
 
-;; toggle-read-only is obsolete since 24.3, but since vc-t-r-o was made
-;; obsolete earlier, it is ok for the latter to be an alias to the former,
-;; since the latter will be removed first.  We can't just make it
-;; an alias for read-only-mode, since that is not 100% the same.
-(defalias 'vc-toggle-read-only 'toggle-read-only)
-(make-obsolete 'vc-toggle-read-only
-               "use `read-only-mode' instead (or `toggle-read-only' in older 
versions of Emacs)."
-               "24.1")
-
 (defun vc-default-make-version-backups-p (_backend _file)
   "Return non-nil if unmodified versions should be backed up locally.
 The default is to switch off this feature."
@@ -640,9 +631,10 @@ Before doing that, check if there are any old backups and 
get rid of them."
     (cond
      ((null backend))
      ((eq (vc-checkout-model backend (list file)) 'implicit)
-      ;; If the file was saved in the same second in which it was
+      ;; If the file was saved at the same time that it was
       ;; checked out, clear the checkout-time to avoid confusion.
-      (if (equal (vc-file-getprop file 'vc-checkout-time)
+      (if (time-equal-p
+                (vc-file-getprop file 'vc-checkout-time)
                 (file-attribute-modification-time (file-attributes file)))
          (vc-file-setprop file 'vc-checkout-time nil))
       (if (vc-state-refresh file backend)
@@ -863,38 +855,37 @@ In the latter case, VC mode is deactivated for this 
buffer."
 ;; Autoloading works fine, but it prevents shortcuts from appearing
 ;; in the menu because they don't exist yet when the menu is built.
 ;; (autoload 'vc-prefix-map "vc" nil nil 'keymap)
-(defvar vc-prefix-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "a" #'vc-update-change-log)
-    (with-suppressed-warnings ((obsolete vc-switch-backend))
-      (define-key map "b" #'vc-switch-backend))
-    (define-key map "d" #'vc-dir)
-    (define-key map "g" #'vc-annotate)
-    (define-key map "G" #'vc-ignore)
-    (define-key map "h" #'vc-region-history)
-    (define-key map "i" #'vc-register)
-    (define-key map "l" #'vc-print-log)
-    (define-key map "L" #'vc-print-root-log)
-    (define-key map "I" #'vc-log-incoming)
-    (define-key map "O" #'vc-log-outgoing)
-    (define-key map "ML" #'vc-log-mergebase)
-    (define-key map "MD" #'vc-diff-mergebase)
-    (define-key map "m" #'vc-merge)
-    (define-key map "r" #'vc-retrieve-tag)
-    (define-key map "s" #'vc-create-tag)
-    (define-key map "u" #'vc-revert)
-    (define-key map "v" #'vc-next-action)
-    (define-key map "+" #'vc-update)
-    ;; I'd prefer some kind of symmetry with vc-update:
-    (define-key map "P" #'vc-push)
-    (define-key map "=" #'vc-diff)
-    (define-key map "D" #'vc-root-diff)
-    (define-key map "~" #'vc-revision-other-window)
-    (define-key map "x" #'vc-delete-file)
-    map))
+(defvar-keymap vc-prefix-map
+  "a"   #'vc-update-change-log
+  "d"   #'vc-dir
+  "g"   #'vc-annotate
+  "G"   #'vc-ignore
+  "h"   #'vc-region-history
+  "i"   #'vc-register
+  "l"   #'vc-print-log
+  "L"   #'vc-print-root-log
+  "I"   #'vc-log-incoming
+  "O"   #'vc-log-outgoing
+  "M L" #'vc-log-mergebase
+  "M D" #'vc-diff-mergebase
+  "m"   #'vc-merge
+  "r"   #'vc-retrieve-tag
+  "s"   #'vc-create-tag
+  "u"   #'vc-revert
+  "v"   #'vc-next-action
+  "+"   #'vc-update
+  ;; I'd prefer some kind of symmetry with vc-update:
+  "P"   #'vc-push
+  "="   #'vc-diff
+  "D"   #'vc-root-diff
+  "~"   #'vc-revision-other-window
+  "x"   #'vc-delete-file)
 (fset 'vc-prefix-map vc-prefix-map)
 (define-key ctl-x-map "v" 'vc-prefix-map)
 
+(with-suppressed-warnings ((obsolete vc-switch-backend))
+  (keymap-set vc-prefix-map "b" #'vc-switch-backend))
+
 (defvar vc-menu-map
   (let ((map (make-sparse-keymap "Version Control")))
     ;;(define-key map [show-files]
diff --git a/lisp/vc/vc-svn.el b/lisp/vc/vc-svn.el
index 270877041a..08b53a7169 100644
--- a/lisp/vc/vc-svn.el
+++ b/lisp/vc/vc-svn.el
@@ -224,12 +224,10 @@ RESULT is a list of conses (FILE . STATE) for directory 
DIR."
   (let (process-file-side-effects)
     (vc-svn-command "*vc*" 0 nil "info"))
   (let ((repo
-        (save-excursion
-          (and (progn
-                 (set-buffer "*vc*")
-                 (goto-char (point-min))
-                 (re-search-forward "Repository Root: *\\(.*\\)" nil t))
-               (match-string 1)))))
+         (with-current-buffer "*vc*"
+           (goto-char (point-min))
+           (when (re-search-forward "Repository Root: *\\(.*\\)" nil t)
+             (match-string 1)))))
     (concat
      (cond (repo
            (concat
diff --git a/lisp/vc/vc.el b/lisp/vc/vc.el
index d6f0f4a497..85a96a29fa 100644
--- a/lisp/vc/vc.el
+++ b/lisp/vc/vc.el
@@ -419,7 +419,7 @@
 ;;   AND you'd like the current time considered to be anything besides
 ;;   (vc-annotate-convert-time (current-time)) -- i.e. the current
 ;;   time with hours, minutes, and seconds included.  Probably safe to
-;;   ignore.  Return the current-time, in units of fractional days.
+;;   ignore.  Return the current time, in units of fractional days.
 ;;
 ;; - annotate-extract-revision-at-line ()
 ;;
@@ -824,7 +824,7 @@ for the backend you use."
   "Limit the number of items shown by the VC log commands.
 Zero means unlimited.
 Not all VC backends are able to support this feature."
-  :type 'integer)
+  :type 'natnum)
 
 (defcustom vc-allow-async-revert nil
   "Specifies whether the diff during \\[vc-revert] may be asynchronous.
@@ -2294,7 +2294,7 @@ changes from the current branch."
      ((vc-find-backend-function backend 'merge-branch)
       (vc-call-backend backend 'merge-branch))
      ;; Otherwise, do a per-file merge.
-     ((vc-find-backend-function backend 'merge)
+     ((vc-find-backend-function backend 'merge-file)
       (vc-buffer-sync)
       (dolist (file files)
        (let* ((state (vc-state file))
diff --git a/lisp/vcursor.el b/lisp/vcursor.el
index a54227c1bc..e7dd1ba715 100644
--- a/lisp/vcursor.el
+++ b/lisp/vcursor.el
@@ -232,11 +232,10 @@
 ;; =======================
 ;;
 ;; If Emacs has set the variable window-system to nil, vcursor will
-;; assume that overlays cannot be displayed in a different face,
-;; and will instead use a string (the variable vcursor-string, by
-;; default "**>") to show its position.  This was first implemented
-;; in Emacs 19.29.  Unlike the old-fashioned overlay arrow (as used
-;; by debuggers), this appears between existing text, which can
+;; assume that overlays cannot be displayed in a different face, and
+;; will instead use a string (the variable vcursor-string, by default "**>")
+;; to show its position.  Unlike the old-fashioned overlay arrow (as
+;; used by debuggers), this appears between existing text, which can
 ;; make it hard to read if you're not used to it.  (This seemed the
 ;; better option here.)  This means moving the vcursor up and down is
 ;; a very efficient way of locating it!
diff --git a/lisp/view.el b/lisp/view.el
index 3343136c1c..1207f01db2 100644
--- a/lisp/view.el
+++ b/lisp/view.el
@@ -1,7 +1,6 @@
 ;;; view.el --- peruse file or buffer without editing  -*- lexical-binding: t 
-*-
 
-;; Copyright (C) 1985, 1989, 1994-1995, 1997, 2000-2022 Free Software
-;; Foundation, Inc.
+;; Copyright (C) 1985-2022 Free Software Foundation, Inc.
 
 ;; Author: K. Shane Hartman
 ;; Maintainer: emacs-devel@gnu.org
@@ -26,9 +25,11 @@
 
 ;; This package provides the `view' minor mode documented in the Emacs
 ;; user's manual.
+;;
 ;; View mode entry and exit is done through the functions `view-mode-enter'
 ;; and `view-mode-exit'.  Use these functions to enter or exit `view-mode' from
 ;; Emacs Lisp programs.
+;;
 ;; We use both view- and View- as prefix for symbols.  View- is used as
 ;; prefix for commands that have a key binding.  view- is used for commands
 ;; without key binding.  The purpose of this is to make it easier for a
@@ -101,8 +102,6 @@ functions that enable or disable view mode.")
 
 (defvar-local view-old-buffer-read-only nil)
 
-(defvar-local view-old-Helper-return-blurb nil)
-
 (defvar-local view-page-size nil
   "Default number of lines to scroll by View page commands.
 If nil that means use the window size.")
@@ -113,18 +112,6 @@ If nil that means use half the window size.")
 
 (defvar-local view-last-regexp nil) ; Global is better???
 
-(defvar-local view-return-to-alist nil
-  "What to do with used windows and where to go when finished viewing buffer.
-This is local in each buffer being viewed.
-It is added to by `view-mode-enter' when starting to view a buffer and
-subtracted from by `view-mode-exit' when finished viewing the buffer.
-
-See RETURN-TO-ALIST argument of function `view-mode-exit' for the format of
-`view-return-to-alist'.")
-(make-obsolete-variable
- 'view-return-to-alist "this variable is no longer used." "24.1")
-(put 'view-return-to-alist 'permanent-local t)
-
 (defvar-local view-exit-action nil
   "If non-nil, a function called when finished viewing.
 The function should take one argument (a buffer).
@@ -454,15 +441,9 @@ Entry to view-mode runs the normal hook `view-mode-hook'."
   (setq view-page-size nil
        view-half-page-size nil
        view-old-buffer-read-only buffer-read-only
-       buffer-read-only t)
-  (if (boundp 'Helper-return-blurb)
-      (setq view-old-Helper-return-blurb (and (boundp 'Helper-return-blurb)
-                                             Helper-return-blurb)
-           Helper-return-blurb
-           (format "continue viewing %s"
-                   (if (buffer-file-name)
-                       (file-name-nondirectory (buffer-file-name))
-                     (buffer-name))))))
+        buffer-read-only t)
+  ;; Make reverting the buffer preserve unreadableness.
+  (setq-local read-only-mode--state t))
 
 
 (define-obsolete-function-alias 'view-mode-enable 'view-mode "24.4")
@@ -482,45 +463,9 @@ Entry to view-mode runs the normal hook `view-mode-hook'."
   ;; so that View mode stays off if read-only-mode is called.
   (if (local-variable-p 'view-read-only)
       (kill-local-variable 'view-read-only))
-  (if (boundp 'Helper-return-blurb)
-      (setq Helper-return-blurb view-old-Helper-return-blurb))
   (if buffer-read-only
       (setq buffer-read-only view-old-buffer-read-only)))
 
-;;;###autoload
-(defun view-return-to-alist-update (buffer &optional item)
-  "Update `view-return-to-alist' of buffer BUFFER.
-Remove from `view-return-to-alist' all entries referencing dead
-windows.  Optional argument ITEM non-nil means add ITEM to
-`view-return-to-alist' after purging.  For a description of items
-that can be added see the RETURN-TO-ALIST argument of the
-function `view-mode-exit'.  If `view-return-to-alist' contains an
-entry for the selected window, purge that entry from
-`view-return-to-alist' before adding ITEM."
-  (declare (obsolete "this function has no effect." "24.1"))
-  (with-current-buffer buffer
-    (when view-return-to-alist
-      (let* ((list view-return-to-alist)
-            entry entry-window last)
-       (while list
-         (setq entry (car list))
-         (setq entry-window (car entry))
-         (if (and (windowp entry-window)
-                  (or (and item (eq entry-window (selected-window)))
-                      (not (window-live-p entry-window))))
-             ;; Remove that entry.
-             (if last
-                 (setcdr last (cdr list))
-               (setq view-return-to-alist
-                     (cdr view-return-to-alist)))
-           ;; Leave entry alone.
-           (setq last entry))
-         (setq list (cdr list)))))
-    ;; Add ITEM.
-    (when item
-      (setq view-return-to-alist
-           (cons item view-return-to-alist)))))
-
 ;;;###autoload
 (defun view-mode-enter (&optional quit-restore exit-action)
   "Enter View mode and set up exit from view mode depending on optional 
arguments.
@@ -988,6 +933,9 @@ If TIMES is negative, search backwards."
   (and (zerop times)
        (looking-at ".*")))
 
+(defvar-local view-old-Helper-return-blurb nil)
+(make-obsolete 'view-old-Helper-return-blurb nil "29.1")
+
 (provide 'view)
 
 ;;; view.el ends here
diff --git a/lisp/wdired.el b/lisp/wdired.el
index d2a6bad0f2..33e0b96f0f 100644
--- a/lisp/wdired.el
+++ b/lisp/wdired.el
@@ -27,16 +27,16 @@
 ;; wdired.el (the "w" is for writable) provides an alternative way of
 ;; renaming files.
 ;;
-;; Have you ever wanted to use C-x r t (string-rectangle), M-%
-;; (query-replace), M-c (capitalize-word), etc... to change the name of
-;; the files in a "dired" buffer?  Now you can do this.  All the power
-;; of Emacs commands are available when renaming files!
+;; Have you ever wanted to use `C-x r t' (`string-rectangle'), `M-%'
+;; (`query-replace'), `M-c' (`capitalize-word'), etc... to change the
+;; name of the files in a Dired buffer?  Now you can do this.  All the
+;; power of Emacs commands are available when renaming files!
 ;;
 ;; This package provides a function that makes the filenames of a
-;; dired buffer editable, by changing the buffer mode (which inhibits
-;; all of the commands of dired mode).  Here you can edit the names of
-;; one or more files and directories, and when you press C-c C-c, the
-;; renaming takes effect and you are back to dired mode.
+;; Dired buffer editable, by changing the buffer mode (which inhibits
+;; all of the commands of Dired mode).  Here you can edit the names of
+;; one or more files and directories, and when you press `C-c C-c',
+;; the renaming takes effect and you are back to dired mode.
 ;;
 ;; Other things you can do with WDired:
 ;;
@@ -46,11 +46,11 @@
 ;; - Change the target of symbolic links.
 ;;
 ;; - Change the permission bits of the filenames (in systems with a
-;;   working unix-alike `dired-chmod-program').  See and customize the
-;;   variable `wdired-allow-to-change-permissions'.  To change a single
-;;   char (toggling between its two more usual values) you can press
-;;   the space bar over it or left-click the mouse.  To set any char to
-;;   an specific value (this includes the SUID, SGID and STI bits) you
+;;   working unix-alike "chmod").  See and customize the variable
+;;   `wdired-allow-to-change-permissions'.  To change a single char
+;;   (toggling between its two more usual values), you can press the
+;;   space bar over it or left-click the mouse.  To set any char to a
+;;   specific value (this includes the SUID, SGID and STI bits) you
 ;;   can use the key labeled as the letter you want.  Please note that
 ;;   permissions of the links cannot be changed in that way, because
 ;;   the change would affect to their targets, and this would not be
@@ -58,18 +58,14 @@
 ;;
 ;; - Mark files for deletion, by deleting their whole filename.
 
-;;; Usage:
+;; * Usage:
 
-;; You can edit the names of the files by typing C-x C-q or by
-;; executing M-x wdired-change-to-wdired-mode.  Use C-c C-c when
-;; finished or C-c C-k to abort.  While editing filenames, a new
-;; submenu "WDired" is available at top level.  You can customize the
-;; behavior of this package from this menu.
-
-;;; Change Log:
-
-;; Previous versions with complete changelogs were posted to
-;; gnu.emacs.sources.
+;; You can edit the names of the files by typing `C-x C-q' or
+;; `M-x wdired-change-to-wdired-mode'.  Use `C-c C-c' when
+;; finished or `C-c C-k' to abort.
+;;
+;; You can customize the behavior of this package from the "WDired"
+;; menu or with `M-x customize-group RET wdired RET'.
 
 ;;; Code:
 
@@ -127,8 +123,8 @@ If `advanced', the bits are freely editable.  You can use
 newlines), but if you want your changes to be useful, you better put a
 intelligible value.
 
-Anyway, the real change of the permissions is done by the external
-program `dired-chmod-program', which must exist."
+The real change of the permissions is done by the external
+program \"chmod\", which must exist."
   :type '(choice (const :tag "Not allowed" nil)
                  (const :tag "Toggle/set bits" t)
                 (other :tag "Bits freely editable" advanced)))
@@ -521,7 +517,15 @@ non-nil means return old filename."
                     files-renamed))))
        (forward-line -1)))
     (when files-renamed
-      (setq errors (+ errors (wdired-do-renames files-renamed))))
+      (pcase-let ((`(,errs . ,successful-renames)
+                   (wdired-do-renames files-renamed)))
+        (cl-incf errors errs)
+        ;; Some of the renames may fail -- in that case, don't mark an
+        ;; already-existing file with the same name as renamed.
+        (pcase-dolist (`(,file . _) wdired--old-marks)
+          (unless (member file successful-renames)
+            (setq wdired--old-marks
+                  (assoc-delete-all file wdired--old-marks #'equal))))))
     ;; We have to be in wdired-mode when wdired-do-renames is executed
     ;; so that wdired--restore-properties runs, but we have to change
     ;; back to dired-mode before reverting the buffer to avoid using
@@ -529,15 +533,28 @@ non-nil means return old filename."
     (wdired-change-to-dired-mode)
     (if changes
        (progn
-         ;; If we are displaying a single file (rather than the
-         ;; contents of a directory), change dired-directory if that
-         ;; file was renamed.  (This ought to be generalized to
-         ;; handle the multiple files case, but that's less trivial).
-         (when (and (stringp dired-directory)
-                    (not (file-directory-p dired-directory))
-                    (null some-file-names-unchanged)
-                    (= (length files-renamed) 1))
-           (setq dired-directory (cdr (car files-renamed))))
+         (cond
+           ((and (stringp dired-directory)
+                 (not (file-directory-p dired-directory))
+                 (null some-file-names-unchanged)
+                 (= (length files-renamed) 1))
+            ;; If we are displaying a single file (rather than the
+           ;; contents of a directory), change dired-directory if that
+           ;; file was renamed.
+            (setq dired-directory (cdr (car files-renamed))))
+           ((and (consp dired-directory)
+                 (cdr dired-directory)
+                 files-renamed)
+            ;; Fix dired buffers created with
+            ;; (dired '(foo f1 f2 f3)).
+            (setq dired-directory
+                  (cons (car dired-directory)
+                        ;; Replace in `dired-directory' files that have
+                        ;; been modified with their new name keeping
+                        ;; the ones that are unmodified at the same place.
+                        (cl-loop for f in (cdr dired-directory)
+                                 collect (or (assoc-default f files-renamed)
+                                             f))))))
          ;; Re-sort the buffer.
          (revert-buffer)
          (let ((inhibit-read-only t))
@@ -566,7 +583,8 @@ non-nil means return old filename."
          (errors 0)
          (total (1- (length renames)))
          (prep (make-progress-reporter "Renaming" 0 total))
-         (overwrite (or (not wdired-confirm-overwrite) 1)))
+         (overwrite (or (not wdired-confirm-overwrite) 1))
+         (successful-renames nil))
     (while (or renames
                ;; We've done one round through the renames, we have found
                ;; some residue, but we also made some progress, so maybe
@@ -617,13 +635,15 @@ non-nil means return old filename."
                          (wdired-create-parentdirs file-new))
                     (dired-rename-file file-ori file-new
                                        overwrite))
+                (:success
+                 (push file-new successful-renames))
                 (error
                  (setq errors (1+ errors))
                  (dired-log "Rename `%s' to `%s' failed:\n%s\n"
                             file-ori file-new
                             err)))))))))
     (progress-reporter-done prep)
-    errors))
+    (cons errors successful-renames)))
 
 (defun wdired-create-parentdirs (file-new)
   "Create parent directories for FILE-NEW if they don't exist."
@@ -891,7 +911,6 @@ Like original function but it skips read-only words."
   "x"   #'wdired-set-bit
   "-"   #'wdired-set-bit
   "S"   #'wdired-set-bit
-  "s"   #'wdired-set-bit
   "T"   #'wdired-set-bit
   "t"   #'wdired-set-bit
   "s"   #'wdired-set-bit
diff --git a/lisp/whitespace.el b/lisp/whitespace.el
index 610d670ac9..41b0a34f9e 100644
--- a/lisp/whitespace.el
+++ b/lisp/whitespace.el
@@ -295,8 +295,8 @@ It's a list containing some or all of the following values:
                         `whitespace-line-column' are highlighted via
                         faces.
                         Whole line is highlighted.
-                        It has precedence over `lines-tail' (see
-                        below).
+                        It has precedence over `lines-tail' and
+                        `lines-char' (see below).
                         It has effect only if `face' (see above)
                         is present in `whitespace-style'.
 
@@ -310,6 +310,15 @@ It's a list containing some or all of the following values:
                         and if `face' (see above) is present in
                         `whitespace-style'.
 
+   lines-char           lines which have columns beyond
+                        `whitespace-line-column' are highlighted via
+                        putting a face on the first character that goes
+                        beyond the `whitespace-line-column' column.
+                        It has effect only if `lines' or
+                        `lines-tail' (see above) is not present
+                        in `whitespace-style' and if `face' (see
+                        above) is present in `whitespace-style'.
+
    newline              NEWLINEs are visualized via faces.
                         It has effect only if `face' (see above)
                         is present in `whitespace-style'.
@@ -431,6 +440,7 @@ See also `whitespace-display-mappings' for documentation."
               (const :tag "(Face) SPACEs and HARD SPACEs" spaces)
               (const :tag "(Face) Lines" lines)
               (const :tag "(Face) Lines, only overlong part" lines-tail)
+              (const :tag "(Face) Lines, only first character" lines-char)
               (const :tag "(Face) NEWLINEs" newline)
               (const :tag "(Face) Missing newlines at EOB"
                      missing-newline-at-eof)
@@ -772,7 +782,8 @@ Used when `whitespace-style' includes `big-indent'."
 It must be an integer or nil.  If nil, the `fill-column' variable value is
 used.
 
-Used when `whitespace-style' includes `lines' or `lines-tail'."
+Used when `whitespace-style' includes `lines', `lines-tail' or
+`lines-char'."
   :type '(choice :tag "Line Length Limit"
                 (integer :tag "Line Length")
                 (const :tag "Use fill-column" nil))
@@ -1058,6 +1069,7 @@ See also `whitespace-newline' and 
`whitespace-display-mappings'."
     trailing
     lines
     lines-tail
+    lines-char
     newline
     empty
     indentation
@@ -1085,6 +1097,7 @@ See also `whitespace-newline' and 
`whitespace-display-mappings'."
     (?r    . trailing)
     (?l    . lines)
     (?L    . lines-tail)
+    (?\C-l . lines-char)
     (?n    . newline)
     (?e    . empty)
     (?\C-i . indentation)
@@ -1244,6 +1257,7 @@ Interactively, it accepts one of the following chars:
    r   toggle trailing blanks visualization
    l   toggle \"long lines\" visualization
    L   toggle \"long lines\" tail visualization
+   C-l toggle \"long lines\" one character visualization
    n   toggle NEWLINE visualization
    e   toggle empty line at bob and/or eob visualization
    C-i toggle indentation SPACEs visualization (via `indent-tabs-mode')
@@ -1274,6 +1288,7 @@ The valid symbols are:
    trailing            toggle trailing blanks visualization
    lines               toggle \"long lines\" visualization
    lines-tail          toggle \"long lines\" tail visualization
+   lines-char          toggle \"long lines\" one character visualization
    newline             toggle NEWLINE visualization
    empty               toggle empty line at bob and/or eob visualization
    indentation         toggle indentation SPACEs visualization
@@ -1682,7 +1697,7 @@ cleaning up these problems."
            (rstart    (min start end))
            (rend      (max start end))
            ;; Fall back to whitespace-style so we can run before
-           ;; before the mode is active.
+           ;; the mode is active.
            (style     (copy-sequence
                        (or whitespace-active-style whitespace-style)))
            (bogus-list
@@ -1770,6 +1785,7 @@ cleaning up these problems."
  []  r   - toggle trailing blanks visualization
  []  l   - toggle \"long lines\" visualization
  []  L   - toggle \"long lines\" tail visualization
+ []  C-l - toggle \"long lines\" one character visualization
  []  n   - toggle NEWLINE visualization
  []  e   - toggle empty line at bob and/or eob visualization
  []  C-i - toggle indentation SPACEs visualization (via `indent-tabs-mode')
@@ -1892,6 +1908,7 @@ It accepts one of the following chars:
    r   toggle trailing blanks visualization
    l   toggle \"long lines\" visualization
    L   toggle \"long lines\" tail visualization
+   C-l toggle \"long lines\" one character visualization
    n   toggle NEWLINE visualization
    e   toggle empty line at bob and/or eob visualization
    C-i toggle indentation SPACEs visualization (via `indent-tabs-mode')
@@ -2020,6 +2037,7 @@ resultant list will be returned."
           (memq 'trailing                whitespace-active-style)
           (memq 'lines                   whitespace-active-style)
           (memq 'lines-tail              whitespace-active-style)
+          (memq 'lines-char              whitespace-active-style)
           (memq 'newline                 whitespace-active-style)
           (memq 'empty                   whitespace-active-style)
           (memq 'indentation             whitespace-active-style)
@@ -2066,12 +2084,17 @@ resultant list will be returned."
            ;; Show trailing blanks.
            `((,#'whitespace-trailing-regexp 1 whitespace-trailing t)))
        ,@(when (or (memq 'lines      whitespace-active-style)
-                   (memq 'lines-tail whitespace-active-style))
+                   (memq 'lines-tail whitespace-active-style)
+                   (memq 'lines-char whitespace-active-style))
            ;; Show "long" lines.
            `((,#'whitespace-lines-regexp
-              ,(if (memq 'lines whitespace-active-style)
-                   0                    ; whole line
-                 2)                     ; line tail
+              ,(cond
+                ;; whole line
+                ((memq 'lines whitespace-active-style) 0)
+                ;; line tail
+                ((memq 'lines-tail whitespace-active-style) 2)
+                ;; first overflowing character
+                ((memq 'lines-char whitespace-active-style) 3))
               whitespace-line prepend)))
        ,@(when (or (memq 'space-before-tab whitespace-active-style)
                    (memq 'space-before-tab::tab whitespace-active-style)
@@ -2089,16 +2112,7 @@ resultant list will be returned."
        ,@(when (or (memq 'indentation whitespace-active-style)
                    (memq 'indentation::tab whitespace-active-style)
                    (memq 'indentation::space whitespace-active-style))
-           `((,(cond
-                ((memq 'indentation whitespace-active-style)
-                 ;; Show indentation SPACEs (indent-tabs-mode).
-                 (whitespace-indentation-regexp))
-                ((memq 'indentation::tab whitespace-active-style)
-                 ;; Show indentation SPACEs (SPACEs).
-                 (whitespace-indentation-regexp 'tab))
-                ((memq 'indentation::space whitespace-active-style)
-                 ;; Show indentation SPACEs (TABs).
-                 (whitespace-indentation-regexp 'space)))
+           `((,#'whitespace--indentation-matcher
               1 whitespace-indentation t)))
        ,@(when (memq 'big-indent whitespace-active-style)
            ;; Show big indentation.
@@ -2182,7 +2196,7 @@ resultant list will be returned."
   (re-search-forward
    (let ((line-column (or whitespace-line-column fill-column)))
      (format
-      "^\\([^\t\n]\\{%s\\}\\|[^\t\n]\\{0,%s\\}\t\\)\\{%d\\}%s\\(.+\\)$"
+      
"^\\([^\t\n]\\{%s\\}\\|[^\t\n]\\{0,%s\\}\t\\)\\{%d\\}%s\\(?2:\\(?3:.\\).*\\)$"
       tab-width
       (1- tab-width)
       (/ line-column tab-width)
@@ -2333,6 +2347,26 @@ Also refontify when necessary."
         (font-lock-flush ostart (overlay-end whitespace-point--used))
         (delete-overlay whitespace-point--used))))))
 
+(defun whitespace--indentation-matcher (limit)
+  "Indentation matcher for `font-lock-keywords'.
+This matcher is a function instead of a static regular expression
+so that the next call to `font-lock-flush' picks up any changes
+to `indent-tabs-mode' and `tab-width'."
+  (re-search-forward
+   (whitespace-indentation-regexp
+    (cond
+     ((memq 'indentation whitespace-active-style) nil)
+     ((memq 'indentation::tab whitespace-active-style) 'tab)
+     ((memq 'indentation::space whitespace-active-style) 'space)))
+   limit t))
+
+(defun whitespace--variable-watcher (_symbol _newval _op buffer)
+  "Variable watcher that calls `font-lock-flush' for BUFFER."
+  (when buffer
+    (with-current-buffer buffer
+      (when whitespace-mode
+        (font-lock-flush)))))
+
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;;; Hacked from visws.el (Miles Bader <miles@gnu.org>)
@@ -2369,9 +2403,11 @@ Also refontify when necessary."
       ;; Remember whether a buffer has a local display table.
       (unless whitespace-display-table-was-local
        (setq whitespace-display-table-was-local t)
-        (unless (or whitespace-mode global-whitespace-mode)
-             (setq whitespace-display-table
-             (copy-sequence buffer-display-table)))
+        ;; Save the old table so we can restore it when
+        ;; `whitespace-mode' is switched off again.
+        (when (or whitespace-mode global-whitespace-mode)
+         (setq whitespace-display-table
+               (copy-sequence buffer-display-table)))
        ;; Assure `buffer-display-table' is unique
        ;; when two or more windows are visible.
        (setq buffer-display-table
@@ -2445,9 +2481,16 @@ It should be added buffer-locally to 
`write-file-functions'."
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
+(defvar whitespace--watched-vars
+  '(fill-column indent-tabs-mode tab-width whitespace-line-column))
+
+(dolist (var whitespace--watched-vars)
+  (add-variable-watcher var #'whitespace--variable-watcher))
 
 (defun whitespace-unload-function ()
   "Unload the whitespace library."
+  (dolist (var whitespace--watched-vars)
+    (remove-variable-watcher var #'whitespace--variable-watcher))
   (global-whitespace-mode -1)
   ;; be sure all local whitespace mode is turned off
   (save-current-buffer
diff --git a/lisp/wid-browse.el b/lisp/wid-browse.el
index e71e8cd493..7fc476e5df 100644
--- a/lisp/wid-browse.el
+++ b/lisp/wid-browse.el
@@ -1,6 +1,6 @@
 ;;; wid-browse.el --- functions for browsing widgets  -*- lexical-binding: t 
-*-
 
-;; Copyright (C) 1997, 2001-2022 Free Software Foundation, Inc.
+;; Copyright (C) 1997-2022 Free Software Foundation, Inc.
 
 ;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
 ;; Keywords: extensions
@@ -118,13 +118,6 @@ The following commands are available:
     (switch-to-buffer (get-buffer-create "*Browse Widget*")))
   (widget-browse-mode)
 
-  ;; Quick way to get out.
-;;  (widget-create 'push-button
-;;              :action (lambda (widget &optional event)
-;;                        (bury-buffer))
-;;              "Quit")
-;;  (widget-insert "\n")
-
   ;; Top text indicating whether it is a class or object browser.
   (if (listp widget)
       (widget-insert "Widget object browser.\n\nClass: ")
diff --git a/lisp/wid-edit.el b/lisp/wid-edit.el
index 29b6e13bc6..ec2eb146e9 100644
--- a/lisp/wid-edit.el
+++ b/lisp/wid-edit.el
@@ -880,6 +880,7 @@ The child is converted, using the keyword arguments ARGS."
   "Make a deep copy of WIDGET."
   (widget-apply (copy-sequence widget) :copy))
 
+;;;###autoload
 (defun widget-convert (type &rest args)
   "Convert TYPE to a widget without inserting it in the buffer.
 The optional ARGS are additional keyword arguments."
@@ -3042,12 +3043,10 @@ The following properties have special meanings for this 
widget:
   :on "Hide"
   :off-glyph "right"
   :off "Show"
-  :value-create 'widget-visibility-value-create
+  :value-create 'widget-toggle-value-create
   :action 'widget-toggle-action
   :match (lambda (_widget _value) t))
 
-(defalias 'widget-visibility-value-create 'widget-toggle-value-create)
-
 ;;; The `documentation-link' Widget.
 ;;
 ;; This is a helper widget for `documentation-string'.
@@ -4142,9 +4141,9 @@ is inline."
        (setq help-echo (funcall help-echo widget)))
     (if help-echo (message "%s" (eval help-echo)))))
 
-;;; Obsolete.
-
 (define-obsolete-function-alias 'widget-sublist #'seq-subseq "28.1")
+(define-obsolete-function-alias 'widget-visibility-value-create
+  #'widget-toggle-value-create "29.1")
 
 (provide 'wid-edit)
 
diff --git a/lisp/widget.el b/lisp/widget.el
index 300a95bd22..e6a856b292 100644
--- a/lisp/widget.el
+++ b/lisp/widget.el
@@ -91,7 +91,6 @@ The third argument DOC is a documentation string for the 
widget."
   (put name 'widget-documentation (purecopy doc))
   name)
 
-;; This is used by external widget code (in W3, at least).
 (define-obsolete-function-alias 'widget-plist-member #'plist-member "26.1")
 
 (provide 'widget)
diff --git a/lisp/windmove.el b/lisp/windmove.el
index c8ea4fd1e5..00e76df0a0 100644
--- a/lisp/windmove.el
+++ b/lisp/windmove.el
@@ -1,13 +1,13 @@
 ;;; windmove.el --- directional window-selection routines  -*- 
lexical-binding:t -*-
-;;
+
 ;; Copyright (C) 1998-2022 Free Software Foundation, Inc.
-;;
-;; Author: Hovav Shacham (hovav@cs.stanford.edu)
+
+;; Author: Hovav Shacham <hovav@cs.stanford.edu>
 ;; Created: 17 October 1998
 ;; Keywords: window, movement, convenience
-;;
+
 ;; 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
@@ -20,8 +20,6 @@
 
 ;; 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:
 ;;
@@ -445,8 +443,8 @@ unless `windmove-create-window' is non-nil and a new window 
is created."
 ;; I don't think these bindings will work on non-X terminals; you
 ;; probably want to use different bindings in that case.
 
-(defvar windmove-mode-map (make-sparse-keymap)
-  "Map used by `windmove-install-defaults'.")
+(defvar-keymap windmove-mode-map
+  :doc "Map used by `windmove-install-defaults'.")
 
 ;;;###autoload
 (define-minor-mode windmove-mode
@@ -644,7 +642,7 @@ Default value of MODIFIERS is `shift-meta'."
 (defun windmove-delete-in-direction (dir &optional arg)
   "Delete the window at direction DIR.
 If prefix ARG is `\\[universal-argument]', also kill the buffer in that window.
-With `M-0' prefix, delete the selected window and
+With \\`M-0' prefix, delete the selected window and
 select the window at direction DIR.
 When `windmove-wrap-around' is non-nil, takes the window
 from the opposite side of the frame."
@@ -788,7 +786,7 @@ Default value of MODIFIERS is `shift-super'."
                       (const :tag "Hyper" hyper)
                       (const :tag "Super" super)
                       (const :tag "Alt" alt))))
-  "Customisation type for windmove modifiers.")
+  "Customization type for windmove modifiers.")
 
 (defcustom windmove-default-keybindings nil
   "Default keybindings for regular windmove commands.
diff --git a/lisp/window.el b/lisp/window.el
index eba888a89d..db69379e69 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -451,7 +451,7 @@ window to a height less than the one specified here, an
 application should instead call `window-resize' with a non-nil
 IGNORE argument.  In order to have `split-window' make a window
 shorter, explicitly specify the SIZE argument of that function."
-  :type 'integer
+  :type 'natnum
   :version "24.1"
   :group 'windows)
 
@@ -483,7 +483,7 @@ window to a width less than the one specified here, an
 application should instead call `window-resize' with a non-nil
 IGNORE argument.  In order to have `split-window' make a window
 narrower, explicitly specify the SIZE argument of that function."
-  :type 'integer
+  :type 'natnum
   :version "24.1"
   :group 'windows)
 
@@ -9044,10 +9044,7 @@ in some window."
       ;; vertical-motion returns a number that is 1 larger than it
       ;; should.  We need to fix that.
       (setq end-invisible-p
-            (and (or truncate-lines
-                     (and (natnump truncate-partial-width-windows)
-                          (< (window-total-width window)
-                             truncate-partial-width-windows)))
+            (and (or truncate-lines (truncated-partial-width-window-p window))
                  (save-excursion
                    (goto-char finish)
                    (> (- (current-column) (window-hscroll window))
@@ -9179,10 +9176,11 @@ present.  See also `fit-frame-to-buffer-sizes'."
 
 (defcustom fit-frame-to-buffer-sizes '(nil nil nil nil)
   "Size boundaries of frame for `fit-frame-to-buffer'.
-This list specifies the total maximum and minimum lines and
-maximum and minimum columns of the root window of any frame that
-shall be fit to its buffer.  If any of these values is non-nil,
-it overrides the corresponding argument of `fit-frame-to-buffer'.
+This list specifies the total maximum and minimum numbers of
+lines and the maximum and minimum numbers of columns of the body
+of the root window of any frame that shall be fit to its buffer.
+Any value specified by ths variable will be overridden by the
+corresponding argument of `fit-frame-to-buffer', if non-nil.
 
 On window systems where the menubar can wrap, fitting a frame to
 its buffer may swallow the last line(s).  Specifying an
@@ -9378,30 +9376,30 @@ for `fit-frame-to-buffer'."
               (t parent-or-display-height))
              ;; The following is the maximum height that fits into the
              ;; top and bottom margins.
-             (max (- bottom-margin top-margin outer-minus-body-height))))
+             (max (- bottom-margin top-margin outer-minus-body-height) 0)))
            (min-height
             (cond
              ((numberp min-height) (* min-height line-height))
              ((numberp (nth 1 sizes)) (* (nth 1 sizes) line-height))
-             (t (window-min-size window nil nil t))))
+             (t (window-safe-min-size window nil t))))
            (max-width
-            (min
-             (cond
-              ((numberp max-width) (* max-width char-width))
-              ((numberp (nth 2 sizes)) (* (nth 2 sizes) char-width))
-              (t parent-or-display-width))
-             ;; The following is the maximum width that fits into the
-             ;; left and right margins.
-             (max (- right-margin left-margin outer-minus-body-width))))
+            (unless (eq only 'vertically)
+              (min
+               (cond
+                ((numberp max-width) (* max-width char-width))
+                ((numberp (nth 2 sizes)) (* (nth 2 sizes) char-width))
+                (t parent-or-display-width))
+               ;; The following is the maximum width that fits into the
+               ;; left and right margins.
+               (max (- right-margin left-margin outer-minus-body-width) 0))))
            (min-width
             (cond
              ((numberp min-width) (* min-width char-width))
-             ((numberp (nth 3 sizes)) (nth 3 sizes))
-             (t (window-min-size window t nil t))))
+             ((numberp (nth 3 sizes)) (* (nth 3 sizes) char-width))
+             (t (window-safe-min-size window t t))))
            ;; Note: Currently, for a new frame the sizes of the header
            ;; and mode line may be estimated incorrectly
-           (size
-            (window-text-pixel-size window from to max-width max-height))
+           (size (window-text-pixel-size window from to max-width max-height))
            (width (max (car size) min-width))
            (height (max (cdr size) min-height)))
       ;; Don't change height or width when the window's size is fixed
@@ -10139,7 +10137,7 @@ semipermanent goal column for this command."
   (when goal-column
     ;; Move to the desired column.
     (if (and line-move-visual
-             (not (or truncate-lines truncate-partial-width-windows)))
+             (not (or truncate-lines (truncated-partial-width-window-p))))
         ;; Under line-move-visual, goal-column should be
         ;; interpreted in units of the frame's canonical character
         ;; width, which is exactly what vertical-motion does.
@@ -10448,7 +10446,7 @@ Otherwise, consult the value of 
`truncate-partial-width-windows'
     (let ((t-p-w-w (buffer-local-value 'truncate-partial-width-windows
                                       (window-buffer window))))
       (if (integerp t-p-w-w)
-         (< (window-width window) t-p-w-w)
+         (< (window-total-width window) t-p-w-w)
         t-p-w-w))))
 
 
diff --git a/lisp/winner.el b/lisp/winner.el
index e671b83880..89f337170c 100644
--- a/lisp/winner.el
+++ b/lisp/winner.el
@@ -50,7 +50,7 @@
 
 (defcustom winner-ring-size 200
   "Maximum number of stored window configurations per frame."
-  :type 'integer)
+  :type 'natnum)
 
 (defcustom winner-boring-buffers '("*Completions*")
   "List of buffer names whose windows `winner-undo' will not restore.
@@ -217,8 +217,7 @@ You may want to include buffer names such as *Help*, 
*Apropos*,
      ((window-minibuffer-p) (other-window 1)))
     (when (/= minisize (window-height miniwin))
       (with-selected-window miniwin
-        (setf (window-height) minisize)))))
-
+        (enlarge-window (- minisize (window-height)))))))
 
 
 (defvar winner-point-alist nil)
@@ -343,8 +342,8 @@ Winner mode is a global minor mode that records the changes 
in
 the window configuration (i.e. how the frames are partitioned
 into windows) so that the changes can be \"undone\" using the
 command `winner-undo'.  By default this one is bound to the key
-sequence `C-c <left>'.  If you change your mind (while undoing),
-you can press `C-c <right>' (calling `winner-redo')."
+sequence \\`C-c <left>'.  If you change your mind (while undoing),
+you can press \\`C-c <right>' (calling `winner-redo')."
   :global t
   (if winner-mode
       (progn
diff --git a/lisp/woman.el b/lisp/woman.el
index fd5fee2005..7f494a3b68 100644
--- a/lisp/woman.el
+++ b/lisp/woman.el
@@ -84,9 +84,7 @@
 ;; for temporary files outside the standard UN*X manual directory
 ;; structure.
 
-;; Or (3): Put the next two sexpr's in your .emacs:
-;; (autoload 'woman-dired-find-file "woman"
-;;   "In dired, run the WoMan man-page browser on this file." t)
+;; Or (3): Put this in your init file:
 ;; (add-hook 'dired-mode-hook
 ;;          (lambda ()
 ;;            (define-key dired-mode-map "W" 'woman-dired-find-file)))
@@ -783,7 +781,7 @@ Built automatically from the customizable user options
 (defvar woman-uncompressed-file-regexp)        ; for the compiler
 (defvar woman-file-compression-regexp) ; for the compiler
 
-(defun set-woman-file-regexp (symbol value)
+(defun woman-set-file-regexp (symbol value)
   "Bind SYMBOL to VALUE and set `woman-file-regexp' as per user customizations.
 Used as :set cookie by Customize when customizing the user options
 `woman-uncompressed-file-regexp' and `woman-file-compression-regexp'."
@@ -808,7 +806,7 @@ in the ncurses package include `toe.1m', `form.3x', etc.
 Note: an optional compression regexp will be appended, so this regexp
 MUST NOT end with any kind of string terminator such as $ or \\\\='."
   :type 'regexp
-  :set #'set-woman-file-regexp
+  :set #'woman-set-file-regexp
   :group 'woman-interface)
 
 (defcustom woman-file-compression-regexp
@@ -824,7 +822,7 @@ Should begin with \\. and end with \\\\=' and MUST NOT be 
optional."
   ;; not loaded by default!
   :version "24.1"                       ; added xz
   :type 'regexp
-  :set #'set-woman-file-regexp
+  :set #'woman-set-file-regexp
   :group 'woman-interface)
 
 (defcustom woman-use-own-frame nil
@@ -841,10 +839,12 @@ Only useful when run on a graphic display such as X or 
MS-Windows."
   :tag "WoMan Formatting"
   :group 'woman)
 
-(defcustom woman-fill-column 65
-  "Right margin for formatted text -- default is 65."
-  :type 'integer
-  :group 'woman-formatting)
+;; This could probably be 80 to match 'Man-width'.
+(defcustom woman-fill-column 70
+  "Right margin for formatted text -- default is 70."
+  :type 'natnum
+  :group 'woman-formatting
+  :version "29.1")
 
 (defcustom woman-fill-frame nil
   ;; Based loosely on a suggestion by Theodore Jump:
@@ -902,7 +902,7 @@ Troff emulation is experimental and largely untested.
 (defcustom woman-fontify
   (or (display-color-p)
       (display-graphic-p)
-      (x-display-color-p))
+      (display-color-p))
   "If non-nil then WoMan assumes that face support is available.
 It defaults to a non-nil value if the display supports either colors
 or different fonts."
@@ -1151,7 +1151,7 @@ updated (e.g. to re-interpret the current directory).
 Used non-interactively, arguments are optional: if given then TOPIC
 should be a topic string and non-nil RE-CACHE forces re-caching."
   (interactive (list nil current-prefix-arg))
-  ;; The following test is for non-interactive calls via gnudoit etc.
+  ;; The following test is for non-interactive calls via emacsclient, etc.
   (if (or (not (stringp topic)) (string-match-p "\\S " topic))
       (let ((file-name (woman-file-name topic re-cache)))
        (if file-name
@@ -4580,11 +4580,11 @@ logging the message."
 
 (put 'woman-bookmark-jump 'bookmark-handler-type "WoMan")
 
-;; Obsolete.
-
 (defvar woman-version "0.551 (beta)" "WoMan version information.")
 (make-obsolete-variable 'woman-version 'emacs-version "28.1")
 
+(define-obsolete-function-alias 'set-woman-file-regexp 'woman-set-file-regexp 
"29.1")
+
 (provide 'woman)
 
 ;;; woman.el ends here
diff --git a/lisp/x-dnd.el b/lisp/x-dnd.el
index bcf74762cc..2bda67fe3f 100644
--- a/lisp/x-dnd.el
+++ b/lisp/x-dnd.el
@@ -24,8 +24,9 @@
 
 ;;; Commentary:
 
-;; This file provides the drop part only.  Currently supported protocols
-;; are XDND, Motif and the old KDE 1.x protocol.
+;; This file provides the receiving side of the XDND and Motif
+;; protocols, and both the receiving and initiating ends of the old
+;; KDE (OffiX) and new OffiX protocols.
 
 ;;; Code:
 
@@ -65,7 +66,10 @@ The default value for this variable is 
`x-dnd-default-test-function'."
     (,(purecopy "text/plain") . dnd-insert-text)
     (,(purecopy "COMPOUND_TEXT") . x-dnd-insert-ctext)
     (,(purecopy "STRING") . dnd-insert-text)
-    (,(purecopy "TEXT")   . dnd-insert-text))
+    (,(purecopy "TEXT")   . dnd-insert-text)
+    (,(purecopy "DndTypeFile") . x-dnd-handle-offix-file)
+    (,(purecopy "DndTypeFiles") . x-dnd-handle-offix-files)
+    (,(purecopy "DndTypeText") . dnd-insert-text))
   "Which function to call to handle a drop of that type.
 If the type for the drop is not present, or the function is nil,
 the drop is rejected.  The function takes three arguments, WINDOW, ACTION
@@ -80,26 +84,82 @@ if drop is successful, nil if not."
 
 (defcustom x-dnd-known-types
   (mapcar 'purecopy
-  '("text/uri-list"
-    "text/x-moz-url"
-    "_NETSCAPE_URL"
-    "FILE_NAME"
-    "UTF8_STRING"
-    "text/plain;charset=UTF-8"
-    "text/plain;charset=utf-8"
-    "text/unicode"
-    "text/plain"
-    "COMPOUND_TEXT"
-    "STRING"
-    "TEXT"))
+          '("XdndDirectSave0"
+            "text/uri-list"
+            "text/x-moz-url"
+            "_NETSCAPE_URL"
+            "FILE_NAME"
+            "UTF8_STRING"
+            "text/plain;charset=UTF-8"
+            "text/plain;charset=utf-8"
+            "text/unicode"
+            "text/plain"
+            "COMPOUND_TEXT"
+            "STRING"
+            "TEXT"
+            "DndTypeFile"
+            "DndTypeText"))
   "The types accepted by default for dropped data.
 The types are chosen in the order they appear in the list."
   :version "22.1"
   :type '(repeat string)
   :group 'x)
 
+(defcustom x-dnd-use-offix-drop 'files
+  "If non-nil, use the OffiX protocol to drop files and text.
+This allows dropping (via `dired-mouse-drag-files' or
+`mouse-drag-and-drop-region-cross-program') on some old Java
+applets and old KDE programs.  Turning this off allows dropping
+only text on some other programs such as xterm and urxvt.
+
+If the symbol `files', use the OffiX protocol when dropping
+files, and the fallback drop method (which is used with programs
+like xterm) for text."
+  :version "29.1"
+  :type '(choice (const :tag "Don't use the OffiX protocol for drag-and-drop" 
nil)
+                 (const :tag "Only use the OffiX protocol to drop files" files)
+                 (const :tag "Use the OffiX protocol for both files and text" 
t))
+  :group 'x)
+
+(defcustom x-dnd-direct-save-function #'x-dnd-save-direct
+  "Function called when a file is dropped that Emacs must save.
+It is called with two arguments: the first is either nil or t,
+and the second is a string.
+
+If the first argument is t, the second argument is the name the
+dropped file should be saved under.  The function should return a
+complete file name describing where the file should be saved.
+
+It can also return nil, which means to cancel the drop.
+
+If the first argument is nil, the second is the name of the file
+that was dropped."
+  :version "29.1"
+  :type '(choice (const :tag "Prompt for name before saving"
+                        x-dnd-save-direct)
+                 (const :tag "Save and open immediately without prompting"
+                        x-dnd-save-direct-immediately)
+                 (function :tag "Other function"))
+  :group 'x)
+
+(defcustom x-dnd-copy-types '("chromium/x-renderer-taint")
+  "List of data types offered by programs that don't support `private'.
+Some programs (such as Chromium) do not support
+`XdndActionPrivate'.  The default `x-dnd-test-function' will
+always return `copy' instead, for programs offering one of the
+data types in this list."
+  :version "29.1"
+  :type '(repeat string)
+  :group 'x)
+
 ;; Internal variables
 
+(defvar x-dnd-debug-errors nil
+  "Whether or not to signal protocol errors during drag-and-drop.
+This is useful for debugging errors in the DND code, but makes
+drag-and-drop much slower over network connections with high
+latency.")
+
 (defvar x-dnd-current-state nil
   "The current state for a drop.
 This is an alist with one entry for each display.  The value for each display
@@ -115,30 +175,37 @@ any protocol specific data.")
 
 (declare-function x-get-selection-internal "xselect.c"
                  (selection-symbol target-type &optional time-stamp terminal))
+(declare-function x-display-set-last-user-time "xfns.c")
 
 (defconst x-dnd-xdnd-to-action
   '(("XdndActionPrivate" . private)
     ("XdndActionCopy" . copy)
     ("XdndActionMove" . move)
     ("XdndActionLink" . link)
-    ("XdndActionAsk" . ask))
+    ("XdndActionAsk" . ask)
+    ("XdndActionDirectSave" . direct-save))
   "Mapping from XDND action types to Lisp symbols.")
 
 (defvar x-dnd-empty-state [nil nil nil nil nil nil nil])
 
 (declare-function x-register-dnd-atom "xselect.c")
 
+(defvar x-fast-protocol-requests)
+
 (defun x-dnd-init-frame (&optional frame)
   "Setup drag and drop for FRAME (i.e. create appropriate properties)."
-  (when (eq 'x (window-system frame))
-    (x-register-dnd-atom "DndProtocol" frame)
-    (x-register-dnd-atom "_MOTIF_DRAG_AND_DROP_MESSAGE" frame)
-    (x-register-dnd-atom "XdndEnter" frame)
-    (x-register-dnd-atom "XdndPosition" frame)
-    (x-register-dnd-atom "XdndLeave" frame)
-    (x-register-dnd-atom "XdndDrop" frame)
-    (x-dnd-init-xdnd-for-frame frame)
-    (x-dnd-init-motif-for-frame frame)))
+  (when (and (eq 'x (window-system frame))
+             (not (frame-parameter frame 'tooltip)))
+    (let ((x-fast-protocol-requests (not x-dnd-debug-errors)))
+      (x-register-dnd-atom "DndProtocol" frame)
+      (x-register-dnd-atom "_MOTIF_DRAG_AND_DROP_MESSAGE" frame)
+      (x-register-dnd-atom "XdndEnter" frame)
+      (x-register-dnd-atom "XdndPosition" frame)
+      (x-register-dnd-atom "XdndLeave" frame)
+      (x-register-dnd-atom "XdndDrop" frame)
+      (x-register-dnd-atom "_DND_PROTOCOL" frame)
+      (x-dnd-init-xdnd-for-frame frame)
+      (x-dnd-init-motif-for-frame frame))))
 
 (defun x-dnd-get-state-cons-for-frame (frame-or-window)
   "Return the entry in `x-dnd-current-state' for a frame or window."
@@ -156,13 +223,22 @@ any protocol specific data.")
 
 (defun x-dnd-default-test-function (_window _action types)
   "The default test function for drag and drop.
-WINDOW is where the mouse is when this function is called.  It may be
-a frame if the mouse is over the menu bar, scroll bar or tool bar.
-ACTION is the suggested action from the source, and TYPES are the
-types the drop data can have.  This function only accepts drops with
-types in `x-dnd-known-types'.  It always returns the action private."
+WINDOW is where the mouse is when this function is called.  It
+may be a frame if the mouse is over the menu bar, scroll bar or
+tool bar.  ACTION is the suggested action from the source, and
+TYPES are the types the drop data can have.  This function only
+accepts drops with types in `x-dnd-known-types'.  It always
+returns the action `private', unless `types' contains a value
+inside `x-dnd-copy-types'."
   (let ((type (x-dnd-choose-type types)))
-    (when type (cons 'private type))))
+    (when type (let ((list x-dnd-copy-types))
+                 (catch 'out
+                   (while t
+                     (if (not list)
+                         (throw 'out (cons 'private type))
+                       (if (x-dnd-find-type (car list) types)
+                           (throw 'out (cons 'copy type))
+                         (setq list (cdr list))))))))))
 
 (defun x-dnd-current-type (frame-or-window)
   "Return the type we want the DND data to be in for the current drop.
@@ -175,29 +251,49 @@ FRAME-OR-WINDOW is the frame or window that the mouse is 
over."
   (setcdr (x-dnd-get-state-cons-for-frame frame-or-window)
          (copy-sequence x-dnd-empty-state)))
 
-(defun x-dnd-maybe-call-test-function (window action)
+(defun x-dnd-find-type (target types)
+  "Find the type TARGET in an array of types TYPES.
+TARGET must be a string, but TYPES can contain either symbols or
+strings."
+  (catch 'done
+    (dotimes (i (length types))
+      (let* ((type (aref types i))
+            (typename (if (symbolp type)
+                          (symbol-name type) type)))
+       (when (equal target typename)
+         (throw 'done t))))
+    nil))
+
+(defun x-dnd-maybe-call-test-function (window action &optional xdnd)
   "Call `x-dnd-test-function' if something has changed.
 WINDOW is the window the mouse is over.  ACTION is the suggested
 action from the source.  If nothing has changed, return the last
-action and type we got from `x-dnd-test-function'."
+action and type we got from `x-dnd-test-function'.
+
+XDND means the XDND protocol is being used."
   (let ((buffer (when (window-live-p window)
                  (window-buffer window)))
        (current-state (x-dnd-get-state-for-frame window)))
-    (unless (and (equal buffer (aref current-state 0))
-                 (equal window (aref current-state 1))
-                 (equal action (aref current-state 3)))
-      (save-current-buffer
-       (when buffer (set-buffer buffer))
-       (let* ((action-type (funcall x-dnd-test-function
-                                    window
-                                    action
-                                    (aref current-state 2)))
-              (handler (cdr (assoc (cdr action-type) x-dnd-types-alist))))
-         ;; Ignore action-type if we have no handler.
-         (setq current-state
-               (x-dnd-save-state window
-                                 action
-                                 (when handler action-type)))))))
+    (if (and xdnd (x-dnd-find-type "XdndDirectSave0"
+                                   (aref current-state 2)))
+        (setq current-state
+              (x-dnd-save-state window 'direct-save
+                                '(direct-save . "XdndDirectSave0")))
+      (unless (and (equal buffer (aref current-state 0))
+                   (equal window (aref current-state 1))
+                   (equal action (aref current-state 3)))
+        (save-current-buffer
+         (when buffer (set-buffer buffer))
+         (let* ((action-type (funcall x-dnd-test-function
+                                      window
+                                      action
+                                      (aref current-state 2)))
+                (handler (cdr (assoc (cdr action-type) x-dnd-types-alist))))
+           ;; Ignore action-type if we have no handler.
+           (setq current-state
+                 (x-dnd-save-state window
+                                   action
+                                   (when handler action-type))))))))
   (let ((current-state (x-dnd-get-state-for-frame window)))
     (cons (aref current-state 5)
          (aref current-state 4))))
@@ -347,6 +443,7 @@ nil if not."
 Currently XDND, Motif and old KDE 1.x protocols are recognized."
   (interactive "e")
   (let* ((client-message (car (cdr (cdr event))))
+         (x-fast-protocol-requests (not x-dnd-debug-errors))
         (window (posn-window (event-start event))))
     (if (eq (and (consp client-message)
                  (car client-message))
@@ -356,7 +453,10 @@ Currently XDND, Motif and old KDE 1.x protocols are 
recognized."
         (progn
           (let ((action (cdr (assoc (symbol-name (cadr client-message))
                                     x-dnd-xdnd-to-action)))
-                (targets (cddr client-message)))
+                (targets (cddr client-message))
+                (local-value (nth 2 client-message)))
+            (when (windowp window)
+              (select-window window))
             (x-dnd-save-state window nil nil
                               (apply #'vector targets))
             (x-dnd-maybe-call-test-function window action)
@@ -364,8 +464,8 @@ Currently XDND, Motif and old KDE 1.x protocols are 
recognized."
                 (x-dnd-drop-data event (if (framep window) window
                                          (window-frame window))
                                  window
-                                 (x-get-selection-internal
-                                  'XdndSelection
+                                 (x-get-local-selection
+                                  local-value
                                   (intern (x-dnd-current-type window)))
                                  (x-dnd-current-type window))
               (x-dnd-forget-drop window))))
@@ -375,7 +475,8 @@ Currently XDND, Motif and old KDE 1.x protocols are 
recognized."
            (data (aref client-message 3)))
         (cond ((equal "DndProtocol" message-atom)      ; Old KDE 1.x.
               (x-dnd-handle-old-kde event frame window message-atom format 
data))
-
+              ((equal "_DND_PROTOCOL" message-atom) ; OffiX protocol.
+               (x-dnd-handle-offix event frame window message-atom format 
data))
              ((equal "_MOTIF_DRAG_AND_DROP_MESSAGE" message-atom)      ; Motif
               (x-dnd-handle-motif event frame window message-atom format data))
 
@@ -385,25 +486,110 @@ Currently XDND, Motif and old KDE 1.x protocols are 
recognized."
 
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;;  Old KDE protocol.  Only dropping of files.
+;;;  Old KDE protocol.
 
 (declare-function x-window-property "xfns.c"
                  (prop &optional frame type source delete-p vector-ret-p))
 
-(defun x-dnd-handle-old-kde (_event frame window _message _format _data)
-  "Open the files in a KDE 1.x drop."
-  (let ((values (x-window-property "DndSelection" frame nil 0 t)))
-    (x-dnd-handle-uri-list window 'private
-                          (replace-regexp-in-string "\0$" "" values))))
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
+(defvar x-dnd-offix-old-kde-to-name '((-1 . DndTypeInvalid)
+                                      (0 . DndTypeUnknown)
+                                      (1 . DndTypeRawData)
+                                      (2 . DndTypeFile)
+                                      (3 . DndTypeFiles)
+                                      (4 . DndTypeText)
+                                      (5 . DndTypeDir)
+                                      (6 . DndTypeLink)
+                                      (7 . DndTypeExe)
+                                      (8 . DndTypeUrl))
+  "Alist of old KDE data types to their names.")
+
+(defun x-dnd-handle-old-kde (event frame window _message _format data)
+  "Handle an old KDE (OffiX) drop.
+EVENT, FRAME, WINDOW and DATA mean the same thing they do in
+`x-dnd-handle-offix.'"
+  (let ((proto (aref data 4)))
+    ;; If PROTO > 0, this is an old KDE drop emulated by a program
+    ;; supporting a newer version of the OffiX protocol, so we should
+    ;; wait for the corresponding modern event instead.
+    (when (zerop proto)
+      (let ((type (cdr (assq (aref data 0) x-dnd-offix-old-kde-to-name)))
+            (data (x-window-property "DndSelection" frame nil 0 t)))
+        ;; First save state.
+        (x-dnd-save-state window nil nil (vector type) nil)
+        ;; Now call the test function to decide what action to perform.
+        (x-dnd-maybe-call-test-function window 'private)
+        (unwind-protect
+            (when (windowp window)
+              (select-window window))
+            (x-dnd-drop-data event frame window data
+                             (symbol-name type))
+          (x-dnd-forget-drop window))))))
 
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; New OffiX protocol.
+
+(defvar x-dnd-offix-id-to-name '((-1 . DndTypeInvalid)
+                                 (0 . DndTypeUnknown)
+                                 (1 . DndTypeRawData)
+                                 (2 . DndTypeFile)
+                                 (3 . DndTypeFiles)
+                                 (4 . DndTypeText)
+                                 (5 . DndTypeDir)
+                                 (6 . DndTypeLink)
+                                 (7 . DndTypeExe)
+                                 (8 . DndTypeUrl)
+                                 (9 . DndTypeMime)
+                                 (10 . DndTypePixmap))
+  "Alist of OffiX data types to their names.")
+
+(defun x-dnd-handle-offix-file (window action string)
+  "Convert OffiX file name to a regular file name.
+Then, call `x-dnd-handle-file-name'.
+
+WINDOW and ACTION mean the same as in `x-dnd-handle-file-name'.
+STRING is the raw OffiX file name data."
+  (x-dnd-handle-file-name window action
+                          (replace-regexp-in-string "\0$" "" string)))
+
+(defun x-dnd-handle-offix-files (window action string)
+  "Convert OffiX file name list to a URI list.
+Then, call `x-dnd-handle-file-name'.
+
+WINDOW and ACTION mean the same as in `x-dnd-handle-file-name'.
+STRING is the raw OffiX file name data."
+  (x-dnd-handle-file-name window action
+                          ;; OffiX file name lists contain one extra
+                          ;; NULL byte at the end.
+                          (if (string-suffix-p "\0\0" string)
+                              (substring string 0 (1- (length string)))
+                            string)))
+
+(defun x-dnd-handle-offix (event frame window _message-atom _format data)
+  "Handle OffiX drop event EVENT.
+FRAME is the frame where the drop happened.
+WINDOW is the window where the drop happened.
+_MESSAGE-ATOM and _FORMAT are unused.
+DATA is the vector containing the contents of the client
+message (format 32) that caused EVENT to be generated."
+  (let ((type (cdr (assq (aref data 0) x-dnd-offix-id-to-name)))
+        (data (x-window-property "_DND_SELECTION" frame nil 0 t)))
+    ;; First save state.
+    (x-dnd-save-state window nil nil (vector type) nil)
+    ;; Now call the test function to decide what action to perform.
+    (x-dnd-maybe-call-test-function window 'private)
+    (unwind-protect
+        (when (windowp window)
+          (select-window window))
+        (x-dnd-drop-data event frame window data
+                         (symbol-name type))
+      (x-dnd-forget-drop window))))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;;  XDND protocol.
 
 (declare-function x-change-window-property "xfns.c"
                  (prop value &optional frame type format outer-P window-id))
+(declare-function x-translate-coordinates "xfns.c")
 
 (defun x-dnd-init-xdnd-for-frame (frame)
   "Set the XdndAware property for FRAME to indicate that we do XDND."
@@ -411,39 +597,93 @@ Currently XDND, Motif and old KDE 1.x protocols are 
recognized."
                            '(5)        ;; The version of XDND we support.
                            frame "ATOM" 32 t))
 
-(defun x-dnd-get-drop-width-height (frame w accept)
-  "Return the width/height to be sent in a XDndStatus message.
-FRAME is the frame and W is the window where the drop happened.
-If ACCEPT is nil return 0 (empty rectangle),
-otherwise if W is a window, return its width/height,
-otherwise return the frame width/height."
-  (if accept
-      (if (windowp w)   ;; w is not a window if dropping on the menu bar,
-                       ;; scroll bar or tool bar.
-         (let ((edges (window-inside-pixel-edges w)))
-           (cons
-            (- (nth 2 edges) (nth 0 edges))    ;; right - left
-            (- (nth 3 edges) (nth 1 edges))))  ;; bottom - top
-       (cons (frame-pixel-width frame)
-             (frame-pixel-height frame)))
-    0))
-
-(defun x-dnd-get-drop-x-y (frame w)
-  "Return the x/y coordinates to be sent in a XDndStatus message.
-Coordinates are required to be absolute.
-FRAME is the frame and W is the window where the drop happened.
-If W is a window, return its absolute coordinates,
-otherwise return the frame coordinates."
-  (let* ((frame-left (or (car-safe (cdr-safe (frame-parameter frame 'left)))
-                        (frame-parameter frame 'left)))
-        (frame-top (or (car-safe (cdr-safe (frame-parameter frame 'top)))
-                       (frame-parameter frame 'top))))
-    (if (windowp w)
-       (let ((edges (window-inside-pixel-edges w)))
-         (cons
-          (+ frame-left (nth 0 edges))
-          (+ frame-top (nth 1 edges))))
-      (cons frame-left frame-top))))
+(defun x-dnd-after-move-frame (frame)
+  "Handle FRAME moving to a different position.
+Clear any cached root window position."
+  (set-frame-parameter frame 'dnd-root-window-position
+                       nil))
+
+(add-hook 'move-frame-functions #'x-dnd-after-move-frame)
+
+(defun x-dnd-compute-root-window-position (frame)
+  "Return the position of FRAME's edit widget relative to the root window.
+The value is a cons of (X . Y), describing the position of
+FRAME's edit widget (inner window) relative to the root window of
+its screen."
+  (or (frame-parameter frame 'dnd-root-window-position)
+      (let* ((result (x-translate-coordinates frame))
+             (param (cons (car result) (cadr result))))
+        (unless result
+          (error "Frame isn't on the same screen as its root window"))
+        (prog1 param
+          (set-frame-parameter frame 'dnd-root-window-position param)))))
+
+(defun x-dnd-get-window-rectangle (window)
+  "Return the bounds of WINDOW as a rectangle.
+The coordinates in the rectangle are relative to its frame's root
+window.  Return the bounds as a list of (X Y WIDTH HEIGHT)."
+  (let* ((frame (window-frame window))
+         (frame-pos (x-dnd-compute-root-window-position frame))
+         (edges (window-inside-pixel-edges window)))
+    (list (+ (car frame-pos) (nth 0 edges))
+          (+ (cdr frame-pos) (nth 1 edges))
+          (- (nth 2 edges) (nth 0 edges))
+          (- (nth 3 edges) (nth 1 edges)))))
+
+(defun x-dnd-intersect-rectangles (r1 r2)
+  "Return the intersection of R1 and R2, both rectangles."
+  (let ((left (if (< (car r1) (car r2)) r1 r2))
+        (right (if (> (car r2) (car r1)) r2 r1))
+        (upper (if (< (cadr r1) (cadr r2)) r1 r2))
+        (lower (if (> (cadr r2) (cadr r1)) r2 r1))
+        (result (list 0 0 0 0)))
+    (when (<= (car right) (+ (car left) (nth 2 left)))
+      (setcar result (car right))
+      (setcar (nthcdr 2 result)
+              (- (min (+ (car left) (nth 2 left))
+                      (+ (car right) (nth 2 right)))
+                 (car result)))
+      (when (<= (cadr lower) (+ (cadr upper) (nth 3 upper)))
+        (setcar (cdr result) (cadr lower))
+        (setcar (nthcdr 3 result)
+                (- (min (+ (cadr lower) (nth 3 lower))
+                        (+ (cadr upper) (nth 3 upper)))
+                   (cadr result)))))
+    result))
+
+(defun x-dnd-get-object-rectangle (window posn)
+  "Return the rectangle of the object (character or image) under POSN.
+WINDOW is the window POSN represents.  The rectangle is returned
+with coordinates relative to the root window."
+  (if (posn-point posn)
+      (with-selected-window window
+        (if-let* ((new-posn (posn-at-point (posn-point posn)))
+                  (posn-x-y (posn-x-y new-posn))
+                  (object-width-height (posn-object-width-height new-posn))
+                  (edges (window-inside-pixel-edges window))
+                  (frame-pos (x-dnd-compute-root-window-position
+                              (window-frame window))))
+            (list (+ (car frame-pos) (car posn-x-y)
+                     (car edges))
+                  (+ (cdr frame-pos) (cdr posn-x-y)
+                     (cadr edges))
+                  (car object-width-height)
+                  (cdr object-width-height))
+          '(0 0 0 0)))
+    '(0 0 0 0)))
+
+(defun x-dnd-get-drop-rectangle (window posn)
+  "Return the drag-and-drop rectangle at POSN on WINDOW."
+  (if (or dnd-scroll-margin
+          (not (windowp window)))
+      '(0 0 0 0)
+    (let ((window-rectangle (x-dnd-get-window-rectangle window))
+          object-rectangle)
+      (when dnd-indicate-insertion-point
+        (setq object-rectangle (x-dnd-get-object-rectangle window posn)
+              window-rectangle (x-dnd-intersect-rectangles object-rectangle
+                                                           window-rectangle)))
+      window-rectangle)))
 
 (declare-function x-get-atom-name "xselect.c" (value &optional frame))
 (declare-function x-send-client-message "xselect.c"
@@ -457,84 +697,263 @@ otherwise return the frame coordinates."
   "Return the nmore-than3 bit from the 32 bit FLAGS in an XDndEnter message."
   (logand flags 1))
 
+(declare-function x-get-modifier-masks "xfns.c")
+
+(defun x-dnd-modifier-mask (mods)
+  "Return the X modifier mask for the Emacs modifier state MODS.
+MODS is a single symbol, or a list of symbols such as `shift' or
+`control'."
+  (let ((virtual-modifiers (x-get-modifier-masks))
+        (mask 0))
+    (unless (consp mods)
+      (setq mods (list mods)))
+    (dolist (modifier mods)
+      (cond ((eq modifier 'shift)
+             (setq mask (logior mask 1))) ; ShiftMask
+            ((eq modifier 'control)
+             (setq mask (logior mask 4))) ; ControlMask
+            ((eq modifier 'meta)
+             (setq mask (logior mask (nth 4 virtual-modifiers))))
+            ((eq modifier 'hyper)
+             (setq mask (car virtual-modifiers)))
+            ((eq modifier 'super)
+             (setq mask (cadr virtual-modifiers)))
+            ((eq modifier 'alt)
+             (setq mask (nth 2 virtual-modifiers)))))
+    mask))
+
+(defun x-dnd-get-modifiers ()
+  "Obtain an X modifier mask containing all modifiers.
+Value is an X modifier mask containing all modifiers that can
+modify an Emacs keyboard or mouse event."
+  (let ((mods (x-get-modifier-masks))
+        (mask 5)) ; ShiftMask | ControlMask
+    (dolist (mod mods)
+      (setq mask (logior mask mod)))
+    mask))
+
+(defun x-dnd-wheel-modifier-type (flags)
+  "Return the modifier type of an X modifier mask.
+FLAGS is the X modifier mask of a turn of the mouse wheel."
+  (let ((modifiers (x-dnd-get-modifiers)))
+    (catch 'type
+      (dolist (modifier mouse-wheel-scroll-amount)
+        (when (and (consp modifier)
+                   (eq (x-dnd-modifier-mask (car modifier))
+                       (logand flags modifiers)))
+          (throw 'type (cdr modifier))))
+      nil)))
+
+(defvar x-dnd-click-count nil
+  "Alist of button numbers to click counters during drag-and-drop.
+The cdr of each association's cdr is the timestamp of the last
+button press event for the given button, and the car is the
+number of clicks in quick succession currently received.")
+
+(defun x-dnd-note-click (button timestamp)
+  "Note that button BUTTON was pressed at TIMESTAMP during drag-and-drop.
+Return the number of clicks that were made in quick succession."
+  (if (not (integerp double-click-time))
+      1
+    (let ((cell (cdr (assq button x-dnd-click-count))))
+      (unless cell
+        (setq cell (cons 0 timestamp))
+        (push (cons button cell)
+              x-dnd-click-count))
+      (when (< (cdr cell) (- timestamp double-click-time))
+        (setcar cell 0))
+      (setcar cell (1+ (car cell)))
+      (setcdr cell timestamp)
+      (car cell))))
+
+(defun x-dnd-mwheel-scroll (button count modifiers)
+  "Call the appropriate wheel scrolling function for BUTTON.
+Use MODIFIERS, an X modifier mask, to determine if any
+alternative operation (such as scrolling horizontally) should be
+taken.  COUNT is the number of times in quick succession BUTTON
+has been pressed."
+  (let* ((type (x-dnd-wheel-modifier-type modifiers))
+         (hscroll (eq type 'hscroll))
+         (amt (or (and (not mouse-wheel-progressive-speed) 1)
+                  (* 1 count))))
+    (unless (and (not mouse-wheel-tilt-scroll)
+                 (or (eq button 6) (eq button 7)))
+      (let ((function (cond ((eq type 'text-scale)
+                             #'text-scale-adjust)
+                            ((eq type 'global-text-scale)
+                             #'global-text-scale-adjust)
+                            ((eq button 4)
+                             (if hscroll
+                                 mwheel-scroll-right-function
+                               mwheel-scroll-down-function))
+                            ((eq button 5)
+                             (if hscroll
+                                 mwheel-scroll-left-function
+                               mwheel-scroll-up-function))
+                            ((eq button 6)
+                             (if mouse-wheel-flip-direction
+                                 mwheel-scroll-right-function
+                               mwheel-scroll-left-function))
+                            ((eq button 7)
+                             (if mouse-wheel-flip-direction
+                                 mwheel-scroll-left-function
+                               mwheel-scroll-right-function)))))
+        ;; Button5 should decrease the text scale, not increase it.
+        (when (and (memq type '(text-scale global-text-scale))
+                   (eq button 5))
+          (setq amt (- amt)))
+        (when function
+          (condition-case nil
+              ;; Don't overwrite any echo-area message that might
+              ;; already be shown, since this can be called from
+              ;; `x-begin-drag'.
+              (let ((inhibit-message t))
+                (funcall function amt))
+            ;; Do not error at buffer limits.  Show a message instead.
+            ;; This is especially important here because signalling an
+            ;; error will mess up the drag-and-drop operation.
+            (beginning-of-buffer
+             (message (error-message-string '(beginning-of-buffer))))
+            (end-of-buffer
+             (message (error-message-string '(end-of-buffer))))))))))
+
 (defun x-dnd-handle-xdnd (event frame window message _format data)
   "Receive one XDND event (client message) and send the appropriate reply.
 EVENT is the client message.  FRAME is where the mouse is now.
 WINDOW is the window within FRAME where the mouse is now.
-FORMAT is 32 (not used).  MESSAGE is the data part of an XClientMessageEvent."
+DATA is the vector containing the data of the client message as a
+vector of cardinals.
+MESSAGE is the type of the ClientMessage that was sent."
   (cond ((equal "XdndEnter" message)
         (let* ((flags (aref data 1))
                (version (x-dnd-version-from-flags flags))
                (more-than-3 (x-dnd-more-than-3-from-flags flags))
                (dnd-source (aref data 0)))
-          (if version  ;; If flags is bad, version will be nil.
-              (x-dnd-save-state
-               window nil nil
-               (if (> more-than-3 0)
-                   (x-window-property "XdndTypeList"
-                                      frame "AnyPropertyType"
-                                      dnd-source nil t)
-                 (vector (x-get-atom-name (aref data 2))
-                         (x-get-atom-name (aref data 3))
-                         (x-get-atom-name (aref data 4))))))))
+          (when version  ;; If flags is bad, version will be nil.
+            (x-dnd-save-state
+             window nil nil
+             (if (> more-than-3 0)
+                 (x-window-property "XdndTypeList"
+                                    frame "AnyPropertyType"
+                                    dnd-source nil t)
+               (vector (x-get-atom-name (aref data 2))
+                       (x-get-atom-name (aref data 3))
+                       (x-get-atom-name (aref data 4))))
+              version))))
 
        ((equal "XdndPosition" message)
-        (let* ((action (x-get-atom-name (aref data 4)))
-               (dnd-source (aref data 0))
-               (action-type (x-dnd-maybe-call-test-function
-                             window
-                             (cdr (assoc action x-dnd-xdnd-to-action))))
-               (reply-action (car (rassoc (car action-type)
-                                          x-dnd-xdnd-to-action)))
-               (accept ;; 1 = accept, 0 = reject
-                (if (and reply-action action-type
-                          ;; Only allow drops on the text area of a
-                          ;; window.
-                          (not (posn-area (event-start event))))
-                     1 0))
-               (list-to-send
-                (list (string-to-number
-                       (frame-parameter frame 'outer-window-id))
-                      accept ;; 1 = Accept, 0 = reject.
-                      (x-dnd-get-drop-x-y frame window)
-                      (x-dnd-get-drop-width-height
-                       frame window (eq accept 1))
-                      (or reply-action 0))))
-          (x-send-client-message
-           frame dnd-source frame "XdndStatus" 32 list-to-send)
-           (dnd-handle-movement (event-start event))))
+         ;; If (flags >> 10) & 1, then Emacs should scroll according
+         ;; to the button passed in bits 8 and 9, and the state passed
+         ;; in bits 0 to 7.
+         (let ((state (x-dnd-get-state-for-frame window)))
+           (when (windowp (posn-window (event-start event)))
+             (let ((flags (aref data 1))
+                   (version (aref state 6)))
+               (when (not (zerop (logand (ash flags -10) 1)))
+                 (let* ((button (+ 4 (logand (ash flags -8) #x3)))
+                        (count (or (and (>= version 1)
+                                        (x-dnd-note-click button
+                                                          (aref data 3)))
+                                   1))
+                        (state (logand flags #xff)))
+                   (with-selected-window (posn-window (event-start event))
+                     (x-dnd-mwheel-scroll button count state)
+                     (let ((old-x-y (posn-x-y (event-start event))))
+                       (setcar (cdr event)
+                               (posn-at-x-y (max (car old-x-y) 0)
+                                            (max (cdr old-x-y) 0)))))))))
+          (let* ((version (aref state 6))
+                  (action (if (< version 2) 'copy ; `copy' is the default 
action.
+                            (x-get-atom-name (aref data 4))))
+                 (dnd-source (aref data 0))
+                 (action-type (x-dnd-maybe-call-test-function
+                               window
+                               (cdr (assoc action x-dnd-xdnd-to-action)) t))
+                 (reply-action (car (rassoc
+                                      ;; Mozilla and some other programs
+                                      ;; support XDS, but only if we
+                                      ;; reply with `copy'.  We can
+                                      ;; recognize these broken programs
+                                      ;; by checking to see if
+                                      ;; `XdndActionDirectSave' was
+                                      ;; originally specified.
+                                      (if (and (eq (car action-type)
+                                                   'direct-save)
+                                               (not (eq action 'direct-save)))
+                                          'copy
+                                        (car action-type))
+                                     x-dnd-xdnd-to-action)))
+                 (accept ;; 1 = accept, 0 = reject
+                  (if (and reply-action action-type
+                            ;; Only allow drops on the text area of a
+                            ;; window.
+                            (not (posn-area (event-start event))))
+                       1 0))
+                  (rect (x-dnd-get-drop-rectangle window
+                                                  (event-start event)))
+                 (list-to-send
+                  (list (string-to-number
+                         (frame-parameter frame 'outer-window-id))
+                         ;; 1 = accept, 0 = reject.  2 = "want position
+                         ;; updates even for movement inside the given
+                         ;; widget bounds".
+                        accept
+                        (cons (car rect) (cadr rect))
+                        (cons (nth 2 rect) (nth 3 rect))
+                         ;; The no-toolkit Emacs build can actually
+                         ;; receive drops from programs that speak
+                         ;; versions of XDND earlier than 3 (such as
+                         ;; GNUstep), since the toplevel window is the
+                         ;; innermost window.
+                        (if (>= version 2)
+                             (or reply-action 0)
+                           0))))
+            (x-send-client-message
+             frame dnd-source frame "XdndStatus" 32 list-to-send)
+             (dnd-handle-movement (event-start event)))))
 
        ((equal "XdndLeave" message)
         (x-dnd-forget-drop window))
 
        ((equal "XdndDrop" message)
         (if (windowp window) (select-window window))
-        (let* ((dnd-source (aref data 0))
+        (let* ((state (x-dnd-get-state-for-frame frame))
+                (version (aref state 6))
+                (dnd-source (aref data 0))
                (timestamp (aref data 2))
-               (value (and (x-dnd-current-type window)
-                           (x-get-selection-internal
-                            'XdndSelection
-                            (intern (x-dnd-current-type window))
-                            timestamp)))
-               success action)
-
-          (setq action (if value
-                           (condition-case info
-                               (x-dnd-drop-data event frame window value
-                                                (x-dnd-current-type window))
-                             (error
-                              (message "Error: %s" info)
-                              nil))))
-
-          (setq success (if action 1 0))
-
-          (x-send-client-message
-           frame dnd-source frame "XdndFinished" 32
-           (list (string-to-number (frame-parameter frame 'outer-window-id))
-                 success       ;; 1 = Success, 0 = Error
-                 (if success "XdndActionPrivate" 0)
-                 ))
-          (x-dnd-forget-drop window)))
+                (current-action (aref state 5))
+                (current-type (aref state 4))
+               success action value)
+           (x-display-set-last-user-time timestamp)
+           (if (and (eq current-action 'direct-save)
+                    (equal current-type "XdndDirectSave0"))
+               (x-dnd-handle-xds-drop event window dnd-source version)
+             (setq value (and (x-dnd-current-type window)
+                             (x-get-selection-internal
+                              'XdndSelection
+                              (intern (x-dnd-current-type window))
+                              timestamp)))
+             (unwind-protect
+                 (setq action (if value
+                                 (condition-case info
+                                     (x-dnd-drop-data
+                                       event frame window value
+                                      (x-dnd-current-type window))
+                                   (error
+                                    (message "Error: %s" info)
+                                    nil))))
+              (setq success (if action 1 0))
+               (when (>= version 2)
+                (x-send-client-message
+                 frame dnd-source frame "XdndFinished" 32
+                 (list (string-to-number
+                         (frame-parameter frame 'outer-window-id))
+                       (if (>= version 5) success 0) ;; 1 = Success, 0 = Error
+                       (if (or (not action) (< version 5)) 0
+                          (or (car (rassoc action
+                                           x-dnd-xdnd-to-action))
+                              0)))))
+              (x-dnd-forget-drop window)))))
 
        (t (error "Unknown XDND message %s %s" message data))))
 
@@ -691,7 +1110,7 @@ Return a vector of atoms containing the selection targets."
 (defun x-dnd-handle-motif (event frame window _message-atom _format data)
   (let* ((message-type (cdr (assoc (logand (aref data 0) #x3f)
                                    x-dnd-motif-message-types)))
-         (initiator-p (eq (lsh (aref data 0) -7) 0))
+         (initiator-p (eq (ash (aref data 0) -7) 0))
         (source-byteorder (aref data 1))
         (my-byteorder (byteorder))
         (source-flags (x-dnd-get-motif-value data 2 2 source-byteorder))
@@ -757,6 +1176,7 @@ Return a vector of atoms containing the selection targets."
                            timestamp
                            x
                            y)))
+               (x-display-set-last-user-time timestamp)
               (x-send-client-message frame
                                      dnd-source
                                      frame
@@ -794,6 +1214,7 @@ Return a vector of atoms containing the selection targets."
                             my-byteorder)
                            reply-flags
                            timestamp)))
+               (x-display-set-last-user-time timestamp)
               (x-send-client-message frame
                                      dnd-source
                                      frame
@@ -802,6 +1223,8 @@ Return a vector of atoms containing the selection targets."
                                      reply)))
 
            ((eq message-type 'XmDROP_START)
+             (when (windowp window)
+               (select-window window))
             (let* ((x (x-dnd-motif-value-to-list
                        (x-dnd-get-motif-value data 8 2 source-byteorder)
                        2 my-byteorder))
@@ -852,30 +1275,32 @@ Return a vector of atoms containing the selection 
targets."
                      (timestamp (x-dnd-get-motif-value
                                  data 4 4 source-byteorder))
                      action)
-
+                 (x-display-set-last-user-time timestamp)
                 (x-send-client-message frame
                                        dnd-source
                                        frame
                                        "_MOTIF_DRAG_AND_DROP_MESSAGE"
                                        8
                                        reply)
-                (setq action
-                      (when (and reply-action atom-name)
-                        (let* ((value (x-get-selection-internal
-                                       (intern atom-name)
-                                       (intern (x-dnd-current-type window)))))
-                          (when value
-                            (condition-case info
-                                (x-dnd-drop-data event frame window value
-                                                 (x-dnd-current-type window))
-                              (error
-                               (message "Error: %s" info)
-                               nil))))))
-                (x-get-selection-internal
-                 (intern atom-name)
-                 (if action 'XmTRANSFER_SUCCESS 'XmTRANSFER_FAILURE)
-                 timestamp)
-                (x-dnd-forget-drop frame))))
+                (unwind-protect
+                     (setq action
+                          (when (and reply-action atom-name)
+                            (let* ((value (x-get-selection-internal
+                                           (intern atom-name)
+                                           (intern (x-dnd-current-type window))
+                                            timestamp)))
+                              (when value
+                                (condition-case info
+                                    (x-dnd-drop-data event frame window value
+                                                     (x-dnd-current-type 
window))
+                                  (error
+                                   (message "Error: %s" info)
+                                   nil))))))
+                  (x-get-selection-internal
+                   (intern atom-name)
+                   (if action 'XmTRANSFER_SUCCESS 'XmTRANSFER_FAILURE)
+                   timestamp)
+                  (x-dnd-forget-drop frame)))))
 
             (t (message "Unknown Motif drag-and-drop message: %s"
                         (logand (aref data 0) #x3f)))))))
@@ -887,14 +1312,99 @@ Return a vector of atoms containing the selection 
targets."
 
 ;;; Handling drops.
 
-(defun x-dnd-handle-unsupported-drop (targets _x _y action _window-id _frame 
_time)
-  "Return non-nil if the drop described by TARGETS and ACTION should not 
proceed."
-  (not (and (or (eq action 'XdndActionCopy)
-                (eq action 'XdndActionMove))
-            (or (member "STRING" targets)
-                (member "UTF8_STRING" targets)
-                (member "COMPOUND_TEXT" targets)
-                (member "TEXT" targets)))))
+(defvar x-treat-local-requests-remotely)
+(declare-function x-get-local-selection "xfns.c")
+
+(defun x-dnd-convert-to-offix (targets local-selection)
+  "Convert local selection data to OffiX data.
+TARGETS should be the list of targets currently available in
+`XdndSelection'.  Return a list of an OffiX type, and data
+suitable for passing to `x-change-window-property', or nil if the
+data could not be converted.
+LOCAL-SELECTION should be the local selection data describing the
+selection data to convert."
+  (let ((x-treat-local-requests-remotely t)
+        file-name-data string-data)
+    (cond
+     ((and (member "FILE_NAME" targets)
+           (setq file-name-data
+                 (x-get-local-selection local-selection 'FILE_NAME)))
+      (if (string-match-p "\0" file-name-data)
+          ;; This means there are multiple file names in
+          ;; XdndSelection.  Convert the file name data to a format
+          ;; that OffiX understands.
+          (cons 'DndTypeFiles (concat file-name-data "\0\0"))
+        (cons 'DndTypeFile (concat file-name-data "\0"))))
+     ((and (member "STRING" targets)
+           (setq string-data
+                 (x-get-local-selection local-selection 'STRING)))
+      (cons 'DndTypeText (encode-coding-string string-data
+                                               'latin-1))))))
+
+(defun x-dnd-do-offix-drop (targets x y frame window-id contents)
+  "Perform an OffiX drop on WINDOW-ID with the given selection contents.
+Return non-nil if the drop succeeded, or nil if it did not
+happen, which can happen if TARGETS didn't contain anything that
+the OffiX protocol can represent.
+
+X and Y are the root window coordinates of the drop.  TARGETS is
+the list of targets CONTENTS can be converted to, and CONTENTS is
+the local selection data to drop onto the target window.
+
+FRAME is the frame that will act as a source window for the
+drop."
+  (if-let* ((data (x-dnd-convert-to-offix targets contents))
+            (type-id (car (rassq (car data)
+                                 x-dnd-offix-id-to-name)))
+            (source-id (string-to-number
+                        (frame-parameter frame 'window-id)))
+            (message-data (list type-id           ; l[0] = DataType
+                                0                 ; l[1] = event->xbutton.state
+                                source-id         ; l[2] = window
+                                (+ x (* 65536 y)) ; l[3] = drop_x + 65536 * 
drop_y
+                                1)))              ; l[4] = protocol version
+    (prog1 t
+      ;; Send a legacy (old KDE) message first.  Newer clients will
+      ;; ignore it, since the protocol version is 1.
+      (x-change-window-property "DndSelection"
+                                (cdr data) frame
+                                "STRING" 8 nil 0)
+      (x-send-client-message frame window-id
+                             frame "DndProtocol"
+                             32 message-data)
+      ;; Now send a modern _DND_PROTOCOL message.
+      (x-change-window-property "_DND_SELECTION"
+                                (cdr data) frame
+                                "STRING" 8 nil 0)
+      (x-send-client-message frame window-id
+                             frame "_DND_PROTOCOL"
+                             32 message-data))))
+
+(defun x-dnd-handle-unsupported-drop (targets x y action window-id frame _time 
local-selection-data)
+  "Return non-nil if the drop described by TARGETS and ACTION should not 
proceed.
+X and Y are the root window coordinates of the drop.
+FRAME is the frame the drop originated on.
+WINDOW-ID is the X window the drop should happen to.
+LOCAL-SELECTION-DATA is the local selection data of the drop."
+  (let ((chosen-action nil))
+    (not (and (or (eq action 'XdndActionCopy)
+                  (eq action 'XdndActionMove))
+              (not (and x-dnd-use-offix-drop local-selection-data
+                        (or (not (eq x-dnd-use-offix-drop 'files))
+                            (member "FILE_NAME" targets))
+                        (when (x-dnd-do-offix-drop targets x
+                                                   y frame window-id
+                                                   local-selection-data)
+                          (setq chosen-action 'XdndActionCopy))))
+              (let ((delegate-p (or (member "STRING" targets)
+                                    (member "UTF8_STRING" targets)
+                                    (member "COMPOUND_TEXT" targets)
+                                    (member "TEXT" targets))))
+                (prog1 delegate-p
+                  ;; A string will avoid the drop emulation done in C
+                  ;; code, but won't be returned from `x-begin-drag'.
+                  (setq chosen-action (unless delegate-p ""))))))
+    chosen-action))
 
 (defvar x-dnd-targets-list)
 (defvar x-dnd-native-test-function)
@@ -913,6 +1423,287 @@ ACTION is the action given to `x-begin-drag'."
 
 (setq x-dnd-native-test-function #'x-dnd-handle-native-drop)
 
+;;; XDS protocol support.
+
+(declare-function x-begin-drag "xfns.c")
+(declare-function x-delete-window-property "xfns.c")
+(defvar selection-converter-alist)
+
+(defvar x-dnd-xds-current-file nil
+  "The file name for which a direct save is currently being performed.")
+
+(defvar x-dnd-xds-source-frame nil
+  "The frame from which a direct save is currently being performed.")
+
+(defvar x-dnd-xds-performed nil
+  "Whether or not the drop target made a request for `XdndDirectSave0'.")
+
+(defvar x-dnd-disable-motif-protocol)
+(defvar x-dnd-use-unsupported-drop)
+
+(defvar x-dnd-xds-testing nil
+  "Whether or not XDS is being tested from ERT.
+When non-nil, throw errors from the `XdndDirectSave0' converters
+instead of returning \"E\".")
+
+(defun x-dnd-handle-direct-save (_selection _type _value)
+  "Handle a selection request for `XdndDirectSave'."
+  (setq x-dnd-xds-performed t)
+  (let* ((uri (x-window-property "XdndDirectSave0"
+                                 x-dnd-xds-source-frame
+                                 "AnyPropertyType" nil t))
+         (local-file-uri (if (and (string-match "^file://\\([^/]*\\)" uri)
+                                  (not (equal (match-string 1 uri) "")))
+                             (dnd-get-local-file-uri uri)
+                           uri))
+         (local-name (and local-file-uri
+                          (dnd-get-local-file-name local-file-uri))))
+    (if (not local-name)
+        '(STRING . "F")
+      ;; We want errors to be signalled immediately during ERT
+      ;; testing, instead of being silently handled.  (bug#56712)
+      (if x-dnd-xds-testing
+          (prog1 '(STRING . "S")
+            (copy-file x-dnd-xds-current-file
+                       local-name t)
+            (when (equal x-dnd-xds-current-file
+                         dnd-last-dragged-remote-file)
+              (dnd-remove-last-dragged-remote-file)))
+        (condition-case nil
+            (progn
+              (copy-file x-dnd-xds-current-file
+                         local-name t)
+              (when (equal x-dnd-xds-current-file
+                           dnd-last-dragged-remote-file)
+                (dnd-remove-last-dragged-remote-file)))
+          (:success '(STRING . "S"))
+          (error '(STRING . "E")))))))
+
+(defun x-dnd-handle-octet-stream (_selection _type _value)
+  "Handle a selection request for `application/octet-stream'.
+Return the contents of the XDS file."
+  (cons 'application/octet-stream
+        (ignore-errors
+          (with-temp-buffer
+            (set-buffer-multibyte nil)
+            (setq buffer-file-coding-system 'binary)
+            (insert-file-contents-literally x-dnd-xds-current-file)
+            (buffer-substring-no-properties (point-min)
+                                            (point-max))))))
+
+(defun x-dnd-do-direct-save (file name frame allow-same-frame)
+  "Perform a direct save operation on FILE, from FRAME.
+FILE is the file containing the contents to drop.
+NAME is the name that should be given to the file after dropping.
+FRAME is the frame from which the drop will originate.
+ALLOW-SAME-FRAME means whether or not dropping will be allowed
+on FRAME.
+
+Return the action taken by the drop target, or nil if no action
+was taken, or the direct save failed."
+  (dnd-remove-last-dragged-remote-file)
+  (let ((file-name file)
+        (original-file-name file)
+        (selection-converter-alist
+         (append '((XdndDirectSave0 . x-dnd-handle-direct-save)
+                   (application/octet-stream . x-dnd-handle-octet-stream))
+                 selection-converter-alist))
+        (x-dnd-xds-current-file nil)
+        (x-dnd-xds-source-frame frame)
+        (x-dnd-xds-performed nil)
+        ;; The XDS protocol is built on top of XDND, and cannot
+        ;; possibly work with Motif or OffiX programs.
+        (x-dnd-disable-motif-protocol t)
+        (x-dnd-use-offix-drop nil)
+        (x-dnd-use-unsupported-drop nil)
+        (prop-deleted nil)
+        encoded-name)
+    (unwind-protect
+        (progn
+          (when (file-remote-p file)
+            (setq file-name (file-local-copy file))
+            (setq dnd-last-dragged-remote-file file-name)
+            (add-hook 'kill-emacs-hook
+                      #'dnd-remove-last-dragged-remote-file))
+          (setq encoded-name
+                (encode-coding-string name
+                                      (or file-name-coding-system
+                                          default-file-name-coding-system)))
+          (setq x-dnd-xds-current-file file-name)
+          (x-change-window-property "XdndDirectSave0" encoded-name
+                                    frame "text/plain" 8 nil)
+          (gui-set-selection 'XdndSelection (concat "file://" file-name))
+          ;; FIXME: this does not work with GTK file managers, since
+          ;; they always reach for `text/uri-list' first, contrary to
+          ;; the spec.
+          (let ((action (x-begin-drag '("XdndDirectSave0" "text/uri-list"
+                                        "application/octet-stream")
+                                      'XdndActionDirectSave
+                                      frame nil allow-same-frame)))
+            (if (not x-dnd-xds-performed)
+                action
+              (let ((property (x-window-property "XdndDirectSave0" frame
+                                                 "AnyPropertyType" nil t)))
+                (setq prop-deleted t)
+                ;; "System-G" deletes the property upon success.
+                (and (or (null property)
+                         (and (stringp property)
+                              (not (equal property ""))))
+                     action)))))
+      (unless prop-deleted
+        (x-delete-window-property "XdndDirectSave0" frame))
+      ;; Delete any remote copy that was made.
+      (when (not (equal file-name original-file-name))
+        (delete-file file-name)))))
+
+(defun x-dnd-save-direct (need-name name)
+  "Handle dropping a file that should be saved immediately.
+NEED-NAME tells whether or not the file was not yet saved.  NAME
+is either the name of the file, or the name the drop source wants
+us to save under.
+
+Prompt the user for a file name, then open it."
+  (if need-name
+      (let ((file-name (read-file-name "Write file: "
+                                       default-directory
+                                       nil nil name)))
+        (when (file-exists-p file-name)
+          (unless (y-or-n-p (format-message
+                             "File `%s' exists; overwrite? " file-name))
+            (setq file-name nil)))
+        file-name)
+    ;; TODO: move this to dired.el once a platform-agonistic
+    ;; interface can be found.
+    (if (derived-mode-p 'dired-mode)
+        (revert-buffer)
+      (find-file name))))
+
+(defun x-dnd-save-direct-immediately (need-name name)
+  "Save and open a dropped file, like `x-dnd-save-direct'.
+NEED-NAME tells whether or not the file was not yet saved.  NAME
+is either the name of the file, or the name the drop source wants
+us to save under.
+
+Unlike `x-dnd-save-direct', do not prompt for the name by which
+to save the file.  Simply save it in the current directory."
+  (if need-name
+      (let ((file-name (expand-file-name name)))
+        (when (file-exists-p file-name)
+          (unless (y-or-n-p (format-message
+                             "File `%s' exists; overwrite? " file-name))
+            (setq file-name nil)))
+        file-name)
+    ;; TODO: move this to dired.el once a platform-agonistic
+    ;; interface can be found.
+    (if (derived-mode-p 'dired-mode)
+        (revert-buffer)
+      (find-file name))))
+
+(defun x-dnd-handle-octet-stream-for-drop (save-to)
+  "Save the contents of the XDS selection to SAVE-TO.
+Return non-nil if successful, nil otherwise."
+  (ignore-errors
+    (let ((coding-system-for-write 'raw-text)
+          (data (x-get-selection-internal 'XdndSelection
+                                          'application/octet-stream)))
+      (when data
+        (write-region data nil save-to)
+        t))))
+
+(defun x-dnd-handle-xds-drop (event window source version)
+  "Handle an XDS (X Direct Save) protocol drop.
+EVENT is the drag-n-drop event containing the drop.
+WINDOW is the window on top of which the drop is supposed to happen.
+SOURCE is the X window that sent the drop.
+VERSION is the version of the XDND protocol understood by SOURCE."
+  (if (not (windowp window))
+      ;; We can't perform an XDS drop if there's no window from which
+      ;; to determine the current directory.
+      (let* ((start (event-start event))
+             (frame (posn-window start)))
+        (x-send-client-message frame source frame
+                               "XdndFinished" 32
+                               (list (string-to-number
+                                      (frame-parameter frame
+                                                       'outer-window-id)))))
+    (let ((desired-name (x-window-property "XdndDirectSave0"
+                                           (window-frame window)
+                                           ;; We currently don't handle
+                                           ;; any alternative character
+                                           ;; encodings.
+                                           "text/plain" source))
+          (frame (window-frame window))
+          (success nil) save-to save-to-remote hostname)
+      (unwind-protect
+          (when (stringp desired-name)
+            (setq desired-name (decode-coding-string
+                                desired-name
+                                (or file-name-coding-system
+                                    default-file-name-coding-system)))
+            (let ((name (funcall x-dnd-direct-save-function
+                                 t desired-name)))
+              (setq save-to name save-to-remote name))
+            (when save-to
+              (if (file-remote-p save-to)
+                  (setq hostname (file-remote-p save-to 'host)
+                        save-to (file-local-name save-to))
+                (setq hostname (system-name)))
+              (with-selected-window window
+                (let ((uri (format "file://%s%s" hostname save-to)))
+                  (x-change-window-property "XdndDirectSave0"
+                                            (encode-coding-string
+                                             (url-encode-url uri) 'ascii)
+                                            frame "text/plain" 8 nil source)
+                  (let ((result (x-get-selection-internal 'XdndSelection
+                                                          'XdndDirectSave0)))
+                    (cond ((equal result "F")
+                           (setq success
+                                 (x-dnd-handle-octet-stream-for-drop 
save-to-remote))
+                           (unless success
+                             (x-change-window-property "XdndDirectSave0" ""
+                                                       frame "text/plain" 8
+                                                       nil source)))
+                          ((equal result "S")
+                           (setq success t))
+                          ((equal result "E")
+                           (setq success nil))
+                          (t (error "Broken implementation of XDS: got %s in 
reply"
+                                    result)))
+                    (when success
+                      (funcall x-dnd-direct-save-function nil 
save-to-remote)))))))
+        ;; We assume XDS always comes from a client supporting version 2
+        ;; or later, since custom actions aren't present before.
+        (x-send-client-message frame source frame
+                               "XdndFinished" 32
+                               (list (string-to-number
+                                      (frame-parameter frame
+                                                       'outer-window-id))
+                                     (if (>= version 5)
+                                         (if success 1 0)
+                                       0)
+                                     (if (or (not success)
+                                             (< version 5))
+                                         0
+                                       "XdndDirectSave0")))))))
+
+;; Internal wheel movement.
+
+(defvar x-dnd-wheel-function)
+
+(defun x-dnd-note-wheel-movement (position button state time)
+  "Note wheel movement at POSITION.
+POSITION is a mouse position list describing the position of the
+wheel movement.
+BUTTON is the wheel button that was pressed.
+STATE is the X modifier state at the time of the wheel movement.
+TIME is the X server time at which the wheel moved."
+  (when (posn-window position)
+    (with-selected-window (posn-window position)
+      (let ((count (x-dnd-note-click button time)))
+        (x-dnd-mwheel-scroll button count state)))))
+
+(setq x-dnd-wheel-function #'x-dnd-note-wheel-movement)
+
 (provide 'x-dnd)
 
 ;;; x-dnd.el ends here
diff --git a/lisp/xdg.el b/lisp/xdg.el
index 6a0b1dedd1..dd0d51290d 100644
--- a/lisp/xdg.el
+++ b/lisp/xdg.el
@@ -171,13 +171,12 @@ file:///foo/bar.jpg"
 ;; https://www.freedesktop.org/wiki/Software/xdg-user-dirs/
 
 (defconst xdg-line-regexp
-  (eval-when-compile
-    (rx "XDG_"
-        (group-n 1 (or "DESKTOP" "DOWNLOAD" "TEMPLATES" "PUBLICSHARE"
-                       "DOCUMENTS" "MUSIC" "PICTURES" "VIDEOS"))
-        "_DIR=\""
-        (group-n 2 (or "/" "$HOME/") (*? (or (not (any "\"")) "\\\"")))
-        "\""))
+  (rx "XDG_"
+      (group-n 1 (or "DESKTOP" "DOWNLOAD" "TEMPLATES" "PUBLICSHARE"
+                     "DOCUMENTS" "MUSIC" "PICTURES" "VIDEOS"))
+      "_DIR=\""
+      (group-n 2 (or "/" "$HOME/") (*? (or (not (any "\"")) "\\\"")))
+      "\"")
   "Regexp matching non-comment lines in `xdg-user-dirs' config files.")
 
 (defvar xdg-user-dirs nil
@@ -251,7 +250,7 @@ This should be called at the beginning of a line."
        ;; Filter localized strings
        ((looking-at (rx (group-n 1 (+ (in alnum "-"))) (* blank) "[")))
        (t (error "Malformed line: %s"
-                 (buffer-substring (point) (point-at-eol)))))
+                 (buffer-substring (point) (line-end-position)))))
       (forward-line))
     res))
 
@@ -266,7 +265,7 @@ Optional argument GROUP defaults to the string \"Desktop 
Entry\"."
       (forward-line))
     (unless (looking-at xdg-desktop-group-regexp)
       (error "Expected group name!  Instead saw: %s"
-             (buffer-substring (point) (point-at-eol))))
+             (buffer-substring (point) (line-end-position))))
     (when group
       (while (and (re-search-forward xdg-desktop-group-regexp nil t)
                   (not (equal (match-string 1) group)))))
diff --git a/lisp/xwidget.el b/lisp/xwidget.el
index 88bc8ff6c5..41a1190c64 100644
--- a/lisp/xwidget.el
+++ b/lisp/xwidget.el
@@ -1,11 +1,11 @@
 ;;; xwidget.el --- api functions for xwidgets  -*- lexical-binding: t -*-
-;;
+
 ;; Copyright (C) 2011-2022 Free Software Foundation, Inc.
-;;
-;; Author: Joakim Verona (joakim@verona.se)
-;;
+
+;; Author: Joakim Verona <joakim@verona.se>
+
 ;; 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
@@ -18,8 +18,6 @@
 
 ;; 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:
 ;;
@@ -134,6 +132,8 @@ Interactively, URL defaults to the string looking like a 
url around point."
         (xwidget-webkit-new-session url)
       (xwidget-webkit-goto-url url))))
 
+(function-put 'xwidget-webkit-browse-url 'browse-url-browser-kind 'internal)
+
 (defun xwidget-webkit-clone-and-split-below ()
   "Clone current URL into a new widget place in new window below.
 Get the URL of current session, then browse to the URL
@@ -963,7 +963,7 @@ You can retrieve the value with `xwidget-get'."
   (set-xwidget-plist xwidget
                      (plist-put (xwidget-plist xwidget) propname value)))
 
-(defvar xwidget-webkit-edit-mode-map (make-keymap))
+(defvar-keymap xwidget-webkit-edit-mode-map :full t)
 
 (define-key xwidget-webkit-edit-mode-map [backspace] 
'xwidget-webkit-pass-command-event)
 (define-key xwidget-webkit-edit-mode-map [tab] 
'xwidget-webkit-pass-command-event)
@@ -1109,8 +1109,9 @@ With argument, add COUNT copies of CHAR."
   (interactive)
   (xwidget-webkit-isearch-mode 0))
 
-(defvar xwidget-webkit-isearch-mode-map (make-keymap)
-  "The keymap used inside xwidget-webkit-isearch-mode.")
+(defvar-keymap xwidget-webkit-isearch-mode-map
+  :doc "The keymap used inside `xwidget-webkit-isearch-mode'."
+  :full t)
 
 (set-char-table-range (nth 1 xwidget-webkit-isearch-mode-map)
                       (cons 0 (max-char))
diff --git a/lwlib/lwlib-Xaw.c b/lwlib/lwlib-Xaw.c
index d17acae728..b09795ec38 100644
--- a/lwlib/lwlib-Xaw.c
+++ b/lwlib/lwlib-Xaw.c
@@ -594,6 +594,8 @@ make_dialog (char* name,
             int nr_xft_data = left_buttons + right_buttons + 1;
             instance->xft_data = calloc (nr_xft_data + 1,
                                          sizeof(*instance->xft_data));
+           if (!instance->xft_data)
+             memory_full ((nr_xft_data + 1) * sizeof *instance->xft_data);
 
             fill_xft_data (&instance->xft_data[0], w, xft_font);
            XtAddCallback (dialog, XtNdestroyCallback, destroy_xft_data,
diff --git a/lwlib/xlwmenu.c b/lwlib/xlwmenu.c
index ace5141cdb..deea50c810 100644
--- a/lwlib/xlwmenu.c
+++ b/lwlib/xlwmenu.c
@@ -48,6 +48,7 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #endif /* not emacs */
 
 static int pointer_grabbed;
+static int keyboard_grabbed;
 static XEvent menu_post_event;
 
 static char
@@ -120,6 +121,10 @@ xlwMenuResources[] =
    offset(menu.disabled_foreground), XtRString, (XtPointer)NULL},
   {XtNbuttonForeground, XtCButtonForeground, XtRPixel, sizeof(Pixel),
      offset(menu.button_foreground), XtRString, "XtDefaultForeground"},
+  {XtNhighlightForeground, XtCHighlightForeground, XtRPixel, sizeof(Pixel),
+     offset(menu.highlight_foreground), XtRImmediate, (XtPointer) -1},
+  {XtNhighlightBackground, XtCHighlightBackground, XtRPixel, sizeof(Pixel),
+     offset(menu.highlight_background), XtRImmediate, (XtPointer)-1},
   {XtNmargin, XtCMargin, XtRDimension,  sizeof(Dimension),
      offset(menu.margin), XtRImmediate, (XtPointer)1},
   {XtNhorizontalSpacing, XtCMargin, XtRDimension,  sizeof(Dimension),
@@ -245,11 +250,6 @@ WidgetClass xlwMenuWidgetClass = (WidgetClass) 
&xlwMenuClassRec;
 
 int submenu_destroyed;
 
-/* For debug, if installation-directory is non-nil this is not an installed
-   Emacs.   In that case we do not grab the keyboard to make it easier to
-   debug. */
-#define GRAB_KEYBOARD  (EQ (Vinstallation_directory, Qnil))
-
 static int next_release_must_exit;
 
 /* Utilities */
@@ -259,7 +259,9 @@ static void
 ungrab_all (Widget w, Time ungrabtime)
 {
   XtUngrabPointer (w, ungrabtime);
-  if (GRAB_KEYBOARD) XtUngrabKeyboard (w, ungrabtime);
+
+  if (keyboard_grabbed)
+    XtUngrabKeyboard (w, ungrabtime);
 }
 
 /* Like abort, but remove grabs from widget W before.  */
@@ -572,8 +574,7 @@ draw_arrow (XlwMenuWidget mw,
             int down_p)
 {
   Display *dpy = XtDisplay (mw);
-  GC top_gc = mw->menu.shadow_top_gc;
-  GC bottom_gc = mw->menu.shadow_bottom_gc;
+  GC top_gc, bottom_gc;
   int thickness = mw->menu.shadow_thickness;
   int height = width;
   XPoint pt[10];
@@ -586,10 +587,13 @@ draw_arrow (XlwMenuWidget mw,
 
   if (down_p)
     {
-      GC temp;
-      temp = top_gc;
-      top_gc = bottom_gc;
-      bottom_gc = temp;
+      top_gc = mw->menu.highlight_shadow_bottom_gc;
+      bottom_gc = mw->menu.highlight_shadow_top_gc;
+    }
+  else
+    {
+      top_gc = mw->menu.shadow_top_gc;
+      bottom_gc = mw->menu.shadow_bottom_gc;
     }
 
   pt[0].x = x;
@@ -623,24 +627,34 @@ draw_arrow (XlwMenuWidget mw,
   XFillPolygon (dpy, window, bottom_gc, pt, 4, Convex, CoordModeOrigin);
 }
 
-
-
+/* Generic draw shadow rectangle function.  It is used to draw shadows
+   on menus, menu items and also toggle buttons.  When ERASE_P is
+   true, it clears shadows.  DOWN_P is true when a menu item is pushed
+   or a button toggled.  TOP_GC and BOTTOM_GC are the graphic contexts
+   used to draw the top and bottom shadow respectively.  */
 static void
-draw_shadow_rectangle (XlwMenuWidget mw,
-                       Window window,
-                       int x,
-                       int y,
-                       int width,
-                       int height,
-                       int erase_p,
-                       int down_p)
+draw_shadow_rectangle (XlwMenuWidget mw, Window window, int x, int y,
+                      int width, int height, int erase_p, int down_p,
+                      GC top_gc, GC bottom_gc)
 {
   Display *dpy = XtDisplay (mw);
-  GC top_gc = !erase_p ? mw->menu.shadow_top_gc : mw->menu.background_gc;
-  GC bottom_gc = !erase_p ? mw->menu.shadow_bottom_gc : mw->menu.background_gc;
   int thickness = !x && !y ? mw->menu.border_thickness : 
mw->menu.shadow_thickness;
   XPoint points [4];
 
+  /* Choose correct GC with a standard default if NULL.  */
+  if (erase_p)
+    {
+      top_gc = mw->menu.background_gc;
+      bottom_gc = mw->menu.background_gc;
+    }
+  else
+    {
+      if (top_gc == NULL)
+       top_gc = mw->menu.shadow_top_gc;
+      if (bottom_gc == NULL)
+       bottom_gc = mw->menu.shadow_bottom_gc;
+    }
+
   if (!erase_p && width == height && width == toggle_button_width (mw))
     {
       points [0].x = x;
@@ -664,6 +678,7 @@ draw_shadow_rectangle (XlwMenuWidget mw,
       bottom_gc = temp;
     }
 
+  /* Do draw (or erase) shadows */
   points [0].x = x;
   points [0].y = y;
   points [1].x = x + width;
@@ -704,21 +719,28 @@ draw_shadow_rectangle (XlwMenuWidget mw,
 
 
 static void
-draw_shadow_rhombus (XlwMenuWidget mw,
-                     Window window,
-                     int x,
-                     int y,
-                     int width,
-                     int height,
-                     int erase_p,
-                     int down_p)
+draw_shadow_rhombus (XlwMenuWidget mw, Window window, int x, int y,
+                     int width, int height, int erase_p, int down_p,
+                    GC top_gc, GC bottom_gc)
 {
   Display *dpy = XtDisplay (mw);
-  GC top_gc = !erase_p ? mw->menu.shadow_top_gc : mw->menu.background_gc;
-  GC bottom_gc = !erase_p ? mw->menu.shadow_bottom_gc : mw->menu.background_gc;
   int thickness = mw->menu.shadow_thickness;
   XPoint points [4];
 
+  /* Choose correct GC with a standard default if NULL */
+  if (erase_p)
+    {
+      top_gc = mw->menu.background_gc;
+      bottom_gc = mw->menu.background_gc;
+    }
+  else
+    {
+      if (top_gc == NULL)
+       top_gc = mw->menu.shadow_top_gc;
+      if (bottom_gc == NULL)
+       top_gc = mw->menu.shadow_bottom_gc;
+    }
+
   if (!erase_p && width == height && width == radio_button_width (mw))
     {
       points [0].x = x;
@@ -786,15 +808,29 @@ draw_shadow_rhombus (XlwMenuWidget mw,
    toggle button is selected.  */
 
 static void
-draw_toggle (XlwMenuWidget mw, Window window, int x, int y, int selected_p)
+draw_toggle (XlwMenuWidget mw, Window window, int x, int y, int selected_p,
+            int highlighted_p)
 {
   int width, height;
+  GC top_gc, bottom_gc;
+
+  if (highlighted_p)
+    {
+      top_gc = mw->menu.highlight_shadow_top_gc;
+      bottom_gc = mw->menu.highlight_shadow_bottom_gc;
+    }
+  else
+    {
+      top_gc = mw->menu.shadow_top_gc;
+      bottom_gc = mw->menu.shadow_bottom_gc;
+    }
 
   width = toggle_button_width (mw);
   height = width;
   x += mw->menu.horizontal_spacing;
   y += (MENU_FONT_ASCENT (mw) - height) / 2;
-  draw_shadow_rectangle (mw, window, x, y, width, height, False, selected_p);
+  draw_shadow_rectangle (mw, window, x, y, width, height, False,
+                        selected_p, top_gc, bottom_gc);
 }
 
 
@@ -803,15 +839,29 @@ draw_toggle (XlwMenuWidget mw, Window window, int x, int 
y, int selected_p)
    toggle button is selected.  */
 
 static void
-draw_radio (XlwMenuWidget mw, Window window, int x, int y, int selected_p)
+draw_radio (XlwMenuWidget mw, Window window, int x, int y, int selected_p,
+           int highlighted_p)
 {
   int width, height;
+  GC top_gc, bottom_gc;
+
+  if (highlighted_p)
+    {
+      top_gc = mw->menu.highlight_shadow_top_gc;
+      bottom_gc = mw->menu.highlight_shadow_bottom_gc;
+    }
+  else
+    {
+      top_gc = mw->menu.shadow_top_gc;
+      bottom_gc = mw->menu.shadow_bottom_gc;
+    }
 
   width = radio_button_width (mw);
   height = width;
   x += mw->menu.horizontal_spacing;
   y += (MENU_FONT_ASCENT (mw) - height) / 2;
-  draw_shadow_rhombus (mw, window, x, y, width, height, False, selected_p);
+  draw_shadow_rhombus (mw, window, x, y, width, height, False, selected_p,
+                      top_gc, bottom_gc);
 }
 
 
@@ -970,6 +1020,31 @@ separator_height (enum menu_separator separator)
     }
 }
 
+/* Draw the highlighted background and shadows.  */
+
+static void
+draw_highlight (XlwMenuWidget mw, Window window, int x, int y, int width,
+               int height)
+{
+  Display *dpy = XtDisplay (mw);
+  XPoint points [4];
+
+  points [0].x = x;
+  points [0].y = y;
+  points [1].x = x + width;
+  points [1].y = y;
+  points [2].x = x + width;
+  points [2].y = y + height;
+  points [3].x = x;
+  points [3].y = y + height;
+  XFillPolygon (dpy, window,
+               mw->menu.highlight_background_gc,
+               points, 4, Convex, CoordModeOrigin);
+
+  draw_shadow_rectangle(mw, window, x, y, width, height, False, False,
+                       mw->menu.highlight_shadow_top_gc,
+                       mw->menu.highlight_shadow_bottom_gc);
+}
 
 /* Display the menu item and increment where.x and where.y to show how large
    the menu item was.  */
@@ -985,7 +1060,6 @@ display_menu_item (XlwMenuWidget mw,
 {
   GC deco_gc;
   GC text_gc;
-  int font_height = MENU_FONT_HEIGHT (mw);
   int font_ascent = MENU_FONT_ASCENT (mw);
   int shadow = mw->menu.shadow_thickness;
   int margin = mw->menu.margin;
@@ -1034,24 +1108,34 @@ display_menu_item (XlwMenuWidget mw,
 
       /* pick the foreground and background GC. */
       if (val->enabled)
-       text_gc = mw->menu.foreground_gc;
+       if (highlighted_p)
+         text_gc = mw->menu.highlight_foreground_gc;
+       else
+         text_gc = mw->menu.foreground_gc;
       else
        text_gc = mw->menu.disabled_gc;
       deco_gc = mw->menu.foreground_gc;
 #if defined USE_CAIRO || defined HAVE_XFT
-      xftfg = val->enabled ? &mw->menu.xft_fg : &mw->menu.xft_disabled_fg;
+      if (val->enabled)
+       if (highlighted_p)
+         xftfg = &mw->menu.xft_highlight_fg;
+       else
+         xftfg = &mw->menu.xft_fg;
+      else
+       xftfg = &mw->menu.xft_disabled_fg;
 #endif
 
       if (separator_p)
-       {
-         draw_separator (mw, ws->pixmap, x, y, width, separator);
-       }
+       draw_separator (mw, ws->pixmap, x, y, width, separator);
       else
        {
          int x_offset = x + h_spacing + shadow;
          char* display_string = resource_widget_value (mw, val);
-         draw_shadow_rectangle (mw, ws->pixmap, x, y, width, height, True,
-                                False);
+         /* Clears shadows and maybe highlight */
+         draw_shadow_rectangle (mw, ws->pixmap, x, y, width, height,
+                                True, False, NULL, NULL);
+         if (highlighted_p)
+           draw_highlight (mw, ws->pixmap, x, y, width, height);
 
          /* Deal with centering a menu title. */
          if (!horizontal_p && !val->contents && !val->call_data)
@@ -1097,10 +1181,10 @@ display_menu_item (XlwMenuWidget mw,
            {
              if (val->button_type == BUTTON_TYPE_TOGGLE)
                draw_toggle (mw, ws->pixmap, x, y + v_spacing + shadow,
-                            val->selected);
+                            val->selected, highlighted_p);
              else if (val->button_type == BUTTON_TYPE_RADIO)
                draw_radio (mw, ws->pixmap, x, y + v_spacing + shadow,
-                           val->selected);
+                           val->selected, highlighted_p);
 
              if (val->contents)
                {
@@ -1147,25 +1231,18 @@ display_menu_item (XlwMenuWidget mw,
            }
          else
            {
-             XDrawRectangle (XtDisplay (mw), ws->pixmap,
-                             mw->menu.background_gc,
-                             x + shadow, y + shadow,
-                             label_width + h_spacing - 1,
-                             font_height + 2 * v_spacing - 1);
-             draw_shadow_rectangle (mw, ws->pixmap, x, y, width, height,
-                                    True, False);
+             /* If not highlighted, clears shadows for horizontal
+                menu item */
+             if (!highlighted_p)
+               draw_shadow_rectangle (mw, ws->pixmap, x, y, width, height,
+                                      True, False, NULL, NULL);
            }
 #ifdef USE_CAIRO
          if (ws->xft_draw)
            cairo_surface_flush (cairo_get_target (ws->xft_draw));
 #endif
-
-         if (highlighted_p)
-           draw_shadow_rectangle (mw, ws->pixmap, x, y, width, height, False,
-                                  False);
        }
     }
-
   where->x += width;
   where->y += height;
 }
@@ -1259,7 +1336,7 @@ display_menu (XlwMenuWidget mw,
   if (!just_compute_p)
     {
       draw_shadow_rectangle (mw, ws->pixmap, 0, 0, ws->width, ws->height,
-                             False, False);
+                             False, False, NULL, NULL);
       XCopyArea (XtDisplay (mw), ws->pixmap, ws->window,
                  mw->menu.foreground_gc, 0, 0, ws->width, ws->height, 0, 0);
     }
@@ -1645,7 +1722,7 @@ map_event_to_widget_value (XlwMenuWidget mw,
   return False;
 }
 
-/* Procedures */
+
 static void
 make_drawing_gcs (XlwMenuWidget mw)
 {
@@ -1716,6 +1793,20 @@ make_drawing_gcs (XlwMenuWidget mw)
   xgcv.foreground = mw->core.background_pixel;
   xgcv.background = mw->menu.foreground;
   mw->menu.background_gc = XtGetGC ((Widget)mw, mask, &xgcv);
+
+  xgcv.foreground = ((mw->menu.highlight_foreground == -1)
+                    ? mw->menu.foreground
+                    : mw->menu.highlight_foreground);
+  xgcv.background = ((mw->menu.highlight_background == -1)
+                    ? mw->core.background_pixel
+                    : mw->menu.highlight_background);
+  mw->menu.highlight_foreground_gc = XtGetGC ((Widget)mw, mask, &xgcv);
+
+  xgcv.foreground = ((mw->menu.highlight_background == -1)
+                    ? mw->core.background_pixel
+                    : mw->menu.highlight_background);
+  xgcv.background = mw->menu.foreground;
+  mw->menu.highlight_background_gc = XtGetGC ((Widget)mw, mask, &xgcv);
 }
 
 static void
@@ -1726,12 +1817,16 @@ release_drawing_gcs (XlwMenuWidget mw)
   XtReleaseGC ((Widget) mw, mw->menu.disabled_gc);
   XtReleaseGC ((Widget) mw, mw->menu.inactive_button_gc);
   XtReleaseGC ((Widget) mw, mw->menu.background_gc);
+  XtReleaseGC ((Widget) mw, mw->menu.highlight_foreground_gc);
+  XtReleaseGC ((Widget) mw, mw->menu.highlight_background_gc);
   /* let's get some segvs if we try to use these... */
   mw->menu.foreground_gc = (GC) -1;
   mw->menu.button_gc = (GC) -1;
   mw->menu.disabled_gc = (GC) -1;
   mw->menu.inactive_button_gc = (GC) -1;
   mw->menu.background_gc = (GC) -1;
+  mw->menu.highlight_foreground_gc = (GC) -1;
+  mw->menu.highlight_background_gc = (GC) -1;
 }
 
 #ifndef emacs
@@ -1740,33 +1835,29 @@ release_drawing_gcs (XlwMenuWidget mw)
 #endif
 
 static void
-make_shadow_gcs (XlwMenuWidget mw)
+compute_shadow_colors (XlwMenuWidget mw, Pixel *top_color, Pixel *bottom_color,
+                      Boolean *free_top_p, Boolean *free_bottom_p,
+                      Pixmap *top_pixmap, Pixmap *bottom_pixmap,
+                      Pixel fore_color, Pixel back_color)
 {
-  XGCValues xgcv;
-  unsigned long pm = 0;
   Display *dpy = XtDisplay ((Widget) mw);
   Screen *screen = XtScreen ((Widget) mw);
   Colormap cmap = mw->core.colormap;
   XColor topc, botc;
   int top_frobbed = 0, bottom_frobbed = 0;
 
-  mw->menu.free_top_shadow_color_p = 0;
-  mw->menu.free_bottom_shadow_color_p = 0;
+  *free_top_p = False;
+  *free_bottom_p = False;
 
-  if (mw->menu.top_shadow_color == -1)
-    mw->menu.top_shadow_color = mw->core.background_pixel;
-  else
-    mw->menu.top_shadow_color = mw->menu.top_shadow_color;
+  if (*top_color == -1)
+    *top_color = back_color;
 
-  if (mw->menu.bottom_shadow_color == -1)
-    mw->menu.bottom_shadow_color = mw->menu.foreground;
-  else
-    mw->menu.bottom_shadow_color = mw->menu.bottom_shadow_color;
+  if (*bottom_color == -1)
+    *bottom_color = fore_color;
 
-  if (mw->menu.top_shadow_color == mw->core.background_pixel ||
-      mw->menu.top_shadow_color == mw->menu.foreground)
+  if (*top_color == back_color || *top_color == fore_color)
     {
-      topc.pixel = mw->core.background_pixel;
+      topc.pixel = back_color;
 #ifdef emacs
       if (x_alloc_lighter_color_for_widget ((Widget) mw, dpy, cmap,
                                            &topc.pixel,
@@ -1780,15 +1871,14 @@ make_shadow_gcs (XlwMenuWidget mw)
       if (XAllocColor (dpy, cmap, &topc))
 #endif
        {
-         mw->menu.top_shadow_color = topc.pixel;
-         mw->menu.free_top_shadow_color_p = 1;
+         *top_color = topc.pixel;
+         *free_top_p = True;
          top_frobbed = 1;
        }
     }
-  if (mw->menu.bottom_shadow_color == mw->menu.foreground ||
-      mw->menu.bottom_shadow_color == mw->core.background_pixel)
+  if (*bottom_color == fore_color || *bottom_color == back_color)
     {
-      botc.pixel = mw->core.background_pixel;
+      botc.pixel = back_color;
 #ifdef emacs
       if (x_alloc_lighter_color_for_widget ((Widget) mw, dpy, cmap,
                                            &botc.pixel,
@@ -1801,8 +1891,8 @@ make_shadow_gcs (XlwMenuWidget mw)
       if (XAllocColor (dpy, cmap, &botc))
 #endif
        {
-         mw->menu.bottom_shadow_color = botc.pixel;
-         mw->menu.free_bottom_shadow_color_p = 1;
+         *bottom_color = botc.pixel;
+         *free_bottom_p = True;
          bottom_frobbed = 1;
        }
     }
@@ -1811,84 +1901,125 @@ make_shadow_gcs (XlwMenuWidget mw)
     {
       if (topc.pixel == botc.pixel)
        {
-         if (botc.pixel == mw->menu.foreground)
+         if (botc.pixel == fore_color)
            {
-             if (mw->menu.free_top_shadow_color_p)
+             if (*free_top_p)
                {
-                 x_free_dpy_colors (dpy, screen, cmap,
-                                    &mw->menu.top_shadow_color, 1);
-                 mw->menu.free_top_shadow_color_p = 0;
+                 x_free_dpy_colors (dpy, screen, cmap, top_color, 1);
+                 *free_top_p = False;
                }
-             mw->menu.top_shadow_color = mw->core.background_pixel;
+             *top_color = back_color;
            }
          else
            {
-             if (mw->menu.free_bottom_shadow_color_p)
+             if (*free_bottom_p)
                {
-                 x_free_dpy_colors (dpy, screen, cmap,
-                                    &mw->menu.bottom_shadow_color, 1);
-                 mw->menu.free_bottom_shadow_color_p = 0;
+                 x_free_dpy_colors (dpy, screen, cmap, bottom_color, 1);
+                 *free_bottom_p = False;
                }
-             mw->menu.bottom_shadow_color = mw->menu.foreground;
+             *bottom_color = fore_color;
            }
        }
     }
 
-  if (!mw->menu.top_shadow_pixmap
-      && mw->menu.top_shadow_color == mw->core.background_pixel)
+  if (!*top_pixmap && *top_color == back_color)
     {
-      mw->menu.top_shadow_pixmap = mw->menu.gray_pixmap;
-      if (mw->menu.free_top_shadow_color_p)
+      *top_pixmap = mw->menu.gray_pixmap;
+      if (*free_top_p)
        {
-         x_free_dpy_colors (dpy, screen, cmap, &mw->menu.top_shadow_color, 1);
-         mw->menu.free_top_shadow_color_p = 0;
+         x_free_dpy_colors (dpy, screen, cmap, top_color, 1);
+         *free_top_p = False;
        }
-      mw->menu.top_shadow_color = mw->menu.foreground;
+      *top_color = fore_color;
     }
-  if (!mw->menu.bottom_shadow_pixmap
-      && mw->menu.bottom_shadow_color == mw->core.background_pixel)
+  if (!*bottom_pixmap && *bottom_color == back_color)
     {
-      mw->menu.bottom_shadow_pixmap = mw->menu.gray_pixmap;
-      if (mw->menu.free_bottom_shadow_color_p)
+      *bottom_pixmap = mw->menu.gray_pixmap;
+      if (*free_bottom_p)
        {
-         x_free_dpy_colors (dpy, screen, cmap,
-                            &mw->menu.bottom_shadow_color, 1);
-         mw->menu.free_bottom_shadow_color_p = 0;
+         x_free_dpy_colors (dpy, screen, cmap, bottom_color, 1);
+         *free_bottom_p = False;
        }
-      mw->menu.bottom_shadow_color = mw->menu.foreground;
+      *bottom_color = fore_color;
     }
+}
+
+static void
+make_shadow_gcs (XlwMenuWidget mw)
+{
+  XGCValues xgcv;
+  unsigned long pm = 0;
+  Pixel highlight_fg;
+
+  highlight_fg = mw->menu.highlight_foreground;
+
+  if (highlight_fg == -1)
+    highlight_fg = mw->menu.foreground;
+
+  /* Normal shadows */
+  compute_shadow_colors (mw, &(mw->menu.top_shadow_color),
+                        &(mw->menu.bottom_shadow_color),
+                        &(mw->menu.free_top_shadow_color_p),
+                        &(mw->menu.free_bottom_shadow_color_p),
+                        &(mw->menu.top_shadow_pixmap),
+                        &(mw->menu.bottom_shadow_pixmap),
+                        mw->menu.foreground, mw->core.background_pixel);
+
+  /* Highlight shadows */
+  compute_shadow_colors (mw, &(mw->menu.top_highlight_shadow_color),
+                        &(mw->menu.bottom_highlight_shadow_color),
+                        &(mw->menu.free_top_highlight_shadow_color_p),
+                        &(mw->menu.free_bottom_highlight_shadow_color_p),
+                        &(mw->menu.top_highlight_shadow_pixmap),
+                        &(mw->menu.bottom_highlight_shadow_pixmap),
+                        highlight_fg, mw->menu.highlight_background);
 
   xgcv.fill_style = FillStippled;
   xgcv.foreground = mw->menu.top_shadow_color;
   xgcv.stipple = mw->menu.top_shadow_pixmap;
-  pm = (xgcv.stipple ? GCStipple|GCFillStyle : 0);
-  mw->menu.shadow_top_gc = XtGetGC ((Widget)mw, GCForeground | pm, &xgcv);
+  pm = (xgcv.stipple ? GCStipple | GCFillStyle : 0);
+  mw->menu.shadow_top_gc = XtGetGC ((Widget) mw, GCForeground | pm, &xgcv);
 
   xgcv.foreground = mw->menu.bottom_shadow_color;
   xgcv.stipple = mw->menu.bottom_shadow_pixmap;
-  pm = (xgcv.stipple ? GCStipple|GCFillStyle : 0);
-  mw->menu.shadow_bottom_gc = XtGetGC ((Widget)mw, GCForeground | pm, &xgcv);
+  pm = (xgcv.stipple ? GCStipple | GCFillStyle : 0);
+  mw->menu.shadow_bottom_gc = XtGetGC ((Widget) mw, GCForeground | pm, &xgcv);
+
+  xgcv.foreground = mw->menu.top_highlight_shadow_color;
+  xgcv.stipple = mw->menu.top_highlight_shadow_pixmap;
+  pm = (xgcv.stipple ? GCStipple | GCFillStyle : 0);
+  mw->menu.highlight_shadow_top_gc = XtGetGC ((Widget) mw, GCForeground | pm, 
&xgcv);
+
+  xgcv.foreground = mw->menu.bottom_highlight_shadow_color;
+  xgcv.stipple = mw->menu.bottom_highlight_shadow_pixmap;
+  pm = (xgcv.stipple ? GCStipple | GCFillStyle : 0);
+  mw->menu.highlight_shadow_bottom_gc = XtGetGC ((Widget) mw, GCForeground | 
pm, &xgcv);
 }
 
-
 static void
 release_shadow_gcs (XlwMenuWidget mw)
 {
   Display *dpy = XtDisplay ((Widget) mw);
   Screen *screen = XtScreen ((Widget) mw);
   Colormap cmap = mw->core.colormap;
-  Pixel px[2];
+  Pixel px[4];
   int i = 0;
 
   if (mw->menu.free_top_shadow_color_p)
     px[i++] = mw->menu.top_shadow_color;
   if (mw->menu.free_bottom_shadow_color_p)
     px[i++] = mw->menu.bottom_shadow_color;
+  if (mw->menu.free_top_highlight_shadow_color_p)
+    px[i++] = mw->menu.top_highlight_shadow_color;
+  if (mw->menu.free_bottom_highlight_shadow_color_p)
+    px[i++] = mw->menu.bottom_highlight_shadow_color;
   if (i > 0)
     x_free_dpy_colors (dpy, screen, cmap, px, i);
 
   XtReleaseGC ((Widget) mw, mw->menu.shadow_top_gc);
   XtReleaseGC ((Widget) mw, mw->menu.shadow_bottom_gc);
+  XtReleaseGC ((Widget) mw, mw->menu.highlight_shadow_top_gc);
+  XtReleaseGC ((Widget) mw, mw->menu.highlight_shadow_bottom_gc);
 }
 
 #if defined USE_CAIRO || defined HAVE_XFT
@@ -1929,6 +2060,46 @@ openXftFont (XlwMenuWidget mw)
 
   return mw->menu.xft_font != 0;
 }
+
+static void
+update_xft_colors (Widget w)
+{
+  XlwMenuWidget mw;
+  XColor colors[4];
+
+  mw = (XlwMenuWidget) w;
+
+  colors[0].pixel = mw->menu.xft_fg.pixel
+    = mw->menu.foreground;
+  colors[1].pixel = mw->menu.xft_bg.pixel
+    = mw->core.background_pixel;
+  colors[2].pixel = mw->menu.xft_disabled_fg.pixel
+    = mw->menu.disabled_foreground;
+  colors[3].pixel = mw->menu.xft_highlight_fg.pixel
+    = (mw->menu.highlight_foreground != -1
+       ? mw->menu.highlight_foreground
+       : mw->menu.foreground);
+
+  XQueryColors (XtDisplay (mw), mw->core.colormap,
+               colors, 4);
+
+  mw->menu.xft_fg.color.alpha = 0xFFFF;
+  mw->menu.xft_fg.color.red = colors[0].red;
+  mw->menu.xft_fg.color.green = colors[0].green;
+  mw->menu.xft_fg.color.blue = colors[0].blue;
+  mw->menu.xft_bg.color.alpha = 0xFFFF;
+  mw->menu.xft_bg.color.red = colors[1].red;
+  mw->menu.xft_bg.color.green = colors[1].green;
+  mw->menu.xft_bg.color.blue = colors[1].blue;
+  mw->menu.xft_disabled_fg.color.alpha = 0xFFFF;
+  mw->menu.xft_disabled_fg.color.red = colors[2].red;
+  mw->menu.xft_disabled_fg.color.green = colors[2].green;
+  mw->menu.xft_disabled_fg.color.blue = colors[2].blue;
+  mw->menu.xft_highlight_fg.color.alpha = 0xFFFF;
+  mw->menu.xft_highlight_fg.color.red = colors[3].red;
+  mw->menu.xft_highlight_fg.color.green = colors[3].green;
+  mw->menu.xft_highlight_fg.color.blue = colors[3].blue;
+}
 #endif
 
 static void
@@ -1970,6 +2141,11 @@ XlwMenuInitialize (Widget request, Widget w, ArgList 
args, Cardinal *num_args)
     mw->menu.font_extents = XExtentsOfFontSet (mw->menu.fontSet);
 #endif
 
+  mw->menu.top_highlight_shadow_color = -1;
+  mw->menu.bottom_highlight_shadow_color = -1;
+  mw->menu.top_highlight_shadow_pixmap = None;
+  mw->menu.bottom_highlight_shadow_pixmap = None;
+
   make_drawing_gcs (mw);
   make_shadow_gcs (mw);
 
@@ -2043,26 +2219,7 @@ XlwMenuRealize (Widget w, Mask *valueMask, 
XSetWindowAttributes *attributes)
 
 #if defined USE_CAIRO || defined HAVE_XFT
   if (mw->menu.xft_font)
-    {
-      XColor colors[3];
-      colors[0].pixel = mw->menu.xft_fg.pixel = mw->menu.foreground;
-      colors[1].pixel = mw->menu.xft_bg.pixel = mw->core.background_pixel;
-      colors[2].pixel = mw->menu.xft_disabled_fg.pixel
-        = mw->menu.disabled_foreground;
-      XQueryColors (XtDisplay (mw), mw->core.colormap, colors, 3);
-      mw->menu.xft_fg.color.alpha = 0xFFFF;
-      mw->menu.xft_fg.color.red = colors[0].red;
-      mw->menu.xft_fg.color.green = colors[0].green;
-      mw->menu.xft_fg.color.blue = colors[0].blue;
-      mw->menu.xft_bg.color.alpha = 0xFFFF;
-      mw->menu.xft_bg.color.red = colors[1].red;
-      mw->menu.xft_bg.color.green = colors[1].green;
-      mw->menu.xft_bg.color.blue = colors[1].blue;
-      mw->menu.xft_disabled_fg.color.alpha = 0xFFFF;
-      mw->menu.xft_disabled_fg.color.red = colors[2].red;
-      mw->menu.xft_disabled_fg.color.green = colors[2].green;
-      mw->menu.xft_disabled_fg.color.blue = colors[2].blue;
-    }
+    update_xft_colors (w);
 #endif
 }
 
@@ -2104,6 +2261,7 @@ XlwMenuDestroy (Widget w)
   if (pointer_grabbed)
     ungrab_all ((Widget)w, CurrentTime);
   pointer_grabbed = 0;
+  keyboard_grabbed = 0;
 
   if (!XtIsShell (XtParent (w)))
     submenu_destroyed = 1;
@@ -2229,6 +2387,12 @@ XlwMenuSetValues (Widget current, Widget request, Widget 
new,
            XClearArea (XtDisplay (oldmw), oldmw->menu.windows[i].window,
                        0, 0, 0, 0, True);
          }
+
+      /* Colors changed.  Update the Xft colors as well.  */
+#if defined USE_CAIRO || defined HAVE_XFT
+      if (oldmw->menu.xft_font)
+       update_xft_colors (new);
+#endif
     }
 
 #if defined USE_CAIRO || defined HAVE_XFT
@@ -2721,15 +2885,22 @@ pop_up_menu (XlwMenuWidget mw, XButtonPressedEvent 
*event)
                      mw->menu.cursor_shape,
                      event->time) == Success)
     {
-      if (! GRAB_KEYBOARD
-          || XtGrabKeyboard ((Widget)mw, False, GrabModeAsync,
-                             GrabModeAsync, event->time) == Success)
+      if (true
+#ifdef emacs
+         && lucid__menu_grab_keyboard
+#endif
+         && XtGrabKeyboard ((Widget) mw, False, GrabModeAsync,
+                            GrabModeAsync, event->time) == Success)
         {
-          XtSetKeyboardFocus((Widget)mw, None);
+          XtSetKeyboardFocus ((Widget) mw, None);
           pointer_grabbed = 1;
+         keyboard_grabbed = 1;
         }
       else
-        XtUngrabPointer ((Widget)mw, event->time);
+       {
+         XtUngrabPointer ((Widget) mw, event->time);
+         keyboard_grabbed = 0;
+       }
     }
 
 #ifdef emacs
diff --git a/lwlib/xlwmenu.h b/lwlib/xlwmenu.h
index 7f4bf35939..4e36bde3fb 100644
--- a/lwlib/xlwmenu.h
+++ b/lwlib/xlwmenu.h
@@ -58,6 +58,10 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #define XtCAllowResize "AllowResize"
 #define XtNborderThickness "borderThickness"
 #define XtCBorderThickness "BorderThickness"
+#define XtNhighlightForeground "highlightForeground"
+#define XtCHighlightForeground "HighlightForeground"
+#define XtNhighlightBackground "highlightBackground"
+#define XtCHighlightBackground "HighlightBackground"
 
 /* Motif-compatible resource names */
 #define XmNshadowThickness     "shadowThickness"
diff --git a/lwlib/xlwmenuP.h b/lwlib/xlwmenuP.h
index 455ecdbce0..c314eb3e91 100644
--- a/lwlib/xlwmenuP.h
+++ b/lwlib/xlwmenuP.h
@@ -63,13 +63,15 @@ typedef struct _XlwMenu_part
 #if defined USE_CAIRO || defined HAVE_XFT
   int           default_face;
   XftFont*      xft_font;
-  XftColor      xft_fg, xft_bg, xft_disabled_fg;
+  XftColor      xft_fg, xft_bg, xft_disabled_fg, xft_highlight_fg;
 #endif
   String       fontName;
   XFontStruct* font;
   Pixel                foreground;
   Pixel                disabled_foreground;
   Pixel                button_foreground;
+  Pixel                highlight_foreground;
+  Pixel                highlight_background;
   Dimension    margin;
   Dimension    horizontal_spacing;
   Dimension    vertical_spacing;
@@ -80,6 +82,10 @@ typedef struct _XlwMenu_part
   Pixel        bottom_shadow_color;
   Pixmap       top_shadow_pixmap;
   Pixmap       bottom_shadow_pixmap;
+  Pixel        top_highlight_shadow_color;
+  Pixel        bottom_highlight_shadow_color;
+  Pixmap       top_highlight_shadow_pixmap;
+  Pixmap       bottom_highlight_shadow_pixmap;
   Cursor       cursor_shape;
   XtCallbackList       open;
   XtCallbackList       select, highlight;
@@ -88,8 +94,10 @@ typedef struct _XlwMenu_part
   int          horizontal;
 
   /* True means top_shadow_color and/or bottom_shadow_color must be freed.  */
-  bool_bf free_top_shadow_color_p : 1;
-  bool_bf free_bottom_shadow_color_p : 1;
+  Boolean free_top_shadow_color_p;
+  Boolean free_bottom_shadow_color_p;
+  Boolean free_top_highlight_shadow_color_p;
+  Boolean free_bottom_highlight_shadow_color_p;
 
   /* State of the XlwMenu */
   int                   top_depth;
@@ -112,9 +120,13 @@ typedef struct _XlwMenu_part
   GC                   button_gc;
   GC                   background_gc;
   GC                   disabled_gc;
+  GC                   highlight_foreground_gc;
+  GC                   highlight_background_gc;
   GC                   inactive_button_gc;
   GC                   shadow_top_gc;
   GC                   shadow_bottom_gc;
+  GC                   highlight_shadow_top_gc;
+  GC                   highlight_shadow_bottom_gc;
   Cursor               cursor;
   Boolean              popped_up;
   Pixmap               gray_pixmap;
diff --git a/m4/fchmodat.m4 b/m4/fchmodat.m4
index a5cf95a88b..f743ce1b02 100644
--- a/m4/fchmodat.m4
+++ b/m4/fchmodat.m4
@@ -1,4 +1,4 @@
-# fchmodat.m4 serial 6
+# fchmodat.m4 serial 7
 dnl Copyright (C) 2004-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,
@@ -97,6 +97,6 @@ AC_DEFUN([gl_FUNC_FCHMODAT],
 # Prerequisites of lib/fchmodat.c.
 AC_DEFUN([gl_PREREQ_FCHMODAT],
 [
-  AC_CHECK_FUNCS_ONCE([lchmod])
+  AC_CHECK_FUNCS_ONCE([readlinkat])
   :
 ])
diff --git a/m4/gnulib-common.m4 b/m4/gnulib-common.m4
index 30911d1581..8a5daa230e 100644
--- a/m4/gnulib-common.m4
+++ b/m4/gnulib-common.m4
@@ -313,7 +313,8 @@ AC_DEFUN([gl_COMMON_BODY], [
 #else
 # define _GL_ATTRIBUTE_MAYBE_UNUSED _GL_ATTRIBUTE_UNUSED
 #endif
-/* Alternative spelling of this macro, for convenience.  */
+/* Alternative spelling of this macro, for convenience and for
+   compatibility with glibc/include/libc-symbols.h.  */
 #define _GL_UNUSED _GL_ATTRIBUTE_MAYBE_UNUSED
 /* Earlier spellings of this macro.  */
 #define _UNUSED_PARAMETER_ _GL_ATTRIBUTE_MAYBE_UNUSED
diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4
index fb5f1b52a4..0c43dde716 100644
--- a/m4/gnulib-comp.m4
+++ b/m4/gnulib-comp.m4
@@ -171,6 +171,7 @@ AC_DEFUN([gl_EARLY],
   # Code from module stat-time:
   # Code from module std-gnu11:
   # Code from module stdalign:
+  # Code from module stdckdint:
   # Code from module stddef:
   # Code from module stdint:
   # Code from module stdio:
@@ -631,6 +632,7 @@ AC_DEFUN([gl_INIT],
   gl_gnulib_enabled_61bcaca76b3e6f9ae55d57a1c3193bc4=false
   gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c=false
   gl_gnulib_enabled_scratch_buffer=false
+  gl_gnulib_enabled_stdckdint=false
   gl_gnulib_enabled_strtoll=false
   gl_gnulib_enabled_utimens=false
   gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec=false
@@ -743,6 +745,9 @@ AC_DEFUN([gl_INIT],
       if test $HAVE_GROUP_MEMBER = 0; then
         func_gl_gnulib_m4code_d3b2383720ee0e541357aa2aac598e2b
       fi
+      if test $HAVE_GROUP_MEMBER = 0; then
+        func_gl_gnulib_m4code_stdckdint
+      fi
     fi
   }
   func_gl_gnulib_m4code_lchmod ()
@@ -880,6 +885,20 @@ AC_DEFUN([gl_INIT],
       func_gl_gnulib_m4code_61bcaca76b3e6f9ae55d57a1c3193bc4
     fi
   }
+  func_gl_gnulib_m4code_stdckdint ()
+  {
+    if ! $gl_gnulib_enabled_stdckdint; then
+      AC_CHECK_HEADERS_ONCE([stdckdint.h])
+      if test $ac_cv_header_stdckdint_h = yes; then
+        GL_GENERATE_STDCKDINT_H=false
+      else
+        GL_GENERATE_STDCKDINT_H=true
+      fi
+      gl_CONDITIONAL_HEADER([stdckdint.h])
+      AC_PROG_MKDIR_P
+      gl_gnulib_enabled_stdckdint=true
+    fi
+  }
   func_gl_gnulib_m4code_strtoll ()
   {
     if ! $gl_gnulib_enabled_strtoll; then
@@ -1006,6 +1025,7 @@ AC_DEFUN([gl_INIT],
   AM_CONDITIONAL([gl_GNULIB_ENABLED_61bcaca76b3e6f9ae55d57a1c3193bc4], 
[$gl_gnulib_enabled_61bcaca76b3e6f9ae55d57a1c3193bc4])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_6099e9737f757db36c47fa9d9f02e88c], 
[$gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_scratch_buffer], 
[$gl_gnulib_enabled_scratch_buffer])
+  AM_CONDITIONAL([gl_GNULIB_ENABLED_stdckdint], [$gl_gnulib_enabled_stdckdint])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_strtoll], [$gl_gnulib_enabled_strtoll])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_utimens], [$gl_gnulib_enabled_utimens])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_682e609604ccaac6be382e4ee3a4eaec], 
[$gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec])
@@ -1277,6 +1297,7 @@ AC_DEFUN([gl_FILE_LIST], [
   lib/idx.h
   lib/ieee754.in.h
   lib/ignore-value.h
+  lib/intprops-internal.h
   lib/intprops.h
   lib/inttypes.in.h
   lib/lchmod.c
@@ -1349,6 +1370,7 @@ AC_DEFUN([gl_FILE_LIST], [
   lib/stat-time.c
   lib/stat-time.h
   lib/stdalign.in.h
+  lib/stdckdint.in.h
   lib/stddef.in.h
   lib/stdint.in.h
   lib/stdio-impl.h
diff --git a/m4/largefile.m4 b/m4/largefile.m4
index 3e8b5e39a7..ec9677c46d 100644
--- a/m4/largefile.m4
+++ b/m4/largefile.m4
@@ -10,8 +10,10 @@
 # It does not set _LARGEFILE_SOURCE=1 on HP-UX/ia64 32-bit, although this
 # setting of _LARGEFILE_SOURCE is needed so that <stdio.h> declares fseeko
 # and ftello in C++ mode as well.
+# Fixed in Autoconf 2.72, which has AC_SYS_YEAR2038.
 AC_DEFUN([gl_SET_LARGEFILE_SOURCE],
 [
+ m4_ifndef([AC_SYS_YEAR2038], [
   AC_REQUIRE([AC_CANONICAL_HOST])
   AC_FUNC_FSEEKO
   case "$host_os" in
@@ -20,9 +22,10 @@ AC_DEFUN([gl_SET_LARGEFILE_SOURCE],
         [Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2).])
       ;;
   esac
+ ])
 ])
 
-# Work around a problem in Autoconf through at least 2.71 on glibc 2.34+
+# Work around a problem in Autoconf through 2.71 on glibc 2.34+
 # with _TIME_BITS.  Also, work around a problem in autoconf <= 2.69:
 # AC_SYS_LARGEFILE does not configure for large inodes on Mac OS X 10.5,
 # or configures them incorrectly in some cases.
@@ -43,6 +46,7 @@ m4_define([_AC_SYS_LARGEFILE_TEST_INCLUDES],
 ])
 ])# m4_version_prereq 2.70
 
+m4_ifndef([AC_SYS_YEAR2038], [
 
 # _AC_SYS_LARGEFILE_MACRO_VALUE(C-MACRO, VALUE,
 #                               CACHE-VAR,
@@ -118,6 +122,7 @@ AS_IF([test "$enable_largefile" != no],
     [64],
       [gl_YEAR2038_BODY([])])])
 ])# AC_SYS_LARGEFILE
+])# m4_ifndef AC_SYS_YEAR2038
 
 # Enable large files on systems where this is implemented by Gnulib, not by the
 # system headers.
diff --git a/m4/lchmod.m4 b/m4/lchmod.m4
index 5baee738ef..cd43beed85 100644
--- a/m4/lchmod.m4
+++ b/m4/lchmod.m4
@@ -1,4 +1,4 @@
-#serial 8
+#serial 10
 
 dnl Copyright (C) 2005-2006, 2008-2022 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
@@ -15,9 +15,7 @@ AC_DEFUN([gl_FUNC_LCHMOD],
   dnl Persuade glibc <sys/stat.h> to declare lchmod().
   AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
 
-  AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
-
-  AC_CHECK_FUNCS_ONCE([lchmod lstat])
+  AC_CHECK_FUNCS_ONCE([lchmod])
   if test "$ac_cv_func_lchmod" = no; then
     HAVE_LCHMOD=0
   fi
diff --git a/m4/sys_stat_h.m4 b/m4/sys_stat_h.m4
index b5a9789b81..2adbfdeef4 100644
--- a/m4/sys_stat_h.m4
+++ b/m4/sys_stat_h.m4
@@ -1,4 +1,4 @@
-# sys_stat_h.m4 serial 41   -*- Autoconf -*-
+# sys_stat_h.m4 serial 42   -*- Autoconf -*-
 dnl Copyright (C) 2006-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,
@@ -46,7 +46,7 @@ AC_DEFUN_ONCE([gl_SYS_STAT_H],
   dnl Check for declarations of anything we want to poison if the
   dnl corresponding gnulib module is not in use.
   gl_WARN_ON_USE_PREPARE([[#include <sys/stat.h>
-    ]], [fchmodat fstat fstatat futimens getumask lchmod lstat
+    ]], [chmod fchmodat fstat fstatat futimens getumask lchmod lstat
     mkdirat mkfifo mkfifoat mknod mknodat stat utimensat])
 
   AC_REQUIRE([AC_C_RESTRICT])
@@ -72,6 +72,7 @@ AC_DEFUN([gl_SYS_STAT_H_REQUIRE_DEFAULTS],
 [
   m4_defun(GL_MODULE_INDICATOR_PREFIX[_SYS_STAT_H_MODULE_INDICATOR_DEFAULTS], [
     gl_UNISTD_H_REQUIRE_DEFAULTS dnl for REPLACE_FCHDIR
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_CHMOD])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FCHMODAT])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FSTAT])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FSTATAT])
@@ -112,6 +113,7 @@ AC_DEFUN([gl_SYS_STAT_H_DEFAULTS],
   HAVE_MKNOD=1;         AC_SUBST([HAVE_MKNOD])
   HAVE_MKNODAT=1;       AC_SUBST([HAVE_MKNODAT])
   HAVE_UTIMENSAT=1;     AC_SUBST([HAVE_UTIMENSAT])
+  REPLACE_CHMOD=0;      AC_SUBST([REPLACE_CHMOD])
   REPLACE_FCHMODAT=0;   AC_SUBST([REPLACE_FCHMODAT])
   REPLACE_FSTAT=0;      AC_SUBST([REPLACE_FSTAT])
   REPLACE_FSTATAT=0;    AC_SUBST([REPLACE_FSTATAT])
diff --git a/m4/year2038.m4 b/m4/year2038.m4
index 06db589ba9..2e4427e6fa 100644
--- a/m4/year2038.m4
+++ b/m4/year2038.m4
@@ -1,4 +1,4 @@
-# year2038.m4 serial 7
+# year2038.m4 serial 8
 dnl Copyright (C) 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,
@@ -7,6 +7,12 @@ dnl with or without modifications, as long as this notice is 
preserved.
 dnl Attempt to ensure that 'time_t' can go past the year 2038 and that
 dnl the functions 'time', 'stat', etc. work with post-2038 timestamps.
 
+m4_ifdef([AC_SYS_YEAR2038], [
+  AC_DEFUN([gl_YEAR2038_EARLY])
+  AC_DEFUN([gl_YEAR2038], [AC_SYS_YEAR2038])
+  AC_DEFUN([gl_YEAR2038_BODY], [_AC_SYS_YEAR2038])
+], [
+
 AC_DEFUN([gl_YEAR2038_EARLY],
 [
   AC_REQUIRE([AC_CANONICAL_HOST])
@@ -122,3 +128,5 @@ AC_DEFUN([gl_YEAR2038],
 [
   gl_YEAR2038_BODY([require-year2038-safe])
 ])
+
+]) # m4_ifndef AC_SYS_YEAR2038
diff --git a/make-dist b/make-dist
index 447e90f018..4646a2809b 100755
--- a/make-dist
+++ b/make-dist
@@ -174,7 +174,7 @@ fi
 
 ### Find out which version of Emacs this is.
 version=`
-  sed -n 's/^AC_INIT(GNU Emacs,[        ]*\([^  ,)]*\).*/\1/p' <configure.ac
+  sed -n 's/^AC_INIT(\[GNU Emacs],[     ]*\[\([^]]*\).*/\1/p' <configure.ac
 ` || version=
 if [ ! "${version}" ]; then
   printf '%s\n' \
@@ -485,6 +485,8 @@ if [ "${make_tar}" = yes ]; then
   esac
   echo "Creating tar file"
   taropt='--numeric-owner --owner=0 --group=0 --mode=go+u,go-w'
+  tar -H ustar -cf /dev/null $tempdir/src/lisp.h 2>/dev/null &&
+    taropt="$taropt -H ustar"
   tar --sort=name -cf /dev/null $tempdir/src/lisp.h 2>/dev/null &&
     taropt="$taropt --sort=name"
   [ "$verbose" = "yes" ] && taropt="$taropt --verbose"
diff --git a/msdos/sedlibmk.inp b/msdos/sedlibmk.inp
index 302fefe19f..79430bbaf1 100644
--- a/msdos/sedlibmk.inp
+++ b/msdos/sedlibmk.inp
@@ -192,6 +192,9 @@ s/@PACKAGE@/emacs/
 /^GL_GNULIB_TIMEGM *=/s/@GL_GNULIB_TIMEGM@/1/
 /^GL_GNULIB_TIME_RZ *=/s/@GL_GNULIB_TIME_RZ@/1/
 /^GL_GNULIB_UNSETENV *=/s/@GL_GNULIB_UNSETENV@/1/
+# Apparently without this `rawmemchr' isn't declared, so
+# we get warnings building canonicalize-lgpl.o
+/^GL_GNULIB_RAWMEMCHR *=/s/@GL_GNULIB_RAWMEMCHR@/1/
 /^GL_GNULIB_[^ =]* *= *@/s/@[^@\n]*@/0/
 /^GL_GSETTINGS_CFLAGS *=/s/@[^@\n]*@//
 /^GL_GSETTINGS_LIBS *=/s/@[^@\n]*@//
@@ -330,6 +333,7 @@ s/@PACKAGE@/emacs/
 /^LIMITS_H *=/s/@[^@\n]*@/limits.h/
 /^IEEE754_H *=/s/@[^@\n]*@/ieee754.h/
 /^STDALIGN_H *=/s/@[^@\n]*@/stdalign.h/
+/^STDCKDINT_H *=/s/@[^@\n]*@/stdckdint.h/
 /^STDDEF_H *=/s/@[^@\n]*@/stddef.h/
 /^STDINT_H *=/s/@[^@\n]*@/stdint.h/
 /^SYS_TIME_H_DEFINES_STRUCT_TIMESPEC *=/s/@[^@\n]*@/0/
@@ -421,6 +425,7 @@ s/= @GL_GENERATE_LIMITS_H_CONDITION@/= /
 s/= @GL_GENERATE_GMP_H_CONDITION@/= 1/
 s/= @GL_GENERATE_GMP_GMP_H_CONDITION@/= /
 s/= @GL_GENERATE_MINI_GMP_H_CONDITION@/= 1/
+s/= @GL_GENERATE_STDCKDINT_H_CONDITION@/= 1/
 s/= @GL_COND_OBJ_STDIO_READ_CONDITION@/= /
 s/= @GL_COND_OBJ_STDIO_WRITE_CONDITION@/= /
 s/\$\(MKDIR_P\) malloc//
diff --git a/nextstep/Makefile.in b/nextstep/Makefile.in
index 9c7059f2c0..82bf13bc92 100644
--- a/nextstep/Makefile.in
+++ b/nextstep/Makefile.in
@@ -26,6 +26,7 @@ srcdir = @srcdir@
 abs_builddir = @abs_builddir@
 abs_top_builddir = @abs_top_builddir@
 EXEEXT = @EXEEXT@
+DUMPING = @DUMPING@
 
 # abs_top_srcdir may contain ".."
 top_srcdir_abs = $(shell cd @top_srcdir@; pwd -P)
@@ -45,7 +46,11 @@ ns_check_file = @ns_appdir@/@ns_check_file@
 
 .PHONY: all
 
-all: ${ns_appdir} ${ns_appbindir}/Emacs ${ns_applibexecdir}/Emacs.pdmp
+ifeq ($(DUMPING),pdumper)
+ns_pdmp_target = ${ns_applibexecdir}/Emacs.pdmp
+endif
+
+all: ${ns_appdir} ${ns_appbindir}/Emacs ${ns_pdmp_target}
 
 ${ns_check_file}: ${ns_appdir}
 
diff --git a/src/.lldbinit b/src/.lldbinit
new file mode 100644
index 0000000000..358cea5f8b
--- /dev/null
+++ b/src/.lldbinit
@@ -0,0 +1,33 @@
+# -*- mode: shell-script -*-
+# 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, 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/>.
+#
+# Use 'lldb --local-init' or add to your ~/.lldbinit the line
+#
+# settings set target.load-cwd-lldbinit true
+#
+# Emacs-specific commands start with 'x'.  Type 'help' to see all
+# commands.  Type 'help <command>' to see help for a command
+# <command>.
+
+# Make Python find our files
+script -- sys.path.append('../etc')
+
+# Load our Python files
+command script import emacs_lldb
+
+# end.
diff --git a/src/Makefile.in b/src/Makefile.in
index a21af42c0b..eb537e2127 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -639,30 +639,23 @@ Emacs.pdmp: $(pdmp)
 endif
 
 ifeq ($(DUMPING),pdumper)
-$(pdmp): emacs$(EXEEXT)
+$(pdmp): emacs$(EXEEXT) $(lispsource)/loaddefs.el $(lispsource)/loaddefs.elc
        LC_ALL=C $(RUN_TEMACS) -batch $(BUILD_DETAILS) -l loadup --temacs=pdump 
\
                --bin-dest $(BIN_DESTDIR) --eln-dest $(ELN_DESTDIR)
        cp -f $@ $(bootstrap_pdmp)
 endif
 
-## We run make-docfile twice because the command line may get too long
-## on some systems.  Unfortunately, no-one has any idea
-## exactly how long the maximum safe command line length is on all the
-## various systems that Emacs supports.
-##
 ## $(SOME_MACHINE_OBJECTS) comes before $(obj) because some files may
 ## or may not be included in $(obj), but they are always included in
 ## $(SOME_MACHINE_OBJECTS).  Since a file is processed when it is mentioned
 ## for the first time, this prevents any variation between configurations
 ## in the contents of the DOC file.
 ##
-$(etc)/DOC: $(libsrc)/make-docfile$(EXEEXT) $(doc_obj) 
$(lispsource)/loaddefs.el
+$(etc)/DOC: $(libsrc)/make-docfile$(EXEEXT) $(doc_obj)
        $(AM_V_GEN)$(MKDIR_P) $(etc)
        $(AM_V_at)rm -f $(etc)/DOC
        $(AM_V_at)$(libsrc)/make-docfile -d $(srcdir) \
          $(SOME_MACHINE_OBJECTS) $(doc_obj) > $(etc)/DOC
-       $(AM_V_at)$(libsrc)/make-docfile -a $(etc)/DOC -d $(lispsource) \
-         loaddefs.el
 
 $(libsrc)/make-docfile$(EXEEXT) $(libsrc)/make-fingerprint$(EXEEXT): \
   $(lib)/libgnu.a
@@ -801,11 +794,12 @@ ctagsfiles3 = $(wildcard ${srcdir}/*.cc)
 ## In out-of-tree builds, TAGS are generated in the build dir, like
 ## other non-bootstrap build products (see Bug#31744).
 
-## This does not need to depend on ../lisp and ../lwlib TAGS files,
+## This does not need to depend on ../lisp, ../lwlib and ../lib TAGS files,
 ## because etags "--include" only includes a pointer to the file,
 ## rather than the file contents.
 TAGS: ${ETAGS} $(ctagsfiles1) $(ctagsfiles2)
        $(AM_V_GEN)${ETAGS} --include=../lisp/TAGS --include=$(lwlibdir)/TAGS \
+         --include=$(lib)/TAGS \
          --regex='{c}/[        ]*DEFVAR_[A-Z_  (]+"\([^"]+\)"/\1/' \
          --regex='{c}/[        ]*DEFVAR_[A-Z_  (]+"[^"]+",[    
]\([A-Za-z0-9_]+\)/\1/' \
          $(ctagsfiles1) \
@@ -814,12 +808,12 @@ TAGS: ${ETAGS} $(ctagsfiles1) $(ctagsfiles2)
          $(ctagsfiles2) \
          $(ctagsfiles3)
 
-## Arrange to make tags tables for ../lisp and ../lwlib,
+## Arrange to make tags tables for ../lisp, ../lwlib and ../lib,
 ## which the above TAGS file for the C files includes by reference.
-../lisp/TAGS $(lwlibdir)/TAGS: FORCE
+../lisp/TAGS $(lwlibdir)/TAGS $(lib)/TAGS: FORCE
        $(MAKE) -C $(dir $@) $(notdir $@) ETAGS="$(ETAGS)"
 
-tags: TAGS ../lisp/TAGS $(lwlibdir)/TAGS
+tags: TAGS ../lisp/TAGS $(lwlibdir)/TAGS $(lib)/TAGS
 .PHONY: tags
 
 
@@ -856,7 +850,6 @@ ifeq ($(HAVE_NATIVE_COMP):$(NATIVE_DISABLED),yes:)
 ## List of *.eln files we need to produce in addition to the preloaded
 ## ones in $(lisp).
 elnlisp := \
-       emacs-lisp/autoload.eln \
        emacs-lisp/byte-opt.eln \
        emacs-lisp/bytecomp.eln \
        emacs-lisp/cconv.eln \
@@ -892,13 +885,7 @@ elnlisp := $(addprefix ${lispsource}/,${elnlisp}) 
$(lisp:.elc=.eln)
        fi
 endif
 
-## VCSWITNESS points to the file that holds info about the current checkout.
-## We use it as a heuristic to decide when to rebuild loaddefs.el.
-## If empty it is ignored; the parent makefile can set it to some other value.
-VCSWITNESS =
-
-$(lispsource)/loaddefs.el: $(VCSWITNESS) | \
-               bootstrap-emacs$(EXEEXT) $(bootstrap_pdmp)
+$(lispsource)/loaddefs.el: | bootstrap-emacs$(EXEEXT) $(bootstrap_pdmp)
        $(MAKE) -C ../lisp autoloads EMACS="$(bootstrap_exe)"
 
 ## Dump an Emacs executable named bootstrap-emacs containing the
diff --git a/src/alloc.c b/src/alloc.c
index 14c3a4cb8d..ced7c73cba 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -479,7 +479,7 @@ enum mem_type
 static bool
 deadp (Lisp_Object x)
 {
-  return EQ (x, dead_object ());
+  return BASE_EQ (x, dead_object ());
 }
 
 #ifdef GC_MALLOC_CHECK
@@ -5334,6 +5334,7 @@ static void *
 pure_alloc (size_t size, int type)
 {
   void *result;
+  static bool pure_overflow_warned = false;
 
  again:
   if (type >= 0)
@@ -5358,6 +5359,12 @@ pure_alloc (size_t size, int type)
   if (pure_bytes_used <= pure_size)
     return result;
 
+  if (!pure_overflow_warned)
+    {
+      message ("Pure Lisp storage overflowed");
+      pure_overflow_warned = true;
+    }
+
   /* Don't allocate a large amount here,
      because it might get mmap'd and then its address
      might not be usable.  */
@@ -5375,9 +5382,6 @@ pure_alloc (size_t size, int type)
   goto again;
 }
 
-
-#ifdef HAVE_UNEXEC
-
 /* Print a warning if PURESIZE is too small.  */
 
 void
@@ -5388,8 +5392,6 @@ check_pure_size (void)
              " bytes needed)"),
             pure_bytes_used + pure_bytes_used_before_overflow);
 }
-#endif
-
 
 /* Find the byte sequence {DATA[0], ..., DATA[NBYTES-1], '\0'} from
    the non-Lisp data pool of the pure storage, and return its start
@@ -6224,6 +6226,10 @@ garbage_collect (void)
   mark_xterm ();
 #endif
 
+#ifdef HAVE_NS
+  mark_nsterm ();
+#endif
+
   /* Everything is now marked, except for the data in font caches,
      undo lists, and finalizers.  The first two are compacted by
      removing an items which aren't reachable otherwise.  */
@@ -6282,6 +6288,11 @@ garbage_collect (void)
   /* GC is complete: now we can run our finalizer callbacks.  */
   run_finalizers (&doomed_finalizers);
 
+#ifdef HAVE_WINDOW_SYSTEM
+  /* Eject unused image cache entries.  */
+  image_prune_animation_caches (false);
+#endif
+
   if (!NILP (Vpost_gc_hook))
     {
       specpdl_ref gc_count = inhibit_garbage_collection ();
diff --git a/src/bidi.c b/src/bidi.c
index 4d2c74b17c..c4d04136e9 100644
--- a/src/bidi.c
+++ b/src/bidi.c
@@ -1277,6 +1277,12 @@ bidi_fetch_char (ptrdiff_t charpos, ptrdiff_t bytepos, 
ptrdiff_t *disp_pos,
       SET_TEXT_POS (pos, charpos, bytepos);
       *disp_pos = compute_display_string_pos (&pos, string, w, frame_window_p,
                                              disp_prop);
+      /* The factor of 100 below is a heuristic that needs to be
+        tuned.  It means we consider 100 buffer positions examined by
+        the above call roughly equivalent to the display engine
+        iterating over a single buffer position.  */
+      if (max_redisplay_ticks > 0 && *disp_pos > charpos)
+       update_redisplay_ticks ((*disp_pos - charpos) / 100 + 1, w);
     }
 
   /* Fetch the character at BYTEPOS.  */
@@ -1385,6 +1391,8 @@ bidi_fetch_char (ptrdiff_t charpos, ptrdiff_t bytepos, 
ptrdiff_t *disp_pos,
       SET_TEXT_POS (pos, charpos + *nchars, bytepos + *ch_len);
       *disp_pos = compute_display_string_pos (&pos, string, w, frame_window_p,
                                              disp_prop);
+      if (max_redisplay_ticks > 0 && *disp_pos > charpos + *nchars)
+       update_redisplay_ticks ((*disp_pos - charpos - *nchars) / 100 + 1, w);
     }
 
   return ch;
@@ -1583,6 +1591,9 @@ bidi_find_paragraph_start (ptrdiff_t pos, ptrdiff_t 
pos_byte)
   return pos_byte;
 }
 
+/* This tracks how far we needed to search for first strong character.  */
+static ptrdiff_t nsearch_for_strong;
+
 /* On a 3.4 GHz machine, searching forward for a strong directional
    character in a long paragraph full of weaks or neutrals takes about
    1 ms for each 20K characters.  The number below limits each call to
@@ -1652,6 +1663,8 @@ find_first_strong_char (ptrdiff_t pos, ptrdiff_t bytepos, 
ptrdiff_t end,
       pos += *nchars;
       bytepos += *ch_len;
     }
+
+  nsearch_for_strong += pos - pos1;
   return type;
 }
 
@@ -1681,6 +1694,9 @@ bidi_paragraph_init (bidi_dir_t dir, struct bidi_it 
*bidi_it, bool no_default_p)
      calls to BYTE_TO_CHAR and its ilk.  */
   ptrdiff_t begbyte = string_p ? 0 : BEGV_BYTE;
   ptrdiff_t end = string_p ? bidi_it->string.schars : ZV;
+  ptrdiff_t pos = bidi_it->charpos;
+
+  nsearch_for_strong = 0;
 
   /* Special case for an empty buffer. */
   if (bytepos == begbyte && bidi_it->charpos == end)
@@ -1702,7 +1718,7 @@ bidi_paragraph_init (bidi_dir_t dir, struct bidi_it 
*bidi_it, bool no_default_p)
   else if (dir == NEUTRAL_DIR) /* P2 */
     {
       ptrdiff_t ch_len, nchars;
-      ptrdiff_t pos, disp_pos = -1;
+      ptrdiff_t disp_pos = -1;
       int disp_prop = 0;
       bidi_type_t type;
       const unsigned char *s;
@@ -1800,6 +1816,14 @@ bidi_paragraph_init (bidi_dir_t dir, struct bidi_it 
*bidi_it, bool no_default_p)
     bidi_it->level_stack[0].level = 0;
 
   bidi_line_init (bidi_it);
+
+  /* The factor of 50 below is a heuristic that needs to be tuned.  It
+     means we consider 50 buffer positions examined by this function
+     roughly equivalent to the display engine iterating over a single
+     buffer position.  */
+  ptrdiff_t nexamined = bidi_it->charpos - pos + nsearch_for_strong;
+  if (max_redisplay_ticks > 0 && nexamined > 0)
+    update_redisplay_ticks (nexamined / 50, bidi_it->w);
 }
 
 
@@ -2566,6 +2590,7 @@ bidi_find_bracket_pairs (struct bidi_it *bidi_it)
   bidi_bracket_type_t btype;
   bidi_type_t type = bidi_it->type;
   bool retval = false;
+  ptrdiff_t n = 0;
 
   /* When scanning backwards, we don't expect any unresolved bidi
      bracket characters.  */
@@ -2695,6 +2720,7 @@ bidi_find_bracket_pairs (struct bidi_it *bidi_it)
            }
          old_sidx = bidi_it->stack_idx;
          type = bidi_resolve_weak (bidi_it);
+         n++;
          /* Skip level runs excluded from this isolating run sequence.  */
          new_sidx = bidi_it->stack_idx;
          if (bidi_it->level_stack[new_sidx].level > current_level
@@ -2718,6 +2744,7 @@ bidi_find_bracket_pairs (struct bidi_it *bidi_it)
                      goto give_up;
                    }
                  type = bidi_resolve_weak (bidi_it);
+                 n++;
                }
            }
          if (type == NEUTRAL_B
@@ -2794,6 +2821,12 @@ bidi_find_bracket_pairs (struct bidi_it *bidi_it)
     }
 
  give_up:
+  /* The factor of 20 below is a heuristic that needs to be tuned.  It
+     means we consider 20 buffer positions examined by this function
+     roughly equivalent to the display engine iterating over a single
+     buffer position.  */
+  if (max_redisplay_ticks > 0 && n > 0)
+    update_redisplay_ticks (n / 20 + 1, bidi_it->w);
   return retval;
 }
 
@@ -3363,6 +3396,7 @@ bidi_find_other_level_edge (struct bidi_it *bidi_it, int 
level, bool end_flag)
   else
     {
       int new_level;
+      ptrdiff_t pos0 = bidi_it->charpos;
 
       /* If we are at end of level, its edges must be cached.  */
       if (end_flag)
@@ -3398,6 +3432,12 @@ bidi_find_other_level_edge (struct bidi_it *bidi_it, int 
level, bool end_flag)
            bidi_cache_iterator_state (bidi_it, 1, 1);
          }
       } while (new_level >= level);
+      /* The factor of 50 below is a heuristic that needs to be
+        tuned.  It means we consider 50 buffer positions examined by
+        the above call roughly equivalent to the display engine
+        iterating over a single buffer position.  */
+      if (max_redisplay_ticks > 0 && bidi_it->charpos > pos0)
+       update_redisplay_ticks ((bidi_it->charpos - pos0) / 50 + 1, bidi_it->w);
     }
 }
 
diff --git a/src/buffer.c b/src/buffer.c
index 97e9e22738..be7c2f2161 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -604,6 +604,7 @@ 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'.  */
@@ -918,7 +919,8 @@ does not run the hooks `kill-buffer-hook',
       set_buffer_internal_1 (b);
       Fset (intern ("buffer-save-without-query"), Qnil);
       Fset (intern ("buffer-file-number"), Qnil);
-      Fset (intern ("buffer-stale-function"), Qnil);
+      if (!NILP (Flocal_variable_p (Qbuffer_stale_function, base_buffer)))
+       Fkill_local_variable (Qbuffer_stale_function);
       /* Cloned buffers need extra setup, to do things such as deep
         variable copies for list variables that might be mangled due
         to destructive operations in the indirect buffer. */
@@ -991,6 +993,7 @@ reset_buffer (register struct buffer *b)
   /* It is more conservative to start out "changed" than "unchanged".  */
   b->clip_changed = 0;
   b->prevent_redisplay_optimizations_p = 1;
+  b->long_line_optimizations_p = 0;
   bset_backed_up (b, Qnil);
   bset_local_minor_modes (b, Qnil);
   BUF_AUTOSAVE_MODIFF (b) = 0;
@@ -1075,7 +1078,7 @@ reset_buffer_local_variables (struct buffer *b, bool 
permanent_too)
           eassert (XSYMBOL (sym)->u.s.redirect == SYMBOL_LOCALIZED);
           /* Need not do anything if some other buffer's binding is
             now cached.  */
-          if (EQ (SYMBOL_BLV (XSYMBOL (sym))->where, buffer))
+          if (BASE_EQ (SYMBOL_BLV (XSYMBOL (sym))->where, buffer))
            {
              /* Symbol is set up for this buffer's old local value:
                 swap it out!  */
@@ -1168,7 +1171,8 @@ is first appended to NAME, to speed up finding a 
non-existent buffer.  */)
     genbase = name;
   else
     {
-      char number[sizeof "-999999"];
+      enum { bug_52711 = true };  /* https://bugs.gnu.org/57211 */
+      char number[bug_52711 ? INT_BUFSIZE_BOUND (int) + 1 : sizeof "-999999"];
       EMACS_INT r = get_random ();
       eassume (0 <= r);
       int i = r % 1000000;
@@ -1510,7 +1514,7 @@ state of the current buffer.  Use with care.  */)
         decrease SAVE_MODIFF and auto_save_modified or increase
         MODIFF.  */
       if (SAVE_MODIFF >= MODIFF)
-       SAVE_MODIFF = modiff_incr (&MODIFF);
+       SAVE_MODIFF = modiff_incr (&MODIFF, 1);
       if (EQ (flag, Qautosaved))
        BUF_AUTOSAVE_MODIFF (b) = MODIFF;
     }
@@ -1570,6 +1574,7 @@ This does not change the name of the visited file (if 
any).  */)
   (register Lisp_Object newname, Lisp_Object unique)
 {
   register Lisp_Object tem, buf;
+  Lisp_Object requestedname = newname;
 
   CHECK_STRING (newname);
 
@@ -1586,7 +1591,8 @@ This does not change the name of the visited file (if 
any).  */)
       if (NILP (unique) && XBUFFER (tem) == current_buffer)
        return BVAR (current_buffer, name);
       if (!NILP (unique))
-       newname = Fgenerate_new_buffer_name (newname, BVAR (current_buffer, 
name));
+       newname = Fgenerate_new_buffer_name (newname,
+                                            BVAR (current_buffer, name));
       else
        error ("Buffer name `%s' is in use", SDATA (newname));
     }
@@ -1606,7 +1612,7 @@ This does not change the name of the visited file (if 
any).  */)
   run_buffer_list_update_hook (current_buffer);
 
   call2 (intern ("uniquify--rename-buffer-advice"),
-         BVAR (current_buffer, name), unique);
+         requestedname, unique);
 
   /* Refetch since that last call may have done GC.  */
   return BVAR (current_buffer, name);
@@ -1617,7 +1623,7 @@ This does not change the name of the visited file (if 
any).  */)
 static bool
 candidate_buffer (Lisp_Object b, Lisp_Object buffer)
 {
-  return (BUFFERP (b) && !EQ (b, buffer)
+  return (BUFFERP (b) && !BASE_EQ (b, buffer)
          && BUFFER_LIVE_P (XBUFFER (b))
          && !BUFFER_HIDDEN_P (XBUFFER (b)));
 }
@@ -1819,10 +1825,12 @@ cleaning up all windows currently displaying the buffer 
to be killed. */)
     /* Query if the buffer is still modified.  */
     if (INTERACTIVE && modified)
       {
-       AUTO_STRING (format, "Buffer %s modified; kill anyway? ");
-       tem = do_yes_or_no_p (CALLN (Fformat, format, BVAR (b, name)));
-       if (NILP (tem))
+       /* Ask whether to kill the buffer, and exit if the user says
+          "no".  */
+       if (NILP (call1 (Qkill_buffer__possibly_save, buffer)))
          return unbind_to (count, Qnil);
+       /* Recheck modified.  */
+       modified = BUF_MODIFF (b) > BUF_SAVE_MODIFF (b);
       }
 
     /* Delete the autosave file, if requested. */
@@ -1861,7 +1869,7 @@ cleaning up all windows currently displaying the buffer 
to be killed. */)
      since anything can happen within do_yes_or_no_p.  */
 
   /* Don't kill the minibuffer now current.  */
-  if (EQ (buffer, XWINDOW (minibuf_window)->contents))
+  if (BASE_EQ (buffer, XWINDOW (minibuf_window)->contents))
     return Qnil;
 
   /* When we kill an ordinary buffer which shares its buffer text
@@ -1905,7 +1913,7 @@ cleaning up all windows currently displaying the buffer 
to be killed. */)
      is the sole other buffer give up.  */
   XSETBUFFER (tem, current_buffer);
   if (EQ (tem, XWINDOW (minibuf_window)->contents)
-      && EQ (buffer, Fother_buffer (buffer, Qnil, Qnil)))
+      && BASE_EQ (buffer, Fother_buffer (buffer, Qnil, Qnil)))
     return Qnil;
 
   /* Now there is no question: we can kill the buffer.  */
@@ -2453,6 +2461,7 @@ results, see Info node `(elisp)Swapping Text'.  */)
   swapfield (bidi_paragraph_cache, struct region_cache *);
   current_buffer->prevent_redisplay_optimizations_p = 1;
   other_buffer->prevent_redisplay_optimizations_p = 1;
+  swapfield (long_line_optimizations_p, bool_bf);
   swapfield (overlays_before, struct Lisp_Overlay *);
   swapfield (overlays_after, struct Lisp_Overlay *);
   swapfield (overlay_center, ptrdiff_t);
@@ -2472,12 +2481,12 @@ results, see Info node `(elisp)Swapping Text'.  */)
   bset_point_before_scroll (current_buffer, Qnil);
   bset_point_before_scroll (other_buffer, Qnil);
 
-  modiff_incr (&current_buffer->text->modiff);
-  modiff_incr (&other_buffer->text->modiff);
-  modiff_incr (&current_buffer->text->chars_modiff);
-  modiff_incr (&other_buffer->text->chars_modiff);
-  modiff_incr (&current_buffer->text->overlay_modiff);
-  modiff_incr (&other_buffer->text->overlay_modiff);
+  modiff_incr (&current_buffer->text->modiff, 1);
+  modiff_incr (&other_buffer->text->modiff, 1);
+  modiff_incr (&current_buffer->text->chars_modiff, 1);
+  modiff_incr (&other_buffer->text->chars_modiff, 1);
+  modiff_incr (&current_buffer->text->overlay_modiff, 1);
+  modiff_incr (&other_buffer->text->overlay_modiff, 1);
   current_buffer->text->beg_unchanged = current_buffer->text->gpt;
   current_buffer->text->end_unchanged = current_buffer->text->gpt;
   other_buffer->text->beg_unchanged = other_buffer->text->gpt;
@@ -2511,23 +2520,23 @@ results, see Info node `(elisp)Swapping Text'.  */)
       {
        ws = Fcons (w, ws);
        if (MARKERP (XWINDOW (w)->pointm)
-           && (EQ (XWINDOW (w)->contents, buf1)
-               || EQ (XWINDOW (w)->contents, buf2)))
+           && (BASE_EQ (XWINDOW (w)->contents, buf1)
+               || BASE_EQ (XWINDOW (w)->contents, buf2)))
          Fset_marker (XWINDOW (w)->pointm,
                       make_fixnum
                       (BUF_BEGV (XBUFFER (XWINDOW (w)->contents))),
                       XWINDOW (w)->contents);
        /* Blindly copied from pointm part.  */
        if (MARKERP (XWINDOW (w)->old_pointm)
-           && (EQ (XWINDOW (w)->contents, buf1)
-               || EQ (XWINDOW (w)->contents, buf2)))
+           && (BASE_EQ (XWINDOW (w)->contents, buf1)
+               || BASE_EQ (XWINDOW (w)->contents, buf2)))
          Fset_marker (XWINDOW (w)->old_pointm,
                       make_fixnum
                       (BUF_BEGV (XBUFFER (XWINDOW (w)->contents))),
                       XWINDOW (w)->contents);
        if (MARKERP (XWINDOW (w)->start)
-           && (EQ (XWINDOW (w)->contents, buf1)
-               || EQ (XWINDOW (w)->contents, buf2)))
+           && (BASE_EQ (XWINDOW (w)->contents, buf1)
+               || BASE_EQ (XWINDOW (w)->contents, buf2)))
          Fset_marker (XWINDOW (w)->start,
                       make_fixnum
                       (XBUFFER (XWINDOW (w)->contents)->last_window_start),
@@ -2537,10 +2546,11 @@ results, see Info node `(elisp)Swapping Text'.  */)
   }
 
   if (current_buffer->text->intervals)
-    (eassert (EQ (current_buffer->text->intervals->up.obj, buffer)),
+    (eassert (BASE_EQ (current_buffer->text->intervals->up.obj, buffer)),
      XSETBUFFER (current_buffer->text->intervals->up.obj, current_buffer));
   if (other_buffer->text->intervals)
-    (eassert (EQ (other_buffer->text->intervals->up.obj, Fcurrent_buffer ())),
+    (eassert (BASE_EQ (other_buffer->text->intervals->up.obj,
+                      Fcurrent_buffer ())),
      XSETBUFFER (other_buffer->text->intervals->up.obj, other_buffer));
 
   return Qnil;
@@ -3950,9 +3960,9 @@ for the rear of the overlay advance when text is inserted 
there
   else
     CHECK_BUFFER (buffer);
 
-  if (MARKERP (beg) && !EQ (Fmarker_buffer (beg), buffer))
+  if (MARKERP (beg) && !BASE_EQ (Fmarker_buffer (beg), buffer))
     signal_error ("Marker points into wrong buffer", beg);
-  if (MARKERP (end) && !EQ (Fmarker_buffer (end), buffer))
+  if (MARKERP (end) && !BASE_EQ (Fmarker_buffer (end), buffer))
     signal_error ("Marker points into wrong buffer", end);
 
   CHECK_FIXNUM_COERCE_MARKER (beg);
@@ -4015,7 +4025,7 @@ modify_overlay (struct buffer *buf, ptrdiff_t start, 
ptrdiff_t end)
 
   bset_redisplay (buf);
 
-  modiff_incr (&BUF_OVERLAY_MODIFF (buf));
+  modiff_incr (&BUF_OVERLAY_MODIFF (buf), 1);
 }
 
 /* Remove OVERLAY from LIST.  */
@@ -4070,9 +4080,9 @@ buffer.  */)
   if (NILP (Fbuffer_live_p (buffer)))
     error ("Attempt to move overlay to a dead buffer");
 
-  if (MARKERP (beg) && !EQ (Fmarker_buffer (beg), buffer))
+  if (MARKERP (beg) && !BASE_EQ (Fmarker_buffer (beg), buffer))
     signal_error ("Marker points into wrong buffer", beg);
-  if (MARKERP (end) && !EQ (Fmarker_buffer (end), buffer))
+  if (MARKERP (end) && !BASE_EQ (Fmarker_buffer (end), buffer))
     signal_error ("Marker points into wrong buffer", end);
 
   CHECK_FIXNUM_COERCE_MARKER (beg);
@@ -5622,7 +5632,7 @@ used.  */);
 
   DEFVAR_PER_BUFFER ("mode-line-format", &BVAR (current_buffer, 
mode_line_format),
                     Qnil,
-                    doc: /* Template for displaying mode line for current 
buffer.
+                    doc: /* Template for displaying mode line for a window's 
buffer.
 
 The value may be nil, a string, a symbol or a list.
 
@@ -5635,6 +5645,9 @@ For any symbol other than t or nil, the symbol's value is 
processed as
  `risky-local-variable' property, all properties in any strings, as
  well as all :eval and :propertize forms in the value, are ignored.
 
+When the value is processed, the window's buffer is temporarily the
+current buffer.
+
 A list whose car is a string or list is processed by processing each
  of the list elements recursively, as separate mode line constructs,
  and concatenating the results.
@@ -6436,6 +6449,37 @@ Since `clone-indirect-buffer' calls 
`make-indirect-buffer', this hook
 will run for `clone-indirect-buffer' calls as well.  */);
   Vclone_indirect_buffer_hook = Qnil;
 
+  DEFVAR_LISP ("long-line-threshold", Vlong_line_threshold,
+    doc: /* Line length above which to use redisplay shortcuts.
+
+The value should be a positive integer or nil.
+If the value is an integer, shortcuts in the display code intended
+to speed up redisplay for long lines will automatically be enabled
+in buffers which contain one or more lines whose length is above
+this threshold.
+If nil, these display shortcuts will always remain disabled.
+
+There is no reason to change that value except for debugging purposes.  */);
+  XSETFASTINT (Vlong_line_threshold, 10000);
+
+  DEFVAR_INT ("large-hscroll-threshold", large_hscroll_threshold,
+    doc: /* Horizontal scroll of truncated lines above which to use redisplay 
shortcuts.
+
+The value should be a positive integer.
+
+Shortcuts in the display code intended to speed up redisplay for long
+and truncated lines will automatically be enabled when a line's
+horizontal scroll amount is or about to become larger than the value
+of this variable.
+
+This variable has effect only in buffers which contain one or more
+lines whose length is above `long-line-threshold', which see.
+To disable redisplay shortcuts for long truncated line, set this
+variable to `most-positive-fixnum'.
+
+There is no reason to change that value except for debugging purposes.  */);
+  large_hscroll_threshold = 10000;
+
   defsubr (&Sbuffer_live_p);
   defsubr (&Sbuffer_list);
   defsubr (&Sget_buffer);
@@ -6489,5 +6533,9 @@ will run for `clone-indirect-buffer' calls as well.  */);
 
   DEFSYM (Qautosaved, "autosaved");
 
+  DEFSYM (Qkill_buffer__possibly_save, "kill-buffer--possibly-save");
+
+  DEFSYM (Qbuffer_stale_function, "buffer-stale-function");
+
   Fput (intern_c_string ("erase-buffer"), Qdisabled, Qt);
 }
diff --git a/src/buffer.h b/src/buffer.h
index bc07a63b53..04792374cd 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -149,12 +149,18 @@ 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.  */
 
@@ -237,9 +243,10 @@ struct buffer_text
     ptrdiff_t z_byte;          /* Byte pos of end of buffer.  */
     ptrdiff_t gap_size;                /* Size of buffer's gap.  */
     modiff_count modiff;       /* This counts buffer-modification events
-                                  for this buffer.  It is incremented for
-                                  each such event, and never otherwise
-                                  changed.  */
+                                  for this buffer.  It is increased
+                                  logarithmically to the extent of the
+                                  modification for each such event,
+                                  and never otherwise changed.  */
     modiff_count chars_modiff; /* This is modified with character change
                                   events for this buffer.  It is set to
                                   modiff for each such event, and never
@@ -267,6 +274,11 @@ 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;
 
@@ -685,6 +697,10 @@ struct buffer
      defined, as well as by with-temp-buffer, for example.  */
   bool_bf inhibit_buffer_hooks : 1;
 
+  /* Non-zero when the buffer contains long lines and specific
+     display optimizations must be used.  */
+  bool_bf long_line_optimizations_p : 1;
+
   /* List of overlays that end at or before the current center,
      in order of end-position.  */
   struct Lisp_Overlay *overlays_before;
diff --git a/src/bytecode.c b/src/bytecode.c
index fa068e1ec6..d75767bb0c 100644
--- a/src/bytecode.c
+++ b/src/bytecode.c
@@ -176,8 +176,8 @@ DEFINE (Bmin, 0136)                                         
        \
 DEFINE (Bmult, 0137)                                                   \
                                                                        \
 DEFINE (Bpoint, 0140)                                                  \
-/* Was Bmark in v17.  */                                               \
-DEFINE (Bsave_current_buffer, 0141) /* Obsolete.  */                   \
+/* 0141 was Bmark in v17, Bsave_current_buffer in 18-19.  */           \
+DEFINE (Bsave_current_buffer_OBSOLETE, 0141)  /* Obsolete since 20. */ \
 DEFINE (Bgoto_char, 0142)                                              \
 DEFINE (Binsert, 0143)                                                 \
 DEFINE (Bpoint_max, 0144)                                              \
@@ -194,7 +194,7 @@ DEFINE (Bbolp, 0156)                                        
                \
 DEFINE (Bbobp, 0157)                                                   \
 DEFINE (Bcurrent_buffer, 0160)                                         \
 DEFINE (Bset_buffer, 0161)                                             \
-DEFINE (Bsave_current_buffer_1, 0162) /* Replacing Bsave_current_buffer.  */ \
+DEFINE (Bsave_current_buffer, 0162)                                    \
 /* 0163 was Bset_mark in v17.  */                                       \
 DEFINE (Binteractive_p, 0164) /* Obsolete since Emacs-24.1.  */                
\
                                                                        \
@@ -924,8 +924,8 @@ exec_byte_code (Lisp_Object fun, ptrdiff_t args_template,
          record_unwind_protect_excursion ();
          NEXT;
 
-       CASE (Bsave_current_buffer): /* Obsolete since ??.  */
-       CASE (Bsave_current_buffer_1):
+       CASE (Bsave_current_buffer_OBSOLETE): /* Obsolete since 20.  */
+       CASE (Bsave_current_buffer):
          record_unwind_current_buffer ();
          NEXT;
 
@@ -1678,6 +1678,12 @@ exec_byte_code (Lisp_Object fun, ptrdiff_t args_template,
             /* TODO: Perhaps introduce another byte-code for switch when the
               number of cases is less, which uses a simple vector for linear
               search as the jump table.  */
+
+           /* TODO: Instead of pushing the table in a separate
+              Bconstant op, use an immediate argument (maybe separate
+              switch opcodes for 1-byte and 2-byte constant indices).
+              This would also get rid of some hacks that assume each
+              Bswitch to be preceded by a Bconstant.  */
             Lisp_Object jmp_table = POP;
            if (BYTE_CODE_SAFE && !HASH_TABLE_P (jmp_table))
               emacs_abort ();
diff --git a/src/callint.c b/src/callint.c
index 8283c61da6..8ef0e5240a 100644
--- a/src/callint.c
+++ b/src/callint.c
@@ -161,73 +161,33 @@ check_mark (bool for_region)
     xsignal0 (Qmark_inactive);
 }
 
-/* If the list of args INPUT was produced with an explicit call to
-   `list', look for elements that were computed with
-   (region-beginning) or (region-end), and put those expressions into
-   VALUES instead of the present values.
+/* If FUNCTION has an `interactive-args' spec, replace relevant
+   elements in VALUES with those forms instead.
 
    This function doesn't return a value because it modifies elements
    of VALUES to do its job.  */
 
 static void
-fix_command (Lisp_Object input, Lisp_Object function, Lisp_Object values)
+fix_command (Lisp_Object function, Lisp_Object values)
 {
-  /* FIXME: Instead of this ugly hack, we should provide a way for an
-     interactive spec to return an expression/function that will re-build the
-     args without user intervention.  */
-  if (CONSP (input))
+  /* Quick exit if there's no values to alter.  */
+  if (!CONSP (values) || !SYMBOLP (function))
+    return;
+
+  Lisp_Object reps = Fget (function, Qinteractive_args);
+
+  if (CONSP (reps))
     {
-      Lisp_Object car;
+      int i = 0;
+      Lisp_Object vals = values;
 
-      car = XCAR (input);
-      /* Skip through certain special forms.  */
-      while (EQ (car, Qlet) || EQ (car, Qletx)
-            || EQ (car, Qsave_excursion)
-            || EQ (car, Qprogn))
+      while (!NILP (vals))
        {
-         while (CONSP (XCDR (input)))
-           input = XCDR (input);
-         input = XCAR (input);
-         if (!CONSP (input))
-           break;
-         car = XCAR (input);
-       }
-      if (EQ (car, Qlist))
-       {
-         Lisp_Object intail, valtail;
-         for (intail = Fcdr (input), valtail = values;
-              CONSP (valtail);
-              intail = Fcdr (intail), valtail = XCDR (valtail))
-           {
-             Lisp_Object elt;
-             elt = Fcar (intail);
-             if (CONSP (elt))
-               {
-                 Lisp_Object presflag, carelt;
-                 carelt = XCAR (elt);
-                 /* If it is (if X Y), look at Y.  */
-                 if (EQ (carelt, Qif)
-                     && NILP (Fnthcdr (make_fixnum (3), elt)))
-                   elt = Fnth (make_fixnum (2), elt);
-                 /* If it is (when ... Y), look at Y.  */
-                 else if (EQ (carelt, Qwhen))
-                   {
-                     while (CONSP (XCDR (elt)))
-                       elt = XCDR (elt);
-                     elt = Fcar (elt);
-                   }
-
-                 /* If the function call we're looking at
-                    is a special preserved one, copy the
-                    whole expression for this argument.  */
-                 if (CONSP (elt))
-                   {
-                     presflag = Fmemq (Fcar (elt), preserved_fns);
-                     if (!NILP (presflag))
-                       Fsetcar (valtail, Fcar (intail));
-                   }
-               }
-           }
+         Lisp_Object rep = Fassq (make_fixnum (i), reps);
+         if (!NILP (rep))
+           Fsetcar (vals, XCDR (rep));
+         vals = XCDR (vals);
+         ++i;
        }
     }
 
@@ -235,31 +195,28 @@ fix_command (Lisp_Object input, Lisp_Object function, 
Lisp_Object values)
      optional, remove them from the list.  This makes navigating the
      history less confusing, since it doesn't contain a lot of
      parameters that aren't used.  */
-  if (CONSP (values))
+  Lisp_Object arity = Ffunc_arity (function);
+  /* We don't want to do this simplification if we have an &rest
+     function, because (cl-defun foo (a &optional (b 'zot)) ..)
+     etc.  */
+  if (FIXNUMP (XCAR (arity)) && FIXNUMP (XCDR (arity)))
     {
-      Lisp_Object arity = Ffunc_arity (function);
-      /* We don't want to do this simplification if we have an &rest
-        function, because (cl-defun foo (a &optional (b 'zot)) ..)
-        etc.  */
-      if (FIXNUMP (XCAR (arity)) && FIXNUMP (XCDR (arity)))
+      Lisp_Object final = Qnil;
+      ptrdiff_t final_i = 0, i = 0;
+      for (Lisp_Object tail = values;
+          CONSP (tail);
+          tail = XCDR (tail), ++i)
        {
-         Lisp_Object final = Qnil;
-         ptrdiff_t final_i = 0, i = 0;
-         for (Lisp_Object tail = values;
-              CONSP (tail);
-              tail = XCDR (tail), ++i)
+         if (!NILP (XCAR (tail)))
            {
-             if (!NILP (XCAR (tail)))
-               {
-                 final = tail;
-                 final_i = i;
-               }
+             final = tail;
+             final_i = i;
            }
-
-         /* Chop the trailing optional values.  */
-         if (final_i > 0 && final_i >= XFIXNUM (XCAR (arity)) - 1)
-           XSETCDR (final,  Qnil);
        }
+
+      /* Chop the trailing optional values.  */
+      if (final_i > 0 && final_i >= XFIXNUM (XCAR (arity)) - 1)
+       XSETCDR (final,  Qnil);
     }
 }
 
@@ -360,7 +317,6 @@ invoke it (via an `interactive' spec that contains, for 
instance, an
     {
       Lisp_Object funval = Findirect_function (function, Qt);
       uintmax_t events = num_input_events;
-      Lisp_Object input = specs;
       /* Compute the arg values using the user's expression.  */
       specs = Feval (specs,
                     CONSP (funval) && EQ (Qclosure, XCAR (funval))
@@ -371,7 +327,7 @@ invoke it (via an `interactive' spec that contains, for 
instance, an
             Make a copy of the list of values, for the command history,
             and turn them into things we can eval.  */
          Lisp_Object values = quotify_args (Fcopy_sequence (specs));
-         fix_command (input, function, values);
+         fix_command (function, values);
           call4 (intern ("add-to-history"), intern ("command-history"),
                  Fcons (function, values), Qnil, Qt);
        }
@@ -439,7 +395,7 @@ invoke it (via an `interactive' spec that contains, for 
instance, an
              && (w = XCAR (w), WINDOWP (w)))
            {
              if (MINI_WINDOW_P (XWINDOW (w))
-                 && ! (minibuf_level > 0 && EQ (w, minibuf_window)))
+                 && ! (minibuf_level > 0 && BASE_EQ (w, minibuf_window)))
                error ("Attempt to select inactive minibuffer window");
 
              /* If the current buffer wants to clean up, let it.  */
@@ -509,7 +465,7 @@ invoke it (via an `interactive' spec that contains, for 
instance, an
 
        case 'b':               /* Name of existing buffer.  */
          args[i] = Fcurrent_buffer ();
-         if (EQ (selected_window, minibuf_window))
+         if (BASE_EQ (selected_window, minibuf_window))
            args[i] = Fother_buffer (args[i], Qnil, Qnil);
          args[i] = Fread_buffer (callint_message, args[i], Qt, Qnil);
          break;
@@ -950,4 +906,6 @@ use `event-start', `event-end', and `event-click-count'.  
*/);
   defsubr (&Scall_interactively);
   defsubr (&Sfuncall_interactively);
   defsubr (&Sprefix_numeric_value);
+
+  DEFSYM (Qinteractive_args, "interactive-args");
 }
diff --git a/src/callproc.c b/src/callproc.c
index dd162f36a6..2d457b3c84 100644
--- a/src/callproc.c
+++ b/src/callproc.c
@@ -650,7 +650,7 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int 
filefd,
 
   child_errno
     = emacs_spawn (&pid, filefd, fd_output, fd_error, new_argv, env,
-                   SSDATA (current_dir), NULL, &oldset);
+                   SSDATA (current_dir), NULL, false, false, &oldset);
   eassert ((child_errno == 0) == (0 < pid));
 
   if (pid > 0)
@@ -1412,14 +1412,15 @@ emacs_posix_spawn_init_attributes (posix_spawnattr_t 
*attributes,
 int
 emacs_spawn (pid_t *newpid, int std_in, int std_out, int std_err,
              char **argv, char **envp, const char *cwd,
-             const char *pty, const sigset_t *oldset)
+             const char *pty_name, bool pty_in, bool pty_out,
+             const sigset_t *oldset)
 {
 #if USABLE_POSIX_SPAWN
   /* Prefer the simpler `posix_spawn' if available.  `posix_spawn'
      doesn't yet support setting up pseudoterminals, so we fall back
      to `vfork' if we're supposed to use a pseudoterminal.  */
 
-  bool use_posix_spawn = pty == NULL;
+  bool use_posix_spawn = pty_name == NULL;
 
   posix_spawn_file_actions_t actions;
   posix_spawnattr_t attributes;
@@ -1473,7 +1474,9 @@ emacs_spawn (pid_t *newpid, int std_in, int std_out, int 
std_err,
   /* vfork, and prevent local vars from being clobbered by the vfork.  */
   pid_t *volatile newpid_volatile = newpid;
   const char *volatile cwd_volatile = cwd;
-  const char *volatile pty_volatile = pty;
+  const char *volatile ptyname_volatile = pty_name;
+  bool volatile ptyin_volatile = pty_in;
+  bool volatile ptyout_volatile = pty_out;
   char **volatile argv_volatile = argv;
   int volatile stdin_volatile = std_in;
   int volatile stdout_volatile = std_out;
@@ -1485,7 +1488,7 @@ emacs_spawn (pid_t *newpid, int std_in, int std_out, int 
std_err,
   /* Darwin doesn't let us run setsid after a vfork, so use fork when
      necessary.  Below, we reset SIGCHLD handling after a vfork, as
      apparently macOS can mistakenly deliver SIGCHLD to the child.  */
-  if (pty != NULL)
+  if (pty_in || pty_out)
     pid = fork ();
   else
     pid = VFORK ();
@@ -1495,7 +1498,9 @@ emacs_spawn (pid_t *newpid, int std_in, int std_out, int 
std_err,
 
   newpid = newpid_volatile;
   cwd = cwd_volatile;
-  pty = pty_volatile;
+  pty_name = ptyname_volatile;
+  pty_in = ptyin_volatile;
+  pty_out = ptyout_volatile;
   argv = argv_volatile;
   std_in = stdin_volatile;
   std_out = stdout_volatile;
@@ -1506,13 +1511,12 @@ emacs_spawn (pid_t *newpid, int std_in, int std_out, 
int std_err,
   if (pid == 0)
 #endif /* not WINDOWSNT */
     {
-      bool pty_flag = pty != NULL;
       /* Make the pty be the controlling terminal of the process.  */
 #ifdef HAVE_PTYS
       dissociate_controlling_tty ();
 
       /* Make the pty's terminal the controlling terminal.  */
-      if (pty_flag && std_in >= 0)
+      if (pty_in && std_in >= 0)
        {
 #ifdef TIOCSCTTY
          /* We ignore the return value
@@ -1521,7 +1525,7 @@ emacs_spawn (pid_t *newpid, int std_in, int std_out, int 
std_err,
 #endif
        }
 #if defined (LDISC1)
-      if (pty_flag && std_in >= 0)
+      if (pty_in && std_in >= 0)
        {
          struct termios t;
          tcgetattr (std_in, &t);
@@ -1531,7 +1535,7 @@ emacs_spawn (pid_t *newpid, int std_in, int std_out, int 
std_err,
        }
 #else
 #if defined (NTTYDISC) && defined (TIOCSETD)
-      if (pty_flag && std_in >= 0)
+      if (pty_in && std_in >= 0)
        {
          /* Use new line discipline.  */
          int ldisc = NTTYDISC;
@@ -1548,18 +1552,21 @@ emacs_spawn (pid_t *newpid, int std_in, int std_out, 
int std_err,
      both TIOCSCTTY is defined.  */
        /* Now close the pty (if we had it open) and reopen it.
           This makes the pty the controlling terminal of the subprocess.  */
-      if (pty_flag)
+      if (pty_name)
        {
 
          /* I wonder if emacs_close (emacs_open (pty, ...))
             would work?  */
-         if (std_in >= 0)
+         if (pty_in && std_in >= 0)
            emacs_close (std_in);
-          std_out = std_in = emacs_open_noquit (pty, O_RDWR, 0);
-
+         int ptyfd = emacs_open_noquit (pty_name, O_RDWR, 0);
+         if (pty_in)
+           std_in = ptyfd;
+         if (pty_out)
+           std_out = ptyfd;
          if (std_in < 0)
            {
-             emacs_perror (pty);
+             emacs_perror (pty_name);
              _exit (EXIT_CANCELED);
            }
 
@@ -1567,7 +1574,7 @@ emacs_spawn (pid_t *newpid, int std_in, int std_out, int 
std_err,
 #endif /* not DONT_REOPEN_PTY */
 
 #ifdef SETUP_SLAVE_PTY
-      if (pty_flag)
+      if (pty_in && std_in >= 0)
        {
          SETUP_SLAVE_PTY;
        }
@@ -1599,7 +1606,7 @@ emacs_spawn (pid_t *newpid, int std_in, int std_out, int 
std_err,
       /* Stop blocking SIGCHLD in the child.  */
       unblock_child_signal (oldset);
 
-      if (pty_flag)
+      if (pty_out)
        child_setup_tty (std_out);
 #endif
 
diff --git a/src/character.c b/src/character.c
index c1a1b55389..968daccafa 100644
--- a/src/character.c
+++ b/src/character.c
@@ -666,35 +666,26 @@ count_size_as_multibyte (const unsigned char *str, 
ptrdiff_t len)
 }
 
 
-/* Convert unibyte text at STR of BYTES bytes to a multibyte text
-   that contains the same single-byte characters.  It actually
-   converts all 8-bit characters to multibyte forms.  It is assured
-   that we can use LEN bytes at STR as a work area and that is
-   enough.  */
-
+/* Convert unibyte text at SRC of NCHARS chars to a multibyte text
+   at DST, that contains the same single-byte characters.
+   Return the number of bytes written at DST.  */
 ptrdiff_t
-str_to_multibyte (unsigned char *str, ptrdiff_t len, ptrdiff_t bytes)
+str_to_multibyte (unsigned char *dst, const unsigned char *src,
+                 ptrdiff_t nchars)
 {
-  unsigned char *p = str, *endp = str + bytes;
-  unsigned char *to;
-
-  while (p < endp && *p < 0x80) p++;
-  if (p == endp)
-    return bytes;
-  to = p;
-  bytes = endp - p;
-  endp = str + len;
-  memmove (endp - bytes, p, bytes);
-  p = endp - bytes;
-  while (p < endp)
+  unsigned char *d = dst;
+  for (ptrdiff_t i = 0; i < nchars; i++)
     {
-      int c = *p++;
-
-      if (c >= 0x80)
-       c = BYTE8_TO_CHAR (c);
-      to += CHAR_STRING (c, to);
+      unsigned char c = src[i];
+      if (c <= 0x7f)
+       *d++ = c;
+      else
+       {
+         *d++ = 0xc0 + ((c >> 6) & 1);
+         *d++ = 0x80 + (c & 0x3f);
+       }
     }
-  return (to - str);
+  return d - dst;
 }
 
 /* Arrange multibyte text at STR of LEN bytes as a unibyte text.  It
@@ -734,31 +725,6 @@ str_as_unibyte (unsigned char *str, ptrdiff_t bytes)
   return (to - str);
 }
 
-/* Convert eight-bit chars in SRC (in multibyte form) to the
-   corresponding byte and store in DST.  CHARS is the number of
-   characters in SRC.  The value is the number of bytes stored in DST.
-   Usually, the value is the same as CHARS, but is less than it if SRC
-   contains a non-ASCII, non-eight-bit character.  */
-
-ptrdiff_t
-str_to_unibyte (const unsigned char *src, unsigned char *dst, ptrdiff_t chars)
-{
-  ptrdiff_t i;
-
-  for (i = 0; i < chars; i++)
-    {
-      int c = string_char_advance (&src);
-
-      if (CHAR_BYTE8_P (c))
-       c = CHAR_TO_BYTE8 (c);
-      else if (! ASCII_CHAR_P (c))
-       return i;
-      *dst++ = c;
-    }
-  return i;
-}
-
-
 static ptrdiff_t
 string_count_byte8 (Lisp_Object string)
 {
diff --git a/src/character.h b/src/character.h
index 6ee6bcab20..6d0f035c2b 100644
--- a/src/character.h
+++ b/src/character.h
@@ -567,10 +567,9 @@ extern int translate_char (Lisp_Object, int c);
 extern ptrdiff_t count_size_as_multibyte (const unsigned char *, ptrdiff_t);
 extern ptrdiff_t str_as_multibyte (unsigned char *, ptrdiff_t, ptrdiff_t,
                                   ptrdiff_t *);
-extern ptrdiff_t str_to_multibyte (unsigned char *, ptrdiff_t, ptrdiff_t);
+extern ptrdiff_t str_to_multibyte (unsigned char *dst, const unsigned char 
*src,
+                                  ptrdiff_t nchars);
 extern ptrdiff_t str_as_unibyte (unsigned char *, ptrdiff_t);
-extern ptrdiff_t str_to_unibyte (const unsigned char *, unsigned char *,
-                                 ptrdiff_t);
 extern ptrdiff_t strwidth (const char *, ptrdiff_t);
 extern ptrdiff_t c_string_width (const unsigned char *, ptrdiff_t, int,
                                 ptrdiff_t *, ptrdiff_t *);
diff --git a/src/charset.c b/src/charset.c
index 9edbd4c8c8..bb59262fe9 100644
--- a/src/charset.c
+++ b/src/charset.c
@@ -1852,9 +1852,8 @@ although this usage is obsolescent.  */)
 
 DEFUN ("encode-char", Fencode_char, Sencode_char, 2, 2, 0,
        doc: /* Encode the character CH into a code-point of CHARSET.
-Return the encoded code-point, a fixnum if its value is small enough,
-otherwise a bignum.
-Return nil if CHARSET doesn't support CH.  */)
+Return the encoded code-point as an integer,
+or nil if CHARSET doesn't support CH.  */)
   (Lisp_Object ch, Lisp_Object charset)
 {
   int c, id;
diff --git a/src/coding.c b/src/coding.c
index aa32efc3f6..0ae8eb3282 100644
--- a/src/coding.c
+++ b/src/coding.c
@@ -8194,7 +8194,7 @@ decode_coding_object (struct coding_system *coding,
   if (saved_pt >= 0)
     {
       /* This is the case of:
-        (BUFFERP (src_object) && EQ (src_object, dst_object))
+        (BUFFERP (src_object) && BASE_EQ (src_object, dst_object))
         As we have moved PT while replacing the original buffer
         contents, we must recover it now.  */
       set_buffer_internal (XBUFFER (src_object));
@@ -8283,7 +8283,7 @@ encode_coding_object (struct coding_system *coding,
   ptrdiff_t chars = to - from;
   ptrdiff_t bytes = to_byte - from_byte;
   Lisp_Object attrs;
-  ptrdiff_t saved_pt = -1, saved_pt_byte;
+  ptrdiff_t saved_pt = -1, saved_pt_byte UNINIT;
   bool need_marker_adjustment = 0;
   bool kill_src_buffer = 0;
   Lisp_Object old_deactivate_mark;
@@ -8298,7 +8298,7 @@ encode_coding_object (struct coding_system *coding,
   attrs = CODING_ID_ATTRS (coding->id);
 
   bool same_buffer = false;
-  if (EQ (src_object, dst_object) && BUFFERP (src_object))
+  if (BASE_EQ (src_object, dst_object) && BUFFERP (src_object))
     {
       struct Lisp_Marker *tail;
 
@@ -8379,7 +8379,7 @@ encode_coding_object (struct coding_system *coding,
   if (BUFFERP (dst_object))
     {
       coding->dst_object = dst_object;
-      if (EQ (src_object, dst_object))
+      if (BASE_EQ (src_object, dst_object))
        {
          coding->dst_pos = from;
          coding->dst_pos_byte = from_byte;
@@ -8434,7 +8434,7 @@ encode_coding_object (struct coding_system *coding,
   if (saved_pt >= 0)
     {
       /* This is the case of:
-        (BUFFERP (src_object) && EQ (src_object, dst_object))
+        (BUFFERP (src_object) && BASE_EQ (src_object, dst_object))
         As we have moved PT while replacing the original buffer
         contents, we must recover it now.  */
       set_buffer_internal (XBUFFER (src_object));
@@ -9416,7 +9416,7 @@ code_convert_region (Lisp_Object start, Lisp_Object end,
   setup_coding_system (coding_system, &coding);
   coding.mode |= CODING_MODE_LAST_BLOCK;
 
-  if (BUFFERP (dst_object) && !EQ (dst_object, src_object))
+  if (BUFFERP (dst_object) && !BASE_EQ (dst_object, src_object))
     {
       struct buffer *buf = XBUFFER (dst_object);
       ptrdiff_t buf_pt = BUF_PT (buf);
@@ -10785,7 +10785,7 @@ usage: (find-operation-coding-system OPERATION 
ARGUMENTS...)  */)
          && ((STRINGP (target)
               && STRINGP (XCAR (elt))
               && fast_string_match (XCAR (elt), target) >= 0)
-             || (FIXNUMP (target) && EQ (target, XCAR (elt)))))
+             || (FIXNUMP (target) && BASE_EQ (target, XCAR (elt)))))
        {
          val = XCDR (elt);
          /* Here, if VAL is both a valid coding system and a valid
@@ -11499,7 +11499,7 @@ DEFUN ("coding-system-put", Fcoding_system_put, 
Scoding_system_put,
     }
 
   ASET (attrs, coding_attr_plist,
-       Fplist_put (CODING_ATTR_PLIST (attrs), prop, val));
+       plist_put (CODING_ATTR_PLIST (attrs), prop, val));
   return val;
 }
 
diff --git a/src/comp.c b/src/comp.c
index c230536ac5..70e7d5a8bb 100644
--- a/src/comp.c
+++ b/src/comp.c
@@ -2626,6 +2626,7 @@ emit_maybe_gc_or_quit (Lisp_Object insn)
 
 /* This is in charge of serializing an object and export a function to
    retrieve it at load time.  */
+#pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Waddress"
 static void
 emit_static_object (const char *name, Lisp_Object obj)
@@ -4397,7 +4398,7 @@ one for the file name and another for its contents, 
followed by .eln.  */)
     {
       Lisp_Object match_idx =
        Fstring_match (XCAR (lds_re_tail), filename, Qnil, Qnil);
-      if (EQ (match_idx, make_fixnum (0)))
+      if (BASE_EQ (match_idx, make_fixnum (0)))
        {
          filename =
            Freplace_match (build_string ("//"), Qt, Qt, filename, Qnil);
@@ -4681,6 +4682,7 @@ DEFUN ("comp--release-ctxt", Fcomp__release_ctxt, 
Scomp__release_ctxt,
   return Qt;
 }
 
+#pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Waddress"
 DEFUN ("comp-native-driver-options-effective-p",
        Fcomp_native_driver_options_effective_p,
@@ -4697,6 +4699,7 @@ DEFUN ("comp-native-driver-options-effective-p",
 }
 #pragma GCC diagnostic pop
 
+#pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Waddress"
 DEFUN ("comp-native-compiler-options-effective-p",
        Fcomp_native_compiler_options_effective_p,
@@ -4943,6 +4946,7 @@ DEFUN ("comp--compile-ctxt-to-file", 
Fcomp__compile_ctxt_to_file,
   return filename;
 }
 
+#pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Waddress"
 DEFUN ("comp-libgccjit-version", Fcomp_libgccjit_version,
        Scomp_libgccjit_version, 0, 0, 0,
@@ -5013,8 +5017,6 @@ helper_GET_SYMBOL_WITH_POSITION (Lisp_Object a)
 
 /* `native-comp-eln-load-path' clean-up support code.  */
 
-static Lisp_Object all_loaded_comp_units_h;
-
 #ifdef WINDOWSNT
 static Lisp_Object
 return_nil (Lisp_Object arg)
@@ -5056,11 +5058,12 @@ eln_load_path_final_clean_up (void)
 }
 
 /* This function puts the compilation unit in the
-  `all_loaded_comp_units_h` hashmap.  */
+  `Vcomp_loaded_comp_units_h` hashmap.  */
 static void
 register_native_comp_unit (Lisp_Object comp_u)
 {
-  Fputhash (XNATIVE_COMP_UNIT (comp_u)->file, comp_u, all_loaded_comp_units_h);
+  Fputhash (
+    XNATIVE_COMP_UNIT (comp_u)->file, comp_u, Vcomp_loaded_comp_units_h);
 }
 
 
@@ -5548,7 +5551,7 @@ LATE_LOAD has to be non-nil when loading for deferred 
compilation.  */)
   struct Lisp_Native_Comp_Unit *comp_u = allocate_native_comp_unit ();
   Lisp_Object encoded_filename = ENCODE_FILE (filename);
 
-  if (!NILP (Fgethash (filename, all_loaded_comp_units_h, Qnil))
+  if (!NILP (Fgethash (filename, Vcomp_loaded_comp_units_h, Qnil))
       && !file_in_eln_sys_dir (filename)
       && !NILP (Ffile_writable_p (filename)))
     {
@@ -5750,10 +5753,6 @@ compiled one.  */);
   staticpro (&loadsearch_re_list);
   loadsearch_re_list = Qnil;
 
-  staticpro (&all_loaded_comp_units_h);
-  all_loaded_comp_units_h =
-    CALLN (Fmake_hash_table, QCweakness, Qkey_and_value, QCtest, Qequal);
-
   DEFVAR_LISP ("comp-ctxt", Vcomp_ctxt,
               doc: /* The compiler context.  */);
   Vcomp_ctxt = Qnil;
@@ -5781,7 +5780,7 @@ For internal use.  */);
   DEFVAR_LISP ("native-comp-eln-load-path", Vnative_comp_eln_load_path,
               doc: /* List of eln cache directories.
 
-If a directory is non absolute is assumed to be relative to
+If a directory is non absolute it is assumed to be relative to
 `invocation-directory'.
 `comp-native-version-dir' value is used as a sub-folder name inside
 each eln cache directory.
@@ -5813,6 +5812,12 @@ For internal use.  */);
               doc: /* When non-nil assume the file being compiled to
 be preloaded.  */);
 
+  DEFVAR_LISP ("comp-loaded-comp-units-h", Vcomp_loaded_comp_units_h,
+              doc: /* Hash table recording all loaded compilation units.
+file -> CU.  */);
+  Vcomp_loaded_comp_units_h =
+    CALLN (Fmake_hash_table, QCweakness, Qvalue, QCtest, Qequal);
+
   Fprovide (intern_c_string ("native-compile"), Qnil);
 #endif /* #ifdef HAVE_NATIVE_COMP */
 
diff --git a/src/composite.c b/src/composite.c
index 4d69702171..22422cca09 100644
--- a/src/composite.c
+++ b/src/composite.c
@@ -24,6 +24,8 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 
 #include <config.h>
 
+#include <stdlib.h>            /* for qsort */
+
 #include "lisp.h"
 #include "character.h"
 #include "composite.h"
@@ -1021,7 +1023,11 @@ composition_compute_stop_pos (struct composition_it 
*cmp_it, ptrdiff_t charpos,
          /* But we don't know where to stop the searching.  */
          endpos = NILP (string) ? BEGV - 1 : -1;
          /* Usually we don't reach ENDPOS because we stop searching
-            at an uncomposable character (NL, LRE, etc).  */
+            at an uncomposable character (NL, LRE, etc).  In buffers
+            with long lines, however, NL might be far away, so
+            pretend that the buffer is smaller.  */
+         if (current_buffer->long_line_optimizations_p)
+           endpos = get_closer_narrowed_begv (cmp_it->parent_it->w, charpos);
        }
     }
   cmp_it->id = -1;
@@ -1513,10 +1519,11 @@ struct position_record
 /* Similar to find_composition, but find an automatic composition instead.
 
    This function looks for automatic composition at or near position
-   POS of OBJECT (a buffer or a string).  OBJECT defaults to the
-   current buffer.  It must be assured that POS is not within a static
-   composition.  Also, the current buffer must be displayed in some
-   window, otherwise the function will return FALSE.
+   POS of STRING object, either a buffer or a Lisp string.  If STRING
+   is nil, it defaults to the current buffer.  It must be assured that
+   POS is not within a static composition.  Also, the current buffer
+   must be displayed in some window, otherwise the function will
+   return FALSE.
 
    If LIMIT is negative, and there's no composition that includes POS
    (i.e. starts at or before POS and ends at or after POS), return
@@ -1525,8 +1532,8 @@ struct position_record
    MAX_AUTO_COMPOSITION_LOOKBACK, the maximum number of look-back for
    automatic compositions (3) -- this is a limitation imposed by
    composition rules in composition-function-table, which see.  If
-   BACKLIM is negative, it stands for the beginning of OBJECT: BEGV
-   for a buffer or position zero for a string.
+   BACKLIM is negative, it stands for the beginning of STRING object:
+   BEGV for a buffer or position zero for a string.
 
    If LIMIT is positive, search for a composition forward (LIMIT >
    POS) or backward (LIMIT < POS).  In this case, LIMIT bounds the
@@ -1535,18 +1542,21 @@ struct position_record
    function can find a composition that starts after POS.
 
    BACKLIM limits how far back is the function allowed to look in
-   OBJECT while trying to find a position where it is safe to start
-   searching forward for compositions.  Such a safe place is generally
-   the position after a character that can never be composed.
+   STRING object while trying to find a position where it is safe to
+   start searching forward for compositions.  Such a safe place is
+   generally the position after a character that can never be
+   composed.
 
    If BACKLIM is negative, that means the first character position of
-   OBJECT; this is useful when calling the function for the first time
-   for a given buffer or string, since it is possible that a
-   composition begins before POS.  However, if POS is very far from
-   the beginning of OBJECT, a negative value of BACKLIM could make the
-   function slow.  Also, in this case the function may return START
-   and END that do not include POS, something that is not necessarily
-   wanted, and needs to be explicitly checked by the caller.
+   STRING object; this is useful when calling the function for the
+   first time for a given buffer or string, since it is possible that
+   a composition begins before POS.  However, if POS is very far from
+   the beginning of STRING object, a negative value of BACKLIM could
+   make the function slow.  For that reason, when STRING is a buffer
+   or nil, we restrict the search back to the first newline before
+   POS.  Also, in this case the function may return START and END that
+   do not include POS, something that is not necessarily wanted, and
+   needs to be explicitly checked by the caller.
 
    When calling the function in a loop for the same buffer/string, the
    caller should generally set BACKLIM equal to POS, to avoid costly
@@ -1585,7 +1595,23 @@ find_automatic_composition (ptrdiff_t pos, ptrdiff_t 
limit, ptrdiff_t backlim,
   cur.pos = pos;
   if (NILP (string))
     {
-      head = backlim < 0 ? BEGV : backlim, tail = ZV, stop = GPT;
+      if (backlim < 0)
+       {
+         /* This assumes a newline can never be composed.  */
+         head = find_newline (pos, -1, 0, -1, -1, NULL, NULL, false);
+       }
+      else
+       head = backlim;
+      if (current_buffer->long_line_optimizations_p)
+       {
+         /* In buffers with very long lines, this function becomes very
+            slow.  Pretend that the buffer is narrowed to make it fast.  */
+         ptrdiff_t begv = get_closer_narrowed_begv (w, window_point (w));
+         if (pos > begv)
+           head = begv;
+       }
+      tail = ZV;
+      stop = GPT;
       cur.pos_byte = CHAR_TO_BYTE (cur.pos);
       cur.p = BYTE_POS_ADDR (cur.pos_byte);
     }
@@ -1871,7 +1897,8 @@ should be ignored.  */)
   else
     {
       CHECK_STRING (string);
-      validate_subarray (string, from, to, SCHARS (string), &frompos, &topos);
+      ptrdiff_t chars = SCHARS (string);
+      validate_subarray (string, from, to, chars, &frompos, &topos);
       if (! STRING_MULTIBYTE (string))
        {
          ptrdiff_t i;
@@ -1881,9 +1908,10 @@ should be ignored.  */)
              error ("Attempt to shape unibyte text");
          /* STRING is a pure-ASCII string, so we can convert it (or,
             rather, its copy) to multibyte and use that thereafter.  */
-         Lisp_Object string_copy = Fconcat (1, &string);
-         STRING_SET_MULTIBYTE (string_copy);
-         string = string_copy;
+         /* FIXME: Not clear why we need to do that: AFAICT the rest of
+             the code should work on an ASCII-only unibyte string just
+             as well (bug#56347).  */
+         string = make_multibyte_string (SSDATA (string), chars, chars);
        }
       frombyte = string_char_to_byte (string, frompos);
     }
@@ -2028,6 +2056,54 @@ See `find-composition' for more details.  */)
   return Fcons (make_fixnum (start), Fcons (make_fixnum (end), tail));
 }
 
+static int
+compare_composition_rules (const void *r1, const void *r2)
+{
+  Lisp_Object vec1 = *(Lisp_Object *)r1, vec2 = *(Lisp_Object *)r2;
+
+  return XFIXNAT (AREF (vec2, 1)) - XFIXNAT (AREF (vec1, 1));
+}
+
+DEFUN ("composition-sort-rules", Fcomposition_sort_rules,
+       Scomposition_sort_rules, 1, 1, 0,
+       doc: /* Sort composition RULES by their LOOKBACK parameter.
+
+If RULES include just one rule, return RULES.
+Otherwise, return a new list of rules where all the rules are
+arranged in decreasing order of the LOOKBACK parameter of the
+rules (the second element of the rule's vector).  This is required
+when combining composition rules from different sources, because
+of the way buffer text is examined for matching one of the rules.  */)
+  (Lisp_Object rules)
+{
+  ptrdiff_t nrules;
+  USE_SAFE_ALLOCA;
+
+  CHECK_LIST (rules);
+  nrules = list_length (rules);
+  if (nrules > 1)
+    {
+      ptrdiff_t i;
+      Lisp_Object *sortvec;
+
+      SAFE_NALLOCA (sortvec, 1, nrules);
+      for (i = 0; i < nrules; i++)
+       {
+         Lisp_Object elt = XCAR (rules);
+         if (VECTORP (elt) && ASIZE (elt) == 3 && FIXNATP (AREF (elt, 1)))
+           sortvec[i] = elt;
+         else
+           error ("Invalid composition rule in RULES argument");
+         rules = XCDR (rules);
+       }
+      qsort (sortvec, nrules, sizeof (Lisp_Object), compare_composition_rules);
+      rules = Flist (nrules, sortvec);
+      SAFE_FREE ();
+    }
+
+  return rules;
+}
+
 
 void
 syms_of_composite (void)
@@ -2159,4 +2235,5 @@ This list is auto-generated, you should not need to 
modify it.  */);
   defsubr (&Sfind_composition_internal);
   defsubr (&Scomposition_get_gstring);
   defsubr (&Sclear_composition_cache);
+  defsubr (&Scomposition_sort_rules);
 }
diff --git a/src/conf_post.h b/src/conf_post.h
index 5108e44efb..6ecebf36ab 100644
--- a/src/conf_post.h
+++ b/src/conf_post.h
@@ -267,7 +267,7 @@ extern void _DebPrint (const char *fmt, ...);
 /* Tell regex.c to use a type compatible with Emacs.  */
 #define RE_TRANSLATE_TYPE Lisp_Object
 #define RE_TRANSLATE(TBL, C) char_table_translate (TBL, C)
-#define RE_TRANSLATE_P(TBL) (!EQ (TBL, make_fixnum (0)))
+#define RE_TRANSLATE_P(TBL) (!BASE_EQ (TBL, make_fixnum (0)))
 #endif
 
 /* Tell time_rz.c to use Emacs's getter and setter for TZ.
diff --git a/src/data.c b/src/data.c
index 2447ed72e4..6921232665 100644
--- a/src/data.c
+++ b/src/data.c
@@ -880,7 +880,7 @@ add_to_function_history (Lisp_Object symbol, Lisp_Object 
olddef)
     if (NILP (XCDR (tail)) && STRINGP (XCAR (tail)))
       file = XCAR (tail);
 
-  Lisp_Object tem = Fplist_member (past, file);
+  Lisp_Object tem = plist_member (past, file);
   if (!NILP (tem))
     { /* New def from a file used before.
          Overwrite the previous record associated with this file.  */
@@ -1552,8 +1552,13 @@ swap_in_symval_forwarding (struct Lisp_Symbol *symbol, 
struct Lisp_Buffer_Local_
 /* Find the value of a symbol, returning Qunbound if it's not bound.
    This is helpful for code which just wants to get a variable's value
    if it has one, without signaling an error.
-   Note that it must not be possible to quit
-   within this function.  Great care is required for this.  */
+
+   This function is very similar to buffer_local_value, but we have
+   two separate code paths here since find_symbol_value has to be very
+   efficient, while buffer_local_value doesn't have to be.
+
+   Note that it must not be possible to quit within this function.
+   Great care is required for this.  */
 
 Lisp_Object
 find_symbol_value (Lisp_Object symbol)
@@ -2336,7 +2341,7 @@ From now on the default value will apply in this buffer.  
Return VARIABLE.  */)
      forwarded objects won't work right.  */
   {
     Lisp_Object buf; XSETBUFFER (buf, current_buffer);
-    if (EQ (buf, blv->where))
+    if (BASE_EQ (buf, blv->where))
       swap_in_global_binding (sym);
   }
 
@@ -3518,9 +3523,16 @@ representation.  */)
 }
 
 DEFUN ("ash", Fash, Sash, 2, 2, 0,
-       doc: /* Return VALUE with its bits shifted left by COUNT.
-If COUNT is negative, shifting is actually to the right.
-In this case, the sign bit is duplicated.  */)
+       doc: /* Return integer VALUE with its bits shifted left by COUNT bit 
positions.
+If COUNT is negative, shift VALUE to the right instead.
+VALUE and COUNT must be integers.
+Mathematically, the return value is VALUE multiplied by 2 to the
+power of COUNT, rounded down.  If the result is non-zero, its sign
+is the same as that of VALUE.
+In terms of bits, when COUNT is positive, the function moves
+the bits of VALUE to the left, adding zero bits on the right; when
+COUNT is negative, it moves the bits of VALUE to the right,
+discarding bits.  */)
   (Lisp_Object value, Lisp_Object count)
 {
   CHECK_INTEGER (value);
@@ -3528,7 +3540,7 @@ In this case, the sign bit is duplicated.  */)
 
   if (! FIXNUMP (count))
     {
-      if (EQ (value, make_fixnum (0)))
+      if (BASE_EQ (value, make_fixnum (0)))
        return value;
       if (mpz_sgn (*xbignum_val (count)) < 0)
        {
@@ -3573,11 +3585,11 @@ Lisp_Object
 expt_integer (Lisp_Object x, Lisp_Object y)
 {
   /* Special cases for -1 <= x <= 1, which never overflow.  */
-  if (EQ (x, make_fixnum (1)))
+  if (BASE_EQ (x, make_fixnum (1)))
     return x;
-  if (EQ (x, make_fixnum (0)))
-    return EQ (x, y) ? make_fixnum (1) : x;
-  if (EQ (x, make_fixnum (-1)))
+  if (BASE_EQ (x, make_fixnum (0)))
+    return BASE_EQ (x, y) ? make_fixnum (1) : x;
+  if (BASE_EQ (x, make_fixnum (-1)))
     return ((FIXNUMP (y) ? XFIXNUM (y) & 1 : mpz_odd_p (*xbignum_val (y)))
            ? x : make_fixnum (1));
 
diff --git a/src/dired.c b/src/dired.c
index cd50012ddc..c2c099f0a5 100644
--- a/src/dired.c
+++ b/src/dired.c
@@ -219,6 +219,13 @@ directory_files_internal (Lisp_Object directory, 
Lisp_Object full,
     }
 #endif
 
+  if (!NILP (full) && !STRING_MULTIBYTE (directory))
+    { /* We will be concatenating 'directory' with local file name.
+         We always decode local file names, so in order to safely concatenate
+         them we need 'directory' to be decoded as well (bug#56469).  */
+      directory = DECODE_FILE (directory);
+    }
+
   ptrdiff_t directory_nbytes = SBYTES (directory);
   re_match_object = Qt;
 
@@ -263,9 +270,20 @@ directory_files_internal (Lisp_Object directory, 
Lisp_Object full,
          ptrdiff_t name_nbytes = SBYTES (name);
          ptrdiff_t nbytes = directory_nbytes + needsep + name_nbytes;
          ptrdiff_t nchars = SCHARS (directory) + needsep + SCHARS (name);
-         finalname = make_uninit_multibyte_string (nchars, nbytes);
-         if (nchars == nbytes)
-           STRING_SET_UNIBYTE (finalname);
+         /* DECODE_FILE may return non-ASCII unibyte strings (e.g. when
+             file-name-coding-system is 'binary'), so we don't know for sure
+             that the bytes we have follow our internal utf-8 representation
+             for multibyte strings.  If nchars == nbytes we don't need to
+             care and just return a unibyte string; and if not, that means
+             one of 'name' or 'directory' is multibyte, in which case we
+             presume that the other one would also be multibyte if it
+             contained non-ASCII.
+             FIXME: This last presumption is broken when 'directory' is
+             multibyte (with non-ASCII), and 'name' is unibyte with non-ASCII
+             (because file-name-coding-system is 'binary').  */
+         finalname = (nchars == nbytes)
+                     ? make_uninit_string (nbytes)
+                     : make_uninit_multibyte_string (nchars, nbytes);
          memcpy (SDATA (finalname), SDATA (directory), directory_nbytes);
          if (needsep)
            SSET (finalname, directory_nbytes, DIRECTORY_SEP);
@@ -482,8 +500,8 @@ file_name_completion (Lisp_Object file, Lisp_Object 
dirname, bool all_flag,
      decoded names in order to filter false positives, such as "a"
      falsely matching "a-ring".  */
   if (!NILP (file_encoding)
-      && !NILP (Fplist_get (Fcoding_system_plist (file_encoding),
-                           Qdecomposed_characters)))
+      && !NILP (plist_get (Fcoding_system_plist (file_encoding),
+                          Qdecomposed_characters)))
     {
       check_decoded = true;
       if (STRING_MULTIBYTE (file))
@@ -521,9 +539,9 @@ file_name_completion (Lisp_Object file, Lisp_Object 
dirname, bool all_flag,
       name = DECODE_FILE (name);
       ptrdiff_t name_blen = SBYTES (name), name_len = SCHARS (name);
       if (completion_ignore_case
-         && !EQ (Fcompare_strings (name, zero, file_len, file, zero, file_len,
-                                   Qt),
-                 Qt))
+         && !BASE_EQ (Fcompare_strings (name, zero, file_len, file, zero,
+                                        file_len, Qt),
+                      Qt))
            continue;
 
       switch (dirent_type (dp))
@@ -603,10 +621,12 @@ file_name_completion (Lisp_Object file, Lisp_Object 
dirname, bool all_flag,
                        skip = name_len - elt_len;
                        cmp_len = make_fixnum (elt_len);
                        if (skip < 0
-                           || !EQ (Fcompare_strings (name, make_fixnum (skip),
-                                                     Qnil,
-                                                     elt, zero, cmp_len, Qt),
-                                   Qt))
+                           || !BASE_EQ (Fcompare_strings (name,
+                                                          make_fixnum (skip),
+                                                          Qnil,
+                                                          elt, zero, cmp_len,
+                                                          Qt),
+                                        Qt))
                          continue;
                      }
                    break;
@@ -637,10 +657,12 @@ file_name_completion (Lisp_Object file, Lisp_Object 
dirname, bool all_flag,
                        skip = name_len - elt_len;
                        cmp_len = make_fixnum (elt_len);
                        if (skip < 0
-                           || !EQ (Fcompare_strings (name, make_fixnum (skip),
-                                                     Qnil,
-                                                     elt, zero, cmp_len, Qt),
-                                   Qt))
+                           || !BASE_EQ (Fcompare_strings (name,
+                                                          make_fixnum (skip),
+                                                          Qnil,
+                                                          elt, zero, cmp_len,
+                                                          Qt),
+                                        Qt))
                          continue;
                      }
                    break;
@@ -699,7 +721,7 @@ file_name_completion (Lisp_Object file, Lisp_Object 
dirname, bool all_flag,
            = Fcompare_strings (name, zero, make_fixnum (compare),
                                file, zero, make_fixnum (compare),
                                completion_ignore_case ? Qt : Qnil);
-         if (!EQ (cmp, Qt))
+         if (!BASE_EQ (cmp, Qt))
            continue;
        }
 
@@ -722,7 +744,8 @@ file_name_completion (Lisp_Object file, Lisp_Object 
dirname, bool all_flag,
            = Fcompare_strings (bestmatch, zero, make_fixnum (compare),
                                name, zero, make_fixnum (compare),
                                completion_ignore_case ? Qt : Qnil);
-         ptrdiff_t matchsize = EQ (cmp, Qt) ? compare : eabs (XFIXNUM (cmp)) - 
1;
+         ptrdiff_t matchsize = BASE_EQ (cmp, Qt)
+                               ? compare : eabs (XFIXNUM (cmp)) - 1;
 
          if (completion_ignore_case)
            {
@@ -751,13 +774,13 @@ file_name_completion (Lisp_Object file, Lisp_Object 
dirname, bool all_flag,
                                               file, zero,
                                               Qnil,
                                               Qnil),
-                      EQ (Qt, cmp))
+                      BASE_EQ (Qt, cmp))
                   && (cmp = Fcompare_strings (bestmatch, zero,
                                               make_fixnum (SCHARS (file)),
                                               file, zero,
                                               Qnil,
                                               Qnil),
-                      ! EQ (Qt, cmp))))
+                      ! BASE_EQ (Qt, cmp))))
                bestmatch = name;
            }
          bestmatchsize = matchsize;
diff --git a/src/dispextern.h b/src/dispextern.h
index c7399ca299..2f5f4335fe 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -2287,6 +2287,8 @@ struct composition_it
      reverse order, and thus the grapheme clusters must be rendered
      from the last to the first.  */
   bool reversed_p;
+  /* Parent iterator. */
+  struct it *parent_it;
 
   /** The following members contain information about the current
       grapheme cluster.  */
@@ -2332,6 +2334,14 @@ struct it
      with which display_string was called.  */
   ptrdiff_t end_charpos;
 
+  /* Alternate begin position of the buffer that may be used to
+     optimize display (see the SET_WITH_NARROWED_BEGV macro).  */
+  ptrdiff_t narrowed_begv;
+
+  /* Alternate end position of the buffer that may be used to
+     optimize display.  */
+  ptrdiff_t narrowed_zv;
+
   /* C string to iterate over.  Non-null means get characters from
      this string, otherwise characters are read from current_buffer
      or it->string.  */
@@ -2342,9 +2352,6 @@ struct it
      used for overlay strings and strings from display properties.  */
   ptrdiff_t string_nchars;
 
-  /* Position at which redisplay end trigger functions should be run.  */
-  ptrdiff_t redisplay_end_trigger_charpos;
-
   /* True means multibyte characters are enabled.  */
   bool_bf multibyte_p : 1;
 
@@ -2742,11 +2749,11 @@ struct it
   /* The line number of point's line, or zero if not computed yet.  */
   ptrdiff_t pt_lnum;
 
-  /* Number of pixels to offset tab stops due to width fixup of the
-     first glyph that crosses first_visible_x.  This is only needed on
-     GUI frames, only when display-line-numbers is in effect, and only
-     in hscrolled windows.  */
-  int tab_offset;
+  /* Number of pixels to adjust tab stops and stretch glyphs due to
+     width fixup of the first stretch glyph that crosses first_visible_x.
+     This is only needed on GUI frames, only when display-line-numbers
+     is in effect, and only in hscrolled windows.  */
+  int stretch_adjust;
 
   /* Left fringe bitmap number (enum fringe_bitmap_type).  */
   unsigned left_user_fringe_bitmap : FRINGE_ID_BITS;
@@ -2867,18 +2874,17 @@ typedef struct {
 INLINE void
 reset_mouse_highlight (Mouse_HLInfo *hlinfo)
 {
-
-    hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
-    hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
-    hlinfo->mouse_face_mouse_x = hlinfo->mouse_face_mouse_y = 0;
-    hlinfo->mouse_face_beg_x = hlinfo->mouse_face_end_x = 0;
-    hlinfo->mouse_face_face_id = DEFAULT_FACE_ID;
-    hlinfo->mouse_face_mouse_frame = NULL;
-    hlinfo->mouse_face_window = Qnil;
-    hlinfo->mouse_face_overlay = Qnil;
-    hlinfo->mouse_face_past_end = false;
-    hlinfo->mouse_face_hidden = false;
-    hlinfo->mouse_face_defer = false;
+  hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
+  hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
+  hlinfo->mouse_face_mouse_x = hlinfo->mouse_face_mouse_y = 0;
+  hlinfo->mouse_face_beg_x = hlinfo->mouse_face_end_x = 0;
+  hlinfo->mouse_face_face_id = DEFAULT_FACE_ID;
+  hlinfo->mouse_face_mouse_frame = NULL;
+  hlinfo->mouse_face_window = Qnil;
+  hlinfo->mouse_face_overlay = Qnil;
+  hlinfo->mouse_face_past_end = false;
+  hlinfo->mouse_face_hidden = false;
+  hlinfo->mouse_face_defer = false;
 }
 
 /***********************************************************************
@@ -3085,12 +3091,15 @@ struct image
   XFORM xform;
 #endif
 #ifdef HAVE_HAIKU
-  /* Non-zero if the image has not yet been transformed for display.  */
-  int have_be_transforms_p;
+  /* The affine transformation to apply to this image.  */
+  double transform[3][3];
 
-  double be_rotate;
-  double be_scale_x;
-  double be_scale_y;
+  /* The original width and height of the image.  */
+  int original_width, original_height;
+
+  /* Whether or not bilinear filtering should be used to "smooth" the
+     image.  */
+  bool use_bilinear_filtering;
 #endif
 
   /* Colors allocated for this image, if any.  Allocated via xmalloc.  */
@@ -3393,6 +3402,9 @@ void mark_window_display_accurate (Lisp_Object, bool);
 void redisplay_preserve_echo_area (int);
 void init_iterator (struct it *, struct window *, ptrdiff_t,
                     ptrdiff_t, struct glyph_row *, enum face_id);
+ptrdiff_t get_narrowed_begv (struct window *, ptrdiff_t);
+ptrdiff_t get_narrowed_zv (struct window *, ptrdiff_t);
+ptrdiff_t get_closer_narrowed_begv (struct window *, ptrdiff_t);
 void init_iterator_to_row_start (struct it *, struct window *,
                                  struct glyph_row *);
 void start_display (struct it *, struct window *, struct text_pos);
@@ -3407,6 +3419,8 @@ int partial_line_height (struct it *it_origin);
 bool in_display_vector_p (struct it *);
 int frame_mode_line_height (struct frame *);
 extern bool redisplaying_p;
+extern bool display_working_on_window_p;
+extern void unwind_display_working_on_window (void);
 extern bool help_echo_showing_p;
 extern Lisp_Object help_echo_string, help_echo_window;
 extern Lisp_Object help_echo_object, previous_help_echo_string;
@@ -3505,6 +3519,8 @@ extern unsigned row_hash (struct glyph_row *);
 
 extern bool buffer_flipping_blocked_p (void);
 
+extern void update_redisplay_ticks (int, struct window *);
+
 /* Defined in image.c */
 
 #ifdef HAVE_WINDOW_SYSTEM
@@ -3533,6 +3549,7 @@ struct image_cache *make_image_cache (void);
 void free_image_cache (struct frame *);
 void clear_image_caches (Lisp_Object);
 void mark_image_cache (struct image_cache *);
+void image_prune_animation_caches (bool);
 bool valid_image_p (Lisp_Object);
 void prepare_image_for_display (struct frame *, struct image *);
 ptrdiff_t lookup_image (struct frame *, Lisp_Object, int);
diff --git a/src/dispnew.c b/src/dispnew.c
index 7a4d9f8710..53a47c4b2f 100644
--- a/src/dispnew.c
+++ b/src/dispnew.c
@@ -2732,12 +2732,25 @@ set_frame_matrix_frame (struct frame *f)
    operations in window matrices of frame_matrix_frame.  */
 
 static void
-make_current (struct glyph_matrix *desired_matrix, struct glyph_matrix 
*current_matrix, int row)
+make_current (struct glyph_matrix *desired_matrix,
+             struct glyph_matrix *current_matrix, int row)
 {
   struct glyph_row *current_row = MATRIX_ROW (current_matrix, row);
   struct glyph_row *desired_row = MATRIX_ROW (desired_matrix, row);
   bool mouse_face_p = current_row->mouse_face_p;
 
+  /* If we aborted redisplay of this window, a row in the desired
+     matrix might not have its hash computed.  But update_window
+     relies on each row having its correct hash, so do it here if
+     needed.  */
+  if (!desired_row->hash
+      /* A glyph row that is not completely empty is unlikely to have
+        a zero hash value.  */
+      && !(!desired_row->used[0]
+          && !desired_row->used[1]
+          && !desired_row->used[2]))
+    desired_row->hash = row_hash (desired_row);
+
   /* Do current_row = desired_row.  This exchanges glyph pointers
      between both rows, and does a structure assignment otherwise.  */
   assign_row (current_row, desired_row);
@@ -4284,11 +4297,11 @@ set_window_cursor_after_update (struct window *w)
       /* If we are showing a message instead of the mini-buffer,
         show the cursor for the message instead.  */
       && XWINDOW (minibuf_window) == w
-      && EQ (minibuf_window, echo_area_window)
+      && BASE_EQ (minibuf_window, echo_area_window)
       /* These cases apply only to the frame that contains
         the active mini-buffer window.  */
       && FRAME_HAS_MINIBUF_P (f)
-      && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window))
+      && BASE_EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window))
     {
       cx = cy = vpos = hpos = 0;
 
@@ -4948,13 +4961,13 @@ update_frame_1 (struct frame *f, bool force_p, bool 
inhibit_id_p,
           /* If we are showing a message instead of the mini-buffer,
              show the cursor for the message instead of for the
              (now hidden) mini-buffer contents.  */
-          || (EQ (minibuf_window, selected_window)
-              && EQ (minibuf_window, echo_area_window)
+          || (BASE_EQ (minibuf_window, selected_window)
+              && BASE_EQ (minibuf_window, echo_area_window)
               && !NILP (echo_area_buffer[0])))
          /* These cases apply only to the frame that contains
             the active mini-buffer window.  */
          && FRAME_HAS_MINIBUF_P (f)
-         && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window))
+         && BASE_EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window))
        {
          int top = WINDOW_TOP_EDGE_LINE (XWINDOW (FRAME_MINIBUF_WINDOW (f)));
          int col;
@@ -6306,7 +6319,7 @@ pass nil for VARIABLE.  */)
     {
       if (idx == ASIZE (state))
        goto changed;
-      if (!EQ (AREF (state, idx++), frame))
+      if (!BASE_EQ (AREF (state, idx++), frame))
        goto changed;
       if (idx == ASIZE (state))
        goto changed;
@@ -6321,7 +6334,7 @@ pass nil for VARIABLE.  */)
        continue;
       if (idx == ASIZE (state))
        goto changed;
-      if (!EQ (AREF (state, idx++), buf))
+      if (!BASE_EQ (AREF (state, idx++), buf))
        goto changed;
       if (idx == ASIZE (state))
        goto changed;
diff --git a/src/doc.c b/src/doc.c
index 14db3189f3..34b80d03aa 100644
--- a/src/doc.c
+++ b/src/doc.c
@@ -346,7 +346,7 @@ string is passed through `substitute-command-keys'.  */)
 
   /* If DOC is 0, it's typically because of a dumped file missing
      from the DOC file (bug in src/Makefile.in).  */
-  if (EQ (doc, make_fixnum (0)))
+  if (BASE_EQ (doc, make_fixnum (0)))
     doc = Qnil;
   if (FIXNUMP (doc) || CONSP (doc))
     {
@@ -400,7 +400,7 @@ aren't strings.  */)
        tem = Fget (indirect, prop);
     }
 
-  if (EQ (tem, make_fixnum (0)))
+  if (BASE_EQ (tem, make_fixnum (0)))
     tem = Qnil;
 
   /* See if we want to look for the string in the DOC file. */
@@ -637,7 +637,7 @@ default_to_grave_quoting_style (void)
   Lisp_Object dv = DISP_CHAR_VECTOR (XCHAR_TABLE (Vstandard_display_table),
                                     LEFT_SINGLE_QUOTATION_MARK);
   return (VECTORP (dv) && ASIZE (dv) == 1
-         && EQ (AREF (dv, 0), make_fixnum ('`')));
+         && BASE_EQ (AREF (dv, 0), make_fixnum ('`')));
 }
 
 DEFUN ("text-quoting-style", Ftext_quoting_style,
diff --git a/src/editfns.c b/src/editfns.c
index 17f0252969..cd5cddee79 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -161,7 +161,7 @@ DEFUN ("byte-to-string", Fbyte_to_string, Sbyte_to_string, 
1, 1, 0,
   if (XFIXNUM (byte) < 0 || XFIXNUM (byte) > 255)
     error ("Invalid byte");
   b = XFIXNUM (byte);
-  return make_string_from_bytes ((char *) &b, 1, 1);
+  return make_unibyte_string ((char *) &b, 1);
 }
 
 DEFUN ("string-to-char", Fstring_to_char, Sstring_to_char, 1, 1, 0,
@@ -648,7 +648,7 @@ Field boundaries are not noticed if 
`inhibit-field-text-motion' is non-nil.  */)
   prev_new = make_fixnum (XFIXNUM (new_pos) - 1);
 
   if (NILP (Vinhibit_field_text_motion)
-      && !EQ (new_pos, old_pos)
+      && !BASE_EQ (new_pos, old_pos)
       && (!NILP (Fget_char_property (new_pos, Qfield, Qnil))
           || !NILP (Fget_char_property (old_pos, Qfield, Qnil))
           /* To recognize field boundaries, we must also look at the
@@ -709,9 +709,28 @@ Field boundaries are not noticed if 
`inhibit-field-text-motion' is non-nil.  */)
 }
 
 
-DEFUN ("line-beginning-position",
-       Fline_beginning_position, Sline_beginning_position, 0, 1, 0,
-       doc: /* Return the character position of the first character on the 
current line.
+static ptrdiff_t
+bol (Lisp_Object n, ptrdiff_t *out_count)
+{
+  ptrdiff_t bytepos, charpos, count;
+
+  if (NILP (n))
+    count = 0;
+  else if (FIXNUMP (n))
+    count = clip_to_bounds (-BUF_BYTES_MAX, XFIXNUM (n) - 1, BUF_BYTES_MAX);
+  else
+    {
+      CHECK_INTEGER (n);
+      count = NILP (Fnatnump (n)) ? -BUF_BYTES_MAX : BUF_BYTES_MAX;
+    }
+  if (out_count)
+    *out_count = count;
+  scan_newline_from_point (count, &charpos, &bytepos);
+  return charpos;
+}
+
+DEFUN ("pos-bol", Fpos_bol, Spos_bol, 0, 1, 0,
+       doc: /* Return the position of the first character on the current line.
 With optional argument N, scan forward N - 1 lines first.
 If the scan reaches the end of the buffer, return that position.
 
@@ -720,6 +739,17 @@ position of the first character in logical order, i.e. the 
smallest
 character position on the logical line.  See `vertical-motion' for
 movement by screen lines.
 
+This function does not move point.  Also see `line-beginning-position'.  */)
+  (Lisp_Object n)
+{
+  return make_fixnum (bol (n, NULL));
+}
+
+DEFUN ("line-beginning-position",
+       Fline_beginning_position, Sline_beginning_position, 0, 1, 0,
+       doc: /* Return the position of the first character in the current 
line/field.
+This function is like `pos-bol' (which see), but respects fields.
+
 This function constrains the returned position to the current field
 unless that position would be on a different line from the original,
 unconstrained result.  If N is nil or 1, and a front-sticky field
@@ -729,28 +759,33 @@ boundaries, bind `inhibit-field-text-motion' to t.
 This function does not move point.  */)
   (Lisp_Object n)
 {
-  ptrdiff_t charpos, bytepos, count;
+  ptrdiff_t count, charpos = bol (n, &count);
+  /* Return END constrained to the current input field.  */
+  return Fconstrain_to_field (make_fixnum (charpos), make_fixnum (PT),
+                             count != 0 ? Qt : Qnil,
+                             Qt, Qnil);
+}
+
+static ptrdiff_t
+eol (Lisp_Object n)
+{
+  ptrdiff_t count;
 
   if (NILP (n))
-    count = 0;
+    count = 1;
   else if (FIXNUMP (n))
-    count = clip_to_bounds (-BUF_BYTES_MAX, XFIXNUM (n) - 1, BUF_BYTES_MAX);
+    count = clip_to_bounds (-BUF_BYTES_MAX, XFIXNUM (n), BUF_BYTES_MAX);
   else
     {
       CHECK_INTEGER (n);
       count = NILP (Fnatnump (n)) ? -BUF_BYTES_MAX : BUF_BYTES_MAX;
     }
-
-  scan_newline_from_point (count, &charpos, &bytepos);
-
-  /* Return END constrained to the current input field.  */
-  return Fconstrain_to_field (make_fixnum (charpos), make_fixnum (PT),
-                             count != 0 ? Qt : Qnil,
-                             Qt, Qnil);
+  return find_before_next_newline (PT, 0, count - (count <= 0),
+                                  NULL);
 }
 
-DEFUN ("line-end-position", Fline_end_position, Sline_end_position, 0, 1, 0,
-       doc: /* Return the character position of the last character on the 
current line.
+DEFUN ("pos-eol", Fpos_eol, Spos_eol, 0, 1, 0,
+       doc: /* Return the position of the last character on the current line.
 With argument N not nil or 1, move forward N - 1 lines first.
 If scan reaches end of buffer, return that position.
 
@@ -758,6 +793,19 @@ This function ignores text display directionality; it 
returns the
 position of the last character in logical order, i.e. the largest
 character position on the line.
 
+This function does not move point.  Also see `line-end-position'.  */)
+  (Lisp_Object n)
+{
+  return make_fixnum (eol (n));
+}
+
+DEFUN ("line-end-position", Fline_end_position, Sline_end_position, 0, 1, 0,
+       doc: /* Return the position of the last character in the current 
line/field.
+With argument N not nil or 1, move forward N - 1 lines first.
+If scan reaches end of buffer, return that position.
+
+This function is like `pos-eol' (which see), but respects fields.
+
 This function constrains the returned position to the current field
 unless that would be on a different line from the original,
 unconstrained result.  If N is nil or 1, and a rear-sticky field ends
@@ -767,24 +815,8 @@ boundaries bind `inhibit-field-text-motion' to t.
 This function does not move point.  */)
   (Lisp_Object n)
 {
-  ptrdiff_t clipped_n;
-  ptrdiff_t end_pos;
-  ptrdiff_t orig = PT;
-
-  if (NILP (n))
-    clipped_n = 1;
-  else if (FIXNUMP (n))
-    clipped_n = clip_to_bounds (-BUF_BYTES_MAX, XFIXNUM (n), BUF_BYTES_MAX);
-  else
-    {
-      CHECK_INTEGER (n);
-      clipped_n = NILP (Fnatnump (n)) ? -BUF_BYTES_MAX : BUF_BYTES_MAX;
-    }
-  end_pos = find_before_next_newline (orig, 0, clipped_n - (clipped_n <= 0),
-                                     NULL);
-
   /* Return END_POS constrained to the current input field.  */
-  return Fconstrain_to_field (make_fixnum (end_pos), make_fixnum (orig),
+  return Fconstrain_to_field (make_fixnum (eol (n)), make_fixnum (PT),
                              Qnil, Qt, Qnil);
 }
 
@@ -797,7 +829,7 @@ save_excursion_save (union specbinding *pdl)
   pdl->unwind_excursion.marker = Fpoint_marker ();
   /* Selected window if current buffer is shown in it, nil otherwise.  */
   pdl->unwind_excursion.window
-    = (EQ (XWINDOW (selected_window)->contents, Fcurrent_buffer ())
+    = (BASE_EQ (XWINDOW (selected_window)->contents, Fcurrent_buffer ())
        ? selected_window : Qnil);
 }
 
@@ -821,7 +853,7 @@ save_excursion_restore (Lisp_Object marker, Lisp_Object 
window)
   /* If buffer was visible in a window, and a different window was
      selected, and the old selected window is still showing this
      buffer, restore point in that window.  */
-  if (WINDOWP (window) && !EQ (window, selected_window))
+  if (WINDOWP (window) && !BASE_EQ (window, selected_window))
     {
       /* Set window point if WINDOW is live and shows the current buffer.  */
       Lisp_Object contents = XWINDOW (window)->contents;
@@ -1172,8 +1204,7 @@ This ignores the environment variables LOGNAME and USER, 
so it differs from
 }
 
 DEFUN ("user-uid", Fuser_uid, Suser_uid, 0, 0, 0,
-       doc: /* Return the effective uid of Emacs.
-Value is a fixnum, if it's small enough, otherwise a bignum.  */)
+       doc: /* Return the effective uid of Emacs, as an integer.  */)
   (void)
 {
   uid_t euid = geteuid ();
@@ -1181,8 +1212,7 @@ Value is a fixnum, if it's small enough, otherwise a 
bignum.  */)
 }
 
 DEFUN ("user-real-uid", Fuser_real_uid, Suser_real_uid, 0, 0, 0,
-       doc: /* Return the real uid of Emacs.
-Value is a fixnum, if it's small enough, otherwise a bignum.  */)
+       doc: /* Return the real uid of Emacs, as an integer.  */)
   (void)
 {
   uid_t uid = getuid ();
@@ -1208,8 +1238,7 @@ Return nil if a group with such GID does not exists or is 
not known.  */)
 }
 
 DEFUN ("group-gid", Fgroup_gid, Sgroup_gid, 0, 0, 0,
-       doc: /* Return the effective gid of Emacs.
-Value is a fixnum, if it's small enough, otherwise a bignum.  */)
+       doc: /* Return the effective gid of Emacs, as an integer.  */)
   (void)
 {
   gid_t egid = getegid ();
@@ -1217,8 +1246,7 @@ Value is a fixnum, if it's small enough, otherwise a 
bignum.  */)
 }
 
 DEFUN ("group-real-gid", Fgroup_real_gid, Sgroup_real_gid, 0, 0, 0,
-       doc: /* Return the real gid of Emacs.
-Value is a fixnum, if it's small enough, otherwise a bignum.  */)
+       doc: /* Return the real gid of Emacs, as an integer.  */)
   (void)
 {
   gid_t gid = getgid ();
@@ -1306,8 +1334,7 @@ DEFUN ("system-name", Fsystem_name, Ssystem_name, 0, 0, 0,
 }
 
 DEFUN ("emacs-pid", Femacs_pid, Semacs_pid, 0, 0, 0,
-       doc: /* Return the process ID of Emacs, as a number.
-Value is a fixnum, if it's small enough, otherwise a bignum.  */)
+       doc: /* Return the process ID of Emacs, as an integer.  */)
   (void)
 {
   pid_t pid = getpid ();
@@ -2658,9 +2685,17 @@ DEFUN ("delete-and-extract-region", 
Fdelete_and_extract_region,
 
 DEFUN ("widen", Fwiden, Swiden, 0, 0, "",
        doc: /* Remove restrictions (narrowing) from current buffer.
-This allows the buffer's full text to be seen and edited.  */)
+This allows the buffer's full text to be seen and edited.
+
+Note that, when the current buffer contains one or more lines whose
+length is above `long-line-threshold', Emacs may decide to leave, for
+performance reasons, the accessible portion of the buffer unchanged
+after this function is called from low-level hooks, such as
+`jit-lock-functions' or `post-command-hook'.  */)
   (void)
 {
+  if (! NILP (Vrestrictions_locked))
+    return Qnil;
   if (BEG != BEGV || Z != ZV)
     current_buffer->clip_changed = 1;
   BEGV = BEG;
@@ -2671,17 +2706,23 @@ This allows the buffer's full text to be seen and 
edited.  */)
   return Qnil;
 }
 
-DEFUN ("narrow-to-region", Fnarrow_to_region, Snarrow_to_region, 2, 2, "r",
-       doc: /* Restrict editing in this buffer to the current region.
-The rest of the text becomes temporarily invisible and untouchable
-but is not deleted; if you save the buffer in a file, the invisible
-text is included in the file.  \\[widen] makes all visible again.
-See also `save-restriction'.
+static void
+unwind_locked_begv (Lisp_Object point_min)
+{
+  SET_BUF_BEGV (current_buffer, XFIXNUM (point_min));
+}
 
-When calling from Lisp, pass two arguments START and END:
-positions (integers or markers) bounding the text that should
-remain visible.  */)
-  (Lisp_Object start, Lisp_Object end)
+static void
+unwind_locked_zv (Lisp_Object point_max)
+{
+  SET_BUF_ZV (current_buffer, XFIXNUM (point_max));
+}
+
+/* Internal function for Fnarrow_to_region, meant to be used with a
+   third argument 'true', in which case it should be followed by "specbind
+   (Qrestrictions_locked, Qt)".  */
+Lisp_Object
+narrow_to_region_internal (Lisp_Object start, Lisp_Object end, bool lock)
 {
   EMACS_INT s = fix_position (start), e = fix_position (end);
 
@@ -2690,14 +2731,36 @@ remain visible.  */)
       EMACS_INT tem = s; s = e; e = tem;
     }
 
-  if (!(BEG <= s && s <= e && e <= Z))
-    args_out_of_range (start, end);
+  if (lock)
+    {
+      if (!(BEGV <= s && s <= e && e <= ZV))
+       args_out_of_range (start, end);
 
-  if (BEGV != s || ZV != e)
-    current_buffer->clip_changed = 1;
+      if (BEGV != s || ZV != e)
+       current_buffer->clip_changed = 1;
+
+      record_unwind_protect (restore_point_unwind, Fpoint_marker ());
+      record_unwind_protect (unwind_locked_begv, Fpoint_min ());
+      record_unwind_protect (unwind_locked_zv, Fpoint_max ());
+
+      SET_BUF_BEGV (current_buffer, s);
+      SET_BUF_ZV (current_buffer, e);
+    }
+  else
+    {
+      if (! NILP (Vrestrictions_locked))
+       return Qnil;
+
+      if (!(BEG <= s && s <= e && e <= Z))
+       args_out_of_range (start, end);
+
+      if (BEGV != s || ZV != e)
+       current_buffer->clip_changed = 1;
+
+      SET_BUF_BEGV (current_buffer, s);
+      SET_BUF_ZV (current_buffer, e);
+    }
 
-  SET_BUF_BEGV (current_buffer, s);
-  SET_BUF_ZV (current_buffer, e);
   if (PT < s)
     SET_PT (s);
   if (e < PT)
@@ -2707,6 +2770,27 @@ remain visible.  */)
   return Qnil;
 }
 
+DEFUN ("narrow-to-region", Fnarrow_to_region, Snarrow_to_region, 2, 2, "r",
+       doc: /* Restrict editing in this buffer to the current region.
+The rest of the text becomes temporarily invisible and untouchable
+but is not deleted; if you save the buffer in a file, the invisible
+text is included in the file.  \\[widen] makes all visible again.
+See also `save-restriction'.
+
+When calling from Lisp, pass two arguments START and END:
+positions (integers or markers) bounding the text that should
+remain visible.
+
+Note that, when the current buffer contains one or more lines whose
+length is above `long-line-threshold', Emacs may decide to leave, for
+performance reasons, the accessible portion of the buffer unchanged
+after this function is called from low-level hooks, such as
+`jit-lock-functions' or `post-command-hook'.  */)
+  (Lisp_Object start, Lisp_Object end)
+{
+  return narrow_to_region_internal (start, end, false);
+}
+
 Lisp_Object
 save_restriction_save (void)
 {
@@ -2843,7 +2927,7 @@ otherwise MSGID-PLURAL.  */)
   CHECK_INTEGER (n);
 
   /* Placeholder implementation until we get our act together.  */
-  return EQ (n, make_fixnum (1)) ? msgid : msgid_plural;
+  return BASE_EQ (n, make_fixnum (1)) ? msgid : msgid_plural;
 }
 
 DEFUN ("message", Fmessage, Smessage, 1, MANY, 0,
@@ -4517,6 +4601,15 @@ This variable is experimental; email 
32252@debbugs.gnu.org if you need
 it to be non-nil.  */);
   binary_as_unsigned = false;
 
+  DEFSYM (Qrestrictions_locked, "restrictions-locked");
+  DEFVAR_LISP ("restrictions-locked", Vrestrictions_locked,
+              doc: /* If non-nil, restrictions are currently locked.
+
+This happens when `narrow-to-region', which see, is called from Lisp
+with an optional argument LOCK non-nil.  */);
+  Vrestrictions_locked = Qnil;
+  Funintern (Qrestrictions_locked, Qnil);
+
   defsubr (&Spropertize);
   defsubr (&Schar_equal);
   defsubr (&Sgoto_char);
@@ -4549,6 +4642,8 @@ it to be non-nil.  */);
 
   defsubr (&Sline_beginning_position);
   defsubr (&Sline_end_position);
+  defsubr (&Spos_bol);
+  defsubr (&Spos_eol);
 
   defsubr (&Ssave_excursion);
   defsubr (&Ssave_current_buffer);
diff --git a/src/emacs.c b/src/emacs.c
index 189692a02e..8f19c48655 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -979,20 +979,24 @@ load_pdump (int argc, char **argv)
   sprintf (dump_file, "%s%c%s-%s%s",
            path_exec, DIRECTORY_SEP, argv0_base, hexbuf, suffix);
 #if !defined (NS_SELF_CONTAINED)
-  /* Assume the Emacs binary lives in a sibling directory as set up by
-     the default installation configuration.  */
-  const char *go_up = "../../../../bin/";
-  needed += (strip_suffix ? strlen (strip_suffix) : 0)
-    - strlen (suffix) + strlen (go_up);
-  if (exec_bufsize < needed)
+  if (!(emacs_executable && *emacs_executable))
     {
-      xfree (emacs_executable);
-      emacs_executable = xpalloc (NULL, &exec_bufsize, needed - exec_bufsize,
-                                 -1, 1);
+      /* If we didn't find the Emacs binary, assume that it lives in a
+        sibling directory as set up by the default installation
+        configuration.  */
+      const char *go_up = "../../../../bin/";
+      needed += (strip_suffix ? strlen (strip_suffix) : 0)
+       - strlen (suffix) + strlen (go_up);
+      if (exec_bufsize < needed)
+       {
+         xfree (emacs_executable);
+         emacs_executable = xpalloc (NULL, &exec_bufsize,
+                                     needed - exec_bufsize, -1, 1);
+       }
+      sprintf (emacs_executable, "%s%c%s%s%s",
+              path_exec, DIRECTORY_SEP, go_up, argv0_base,
+              strip_suffix ? strip_suffix : "");
     }
-  sprintf (emacs_executable, "%s%c%s%s%s",
-          path_exec, DIRECTORY_SEP, go_up, argv0_base,
-          strip_suffix ? strip_suffix : "");
 #endif
   result = pdumper_load (dump_file, emacs_executable);
 
@@ -1930,9 +1934,6 @@ Using an Emacs configured with --with-x-toolkit=lucid 
does not have this problem
   init_bignum ();
   init_threads ();
   init_eval ();
-#ifdef HAVE_PGTK
-  init_pgtkterm (); /* Must come before `init_atimer'.  */
-#endif
   running_asynch_code = 0;
   init_random ();
   init_xfaces ();
@@ -1944,6 +1945,11 @@ Using an Emacs configured with --with-x-toolkit=lucid 
does not have this problem
   if (!initialized)
     syms_of_comp ();
 
+  /* Do less garbage collection in batch mode (since these tend to be
+     more short-lived, and the memory is returned to the OS on exit
+     anyway).  */
+  Vgc_cons_percentage = make_float (noninteractive? 1.0: 0.1);
+
   no_loadup
     = argmatch (argv, argc, "-nl", "--no-loadup", 6, NULL, &skip_args);
 
@@ -2419,11 +2425,11 @@ Using an Emacs configured with --with-x-toolkit=lucid 
does not have this problem
 #if defined WINDOWSNT || defined HAVE_NTGUI
       globals_of_w32select ();
 #endif
+    }
 
 #ifdef HAVE_HAIKU
-      init_haiku_select ();
+  init_haiku_select ();
 #endif
-    }
 
   init_charset ();
 
diff --git a/src/eval.c b/src/eval.c
index 45ddbab2a2..6ea7a473f6 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -57,6 +57,12 @@ Lisp_Object Vrun_hooks;
 /* FIXME: We should probably get rid of this!  */
 Lisp_Object Vsignaling_function;
 
+/* The handler structure which will catch errors in Lisp hooks called
+   from redisplay.  We do not use it for this; we compare it with the
+   handler which is about to be used in signal_or_quit, and if it
+   matches, cause a backtrace to be generated.  */
+static struct handler *redisplay_deep_handler;
+
 /* These would ordinarily be static, but they need to be visible to GDB.  */
 bool backtrace_p (union specbinding *) EXTERNALLY_VISIBLE;
 Lisp_Object *backtrace_args (union specbinding *) EXTERNALLY_VISIBLE;
@@ -246,6 +252,7 @@ init_eval (void)
   lisp_eval_depth = 0;
   /* This is less than the initial value of num_nonmacro_input_events.  */
   when_entered_debugger = -1;
+  redisplay_deep_handler = NULL;
 }
 
 /* Ensure that *M is at least A + B if possible, or is its maximum
@@ -333,7 +340,8 @@ call_debugger (Lisp_Object arg)
   /* Interrupting redisplay and resuming it later is not safe under
      all circumstances.  So, when the debugger returns, abort the
      interrupted redisplay by going back to the top-level.  */
-  if (debug_while_redisplaying)
+  if (debug_while_redisplaying
+      && !EQ (Vdebugger, Qdebug_early))
     Ftop_level ();
 
   return unbind_to (count, val);
@@ -593,16 +601,19 @@ The return value is BASE-VARIABLE.  */)
 
   if (SYMBOL_CONSTANT_P (new_alias))
     /* Making it an alias effectively changes its value.  */
-    error ("Cannot make a constant an alias");
+    error ("Cannot make a constant an alias: %s",
+          SDATA (SYMBOL_NAME (new_alias)));
 
   sym = XSYMBOL (new_alias);
 
   switch (sym->u.s.redirect)
     {
     case SYMBOL_FORWARDED:
-      error ("Cannot make an internal variable an alias");
+      error ("Cannot make a built-in variable an alias: %s",
+            SDATA (SYMBOL_NAME (new_alias)));
     case SYMBOL_LOCALIZED:
-      error ("Don't know how to make a localized variable an alias");
+      error ("Don't know how to make a buffer-local variable an alias: %s",
+            SDATA (SYMBOL_NAME (new_alias)));
     case SYMBOL_PLAINVAL:
     case SYMBOL_VARALIAS:
       break;
@@ -633,7 +644,8 @@ The return value is BASE-VARIABLE.  */)
     for (p = specpdl_ptr; p > specpdl; )
       if ((--p)->kind >= SPECPDL_LET
          && (EQ (new_alias, specpdl_symbol (p))))
-       error ("Don't know how to make a let-bound variable an alias");
+       error ("Don't know how to make a let-bound variable an alias: %s",
+              SDATA (SYMBOL_NAME (new_alias)));
   }
 
   if (sym->u.s.trapped_write == SYMBOL_TRAPPED_WRITE)
@@ -1552,12 +1564,16 @@ internal_condition_case_n (Lisp_Object (*bfun) 
(ptrdiff_t, Lisp_Object *),
                                                ptrdiff_t nargs,
                                                Lisp_Object *args))
 {
+  struct handler *old_deep = redisplay_deep_handler;
   struct handler *c = push_handler (handlers, CONDITION_CASE);
+  if (redisplaying_p)
+    redisplay_deep_handler = c;
   if (sys_setjmp (c->jmp))
     {
       Lisp_Object val = handlerlist->val;
       clobbered_eassert (handlerlist == c);
       handlerlist = handlerlist->next;
+      redisplay_deep_handler = old_deep;
       return hfun (val, nargs, args);
     }
   else
@@ -1565,6 +1581,7 @@ internal_condition_case_n (Lisp_Object (*bfun) 
(ptrdiff_t, Lisp_Object *),
       Lisp_Object val = bfun (nargs, args);
       eassert (handlerlist == c);
       handlerlist = c->next;
+      redisplay_deep_handler = old_deep;
       return val;
     }
 }
@@ -1697,6 +1714,11 @@ quit (void)
   return signal_or_quit (Qquit, Qnil, true);
 }
 
+/* Has an error in redisplay giving rise to a backtrace occurred as
+   yet in the current command?  This gets reset in the command
+   loop.  */
+bool backtrace_yet = false;
+
 /* Signal an error, or quit.  ERROR_SYMBOL and DATA are as with Fsignal.
    If KEYBOARD_QUIT, this is a quit; ERROR_SYMBOL should be
    Qquit and DATA should be Qnil, and this function may return.
@@ -1812,6 +1834,40 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object 
data, bool keyboard_quit)
       unbind_to (count, Qnil);
     }
 
+  /* If an error is signalled during a Lisp hook in redisplay, write a
+     backtrace into the buffer *Redisplay-trace*.  */
+  if (!debugger_called && !NILP (error_symbol)
+      && backtrace_on_redisplay_error
+      && (NILP (clause) || h == redisplay_deep_handler)
+      && NILP (Vinhibit_debugger)
+      && !NILP (Ffboundp (Qdebug_early)))
+    {
+      max_ensure_room (&max_lisp_eval_depth, lisp_eval_depth, 100);
+      specpdl_ref count = SPECPDL_INDEX ();
+      ptrdiff_t counti = specpdl_ref_to_count (count);
+      AUTO_STRING (redisplay_trace, "*Redisplay_trace*");
+      Lisp_Object redisplay_trace_buffer;
+      AUTO_STRING (gap, "\n\n\n\n"); /* Separates things in *Redisplay-trace* 
*/
+      Lisp_Object delayed_warning;
+      max_ensure_room (&max_specpdl_size, counti, 200);
+      redisplay_trace_buffer = Fget_buffer_create (redisplay_trace, Qnil);
+      current_buffer = XBUFFER (redisplay_trace_buffer);
+      if (!backtrace_yet) /* Are we on the first backtrace of the command?  */
+       Ferase_buffer ();
+      else
+       Finsert (1, &gap);
+      backtrace_yet = true;
+      specbind (Qstandard_output, redisplay_trace_buffer);
+      specbind (Qdebugger, Qdebug_early);
+      call_debugger (list2 (Qerror, Fcons (error_symbol, data)));
+      unbind_to (count, Qnil);
+      delayed_warning = make_string
+       ("Error in a redisplay Lisp hook.  See buffer *Redisplay_trace*", 61);
+
+      Vdelayed_warnings_list = Fcons (list2 (Qerror, delayed_warning),
+                                     Vdelayed_warnings_list);
+    }
+
   if (!NILP (clause))
     {
       Lisp_Object unwind_data
@@ -2208,7 +2264,7 @@ this does nothing and returns nil.  */)
       && !AUTOLOADP (XSYMBOL (function)->u.s.function))
     return Qnil;
 
-  if (!NILP (Vpurify_flag) && EQ (docstring, make_fixnum (0)))
+  if (!NILP (Vpurify_flag) && BASE_EQ (docstring, make_fixnum (0)))
     /* `read1' in lread.c has found the docstring starting with "\
        and assumed the docstring will be provided by Snarf-documentation, so it
        passed us 0 instead.  But that leads to accidental sharing in purecopy's
@@ -2229,7 +2285,7 @@ un_autoload (Lisp_Object oldqueue)
   while (CONSP (queue))
     {
       Lisp_Object first = XCAR (queue);
-      if (CONSP (first) && EQ (XCAR (first), make_fixnum (0)))
+      if (CONSP (first) && BASE_EQ (XCAR (first), make_fixnum (0)))
        Vfeatures = XCDR (first);
       else
        Ffset (first, Fcar (Fcdr (Fget (first, Qfunction_history))));
@@ -2286,8 +2342,13 @@ it defines a macro.  */)
   /* This is to make sure that loadup.el gives a clear picture
      of what files are preloaded and when.  */
   if (will_dump_p () && !will_bootstrap_p ())
-    error ("Attempt to autoload %s while preparing to dump",
-          SDATA (SYMBOL_NAME (funname)));
+    {
+      /* Avoid landing here recursively while outputting the
+        backtrace from the error.  */
+      gflags.will_dump_ = false;
+      error ("Attempt to autoload %s while preparing to dump",
+            SDATA (SYMBOL_NAME (funname)));
+    }
 
   CHECK_SYMBOL (funname);
 
@@ -3464,7 +3525,7 @@ specbind (Lisp_Object symbol, Lisp_Object value)
        specpdl_ptr->let.where = Fcurrent_buffer ();
 
        eassert (sym->u.s.redirect != SYMBOL_LOCALIZED
-                || (EQ (SYMBOL_BLV (sym)->where, Fcurrent_buffer ())));
+                || (BASE_EQ (SYMBOL_BLV (sym)->where, Fcurrent_buffer ())));
 
        if (sym->u.s.redirect == SYMBOL_LOCALIZED)
          {
@@ -4282,6 +4343,11 @@ Does not apply if quit is handled by a `condition-case'. 
 */);
   DEFVAR_BOOL ("debug-on-next-call", debug_on_next_call,
               doc: /* Non-nil means enter debugger before next `eval', `apply' 
or `funcall'.  */);
 
+  DEFVAR_BOOL ("backtrace-on-redisplay-error", backtrace_on_redisplay_error,
+              doc: /* Non-nil means create a backtrace if a lisp error occurs 
in redisplay.
+The backtrace is written to buffer *Redisplay-trace*.  */);
+  backtrace_on_redisplay_error = false;
+
   DEFVAR_BOOL ("debugger-may-continue", debugger_may_continue,
               doc: /* Non-nil means debugger may continue execution.
 This is nil when the debugger is called under circumstances where it
diff --git a/src/fileio.c b/src/fileio.c
index e29685e07b..9697f6c8cf 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -708,7 +708,7 @@ This function does not grok magic file names.  */)
   memset (data + prefix_len, 'X', nX);
   memcpy (data + prefix_len + nX, SSDATA (encoded_suffix), suffix_len);
   int kind = (NILP (dir_flag) ? GT_FILE
-             : EQ (dir_flag, make_fixnum (0)) ? GT_NOCREATE
+             : BASE_EQ (dir_flag, make_fixnum (0)) ? GT_NOCREATE
              : GT_DIR);
   int fd = gen_tempname (data, suffix_len, O_BINARY | O_CLOEXEC, kind);
   bool failed = fd < 0;
@@ -2601,9 +2601,9 @@ is case-insensitive.  */)
       if (err <= 0)
        return err < 0 ? Qt : Qnil;
       Lisp_Object parent = file_name_directory (filename);
-      /* Avoid infinite loop if the root has trouble
-        (impossible?).  */
-      if (!NILP (Fstring_equal (parent, filename)))
+      /* Avoid infinite loop if the root has trouble (if that's even possible).
+        Without a parent, we just don't know and return nil as well.  */
+      if (!STRINGP (parent) || !NILP (Fstring_equal (parent, filename)))
        return Qnil;
       filename = parent;
     }
@@ -3532,8 +3532,9 @@ DEFUN ("set-file-modes", Fset_file_modes, 
Sset_file_modes, 2, 3,
 Only the 12 low bits of MODE are used.  If optional FLAG is `nofollow',
 do not follow FILENAME if it is a symbolic link.
 
-Interactively, mode bits are read by `read-file-modes', which accepts
-symbolic notation, like the `chmod' command from GNU Coreutils.  */)
+Interactively, prompt for FILENAME, and read MODE with
+`read-file-modes', which accepts symbolic notation, like the `chmod'
+command from GNU Coreutils.  */)
   (Lisp_Object filename, Lisp_Object mode, Lisp_Object flag)
 {
   CHECK_FIXNUM (mode);
@@ -5831,6 +5832,15 @@ See Info node `(elisp)Modification Time' for more 
details.  */)
   return Qnil;
 }
 
+Lisp_Object
+buffer_visited_file_modtime (struct buffer *buf)
+{
+  int ns = buf->modtime.tv_nsec;
+  if (ns < 0)
+    return make_fixnum (UNKNOWN_MODTIME_NSECS - ns);
+  return make_lisp_time (buf->modtime);
+}
+
 DEFUN ("visited-file-modtime", Fvisited_file_modtime,
        Svisited_file_modtime, 0, 0, 0,
        doc: /* Return the current buffer's recorded visited file modification 
time.
@@ -5840,10 +5850,7 @@ visited file doesn't exist.
 See Info node `(elisp)Modification Time' for more details.  */)
   (void)
 {
-  int ns = current_buffer->modtime.tv_nsec;
-  if (ns < 0)
-    return make_fixnum (UNKNOWN_MODTIME_NSECS - ns);
-  return make_lisp_time (current_buffer->modtime);
+  return buffer_visited_file_modtime (current_buffer);
 }
 
 DEFUN ("set-visited-file-modtime", Fset_visited_file_modtime,
@@ -5870,6 +5877,8 @@ in `current-time' or an integer flag as returned by 
`visited-file-modtime'.  */)
       current_buffer->modtime = mtime;
       current_buffer->modtime_size = -1;
     }
+  else if (current_buffer->base_buffer)
+    error ("An indirect buffer does not have a visited file");
   else
     {
       register Lisp_Object filename;
diff --git a/src/fns.c b/src/fns.c
index 6094c00b27..7e78bba3a0 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -589,20 +589,21 @@ Do NOT use this function to compare file names for 
equality.  */)
 #endif /* !__STDC_ISO_10646__, !WINDOWSNT */
 }
 
-static Lisp_Object concat (ptrdiff_t nargs, Lisp_Object *args,
-                          Lisp_Object last_tail, bool vector_target);
-static Lisp_Object concat_strings (ptrdiff_t nargs, Lisp_Object *args);
+static Lisp_Object concat_to_list (ptrdiff_t nargs, Lisp_Object *args,
+                                  Lisp_Object last_tail);
+static Lisp_Object concat_to_vector (ptrdiff_t nargs, Lisp_Object *args);
+static Lisp_Object concat_to_string (ptrdiff_t nargs, Lisp_Object *args);
 
 Lisp_Object
 concat2 (Lisp_Object s1, Lisp_Object s2)
 {
-  return concat_strings (2, ((Lisp_Object []) {s1, s2}));
+  return concat_to_string (2, ((Lisp_Object []) {s1, s2}));
 }
 
 Lisp_Object
 concat3 (Lisp_Object s1, Lisp_Object s2, Lisp_Object s3)
 {
-  return concat_strings (3, ((Lisp_Object []) {s1, s2, s3}));
+  return concat_to_string (3, ((Lisp_Object []) {s1, s2, s3}));
 }
 
 DEFUN ("append", Fappend, Sappend, 0, MANY, 0,
@@ -615,7 +616,7 @@ usage: (append &rest SEQUENCES)  */)
 {
   if (nargs == 0)
     return Qnil;
-  return concat (nargs - 1, args, args[nargs - 1], false);
+  return concat_to_list (nargs - 1, args, args[nargs - 1]);
 }
 
 DEFUN ("concat", Fconcat, Sconcat, 0, MANY, 0,
@@ -628,7 +629,7 @@ to be `eq'.
 usage: (concat &rest SEQUENCES)  */)
   (ptrdiff_t nargs, Lisp_Object *args)
 {
-  return concat_strings (nargs, args);
+  return concat_to_string (nargs, args);
 }
 
 DEFUN ("vconcat", Fvconcat, Svconcat, 0, MANY, 0,
@@ -638,7 +639,7 @@ Each argument may be a list, vector or string.
 usage: (vconcat &rest SEQUENCES)   */)
   (ptrdiff_t nargs, Lisp_Object *args)
 {
-  return concat (nargs, args, Qnil, true);
+  return concat_to_vector (nargs, args);
 }
 
 
@@ -706,17 +707,16 @@ the same empty object instead of its copy.  */)
   wrong_type_argument (Qsequencep, arg);
 }
 
-/* This structure holds information of an argument of `concat_strings' that is
-   a string and has text properties to be copied.  */
+/* This structure holds information of an argument of `concat_to_string'
+   that is a string and has text properties to be copied.  */
 struct textprop_rec
 {
   ptrdiff_t argnum;            /* refer to ARGS (arguments of `concat') */
-  ptrdiff_t from;              /* refer to ARGS[argnum] (argument string) */
   ptrdiff_t to;                        /* refer to VAL (the target string) */
 };
 
 static Lisp_Object
-concat_strings (ptrdiff_t nargs, Lisp_Object *args)
+concat_to_string (ptrdiff_t nargs, Lisp_Object *args)
 {
   USE_SAFE_ALLOCA;
 
@@ -842,7 +842,6 @@ concat_strings (ptrdiff_t nargs, Lisp_Object *args)
          if (string_intervals (arg))
            {
              textprops[num_textprops].argnum = i;
-             textprops[num_textprops].from = 0;
              textprops[num_textprops].to = toindex;
              num_textprops++;
            }
@@ -857,9 +856,8 @@ concat_strings (ptrdiff_t nargs, Lisp_Object *args)
          else
            {
              /* Copy a single-byte string to a multibyte string.  */
-             toindex_byte += copy_text (SDATA (arg),
-                                        SDATA (result) + toindex_byte,
-                                        nchars, 0, 1);
+             toindex_byte += str_to_multibyte (SDATA (result) + toindex_byte,
+                                               SDATA (arg), nchars);
            }
          toindex += nchars;
        }
@@ -912,19 +910,100 @@ concat_strings (ptrdiff_t nargs, Lisp_Object *args)
   return result;
 }
 
-/* Concatenate sequences into a list or vector. */
+/* Concatenate sequences into a list. */
+Lisp_Object
+concat_to_list (ptrdiff_t nargs, Lisp_Object *args, Lisp_Object last_tail)
+{
+  /* Copy the contents of the args into the result.  */
+  Lisp_Object result = Qnil;
+  Lisp_Object last = Qnil;     /* Last cons in result if nonempty.  */
+
+  for (ptrdiff_t i = 0; i < nargs; i++)
+    {
+      Lisp_Object arg = args[i];
+      /* List arguments are treated specially since this is the common case.  
*/
+      if (CONSP (arg))
+       {
+         Lisp_Object head = Fcons (XCAR (arg), Qnil);
+         Lisp_Object prev = head;
+         arg = XCDR (arg);
+         FOR_EACH_TAIL (arg)
+           {
+             Lisp_Object next = Fcons (XCAR (arg), Qnil);
+             XSETCDR (prev, next);
+             prev = next;
+           }
+         CHECK_LIST_END (arg, arg);
+         if (NILP (result))
+           result = head;
+         else
+           XSETCDR (last, head);
+         last = prev;
+       }
+      else if (NILP (arg))
+       ;
+      else if (VECTORP (arg) || STRINGP (arg)
+              || BOOL_VECTOR_P (arg) || COMPILEDP (arg))
+       {
+         ptrdiff_t arglen = XFIXNUM (Flength (arg));
+         ptrdiff_t argindex_byte = 0;
+
+         /* Copy element by element.  */
+         for (ptrdiff_t argindex = 0; argindex < arglen; argindex++)
+           {
+             /* Fetch next element of `arg' arg into `elt', or break if
+                `arg' is exhausted. */
+             Lisp_Object elt;
+             if (STRINGP (arg))
+               {
+                 int c;
+                 if (STRING_MULTIBYTE (arg))
+                   {
+                     ptrdiff_t char_idx = argindex;
+                     c = fetch_string_char_advance_no_check (arg, &char_idx,
+                                                             &argindex_byte);
+                   }
+                 else
+                   c = SREF (arg, argindex);
+                 elt = make_fixed_natnum (c);
+               }
+             else if (BOOL_VECTOR_P (arg))
+               elt = bool_vector_ref (arg, argindex);
+             else
+               elt = AREF (arg, argindex);
+
+             /* Store this element into the result.  */
+             Lisp_Object node = Fcons (elt, Qnil);
+             if (NILP (result))
+               result = node;
+             else
+               XSETCDR (last, node);
+             last = node;
+           }
+       }
+      else
+       wrong_type_argument (Qsequencep, arg);
+    }
+
+  if (NILP (result))
+    result = last_tail;
+  else
+    XSETCDR (last, last_tail);
 
+  return result;
+}
+
+/* Concatenate sequences into a vector.  */
 Lisp_Object
-concat (ptrdiff_t nargs, Lisp_Object *args, Lisp_Object last_tail,
-       bool vector_target)
+concat_to_vector (ptrdiff_t nargs, Lisp_Object *args)
 {
   /* Check argument types and compute total length of arguments.  */
   EMACS_INT result_len = 0;
   for (ptrdiff_t i = 0; i < nargs; i++)
     {
       Lisp_Object arg = args[i];
-      if (!(CONSP (arg) || NILP (arg) || VECTORP (arg) || STRINGP (arg)
-           || COMPILEDP (arg) || BOOL_VECTOR_P (arg)))
+      if (!(VECTORP (arg) || CONSP (arg) || NILP (arg) || STRINGP (arg)
+           || BOOL_VECTOR_P (arg) || COMPILEDP (arg)))
        wrong_type_argument (Qsequencep, arg);
       EMACS_INT len = XFIXNAT (Flength (arg));
       result_len += len;
@@ -932,90 +1011,61 @@ concat (ptrdiff_t nargs, Lisp_Object *args, Lisp_Object 
last_tail,
        memory_full (SIZE_MAX);
     }
 
-  /* When the target is a list, return the tail directly if all other
-     arguments are empty.  */
-  if (!vector_target && result_len == 0)
-    return last_tail;
-
-  /* Create the output object.  */
-  Lisp_Object result = vector_target
-    ? make_nil_vector (result_len)
-    : Fmake_list (make_fixnum (result_len), Qnil);
+  /* Create the output vector.  */
+  Lisp_Object result = make_uninit_vector (result_len);
+  Lisp_Object *dst = XVECTOR (result)->contents;
 
   /* Copy the contents of the args into the result.  */
-  Lisp_Object tail = Qnil;
-  ptrdiff_t toindex = 0;
-  if (CONSP (result))
-    {
-      tail = result;
-      toindex = -1;   /* -1 in toindex is flag we are making a list */
-    }
-
-  Lisp_Object prev = Qnil;
 
   for (ptrdiff_t i = 0; i < nargs; i++)
     {
-      ptrdiff_t arglen = 0;
-      ptrdiff_t argindex = 0;
-      ptrdiff_t argindex_byte = 0;
-
       Lisp_Object arg = args[i];
-      if (!CONSP (arg))
-       arglen = XFIXNUM (Flength (arg));
-
-      /* Copy element by element.  */
-      while (1)
+      if (VECTORP (arg))
        {
-         /* Fetch next element of `arg' arg into `elt', or break if
-            `arg' is exhausted. */
-         Lisp_Object elt;
-         if (CONSP (arg))
-           {
-             elt = XCAR (arg);
-             arg = XCDR (arg);
-           }
-         else if (NILP (arg) || argindex >= arglen)
-           break;
-         else if (STRINGP (arg))
+         ptrdiff_t size = ASIZE (arg);
+         memcpy (dst, XVECTOR (arg)->contents, size * sizeof *dst);
+         dst += size;
+       }
+      else if (CONSP (arg))
+       do
+         {
+           *dst++ = XCAR (arg);
+           arg = XCDR (arg);
+         }
+       while (!NILP (arg));
+      else if (NILP (arg))
+       ;
+      else if (STRINGP (arg))
+       {
+         ptrdiff_t size = SCHARS (arg);
+         if (STRING_MULTIBYTE (arg))
            {
-             int c;
-             if (STRING_MULTIBYTE (arg))
-               c = fetch_string_char_advance_no_check (arg, &argindex,
-                                                       &argindex_byte);
-             else
+             ptrdiff_t byte = 0;
+             for (ptrdiff_t i = 0; i < size;)
                {
-                 c = SREF (arg, argindex);
-                 argindex++;
+                 int c = fetch_string_char_advance_no_check (arg, &i, &byte);
+                 *dst++ = make_fixnum (c);
                }
-             XSETFASTINT (elt, c);
-           }
-         else if (BOOL_VECTOR_P (arg))
-           {
-             elt = bool_vector_ref (arg, argindex);
-             argindex++;
            }
          else
-           {
-             elt = AREF (arg, argindex);
-             argindex++;
-           }
-
-         /* Store this element into the result.  */
-         if (toindex < 0)
-           {
-             XSETCAR (tail, elt);
-             prev = tail;
-             tail = XCDR (tail);
-           }
-         else
-           {
-             ASET (result, toindex, elt);
-             toindex++;
-           }
+           for (ptrdiff_t i = 0; i < size; i++)
+             *dst++ = make_fixnum (SREF (arg, i));
+       }
+      else if (BOOL_VECTOR_P (arg))
+       {
+         ptrdiff_t size = bool_vector_size (arg);
+         for (ptrdiff_t i = 0; i < size; i++)
+           *dst++ = bool_vector_ref (arg, i);
+       }
+      else
+       {
+         eassert (COMPILEDP (arg));
+         ptrdiff_t size = PVSIZE (arg);
+         memcpy (dst, XVECTOR (arg)->contents, size * sizeof *dst);
+         dst += size;
        }
     }
-  if (!NILP (prev))
-    XSETCDR (prev, last_tail);
+  eassert (dst == XVECTOR (result)->contents + result_len);
 
   return result;
 }
@@ -1045,7 +1095,7 @@ string_char_to_byte (Lisp_Object string, ptrdiff_t 
char_index)
   if (best_above == best_above_byte)
     return char_index;
 
-  if (EQ (string, string_char_byte_cache_string))
+  if (BASE_EQ (string, string_char_byte_cache_string))
     {
       if (string_char_byte_cache_charpos < char_index)
        {
@@ -1105,7 +1155,7 @@ string_byte_to_char (Lisp_Object string, ptrdiff_t 
byte_index)
   if (best_above == best_above_byte)
     return byte_index;
 
-  if (EQ (string, string_char_byte_cache_string))
+  if (BASE_EQ (string, string_char_byte_cache_string))
     {
       if (string_char_byte_cache_bytepos < byte_index)
        {
@@ -1154,65 +1204,25 @@ string_byte_to_char (Lisp_Object string, ptrdiff_t 
byte_index)
   return i;
 }
 
-/* Convert STRING to a multibyte string.  */
-
-static Lisp_Object
-string_make_multibyte (Lisp_Object string)
-{
-  unsigned char *buf;
-  ptrdiff_t nbytes;
-  Lisp_Object ret;
-  USE_SAFE_ALLOCA;
-
-  if (STRING_MULTIBYTE (string))
-    return string;
-
-  nbytes = count_size_as_multibyte (SDATA (string),
-                                   SCHARS (string));
-  /* If all the chars are ASCII, they won't need any more bytes
-     once converted.  In that case, we can return STRING itself.  */
-  if (nbytes == SBYTES (string))
-    return string;
-
-  buf = SAFE_ALLOCA (nbytes);
-  copy_text (SDATA (string), buf, SBYTES (string),
-            0, 1);
-
-  ret = make_multibyte_string ((char *) buf, SCHARS (string), nbytes);
-  SAFE_FREE ();
-
-  return ret;
-}
-
-
 /* Convert STRING (if unibyte) to a multibyte string without changing
-   the number of characters.  Characters 0200 through 0237 are
-   converted to eight-bit characters. */
+   the number of characters.  Characters 0x80..0xff are interpreted as
+   raw bytes. */
 
 Lisp_Object
 string_to_multibyte (Lisp_Object string)
 {
-  unsigned char *buf;
-  ptrdiff_t nbytes;
-  Lisp_Object ret;
-  USE_SAFE_ALLOCA;
-
   if (STRING_MULTIBYTE (string))
     return string;
 
-  nbytes = count_size_as_multibyte (SDATA (string), SBYTES (string));
+  ptrdiff_t nchars = SCHARS (string);
+  ptrdiff_t nbytes = count_size_as_multibyte (SDATA (string), nchars);
   /* If all the chars are ASCII, they won't need any more bytes once
      converted.  */
-  if (nbytes == SBYTES (string))
+  if (nbytes == nchars)
     return make_multibyte_string (SSDATA (string), nbytes, nbytes);
 
-  buf = SAFE_ALLOCA (nbytes);
-  memcpy (buf, SDATA (string), SBYTES (string));
-  str_to_multibyte (buf, nbytes, SBYTES (string));
-
-  ret = make_multibyte_string ((char *) buf, SCHARS (string), nbytes);
-  SAFE_FREE ();
-
+  Lisp_Object ret = make_uninit_multibyte_string (nchars, nbytes);
+  str_to_multibyte (SDATA (ret), SDATA (string), nchars);
   return ret;
 }
 
@@ -1257,7 +1267,17 @@ string the same way whether it is unibyte or multibyte.) 
 */)
 {
   CHECK_STRING (string);
 
-  return string_make_multibyte (string);
+  if (STRING_MULTIBYTE (string))
+    return string;
+
+  ptrdiff_t nchars = SCHARS (string);
+  ptrdiff_t nbytes = count_size_as_multibyte (SDATA (string), nchars);
+  if (nbytes == nchars)
+    return string;
+
+  Lisp_Object ret = make_uninit_multibyte_string (nchars, nbytes);
+  str_to_multibyte (SDATA (ret), SDATA (string), nchars);
+  return ret;
 }
 
 DEFUN ("string-make-unibyte", Fstring_make_unibyte, Sstring_make_unibyte,
@@ -1362,19 +1382,24 @@ an error is signaled.  */)
   (Lisp_Object string)
 {
   CHECK_STRING (string);
+  if (!STRING_MULTIBYTE (string))
+    return string;
 
-  if (STRING_MULTIBYTE (string))
+  ptrdiff_t chars = SCHARS (string);
+  Lisp_Object ret = make_uninit_string (chars);
+  unsigned char *src = SDATA (string);
+  unsigned char *dst = SDATA (ret);
+  for (ptrdiff_t i = 0; i < chars; i++)
     {
-      ptrdiff_t chars = SCHARS (string);
-      unsigned char *str = xmalloc (chars);
-      ptrdiff_t converted = str_to_unibyte (SDATA (string), str, chars);
-
-      if (converted < chars)
-       error ("Can't convert the %"pD"dth character to unibyte", converted);
-      string = make_unibyte_string ((char *) str, chars);
-      xfree (str);
+      unsigned char b = *src++;
+      if (b <= 0x7f)
+       *dst++ = b;                                      /* ASCII */
+      else if (CHAR_BYTE8_HEAD_P (b))
+       *dst++ = 0x80 | (b & 1) << 6 | (*src++ & 0x3f);  /* raw byte */
+      else
+       error ("Cannot convert character at index %"pD"d to unibyte", i);
     }
-  return string;
+  return ret;
 }
 
 
@@ -1532,6 +1557,62 @@ substring_both (Lisp_Object string, ptrdiff_t from, 
ptrdiff_t from_byte,
   return res;
 }
 
+DEFUN ("take", Ftake, Stake, 2, 2, 0,
+       doc: /* Return the first N elements of LIST.
+If N is zero or negative, return nil.
+If N is greater or equal to the length of LIST, return LIST (or a copy).  */)
+  (Lisp_Object n, Lisp_Object list)
+{
+  CHECK_FIXNUM (n);
+  EMACS_INT m = XFIXNUM (n);
+  if (m <= 0)
+    return Qnil;
+  CHECK_LIST (list);
+  if (NILP (list))
+    return Qnil;
+  Lisp_Object ret = Fcons (XCAR (list), Qnil);
+  Lisp_Object prev = ret;
+  m--;
+  list = XCDR (list);
+  while (m > 0 && CONSP (list))
+    {
+      Lisp_Object p = Fcons (XCAR (list), Qnil);
+      XSETCDR (prev, p);
+      prev = p;
+      m--;
+      list = XCDR (list);
+    }
+  if (m > 0 && !NILP (list))
+    wrong_type_argument (Qlistp, list);
+  return ret;
+}
+
+DEFUN ("ntake", Fntake, Sntake, 2, 2, 0,
+       doc: /* Modify LIST to keep only the first N elements.
+If N is zero or negative, return nil.
+If N is greater or equal to the length of LIST, return LIST unmodified.
+Otherwise, return LIST after truncating it.  */)
+  (Lisp_Object n, Lisp_Object list)
+{
+  CHECK_FIXNUM (n);
+  EMACS_INT m = XFIXNUM (n);
+  if (m <= 0)
+    return Qnil;
+  CHECK_LIST (list);
+  Lisp_Object tail = list;
+  --m;
+  while (m > 0 && CONSP (tail))
+    {
+      tail = XCDR (tail);
+      m--;
+    }
+  if (CONSP (tail))
+    XSETCDR (tail, Qnil);
+  else if (!NILP (tail))
+    wrong_type_argument (Qlistp, list);
+  return list;
+}
+
 DEFUN ("nthcdr", Fnthcdr, Snthcdr, 2, 2, 0,
        doc: /* Take cdr N times on LIST, return the result.  */)
   (Lisp_Object n, Lisp_Object list)
@@ -1576,7 +1657,7 @@ DEFUN ("nthcdr", Fnthcdr, Snthcdr, 2, 2, 0,
     {
       /* If the tortoise just jumped (which is rare),
         update TORTOISE_NUM accordingly.  */
-      if (EQ (tail, li.tortoise))
+      if (BASE_EQ (tail, li.tortoise))
        tortoise_num = num;
 
       saved_tail = XCDR (tail);
@@ -2014,7 +2095,7 @@ This function may destructively modify SEQ to produce the 
value.  */)
          next = XCDR (tail);
          /* If SEQ contains a cycle, attempting to reverse it
             in-place will inevitably come back to SEQ.  */
-         if (EQ (next, seq))
+         if (BASE_EQ (next, seq))
            circular_list (seq);
          Fsetcdr (tail, prev);
          prev = tail;
@@ -2276,24 +2357,27 @@ merge_c (Lisp_Object org_l1, Lisp_Object org_l2, bool 
(*less) (Lisp_Object, Lisp
 
 /* This does not check for quits.  That is safe since it must terminate.  */
 
-DEFUN ("plist-get", Fplist_get, Splist_get, 2, 2, 0,
+DEFUN ("plist-get", Fplist_get, Splist_get, 2, 3, 0,
        doc: /* Extract a value from a property list.
 PLIST is a property list, which is a list of the form
 \(PROP1 VALUE1 PROP2 VALUE2...).
 
 This function returns the value corresponding to the given PROP, or
 nil if PROP is not one of the properties on the list.  The comparison
-with PROP is done using `eq'.
+with PROP is done using PREDICATE, which defaults to `eq'.
 
-This function never signals an error.  */)
-  (Lisp_Object plist, Lisp_Object prop)
+This function doesn't signal an error if PLIST is invalid.  */)
+  (Lisp_Object plist, Lisp_Object prop, Lisp_Object predicate)
 {
   Lisp_Object tail = plist;
+  if (NILP (predicate))
+    return plist_get (plist, prop);
+
   FOR_EACH_TAIL_SAFE (tail)
     {
       if (! CONSP (XCDR (tail)))
        break;
-      if (EQ (prop, XCAR (tail)))
+      if (!NILP (call2 (predicate, prop, XCAR (tail))))
        return XCAR (XCDR (tail));
       tail = XCDR (tail);
     }
@@ -2301,39 +2385,58 @@ This function never signals an error.  */)
   return Qnil;
 }
 
+/* Faster version of the above that works with EQ only */
+Lisp_Object
+plist_get (Lisp_Object plist, Lisp_Object prop)
+{
+  Lisp_Object tail = plist;
+  FOR_EACH_TAIL_SAFE (tail)
+    {
+      if (! CONSP (XCDR (tail)))
+       break;
+      if (EQ (prop, XCAR (tail)))
+       return XCAR (XCDR (tail));
+      tail = XCDR (tail);
+    }
+  return Qnil;
+}
+
 DEFUN ("get", Fget, Sget, 2, 2, 0,
        doc: /* Return the value of SYMBOL's PROPNAME property.
 This is the last value stored with `(put SYMBOL PROPNAME VALUE)'.  */)
   (Lisp_Object symbol, Lisp_Object propname)
 {
   CHECK_SYMBOL (symbol);
-  Lisp_Object propval = Fplist_get (CDR (Fassq (symbol, 
Voverriding_plist_environment)),
-                                    propname);
+  Lisp_Object propval = plist_get (CDR (Fassq (symbol,
+                                              Voverriding_plist_environment)),
+                                  propname);
   if (!NILP (propval))
     return propval;
-  return Fplist_get (XSYMBOL (symbol)->u.s.plist, propname);
+  return plist_get (XSYMBOL (symbol)->u.s.plist, propname);
 }
 
-DEFUN ("plist-put", Fplist_put, Splist_put, 3, 3, 0,
+DEFUN ("plist-put", Fplist_put, Splist_put, 3, 4, 0,
        doc: /* Change value in PLIST of PROP to VAL.
 PLIST is a property list, which is a list of the form
 \(PROP1 VALUE1 PROP2 VALUE2 ...).
 
-The comparison with PROP is done using `eq'.
+The comparison with PROP is done using PREDICATE, which defaults to `eq'.
 
 If PROP is already a property on the list, its value is set to VAL,
 otherwise the new PROP VAL pair is added.  The new plist is returned;
 use `(setq x (plist-put x prop val))' to be sure to use the new value.
 The PLIST is modified by side effects.  */)
-  (Lisp_Object plist, Lisp_Object prop, Lisp_Object val)
+  (Lisp_Object plist, Lisp_Object prop, Lisp_Object val, Lisp_Object predicate)
 {
   Lisp_Object prev = Qnil, tail = plist;
+  if (NILP (predicate))
+    return plist_put (plist, prop, val);
   FOR_EACH_TAIL (tail)
     {
       if (! CONSP (XCDR (tail)))
        break;
 
-      if (EQ (prop, XCAR (tail)))
+      if (!NILP (call2 (predicate, prop, XCAR (tail))))
        {
          Fsetcar (XCDR (tail), val);
          return plist;
@@ -2351,47 +2454,8 @@ The PLIST is modified by side effects.  */)
   return plist;
 }
 
-DEFUN ("put", Fput, Sput, 3, 3, 0,
-       doc: /* Store SYMBOL's PROPNAME property with value VALUE.
-It can be retrieved with `(get SYMBOL PROPNAME)'.  */)
-  (Lisp_Object symbol, Lisp_Object propname, Lisp_Object value)
-{
-  CHECK_SYMBOL (symbol);
-  set_symbol_plist
-    (symbol, Fplist_put (XSYMBOL (symbol)->u.s.plist, propname, value));
-  return value;
-}
-
-DEFUN ("lax-plist-get", Flax_plist_get, Slax_plist_get, 2, 2, 0,
-       doc: /* Extract a value from a property list, comparing with `equal'.
-This function is otherwise like `plist-get', but may signal an error
-if PLIST isn't a valid plist.  */)
-  (Lisp_Object plist, Lisp_Object prop)
-{
-  Lisp_Object tail = plist;
-  FOR_EACH_TAIL (tail)
-    {
-      if (! CONSP (XCDR (tail)))
-       break;
-      if (! NILP (Fequal (prop, XCAR (tail))))
-       return XCAR (XCDR (tail));
-      tail = XCDR (tail);
-    }
-
-  CHECK_TYPE (NILP (tail), Qplistp, plist);
-
-  return Qnil;
-}
-
-DEFUN ("lax-plist-put", Flax_plist_put, Slax_plist_put, 3, 3, 0,
-       doc: /* Change value in PLIST of PROP to VAL, comparing with `equal'.
-PLIST is a property list, which is a list of the form
-\(PROP1 VALUE1 PROP2 VALUE2 ...).  PROP and VAL are any objects.
-If PROP is already a property on the list, its value is set to VAL,
-otherwise the new PROP VAL pair is added.  The new plist is returned;
-use `(setq x (lax-plist-put x prop val))' to be sure to use the new value.
-The PLIST is modified by side effects.  */)
-  (Lisp_Object plist, Lisp_Object prop, Lisp_Object val)
+Lisp_Object
+plist_put (Lisp_Object plist, Lisp_Object prop, Lisp_Object val)
 {
   Lisp_Object prev = Qnil, tail = plist;
   FOR_EACH_TAIL (tail)
@@ -2399,7 +2463,7 @@ The PLIST is modified by side effects.  */)
       if (! CONSP (XCDR (tail)))
        break;
 
-      if (! NILP (Fequal (prop, XCAR (tail))))
+      if (EQ (prop, XCAR (tail)))
        {
          Fsetcar (XCDR (tail), val);
          return plist;
@@ -2409,12 +2473,24 @@ The PLIST is modified by side effects.  */)
       tail = XCDR (tail);
     }
   CHECK_TYPE (NILP (tail), Qplistp, plist);
-  Lisp_Object newcell = list2 (prop, val);
+  Lisp_Object newcell
+    = Fcons (prop, Fcons (val, NILP (prev) ? plist : XCDR (XCDR (prev))));
   if (NILP (prev))
     return newcell;
   Fsetcdr (XCDR (prev), newcell);
   return plist;
 }
+
+DEFUN ("put", Fput, Sput, 3, 3, 0,
+       doc: /* Store SYMBOL's PROPNAME property with value VALUE.
+It can be retrieved with `(get SYMBOL PROPNAME)'.  */)
+  (Lisp_Object symbol, Lisp_Object propname, Lisp_Object value)
+{
+  CHECK_SYMBOL (symbol);
+  set_symbol_plist
+    (symbol, plist_put (XSYMBOL (symbol)->u.s.plist, propname, value));
+  return value;
+}
 
 DEFUN ("eql", Feql, Seql, 2, 2, 0,
        doc: /* Return t if the two args are `eq' or are indistinguishable 
numbers.
@@ -2757,20 +2833,26 @@ usage: (nconc &rest LISTS)  */)
 static EMACS_INT
 mapcar1 (EMACS_INT leni, Lisp_Object *vals, Lisp_Object fn, Lisp_Object seq)
 {
-  if (VECTORP (seq) || COMPILEDP (seq))
+  if (NILP (seq))
+    return 0;
+  else if (CONSP (seq))
     {
+      Lisp_Object tail = seq;
       for (ptrdiff_t i = 0; i < leni; i++)
        {
-         Lisp_Object dummy = call1 (fn, AREF (seq, i));
+         if (! CONSP (tail))
+           return i;
+         Lisp_Object dummy = call1 (fn, XCAR (tail));
          if (vals)
            vals[i] = dummy;
+         tail = XCDR (tail);
        }
     }
-  else if (BOOL_VECTOR_P (seq))
+  else if (VECTORP (seq) || COMPILEDP (seq))
     {
-      for (EMACS_INT i = 0; i < leni; i++)
+      for (ptrdiff_t i = 0; i < leni; i++)
        {
-         Lisp_Object dummy = call1 (fn, bool_vector_ref (seq, i));
+         Lisp_Object dummy = call1 (fn, AREF (seq, i));
          if (vals)
            vals[i] = dummy;
        }
@@ -2788,17 +2870,14 @@ mapcar1 (EMACS_INT leni, Lisp_Object *vals, Lisp_Object 
fn, Lisp_Object seq)
            vals[i_before] = dummy;
        }
     }
-  else   /* Must be a list, since Flength did not get an error */
+  else
     {
-      Lisp_Object tail = seq;
-      for (ptrdiff_t i = 0; i < leni; i++)
+      eassert (BOOL_VECTOR_P (seq));
+      for (EMACS_INT i = 0; i < leni; i++)
        {
-         if (! CONSP (tail))
-           return i;
-         Lisp_Object dummy = call1 (fn, XCAR (tail));
+         Lisp_Object dummy = call1 (fn, bool_vector_ref (seq, i));
          if (vals)
            vals[i] = dummy;
-         tail = XCDR (tail);
        }
     }
 
@@ -2831,12 +2910,18 @@ FUNCTION must be a function of one argument, and must 
return a value
   SAFE_ALLOCA_LISP (args, args_alloc);
   ptrdiff_t nmapped = mapcar1 (leni, args, function, sequence);
   ptrdiff_t nargs = 2 * nmapped - 1;
+  eassert (nmapped == leni);
 
-  for (ptrdiff_t i = nmapped - 1; i > 0; i--)
-    args[i + i] = args[i];
+  if (NILP (separator) || (STRINGP (separator) && SCHARS (separator) == 0))
+    nargs = nmapped;
+  else
+    {
+      for (ptrdiff_t i = nmapped - 1; i > 0; i--)
+        args[i + i] = args[i];
 
-  for (ptrdiff_t i = 1; i < nargs; i += 2)
-    args[i] = separator;
+      for (ptrdiff_t i = 1; i < nargs; i += 2)
+        args[i] = separator;
+    }
 
   Lisp_Object ret = Fconcat (nargs, args);
   SAFE_FREE ();
@@ -2946,6 +3031,9 @@ if `last-nonmenu-event' is nil, and `use-dialog-box' is 
non-nil.  */)
 
   specpdl_ref count = SPECPDL_INDEX ();
   specbind (Qenable_recursive_minibuffers, Qt);
+  /* Preserve the actual command that eventually called `yes-or-no-p'
+     (otherwise `repeat' will be repeating `exit-minibuffer').  */
+  specbind (Qreal_this_command, Vreal_this_command);
 
   while (1)
     {
@@ -3069,7 +3157,7 @@ dynamic module files, in that order; but the function 
will not try to
 load the file without any suffix.  See `get-load-suffixes' for the
 complete list of suffixes.
 
-To find the file, this function searches that directories in `load-path'.
+To find the file, this function searches the directories in `load-path'.
 
 If the optional third argument NOERROR is non-nil, then, if
 the file is not found, the function returns nil instead of signaling
@@ -3112,8 +3200,13 @@ FILENAME are suppressed.  */)
       /* This is to make sure that loadup.el gives a clear picture
         of what files are preloaded and when.  */
       if (will_dump_p () && !will_bootstrap_p ())
-       error ("(require %s) while preparing to dump",
-              SDATA (SYMBOL_NAME (feature)));
+       {
+         /* Avoid landing here recursively while outputting the
+            backtrace from the error.  */
+         gflags.will_dump_ = false;
+         error ("(require %s) while preparing to dump",
+                SDATA (SYMBOL_NAME (feature)));
+       }
 
       /* A certain amount of recursive `require' is legitimate,
         but if we require the same feature recursively 3 times,
@@ -3169,22 +3262,25 @@ FILENAME are suppressed.  */)
    bottleneck of Widget operation.  Here is their translation to C,
    for the sole reason of efficiency.  */
 
-DEFUN ("plist-member", Fplist_member, Splist_member, 2, 2, 0,
+DEFUN ("plist-member", Fplist_member, Splist_member, 2, 3, 0,
        doc: /* Return non-nil if PLIST has the property PROP.
 PLIST is a property list, which is a list of the form
 \(PROP1 VALUE1 PROP2 VALUE2 ...).
 
-The comparison with PROP is done using `eq'.
+The comparison with PROP is done using PREDICATE, which defaults to
+`eq'.
 
 Unlike `plist-get', this allows you to distinguish between a missing
 property and a property with the value nil.
 The value is actually the tail of PLIST whose car is PROP.  */)
-  (Lisp_Object plist, Lisp_Object prop)
+  (Lisp_Object plist, Lisp_Object prop, Lisp_Object predicate)
 {
   Lisp_Object tail = plist;
+  if (NILP (predicate))
+    predicate = Qeq;
   FOR_EACH_TAIL (tail)
     {
-      if (EQ (XCAR (tail), prop))
+      if (!NILP (call2 (predicate, XCAR (tail), prop)))
        return tail;
       tail = XCDR (tail);
       if (! CONSP (tail))
@@ -3194,13 +3290,22 @@ The value is actually the tail of PLIST whose car is 
PROP.  */)
   return Qnil;
 }
 
+/* plist_member isn't used much in the Emacs sources, so just provide
+   a shim so that the function name follows the same pattern as
+   plist_get/plist_put.  */
+Lisp_Object
+plist_member (Lisp_Object plist, Lisp_Object prop)
+{
+  return Fplist_member (plist, prop, Qnil);
+}
+
 DEFUN ("widget-put", Fwidget_put, Swidget_put, 3, 3, 0,
        doc: /* In WIDGET, set PROPERTY to VALUE.
 The value can later be retrieved with `widget-get'.  */)
   (Lisp_Object widget, Lisp_Object property, Lisp_Object value)
 {
   CHECK_CONS (widget);
-  XSETCDR (widget, Fplist_put (XCDR (widget), property, value));
+  XSETCDR (widget, plist_put (XCDR (widget), property, value));
   return value;
 }
 
@@ -3217,7 +3322,7 @@ later with `widget-put'.  */)
       if (NILP (widget))
        return Qnil;
       CHECK_CONS (widget);
-      tmp = Fplist_member (XCDR (widget), property);
+      tmp = plist_member (XCDR (widget), property);
       if (CONSP (tmp))
        {
          tmp = XCDR (tmp);
@@ -4902,7 +5007,8 @@ Hash codes are not guaranteed to be preserved across 
Emacs sessions.  */)
 
 DEFUN ("sxhash-eql", Fsxhash_eql, Ssxhash_eql, 1, 1, 0,
        doc: /* Return an integer hash code for OBJ suitable for `eql'.
-If (eql A B), then (= (sxhash-eql A) (sxhash-eql B)).
+If (eql A B), then (= (sxhash-eql A) (sxhash-eql B)), but the opposite
+isn't necessarily true.
 
 Hash codes are not guaranteed to be preserved across Emacs sessions.  */)
   (Lisp_Object obj)
@@ -4912,7 +5018,8 @@ Hash codes are not guaranteed to be preserved across 
Emacs sessions.  */)
 
 DEFUN ("sxhash-equal", Fsxhash_equal, Ssxhash_equal, 1, 1, 0,
        doc: /* Return an integer hash code for OBJ suitable for `equal'.
-If (equal A B), then (= (sxhash-equal A) (sxhash-equal B)).
+If (equal A B), then (= (sxhash-equal A) (sxhash-equal B)), but the
+opposite isn't necessarily true.
 
 Hash codes are not guaranteed to be preserved across Emacs sessions.  */)
   (Lisp_Object obj)
@@ -6031,6 +6138,8 @@ The same variable also affects the function 
`read-answer'.  */);
   defsubr (&Scopy_alist);
   defsubr (&Ssubstring);
   defsubr (&Ssubstring_no_properties);
+  defsubr (&Stake);
+  defsubr (&Sntake);
   defsubr (&Snthcdr);
   defsubr (&Snth);
   defsubr (&Selt);
@@ -6050,8 +6159,6 @@ The same variable also affects the function 
`read-answer'.  */);
   defsubr (&Sget);
   defsubr (&Splist_put);
   defsubr (&Sput);
-  defsubr (&Slax_plist_get);
-  defsubr (&Slax_plist_put);
   defsubr (&Seql);
   defsubr (&Sequal);
   defsubr (&Sequal_including_properties);
@@ -6083,4 +6190,6 @@ The same variable also affects the function 
`read-answer'.  */);
   defsubr (&Sbuffer_hash);
   defsubr (&Slocale_info);
   defsubr (&Sbuffer_line_statistics);
+
+  DEFSYM (Qreal_this_command, "real-this-command");
 }
diff --git a/src/font.c b/src/font.c
index 702536c1ca..8acedb9bf8 100644
--- a/src/font.c
+++ b/src/font.c
@@ -3589,8 +3589,8 @@ font_open_by_name (struct frame *f, Lisp_Object name)
 
    The second is with frame F NULL.  In this case, DRIVER is globally
    registered in the variable `font_driver_list'.  All font-driver
-   implementations must call this function in its syms_of_XXXX
-   (e.g. syms_of_xfont).  */
+   implementations must call this function in its
+   syms_of_XXXX_for_pdumper (e.g. syms_of_xfont_for_pdumper).  */
 
 void
 register_font_driver (struct font_driver const *driver, struct frame *f)
@@ -4691,8 +4691,7 @@ Each element of the value is a cons (VARIATION-SELECTOR . 
GLYPH-ID),
 where
   VARIATION-SELECTOR is a character code of variation selector
     (#xFE00..#xFE0F or #xE0100..#xE01EF).
-  GLYPH-ID is a glyph code of the corresponding variation glyph,
-a fixnum, if it's small enough, otherwise a bignum.  */)
+  GLYPH-ID is a glyph code of the corresponding variation glyph, an integer.  
*/)
   (Lisp_Object font_object, Lisp_Object character)
 {
   unsigned variations[256];
@@ -4729,8 +4728,7 @@ a fixnum, if it's small enough, otherwise a bignum.  */)
    that apply to POSITION.  POSITION may be nil, in which case,
    FONT-SPEC is the font for displaying the character CH with the
    default face.  GLYPH-CODE is the glyph code in the font to use for
-   the character, it is a fixnum, if it is small enough, otherwise a
-   bignum.
+   the character, as an integer.
 
    For a text terminal, return a nonnegative integer glyph code for
    the character, or a negative integer if the character is not
diff --git a/src/frame.c b/src/frame.c
index c21461d49f..25d71e0769 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -1444,10 +1444,6 @@ affects all frames on the same terminal device.  */)
    If FRAME is a switch-frame event `(switch-frame FRAME1)', use
    FRAME1 as frame.
 
-   If TRACK is non-zero and the frame that currently has the focus
-   redirects its focus to the selected frame, redirect that focused
-   frame's focus to FRAME instead.
-
    FOR_DELETION non-zero means that the selected frame is being
    deleted, which includes the possibility that the frame's terminal
    is dead.
@@ -1455,7 +1451,7 @@ affects all frames on the same terminal device.  */)
    The value of NORECORD is passed as argument to Fselect_window.  */
 
 Lisp_Object
-do_switch_frame (Lisp_Object frame, int track, int for_deletion, Lisp_Object 
norecord)
+do_switch_frame (Lisp_Object frame, int for_deletion, Lisp_Object norecord)
 {
   struct frame *sf = SELECTED_FRAME (), *f;
 
@@ -1477,59 +1473,6 @@ do_switch_frame (Lisp_Object frame, int track, int 
for_deletion, Lisp_Object nor
   else if (f == sf)
     return frame;
 
-  /* If a frame's focus has been redirected toward the currently
-     selected frame, we should change the redirection to point to the
-     newly selected frame.  This means that if the focus is redirected
-     from a minibufferless frame to a surrogate minibuffer frame, we
-     can use `other-window' to switch between all the frames using
-     that minibuffer frame, and the focus redirection will follow us
-     around.  */
-#if 0
-  /* This is too greedy; it causes inappropriate focus redirection
-     that's hard to get rid of.  */
-  if (track)
-    {
-      Lisp_Object tail;
-
-      for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
-       {
-         Lisp_Object focus;
-
-         if (!FRAMEP (XCAR (tail)))
-           emacs_abort ();
-
-         focus = FRAME_FOCUS_FRAME (XFRAME (XCAR (tail)));
-
-         if (FRAMEP (focus) && XFRAME (focus) == SELECTED_FRAME ())
-           Fredirect_frame_focus (XCAR (tail), frame);
-       }
-    }
-#else /* ! 0 */
-  /* Instead, apply it only to the frame we're pointing to.  */
-#ifdef HAVE_WINDOW_SYSTEM
-  if (track && FRAME_WINDOW_P (f) && FRAME_TERMINAL (f)->get_focus_frame)
-    {
-      Lisp_Object focus, gfocus;
-
-      gfocus = FRAME_TERMINAL (f)->get_focus_frame (f);
-      if (FRAMEP (gfocus))
-       {
-         focus = FRAME_FOCUS_FRAME (XFRAME (gfocus));
-         if (FRAMEP (focus) && XFRAME (focus) == SELECTED_FRAME ())
-             /* Redirect frame focus also when FRAME has its minibuffer
-                window on the selected frame (see Bug#24500).
-
-                Don't do that: It causes redirection problem with a
-                separate minibuffer frame (Bug#24803) and problems
-                when updating the cursor on such frames.
-             || (NILP (focus)
-                 && EQ (FRAME_MINIBUF_WINDOW (f), sf->selected_window)))  */
-           Fredirect_frame_focus (gfocus, frame);
-       }
-    }
-#endif /* HAVE_X_WINDOWS */
-#endif /* ! 0 */
-
   if (!for_deletion && FRAME_HAS_MINIBUF_P (sf))
     resize_mini_window (XWINDOW (FRAME_MINIBUF_WINDOW (sf)), 1);
 
@@ -1627,7 +1570,7 @@ This function returns FRAME, or nil if FRAME has been 
deleted.  */)
     /* Do not select a tooltip frame (Bug#47207).  */
     error ("Cannot select a tooltip frame");
   else
-    return do_switch_frame (frame, 1, 0, norecord);
+    return do_switch_frame (frame, 0, norecord);
 }
 
 DEFUN ("handle-switch-frame", Fhandle_switch_frame,
@@ -1643,7 +1586,7 @@ necessarily represent user-visible input focus.  */)
   kset_prefix_arg (current_kboard, Vcurrent_prefix_arg);
   run_hook (Qmouse_leave_buffer_hook);
 
-  return do_switch_frame (event, 0, 0, Qnil);
+  return do_switch_frame (event, 0, Qnil);
 }
 
 DEFUN ("selected-frame", Fselected_frame, Sselected_frame, 0, 0, 0,
@@ -1990,6 +1933,9 @@ delete_frame (Lisp_Object frame, Lisp_Object force)
   int is_tooltip_frame;
   bool nochild = !FRAME_PARENT_FRAME (f);
   Lisp_Object minibuffer_child_frame = Qnil;
+#ifdef HAVE_X_WINDOWS
+  specpdl_ref ref;
+#endif
 
   if (!FRAME_LIVE_P (f))
     return Qnil;
@@ -2158,7 +2104,7 @@ delete_frame (Lisp_Object frame, Lisp_Object force)
        Fraise_frame (frame1);
 #endif
 
-      do_switch_frame (frame1, 0, 1, Qnil);
+      do_switch_frame (frame1, 1, Qnil);
       sf = SELECTED_FRAME ();
     }
   else
@@ -2173,7 +2119,29 @@ delete_frame (Lisp_Object frame, Lisp_Object force)
   /* Clear any X selections for this frame.  */
 #ifdef HAVE_X_WINDOWS
   if (FRAME_X_P (f))
-    x_clear_frame_selections (f);
+    {
+      /* Don't preserve selections when a display is going away, since
+        that sends stuff down the wire.  */
+
+      ref = SPECPDL_INDEX ();
+
+      if (EQ (force, Qnoelisp))
+       specbind (Qx_auto_preserve_selections, Qnil);
+
+      x_clear_frame_selections (f);
+      unbind_to (ref, Qnil);
+    }
+#endif
+
+#ifdef HAVE_PGTK
+  if (FRAME_PGTK_P (f))
+    {
+      /* Do special selection events now, in case the window gets
+        destroyed by this deletion.  Does this run Lisp code?  */
+      swallow_events (false);
+
+      pgtk_clear_frame_selections (f);
+    }
 #endif
 
   /* Free glyphs.
@@ -3948,9 +3916,10 @@ static const struct frame_parm_table frame_parms[] =
   {"z-group",                  SYMBOL_INDEX (Qz_group)},
   {"override-redirect",                SYMBOL_INDEX (Qoverride_redirect)},
   {"no-special-glyphs",                SYMBOL_INDEX (Qno_special_glyphs)},
-  {"alpha-background",          SYMBOL_INDEX (Qalpha_background)},
+  {"alpha-background",         SYMBOL_INDEX (Qalpha_background)},
+  {"use-frame-synchronization",        SYMBOL_INDEX 
(Quse_frame_synchronization)},
 #ifdef HAVE_X_WINDOWS
-  {"shaded",                   SYMBOL_INDEX (Qshaded)},
+  {"shaded",                   SYMBOL_INDEX (Qshaded)},
 #endif
 #ifdef NS_IMPL_COCOA
   {"ns-appearance",            SYMBOL_INDEX (Qns_appearance)},
@@ -5119,7 +5088,9 @@ gui_set_no_special_glyphs (struct frame *f, Lisp_Object 
new_value, Lisp_Object o
 bool
 gui_mouse_grabbed (Display_Info *dpyinfo)
 {
-  return (dpyinfo->grabbed
+  return ((dpyinfo->grabbed
+          || (dpyinfo->terminal->any_grab_hook
+              && dpyinfo->terminal->any_grab_hook (dpyinfo)))
          && dpyinfo->last_mouse_frame
          && FRAME_LIVE_P (dpyinfo->last_mouse_frame));
 }
@@ -6225,6 +6196,7 @@ syms_of_frame (void)
   DEFSYM (Qtop_only, "top-only");
   DEFSYM (Qiconify_top_level, "iconify-top-level");
   DEFSYM (Qmake_invisible, "make-invisible");
+  DEFSYM (Quse_frame_synchronization, "use-frame-synchronization");
 
   {
     int i;
diff --git a/src/fringe.c b/src/fringe.c
index bf0b5fde76..5d7c8dca99 100644
--- a/src/fringe.c
+++ b/src/fringe.c
@@ -209,6 +209,20 @@ static unsigned short left_curly_arrow_bits[] = {
 static unsigned short right_curly_arrow_bits[] = {
    0x3c, 0x3e, 0x03, 0x27, 0x3f, 0x3e, 0x3c, 0x3e};
 
+/* Large circle bitmap.  */
+/*
+  ........
+  ..xxxx..
+  .xxxxxx.
+  xxxxxxxx
+  xxxxxxxx
+  .xxxxxx.
+  ..xxxx..
+  ........
+*/
+static unsigned short large_circle_bits[] = {
+  0x3c, 0x7e, 0xff, 0xff, 0xff, 0xff, 0x7e, 0x3c};
+
 /* Reverse Overlay arrow bitmap.  A triangular arrow.  */
 /*
   ......xx
@@ -454,6 +468,7 @@ static struct fringe_bitmap standard_bitmaps[] =
   { FRBITS (down_arrow_bits),         8, 0, ALIGN_BITMAP_BOTTOM, 0 },
   { FRBITS (left_curly_arrow_bits),   8, 0, ALIGN_BITMAP_CENTER, 0 },
   { FRBITS (right_curly_arrow_bits),  8, 0, ALIGN_BITMAP_CENTER, 0 },
+  { FRBITS (large_circle_bits),       8, 0, ALIGN_BITMAP_CENTER, 0 },
   { FRBITS (left_triangle_bits),      8, 0, ALIGN_BITMAP_CENTER, 0 },
   { FRBITS (right_triangle_bits),     8, 0, ALIGN_BITMAP_CENTER, 0 },
   { FRBITS (top_left_angle_bits),     8, 0, ALIGN_BITMAP_TOP,    0 },
diff --git a/src/ftcrfont.c b/src/ftcrfont.c
index 6bb41110d5..e089f9dea8 100644
--- a/src/ftcrfont.c
+++ b/src/ftcrfont.c
@@ -567,7 +567,7 @@ ftcrfont_draw (struct glyph_string *s,
       unblock_input ();
       return 0;
     }
-  BView_cr_dump_clipping (FRAME_HAIKU_VIEW (f), cr);
+  BView_cr_dump_clipping (FRAME_HAIKU_DRAWABLE (f), cr);
 #endif
 
   if (with_background)
@@ -677,7 +677,11 @@ ftcrhbfont_begin_hb_font (struct font *font, double 
*position_unit)
 
   ftcrfont_info->ft_size = ft_face->size;
   hb_font_t *hb_font = fthbfont_begin_hb_font (font, position_unit);
-  if (ftcrfont_info->bitmap_position_unit)
+  /* HarfBuzz 5 correctly scales bitmap-only fonts without position
+     unit adjustment.
+     (https://github.com/harfbuzz/harfbuzz/issues/489) */
+  if (!hb_version_atleast (5, 0, 0)
+      && ftcrfont_info->bitmap_position_unit)
     *position_unit = ftcrfont_info->bitmap_position_unit;
 
   return hb_font;
diff --git a/src/gnutls.c b/src/gnutls.c
index 0e1e63e157..a0de0238c4 100644
--- a/src/gnutls.c
+++ b/src/gnutls.c
@@ -1635,10 +1635,10 @@ gnutls_verify_boot (Lisp_Object proc, Lisp_Object 
proplist)
   char *c_hostname;
 
   if (NILP (proplist))
-    proplist = Fcdr (Fplist_get (p->childp, QCtls_parameters));
+    proplist = Fcdr (plist_get (p->childp, QCtls_parameters));
 
-  verify_error = Fplist_get (proplist, QCverify_error);
-  hostname = Fplist_get (proplist, QChostname);
+  verify_error = plist_get (proplist, QCverify_error);
+  hostname = plist_get (proplist, QChostname);
 
   if (EQ (verify_error, Qt))
     verify_error_all = true;
@@ -1668,7 +1668,7 @@ gnutls_verify_boot (Lisp_Object proc, Lisp_Object 
proplist)
 
   p->gnutls_peer_verification = peer_verification;
 
-  warnings = Fplist_get (Fgnutls_peer_status (proc), intern (":warnings"));
+  warnings = plist_get (Fgnutls_peer_status (proc), intern (":warnings"));
   if (!NILP (warnings))
     {
       for (Lisp_Object tail = warnings; CONSP (tail); tail = XCDR (tail))
@@ -1870,13 +1870,13 @@ one trustfile (usually a CA bundle).  */)
       return Qnil;
     }
 
-  hostname              = Fplist_get (proplist, QChostname);
-  priority_string       = Fplist_get (proplist, QCpriority);
-  trustfiles            = Fplist_get (proplist, QCtrustfiles);
-  keylist               = Fplist_get (proplist, QCkeylist);
-  crlfiles              = Fplist_get (proplist, QCcrlfiles);
-  loglevel              = Fplist_get (proplist, QCloglevel);
-  prime_bits            = Fplist_get (proplist, QCmin_prime_bits);
+  hostname              = plist_get (proplist, QChostname);
+  priority_string       = plist_get (proplist, QCpriority);
+  trustfiles            = plist_get (proplist, QCtrustfiles);
+  keylist               = plist_get (proplist, QCkeylist);
+  crlfiles              = plist_get (proplist, QCcrlfiles);
+  loglevel              = plist_get (proplist, QCloglevel);
+  prime_bits            = plist_get (proplist, QCmin_prime_bits);
 
   if (!STRINGP (hostname))
     {
@@ -1929,7 +1929,7 @@ one trustfile (usually a CA bundle).  */)
       check_memory_full (gnutls_certificate_allocate_credentials (&x509_cred));
       XPROCESS (proc)->gnutls_x509_cred = x509_cred;
 
-      verify_flags = Fplist_get (proplist, QCverify_flags);
+      verify_flags = plist_get (proplist, QCverify_flags);
       if (TYPE_RANGED_FIXNUMP (unsigned int, verify_flags))
        {
          gnutls_verify_flags = XFIXNAT (verify_flags);
@@ -2109,7 +2109,7 @@ one trustfile (usually a CA bundle).  */)
     }
 
   XPROCESS (proc)->gnutls_complete_negotiation_p =
-    !NILP (Fplist_get (proplist, QCcomplete_negotiation));
+    !NILP (plist_get (proplist, QCcomplete_negotiation));
   GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_CRED_SET;
   ret = emacs_gnutls_handshake (XPROCESS (proc));
   if (ret < GNUTLS_E_SUCCESS)
@@ -2348,7 +2348,7 @@ gnutls_symmetric (bool encrypting, Lisp_Object cipher,
 
   if (!NILP (info) && CONSP (info))
     {
-      Lisp_Object v = Fplist_get (info, QCcipher_id);
+      Lisp_Object v = plist_get (info, QCcipher_id);
       if (TYPE_RANGED_FIXNUMP (gnutls_cipher_algorithm_t, v))
         gca = XFIXNUM (v);
     }
@@ -2625,7 +2625,7 @@ itself. */)
 
   if (!NILP (info) && CONSP (info))
     {
-      Lisp_Object v = Fplist_get (info, QCmac_algorithm_id);
+      Lisp_Object v = plist_get (info, QCmac_algorithm_id);
       if (TYPE_RANGED_FIXNUMP (gnutls_mac_algorithm_t, v))
         gma = XFIXNUM (v);
     }
@@ -2715,7 +2715,7 @@ the number itself. */)
 
   if (!NILP (info) && CONSP (info))
     {
-      Lisp_Object v = Fplist_get (info, QCdigest_algorithm_id);
+      Lisp_Object v = plist_get (info, QCdigest_algorithm_id);
       if (TYPE_RANGED_FIXNUMP (gnutls_digest_algorithm_t, v))
         gda = XFIXNUM (v);
     }
diff --git a/src/gtkutil.c b/src/gtkutil.c
index f2018bc01f..a6bba096a4 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -1887,7 +1887,9 @@ xg_free_frame_widgets (struct frame *f)
 
       /* x_free_frame_resources should have taken care of it */
 #ifndef HAVE_PGTK
+#ifdef HAVE_XDBE
       eassert (!FRAME_X_DOUBLE_BUFFERED_P (f));
+#endif
       g_object_unref (FRAME_X_OUTPUT (f)->im_context);
 #endif
       gtk_widget_destroy (FRAME_GTK_OUTER_WIDGET (f));
diff --git a/src/haiku_draw_support.cc b/src/haiku_draw_support.cc
index f0cc084bb3..8e911dd184 100644
--- a/src/haiku_draw_support.cc
+++ b/src/haiku_draw_support.cc
@@ -280,14 +280,19 @@ hsl_color_rgb (double h, double s, double l, uint32_t 
*rgb)
 void
 BView_DrawBitmap (void *view, void *bitmap, int x, int y,
                  int width, int height, int vx, int vy, int vwidth,
-                 int vheight)
+                 int vheight, bool use_bilinear_filtering)
 {
   BView *vw = get_view (view);
   BBitmap *bm = (BBitmap *) bitmap;
 
   vw->SetDrawingMode (B_OP_OVER);
-  vw->DrawBitmap (bm, BRect (x, y, x + width - 1, y + height - 1),
-                 BRect (vx, vy, vx + vwidth - 1, vy + vheight - 1));
+  if (!use_bilinear_filtering)
+    vw->DrawBitmap (bm, BRect (x, y, x + width - 1, y + height - 1),
+                   BRect (vx, vy, vx + vwidth - 1, vy + vheight - 1));
+  else
+    vw->DrawBitmap (bm, BRect (x, y, x + width - 1, y + height - 1),
+                   BRect (vx, vy, vx + vwidth - 1, vy + vheight - 1),
+                   B_FILTER_BITMAP_BILINEAR);
   vw->SetDrawingMode (B_OP_COPY);
 }
 
@@ -357,134 +362,64 @@ BView_DrawBitmapWithEraseOp (void *view, void *bitmap, 
int x,
 }
 
 void
-BView_DrawMask (void *src, void *view,
-               int x, int y, int width, int height,
-               int vx, int vy, int vwidth, int vheight,
-               uint32_t color)
+be_draw_image_mask (void *src, void *view, int x, int y, int width,
+                   int height, int vx, int vy, int vwidth, int vheight,
+                   uint32_t color)
 {
   BBitmap *source = (BBitmap *) src;
   BBitmap bm (source->Bounds (), B_RGBA32);
   BRect bounds = bm.Bounds ();
+  int bx, by, bit;
+  BView *vw;
 
   if (bm.InitCheck () != B_OK)
     return;
-  for (int y = 0; y < BE_RECT_HEIGHT (bounds); ++y)
+
+  /* Fill the background color or transparency into the bitmap,
+     depending on the value of the mask.  */
+  for (by = 0; by < BE_RECT_HEIGHT (bounds); ++by)
     {
-      for (int x = 0; x < BE_RECT_WIDTH (bounds); ++x)
+      for (bx = 0; bx < BE_RECT_WIDTH (bounds); ++bx)
        {
-         int bit = haiku_get_pixel ((void *) source, x, y);
+         bit = haiku_get_pixel ((void *) source, bx, by);
 
          if (!bit)
-           haiku_put_pixel ((void *) &bm, x, y, ((uint32_t) 255 << 24) | 
color);
+           haiku_put_pixel ((void *) &bm, bx, by,
+                            ((uint32_t) 255 << 24) | color);
          else
-           haiku_put_pixel ((void *) &bm, x, y, 0);
+           haiku_put_pixel ((void *) &bm, bx, by, 0);
        }
     }
-  BView *vw = get_view (view);
+
+  vw = get_view (view);
   vw->SetDrawingMode (B_OP_OVER);
   vw->DrawBitmap (&bm, BRect (x, y, x + width - 1, y + height - 1),
                  BRect (vx, vy, vx + vwidth - 1, vy + vheight - 1));
   vw->SetDrawingMode (B_OP_COPY);
 }
 
-static BBitmap *
-rotate_bitmap_270 (BBitmap *bmp)
+void
+be_apply_affine_transform (void *view, double m0, double m1, double tx,
+                          double m2, double m3, double ty)
 {
-  BRect r = bmp->Bounds ();
-  BBitmap *bm = new BBitmap (BRect (r.top, r.left, r.bottom, r.right),
-                            bmp->ColorSpace (), true);
-  if (bm->InitCheck () != B_OK)
-    gui_abort ("Failed to init bitmap for rotate");
-  int w = BE_RECT_WIDTH (r);
-  int h = BE_RECT_HEIGHT (r);
+  BAffineTransform transform (m0, m2, m1, m3, tx, ty);
 
-  for (int y = 0; y < h; ++y)
-    for (int x = 0; x < w; ++x)
-      haiku_put_pixel ((void *) bm, y, w - x - 1,
-                      haiku_get_pixel ((void *) bmp, x, y));
-
-  return bm;
+  get_view (view)->SetTransform (transform);
 }
 
-static BBitmap *
-rotate_bitmap_90 (BBitmap *bmp)
+void
+be_apply_inverse_transform (double (*matrix3x3)[3], int x, int y,
+                           int *x_out, int *y_out)
 {
-  BRect r = bmp->Bounds ();
-  BBitmap *bm = new BBitmap (BRect (r.top, r.left, r.bottom, r.right),
-                            bmp->ColorSpace (), true);
-  if (bm->InitCheck () != B_OK)
-    gui_abort ("Failed to init bitmap for rotate");
-  int w = BE_RECT_WIDTH (r);
-  int h = BE_RECT_HEIGHT (r);
+  BAffineTransform transform (matrix3x3[0][0], matrix3x3[1][0],
+                             matrix3x3[0][1], matrix3x3[1][1],
+                             matrix3x3[0][2], matrix3x3[1][2]);
+  BPoint point (x, y);
 
-  for (int y = 0; y < h; ++y)
-    for (int x = 0; x < w; ++x)
-      haiku_put_pixel ((void *) bm, h - y - 1, x,
-                      haiku_get_pixel ((void *) bmp, x, y));
-
-  return bm;
-}
-
-void *
-BBitmap_transform_bitmap (void *bitmap, void *mask, uint32_t m_color,
-                         double rot, int desw, int desh)
-{
-  BBitmap *bm = (BBitmap *) bitmap;
-  BBitmap *mk = (BBitmap *) mask;
-  int copied_p = 0;
-
-  if (rot == 90)
-    {
-      copied_p = 1;
-      bm = rotate_bitmap_90 (bm);
-      if (mk)
-       mk = rotate_bitmap_90 (mk);
-    }
-
-  if (rot == 270)
-    {
-      copied_p = 1;
-      bm = rotate_bitmap_270 (bm);
-      if (mk)
-       mk = rotate_bitmap_270 (mk);
-    }
-
-  BRect n = BRect (0, 0, desw - 1, desh - 1);
-  BView vw (n, NULL, B_FOLLOW_NONE, 0);
-  BBitmap *dst = new BBitmap (n, bm->ColorSpace (), true);
-  if (dst->InitCheck () != B_OK)
-    if (bm->InitCheck () != B_OK)
-      gui_abort ("Failed to init bitmap for scale");
-  dst->AddChild (&vw);
-
-  if (!vw.LockLooper ())
-    gui_abort ("Failed to lock offscreen view for scale");
-
-  if (rot != 90 && rot != 270)
-    {
-      BAffineTransform tr;
-      tr.RotateBy (BPoint (desw / 2, desh / 2), rot * M_PI / 180.0);
-      vw.SetTransform (tr);
-    }
-
-  vw.MovePenTo (0, 0);
-  vw.DrawBitmap (bm, n);
-  if (mk)
-    {
-      BRect k = mk->Bounds ();
-      BView_DrawMask ((void *) mk, (void *) &vw,
-                     0, 0, BE_RECT_WIDTH (k),
-                     BE_RECT_HEIGHT (k),
-                     0, 0, desw, desh, m_color);
-    }
-  vw.Sync ();
-  vw.RemoveSelf ();
+  transform.ApplyInverse (&point);
 
-  if (copied_p)
-    delete bm;
-  if (copied_p && mk)
-    delete mk;
-  return dst;
+  *x_out = std::floor (point.x);
+  *y_out = std::floor (point.y);
 }
 
 void
@@ -540,3 +475,62 @@ be_draw_cross_on_pixmap (void *bitmap, int x, int y, int 
width,
   be_draw_cross_on_pixmap_1 (target, x, y, width, height,
                             color);
 }
+
+void
+be_draw_bitmap_with_mask (void *view, void *bitmap, void *mask,
+                         int dx, int dy, int width, int height,
+                         int vx, int vy, int vwidth, int vheight,
+                         bool use_bilinear_filtering)
+{
+  BBitmap *source ((BBitmap *) bitmap);
+  BBitmap combined (source->Bounds (), B_RGBA32);
+  BRect bounds;
+  int x, y, bit;
+  BView *vw;
+  uint32_t source_mask;
+  unsigned long pixel;
+
+  if (combined.InitCheck () != B_OK)
+    return;
+
+  if (combined.ImportBits (source) != B_OK)
+    return;
+
+  bounds = source->Bounds ();
+
+  if (source->ColorSpace () == B_RGB32)
+    source_mask = 255u << 24;
+  else
+    source_mask = 0;
+
+  for (y = 0; y < BE_RECT_HEIGHT (bounds); ++y)
+    {
+      for (x = 0; x < BE_RECT_WIDTH (bounds); ++x)
+       {
+         bit = haiku_get_pixel (mask, x, y);
+
+         if (bit)
+           {
+             pixel = haiku_get_pixel (bitmap, x, y);
+             haiku_put_pixel ((void *) &combined, x, y,
+                              source_mask | pixel);
+           }
+         else
+           haiku_put_pixel ((void *) &combined, x, y, 0);
+       }
+    }
+
+  vw = get_view (view);
+
+  vw->SetDrawingMode (B_OP_OVER);
+  if (!use_bilinear_filtering)
+    vw->DrawBitmap (&combined,
+                   BRect (dx, dy, dx + width - 1, dy + height - 1),
+                   BRect (vx, vy, vx + vwidth - 1, vy + vheight - 1));
+  else
+    vw->DrawBitmap (&combined,
+                   BRect (dx, dy, dx + width - 1, dy + height - 1),
+                   BRect (vx, vy, vx + vwidth - 1, vy + vheight - 1),
+                   B_FILTER_BITMAP_BILINEAR);
+  vw->SetDrawingMode (B_OP_COPY);
+}
diff --git a/src/haiku_font_support.cc b/src/haiku_font_support.cc
index ca6aaf7120..d824cc59ae 100644
--- a/src/haiku_font_support.cc
+++ b/src/haiku_font_support.cc
@@ -598,6 +598,12 @@ BFont_find (struct haiku_font_pattern *pt)
              p->last = NULL;
              p->next_family = r;
              r = p;
+
+             if (pt->specified & FSPEC_ANTIALIAS)
+               {
+                 p->specified |= FSPEC_ANTIALIAS;
+                 p->use_antialiasing = pt->use_antialiasing;
+               }
            }
          else if (sty_count)
            {
@@ -623,6 +629,12 @@ BFont_find (struct haiku_font_pattern *pt)
                          p->family_index = fi;
                          p->style_index = si;
 
+                         if (pt->specified & FSPEC_ANTIALIAS)
+                           {
+                             p->specified |= FSPEC_ANTIALIAS;
+                             p->use_antialiasing = pt->use_antialiasing;
+                           }
+
                          if (p->specified & FSPEC_SLANT
                              && (p->slant == SLANT_OBLIQUE
                                  || p->slant == SLANT_ITALIC))
@@ -916,3 +928,14 @@ be_find_font_indices (struct haiku_font_pattern *pattern,
 
   return 1;
 }
+
+void
+be_set_font_antialiasing (void *font, bool antialias_p)
+{
+  BFont *font_object;
+
+  font_object = (BFont *) font;
+  font_object->SetFlags (antialias_p
+                        ? B_FORCE_ANTIALIASING
+                        : B_DISABLE_ANTIALIASING);
+}
diff --git a/src/haiku_io.c b/src/haiku_io.c
index d345527685..5cc70f6f71 100644
--- a/src/haiku_io.c
+++ b/src/haiku_io.c
@@ -107,6 +107,8 @@ haiku_len (enum haiku_event_type type)
       return sizeof (struct haiku_scroll_bar_part_event);
     case SCREEN_CHANGED_EVENT:
       return sizeof (struct haiku_screen_changed_event);
+    case CLIPBOARD_CHANGED_EVENT:
+      return sizeof (struct haiku_clipboard_changed_event);
     }
 
   emacs_abort ();
diff --git a/src/haiku_select.cc b/src/haiku_select.cc
index 764001f62b..872da1d6c4 100644
--- a/src/haiku_select.cc
+++ b/src/haiku_select.cc
@@ -18,6 +18,7 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 
 #include <config.h>
 
+#include <Application.h>
 #include <Clipboard.h>
 #include <Message.h>
 #include <Path.h>
@@ -47,6 +48,16 @@ static int64 count_primary = -1;
 /* The number of times the secondary selection has changed.  */
 static int64 count_secondary = -1;
 
+/* Whether or not we currently think Emacs owns the primary
+   selection.  */
+static bool owned_primary;
+
+/* Likewise for the secondary selection.  */
+static bool owned_secondary;
+
+/* And the clipboard.  */
+static bool owned_clipboard;
+
 static BClipboard *
 get_clipboard_object (enum haiku_clipboard clipboard)
 {
@@ -110,53 +121,6 @@ be_find_clipboard_data_1 (BClipboard *cb, const char 
*type, ssize_t *len)
   return (char *) value;
 }
 
-static void
-be_get_clipboard_targets_1 (BClipboard *cb, char **buf, int buf_size)
-{
-  BMessage *data;
-  char *name;
-  int32 count_found;
-  type_code type;
-  int32 i;
-  int index;
-
-  if (!cb->Lock ())
-    {
-      buf[0] = NULL;
-      return;
-    }
-
-  data = cb->Data ();
-  index = 0;
-
-  if (!data)
-    {
-      buf[0] = NULL;
-      cb->Unlock ();
-      return;
-    }
-
-  for (i = 0; (data->GetInfo (B_ANY_TYPE, i, &name,
-                            &type, &count_found)
-              == B_OK); ++i)
-    {
-      if (type == B_MIME_TYPE)
-       {
-         if (index < (buf_size - 1))
-           {
-             buf[index++] = strdup (name);
-
-             if (!buf[index - 1])
-               break;
-           }
-       }
-    }
-
-  buf[index] = NULL;
-
-  cb->Unlock ();
-}
-
 static void
 be_set_clipboard_data_1 (BClipboard *cb, const char *type, const char *data,
                         ssize_t len, bool clear)
@@ -197,14 +161,17 @@ be_update_clipboard_count (enum haiku_clipboard id)
     {
     case CLIPBOARD_CLIPBOARD:
       count_clipboard = system_clipboard->SystemCount ();
+      owned_clipboard = true;
       break;
 
     case CLIPBOARD_PRIMARY:
       count_primary = primary->SystemCount ();
+      owned_primary = true;
       break;
 
     case CLIPBOARD_SECONDARY:
       count_secondary = secondary->SystemCount ();
+      owned_secondary = true;
       break;
     }
 }
@@ -227,14 +194,6 @@ be_set_clipboard_data (enum haiku_clipboard id, const char 
*type,
                           data, len, clear);
 }
 
-void
-be_get_clipboard_targets (enum haiku_clipboard id, char **targets,
-                         int len)
-{
-  be_get_clipboard_targets_1 (get_clipboard_object (id), targets,
-                             len);
-}
-
 static bool
 clipboard_owner_p (void)
 {
@@ -278,7 +237,7 @@ be_clipboard_owner_p (enum haiku_clipboard clipboard)
 }
 
 void
-init_haiku_select (void)
+be_clipboard_init (void)
 {
   system_clipboard = new BClipboard ("system");
   primary = new BClipboard ("primary");
@@ -488,3 +447,73 @@ be_unlock_clipboard (enum haiku_clipboard clipboard, bool 
discard)
 
   board->Unlock ();
 }
+
+void
+be_handle_clipboard_changed_message (void)
+{
+  int64 n_clipboard, n_primary, n_secondary;
+
+  n_clipboard = system_clipboard->SystemCount ();
+  n_primary = primary->SystemCount ();
+  n_secondary = secondary->SystemCount ();
+
+  if (count_clipboard != -1
+      && (n_clipboard > count_clipboard + 1)
+      && owned_clipboard)
+    {
+      owned_clipboard = false;
+      haiku_selection_disowned (CLIPBOARD_CLIPBOARD,
+                               n_clipboard);
+    }
+
+  if (count_primary != -1
+      && (n_primary > count_primary + 1)
+      && owned_primary)
+    {
+      owned_primary = false;
+      haiku_selection_disowned (CLIPBOARD_PRIMARY,
+                               n_primary);
+    }
+
+  if (count_secondary != -1
+      && (n_secondary > count_secondary + 1)
+      && owned_secondary)
+    {
+      owned_secondary = false;
+      haiku_selection_disowned (CLIPBOARD_SECONDARY,
+                               n_secondary);
+    }
+}
+
+void
+be_start_watching_selection (enum haiku_clipboard id)
+{
+  BClipboard *clipboard;
+
+  clipboard = get_clipboard_object (id);
+  clipboard->StartWatching (be_app);
+}
+
+bool
+be_selection_outdated_p (enum haiku_clipboard id, int64 count)
+{
+  if (id == CLIPBOARD_CLIPBOARD && count_clipboard > count)
+    return true;
+
+  if (id == CLIPBOARD_PRIMARY && count_primary > count)
+    return true;
+
+  if (id == CLIPBOARD_SECONDARY && count_secondary > count)
+    return true;
+
+  return false;
+}
+
+int64
+be_get_clipboard_count (enum haiku_clipboard id)
+{
+  BClipboard *clipboard;
+
+  clipboard = get_clipboard_object (id);
+  return clipboard->SystemCount ();
+}
diff --git a/src/haiku_support.cc b/src/haiku_support.cc
index 182f212847..983928442a 100644
--- a/src/haiku_support.cc
+++ b/src/haiku_support.cc
@@ -21,6 +21,7 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 
 #include <app/Application.h>
 #include <app/Cursor.h>
+#include <app/Clipboard.h>
 #include <app/Messenger.h>
 #include <app/Roster.h>
 
@@ -92,22 +93,23 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 /* Some messages that Emacs sends to itself.  */
 enum
   {
-    SCROLL_BAR_UPDATE    = 3000,
-    WAIT_FOR_RELEASE     = 3001,
-    RELEASE_NOW                  = 3002,
-    CANCEL_DROP                  = 3003,
-    SHOW_MENU_BAR        = 3004,
-    BE_MENU_BAR_OPEN     = 3005,
-    QUIT_APPLICATION     = 3006,
-    REPLAY_MENU_BAR      = 3007,
-    FONT_FAMILY_SELECTED  = 3008,
-    FONT_STYLE_SELECTED          = 3009,
-    FILE_PANEL_SELECTION  = 3010,
-    QUIT_PREVIEW_DIALOG          = 3011,
-    SET_FONT_INDICES     = 3012,
-    SET_PREVIEW_DIALOG   = 3013,
-    UPDATE_PREVIEW_DIALOG = 3014,
-    SEND_MOVE_FRAME_EVENT = 3015,
+    SCROLL_BAR_UPDATE       = 3000,
+    WAIT_FOR_RELEASE        = 3001,
+    RELEASE_NOW                     = 3002,
+    CANCEL_DROP                     = 3003,
+    SHOW_MENU_BAR           = 3004,
+    BE_MENU_BAR_OPEN        = 3005,
+    QUIT_APPLICATION        = 3006,
+    REPLAY_MENU_BAR         = 3007,
+    FONT_FAMILY_SELECTED     = 3008,
+    FONT_STYLE_SELECTED             = 3009,
+    FILE_PANEL_SELECTION     = 3010,
+    QUIT_PREVIEW_DIALOG             = 3011,
+    SET_FONT_INDICES        = 3012,
+    SET_PREVIEW_DIALOG      = 3013,
+    UPDATE_PREVIEW_DIALOG    = 3014,
+    SEND_MOVE_FRAME_EVENT    = 3015,
+    SET_DISABLE_ANTIALIASING = 3016,
   };
 
 /* X11 keysyms that we use.  */
@@ -140,12 +142,15 @@ enum
 
 struct font_selection_dialog_message
 {
-  /* Whether or not font selection was cancelled.  */
+  /* Whether or not font selection was canceled.  */
   bool_bf cancel : 1;
 
   /* Whether or not a size was explicitly specified.  */
   bool_bf size_specified : 1;
 
+  /* Whether or not antialiasing should be disabled.  */
+  bool_bf disable_antialias : 1;
+
   /* The index of the selected font family.  */
   int family_idx;
 
@@ -184,10 +189,6 @@ static BMessage volatile *popup_track_message;
    number.  */
 static int32 volatile alert_popup_value;
 
-/* The current window ID.  This is increased every time a frame is
-   created.  */
-static int current_window_id;
-
 /* The view that has the passive grab.  */
 static void *grab_view;
 
@@ -644,8 +645,12 @@ public:
   void
   MessageReceived (BMessage *msg)
   {
+    struct haiku_clipboard_changed_event rq;
+
     if (msg->what == QUIT_APPLICATION)
       Quit ();
+    else if (msg->what == B_CLIPBOARD_CHANGED)
+      haiku_write (CLIPBOARD_CHANGED_EVENT, &rq);
     else
       BApplication::MessageReceived (msg);
   }
@@ -689,7 +694,6 @@ public:
                   was_shown_p (false),
                   menu_bar_active_p (false),
                   override_redirect_p (false),
-                  window_id (current_window_id),
                   menus_begun (NULL),
                   z_group (Z_GROUP_NONE),
                   tooltip_p (false),
@@ -932,12 +936,11 @@ public:
     if (msg->WasDropped ())
       {
        BPoint whereto;
-       int32 windowid;
+       int64 threadid;
        struct haiku_drag_and_drop_event rq;
 
-       if (msg->FindInt32 ("emacs:window_id", &windowid) == B_OK
-           && !msg->IsSourceRemote ()
-           && windowid == this->window_id)
+       if (msg->FindInt64 ("emacs:thread_id", &threadid) == B_OK
+           && threadid == find_thread (NULL))
          return;
 
        whereto = msg->DropPoint ();
@@ -1493,7 +1496,6 @@ public:
 class EmacsView : public BView
 {
 public:
-  uint32_t previous_buttons;
   int looper_locked_count;
   BRegion sb_region;
   BRegion invalid_region;
@@ -1508,12 +1510,13 @@ public:
   BLocker cr_surface_lock;
 #endif
 
-  BPoint tt_absl_pos;
   BMessage *wait_for_release_message;
+  int64 grabbed_buttons;
+  BScreen screen;
+  bool use_frame_synchronization;
 
   EmacsView () : BView (BRect (0, 0, 0, 0), "Emacs",
                        B_FOLLOW_NONE, B_WILL_DRAW),
-                previous_buttons (0),
                 looper_locked_count (0),
                 offscreen_draw_view (NULL),
                 offscreen_draw_bitmap_1 (NULL),
@@ -1522,7 +1525,9 @@ public:
                 cr_surface (NULL),
                 cr_context (NULL),
 #endif
-                wait_for_release_message (NULL)
+                wait_for_release_message (NULL),
+                grabbed_buttons (0),
+                use_frame_synchronization (false)
   {
 
   }
@@ -1544,6 +1549,16 @@ public:
     grab_view_locker.Unlock ();
   }
 
+  void
+  SetFrameSynchronization (bool sync)
+  {
+    if (LockLooper ())
+      {
+       use_frame_synchronization = sync;
+       UnlockLooper ();
+      }
+  }
+
   void
   MessageReceived (BMessage *msg)
   {
@@ -1720,14 +1735,14 @@ public:
   void
   FlipBuffers (void)
   {
+    EmacsWindow *w;
     if (!LockLooper ())
       gui_abort ("Failed to lock looper during buffer flip");
     if (!offscreen_draw_view)
       gui_abort ("Failed to lock offscreen view during buffer flip");
 
     offscreen_draw_view->Sync ();
-
-    EmacsWindow *w = (EmacsWindow *) Window ();
+    w = (EmacsWindow *) Window ();
     w->shown_flag = 0;
 
     if (copy_bitmap &&
@@ -1748,6 +1763,11 @@ public:
     if (copy_bitmap->InitCheck () != B_OK)
       gui_abort ("Failed to init copy bitmap during buffer flip");
 
+    /* Wait for VBLANK.  If responding to the invalidation or buffer
+       flipping takes longer than the blanking period, we lose.  */
+    if (use_frame_synchronization)
+      screen.WaitForRetrace ();
+
     Invalidate (&invalid_region);
     invalid_region.MakeEmpty ();
     UnlockLooper ();
@@ -1786,31 +1806,29 @@ public:
   MouseMoved (BPoint point, uint32 transit, const BMessage *drag_msg)
   {
     struct haiku_mouse_motion_event rq;
-    int32 windowid;
+    int64 threadid;
     EmacsWindow *window;
-    BToolTip *tooltip;
 
     window = (EmacsWindow *) Window ();
-    tooltip = ToolTip ();
 
-    rq.just_exited_p = transit == B_EXITED_VIEW;
+    if (transit == B_EXITED_VIEW)
+      rq.just_exited_p = true;
+    else
+      rq.just_exited_p = false;
+
     rq.x = point.x;
     rq.y = point.y;
     rq.window = window;
     rq.time = system_time ();
 
     if (drag_msg && (drag_msg->IsSourceRemote ()
-                    || drag_msg->FindInt32 ("emacs:window_id",
-                                            &windowid) != B_OK
-                    || windowid != window->window_id))
+                    || drag_msg->FindInt64 ("emacs:thread_id",
+                                            &threadid) != B_OK
+                    || threadid != find_thread (NULL)))
       rq.dnd_message = true;
     else
       rq.dnd_message = false;
 
-    if (tooltip)
-      tooltip->SetMouseRelativeLocation (BPoint (-(point.x - tt_absl_pos.x),
-                                                -(point.y - tt_absl_pos.y)));
-
     if (!grab_view_locker.Lock ())
       gui_abort ("Couldn't lock grab view locker");
 
@@ -1826,42 +1844,51 @@ public:
   }
 
   void
-  BasicMouseDown (BPoint point, BView *scroll_bar)
+  BasicMouseDown (BPoint point, BView *scroll_bar, BMessage *message)
   {
     struct haiku_button_event rq;
-    uint32 mods, buttons;
+    int64 when;
+    int32 mods, buttons, button;
 
-    this->GetMouse (&point, &buttons, false);
+    if (message->FindInt64 ("when", &when) != B_OK
+       || message->FindInt32 ("modifiers", &mods) != B_OK
+       || message->FindInt32 ("buttons", &buttons) != B_OK)
+      return;
 
-    if (!grab_view_locker.Lock ())
-      gui_abort ("Couldn't lock grab view locker");
-    if (buttons)
-      grab_view = this;
-    grab_view_locker.Unlock ();
+    /* Find which button was pressed by comparing the previous button
+       mask to the current one.  This assumes that B_MOUSE_DOWN will
+       be sent for each button press.  */
+    button = buttons & ~grabbed_buttons;
+    grabbed_buttons = buttons;
+
+    if (!scroll_bar)
+      {
+       if (!grab_view_locker.Lock ())
+         gui_abort ("Couldn't lock grab view locker");
+       grab_view = this;
+       grab_view_locker.Unlock ();
+      }
 
     rq.window = this->Window ();
     rq.scroll_bar = scroll_bar;
 
-    if (!(previous_buttons & B_PRIMARY_MOUSE_BUTTON)
-       && (buttons & B_PRIMARY_MOUSE_BUTTON))
+    if (button == B_PRIMARY_MOUSE_BUTTON)
       rq.btn_no = 0;
-    else if (!(previous_buttons & B_SECONDARY_MOUSE_BUTTON)
-            && (buttons & B_SECONDARY_MOUSE_BUTTON))
+    else if (button == B_SECONDARY_MOUSE_BUTTON)
       rq.btn_no = 2;
-    else if (!(previous_buttons & B_TERTIARY_MOUSE_BUTTON)
-            && (buttons & B_TERTIARY_MOUSE_BUTTON))
+    else if (button == B_TERTIARY_MOUSE_BUTTON)
       rq.btn_no = 1;
     else
+      /* We don't know which button was pressed.  This usually happens
+        when a B_MOUSE_UP is sent to a view that didn't receive a
+        corresponding B_MOUSE_DOWN event, so simply ignore the
+        message.  */
       return;
 
-    previous_buttons = buttons;
-
     rq.x = point.x;
     rq.y = point.y;
-
-    mods = modifiers ();
-
     rq.modifiers = 0;
+
     if (mods & B_SHIFT_KEY)
       rq.modifiers |= HAIKU_MODIFIER_SHIFT;
 
@@ -1878,62 +1905,76 @@ public:
       SetMouseEventMask (B_POINTER_EVENTS, (B_LOCK_WINDOW_FOCUS
                                            | B_NO_POINTER_HISTORY));
 
-    rq.time = system_time ();
+    rq.time = when;
     haiku_write (BUTTON_DOWN, &rq);
   }
 
   void
   MouseDown (BPoint point)
   {
-    BasicMouseDown (point, NULL);
+    BMessage *msg;
+    BLooper *looper;
+
+    looper = Looper ();
+    msg = (looper
+          ? looper->CurrentMessage ()
+          : NULL);
+
+    if (msg)
+      BasicMouseDown (point, NULL, msg);
   }
 
   void
-  BasicMouseUp (BPoint point, BView *scroll_bar)
+  BasicMouseUp (BPoint point, BView *scroll_bar, BMessage *message)
   {
     struct haiku_button_event rq;
-    uint32 buttons, mods;
+    int64 when;
+    int32 mods, button, buttons;
 
-    this->GetMouse (&point, &buttons, false);
+    if (message->FindInt64 ("when", &when) != B_OK
+       || message->FindInt32 ("modifiers", &mods) != B_OK
+       || message->FindInt32 ("buttons", &buttons) != B_OK)
+      return;
 
-    if (!grab_view_locker.Lock ())
-      gui_abort ("Couldn't lock grab view locker");
-    if (!buttons)
-      grab_view = NULL;
-    grab_view_locker.Unlock ();
+    if (!scroll_bar)
+      {
+       if (!grab_view_locker.Lock ())
+         gui_abort ("Couldn't lock grab view locker");
+       if (!buttons)
+         grab_view = NULL;
+       grab_view_locker.Unlock ();
+      }
+
+    button = (grabbed_buttons & ~buttons);
+    grabbed_buttons = buttons;
 
-    if (!buttons && wait_for_release_message)
+    if (wait_for_release_message)
       {
-       wait_for_release_message->SendReply (wait_for_release_message);
-       delete wait_for_release_message;
-       wait_for_release_message = NULL;
+       if (!grabbed_buttons)
+         {
+           wait_for_release_message->SendReply (wait_for_release_message);
+           delete wait_for_release_message;
+           wait_for_release_message = NULL;
+         }
 
-       previous_buttons = buttons;
        return;
       }
 
     rq.window = this->Window ();
     rq.scroll_bar = scroll_bar;
 
-    if ((previous_buttons & B_PRIMARY_MOUSE_BUTTON)
-       && !(buttons & B_PRIMARY_MOUSE_BUTTON))
+    if (button == B_PRIMARY_MOUSE_BUTTON)
       rq.btn_no = 0;
-    else if ((previous_buttons & B_SECONDARY_MOUSE_BUTTON)
-            && !(buttons & B_SECONDARY_MOUSE_BUTTON))
+    else if (button == B_SECONDARY_MOUSE_BUTTON)
       rq.btn_no = 2;
-    else if ((previous_buttons & B_TERTIARY_MOUSE_BUTTON)
-            && !(buttons & B_TERTIARY_MOUSE_BUTTON))
+    else if (button == B_TERTIARY_MOUSE_BUTTON)
       rq.btn_no = 1;
     else
       return;
 
-    previous_buttons = buttons;
-
     rq.x = point.x;
     rq.y = point.y;
 
-    mods = modifiers ();
-
     rq.modifiers = 0;
     if (mods & B_SHIFT_KEY)
       rq.modifiers |= HAIKU_MODIFIER_SHIFT;
@@ -1947,14 +1988,23 @@ public:
     if (mods & B_OPTION_KEY)
       rq.modifiers |= HAIKU_MODIFIER_SUPER;
 
-    rq.time = system_time ();
+    rq.time = when;
     haiku_write (BUTTON_UP, &rq);
   }
 
   void
   MouseUp (BPoint point)
   {
-    BasicMouseUp (point, NULL);
+    BMessage *msg;
+    BLooper *looper;
+
+    looper = Looper ();
+    msg = (looper
+          ? looper->CurrentMessage ()
+          : NULL);
+
+    if (msg)
+      BasicMouseUp (point, NULL, msg);
   }
 };
 
@@ -1967,8 +2017,9 @@ public:
   float old_value;
   scroll_bar_info info;
 
-  /* True if button events should be passed to the parent.  */
-  bool handle_button;
+  /* How many button events were passed to the parent without
+     release.  */
+  int handle_button_count;
   bool in_overscroll;
   bool can_overscroll;
   bool maybe_overscroll;
@@ -1984,7 +2035,7 @@ public:
     : BScrollBar (BRect (x, y, x1, y1), NULL, NULL, 0, 0, horizontal_p ?
                  B_HORIZONTAL : B_VERTICAL),
       dragging (0),
-      handle_button (false),
+      handle_button_count (0),
       in_overscroll (false),
       can_overscroll (false),
       maybe_overscroll (false),
@@ -2208,10 +2259,10 @@ public:
        && mods & B_CONTROL_KEY)
       {
        /* Allow C-mouse-3 to split the window on a scroll bar.   */
-       handle_button = true;
+       handle_button_count += 1;
        SetMouseEventMask (B_POINTER_EVENTS, (B_SUSPEND_VIEW_FOCUS
                                              | B_LOCK_WINDOW_FOCUS));
-       parent->BasicMouseDown (ConvertToParent (pt), this);
+       parent->BasicMouseDown (ConvertToParent (pt), this, message);
 
        return;
       }
@@ -2274,14 +2325,23 @@ public:
   MouseUp (BPoint pt)
   {
     struct haiku_scroll_bar_drag_event rq;
+    BMessage *msg;
+    BLooper *looper;
 
     in_overscroll = false;
     maybe_overscroll = false;
 
-    if (handle_button)
+    if (handle_button_count)
       {
-       handle_button = false;
-       parent->BasicMouseUp (ConvertToParent (pt), this);
+       handle_button_count--;
+       looper = Looper ();
+       msg = (looper
+              ? looper->CurrentMessage ()
+              : NULL);
+
+       if (msg)
+         parent->BasicMouseUp (ConvertToParent (pt),
+                               this, msg);
 
        return;
       }
@@ -2574,6 +2634,9 @@ class EmacsFontPreviewDialog : public BWindow
        current_font = new BFont;
        current_font->SetFamilyAndStyle (name, sname);
 
+       if (message->GetBool ("emacs:disable_antialiasing", false))
+         current_font->SetFlags (B_DISABLE_ANTIALIASING);
+
        if (size_name && strlen (size_name))
          {
            size = atoi (size_name);
@@ -2615,26 +2678,32 @@ public:
   }
 };
 
-class DualLayoutView : public BView
+class TripleLayoutView : public BView
 {
   BScrollView *view_1;
-  BView *view_2;
+  BView *view_2, *view_3;
 
   void
   FrameResized (float new_width, float new_height)
   {
     BRect frame;
-    float width, height;
+    float width, height, height_1, width_1;
+    float basic_height;
 
     frame = Frame ();
 
     view_2->GetPreferredSize (&width, &height);
+    view_3->GetPreferredSize (&width_1, &height_1);
+
+    basic_height = height + height_1;
 
     view_1->MoveTo (0, 0);
     view_1->ResizeTo (BE_RECT_WIDTH (frame),
-                     BE_RECT_HEIGHT (frame) - height);
-    view_2->MoveTo (2, BE_RECT_HEIGHT (frame) - height);
+                     BE_RECT_HEIGHT (frame) - basic_height);
+    view_2->MoveTo (2, BE_RECT_HEIGHT (frame) - basic_height);
     view_2->ResizeTo (BE_RECT_WIDTH (frame) - 4, height);
+    view_3->MoveTo (2, BE_RECT_HEIGHT (frame) - height_1);
+    view_3->ResizeTo (BE_RECT_WIDTH (frame) - 4, height_1);
 
     BView::FrameResized (new_width, new_height);
   }
@@ -2644,19 +2713,24 @@ class DualLayoutView : public BView
   MinSize (void)
   {
     float width, height;
+    float width_1, height_1;
     BSize size_1;
 
     size_1 = view_1->MinSize ();
     view_2->GetPreferredSize (&width, &height);
+    view_3->GetPreferredSize (&width_1, &height_1);
 
-    return BSize (std::max (size_1.width, width),
-                 std::max (size_1.height, height));
+    return BSize (std::max (size_1.width,
+                           std::max (width_1, width)),
+                 std::max (size_1.height, height + height_1));
   }
 
 public:
-  DualLayoutView (BScrollView *first, BView *second) : BView (NULL, 
B_FRAME_EVENTS),
-                                                      view_1 (first),
-                                                      view_2 (second)
+  TripleLayoutView (BScrollView *first, BView *second,
+                   BView *third) : BView (NULL, B_FRAME_EVENTS),
+                                   view_1 (first),
+                                   view_2 (second),
+                                   view_3 (third)
   {
     FrameResized (801, 801);
   }
@@ -2665,13 +2739,14 @@ public:
 class EmacsFontSelectionDialog : public BWindow
 {
   BView basic_view;
+  BCheckBox antialias_checkbox;
   BCheckBox preview_checkbox;
   BSplitView split_view;
   BListView font_family_pane;
   BListView font_style_pane;
   BScrollView font_family_scroller;
   BScrollView font_style_scroller;
-  DualLayoutView style_view;
+  TripleLayoutView style_view;
   BObjectList<BStringItem> all_families;
   BObjectList<BStringItem> all_styles;
   BButton cancel_button, ok_button;
@@ -2707,6 +2782,9 @@ class EmacsFontSelectionDialog : public BWindow
     message.AddInt32 ("emacs:family", family);
     message.AddInt32 ("emacs:style", style);
 
+    if (antialias_checkbox.Value () == B_CONTROL_ON)
+      message.AddBool ("emacs:disable_antialiasing", true);
+
     message.AddString ("emacs:size",
                       size_entry.Text ());
 
@@ -2834,6 +2912,11 @@ class EmacsFontSelectionDialog : public BWindow
        rq.size = atoi (text);
        rq.size_specified = rq.size > 0 || strlen (text);
 
+       if (antialias_checkbox.Value () == B_CONTROL_ON)
+         rq.disable_antialias = true;
+       else
+         rq.disable_antialias = false;
+
        write_port (comm_port, 0, &rq, sizeof rq);
       }
     else if (msg->what == B_CANCEL)
@@ -2859,6 +2942,11 @@ class EmacsFontSelectionDialog : public BWindow
        if (preview)
          UpdatePreview ();
       }
+    else if (msg->what == SET_DISABLE_ANTIALIASING)
+      {
+       if (preview)
+         UpdatePreview ();
+      }
 
     BWindow::MessageReceived (msg);
   }
@@ -2881,6 +2969,7 @@ public:
 
     font_family_pane.RemoveSelf ();
     font_style_pane.RemoveSelf ();
+    antialias_checkbox.RemoveSelf ();
     preview_checkbox.RemoveSelf ();
     style_view.RemoveSelf ();
     font_family_scroller.RemoveSelf ();
@@ -2897,12 +2986,15 @@ public:
   EmacsFontSelectionDialog (bool monospace_only,
                            int initial_family_idx,
                            int initial_style_idx,
-                           int initial_size)
+                           int initial_size,
+                           bool initial_antialias)
     : BWindow (BRect (0, 0, 500, 500),
               "Select font from list",
               B_TITLED_WINDOW_LOOK,
               B_MODAL_APP_WINDOW_FEEL, 0),
       basic_view (NULL, 0),
+      antialias_checkbox ("Disable antialiasing", "Disable antialiasing",
+                         new BMessage (SET_DISABLE_ANTIALIASING)),
       preview_checkbox ("Show preview", "Show preview",
                        new BMessage (SET_PREVIEW_DIALOG)),
       font_family_pane (BRect (0, 0, 0, 0), NULL,
@@ -2917,7 +3009,8 @@ public:
       font_style_scroller (NULL, &font_style_pane,
                           B_FOLLOW_ALL_SIDES,
                           B_SUPPORTS_LAYOUT, false, true),
-      style_view (&font_style_scroller, &preview_checkbox),
+      style_view (&font_style_scroller, &antialias_checkbox,
+                 &preview_checkbox),
       all_families (20, true),
       all_styles (20, true),
       cancel_button ("Cancel", "Cancel",
@@ -2946,6 +3039,7 @@ public:
     split_view.AddChild (&font_family_scroller, 0.7);
     split_view.AddChild (&style_view, 0.3);
     style_view.AddChild (&font_style_scroller);
+    style_view.AddChild (&antialias_checkbox);
     style_view.AddChild (&preview_checkbox);
 
     basic_view.SetViewUIColor (B_PANEL_BACKGROUND_COLOR);
@@ -3007,6 +3101,9 @@ public:
        sprintf (format_buffer, "%d", initial_size);
        size_entry.SetText (format_buffer);
       }
+
+    if (!initial_antialias)
+      antialias_checkbox.SetValue (B_CONTROL_ON);
   }
 
   void
@@ -3225,6 +3322,41 @@ public:
   }
 };
 
+/* A view that is added as a child of a tooltip's text view, and
+   prevents motion events from reaching it (thereby moving the
+   tooltip).  */
+class EmacsMotionSuppressionView : public BView
+{
+  void
+  AttachedToWindow (void)
+  {
+    BView *text_view, *tooltip_view;
+
+    /* We know that this view is a child of the text view, whose
+       parent is the tooltip view, and that the tooltip view has
+       already set its mouse event mask.  */
+
+    text_view = Parent ();
+
+    if (!text_view)
+      return;
+
+    tooltip_view = text_view->Parent ();
+
+    if (!tooltip_view)
+      return;
+
+    tooltip_view->SetEventMask (B_KEYBOARD_EVENTS, 0);
+  }
+
+public:
+  EmacsMotionSuppressionView (void) : BView (BRect (-1, -1, 1, 1),
+                                            NULL, 0, 0)
+  {
+    return;
+  }
+};
+
 static int32
 start_running_application (void *data)
 {
@@ -3474,8 +3606,8 @@ be_get_screen_dimensions (int *width, int *height)
 
   frame = screen.Frame ();
 
-  *width = 1 + frame.right - frame.left;
-  *height = 1 + frame.bottom - frame.top;
+  *width = BE_RECT_WIDTH (frame);
+  *height = BE_RECT_HEIGHT (frame);
 }
 
 /* Resize VIEW to WIDTH, HEIGHT.  */
@@ -4263,30 +4395,48 @@ BView_set_tooltip (void *view, const char *tooltip)
 
 /* Set VIEW's tooltip to a sticky tooltip at X by Y.  */
 void
-BView_set_and_show_sticky_tooltip (void *view, const char *tooltip,
-                                  int x, int y)
+be_show_sticky_tooltip (void *view, const char *tooltip_text,
+                       int x, int y)
 {
-  BToolTip *tip;
-  BView *vw = (BView *) view;
+  BToolTip *tooltip;
+  BView *vw, *tooltip_view;
+  BPoint point;
+
+  vw = (BView *) view;
+
   if (!vw->LockLooper ())
     gui_abort ("Failed to lock view while showing sticky tooltip");
-  vw->SetToolTip (tooltip);
-  tip = vw->ToolTip ();
-  BPoint pt;
-  EmacsView *ev = dynamic_cast<EmacsView *> (vw);
-  if (ev)
-    ev->tt_absl_pos = BPoint (x, y);
 
-  vw->GetMouse (&pt, NULL, 1);
-  pt.x -= x;
-  pt.y -= y;
+  vw->SetToolTip ((const char *) NULL);
+
+  /* If the tooltip text is empty, then a tooltip object won't be
+     created by SetToolTip.  */
+  if (tooltip_text[0] == '\0')
+    tooltip_text = " ";
+
+  vw->SetToolTip (tooltip_text);
+
+  tooltip = vw->ToolTip ();
+
+  vw->GetMouse (&point, NULL, 1);
+  point.x -= x;
+  point.y -= y;
+
+  point.x = -point.x;
+  point.y = -point.y;
+
+  /* We don't have to make the tooltip sticky since not receiving
+     mouse movement is enough to prevent it from being hidden.  */
+  tooltip->SetMouseRelativeLocation (point);
 
-  pt.x = -pt.x;
-  pt.y = -pt.y;
+  /* Prevent the tooltip from moving in response to mouse
+     movement.  */
+  tooltip_view = tooltip->View ();
 
-  tip->SetMouseRelativeLocation (pt);
-  tip->SetSticky (1);
-  vw->ShowToolTip (tip);
+  if (tooltip_view)
+    tooltip_view->AddChild (new EmacsMotionSuppressionView);
+
+  vw->ShowToolTip (tooltip);
   vw->UnlockLooper ();
 }
 
@@ -4950,13 +5100,17 @@ be_drag_message (void *view, void *message, bool 
allow_same_view,
   BMessage cancel_message (CANCEL_DROP);
   struct object_wait_info infos[2];
   ssize_t stat;
+  thread_id window_thread;
 
   block_input_function ();
 
-  if (!allow_same_view &&
-      (msg->ReplaceInt32 ("emacs:window_id", window->window_id)
-       == B_NAME_NOT_FOUND))
-    msg->AddInt32 ("emacs:window_id", window->window_id);
+  if (!allow_same_view)
+    window_thread = window->Looper ()->Thread ();
+
+  if (!allow_same_view
+      && (msg->ReplaceInt64 ("emacs:thread_id", window_thread)
+         == B_NAME_NOT_FOUND))
+    msg->AddInt64 ("emacs:thread_id", window_thread);
 
   if (!vw->LockLooper ())
     gui_abort ("Failed to lock view looper for drag");
@@ -5096,7 +5250,8 @@ be_select_font (void (*process_pending_signals_function) 
(void),
                haiku_font_family_or_style *style,
                int *size, bool allow_monospace_only,
                int initial_family, int initial_style,
-               int initial_size)
+               int initial_size, bool initial_antialias,
+               bool *disable_antialias)
 {
   EmacsFontSelectionDialog *dialog;
   struct font_selection_dialog_message msg;
@@ -5106,7 +5261,7 @@ be_select_font (void (*process_pending_signals_function) 
(void),
 
   dialog = new EmacsFontSelectionDialog (allow_monospace_only,
                                         initial_family, initial_style,
-                                        initial_size);
+                                        initial_size, initial_antialias);
   dialog->CenterOnScreen ();
 
   if (dialog->InitCheck () < B_OK)
@@ -5135,6 +5290,7 @@ be_select_font (void (*process_pending_signals_function) 
(void),
   memcpy (family, family_buffer, sizeof *family);
   memcpy (style, style_buffer, sizeof *style);
   *size = msg.size_specified ? msg.size : -1;
+  *disable_antialias = msg.disable_antialias;
 
   return true;
 }
@@ -5322,3 +5478,26 @@ be_get_explicit_workarea (int *x, int *y, int *width, 
int *height)
 
   return true;
 }
+
+/* Clear the grab view.  This has to be called manually from some
+   places, since we don't get B_MOUSE_UP messages after a popup menu
+   is run.  */
+
+void
+be_clear_grab_view (void)
+{
+  if (grab_view_locker.Lock ())
+    {
+      grab_view = NULL;
+      grab_view_locker.Unlock ();
+    }
+}
+
+void
+be_set_use_frame_synchronization (void *view, bool sync)
+{
+  EmacsView *vw;
+
+  vw = (EmacsView *) view;
+  vw->SetFrameSynchronization (sync);
+}
diff --git a/src/haiku_support.h b/src/haiku_support.h
index 7f8d471b65..ca1808556a 100644
--- a/src/haiku_support.h
+++ b/src/haiku_support.h
@@ -114,8 +114,14 @@ enum haiku_event_type
     DUMMY_EVENT,
     SCREEN_CHANGED_EVENT,
     MENU_BAR_LEFT,
+    CLIPBOARD_CHANGED_EVENT,
   };
 
+struct haiku_clipboard_changed_event
+{
+  char dummy;
+};
+
 struct haiku_screen_changed_event
 {
   bigtime_t when;
@@ -271,6 +277,7 @@ enum haiku_font_specification
     FSPEC_WIDTH              = 1 << 7,
     FSPEC_LANGUAGE    = 1 << 8,
     FSPEC_INDICES     = 1 << 9,
+    FSPEC_ANTIALIAS   = 1 << 10,
   };
 
 typedef char haiku_font_family_or_style[64];
@@ -390,6 +397,10 @@ struct haiku_font_pattern
 
   /* Temporary field used during font enumeration.  */
   int oblique_seen_p;
+
+  /* Whether or not to enable antialiasing in the font.  This field is
+     special in that it's not handled by `BFont_open_pattern'.  */
+  int use_antialiasing;
 };
 
 struct haiku_scroll_bar_value_event
@@ -553,10 +564,8 @@ extern void BView_StrokeLine (void *, int, int, int, int);
 extern void BView_CopyBits (void *, int, int, int, int, int, int, int, int);
 extern void BView_InvertRect (void *, int, int, int, int);
 extern void BView_DrawBitmap (void *, void *, int, int, int, int, int, int,
-                             int, int);
+                             int, int, bool);
 extern void BView_DrawBitmapWithEraseOp (void *, void *, int, int, int, int);
-extern void BView_DrawMask (void *, void *, int, int, int, int,        int, 
int,
-                           int, int, uint32_t);
 extern void BView_DrawBitmapTiled (void *, void *, int, int,
                                   int, int, int, int, int, int);
 
@@ -565,8 +574,15 @@ extern void BView_set_view_cursor (void *, void *);
 extern void BView_move_frame (void *, int, int, int, int);
 extern void BView_scroll_bar_update (void *, int, int, int, int, bool);
 
-extern void *BBitmap_transform_bitmap (void *, void *, uint32_t, double,
-                                      int, int);
+extern void *be_transform_bitmap (void *, void *, uint32_t, double,
+                                 int, int, bool);
+extern void be_apply_affine_transform (void *, double, double, double,
+                                      double, double, double);
+extern void be_apply_inverse_transform (double (*)[3], int, int, int *, int *);
+extern void be_draw_image_mask (void *, void *, int, int, int, int, int, int,
+                               int, int, uint32_t);
+extern void be_draw_bitmap_with_mask (void *, void *, void *, int, int, int,
+                                     int, int, int, int, int, bool);
 
 extern void be_get_display_resolution (double *, double *);
 extern void be_get_screen_dimensions (int *, int *);
@@ -632,8 +648,7 @@ extern int32 BAlert_go (void *, void (*) (void), void (*) 
(void),
 extern void BButton_set_enabled (void *, int);
 extern void BView_set_tooltip (void *, const char *);
 extern void BView_show_tooltip (void *);
-extern void BView_set_and_show_sticky_tooltip (void *, const char *,
-                                              int, int);
+extern void be_show_sticky_tooltip (void *, const char *, int, int);
 
 extern void BAlert_delete (void *);
 
@@ -684,6 +699,7 @@ extern const char *be_find_setting (const char *);
 extern haiku_font_family_or_style *be_list_font_families (size_t *);
 extern void be_font_style_to_flags (char *, struct haiku_font_pattern *);
 extern void *be_open_font_at_index (int, int, float);
+extern void be_set_font_antialiasing (void *, bool);
 extern int be_get_ui_color (const char *, uint32_t *);
 
 extern void BMessage_delete (void *);
@@ -697,7 +713,8 @@ extern bool be_replay_menu_bar_event (void *, struct 
haiku_menu_bar_click_event
 extern bool be_select_font (void (*) (void), bool (*) (void),
                            haiku_font_family_or_style *,
                            haiku_font_family_or_style *,
-                           int *, bool, int, int, int);
+                           int *, bool, int, int, int,
+                           bool, bool *);
 
 extern int be_find_font_indices (struct haiku_font_pattern *, int *, int *);
 extern status_t be_roster_launch (const char *, const char *, char **,
@@ -710,6 +727,8 @@ extern void be_set_window_fullscreen_mode (void *, enum 
haiku_fullscreen_mode);
 extern void be_lock_window (void *);
 extern void be_unlock_window (void *);
 extern bool be_get_explicit_workarea (int *, int *, int *, int *);
+extern void be_clear_grab_view (void);
+extern void be_set_use_frame_synchronization (void *, bool);
 #ifdef __cplusplus
 }
 
diff --git a/src/haikufns.c b/src/haikufns.c
index b79443203f..aaa4e86622 100644
--- a/src/haikufns.c
+++ b/src/haikufns.c
@@ -949,6 +949,10 @@ haiku_create_frame (Lisp_Object parms)
          || !FRAME_LIVE_P (XFRAME (KVAR (kb, Vdefault_minibuffer_frame)))))
     kset_default_minibuffer_frame (kb, frame);
 
+  /* Set whether or not frame synchronization is enabled.  */
+  gui_default_parameter (f, parms, Quse_frame_synchronization, Qt,
+                        NULL, NULL, RES_TYPE_BOOLEAN);
+
   gui_default_parameter (f, parms, Qz_group, Qnil,
                         NULL, NULL, RES_TYPE_SYMBOL);
 
@@ -1290,16 +1294,17 @@ compute_tip_xy (struct frame *f,
 static Lisp_Object
 haiku_hide_tip (bool delete)
 {
+  Lisp_Object it, frame;
+
   if (!NILP (tip_timer))
     {
       call1 (Qcancel_timer, tip_timer);
       tip_timer = Qnil;
     }
 
-  Lisp_Object it, frame;
   FOR_EACH_FRAME (it, frame)
-    if (FRAME_WINDOW_P (XFRAME (frame)) &&
-       FRAME_HAIKU_VIEW (XFRAME (frame)))
+    if (FRAME_WINDOW_P (XFRAME (frame))
+       && FRAME_HAIKU_VIEW (XFRAME (frame)))
       BView_set_tooltip (FRAME_HAIKU_VIEW (XFRAME (frame)), NULL);
 
   if (NILP (tip_frame)
@@ -1500,9 +1505,9 @@ haiku_set_background_color (struct frame *f, Lisp_Object 
arg, Lisp_Object oldval
 
   if (FRAME_HAIKU_VIEW (f))
     {
-      BView_draw_lock (FRAME_HAIKU_VIEW (f), false, 0, 0, 0, 0);
-      BView_SetViewColor (FRAME_HAIKU_VIEW (f), background);
-      BView_draw_unlock (FRAME_HAIKU_VIEW (f));
+     BView_draw_lock (FRAME_HAIKU_DRAWABLE (f), false, 0, 0, 0, 0);
+      BView_SetViewColor (FRAME_HAIKU_DRAWABLE (f), background);
+      BView_draw_unlock (FRAME_HAIKU_DRAWABLE (f));
 
       FRAME_OUTPUT_DATA (f)->cursor_fg = background;
       update_face_from_frame_parameter (f, Qbackground_color, arg);
@@ -2114,6 +2119,13 @@ haiku_set_mouse_color (struct frame *f, Lisp_Object arg, 
Lisp_Object oldval)
   update_face_from_frame_parameter (f, Qmouse_color, arg);
 }
 
+static void
+haiku_set_use_frame_synchronization (struct frame *f, Lisp_Object arg,
+                                    Lisp_Object oldval)
+{
+  be_set_use_frame_synchronization (FRAME_HAIKU_VIEW (f), !NILP (arg));
+}
+
 
 
 DEFUN ("haiku-set-mouse-absolute-pixel-position",
@@ -2329,6 +2341,10 @@ DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
   int old_windows_or_buffers_changed = windows_or_buffers_changed;
   specpdl_ref count = SPECPDL_INDEX ();
   Lisp_Object window, size, tip_buf;
+  bool displayed;
+#ifdef ENABLE_CHECKING
+  struct glyph_row *row, *end;
+#endif
   AUTO_STRING (tip, " *tip*");
 
   specbind (Qinhibit_redisplay, Qt);
@@ -2391,8 +2407,8 @@ DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
                      reliable way to get it.  */
       compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
       BView_convert_from_screen (FRAME_HAIKU_VIEW (f), &root_x, &root_y);
-      BView_set_and_show_sticky_tooltip (FRAME_HAIKU_VIEW (f), SSDATA (string),
-                                        root_x, root_y);
+      be_show_sticky_tooltip (FRAME_HAIKU_VIEW (f), SSDATA (string),
+                             root_x, root_y);
       unblock_input ();
       goto start_timer;
     }
@@ -2400,7 +2416,6 @@ DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
   if (!NILP (tip_frame) && FRAME_LIVE_P (XFRAME (tip_frame)))
     {
       if (FRAME_VISIBLE_P (XFRAME (tip_frame))
-         && EQ (frame, tip_last_frame)
          && !NILP (Fequal_including_properties (tip_last_string, string))
          && !NILP (Fequal (tip_last_parms, parms)))
        {
@@ -2557,7 +2572,26 @@ DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
   clear_glyph_matrix (w->desired_matrix);
   clear_glyph_matrix (w->current_matrix);
   SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
-  try_window (window, pos, TRY_WINDOW_IGNORE_FONTS_CHANGE);
+  displayed = try_window (window, pos, TRY_WINDOW_IGNORE_FONTS_CHANGE);
+
+  if (!displayed && NILP (Vx_max_tooltip_size))
+    {
+#ifdef ENABLE_CHECKING
+      row = w->desired_matrix->rows;
+      end = w->desired_matrix->rows + w->desired_matrix->nrows;
+
+      while (row < end)
+       {
+         if (!row->displays_text_p
+             || row->ends_at_zv_p)
+           break;
+         ++row;
+       }
+
+      eassert (row < end && row->ends_at_zv_p);
+#endif
+    }
+
   /* Calculate size of tooltip window.  */
   size = Fwindow_text_pixel_size (window, Qnil, Qnil, Qnil,
                                  make_fixnum (w->pixel_height), Qnil,
@@ -3105,6 +3139,7 @@ frame_parm_handler haiku_frame_parm_handlers[] =
     haiku_set_override_redirect,
     gui_set_no_special_glyphs,
     gui_set_alpha_background,
+    haiku_set_use_frame_synchronization,
   };
 
 void
@@ -3178,7 +3213,7 @@ syms_of_haikufns (void)
 
   DEFVAR_LISP ("x-max-tooltip-size", Vx_max_tooltip_size,
               doc: /* SKIP: real doc in xfns.c.  */);
-  Vx_max_tooltip_size = Fcons (make_fixnum (80), make_fixnum (40));
+  Vx_max_tooltip_size = Qnil;
 
   DEFVAR_LISP ("x-cursor-fore-pixel", Vx_cursor_fore_pixel,
               doc: /* SKIP: real doc in xfns.c.  */);
diff --git a/src/haikufont.c b/src/haikufont.c
index 54f11c6e41..3e7f6f86dc 100644
--- a/src/haikufont.c
+++ b/src/haikufont.c
@@ -381,54 +381,67 @@ haikufont_maybe_handle_special_family (Lisp_Object family,
 static Lisp_Object
 haikufont_pattern_to_entity (struct haiku_font_pattern *ptn)
 {
-  Lisp_Object ent;
+  Lisp_Object entity, extras;
+
+  entity = font_make_entity ();
+  extras = Qnil;
+
+  ASET (entity, FONT_TYPE_INDEX, Qhaiku);
+  ASET (entity, FONT_FOUNDRY_INDEX, Qhaiku);
+  ASET (entity, FONT_FAMILY_INDEX, Qdefault);
+  ASET (entity, FONT_ADSTYLE_INDEX, Qnil);
+  ASET (entity, FONT_REGISTRY_INDEX, Qiso10646_1);
+  ASET (entity, FONT_SIZE_INDEX, make_fixnum (0));
+  ASET (entity, FONT_AVGWIDTH_INDEX, make_fixnum (0));
+  ASET (entity, FONT_SPACING_INDEX, make_fixnum (FONT_SPACING_MONO));
+
+  /* FONT_EXTRA_INDEX in a font entity can contain a cons of two
+     numbers (STYLE . IDX) under the key :indices that tell Emacs how
+     to open a font.  */
+  if (ptn->specified & FSPEC_INDICES)
+    extras = Fcons (Fcons (QCindices,
+                          Fcons (make_fixnum (ptn->family_index),
+                                 make_fixnum (ptn->style_index))),
+                   extras);
 
-  ent = font_make_entity ();
-  ASET (ent, FONT_TYPE_INDEX, Qhaiku);
-  ASET (ent, FONT_FOUNDRY_INDEX, Qhaiku);
-  ASET (ent, FONT_FAMILY_INDEX, Qdefault);
-  ASET (ent, FONT_ADSTYLE_INDEX, Qnil);
-  ASET (ent, FONT_REGISTRY_INDEX, Qiso10646_1);
-  ASET (ent, FONT_SIZE_INDEX, make_fixnum (0));
-  ASET (ent, FONT_AVGWIDTH_INDEX, make_fixnum (0));
-  ASET (ent, FONT_SPACING_INDEX, make_fixnum (FONT_SPACING_MONO));
+  if (ptn->specified & FSPEC_ANTIALIAS)
+    extras = Fcons (Fcons (QCantialias,
+                          ptn->use_antialiasing ? Qt : Qnil),
+                   extras);
 
-  /* FONT_EXTRA_INDEX in a font entity can be a cons of two numbers
-     (STYLE . IDX) that tell Emacs how to open a font.  */
-  if (ptn->specified & FSPEC_INDICES)
-    ASET (ent, FONT_EXTRA_INDEX,
-         Fcons (make_fixnum (ptn->family_index),
-                make_fixnum (ptn->style_index)));
+  ASET (entity, FONT_EXTRA_INDEX, extras);
 
-  FONT_SET_STYLE (ent, FONT_WIDTH_INDEX, Qnormal);
-  FONT_SET_STYLE (ent, FONT_WEIGHT_INDEX, Qnormal);
-  FONT_SET_STYLE (ent, FONT_SLANT_INDEX, Qnormal);
+  FONT_SET_STYLE (entity, FONT_WIDTH_INDEX, Qnormal);
+  FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX, Qnormal);
+  FONT_SET_STYLE (entity, FONT_SLANT_INDEX, Qnormal);
 
   if (ptn->specified & FSPEC_FAMILY)
-    ASET (ent, FONT_FAMILY_INDEX, intern (ptn->family));
+    ASET (entity, FONT_FAMILY_INDEX, intern (ptn->family));
   else
-    ASET (ent, FONT_FAMILY_INDEX, Qdefault);
+    ASET (entity, FONT_FAMILY_INDEX, Qdefault);
 
   if (ptn->specified & FSPEC_STYLE)
-    ASET (ent, FONT_ADSTYLE_INDEX, intern (ptn->style));
+    ASET (entity, FONT_ADSTYLE_INDEX, intern (ptn->style));
   else
     {
       if (ptn->specified & FSPEC_WEIGHT)
-       FONT_SET_STYLE (ent, FONT_WEIGHT_INDEX,
+       FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX,
                        haikufont_weight_to_lisp (ptn->weight));
       if (ptn->specified & FSPEC_SLANT)
-       FONT_SET_STYLE (ent, FONT_SLANT_INDEX,
+       FONT_SET_STYLE (entity, FONT_SLANT_INDEX,
                        haikufont_slant_to_lisp (ptn->slant));
       if (ptn->specified & FSPEC_WIDTH)
-       FONT_SET_STYLE (ent, FONT_WIDTH_INDEX,
+       FONT_SET_STYLE (entity, FONT_WIDTH_INDEX,
                        haikufont_width_to_lisp (ptn->width));
     }
 
   if (ptn->specified & FSPEC_SPACING)
-    ASET (ent, FONT_SPACING_INDEX,
-         make_fixnum (ptn->mono_spacing_p ?
-                      FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL));
-  return ent;
+    ASET (entity, FONT_SPACING_INDEX,
+         make_fixnum (ptn->mono_spacing_p
+                      ? FONT_SPACING_MONO
+                      : FONT_SPACING_PROPORTIONAL));
+
+  return entity;
 }
 
 static void
@@ -479,6 +492,14 @@ haikufont_pattern_from_object (struct haiku_font_pattern 
*pattern,
       pattern->specified |= FSPEC_WIDTH;
       pattern->width = haikufont_lisp_to_width (val);
     }
+
+  val = assq_no_quit (QCantialias,
+                     AREF (font_object, FONT_EXTRA_INDEX));
+  if (CONSP (val))
+    {
+      pattern->specified |= FSPEC_ANTIALIAS;
+      pattern->use_antialiasing = !NILP (XCDR (val));
+    }
 }
 
 static void
@@ -613,6 +634,13 @@ haikufont_spec_or_entity_to_pattern (Lisp_Object ent, int 
list_p,
        }
     }
 
+  tem = assq_no_quit (QCantialias, AREF (ent, FONT_EXTRA_INDEX));
+  if (CONSP (tem))
+    {
+      ptn->specified |= FSPEC_ANTIALIAS;
+      ptn->use_antialiasing = !NILP (XCDR (tem));
+    }
+
   tem = AREF (ent, FONT_REGISTRY_INDEX);
   if (SYMBOLP (tem))
     haikufont_apply_registry (ptn, tem);
@@ -732,10 +760,10 @@ haikufont_open (struct frame *f, Lisp_Object font_entity, 
int x)
   struct haiku_font_pattern ptn;
   struct font *font;
   void *be_font;
-  Lisp_Object font_object, tem, extra;
-  int px_size, min_width, max_width,
-    avg_width, height, space_width, ascent,
-    descent, underline_pos, underline_thickness;
+  Lisp_Object font_object, tem, extra, indices, antialias;
+  int px_size, min_width, max_width;
+  int avg_width, height, space_width, ascent;
+  int descent, underline_pos, underline_thickness;
 
   if (x <= 0)
     {
@@ -746,15 +774,21 @@ haikufont_open (struct frame *f, Lisp_Object font_entity, 
int x)
 
   extra = AREF (font_entity, FONT_EXTRA_INDEX);
 
+  indices = assq_no_quit (QCindices, extra);
+  antialias = assq_no_quit (QCantialias, extra);
+
+  if (CONSP (indices))
+    indices = XCDR (indices);
+
   /* If the font's indices is already available, open the font using
      those instead.  */
 
-  if (CONSP (extra) && FIXNUMP (XCAR (extra))
-      && FIXNUMP (XCDR (extra)))
+  if (CONSP (indices) && FIXNUMP (XCAR (indices))
+      && FIXNUMP (XCDR (indices)))
     {
       block_input ();
-      be_font = be_open_font_at_index (XFIXNUM (XCAR (extra)),
-                                      XFIXNUM (XCDR (extra)), x);
+      be_font = be_open_font_at_index (XFIXNUM (XCAR (indices)),
+                                      XFIXNUM (XCDR (indices)), x);
       unblock_input ();
 
       if (!be_font)
@@ -778,13 +812,8 @@ haikufont_open (struct frame *f, Lisp_Object font_entity, 
int x)
 
   block_input ();
 
-  /* `font_make_object' tries to treat the extra data as an alist.
-     There is never any real data here, so clear that field.  */
-
-  ASET (font_entity, FONT_EXTRA_INDEX, Qnil);
   font_object = font_make_object (VECSIZE (struct haikufont_info),
                                  font_entity, x);
-  ASET (font_entity, FONT_EXTRA_INDEX, extra);
 
   ASET (font_object, FONT_TYPE_INDEX, Qhaiku);
   font_info = (struct haikufont_info *) XFONT_OBJECT (font_object);
@@ -799,6 +828,9 @@ haikufont_open (struct frame *f, Lisp_Object font_entity, 
int x)
   font_info->be_font = be_font;
   font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs);
 
+  if (CONSP (antialias))
+    be_set_font_antialiasing (be_font, !NILP (XCDR (antialias)));
+
   font->pixel_size = 0;
   font->driver = &haikufont_driver;
   font->encoding_charset = -1;
@@ -1149,6 +1181,24 @@ haikufont_list_family (struct frame *f)
   return list;
 }
 
+/* List of boolean properties in font names accepted by this font
+   driver.  */
+static const char *const haikufont_booleans[] =
+  {
+    ":antialias",
+    NULL,
+  };
+
+/* List of non-boolean properties.  Currently empty.  */
+static const char *const haikufont_non_booleans[1];
+
+static void
+haikufont_filter_properties (Lisp_Object font, Lisp_Object alist)
+{
+  font_filter_properties (font, alist, haikufont_booleans,
+                         haikufont_non_booleans);
+}
+
 struct font_driver const haikufont_driver =
   {
     .type = LISPSYM_INITIALLY (Qhaiku),
@@ -1163,7 +1213,8 @@ struct font_driver const haikufont_driver =
     .encode_char = haikufont_encode_char,
     .text_extents = haikufont_text_extents,
     .shape = haikufont_shape,
-    .list_family = haikufont_list_family
+    .list_family = haikufont_list_family,
+    .filter_properties = haikufont_filter_properties,
   };
 
 static bool
@@ -1189,6 +1240,7 @@ in the font selection dialog.  */)
   int rc, size, initial_family, initial_style, initial_size;
   struct haiku_font_pattern pattern;
   Lisp_Object lfamily, lweight, lslant, lwidth, ladstyle, lsize;
+  bool disable_antialiasing, initial_antialias;
 
   f = decode_window_system_frame (frame);
 
@@ -1198,6 +1250,7 @@ in the font selection dialog.  */)
   initial_style = -1;
   initial_family = -1;
   initial_size = -1;
+  initial_antialias = true;
 
   font = FRAME_FONT (f);
 
@@ -1211,6 +1264,11 @@ in the font selection dialog.  */)
       haikufont_done_with_query_pattern (&pattern);
 
       initial_size = font->pixel_size;
+
+      /* This field is safe to access even after
+        haikufont_done_with_query_pattern.  */
+      if (pattern.specified & FSPEC_ANTIALIAS)
+       initial_antialias = pattern.use_antialiasing;
     }
 
   popup_activated_p++;
@@ -1220,7 +1278,8 @@ in the font selection dialog.  */)
                       &family, &style, &size,
                       !NILP (exclude_proportional),
                       initial_family, initial_style,
-                      initial_size);
+                      initial_size, initial_antialias,
+                      &disable_antialiasing);
   request_sigio ();
   popup_activated_p--;
 
@@ -1237,15 +1296,27 @@ in the font selection dialog.  */)
   lwidth = (pattern.specified & FSPEC_WIDTH
            ? haikufont_width_to_lisp (pattern.width) : Qnil);
   ladstyle = (pattern.specified & FSPEC_STYLE
-            ? intern (pattern.style) : Qnil);
+             ? intern (pattern.style) : Qnil);
   lsize = (size >= 0 ? make_fixnum (size) : Qnil);
 
+  if (disable_antialiasing)
+    return CALLN (Ffont_spec, QCfamily, lfamily,
+                 QCweight, lweight, QCslant, lslant,
+                 QCwidth, lwidth, QCadstyle, ladstyle,
+                 QCsize, lsize, QCantialias, Qnil);
+
   return CALLN (Ffont_spec, QCfamily, lfamily,
                QCweight, lweight, QCslant, lslant,
                QCwidth, lwidth, QCadstyle, ladstyle,
                QCsize, lsize);
 }
 
+static void
+syms_of_haikufont_for_pdumper (void)
+{
+  register_font_driver (&haikufont_driver, NULL);
+}
+
 void
 syms_of_haikufont (void)
 {
@@ -1270,9 +1341,12 @@ syms_of_haikufont (void)
   DEFSYM (Qko, "ko");
   DEFSYM (Qjp, "jp");
 
+  DEFSYM (QCindices, ":indices");
+
 #ifdef USE_BE_CAIRO
   Fput (Qhaiku, Qfont_driver_superseded_by, Qftcr);
 #endif
+  pdumper_do_now_and_after_load (syms_of_haikufont_for_pdumper);
 
   font_cache = list (Qnil);
   staticpro (&font_cache);
diff --git a/src/haikumenu.c b/src/haikumenu.c
index 5729bed4a9..69bb56c124 100644
--- a/src/haikumenu.c
+++ b/src/haikumenu.c
@@ -422,14 +422,21 @@ haiku_menu_show (struct frame *f, int x, int y, int 
menuflags,
   BView_convert_to_screen (view, &x, &y);
   unblock_input ();
 
+  unrequest_sigio ();
   popup_activated_p++;
   menu_item_selection = BMenu_run (menu, x, y,  haiku_menu_show_help,
                                   block_input, unblock_input,
                                   haiku_process_pending_signals_for_menu, 
NULL);
   popup_activated_p--;
+  request_sigio ();
 
   FRAME_DISPLAY_INFO (f)->grabbed = 0;
 
+  /* Clear the grab view manually.  There is a race condition here if
+     the window thread receives a button press between here and the
+     end of BMenu_run.  */
+  be_clear_grab_view ();
+
   if (menu_item_selection)
     {
       prefix = entry = Qnil;
@@ -627,8 +634,6 @@ set_frame_menubar (struct frame *f, bool deep_p)
 
       /* If it has changed current-menubar from previous value,
         really recompute the menubar from the value.  */
-      if (! NILP (Vlucid_menu_bar_dirty_flag))
-       call0 (Qrecompute_lucid_menubar);
       safe_run_hooks (Qmenu_bar_update_hook);
       fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
 
diff --git a/src/haikuselect.c b/src/haikuselect.c
index 8a7b6f2e0b..7eb93a2754 100644
--- a/src/haikuselect.c
+++ b/src/haikuselect.c
@@ -24,6 +24,7 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #include "haikuselect.h"
 #include "haikuterm.h"
 #include "haiku_support.h"
+#include "keyboard.h"
 
 #include <stdlib.h>
 
@@ -36,6 +37,10 @@ struct frame *haiku_dnd_frame;
 /* Whether or not to move the tip frame during drag-and-drop.  */
 bool haiku_dnd_follow_tooltip;
 
+/* Whether or not the current DND frame is able to receive drops from
+   the current drag-and-drop operation.  */
+bool haiku_dnd_allow_same_frame;
+
 static void haiku_lisp_to_message (Lisp_Object, void *);
 
 static enum haiku_clipboard
@@ -53,6 +58,23 @@ haiku_get_clipboard_name (Lisp_Object clipboard)
   signal_error ("Invalid clipboard", clipboard);
 }
 
+DEFUN ("haiku-selection-timestamp", Fhaiku_selection_timestamp,
+       Shaiku_selection_timestamp, 1, 1, 0,
+       doc: /* Retrieve the "timestamp" of the clipboard CLIPBOARD.
+CLIPBOARD can either be the symbol `PRIMARY', `SECONDARY' or
+`CLIPBOARD'.  The timestamp is returned as a number describing the
+number of times programs have put data into CLIPBOARD.  */)
+  (Lisp_Object clipboard)
+{
+  enum haiku_clipboard clipboard_name;
+  int64 timestamp;
+
+  clipboard_name = haiku_get_clipboard_name (clipboard);
+  timestamp = be_get_clipboard_count (clipboard_name);
+
+  return INT_TO_INTEGER (timestamp);
+}
+
 DEFUN ("haiku-selection-data", Fhaiku_selection_data, Shaiku_selection_data,
        2, 2, 0,
        doc: /* Retrieve content typed as NAME from the clipboard
@@ -441,10 +463,10 @@ haiku_lisp_to_message (Lisp_Object obj, void *message)
   int rc;
   specpdl_ref ref;
 
-  CHECK_LIST (obj);
-  for (tem = obj; CONSP (tem); tem = XCDR (tem))
+  tem = obj;
+
+  FOR_EACH_TAIL (tem)
     {
-      maybe_quit ();
       t1 = XCAR (tem);
       CHECK_CONS (t1);
 
@@ -490,9 +512,9 @@ haiku_lisp_to_message (Lisp_Object obj, void *message)
        signal_error ("Unknown data type", type_sym);
 
       CHECK_LIST (t1);
-      for (t2 = XCDR (t1); CONSP (t2); t2 = XCDR (t2))
+      t2 = XCDR (t1);
+      FOR_EACH_TAIL (t2)
        {
-         maybe_quit ();
          data = XCAR (t2);
 
          if (FIXNUMP (type_sym) || BIGNUMP (type_sym))
@@ -515,7 +537,7 @@ haiku_lisp_to_message (Lisp_Object obj, void *message)
              unblock_input ();
 
              if (rc)
-               signal_error ("Invalid message", msg_data);
+               signal_error ("Invalid message", data);
              unbind_to (ref, Qnil);
              break;
 
@@ -812,6 +834,8 @@ currently being displayed to move along with the mouse 
pointer.  */)
 
   haiku_dnd_frame = f;
   haiku_dnd_follow_tooltip = !NILP (follow_tooltip);
+  haiku_dnd_allow_same_frame = !NILP (allow_same_frame);
+
   be_message = be_create_simple_message ();
 
   record_unwind_protect_ptr (haiku_unwind_drag_message, be_message);
@@ -1012,29 +1036,138 @@ haiku_note_drag_motion (void)
 
   internal_catch_all (haiku_note_drag_motion_1, NULL,
                      haiku_note_drag_motion_2);
+
+  /* Redisplay this way to preserve the echo area.  Otherwise, the
+     contents will abruptly disappear when the mouse moves over a
+     frame.  */
+  redisplay_preserve_echo_area (34);
+}
+
+void
+haiku_note_drag_wheel (struct input_event *ie)
+{
+  bool horizontal, up;
+
+  up = false;
+  horizontal = false;
+
+  if (ie->modifiers & up_modifier)
+    up = true;
+
+  if (ie->kind == HORIZ_WHEEL_EVENT)
+    horizontal = true;
+
+  ie->kind = NO_EVENT;
+
+  if (!NILP (Vhaiku_drag_wheel_function)
+      && (haiku_dnd_allow_same_frame
+         || XFRAME (ie->frame_or_window) != haiku_dnd_frame))
+    safe_call (7, Vhaiku_drag_wheel_function, ie->frame_or_window,
+              ie->x, ie->y, horizontal ? Qt : Qnil, up ? Qt : Qnil,
+              make_int (ie->modifiers));
+
+  redisplay_preserve_echo_area (35);
+}
+
+void
+init_haiku_select (void)
+{
+  be_clipboard_init ();
+}
+
+void
+haiku_handle_selection_clear (struct input_event *ie)
+{
+  enum haiku_clipboard id;
+
+  id = haiku_get_clipboard_name (ie->arg);
+
+  if (be_selection_outdated_p (id, ie->timestamp))
+    return;
+
+  CALLN (Frun_hook_with_args,
+        Qhaiku_lost_selection_functions, ie->arg);
+
+  /* This is required for redisplay to happen if something changed the
+     display inside the selection loss functions.  */
+  redisplay_preserve_echo_area (20);
+}
+
+void
+haiku_selection_disowned (enum haiku_clipboard id, int64 count)
+{
+  struct input_event ie;
+
+  EVENT_INIT (ie);
+  ie.kind = SELECTION_CLEAR_EVENT;
+
+  switch (id)
+    {
+    case CLIPBOARD_CLIPBOARD:
+      ie.arg = QCLIPBOARD;
+      break;
+
+    case CLIPBOARD_PRIMARY:
+      ie.arg = QPRIMARY;
+      break;
+
+    case CLIPBOARD_SECONDARY:
+      ie.arg = QSECONDARY;
+      break;
+    }
+
+  ie.timestamp = count;
+  kbd_buffer_store_event (&ie);
+}
+
+void
+haiku_start_watching_selections (void)
+{
+  be_start_watching_selection (CLIPBOARD_CLIPBOARD);
+  be_start_watching_selection (CLIPBOARD_PRIMARY);
+  be_start_watching_selection (CLIPBOARD_SECONDARY);
 }
 
 void
 syms_of_haikuselect (void)
 {
   DEFVAR_BOOL ("haiku-signal-invalid-refs", haiku_signal_invalid_refs,
-     doc: /* If nil, silently ignore invalid file names in system messages.
+    doc: /* If nil, silently ignore invalid file names in system messages.
 Otherwise, an error will be signalled if adding a file reference to a
 system message failed.  */);
   haiku_signal_invalid_refs = true;
 
   DEFVAR_LISP ("haiku-drag-track-function", Vhaiku_drag_track_function,
-     doc: /* If non-nil, a function to call upon mouse movement while dragging 
a message.
+    doc: /* If non-nil, a function to call upon mouse movement while dragging 
a message.
 The function is called without any arguments.  `mouse-position' can be
 used to retrieve the current position of the mouse.  */);
   Vhaiku_drag_track_function = Qnil;
 
+  DEFVAR_LISP ("haiku-lost-selection-functions", 
Vhaiku_lost_selection_functions,
+    doc: /* A list of functions to be called when Emacs loses an X selection.
+These are only called if a connection to the Haiku display was opened.  */);
+  Vhaiku_lost_selection_functions = Qnil;
+
+  DEFVAR_LISP ("haiku-drag-wheel-function", Vhaiku_drag_wheel_function,
+    doc: /* Function called upon wheel movement while dragging a message.
+If non-nil, it is called with 6 arguments when the mouse wheel moves
+while a drag-and-drop operation is in progress: the frame where the
+mouse moved, the frame-relative X and Y positions where the mouse
+moved, whether or not the wheel movement was horizontal, whether or
+not the wheel moved up (or left, if the movement was horizontal), and
+keyboard modifiers currently held down.  */);
+  Vhaiku_drag_wheel_function = Qnil;
+
   DEFSYM (QSECONDARY, "SECONDARY");
   DEFSYM (QCLIPBOARD, "CLIPBOARD");
   DEFSYM (QSTRING, "STRING");
   DEFSYM (QUTF8_STRING, "UTF8_STRING");
   DEFSYM (Qforeign_selection, "foreign-selection");
   DEFSYM (QTARGETS, "TARGETS");
+
+  DEFSYM (Qhaiku_lost_selection_functions,
+         "haiku-lost-selection-functions");
+
   DEFSYM (Qmessage, "message");
   DEFSYM (Qstring, "string");
   DEFSYM (Qref, "ref");
@@ -1053,6 +1186,7 @@ used to retrieve the current position of the mouse.  */);
   DEFSYM (Qalready_running, "already-running");
 
   defsubr (&Shaiku_selection_data);
+  defsubr (&Shaiku_selection_timestamp);
   defsubr (&Shaiku_selection_put);
   defsubr (&Shaiku_selection_owner_p);
   defsubr (&Shaiku_drag_message);
diff --git a/src/haikuselect.h b/src/haikuselect.h
index e9a2f2dd77..42e9c93f7e 100644
--- a/src/haikuselect.h
+++ b/src/haikuselect.h
@@ -37,15 +37,15 @@ enum haiku_clipboard
 #ifdef __cplusplus
 extern "C"
 {
-/* Also declared in haikuterm.h for use in emacs.c.  */
-extern void init_haiku_select (void);
 #endif
-/* Whether or not the selection was recently changed.  */
+/* Defined in haikuselect.c.  */
+extern void haiku_selection_disowned (enum haiku_clipboard, int64);
 
+/* Defined in haiku_select.cc.  */
+extern void be_clipboard_init (void);
 extern char *be_find_clipboard_data (enum haiku_clipboard, const char *, 
ssize_t *);
 extern void be_set_clipboard_data (enum haiku_clipboard, const char *, const 
char *,
                                   ssize_t, bool);
-extern void be_get_clipboard_targets (enum haiku_clipboard, char **, int);
 extern bool be_clipboard_owner_p (enum haiku_clipboard);
 extern void be_update_clipboard_count (enum haiku_clipboard);
 
@@ -64,6 +64,11 @@ extern int be_add_point_data (void *, const char *, float, 
float);
 extern int be_add_message_message (void *, const char *, void *);
 extern int be_lock_clipboard_message (enum haiku_clipboard, void **, bool);
 extern void be_unlock_clipboard (enum haiku_clipboard, bool);
+extern void be_handle_clipboard_changed_message (void);
+extern void be_start_watching_selection (enum haiku_clipboard);
+extern bool be_selection_outdated_p (enum haiku_clipboard, int64);
+extern int64 be_get_clipboard_count (enum haiku_clipboard);
+
 #ifdef __cplusplus
 };
 #endif
diff --git a/src/haikuterm.c b/src/haikuterm.c
index 365b23cd92..df1c39974f 100644
--- a/src/haikuterm.c
+++ b/src/haikuterm.c
@@ -32,6 +32,7 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #include "haiku_support.h"
 #include "thread.h"
 #include "window.h"
+#include "haikuselect.h"
 
 #include <math.h>
 #include <stdlib.h>
@@ -162,15 +163,15 @@ haiku_clip_to_string (struct glyph_string *s)
       /* If n[FOO].width is 0, it means to not draw at all, so set the
         clipping to some impossible value.  */
       if (r[0].width <= 0)
-       BView_ClipToRect (FRAME_HAIKU_VIEW (s->f),
+       BView_ClipToRect (FRAME_HAIKU_DRAWABLE (s->f),
                          FRAME_PIXEL_WIDTH (s->f),
                          FRAME_PIXEL_HEIGHT (s->f),
                          10, 10);
       else
        {
-         BView_ClipToRect (FRAME_HAIKU_VIEW (s->f), r[0].x,
+         BView_ClipToRect (FRAME_HAIKU_DRAWABLE (s->f), r[0].x,
                            r[0].y, r[0].width, r[0].height);
-         BView_invalidate_region (FRAME_HAIKU_VIEW (s->f), r[0].x,
+         BView_invalidate_region (FRAME_HAIKU_DRAWABLE (s->f), r[0].x,
                                   r[0].y, r[0].width, r[0].height);
        }
     }
@@ -180,15 +181,15 @@ haiku_clip_to_string (struct glyph_string *s)
       /* If n[FOO].width is 0, it means to not draw at all, so set the
         clipping to some impossible value.  */
       if (r[1].width <= 0)
-       BView_ClipToRect (FRAME_HAIKU_VIEW (s->f),
+       BView_ClipToRect (FRAME_HAIKU_DRAWABLE (s->f),
                          FRAME_PIXEL_WIDTH (s->f),
                          FRAME_PIXEL_HEIGHT (s->f),
                          10, 10);
       else
        {
-         BView_ClipToRect (FRAME_HAIKU_VIEW (s->f), r[1].x, r[1].y,
+         BView_ClipToRect (FRAME_HAIKU_DRAWABLE (s->f), r[1].x, r[1].y,
                            r[1].width, r[1].height);
-         BView_invalidate_region (FRAME_HAIKU_VIEW (s->f), r[1].x,
+         BView_invalidate_region (FRAME_HAIKU_DRAWABLE (s->f), r[1].x,
                                   r[1].y, r[1].width, r[1].height);
        }
     }
@@ -197,9 +198,9 @@ haiku_clip_to_string (struct glyph_string *s)
 static void
 haiku_clip_to_string_exactly (struct glyph_string *s, struct glyph_string *dst)
 {
-  BView_ClipToRect (FRAME_HAIKU_VIEW (s->f), s->x, s->y,
+  BView_ClipToRect (FRAME_HAIKU_DRAWABLE (s->f), s->x, s->y,
                    s->width, s->height);
-  BView_invalidate_region (FRAME_HAIKU_VIEW (s->f), s->x,
+  BView_invalidate_region (FRAME_HAIKU_DRAWABLE (s->f), s->x,
                           s->y, s->width, s->height);
 }
 
@@ -245,7 +246,7 @@ static void
 haiku_clear_frame_area (struct frame *f, int x, int y,
                        int width, int height)
 {
-  void *vw = FRAME_HAIKU_VIEW (f);
+  void *vw = FRAME_HAIKU_DRAWABLE (f);
   block_input ();
   BView_draw_lock (vw, true, x, y, width, height);
   BView_StartClip (vw);
@@ -260,7 +261,7 @@ haiku_clear_frame_area (struct frame *f, int x, int y,
 static void
 haiku_clear_frame (struct frame *f)
 {
-  void *view = FRAME_HAIKU_VIEW (f);
+  void *view = FRAME_HAIKU_DRAWABLE (f);
 
   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
 
@@ -286,11 +287,16 @@ haiku_clear_frame (struct frame *f)
 static Lisp_Object
 haiku_new_font (struct frame *f, Lisp_Object font_object, int fontset)
 {
-  struct font *font = XFONT_OBJECT (font_object);
+  struct font *font;
+  int ascent, descent, unit;
+
+  font = XFONT_OBJECT (font_object);
+
   if (fontset < 0)
     fontset = fontset_from_font (font_object);
 
   FRAME_FONTSET (f) = fontset;
+
   if (FRAME_FONT (f) == font)
     return font_object;
 
@@ -298,12 +304,11 @@ haiku_new_font (struct frame *f, Lisp_Object font_object, 
int fontset)
   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
   FRAME_COLUMN_WIDTH (f) = font->average_width;
 
-  int ascent, descent;
   get_font_ascent_descent (font, &ascent, &descent);
   FRAME_LINE_HEIGHT (f) = ascent + descent;
   FRAME_TAB_BAR_HEIGHT (f) = FRAME_TAB_BAR_LINES (f) * FRAME_LINE_HEIGHT (f);
 
-  int unit = FRAME_COLUMN_WIDTH (f);
+  unit = FRAME_COLUMN_WIDTH (f);
   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
     FRAME_CONFIG_SCROLL_BAR_COLS (f)
       = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + unit - 1) / unit;
@@ -311,13 +316,10 @@ haiku_new_font (struct frame *f, Lisp_Object font_object, 
int fontset)
     FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + unit - 1) / unit;
 
   if (FRAME_HAIKU_WINDOW (f) && !FRAME_TOOLTIP_P (f))
-    {
-      adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
-                        FRAME_LINES (f) * FRAME_LINE_HEIGHT (f),
-                        3, false, Qfont);
+    adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
+                      FRAME_LINES (f) * FRAME_LINE_HEIGHT (f),
+                      3, false, Qfont);
 
-      haiku_clear_under_internal_border (f);
-    }
   return font_object;
 }
 
@@ -594,7 +596,7 @@ haiku_draw_box_rect (struct glyph_string *s, int left_x, 
int top_y,
                     int right_x, int bottom_y, int hwidth, int vwidth,
                     bool left_p, bool right_p, struct haiku_rect *clip_rect)
 {
-  void *view = FRAME_HAIKU_VIEW (s->f);
+  void *view = FRAME_HAIKU_DRAWABLE (s->f);
   struct face *face = s->face;
 
   BView_SetHighColor (view, face->box_color);
@@ -658,7 +660,7 @@ haiku_draw_relief_rect (struct glyph_string *s, int left_x, 
int top_y,
   uint32_t color_white, color_black;
   void *view;
 
-  view = FRAME_HAIKU_VIEW (s->f);
+  view = FRAME_HAIKU_DRAWABLE (s->f);
   haiku_calculate_relief_colors (s, &color_white, &color_black);
 
   BView_SetHighColor (view, raised_p ? color_white : color_black);
@@ -767,7 +769,7 @@ haiku_draw_underwave (struct glyph_string *s, int width, 
int x)
   dy = wave_height - 1;
   y = s->ybase - wave_height + 3;
   xmax = x + width;
-  view = FRAME_HAIKU_VIEW (s->f);
+  view = FRAME_HAIKU_DRAWABLE (s->f);
 
   BView_StartClip (view);
   haiku_clip_to_string (s);
@@ -809,7 +811,7 @@ haiku_draw_text_decoration (struct glyph_string *s, struct 
face *face,
   if (s->hl == DRAW_CURSOR)
     haiku_merge_cursor_foreground (s, &cursor_color, NULL);
 
-  void *view = FRAME_HAIKU_VIEW (s->f);
+  void *view = FRAME_HAIKU_DRAWABLE (s->f);
 
   if (face->underline)
     {
@@ -1011,7 +1013,7 @@ static void
 haiku_draw_plain_background (struct glyph_string *s, struct face *face,
                             int x, int y, int width, int height)
 {
-  void *view = FRAME_HAIKU_VIEW (s->f);
+  void *view = FRAME_HAIKU_DRAWABLE (s->f);
   unsigned long cursor_color;
 
   if (s->hl == DRAW_CURSOR)
@@ -1073,7 +1075,7 @@ haiku_draw_stipple_background (struct glyph_string *s, 
struct face *face,
   unsigned long foreground, background;
   void *view;
 
-  view = FRAME_HAIKU_VIEW (s->f);
+  view = FRAME_HAIKU_DRAWABLE (s->f);
   rec = haiku_get_bitmap_rec (s->f, s->face->stipple);
 
   if (explicit_colors_p)
@@ -1171,7 +1173,7 @@ haiku_draw_glyph_string_foreground (struct glyph_string 
*s)
   else
     x = s->x;
 
-  void *view = FRAME_HAIKU_VIEW (s->f);
+  void *view = FRAME_HAIKU_DRAWABLE (s->f);
 
   if (s->font_not_found_p)
     {
@@ -1250,6 +1252,8 @@ haiku_draw_glyphless_glyph_string_foreground (struct 
glyph_string *s)
                   ? CHAR_TABLE_REF (Vglyphless_char_display,
                                     glyph->u.glyphless.ch)
                   : XCHAR_TABLE (Vglyphless_char_display)->extras[0]);
+             if (CONSP (acronym))
+               acronym = XCAR (acronym);
              if (STRINGP (acronym))
                str = SSDATA (acronym);
            }
@@ -1287,9 +1291,9 @@ haiku_draw_glyphless_glyph_string_foreground (struct 
glyph_string *s)
          else
            color = s->face->foreground;
 
-         BView_SetHighColor (FRAME_HAIKU_VIEW (s->f), color);
-         BView_SetPenSize (FRAME_HAIKU_VIEW (s->f), 1);
-         BView_StrokeRectangle (FRAME_HAIKU_VIEW (s->f),
+         BView_SetHighColor (FRAME_HAIKU_DRAWABLE (s->f), color);
+         BView_SetPenSize (FRAME_HAIKU_DRAWABLE (s->f), 1);
+         BView_StrokeRectangle (FRAME_HAIKU_DRAWABLE (s->f),
                                 x, s->ybase - glyph->ascent,
                                 glyph->pixel_width,
                                 glyph->ascent + glyph->descent);
@@ -1333,7 +1337,7 @@ haiku_draw_stretch_glyph_string (struct glyph_string *s)
       if (s->row->reversed_p)
        x -= width;
 
-      void *view = FRAME_HAIKU_VIEW (s->f);
+      void *view = FRAME_HAIKU_DRAWABLE (s->f);
       unsigned long cursor_color;
 
       haiku_merge_cursor_foreground (s, NULL, &cursor_color);
@@ -1399,14 +1403,14 @@ haiku_draw_stretch_glyph_string (struct glyph_string *s)
 static void
 haiku_start_clip (struct glyph_string *s)
 {
-  void *view = FRAME_HAIKU_VIEW (s->f);
+  void *view = FRAME_HAIKU_DRAWABLE (s->f);
   BView_StartClip (view);
 }
 
 static void
 haiku_end_clip (struct glyph_string *s)
 {
-  void *view = FRAME_HAIKU_VIEW (s->f);
+  void *view = FRAME_HAIKU_DRAWABLE (s->f);
   BView_EndClip (view);
 }
 
@@ -1426,7 +1430,7 @@ haiku_clip_to_row (struct window *w, struct glyph_row 
*row,
   width = window_width;
   height = row->visible_height;
 
-  BView_ClipToRect (FRAME_HAIKU_VIEW (f), x, y, width, height);
+  BView_ClipToRect (FRAME_HAIKU_DRAWABLE (f), x, y, width, height);
 }
 
 static void
@@ -1446,7 +1450,7 @@ haiku_draw_composite_glyph_string_foreground (struct 
glyph_string *s)
 {
   int i, j, x;
   struct font *font = s->font;
-  void *view = FRAME_HAIKU_VIEW (s->f);
+  void *view = FRAME_HAIKU_DRAWABLE (s->f);
   struct face *face = s->face;
 
   /* If first glyph of S has a left box line, start drawing the text
@@ -1628,6 +1632,14 @@ haiku_draw_image_relief (struct glyph_string *s)
                          top_p, bot_p, left_p, right_p, &r);
 }
 
+static void
+haiku_translate_transform (double (*transform)[3], double dx,
+                          double dy)
+{
+  transform[0][2] += dx;
+  transform[1][2] += dy;
+}
+
 static void
 haiku_draw_image_glyph_string (struct glyph_string *s)
 {
@@ -1639,6 +1651,7 @@ haiku_draw_image_glyph_string (struct glyph_string *s)
   struct haiku_rect nr;
   Emacs_Rectangle cr, ir, r;
   unsigned long background;
+  double image_transform[3][3];
 
   height = s->height;
   if (s->slice.y == 0)
@@ -1659,10 +1672,9 @@ haiku_draw_image_glyph_string (struct glyph_string *s)
   if (s->slice.y == 0)
     y += box_line_vwidth;
 
-  view = FRAME_HAIKU_VIEW (s->f);
+  view = FRAME_HAIKU_DRAWABLE (s->f);
   bitmap = s->img->pixmap;
 
-  /* TODO: implement stipples for images with masks.  */
   s->stippled_p = face->stipple != 0;
 
   if (s->hl == DRAW_CURSOR)
@@ -1670,8 +1682,8 @@ haiku_draw_image_glyph_string (struct glyph_string *s)
   else
     background = face->background;
 
-  BView_SetHighColor (view, background);
-  BView_FillRectangle (view, x, y, width, height);
+  haiku_draw_background_rect (s, face, x, y,
+                             width, height);
 
   if (bitmap)
     {
@@ -1700,34 +1712,66 @@ haiku_draw_image_glyph_string (struct glyph_string *s)
 
       if (gui_intersect_rectangles (&cr, &ir, &r))
        {
-         if (s->img->have_be_transforms_p)
+         memcpy (&image_transform, &s->img->transform,
+                 sizeof image_transform);
+
+         if (s->slice.x != x || s->slice.y != y
+             || s->slice.width != s->img->width
+             || s->slice.height != s->img->height)
            {
-             bitmap = BBitmap_transform_bitmap (bitmap,
-                                                s->img->mask,
-                                                face->background,
-                                                s->img->be_rotate,
-                                                s->img->width,
-                                                s->img->height);
-             mask = NULL;
+             BView_StartClip (view);
+             BView_ClipToRect (view, r.x, r.y, r.width, r.height);
            }
 
-         BView_DrawBitmap (view, bitmap,
-                           s->slice.x + r.x - x,
-                           s->slice.y + r.y - y,
-                           r.width, r.height,
-                           r.x, r.y, r.width, r.height);
-         if (mask)
+         haiku_translate_transform (image_transform,
+                                    x - s->slice.x,
+                                    y - s->slice.y);
+
+         be_apply_affine_transform (view,
+                                    image_transform[0][0],
+                                    image_transform[0][1],
+                                    image_transform[0][2],
+                                    image_transform[1][0],
+                                    image_transform[1][1],
+                                    image_transform[1][2]);
+
+         if (!s->stippled_p || !mask)
            {
-             BView_DrawMask (mask, view,
-                             s->slice.x + r.x - x,
-                             s->slice.y + r.y - y,
-                             r.width, r.height,
-                             r.x, r.y, r.width, r.height,
-                             face->background);
+             BView_DrawBitmap (view, bitmap, 0, 0,
+                               s->img->original_width,
+                               s->img->original_height,
+                               0, 0,
+                               s->img->original_width,
+                               s->img->original_height,
+                               s->img->use_bilinear_filtering);
+
+             if (mask)
+               be_draw_image_mask (mask, view, 0, 0,
+                                   s->img->original_width,
+                                   s->img->original_height,
+                                   0, 0,
+                                   s->img->original_width,
+                                   s->img->original_height,
+                                   background);
            }
-
-         if (s->img->have_be_transforms_p)
-           BBitmap_free (bitmap);
+         else
+           /* In order to make sure the stipple background remains
+              visible, use the mask for the alpha channel of BITMAP
+              and composite it onto the view instead.  */
+           be_draw_bitmap_with_mask (view, bitmap, mask, 0, 0,
+                                     s->img->original_width,
+                                     s->img->original_height,
+                                     0, 0,
+                                     s->img->original_width,
+                                     s->img->original_height,
+                                     s->img->use_bilinear_filtering);
+
+         if (s->slice.x != x || s->slice.y != y
+             || s->slice.width != s->img->width
+             || s->slice.height != s->img->height)
+           BView_EndClip (view);
+
+         be_apply_affine_transform (view, 1, 0, 0, 0, 1, 0);
        }
 
       if (!s->img->mask)
@@ -1761,7 +1805,7 @@ haiku_draw_image_glyph_string (struct glyph_string *s)
 static void
 haiku_draw_glyph_string (struct glyph_string *s)
 {
-  void *view = FRAME_HAIKU_VIEW (s->f);;
+  void *view = FRAME_HAIKU_DRAWABLE (s->f);;
   struct face *face = s->face;
 
   block_input ();
@@ -1921,10 +1965,8 @@ haiku_draw_glyph_string (struct glyph_string *s)
   /* Set the stipple_p flag indicating whether or not a stipple was
      drawn in s->row.  That is the case either when s is a stretch
      glyph string and s->face->stipple is not NULL, or when
-     s->face->stipple exists and s->hl is not DRAW_CURSOR, and s is
-     not an image.  This is different from X.  */
-  if (s->first_glyph->type != IMAGE_GLYPH
-      && s->face->stipple
+     s->face->stipple exists and s->hl is not DRAW_CURSOR.  */
+  if (s->face->stipple
       && (s->first_glyph->type == STRETCH_GLYPH
          || s->hl != DRAW_CURSOR))
     s->row->stipple_p = true;
@@ -1961,7 +2003,7 @@ haiku_after_update_window_line (struct window *w,
       block_input ();
       if (face)
        {
-         void *view = FRAME_HAIKU_VIEW (f);
+         void *view = FRAME_HAIKU_DRAWABLE (f);
          BView_draw_lock (view, false, 0, 0, 0, 0);
          BView_StartClip (view);
          BView_SetHighColor (view, (face->background_defaulted_p
@@ -1970,7 +2012,7 @@ haiku_after_update_window_line (struct window *w,
          BView_FillRectangle (view, 0, y, width, height);
          BView_FillRectangle (view, FRAME_PIXEL_WIDTH (f) - width,
                               y, width, height);
-         BView_invalidate_region (FRAME_HAIKU_VIEW (f),
+         BView_invalidate_region (FRAME_HAIKU_DRAWABLE (f),
                                   0, y, width, height);
          BView_invalidate_region (view, FRAME_PIXEL_WIDTH (f) - width,
                                   y, width, height);
@@ -2035,7 +2077,7 @@ haiku_draw_hollow_cursor (struct window *w, struct 
glyph_row *row)
   void *view;
 
   f = XFRAME (WINDOW_FRAME (w));
-  view = FRAME_HAIKU_VIEW (f);
+  view = FRAME_HAIKU_DRAWABLE (f);
 
   /* Get the glyph the cursor is on.  If we can't tell because
      the current matrix is invalid or such, give up.  */
@@ -2108,7 +2150,7 @@ haiku_draw_bar_cursor (struct window *w, struct glyph_row 
*row,
     }
   else
     {
-      view = FRAME_HAIKU_VIEW (f);
+      view = FRAME_HAIKU_DRAWABLE (f);
       face = FACE_FROM_ID (f, cursor_glyph->face_id);
 
       /* If the glyph's background equals the color we normally draw
@@ -2294,7 +2336,7 @@ haiku_draw_vertical_window_border (struct window *w,
   struct face *face;
 
   face = FACE_FROM_ID_OR_NULL (f, VERTICAL_BORDER_FACE_ID);
-  void *view = FRAME_HAIKU_VIEW (f);
+  void *view = FRAME_HAIKU_DRAWABLE (f);
   BView_draw_lock (view, true, x, y_0, 1, y_1);
   BView_StartClip (view);
   if (face)
@@ -2344,7 +2386,7 @@ haiku_draw_window_divider (struct window *w, int x0, int 
x1, int y0, int y1)
   unsigned long color_last = (face_last
                              ? face_last->foreground
                              : FRAME_FOREGROUND_PIXEL (f));
-  void *view = FRAME_HAIKU_VIEW (f);
+  void *view = FRAME_HAIKU_DRAWABLE (f);
 
   BView_draw_lock (view, true, x0, y0, x1 - x0 + 1, y1 - y0 + 1);
   BView_StartClip (view);
@@ -2514,7 +2556,7 @@ haiku_scroll_bar_create (struct window *w, int left, int 
top,
   void *view;
 
   f = XFRAME (WINDOW_FRAME (w));
-  view = FRAME_HAIKU_VIEW (f);
+  view = FRAME_HAIKU_DRAWABLE (f);
 
   block_input ();
   bar = ALLOCATE_PSEUDOVECTOR (struct scroll_bar, prev, PVEC_OTHER);
@@ -2564,7 +2606,7 @@ haiku_set_horizontal_scroll_bar (struct window *w, int 
portion, int whole, int p
   width = window_width;
   top = WINDOW_SCROLL_BAR_AREA_Y (w);
   height = WINDOW_CONFIG_SCROLL_BAR_HEIGHT (w);
-  view = FRAME_HAIKU_VIEW (WINDOW_XFRAME (w));
+  view = FRAME_HAIKU_DRAWABLE (WINDOW_XFRAME (w));
 
   block_input ();
 
@@ -2623,7 +2665,7 @@ haiku_set_vertical_scroll_bar (struct window *w, int 
portion, int whole, int pos
   left = WINDOW_SCROLL_BAR_AREA_X (w);
   width = WINDOW_SCROLL_BAR_AREA_WIDTH (w);
 
-  view = FRAME_HAIKU_VIEW (WINDOW_XFRAME (w));
+  view = FRAME_HAIKU_DRAWABLE (WINDOW_XFRAME (w));
 
   block_input ();
   if (NILP (w->vertical_scroll_bar))
@@ -2672,7 +2714,7 @@ haiku_draw_fringe_bitmap (struct window *w, struct 
glyph_row *row,
   uint32 col;
 
   f = XFRAME (WINDOW_FRAME (w));
-  view = FRAME_HAIKU_VIEW (f);
+  view = FRAME_HAIKU_DRAWABLE (f);
   face = p->face;
 
   block_input ();
@@ -2788,7 +2830,7 @@ static void
 haiku_scroll_run (struct window *w, struct run *run)
 {
   struct frame *f = XFRAME (w->frame);
-  void *view = FRAME_HAIKU_VIEW (f);
+  void *view = FRAME_HAIKU_DRAWABLE (f);
   int x, y, width, height, from_y, to_y, bottom_y;
   window_box (w, ANY_AREA, &x, &y, &width, &height);
 
@@ -3163,12 +3205,17 @@ haiku_read_socket (struct terminal *terminal, struct 
input_event *hold_quit)
                FRAME_PIXEL_HEIGHT (f) = height;
 
                haiku_clear_under_internal_border (f);
+
+               /* Flush the frame and flip buffers here.  It is
+                  necessary for tooltips displayed inside menus, as
+                  redisplay cannot happen.  */
+               haiku_flush (f);
                continue;
              }
 
-           BView_draw_lock (FRAME_HAIKU_VIEW (f), false, 0, 0, 0, 0);
-           BView_resize_to (FRAME_HAIKU_VIEW (f), width, height);
-           BView_draw_unlock (FRAME_HAIKU_VIEW (f));
+           BView_draw_lock (FRAME_HAIKU_DRAWABLE (f), false, 0, 0, 0, 0);
+           BView_resize_to (FRAME_HAIKU_DRAWABLE (f), width, height);
+           BView_draw_unlock (FRAME_HAIKU_DRAWABLE (f));
 
            if (width != FRAME_PIXEL_WIDTH (f)
                || height != FRAME_PIXEL_HEIGHT (f)
@@ -3320,6 +3367,7 @@ haiku_read_socket (struct terminal *terminal, struct 
input_event *hold_quit)
            if (b->just_exited_p)
              {
                Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
+
                if (f == hlinfo->mouse_face_mouse_frame)
                  {
                    /* If we move outside the frame, then we're
@@ -3330,6 +3378,9 @@ haiku_read_socket (struct terminal *terminal, struct 
input_event *hold_quit)
                    haiku_flush_dirty_back_buffer_on (f);
                  }
 
+               if (f == x_display_list->last_mouse_glyph_frame)
+                 x_display_list->last_mouse_glyph_frame = NULL;
+
                if (f->auto_lower && !popup_activated_p
                    /* Don't do this if the mouse entered a scroll bar.  */
                    && !BView_inside_scroll_bar (FRAME_HAIKU_VIEW (f),
@@ -3822,6 +3873,9 @@ haiku_read_socket (struct terminal *terminal, struct 
input_event *hold_quit)
                                   : down_modifier);
                py = 0.0f;
                px = 0.0f;
+
+               if (be_drag_and_drop_in_progress ())
+                 haiku_note_drag_wheel (&inev);
              }
 
            break;
@@ -3966,6 +4020,9 @@ haiku_read_socket (struct terminal *terminal, struct 
input_event *hold_quit)
            inev.timestamp = b->when / 1000;
            break;
          }
+       case CLIPBOARD_CHANGED_EVENT:
+         be_handle_clipboard_changed_message ();
+         break;
        case APP_QUIT_REQUESTED_EVENT:
          inev.kind = SAVE_SESSION_EVENT;
          inev.arg = Qt;
@@ -4071,7 +4128,7 @@ haiku_flash (struct frame *f)
   int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
   int flash_right = FRAME_PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f);
   int width = flash_right - flash_left;
-  void *view = FRAME_HAIKU_VIEW (f);
+  void *view = FRAME_HAIKU_DRAWABLE (f);
   object_wait_info info;
   bigtime_t wakeup;
 
@@ -4359,6 +4416,7 @@ haiku_term_init (void)
   else
     dpyinfo->default_name = build_string ("GNU Emacs");
 
+  haiku_start_watching_selections ();
   unblock_input ();
 
   return dpyinfo;
@@ -4398,7 +4456,8 @@ haiku_clear_under_internal_border (struct frame *f)
            ? lookup_basic_face (NULL, f, INTERNAL_BORDER_FACE_ID)
            : INTERNAL_BORDER_FACE_ID));
       struct face *face = FACE_FROM_ID_OR_NULL (f, face_id);
-      void *view = FRAME_HAIKU_VIEW (f);
+      void *view = FRAME_HAIKU_DRAWABLE (f);
+
       block_input ();
       BView_draw_lock (view, true, 0, 0, FRAME_PIXEL_WIDTH (f),
                       FRAME_PIXEL_HEIGHT (f));
@@ -4439,7 +4498,7 @@ haiku_scroll_bar_remove (struct scroll_bar *bar)
   struct frame *f;
 
   f = WINDOW_XFRAME (XWINDOW (bar->window));
-  view = FRAME_HAIKU_VIEW (f);
+  view = FRAME_HAIKU_DRAWABLE (f);
 
   block_input ();
   BView_forget_scroll_bar (view, bar->left, bar->top,
diff --git a/src/haikuterm.h b/src/haikuterm.h
index ea20289b5d..b603c0a482 100644
--- a/src/haikuterm.h
+++ b/src/haikuterm.h
@@ -275,7 +275,8 @@ struct scroll_bar
 #define MAKE_FRAME_DIRTY(f)            (FRAME_DIRTY_P (f) = 1)
 #define FRAME_OUTPUT_DATA(f)           ((f)->output_data.haiku)
 #define FRAME_HAIKU_WINDOW(f)          (FRAME_OUTPUT_DATA (f)->window)
-#define FRAME_HAIKU_VIEW(f)            ((MAKE_FRAME_DIRTY (f)), 
FRAME_OUTPUT_DATA (f)->view)
+#define FRAME_HAIKU_VIEW(f)            (FRAME_OUTPUT_DATA (f)->view)
+#define FRAME_HAIKU_DRAWABLE(f)                ((MAKE_FRAME_DIRTY (f)), 
FRAME_HAIKU_VIEW (f))
 #define FRAME_HAIKU_MENU_BAR(f)                (FRAME_OUTPUT_DATA (f)->menubar)
 #define FRAME_DISPLAY_INFO(f)          (FRAME_OUTPUT_DATA (f)->display_info)
 #define FRAME_FONT(f)                  (FRAME_OUTPUT_DATA (f)->font)
@@ -287,7 +288,7 @@ struct scroll_bar
 #ifdef USE_BE_CAIRO
 #define FRAME_CR_CONTEXT(f)                                    \
   (FRAME_HAIKU_VIEW (f)                                                \
-   ? EmacsView_cairo_context (FRAME_HAIKU_VIEW (f))            \
+   ? EmacsView_cairo_context (FRAME_HAIKU_DRAWABLE (f))                \
    : NULL)
 #endif
 
@@ -333,6 +334,7 @@ extern Lisp_Object haiku_popup_dialog (struct frame *, 
Lisp_Object, Lisp_Object)
 extern void haiku_activate_menubar (struct frame *);
 extern void haiku_wait_for_event (struct frame *, int);
 extern void haiku_note_drag_motion (void);
+extern void haiku_note_drag_wheel (struct input_event *);
 
 extern void initialize_frame_menubar (struct frame *);
 
@@ -357,4 +359,6 @@ extern void haiku_end_cr_clip (cairo_t *);
 
 extern void haiku_merge_cursor_foreground (struct glyph_string *, unsigned 
long *,
                                           unsigned long *);
+extern void haiku_handle_selection_clear (struct input_event *);
+extern void haiku_start_watching_selections (void);
 #endif /* _HAIKU_TERM_H_ */
diff --git a/src/image.c b/src/image.c
index 058c175570..f5004c2c4c 100644
--- a/src/image.c
+++ b/src/image.c
@@ -186,6 +186,10 @@ static void free_color_table (void);
 static unsigned long *colors_in_color_table (int *n);
 #endif
 
+#if defined (HAVE_WEBP) || defined (HAVE_GIF)
+static void anim_prune_animation_cache (Lisp_Object);
+#endif
+
 #ifdef USE_CAIRO
 
 static Emacs_Pix_Container
@@ -1071,9 +1075,16 @@ struct image_type
      libraries on Windows), or NULL if none.  */
   bool (*init) (void);
   /* An initializer for the init field.  */
-# define IMAGE_TYPE_INIT(f) f
-#else
-# define IMAGE_TYPE_INIT(f)
+#endif
+#if defined HAVE_RSVG || defined HAVE_PNG || defined HAVE_GIF || \
+  defined HAVE_TIFF || defined HAVE_JPEG || defined HAVE_XPM || \
+  defined HAVE_NS || defined HAVE_HAIKU || defined HAVE_PGTK || \
+  defined HAVE_WEBP
+# ifdef WINDOWSNT
+#  define IMAGE_TYPE_INIT(f) f
+# else
+#  define IMAGE_TYPE_INIT(f)
+# endif
 #endif
 };
 
@@ -2120,19 +2131,35 @@ clear_image_caches (Lisp_Object filter)
 }
 
 DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
-       0, 1, 0,
+       0, 2, 0,
        doc: /* Clear the image cache.
 FILTER nil or a frame means clear all images in the selected frame.
 FILTER t means clear the image caches of all frames.
 Anything else means clear only those images that refer to FILTER,
-which is then usually a filename.  */)
-  (Lisp_Object filter)
+which is then usually a filename.
+
+This function also clears the image animation cache.  If
+ANIMATION-CACHE is non-nil, only the image spec `eq' with
+ANIMATION-CACHE is removed, and other image cache entries are not
+evicted.  */)
+  (Lisp_Object filter, Lisp_Object animation_cache)
 {
+  if (!NILP (animation_cache))
+    {
+#if defined (HAVE_WEBP) || defined (HAVE_GIF)
+      anim_prune_animation_cache (XCDR (animation_cache));
+#endif
+      return Qnil;
+    }
+
   if (! (NILP (filter) || FRAMEP (filter)))
     clear_image_caches (filter);
   else
     clear_image_cache (decode_window_system_frame (filter), Qt);
 
+  /* Also clear the animation caches.  */
+  image_prune_animation_caches (true);
+
   return Qnil;
 }
 
@@ -2200,21 +2227,6 @@ image_frame_cache_size (struct frame *f)
   return total;
 }
 
-DEFUN ("image-cache-size", Fimage_cache_size, Simage_cache_size, 0, 0, 0,
-       doc: /* Return the size of the image cache.  */)
-  (void)
-{
-  Lisp_Object tail, frame;
-  size_t total = 0;
-
-  FOR_EACH_FRAME (tail, frame)
-    if (FRAME_WINDOW_P (XFRAME (frame)))
-      total += image_frame_cache_size (XFRAME (frame));
-
-  return make_int (total);
-}
-
-
 DEFUN ("image-flush", Fimage_flush, Simage_flush,
        1, 2, 0,
        doc: /* Flush the image with specification SPEC on frame FRAME.
@@ -2309,8 +2321,8 @@ postprocess_image (struct frame *f, struct image *img)
          tem = XCDR (conversion);
          if (CONSP (tem))
            image_edge_detection (f, img,
-                                  Fplist_get (tem, QCmatrix),
-                                  Fplist_get (tem, QCcolor_adjustment));
+                                  plist_get (tem, QCmatrix),
+                                  plist_get (tem, QCcolor_adjustment));
        }
     }
 }
@@ -2503,17 +2515,17 @@ compute_image_size (double width, double height,
    finally move the origin back to the top left of the image, which
    may now be a different corner.
 
-   Note that different GUI backends (X, Cairo, w32, NS) want the
-   transform matrix defined as transform from the original image to
-   the transformed image, while others want the matrix to describe the
-   transform of the space, which boils down to inverting the matrix.
+   Note that different GUI backends (X, Cairo, w32, NS, Haiku) want
+   the transform matrix defined as transform from the original image
+   to the transformed image, while others want the matrix to describe
+   the transform of the space, which boils down to inverting the
+   matrix.
 
    It's possible to pre-calculate the matrix multiplications and just
    generate one transform matrix that will do everything we need in a
    single step, but the maths for each element is much more complex
    and performing the steps separately makes for more readable code.  */
 
-#ifndef HAVE_HAIKU
 typedef double matrix3x3[3][3];
 
 static void
@@ -2528,7 +2540,6 @@ matrix3x3_mult (matrix3x3 a, matrix3x3 b, matrix3x3 
result)
        result[i][j] = sum;
       }
 }
-#endif /* not HAVE_HAIKU */
 
 static void
 compute_image_rotation (struct image *img, double *rotation)
@@ -2553,6 +2564,22 @@ compute_image_rotation (struct image *img, double 
*rotation)
 static void
 image_set_transform (struct frame *f, struct image *img)
 {
+  bool flip;
+
+#if defined HAVE_HAIKU
+  matrix3x3 identity = {
+    { 1, 0, 0 },
+    { 0, 1, 0 },
+    { 0, 0, 1 },
+  };
+
+  img->original_width = img->width;
+  img->original_height = img->height;
+  img->use_bilinear_filtering = false;
+
+  memcpy (&img->transform, identity, sizeof identity);
+#endif
+
 # if (defined HAVE_IMAGEMAGICK \
       && !defined DONT_CREATE_TRANSFORMED_IMAGEMAGICK_IMAGE)
   /* ImageMagick images already have the correct transform.  */
@@ -2587,8 +2614,10 @@ image_set_transform (struct frame *f, struct image *img)
   double rotation = 0.0;
   compute_image_rotation (img, &rotation);
 
-#ifndef HAVE_HAIKU
-# if defined USE_CAIRO || defined HAVE_XRENDER || defined HAVE_NS
+  /* Determine flipping.  */
+  flip = !NILP (image_spec_value (img->spec, QCflip, NULL));
+
+# if defined USE_CAIRO || defined HAVE_XRENDER || defined HAVE_NS || defined 
HAVE_HAIKU
   /* We want scale up operations to use a nearest neighbor filter to
      show real pixels instead of munging them, but scale down
      operations to use a blended filter, to avoid aliasing and the like.
@@ -2602,6 +2631,10 @@ image_set_transform (struct frame *f, struct image *img)
     smoothing = !NILP (s);
 # endif
 
+#ifdef HAVE_HAIKU
+  img->use_bilinear_filtering = smoothing;
+#endif
+
   /* Perform scale transformation.  */
 
   matrix3x3 matrix
@@ -2611,7 +2644,7 @@ image_set_transform (struct frame *f, struct image *img)
                  : img->width / (double) width),
        [1][1] = (!IEEE_FLOATING_POINT && height == 0 ? DBL_MAX
                  : img->height / (double) height),
-# elif defined HAVE_NTGUI || defined HAVE_NS
+# elif defined HAVE_NTGUI || defined HAVE_NS || defined HAVE_HAIKU
        [0][0] = (!IEEE_FLOATING_POINT && img->width == 0 ? DBL_MAX
                  : width / (double) img->width),
        [1][1] = (!IEEE_FLOATING_POINT && img->height == 0 ? DBL_MAX
@@ -2626,26 +2659,65 @@ image_set_transform (struct frame *f, struct image *img)
   /* Perform rotation transformation.  */
 
   int rotate_flag = -1;
-  if (rotation == 0)
+
+  /* Haiku needs this, since the transformation is done on the basis
+     of the view, and not the image.  */
+#ifdef HAVE_HAIKU
+  int extra_tx, extra_ty;
+
+  extra_tx = 0;
+  extra_ty = 0;
+#endif
+
+  if (rotation == 0 && !flip)
     rotate_flag = 0;
   else
     {
 # if (defined USE_CAIRO || defined HAVE_XRENDER \
-      || defined HAVE_NTGUI || defined HAVE_NS)
+      || defined HAVE_NTGUI || defined HAVE_NS \
+      || defined HAVE_HAIKU)
       int cos_r, sin_r;
-      if (rotation == 90)
+      if (rotation == 0)
+       {
+         /* FLIP is always true here.  As this will rotate by 0
+            degrees, it has no visible effect.  Applying only
+            translation matrix to the image would be sufficient for
+            horizontal flipping, but writing special handling for
+            this case would increase code complexity somewhat.  */
+         cos_r = 1;
+         sin_r = 0;
+         rotate_flag = 1;
+
+#ifdef HAVE_HAIKU
+         extra_tx = width;
+         extra_ty = 0;
+#endif
+       }
+      else if (rotation == 90)
        {
          width = img->height;
          height = img->width;
          cos_r = 0;
          sin_r = 1;
          rotate_flag = 1;
+
+#ifdef HAVE_HAIKU
+         if (!flip)
+           extra_ty = height;
+         extra_tx = 0;
+#endif
        }
       else if (rotation == 180)
        {
          cos_r = -1;
          sin_r = 0;
          rotate_flag = 1;
+
+#ifdef HAVE_HAIKU
+         if (!flip)
+           extra_tx = width;
+         extra_ty = height;
+#endif
        }
       else if (rotation == 270)
        {
@@ -2654,6 +2726,13 @@ image_set_transform (struct frame *f, struct image *img)
          cos_r = 0;
          sin_r = -1;
          rotate_flag = 1;
+
+#ifdef HAVE_HAIKU
+         extra_tx = width;
+
+         if (flip)
+           extra_ty = height;
+#endif
        }
 
       if (0 < rotate_flag)
@@ -2674,9 +2753,14 @@ image_set_transform (struct frame *f, struct image *img)
          matrix3x3 v;
          matrix3x3_mult (rot, u, v);
 
-         /* 3. Translate back.  */
+         /* 3. Translate back.  Flip horizontally if requested.  */
          t[2][0] = width * -.5;
          t[2][1] = height * -.5;
+         if (flip)
+           {
+             t[0][0] = -t[0][0];
+             t[2][0] = -t[2][0];
+           }
          matrix3x3_mult (t, v, matrix);
 #  else
          /* 1. Translate so (0, 0) is in the center of the image.  */
@@ -2694,9 +2778,10 @@ image_set_transform (struct frame *f, struct image *img)
          matrix3x3 v;
          matrix3x3_mult (u, rot, v);
 
-         /* 3. Translate back.  */
+         /* 3. Translate back.  Flip horizontally if requested.  */
          t[2][0] = width * .5;
          t[2][1] = height * .5;
+         if (flip) t[0][0] = -t[0][0];
          matrix3x3_mult (v, t, matrix);
 #  endif
          img->width = width;
@@ -2757,35 +2842,17 @@ image_set_transform (struct frame *f, struct image *img)
   img->xform.eM22 = matrix[1][1];
   img->xform.eDx  = matrix[2][0];
   img->xform.eDy  = matrix[2][1];
-# endif
-#else
-  if (rotation != 0 &&
-      rotation != 90 &&
-      rotation != 180 &&
-      rotation != 270 &&
-      rotation != 360)
-    {
-      image_error ("No native support for rotation by %g degrees",
-                  make_float (rotation));
-      return;
-    }
-
-  rotation = fmod (rotation, 360.0);
+# elif defined HAVE_HAIKU
+  /* Store the transform in the struct image for later.  */
+  memcpy (&img->transform, &matrix, sizeof matrix);
 
-  if (rotation == 90 || rotation == 270)
+  /* Also add the extra translations.   */
+  if (rotate_flag)
     {
-      int w = width;
-      width = height;
-      height = w;
+      img->transform[0][2] = extra_tx;
+      img->transform[1][2] = extra_ty;
     }
-
-  img->have_be_transforms_p = rotation != 0 || (img->width != width) || 
(img->height != height);
-  img->be_rotate = rotation;
-  img->be_scale_x = 1.0 / (img->width / (double) width);
-  img->be_scale_y = 1.0 / (img->height / (double) height);
-  img->width = width;
-  img->height = height;
-#endif /* not HAVE_HAIKU */
+#endif
 }
 
 #endif /* HAVE_IMAGEMAGICK || HAVE_NATIVE_TRANSFORMS */
@@ -2972,6 +3039,11 @@ struct anim_cache
   /* A function to call to free the handle.  */
   void (*destructor) (void *);
   int index, width, height, frames;
+  /* This is used to be able to say something about the cache size.
+     We don't actually know how much memory the different libraries
+     actually use here (since these cache structures are opaque), so
+     this is mostly just the size of the original image file.  */
+  int byte_size;
   struct timespec update_time;
   struct anim_cache *next;
 };
@@ -2988,12 +3060,16 @@ anim_create_cache (Lisp_Object spec)
   cache->index = -1;
   cache->next = NULL;
   cache->spec = spec;
+  cache->byte_size = 0;
   return cache;
 }
 
-/* Discard cached images that haven't been used for a minute. */
+/* Discard cached images that haven't been used for a minute.  If
+   CLEAR is t, remove all animation cache entries.  If CLEAR is
+   anything other than nil or t, only remove the entries that have a
+   spec `eq' to CLEAR.  */
 static void
-anim_prune_animation_cache (void)
+anim_prune_animation_cache (Lisp_Object clear)
 {
   struct anim_cache **pcache = &anim_cache;
   struct timespec old = timespec_sub (current_timespec (),
@@ -3002,9 +3078,9 @@ anim_prune_animation_cache (void)
   while (*pcache)
     {
       struct anim_cache *cache = *pcache;
-      if (timespec_cmp (old, cache->update_time) <= 0)
-       pcache = &cache->next;
-      else
+      if (EQ (clear, Qt)
+         || (EQ (clear, Qnil) && timespec_cmp (old, cache->update_time) > 0)
+         || EQ (clear, cache->spec))
        {
          if (cache->handle)
            cache->destructor (cache);
@@ -3013,6 +3089,8 @@ anim_prune_animation_cache (void)
          *pcache = cache->next;
          xfree (cache);
        }
+      else
+       pcache = &cache->next;
     }
 }
 
@@ -3022,7 +3100,7 @@ anim_get_animation_cache (Lisp_Object spec)
   struct anim_cache *cache;
   struct anim_cache **pcache = &anim_cache;
 
-  anim_prune_animation_cache ();
+  anim_prune_animation_cache (Qnil);
 
   while (1)
     {
@@ -3723,6 +3801,8 @@ enum xbm_keyword_index
   XBM_ALGORITHM,
   XBM_HEURISTIC_MASK,
   XBM_MASK,
+  XBM_DATA_WIDTH,
+  XBM_DATA_HEIGHT,
   XBM_LAST
 };
 
@@ -3744,7 +3824,9 @@ static const struct image_keyword xbm_format[XBM_LAST] =
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
   {":conversion",      IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":heuristic-mask",  IMAGE_DONT_CHECK_VALUE_TYPE,            0},
-  {":mask",            IMAGE_DONT_CHECK_VALUE_TYPE,            0}
+  {":mask",            IMAGE_DONT_CHECK_VALUE_TYPE,            0},
+  {":data-width",      IMAGE_POSITIVE_INTEGER_VALUE,           0},
+  {":data-height",     IMAGE_POSITIVE_INTEGER_VALUE,           0}
 };
 
 /* Tokens returned from xbm_scan.  */
@@ -3766,8 +3848,8 @@ enum xbm_token
    an entry `:file FILENAME' where FILENAME is a string.
 
    If the specification is for a bitmap loaded from memory it must
-   contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
-   WIDTH and HEIGHT are integers > 0.  DATA may be:
+   contain `:data-width WIDTH', `:data-height HEIGHT', and `:data DATA',
+   where WIDTH and HEIGHT are integers > 0.  DATA may be:
 
    1. a string large enough to hold the bitmap data, i.e. it must
    have a size >= (WIDTH + 7) / 8 * HEIGHT
@@ -3777,9 +3859,7 @@ enum xbm_token
    3. a vector of strings or bool-vectors, one for each line of the
    bitmap.
 
-   4. a string containing an in-memory XBM file.  WIDTH and HEIGHT
-   may not be specified in this case because they are defined in the
-   XBM file.
+   4. a string containing an in-memory XBM file.
 
    Both the file and data forms may contain the additional entries
    `:background COLOR' and `:foreground COLOR'.  If not present,
@@ -3799,13 +3879,13 @@ xbm_image_p (Lisp_Object object)
 
   if (kw[XBM_FILE].count)
     {
-      if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
+      if (kw[XBM_DATA].count)
        return 0;
     }
   else if (kw[XBM_DATA].count && xbm_file_p (kw[XBM_DATA].value))
     {
       /* In-memory XBM file.  */
-      if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_FILE].count)
+      if (kw[XBM_FILE].count)
        return 0;
     }
   else
@@ -3814,14 +3894,14 @@ xbm_image_p (Lisp_Object object)
       int width, height, stride;
 
       /* Entries for `:width', `:height' and `:data' must be present.  */
-      if (!kw[XBM_WIDTH].count
-         || !kw[XBM_HEIGHT].count
+      if (!kw[XBM_DATA_WIDTH].count
+         || !kw[XBM_DATA_HEIGHT].count
          || !kw[XBM_DATA].count)
        return 0;
 
       data = kw[XBM_DATA].value;
-      width = XFIXNAT (kw[XBM_WIDTH].value);
-      height = XFIXNAT (kw[XBM_HEIGHT].value);
+      width = XFIXNAT (kw[XBM_DATA_WIDTH].value);
+      height = XFIXNAT (kw[XBM_DATA_HEIGHT].value);
 
       if (!kw[XBM_STRIDE].count)
        stride = width;
@@ -4445,8 +4525,8 @@ xbm_load (struct frame *f, struct image *img)
       /* Get specified width, and height.  */
       if (!in_memory_file_p)
        {
-         img->width = XFIXNAT (fmt[XBM_WIDTH].value);
-         img->height = XFIXNAT (fmt[XBM_HEIGHT].value);
+         img->width = XFIXNAT (fmt[XBM_DATA_WIDTH].value);
+         img->height = XFIXNAT (fmt[XBM_DATA_HEIGHT].value);
          eassert (img->width > 0 && img->height > 0);
          if (!check_image_size (f, img->width, img->height))
            {
@@ -8954,13 +9034,14 @@ gif_load (struct frame *f, struct image *img)
   struct anim_cache* cache = NULL;
   /* Which sub-image are we to display?  */
   Lisp_Object image_number = image_spec_value (img->spec, QCindex, NULL);
+  int byte_size = 0;
 
   idx = FIXNUMP (image_number) ? XFIXNAT (image_number) : 0;
 
   if (!NILP (image_number))
     {
       /* If this is an animated image, create a cache for it.  */
-      cache = anim_get_animation_cache (img->spec);
+      cache = anim_get_animation_cache (XCDR (img->spec));
       /* We have an old cache entry, so use it.  */
       if (cache->handle)
        {
@@ -9007,6 +9088,14 @@ gif_load (struct frame *f, struct image *img)
                image_error ("Cannot open `%s'", file);
              return false;
            }
+
+         /* Get the file size so that we can report it in
+            `image-cache-size'.  */
+         struct stat st;
+         FILE *fp = fopen (SSDATA (encoded_file), "rb");
+         if (fstat (fileno (fp), &st) == 0)
+           byte_size = st.st_size;
+         fclose (fp);
        }
       else
        {
@@ -9021,6 +9110,7 @@ gif_load (struct frame *f, struct image *img)
          memsrc.bytes = SDATA (specified_data);
          memsrc.len = SBYTES (specified_data);
          memsrc.index = 0;
+         byte_size = memsrc.len;
 
 #if GIFLIB_MAJOR < 5
          gif = DGifOpen (&memsrc, gif_read_from_memory);
@@ -9115,6 +9205,7 @@ gif_load (struct frame *f, struct image *img)
       cache->destructor = (void (*)(void *)) &gif_destroy;
       cache->width = width;
       cache->height = height;
+      cache->byte_size = byte_size;
     }
 
   img->corners[TOP_CORNER] = gif->SavedImages[0].ImageDesc.Top;
@@ -9652,7 +9743,7 @@ webp_load (struct frame *f, struct image *img)
       /* Animated image.  */
       int timestamp;
 
-      struct anim_cache* cache = anim_get_animation_cache (img->spec);
+      struct anim_cache* cache = anim_get_animation_cache (XCDR (img->spec));
       /* Get the next frame from the animation cache.  */
       if (cache->handle && cache->index == idx - 1)
        {
@@ -9686,6 +9777,9 @@ webp_load (struct frame *f, struct image *img)
             purge the anim cache.  */
          webp_data.size = size;
 
+         /* This is used just for reporting by `image-cache-size'.  */
+         cache->byte_size = size;
+
          /* Get the width/height of the total image.  */
          WebPDemuxer* demux = WebPDemux (&webp_data);
          cache->width = width = WebPDemuxGetI (demux, WEBP_FF_CANVAS_WIDTH);
@@ -10025,9 +10119,10 @@ imagemagick_create_cache (char *signature)
   return cache;
 }
 
-/* Discard cached images that haven't been used for a minute. */
+/* Discard cached images that haven't been used for a minute.  If
+   CLEAR, discard all cached animated images.  */
 static void
-imagemagick_prune_animation_cache (void)
+imagemagick_prune_animation_cache (bool clear)
 {
   struct animation_cache **pcache = &animation_cache;
   struct timespec old = timespec_sub (current_timespec (),
@@ -10036,15 +10131,15 @@ imagemagick_prune_animation_cache (void)
   while (*pcache)
     {
       struct animation_cache *cache = *pcache;
-      if (timespec_cmp (old, cache->update_time) <= 0)
-       pcache = &cache->next;
-      else
+      if (clear || timespec_cmp (old, cache->update_time) > 0)
        {
          if (cache->wand)
            DestroyMagickWand (cache->wand);
          *pcache = cache->next;
          xfree (cache);
        }
+      else
+       pcache = &cache->next;
     }
 }
 
@@ -10055,7 +10150,7 @@ imagemagick_get_animation_cache (MagickWand *wand)
   struct animation_cache *cache;
   struct animation_cache **pcache = &animation_cache;
 
-  imagemagick_prune_animation_cache ();
+  imagemagick_prune_animation_cache (false);
 
   while (1)
     {
@@ -11785,6 +11880,30 @@ The list of capabilities can include one or more of 
the following:
   return Qnil;
 }
 
+DEFUN ("image-cache-size", Fimage_cache_size, Simage_cache_size, 0, 0, 0,
+       doc: /* Return the size of the image cache.  */)
+  (void)
+{
+  Lisp_Object tail, frame;
+  size_t total = 0;
+
+  FOR_EACH_FRAME (tail, frame)
+    if (FRAME_WINDOW_P (XFRAME (frame)))
+      total += image_frame_cache_size (XFRAME (frame));
+
+#if defined (HAVE_WEBP) || defined (HAVE_GIF)
+  struct anim_cache *pcache = anim_cache;
+  while (pcache)
+    {
+      total += pcache->byte_size;
+      pcache = pcache->next;
+    }
+#endif
+
+  return make_int (total);
+}
+
+
 DEFUN ("init-image-library", Finit_image_library, Sinit_image_library, 1, 1, 0,
        doc: /* Initialize image library implementing image type TYPE.
 Return t if TYPE is a supported image type.
@@ -11894,6 +12013,18 @@ lookup_image_type (Lisp_Object type)
   return NULL;
 }
 
+/* Prune the animation caches.  If CLEAR, remove all animation cache
+   entries.  */
+void
+image_prune_animation_caches (bool clear)
+{
+#if defined (HAVE_WEBP) || defined (HAVE_GIF)
+  anim_prune_animation_cache (clear? Qt: Qnil);
+#endif
+#ifdef HAVE_IMAGEMAGICK
+  imagemagick_prune_animation_cache (clear);
+#endif
+}
 
 void
 syms_of_image (void)
@@ -11938,6 +12069,7 @@ non-numeric, there is no explicit limit on the size of 
images.  */);
   DEFSYM (QCtransform_smoothing, ":transform-smoothing");
   DEFSYM (QCcolor_adjustment, ":color-adjustment");
   DEFSYM (QCmask, ":mask");
+  DEFSYM (QCflip, ":flip");
 
   /* Other symbols.  */
   DEFSYM (Qlaplace, "laplace");
diff --git a/src/indent.c b/src/indent.c
index 51f6f414de..aa905f387b 100644
--- a/src/indent.c
+++ b/src/indent.c
@@ -306,6 +306,8 @@ and point (e.g., control characters will have a width of 2 
or 4, tabs
 will have a variable width).
 Ignores finite width of frame, which means that this function may return
 values greater than (frame-width).
+In a buffer with very long lines, the value will be an approximation,
+because calculating the exact number is very expensive.
 Whether the line is visible (if `selective-display' is t) has no effect;
 however, ^M is treated as end of line when `selective-display' is t.
 Text that has an invisible property is considered as having width 0, unless
@@ -313,6 +315,7 @@ Text that has an invisible property is considered as having 
width 0, unless
   (void)
 {
   Lisp_Object temp;
+
   XSETFASTINT (temp, current_column ());
   return temp;
 }
@@ -341,6 +344,14 @@ current_column (void)
       && MODIFF == last_known_column_modified)
     return last_known_column;
 
+  ptrdiff_t line_beg = find_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -1,
+                                    NULL, NULL, 1);
+
+  /* Avoid becoming abysmally slow for very long lines.  */
+  if (current_buffer->long_line_optimizations_p
+      && !NILP (Vlong_line_threshold)
+      && PT - line_beg > XFIXNUM (Vlong_line_threshold))
+    return PT - line_beg;      /* this is an approximation! */
   /* If the buffer has overlays, text properties,
      or multibyte characters, use a more general algorithm.  */
   if (buffer_intervals (current_buffer)
@@ -484,15 +495,15 @@ check_display_width (ptrdiff_t pos, ptrdiff_t col, 
ptrdiff_t *endpos)
             : MOST_POSITIVE_FIXNUM);
 
          plist = XCDR (val);
-         if ((prop = Fplist_get (plist, QCwidth),
+         if ((prop = plist_get (plist, QCwidth),
               RANGED_FIXNUMP (0, prop, INT_MAX))
-             || (prop = Fplist_get (plist, QCrelative_width),
+             || (prop = plist_get (plist, QCrelative_width),
                  RANGED_FIXNUMP (0, prop, INT_MAX)))
            width = XFIXNUM (prop);
          else if (FLOATP (prop) && 0 <= XFLOAT_DATA (prop)
                   && XFLOAT_DATA (prop) <= INT_MAX)
            width = (int)(XFLOAT_DATA (prop) + 0.5);
-         else if ((prop = Fplist_get (plist, QCalign_to),
+         else if ((prop = plist_get (plist, QCalign_to),
                    RANGED_FIXNUMP (col, prop, align_to_max)))
            width = XFIXNUM (prop) - col;
          else if (FLOATP (prop) && col <= XFLOAT_DATA (prop)
@@ -514,7 +525,7 @@ check_display_width (ptrdiff_t pos, ptrdiff_t col, 
ptrdiff_t *endpos)
          /* For :relative-width, we need to multiply by the column
             width of the character at POS, if it is greater than 1.  */
          if (!NILP (plist)
-             && !NILP (Fplist_get (plist, QCrelative_width))
+             && !NILP (plist_get (plist, QCrelative_width))
              && !NILP (BVAR (current_buffer, enable_multibyte_characters)))
            {
              int b, wd;
@@ -556,13 +567,56 @@ scan_for_column (ptrdiff_t *endpos, EMACS_INT *goalcol,
   ptrdiff_t scan, scan_byte, next_boundary, prev_pos, prev_bpos;
 
   scan = find_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -1, NULL, &scan_byte, 1);
-  next_boundary = scan;
-  prev_pos = scan;
-  prev_bpos = scan_byte;
 
   window = Fget_buffer_window (Fcurrent_buffer (), Qnil);
   w = ! NILP (window) ? XWINDOW (window) : NULL;
 
+  if (current_buffer->long_line_optimizations_p)
+    {
+      bool lines_truncated = false;
+
+      if (!NILP (BVAR (current_buffer, truncate_lines)))
+       lines_truncated = true;
+      else if (!NILP (Vtruncate_partial_width_windows) && w
+              && w->total_cols < FRAME_COLS (XFRAME (WINDOW_FRAME (w))))
+       {
+         if (FIXNUMP (Vtruncate_partial_width_windows))
+           lines_truncated =
+             w->total_cols < XFIXNAT (Vtruncate_partial_width_windows);
+         else
+           lines_truncated = true;
+       }
+      /* Special optimization for buffers with long and truncated
+        lines: assumes that each character is a single column.  */
+      if (lines_truncated)
+       {
+         ptrdiff_t bolpos = scan;
+         /* The newline which ends this line or ZV.  */
+         ptrdiff_t eolpos =
+           find_newline (PT, PT_BYTE, ZV, ZV_BYTE, 1, NULL, NULL, 1);
+
+         scan = bolpos + goal;
+         if (scan > end)
+           scan = end;
+         if (scan > eolpos)
+           scan = (eolpos == ZV ? ZV : eolpos - 1);
+         col = scan - bolpos;
+         if (col > large_hscroll_threshold)
+           {
+             prev_col = col - 1;
+             prev_pos = scan - 1;
+             prev_bpos = CHAR_TO_BYTE (scan);
+             goto endloop;
+           }
+         /* Restore the values we've overwritten above.  */
+         scan = bolpos;
+         col = 0;
+       }
+    }
+  next_boundary = scan;
+  prev_pos = scan;
+  prev_bpos = scan_byte;
+
   memset (&cmp_it, 0, sizeof cmp_it);
   cmp_it.id = -1;
   composition_compute_stop_pos (&cmp_it, scan, scan_byte, end, Qnil);
@@ -877,8 +931,10 @@ The return value is the column where the insertion ends.  
*/)
 DEFUN ("current-indentation", Fcurrent_indentation, Scurrent_indentation,
        0, 0, 0,
        doc: /* Return the indentation of the current line.
-This is the horizontal position of the character
-following any initial whitespace.  */)
+This is the horizontal position of the character following any initial
+whitespace.
+Text that has an invisible property is considered as having width 0, unless
+`buffer-invisibility-spec' specifies that it is replaced by an ellipsis.  */)
   (void)
 {
   ptrdiff_t posbyte;
@@ -996,6 +1052,9 @@ as displayed of the previous characters in the line.
 This function ignores line-continuation;
 there is no upper limit on the column number a character can have
 and horizontal scrolling has no effect.
+Text that has an invisible property is considered as having width 0,
+unless `buffer-invisibility-spec' specifies that it is replaced by
+an ellipsis.
 
 If specified column is within a character, point goes after that character.
 If it's past end of line, point goes to end of line.
@@ -1861,7 +1920,7 @@ vmotion (ptrdiff_t from, ptrdiff_t from_byte,
 
   /* If the window contains this buffer, use it for getting text properties.
      Otherwise use the current buffer as arg for doing that.  */
-  if (EQ (w->contents, Fcurrent_buffer ()))
+  if (BASE_EQ (w->contents, Fcurrent_buffer ()))
     text_prop_object = window;
   else
     text_prop_object = Fcurrent_buffer ();
@@ -2177,6 +2236,8 @@ whether or not it is currently displayed in some window.  
*/)
        line_number_display_width (w, &lnum_width, &lnum_pixel_width);
       SET_TEXT_POS (pt, PT, PT_BYTE);
       itdata = bidi_shelve_cache ();
+      record_unwind_protect_void (unwind_display_working_on_window);
+      display_working_on_window_p = true;
       start_display (&it, w, pt);
       it.lnum_width = lnum_width;
       first_x = it.first_visible_x;
@@ -2333,7 +2394,15 @@ whether or not it is currently displayed in some window. 
 */)
             last line that it occupies.  */
          if (it_start < ZV)
            {
-             while (IT_CHARPOS (it) <= it_start)
+             if ((it.bidi_it.scan_dir > 0)
+                 ? IT_CHARPOS (it) < it_start
+                 : IT_CHARPOS (it) > it_start)
+               {
+                 it.vpos = 0;
+                 it.current_y = 0;
+                 move_it_by_lines (&it, 1);
+               }
+             while (IT_CHARPOS (it) == it_start)
                {
                  it.vpos = 0;
                  it.current_y = 0;
diff --git a/src/inotify.c b/src/inotify.c
index e92ad40abc..16d20e7e92 100644
--- a/src/inotify.c
+++ b/src/inotify.c
@@ -217,7 +217,7 @@ add_watch (int wd, Lisp_Object filename,
       /* Assign a watch ID that is not already in use, by looking
         for a gap in the existing sorted list.  */
       for (; ! NILP (XCDR (tail)); tail = XCDR (tail), id++)
-       if (!EQ (XCAR (XCAR (XCDR (tail))), make_fixnum (id)))
+       if (!BASE_EQ (XCAR (XCAR (XCDR (tail))), make_fixnum (id)))
          break;
       if (MOST_POSITIVE_FIXNUM < id)
        emacs_abort ();
diff --git a/src/insdel.c b/src/insdel.c
index 4676330cb7..7cbc88e51d 100644
--- a/src/insdel.c
+++ b/src/insdel.c
@@ -913,7 +913,7 @@ insert_1_both (const char *string,
      the insertion.  This, together with recording the insertion,
      will add up to the right stuff in the undo list.  */
   record_insert (PT, nchars);
-  modiff_incr (&MODIFF);
+  modiff_incr (&MODIFF, nchars);
   CHARS_MODIFF = MODIFF;
 
   memcpy (GPT_ADDR, string, nbytes);
@@ -1047,7 +1047,7 @@ insert_from_string_1 (Lisp_Object string, ptrdiff_t pos, 
ptrdiff_t pos_byte,
 #endif
 
   record_insert (PT, nchars);
-  modiff_incr (&MODIFF);
+  modiff_incr (&MODIFF, nchars);
   CHARS_MODIFF = MODIFF;
 
   GAP_SIZE -= outgoing_nbytes;
@@ -1138,7 +1138,8 @@ insert_from_gap (ptrdiff_t nchars, ptrdiff_t nbytes, bool 
text_at_gap_tail)
      of this dance.  */
   invalidate_buffer_caches (current_buffer, GPT, GPT);
   record_insert (GPT, nchars);
-  modiff_incr (&MODIFF);
+  modiff_incr (&MODIFF, nchars);
+  CHARS_MODIFF = MODIFF;
 
   insert_from_gap_1 (nchars, nbytes, text_at_gap_tail);
 
@@ -1272,7 +1273,7 @@ insert_from_buffer_1 (struct buffer *buf,
 #endif
 
   record_insert (PT, nchars);
-  modiff_incr (&MODIFF);
+  modiff_incr (&MODIFF, nchars);
   CHARS_MODIFF = MODIFF;
 
   GAP_SIZE -= outgoing_nbytes;
@@ -1379,7 +1380,7 @@ adjust_after_replace (ptrdiff_t from, ptrdiff_t from_byte,
 
   if (len == 0)
     evaporate_overlays (from);
-  modiff_incr (&MODIFF);
+  modiff_incr (&MODIFF, nchars_del + len);
   CHARS_MODIFF = MODIFF;
 }
 
@@ -1581,7 +1582,7 @@ replace_range (ptrdiff_t from, ptrdiff_t to, Lisp_Object 
new,
 
   check_markers ();
 
-  modiff_incr (&MODIFF);
+  modiff_incr (&MODIFF, nchars_del + inschars);
   CHARS_MODIFF = MODIFF;
 
   if (adjust_match_data)
@@ -1719,7 +1720,7 @@ replace_range_2 (ptrdiff_t from, ptrdiff_t from_byte,
 
   check_markers ();
 
-  modiff_incr (&MODIFF);
+  modiff_incr (&MODIFF, nchars_del + inschars);
   CHARS_MODIFF = MODIFF;
 }
 
@@ -1894,7 +1895,7 @@ del_range_2 (ptrdiff_t from, ptrdiff_t from_byte,
      at the end of the text before the gap.  */
   adjust_markers_for_delete (from, from_byte, to, to_byte);
 
-  modiff_incr (&MODIFF);
+  modiff_incr (&MODIFF, nchars_del);
   CHARS_MODIFF = MODIFF;
 
   /* Relocate point as if it were a marker.  */
@@ -1954,7 +1955,7 @@ modify_text (ptrdiff_t start, ptrdiff_t end)
   BUF_COMPUTE_UNCHANGED (current_buffer, start - 1, end);
   if (MODIFF <= SAVE_MODIFF)
     record_first_change ();
-  modiff_incr (&MODIFF);
+  modiff_incr (&MODIFF, end - start);
   CHARS_MODIFF = MODIFF;
 
   bset_point_before_scroll (current_buffer, Qnil);
diff --git a/src/intervals.c b/src/intervals.c
index 9e28637d6b..85152c58a5 100644
--- a/src/intervals.c
+++ b/src/intervals.c
@@ -1737,11 +1737,11 @@ lookup_char_property (Lisp_Object plist, Lisp_Object 
prop, bool textprop)
     {
       tail = XCDR (tail);
       for (; NILP (fallback) && CONSP (tail); tail = XCDR (tail))
-       fallback = Fplist_get (plist, XCAR (tail));
+       fallback = plist_get (plist, XCAR (tail));
     }
 
   if (textprop && NILP (fallback) && CONSP (Vdefault_text_properties))
-    fallback = Fplist_get (Vdefault_text_properties, prop);
+    fallback = plist_get (Vdefault_text_properties, prop);
   return fallback;
 }
 
diff --git a/src/json.c b/src/json.c
index 4b3fabb3eb..cdcc11358e 100644
--- a/src/json.c
+++ b/src/json.c
@@ -975,7 +975,7 @@ usage: (json-parse-string STRING &rest ARGS) */)
 
   json_error_t error;
   json_t *object
-    = json_loads (SSDATA (encoded), JSON_DECODE_ANY, &error);
+    = json_loads (SSDATA (encoded), JSON_DECODE_ANY | JSON_ALLOW_NUL, &error);
   if (object == NULL)
     json_parse_error (&error);
 
@@ -1071,7 +1071,9 @@ usage: (json-parse-buffer &rest args) */)
   json_error_t error;
   json_t *object
     = json_load_callback (json_read_buffer_callback, &data,
-                          JSON_DECODE_ANY | JSON_DISABLE_EOF_CHECK,
+                          JSON_DECODE_ANY
+                         | JSON_DISABLE_EOF_CHECK
+                         | JSON_ALLOW_NUL,
                           &error);
 
   if (object == NULL)
diff --git a/src/keyboard.c b/src/keyboard.c
index 55d710ed62..1d7125a0a3 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -1295,7 +1295,8 @@ command_loop_1 (void)
       /* Note that the value cell will never directly contain nil
         if the symbol is a local variable.  */
       if (!NILP (Vpost_command_hook) && !NILP (Vrun_hooks))
-       safe_run_hooks (Qpost_command_hook);
+       safe_run_hooks_maybe_narrowed (Qpost_command_hook,
+                                      XWINDOW (selected_window));
 
       /* If displaying a message, resize the echo area window to fit
         that message's size exactly.  */
@@ -1305,9 +1306,6 @@ command_loop_1 (void)
       /* If there are warnings waiting, process them.  */
       if (!NILP (Vdelayed_warnings_list))
         safe_run_hooks (Qdelayed_warnings_hook);
-
-      if (!NILP (Vdeferred_action_list))
-       safe_run_hooks (Qdeferred_action_function);
     }
 
   /* Do this after running Vpost_command_hook, for consistency.  */
@@ -1333,6 +1331,7 @@ command_loop_1 (void)
        display_malloc_warning ();
 
       Vdeactivate_mark = Qnil;
+      backtrace_yet = false;
 
       /* Don't ignore mouse movements for more than a single command
         loop.  (This flag is set in xdisp.c whenever the tool bar is
@@ -1345,7 +1344,7 @@ command_loop_1 (void)
 
       if (minibuf_level
          && !NILP (echo_area_buffer[0])
-         && EQ (minibuf_window, echo_area_window)
+         && BASE_EQ (minibuf_window, echo_area_window)
          && NUMBERP (Vminibuffer_message_timeout))
        {
          /* Bind inhibit-quit to t so that C-g gets read in
@@ -1374,12 +1373,6 @@ command_loop_1 (void)
            }
        }
 
-      /* If it has changed current-menubar from previous value,
-        really recompute the menubar from the value.  */
-      if (! NILP (Vlucid_menu_bar_dirty_flag)
-         && !NILP (Ffboundp (Qrecompute_lucid_menubar)))
-       call0 (Qrecompute_lucid_menubar);
-
       Vthis_command = Qnil;
       Vreal_this_command = Qnil;
       Vthis_original_command = Qnil;
@@ -1470,7 +1463,9 @@ command_loop_1 (void)
       }
       Vthis_command = cmd;
       Vreal_this_command = cmd;
-      safe_run_hooks (Qpre_command_hook);
+
+      safe_run_hooks_maybe_narrowed (Qpre_command_hook,
+                                    XWINDOW (selected_window));
 
       already_adjusted = 0;
 
@@ -1501,7 +1496,14 @@ command_loop_1 (void)
             point_before_last_command_or_undo = PT;
             buffer_before_last_command_or_undo = current_buffer;
 
+           /* Restart our counting of redisplay ticks before
+              executing the command, so that we don't blame the new
+              command for the sins of the previous one.  */
+           update_redisplay_ticks (0, NULL);
+           display_working_on_window_p = false;
+
             call1 (Qcommand_execute, Vthis_command);
+           display_working_on_window_p = false;
 
 #ifdef HAVE_WINDOW_SYSTEM
          /* Do not check display_hourglass_p here, because
@@ -1515,7 +1517,8 @@ command_loop_1 (void)
           }
       kset_last_prefix_arg (current_kboard, Vcurrent_prefix_arg);
 
-      safe_run_hooks (Qpost_command_hook);
+      safe_run_hooks_maybe_narrowed (Qpost_command_hook,
+                                    XWINDOW (selected_window));
 
       /* If displaying a message, resize the echo area window to fit
         that message's size exactly.  Do this only if the echo area
@@ -1530,8 +1533,6 @@ command_loop_1 (void)
       if (!NILP (Vdelayed_warnings_list))
         safe_run_hooks (Qdelayed_warnings_hook);
 
-      safe_run_hooks (Qdeferred_action_function);
-
       kset_last_command (current_kboard, Vthis_command);
       kset_real_last_command (current_kboard, Vreal_this_command);
       if (!CONSP (last_command_event))
@@ -1567,9 +1568,15 @@ command_loop_1 (void)
            call0 (Qdeactivate_mark);
          else
            {
+             Lisp_Object symval;
              /* Even if not deactivating the mark, set PRIMARY if
                 `select-active-regions' is non-nil.  */
-             if (!NILP (Fwindow_system (Qnil))
+             if ((!NILP (Fwindow_system (Qnil))
+                  || ((symval =
+                       find_symbol_value (Qtty_select_active_regions),
+                       (!EQ (symval, Qunbound) && !NILP (symval)))
+                      && !NILP (Fterminal_parameter (Qnil,
+                                                     Qxterm__set_selection))))
                  /* Even if mark_active is non-nil, the actual buffer
                     marker may not have been set yet (Bug#7044).  */
                  && XMARKER (BVAR (current_buffer, mark))->buffer
@@ -1582,9 +1589,12 @@ command_loop_1 (void)
                {
                  Lisp_Object txt
                    = call1 (Vregion_extract_function, Qnil);
+
                  if (XFIXNUM (Flength (txt)) > 0)
                    /* Don't set empty selections.  */
                    call2 (Qgui_set_selection, QPRIMARY, txt);
+
+                 CALLN (Frun_hook_with_args, Qpost_select_region_hook, txt);
                }
 
              if (current_buffer != prev_buffer || MODIFF != prev_modiff)
@@ -1822,8 +1832,16 @@ adjust_point_for_property (ptrdiff_t last_pt, bool 
modified)
 static Lisp_Object
 safe_run_hooks_1 (ptrdiff_t nargs, Lisp_Object *args)
 {
-  eassert (nargs == 2);
-  return call0 (args[1]);
+  eassert (nargs >= 2 && nargs <= 4);
+  switch (nargs)
+    {
+    case 2:
+      return call0 (args[1]);
+    case 3:
+      return call1 (args[1], args[2]);
+    default:
+      return call2 (args[1], args[2], args[3]);
+    }
 }
 
 /* Subroutine for safe_run_hooks: handle an error by clearing out the function
@@ -1832,7 +1850,7 @@ safe_run_hooks_1 (ptrdiff_t nargs, Lisp_Object *args)
 static Lisp_Object
 safe_run_hooks_error (Lisp_Object error, ptrdiff_t nargs, Lisp_Object *args)
 {
-  eassert (nargs == 2);
+  eassert (nargs >= 2 && nargs <= 4);
   AUTO_STRING (format, "Error in %s (%S): %S");
   Lisp_Object hook = args[0];
   Lisp_Object fun = args[1];
@@ -1868,11 +1886,27 @@ safe_run_hooks_error (Lisp_Object error, ptrdiff_t 
nargs, Lisp_Object *args)
 static Lisp_Object
 safe_run_hook_funcall (ptrdiff_t nargs, Lisp_Object *args)
 {
-  eassert (nargs == 2);
+  eassert (nargs >= 2 && nargs <= 4);
   /* Yes, run_hook_with_args works with args in the other order.  */
-  internal_condition_case_n (safe_run_hooks_1,
-                            2, ((Lisp_Object []) {args[1], args[0]}),
-                            Qt, safe_run_hooks_error);
+  switch (nargs)
+    {
+    case 2:
+      internal_condition_case_n (safe_run_hooks_1,
+                                2, ((Lisp_Object []) {args[1], args[0]}),
+                                Qt, safe_run_hooks_error);
+      break;
+    case 3:
+      internal_condition_case_n (safe_run_hooks_1,
+                                3, ((Lisp_Object []) {args[1], args[0], 
args[2]}),
+                                Qt, safe_run_hooks_error);
+      break;
+    default:
+      internal_condition_case_n (safe_run_hooks_1,
+                                4, ((Lisp_Object [])
+                                    {args[1], args[0], args[2], args[3]}),
+                                Qt, safe_run_hooks_error);
+      break;
+    }
   return Qnil;
 }
 
@@ -1890,6 +1924,33 @@ safe_run_hooks (Lisp_Object hook)
   unbind_to (count, Qnil);
 }
 
+void
+safe_run_hooks_maybe_narrowed (Lisp_Object hook, struct window *w)
+{
+  specpdl_ref count = SPECPDL_INDEX ();
+
+  specbind (Qinhibit_quit, Qt);
+
+  if (current_buffer->long_line_optimizations_p)
+    narrow_to_region_internal (make_fixnum (get_narrowed_begv (w, PT)),
+                              make_fixnum (get_narrowed_zv (w, PT)),
+                              true);
+
+  run_hook_with_args (2, ((Lisp_Object []) {hook, hook}), 
safe_run_hook_funcall);
+  unbind_to (count, Qnil);
+}
+
+void
+safe_run_hooks_2 (Lisp_Object hook, Lisp_Object arg1, Lisp_Object arg2)
+{
+  specpdl_ref count = SPECPDL_INDEX ();
+
+  specbind (Qinhibit_quit, Qt);
+  run_hook_with_args (4, ((Lisp_Object []) {hook, hook, arg1, arg2}),
+                     safe_run_hook_funcall);
+  unbind_to (count, Qnil);
+}
+
 
 /* Nonzero means polling for input is temporarily suppressed.  */
 
@@ -2576,7 +2637,7 @@ read_char (int commandflag, Lisp_Object map,
               && (input_was_pending || !redisplay_dont_pause)))
        {
          input_was_pending = input_pending;
-         if (help_echo_showing_p && !EQ (selected_window, minibuf_window))
+         if (help_echo_showing_p && !BASE_EQ (selected_window, minibuf_window))
            redisplay_preserve_echo_area (5);
          else
            redisplay ();
@@ -2924,7 +2985,7 @@ read_char (int commandflag, Lisp_Object map,
           goto exit;
         }
 
-      if (EQ (c, make_fixnum (-2)))
+      if (BASE_EQ (c, make_fixnum (-2)))
        return c;
 
       if (CONSP (c) && EQ (XCAR (c), Qt))
@@ -3249,7 +3310,7 @@ read_char (int commandflag, Lisp_Object map,
       unbind_to (count, Qnil);
 
       redisplay ();
-      if (EQ (c, make_fixnum (040)))
+      if (BASE_EQ (c, make_fixnum (040)))
        {
          cancel_echoing ();
          do
@@ -3307,6 +3368,11 @@ help_char_p (Lisp_Object c)
 static void
 record_char (Lisp_Object c)
 {
+  /* subr.el/read-passwd binds inhibit_record_char to avoid recording
+     passwords.  */
+  if (!record_all_keys && inhibit_record_char)
+    return;
+
   int recorded = 0;
 
   if (CONSP (c) && (EQ (XCAR (c), Qhelp_echo) || EQ (XCAR (c), 
Qmouse_movement)))
@@ -3720,7 +3786,7 @@ Time_to_position (Time encoded_pos)
 {
   if (encoded_pos <= INPUT_EVENT_POS_MAX)
     return encoded_pos;
-  Time encoded_pos_min = INPUT_EVENT_POS_MIN;
+  Time encoded_pos_min = position_to_Time (INPUT_EVENT_POS_MIN);
   eassert (encoded_pos_min <= encoded_pos);
   ptrdiff_t notpos = -1 - encoded_pos;
   return -1 - notpos;
@@ -3994,17 +4060,23 @@ kbd_buffer_get_event (KBOARD **kbp,
         We return nil for them.  */
       switch (event->kind)
       {
+#ifndef HAVE_HAIKU
       case SELECTION_REQUEST_EVENT:
       case SELECTION_CLEAR_EVENT:
        {
-#ifdef HAVE_X11
+#if defined HAVE_X11 || HAVE_PGTK
          /* Remove it from the buffer before processing it,
             since otherwise swallow_events will see it
             and process it again.  */
          struct selection_input_event copy = event->sie;
          kbd_fetch_ptr = next_kbd_event (event);
          input_pending = readable_events (0);
+
+#ifdef HAVE_X11
          x_handle_selection_event (&copy);
+#else
+         pgtk_handle_selection_event (&copy);
+#endif
 #else
          /* We're getting selection request events, but we don't have
              a window system.  */
@@ -4012,51 +4084,19 @@ kbd_buffer_get_event (KBOARD **kbp,
 #endif
        }
         break;
+#else
+      case SELECTION_REQUEST_EVENT:
+       emacs_abort ();
 
-#ifdef HAVE_X_WINDOWS
-      case UNSUPPORTED_DROP_EVENT:
+      case SELECTION_CLEAR_EVENT:
        {
-         struct frame *f;
+         struct input_event copy = event->ie;
 
          kbd_fetch_ptr = next_kbd_event (event);
          input_pending = readable_events (0);
-
-         /* This means this event was already handled in
-            `x_dnd_begin_drag_and_drop'.  */
-         if (event->ie.modifiers < x_dnd_unsupported_event_level)
-           break;
-
-         f = XFRAME (event->ie.frame_or_window);
-
-         if (!FRAME_LIVE_P (f))
-           break;
-
-         if (!NILP (Vx_dnd_unsupported_drop_function))
-           {
-             if (!NILP (call7 (Vx_dnd_unsupported_drop_function,
-                               XCAR (XCDR (event->ie.arg)), event->ie.x,
-                               event->ie.y, XCAR (XCDR (XCDR (event->ie.arg))),
-                               make_uint (event->ie.code),
-                               event->ie.frame_or_window,
-                               make_int (event->ie.timestamp))))
-               break;
-           }
-
-         /* `x-dnd-unsupported-drop-function' could have deleted the
-            event frame.  */
-         if (!FRAME_LIVE_P (f))
-           break;
-
-         x_dnd_do_unsupported_drop (FRAME_DISPLAY_INFO (f),
-                                    event->ie.frame_or_window,
-                                    XCAR (event->ie.arg),
-                                    XCAR (XCDR (event->ie.arg)),
-                                    (Window) event->ie.code,
-                                    XFIXNUM (event->ie.x),
-                                    XFIXNUM (event->ie.y),
-                                    event->ie.timestamp);
-         break;
+         haiku_handle_selection_clear (&copy);
        }
+       break;
 #endif
 
       case MONITORS_CHANGED_EVENT:
@@ -4368,14 +4408,24 @@ kbd_buffer_get_event (KBOARD **kbp,
 static void
 process_special_events (void)
 {
-  for (union buffered_input_event *event = kbd_fetch_ptr;
-       event != kbd_store_ptr; event = next_kbd_event (event))
+  union buffered_input_event *event;
+#if defined HAVE_X11 || defined HAVE_PGTK || defined HAVE_HAIKU
+#ifndef HAVE_HAIKU
+  struct selection_input_event copy;
+#else
+  struct input_event copy;
+#endif
+  int moved_events;
+#endif
+
+  for (event = kbd_fetch_ptr;  event != kbd_store_ptr;
+       event = next_kbd_event (event))
     {
       /* If we find a stored X selection request, handle it now.  */
       if (event->kind == SELECTION_REQUEST_EVENT
          || event->kind == SELECTION_CLEAR_EVENT)
        {
-#ifdef HAVE_X11
+#if defined HAVE_X11 || defined HAVE_PGTK
 
          /* Remove the event from the fifo buffer before processing;
             otherwise swallow_events called recursively could see it
@@ -4383,8 +4433,7 @@ process_special_events (void)
             between kbd_fetch_ptr and EVENT one slot to the right,
             cyclically.  */
 
-         struct selection_input_event copy = event->sie;
-         int moved_events;
+         copy = event->sie;
 
          if (event < kbd_fetch_ptr)
            {
@@ -4400,7 +4449,33 @@ process_special_events (void)
                   moved_events * sizeof *kbd_fetch_ptr);
          kbd_fetch_ptr = next_kbd_event (kbd_fetch_ptr);
          input_pending = readable_events (0);
+
+#ifdef HAVE_X11
          x_handle_selection_event (&copy);
+#else
+         pgtk_handle_selection_event (&copy);
+#endif
+#elif defined HAVE_HAIKU
+         if (event->ie.kind != SELECTION_CLEAR_EVENT)
+           emacs_abort ();
+
+         copy = event->ie;
+
+         if (event < kbd_fetch_ptr)
+           {
+             memmove (kbd_buffer + 1, kbd_buffer,
+                      (event - kbd_buffer) * sizeof *kbd_buffer);
+             kbd_buffer[0] = kbd_buffer[KBD_BUFFER_SIZE - 1];
+             moved_events = kbd_buffer + KBD_BUFFER_SIZE - 1 - kbd_fetch_ptr;
+           }
+         else
+           moved_events = event - kbd_fetch_ptr;
+
+         memmove (kbd_fetch_ptr + 1, kbd_fetch_ptr,
+                  moved_events * sizeof *kbd_fetch_ptr);
+         kbd_fetch_ptr = next_kbd_event (kbd_fetch_ptr);
+         input_pending = readable_events (0);
+         haiku_handle_selection_clear (&copy);
 #else
          /* We're getting selection request events, but we don't have
              a window system.  */
@@ -4603,6 +4678,11 @@ timer_check_2 (Lisp_Object timers, Lisp_Object 
idle_timers)
       /* If timer is ripe, run it if it hasn't been run.  */
       if (ripe)
        {
+         /* If we got here, presumably `decode_timer` has checked
+             that this timer has not yet been triggered.  */
+         eassert (NILP (AREF (chosen_timer, 0)));
+         /* In a production build, where assertions compile to
+            nothing, we still want to play it safe here.  */
          if (NILP (AREF (chosen_timer, 0)))
            {
              specpdl_ref count = SPECPDL_INDEX ();
@@ -4621,8 +4701,8 @@ timer_check_2 (Lisp_Object timers, Lisp_Object 
idle_timers)
 
              /* Since we have handled the event,
                 we don't need to tell the caller to wake up and do it.  */
-              /* But the caller must still wait for the next timer, so
-                 return 0 to indicate that.  */
+             /* But the caller must still wait for the next timer, so
+                return 0 to indicate that.  */
            }
 
          nexttime = make_timespec (0, 0);
@@ -5573,7 +5653,7 @@ make_lispy_position (struct frame *f, Lisp_Object x, 
Lisp_Object y,
       if (IMAGEP (object))
        {
          Lisp_Object image_map, hotspot;
-         if ((image_map = Fplist_get (XCDR (object), QCmap),
+         if ((image_map = plist_get (XCDR (object), QCmap),
               !NILP (image_map))
              && (hotspot = find_hot_spot (image_map, dx, dy),
                  CONSP (hotspot))
@@ -9498,7 +9578,7 @@ read_char_minibuf_menu_prompt (int commandflag,
       if (!FIXNUMP (obj) || XFIXNUM (obj) == -2
          || (! EQ (obj, menu_prompt_more_char)
              && (!FIXNUMP (menu_prompt_more_char)
-                 || ! EQ (obj, make_fixnum (Ctl (XFIXNUM 
(menu_prompt_more_char)))))))
+                 || ! BASE_EQ (obj, make_fixnum (Ctl (XFIXNUM 
(menu_prompt_more_char)))))))
        {
          if (!NILP (KVAR (current_kboard, defining_kbd_macro)))
            store_kbd_macro_char (obj);
@@ -11437,7 +11517,7 @@ quit_throw_to_read_char (bool from_signal)
   if (FRAMEP (internal_last_event_frame)
       && !EQ (internal_last_event_frame, selected_frame))
     do_switch_frame (make_lispy_switch_frame (internal_last_event_frame),
-                    0, 0, Qnil);
+                    0, Qnil);
 
   sys_longjmp (getcjmp, 1);
 }
@@ -12058,11 +12138,13 @@ syms_of_keyboard (void)
   DEFSYM (Qpre_command_hook, "pre-command-hook");
   DEFSYM (Qpost_command_hook, "post-command-hook");
 
+  /* Hook run after the region is selected.  */
+  DEFSYM (Qpost_select_region_hook, "post-select-region-hook");
+
   DEFSYM (Qundo_auto__add_boundary, "undo-auto--add-boundary");
   DEFSYM (Qundo_auto__undoably_changed_buffers,
           "undo-auto--undoably-changed-buffers");
 
-  DEFSYM (Qdeferred_action_function, "deferred-action-function");
   DEFSYM (Qdelayed_warnings_hook, "delayed-warnings-hook");
   DEFSYM (Qfunction_key, "function-key");
 
@@ -12157,12 +12239,13 @@ syms_of_keyboard (void)
      apply_modifiers.  */
   DEFSYM (Qmodifier_cache, "modifier-cache");
 
-  DEFSYM (Qrecompute_lucid_menubar, "recompute-lucid-menubar");
   DEFSYM (Qactivate_menubar_hook, "activate-menubar-hook");
 
   DEFSYM (Qpolling_period, "polling-period");
 
   DEFSYM (Qgui_set_selection, "gui-set-selection");
+  DEFSYM (Qxterm__set_selection, "xterm--set-selection");
+  DEFSYM (Qtty_select_active_regions, "tty-select-active-regions");
 
   /* The primary selection.  */
   DEFSYM (QPRIMARY, "PRIMARY");
@@ -12591,32 +12674,55 @@ cancels any modification.  */);
 
   DEFSYM (Qdeactivate_mark, "deactivate-mark");
   DEFVAR_LISP ("deactivate-mark", Vdeactivate_mark,
-              doc: /* If an editing command sets this to t, deactivate the 
mark afterward.
+    doc: /* Whether to deactivate the mark after an editing command.
 The command loop sets this to nil before each command,
 and tests the value when the command returns.
-Buffer modification stores t in this variable.  */);
+If an editing command sets this non-nil, deactivate the mark after
+the command returns.
+
+Buffer modifications store t in this variable.
+
+By default, deactivating the mark will save the contents of the region
+according to `select-active-regions', unless this is set to the symbol
+`dont-save'.  */);
   Vdeactivate_mark = Qnil;
   Fmake_variable_buffer_local (Qdeactivate_mark);
 
   DEFVAR_LISP ("pre-command-hook", Vpre_command_hook,
               doc: /* Normal hook run before each command is executed.
-If an unhandled error happens in running this hook,
-the function in which the error occurred is unconditionally removed, since
-otherwise the error might happen repeatedly and make Emacs nonfunctional.
+
+If an unhandled error happens in running this hook, the function in
+which the error occurred is unconditionally removed, since otherwise
+the error might happen repeatedly and make Emacs nonfunctional.
+
+Note that, when the current buffer contains one or more lines whose
+length is above `long-line-threshold', these hook functions are called
+with the buffer narrowed to a small portion around point, and the
+narrowing is locked (see `narrow-to-region'), so that these hook
+functions cannot use `widen' to gain access to other portions of
+buffer text.
 
 See also `post-command-hook'.  */);
   Vpre_command_hook = Qnil;
 
   DEFVAR_LISP ("post-command-hook", Vpost_command_hook,
               doc: /* Normal hook run after each command is executed.
-If an unhandled error happens in running this hook,
-the function in which the error occurred is unconditionally removed, since
-otherwise the error might happen repeatedly and make Emacs nonfunctional.
+
+If an unhandled error happens in running this hook, the function in
+which the error occurred is unconditionally removed, since otherwise
+the error might happen repeatedly and make Emacs nonfunctional.
 
 It is a bad idea to use this hook for expensive processing.  If
 unavoidable, wrap your code in `(while-no-input (redisplay) CODE)' to
 avoid making Emacs unresponsive while the user types.
 
+Note that, when the current buffer contains one or more lines whose
+length is above `long-line-threshold', these hook functions are called
+with the buffer narrowed to a small portion around point, and the
+narrowing is locked (see `narrow-to-region'), so that these hook
+functions cannot use `widen' to gain access to other portions of
+buffer text.
+
 See also `pre-command-hook'.  */);
   Vpost_command_hook = Qnil;
 
@@ -12636,9 +12742,14 @@ See also `pre-command-hook'.  */);
 
   Fset (Qecho_area_clear_hook, Qnil);
 
-  DEFVAR_LISP ("lucid-menu-bar-dirty-flag", Vlucid_menu_bar_dirty_flag,
-              doc: /* Non-nil means menu bar, specified Lucid style, needs to 
be recomputed.  */);
-  Vlucid_menu_bar_dirty_flag = Qnil;
+#ifdef USE_LUCID
+  DEFVAR_BOOL ("lucid--menu-grab-keyboard",
+               lucid__menu_grab_keyboard,
+               doc: /* If non-nil, grab keyboard during menu operations.
+This is only relevant when using the Lucid X toolkit.  It can be
+convenient to disable this for debugging purposes.  */);
+  lucid__menu_grab_keyboard = true;
+#endif
 
   DEFVAR_LISP ("menu-bar-final-items", Vmenu_bar_final_items,
               doc: /* List of menu bar items to move to the end of the menu 
bar.
@@ -12769,17 +12880,6 @@ This keymap works like `input-decode-map', but comes 
after `function-key-map'.
 Another difference is that it is global rather than terminal-local.  */);
   Vkey_translation_map = Fmake_sparse_keymap (Qnil);
 
-  DEFVAR_LISP ("deferred-action-list", Vdeferred_action_list,
-              doc: /* List of deferred actions to be performed at a later time.
-The precise format isn't relevant here; we just check whether it is nil.  */);
-  Vdeferred_action_list = Qnil;
-
-  DEFVAR_LISP ("deferred-action-function", Vdeferred_action_function,
-              doc: /* Function to call to handle deferred actions, after each 
command.
-This function is called with no arguments after each command
-whenever `deferred-action-list' is non-nil.  */);
-  Vdeferred_action_function = Qnil;
-
   DEFVAR_LISP ("delayed-warnings-list", Vdelayed_warnings_list,
                doc: /* List of warnings to be displayed after this command.
 Each element must be a list (TYPE MESSAGE [LEVEL [BUFFER-NAME]]),
@@ -12898,7 +12998,10 @@ This variable only has an effect when Transient Mark 
mode is enabled.
 
 If the value is `only', only temporarily active regions (usually made
 by mouse-dragging or shift-selection) set the window system's primary
-selection.  */);
+selection.
+
+If this variable causes the region to be set as the primary selection,
+`post-select-region-hook' is then run afterwards.  */);
   Vselect_active_regions = Qt;
 
   DEFVAR_LISP ("saved-region-selection",
@@ -12966,7 +13069,7 @@ Emacs allows binding both upper and lower case key 
sequences to
 commands.  However, if there is a lower case key sequence bound to a
 command, and the user enters an upper case key sequence that is not
 bound to a command, Emacs will use the lower case binding.  Setting
-this variable to nil inhibits this behaviour.  */);
+this variable to nil inhibits this behavior.  */);
   translate_upper_case_key_bindings = true;
 
   DEFVAR_BOOL ("input-pending-p-filter-events",
@@ -12992,6 +13095,27 @@ argument, which is the terminal on which the monitor 
configuration
 changed.  */);
   Vdisplay_monitors_changed_functions = Qnil;
 
+  DEFVAR_BOOL ("inhibit--record-char",
+              inhibit_record_char,
+              doc: /* If non-nil, don't record input events.
+This inhibits recording input events for the purposes of keyboard
+macros, dribble file, and `recent-keys'.
+Internal use only.  */);
+  inhibit_record_char = false;
+
+  DEFVAR_BOOL ("record-all-keys", record_all_keys,
+              doc: /* Non-nil means record all keys you type.
+When nil, the default, characters typed as part of passwords are
+not recorded.  The non-nil value countermands `inhibit--record-char',
+which see.  */);
+  record_all_keys = false;
+
+  DEFVAR_LISP ("post-select-region-hook", Vpost_select_region_hook,
+    doc: /* Abnormal hook run after the region is selected.
+This usually happens as a result of `select-active-regions'.  The hook
+is called with one argument, the string that was selected.  */);;
+  Vpost_select_region_hook = Qnil;
+
   pdumper_do_now_and_after_load (syms_of_keyboard_for_pdumper);
 }
 
@@ -13019,7 +13143,6 @@ syms_of_keyboard_for_pdumper (void)
   PDUMPER_RESET (num_input_keys, 0);
   PDUMPER_RESET (num_nonmacro_input_events, 0);
   PDUMPER_RESET_LV (Vlast_event_frame, Qnil);
-  PDUMPER_RESET_LV (Vdeferred_action_list, Qnil);
   PDUMPER_RESET_LV (Vdelayed_warnings_list, Qnil);
 
   /* Create the initial keyboard.  Qt means 'unset'.  */
@@ -13141,7 +13264,10 @@ mark_kboards (void)
     {
       /* These two special event types have no Lisp_Objects to mark.  */
       if (event->kind != SELECTION_REQUEST_EVENT
-         && event->kind != SELECTION_CLEAR_EVENT)
+#ifndef HAVE_HAIKU
+         && event->kind != SELECTION_CLEAR_EVENT
+#endif
+         )
        {
          mark_object (event->ie.x);
          mark_object (event->ie.y);
diff --git a/src/keyboard.h b/src/keyboard.h
index 6ae2dc9c4c..507d80c297 100644
--- a/src/keyboard.h
+++ b/src/keyboard.h
@@ -27,6 +27,10 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 # include "xterm.h"            /* for struct selection_input_event */
 #endif
 
+#ifdef HAVE_PGTK
+#include "pgtkterm.h"          /* for struct selection_input_event */
+#endif
+
 INLINE_HEADER_BEGIN
 
 /* Most code should use this macro to access Lisp fields in struct kboard.  */
@@ -226,7 +230,7 @@ union buffered_input_event
 {
   ENUM_BF (event_kind) kind : EVENT_KIND_WIDTH;
   struct input_event ie;
-#ifdef HAVE_X11
+#if defined HAVE_X11 || defined HAVE_PGTK
   struct selection_input_event sie;
 #endif
 };
diff --git a/src/keymap.c b/src/keymap.c
index c8b01eed6f..506b755e5d 100644
--- a/src/keymap.c
+++ b/src/keymap.c
@@ -1026,8 +1026,14 @@ DEFUN ("copy-keymap", Fcopy_keymap, Scopy_keymap, 1, 1, 
0,
        doc: /* Return a copy of the keymap KEYMAP.
 
 Note that this is almost never needed.  If you want a keymap that's like
-another yet with a few changes, you should use map inheritance rather
-than copying.  I.e. something like:
+another yet with a few changes, you should use keymap inheritance rather
+than copying.  That is, something like:
+
+    (defvar-keymap foo-map
+      :parent <theirmap>
+      ...)
+
+Or, if you need to support Emacs versions older than 29:
 
     (let ((map (make-sparse-keymap)))
       (set-keymap-parent map <theirmap>)
@@ -2596,7 +2602,10 @@ The optional 5th arg NO-REMAP alters how command 
remapping is handled:
 
 - If DEFINITION is remapped to OTHER-COMMAND, normally return the
   bindings for OTHER-COMMAND.  But if NO-REMAP is non-nil, return the
-  bindings for DEFINITION instead, ignoring its remapping.  */)
+  bindings for DEFINITION instead, ignoring its remapping.
+
+Keys that are represented as events that have a `non-key-event' non-nil
+symbol property are ignored.  */)
   (Lisp_Object definition, Lisp_Object keymap, Lisp_Object firstonly, 
Lisp_Object noindirect, Lisp_Object no_remap)
 {
   /* The keymaps in which to search.  */
@@ -2720,7 +2729,12 @@ The optional 5th arg NO-REMAP alters how command 
remapping is handled:
 
       /* It is a true unshadowed match.  Record it, unless it's already
         been seen (as could happen when inheriting keymaps).  */
-      if (NILP (Fmember (sequence, found)))
+      if (NILP (Fmember (sequence, found))
+         /* Filter out non key events.  */
+         && !(VECTORP (sequence)
+              && ASIZE (sequence) == 1
+              && SYMBOLP (AREF (sequence, 0))
+              && !NILP (Fget (AREF (sequence, 0), Qnon_key_event))))
        found = Fcons (sequence, found);
 
       /* If firstonly is Qnon_ascii, then we can return the first
@@ -3461,4 +3475,6 @@ that describe key bindings.  That is why the default is 
nil.  */);
 
   DEFSYM (Qkey_parse, "key-parse");
   DEFSYM (Qkey_valid_p, "key-valid-p");
+
+  DEFSYM (Qnon_key_event, "non-key-event");
 }
diff --git a/src/kqueue.c b/src/kqueue.c
index c3c4631784..99a9434cc2 100644
--- a/src/kqueue.c
+++ b/src/kqueue.c
@@ -159,8 +159,8 @@ kqueue_compare_dir_list (Lisp_Object watch_object)
            (watch_object, Fcons (Qwrite, Qnil), XCAR (XCDR (old_entry)), Qnil);
        /* Status change time has been changed, the file attributes
           have changed.  */
-         if (NILP (Fequal (Fnth (make_fixnum (3), old_entry),
-                           Fnth (make_fixnum (3), new_entry))))
+       if (NILP (Fequal (Fnth (make_fixnum (3), old_entry),
+                         Fnth (make_fixnum (3), new_entry))))
          kqueue_generate_event
            (watch_object, Fcons (Qattrib, Qnil),
             XCAR (XCDR (old_entry)), Qnil);
diff --git a/src/lisp.h b/src/lisp.h
index 361a3f63b2..0281c483e3 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -368,6 +368,11 @@ typedef EMACS_INT Lisp_Word;
    ((ok) ? (void) 0 : wrong_type_argument (predicate, x))
 #define lisp_h_CONSP(x) TAGGEDP (x, Lisp_Cons)
 #define lisp_h_BASE_EQ(x, y) (XLI (x) == XLI (y))
+#define lisp_h_BASE2_EQ(x, y)                              \
+  (BASE_EQ (x, y)                                          \
+   || (symbols_with_pos_enabled                                    \
+       && SYMBOL_WITH_POS_P (x)                                    \
+       && BASE_EQ (XSYMBOL_WITH_POS (x)->sym, y)))
 
 /* FIXME: Do we really need to inline the whole thing?
  * What about keeping the part after `symbols_with_pos_enabled` in
@@ -453,6 +458,7 @@ typedef EMACS_INT Lisp_Word;
 # define CHECK_TYPE(ok, predicate, x) lisp_h_CHECK_TYPE (ok, predicate, x)
 # define CONSP(x) lisp_h_CONSP (x)
 # define BASE_EQ(x, y) lisp_h_BASE_EQ (x, y)
+# define BASE2_EQ(x, y) lisp_h_BASE2_EQ (x, y)
 # define FLOATP(x) lisp_h_FLOATP (x)
 # define FIXNUMP(x) lisp_h_FIXNUMP (x)
 # define NILP(x) lisp_h_NILP (x)
@@ -1323,6 +1329,14 @@ INLINE bool
   return lisp_h_BASE_EQ (x, y);
 }
 
+/* Return true if X and Y are the same object, reckoning X to be the
+   same as a bare symbol Y if X is Y with position.  */
+INLINE bool
+(BASE2_EQ) (Lisp_Object x, Lisp_Object y)
+{
+  return lisp_h_BASE2_EQ (x, y);
+}
+
 /* Return true if X and Y are the same object, reckoning a symbol with
    position as being the same as the bare symbol.  */
 INLINE bool
@@ -1631,13 +1645,13 @@ STRING_MULTIBYTE (Lisp_Object str)
 
 /* Mark STR as a multibyte string.  Assure that STR contains only
    ASCII characters in advance.  */
-#define STRING_SET_MULTIBYTE(STR)                      \
-  do {                                                 \
-    if (XSTRING (STR)->u.s.size == 0)                  \
-      (STR) = empty_multibyte_string;                  \
-    else                                               \
-      XSTRING (STR)->u.s.size_byte = XSTRING (STR)->u.s.size; \
-  } while (false)
+INLINE void
+STRING_SET_MULTIBYTE (Lisp_Object str)
+{
+  /* The 0-length strings are unique&shared so we can't modify them.  */
+  eassert (XSTRING (str)->u.s.size > 0);
+  XSTRING (str)->u.s.size_byte = XSTRING (str)->u.s.size;
+}
 
 /* Convenience functions for dealing with Lisp strings.  */
 
@@ -3137,7 +3151,7 @@ CHECK_NUMBER (Lisp_Object x)
 INLINE void
 CHECK_INTEGER (Lisp_Object x)
 {
-  CHECK_TYPE (INTEGERP (x), Qnumberp, x);
+  CHECK_TYPE (INTEGERP (x), Qintegerp, x);
 }
 
 INLINE void
@@ -3442,7 +3456,7 @@ union specbinding
 #define WRAP_SPECPDL_REF 1
 #endif
 
-/* Abstract reference to to a specpdl entry.
+/* Abstract reference to a specpdl entry.
    The number is always a multiple of sizeof (union specbinding).  */
 #ifdef WRAP_SPECPDL_REF
 /* Use a proper type for specpdl_ref if it does not make the code slower,
@@ -3784,10 +3798,10 @@ make_symbol_constant (Lisp_Object sym)
 
 /* Buffer-local variable access functions.  */
 
-INLINE int
+INLINE bool
 blv_found (struct Lisp_Buffer_Local_Value *blv)
 {
-  eassert (blv->found == !EQ (blv->defcell, blv->valcell));
+  eassert (blv->found == !BASE_EQ (blv->defcell, blv->valcell));
   return blv->found;
 }
 
@@ -3902,10 +3916,14 @@ integer_to_uintmax (Lisp_Object num, uintmax_t *n)
 typedef intmax_t modiff_count;
 
 INLINE modiff_count
-modiff_incr (modiff_count *a)
-{
-  modiff_count a0 = *a;
-  bool modiff_overflow = INT_ADD_WRAPV (a0, 1, a);
+modiff_incr (modiff_count *a, ptrdiff_t len)
+{
+  modiff_count a0 = *a; int incr = len ? 1 : 0;
+  /* Increase the counter more for a large modification and less for a
+     small modification.  Increase it logarithmically to avoid
+     increasing it too much.  */
+  while (len >>= 1) incr++;
+  bool modiff_overflow = INT_ADD_WRAPV (a0, incr, a);
   eassert (!modiff_overflow && *a >> 30 >> 30 == 0);
   return a0;
 }
@@ -4025,6 +4043,10 @@ extern ptrdiff_t string_char_to_byte (Lisp_Object, 
ptrdiff_t);
 extern ptrdiff_t string_byte_to_char (Lisp_Object, ptrdiff_t);
 extern Lisp_Object string_to_multibyte (Lisp_Object);
 extern Lisp_Object string_make_unibyte (Lisp_Object);
+extern Lisp_Object plist_get (Lisp_Object plist, Lisp_Object prop);
+extern Lisp_Object plist_put (Lisp_Object plist, Lisp_Object prop,
+                             Lisp_Object val);
+extern Lisp_Object plist_member (Lisp_Object plist, Lisp_Object prop);
 extern void syms_of_fns (void);
 
 /* Defined in sort.c  */
@@ -4513,6 +4535,7 @@ extern Lisp_Object Vrun_hooks;
 extern Lisp_Object Vsignaling_function;
 extern Lisp_Object inhibit_lisp_code;
 extern bool signal_quit_p (Lisp_Object);
+extern bool backtrace_yet;
 
 /* To run a normal hook, use the appropriate function from the list below.
    The calling convention:
@@ -4662,6 +4685,7 @@ extern void save_restriction_restore (Lisp_Object);
 extern Lisp_Object make_buffer_string (ptrdiff_t, ptrdiff_t, bool);
 extern Lisp_Object make_buffer_string_both (ptrdiff_t, ptrdiff_t, ptrdiff_t,
                                            ptrdiff_t, bool);
+extern Lisp_Object narrow_to_region_internal (Lisp_Object, Lisp_Object, bool);
 extern void init_editfns (void);
 extern void syms_of_editfns (void);
 
@@ -4720,6 +4744,7 @@ extern bool internal_delete_file (Lisp_Object);
 extern Lisp_Object check_emacs_readlinkat (int, Lisp_Object, char const *);
 extern bool file_directory_p (Lisp_Object);
 extern bool file_accessible_directory_p (Lisp_Object);
+extern Lisp_Object buffer_visited_file_modtime (struct buffer *);
 extern void init_fileio (void);
 extern void syms_of_fileio (void);
 
@@ -4748,6 +4773,8 @@ extern ptrdiff_t fast_c_string_match_ignore_case 
(Lisp_Object, const char *,
                                                  ptrdiff_t);
 extern ptrdiff_t fast_looking_at (Lisp_Object, ptrdiff_t, ptrdiff_t,
                                   ptrdiff_t, ptrdiff_t, Lisp_Object);
+extern ptrdiff_t find_newline1 (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t,
+                               ptrdiff_t, ptrdiff_t *, ptrdiff_t *, bool);
 extern ptrdiff_t find_newline (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t,
                               ptrdiff_t, ptrdiff_t *, ptrdiff_t *, bool);
 extern void scan_newline (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t,
@@ -4809,6 +4836,8 @@ extern bool detect_input_pending (void);
 extern bool detect_input_pending_ignore_squeezables (void);
 extern bool detect_input_pending_run_timers (bool);
 extern void safe_run_hooks (Lisp_Object);
+extern void safe_run_hooks_maybe_narrowed (Lisp_Object, struct window *);
+extern void safe_run_hooks_2 (Lisp_Object, Lisp_Object, Lisp_Object);
 extern void cmd_error_internal (Lisp_Object, const char *);
 extern Lisp_Object command_loop_2 (Lisp_Object);
 extern Lisp_Object read_menu_command (void);
@@ -4828,7 +4857,7 @@ extern void syms_of_indent (void);
 /* Defined in frame.c.  */
 extern void store_frame_param (struct frame *, Lisp_Object, Lisp_Object);
 extern void store_in_alist (Lisp_Object *, Lisp_Object, Lisp_Object);
-extern Lisp_Object do_switch_frame (Lisp_Object, int, int, Lisp_Object);
+extern Lisp_Object do_switch_frame (Lisp_Object, int, Lisp_Object);
 extern Lisp_Object get_frame_param (struct frame *, Lisp_Object);
 extern void frames_discard_buffer (Lisp_Object);
 extern void init_frame_once (void);
@@ -4921,7 +4950,8 @@ extern void setup_process_coding_systems (Lisp_Object);
 #endif
 
 extern int emacs_spawn (pid_t *, int, int, int, char **, char **,
-                        const char *, const char *, const sigset_t *);
+                        const char *, const char *, bool, bool,
+                        const sigset_t *);
 extern char **make_environment_block (Lisp_Object) ATTRIBUTE_RETURNS_NONNULL;
 extern void init_callproc_1 (void);
 extern void init_callproc (void);
diff --git a/src/lread.c b/src/lread.c
index dfabe75113..06fac7185b 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -131,25 +131,15 @@ static ptrdiff_t read_from_string_limit;
 /* Position in object from which characters are being read by `readchar'.  */
 static EMACS_INT readchar_offset;
 
-/* This contains the last string skipped with #@.  */
-static char *saved_doc_string;
-/* Length of buffer allocated in saved_doc_string.  */
-static ptrdiff_t saved_doc_string_size;
-/* Length of actual data in saved_doc_string.  */
-static ptrdiff_t saved_doc_string_length;
-/* This is the file position that string came from.  */
-static file_offset saved_doc_string_position;
-
-/* This contains the previous string skipped with #@.
-   We copy it from saved_doc_string when a new string
-   is put in saved_doc_string.  */
-static char *prev_saved_doc_string;
-/* Length of buffer allocated in prev_saved_doc_string.  */
-static ptrdiff_t prev_saved_doc_string_size;
-/* Length of actual data in prev_saved_doc_string.  */
-static ptrdiff_t prev_saved_doc_string_length;
-/* This is the file position that string came from.  */
-static file_offset prev_saved_doc_string_position;
+struct saved_string {
+  char *string;                        /* string in allocated buffer */
+  ptrdiff_t size;              /* allocated size of buffer */
+  ptrdiff_t length;            /* length of string in buffer */
+  file_offset position;                /* position in file the string came 
from */
+};
+
+/* The last two strings skipped with #@ (most recent first).  */
+static struct saved_string saved_strings[2];
 
 /* A list of file names for files being loaded in Fload.  Used to
    check for recursive loads.  */
@@ -1605,13 +1595,12 @@ Return t if the file exists and loads successfully.  */)
   if (!NILP (Ffboundp (Qdo_after_load_evaluation)))
     call1 (Qdo_after_load_evaluation, hist_file_name) ;
 
-  xfree (saved_doc_string);
-  saved_doc_string = 0;
-  saved_doc_string_size = 0;
-
-  xfree (prev_saved_doc_string);
-  prev_saved_doc_string = 0;
-  prev_saved_doc_string_size = 0;
+  for (int i = 0; i < ARRAYELTS (saved_strings); i++)
+    {
+      xfree (saved_strings[i].string);
+      saved_strings[i].string = NULL;
+      saved_strings[i].size = 0;
+    }
 
   if (!noninteractive && (NILP (nomessage) || force_load_messages))
     {
@@ -1735,13 +1724,24 @@ maybe_swap_for_eln (bool no_native, Lisp_Object 
*filename, int *fd,
        {
          if (!NILP (find_symbol_value (
                       Qnative_comp_warning_on_missing_source)))
-           call2 (intern_c_string ("display-warning"),
-                  Qcomp,
-                  CALLN (Fformat,
-                         build_string ("Cannot look-up eln file as no source "
-                                       "file was found for %s"),
-                         *filename));
-         return;
+           {
+             /* If we have an installation without any .el files,
+                there's really no point in giving a warning here,
+                because that will trigger a cascade of warnings.  So
+                just do a sanity check and refuse to do anything if we
+                can't find even central .el files.  */
+             if (NILP (Flocate_file_internal (build_string ("simple.el"),
+                                              Vload_path,
+                                              Qnil, Qnil)))
+               return;
+             call2 (intern_c_string ("display-warning"),
+                    Qcomp,
+                    CALLN (Fformat,
+                           build_string ("Cannot look up eln file as "
+                                         "no source file was found for %s"),
+                           *filename));
+             return;
+           }
        }
     }
   Lisp_Object eln_rel_name = Fcomp_el_to_eln_rel_filename (src_name);
@@ -3045,7 +3045,6 @@ read_string_literal (char stackbuf[VLA_ELEMS 
(stackbufsize)],
   /* True if we saw an escape sequence specifying
      a single-byte character.  */
   bool force_singlebyte = false;
-  bool cancel = false;
   ptrdiff_t nchars = 0;
 
   int ch;
@@ -3074,8 +3073,6 @@ read_string_literal (char stackbuf[VLA_ELEMS 
(stackbufsize)],
            case ' ':
            case '\n':
              /* `\SPC' and `\LF' generate no characters at all.  */
-             if (p == read_buffer)
-               cancel = true;
              continue;
            default:
              UNREAD (ch);
@@ -3141,15 +3138,6 @@ read_string_literal (char stackbuf[VLA_ELEMS 
(stackbufsize)],
   if (ch < 0)
     end_of_file_error ();
 
-  /* If purifying, and string starts with \ newline,
-     return zero instead.  This is for doc strings
-     that we are really going to find in etc/DOC.nn.nn.  */
-  if (!NILP (Vpurify_flag) && NILP (Vdoc_file_name) && cancel)
-    {
-      unbind_to (count, Qnil);
-      return make_fixnum (0);
-    }
-
   if (!force_multibyte && force_singlebyte)
     {
       /* READ_BUFFER contains raw 8-bit bytes and no multibyte
@@ -3175,7 +3163,7 @@ hash_table_from_plist (Lisp_Object plist)
   /* This is repetitive but fast and simple.  */
 #define ADDPARAM(name)                                 \
   do {                                                 \
-    Lisp_Object val = Fplist_get (plist, Q ## name);   \
+    Lisp_Object val = plist_get (plist, Q ## name);    \
     if (!NILP (val))                                   \
       {                                                        \
        *par++ = QC ## name;                            \
@@ -3190,7 +3178,7 @@ hash_table_from_plist (Lisp_Object plist)
   ADDPARAM (rehash_threshold);
   ADDPARAM (purecopy);
 
-  Lisp_Object data = Fplist_get (plist, Qdata);
+  Lisp_Object data = plist_get (plist, Qdata);
 
   /* Now use params to make a new hash table and fill it.  */
   Lisp_Object ht = Fmake_hash_table (par - params, params);
@@ -3446,57 +3434,95 @@ skip_lazy_string (Lisp_Object readcharfun)
         record the last string that we skipped,
         and record where in the file it comes from.  */
 
-      /* But first exchange saved_doc_string
-        with prev_saved_doc_string, so we save two strings.  */
-      {
-       char *temp = saved_doc_string;
-       ptrdiff_t temp_size = saved_doc_string_size;
-       file_offset temp_pos = saved_doc_string_position;
-       ptrdiff_t temp_len = saved_doc_string_length;
-
-       saved_doc_string = prev_saved_doc_string;
-       saved_doc_string_size = prev_saved_doc_string_size;
-       saved_doc_string_position = prev_saved_doc_string_position;
-       saved_doc_string_length = prev_saved_doc_string_length;
-
-       prev_saved_doc_string = temp;
-       prev_saved_doc_string_size = temp_size;
-       prev_saved_doc_string_position = temp_pos;
-       prev_saved_doc_string_length = temp_len;
-      }
+      /* First exchange the two saved_strings.  */
+      verify (ARRAYELTS (saved_strings) == 2);
+      struct saved_string t = saved_strings[0];
+      saved_strings[0] = saved_strings[1];
+      saved_strings[1] = t;
 
       enum { extra = 100 };
-      if (saved_doc_string_size == 0)
+      struct saved_string *ss = &saved_strings[0];
+      if (ss->size == 0)
        {
-         saved_doc_string = xmalloc (nskip + extra);
-         saved_doc_string_size = nskip + extra;
+         ss->size = nskip + extra;
+         ss->string = xmalloc (ss->size);
        }
-      if (nskip > saved_doc_string_size)
+      else if (nskip > ss->size)
        {
-         saved_doc_string = xrealloc (saved_doc_string, nskip + extra);
-         saved_doc_string_size = nskip + extra;
+         ss->size = nskip + extra;
+         ss->string = xrealloc (ss->string, ss->size);
        }
 
       FILE *instream = infile->stream;
-      saved_doc_string_position = (file_tell (instream) - infile->lookahead);
+      ss->position = (file_tell (instream) - infile->lookahead);
 
-      /* Copy that many bytes into saved_doc_string.  */
+      /* Copy that many bytes into the saved string.  */
       ptrdiff_t i = 0;
       int c = 0;
       for (int n = min (nskip, infile->lookahead); n > 0; n--)
-       saved_doc_string[i++] = c = infile->buf[--infile->lookahead];
+       ss->string[i++] = c = infile->buf[--infile->lookahead];
       block_input ();
       for (; i < nskip && c >= 0; i++)
-       saved_doc_string[i] = c = getc (instream);
+       ss->string[i] = c = getc (instream);
       unblock_input ();
 
-      saved_doc_string_length = i;
+      ss->length = i;
     }
   else
     /* Skip that many bytes.  */
     skip_dyn_bytes (readcharfun, nskip);
 }
 
+/* Given a lazy-loaded string designator VAL, return the actual string.
+   VAL is (FILENAME . POS).  */
+static Lisp_Object
+get_lazy_string (Lisp_Object val)
+{
+  /* Get a doc string from the file we are loading.
+     If it's in a saved string, get it from there.
+
+     Here, we don't know if the string is a bytecode string or a doc
+     string.  As a bytecode string must be unibyte, we always return a
+     unibyte string.  If it is actually a doc string, caller must make
+     it multibyte.  */
+
+  /* We used to emit negative positions for 'user variables' (whose doc
+     strings started with an asterisk); take the absolute value for
+     compatibility.  */
+  EMACS_INT pos = eabs (XFIXNUM (XCDR (val)));
+  struct saved_string *ss = &saved_strings[0];
+  struct saved_string *ssend = ss + ARRAYELTS (saved_strings);
+  while (ss < ssend
+        && !(pos >= ss->position && pos < ss->position + ss->length))
+    ss++;
+  if (ss >= ssend)
+    return get_doc_string (val, 1, 0);
+
+  ptrdiff_t start = pos - ss->position;
+  char *str = ss->string;
+  ptrdiff_t from = start;
+  ptrdiff_t to = start;
+
+  /* Process quoting with ^A, and find the end of the string,
+     which is marked with ^_ (037).  */
+  while (str[from] != 037)
+    {
+      int c = str[from++];
+      if (c == 1)
+       {
+         c = str[from++];
+         str[to++] = (c == 1 ? c
+                      : c == '0' ? 0
+                      : c == '_' ? 037
+                      : c);
+       }
+      else
+       str[to++] = c;
+    }
+
+  return make_unibyte_string (str + start, to - start);
+}
+
 
 /* Length of prefix only consisting of symbol constituent characters.  */
 static ptrdiff_t
@@ -4238,6 +4264,15 @@ read0 (Lisp_Object readcharfun, bool locate_syms)
            XSETCDR (e->u.list.tail, obj);
            read_stack_pop ();
            obj = e->u.list.head;
+
+           /* Hack: immediately convert (#$ . FIXNUM) to the corresponding
+              string if load-force-doc-strings is set.  */
+           if (load_force_doc_strings
+               && BASE_EQ (XCAR (obj), Vload_file_name)
+               && !NILP (XCAR (obj))
+               && FIXNUMP (XCDR (obj)))
+             obj = get_lazy_string (obj);
+
            break;
          }
 
@@ -4265,7 +4300,7 @@ read0 (Lisp_Object readcharfun, bool locate_syms)
                  /* Catch silly games like #1=#1# */
                  invalid_syntax ("nonsensical self-reference", readcharfun);
 
-               /* Optimisation: since the placeholder is already
+               /* Optimization: since the placeholder is already
                   a cons, repurpose it as the actual value.
                   This allows us to skip the substitution below,
                   since the placeholder is already referenced
@@ -4855,7 +4890,7 @@ oblookup (Lisp_Object obarray, register const char *ptr, 
ptrdiff_t size, ptrdiff
   hash = hash_string (ptr, size_byte) % obsize;
   bucket = AREF (obarray, hash);
   oblookup_last_bucket_number = hash;
-  if (EQ (bucket, make_fixnum (0)))
+  if (BASE_EQ (bucket, make_fixnum (0)))
     ;
   else if (!SYMBOLP (bucket))
     /* Like CADR error message.  */
@@ -4877,7 +4912,7 @@ oblookup (Lisp_Object obarray, register const char *ptr, 
ptrdiff_t size, ptrdiff
 
 /* Like 'oblookup', but considers 'Vread_symbol_shorthands',
    potentially recognizing that IN is shorthand for some other
-   longhand name, which is then then placed in OUT.  In that case,
+   longhand name, which is then placed in OUT.  In that case,
    memory is malloc'ed for OUT (which the caller must free) while
    SIZE_OUT and SIZE_BYTE_OUT respectively hold the character and byte
    sizes of the transformed symbol name.  If IN is not recognized
diff --git a/src/macfont.m b/src/macfont.m
index 4dd55e7746..4de056cb36 100644
--- a/src/macfont.m
+++ b/src/macfont.m
@@ -929,7 +929,7 @@ macfont_descriptor_entity (CTFontDescriptorRef desc, 
Lisp_Object extra,
         cfnumber_get_font_symbolic_traits_value (num, &sym_traits);
       CFRelease (dict);
     }
-  if (EQ (AREF (entity, FONT_SIZE_INDEX), make_fixnum (0)))
+  if (BASE_EQ (AREF (entity, FONT_SIZE_INDEX), make_fixnum (0)))
     ASET (entity, FONT_AVGWIDTH_INDEX, make_fixnum (0));
   ASET (entity, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
   name = CTFontDescriptorCopyAttribute (desc, kCTFontNameAttribute);
@@ -2645,6 +2645,9 @@ macfont_open (struct frame * f, Lisp_Object entity, int 
pixel_size)
   font->pixel_size = size;
   font->driver = &macfont_driver;
   font->encoding_charset = font->repertory_charset = -1;
+  /* Clear font->space_width so macfont_monospace_width_multiplier may
+     not be confused by an uninitialized value.  */
+  font->space_width = 0;
 
   block_input ();
 
@@ -2653,7 +2656,7 @@ macfont_open (struct frame * f, Lisp_Object entity, int 
pixel_size)
   macfont_info->cgfont = CTFontCopyGraphicsFont (macfont, NULL);
 
   val = assq_no_quit (QCdestination, AREF (entity, FONT_EXTRA_INDEX));
-  if (CONSP (val) && EQ (XCDR (val), make_fixnum (1)))
+  if (CONSP (val) && BASE_EQ (XCDR (val), make_fixnum (1)))
     macfont_info->screen_font = mac_screen_font_create_with_name (font_name,
                                                                   size);
   else
diff --git a/src/marker.c b/src/marker.c
index 3c8e628762..9727586f42 100644
--- a/src/marker.c
+++ b/src/marker.c
@@ -214,11 +214,12 @@ buf_charpos_to_bytepos (struct buffer *b, ptrdiff_t 
charpos)
      We have one known above and one known below.
      Scan, counting characters, from whichever one is closer.  */
 
+  eassert (best_below <= charpos && charpos <= best_above);
   if (charpos - best_below < best_above - charpos)
     {
       bool record = charpos - best_below > 5000;
 
-      while (best_below != charpos)
+      while (best_below < charpos)
        {
          best_below++;
          best_below_byte += buf_next_char_len (b, best_below_byte);
@@ -243,7 +244,7 @@ buf_charpos_to_bytepos (struct buffer *b, ptrdiff_t charpos)
     {
       bool record = best_above - charpos > 5000;
 
-      while (best_above != charpos)
+      while (best_above > charpos)
        {
          best_above--;
          best_above_byte -= buf_prev_char_len (b, best_above_byte);
diff --git a/src/minibuf.c b/src/minibuf.c
index 1f77a6cdc1..bedc564480 100644
--- a/src/minibuf.c
+++ b/src/minibuf.c
@@ -427,8 +427,8 @@ No argument or nil as argument means use the current buffer 
as BUFFER.  */)
 {
   if (NILP (buffer))
     buffer = Fcurrent_buffer ();
-  return EQ (buffer, (Fcar (Fnthcdr (make_fixnum (minibuf_level),
-                                    Vminibuffer_list))))
+  return BASE_EQ (buffer, (Fcar (Fnthcdr (make_fixnum (minibuf_level),
+                                         Vminibuffer_list))))
     ? Qt
     : Qnil;
 }
@@ -1123,8 +1123,8 @@ read_minibuf_unwind (void)
  found:
   if (!EQ (exp_MB_frame, saved_selected_frame)
       && !NILP (exp_MB_frame))
-    do_switch_frame (exp_MB_frame, 0, 0, Qt); /* This also sets
-                                            minibuf_window */
+    do_switch_frame (exp_MB_frame, 0, Qt); /* This also sets
+                                             minibuf_window */
 
   /* To keep things predictable, in case it matters, let's be in the
      minibuffer when we reset the relevant variables.  Don't depend on
@@ -1236,7 +1236,7 @@ read_minibuf_unwind (void)
   /* Restore the selected frame. */
   if (!EQ (exp_MB_frame, saved_selected_frame)
       && !NILP (exp_MB_frame))
-    do_switch_frame (saved_selected_frame, 0, 0, Qt);
+    do_switch_frame (saved_selected_frame, 0, Qt);
 }
 
 /* Replace the expired minibuffer in frame exp_MB_frame with the next less
@@ -1545,18 +1545,6 @@ function, instead of the usual behavior.  */)
   return unbind_to (count, result);
 }
 
-static Lisp_Object
-minibuf_conform_representation (Lisp_Object string, Lisp_Object basis)
-{
-  if (STRING_MULTIBYTE (string) == STRING_MULTIBYTE (basis))
-    return string;
-
-  if (STRING_MULTIBYTE (string))
-    return Fstring_make_unibyte (string);
-  else
-    return Fstring_make_multibyte (string);
-}
-
 static bool
 match_regexps (Lisp_Object string, Lisp_Object regexps,
               bool ignore_case)
@@ -1791,10 +1779,10 @@ or from one of the possible completions.  */)
              if (bestmatchsize != SCHARS (eltstring)
                  || bestmatchsize != matchsize
                  || (completion_ignore_case
-                     && !EQ (Fcompare_strings (old_bestmatch, zero, lcompare,
-                                               eltstring, zero, lcompare,
-                                               Qnil),
-                             Qt)))
+                     && !BASE_EQ (Fcompare_strings (old_bestmatch, zero,
+                                                    lcompare, eltstring, zero,
+                                                    lcompare, Qnil),
+                                  Qt)))
                /* Don't count the same string multiple times.  */
                matchcount += matchcount <= 1;
              bestmatchsize = matchsize;
@@ -1817,7 +1805,7 @@ or from one of the possible completions.  */)
      don't change the case of what the user typed.  */
   if (completion_ignore_case && bestmatchsize == SCHARS (string)
       && SCHARS (bestmatch) > bestmatchsize)
-    return minibuf_conform_representation (string, bestmatch);
+    return string;
 
   /* Return t if the supplied string is an exact match (counting case);
      it does not require any change to be made.  */
@@ -2011,8 +1999,9 @@ REQUIRE-MATCH can take the following values:
   input, but she needs to confirm her choice if she called
   `minibuffer-complete' right before `minibuffer-complete-and-exit'
   and the input is not an element of COLLECTION.
-- a function, which will be called with the input as the parameter.
-  If it returns a non-nil value, the minibuffer is exited with that value.
+- a function, which will be called with the input as the
+  argument.  If the function returns a non-nil value, the
+  minibuffer is exited with that argument as the value.
 - anything else behaves like t except that typing RET does not exit if it
   does non-null completion.
 
@@ -2089,19 +2078,6 @@ the values STRING, PREDICATE and `lambda'.  */)
                      SSDATA (string),
                      SCHARS (string),
                      SBYTES (string));
-      if (!SYMBOLP (tem))
-       {
-         if (STRING_MULTIBYTE (string))
-           string = Fstring_make_unibyte (string);
-         else
-           string = Fstring_make_multibyte (string);
-
-         tem = oblookup (collection,
-                         SSDATA (string),
-                         SCHARS (string),
-                         SBYTES (string));
-       }
-
       if (completion_ignore_case && !SYMBOLP (tem))
        {
          for (i = ASIZE (collection) - 1; i >= 0; i--)
@@ -2110,10 +2086,11 @@ the values STRING, PREDICATE and `lambda'.  */)
              if (SYMBOLP (tail))
                while (1)
                  {
-                   if (EQ (Fcompare_strings (string, make_fixnum (0), Qnil,
-                                             Fsymbol_name (tail),
-                                             make_fixnum (0) , Qnil, Qt),
-                          Qt))
+                   if (BASE_EQ (Fcompare_strings (string, make_fixnum (0),
+                                                  Qnil,
+                                                  Fsymbol_name (tail),
+                                                  make_fixnum (0) , Qnil, Qt),
+                                Qt))
                      {
                        tem = tail;
                        break;
@@ -2144,9 +2121,9 @@ the values STRING, PREDICATE and `lambda'.  */)
             if (BASE_EQ (tem, Qunbound)) continue;
             Lisp_Object strkey = (SYMBOLP (tem) ? Fsymbol_name (tem) : tem);
             if (!STRINGP (strkey)) continue;
-            if (EQ (Fcompare_strings (string, Qnil, Qnil,
-                                      strkey, Qnil, Qnil,
-                                      completion_ignore_case ? Qt : Qnil),
+            if (BASE_EQ (Fcompare_strings (string, Qnil, Qnil,
+                                          strkey, Qnil, Qnil,
+                                          completion_ignore_case ? Qt : Qnil),
                     Qt))
               goto found_matching_key;
           }
diff --git a/src/nsfns.m b/src/nsfns.m
index 5ab2b2ee35..2699cf37a5 100644
--- a/src/nsfns.m
+++ b/src/nsfns.m
@@ -382,7 +382,7 @@ ns_set_icon_name (struct frame *f, Lisp_Object arg, 
Lisp_Object oldval)
   /* See if it's changed.  */
   if (STRINGP (arg))
     {
-      if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
+      if (STRINGP (oldval) && BASE_EQ (Fstring_equal (oldval, arg), Qt))
         return;
     }
   else if (!STRINGP (oldval) && NILP (oldval) == NILP (arg))
@@ -1057,6 +1057,7 @@ frame_parm_handler ns_frame_parm_handlers[] =
   0, /* x_set_override_redirect */
   gui_set_no_special_glyphs,
   gui_set_alpha_background,
+  NULL,
 #ifdef NS_IMPL_COCOA
   ns_set_appearance,
   ns_set_transparent_titlebar,
@@ -1726,7 +1727,7 @@ Optional arg DIR, if non-nil, supplies a default 
directory.
 Optional arg MUSTMATCH, if non-nil, means the returned file or
 directory must exist.
 Optional arg INIT, if non-nil, provides a default file name to use.
-Optional arg DIR_ONLY_P, if non-nil, means choose only directories.  */)
+Optional arg DIR-ONLY-P, if non-nil, means choose only directories.  */)
   (Lisp_Object prompt, Lisp_Object dir, Lisp_Object mustmatch,
    Lisp_Object init, Lisp_Object dir_only_p)
 {
@@ -3210,7 +3211,8 @@ x_hide_tip (bool delete)
 
 DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
        doc: /* SKIP: real doc in xfns.c.  */)
-     (Lisp_Object string, Lisp_Object frame, Lisp_Object parms, Lisp_Object 
timeout, Lisp_Object dx, Lisp_Object dy)
+  (Lisp_Object string, Lisp_Object frame, Lisp_Object parms,
+   Lisp_Object timeout, Lisp_Object dx, Lisp_Object dy)
 {
   int root_x, root_y;
   specpdl_ref count = SPECPDL_INDEX ();
@@ -3224,6 +3226,10 @@ DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
   Lisp_Object window, size, tip_buf;
   char *str;
   NSWindow *nswindow;
+  bool displayed;
+#ifdef ENABLE_CHECKING
+  struct glyph_row *row, *end;
+#endif
 
   AUTO_STRING (tip, " *tip*");
 
@@ -3287,7 +3293,6 @@ DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
       if (!NILP (tip_frame) && FRAME_LIVE_P (XFRAME (tip_frame)))
        {
          if (FRAME_VISIBLE_P (XFRAME (tip_frame))
-             && EQ (frame, tip_last_frame)
              && !NILP (Fequal_including_properties (tip_last_string, string))
              && !NILP (Fequal (tip_last_parms, parms)))
            {
@@ -3454,7 +3459,26 @@ DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
       clear_glyph_matrix (w->desired_matrix);
       clear_glyph_matrix (w->current_matrix);
       SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
-      try_window (window, pos, TRY_WINDOW_IGNORE_FONTS_CHANGE);
+      displayed = try_window (window, pos, TRY_WINDOW_IGNORE_FONTS_CHANGE);
+
+      if (!displayed && NILP (Vx_max_tooltip_size))
+       {
+#ifdef ENABLE_CHECKING
+         row = w->desired_matrix->rows;
+         end = w->desired_matrix->rows + w->desired_matrix->nrows;
+
+         while (row < end)
+           {
+             if (!row->displays_text_p
+                 || row->ends_at_zv_p)
+               break;
+             ++row;
+           }
+
+         eassert (row < end && row->ends_at_zv_p);
+#endif
+       }
+
       /* Calculate size of tooltip window.  */
       size = Fwindow_text_pixel_size (window, Qnil, Qnil, Qnil,
                                      make_fixnum (w->pixel_height), Qnil,
@@ -3889,7 +3913,7 @@ Default is t.  */);
 
   DEFVAR_LISP ("x-max-tooltip-size", Vx_max_tooltip_size,
     doc: /* SKIP: real doc in xfns.c.  */);
-  Vx_max_tooltip_size = Fcons (make_fixnum (80), make_fixnum (40));
+  Vx_max_tooltip_size = Qnil;
 
   defsubr (&Sns_read_file_name);
   defsubr (&Sns_get_resource);
diff --git a/src/nsfont.m b/src/nsfont.m
index ae5e134e15..b54118afe5 100644
--- a/src/nsfont.m
+++ b/src/nsfont.m
@@ -1763,8 +1763,11 @@ syms_of_nsfont (void)
   DEFSYM (Qcondensed, "condensed");
   DEFSYM (Qexpanded, "expanded");
   DEFSYM (Qmedium, "medium");
+
   DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script,
-               doc: /* Internal use: maps font registry to Unicode script.  
*/);
+    doc: /* Internal map of font registry to Unicode script.  */);
+  Vns_reg_to_script = Qnil;
+
   pdumper_do_now_and_after_load (syms_of_nsfont_for_pdumper);
 }
 
diff --git a/src/nsimage.m b/src/nsimage.m
index 2fff987f9f..9cb5090dd0 100644
--- a/src/nsimage.m
+++ b/src/nsimage.m
@@ -142,7 +142,7 @@ ns_load_image (struct frame *f, struct image *img,
 
   eassert (valid_image_p (img->spec));
 
-  lisp_index = Fplist_get (XCDR (img->spec), QCindex);
+  lisp_index = plist_get (XCDR (img->spec), QCindex);
   index = FIXNUMP (lisp_index) ? XFIXNAT (lisp_index) : 0;
 
   if (STRINGP (spec_file))
diff --git a/src/nsmenu.m b/src/nsmenu.m
index d02d7bae4b..ae795a0d22 100644
--- a/src/nsmenu.m
+++ b/src/nsmenu.m
@@ -207,8 +207,6 @@ ns_update_menubar (struct frame *f, bool deep_p)
 
       /* If it has changed current-menubar from previous value,
         really recompute the menubar from the value.  */
-      if (! NILP (Vlucid_menu_bar_dirty_flag))
-       call0 (Qrecompute_lucid_menubar);
       safe_run_hooks (Qmenu_bar_update_hook);
       fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
 
diff --git a/src/nsselect.m b/src/nsselect.m
index c46bfeaf42..5b47d74612 100644
--- a/src/nsselect.m
+++ b/src/nsselect.m
@@ -724,7 +724,7 @@ Return the action that the drop target actually chose to 
perform, or
 nil if no action was performed (either because there was no drop
 target, or the drop was rejected).  If RETURN-FRAME is the symbol
 `now', also return any frame that mouse moves into during the
-drag-and-drop operation, whilst simultaneously cancelling it.  Any
+drag-and-drop operation, whilst simultaneously canceling it.  Any
 other non-nil value means to do the same, but to wait for the mouse to
 leave FRAME first.
 
diff --git a/src/nsterm.h b/src/nsterm.h
index c4fdc7054f..2a4c7571a3 100644
--- a/src/nsterm.h
+++ b/src/nsterm.h
@@ -724,6 +724,7 @@ enum ns_return_frame_mode
    int em_whole;
    }
 
+- (void) mark;
 - (instancetype) initFrame: (NSRect )r window: (Lisp_Object)win;
 - (void)setFrame: (NSRect)r;
 
@@ -926,6 +927,9 @@ struct ns_output
   NSColor *cursor_color;
   NSColor *foreground_color;
   NSColor *background_color;
+  NSColor *relief_background_color;
+  NSColor *light_relief_color;
+  NSColor *dark_relief_color;
   EmacsToolbar *toolbar;
 #else
   void *view;
@@ -933,6 +937,9 @@ struct ns_output
   void *cursor_color;
   void *foreground_color;
   void *background_color;
+  void *relief_background_color;
+  void *light_relief_color;
+  void *dark_relief_color;
   void *toolbar;
 #endif
 
@@ -1373,4 +1380,7 @@ enum NSWindowTabbingMode
 #define NSBezelStyleRounded NSRoundedBezelStyle
 #define NSButtonTypeMomentaryPushIn NSMomentaryPushInButton
 #endif
+
+extern void mark_nsterm (void);
+
 #endif /* HAVE_NS */
diff --git a/src/nsterm.m b/src/nsterm.m
index 891d52ea3f..6c6151701b 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -358,7 +358,7 @@ mod_of_kind (Lisp_Object modifier, Lisp_Object kind)
     return modifier;
   else
     {
-      Lisp_Object val = Fplist_get (modifier, kind);
+      Lisp_Object val = plist_get (modifier, kind);
       return SYMBOLP (val) ? val : Qnil;
     }
 }
@@ -2900,10 +2900,7 @@ ns_define_fringe_bitmap (int which, unsigned short 
*bits, int h, int w)
   for (int y = 0 ; y < h ; y++)
     for (int x = 0 ; x < w ; x++)
       {
-        /* XBM rows are always round numbers of bytes, with any unused
-           bits ignored.  */
-        int byte = y * (w/8 + (w%8 ? 1 : 0)) + x/8;
-        bool bit = bits[byte] & (0x80 >> x%8);
+        bool bit = bits[y] & (1 << (w - x - 1));
         if (bit)
           [p appendBezierPathWithRect:NSMakeRect (x, y, 1, 1)];
       }
@@ -3103,16 +3100,21 @@ ns_draw_window_cursor (struct window *w, struct 
glyph_row *glyph_row,
     case NO_CURSOR:
       break;
     case FILLED_BOX_CURSOR:
+      /* The call to draw_phys_cursor_glyph can end up undoing the
+        ns_focus, so unfocus here and regain focus later.  */
+      [ctx restoreGraphicsState];
+      ns_unfocus (f);
       draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
+      ns_focus (f, &r, 1);
       break;
     case HOLLOW_BOX_CURSOR:
-      draw_phys_cursor_glyph (w, glyph_row, DRAW_NORMAL_TEXT);
-
       /* This works like it does in PostScript, not X Windows.  */
       [NSBezierPath strokeRect: NSInsetRect (r, 0.5, 0.5)];
+      [ctx restoreGraphicsState];
       break;
     case HBAR_CURSOR:
       NSRectFill (r);
+      [ctx restoreGraphicsState];
       break;
     case BAR_CURSOR:
       s = r;
@@ -3123,10 +3125,10 @@ ns_draw_window_cursor (struct window *w, struct 
glyph_row *glyph_row,
         s.origin.x += cursor_glyph->pixel_width - s.size.width;
 
       NSRectFill (s);
+      [ctx restoreGraphicsState];
       break;
     }
 
-  [ctx restoreGraphicsState];
   ns_unfocus (f);
 }
 
@@ -3475,6 +3477,35 @@ ns_draw_box (NSRect r, CGFloat hthickness, CGFloat 
vthickness,
     }
 }
 
+/* Set up colors for the relief lines around glyph string S.  */
+
+static void
+ns_setup_relief_colors (struct glyph_string *s)
+{
+  struct ns_output *di = FRAME_OUTPUT_DATA (s->f);
+  NSColor *color;
+
+  if (s->face->use_box_color_for_shadows_p)
+    color = [NSColor colorWithUnsignedLong: s->face->box_color];
+  else
+    color = [NSColor colorWithUnsignedLong: s->face->background];
+
+  if (s->hl == DRAW_CURSOR)
+    color = FRAME_CURSOR_COLOR (s->f);
+
+  if (color == nil)
+    color = [NSColor grayColor];
+
+  if (color != di->relief_background_color)
+    {
+      [di->relief_background_color release];
+      di->relief_background_color = [color retain];
+      [di->light_relief_color release];
+      di->light_relief_color = [[color highlightWithLevel: 0.4] retain];
+      [di->dark_relief_color release];
+      di->dark_relief_color = [[color shadowWithLevel: 0.4] retain];
+    }
+}
 
 static void
 ns_draw_relief (NSRect outer, int hthickness, int vthickness, char raised_p,
@@ -3486,40 +3517,13 @@ ns_draw_relief (NSRect outer, int hthickness, int 
vthickness, char raised_p,
     of some sides not being drawn, and because the rect will be filled.
    -------------------------------------------------------------------------- 
*/
 {
-  static NSColor *baseCol, *lightCol, *darkCol;
-  NSColor *newBaseCol;
   NSRect inner;
-  NSBezierPath *p;
-
-  baseCol = nil;
-  lightCol = nil;
-  newBaseCol = nil;
-  p = nil;
+  NSBezierPath *p = nil;
 
   NSTRACE ("ns_draw_relief");
 
   /* set up colors */
-
-  if (s->face->use_box_color_for_shadows_p)
-    newBaseCol = [NSColor colorWithUnsignedLong: s->face->box_color];
-  else
-    newBaseCol = [NSColor colorWithUnsignedLong: s->face->background];
-
-  if (s->hl == DRAW_CURSOR)
-    newBaseCol = FRAME_CURSOR_COLOR (s->f);
-
-  if (newBaseCol == nil)
-    newBaseCol = [NSColor grayColor];
-
-  if (newBaseCol != baseCol)  /* TODO: better check */
-    {
-      [baseCol release];
-      baseCol = [newBaseCol retain];
-      [lightCol release];
-      lightCol = [[baseCol highlightWithLevel: 0.4] retain];
-      [darkCol release];
-      darkCol = [[baseCol shadowWithLevel: 0.4] retain];
-    }
+  ns_setup_relief_colors (s);
 
   /* Calculate the inner rectangle.  */
   inner = outer;
@@ -3542,7 +3546,9 @@ ns_draw_relief (NSRect outer, int hthickness, int 
vthickness, char raised_p,
   if (bottom_p)
     inner.size.height -= hthickness;
 
-  [(raised_p ? lightCol : darkCol) set];
+  struct ns_output *di = FRAME_OUTPUT_DATA (s->f);
+
+  [(raised_p ? di->light_relief_color : di->dark_relief_color) set];
 
   if (top_p || left_p)
     {
@@ -3564,7 +3570,7 @@ ns_draw_relief (NSRect outer, int hthickness, int 
vthickness, char raised_p,
       [p fill];
     }
 
-  [(raised_p ? darkCol : lightCol) set];
+  [(raised_p ? di->dark_relief_color : di->light_relief_color) set];
 
   if (bottom_p || right_p)
     {
@@ -3626,7 +3632,7 @@ ns_draw_relief (NSRect outer, int hthickness, int 
vthickness, char raised_p,
                                   NSMaxY (outer) - 0.5)];
     }
 
-  [darkCol set];
+  [di->dark_relief_color set];
   [p stroke];
 
   if (vthickness > 1 && hthickness > 1)
@@ -3987,42 +3993,104 @@ ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
 
 
 static void
-ns_dumpglyphs_stretch (struct glyph_string *s)
+ns_draw_stretch_glyph_string (struct glyph_string *s)
 {
-  NSRect glyphRect;
-  struct face *face = s->face;
-  NSColor *fgCol, *bgCol;
+  struct face *face;
 
-  if (!s->background_filled_p)
+  if (s->hl == DRAW_CURSOR
+      && !x_stretch_cursor_p)
     {
+      /* If `x-stretch-cursor' is nil, don't draw a block cursor as
+        wide as the stretch glyph.  */
+      int width, background_width = s->background_width;
+      int x = s->x;
+
+      if (!s->row->reversed_p)
+       {
+         int left_x = window_box_left_offset (s->w, TEXT_AREA);
+
+         if (x < left_x)
+           {
+             background_width -= left_x - x;
+             x = left_x;
+           }
+       }
+      else
+       {
+         /* In R2L rows, draw the cursor on the right edge of the
+            stretch glyph.  */
+         int right_x = window_box_right (s->w, TEXT_AREA);
 
-      face = s->face;
+         if (x + background_width > right_x)
+           background_width -= x - right_x;
+         x += background_width;
+       }
 
-      bgCol = [NSColor colorWithUnsignedLong:NS_FACE_BACKGROUND (face)];
-      fgCol = [NSColor colorWithUnsignedLong:NS_FACE_FOREGROUND (face)];
+      width = min (FRAME_COLUMN_WIDTH (s->f), background_width);
+      if (s->row->reversed_p)
+       x -= width;
 
       if (s->hl == DRAW_CURSOR)
+       [FRAME_CURSOR_COLOR (s->f) set];
+      else
+       [[NSColor colorWithUnsignedLong: s->face->foreground] set];
+
+      NSRectFill (NSMakeRect (x, s->y, width, s->height));
+
+      /* Clear rest using the GC of the original non-cursor face.  */
+      if (width < background_width)
        {
-         fgCol = bgCol;
-         bgCol = FRAME_CURSOR_COLOR (s->f);
-       }
+         int y = s->y;
+         int w = background_width - width, h = s->height;
 
-      glyphRect = NSMakeRect (s->x, s->y, s->background_width, s->height);
+         if (!s->row->reversed_p)
+           x += width;
+         else
+           x = s->x;
 
-      [bgCol set];
+         if (s->row->mouse_face_p
+             && cursor_in_mouse_face_p (s->w))
+           {
+             face = FACE_FROM_ID_OR_NULL (s->f,
+                                          MOUSE_HL_INFO 
(s->f)->mouse_face_face_id);
 
-      NSRectFill (glyphRect);
+             if (!s->face)
+               face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
+             prepare_face_for_display (s->f, face);
 
-      /* Draw overlining, etc. on the stretch glyph (or the part of
-         the stretch glyph after the cursor).  If the glyph has a box,
-         then decorations will be drawn after drawing the box in
-         ns_draw_glyph_string, in order to prevent them from being
-         overwritten by the box.  */
-      if (s->face->box == FACE_NO_BOX)
-       ns_draw_text_decoration (s, face, fgCol, NSWidth (glyphRect),
-                                NSMinX (glyphRect));
+             [[NSColor colorWithUnsignedLong: face->background] set];
+           }
+         else
+           [[NSColor colorWithUnsignedLong: s->face->background] set];
+         NSRectFill (NSMakeRect (x, y, w, h));
+       }
+    }
+  else if (!s->background_filled_p)
+    {
+      int background_width = s->background_width;
+      int x = s->x, text_left_x = window_box_left (s->w, TEXT_AREA);
 
-      s->background_filled_p = 1;
+      /* Don't draw into left fringe or scrollbar area except for
+         header line and mode line.  */
+      if (s->area == TEXT_AREA
+         && x < text_left_x && !s->row->mode_line_p)
+       {
+         background_width -= text_left_x - x;
+         x = text_left_x;
+       }
+
+      if (!s->row->stipple_p)
+       s->row->stipple_p = s->stippled_p;
+
+      if (background_width > 0)
+       {
+         if (s->hl == DRAW_CURSOR)
+           [FRAME_CURSOR_COLOR (s->f) set];
+         else
+           [[NSColor colorWithUnsignedLong: s->face->background] set];
+
+         NSRectFill (NSMakeRect (x, s->y, background_width, s->height));
+       }
     }
 }
 
@@ -4173,6 +4241,8 @@ ns_draw_glyphless_glyph_string_foreground (struct 
glyph_string *s)
                   ? CHAR_TABLE_REF (Vglyphless_char_display,
                                     glyph->u.glyphless.ch)
                   : XCHAR_TABLE (Vglyphless_char_display)->extras[0]);
+             if (CONSP (acronym))
+               acronym = XCAR (acronym);
              if (STRINGP (acronym))
                str = SSDATA (acronym);
            }
@@ -4244,13 +4314,9 @@ ns_draw_glyph_string (struct glyph_string *s)
            n = ns_get_glyph_string_clip_rect (s->next, r);
            ns_focus (s->f, r, n);
             if (next->first_glyph->type != STRETCH_GLYPH)
-              {
-                ns_maybe_dumpglyphs_background (s->next, 1);
-              }
-            else
-              {
-                ns_dumpglyphs_stretch (s->next);
-              }
+             ns_maybe_dumpglyphs_background (s->next, 1);
+           else
+             ns_draw_stretch_glyph_string (s->next);
            ns_unfocus (s->f);
             next->num_clips = 0;
           }
@@ -4290,7 +4356,7 @@ ns_draw_glyph_string (struct glyph_string *s)
       break;
 
     case STRETCH_GLYPH:
-      ns_dumpglyphs_stretch (s);
+      ns_draw_stretch_glyph_string (s);
       break;
 
     case CHAR_GLYPH:
@@ -9924,6 +9990,16 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
   return ret;
 }
 
+- (void) mark
+{
+  if (window)
+    {
+      Lisp_Object win;
+      XSETWINDOW (win, window);
+      mark_object (win);
+    }
+}
+
 
 - (void)resetCursorRects
 {
@@ -10665,6 +10741,26 @@ ns_xlfd_to_fontname (const char *xlfd)
   return ret;
 }
 
+void
+mark_nsterm (void)
+{
+  NSTRACE ("mark_nsterm");
+  Lisp_Object tail, frame;
+  FOR_EACH_FRAME (tail, frame)
+    {
+      struct frame *f = XFRAME (frame);
+      if (FRAME_NS_P (f))
+       {
+         NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
+         for (int i = [subviews count] - 1; i >= 0; --i)
+           {
+             id scroller = [subviews objectAtIndex: i];
+             if ([scroller isKindOfClass: [EmacsScroller class]])
+                  [scroller mark];
+           }
+       }
+    }
+}
 
 void
 syms_of_nsterm (void)
@@ -10883,7 +10979,7 @@ This variable is ignored on macOS < 10.7 and GNUstep.  
Default is t.  */);
 It is called with three arguments FRAME, X, and Y, whenever the user
 moves the mouse over an Emacs frame as part of a drag-and-drop
 operation.  FRAME is the frame the mouse is on top of, and X and Y are
-the frame-relative positions of the mouse in the X and Y axises
+the frame-relative positions of the mouse in the X and Y axes
 respectively.  */);
   Vns_drag_motion_function = Qns_handle_drag_motion;
 
diff --git a/src/pdumper.c b/src/pdumper.c
index 50ae4f85e7..903298f17d 100644
--- a/src/pdumper.c
+++ b/src/pdumper.c
@@ -1210,8 +1210,8 @@ dump_queue_find_score_of_one_weight_queue (struct 
dump_queue *dump_queue,
 static Lisp_Object
 dump_queue_dequeue (struct dump_queue *dump_queue, dump_off basis)
 {
-  eassert (EQ (Fhash_table_count (dump_queue->sequence_numbers),
-               Fhash_table_count (dump_queue->link_weights)));
+  eassert (BASE_EQ (Fhash_table_count (dump_queue->sequence_numbers),
+                   Fhash_table_count (dump_queue->link_weights)));
 
   eassert (XFIXNUM (Fhash_table_count (dump_queue->sequence_numbers))
           <= (dump_tailq_length (&dump_queue->fancy_weight_objects)
@@ -2701,7 +2701,7 @@ dump_hash_table (struct dump_context *ctx,
 static dump_off
 dump_buffer (struct dump_context *ctx, const struct buffer *in_buffer)
 {
-#if CHECK_STRUCTS && !defined HASH_buffer_F8FE65D42F
+#if CHECK_STRUCTS && !defined HASH_buffer_AA373AEE10
 # error "buffer changed. See CHECK_STRUCTS comment in config.h."
 #endif
   struct buffer munged_buffer = *in_buffer;
@@ -2764,6 +2764,7 @@ 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,
@@ -2813,6 +2814,7 @@ dump_buffer (struct dump_context *ctx, const struct 
buffer *in_buffer)
   DUMP_FIELD_COPY (out, buffer, prevent_redisplay_optimizations_p);
   DUMP_FIELD_COPY (out, buffer, clip_changed);
   DUMP_FIELD_COPY (out, buffer, inhibit_buffer_hooks);
+  DUMP_FIELD_COPY (out, buffer, long_line_optimizations_p);
 
   dump_field_lv_rawptr (ctx, out, buffer, &buffer->overlays_before,
                         Lisp_Vectorlike, WEIGHT_NORMAL);
@@ -2909,6 +2911,9 @@ static dump_off
 dump_native_comp_unit (struct dump_context *ctx,
                       struct Lisp_Native_Comp_Unit *comp_u)
 {
+  if (!CONSP (comp_u->file))
+    error ("Trying to dump non fixed-up eln file");
+
   /* Have function documentation always lazy loaded to optimize load-time.  */
   comp_u->data_fdoc_v = Qnil;
   START_DUMP_PVEC (ctx, &comp_u->header, struct Lisp_Native_Comp_Unit, out);
@@ -4039,6 +4044,8 @@ types.  */)
   if (!NILP (XCDR (Fall_threads ())))
     error ("No other Lisp threads can be running when this function is 
called");
 
+  check_pure_size ();
+
   /* Clear out any detritus in memory.  */
   do
     {
diff --git a/src/pgtkfns.c b/src/pgtkfns.c
index 294bdb3791..beaf28f69d 100644
--- a/src/pgtkfns.c
+++ b/src/pgtkfns.c
@@ -613,7 +613,7 @@ pgtk_set_icon_type (struct frame *f, Lisp_Object arg, 
Lisp_Object oldval)
 
   if (STRINGP (arg))
     {
-      if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
+      if (STRINGP (oldval) && BASE_EQ (Fstring_equal (oldval, arg), Qt))
        return;
     }
   else if (!STRINGP (oldval) && NILP (oldval) == NILP (arg))
@@ -643,7 +643,7 @@ pgtk_set_icon_name (struct frame *f, Lisp_Object arg, 
Lisp_Object oldval)
 
   if (STRINGP (arg))
     {
-      if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
+      if (STRINGP (oldval) && BASE_EQ (Fstring_equal (oldval, arg), Qt))
        return;
     }
   else if (!NILP (arg) || NILP (oldval))
@@ -991,6 +991,7 @@ frame_parm_handler pgtk_frame_parm_handlers[] =
     pgtk_set_override_redirect,
     gui_set_no_special_glyphs,
     pgtk_set_alpha_background,
+    NULL,
   };
 
 
@@ -2043,7 +2044,7 @@ use `(length \(display-monitor-attributes-list 
TERMINAL))' instead.  */)
 
 
 DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 
1, 0,
-       doc: /* Return the height in millimeters of the the display TERMINAL.
+       doc: /* Return the height in millimeters of the display TERMINAL.
 The optional argument TERMINAL specifies which display to ask about.
 TERMINAL should be a terminal object, a frame or a display name (a string).
 If omitted or nil, that stands for the selected frame's display.
@@ -2084,7 +2085,7 @@ for each physical monitor, use 
`display-monitor-attributes-list'.  */)
 
 
 DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
-       doc: /* Return the width in millimeters of the the display TERMINAL.
+       doc: /* Return the width in millimeters of the display TERMINAL.
 The optional argument TERMINAL specifies which display to ask about.
 TERMINAL should be a terminal object, a frame or a display name (a string).
 If omitted or nil, that stands for the selected frame's display.
@@ -2125,7 +2126,7 @@ for each physical monitor, use 
`display-monitor-attributes-list'.  */)
 
 
 DEFUN ("x-display-backing-store", Fx_display_backing_store, 
Sx_display_backing_store, 0, 1, 0,
-       doc: /* Return an indication of whether the the display TERMINAL does 
backing store.
+       doc: /* Return an indication of whether the display TERMINAL does 
backing store.
 The value may be `buffered', `retained', or `non-retained'.
 The optional argument TERMINAL specifies which display to ask about.
 TERMINAL should be a terminal object, a frame or a display name (a string).
@@ -2138,7 +2139,7 @@ If omitted or nil, that stands for the selected frame's 
display.  */)
 
 
 DEFUN ("x-display-visual-class", Fx_display_visual_class, 
Sx_display_visual_class, 0, 1, 0,
-       doc: /* Return the visual class of the the display TERMINAL.
+       doc: /* Return the visual class of the display TERMINAL.
 The value is one of the symbols `static-gray', `gray-scale',
 `static-color', `pseudo-color', `true-color', or `direct-color'.
 
@@ -3130,6 +3131,10 @@ Text larger than the specified size is clipped.  */)
   int old_windows_or_buffers_changed = windows_or_buffers_changed;
   specpdl_ref count = SPECPDL_INDEX ();
   Lisp_Object window, size, tip_buf;
+  bool displayed;
+#ifdef ENABLE_CHECKING
+  struct glyph_row *row, *end;
+#endif
   AUTO_STRING (tip, " *tip*");
 
   specbind (Qinhibit_redisplay, Qt);
@@ -3334,7 +3339,26 @@ Text larger than the specified size is clipped.  */)
   clear_glyph_matrix (w->desired_matrix);
   clear_glyph_matrix (w->current_matrix);
   SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
-  try_window (window, pos, TRY_WINDOW_IGNORE_FONTS_CHANGE);
+  displayed = try_window (window, pos, TRY_WINDOW_IGNORE_FONTS_CHANGE);
+
+  if (!displayed && NILP (Vx_max_tooltip_size))
+    {
+#ifdef ENABLE_CHECKING
+      row = w->desired_matrix->rows;
+      end = w->desired_matrix->rows + w->desired_matrix->nrows;
+
+      while (row < end)
+       {
+         if (!row->displays_text_p
+             || row->ends_at_zv_p)
+           break;
+         ++row;
+       }
+
+      eassert (row < end && row->ends_at_zv_p);
+#endif
+    }
+
   /* Calculate size of tooltip window.  */
   size = Fwindow_text_pixel_size (window, Qnil, Qnil, Qnil,
                                  make_fixnum (w->pixel_height), Qnil,
@@ -3924,7 +3948,7 @@ syms_of_pgtkfns (void)
 
   DEFVAR_LISP ("x-max-tooltip-size", Vx_max_tooltip_size,
               doc: /* SKIP: real doc in xfns.c.  */);
-  Vx_max_tooltip_size = Fcons (make_fixnum (80), make_fixnum (40));
+  Vx_max_tooltip_size = Qnil;
 
   DEFSYM (Qmono, "mono");
   DEFSYM (Qassq_delete_all, "assq-delete-all");
diff --git a/src/pgtkmenu.c b/src/pgtkmenu.c
index 2eabf6ac1b..d147f4b416 100644
--- a/src/pgtkmenu.c
+++ b/src/pgtkmenu.c
@@ -289,8 +289,6 @@ set_frame_menubar (struct frame *f, bool deep_p)
 
       /* If it has changed current-menubar from previous value,
          really recompute the menubar from the value.  */
-      if (!NILP (Vlucid_menu_bar_dirty_flag))
-       call0 (Qrecompute_lucid_menubar);
       safe_run_hooks (Qmenu_bar_update_hook);
       fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
 
diff --git a/src/pgtkselect.c b/src/pgtkselect.c
index 76901b9eb1..212bbd56aa 100644
--- a/src/pgtkselect.c
+++ b/src/pgtkselect.c
@@ -17,16 +17,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/>.  */
 
-/* FIXME: this file needs a major rewrite to replace the use of GTK's
-   own high-level GtkClipboard API with the GDK selection API:
-
-   https://developer-old.gnome.org/gdk3/stable/gdk3-Selections.html
-
-   That way, most of the code can be shared with X, and non-text
-   targets along with drag-and-drop can be supported.  GDK implements
-   selections according to the ICCCM, as on X, but its selection API
-   will work on any supported window system.  */
-
 /* This should be the first include, as it may set up #defines affecting
    interpretation of even the system includes.  */
 #include <config.h>
@@ -35,21 +25,37 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #include "pgtkterm.h"
 #include "termhooks.h"
 #include "keyboard.h"
-#include "pgtkselect.h"
-#include <gdk/gdk.h>
-
-static GQuark quark_primary_data = 0;
-static GQuark quark_primary_size = 0;
-static GQuark quark_secondary_data = 0;
-static GQuark quark_secondary_size = 0;
-static GQuark quark_clipboard_data = 0;
-static GQuark quark_clipboard_size = 0;
-
-/* ==========================================================================
-
-    Internal utility functions
-
-   ========================================================================== 
*/
+#include "atimer.h"
+#include "blockinput.h"
+
+/* This file deliberately does not implement INCR, since it adds a
+   bunch of extra code for no real gain, as PGTK isn't supposed to
+   support X11 anyway.  */
+
+/* Advance declaration of structs.  */
+struct selection_data;
+struct prop_location;
+
+static void pgtk_decline_selection_request (struct selection_input_event *);
+static bool pgtk_convert_selection (Lisp_Object, Lisp_Object, GdkAtom, bool,
+                                   struct pgtk_display_info *);
+static bool waiting_for_other_props_on_window (GdkDisplay *, GdkWindow *);
+#if 0
+static struct prop_location *expect_property_change (GdkDisplay *, GdkWindow *,
+                                                     GdkAtom, int);
+#endif
+static void unexpect_property_change (struct prop_location *);
+static void wait_for_property_change (struct prop_location *);
+static Lisp_Object pgtk_get_window_property_as_lisp_data (struct 
pgtk_display_info *,
+                                                         GdkWindow *, GdkAtom,
+                                                         Lisp_Object, GdkAtom, 
bool);
+static Lisp_Object selection_data_to_lisp_data (struct pgtk_display_info *,
+                                               const unsigned char *,
+                                               ptrdiff_t, GdkAtom, int);
+static void lisp_data_to_selection_data (struct pgtk_display_info *, 
Lisp_Object,
+                                        struct selection_data *);
+static Lisp_Object pgtk_get_local_selection (Lisp_Object, Lisp_Object,
+                                            bool, struct pgtk_display_info *);
 
 /* From a Lisp_Object, return a suitable frame for selection
    operations.  OBJECT may be a frame, a terminal object, or nil
@@ -98,397 +104,1763 @@ frame_for_pgtk_selection (Lisp_Object object)
   return NULL;
 }
 
-static GtkClipboard *
-symbol_to_gtk_clipboard (GtkWidget * widget, Lisp_Object symbol)
+#define LOCAL_SELECTION(selection_symbol, dpyinfo)                     \
+  assq_no_quit (selection_symbol, dpyinfo->terminal->Vselection_alist)
+
+static GdkAtom
+symbol_to_gdk_atom (Lisp_Object sym)
 {
-  GdkAtom atom;
+  if (NILP (sym))
+    return GDK_NONE;
 
-  CHECK_SYMBOL (symbol);
-  if (NILP (symbol))
-    {
-      atom = GDK_SELECTION_PRIMARY;
-    }
-  else if (EQ (symbol, QCLIPBOARD))
+  if (EQ (sym, QPRIMARY))
+    return GDK_SELECTION_PRIMARY;
+  if (EQ (sym, QSECONDARY))
+    return GDK_SELECTION_SECONDARY;
+  if (EQ (sym, QCLIPBOARD))
+    return GDK_SELECTION_CLIPBOARD;
+
+  if (!SYMBOLP (sym))
+    emacs_abort ();
+
+  return gdk_atom_intern (SSDATA (SYMBOL_NAME (sym)), FALSE);
+}
+
+static Lisp_Object
+gdk_atom_to_symbol (GdkAtom atom)
+{
+  return intern (gdk_atom_name (atom));
+}
+
+
+
+/* Do protocol to assert ourself as a selection owner.
+   FRAME shall be the owner; it must be a valid GDK frame.
+   Update the Vselection_alist so that we can reply to later requests for
+   our selection.  */
+
+static void
+pgtk_own_selection (Lisp_Object selection_name, Lisp_Object selection_value,
+                   Lisp_Object frame)
+{
+  struct frame *f = XFRAME (frame);
+  struct pgtk_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
+  guint32 timestamp = gtk_get_current_event_time ();
+  GdkAtom selection_atom = symbol_to_gdk_atom (selection_name);
+  Lisp_Object targets;
+  ptrdiff_t i, ntargets;
+  GtkTargetEntry *gtargets;
+
+  if (timestamp == GDK_CURRENT_TIME)
+    timestamp = dpyinfo->last_user_time;
+
+  /* Assert ownership over the selection.  Ideally we would use only
+     the GDK selection API for this, but it just doesn't work on
+     Wayland.  */
+
+  if (!gdk_selection_owner_set_for_display (dpyinfo->display,
+                                           FRAME_GDK_WINDOW (f),
+                                           selection_atom,
+                                           timestamp, TRUE))
+    signal_error ("Could not assert ownership over selection", selection_name);
+
+  /* Update the local cache */
+  {
+    Lisp_Object selection_data;
+    Lisp_Object prev_value;
+
+    selection_data = list4 (selection_name, selection_value,
+                           INT_TO_INTEGER (timestamp), frame);
+    prev_value = LOCAL_SELECTION (selection_name, dpyinfo);
+
+    tset_selection_alist
+      (dpyinfo->terminal,
+       Fcons (selection_data, dpyinfo->terminal->Vselection_alist));
+
+    /* If we already owned the selection, remove the old selection
+       data.  Don't use Fdelq as that may quit.  */
+    if (!NILP (prev_value))
+      {
+       /* We know it's not the CAR, so it's easy.  */
+       Lisp_Object rest = dpyinfo->terminal->Vselection_alist;
+       for (; CONSP (rest); rest = XCDR (rest))
+         if (EQ (prev_value, Fcar (XCDR (rest))))
+           {
+             XSETCDR (rest, XCDR (XCDR (rest)));
+             break;
+           }
+      }
+  }
+
+  /* Announce the targets to the display server.  This isn't required
+     on X, but is on Wayland.  */
+
+  targets = pgtk_get_local_selection (selection_name, QTARGETS,
+                                     true, dpyinfo);
+
+  /* GC must not happen inside this segment.  */
+  block_input ();
+  gtk_selection_clear_targets (FRAME_GTK_WIDGET (f), selection_atom);
+
+  if (VECTORP (targets))
     {
-      atom = GDK_SELECTION_CLIPBOARD;
+      gtargets = xzalloc (sizeof *gtargets * ASIZE (targets));
+      ntargets = 0;
+
+      for (i = 0; i < ASIZE (targets); ++i)
+       {
+         if (SYMBOLP (AREF (targets, i)))
+           gtargets[ntargets++].target
+             = SSDATA (SYMBOL_NAME (AREF (targets, i)));
+       }
+
+      gtk_selection_add_targets (FRAME_GTK_WIDGET (f),
+                                selection_atom, gtargets,
+                                ntargets);
+
+      xfree (gtargets);
     }
-  else if (EQ (symbol, QPRIMARY))
+  unblock_input ();
+}
+
+static Lisp_Object
+pgtk_get_local_selection (Lisp_Object selection_symbol, Lisp_Object 
target_type,
+                         bool local_request, struct pgtk_display_info *dpyinfo)
+{
+  Lisp_Object local_value, tem;
+  Lisp_Object handler_fn, value, check;
+
+  local_value = LOCAL_SELECTION (selection_symbol, dpyinfo);
+
+  if (NILP (local_value)) return Qnil;
+
+  /* TIMESTAMP is a special case.  */
+  if (EQ (target_type, QTIMESTAMP))
     {
-      atom = GDK_SELECTION_PRIMARY;
+      handler_fn = Qnil;
+      value = XCAR (XCDR (XCDR (local_value)));
     }
-  else if (EQ (symbol, QSECONDARY))
+  else
     {
-      atom = GDK_SELECTION_SECONDARY;
+      /* Don't allow a quit within the converter.
+        When the user types C-g, he would be surprised
+        if by luck it came during a converter.  */
+      specpdl_ref count = SPECPDL_INDEX ();
+      specbind (Qinhibit_quit, Qt);
+
+      CHECK_SYMBOL (target_type);
+      handler_fn = Fcdr (Fassq (target_type, Vselection_converter_alist));
+
+      if (CONSP (handler_fn))
+       handler_fn = XCDR (handler_fn);
+
+      tem = XCAR (XCDR (local_value));
+
+      if (STRINGP (tem))
+       {
+         local_value = Fget_text_property (make_fixnum (0),
+                                           target_type, tem);
+
+         if (!NILP (local_value))
+           tem = local_value;
+       }
+
+      if (!NILP (handler_fn))
+       value = call3 (handler_fn, selection_symbol,
+                      (local_request
+                       ? Qnil
+                       : target_type),
+                      tem);
+      else
+       value = Qnil;
+      value = unbind_to (count, value);
     }
-  else if (EQ (symbol, Qt))
+
+  /* Make sure this value is of a type that we could transmit
+     to another client.  */
+
+  check = value;
+  if (CONSP (value)
+      && SYMBOLP (XCAR (value)))
+    check = XCDR (value);
+
+  if (STRINGP (check)
+      || VECTORP (check)
+      || SYMBOLP (check)
+      || INTEGERP (check)
+      || NILP (value))
+    return value;
+  /* Check for a value that CONS_TO_INTEGER could handle.  */
+  else if (CONSP (check)
+          && INTEGERP (XCAR (check))
+          && (INTEGERP (XCDR (check))
+              ||
+              (CONSP (XCDR (check))
+               && INTEGERP (XCAR (XCDR (check)))
+               && NILP (XCDR (XCDR (check))))))
+    return value;
+
+  signal_error ("Invalid data returned by selection-conversion function",
+               list2 (handler_fn, value));
+}
+
+static void
+pgtk_decline_selection_request (struct selection_input_event *event)
+{
+  gdk_selection_send_notify (SELECTION_EVENT_REQUESTOR (event),
+                            SELECTION_EVENT_SELECTION (event),
+                            SELECTION_EVENT_TARGET (event),
+                            GDK_NONE, SELECTION_EVENT_TIME (event));
+}
+
+struct selection_data
+{
+  unsigned char *data;
+  ptrdiff_t size;
+  int format;
+  GdkAtom type;
+  bool nofree;
+  GdkAtom property;
+
+  /* This can be set to non-NULL during x_reply_selection_request, if
+     the selection is waiting for an INCR transfer to complete.  Don't
+     free these; that's done by unexpect_property_change.  */
+  struct prop_location *wait_object;
+  struct selection_data *next;
+};
+
+struct pgtk_selection_request
+{
+  /* The last element in this stack.  */
+  struct pgtk_selection_request *last;
+
+  /* Its display info.  */
+  struct pgtk_display_info *dpyinfo;
+
+  /* Its selection input event.  */
+  struct selection_input_event *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.  */
+  GdkAtom conversion_fail_tag;
+
+  /* Whether or not conversion was successful.  */
+  bool converted;
+};
+
+/* Stack of selections currently being processed.
+   NULL if all requests have been fully processed.  */
+
+struct pgtk_selection_request *selection_request_stack;
+
+static void
+pgtk_push_current_selection_request (struct selection_input_event *se,
+                                    struct pgtk_display_info *dpyinfo)
+{
+  struct pgtk_selection_request *frame;
+
+  frame = xmalloc (sizeof *frame);
+  frame->converted = false;
+  frame->last = selection_request_stack;
+  frame->request = se;
+  frame->dpyinfo = dpyinfo;
+  frame->converted_selections = NULL;
+  frame->conversion_fail_tag = GDK_NONE;
+
+  selection_request_stack = frame;
+}
+
+static void
+pgtk_pop_current_selection_request (void)
+{
+  struct pgtk_selection_request *tem;
+
+  tem = selection_request_stack;
+  selection_request_stack = selection_request_stack->last;
+
+  xfree (tem);
+}
+
+/* Used as an unwind-protect clause so that, if a selection-converter signals
+   an error, we tell the requestor that we were unable to do what they wanted
+   before we throw to top-level or go into the debugger or whatever.  */
+
+static void
+pgtk_selection_request_lisp_error (void)
+{
+  struct selection_data *cs, *next;
+  struct pgtk_selection_request *frame;
+
+  frame = selection_request_stack;
+
+  for (cs = frame->converted_selections; cs; cs = next)
     {
-      atom = GDK_SELECTION_SECONDARY;
+      next = cs->next;
+      if (! cs->nofree && cs->data)
+       xfree (cs->data);
+      xfree (cs);
     }
-  else
+  frame->converted_selections = NULL;
+
+  if (!frame->converted && frame->dpyinfo->display)
+    pgtk_decline_selection_request (frame->request);
+}
+
+/* This stuff is so that INCR selections are reentrant (that is, so we can
+   be servicing multiple INCR selection requests simultaneously.)  I haven't
+   actually tested that yet.  */
+
+/* Keep a list of the property changes that are awaited.  */
+
+struct prop_location
+{
+  int identifier;
+  GdkDisplay *display;
+  GdkWindow *window;
+  GdkAtom property;
+  int desired_state;
+  bool arrived;
+  struct prop_location *next;
+};
+
+#if 0
+
+static int prop_location_identifier;
+
+#endif
+
+static Lisp_Object property_change_reply;
+
+static struct prop_location *property_change_reply_object;
+
+static struct prop_location *property_change_wait_list;
+
+static void
+set_property_change_object (struct prop_location *location)
+{
+  /* Input must be blocked so we don't get the event before we set these.  */
+  if (!input_blocked_p ())
+    emacs_abort ();
+
+  XSETCAR (property_change_reply, Qnil);
+  property_change_reply_object = location;
+}
+
+
+/* Send the reply to a selection request event EVENT.  */
+
+static void
+pgtk_reply_selection_request (struct selection_input_event *event,
+                             struct pgtk_display_info *dpyinfo)
+{
+  GdkDisplay *display = SELECTION_EVENT_DISPLAY (event);
+  GdkWindow *window = SELECTION_EVENT_REQUESTOR (event);
+  ptrdiff_t bytes_remaining;
+  struct selection_data *cs;
+  struct pgtk_selection_request *frame;
+
+  frame = selection_request_stack;
+
+  block_input ();
+  /* Loop over converted selections, storing them in the requested
+     properties.  If data is large, only store the first N bytes
+     (section 2.7.2 of ICCCM).  Note that we store the data for a
+     MULTIPLE request in the opposite order; the ICCM says only that
+     the conversion itself must be done in the same order. */
+  for (cs = frame->converted_selections; cs; cs = cs->next)
     {
-      atom = 0;
-      error ("Bad selection");
+      if (cs->property == GDK_NONE)
+       continue;
+
+      bytes_remaining = cs->size;
+      bytes_remaining *= cs->format >> 3;
+
+      gdk_property_change (window, cs->property,
+                          cs->type, cs->format,
+                          GDK_PROP_MODE_APPEND,
+                          cs->data, cs->size);
     }
 
-  return gtk_widget_get_clipboard (widget, atom);
+  /* Now issue the SelectionNotify event.  */
+  gdk_selection_send_notify (window,
+                            SELECTION_EVENT_SELECTION (event),
+                            SELECTION_EVENT_TARGET (event),
+                            SELECTION_EVENT_PROPERTY (event),
+                            SELECTION_EVENT_TIME (event));
+  gdk_display_flush (display);
+
+  /* Finish sending the rest of each of the INCR values.  This should
+     be improved; there's a chance of deadlock if more than one
+     subtarget in a MULTIPLE selection requires an INCR transfer, and
+     the requestor and Emacs loop waiting on different transfers.  */
+  for (cs = frame->converted_selections; cs; cs = cs->next)
+    if (cs->wait_object)
+      {
+       int format_bytes = cs->format / 8;
+
+        /* Must set this inside block_input ().  unblock_input may read
+           events and setting property_change_reply in
+           wait_for_property_change is then too late.  */
+        set_property_change_object (cs->wait_object);
+       unblock_input ();
+
+       bytes_remaining = cs->size;
+       bytes_remaining *= format_bytes;
+
+       /* Wait for the requestor to ack by deleting the property.
+          This can run Lisp code (process handlers) or signal.  */
+       wait_for_property_change (cs->wait_object);
+
+       /* Now write a zero-length chunk to the property to tell the
+          requestor that we're done.  */
+       block_input ();
+       if (! waiting_for_other_props_on_window (display, window))
+         gdk_window_set_events (window, 0);
+       gdk_property_change (window, cs->property, cs->type, cs->format,
+                            GDK_PROP_MODE_REPLACE, cs->data, 0);
+      }
+
+  gdk_display_sync (display);
+  unblock_input ();
 }
 
+
+
+/* Handle a SelectionRequest event EVENT.
+   This is called from keyboard.c when such an event is found in the queue.  */
+
 static void
-selection_type_to_quarks (GdkAtom type, GQuark * quark_data,
-                         GQuark * quark_size)
+pgtk_handle_selection_request (struct selection_input_event *event)
 {
-  if (type == GDK_SELECTION_PRIMARY)
+  guint32 local_selection_time;
+  struct pgtk_display_info *dpyinfo = SELECTION_EVENT_DPYINFO (event);
+  GdkAtom selection = SELECTION_EVENT_SELECTION (event);
+  Lisp_Object selection_symbol = gdk_atom_to_symbol (selection);
+  GdkAtom target = SELECTION_EVENT_TARGET (event);
+  Lisp_Object target_symbol = gdk_atom_to_symbol (target);
+  GdkAtom property = SELECTION_EVENT_PROPERTY (event);
+  Lisp_Object local_selection_data;
+  bool success = false;
+  specpdl_ref count = SPECPDL_INDEX ();
+  bool pushed;
+  Lisp_Object alias, tem;
+
+  alias = Vpgtk_selection_alias_alist;
+
+  FOR_EACH_TAIL_SAFE (alias)
     {
-      *quark_data = quark_primary_data;
-      *quark_size = quark_primary_size;
+      tem = Qnil;
+
+      if (CONSP (alias))
+       tem = XCAR (alias);
+
+      if (CONSP (tem)
+         && EQ (XCAR (tem), selection_symbol)
+         && SYMBOLP (XCDR (tem)))
+       {
+         selection_symbol = XCDR (tem);
+         break;
+       }
     }
-  else if (type == GDK_SELECTION_SECONDARY)
+
+  pushed = false;
+
+  if (!dpyinfo)
+    goto DONE;
+
+  local_selection_data = LOCAL_SELECTION (selection_symbol, dpyinfo);
+
+  /* Decline if we don't own any selections.  */
+  if (NILP (local_selection_data)) goto DONE;
+
+  /* Decline requests issued prior to our acquiring the selection.  */
+  CONS_TO_INTEGER (XCAR (XCDR (XCDR (local_selection_data))),
+                  guint32, local_selection_time);
+  if (SELECTION_EVENT_TIME (event) != GDK_CURRENT_TIME
+      && local_selection_time > SELECTION_EVENT_TIME (event))
+    goto DONE;
+
+  block_input ();
+  pushed = true;
+  pgtk_push_current_selection_request (event, dpyinfo);
+  record_unwind_protect_void (pgtk_pop_current_selection_request);
+  record_unwind_protect_void (pgtk_selection_request_lisp_error);
+  unblock_input ();
+
+  if (EQ (target_symbol, QMULTIPLE))
     {
-      *quark_data = quark_secondary_data;
-      *quark_size = quark_secondary_size;
+      /* For MULTIPLE targets, the event property names a list of atom
+        pairs; the first atom names a target and the second names a
+        non-GDK_NONE property.  */
+      GdkWindow *requestor = SELECTION_EVENT_REQUESTOR (event);
+      Lisp_Object multprop;
+      ptrdiff_t j, nselections;
+      struct selection_data cs;
+
+      if (property == GDK_NONE)
+       goto DONE;
+
+      multprop = pgtk_get_window_property_as_lisp_data (dpyinfo,
+                                                       requestor,
+                                                       property,
+                                                       QMULTIPLE,
+                                                       selection,
+                                                       true);
+
+      if (!VECTORP (multprop) || ASIZE (multprop) % 2)
+       goto DONE;
+
+      nselections = ASIZE (multprop) / 2;
+      /* Perform conversions.  This can signal.  */
+      for (j = 0; j < nselections; j++)
+       {
+         Lisp_Object subtarget = AREF (multprop, 2*j);
+         GdkAtom subproperty = symbol_to_gdk_atom (AREF (multprop, 2 * j + 1));
+         bool subsuccess = false;
+
+         if (subproperty != GDK_NONE)
+           subsuccess = pgtk_convert_selection (selection_symbol, subtarget,
+                                                subproperty, true, dpyinfo);
+         if (!subsuccess)
+           ASET (multprop, 2*j+1, Qnil);
+       }
+      /* Save conversion results */
+      lisp_data_to_selection_data (dpyinfo, multprop, &cs);
+      gdk_property_change (requestor, property,
+                          cs.type, cs.format,
+                          GDK_PROP_MODE_REPLACE,
+                          cs.data, cs.size);
+      success = true;
     }
-  else if (type == GDK_SELECTION_CLIPBOARD)
+  else
     {
-      *quark_data = quark_clipboard_data;
-      *quark_size = quark_clipboard_size;
+      if (property == GDK_NONE)
+       property = SELECTION_EVENT_TARGET (event);
+
+      success = pgtk_convert_selection (selection_symbol,
+                                       target_symbol, property,
+                                       false, dpyinfo);
     }
+
+ DONE:
+
+  if (pushed)
+    selection_request_stack->converted = true;
+
+  if (success)
+    pgtk_reply_selection_request (event, dpyinfo);
   else
-    /* FIXME: Is it safe to use 'error' here? */
-    error ("Unknown selection type.");
+    pgtk_decline_selection_request (event);
+
+  /* Run the `pgtk-sent-selection-functions' abnormal hook.  */
+  if (!NILP (Vpgtk_sent_selection_functions)
+      && !BASE_EQ (Vpgtk_sent_selection_functions, Qunbound))
+    CALLN (Frun_hook_with_args, Qpgtk_sent_selection_functions,
+          selection_symbol, target_symbol, success ? Qt : Qnil);
+
+  unbind_to (count, Qnil);
 }
 
-static void
-get_func (GtkClipboard * cb, GtkSelectionData * data, guint info,
-         gpointer user_data_or_owner)
+/* 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.
+
+   Return true if (and only if) successful.  */
+
+static bool
+pgtk_convert_selection (Lisp_Object selection_symbol,
+                       Lisp_Object target_symbol, GdkAtom property,
+                       bool for_multiple, struct pgtk_display_info *dpyinfo)
 {
-  GObject *obj = G_OBJECT (user_data_or_owner);
-  const char *str;
-  int size;
-  GQuark quark_data, quark_size;
+  Lisp_Object lisp_selection;
+  struct selection_data *cs;
+  struct pgtk_selection_request *frame;
+
+  lisp_selection
+    = pgtk_get_local_selection (selection_symbol, target_symbol,
+                               false, dpyinfo);
+
+  frame = selection_request_stack;
+
+  /* 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->format = 32;
+         cs->type = GDK_SELECTION_TYPE_ATOM;
+         cs->nofree = true;
+         cs->property = property;
+         cs->wait_object = NULL;
+         cs->next = frame->converted_selections;
+         frame->converted_selections = cs;
+       }
 
-  selection_type_to_quarks (gtk_clipboard_get_selection (cb), &quark_data,
-                           &quark_size);
+      return false;
+    }
 
-  str = g_object_get_qdata (obj, quark_data);
-  size = GPOINTER_TO_SIZE (g_object_get_qdata (obj, quark_size));
-  gtk_selection_data_set_text (data, str, size);
+  /* Otherwise, record the converted selection to binary.  */
+  cs = xmalloc (sizeof *cs);
+  cs->data = NULL;
+  cs->nofree = true;
+  cs->property = property;
+  cs->wait_object = NULL;
+  cs->next = frame->converted_selections;
+  frame->converted_selections = cs;
+  lisp_data_to_selection_data (dpyinfo, lisp_selection, cs);
+  return true;
 }
 
+
+
+/* Handle a SelectionClear event EVENT, which indicates that some
+   client cleared out our previously asserted selection.
+   This is called from keyboard.c when such an event is found in the queue.  */
+
 static void
-clear_func (GtkClipboard * cb, gpointer user_data_or_owner)
+pgtk_handle_selection_clear (struct selection_input_event *event)
 {
-  GObject *obj = G_OBJECT (user_data_or_owner);
-  GQuark quark_data, quark_size;
+  GdkAtom selection = SELECTION_EVENT_SELECTION (event);
+  guint32 changed_owner_time = SELECTION_EVENT_TIME (event);
 
-  selection_type_to_quarks (gtk_clipboard_get_selection (cb), &quark_data,
-                           &quark_size);
+  Lisp_Object selection_symbol, local_selection_data;
+  guint32 local_selection_time;
+  struct pgtk_display_info *dpyinfo = SELECTION_EVENT_DPYINFO (event);
+  Lisp_Object Vselection_alist;
 
-  g_object_set_qdata (obj, quark_data, NULL);
-  g_object_set_qdata (obj, quark_size, 0);
-}
+  if (!dpyinfo) return;
 
+  selection_symbol = gdk_atom_to_symbol (selection);
+  local_selection_data = LOCAL_SELECTION (selection_symbol, dpyinfo);
 
-/* ==========================================================================
+  /* Well, we already believe that we don't own it, so that's just fine.  */
+  if (NILP (local_selection_data)) return;
 
-    Functions used externally
+  CONS_TO_INTEGER (XCAR (XCDR (XCDR (local_selection_data))),
+                  guint32, local_selection_time);
 
-   ========================================================================== 
*/
+  /* We have reasserted the selection since this SelectionClear was
+     generated, so we can disregard it.  */
+  if (changed_owner_time != GDK_CURRENT_TIME
+      && local_selection_time > changed_owner_time)
+    return;
+
+  /* Otherwise, really clear.  Don't use Fdelq as that may quit.  */
+  Vselection_alist = dpyinfo->terminal->Vselection_alist;
+  if (EQ (local_selection_data, CAR (Vselection_alist)))
+    Vselection_alist = XCDR (Vselection_alist);
+  else
+    {
+      Lisp_Object rest;
+      for (rest = Vselection_alist; CONSP (rest); rest = XCDR (rest))
+       if (EQ (local_selection_data, CAR (XCDR (rest))))
+         {
+           XSETCDR (rest, XCDR (XCDR (rest)));
+           break;
+         }
+    }
+  tset_selection_alist (dpyinfo->terminal, Vselection_alist);
+
+  /* Run the `pgtk-lost-selection-functions' abnormal hook.  */
+  CALLN (Frun_hook_with_args, Qpgtk_lost_selection_functions, 
selection_symbol);
+
+  redisplay_preserve_echo_area (20);
+}
 
 void
-pgtk_selection_init (void)
+pgtk_handle_selection_event (struct selection_input_event *event)
+{
+  if (event->kind != SELECTION_REQUEST_EVENT)
+    pgtk_handle_selection_clear (event);
+  else
+    pgtk_handle_selection_request (event);
+}
+
+/* Clear all selections that were made from frame F.
+   We do this when about to delete a frame.  */
+
+void
+pgtk_clear_frame_selections (struct frame *f)
+{
+  Lisp_Object frame, rest, timestamp, symbol;
+  guint32 time;
+  struct pgtk_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
+  struct terminal *t = dpyinfo->terminal;
+
+  XSETFRAME (frame, f);
+
+  /* Delete elements from the beginning of Vselection_alist.  */
+  while (CONSP (t->Vselection_alist)
+        && EQ (frame, XCAR (XCDR (XCDR (XCDR (XCAR (t->Vselection_alist)))))))
+    {
+      symbol = Fcar (Fcar (t->Vselection_alist));
+
+      /* Run the `pgtk-lost-selection-functions' abnormal hook.  */
+      CALLN (Frun_hook_with_args, Qpgtk_lost_selection_functions,
+            symbol);
+
+      timestamp = Fcar (Fcdr (Fcdr (Fcar (t->Vselection_alist))));
+      CONS_TO_INTEGER (timestamp, guint32, time);
+
+      /* On Wayland, GDK will still ask the (now non-existent) frame for
+        selection data, even though we no longer think the selection is
+        owned by us.  Manually relinquish ownership of the selection.  */
+      gdk_selection_owner_set_for_display (dpyinfo->display,
+                                          NULL,
+                                          symbol_to_gdk_atom (symbol),
+                                          time, TRUE);
+
+      tset_selection_alist (t, XCDR (t->Vselection_alist));
+    }
+
+  /* Delete elements after the beginning of Vselection_alist.  */
+  for (rest = t->Vselection_alist; CONSP (rest); rest = XCDR (rest))
+    if (CONSP (XCDR (rest))
+       && EQ (frame, XCAR (XCDR (XCDR (XCDR (XCAR (XCDR (rest))))))))
+      {
+       symbol = XCAR (XCAR (XCDR (rest)));
+       CALLN (Frun_hook_with_args, Qpgtk_lost_selection_functions,
+              symbol);
+
+       timestamp = XCAR (XCDR (XCDR (XCAR (XCDR (rest)))));
+       CONS_TO_INTEGER (timestamp, guint32, time);
+
+       gdk_selection_owner_set_for_display (dpyinfo->display,
+                                            NULL,
+                                            symbol_to_gdk_atom (symbol),
+                                            time, TRUE);
+
+       XSETCDR (rest, XCDR (XCDR (rest)));
+       break;
+      }
+}
+
+/* True if any properties for DISPLAY and WINDOW
+   are on the list of what we are waiting for.  */
+
+static bool
+waiting_for_other_props_on_window (GdkDisplay *display, GdkWindow *window)
+{
+  for (struct prop_location *p = property_change_wait_list; p; p = p->next)
+    if (p->display == display && p->window == window)
+      return true;
+  return false;
+}
+
+/* Add an entry to the list of property changes we are waiting for.
+   DISPLAY, WINDOW, PROPERTY, STATE describe what we will wait for.
+   The return value is a number that uniquely identifies
+   this awaited property change.  */
+
+/* Currently unused -- uncomment later if we decide to implement INCR
+   transfer for X.  */
+
+#if 0
+
+static struct prop_location *
+expect_property_change (GdkDisplay *display, GdkWindow *window,
+                        GdkAtom property, int state)
+{
+  struct prop_location *pl = xmalloc (sizeof *pl);
+  pl->identifier = ++prop_location_identifier;
+  pl->display = display;
+  pl->window = window;
+  pl->property = property;
+  pl->desired_state = state;
+  pl->next = property_change_wait_list;
+  pl->arrived = false;
+  property_change_wait_list = pl;
+  return pl;
+}
+
+#endif
+
+/* Delete an entry from the list of property changes we are waiting for.
+   IDENTIFIER is the number that uniquely identifies the entry.  */
+
+static void
+unexpect_property_change (struct prop_location *location)
+{
+  struct prop_location *prop, **pprev = &property_change_wait_list;
+
+  for (prop = property_change_wait_list; prop; prop = *pprev)
+    {
+      if (prop == location)
+       {
+         *pprev = prop->next;
+         xfree (prop);
+         break;
+       }
+      else
+       pprev = &prop->next;
+    }
+}
+
+/* Remove the property change expectation element for IDENTIFIER.  */
+
+static void
+wait_for_property_change_unwind (void *loc)
+{
+  struct prop_location *location = loc;
+
+  unexpect_property_change (location);
+  if (location == property_change_reply_object)
+    property_change_reply_object = 0;
+}
+
+/* Actually wait for a property change.
+   IDENTIFIER should be the value that expect_property_change returned.  */
+
+static void
+wait_for_property_change (struct prop_location *location)
 {
-  if (quark_primary_data == 0)
+  specpdl_ref count = SPECPDL_INDEX ();
+
+  /* Make sure to do unexpect_property_change if we quit or err.  */
+  record_unwind_protect_ptr (wait_for_property_change_unwind, location);
+
+  /* See comment in x_reply_selection_request about setting
+     property_change_reply.  Do not do it here.  */
+
+  /* If the event we are waiting for arrives beyond here, it will set
+     property_change_reply, because property_change_reply_object says so.  */
+  if (! location->arrived)
     {
-      quark_primary_data = g_quark_from_static_string ("pgtk-primary-data");
-      quark_primary_size = g_quark_from_static_string ("pgtk-primary-size");
-      quark_secondary_data =
-       g_quark_from_static_string ("pgtk-secondary-data");
-      quark_secondary_size =
-       g_quark_from_static_string ("pgtk-secondary-size");
-      quark_clipboard_data =
-       g_quark_from_static_string ("pgtk-clipboard-data");
-      quark_clipboard_size =
-       g_quark_from_static_string ("pgtk-clipboard-size");
+      intmax_t timeout = max (0, pgtk_selection_timeout);
+      intmax_t secs = timeout / 1000;
+      int nsecs = (timeout % 1000) * 1000000;
+
+      wait_reading_process_output (secs, nsecs, 0, false,
+                                  property_change_reply, NULL, 0);
+
+      if (NILP (XCAR (property_change_reply)))
+       error ("Timed out waiting for property-notify event");
     }
+
+  unbind_to (count, Qnil);
 }
 
+/* Called from the big filter in response to a PropertyNotify
+   event.  */
+
 void
-pgtk_selection_lost (GtkWidget * widget, GdkEventSelection * event,
-                    gpointer user_data)
+pgtk_handle_property_notify (GdkEventProperty *event)
 {
-  GQuark quark_data, quark_size;
+  struct prop_location *rest;
+  GdkDisplay *dpy;
 
-  selection_type_to_quarks (event->selection, &quark_data, &quark_size);
+  dpy = gdk_window_get_display (event->window);
 
-  g_object_set_qdata (G_OBJECT (widget), quark_data, NULL);
-  g_object_set_qdata (G_OBJECT (widget), quark_size, 0);
+  for (rest = property_change_wait_list; rest; rest = rest->next)
+    {
+      if (!rest->arrived
+         && rest->property == event->atom
+         && rest->window == event->window
+         && rest->display == dpy
+         && rest->desired_state == event->state)
+       {
+         rest->arrived = true;
+
+         /* If this is the one wait_for_property_change is waiting for,
+            tell it to wake up.  */
+         if (rest == property_change_reply_object)
+           XSETCAR (property_change_reply, Qt);
+
+         return;
+       }
+    }
 }
 
-static bool
-pgtk_selection_usable (void)
+static void
+pgtk_display_selection_waiting_message (struct atimer *timer)
 {
-  if (pgtk_enable_selection_on_multi_display)
-    return true;
+  Lisp_Object val;
 
-  /* Gdk uses `gdk_display_get_default' when handling selections, so
-     selections don't work properly when Emacs is connected to
-     multiple displays.  */
+  val = build_string ("Waiting for reply from selection owner...");
+  message3_nolog (val);
+}
 
-  GdkDisplayManager *dpyman = gdk_display_manager_get ();
-  GSList *list = gdk_display_manager_list_displays (dpyman);
-  int len = g_slist_length (list);
-  g_slist_free (list);
-  return len < 2;
+static void
+pgtk_cancel_atimer (void *atimer)
+{
+  cancel_atimer (atimer);
 }
 
-/* ==========================================================================
+
+/* Variables for communication with pgtk_handle_selection_notify.  */
+static GdkAtom reading_which_selection;
+static Lisp_Object reading_selection_reply;
+static GdkWindow *reading_selection_window;
 
-    Lisp Defuns
+/* Do protocol to read selection-data from the window server.
+   Converts this to Lisp data and returns it.
+   FRAME is the frame whose window shall request the selection.  */
 
-   ========================================================================== 
*/
+static Lisp_Object
+pgtk_get_foreign_selection (Lisp_Object selection_symbol, Lisp_Object 
target_type,
+                           Lisp_Object time_stamp, Lisp_Object frame)
+{
+  struct frame *f = XFRAME (frame);
+  struct pgtk_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
+  GdkWindow *requestor_window = FRAME_GDK_WINDOW (f);
+  guint32 requestor_time = dpyinfo->last_user_time;
+  GdkAtom selection_atom = symbol_to_gdk_atom (selection_symbol);
+  GdkAtom type_atom = (CONSP (target_type)
+                      ? symbol_to_gdk_atom (XCAR (target_type))
+                      : symbol_to_gdk_atom (target_type));
+  struct atimer *delayed_message;
+  struct timespec message_interval;
+  specpdl_ref count;
+
+  count = SPECPDL_INDEX ();
+
+  if (!FRAME_LIVE_P (f))
+    return unbind_to (count, Qnil);
+
+  if (!NILP (time_stamp))
+    CONS_TO_INTEGER (time_stamp, guint32, requestor_time);
+
+  block_input ();
+  /* Prepare to block until the reply has been read.  */
+  reading_selection_window = requestor_window;
+  reading_which_selection = selection_atom;
+  XSETCAR (reading_selection_reply, Qnil);
+
+  gdk_selection_convert (requestor_window, selection_atom,
+                        type_atom, requestor_time);
+  unblock_input ();
+
+  /* It should not be necessary to stop handling selection requests
+     during this time.  In fact, the SAVE_TARGETS mechanism requires
+     us to handle a clipboard manager's requests before it returns
+     GDK_SELECTION_NOTIFY. */
+
+  message_interval = make_timespec (1, 0);
+  delayed_message = start_atimer (ATIMER_RELATIVE, message_interval,
+                                 pgtk_display_selection_waiting_message,
+                                 NULL);
+  record_unwind_protect_ptr (pgtk_cancel_atimer, delayed_message);
+
+  /* This allows quits.  Also, don't wait forever.  */
+  intmax_t timeout = max (0, pgtk_selection_timeout);
+  intmax_t secs = timeout / 1000;
+  int nsecs = (timeout % 1000) * 1000000;
+
+  wait_reading_process_output (secs, nsecs, 0, false,
+                              reading_selection_reply, NULL, 0);
+
+  if (NILP (XCAR (reading_selection_reply)))
+    error ("Timed out waiting for reply from selection owner");
+  if (EQ (XCAR (reading_selection_reply), Qlambda))
+    return unbind_to (count, Qnil);
+
+  /* Otherwise, the selection is waiting for us on the requested property.  */
+  return unbind_to (count,
+                   pgtk_get_window_property_as_lisp_data (dpyinfo,
+                                                          requestor_window,
+                                                          GDK_NONE,
+                                                          target_type,
+                                                          selection_atom,
+                                                          false));
+}
 
+/* Subroutines of pgtk_get_window_property_as_lisp_data */
 
-DEFUN ("pgtk-own-selection-internal", Fpgtk_own_selection_internal, 
Spgtk_own_selection_internal, 2, 3, 0,
-       doc: /* Assert an X selection of type SELECTION and value VALUE.
-SELECTION is a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD'.
-\(Those are literal upper-case symbol names, since that's what X expects.)
-VALUE is typically a string, or a cons of two markers, but may be
-anything that the functions on `selection-converter-alist' know about.
+static ptrdiff_t
+pgtk_size_for_format (gint format)
+{
+  switch (format)
+    {
+    case 8:
+      return sizeof (unsigned char);
+    case 16:
+      return sizeof (unsigned short);
+    case 32:
+      return sizeof (unsigned long);
+
+    default:
+      emacs_abort ();
+    }
+}
 
-FRAME should be a frame that should own the selection.  If omitted or
-nil, it defaults to the selected frame. */)
-  (Lisp_Object selection, Lisp_Object value, Lisp_Object frame)
+/* Use xfree, not g_free, to free the data obtained with this function.  */
+
+static void
+pgtk_get_window_property (GdkWindow *window, unsigned char **data_ret,
+                         ptrdiff_t *bytes_ret, GdkAtom *actual_type_ret,
+                         int *actual_format_ret, unsigned long 
*actual_size_ret)
 {
-  Lisp_Object successful_p = Qnil;
-  Lisp_Object target_symbol, rest;
-  GtkClipboard *cb;
-  struct frame *f;
-  GQuark quark_data, quark_size;
+  gint length, actual_format;
+  unsigned char *data;
+  ptrdiff_t element_size;
+  void *xdata;
+  GdkAtom actual_type;
+  unsigned long i;
+  unsigned int *idata;
+  unsigned long *ldata;
+
+  data = NULL;
+
+  length = gdk_selection_property_get (window, &data,
+                                      &actual_type,
+                                      &actual_format);
+
+  if (!data)
+    {
+      *data_ret = NULL;
+      *actual_type_ret = GDK_NONE;
+      *bytes_ret = 0;
+      *actual_format_ret = 8;
+      *actual_size_ret = 0;
 
-  check_window_system (NULL);
+      return;
+    }
 
-  if (!pgtk_selection_usable ())
-    return Qnil;
+  if (actual_type == GDK_SELECTION_TYPE_ATOM
+      || actual_type == gdk_atom_intern_static_string ("ATOM_PAIR"))
+    {
+      /* GDK should not allow anything else.  */
+      eassert (actual_format == 32);
 
-  if (NILP (frame))
-    frame = selected_frame;
-  if (!FRAME_LIVE_P (XFRAME (frame)) || !FRAME_PGTK_P (XFRAME (frame)))
-    error ("pgtk selection unavailable for this frame");
-  f = XFRAME (frame);
+      length = length / sizeof (GdkAtom);
+      xdata = xmalloc (sizeof (GdkAtom) * length + 1);
+      memcpy (xdata, data, 1 + length * sizeof (GdkAtom));
 
-  cb = symbol_to_gtk_clipboard (FRAME_GTK_WIDGET (f), selection);
-  selection_type_to_quarks (gtk_clipboard_get_selection (cb), &quark_data,
-                           &quark_size);
+      g_free (data);
+
+      *data_ret = xdata;
+      *actual_type_ret = actual_type;
+      *bytes_ret = length * sizeof (GdkAtom);
+      *actual_format_ret = 32;
+      *actual_size_ret = length;
+
+      return;
+    }
 
-  /* We only support copy of text.  */
-  target_symbol = QTEXT;
-  if (STRINGP (value))
+  element_size = pgtk_size_for_format (actual_format);
+  length = length / element_size;
+
+  /* Add an extra byte on the end.  GDK guarantees that it is
+     NULL.  */
+  xdata = xmalloc (1 + element_size * length);
+  memcpy (xdata, data, 1 + element_size * length);
+
+  if (actual_format == 32 && LONG_WIDTH > 32)
     {
-      GtkTargetList *list;
-      GtkTargetEntry *targets;
-      gint n_targets;
-      GtkWidget *widget;
+      ldata = (typeof (ldata)) data;
+      idata = xdata;
 
-      list = gtk_target_list_new (NULL, 0);
-      gtk_target_list_add_text_targets (list, 0);
+      for (i = 0; i < length; ++i)
+       idata[i] = ldata[i];
 
-      {
-       /* text/plain: Strings encoded by Gtk are not correctly decoded by 
Chromium(Wayland). */
-       GdkAtom atom_text_plain = gdk_atom_intern ("text/plain", false);
-       gtk_target_list_remove (list, atom_text_plain);
-      }
+      /* There is always enough space in idata.  */
+      idata[length] = 0;
+      *bytes_ret = sizeof *idata * length;
+    }
+  else
+    /* I think GDK itself prevents element_size from exceeding the
+       length at which this computation fails.  */
+    *bytes_ret = element_size * length;
+
+  /* Now free the original `data' allocated by GDK.  */
+  g_free (data);
+
+  *data_ret = xdata;
+  *actual_type_ret = GDK_NONE;
+  *actual_size_ret = length;
+  *actual_format_ret = actual_format;
+  *actual_type_ret = actual_type;
+}
+
+static Lisp_Object
+pgtk_get_window_property_as_lisp_data (struct pgtk_display_info *dpyinfo,
+                                      GdkWindow *window, GdkAtom property,
+                                      Lisp_Object target_type, GdkAtom 
selection_atom,
+                                      bool for_multiple)
+{
+  GdkAtom actual_type;
+  int actual_format;
+  unsigned long actual_size;
+  unsigned char *data = 0;
+  ptrdiff_t bytes = 0;
+  Lisp_Object val;
+  GdkDisplay *display = dpyinfo->display;
+
+  pgtk_get_window_property (window, &data, &bytes,
+                           &actual_type, &actual_format,
+                           &actual_size);
+
+  if (!data)
+    {
+      if (for_multiple)
+       return Qnil;
+
+      if (gdk_selection_owner_get_for_display (display, selection_atom))
+       {
+         AUTO_STRING (format, "Selection owner couldn't convert: %s");
+         CALLN (Fmessage, format,
+                actual_type
+                ? list2 (target_type,
+                         gdk_atom_to_symbol (actual_type))
+                : target_type);
+         return Qnil;
+       }
+      else
+       {
+         AUTO_STRING (format, "No selection: %s");
+         CALLN (Fmessage, format,
+                gdk_atom_to_symbol (selection_atom));
+         return Qnil;
+       }
+    }
+
+  if (!for_multiple && property != GDK_NONE)
+    gdk_property_delete (window, property);
 
-      targets = gtk_target_table_new_from_list (list, &n_targets);
+  /* It's been read.  Now convert it to a lisp object in some semi-rational
+     manner.  */
+  val = selection_data_to_lisp_data (dpyinfo, data, bytes,
+                                    actual_type, actual_format);
 
-      int size = SBYTES (value);
-      gchar *str = xmalloc (size + 1);
-      memcpy (str, SSDATA (value), size);
-      str[size] = '\0';
+  /* Use xfree, not g_free, because pgtk_get_window_property calls
+     xmalloc itself.  */
+  xfree (data);
+  return val;
+}
 
-      widget = FRAME_GTK_WIDGET (f);
-      g_object_set_qdata_full (G_OBJECT (widget), quark_data, str, xfree);
-      g_object_set_qdata_full (G_OBJECT (widget), quark_size,
-                              GSIZE_TO_POINTER (size), NULL);
+
+
+/* These functions convert from the selection data read from the
+   server into something that we can use from Lisp, and vice versa.
+
+       Type:   Format: Size:           Lisp Type:
+       -----   ------- -----           -----------
+       *       8       *               String
+       ATOM    32      1               Symbol
+       ATOM    32      > 1             Vector of Symbols
+       *       16      1               Integer
+       *       16      > 1             Vector of Integers
+       *       32      1               Integer
+       *       32      > 1             Vector of the above
+
+   When converting an object to C, it may be of the form (SYMBOL
+   . <data>) where SYMBOL is what we should claim that the type is.
+   Format and representation are as above.
+
+   Important: When format is 32, data should contain an array of int,
+   not an array of long as GDK returns.  Unless TYPE is also
+   GDK_SELECTION_TYPE_ATOM, in which case data should be an array of
+   GdkAtom.  This makes a difference when sizeof (long) != sizeof
+   (int).  */
+
+static Lisp_Object
+selection_data_to_lisp_data (struct pgtk_display_info *dpyinfo,
+                            const unsigned char *data,
+                            ptrdiff_t size, GdkAtom type, int format)
+{
+  if (type == gdk_atom_intern_static_string ("NULL"))
+    return QNULL;
+  /* Convert any 8-bit data to a string, for compactness.  */
+  else if (format == 8)
+    {
+      Lisp_Object str, lispy_type;
 
-      if (gtk_clipboard_set_with_owner (cb,
-                                       targets, n_targets,
-                                       get_func, clear_func,
-                                       G_OBJECT (FRAME_GTK_WIDGET (f))))
+      str = make_unibyte_string ((char *) data, size);
+      /* Indicate that this string is from foreign selection by a text
+        property `foreign-selection' so that the caller of
+        x-get-selection-internal (usually x-get-selection) can know
+        that the string must be decode.  */
+      if (type == gdk_atom_intern_static_string ("COMPOUND_TEXT"))
+       lispy_type = QCOMPOUND_TEXT;
+      else if (type == gdk_atom_intern_static_string ("UTF8_STRING"))
+       lispy_type = QUTF8_STRING;
+      else
+       lispy_type = QSTRING;
+
+      Fput_text_property (make_fixnum (0), make_fixnum (size),
+                         Qforeign_selection, lispy_type, str);
+      return str;
+    }
+  /* Convert a single atom to a Lisp_Symbol.  Convert a set of atoms to
+     a vector of symbols.  */
+  else if (format == 32
+          && (type == GDK_SELECTION_TYPE_ATOM
+              /* Treat ATOM_PAIR type similar to list of atoms.  */
+              || type == gdk_atom_intern_static_string ("ATOM_PAIR")))
+    {
+      ptrdiff_t i;
+      GdkAtom *idata = (GdkAtom *) data;
+
+      if (size == sizeof (GdkAtom))
+       return gdk_atom_to_symbol (idata[0]);
+      else
        {
-         successful_p = Qt;
+         Lisp_Object v = make_nil_vector (size / sizeof (GdkAtom));
+
+         for (i = 0; i < size / sizeof (GdkAtom); i++)
+           ASET (v, i, gdk_atom_to_symbol (idata[i]));
+         return v;
        }
-      gtk_clipboard_set_can_store (cb, NULL, 0);
+    }
+
+  /* Convert a single 16-bit number or a small 32-bit number to a Lisp_Int.
+     If the number is 32 bits and won't fit in a Lisp_Int, convert it
+     to a bignum.
+
+     INTEGER is a signed type, CARDINAL is unsigned.
+     Assume any other types are unsigned as well.
+   */
+  else if (format == 32 && size == sizeof (int))
+    {
+      if (type == GDK_SELECTION_TYPE_INTEGER)
+        return INT_TO_INTEGER (((int *) data) [0]);
+      else
+        return INT_TO_INTEGER (((unsigned int *) data) [0]);
+    }
+  else if (format == 16 && size == sizeof (short))
+    {
+      if (type == GDK_SELECTION_TYPE_INTEGER)
+        return make_fixnum (((short *) data) [0]);
+      else
+        return make_fixnum (((unsigned short *) data) [0]);
+    }
+  /* Convert any other kind of data to a vector of numbers, represented
+     as above (as an integer, or a cons of two 16 bit integers.)
+   */
+  else if (format == 16)
+    {
+      ptrdiff_t i;
+      Lisp_Object v = make_uninit_vector (size / 2);
+
+      if (type == GDK_SELECTION_TYPE_INTEGER)
+        {
+          for (i = 0; i < size / 2; i++)
+            {
+              short j = ((short *) data) [i];
+              ASET (v, i, make_fixnum (j));
+            }
+        }
+      else
+        {
+          for (i = 0; i < size / 2; i++)
+            {
+             unsigned short j = ((unsigned short *) data) [i];
+              ASET (v, i, make_fixnum (j));
+            }
+        }
+      return v;
+    }
+  else
+    {
+      ptrdiff_t i;
+      Lisp_Object v = make_nil_vector (size / sizeof (gint));
+
+      if (type == GDK_SELECTION_TYPE_INTEGER)
+        {
+          for (i = 0; i < size / sizeof (gint); i++)
+            {
+              int j = ((gint *) data) [i];
+              ASET (v, i, INT_TO_INTEGER (j));
+            }
+        }
+      else
+        {
+          for (i = 0; i < size / sizeof (gint); i++)
+            {
+             unsigned int j = ((unsigned int *) data) [i];
+              ASET (v, i, INT_TO_INTEGER (j));
+            }
+        }
+      return v;
+    }
+}
 
-      gtk_target_table_free (targets, n_targets);
-      gtk_target_list_unref (list);
+/* Convert OBJ to an X long value, and return it as unsigned long.
+   OBJ should be an integer or a cons representing an integer.
+   Treat values in the range X_LONG_MAX + 1 .. X_ULONG_MAX as X
+   unsigned long values: in theory these values are supposed to be
+   signed but in practice unsigned 32-bit data are communicated via X
+   selections and we need to support that.  */
+static unsigned long
+cons_to_gdk_long (Lisp_Object obj)
+{
+  if (G_MAXUINT32 <= INTMAX_MAX
+      || NILP (Fnatnump (CONSP (obj) ? XCAR (obj) : obj)))
+    return cons_to_signed (obj, 0, min (G_MAXUINT32, INTMAX_MAX));
+  else
+    return cons_to_unsigned (obj, G_MAXUINT32);
+}
+
+/* Use xfree, not XFree, to free the data obtained with this function.  */
+
+static void
+lisp_data_to_selection_data (struct pgtk_display_info *dpyinfo,
+                            Lisp_Object obj, struct selection_data *cs)
+{
+  Lisp_Object type = Qnil;
+
+  eassert (cs != NULL);
+  cs->nofree = false;
+
+  if (CONSP (obj) && SYMBOLP (XCAR (obj)))
+    {
+      type = XCAR (obj);
+      obj = XCDR (obj);
+      if (CONSP (obj) && NILP (XCDR (obj)))
+       obj = XCAR (obj);
+    }
+
+  if (EQ (obj, QNULL) || (EQ (type, QNULL)))
+    {                          /* This is not the same as declining */
+      cs->format = 32;
+      cs->size = 0;
+      cs->data = NULL;
+      type = QNULL;
+    }
+  else if (STRINGP (obj))
+    {
+      if (SCHARS (obj) < SBYTES (obj))
+       /* OBJ is a multibyte string containing a non-ASCII char.  */
+       signal_error ("Non-ASCII string must be encoded in advance", obj);
+      if (NILP (type))
+       type = QSTRING;
+      cs->format = 8;
+      cs->size = SBYTES (obj);
+      cs->data = SDATA (obj);
+      cs->nofree = true;
+    }
+  else if (SYMBOLP (obj))
+    {
+      void *data = xmalloc (sizeof (GdkAtom) + 1);
+      GdkAtom *x_atom_ptr = data;
+      cs->data = data;
+      cs->format = 32;
+      cs->size = 1;
+      cs->data[sizeof (GdkAtom)] = 0;
+      *x_atom_ptr = symbol_to_gdk_atom (obj);
+      if (NILP (type)) type = QATOM;
+    }
+  else if (RANGED_FIXNUMP (SHRT_MIN, obj, SHRT_MAX))
+    {
+      void *data = xmalloc (sizeof (short) + 1);
+      short *short_ptr = data;
+      cs->data = data;
+      cs->format = 16;
+      cs->size = 1;
+      cs->data[sizeof (short)] = 0;
+      *short_ptr = XFIXNUM (obj);
+      if (NILP (type)) type = QINTEGER;
+    }
+  else if (INTEGERP (obj)
+          || (CONSP (obj) && INTEGERP (XCAR (obj))
+              && (FIXNUMP (XCDR (obj))
+                  || (CONSP (XCDR (obj))
+                      && FIXNUMP (XCAR (XCDR (obj)))))))
+    {
+      void *data = xmalloc (sizeof (unsigned long) + 1);
+      unsigned long *x_long_ptr = data;
+      cs->data = data;
+      cs->format = 32;
+      cs->size = 1;
+      cs->data[sizeof (unsigned long)] = 0;
+      *x_long_ptr = cons_to_gdk_long (obj);
+      if (NILP (type)) type = QINTEGER;
     }
+  else if (VECTORP (obj))
+    {
+      /* Lisp_Vectors may represent a set of ATOMs;
+        a set of 16 or 32 bit INTEGERs;
+        or a set of ATOM_PAIRs (represented as [[A1 A2] [A3 A4] ...]
+       */
+      ptrdiff_t i;
+      ptrdiff_t size = ASIZE (obj);
+
+      if (SYMBOLP (AREF (obj, 0)))
+       /* This vector is an ATOM set */
+       {
+         void *data;
+         GdkAtom *x_atoms;
+         if (NILP (type)) type = QATOM;
+         for (i = 0; i < size; i++)
+           if (!SYMBOLP (AREF (obj, i)))
+             signal_error ("All elements of selection vector must have same 
type", obj);
+
+         cs->data = data = xnmalloc (size, sizeof *x_atoms);
+         x_atoms = data;
+         cs->format = 32;
+         cs->size = size;
+         for (i = 0; i < size; i++)
+           x_atoms[i] = symbol_to_gdk_atom (AREF (obj, i));
+       }
+      else
+       /* This vector is an INTEGER set, or something like it */
+       {
+         int format = 16;
+         int data_size = sizeof (short);
+         void *data;
+         unsigned long *x_atoms;
+         short *shorts;
+         if (NILP (type)) type = QINTEGER;
+         for (i = 0; i < size; i++)
+           {
+             if (! RANGED_FIXNUMP (SHRT_MIN, AREF (obj, i), SHRT_MAX))
+               {
+                 /* Use sizeof (long) even if it is more than 32 bits.
+                    See comment in x_get_window_property and
+                    x_fill_property_data.  */
+                 data_size = sizeof (long);
+                 format = 32;
+                 break;
+               }
+           }
+         cs->data = data = xnmalloc (size, data_size);
+         x_atoms = data;
+         shorts = data;
+         cs->format = format;
+         cs->size = size;
+         for (i = 0; i < size; i++)
+           {
+             if (format == 32)
+               x_atoms[i] = cons_to_gdk_long (AREF (obj, i));
+             else
+               shorts[i] = XFIXNUM (AREF (obj, i));
+           }
+       }
+    }
+  else
+    signal_error (/* Qselection_error */ "Unrecognized selection data", obj);
 
-  if (!BASE_EQ (Vpgtk_sent_selection_hooks, Qunbound))
+  cs->type = symbol_to_gdk_atom (type);
+}
+
+static Lisp_Object
+clean_local_selection_data (Lisp_Object obj)
+{
+  if (CONSP (obj)
+      && INTEGERP (XCAR (obj))
+      && CONSP (XCDR (obj))
+      && FIXNUMP (XCAR (XCDR (obj)))
+      && NILP (XCDR (XCDR (obj))))
+    obj = Fcons (XCAR (obj), XCDR (obj));
+
+  if (CONSP (obj)
+      && INTEGERP (XCAR (obj))
+      && FIXNUMP (XCDR (obj)))
     {
-      /* FIXME: Use run-hook-with-args!  */
-      for (rest = Vpgtk_sent_selection_hooks; CONSP (rest);
-          rest = Fcdr (rest))
-       call3 (Fcar (rest), selection, target_symbol, successful_p);
+      if (BASE_EQ (XCAR (obj), make_fixnum (0)))
+       return XCDR (obj);
+      if (BASE_EQ (XCAR (obj), make_fixnum (-1)))
+       return make_fixnum (- XFIXNUM (XCDR (obj)));
     }
+  if (VECTORP (obj))
+    {
+      ptrdiff_t i;
+      ptrdiff_t size = ASIZE (obj);
+      Lisp_Object copy;
+      if (size == 1)
+       return clean_local_selection_data (AREF (obj, 0));
+      copy = make_nil_vector (size);
+      for (i = 0; i < size; i++)
+       ASET (copy, i, clean_local_selection_data (AREF (obj, i)));
+      return copy;
+    }
+  return obj;
+}
+
+DEFUN ("pgtk-own-selection-internal", Fpgtk_own_selection_internal,
+       Spgtk_own_selection_internal, 2, 3, 0,
+       doc: /* Assert a selection of type SELECTION and value VALUE.
+SELECTION is a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD'.
+\(Those are literal upper-case symbol names, since that's what GDK expects.)
+VALUE is typically a string, or a cons of two markers, but may be
+anything that the functions on `selection-converter-alist' know about.
+
+FRAME should be a frame that should own the selection.  If omitted or
+nil, it defaults to the selected frame.  */)
+  (Lisp_Object selection, Lisp_Object value, Lisp_Object frame)
+{
+  if (NILP (frame)) frame = selected_frame;
+  if (!FRAME_LIVE_P (XFRAME (frame)) || !FRAME_PGTK_P (XFRAME (frame)))
+    error ("GDK selection unavailable for this frame");
 
+  CHECK_SYMBOL (selection);
+  if (NILP (value)) error ("VALUE may not be nil");
+  pgtk_own_selection (selection, value, frame);
   return value;
 }
 
+/* Request the selection value from the owner.  If we are the owner,
+   simply return our selection value.  If we are not the owner, this
+   will block until all of the data has arrived.  */
 
-DEFUN ("pgtk-disown-selection-internal", Fpgtk_disown_selection_internal,
-       Spgtk_disown_selection_internal, 1, 2, 0,
-       doc: /* If we own the selection SELECTION, disown it.
-Disowning it means there is no such selection.
+DEFUN ("pgtk-get-selection-internal", Fpgtk_get_selection_internal,
+       Spgtk_get_selection_internal, 2, 4, 0,
+       doc: /* Return text selected from some X window.
+SELECTION-SYMBOL is typically `PRIMARY', `SECONDARY', or `CLIPBOARD'.
+\(Those are literal upper-case symbol names, since that's what X expects.)
+TARGET-TYPE is the type of data desired, typically `STRING'.
+
+TIME-STAMP is the time to use in the XConvertSelection call for foreign
+selections.  If omitted, defaults to the time for the last event.
 
 TERMINAL should be a terminal object or a frame specifying the X
 server to query.  If omitted or nil, that stands for the selected
 frame's display, or the first available X display.  */)
-  (Lisp_Object selection, Lisp_Object terminal)
+  (Lisp_Object selection_symbol, Lisp_Object target_type,
+   Lisp_Object time_stamp, Lisp_Object terminal)
 {
+  Lisp_Object val = Qnil;
+  Lisp_Object maybe_alias;
   struct frame *f = frame_for_pgtk_selection (terminal);
-  GtkClipboard *cb;
 
-  if (!pgtk_selection_usable ())
-    return Qnil;
+  CHECK_SYMBOL (selection_symbol);
+  CHECK_SYMBOL (target_type);
 
+  if (EQ (target_type, QMULTIPLE))
+    error ("Retrieving MULTIPLE selections is currently unimplemented");
   if (!f)
-    return Qnil;
+    error ("GDK selection unavailable for this frame");
 
-  cb = symbol_to_gtk_clipboard (FRAME_GTK_WIDGET (f), selection);
+  /* Quitting inside this function is okay, so we don't have to use
+     FOR_EACH_TAIL_SAFE.  */
+  maybe_alias = Fassq (selection_symbol, Vpgtk_selection_alias_alist);
 
-  gtk_clipboard_clear (cb);
+  if (!NILP (maybe_alias))
+    {
+      selection_symbol = XCDR (maybe_alias);
+      CHECK_SYMBOL (selection_symbol);
+    }
 
-  return Qt;
+  val = pgtk_get_local_selection (selection_symbol, target_type, true,
+                                 FRAME_DISPLAY_INFO (f));
+
+  if (NILP (val) && FRAME_LIVE_P (f))
+    {
+      Lisp_Object frame;
+      XSETFRAME (frame, f);
+      return pgtk_get_foreign_selection (selection_symbol, target_type,
+                                        time_stamp, frame);
+    }
+
+  if (CONSP (val) && SYMBOLP (XCAR (val)))
+    {
+      val = XCDR (val);
+      if (CONSP (val) && NILP (XCDR (val)))
+       val = XCAR (val);
+    }
+  return clean_local_selection_data (val);
 }
 
+DEFUN ("pgtk-disown-selection-internal", Fpgtk_disown_selection_internal,
+       Spgtk_disown_selection_internal, 1, 3, 0,
+       doc: /* If we own the selection SELECTION, disown it.
+Disowning it means there is no such selection.
 
-DEFUN ("pgtk-selection-exists-p", Fpgtk_selection_exists_p, 
Spgtk_selection_exists_p, 0, 2, 0,
-       doc: /* Whether there is an owner for the given X selection.
-SELECTION should be the name of the selection in question, typically
-one of the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.  (X expects
-these literal upper-case names.)  The symbol nil is the same as
-`PRIMARY', and t is the same as `SECONDARY'.
+Sets the last-change time for the selection to TIME-OBJECT (by default
+the time of the last event).
 
 TERMINAL should be a terminal object or a frame specifying the X
 server to query.  If omitted or nil, that stands for the selected
-frame's display, or the first available X display.
-
-On Nextstep, TERMINAL is unused.  */)
-  (Lisp_Object selection, Lisp_Object terminal)
+frame's display, or the first available X display.  */)
+  (Lisp_Object selection, Lisp_Object time_object, Lisp_Object terminal)
 {
+  guint32 timestamp;
+  GdkAtom selection_atom;
   struct frame *f = frame_for_pgtk_selection (terminal);
-  GtkClipboard *cb;
+  struct pgtk_display_info *dpyinfo;
 
-  if (!pgtk_selection_usable ())
+  if (!f)
     return Qnil;
 
-  if (!f)
+  dpyinfo = FRAME_DISPLAY_INFO (f);
+  CHECK_SYMBOL (selection);
+
+  /* Don't disown the selection when we're not the owner.  */
+  if (NILP (LOCAL_SELECTION (selection, dpyinfo)))
     return Qnil;
 
-  cb = symbol_to_gtk_clipboard (FRAME_GTK_WIDGET (f), selection);
+  selection_atom = symbol_to_gdk_atom (selection);
 
-  return gtk_clipboard_wait_is_text_available (cb) ? Qt : Qnil;
-}
+  block_input ();
+  if (NILP (time_object))
+    timestamp = dpyinfo->last_user_time;
+  else
+    CONS_TO_INTEGER (time_object, guint32, timestamp);
+  gdk_selection_owner_set_for_display (dpyinfo->display, NULL,
+                                      selection_atom, timestamp,
+                                      TRUE);
+  unblock_input ();
 
+  return Qt;
+}
 
-DEFUN ("pgtk-selection-owner-p", Fpgtk_selection_owner_p, 
Spgtk_selection_owner_p, 0, 2, 0,
-       doc: /* Whether the current Emacs process owns the given X Selection.
+DEFUN ("pgtk-selection-owner-p", Fpgtk_selection_owner_p, 
Spgtk_selection_owner_p,
+       0, 2, 0,
+       doc: /* Whether the current Emacs process owns the given selection.
 The arg should be the name of the selection in question, typically one of
 the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.
-\(Those are literal upper-case symbol names, since that's what X expects.)
+\(Those are literal upper-case symbol names, since that's what GDK expects.)
 For convenience, the symbol nil is the same as `PRIMARY',
 and t is the same as `SECONDARY'.
 
-TERMINAL should be a terminal object or a frame specifying the X
+TERMINAL should be a terminal object or a frame specifying the GDK
 server to query.  If omitted or nil, that stands for the selected
-frame's display, or the first available X display.
-
-On Nextstep, TERMINAL is unused.  */)
+frame's display, or the first available X display.  */)
   (Lisp_Object selection, Lisp_Object terminal)
 {
   struct frame *f = frame_for_pgtk_selection (terminal);
-  GtkClipboard *cb;
-  GObject *obj;
-  GQuark quark_data, quark_size;
 
-  if (!pgtk_selection_usable ())
-    return Qnil;
+  CHECK_SYMBOL (selection);
+  if (NILP (selection)) selection = QPRIMARY;
+  if (EQ (selection, Qt)) selection = QSECONDARY;
 
-  cb = symbol_to_gtk_clipboard (FRAME_GTK_WIDGET (f), selection);
-  selection_type_to_quarks (gtk_clipboard_get_selection (cb), &quark_data,
-                           &quark_size);
-
-  obj = gtk_clipboard_get_owner (cb);
-
-  return obj && g_object_get_qdata (obj, quark_data) != NULL ? Qt : Qnil;
+  if (f && !NILP (LOCAL_SELECTION (selection, FRAME_DISPLAY_INFO (f))))
+    return Qt;
+  else
+    return Qnil;
 }
 
+DEFUN ("pgtk-selection-exists-p", Fpgtk_selection_exists_p, 
Spgtk_selection_exists_p,
+       0, 2, 0,
+       doc: /* Whether there is an owner for the given selection.
+SELECTION should be the name of the selection in question, typically
+one of the symbols `PRIMARY', `SECONDARY', `CLIPBOARD', or
+`CLIPBOARD_MANAGER' (GDK expects these literal upper-case names.)  The
+symbol nil is the same as `PRIMARY', and t is the same as `SECONDARY'.
 
-DEFUN ("pgtk-get-selection-internal", Fpgtk_get_selection_internal,
-       Spgtk_get_selection_internal, 2, 3, 0,
-       doc: /* Return text selected from some program.
-SELECTION-SYMBOL is typically `PRIMARY', `SECONDARY', or `CLIPBOARD'.
-\(Those are literal upper-case symbol names, since that's what X expects.)
-TARGET-TYPE is the type of data desired, typically `STRING'.
-
-TERMINAL should be a terminal object or a frame specifying the X
+TERMINAL should be a terminal object or a frame specifying the GDK
 server to query.  If omitted or nil, that stands for the selected
-frame's display, or the first available display.  */)
-  (Lisp_Object selection_symbol, Lisp_Object target_type,
-   Lisp_Object terminal)
+frame's display, or the first available X display.  */)
+  (Lisp_Object selection, Lisp_Object terminal)
 {
+  GdkWindow *owner;
+  GdkAtom atom;
   struct frame *f = frame_for_pgtk_selection (terminal);
-  GtkClipboard *cb;
+  struct pgtk_display_info *dpyinfo;
 
-  CHECK_SYMBOL (selection_symbol);
-  CHECK_SYMBOL (target_type);
+  CHECK_SYMBOL (selection);
+  if (NILP (selection)) selection = QPRIMARY;
+  if (EQ (selection, Qt)) selection = QSECONDARY;
 
-  if (EQ (target_type, QMULTIPLE))
-    error ("Retrieving MULTIPLE selections is currently unimplemented");
   if (!f)
-    error ("PGTK selection unavailable for this frame");
-
-  if (!pgtk_selection_usable ())
     return Qnil;
 
-  cb = symbol_to_gtk_clipboard (FRAME_GTK_WIDGET (f), selection_symbol);
+  dpyinfo = FRAME_DISPLAY_INFO (f);
 
-  GdkAtom target_atom = gdk_atom_intern (SSDATA (SYMBOL_NAME (target_type)), 
false);
-  GtkSelectionData *seldata = gtk_clipboard_wait_for_contents (cb, 
target_atom);
+  if (!NILP (LOCAL_SELECTION (selection, dpyinfo)))
+    return Qt;
 
-  if (seldata == NULL)
-    return Qnil;
+  atom = symbol_to_gdk_atom (selection);
+  if (atom == 0) return Qnil;
+  block_input ();
+  owner = gdk_selection_owner_get_for_display (dpyinfo->display, atom);
+  unblock_input ();
+  return (owner ? Qt : Qnil);
+}
+
+/* Called to handle GDK_SELECTION_NOTIFY events.
+   If it's the selection we are waiting for, stop waiting
+   by setting the car of reading_selection_reply to non-nil.
+   We store t there if the reply is successful, lambda if not.  */
 
-  const guchar *sd_data = gtk_selection_data_get_data (seldata);
-  int sd_len = gtk_selection_data_get_length (seldata);
-  int sd_format = gtk_selection_data_get_format (seldata);
-  GdkAtom sd_type = gtk_selection_data_get_data_type (seldata);
+void
+pgtk_handle_selection_notify (GdkEventSelection *event)
+{
+  /* GDK doesn't populate event->requestor, contrary to what the ICCCM
+     says should be done with SelectionNotify events.  */
 
-  if (sd_format == 8)
+  if (event->selection != reading_which_selection)
+    return;
+
+  XSETCAR (reading_selection_reply,
+          (event->property != GDK_NONE ? Qt : Qlambda));
+}
+
+
+/***********************************************************************
+                      Drag and drop support
+***********************************************************************/
+
+DEFUN ("pgtk-register-dnd-targets", Fpgtk_register_dnd_targets,
+       Spgtk_register_dnd_targets, 2, 2, 0,
+       doc: /* Register TARGETS on FRAME.
+TARGETS should be a list of strings describing data types (selection
+targets) that can be dropped on top of FRAME.  */)
+  (Lisp_Object frame, Lisp_Object targets)
+{
+  struct frame *f;
+  GtkTargetEntry *entries;
+  GtkTargetList *list;
+  ptrdiff_t length, n;
+  Lisp_Object tem, t;
+  char *buf;
+  USE_SAFE_ALLOCA;
+
+  f = decode_window_system_frame (frame);
+  CHECK_LIST (targets);
+  length = list_length (targets);
+  n = 0;
+  entries = SAFE_ALLOCA (sizeof *entries * length);
+  memset (entries, 0, sizeof *entries * length);
+  tem = targets;
+
+  FOR_EACH_TAIL (tem)
     {
-      Lisp_Object str, lispy_type;
+      if (!CONSP (tem))
+       continue;
 
-      str = make_unibyte_string ((char *) sd_data, sd_len);
-      /* Indicate that this string is from foreign selection by a text
-        property `foreign-selection' so that the caller of
-        x-get-selection-internal (usually x-get-selection) can know
-        that the string must be decode.  */
-      if (sd_type == gdk_atom_intern ("COMPOUND_TEXT", false))
-       lispy_type = QCOMPOUND_TEXT;
-      else if (sd_type == gdk_atom_intern ("UTF8_STRING", false))
-       lispy_type = QUTF8_STRING;
-      else if (sd_type == gdk_atom_intern ("text/plain;charset=utf-8", false))
-       lispy_type = Qtext_plain_charset_utf_8;
-      else
-       lispy_type = QSTRING;
-      Fput_text_property (make_fixnum (0), make_fixnum (sd_len),
-                         Qforeign_selection, lispy_type, str);
+      t = XCAR (tem);
 
-      gtk_selection_data_free (seldata);
-      return str;
+      CHECK_STRING (t);
+      SAFE_ALLOCA_STRING (buf, t);
+
+      entries[n++].target = buf;
     }
+  CHECK_LIST_END (tem, targets);
+
+  if (n != length)
+    emacs_abort ();
+
+  list = gtk_target_list_new (entries, n);
+  gtk_drag_dest_set_target_list (FRAME_GTK_WIDGET (f), list);
+  gtk_target_list_unref (list);
+
+  SAFE_FREE ();
+
+  return Qnil;
+}
+
+DEFUN ("pgtk-drop-finish", Fpgtk_drop_finish, Spgtk_drop_finish, 3, 3, 0,
+       doc: /* Finish the drag-n-drop event that happened at TIMESTAMP.
+SUCCESS is whether or not the drop was successful, i.e. the action
+chosen in the last call to `pgtk-update-drop-status' was performed.
+TIMESTAMP is the time associated with the drag-n-drop event that is
+being finished.
+DELETE is whether or not the action was `move'.  */)
+  (Lisp_Object success, Lisp_Object timestamp, Lisp_Object delete)
+{
+  pgtk_finish_drop (success, timestamp, delete);
+
+  return Qnil;
+}
+
+DEFUN ("pgtk-update-drop-status", Fpgtk_update_drop_status,
+       Spgtk_update_drop_status, 2, 2, 0,
+       doc: /* Update the status of the current drag-and-drop operation.
+ACTION is the action the drop source should take.
+TIMESTAMP is the same as in `pgtk-drop-finish'.  */)
+  (Lisp_Object action, Lisp_Object timestamp)
+{
+  pgtk_update_drop_status (action, timestamp);
 
-  gtk_selection_data_free (seldata);
   return Qnil;
 }
 
@@ -499,19 +1871,56 @@ syms_of_pgtkselect (void)
   DEFSYM (QSECONDARY, "SECONDARY");
   DEFSYM (QTEXT, "TEXT");
   DEFSYM (QFILE_NAME, "FILE_NAME");
+  DEFSYM (QSTRING, "STRING");
+  DEFSYM (QINTEGER, "INTEGER");
+  DEFSYM (QTIMESTAMP, "TIMESTAMP");
+  DEFSYM (QTEXT, "TEXT");
   DEFSYM (QMULTIPLE, "MULTIPLE");
-
-  DEFSYM (Qforeign_selection, "foreign-selection");
+  DEFSYM (QNULL, "NULL");
+  DEFSYM (QATOM, "ATOM");
+  DEFSYM (QTARGETS, "TARGETS");
   DEFSYM (QUTF8_STRING, "UTF8_STRING");
-  DEFSYM (QSTRING, "STRING");
   DEFSYM (QCOMPOUND_TEXT, "COMPOUND_TEXT");
-  DEFSYM (Qtext_plain_charset_utf_8, "text/plain;charset=utf-8");
+
+  DEFSYM (Qforeign_selection, "foreign-selection");
+
+  DEFSYM (Qpgtk_sent_selection_functions, "pgtk-sent-selection-functions");
+  DEFSYM (Qpgtk_lost_selection_functions, "pgtk-lost-selection-functions");
 
   defsubr (&Spgtk_disown_selection_internal);
   defsubr (&Spgtk_get_selection_internal);
   defsubr (&Spgtk_own_selection_internal);
   defsubr (&Spgtk_selection_exists_p);
   defsubr (&Spgtk_selection_owner_p);
+  defsubr (&Spgtk_register_dnd_targets);
+  defsubr (&Spgtk_update_drop_status);
+  defsubr (&Spgtk_drop_finish);
+
+  DEFVAR_LISP ("selection-converter-alist", Vselection_converter_alist,
+              doc: /* SKIP: real doc in xselect.c.  */);
+  Vselection_converter_alist = Qnil;
+
+  DEFVAR_LISP ("pgtk-lost-selection-functions", Vpgtk_lost_selection_functions,
+              doc: /* A list of functions to be called when Emacs loses a 
selection.
+\(This happens when some other client makes its own selection
+or when a Lisp program explicitly clears the selection.)
+The functions are called with one argument, the selection type
+\(a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD').  */);
+  Vpgtk_lost_selection_functions = Qnil;
+
+  DEFVAR_LISP ("pgtk-sent-selection-functions", Vpgtk_sent_selection_functions,
+              doc: /* A list of functions to be called when Emacs answers a 
selection request.
+The functions are called with three arguments:
+  - the selection name (typically `PRIMARY', `SECONDARY', or `CLIPBOARD');
+  - the selection-type which Emacs was asked to convert the
+    selection into before sending (for example, `STRING' or `LENGTH');
+  - a flag indicating success or failure for responding to the request.
+We might have failed (and declined the request) for any number of reasons,
+including being asked for a selection that we no longer own, or being asked
+to convert into a type that we don't know about or that is inappropriate.
+xThis hook doesn't let you change the behavior of Emacs's selection replies,
+it merely informs you that they have happened.  */);
+  Vpgtk_sent_selection_functions = Qnil;
 
   DEFVAR_LISP ("pgtk-sent-selection-hooks", Vpgtk_sent_selection_hooks,
               doc: /* A list of functions to be called when Emacs answers a 
selection request
@@ -527,10 +1936,24 @@ This hook doesn't let you change the behavior of Emacs's 
selection replies,
 it merely informs you that they have happened.  */);
   Vpgtk_sent_selection_hooks = Qnil;
 
-  DEFVAR_BOOL ("pgtk-enable-selection-on-multi-display", 
pgtk_enable_selection_on_multi_display,
-              doc: /* Enable selections when connected to multiple displays.
-This may cause crashes due to a GTK bug, which assumes that clients
-will connect to a single display.  It might also cause selections to
-not arrive at the correct display.  */);
-  pgtk_enable_selection_on_multi_display = false;
+  DEFVAR_INT ("pgtk-selection-timeout", pgtk_selection_timeout,
+             doc: /* Number of milliseconds to wait for a selection reply.
+If the selection owner doesn't reply in this time, we give up.
+A value of 0 means wait as long as necessary.  */);
+  pgtk_selection_timeout = 0;
+
+  DEFVAR_LISP ("pgtk-selection-alias-alist", Vpgtk_selection_alias_alist,
+    doc: /* List of selections to alias to another.
+It should be an alist of a selection name to another.  When a
+selection request arrives for the first selection, Emacs will respond
+as if the request was meant for the other.
+
+Note that this does not affect setting or owning selections.  */);
+  Vpgtk_selection_alias_alist = Qnil;
+
+  reading_selection_reply = Fcons (Qnil, Qnil);
+  staticpro (&reading_selection_reply);
+
+  property_change_reply = Fcons (Qnil, Qnil);
+  staticpro (&property_change_reply);
 }
diff --git a/src/pgtkselect.h b/src/pgtkselect.h
deleted file mode 100644
index fd9910b2d1..0000000000
--- a/src/pgtkselect.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/* Definitions and headers for selection of pure Gtk+3.
-   Copyright (C) 1989, 1993, 2005, 2008-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/>.  */
-
-
-#include "dispextern.h"
-#include "frame.h"
-
-#ifdef HAVE_PGTK
-
-#include <gtk/gtk.h>
-
-extern void pgtk_selection_init (void);
-extern void pgtk_selection_lost (GtkWidget *, GdkEventSelection *, gpointer);
-
-#endif /* HAVE_PGTK */
diff --git a/src/pgtkterm.c b/src/pgtkterm.c
index da958a6664..491ba33882 100644
--- a/src/pgtkterm.c
+++ b/src/pgtkterm.c
@@ -61,7 +61,6 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #include "buffer.h"
 #include "font.h"
 #include "xsettings.h"
-#include "pgtkselect.h"
 #include "emacsgtkfixed.h"
 
 #ifdef GDK_WINDOWING_WAYLAND
@@ -77,25 +76,36 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 
 static bool any_help_event_p;
 
-struct pgtk_display_info *x_display_list;      /* Chain of existing displays */
-extern Lisp_Object tip_frame;
+/* Chain of existing displays */
+struct pgtk_display_info *x_display_list;
 
-static struct event_queue_t
+struct event_queue_t
 {
   union buffered_input_event *q;
   int nr, cap;
-} event_q = {
-  NULL, 0, 0,
 };
 
+/* A queue of events that will be read by the read_socket_hook.  */
+static struct event_queue_t event_q;
+
 /* Non-zero timeout value means ignore next mouse click if it arrives
    before that timeout elapses (i.e. as part of the same sequence of
    events resulting from clicking on a frame to select it).  */
-
 static Time ignore_next_mouse_click_timeout;
 
+/* The default Emacs icon .  */
 static Lisp_Object xg_default_icon_file;
 
+/* The current GdkDragContext of a drop.  */
+static GdkDragContext *current_drop_context;
+
+/* Whether or not current_drop_context was set from a drop
+   handler.  */
+static bool current_drop_context_drop;
+
+/* The time of the last drop.  */
+static guint32 current_drop_time;
+
 static void pgtk_delete_display (struct pgtk_display_info *);
 static void pgtk_clear_frame_area (struct frame *, int, int, int, int);
 static void pgtk_fill_rectangle (struct frame *, unsigned long, int, int,
@@ -290,6 +300,9 @@ static void
 evq_enqueue (union buffered_input_event *ev)
 {
   struct event_queue_t *evq = &event_q;
+  struct frame *frame;
+  struct pgtk_display_info *dpyinfo;
+
   if (evq->cap == 0)
     {
       evq->cap = 4;
@@ -303,6 +316,27 @@ evq_enqueue (union buffered_input_event *ev)
     }
 
   evq->q[evq->nr++] = *ev;
+
+  if (ev->ie.kind != SELECTION_REQUEST_EVENT
+      && ev->ie.kind != SELECTION_CLEAR_EVENT)
+    {
+      frame = NULL;
+
+      if (WINDOWP (ev->ie.frame_or_window))
+       frame = WINDOW_XFRAME (XWINDOW (ev->ie.frame_or_window));
+
+      if (FRAMEP (ev->ie.frame_or_window))
+       frame = XFRAME (ev->ie.frame_or_window);
+
+      if (frame)
+       {
+         dpyinfo = FRAME_DISPLAY_INFO (frame);
+
+         if (dpyinfo->last_user_time < ev->ie.timestamp)
+           dpyinfo->last_user_time = ev->ie.timestamp;
+       }
+    }
+
   raise (SIGIO);
 }
 
@@ -1550,6 +1584,8 @@ pgtk_draw_glyphless_glyph_string_foreground (struct 
glyph_string *s)
                   ? CHAR_TABLE_REF (Vglyphless_char_display,
                                     glyph->u.glyphless.ch)
                   : XCHAR_TABLE (Vglyphless_char_display)->extras[0]);
+             if (CONSP (acronym))
+               acronym = XCAR (acronym);
              if (STRINGP (acronym))
                str = SSDATA (acronym);
            }
@@ -4809,16 +4845,16 @@ pgtk_any_window_to_frame (GdkWindow *window)
     return NULL;
 
   FOR_EACH_FRAME (tail, frame)
-  {
-    if (found)
-      break;
-    f = XFRAME (frame);
-    if (FRAME_PGTK_P (f))
-      {
-       if (pgtk_window_is_of_frame (f, window))
-         found = f;
-      }
-  }
+    {
+      if (found)
+       break;
+      f = XFRAME (frame);
+      if (FRAME_PGTK_P (f))
+       {
+         if (pgtk_window_is_of_frame (f, window))
+           found = f;
+       }
+    }
 
   return found;
 }
@@ -5420,15 +5456,18 @@ window_state_event (GtkWidget *widget,
                    gpointer *user_data)
 {
   struct frame *f = pgtk_any_window_to_frame (event->window_state.window);
+  GdkWindowState new_state;
   union buffered_input_event inev;
 
+  new_state = event->window_state.new_window_state;
+
   EVENT_INIT (inev.ie);
   inev.ie.kind = NO_EVENT;
   inev.ie.arg = Qnil;
 
   if (f)
     {
-      if (event->window_state.new_window_state & GDK_WINDOW_STATE_FOCUSED)
+      if (new_state & GDK_WINDOW_STATE_FOCUSED)
        {
          if (FRAME_ICONIFIED_P (f))
            {
@@ -5444,17 +5483,24 @@ window_state_event (GtkWidget *widget,
        }
     }
 
-  if (event->window_state.new_window_state
-      & GDK_WINDOW_STATE_FULLSCREEN)
+  if (new_state & GDK_WINDOW_STATE_FULLSCREEN)
     store_frame_param (f, Qfullscreen, Qfullboth);
-  else if (event->window_state.new_window_state
-          & GDK_WINDOW_STATE_MAXIMIZED)
+  else if (new_state & GDK_WINDOW_STATE_MAXIMIZED)
     store_frame_param (f, Qfullscreen, Qmaximized);
+  else if ((new_state & GDK_WINDOW_STATE_TOP_TILED)
+          && (new_state & GDK_WINDOW_STATE_BOTTOM_TILED)
+          && !(new_state & GDK_WINDOW_STATE_TOP_RESIZABLE)
+          && !(new_state & GDK_WINDOW_STATE_BOTTOM_RESIZABLE))
+    store_frame_param (f, Qfullscreen, Qfullheight);
+  else if ((new_state & GDK_WINDOW_STATE_LEFT_TILED)
+          && (new_state & GDK_WINDOW_STATE_RIGHT_TILED)
+          && !(new_state & GDK_WINDOW_STATE_LEFT_RESIZABLE)
+          && !(new_state & GDK_WINDOW_STATE_RIGHT_RESIZABLE))
+    store_frame_param (f, Qfullscreen, Qfullwidth);
   else
     store_frame_param (f, Qfullscreen, Qnil);
 
-  if (event->window_state.new_window_state
-      & GDK_WINDOW_STATE_ICONIFIED)
+  if (new_state & GDK_WINDOW_STATE_ICONIFIED)
     SET_FRAME_ICONIFIED (f, true);
   else
     {
@@ -5464,8 +5510,7 @@ window_state_event (GtkWidget *widget,
       SET_FRAME_ICONIFIED (f, false);
     }
 
-  if (event->window_state.new_window_state
-      & GDK_WINDOW_STATE_STICKY)
+  if (new_state & GDK_WINDOW_STATE_STICKY)
     store_frame_param (f, Qsticky, Qt);
   else
     store_frame_param (f, Qsticky, Qnil);
@@ -5868,8 +5913,7 @@ construct_mouse_click (struct input_event *result,
 }
 
 static gboolean
-button_event (GtkWidget *widget,
-             GdkEvent *event,
+button_event (GtkWidget *widget, GdkEvent *event,
              gpointer *user_data)
 {
   union buffered_input_event inev;
@@ -6124,40 +6168,219 @@ scroll_event (GtkWidget *widget, GdkEvent *event, 
gpointer *user_data)
   return TRUE;
 }
 
+
+
+/* C part of drop handling code.
+   The Lisp part is in pgtk-dnd.el.  */
+
+static GdkDragAction
+symbol_to_drag_action (Lisp_Object act)
+{
+  if (EQ (act, Qcopy))
+    return GDK_ACTION_COPY;
+
+  if (EQ (act, Qmove))
+    return GDK_ACTION_MOVE;
+
+  if (EQ (act, Qlink))
+    return GDK_ACTION_LINK;
+
+  if (EQ (act, Qprivate))
+    return GDK_ACTION_PRIVATE;
+
+  if (NILP (act))
+    return GDK_ACTION_DEFAULT;
+
+  signal_error ("Invalid drag acction", act);
+}
+
+static Lisp_Object
+drag_action_to_symbol (GdkDragAction action)
+{
+  switch (action)
+    {
+    case GDK_ACTION_COPY:
+      return Qcopy;
+
+    case GDK_ACTION_MOVE:
+      return Qmove;
+
+    case GDK_ACTION_LINK:
+      return Qlink;
+
+    case GDK_ACTION_PRIVATE:
+      return Qprivate;
+
+    case GDK_ACTION_DEFAULT:
+    default:
+      return Qnil;
+    }
+}
+
+void
+pgtk_update_drop_status (Lisp_Object action, Lisp_Object event_time)
+{
+  guint32 time;
+
+  CONS_TO_INTEGER (event_time, guint32, time);
+
+  if (!current_drop_context || time < current_drop_time)
+    return;
+
+  gdk_drag_status (current_drop_context,
+                  symbol_to_drag_action (action),
+                  time);
+}
+
+void
+pgtk_finish_drop (Lisp_Object success, Lisp_Object event_time,
+                 Lisp_Object del)
+{
+  guint32 time;
+
+  CONS_TO_INTEGER (event_time, guint32, time);
+
+  if (!current_drop_context || time < current_drop_time)
+    return;
+
+  gtk_drag_finish (current_drop_context, !NILP (success),
+                  !NILP (del), time);
+
+  if (current_drop_context_drop)
+    g_clear_pointer (&current_drop_context,
+                    g_object_unref);
+}
+
 static void
-drag_data_received (GtkWidget *widget, GdkDragContext *context,
-                   gint x, gint y, GtkSelectionData *data,
-                   guint info, guint time, gpointer user_data)
+drag_leave (GtkWidget *widget, GdkDragContext *context,
+           guint time, gpointer user_data)
 {
-  struct frame *f = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
-  gchar **uris = gtk_selection_data_get_uris (data);
+  struct frame *f;
+  union buffered_input_event inev;
 
-  if (uris != NULL)
+  f = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
+
+  if (current_drop_context)
     {
-      for (int i = 0; uris[i] != NULL; i++)
-       {
-         union buffered_input_event inev;
-         Lisp_Object arg = Qnil;
+      if (current_drop_context_drop)
+       gtk_drag_finish (current_drop_context,
+                        FALSE, FALSE, current_drop_time);
 
-         EVENT_INIT (inev.ie);
-         inev.ie.kind = NO_EVENT;
-         inev.ie.arg = Qnil;
+      g_clear_pointer (&current_drop_context,
+                      g_object_unref);
+    }
 
-         arg = list2 (Qurl, build_string (uris[i]));
+  EVENT_INIT (inev.ie);
 
-         inev.ie.kind = DRAG_N_DROP_EVENT;
-         inev.ie.modifiers = 0;
-         XSETINT (inev.ie.x, x);
-         XSETINT (inev.ie.y, y);
-         XSETFRAME (inev.ie.frame_or_window, f);
-         inev.ie.arg = arg;
-         inev.ie.timestamp = 0;
+  inev.ie.kind = DRAG_N_DROP_EVENT;
+  inev.ie.modifiers = 0;
+  inev.ie.arg = Qnil;
+  inev.ie.timestamp = time;
 
-         evq_enqueue (&inev);
-       }
+  XSETINT (inev.ie.x, 0);
+  XSETINT (inev.ie.y, 0);
+  XSETFRAME (inev.ie.frame_or_window, f);
+
+  evq_enqueue (&inev);
+}
+
+static gboolean
+drag_motion (GtkWidget *widget, GdkDragContext *context,
+             gint x, gint y, guint time)
+
+{
+  struct frame *f;
+  union buffered_input_event inev;
+  GdkAtom name;
+  GdkDragAction suggestion;
+
+  f = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
+
+  if (!f)
+    return FALSE;
+
+  if (current_drop_context)
+    {
+      if (current_drop_context_drop)
+       gtk_drag_finish (current_drop_context,
+                        FALSE, FALSE, current_drop_time);
+
+      g_clear_pointer (&current_drop_context,
+                      g_object_unref);
     }
 
-  gtk_drag_finish (context, TRUE, FALSE, time);
+  current_drop_context = g_object_ref (context);
+  current_drop_time = time;
+  current_drop_context_drop = false;
+
+  name = gdk_drag_get_selection (context);
+  suggestion = gdk_drag_context_get_suggested_action (context);
+
+  EVENT_INIT (inev.ie);
+
+  inev.ie.kind = DRAG_N_DROP_EVENT;
+  inev.ie.modifiers = 0;
+  inev.ie.arg = list4 (Qlambda, intern (gdk_atom_name (name)),
+                      make_uint (time),
+                      drag_action_to_symbol (suggestion));
+  inev.ie.timestamp = time;
+
+  XSETINT (inev.ie.x, x);
+  XSETINT (inev.ie.y, y);
+  XSETFRAME (inev.ie.frame_or_window, f);
+
+  evq_enqueue (&inev);
+
+  return TRUE;
+}
+
+static gboolean
+drag_drop (GtkWidget *widget, GdkDragContext *context,
+          int x, int y, guint time, gpointer user_data)
+{
+  struct frame *f;
+  union buffered_input_event inev;
+  GdkAtom name;
+  GdkDragAction selected_action;
+
+  f = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
+
+  if (!f)
+    return FALSE;
+
+  if (current_drop_context)
+    {
+      if (current_drop_context_drop)
+       gtk_drag_finish (current_drop_context,
+                        FALSE, FALSE, current_drop_time);
+
+      g_clear_pointer (&current_drop_context,
+                      g_object_unref);
+    }
+
+  current_drop_context = g_object_ref (context);
+  current_drop_time = time;
+  current_drop_context_drop = true;
+
+  name = gdk_drag_get_selection (context);
+  selected_action = gdk_drag_context_get_selected_action (context);
+
+  EVENT_INIT (inev.ie);
+
+  inev.ie.kind = DRAG_N_DROP_EVENT;
+  inev.ie.modifiers = 0;
+  inev.ie.arg = list4 (Qquote, intern (gdk_atom_name (name)),
+                      make_uint (time),
+                      drag_action_to_symbol (selected_action));
+  inev.ie.timestamp = time;
+
+  XSETINT (inev.ie.x, x);
+  XSETINT (inev.ie.y, y);
+  XSETFRAME (inev.ie.frame_or_window, f);
+
+  evq_enqueue (&inev);
+
+  return TRUE;
 }
 
 static void
@@ -6174,6 +6397,8 @@ pgtk_monitors_changed_cb (GdkScreen *screen, gpointer 
user_data)
   evq_enqueue (&inev);
 }
 
+static gboolean pgtk_selection_event (GtkWidget *, GdkEvent *, gpointer);
+
 void
 pgtk_set_event_handler (struct frame *f)
 {
@@ -6184,9 +6409,9 @@ pgtk_set_event_handler (struct frame *f)
       return;
     }
 
-  gtk_drag_dest_set (FRAME_GTK_WIDGET (f), GTK_DEST_DEFAULT_ALL, NULL, 0,
-                    GDK_ACTION_COPY);
-  gtk_drag_dest_add_uri_targets (FRAME_GTK_WIDGET (f));
+  gtk_drag_dest_set (FRAME_GTK_WIDGET (f), 0, NULL, 0,
+                    (GDK_ACTION_MOVE | GDK_ACTION_COPY
+                     | GDK_ACTION_LINK | GDK_ACTION_PRIVATE));
 
   if (FRAME_GTK_OUTER_WIDGET (f))
     {
@@ -6225,14 +6450,24 @@ pgtk_set_event_handler (struct frame *f)
                    G_CALLBACK (button_event), NULL);
   g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "scroll-event",
                    G_CALLBACK (scroll_event), NULL);
-  g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "selection-clear-event",
-                   G_CALLBACK (pgtk_selection_lost), NULL);
   g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "configure-event",
                    G_CALLBACK (configure_event), NULL);
-  g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "drag-data-received",
-                   G_CALLBACK (drag_data_received), NULL);
+  g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "drag-leave",
+                   G_CALLBACK (drag_leave), NULL);
+  g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "drag-motion",
+                   G_CALLBACK (drag_motion), NULL);
+  g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "drag-drop",
+                   G_CALLBACK (drag_drop), NULL);
   g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "draw",
                    G_CALLBACK (pgtk_handle_draw), NULL);
+  g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "property-notify-event",
+                   G_CALLBACK (pgtk_selection_event), NULL);
+  g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "selection-clear-event",
+                   G_CALLBACK (pgtk_selection_event), NULL);
+  g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "selection-request-event",
+                   G_CALLBACK (pgtk_selection_event), NULL);
+  g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "selection-notify-event",
+                   G_CALLBACK (pgtk_selection_event), NULL);
   g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "event",
                    G_CALLBACK (pgtk_handle_event), NULL);
 }
@@ -6292,6 +6527,73 @@ same_x_server (const char *name1, const char *name2)
          && (*name2 == '.' || *name2 == '\0'));
 }
 
+static struct frame *
+pgtk_find_selection_owner (GdkWindow *window)
+{
+  Lisp_Object tail, tem;
+  struct frame *f;
+
+  FOR_EACH_FRAME (tail, tem)
+    {
+      f = XFRAME (tem);
+
+      if (FRAME_PGTK_P (f)
+         && (FRAME_GDK_WINDOW (f) == window))
+       return f;
+    }
+
+  return NULL;
+}
+
+static gboolean
+pgtk_selection_event (GtkWidget *widget, GdkEvent *event,
+                     gpointer user_data)
+{
+  struct frame *f;
+  union buffered_input_event inev;
+
+  if (event->type == GDK_PROPERTY_NOTIFY)
+    pgtk_handle_property_notify (&event->property);
+  else if (event->type == GDK_SELECTION_CLEAR
+          || event->type == GDK_SELECTION_REQUEST)
+    {
+      f = pgtk_find_selection_owner (event->selection.window);
+
+      if (f)
+       {
+         EVENT_INIT (inev.ie);
+
+         inev.sie.kind = (event->type == GDK_SELECTION_CLEAR
+                          ? SELECTION_CLEAR_EVENT
+                          : SELECTION_REQUEST_EVENT);
+
+         SELECTION_EVENT_DPYINFO (&inev.sie) = FRAME_DISPLAY_INFO (f);
+         SELECTION_EVENT_SELECTION (&inev.sie) = event->selection.selection;
+         SELECTION_EVENT_TIME (&inev.sie) = event->selection.time;
+
+         if (event->type == GDK_SELECTION_REQUEST)
+           {
+             /* FIXME: when does GDK destroy the requestor GdkWindow
+                object?
+
+                It would make sense to wait for the transfer to
+                complete.  But I don't know if GDK actually does
+                that.  */
+             SELECTION_EVENT_REQUESTOR (&inev.sie) = 
event->selection.requestor;
+             SELECTION_EVENT_TARGET (&inev.sie) = event->selection.target;
+             SELECTION_EVENT_PROPERTY (&inev.sie) = event->selection.property;
+           }
+
+         evq_enqueue (&inev);
+         return TRUE;
+       }
+    }
+  else if (event->type == GDK_SELECTION_NOTIFY)
+    pgtk_handle_selection_notify (&event->selection);
+
+  return FALSE;
+}
+
 /* Open a connection to X display DISPLAY_NAME, and return
    the structure that describes the open display.
    If we cannot contact the display, return null.  */
@@ -6525,8 +6827,6 @@ pgtk_term_init (Lisp_Object display_name, char 
*resource_name)
 
   xsettings_initialize (dpyinfo);
 
-  pgtk_selection_init ();
-
   pgtk_im_init (dpyinfo);
 
   g_signal_connect (G_OBJECT (dpyinfo->gdpy), "seat-added",
@@ -6708,12 +7008,17 @@ syms_of_pgtkterm (void)
 
   DEFSYM (Qlatin_1, "latin-1");
 
-  xg_default_icon_file =
-    build_pure_c_string ("icons/hicolor/scalable/apps/emacs.svg");
+  xg_default_icon_file
+    = build_pure_c_string ("icons/hicolor/scalable/apps/emacs.svg");
   staticpro (&xg_default_icon_file);
 
   DEFSYM (Qx_gtk_map_stock, "x-gtk-map-stock");
 
+  DEFSYM (Qcopy, "copy");
+  DEFSYM (Qmove, "move");
+  DEFSYM (Qlink, "link");
+  DEFSYM (Qprivate, "private");
+
 
   Fput (Qalt, Qmodifier_value, make_fixnum (alt_modifier));
   Fput (Qhyper, Qmodifier_value, make_fixnum (hyper_modifier));
@@ -6998,8 +7303,3 @@ pgtk_cr_export_frames (Lisp_Object frames, 
cairo_surface_type_t surface_type)
 
   return CALLN (Fapply, intern ("concat"), Fnreverse (acc));
 }
-
-void
-init_pgtkterm (void)
-{
-}
diff --git a/src/pgtkterm.h b/src/pgtkterm.h
index e31e62ae19..fcc6c5310e 100644
--- a/src/pgtkterm.h
+++ b/src/pgtkterm.h
@@ -127,8 +127,14 @@ struct pgtk_display_info
   /* The generic display parameters corresponding to this PGTK display. */
   struct terminal *terminal;
 
-  /* This says how to access this display in Gdk.  */
-  GdkDisplay *gdpy;
+  union
+  {
+    /* This says how to access this display through GDK.  */
+    GdkDisplay *gdpy;
+
+    /* An alias defined to make porting X code easier.  */
+    GdkDisplay *display;
+  };
 
   /* This is a cons cell of the form (NAME . FONT-LIST-CACHE).  */
   Lisp_Object name_list_element;
@@ -210,6 +216,9 @@ struct pgtk_display_info
   /* Time of last mouse movement.  */
   Time last_mouse_movement_time;
 
+  /* Time of last user interaction.  */
+  guint32 last_user_time;
+
   /* The scroll bar in which the last motion event occurred.  */
   void *last_mouse_scroll_bar;
 
@@ -439,14 +448,15 @@ enum
 #define FRAME_FONT(f)             (FRAME_X_OUTPUT (f)->font)
 #define FRAME_GTK_OUTER_WIDGET(f) (FRAME_X_OUTPUT (f)->widget)
 #define FRAME_GTK_WIDGET(f)       (FRAME_X_OUTPUT (f)->edit_widget)
-#define FRAME_WIDGET(f)           (FRAME_GTK_OUTER_WIDGET (f) ?                
\
-                                   FRAME_GTK_OUTER_WIDGET (f) :                
\
-                                   FRAME_GTK_WIDGET (f))
+#define FRAME_WIDGET(f)           (FRAME_GTK_OUTER_WIDGET (f)  \
+                                   ? FRAME_GTK_OUTER_WIDGET (f)        \
+                                   : FRAME_GTK_WIDGET (f))
 
-/* aliases */
 #define FRAME_PGTK_VIEW(f)         FRAME_GTK_WIDGET (f)
 #define FRAME_X_WINDOW(f)          FRAME_GTK_OUTER_WIDGET (f)
 #define FRAME_NATIVE_WINDOW(f)     GTK_WINDOW (FRAME_X_WINDOW (f))
+#define FRAME_GDK_WINDOW(f)                    \
+  (gtk_widget_get_window (FRAME_GTK_WIDGET (f)))
 
 #define FRAME_X_DISPLAY(f)        (FRAME_DISPLAY_INFO (f)->gdpy)
 
@@ -484,70 +494,101 @@ enum
 #define FRAME_CR_SURFACE_DESIRED_HEIGHT(f) \
   ((f)->output_data.pgtk->cr_surface_desired_height)
 
+
+/* If a struct input_event has a kind which is SELECTION_REQUEST_EVENT
+   or SELECTION_CLEAR_EVENT, then its contents are really described
+   by this structure.  */
+
+/* For an event of kind SELECTION_REQUEST_EVENT,
+   this structure really describes the contents.  */
+
+struct selection_input_event
+{
+  ENUM_BF (event_kind) kind : EVENT_KIND_WIDTH;
+  struct pgtk_display_info *dpyinfo;
+  /* We spell it with an "o" here because X does.  */
+  GdkWindow *requestor;
+  GdkAtom selection, target, property;
+  guint32 time;
+};
+
+/* Unlike macros below, this can't be used as an lvalue.  */
+INLINE GdkDisplay *
+SELECTION_EVENT_DISPLAY (struct selection_input_event *ev)
+{
+  return ev->dpyinfo->display;
+}
+#define SELECTION_EVENT_DPYINFO(eventp) \
+  ((eventp)->dpyinfo)
+/* We spell it with an "o" here because X does.  */
+#define SELECTION_EVENT_REQUESTOR(eventp)      \
+  ((eventp)->requestor)
+#define SELECTION_EVENT_SELECTION(eventp)      \
+  ((eventp)->selection)
+#define SELECTION_EVENT_TARGET(eventp) \
+  ((eventp)->target)
+#define SELECTION_EVENT_PROPERTY(eventp)       \
+  ((eventp)->property)
+#define SELECTION_EVENT_TIME(eventp)   \
+  ((eventp)->time)
+
+extern void pgtk_handle_selection_event (struct selection_input_event *);
+extern void pgtk_clear_frame_selections (struct frame *);
+extern void pgtk_handle_property_notify (GdkEventProperty *);
+extern void pgtk_handle_selection_notify (GdkEventSelection *);
+
 /* Display init/shutdown functions implemented in pgtkterm.c */
-extern struct pgtk_display_info *pgtk_term_init (Lisp_Object display_name,
-                                                char *resource_name);
-extern void pgtk_term_shutdown (int sig);
+extern struct pgtk_display_info *pgtk_term_init (Lisp_Object, char *);
+extern void pgtk_term_shutdown (int);
 
 /* Implemented in pgtkterm, published in or needed from pgtkfns. */
-extern void pgtk_clear_frame (struct frame *f);
-extern char *pgtk_xlfd_to_fontname (const char *xlfd);
+extern void pgtk_clear_frame (struct frame *);
+extern char *pgtk_xlfd_to_fontname (const char *);
 
-/* Implemented in pgtkfns. */
+/* Implemented in pgtkfns.c.  */
 extern void pgtk_set_doc_edited (void);
-extern const char *pgtk_get_defaults_value (const char *key);
-extern const char *pgtk_get_string_resource (XrmDatabase rdb,
-                                            const char *name,
-                                            const char *class);
-extern void pgtk_implicitly_set_name (struct frame *f, Lisp_Object arg,
-                                     Lisp_Object oldval);
+extern const char *pgtk_get_defaults_value (const char *);
+extern const char *pgtk_get_string_resource (XrmDatabase, const char *, const 
char *);
+extern void pgtk_implicitly_set_name (struct frame *, Lisp_Object, 
Lisp_Object);
 
 /* Color management implemented in pgtkterm. */
-extern bool pgtk_defined_color (struct frame *f,
-                               const char *name,
-                               Emacs_Color * color_def, bool alloc,
-                               bool makeIndex);
-extern void pgtk_query_color (struct frame *f, Emacs_Color * color);
-extern void pgtk_query_colors (struct frame *f, Emacs_Color * colors,
-                              int ncolors);
-extern int pgtk_parse_color (struct frame *f, const char *color_name,
-                            Emacs_Color * color);
+extern bool pgtk_defined_color (struct frame *, const char *,
+                               Emacs_Color *, bool, bool);
+extern void pgtk_query_color (struct frame *, Emacs_Color *);
+extern void pgtk_query_colors (struct frame *, Emacs_Color *, int);
+extern int pgtk_parse_color (struct frame *, const char *, Emacs_Color *);
 
 /* Implemented in pgtkterm.c */
-extern void pgtk_clear_area (struct frame *f, int x, int y, int width,
-                            int height);
-extern int pgtk_gtk_to_emacs_modifiers (struct pgtk_display_info *dpyinfo,
-                                       int state);
-extern void pgtk_clear_under_internal_border (struct frame *f);
-extern void pgtk_set_event_handler (struct frame *f);
+extern void pgtk_clear_area (struct frame *, int, int, int, int);
+extern int pgtk_gtk_to_emacs_modifiers (struct pgtk_display_info *, int);
+extern void pgtk_clear_under_internal_border (struct frame *);
+extern void pgtk_set_event_handler (struct frame *);
 
 /* Implemented in pgtkterm.c */
 extern int pgtk_display_pixel_height (struct pgtk_display_info *);
 extern int pgtk_display_pixel_width (struct pgtk_display_info *);
 
-extern void pgtk_destroy_window (struct frame *f);
-extern void pgtk_set_parent_frame (struct frame *f, Lisp_Object, Lisp_Object);
+extern void pgtk_destroy_window (struct frame *);
+extern void pgtk_set_parent_frame (struct frame *, Lisp_Object, Lisp_Object);
 extern void pgtk_set_no_focus_on_map (struct frame *, Lisp_Object, 
Lisp_Object);
 extern void pgtk_set_no_accept_focus (struct frame *, Lisp_Object, 
Lisp_Object);
 extern void pgtk_set_z_group (struct frame *, Lisp_Object, Lisp_Object);
 
 /* Cairo related functions implemented in pgtkterm.c */
 extern void pgtk_cr_update_surface_desired_size (struct frame *, int, int, 
bool);
-extern cairo_t *pgtk_begin_cr_clip (struct frame *f);
-extern void pgtk_end_cr_clip (struct frame *f);
+extern cairo_t *pgtk_begin_cr_clip (struct frame *);
+extern void pgtk_end_cr_clip (struct frame *);
 extern void pgtk_set_cr_source_with_gc_foreground (struct frame *, Emacs_GC *, 
bool);
 extern void pgtk_set_cr_source_with_gc_background (struct frame *, Emacs_GC *, 
bool);
 extern void pgtk_set_cr_source_with_color (struct frame *, unsigned long, 
bool);
-extern void pgtk_cr_draw_frame (cairo_t * cr, struct frame *f);
-extern void pgtk_cr_destroy_frame_context (struct frame *f);
-extern Lisp_Object pgtk_cr_export_frames (Lisp_Object frames, 
cairo_surface_type_t surface_type);
+extern void pgtk_cr_draw_frame (cairo_t *, struct frame *);
+extern void pgtk_cr_destroy_frame_context (struct frame *);
+extern Lisp_Object pgtk_cr_export_frames (Lisp_Object , cairo_surface_type_t);
 
 /* Defined in pgtkmenu.c */
-extern Lisp_Object pgtk_popup_dialog (struct frame *f, Lisp_Object header,
-                                     Lisp_Object contents);
-extern Lisp_Object pgtk_dialog_show (struct frame *f, Lisp_Object title,
-                                    Lisp_Object header,
-                                    const char **error_name);
+extern Lisp_Object pgtk_popup_dialog (struct frame *, Lisp_Object, 
Lisp_Object);
+extern Lisp_Object pgtk_dialog_show (struct frame *, Lisp_Object, Lisp_Object,
+                                    const char **);
 extern void initialize_frame_menubar (struct frame *);
 
 
@@ -559,44 +600,46 @@ extern void syms_of_pgtkselect (void);
 extern void syms_of_pgtkim (void);
 
 /* Initialization and marking implemented in pgtkterm.c */
-extern void init_pgtkterm (void);
 extern void mark_pgtkterm (void);
-extern void pgtk_delete_terminal (struct terminal *terminal);
+extern void pgtk_delete_terminal (struct terminal *);
 
-extern void pgtk_make_frame_visible (struct frame *f);
-extern void pgtk_make_frame_invisible (struct frame *f);
+extern void pgtk_make_frame_visible (struct frame *);
+extern void pgtk_make_frame_invisible (struct frame *);
 extern void pgtk_free_frame_resources (struct frame *);
-extern void pgtk_iconify_frame (struct frame *f);
-extern void pgtk_focus_frame (struct frame *f, bool noactivate);
-extern void pgtk_set_scroll_bar_default_width (struct frame *f);
-extern void pgtk_set_scroll_bar_default_height (struct frame *f);
-extern Lisp_Object pgtk_get_focus_frame (struct frame *frame);
+extern void pgtk_iconify_frame (struct frame *);
+extern void pgtk_focus_frame (struct frame *, bool);
+extern void pgtk_set_scroll_bar_default_width (struct frame *);
+extern void pgtk_set_scroll_bar_default_height (struct frame *);
+extern Lisp_Object pgtk_get_focus_frame (struct frame *);
 
-extern void pgtk_frame_rehighlight (struct pgtk_display_info *dpyinfo);
+extern void pgtk_frame_rehighlight (struct pgtk_display_info *);
 
 extern void pgtk_change_tab_bar_height (struct frame *, int);
 
-extern struct pgtk_display_info *check_pgtk_display_info (Lisp_Object object);
+extern struct pgtk_display_info *check_pgtk_display_info (Lisp_Object);
 
-extern void pgtk_default_font_parameter (struct frame *f, Lisp_Object parms);
+extern void pgtk_default_font_parameter (struct frame *, Lisp_Object);
 
-extern void pgtk_menu_set_in_use (bool in_use);
+extern void pgtk_menu_set_in_use (bool);
 
+/* Drag and drop functions used by Lisp.  */
+extern void pgtk_update_drop_status (Lisp_Object, Lisp_Object);
+extern void pgtk_finish_drop (Lisp_Object, Lisp_Object, Lisp_Object);
 
-extern void pgtk_enqueue_string (struct frame *f, gchar * str);
-extern void pgtk_enqueue_preedit (struct frame *f, Lisp_Object image_data);
-extern void pgtk_im_focus_in (struct frame *f);
-extern void pgtk_im_focus_out (struct frame *f);
-extern bool pgtk_im_filter_keypress (struct frame *f, GdkEventKey * ev);
-extern void pgtk_im_set_cursor_location (struct frame *f, int x, int y,
-                                        int width, int height);
-extern void pgtk_im_init (struct pgtk_display_info *dpyinfo);
-extern void pgtk_im_finish (struct pgtk_display_info *dpyinfo);
+extern void pgtk_enqueue_string (struct frame *, gchar *);
+extern void pgtk_enqueue_preedit (struct frame *, Lisp_Object);
+extern void pgtk_im_focus_in (struct frame *);
+extern void pgtk_im_focus_out (struct frame *);
+extern bool pgtk_im_filter_keypress (struct frame *, GdkEventKey *);
+extern void pgtk_im_set_cursor_location (struct frame *, int, int,
+                                        int, int);
+extern void pgtk_im_init (struct pgtk_display_info *);
+extern void pgtk_im_finish (struct pgtk_display_info *);
 
 extern bool xg_set_icon (struct frame *, Lisp_Object);
-extern bool xg_set_icon_from_xpm_data (struct frame *f, const char **data);
+extern bool xg_set_icon_from_xpm_data (struct frame *, const char **);
 
-extern bool pgtk_text_icon (struct frame *f, const char *icon_name);
+extern bool pgtk_text_icon (struct frame *, const char *);
 
 extern double pgtk_frame_scale_factor (struct frame *);
 extern int pgtk_emacs_to_gtk_modifiers (struct pgtk_display_info *, int);
diff --git a/src/print.c b/src/print.c
index 5aee5731e4..12b5087435 100644
--- a/src/print.c
+++ b/src/print.c
@@ -67,16 +67,17 @@ static Lisp_Object being_printed[PRINT_CIRCLE];
 /* Last char printed to stdout by printchar.  */
 static unsigned int printchar_stdout_last;
 
+struct print_buffer
+{
+  char *buffer;                        /* Allocated buffer.  */
+  ptrdiff_t size;              /* Size of allocated buffer.  */
+  ptrdiff_t pos;               /* Chars stored in buffer.  */
+  ptrdiff_t pos_byte;          /* Bytes stored in buffer.  */
+};
+
 /* When printing into a buffer, first we put the text in this
    block, then insert it all at once.  */
-static char *print_buffer;
-
-/* Size allocated in print_buffer.  */
-static ptrdiff_t print_buffer_size;
-/* Chars stored in print_buffer.  */
-static ptrdiff_t print_buffer_pos;
-/* Bytes stored in print_buffer.  */
-static ptrdiff_t print_buffer_pos_byte;
+static struct print_buffer print_buffer;
 
 /* Vprint_number_table is a table, that keeps objects that are going to
    be printed, to allow use of #n= and #n# to express sharing.
@@ -95,117 +96,139 @@ bool print_output_debug_flag EXTERNALLY_VISIBLE = 1;
 
 /* Low level output routines for characters and strings.  */
 
-/* Lisp functions to do output using a stream
-   must have the stream in a variable called printcharfun
-   and must start with PRINTPREPARE, end with PRINTFINISH.
-   Use printchar to output one character,
-   or call strout to output a block of characters.  */
-
-#define PRINTPREPARE                                                   \
-   struct buffer *old = current_buffer;                                        
\
-   ptrdiff_t old_point = -1, start_point = -1;                         \
-   ptrdiff_t old_point_byte = -1, start_point_byte = -1;               \
-   specpdl_ref specpdl_count = SPECPDL_INDEX ();                       \
-   bool free_print_buffer = 0;                                         \
-   bool multibyte                                                      \
-     = !NILP (BVAR (current_buffer, enable_multibyte_characters));     \
-   Lisp_Object original = printcharfun;                                        
\
-   if (NILP (printcharfun)) printcharfun = Qt;                         \
-   if (BUFFERP (printcharfun))                                         \
-     {                                                                 \
-       if (XBUFFER (printcharfun) != current_buffer)                   \
-        Fset_buffer (printcharfun);                                    \
-       printcharfun = Qnil;                                            \
-     }                                                                 \
-   if (MARKERP (printcharfun))                                         \
-     {                                                                 \
-       ptrdiff_t marker_pos;                                           \
-       if (! XMARKER (printcharfun)->buffer)                           \
-         error ("Marker does not point anywhere");                     \
-       if (XMARKER (printcharfun)->buffer != current_buffer)           \
-         set_buffer_internal (XMARKER (printcharfun)->buffer);         \
-       marker_pos = marker_position (printcharfun);                    \
-       if (marker_pos < BEGV || marker_pos > ZV)                       \
-        signal_error ("Marker is outside the accessible "              \
-                      "part of the buffer", printcharfun);             \
-       old_point = PT;                                                 \
-       old_point_byte = PT_BYTE;                                       \
-       SET_PT_BOTH (marker_pos,                                                
\
-                   marker_byte_position (printcharfun));               \
-       start_point = PT;                                               \
-       start_point_byte = PT_BYTE;                                     \
-       printcharfun = Qnil;                                            \
-     }                                                                 \
-   if (NILP (printcharfun))                                            \
-     {                                                                 \
-       Lisp_Object string;                                             \
-       if (NILP (BVAR (current_buffer, enable_multibyte_characters))   \
-          && ! print_escape_multibyte)                                 \
-         specbind (Qprint_escape_multibyte, Qt);                       \
-       if (! NILP (BVAR (current_buffer, enable_multibyte_characters)) \
-          && ! print_escape_nonascii)                                  \
-         specbind (Qprint_escape_nonascii, Qt);                                
\
-       if (print_buffer != 0)                                          \
-        {                                                              \
-          string = make_string_from_bytes (print_buffer,               \
-                                           print_buffer_pos,           \
-                                           print_buffer_pos_byte);     \
-          record_unwind_protect (print_unwind, string);                \
-        }                                                              \
-       else                                                            \
-        {                                                              \
-          int new_size = 1000;                                         \
-          print_buffer = xmalloc (new_size);                           \
-          print_buffer_size = new_size;                                \
-          free_print_buffer = 1;                                       \
-        }                                                              \
-       print_buffer_pos = 0;                                           \
-       print_buffer_pos_byte = 0;                                      \
-     }                                                                 \
-   if (EQ (printcharfun, Qt) && ! noninteractive)                      \
-     setup_echo_area_for_printing (multibyte);
-
-#define PRINTFINISH                                                    \
-   if (NILP (printcharfun))                                            \
-     {                                                                 \
-       if (print_buffer_pos != print_buffer_pos_byte                   \
-          && NILP (BVAR (current_buffer, enable_multibyte_characters)))\
-        {                                                              \
-          USE_SAFE_ALLOCA;                                             \
-          unsigned char *temp = SAFE_ALLOCA (print_buffer_pos + 1);    \
-          copy_text ((unsigned char *) print_buffer, temp,             \
-                     print_buffer_pos_byte, 1, 0);                     \
-          insert_1_both ((char *) temp, print_buffer_pos,              \
-                         print_buffer_pos, 0, 1, 0);                   \
-          SAFE_FREE ();                                                \
-        }                                                              \
-       else                                                            \
-        insert_1_both (print_buffer, print_buffer_pos,                 \
-                       print_buffer_pos_byte, 0, 1, 0);                \
-       signal_after_change (PT - print_buffer_pos, 0, print_buffer_pos);\
-     }                                                                 \
-   if (free_print_buffer)                                              \
-     {                                                                 \
-       xfree (print_buffer);                                           \
-       print_buffer = 0;                                               \
-     }                                                                 \
-   unbind_to (specpdl_count, Qnil);                                    \
-   if (MARKERP (original))                                             \
-     set_marker_both (original, Qnil, PT, PT_BYTE);                    \
-   if (old_point >= 0)                                                 \
-     SET_PT_BOTH (old_point + (old_point >= start_point                        
\
-                              ? PT - start_point : 0),                 \
-                 old_point_byte + (old_point_byte >= start_point_byte  \
-                                   ? PT_BYTE - start_point_byte : 0)); \
-   set_buffer_internal (old);
+/* This is used to free the print buffer; we don't simply record xfree
+   since print_buffer can be reallocated during the printing.  */
+static void
+print_free_buffer (void)
+{
+  xfree (print_buffer.buffer);
+  print_buffer.buffer = NULL;
+}
 
 /* This is used to restore the saved contents of print_buffer
    when there is a recursive call to print.  */
-
 static void
 print_unwind (Lisp_Object saved_text)
 {
-  memcpy (print_buffer, SDATA (saved_text), SCHARS (saved_text));
+  memcpy (print_buffer.buffer, SDATA (saved_text), SCHARS (saved_text));
+}
+
+/* Lisp functions to do output using a stream must start with a call to
+   print_prepare, and end with calling print_finish.
+   Use printchar to output one character, or call strout to output a
+   block of characters.  */
+
+/* State carried between print_prepare and print_finish.  */
+struct print_context
+{
+  Lisp_Object printcharfun;
+  Lisp_Object old_printcharfun;
+  ptrdiff_t old_point, start_point;
+  ptrdiff_t old_point_byte, start_point_byte;
+  specpdl_ref specpdl_count;
+};
+
+static inline struct print_context
+print_prepare (Lisp_Object printcharfun)
+{
+  struct print_context pc = {
+    .old_printcharfun = printcharfun,
+    .old_point = -1,
+    .start_point = -1,
+    .old_point_byte = -1,
+    .start_point_byte = -1,
+    .specpdl_count = SPECPDL_INDEX (),
+  };
+  bool multibyte = !NILP (BVAR (current_buffer, enable_multibyte_characters));
+  record_unwind_current_buffer ();
+  specbind(Qprint__unreadable_callback_buffer, Fcurrent_buffer ());
+  if (NILP (printcharfun))
+    printcharfun = Qt;
+  if (BUFFERP (printcharfun))
+    {
+      if (XBUFFER (printcharfun) != current_buffer)
+       Fset_buffer (printcharfun);
+      printcharfun = Qnil;
+    }
+  if (MARKERP (printcharfun))
+    {
+      if (! XMARKER (printcharfun)->buffer)
+       error ("Marker does not point anywhere");
+      if (XMARKER (printcharfun)->buffer != current_buffer)
+       set_buffer_internal (XMARKER (printcharfun)->buffer);
+      ptrdiff_t marker_pos = marker_position (printcharfun);
+      if (marker_pos < BEGV || marker_pos > ZV)
+       signal_error ("Marker is outside the accessible part of the buffer",
+                     printcharfun);
+      pc.old_point = PT;
+      pc.old_point_byte = PT_BYTE;
+      SET_PT_BOTH (marker_pos, marker_byte_position (printcharfun));
+      pc.start_point = PT;
+      pc.start_point_byte = PT_BYTE;
+      printcharfun = Qnil;
+    }
+  if (NILP (printcharfun))
+    {
+      if (NILP (BVAR (current_buffer, enable_multibyte_characters))
+         && ! print_escape_multibyte)
+       specbind (Qprint_escape_multibyte, Qt);
+      if (! NILP (BVAR (current_buffer, enable_multibyte_characters))
+         && ! print_escape_nonascii)
+       specbind (Qprint_escape_nonascii, Qt);
+      if (print_buffer.buffer != NULL)
+       {
+         Lisp_Object string = make_string_from_bytes (print_buffer.buffer,
+                                                      print_buffer.pos,
+                                                      print_buffer.pos_byte);
+         record_unwind_protect (print_unwind, string);
+       }
+      else
+       {
+         int new_size = 1000;
+         print_buffer.buffer = xmalloc (new_size);
+         print_buffer.size = new_size;
+         record_unwind_protect_void (print_free_buffer);
+       }
+      print_buffer.pos = 0;
+      print_buffer.pos_byte = 0;
+    }
+  if (EQ (printcharfun, Qt) && ! noninteractive)
+    setup_echo_area_for_printing (multibyte);
+  pc.printcharfun = printcharfun;
+  return pc;
+}
+
+static inline void
+print_finish (struct print_context *pc)
+{
+  if (NILP (pc->printcharfun))
+    {
+      if (print_buffer.pos != print_buffer.pos_byte
+         && NILP (BVAR (current_buffer, enable_multibyte_characters)))
+       {
+         USE_SAFE_ALLOCA;
+         unsigned char *temp = SAFE_ALLOCA (print_buffer.pos + 1);
+         copy_text ((unsigned char *) print_buffer.buffer, temp,
+                    print_buffer.pos_byte, 1, 0);
+         insert_1_both ((char *) temp, print_buffer.pos,
+                        print_buffer.pos, 0, 1, 0);
+         SAFE_FREE ();
+       }
+      else
+       insert_1_both (print_buffer.buffer, print_buffer.pos,
+                      print_buffer.pos_byte, 0, 1, 0);
+      signal_after_change (PT - print_buffer.pos, 0, print_buffer.pos);
+    }
+  if (MARKERP (pc->old_printcharfun))
+    set_marker_both (pc->old_printcharfun, Qnil, PT, PT_BYTE);
+  if (pc->old_point >= 0)
+    SET_PT_BOTH (pc->old_point
+                + (pc->old_point >= pc->start_point
+                   ? PT - pc->start_point : 0),
+                pc->old_point_byte
+                + (pc->old_point_byte >= pc->start_point_byte
+                   ? PT_BYTE - pc->start_point_byte : 0));
+  unbind_to (pc->specpdl_count, Qnil);
 }
 
 /* Print character CH to the stdio stream STREAM.  */
@@ -293,13 +316,14 @@ printchar (unsigned int ch, Lisp_Object fun)
 
       if (NILP (fun))
        {
-         ptrdiff_t incr = len - (print_buffer_size - print_buffer_pos_byte);
+         ptrdiff_t incr = len - (print_buffer.size - print_buffer.pos_byte);
          if (incr > 0)
-           print_buffer = xpalloc (print_buffer, &print_buffer_size,
-                                   incr, -1, 1);
-         memcpy (print_buffer + print_buffer_pos_byte, str, len);
-         print_buffer_pos += 1;
-         print_buffer_pos_byte += len;
+           print_buffer.buffer = xpalloc (print_buffer.buffer,
+                                          &print_buffer.size,
+                                          incr, -1, 1);
+         memcpy (print_buffer.buffer + print_buffer.pos_byte, str, len);
+         print_buffer.pos += 1;
+         print_buffer.pos_byte += len;
        }
       else if (noninteractive)
        {
@@ -358,12 +382,13 @@ strout (const char *ptr, ptrdiff_t size, ptrdiff_t 
size_byte,
 {
   if (NILP (printcharfun))
     {
-      ptrdiff_t incr = size_byte - (print_buffer_size - print_buffer_pos_byte);
+      ptrdiff_t incr = size_byte - (print_buffer.size - print_buffer.pos_byte);
       if (incr > 0)
-       print_buffer = xpalloc (print_buffer, &print_buffer_size, incr, -1, 1);
-      memcpy (print_buffer + print_buffer_pos_byte, ptr, size_byte);
-      print_buffer_pos += size;
-      print_buffer_pos_byte += size_byte;
+       print_buffer.buffer = xpalloc (print_buffer.buffer,
+                                      &print_buffer.size, incr, -1, 1);
+      memcpy (print_buffer.buffer + print_buffer.pos_byte, ptr, size_byte);
+      print_buffer.pos += size;
+      print_buffer.pos_byte += size_byte;
     }
   else if (noninteractive && EQ (printcharfun, Qt))
     {
@@ -471,8 +496,7 @@ print_string (Lisp_Object string, Lisp_Object printcharfun)
          if (chars < bytes)
            {
              newstr = make_uninit_multibyte_string (chars, bytes);
-             memcpy (SDATA (newstr), SDATA (string), chars);
-             str_to_multibyte (SDATA (newstr), bytes, chars);
+             str_to_multibyte (SDATA (newstr), SDATA (string), chars);
              string = newstr;
            }
        }
@@ -528,14 +552,14 @@ PRINTCHARFUN defaults to the value of `standard-output' 
(which see).  */)
   if (NILP (printcharfun))
     printcharfun = Vstandard_output;
   CHECK_FIXNUM (character);
-  PRINTPREPARE;
-  printchar (XFIXNUM (character), printcharfun);
-  PRINTFINISH;
+  struct print_context pc = print_prepare (printcharfun);
+  printchar (XFIXNUM (character), pc.printcharfun);
+  print_finish (&pc);
   return character;
 }
 
 /* Print the contents of a unibyte C string STRING using PRINTCHARFUN.
-   The caller should arrange to put this inside PRINTPREPARE and PRINTFINISH.
+   The caller should arrange to put this inside print_prepare and print_finish.
    Do not use this on the contents of a Lisp string.  */
 
 static void
@@ -551,9 +575,9 @@ print_c_string (char const *string, Lisp_Object 
printcharfun)
 static void
 write_string (const char *data, Lisp_Object printcharfun)
 {
-  PRINTPREPARE;
-  print_c_string (data, printcharfun);
-  PRINTFINISH;
+  struct print_context pc = print_prepare (printcharfun);
+  print_c_string (data, pc.printcharfun);
+  print_finish (&pc);
 }
 
 
@@ -606,21 +630,21 @@ If PRINTCHARFUN is omitted or nil, the value of 
`standard-output' is used.  */)
 
   if (NILP (printcharfun))
     printcharfun = Vstandard_output;
-  PRINTPREPARE;
+  struct print_context pc = print_prepare (printcharfun);
 
   if (NILP (ensure))
     val = Qt;
   /* Difficult to check if at line beginning so abort.  */
-  else if (FUNCTIONP (printcharfun))
-    signal_error ("Unsupported function argument", printcharfun);
-  else if (noninteractive && !NILP (printcharfun))
+  else if (FUNCTIONP (pc.printcharfun))
+    signal_error ("Unsupported function argument", pc.printcharfun);
+  else if (noninteractive && !NILP (pc.printcharfun))
     val = printchar_stdout_last == 10 ? Qnil : Qt;
   else
     val = NILP (Fbolp ()) ? Qt : Qnil;
 
   if (!NILP (val))
-    printchar ('\n', printcharfun);
-  PRINTFINISH;
+    printchar ('\n', pc.printcharfun);
+  print_finish (&pc);
   return val;
 }
 
@@ -731,7 +755,7 @@ Optional argument OVERRIDES should be a list of settings 
for print-related
 variables.  An element in this list can be the symbol t, which means "reset
 all the values to their defaults".  Otherwise, an element should be a pair,
 where the `car' or the pair is the setting symbol, and the `cdr' is the
-value of of the setting to use for this `prin1' call.
+value of the setting to use for this `prin1' call.
 
 For instance:
 
@@ -751,9 +775,9 @@ means "use default values for all the print-related 
settings".  */)
   if (!NILP (overrides))
     print_bind_overrides (overrides);
 
-  PRINTPREPARE;
-  print (object, printcharfun, 1);
-  PRINTFINISH;
+  struct print_context pc = print_prepare (printcharfun);
+  print (object, pc.printcharfun, 1);
+  print_finish (&pc);
 
   return unbind_to (count, object);
 }
@@ -788,11 +812,10 @@ A printed representation of an object is text which 
describes that object.  */)
      No need for specbind, since errors deactivate the mark.  */
   Lisp_Object save_deactivate_mark = Vdeactivate_mark;
 
-  Lisp_Object printcharfun = Vprin1_to_string_buffer;
-  PRINTPREPARE;
-  print (object, printcharfun, NILP (noescape));
-  /* Make Vprin1_to_string_buffer be the default buffer after PRINTFINISH */
-  PRINTFINISH;
+  struct print_context pc = print_prepare (Vprin1_to_string_buffer);
+  print (object, pc.printcharfun, NILP (noescape));
+  /* Make Vprin1_to_string_buffer be the default buffer after print_finish */
+  print_finish (&pc);
 
   struct buffer *previous = current_buffer;
   set_buffer_internal (XBUFFER (Vprin1_to_string_buffer));
@@ -837,15 +860,15 @@ is used instead.  */)
 {
   if (NILP (printcharfun))
     printcharfun = Vstandard_output;
-  PRINTPREPARE;
+  struct print_context pc = print_prepare (printcharfun);
   if (STRINGP (object)
       && !string_intervals (object)
       && NILP (Vprint_continuous_numbering))
     /* fast path for plain strings */
-    print_string (object, printcharfun);
+    print_string (object, pc.printcharfun);
   else
-    print (object, printcharfun, 0);
-  PRINTFINISH;
+    print (object, pc.printcharfun, 0);
+  print_finish (&pc);
   return object;
 }
 
@@ -876,11 +899,11 @@ is used instead.  */)
 {
   if (NILP (printcharfun))
     printcharfun = Vstandard_output;
-  PRINTPREPARE;
-  printchar ('\n', printcharfun);
-  print (object, printcharfun, 1);
-  printchar ('\n', printcharfun);
-  PRINTFINISH;
+  struct print_context pc = print_prepare (printcharfun);
+  printchar ('\n', pc.printcharfun);
+  print (object, pc.printcharfun, 1);
+  printchar ('\n', pc.printcharfun);
+  print_finish (&pc);
   return object;
 }
 
@@ -1657,6 +1680,17 @@ print_vectorlike (Lisp_Object obj, Lisp_Object 
printcharfun, bool escapeflag,
         infinite recursion in the function called.  */
       Lisp_Object func = Vprint_unreadable_function;
       specbind (Qprint_unreadable_function, Qnil);
+
+      /* If we're being called from `prin1-to-string' or the like,
+        we're now in the secret " prin1" buffer.  This can lead to
+        problems if, for instance, the callback function switches a
+        window to this buffer -- this will make Emacs segfault.  */
+      if (!NILP (Vprint__unreadable_callback_buffer)
+         && !NILP (Fbuffer_live_p (Vprint__unreadable_callback_buffer)))
+       {
+         record_unwind_current_buffer ();
+         set_buffer_internal (XBUFFER (Vprint__unreadable_callback_buffer));
+       }
       Lisp_Object result = CALLN (Ffuncall, func, obj,
                                  escapeflag? Qt: Qnil);
       unbind_to (count, Qnil);
@@ -1731,10 +1765,10 @@ print_vectorlike (Lisp_Object obj, Lisp_Object 
printcharfun, bool escapeflag,
 
     case PVEC_USER_PTR:
       {
-       void *finalizer = XUSER_PTR (obj)->finalizer;
        print_c_string ("#<user-ptr ", printcharfun);
        int i = sprintf (buf, "ptr=%p finalizer=%p",
-                        XUSER_PTR (obj)->p, finalizer);
+                        XUSER_PTR (obj)->p,
+                        (void *) XUSER_PTR (obj)->finalizer);
        strout (buf, i, i, printcharfun);
        printchar ('>', printcharfun);
       }
@@ -2942,6 +2976,15 @@ be printed.  */);
   Vprint_unreadable_function = Qnil;
   DEFSYM (Qprint_unreadable_function, "print-unreadable-function");
 
+  DEFVAR_LISP ("print--unreadable-callback-buffer",
+              Vprint__unreadable_callback_buffer,
+              doc: /* Dynamically bound to indicate current buffer.  */);
+  Vprint__unreadable_callback_buffer = Qnil;
+  DEFSYM (Qprint__unreadable_callback_buffer,
+         "print--unreadable-callback-buffer");
+  /* Don't export this variable to Elisp.  */
+  Funintern (Qprint__unreadable_callback_buffer, Qnil);
+
   defsubr (&Sflush_standard_output);
 
   /* Initialized in print_create_variable_mapping.  */
diff --git a/src/process.c b/src/process.c
index ccfc0bdf54..7a133cda00 100644
--- a/src/process.c
+++ b/src/process.c
@@ -1209,8 +1209,8 @@ If PROCESS has not yet exited or died, return 0.  */)
 
 DEFUN ("process-id", Fprocess_id, Sprocess_id, 1, 1, 0,
        doc: /* Return the process id of PROCESS.
-This is the pid of the external process which PROCESS uses or talks to.
-It is a fixnum if the value is small enough, otherwise a bignum.
+This is the pid of the external process which PROCESS uses or talks to,
+an integer.
 For a network, serial, and pipe connections, this value is nil.  */)
   (register Lisp_Object process)
 {
@@ -1243,14 +1243,31 @@ or t (process is stopped).  */)
   return XPROCESS (process)->command;
 }
 
-DEFUN ("process-tty-name", Fprocess_tty_name, Sprocess_tty_name, 1, 1, 0,
+DEFUN ("process-tty-name", Fprocess_tty_name, Sprocess_tty_name, 1, 2, 0,
        doc: /* Return the name of the terminal PROCESS uses, or nil if none.
 This is the terminal that the process itself reads and writes on,
-not the name of the pty that Emacs uses to talk with that terminal.  */)
-  (register Lisp_Object process)
+not the name of the pty that Emacs uses to talk with that terminal.
+
+If STREAM is nil, return the terminal name if any of PROCESS's
+standard streams use a terminal for communication.  If STREAM is one
+of `stdin', `stdout', or `stderr', return the name of the terminal
+PROCESS uses for that stream specifically, or nil if that stream
+communicates via a pipe.  */)
+  (register Lisp_Object process, Lisp_Object stream)
 {
   CHECK_PROCESS (process);
-  return XPROCESS (process)->tty_name;
+  register struct Lisp_Process *p = XPROCESS (process);
+
+  if (NILP (stream))
+    return p->tty_name;
+  else if (EQ (stream, Qstdin))
+    return p->pty_in ? p->tty_name : Qnil;
+  else if (EQ (stream, Qstdout))
+    return p->pty_out ? p->tty_name : Qnil;
+  else if (EQ (stream, Qstderr))
+    return p->pty_out && NILP (p->stderrproc) ? p->tty_name : Qnil;
+  else
+    signal_error ("Unknown stream", stream);
 }
 
 static void
@@ -1281,7 +1298,7 @@ Return BUFFER.  */)
       update_process_mark (p);
     }
   if (NETCONN1_P (p) || SERIALCONN1_P (p) || PIPECONN1_P (p))
-    pset_childp (p, Fplist_put (p->childp, QCbuffer, buffer));
+    pset_childp (p, plist_put (p->childp, QCbuffer, buffer));
   setup_process_coding_systems (process);
   return buffer;
 }
@@ -1316,6 +1333,19 @@ set_process_filter_masks (struct Lisp_Process *p)
     add_process_read_fd (p->infd);
 }
 
+static bool
+is_pty_from_symbol (Lisp_Object symbol)
+{
+  if (EQ (symbol, Qpty))
+    return true;
+  else if (EQ (symbol, Qpipe))
+    return false;
+  else if (NILP (symbol))
+    return !NILP (Vprocess_connection_type);
+  else
+    report_file_error ("Unknown connection type", symbol);
+}
+
 DEFUN ("set-process-filter", Fset_process_filter, Sset_process_filter,
        2, 2, 0,
        doc: /* Give PROCESS the filter function FILTER; nil means default.
@@ -1360,7 +1390,7 @@ The string argument is normally a multibyte string, 
except:
   pset_filter (p, filter);
 
   if (NETCONN1_P (p) || SERIALCONN1_P (p) || PIPECONN1_P (p))
-    pset_childp (p, Fplist_put (p->childp, QCfilter, filter));
+    pset_childp (p, plist_put (p->childp, QCfilter, filter));
   setup_process_coding_systems (process);
   return filter;
 }
@@ -1392,7 +1422,7 @@ It gets two arguments: the process, and a string 
describing the change.  */)
 
   pset_sentinel (p, sentinel);
   if (NETCONN1_P (p) || SERIALCONN1_P (p) || PIPECONN1_P (p))
-    pset_childp (p, Fplist_put (p->childp, QCsentinel, sentinel));
+    pset_childp (p, plist_put (p->childp, QCsentinel, sentinel));
   return sentinel;
 }
 
@@ -1553,25 +1583,25 @@ waiting for the process to be fully set up.*/)
 
   if (DATAGRAM_CONN_P (process)
       && (EQ (key, Qt) || EQ (key, QCremote)))
-    contact = Fplist_put (contact, QCremote,
-                         Fprocess_datagram_address (process));
+    contact = plist_put (contact, QCremote,
+                        Fprocess_datagram_address (process));
 #endif
 
   if ((!NETCONN_P (process) && !SERIALCONN_P (process) && !PIPECONN_P 
(process))
       || EQ (key, Qt))
     return contact;
   if (NILP (key) && NETCONN_P (process))
-    return list2 (Fplist_get (contact, QChost),
-                 Fplist_get (contact, QCservice));
+    return list2 (plist_get (contact, QChost),
+                 plist_get (contact, QCservice));
   if (NILP (key) && SERIALCONN_P (process))
-    return list2 (Fplist_get (contact, QCport),
-                 Fplist_get (contact, QCspeed));
+    return list2 (plist_get (contact, QCport),
+                 plist_get (contact, QCspeed));
   /* FIXME: Return a meaningful value (e.g., the child end of the pipe)
      if the pipe process is useful for purposes other than receiving
      stderr.  */
   if (NILP (key) && PIPECONN_P (process))
     return Qt;
-  return Fplist_get (contact, key);
+  return plist_get (contact, key);
 }
 
 DEFUN ("process-plist", Fprocess_plist, Sprocess_plist,
@@ -1741,15 +1771,18 @@ signals to stop and continue a process.
 :connection-type TYPE -- TYPE is control type of device used to
 communicate with subprocesses.  Values are `pipe' to use a pipe, `pty'
 to use a pty, or nil to use the default specified through
-`process-connection-type'.
+`process-connection-type'.  If TYPE is a cons (INPUT . OUTPUT), then
+INPUT will be used for standard input and OUTPUT for standard output
+(and standard error if `:stderr' is nil).
 
 :filter FILTER -- Install FILTER as the process filter.
 
 :sentinel SENTINEL -- Install SENTINEL as the process sentinel.
 
 :stderr STDERR -- STDERR is either a buffer or a pipe process attached
-to the standard error of subprocess.  Specifying this implies
-`:connection-type' is set to `pipe'.  If STDERR is nil, standard error
+to the standard error of subprocess.  When specifying this, the
+subprocess's standard error will always communicate via a pipe, no
+matter the value of `:connection-type'.  If STDERR is nil, standard error
 is mixed with standard output and sent to BUFFER or FILTER.  (Note
 that specifying :stderr will create a new, separate (but associated)
 process, with its own filter and sentinel.  See
@@ -1773,7 +1806,7 @@ usage: (make-process &rest ARGS)  */)
   /* Save arguments for process-contact and clone-process.  */
   contact = Flist (nargs, args);
 
-  if (!NILP (Fplist_get (contact, QCfile_handler)))
+  if (!NILP (plist_get (contact, QCfile_handler)))
     {
       Lisp_Object file_handler
         = Ffind_file_name_handler (BVAR (current_buffer, directory),
@@ -1782,7 +1815,7 @@ usage: (make-process &rest ARGS)  */)
         return CALLN (Fapply, file_handler, Qmake_process, contact);
     }
 
-  buffer = Fplist_get (contact, QCbuffer);
+  buffer = plist_get (contact, QCbuffer);
   if (!NILP (buffer))
     buffer = Fget_buffer_create (buffer, Qnil);
 
@@ -1792,10 +1825,10 @@ usage: (make-process &rest ARGS)  */)
      chdir, since it's in a vfork.  */
   current_dir = get_current_directory (true);
 
-  name = Fplist_get (contact, QCname);
+  name = plist_get (contact, QCname);
   CHECK_STRING (name);
 
-  command = Fplist_get (contact, QCcommand);
+  command = plist_get (contact, QCcommand);
   if (CONSP (command))
     program = XCAR (command);
   else
@@ -1804,10 +1837,10 @@ usage: (make-process &rest ARGS)  */)
   if (!NILP (program))
     CHECK_STRING (program);
 
-  bool query_on_exit = NILP (Fplist_get (contact, QCnoquery));
+  bool query_on_exit = NILP (plist_get (contact, QCnoquery));
 
   stderrproc = Qnil;
-  xstderr = Fplist_get (contact, QCstderr);
+  xstderr = plist_get (contact, QCstderr);
   if (PROCESSP (xstderr))
     {
       if (!PIPECONN_P (xstderr))
@@ -1833,34 +1866,32 @@ usage: (make-process &rest ARGS)  */)
   eassert (NILP (XPROCESS (proc)->plist));
   pset_type (XPROCESS (proc), Qreal);
   pset_buffer (XPROCESS (proc), buffer);
-  pset_sentinel (XPROCESS (proc), Fplist_get (contact, QCsentinel));
-  pset_filter (XPROCESS (proc), Fplist_get (contact, QCfilter));
+  pset_sentinel (XPROCESS (proc), plist_get (contact, QCsentinel));
+  pset_filter (XPROCESS (proc), plist_get (contact, QCfilter));
   pset_command (XPROCESS (proc), Fcopy_sequence (command));
 
   if (!query_on_exit)
     XPROCESS (proc)->kill_without_query = 1;
-  tem = Fplist_get (contact, QCstop);
+  tem = plist_get (contact, QCstop);
   /* Normal processes can't be started in a stopped state, see
      Bug#30460.  */
   CHECK_TYPE (NILP (tem), Qnull, tem);
 
-  tem = Fplist_get (contact, QCconnection_type);
-  if (EQ (tem, Qpty))
-    XPROCESS (proc)->pty_flag = true;
-  else if (EQ (tem, Qpipe))
-    XPROCESS (proc)->pty_flag = false;
-  else if (NILP (tem))
-    XPROCESS (proc)->pty_flag = !NILP (Vprocess_connection_type);
+  tem = plist_get (contact, QCconnection_type);
+  if (CONSP (tem))
+    {
+      XPROCESS (proc)->pty_in = is_pty_from_symbol (XCAR (tem));
+      XPROCESS (proc)->pty_out = is_pty_from_symbol (XCDR (tem));
+    }
   else
-    report_file_error ("Unknown connection type", tem);
-
-  if (!NILP (stderrproc))
     {
-      pset_stderrproc (XPROCESS (proc), stderrproc);
-
-      XPROCESS (proc)->pty_flag = false;
+      XPROCESS (proc)->pty_in = XPROCESS (proc)->pty_out =
+       is_pty_from_symbol (tem);
     }
 
+  if (!NILP (stderrproc))
+    pset_stderrproc (XPROCESS (proc), stderrproc);
+
 #ifdef HAVE_GNUTLS
   /* AKA GNUTLS_INITSTAGE(proc).  */
   verify (GNUTLS_STAGE_EMPTY == 0);
@@ -1886,7 +1917,7 @@ usage: (make-process &rest ARGS)  */)
     Lisp_Object coding_systems = Qt;
     Lisp_Object val, *args2;
 
-    tem = Fplist_get (contact, QCcoding);
+    tem = plist_get (contact, QCcoding);
     if (!NILP (tem))
       {
        val = tem;
@@ -2099,66 +2130,80 @@ static void
 create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
 {
   struct Lisp_Process *p = XPROCESS (process);
-  int inchannel, outchannel;
+  int inchannel = -1, outchannel = -1;
   pid_t pid = -1;
   int vfork_errno;
   int forkin, forkout, forkerr = -1;
-  bool pty_flag = 0;
+  bool pty_in = false, pty_out = false;
   char pty_name[PTY_NAME_SIZE];
   Lisp_Object lisp_pty_name = Qnil;
+  int ptychannel = -1, pty_tty = -1;
   sigset_t oldset;
 
   /* Ensure that the SIGCHLD handler can notify
      `wait_reading_process_output'.  */
   child_signal_init ();
 
-  inchannel = outchannel = -1;
+  if (p->pty_in || p->pty_out)
+    ptychannel = allocate_pty (pty_name);
 
-  if (p->pty_flag)
-    outchannel = inchannel = allocate_pty (pty_name);
-
-  if (inchannel >= 0)
+  if (ptychannel >= 0)
     {
-      p->open_fd[READ_FROM_SUBPROCESS] = inchannel;
 #if ! defined (USG) || defined (USG_SUBTTY_WORKS)
       /* On most USG systems it does not work to open the pty's tty here,
         then close it and reopen it in the child.  */
       /* Don't let this terminal become our controlling terminal
         (in case we don't have one).  */
-      forkout = forkin = emacs_open (pty_name, O_RDWR | O_NOCTTY, 0);
-      if (forkin < 0)
+      pty_tty = emacs_open (pty_name, O_RDWR | O_NOCTTY, 0);
+      if (pty_tty < 0)
        report_file_error ("Opening pty", Qnil);
-      p->open_fd[SUBPROCESS_STDIN] = forkin;
-#else
-      forkin = forkout = -1;
 #endif /* not USG, or USG_SUBTTY_WORKS */
-      pty_flag = 1;
+      pty_in = p->pty_in;
+      pty_out = p->pty_out;
       lisp_pty_name = build_string (pty_name);
     }
+
+  /* Set up stdin for the child process.  */
+  if (ptychannel >= 0 && p->pty_in)
+    {
+      p->open_fd[SUBPROCESS_STDIN] = forkin = pty_tty;
+      outchannel = ptychannel;
+    }
   else
     {
-      if (emacs_pipe (p->open_fd + SUBPROCESS_STDIN) != 0
-         || emacs_pipe (p->open_fd + READ_FROM_SUBPROCESS) != 0)
+      if (emacs_pipe (p->open_fd + SUBPROCESS_STDIN) != 0)
        report_file_error ("Creating pipe", Qnil);
       forkin = p->open_fd[SUBPROCESS_STDIN];
       outchannel = p->open_fd[WRITE_TO_SUBPROCESS];
+    }
+
+  /* Set up stdout for the child process.  */
+  if (ptychannel >= 0 && p->pty_out)
+    {
+      forkout = pty_tty;
+      p->open_fd[READ_FROM_SUBPROCESS] = inchannel = ptychannel;
+    }
+  else
+    {
+      if (emacs_pipe (p->open_fd + READ_FROM_SUBPROCESS) != 0)
+       report_file_error ("Creating pipe", Qnil);
       inchannel = p->open_fd[READ_FROM_SUBPROCESS];
       forkout = p->open_fd[SUBPROCESS_STDOUT];
 
 #if defined(GNU_LINUX) && defined(F_SETPIPE_SZ)
       fcntl (inchannel, F_SETPIPE_SZ, read_process_output_max);
 #endif
+    }
 
-      if (!NILP (p->stderrproc))
-       {
-         struct Lisp_Process *pp = XPROCESS (p->stderrproc);
+  if (!NILP (p->stderrproc))
+    {
+      struct Lisp_Process *pp = XPROCESS (p->stderrproc);
 
-         forkerr = pp->open_fd[SUBPROCESS_STDOUT];
+      forkerr = pp->open_fd[SUBPROCESS_STDOUT];
 
-         /* Close unnecessary file descriptors.  */
-         close_process_fd (&pp->open_fd[WRITE_TO_SUBPROCESS]);
-         close_process_fd (&pp->open_fd[SUBPROCESS_STDIN]);
-       }
+      /* Close unnecessary file descriptors.  */
+      close_process_fd (&pp->open_fd[WRITE_TO_SUBPROCESS]);
+      close_process_fd (&pp->open_fd[SUBPROCESS_STDIN]);
     }
 
   if (FD_SETSIZE <= inchannel || FD_SETSIZE <= outchannel)
@@ -2183,7 +2228,8 @@ create_process (Lisp_Object process, char **new_argv, 
Lisp_Object current_dir)
      we just reopen the device (see emacs_get_tty_pgrp) as this is
      more portable (see USG_SUBTTY_WORKS above).  */
 
-  p->pty_flag = pty_flag;
+  p->pty_in = pty_in;
+  p->pty_out = pty_out;
   pset_status (p, Qrun);
 
   if (!EQ (p->command, Qt)
@@ -2199,13 +2245,15 @@ create_process (Lisp_Object process, char **new_argv, 
Lisp_Object current_dir)
   block_input ();
   block_child_signal (&oldset);
 
-  pty_flag = p->pty_flag;
-  eassert (pty_flag == ! NILP (lisp_pty_name));
+  pty_in = p->pty_in;
+  pty_out = p->pty_out;
+  eassert ((pty_in || pty_out) == ! NILP (lisp_pty_name));
 
   vfork_errno
     = emacs_spawn (&pid, forkin, forkout, forkerr, new_argv, env,
                    SSDATA (current_dir),
-                   pty_flag ? SSDATA (lisp_pty_name) : NULL, &oldset);
+                   pty_in || pty_out ? SSDATA (lisp_pty_name) : NULL,
+                   pty_in, pty_out, &oldset);
 
   eassert ((vfork_errno == 0) == (0 < pid));
 
@@ -2263,7 +2311,7 @@ create_pty (Lisp_Object process)
 {
   struct Lisp_Process *p = XPROCESS (process);
   char pty_name[PTY_NAME_SIZE];
-  int pty_fd = !p->pty_flag ? -1 : allocate_pty (pty_name);
+  int pty_fd = !(p->pty_in || p->pty_out) ? -1 : allocate_pty (pty_name);
 
   if (pty_fd >= 0)
     {
@@ -2301,7 +2349,7 @@ create_pty (Lisp_Object process)
         we just reopen the device (see emacs_get_tty_pgrp) as this is
         more portable (see USG_SUBTTY_WORKS above).  */
 
-      p->pty_flag = 1;
+      p->pty_in = p->pty_out = true;
       pset_status (p, Qrun);
       setup_process_coding_systems (process);
 
@@ -2364,7 +2412,7 @@ usage:  (make-pipe-process &rest ARGS)  */)
 
   contact = Flist (nargs, args);
 
-  name = Fplist_get (contact, QCname);
+  name = plist_get (contact, QCname);
   CHECK_STRING (name);
   proc = make_process (name);
   specpdl_ref specpdl_count = SPECPDL_INDEX ();
@@ -2396,23 +2444,23 @@ usage:  (make-pipe-process &rest ARGS)  */)
   if (inchannel > max_desc)
     max_desc = inchannel;
 
-  buffer = Fplist_get (contact, QCbuffer);
+  buffer = plist_get (contact, QCbuffer);
   if (NILP (buffer))
     buffer = name;
   buffer = Fget_buffer_create (buffer, Qnil);
   pset_buffer (p, buffer);
 
   pset_childp (p, contact);
-  pset_plist (p, Fcopy_sequence (Fplist_get (contact, QCplist)));
+  pset_plist (p, Fcopy_sequence (plist_get (contact, QCplist)));
   pset_type (p, Qpipe);
-  pset_sentinel (p, Fplist_get (contact, QCsentinel));
-  pset_filter (p, Fplist_get (contact, QCfilter));
+  pset_sentinel (p, plist_get (contact, QCsentinel));
+  pset_filter (p, plist_get (contact, QCfilter));
   eassert (NILP (p->log));
-  if (tem = Fplist_get (contact, QCnoquery), !NILP (tem))
+  if (tem = plist_get (contact, QCnoquery), !NILP (tem))
     p->kill_without_query = 1;
-  if (tem = Fplist_get (contact, QCstop), !NILP (tem))
+  if (tem = plist_get (contact, QCstop), !NILP (tem))
     pset_command (p, Qt);
-  eassert (! p->pty_flag);
+  eassert (! p->pty_in && ! p->pty_out);
 
   if (!EQ (p->command, Qt)
       && !EQ (p->filter, Qt))
@@ -2431,7 +2479,7 @@ usage:  (make-pipe-process &rest ARGS)  */)
     Lisp_Object coding_systems = Qt;
     Lisp_Object val;
 
-    tem = Fplist_get (contact, QCcoding);
+    tem = plist_get (contact, QCcoding);
     val = Qnil;
     if (!NILP (tem))
       {
@@ -2918,7 +2966,7 @@ set up yet, this function will block until socket setup 
has completed. */)
 
   if (set_socket_option (s, option, value))
     {
-      pset_childp (p, Fplist_put (p->childp, option, value));
+      pset_childp (p, plist_put (p->childp, option, value));
       return Qt;
     }
 
@@ -2996,19 +3044,19 @@ usage: (serial-process-configure &rest ARGS)  */)
 
   contact = Flist (nargs, args);
 
-  proc = Fplist_get (contact, QCprocess);
+  proc = plist_get (contact, QCprocess);
   if (NILP (proc))
-    proc = Fplist_get (contact, QCname);
+    proc = plist_get (contact, QCname);
   if (NILP (proc))
-    proc = Fplist_get (contact, QCbuffer);
+    proc = plist_get (contact, QCbuffer);
   if (NILP (proc))
-    proc = Fplist_get (contact, QCport);
+    proc = plist_get (contact, QCport);
   proc = get_process (proc);
   p = XPROCESS (proc);
   if (!EQ (p->type, Qserial))
     error ("Not a serial process");
 
-  if (NILP (Fplist_get (p->childp, QCspeed)))
+  if (NILP (plist_get (p->childp, QCspeed)))
     return Qnil;
 
   serial_configure (p, contact);
@@ -3101,17 +3149,17 @@ usage:  (make-serial-process &rest ARGS)  */)
 
   contact = Flist (nargs, args);
 
-  port = Fplist_get (contact, QCport);
+  port = plist_get (contact, QCport);
   if (NILP (port))
     error ("No port specified");
   CHECK_STRING (port);
 
-  if (NILP (Fplist_member (contact, QCspeed)))
+  if (NILP (plist_member (contact, QCspeed)))
     error (":speed not specified");
-  if (!NILP (Fplist_get (contact, QCspeed)))
-    CHECK_FIXNUM (Fplist_get (contact, QCspeed));
+  if (!NILP (plist_get (contact, QCspeed)))
+    CHECK_FIXNUM (plist_get (contact, QCspeed));
 
-  name = Fplist_get (contact, QCname);
+  name = plist_get (contact, QCname);
   if (NILP (name))
     name = port;
   CHECK_STRING (name);
@@ -3131,23 +3179,23 @@ usage:  (make-serial-process &rest ARGS)  */)
   eassert (0 <= fd && fd < FD_SETSIZE);
   chan_process[fd] = proc;
 
-  buffer = Fplist_get (contact, QCbuffer);
+  buffer = plist_get (contact, QCbuffer);
   if (NILP (buffer))
     buffer = name;
   buffer = Fget_buffer_create (buffer, Qnil);
   pset_buffer (p, buffer);
 
   pset_childp (p, contact);
-  pset_plist (p, Fcopy_sequence (Fplist_get (contact, QCplist)));
+  pset_plist (p, Fcopy_sequence (plist_get (contact, QCplist)));
   pset_type (p, Qserial);
-  pset_sentinel (p, Fplist_get (contact, QCsentinel));
-  pset_filter (p, Fplist_get (contact, QCfilter));
+  pset_sentinel (p, plist_get (contact, QCsentinel));
+  pset_filter (p, plist_get (contact, QCfilter));
   eassert (NILP (p->log));
-  if (tem = Fplist_get (contact, QCnoquery), !NILP (tem))
+  if (tem = plist_get (contact, QCnoquery), !NILP (tem))
     p->kill_without_query = 1;
-  if (tem = Fplist_get (contact, QCstop), !NILP (tem))
+  if (tem = plist_get (contact, QCstop), !NILP (tem))
     pset_command (p, Qt);
-  eassert (! p->pty_flag);
+  eassert (! p->pty_in && ! p->pty_out);
 
   if (!EQ (p->command, Qt)
       && !EQ (p->filter, Qt))
@@ -3155,7 +3203,7 @@ usage:  (make-serial-process &rest ARGS)  */)
 
   update_process_mark (p);
 
-  tem = Fplist_get (contact, QCcoding);
+  tem = plist_get (contact, QCcoding);
 
   val = Qnil;
   if (!NILP (tem))
@@ -3209,7 +3257,7 @@ set_network_socket_coding_system (Lisp_Object proc, 
Lisp_Object host,
   Lisp_Object coding_systems = Qt;
   Lisp_Object val;
 
-  tem = Fplist_get (contact, QCcoding);
+  tem = plist_get (contact, QCcoding);
 
   /* Setup coding systems for communicating with the network stream.  */
   /* Qt denotes we have not yet called Ffind_operation_coding_system.  */
@@ -3297,8 +3345,8 @@ finish_after_tls_connection (Lisp_Object proc)
   if (!NILP (Ffboundp (Qnsm_verify_connection)))
     result = call3 (Qnsm_verify_connection,
                    proc,
-                   Fplist_get (contact, QChost),
-                   Fplist_get (contact, QCservice));
+                   plist_get (contact, QChost),
+                   plist_get (contact, QCservice));
 
   eassert (p->outfd < FD_SETSIZE);
   if (NILP (result))
@@ -3479,7 +3527,7 @@ connect_network_socket (Lisp_Object proc, Lisp_Object 
addrinfos,
              if (getsockname (s, psa1, &len1) == 0)
                {
                  Lisp_Object service = make_fixnum (ntohs (sa1.sin_port));
-                 contact = Fplist_put (contact, QCservice, service);
+                 contact = plist_put (contact, QCservice, service);
                  /* Save the port number so that we can stash it in
                     the process object later.  */
                  DECLARE_POINTER_ALIAS (psa, struct sockaddr_in, sa);
@@ -3570,7 +3618,7 @@ connect_network_socket (Lisp_Object proc, Lisp_Object 
addrinfos,
            {
              Lisp_Object remote;
              memset (datagram_address[s].sa, 0, addrlen);
-             if (remote = Fplist_get (contact, QCremote), !NILP (remote))
+             if (remote = plist_get (contact, QCremote), !NILP (remote))
                {
                  int rfamily;
                  ptrdiff_t rlen = get_lisp_to_sockaddr_size (remote, &rfamily);
@@ -3585,8 +3633,8 @@ connect_network_socket (Lisp_Object proc, Lisp_Object 
addrinfos,
        }
 #endif
 
-      contact = Fplist_put (contact, p->is_server? QClocal: QCremote,
-                           conv_sockaddr_to_lisp (sa, addrlen));
+      contact = plist_put (contact, p->is_server? QClocal: QCremote,
+                          conv_sockaddr_to_lisp (sa, addrlen));
 #ifdef HAVE_GETSOCKNAME
       if (!p->is_server)
        {
@@ -3594,8 +3642,8 @@ connect_network_socket (Lisp_Object proc, Lisp_Object 
addrinfos,
          socklen_t len1 = sizeof (sa1);
          DECLARE_POINTER_ALIAS (psa1, struct sockaddr, &sa1);
          if (getsockname (s, psa1, &len1) == 0)
-           contact = Fplist_put (contact, QClocal,
-                                 conv_sockaddr_to_lisp (psa1, len1));
+           contact = plist_put (contact, QClocal,
+                                conv_sockaddr_to_lisp (psa1, len1));
        }
 #endif
     }
@@ -3908,7 +3956,7 @@ usage: (make-network-process &rest ARGS)  */)
 #endif
 
   /* :type TYPE  (nil: stream, datagram */
-  tem = Fplist_get (contact, QCtype);
+  tem = plist_get (contact, QCtype);
   if (NILP (tem))
     socktype = SOCK_STREAM;
 #ifdef DATAGRAM_SOCKETS
@@ -3922,13 +3970,13 @@ usage: (make-network-process &rest ARGS)  */)
   else
     error ("Unsupported connection type");
 
-  name = Fplist_get (contact, QCname);
-  buffer = Fplist_get (contact, QCbuffer);
-  filter = Fplist_get (contact, QCfilter);
-  sentinel = Fplist_get (contact, QCsentinel);
-  use_external_socket_p = Fplist_get (contact, QCuse_external_socket);
-  Lisp_Object server = Fplist_get (contact, QCserver);
-  bool nowait = !NILP (Fplist_get (contact, QCnowait));
+  name = plist_get (contact, QCname);
+  buffer = plist_get (contact, QCbuffer);
+  filter = plist_get (contact, QCfilter);
+  sentinel = plist_get (contact, QCsentinel);
+  use_external_socket_p = plist_get (contact, QCuse_external_socket);
+  Lisp_Object server = plist_get (contact, QCserver);
+  bool nowait = !NILP (plist_get (contact, QCnowait));
 
   if (!NILP (server) && nowait)
     error ("`:server' is incompatible with `:nowait'");
@@ -3936,9 +3984,9 @@ usage: (make-network-process &rest ARGS)  */)
 
   /* :local ADDRESS or :remote ADDRESS */
   if (NILP (server))
-    address = Fplist_get (contact, QCremote);
+    address = plist_get (contact, QCremote);
   else
-    address = Fplist_get (contact, QClocal);
+    address = plist_get (contact, QClocal);
   if (!NILP (address))
     {
       host = service = Qnil;
@@ -3951,7 +3999,7 @@ usage: (make-network-process &rest ARGS)  */)
     }
 
   /* :family FAMILY -- nil (for Inet), local, or integer.  */
-  tem = Fplist_get (contact, QCfamily);
+  tem = plist_get (contact, QCfamily);
   if (NILP (tem))
     {
 #ifdef AF_INET6
@@ -3976,10 +4024,10 @@ usage: (make-network-process &rest ARGS)  */)
     error ("Unknown address family");
 
   /* :service SERVICE -- string, integer (port number), or t (random port).  */
-  service = Fplist_get (contact, QCservice);
+  service = plist_get (contact, QCservice);
 
   /* :host HOST -- hostname, ip address, or 'local for localhost.  */
-  host = Fplist_get (contact, QChost);
+  host = plist_get (contact, QChost);
   if (NILP (host))
     {
       /* The "connection" function gets it bind info from the address we're
@@ -4018,7 +4066,7 @@ usage: (make-network-process &rest ARGS)  */)
       if (!NILP (host))
        {
          message (":family local ignores the :host property");
-         contact = Fplist_put (contact, QChost, Qnil);
+         contact = plist_put (contact, QChost, Qnil);
          host = Qnil;
        }
       CHECK_STRING (service);
@@ -4172,16 +4220,16 @@ usage: (make-network-process &rest ARGS)  */)
   record_unwind_protect (remove_process, proc);
   p = XPROCESS (proc);
   pset_childp (p, contact);
-  pset_plist (p, Fcopy_sequence (Fplist_get (contact, QCplist)));
+  pset_plist (p, Fcopy_sequence (plist_get (contact, QCplist)));
   pset_type (p, Qnetwork);
 
   pset_buffer (p, buffer);
   pset_sentinel (p, sentinel);
   pset_filter (p, filter);
-  pset_log (p, Fplist_get (contact, QClog));
-  if (tem = Fplist_get (contact, QCnoquery), !NILP (tem))
+  pset_log (p, plist_get (contact, QClog));
+  if (tem = plist_get (contact, QCnoquery), !NILP (tem))
     p->kill_without_query = 1;
-  if ((tem = Fplist_get (contact, QCstop), !NILP (tem)))
+  if ((tem = plist_get (contact, QCstop), !NILP (tem)))
     pset_command (p, Qt);
   eassert (p->pid == 0);
   p->backlog = 5;
@@ -4193,7 +4241,7 @@ usage: (make-network-process &rest ARGS)  */)
   eassert (! p->dns_request);
 #endif
 #ifdef HAVE_GNUTLS
-  tem = Fplist_get (contact, QCtls_parameters);
+  tem = plist_get (contact, QCtls_parameters);
   CHECK_LIST (tem);
   p->gnutls_boot_parameters = tem;
 #endif
@@ -4641,15 +4689,20 @@ network_lookup_address_info_1 (Lisp_Object host, const 
char *service,
 }
 
 DEFUN ("network-lookup-address-info", Fnetwork_lookup_address_info,
-       Snetwork_lookup_address_info, 1, 2, 0,
+       Snetwork_lookup_address_info, 1, 3, 0,
        doc: /* Look up Internet Protocol (IP) address info of NAME.
-Optional parameter FAMILY controls whether to look up IPv4 or IPv6
+Optional argument FAMILY controls whether to look up IPv4 or IPv6
 addresses.  The default of nil means both, symbol `ipv4' means IPv4
-only, symbol `ipv6' means IPv6 only.  Returns a list of addresses, or
-nil if none were found.  Each address is a vector of integers, as per
-the description of ADDRESS in `make-network-process'.  In case of
-error displays the error message.  */)
-     (Lisp_Object name, Lisp_Object family)
+only, symbol `ipv6' means IPv6 only.
+Optional argument HINTS allows specifying the hints passed to the
+underlying library call.  The only supported value is `numeric', which
+means treat NAME as a numeric IP address.  This also suppresses DNS
+traffic.
+Return a list of addresses, or nil if none were found.  Each address
+is a vector of integers, as per the description of ADDRESS in
+`make-network-process'.  In case of error log the error message
+returned from the lookup.  */)
+  (Lisp_Object name, Lisp_Object family, Lisp_Object hint)
 {
   Lisp_Object addresses = Qnil;
   Lisp_Object msg = Qnil;
@@ -4667,9 +4720,14 @@ error displays the error message.  */)
     hints.ai_family = AF_INET6;
 #endif
   else
-    error ("Unsupported lookup type");
+    error ("Unsupported family");
   hints.ai_socktype = SOCK_DGRAM;
 
+  if (EQ (hint, Qnumeric))
+    hints.ai_flags = AI_NUMERICHOST;
+  else if (!NILP (hint))
+    error ("Unsupported hints value");
+
   msg = network_lookup_address_info_1 (name, NULL, &hints, &res);
   if (!EQ (msg, Qt))
     message ("%s", SSDATA(msg));
@@ -4775,7 +4833,7 @@ corresponding connection was closed.  */)
 
       /* Can't wait for a process that is dedicated to a different
         thread.  */
-      if (!NILP (proc->thread) && !EQ (proc->thread, Fcurrent_thread ()))
+      if (!NILP (proc->thread) && !BASE_EQ (proc->thread, Fcurrent_thread ()))
        {
          Lisp_Object proc_thread_name = XTHREAD (proc->thread)->name;
 
@@ -4969,17 +5027,17 @@ server_accept_connection (Lisp_Object server, int 
channel)
 
   /* Build new contact information for this setup.  */
   contact = Fcopy_sequence (ps->childp);
-  contact = Fplist_put (contact, QCserver, Qnil);
-  contact = Fplist_put (contact, QChost, host);
+  contact = plist_put (contact, QCserver, Qnil);
+  contact = plist_put (contact, QChost, host);
   if (!NILP (service))
-    contact = Fplist_put (contact, QCservice, service);
-  contact = Fplist_put (contact, QCremote,
-                       conv_sockaddr_to_lisp (&saddr.sa, len));
+    contact = plist_put (contact, QCservice, service);
+  contact = plist_put (contact, QCremote,
+                      conv_sockaddr_to_lisp (&saddr.sa, len));
 #ifdef HAVE_GETSOCKNAME
   len = sizeof saddr;
   if (getsockname (s, &saddr.sa, &len) == 0)
-    contact = Fplist_put (contact, QClocal,
-                         conv_sockaddr_to_lisp (&saddr.sa, len));
+    contact = plist_put (contact, QClocal,
+                        conv_sockaddr_to_lisp (&saddr.sa, len));
 #endif
 
   pset_childp (p, contact);
@@ -5492,7 +5550,17 @@ wait_reading_process_output (intmax_t time_limit, int 
nsecs, int read_kbd,
         triggered by processing X events).  In the latter case, set
         nfds to 1 to avoid breaking the loop.  */
       no_avail = 0;
-      if ((read_kbd || !NILP (wait_for_cell))
+      if ((read_kbd
+          /* The following code doesn't make any sense for just the
+             wait_for_cell case, because detect_input_pending returns
+             whether or not the keyboard buffer isn't empty or there
+             is mouse movement.  Any keyboard input that arrives
+             while waiting for a cell will cause the select call to
+             be skipped, and gobble_input to be called even when
+             there is no input available from the terminal itself.
+             Skipping the call to select also causes the timeout to
+             be ignored.  (bug#46935) */
+          /* || !NILP (wait_for_cell) */)
          && detect_input_pending ())
        {
          nfds = read_kbd ? 0 : 1;
@@ -6788,7 +6856,7 @@ process_send_signal (Lisp_Object process, int signo, 
Lisp_Object current_group,
     error ("Process %s is not active",
           SDATA (p->name));
 
-  if (!p->pty_flag)
+  if (! p->pty_in)
     current_group = Qnil;
 
   /* If we are using pgrps, get a pgrp number and make it negative.  */
@@ -7099,7 +7167,7 @@ See function `signal-process' for more details on usage.  
*/)
 }
 
 DEFUN ("signal-process", Fsignal_process, Ssignal_process,
-       2, 3, "sProcess (name or number): \nnSignal code: ",
+       2, 3, "(list (read-string \"Process (name or number): \") 
(read-signal-name))",
        doc: /* Send PROCESS the signal with code SIGCODE.
 PROCESS may also be a number specifying the process id of the
 process to signal; in this case, the process need not be a child of
@@ -7157,7 +7225,7 @@ process has been transmitted to the serial port.  */)
       send_process (proc, "", 0, Qnil);
     }
 
-  if (XPROCESS (proc)->pty_flag)
+  if (XPROCESS (proc)->pty_in)
     send_process (proc, "\004", 1, Qnil);
   else if (EQ (XPROCESS (proc)->type, Qserial))
     {
@@ -7705,46 +7773,6 @@ DEFUN ("process-coding-system",
                XPROCESS (process)->encode_coding_system);
 }
 
-DEFUN ("set-process-filter-multibyte", Fset_process_filter_multibyte,
-       Sset_process_filter_multibyte, 2, 2, 0,
-       doc: /* Set multibyteness of the strings given to PROCESS's filter.
-If FLAG is non-nil, the filter is given multibyte strings.
-If FLAG is nil, the filter is given unibyte strings.  In this case,
-all character code conversion except for end-of-line conversion is
-suppressed.  */)
-  (Lisp_Object process, Lisp_Object flag)
-{
-  CHECK_PROCESS (process);
-
-  struct Lisp_Process *p = XPROCESS (process);
-  if (NILP (flag))
-    pset_decode_coding_system
-      (p, raw_text_coding_system (p->decode_coding_system));
-
-  /* If the sockets haven't been set up yet, the final setup part of
-     this will be called asynchronously. */
-  if (p->infd < 0 || p->outfd < 0)
-    return Qnil;
-
-  setup_process_coding_systems (process);
-
-  return Qnil;
-}
-
-DEFUN ("process-filter-multibyte-p", Fprocess_filter_multibyte_p,
-       Sprocess_filter_multibyte_p, 1, 1, 0,
-       doc: /* Return t if a multibyte string is given to PROCESS's filter.*/)
-  (Lisp_Object process)
-{
-  CHECK_PROCESS (process);
-  struct Lisp_Process *p = XPROCESS (process);
-  if (p->infd < 0)
-    return Qnil;
-  eassert (p->infd < FD_SETSIZE);
-  struct coding_system *coding = proc_decode_coding_system[p->infd];
-  return (CODING_FOR_UNIBYTE (coding) ? Qnil : Qt);
-}
-
 
 
 
@@ -8307,6 +8335,27 @@ If QUERY is `all', also count processors not available.  
*/)
 #endif
 }
 
+DEFUN ("signal-names", Fsignal_names, Ssignal_names, 0, 0, 0,
+       doc: /* Return a list of known signal names on this system.  */)
+  (void)
+{
+#ifndef MSDOS
+  int i;
+  char name[SIG2STR_MAX];
+  Lisp_Object names = Qnil;
+
+  for (i = 0; i <= SIGNUM_BOUND; ++i)
+    {
+      if (!sig2str (i, name))
+       names = Fcons (build_string (name), names);
+    }
+
+  return names;
+#else
+  return Qnil;
+#endif
+}
+
 #ifdef subprocesses
 /* Arrange to catch SIGCHLD if this hasn't already been arranged.
    Invoke this after init_process_emacs, and after glib and/or GNUstep
@@ -8484,6 +8533,7 @@ syms_of_process (void)
 #ifdef AF_INET6
   DEFSYM (Qipv6, "ipv6");
 #endif
+  DEFSYM (Qnumeric, "numeric");
   DEFSYM (Qdatagram, "datagram");
   DEFSYM (Qseqpacket, "seqpacket");
 
@@ -8718,8 +8768,6 @@ sentinel or a process filter function has an error.  */);
   defsubr (&Sinternal_default_process_filter);
   defsubr (&Sset_process_coding_system);
   defsubr (&Sprocess_coding_system);
-  defsubr (&Sset_process_filter_multibyte);
-  defsubr (&Sprocess_filter_multibyte_p);
 
  {
    Lisp_Object subfeatures = Qnil;
@@ -8760,4 +8808,5 @@ sentinel or a process filter function has an error.  */);
   defsubr (&Slist_system_processes);
   defsubr (&Sprocess_attributes);
   defsubr (&Snum_processors);
+  defsubr (&Ssignal_names);
 }
diff --git a/src/process.h b/src/process.h
index 392b661ce6..92baf0c4cb 100644
--- a/src/process.h
+++ b/src/process.h
@@ -156,8 +156,9 @@ struct Lisp_Process
     /* True means kill silently if Emacs is exited.
        This is the inverse of the `query-on-exit' flag.  */
     bool_bf kill_without_query : 1;
-    /* True if communicating through a pty.  */
-    bool_bf pty_flag : 1;
+    /* True if communicating through a pty for input or output.  */
+    bool_bf pty_in : 1;
+    bool_bf pty_out : 1;
     /* Flag to set coding-system of the process buffer from the
        coding_system used to decode process output.  */
     bool_bf inherit_coding_system_flag : 1;
diff --git a/src/puresize.h b/src/puresize.h
index 5516747ac2..4b746924bb 100644
--- a/src/puresize.h
+++ b/src/puresize.h
@@ -47,7 +47,7 @@ INLINE_HEADER_BEGIN
 #endif
 
 #ifndef BASE_PURESIZE
-#define BASE_PURESIZE (2000000 + SYSTEM_PURESIZE_EXTRA + 
SITELOAD_PURESIZE_EXTRA)
+#define BASE_PURESIZE (2750000 + SYSTEM_PURESIZE_EXTRA + 
SITELOAD_PURESIZE_EXTRA)
 #endif
 
 /* Increase BASE_PURESIZE by a ratio depending on the machine's word size.  */
diff --git a/src/regex-emacs.c b/src/regex-emacs.c
index 8662fe8d6d..9b2c14c413 100644
--- a/src/regex-emacs.c
+++ b/src/regex-emacs.c
@@ -33,6 +33,7 @@
 #include "buffer.h"
 #include "syntax.h"
 #include "category.h"
+#include "dispextern.h"
 
 /* Maximum number of duplicates an interval can allow.  Some systems
    define this in other header files, but we want our value, so remove
@@ -3953,6 +3954,9 @@ re_match_2_internal (struct re_pattern_buffer *bufp,
      and need to test it, it's not garbage.  */
   re_char *match_end = NULL;
 
+  /* This keeps track of how many buffer/string positions we examined.  */
+  ptrdiff_t nchars = 0;
+
 #ifdef DEBUG_COMPILES_ARGUMENTS
   /* Counts the total number of registers pushed.  */
   ptrdiff_t num_regs_pushed = 0;
@@ -4209,6 +4213,12 @@ re_match_2_internal (struct re_pattern_buffer *bufp,
 
          unbind_to (count, Qnil);
          SAFE_FREE ();
+         /* The factor of 50 below is a heuristic that needs to be tuned.  It
+            means we consider 50 buffer positions examined by this function
+            roughly equivalent to the display engine iterating over a single
+            buffer position.  */
+         if (max_redisplay_ticks > 0 && nchars > 0)
+           update_redisplay_ticks (nchars / 50 + 1, NULL);
          return dcnt;
        }
 
@@ -4261,6 +4271,7 @@ re_match_2_internal (struct re_pattern_buffer *bufp,
                p += pat_charlen;
                d += buf_charlen;
                mcnt -= pat_charlen;
+               nchars++;
              }
            while (mcnt > 0);
          else
@@ -4298,6 +4309,7 @@ re_match_2_internal (struct re_pattern_buffer *bufp,
                p += pat_charlen;
                d++;
                mcnt -= pat_charlen;
+               nchars++;
              }
            while (mcnt > 0);
 
@@ -4321,6 +4333,7 @@ re_match_2_internal (struct re_pattern_buffer *bufp,
 
            DEBUG_PRINT ("  Matched \"%d\".\n", *d);
            d += buf_charlen;
+           nchars++;
          }
          break;
 
@@ -4373,6 +4386,7 @@ re_match_2_internal (struct re_pattern_buffer *bufp,
              goto fail;
 
            d += len;
+           nchars++;
          }
          break;
 
@@ -4492,6 +4506,7 @@ re_match_2_internal (struct re_pattern_buffer *bufp,
                    goto fail;
                  }
                d += dcnt, d2 += dcnt;
+               nchars++;
              }
          }
          break;
@@ -4773,10 +4788,12 @@ re_match_2_internal (struct re_pattern_buffer *bufp,
                 ptrdiff_t charpos = SYNTAX_TABLE_BYTE_TO_CHAR (offset) - 1;
                UPDATE_SYNTAX_TABLE (charpos);
                GET_CHAR_BEFORE_2 (c1, d, string1, end1, string2, end2);
+               nchars++;
                s1 = SYNTAX (c1);
                UPDATE_SYNTAX_TABLE_FORWARD (charpos + 1);
                PREFETCH_NOLIMIT ();
                GET_CHAR_AFTER (c2, d, dummy);
+               nchars++;
                s2 = SYNTAX (c2);
 
                if (/* Case 2: Only one of S1 and S2 is Sword.  */
@@ -4812,6 +4829,7 @@ re_match_2_internal (struct re_pattern_buffer *bufp,
              UPDATE_SYNTAX_TABLE (charpos);
              PREFETCH ();
              GET_CHAR_AFTER (c2, d, dummy);
+             nchars++;
              s2 = SYNTAX (c2);
 
              /* Case 2: S2 is not Sword. */
@@ -4822,6 +4840,7 @@ re_match_2_internal (struct re_pattern_buffer *bufp,
              if (!AT_STRINGS_BEG (d))
                {
                  GET_CHAR_BEFORE_2 (c1, d, string1, end1, string2, end2);
+                 nchars++;
                  UPDATE_SYNTAX_TABLE_BACKWARD (charpos - 1);
                  s1 = SYNTAX (c1);
 
@@ -4852,6 +4871,7 @@ re_match_2_internal (struct re_pattern_buffer *bufp,
               ptrdiff_t charpos = SYNTAX_TABLE_BYTE_TO_CHAR (offset) - 1;
              UPDATE_SYNTAX_TABLE (charpos);
              GET_CHAR_BEFORE_2 (c1, d, string1, end1, string2, end2);
+             nchars++;
              s1 = SYNTAX (c1);
 
              /* Case 2: S1 is not Sword.  */
@@ -4863,6 +4883,7 @@ re_match_2_internal (struct re_pattern_buffer *bufp,
                {
                  PREFETCH_NOLIMIT ();
                  GET_CHAR_AFTER (c2, d, dummy);
+                 nchars++;
                   UPDATE_SYNTAX_TABLE_FORWARD (charpos + 1);
                  s2 = SYNTAX (c2);
 
@@ -4893,6 +4914,7 @@ re_match_2_internal (struct re_pattern_buffer *bufp,
              UPDATE_SYNTAX_TABLE (charpos);
              PREFETCH ();
              c2 = RE_STRING_CHAR (d, target_multibyte);
+             nchars++;
              s2 = SYNTAX (c2);
 
              /* Case 2: S2 is neither Sword nor Ssymbol. */
@@ -4903,6 +4925,7 @@ re_match_2_internal (struct re_pattern_buffer *bufp,
              if (!AT_STRINGS_BEG (d))
                {
                  GET_CHAR_BEFORE_2 (c1, d, string1, end1, string2, end2);
+                 nchars++;
                  UPDATE_SYNTAX_TABLE_BACKWARD (charpos - 1);
                  s1 = SYNTAX (c1);
 
@@ -4931,6 +4954,7 @@ re_match_2_internal (struct re_pattern_buffer *bufp,
               ptrdiff_t charpos = SYNTAX_TABLE_BYTE_TO_CHAR (offset) - 1;
              UPDATE_SYNTAX_TABLE (charpos);
              GET_CHAR_BEFORE_2 (c1, d, string1, end1, string2, end2);
+             nchars++;
              s1 = SYNTAX (c1);
 
              /* Case 2: S1 is neither Ssymbol nor Sword.  */
@@ -4942,6 +4966,7 @@ re_match_2_internal (struct re_pattern_buffer *bufp,
                {
                  PREFETCH_NOLIMIT ();
                  c2 = RE_STRING_CHAR (d, target_multibyte);
+                 nchars++;
                  UPDATE_SYNTAX_TABLE_FORWARD (charpos + 1);
                  s2 = SYNTAX (c2);
 
@@ -4973,6 +4998,7 @@ re_match_2_internal (struct re_pattern_buffer *bufp,
              if ((SYNTAX (c) != (enum syntaxcode) mcnt) ^ not)
                goto fail;
              d += len;
+             nchars++;
            }
          }
          break;
@@ -4999,6 +5025,7 @@ re_match_2_internal (struct re_pattern_buffer *bufp,
              if ((!CHAR_HAS_CATEGORY (c, mcnt)) ^ not)
                goto fail;
              d += len;
+             nchars++;
            }
          }
          break;
@@ -5060,6 +5087,9 @@ re_match_2_internal (struct re_pattern_buffer *bufp,
   unbind_to (count, Qnil);
   SAFE_FREE ();
 
+  if (max_redisplay_ticks > 0 && nchars > 0)
+    update_redisplay_ticks (nchars / 50 + 1, NULL);
+
   return -1;                           /* Failure to match.  */
 }
 
diff --git a/src/search.c b/src/search.c
index 816a757c18..b5d6a442c0 100644
--- a/src/search.c
+++ b/src/search.c
@@ -370,7 +370,6 @@ string_match_1 (Lisp_Object regexp, Lisp_Object string, 
Lisp_Object start,
                bool posix, bool modify_data)
 {
   ptrdiff_t val;
-  struct re_pattern_buffer *bufp;
   EMACS_INT pos;
   ptrdiff_t pos_byte, i;
   bool modify_match_data = NILP (Vinhibit_changing_match_data) && modify_data;
@@ -401,17 +400,22 @@ string_match_1 (Lisp_Object regexp, Lisp_Object string, 
Lisp_Object start,
   set_char_table_extras (BVAR (current_buffer, case_canon_table), 2,
                         BVAR (current_buffer, case_eqv_table));
 
-  bufp = &compile_pattern (regexp,
-                           (modify_match_data ? &search_regs : NULL),
-                           (!NILP (BVAR (current_buffer, case_fold_search))
-                            ? BVAR (current_buffer, case_canon_table) : Qnil),
-                           posix,
-                           STRING_MULTIBYTE (string))->buf;
+  specpdl_ref count = SPECPDL_INDEX ();
+  struct regexp_cache *cache_entry
+    = compile_pattern (regexp,
+                      modify_match_data ? &search_regs : NULL,
+                      (!NILP (BVAR (current_buffer, case_fold_search))
+                       ? BVAR (current_buffer, case_canon_table)
+                       : Qnil),
+                      posix,
+                      STRING_MULTIBYTE (string));
+  freeze_pattern (cache_entry);
   re_match_object = string;
-  val = re_search (bufp, SSDATA (string),
+  val = re_search (&cache_entry->buf, SSDATA (string),
                   SBYTES (string), pos_byte,
                   SBYTES (string) - pos_byte,
                   (modify_match_data ? &search_regs : NULL));
+  unbind_to (count, Qnil);
 
   /* Set last_thing_searched only when match data is changed.  */
   if (modify_match_data)
@@ -480,15 +484,15 @@ ptrdiff_t
 fast_string_match_internal (Lisp_Object regexp, Lisp_Object string,
                            Lisp_Object table)
 {
-  ptrdiff_t val;
-  struct re_pattern_buffer *bufp;
-
-  bufp = &compile_pattern (regexp, 0, table,
-                           0, STRING_MULTIBYTE (string))->buf;
   re_match_object = string;
-  val = re_search (bufp, SSDATA (string),
-                  SBYTES (string), 0,
-                  SBYTES (string), 0);
+  specpdl_ref count = SPECPDL_INDEX ();
+  struct regexp_cache *cache_entry
+    = compile_pattern (regexp, 0, table, 0, STRING_MULTIBYTE (string));
+  freeze_pattern (cache_entry);
+  ptrdiff_t val = re_search (&cache_entry->buf, SSDATA (string),
+                            SBYTES (string), 0,
+                            SBYTES (string), 0);
+  unbind_to (count, Qnil);
   return val;
 }
 
@@ -501,15 +505,14 @@ ptrdiff_t
 fast_c_string_match_ignore_case (Lisp_Object regexp,
                                 const char *string, ptrdiff_t len)
 {
-  ptrdiff_t val;
-  struct re_pattern_buffer *bufp;
-
   regexp = string_make_unibyte (regexp);
-  bufp = &compile_pattern (regexp, 0,
-                           Vascii_canon_table, 0,
-                           0)->buf;
+  specpdl_ref count = SPECPDL_INDEX ();
+  struct regexp_cache *cache_entry
+    = compile_pattern (regexp, 0, Vascii_canon_table, 0, 0);
+  freeze_pattern (cache_entry);
   re_match_object = Qt;
-  val = re_search (bufp, string, len, 0, len, 0);
+  ptrdiff_t val = re_search (&cache_entry->buf, string, len, 0, len, 0);
+  unbind_to (count, Qnil);
   return val;
 }
 
@@ -3189,7 +3192,7 @@ DEFUN ("regexp-quote", Fregexp_quote, Sregexp_quote, 1, 
1, 0,
 }
 
 /* Like find_newline, but doesn't use the cache, and only searches forward.  */
-static ptrdiff_t
+ptrdiff_t
 find_newline1 (ptrdiff_t start, ptrdiff_t start_byte, ptrdiff_t end,
               ptrdiff_t end_byte, ptrdiff_t count, ptrdiff_t *counted,
               ptrdiff_t *bytepos, bool allow_quit)
diff --git a/src/sheap.h b/src/sheap.h
index 297b7cf317..cef111bc2f 100644
--- a/src/sheap.h
+++ b/src/sheap.h
@@ -23,7 +23,7 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 /* Size of the static heap.  Guess a value that is probably too large,
    by up to a factor of four or so.  Typically the unused part is not
    paged in and so does not cost much.  */
-enum { STATIC_HEAP_SIZE = sizeof (Lisp_Object) << 22 };
+enum { STATIC_HEAP_SIZE = sizeof (Lisp_Object) << 24 };
 
 extern char bss_sbrk_buffer[STATIC_HEAP_SIZE];
 extern char *max_bss_sbrk_ptr;
diff --git a/src/sound.c b/src/sound.c
index 93c84a03b1..0a30782800 100644
--- a/src/sound.c
+++ b/src/sound.c
@@ -361,10 +361,10 @@ parse_sound (Lisp_Object sound, Lisp_Object *attrs)
     return 0;
 
   sound = XCDR (sound);
-  attrs[SOUND_FILE] = Fplist_get (sound, QCfile);
-  attrs[SOUND_DATA] = Fplist_get (sound, QCdata);
-  attrs[SOUND_DEVICE] = Fplist_get (sound, QCdevice);
-  attrs[SOUND_VOLUME] = Fplist_get (sound, QCvolume);
+  attrs[SOUND_FILE] = plist_get (sound, QCfile);
+  attrs[SOUND_DATA] = plist_get (sound, QCdata);
+  attrs[SOUND_DEVICE] = plist_get (sound, QCdevice);
+  attrs[SOUND_VOLUME] = plist_get (sound, QCvolume);
 
 #ifndef WINDOWSNT
   /* File name or data must be specified.  */
diff --git a/src/sqlite.c b/src/sqlite.c
index 75a3b2ea32..54bfb7b6c6 100644
--- a/src/sqlite.c
+++ b/src/sqlite.c
@@ -246,8 +246,10 @@ If FILE is nil, an in-memory database will be opened 
instead.  */)
   (Lisp_Object file)
 {
   Lisp_Object name;
-  int flags = (SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX
-              | SQLITE_OPEN_READWRITE);
+  int flags = (SQLITE_OPEN_CREATE  | SQLITE_OPEN_READWRITE);
+#ifdef SQLITE_OPEN_FULLMUTEX
+  flags |= SQLITE_OPEN_FULLMUTEX;
+#endif
 #ifdef SQLITE_OPEN_URI
   flags |= SQLITE_OPEN_URI;
 #endif
diff --git a/src/syntax.c b/src/syntax.c
index f9022d18d2..15625b4d0e 100644
--- a/src/syntax.c
+++ b/src/syntax.c
@@ -20,6 +20,7 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #include <config.h>
 
 #include "lisp.h"
+#include "dispextern.h"
 #include "character.h"
 #include "buffer.h"
 #include "regex-emacs.h"
@@ -3195,6 +3196,7 @@ scan_sexps_forward (struct lisp_parse_state *state,
   ptrdiff_t out_bytepos, out_charpos;
   int temp;
   unsigned short int quit_count = 0;
+  ptrdiff_t started_from = from;
 
   prev_from = from;
   prev_from_byte = from_byte;
@@ -3474,6 +3476,13 @@ do { prev_from = from;                           \
                                 state->levelstarts);
   state->prev_syntax = (SYNTAX_FLAGS_COMSTARTEND_FIRST (prev_from_syntax)
                         || state->quoted) ? prev_from_syntax : Smax;
+
+  /* The factor of 10 below is a heuristic that needs to be tuned.  It
+     means we consider 10 buffer positions examined by this function
+     roughly equivalent to the display engine iterating over a single
+     buffer position.  */
+  if (max_redisplay_ticks > 0 && from > started_from)
+    update_redisplay_ticks ((from - started_from) / 10 + 1, NULL);
 }
 
 /* Convert a (lisp) parse state to the internal form used in
diff --git a/src/sysdep.c b/src/sysdep.c
index 95295e7e67..efd9638b07 100644
--- a/src/sysdep.c
+++ b/src/sysdep.c
@@ -2939,21 +2939,21 @@ serial_configure (struct Lisp_Process *p,
 #endif
 
   /* Configure speed.  */
-  if (!NILP (Fplist_member (contact, QCspeed)))
-    tem = Fplist_get (contact, QCspeed);
+  if (!NILP (plist_member (contact, QCspeed)))
+    tem = plist_get (contact, QCspeed);
   else
-    tem = Fplist_get (p->childp, QCspeed);
+    tem = plist_get (p->childp, QCspeed);
   CHECK_FIXNUM (tem);
   err = cfsetspeed (&attr, convert_speed (XFIXNUM (tem)));
   if (err != 0)
     report_file_error ("Failed cfsetspeed", tem);
-  childp2 = Fplist_put (childp2, QCspeed, tem);
+  childp2 = plist_put (childp2, QCspeed, tem);
 
   /* Configure bytesize.  */
-  if (!NILP (Fplist_member (contact, QCbytesize)))
-    tem = Fplist_get (contact, QCbytesize);
+  if (!NILP (plist_member (contact, QCbytesize)))
+    tem = plist_get (contact, QCbytesize);
   else
-    tem = Fplist_get (p->childp, QCbytesize);
+    tem = plist_get (p->childp, QCbytesize);
   if (NILP (tem))
     tem = make_fixnum (8);
   CHECK_FIXNUM (tem);
@@ -2968,13 +2968,13 @@ serial_configure (struct Lisp_Process *p,
   if (XFIXNUM (tem) != 8)
     error ("Bytesize cannot be changed");
 #endif
-  childp2 = Fplist_put (childp2, QCbytesize, tem);
+  childp2 = plist_put (childp2, QCbytesize, tem);
 
   /* Configure parity.  */
-  if (!NILP (Fplist_member (contact, QCparity)))
-    tem = Fplist_get (contact, QCparity);
+  if (!NILP (plist_member (contact, QCparity)))
+    tem = plist_get (contact, QCparity);
   else
-    tem = Fplist_get (p->childp, QCparity);
+    tem = plist_get (p->childp, QCparity);
   if (!NILP (tem) && !EQ (tem, Qeven) && !EQ (tem, Qodd))
     error (":parity must be nil (no parity), `even', or `odd'");
 #if defined (PARENB) && defined (PARODD) && defined (IGNPAR) && defined (INPCK)
@@ -3001,13 +3001,13 @@ serial_configure (struct Lisp_Process *p,
   if (!NILP (tem))
     error ("Parity cannot be configured");
 #endif
-  childp2 = Fplist_put (childp2, QCparity, tem);
+  childp2 = plist_put (childp2, QCparity, tem);
 
   /* Configure stopbits.  */
-  if (!NILP (Fplist_member (contact, QCstopbits)))
-    tem = Fplist_get (contact, QCstopbits);
+  if (!NILP (plist_member (contact, QCstopbits)))
+    tem = plist_get (contact, QCstopbits);
   else
-    tem = Fplist_get (p->childp, QCstopbits);
+    tem = plist_get (p->childp, QCstopbits);
   if (NILP (tem))
     tem = make_fixnum (1);
   CHECK_FIXNUM (tem);
@@ -3023,13 +3023,13 @@ serial_configure (struct Lisp_Process *p,
   if (XFIXNUM (tem) != 1)
     error ("Stopbits cannot be configured");
 #endif
-  childp2 = Fplist_put (childp2, QCstopbits, tem);
+  childp2 = plist_put (childp2, QCstopbits, tem);
 
   /* Configure flowcontrol.  */
-  if (!NILP (Fplist_member (contact, QCflowcontrol)))
-    tem = Fplist_get (contact, QCflowcontrol);
+  if (!NILP (plist_member (contact, QCflowcontrol)))
+    tem = plist_get (contact, QCflowcontrol);
   else
-    tem = Fplist_get (p->childp, QCflowcontrol);
+    tem = plist_get (p->childp, QCflowcontrol);
   if (!NILP (tem) && !EQ (tem, Qhw) && !EQ (tem, Qsw))
     error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
 #if defined (CRTSCTS)
@@ -3063,14 +3063,14 @@ serial_configure (struct Lisp_Process *p,
       error ("Software flowcontrol (XON/XOFF) not supported");
 #endif
     }
-  childp2 = Fplist_put (childp2, QCflowcontrol, tem);
+  childp2 = plist_put (childp2, QCflowcontrol, tem);
 
   /* Activate configuration.  */
   err = tcsetattr (p->outfd, TCSANOW, &attr);
   if (err != 0)
     report_file_error ("Failed tcsetattr", Qnil);
 
-  childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
+  childp2 = plist_put (childp2, QCsummary, build_string (summary));
   pset_childp (p, childp2);
 }
 #endif /* not DOS_NT  */
@@ -3169,7 +3169,8 @@ list_system_processes (void)
 
 #endif /* !defined (WINDOWSNT) */
 
-#if defined __FreeBSD__ || defined DARWIN_OS || defined __OpenBSD__
+#if (HAVE_GETRUSAGE \
+     || defined __FreeBSD__ || defined DARWIN_OS || defined __OpenBSD__)
 
 static Lisp_Object
 make_lisp_s_us (time_t s, long us)
@@ -3869,7 +3870,7 @@ system_process_attributes (Lisp_Object pid)
 Lisp_Object
 system_process_attributes (Lisp_Object pid)
 {
-  int proc_id, nentries, fscale, i;
+  int proc_id, fscale, i;
   int pagesize = getpagesize ();
   int mib[6];
   size_t len;
@@ -4276,7 +4277,7 @@ does the same thing as `current-time'.  */)
       usecs -= 1000000;
       secs++;
     }
-  return make_lisp_time (make_timespec (secs, usecs * 1000));
+  return make_lisp_s_us (secs, usecs);
 #else /* ! HAVE_GETRUSAGE  */
 #ifdef WINDOWSNT
   return w32_get_internal_run_time ();
diff --git a/src/systime.h b/src/systime.h
index 75088bd4a6..085a7ddeab 100644
--- a/src/systime.h
+++ b/src/systime.h
@@ -26,6 +26,9 @@ INLINE_HEADER_BEGIN
 
 #ifdef HAVE_X_WINDOWS
 # include <X11/X.h>
+#elif defined HAVE_HAIKU
+# include <support/SupportDefs.h>
+typedef int64 Time;
 #else
 typedef unsigned long Time;
 #endif
diff --git a/src/term.c b/src/term.c
index 3bea621dbd..2e43d89232 100644
--- a/src/term.c
+++ b/src/term.c
@@ -1862,12 +1862,24 @@ produce_glyphless_glyph (struct it *it, Lisp_Object 
acronym)
            acronym = CHAR_TABLE_REF (Vglyphless_char_display, it->c);
          if (CONSP (acronym))
            acronym = XCDR (acronym);
-         buf[0] = '[';
          str = STRINGP (acronym) ? SSDATA (acronym) : "";
-         for (len = 0; len < 6 && str[len] && ASCII_CHAR_P (str[len]); len++)
-           buf[1 + len] = str[len];
-         buf[1 + len] = ']';
-         len += 2;
+         /* A special kludgey feature for single-character acronyms:
+            don't put them in a box, effectively treating them as a
+            replacement character.  */
+         if (STRINGP (acronym) && SCHARS (acronym) == 1)
+           {
+             buf[0] = str[0];
+             len = 1;
+           }
+         else
+           {
+             buf[0] = '[';
+             for (len = 0;
+                  len < 6 && str[len] && ASCII_CHAR_P (str[len]); len++)
+               buf[1 + len] = str[len];
+             buf[1 + len] = ']';
+             len += 2;
+           }
        }
       else
        {
diff --git a/src/termhooks.h b/src/termhooks.h
index d7190e7736..c5f1e286e9 100644
--- a/src/termhooks.h
+++ b/src/termhooks.h
@@ -209,30 +209,6 @@ enum event_kind
                                   representation of the dropped items.
                                   .timestamp gives a timestamp (in
                                   milliseconds) for the click.  */
-#ifdef HAVE_X_WINDOWS
-  UNSUPPORTED_DROP_EVENT,      /* Event sent when the regular C
-                                 drag-and-drop machinery could not
-                                 handle a drop to a window.
-
-                                 .code is the XID of the window that
-                                 could not be dropped to.
-
-                                 .arg is a list of the local value of
-                                 XdndSelection, a list of selection
-                                 targets, and the intended action to
-                                 be taken upon drop, and .timestamp
-                                 gives the timestamp where the drop
-                                 happened.
-
-                                 .modifiers gives a number that
-                                 determines if an event was already
-                                 handled by
-                                 `x_dnd_begin_drag_and_drop'.
-
-                                 .x and .y give the coordinates of
-                                 the drop originating from the root
-                                 window.  */
-#endif
   USER_SIGNAL_EVENT,           /* A user signal.
                                    code is a number identifying it,
                                    index into lispy_user_signals.  */
@@ -877,6 +853,13 @@ struct terminal
      MENU_BAR_P if X and Y are in FRAME's toolkit menu bar, and true
      into TOOL_BAR_P if X and Y are in FRAME's toolkit tool bar.  */
   void (*toolkit_position_hook) (struct frame *, int, int, bool *, bool *);
+
+#ifdef HAVE_WINDOW_SYSTEM
+  /* Called to determine if the mouse is grabbed on the given display.
+     If either dpyinfo->grabbed or this returns true, then the display
+     will be considered as grabbed.  */
+  bool (*any_grab_hook) (Display_Info *);
+#endif
 } GCALIGNED_STRUCT;
 
 INLINE bool
diff --git a/src/terminal.c b/src/terminal.c
index dcde8e9f55..d366e9d243 100644
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -402,7 +402,7 @@ but if the second argument FORCE is non-nil, you may do so. 
*/)
 
 DEFUN ("frame-terminal", Fframe_terminal, Sframe_terminal, 0, 1, 0,
        doc: /* Return the terminal that FRAME is displayed on.
-If FRAME is nil, the selected frame is used.
+If FRAME is nil, use the selected frame.
 
 The terminal device is represented by its integer identifier.  */)
   (Lisp_Object frame)
@@ -421,10 +421,12 @@ The terminal device is represented by its integer 
identifier.  */)
 
 DEFUN ("terminal-live-p", Fterminal_live_p, Sterminal_live_p, 1, 1, 0,
        doc: /* Return non-nil if OBJECT is a terminal which has not been 
deleted.
-Value is nil if OBJECT is not a live display terminal.
-If object is a live display terminal, the return value indicates what
-sort of output terminal it uses.  See the documentation of `framep' for
-possible return values.  */)
+Return nil if OBJECT is not a live display terminal.
+OBJECT may be a terminal object, a frame, or nil (meaning the
+selected frame's terminal).
+If OBJECT is a live display terminal, return what sort of output
+terminal it uses.  See the documentation of `framep' for possible
+return values.  */)
   (Lisp_Object object)
 {
   struct terminal *t = decode_terminal (object);
diff --git a/src/textprop.c b/src/textprop.c
index c11ee98f02..c91a2b729c 100644
--- a/src/textprop.c
+++ b/src/textprop.c
@@ -88,7 +88,7 @@ modify_text_properties (Lisp_Object buffer, Lisp_Object 
start, Lisp_Object end)
   BUF_COMPUTE_UNCHANGED (buf, b - 1, e);
   if (MODIFF <= SAVE_MODIFF)
     record_first_change ();
-  modiff_incr (&MODIFF);
+  modiff_incr (&MODIFF, 1);
 
   bset_point_before_scroll (current_buffer, Qnil);
 
@@ -1407,8 +1407,8 @@ set_text_properties (Lisp_Object start, Lisp_Object end, 
Lisp_Object properties,
   /* If we want no properties for a whole string,
      get rid of its intervals.  */
   if (NILP (properties) && STRINGP (object)
-      && EQ (start, make_fixnum (0))
-      && EQ (end, make_fixnum (SCHARS (object))))
+      && BASE_EQ (start, make_fixnum (0))
+      && BASE_EQ (end, make_fixnum (SCHARS (object))))
     {
       if (!string_intervals (object))
        return Qnil;
@@ -2249,7 +2249,7 @@ verify_interval_modification (struct buffer *buf,
 
                      tem = textget (i->plist, Qfront_sticky);
                      if (TMEM (Qread_only, tem)
-                         || (NILP (Fplist_get (i->plist, Qread_only))
+                         || (NILP (plist_get (i->plist, Qread_only))
                              && TMEM (Qcategory, tem)))
                        text_read_only (after);
                    }
@@ -2269,7 +2269,7 @@ verify_interval_modification (struct buffer *buf,
 
                      tem = textget (prev->plist, Qrear_nonsticky);
                      if (! TMEM (Qread_only, tem)
-                         && (! NILP (Fplist_get (prev->plist,Qread_only))
+                         && (! NILP (plist_get (prev->plist,Qread_only))
                              || ! TMEM (Qcategory, tem)))
                        text_read_only (before);
                    }
@@ -2288,13 +2288,13 @@ verify_interval_modification (struct buffer *buf,
 
                  tem = textget (i->plist, Qfront_sticky);
                  if (TMEM (Qread_only, tem)
-                     || (NILP (Fplist_get (i->plist, Qread_only))
+                     || (NILP (plist_get (i->plist, Qread_only))
                          && TMEM (Qcategory, tem)))
                    text_read_only (after);
 
                  tem = textget (prev->plist, Qrear_nonsticky);
                  if (! TMEM (Qread_only, tem)
-                     && (! NILP (Fplist_get (prev->plist, Qread_only))
+                     && (! NILP (plist_get (prev->plist, Qread_only))
                          || ! TMEM (Qcategory, tem)))
                    text_read_only (after);
                }
diff --git a/src/timefns.c b/src/timefns.c
index 7d2e3f6414..eed2edf1cc 100644
--- a/src/timefns.c
+++ b/src/timefns.c
@@ -212,7 +212,7 @@ tzlookup (Lisp_Object zone, bool settz)
 
   if (NILP (zone))
     return local_tz;
-  else if (EQ (zone, Qt) || EQ (zone, make_fixnum (0)))
+  else if (BASE_EQ (zone, make_fixnum (0)) || BASE2_EQ (zone, Qt))
     {
       zone_string = "UTC0";
       new_tz = utc_tz;
@@ -221,7 +221,7 @@ tzlookup (Lisp_Object zone, bool settz)
     {
       bool plain_integer = FIXNUMP (zone);
 
-      if (EQ (zone, Qwall))
+      if (BASE2_EQ (zone, Qwall))
        zone_string = 0;
       else if (STRINGP (zone))
        zone_string = SSDATA (ENCODE_SYSTEM (zone));
@@ -387,9 +387,9 @@ enum { flt_radix_power_size = DBL_MANT_DIG - DBL_MIN_EXP + 
1 };
    equals FLT_RADIX**P.  */
 static Lisp_Object flt_radix_power;
 
-/* Convert T into an Emacs time *RESULT, truncating toward minus infinity.
-   Return zero if successful, an error number otherwise.  */
-static int
+/* Convert the finite number T into an Emacs time *RESULT, truncating
+   toward minus infinity.  Signal an error if unsuccessful.  */
+static void
 decode_float_time (double t, struct lisp_time *result)
 {
   Lisp_Object ticks, hz;
@@ -401,6 +401,11 @@ decode_float_time (double t, struct lisp_time *result)
   else
     {
       int scale = double_integer_scale (t);
+      /* FIXME: `double_integer_scale` often returns values that are
+         "pessimistic" (i.e. larger than necessary), so 3.5 gets converted
+         to (7881299347898368 . 2251799813685248) rather than (7 . 2).
+         On 64bit systems, this should not matter very much, tho.  */
+      eassume (scale < flt_radix_power_size);
 
       if (scale < 0)
        {
@@ -412,8 +417,6 @@ decode_float_time (double t, struct lisp_time *result)
            which is typically better than signaling overflow.  */
          scale = 0;
        }
-      else if (flt_radix_power_size <= scale)
-       return isnan (t) ? EDOM : EOVERFLOW;
 
       /* Compute TICKS, HZ such that TICKS / HZ exactly equals T, where HZ is
         T's frequency or 1, whichever is greater.  Here, “frequency” means
@@ -431,7 +434,6 @@ decode_float_time (double t, struct lisp_time *result)
     }
   result->ticks = ticks;
   result->hz = hz;
-  return 0;
 }
 
 /* Make a 4-element timestamp (HI LO US PS) from TICKS and HZ.
@@ -516,7 +518,7 @@ lisp_time_hz_ticks (struct lisp_time t, Lisp_Object hz)
   /* The idea is to return the floor of ((T.ticks * HZ) / T.hz).  */
 
   /* For speed, just return T.ticks if T.hz == HZ.  */
-  if (FASTER_TIMEFNS && EQ (t.hz, hz))
+  if (FASTER_TIMEFNS && BASE_EQ (t.hz, hz))
     return t.ticks;
 
   /* Check HZ for validity.  */
@@ -705,7 +707,7 @@ enum timeform
    TIMEFORM_TICKS_HZ /* fractional time: HI is ticks, LO is ticks per second */
   };
 
-/* From the valid form FORM and the time components HIGH, LOW, USEC
+/* From the non-float form FORM and the time components HIGH, LOW, USEC
    and PSEC, generate the corresponding time value.  If LOW is
    floating point, the other components should be zero and FORM should
    not be TIMEFORM_TICKS_HZ.
@@ -729,21 +731,12 @@ decode_time_components (enum timeform form,
 
     case TIMEFORM_TICKS_HZ:
       if (INTEGERP (high)
-         && (!NILP (Fnatnump (low)) && !EQ (low, make_fixnum (0))))
+         && !NILP (Fnatnump (low)) && !BASE_EQ (low, make_fixnum (0)))
        return decode_ticks_hz (high, low, result, dresult);
       return EINVAL;
 
     case TIMEFORM_FLOAT:
-      {
-       double t = XFLOAT_DATA (low);
-       if (result)
-         return decode_float_time (t, result);
-       else
-         {
-           *dresult = t;
-           return 0;
-         }
-      }
+      eassume (false);
 
     case TIMEFORM_NIL:
       return decode_ticks_hz (timespec_ticks (current_timespec ()),
@@ -829,8 +822,6 @@ decode_lisp_time (Lisp_Object specified_time, bool 
decode_secs_only,
 
   if (NILP (specified_time))
     form = TIMEFORM_NIL;
-  else if (FLOATP (specified_time))
-    form = TIMEFORM_FLOAT;
   else if (CONSP (specified_time))
     {
       high = XCAR (specified_time);
@@ -870,6 +861,22 @@ decode_lisp_time (Lisp_Object specified_time, bool 
decode_secs_only,
       if (! INTEGERP (low))
        form = TIMEFORM_INVALID;
     }
+  else if (FASTER_TIMEFNS && INTEGERP (specified_time))
+    {
+      decode_ticks_hz (specified_time, make_fixnum (1), result, dresult);
+      return form;
+    }
+  else if (FLOATP (specified_time))
+    {
+      double d = XFLOAT_DATA (specified_time);
+      if (!isfinite (d))
+       time_error (isnan (d) ? EDOM : EOVERFLOW);
+      if (result)
+       decode_float_time (d, result);
+      else
+       *dresult = d;
+      return TIMEFORM_FLOAT;
+    }
 
   int err = decode_time_components (form, high, low, usec, psec,
                                    result, dresult);
@@ -878,7 +885,7 @@ decode_lisp_time (Lisp_Object specified_time, bool 
decode_secs_only,
   return form;
 }
 
-/* Convert a Lisp timestamp SPECIFIED_TIME to double.
+/* Convert a non-float Lisp timestamp SPECIFIED_TIME to double.
    Signal an error if unsuccessful.  */
 double
 float_time (Lisp_Object specified_time)
@@ -923,7 +930,7 @@ lisp_to_timespec (struct lisp_time t)
      yielding quotient Q (tv_sec) and remainder NS (tv_nsec).
      Return an invalid timespec if Q does not fit in time_t.
      For speed, prefer fixnum arithmetic if it works.  */
-  if (FASTER_TIMEFNS && EQ (t.hz, timespec_hz))
+  if (FASTER_TIMEFNS && BASE_EQ (t.hz, timespec_hz))
     {
       if (FIXNUMP (t.ticks))
        {
@@ -942,7 +949,7 @@ lisp_to_timespec (struct lisp_time t)
       else
        ns = mpz_fdiv_q_ui (*q, *xbignum_val (t.ticks), TIMESPEC_HZ);
     }
-  else if (FASTER_TIMEFNS && EQ (t.hz, make_fixnum (1)))
+  else if (FASTER_TIMEFNS && BASE_EQ (t.hz, make_fixnum (1)))
     {
       ns = 0;
       if (FIXNUMP (t.ticks))
@@ -1043,7 +1050,7 @@ lispint_arith (Lisp_Object a, Lisp_Object b, bool 
subtract)
 
   if (FASTER_TIMEFNS && FIXNUMP (b))
     {
-      if (EQ (b, make_fixnum (0)))
+      if (BASE_EQ (b, make_fixnum (0)))
        return a;
 
       /* For speed, use EMACS_INT arithmetic if it will do.  */
@@ -1074,30 +1081,12 @@ lispint_arith (Lisp_Object a, Lisp_Object b, bool 
subtract)
 static Lisp_Object
 time_arith (Lisp_Object a, Lisp_Object b, bool subtract)
 {
-  if (FLOATP (a) && !isfinite (XFLOAT_DATA (a)))
-    {
-      double da = XFLOAT_DATA (a);
-      double db = float_time (b);
-      return make_float (subtract ? da - db : da + db);
-    }
   enum timeform aform, bform;
   struct lisp_time ta = lisp_time_struct (a, &aform);
-
-  if (FLOATP (b) && !isfinite (XFLOAT_DATA (b)))
-    return subtract ? make_float (-XFLOAT_DATA (b)) : b;
-
-  /* Subtract nil from nil correctly, and handle other eq values
-     quicker while we're at it.  Compare here rather than earlier, to
-     handle NaNs and check formats.  */
-  struct lisp_time tb;
-  if (EQ (a, b))
-    bform = aform, tb = ta;
-  else
-    tb = lisp_time_struct (b, &bform);
-
+  struct lisp_time tb = lisp_time_struct (b, &bform);
   Lisp_Object ticks, hz;
 
-  if (FASTER_TIMEFNS && EQ (ta.hz, tb.hz))
+  if (FASTER_TIMEFNS && BASE_EQ (ta.hz, tb.hz))
     {
       hz = ta.hz;
       ticks = lispint_arith (ta.ticks, tb.ticks, subtract);
@@ -1175,7 +1164,7 @@ time_arith (Lisp_Object a, Lisp_Object b, bool subtract)
      either input used (TICKS . HZ) form or the result can't be expressed
      exactly in (HI LO US PS) form, otherwise the (HI LO US PS) form
      for backward compatibility.  */
-  return (EQ (hz, make_fixnum (1))
+  return (BASE_EQ (hz, make_fixnum (1))
          ? ticks
          : (!current_time_list
             || aform == TIMEFORM_TICKS_HZ
@@ -1201,37 +1190,45 @@ See `format-time-string' for the various forms of a 
time value.
 For example, nil stands for the current time.  */)
   (Lisp_Object a, Lisp_Object b)
 {
+  /* Subtract nil from nil correctly, and handle other eq values
+     quicker while we're at it.  This means (time-subtract X X) does
+     not signal an error if X is not a valid time value, but that's OK.  */
+  if (BASE_EQ (a, b))
+    return timespec_to_lisp ((struct timespec) {0});
+
   return time_arith (a, b, true);
 }
 
-/* Return negative, 0, positive if a < b, a == b, a > b respectively.
-   Return positive if either a or b is a NaN; this is good enough
-   for the current callers.  */
-static int
+/* Return negative, 0, positive if A < B, A == B, A > B respectively.
+   A and B should be Lisp time values.  */
+static EMACS_INT
 time_cmp (Lisp_Object a, Lisp_Object b)
 {
-  if ((FLOATP (a) && !isfinite (XFLOAT_DATA (a)))
-      || (FLOATP (b) && !isfinite (XFLOAT_DATA (b))))
-    {
-      double da = FLOATP (a) ? XFLOAT_DATA (a) : 0;
-      double db = FLOATP (b) ? XFLOAT_DATA (b) : 0;
-      return da < db ? -1 : da != db;
-    }
-
   /* Compare nil to nil correctly, and handle other eq values quicker
-     while we're at it.  Compare here rather than earlier, to handle
-     NaNs.  This means (time-equal-p X X) does not signal an error if
-     X is not a valid time value, but that's OK.  */
-  if (EQ (a, b))
+     while we're at it.  This means (time-equal-p X X) does not signal
+     an error if X is not a valid time value, but that's OK.  */
+  if (BASE_EQ (a, b))
     return 0;
 
+  /* Compare (X . Z) to (Y . Z) quickly if X and Y are fixnums.
+     Do not inspect Z, as it is OK to not signal if A and B are invalid.
+     Also, compare X to Y quickly if X and Y are fixnums.  */
+  if (FASTER_TIMEFNS)
+    {
+      Lisp_Object x = a, y = b;
+      if (CONSP (a) && CONSP (b) && BASE_EQ (XCDR (a), XCDR (b)))
+       x = XCAR (a), y = XCAR (b);
+      if (FIXNUMP (x) && FIXNUMP (y))
+       return XFIXNUM (x) - XFIXNUM (y);
+    }
+
   /* Compare (ATICKS . AZ) to (BTICKS . BHZ) by comparing
      ATICKS * BHZ to BTICKS * AHZ.  */
   struct lisp_time ta = lisp_time_struct (a, 0);
   struct lisp_time tb = lisp_time_struct (b, 0);
   mpz_t const *za = bignum_integer (&mpz[0], ta.ticks);
   mpz_t const *zb = bignum_integer (&mpz[1], tb.ticks);
-  if (! (FASTER_TIMEFNS && EQ (ta.hz, tb.hz)))
+  if (! (FASTER_TIMEFNS && BASE_EQ (ta.hz, tb.hz)))
     {
       /* This could be sped up by looking at the signs, sizes, and
         number of bits of the two sides; see how GMP does mpq_cmp.
@@ -1258,7 +1255,9 @@ DEFUN ("time-equal-p", Ftime_equal_p, Stime_equal_p, 2, 
2, 0,
 See `format-time-string' for the various forms of a time value.  */)
   (Lisp_Object a, Lisp_Object b)
 {
-  return time_cmp (a, b) == 0 ? Qt : Qnil;
+  /* A nil arg compares unequal to a non-nil arg.  This also saves the
+     expense of current_timespec if either arg is nil.  */
+  return NILP (a) == NILP (b) && time_cmp (a, b) == 0 ? Qt : Qnil;
 }
 
 
@@ -1269,11 +1268,12 @@ instead of the current time.  See `format-time-string' 
for the various
 forms of a time value.
 
 WARNING: Since the result is floating point, it may not be exact.
-If precise time stamps are required, use either `encode-time',
+If precise time stamps are required, use either `time-convert',
 or (if you need time as a string) `format-time-string'.  */)
   (Lisp_Object specified_time)
 {
-  return make_float (float_time (specified_time));
+  return (FLOATP (specified_time) ? specified_time
+         : make_float (float_time (specified_time)));
 }
 
 /* Write information into buffer S of size MAXSIZE, according to the
@@ -1463,7 +1463,7 @@ usage: (format-time-string FORMAT-STRING &optional TIME 
ZONE)  */)
 }
 
 DEFUN ("decode-time", Fdecode_time, Sdecode_time, 0, 3, 0,
-       doc: /* Decode a time value as (SEC MINUTE HOUR DAY MONTH YEAR DOW DST 
UTCOFF).
+       doc: /* Decode a timestamp into (SEC MINUTE HOUR DAY MONTH YEAR DOW DST 
UTCOFF).
 The optional TIME is the time value to convert.  See
 `format-time-string' for the various forms of a time value.
 
@@ -1535,7 +1535,7 @@ usage: (decode-time &optional TIME ZONE FORM)  */)
 
   /* Compute SEC from LOCAL_TM.tm_sec and HZ.  */
   Lisp_Object hz = lt.hz, sec;
-  if (EQ (hz, make_fixnum (1)) || !EQ (form, Qt))
+  if (BASE_EQ (hz, make_fixnum (1)) || !BASE2_EQ (form, Qt))
     sec = make_fixnum (local_tm.tm_sec);
   else
     {
@@ -1685,7 +1685,7 @@ usage: (encode-time TIME &rest OBSOLESCENT-ARGUMENTS)  */)
   struct lisp_time lt;
   decode_lisp_time (secarg, false, &lt, 0);
   Lisp_Object hz = lt.hz, sec, subsecticks;
-  if (FASTER_TIMEFNS && EQ (hz, make_fixnum (1)))
+  if (FASTER_TIMEFNS && BASE_EQ (hz, make_fixnum (1)))
     {
       sec = lt.ticks;
       subsecticks = make_fixnum (0);
@@ -1715,7 +1715,7 @@ usage: (encode-time TIME &rest OBSOLESCENT-ARGUMENTS)  */)
   if (tm.tm_wday < 0)
     time_error (mktime_errno);
 
-  if (EQ (hz, make_fixnum (1)))
+  if (BASE_EQ (hz, make_fixnum (1)))
     return (current_time_list
            ? list2 (hi_time (value), lo_time (value))
            : INT_TO_INTEGER (value));
@@ -1729,33 +1729,43 @@ usage: (encode-time TIME &rest OBSOLESCENT-ARGUMENTS)  
*/)
 }
 
 DEFUN ("time-convert", Ftime_convert, Stime_convert, 1, 2, 0,
-       doc: /* Convert TIME value to a Lisp timestamp.
-With optional FORM, convert to that timestamp form.
+       doc: /* Convert TIME value to a Lisp timestamp of the given FORM.
 Truncate the returned value toward minus infinity.
 
-If FORM is nil (the default), return the same form as `current-time'.
 If FORM is a positive integer, return a pair of integers (TICKS . FORM),
 where TICKS is the number of clock ticks and FORM is the clock frequency
-in ticks per second.  If FORM is t, return (TICKS . PHZ), where
-PHZ is a suitable clock frequency in ticks per second.  If FORM is
-`integer', return an integer count of seconds.  If FORM is `list',
-return an integer list (HIGH LOW USEC PSEC), where HIGH has the most
-significant bits of the seconds, LOW has the least significant 16
-bits, and USEC and PSEC are the microsecond and picosecond counts.  */)
+in ticks per second.
+
+If FORM is t, return (TICKS . PHZ), where PHZ is a suitable clock
+frequency in ticks per second.
+
+If FORM is `integer', return an integer count of seconds.
+
+If FORM is `list', return an integer list (HIGH LOW USEC PSEC), where
+HIGH has the most significant bits of the seconds, LOW has the least
+significant 16 bits, and USEC and PSEC are the microsecond and
+picosecond counts.
+
+If FORM is nil, the behavior depends on `current-time-list',
+but new code should not rely on it.  */)
      (Lisp_Object time, Lisp_Object form)
 {
+  /* FIXME: Any reason why we don't offer a `float` output format option as
+     well, since we accept it as input?  */
   struct lisp_time t;
   enum timeform input_form = decode_lisp_time (time, false, &t, 0);
   if (NILP (form))
     form = current_time_list ? Qlist : Qt;
-  if (EQ (form, Qlist))
+  if (symbols_with_pos_enabled && SYMBOL_WITH_POS_P (form))
+    form = SYMBOL_WITH_POS_SYM (form);
+  if (BASE_EQ (form, Qlist))
     return ticks_hz_list4 (t.ticks, t.hz);
-  if (EQ (form, Qinteger))
+  if (BASE_EQ (form, Qinteger))
     return FASTER_TIMEFNS && INTEGERP (time) ? time : lisp_time_seconds (t);
-  if (EQ (form, Qt))
+  if (BASE_EQ (form, Qt))
     form = t.hz;
   if (FASTER_TIMEFNS
-      && input_form == TIMEFORM_TICKS_HZ && EQ (form, XCDR (time)))
+      && input_form == TIMEFORM_TICKS_HZ && BASE_EQ (form, XCDR (time)))
     return time;
   return Fcons (lisp_time_hz_ticks (t, form), form);
 }
diff --git a/src/undo.c b/src/undo.c
index 36664d1642..f76977dbe5 100644
--- a/src/undo.c
+++ b/src/undo.c
@@ -218,7 +218,7 @@ record_first_change (void)
     base_buffer = base_buffer->base_buffer;
 
   bset_undo_list (current_buffer,
-                 Fcons (Fcons (Qt, Fvisited_file_modtime ()),
+                 Fcons (Fcons (Qt, buffer_visited_file_modtime (base_buffer)),
                         BVAR (current_buffer, undo_list)));
 }
 
diff --git a/src/w32.c b/src/w32.c
index 590d9e85d9..44c279602c 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -5992,12 +5992,22 @@ sys_umask (int mode)
 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
 #define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
 #endif
+#ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
+#define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE 0x2
+#endif
 
 int
 symlink (char const *filename, char const *linkname)
 {
   char linkfn[MAX_UTF8_PATH], *tgtfn;
-  DWORD flags = 0;
+  /* The SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE flag is
+     supported from Windows 10 build 14972.  It is only supported if
+     Developer Mode is enabled, and is ignored if it isn't.  */
+  DWORD flags =
+    (os_subtype == OS_SUBTYPE_NT
+     && (w32_major_version > 10
+        || (w32_major_version == 10 && w32_build_number >= 14972)))
+    ? SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE : 0;
   int dir_access, filename_ends_in_slash;
 
   /* Diagnostics follows Posix as much as possible.  */
@@ -6055,7 +6065,7 @@ symlink (char const *filename, char const *linkname)
      directory.  */
   filename_ends_in_slash = IS_DIRECTORY_SEP (filename[strlen (filename) - 1]);
   if (dir_access == 0 || filename_ends_in_slash)
-    flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
+    flags |= SYMBOLIC_LINK_FLAG_DIRECTORY;
 
   tgtfn = (char *)map_w32_filename (filename, NULL);
   if (filename_ends_in_slash)
@@ -8573,6 +8583,7 @@ int
 sys_close (int fd)
 {
   int rc = -1;
+  bool reader_thread_exited = false;
 
   if (fd < 0)
     {
@@ -8583,6 +8594,13 @@ sys_close (int fd)
   if (fd < MAXDESC && fd_info[fd].cp)
     {
       child_process * cp = fd_info[fd].cp;
+      DWORD thrd_status = STILL_ACTIVE;
+
+      /* Thread handle will be NULL if we already called delete_child.  */
+      if (cp->thrd != NULL
+         && GetExitCodeThread (cp->thrd, &thrd_status)
+         && thrd_status != STILL_ACTIVE)
+       reader_thread_exited = true;
 
       fd_info[fd].cp = NULL;
 
@@ -8633,7 +8651,11 @@ sys_close (int fd)
      because socket handles are fully fledged kernel handles. */
   if (fd < MAXDESC)
     {
-      if ((fd_info[fd].flags & FILE_DONT_CLOSE) == 0)
+      if ((fd_info[fd].flags & FILE_DONT_CLOSE) == 0
+         /* If the reader thread already exited, close the descriptor,
+            since otherwise no one will close it, and we will be
+            leaking descriptors.  */
+         || reader_thread_exited)
        {
          fd_info[fd].flags = 0;
          rc = _close (fd);
@@ -8641,10 +8663,11 @@ sys_close (int fd)
       else
        {
          /* We don't close here descriptors open by pipe processes
-            for reading from the pipe, because the reader thread
-            might be stuck in _sys_read_ahead, and then we will hang
-            here.  If the reader thread exits normally, it will close
-            the descriptor; otherwise we will leave a zombie thread
+            for reading from the pipe when the reader thread might
+            still be running, since that thread might be stuck in
+            _sys_read_ahead, and then we will hang here.  If the
+            reader thread exits normally, it will close the
+            descriptor; otherwise we will leave a zombie thread
             hanging around.  */
          rc = 0;
          /* Leave the flag set for the reader thread to close the
@@ -10953,19 +10976,19 @@ serial_configure (struct Lisp_Process *p, Lisp_Object 
contact)
   dcb.EvtChar       = 0;
 
   /* Configure speed.  */
-  if (!NILP (Fplist_member (contact, QCspeed)))
-    tem = Fplist_get (contact, QCspeed);
+  if (!NILP (plist_member (contact, QCspeed)))
+    tem = plist_get (contact, QCspeed);
   else
-    tem = Fplist_get (p->childp, QCspeed);
+    tem = plist_get (p->childp, QCspeed);
   CHECK_FIXNUM (tem);
   dcb.BaudRate = XFIXNUM (tem);
-  childp2 = Fplist_put (childp2, QCspeed, tem);
+  childp2 = plist_put (childp2, QCspeed, tem);
 
   /* Configure bytesize.  */
-  if (!NILP (Fplist_member (contact, QCbytesize)))
-    tem = Fplist_get (contact, QCbytesize);
+  if (!NILP (plist_member (contact, QCbytesize)))
+    tem = plist_get (contact, QCbytesize);
   else
-    tem = Fplist_get (p->childp, QCbytesize);
+    tem = plist_get (p->childp, QCbytesize);
   if (NILP (tem))
     tem = make_fixnum (8);
   CHECK_FIXNUM (tem);
@@ -10973,13 +10996,13 @@ serial_configure (struct Lisp_Process *p, Lisp_Object 
contact)
     error (":bytesize must be nil (8), 7, or 8");
   dcb.ByteSize = XFIXNUM (tem);
   summary[0] = XFIXNUM (tem) + '0';
-  childp2 = Fplist_put (childp2, QCbytesize, tem);
+  childp2 = plist_put (childp2, QCbytesize, tem);
 
   /* Configure parity.  */
-  if (!NILP (Fplist_member (contact, QCparity)))
-    tem = Fplist_get (contact, QCparity);
+  if (!NILP (plist_member (contact, QCparity)))
+    tem = plist_get (contact, QCparity);
   else
-    tem = Fplist_get (p->childp, QCparity);
+    tem = plist_get (p->childp, QCparity);
   if (!NILP (tem) && !EQ (tem, Qeven) && !EQ (tem, Qodd))
     error (":parity must be nil (no parity), `even', or `odd'");
   dcb.fParity = FALSE;
@@ -11003,13 +11026,13 @@ serial_configure (struct Lisp_Process *p, Lisp_Object 
contact)
       dcb.Parity = ODDPARITY;
       dcb.fErrorChar = TRUE;
     }
-  childp2 = Fplist_put (childp2, QCparity, tem);
+  childp2 = plist_put (childp2, QCparity, tem);
 
   /* Configure stopbits.  */
-  if (!NILP (Fplist_member (contact, QCstopbits)))
-    tem = Fplist_get (contact, QCstopbits);
+  if (!NILP (plist_member (contact, QCstopbits)))
+    tem = plist_get (contact, QCstopbits);
   else
-    tem = Fplist_get (p->childp, QCstopbits);
+    tem = plist_get (p->childp, QCstopbits);
   if (NILP (tem))
     tem = make_fixnum (1);
   CHECK_FIXNUM (tem);
@@ -11020,13 +11043,13 @@ serial_configure (struct Lisp_Process *p, Lisp_Object 
contact)
     dcb.StopBits = ONESTOPBIT;
   else if (XFIXNUM (tem) == 2)
     dcb.StopBits = TWOSTOPBITS;
-  childp2 = Fplist_put (childp2, QCstopbits, tem);
+  childp2 = plist_put (childp2, QCstopbits, tem);
 
   /* Configure flowcontrol.  */
-  if (!NILP (Fplist_member (contact, QCflowcontrol)))
-    tem = Fplist_get (contact, QCflowcontrol);
+  if (!NILP (plist_member (contact, QCflowcontrol)))
+    tem = plist_get (contact, QCflowcontrol);
   else
-    tem = Fplist_get (p->childp, QCflowcontrol);
+    tem = plist_get (p->childp, QCflowcontrol);
   if (!NILP (tem) && !EQ (tem, Qhw) && !EQ (tem, Qsw))
     error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
   dcb.fOutxCtsFlow     = FALSE;
@@ -11053,13 +11076,13 @@ serial_configure (struct Lisp_Process *p, Lisp_Object 
contact)
       dcb.fOutX = TRUE;
       dcb.fInX = TRUE;
     }
-  childp2 = Fplist_put (childp2, QCflowcontrol, tem);
+  childp2 = plist_put (childp2, QCflowcontrol, tem);
 
   /* Activate configuration.  */
   if (!SetCommState (hnd, &dcb))
     error ("SetCommState() failed");
 
-  childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
+  childp2 = plist_put (childp2, QCsummary, build_string (summary));
   pset_childp (p, childp2);
 }
 
diff --git a/src/w32fns.c b/src/w32fns.c
index 8716b762eb..28d13a68d4 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -797,13 +797,6 @@ w32_default_color_map (void)
   return (cmap);
 }
 
-DEFUN ("w32-default-color-map", Fw32_default_color_map, Sw32_default_color_map,
-       0, 0, 0, doc: /* Return the default color map.  */)
-  (void)
-{
-  return w32_default_color_map ();
-}
-
 static Lisp_Object
 w32_color_map_lookup (const char *colorname)
 {
@@ -1463,7 +1456,7 @@ w32_set_icon_type (struct frame *f, Lisp_Object arg, 
Lisp_Object oldval)
     return;
 
   if (STRINGP (arg) && STRINGP (oldval)
-      && EQ (Fstring_equal (oldval, arg), Qt))
+      && BASE_EQ (Fstring_equal (oldval, arg), Qt))
     return;
 
   if (SYMBOLP (arg) && SYMBOLP (oldval) && EQ (arg, oldval))
@@ -1486,7 +1479,7 @@ w32_set_icon_name (struct frame *f, Lisp_Object arg, 
Lisp_Object oldval)
 {
   if (STRINGP (arg))
     {
-      if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
+      if (STRINGP (oldval) && BASE_EQ (Fstring_equal (oldval, arg), Qt))
        return;
     }
   else if (!NILP (arg) || NILP (oldval))
@@ -7575,7 +7568,23 @@ DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
   clear_glyph_matrix (w->desired_matrix);
   clear_glyph_matrix (w->current_matrix);
   SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
-  try_window (window, pos, TRY_WINDOW_IGNORE_FONTS_CHANGE);
+  bool displayed = try_window (window, pos, TRY_WINDOW_IGNORE_FONTS_CHANGE);
+  if (!displayed && NILP (Vx_max_tooltip_size))
+    {
+#ifdef ENABLE_CHECKING
+      struct glyph_row *row = w->desired_matrix->rows;
+      struct glyph_row *end =
+       w->desired_matrix->rows + w->desired_matrix->nrows;
+      while (row < end)
+       {
+         if (!row->displays_text_p
+             || row->ends_at_zv_p)
+           break;
+         ++row;
+       }
+      eassert (row < end && row->ends_at_zv_p);
+#endif
+    }
   /* Calculate size of tooltip window.  */
   size = Fwindow_text_pixel_size (window, Qnil, Qnil, Qnil,
                                  make_fixnum (w->pixel_height), Qnil,
@@ -10212,21 +10221,21 @@ usage: (w32-notification-notify &rest PARAMS)  */)
   arg_plist = Flist (nargs, args);
 
   /* Icon.  */
-  lres = Fplist_get (arg_plist, QCicon);
+  lres = plist_get (arg_plist, QCicon);
   if (STRINGP (lres))
     icon = SSDATA (ENCODE_FILE (Fexpand_file_name (lres, Qnil)));
   else
     icon = (char *)"";
 
   /* Tip.  */
-  lres = Fplist_get (arg_plist, QCtip);
+  lres = plist_get (arg_plist, QCtip);
   if (STRINGP (lres))
     tip = SSDATA (code_convert_string_norecord (lres, Qutf_8, 1));
   else
     tip = (char *)"Emacs notification";
 
   /* Severity.  */
-  lres = Fplist_get (arg_plist, QClevel);
+  lres = plist_get (arg_plist, QClevel);
   if (NILP (lres))
     severity = Ni_None;
   else if (EQ (lres, Qinfo))
@@ -10239,14 +10248,14 @@ usage: (w32-notification-notify &rest PARAMS)  */)
     severity = Ni_Info;
 
   /* Title.  */
-  lres = Fplist_get (arg_plist, QCtitle);
+  lres = plist_get (arg_plist, QCtitle);
   if (STRINGP (lres))
     title = SSDATA (code_convert_string_norecord (lres, Qutf_8, 1));
   else
     title = (char *)"";
 
   /* Notification body text.  */
-  lres = Fplist_get (arg_plist, QCbody);
+  lres = plist_get (arg_plist, QCbody);
   if (STRINGP (lres))
     msg = SSDATA (code_convert_string_norecord (lres, Qutf_8, 1));
   else
@@ -10499,6 +10508,7 @@ frame_parm_handler w32_frame_parm_handlers[] =
   0, /* x_set_override_redirect */
   gui_set_no_special_glyphs,
   gui_set_alpha_background,
+  0, /* x_set_use_frame_synchronization */
 };
 
 void
@@ -10777,7 +10787,7 @@ bass-down, bass-boost, bass-up, treble-down, treble-up  
*/);
 
   DEFVAR_LISP ("x-max-tooltip-size", Vx_max_tooltip_size,
               doc: /* SKIP: real doc in xfns.c.  */);
-  Vx_max_tooltip_size = Fcons (make_fixnum (80), make_fixnum (40));
+  Vx_max_tooltip_size = Qnil;
 
   DEFVAR_LISP ("x-no-window-manager", Vx_no_window_manager,
               doc: /* SKIP: real doc in xfns.c.  */);
@@ -10879,7 +10889,6 @@ keys when IME input is received.  */);
   /* W32 specific functions */
 
   defsubr (&Sw32_define_rgb_color);
-  defsubr (&Sw32_default_color_map);
   defsubr (&Sw32_display_monitor_attributes_list);
   defsubr (&Sw32_send_sys_command);
   defsubr (&Sw32_shell_execute);
diff --git a/src/w32image.c b/src/w32image.c
index 1f7c4921b3..da748b8dab 100644
--- a/src/w32image.c
+++ b/src/w32image.c
@@ -382,7 +382,7 @@ w32_select_active_frame (GpBitmap *pBitmap, int frame, int 
*nframes,
 static ARGB
 w32_image_bg_color (struct frame *f, struct image *img)
 {
-  Lisp_Object specified_bg = Fplist_get (XCDR (img->spec), QCbackground);
+  Lisp_Object specified_bg = plist_get (XCDR (img->spec), QCbackground);
   Emacs_Color color;
 
   /* If the user specified a color, try to use it; if not, use the
@@ -435,7 +435,7 @@ w32_load_image (struct frame *f, struct image *img,
   if (status == Ok)
     {
       /* In multiframe pictures, select the first frame.  */
-      Lisp_Object lisp_index = Fplist_get (XCDR (img->spec), QCindex);
+      Lisp_Object lisp_index = plist_get (XCDR (img->spec), QCindex);
       int index = FIXNATP (lisp_index) ? XFIXNAT (lisp_index) : 0;
       int nframes;
       double delay;
diff --git a/src/w32proc.c b/src/w32proc.c
index 7acfba64d7..f771ebc851 100644
--- a/src/w32proc.c
+++ b/src/w32proc.c
@@ -1287,10 +1287,21 @@ reader_thread (void *arg)
     }
   /* If this thread was reading from a pipe process, close the
      descriptor used for reading, as sys_close doesn't in that case.  */
-  if (fd_info[fd].flags == FILE_DONT_CLOSE)
+  if ((fd_info[fd].flags & FILE_DONT_CLOSE) == FILE_DONT_CLOSE)
     {
-      fd_info[fd].flags = 0;
-      _close (fd);
+      int i;
+      /* If w32.c:sys_close is still processing this descriptor, wait
+        for a while for it to finish.  */
+      for (i = 0; i < 5; i++)
+       {
+         if (fd_info[fd].flags == FILE_DONT_CLOSE)
+           {
+             fd_info[fd].flags = 0;
+             _close (fd);
+             break;
+           }
+         Sleep (5);
+       }
     }
   return 0;
 }
diff --git a/src/w32select.c b/src/w32select.c
index eae1a0bac0..3720611812 100644
--- a/src/w32select.c
+++ b/src/w32select.c
@@ -631,7 +631,7 @@ validate_coding_system (Lisp_Object coding_system)
   eol_type = Fcoding_system_eol_type (coding_system);
 
   /* Already a DOS coding system? */
-  if (EQ (eol_type, make_fixnum (1)))
+  if (BASE_EQ (eol_type, make_fixnum (1)))
     return coding_system;
 
   /* Get EOL_TYPE vector of the base of CODING_SYSTEM.  */
diff --git a/src/w32term.c b/src/w32term.c
index d0577efccc..dff21489e5 100644
--- a/src/w32term.c
+++ b/src/w32term.c
@@ -1490,6 +1490,8 @@ w32_draw_glyphless_glyph_string_foreground (struct 
glyph_string *s)
                   ? CHAR_TABLE_REF (Vglyphless_char_display,
                                     glyph->u.glyphless.ch)
                   : XCHAR_TABLE (Vglyphless_char_display)->extras[0]);
+             if (CONSP (acronym))
+               acronym = XCAR (acronym);
              if (STRINGP (acronym))
                str = SSDATA (acronym);
            }
diff --git a/src/window.c b/src/window.c
index ac8408a9a9..2bce4c9723 100644
--- a/src/window.c
+++ b/src/window.c
@@ -556,7 +556,9 @@ select_window (Lisp_Object window, Lisp_Object norecord,
         frame is active.  */
       Fselect_frame (frame, norecord);
       /* Fselect_frame called us back so we've done all the work already.  */
-      eassert (EQ (window, selected_window));
+      eassert (EQ (window, selected_window)
+              || (EQ (window, f->minibuffer_window)
+                  && NILP (Fminibufferp (XWINDOW (window)->contents, Qt))));
       return window;
     }
   else
@@ -1028,7 +1030,7 @@ window_body_unit_from_symbol (Lisp_Object unit)
 /* Return the number of lines/pixels of W's body.  Don't count any mode
    or header line or horizontal divider of W.  Rounds down to nearest
    integer when not working pixelwise. */
-static int
+int
 window_body_height (struct window *w, enum window_body_unit pixelwise)
 {
   int height = (w->pixel_height
@@ -1275,7 +1277,10 @@ set_window_hscroll (struct window *w, EMACS_INT hscroll)
 
   /* Prevent redisplay shortcuts when changing the hscroll.  */
   if (w->hscroll != new_hscroll)
-    XBUFFER (w->contents)->prevent_redisplay_optimizations_p = true;
+    {
+      XBUFFER (w->contents)->prevent_redisplay_optimizations_p = true;
+      wset_redisplay (w);
+    }
 
   w->hscroll = new_hscroll;
   w->suspend_auto_hscroll = true;
@@ -1289,7 +1294,7 @@ WINDOW must be a live window and defaults to the selected 
one.
 Clip the number to a reasonable value if out of range.
 Return the new number.  NCOL should be zero or positive.
 
-Note that if `automatic-hscrolling' is non-nil, you cannot scroll the
+Note that if `auto-hscroll-mode' is non-nil, you cannot scroll the
 window so that the location of point moves off-window.  */)
   (Lisp_Object window, Lisp_Object ncol)
 {
@@ -1297,31 +1302,6 @@ window so that the location of point moves off-window.  
*/)
   return set_window_hscroll (decode_live_window (window), XFIXNUM (ncol));
 }
 
-DEFUN ("window-redisplay-end-trigger", Fwindow_redisplay_end_trigger,
-       Swindow_redisplay_end_trigger, 0, 1, 0,
-       doc: /* Return WINDOW's redisplay end trigger value.
-WINDOW must be a live window and defaults to the selected one.
-See `set-window-redisplay-end-trigger' for more information.  */)
-  (Lisp_Object window)
-{
-  return decode_live_window (window)->redisplay_end_trigger;
-}
-
-DEFUN ("set-window-redisplay-end-trigger", Fset_window_redisplay_end_trigger,
-       Sset_window_redisplay_end_trigger, 2, 2, 0,
-       doc: /* Set WINDOW's redisplay end trigger value to VALUE.
-WINDOW must be a live window and defaults to the selected one.  VALUE
-should be a buffer position (typically a marker) or nil.  If it is a
-buffer position, then if redisplay in WINDOW reaches a position beyond
-VALUE, the functions in `redisplay-end-trigger-functions' are called
-with two arguments: WINDOW, and the end trigger value.  Afterwards the
-end-trigger value is reset to nil.  */)
-  (register Lisp_Object window, Lisp_Object value)
-{
-  wset_redisplay_end_trigger (decode_live_window (window), value);
-  return value;
-}
-
 /* Test if the character at column X, row Y is within window W.
    If it is not, return ON_NOTHING;
    if it is on the window's vertical divider, return
@@ -2786,7 +2766,7 @@ decode_next_window_args (Lisp_Object *window, Lisp_Object 
*minibuf, Lisp_Object
         ? miniwin : Qnil);
   else if (EQ (*all_frames, Qvisible))
     ;
-  else if (EQ (*all_frames, make_fixnum (0)))
+  else if (BASE_EQ (*all_frames, make_fixnum (0)))
     ;
   else if (FRAMEP (*all_frames))
     ;
@@ -3083,7 +3063,7 @@ window_loop (enum window_loop type, Lisp_Object obj, bool 
mini,
 
   if (f)
     frame_arg = Qlambda;
-  else if (EQ (frames, make_fixnum (0)))
+  else if (BASE_EQ (frames, make_fixnum (0)))
     frame_arg = frames;
   else if (EQ (frames, Qvisible))
     frame_arg = frames;
@@ -5568,7 +5548,11 @@ window_scroll (Lisp_Object window, EMACS_INT n, bool 
whole, bool noerror)
   /* On GUI frames, use the pixel-based version which is much slower
      than the line-based one but can handle varying line heights.  */
   if (FRAME_WINDOW_P (XFRAME (XWINDOW (window)->frame)))
-    window_scroll_pixel_based (window, n, whole, noerror);
+    {
+      record_unwind_protect_void (unwind_display_working_on_window);
+      display_working_on_window_p = true;
+      window_scroll_pixel_based (window, n, whole, noerror);
+    }
   else
     window_scroll_line_based (window, n, whole, noerror);
 
@@ -6496,9 +6480,14 @@ displayed_window_lines (struct window *w)
   CLIP_TEXT_POS_FROM_MARKER (start, w->start);
 
   itdata = bidi_shelve_cache ();
+
+  specpdl_ref count = SPECPDL_INDEX ();
+  record_unwind_protect_void (unwind_display_working_on_window);
+  display_working_on_window_p = true;
   start_display (&it, w, start);
   move_it_vertically (&it, height);
   bottom_y = line_bottom_y (&it);
+  unbind_to (count, Qnil);
   bidi_unshelve_cache (itdata, false);
 
   /* Add in empty lines at the bottom of the window.  */
@@ -6588,10 +6577,17 @@ and redisplay normally--don't erase and redraw the 
frame.  */)
      in case scroll_margin is buffer-local.  */
   this_scroll_margin = window_scroll_margin (w, MARGIN_IN_LINES);
 
-  /* Don't use redisplay code for initial frames, as the necessary
-     data structures might not be set up yet then.  */
-  if (!FRAME_INITIAL_P (XFRAME (w->frame)))
+  /* Don't use the display code for initial frames, as the necessary
+     data structures might not be set up yet then.  Also don't use it
+     for buffers with very long lines, as it tremdously slows down
+     redisplay, especially when lines are truncated.  */
+  if (!FRAME_INITIAL_P (XFRAME (w->frame))
+      && !current_buffer->long_line_optimizations_p)
     {
+      specpdl_ref count = SPECPDL_INDEX ();
+
+      record_unwind_protect_void (unwind_display_working_on_window);
+      display_working_on_window_p = true;
       if (center_p)
        {
          struct it it;
@@ -6654,6 +6650,7 @@ and redisplay normally--don't erase and redraw the frame. 
 */)
          if (h <= 0)
            {
              bidi_unshelve_cache (itdata, false);
+             unbind_to (count, Qnil);
              return Qnil;
            }
 
@@ -6670,7 +6667,7 @@ and redisplay normally--don't erase and redraw the frame. 
 */)
             considered to be part of the visible height of the line.
          */
          h += extra_line_spacing;
-         while (-it.current_y > h)
+         while (-it.current_y > h && it.what != IT_EOB)
            move_it_by_lines (&it, 1);
 
          charpos = IT_CHARPOS (it);
@@ -6708,6 +6705,7 @@ and redisplay normally--don't erase and redraw the frame. 
 */)
 
          bidi_unshelve_cache (itdata, false);
        }
+      unbind_to (count, Qnil);
     }
   else
     {
@@ -6901,6 +6899,7 @@ struct saved_window
   Lisp_Object left_col, top_line, total_cols, total_lines;
   Lisp_Object normal_cols, normal_lines;
   Lisp_Object hscroll, min_hscroll, hscroll_whole, suspend_auto_hscroll;
+  Lisp_Object vscroll;
   Lisp_Object parent, prev;
   Lisp_Object start_at_line_beg;
   Lisp_Object display_table;
@@ -7128,6 +7127,7 @@ the return value is nil.  Otherwise the value is t.  */)
          w->suspend_auto_hscroll = !NILP (p->suspend_auto_hscroll);
          w->min_hscroll = XFIXNAT (p->min_hscroll);
          w->hscroll_whole = XFIXNAT (p->hscroll_whole);
+         w->vscroll = -XFIXNAT (p->vscroll);
          wset_display_table (w, p->display_table);
          w->left_margin_cols = XFIXNUM (p->left_margin_cols);
          w->right_margin_cols = XFIXNUM (p->right_margin_cols);
@@ -7282,7 +7282,7 @@ the return value is nil.  Otherwise the value is t.  */)
        do_switch_frame (NILP (dont_set_frame)
                          ? data->selected_frame
                          : old_frame
-                         , 0, 0, Qnil);
+                         , 0, Qnil);
     }
 
   FRAME_WINDOW_CHANGE (f) = true;
@@ -7462,6 +7462,7 @@ save_window_save (Lisp_Object window, struct Lisp_Vector 
*vector, ptrdiff_t i)
       p->suspend_auto_hscroll = w->suspend_auto_hscroll ? Qt : Qnil;
       XSETFASTINT (p->min_hscroll, w->min_hscroll);
       XSETFASTINT (p->hscroll_whole, w->hscroll_whole);
+      XSETFASTINT (p->vscroll, -w->vscroll);
       p->display_table = w->display_table;
       p->left_margin_cols = make_fixnum (w->left_margin_cols);
       p->right_margin_cols = make_fixnum (w->right_margin_cols);
@@ -7493,7 +7494,7 @@ save_window_save (Lisp_Object window, struct Lisp_Vector 
*vector, ptrdiff_t i)
              hare = XCDR (hare);
              tortoise = XCDR (tortoise);
 
-             if (EQ (hare, tortoise))
+             if (BASE_EQ (hare, tortoise))
                /* Reset Vwindow_persistent_parameters to Qnil.  */
                {
                  Vwindow_persistent_parameters = Qnil;
@@ -8619,8 +8620,6 @@ displayed after a scrolling operation to be somewhat 
inaccurate.  */);
   defsubr (&Swindow_body_width);
   defsubr (&Swindow_hscroll);
   defsubr (&Sset_window_hscroll);
-  defsubr (&Swindow_redisplay_end_trigger);
-  defsubr (&Sset_window_redisplay_end_trigger);
   defsubr (&Swindow_mode_line_height);
   defsubr (&Swindow_header_line_height);
   defsubr (&Swindow_tab_line_height);
diff --git a/src/window.h b/src/window.h
index 298a80a536..93817a9544 100644
--- a/src/window.h
+++ b/src/window.h
@@ -199,10 +199,6 @@ struct window
        and Qt, so bitfield can't be used here.  */
     Lisp_Object dedicated;
 
-    /* If redisplay in this window goes beyond this buffer position,
-       must run the redisplay-end-trigger-hook.  */
-    Lisp_Object redisplay_end_trigger;
-
     /* t means this window's child windows are not (re-)combined.  */
     Lisp_Object combination_limit;
 
@@ -497,12 +493,6 @@ wset_prev (struct window *w, Lisp_Object val)
   w->prev = val;
 }
 
-INLINE void
-wset_redisplay_end_trigger (struct window *w, Lisp_Object val)
-{
-  w->redisplay_end_trigger = val;
-}
-
 INLINE void
 wset_mode_line_help_echo (struct window *w, Lisp_Object val)
 {
@@ -1193,6 +1183,7 @@ enum window_body_unit
     WINDOW_BODY_IN_REMAPPED_CHARS
   };
 extern int window_body_width (struct window *w, enum window_body_unit);
+extern int window_body_height (struct window *w, enum window_body_unit);
 enum margin_unit { MARGIN_IN_LINES, MARGIN_IN_PIXELS };
 extern int window_scroll_margin (struct window *, enum margin_unit);
 extern void temp_output_buffer_show (Lisp_Object);
diff --git a/src/xdisp.c b/src/xdisp.c
index b02375ab2d..70f6936dd0 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -832,7 +832,7 @@ void
 wset_redisplay (struct window *w)
 {
   /* Beware: selected_window can be nil during early stages.  */
-  if (!EQ (make_lisp_ptr (w, Lisp_Vectorlike), selected_window))
+  if (!BASE_EQ (make_lisp_ptr (w, Lisp_Vectorlike), selected_window))
     redisplay_other_windows ();
   w->redisplay = true;
 }
@@ -1030,6 +1030,15 @@ static struct glyph_slice null_glyph_slice = { 0, 0, 0, 
0 };
 
 bool redisplaying_p;
 
+/* True while some display-engine code is working on layout of some
+   window.
+
+   WARNING: Use sparingly, preferably only in top level of commands
+   and important functions, because using it in nested calls might
+   reset the flag when the inner call returns, behind the back of
+   the callers.  */
+bool display_working_on_window_p;
+
 /* If a string, XTread_socket generates an event to display that string.
    (The display is done in read_char.)  */
 
@@ -1129,7 +1138,6 @@ static int display_string (const char *, Lisp_Object, 
Lisp_Object,
                            ptrdiff_t, ptrdiff_t, struct it *, int, int, int,
                           int);
 static void compute_line_metrics (struct it *);
-static void run_redisplay_end_trigger_hook (struct it *);
 static bool get_overlay_strings (struct it *, ptrdiff_t);
 static bool get_overlay_strings_1 (struct it *, ptrdiff_t, bool);
 static void next_overlay_string (struct it *);
@@ -3221,6 +3229,10 @@ init_iterator (struct it *it, struct window *w,
   it->f = XFRAME (w->frame);
 
   it->cmp_it.id = -1;
+  it->cmp_it.parent_it = it;
+
+  if (max_redisplay_ticks > 0)
+    update_redisplay_ticks (0, w);
 
   /* Extra space between lines (on window systems only).  */
   if (base_face_id == DEFAULT_FACE_ID
@@ -3267,17 +3279,6 @@ init_iterator (struct it *it, struct window *w,
   /* Are multibyte characters enabled in current_buffer?  */
   it->multibyte_p = !NILP (BVAR (current_buffer, enable_multibyte_characters));
 
-  /* Get the position at which the redisplay_end_trigger hook should
-     be run, if it is to be run at all.  */
-  if (MARKERP (w->redisplay_end_trigger)
-      && XMARKER (w->redisplay_end_trigger)->buffer != 0)
-    it->redisplay_end_trigger_charpos
-      = marker_position (w->redisplay_end_trigger);
-  else if (FIXNUMP (w->redisplay_end_trigger))
-    it->redisplay_end_trigger_charpos
-      = clip_to_bounds (PTRDIFF_MIN, XFIXNUM (w->redisplay_end_trigger),
-                       PTRDIFF_MAX);
-
   it->tab_width = SANE_TAB_WIDTH (current_buffer);
 
   /* Are lines in the display truncated?  */
@@ -3472,6 +3473,10 @@ init_iterator (struct it *it, struct window *w,
                        &it->bidi_it);
        }
 
+      /* This is set only when long_line_optimizations_p is non-zero
+        for the current buffer.  */
+      it->narrowed_begv = 0;
+
       /* Compute faces etc.  */
       reseat (it, it->current.pos, true);
     }
@@ -3479,6 +3484,70 @@ init_iterator (struct it *it, struct window *w,
   CHECK_IT (it);
 }
 
+/* Compute a suitable alternate value for BEGV and ZV that may be used
+   temporarily to optimize display if the buffer in window W contains
+   long lines.  */
+
+static int
+get_narrowed_width (struct window *w)
+{
+  int fact;
+  /* In a character-only terminal, only one font size is used, so we
+     can use a smaller factor.  */
+  fact = EQ (Fterminal_live_p (Qnil), Qt) ? 2 : 3;
+  return fact * window_body_width (w, WINDOW_BODY_IN_CANONICAL_CHARS);
+}
+
+static int
+get_narrowed_len (struct window *w)
+{
+  return get_narrowed_width (w) *
+    window_body_height (w, WINDOW_BODY_IN_CANONICAL_CHARS);
+}
+
+ptrdiff_t
+get_narrowed_begv (struct window *w, ptrdiff_t pos)
+{
+  int len = get_narrowed_len (w);
+  return max ((pos / len - 1) * len, BEGV);
+}
+
+ptrdiff_t
+get_narrowed_zv (struct window *w, ptrdiff_t pos)
+{
+  int len = get_narrowed_len (w);
+  return min ((pos / len + 1) * len, ZV);
+}
+
+ptrdiff_t
+get_closer_narrowed_begv (struct window *w, ptrdiff_t pos)
+{
+  int len = get_narrowed_width (w);
+  return max ((pos / len - 1) * len, BEGV);
+}
+
+static void
+unwind_narrowed_begv (Lisp_Object point_min)
+{
+  SET_BUF_BEGV (current_buffer, XFIXNUM (point_min));
+}
+
+/* Set DST to EXPR.  When IT indicates that BEGV should temporarily be
+   updated to optimize display, evaluate EXPR with BEGV set to BV.  */
+
+#define SET_WITH_NARROWED_BEGV(IT,DST,EXPR,BV)                         \
+  do {                                                                 \
+    if (IT->narrowed_begv)                                             \
+      {                                                                        
\
+       specpdl_ref count = SPECPDL_INDEX ();                           \
+       record_unwind_protect (unwind_narrowed_begv, Fpoint_min ());    \
+       SET_BUF_BEGV (current_buffer, BV);                              \
+       DST = EXPR;                                                     \
+       unbind_to (count, Qnil);                                        \
+      }                                                                        
\
+    else                                                               \
+      DST = EXPR;                                                      \
+  } while (0)
 
 /* Initialize IT for the display of window W with window start POS.  */
 
@@ -4323,6 +4392,20 @@ handle_fontified_prop (struct it *it)
 
       eassert (it->end_charpos == ZV);
 
+      if (current_buffer->long_line_optimizations_p)
+       {
+         ptrdiff_t begv = it->narrowed_begv;
+         ptrdiff_t zv = it->narrowed_zv;
+         ptrdiff_t charpos = IT_CHARPOS (*it);
+         if (charpos < begv || charpos > zv)
+           {
+             begv = get_narrowed_begv (it->w, charpos);
+             zv = get_narrowed_zv (it->w, charpos);
+           }
+         narrow_to_region_internal (make_fixnum (begv), make_fixnum (zv), 
true);
+         specbind (Qrestrictions_locked, Qt);
+       }
+
       /* Don't allow Lisp that runs from 'fontification-functions'
         clear our face and image caches behind our back.  */
       it->f->inhibit_clear_image_cache = true;
@@ -6980,7 +7063,109 @@ back_to_previous_line_start (struct it *it)
   ptrdiff_t cp = IT_CHARPOS (*it), bp = IT_BYTEPOS (*it);
 
   dec_both (&cp, &bp);
-  IT_CHARPOS (*it) = find_newline_no_quit (cp, bp, -1, &IT_BYTEPOS (*it));
+  SET_WITH_NARROWED_BEGV (it, IT_CHARPOS (*it),
+                         find_newline_no_quit (cp, bp, -1, &IT_BYTEPOS (*it)),
+                         get_closer_narrowed_begv (it->w, IT_CHARPOS (*it)));
+}
+
+/* Find in the current buffer the first display or overlay string
+   between STARTPOS and ENDPOS that includes embedded newlines.
+   Consider only overlays that apply to window W.
+   Value is non-zero if such a display/overlay string is found.  */
+static bool
+strings_with_newlines (ptrdiff_t startpos, ptrdiff_t endpos, struct window *w)
+{
+  /* Process overlays before the overlay center.  */
+  for (struct Lisp_Overlay *ov = current_buffer->overlays_before;
+       ov; ov = ov->next)
+    {
+      Lisp_Object overlay = make_lisp_ptr (ov, Lisp_Vectorlike);
+      eassert (OVERLAYP (overlay));
+
+      /* Skip this overlay if it doesn't apply to our window.  */
+      Lisp_Object window = Foverlay_get (overlay, Qwindow);
+      if (WINDOWP (window) && XWINDOW (window) != w)
+       continue;
+
+      ptrdiff_t ostart = OVERLAY_POSITION (OVERLAY_START (overlay));
+      ptrdiff_t oend = OVERLAY_POSITION (OVERLAY_END (overlay));
+
+      /* Due to the order of overlays in overlays_before, once we get
+        to an overlay whose end position is before STARTPOS, all the
+        rest also end before STARTPOS, and thus are of no concern to us.  */
+      if (oend < startpos)
+       break;
+
+      /* Skip overlays that don't overlap the range.  */
+      if (!((startpos < oend && ostart < endpos)
+           || (ostart == oend
+               && (startpos == oend || (endpos == ZV && oend == endpos)))))
+       continue;
+
+      Lisp_Object str;
+      str = Foverlay_get (overlay, Qbefore_string);
+      if (STRINGP (str) && SCHARS (str)
+         && memchr (SDATA (str), '\n', SBYTES (str)))
+       return true;
+      str = Foverlay_get (overlay, Qafter_string);
+      if (STRINGP (str) && SCHARS (str)
+         && memchr (SDATA (str), '\n', SBYTES (str)))
+       return true;
+    }
+
+  /* Process overlays after the overlay center.  */
+  for (struct Lisp_Overlay *ov = current_buffer->overlays_after;
+       ov; ov = ov->next)
+    {
+      Lisp_Object overlay = make_lisp_ptr (ov, Lisp_Vectorlike);
+      eassert (OVERLAYP (overlay));
+
+      /* Skip this overlay if it doesn't apply to our window.  */
+      Lisp_Object window = Foverlay_get (overlay, Qwindow);
+      if (WINDOWP (window) && XWINDOW (window) != w)
+       continue;
+
+      ptrdiff_t ostart = OVERLAY_POSITION (OVERLAY_START (overlay));
+      ptrdiff_t oend = OVERLAY_POSITION (OVERLAY_END (overlay));
+
+      /* Due to the order of overlays in overlays_after, once we get
+        to an overlay whose start position is after ENDPOS, all the
+        rest also start after ENDPOS, and thus are of no concern to us.  */
+      if (ostart > endpos)
+       break;
+
+      /* Skip overlays that don't overlap the range.  */
+      if (!((startpos < oend && ostart < endpos)
+           || (ostart == oend
+               && (startpos == oend || (endpos == ZV && oend == endpos)))))
+       continue;
+
+      Lisp_Object str;
+      str = Foverlay_get (overlay, Qbefore_string);
+      if (STRINGP (str) && SCHARS (str)
+         && memchr (SDATA (str), '\n', SBYTES (str)))
+       return true;
+      str = Foverlay_get (overlay, Qafter_string);
+      if (STRINGP (str) && SCHARS (str)
+         && memchr (SDATA (str), '\n', SBYTES (str)))
+       return true;
+    }
+
+  /* Check for 'display' properties whose values include strings.  */
+  Lisp_Object cpos = make_fixnum (startpos);
+  Lisp_Object limpos = make_fixnum (endpos);
+
+  while ((cpos = Fnext_single_property_change (cpos, Qdisplay, Qnil, limpos),
+         !(NILP (cpos) || XFIXNAT (cpos) >= endpos)))
+    {
+      Lisp_Object spec = Fget_char_property (cpos, Qdisplay, Qnil);
+      Lisp_Object string = string_from_display_spec (spec);
+      if (STRINGP (string)
+         && memchr (SDATA (string), '\n', SBYTES (string)))
+       return true;
+    }
+
+  return false;
 }
 
 
@@ -7035,7 +7220,8 @@ forward_to_next_line_start (struct it *it, bool 
*skipped_p,
   it->selective = 0;
 
   /* Scan for a newline within MAX_NEWLINE_DISTANCE display elements
-     from buffer text.  */
+     from buffer text, or till the end of the string if iterating a
+     string.  */
   for (n = 0;
        !newline_found_p && n < MAX_NEWLINE_DISTANCE;
        n += !STRINGP (it->string))
@@ -7055,27 +7241,55 @@ forward_to_next_line_start (struct it *it, bool 
*skipped_p,
       ptrdiff_t bytepos, start = IT_CHARPOS (*it);
       ptrdiff_t limit = find_newline_no_quit (start, IT_BYTEPOS (*it),
                                              1, &bytepos);
-      Lisp_Object pos;
-
       eassert (!STRINGP (it->string));
 
-      /* If there isn't any `display' property in sight, and no
-        overlays, we can just use the position of the newline in
-        buffer text.  */
-      if (it->stop_charpos >= limit
-         || ((pos = Fnext_single_property_change (make_fixnum (start),
-                                                  Qdisplay, Qnil,
-                                                  make_fixnum (limit)),
-              NILP (pos))
-             && next_overlay_change (start) == ZV))
+      /* it->stop_charpos >= limit means we already know there's no
+        stop position up until the newline at LIMIT, so there's no
+        need for any further checks.  */
+      bool no_strings_with_newlines = it->stop_charpos >= limit;
+
+      if (!no_strings_with_newlines)
        {
-         if (!it->bidi_p)
+         if (!(current_buffer->long_line_optimizations_p
+               && it->line_wrap == TRUNCATE))
+           {
+             /* Quick-and-dirty check: if there isn't any `display'
+                property in sight, and no overlays, we're done.  */
+             Lisp_Object pos =
+               Fnext_single_property_change (make_fixnum (start),
+                                             Qdisplay, Qnil,
+                                             make_fixnum (limit));
+             no_strings_with_newlines =
+               (NILP (pos) || XFIXNAT (pos) == limit) /* no 'display' props */
+               && next_overlay_change (start) == ZV;  /* no overlays */
+           }
+         else
+           {
+             /* For buffers with very long and truncated lines we try
+                harder, because it's worth our while to spend some
+                time looking into the overlays and 'display' properties
+                if we can then avoid iterating through all of them.  */
+             no_strings_with_newlines =
+               !strings_with_newlines (start, limit, it->w);
+           }
+       }
+
+      /* If there's no display or overlay strings with embedded
+        newlines until the position of the newline in buffer text, we
+        can just use that position.  */
+      if (no_strings_with_newlines)
+       {
+         if (!it->bidi_p || !bidi_it_prev)
            {
+             /* The optimal case: just jump there.  */
              IT_CHARPOS (*it) = limit;
              IT_BYTEPOS (*it) = bytepos;
            }
          else
            {
+             /* The less optimal case: need to bidi-walk there, but
+                this is still cheaper that the full iteration using
+                get_next_display_element and set_iterator_to_next.  */
              struct bidi_it bprev;
 
              /* Help bidi.c avoid expensive searches for display
@@ -7099,6 +7313,7 @@ forward_to_next_line_start (struct it *it, bool 
*skipped_p,
        }
       else
        {
+         /* The slow case.  */
          while (!newline_found_p)
            {
              if (!get_next_display_element (it))
@@ -7198,7 +7413,8 @@ back_to_previous_visible_line_start (struct it *it)
   it->continuation_lines_width = 0;
 
   eassert (IT_CHARPOS (*it) >= BEGV);
-  eassert (IT_CHARPOS (*it) == BEGV
+  eassert (it->narrowed_begv > 0 /* long-line optimizations: all bets off */
+          || IT_CHARPOS (*it) == BEGV
           || FETCH_BYTE (IT_BYTEPOS (*it) - 1) == '\n');
   CHECK_IT (it);
 }
@@ -7231,7 +7447,8 @@ reseat_at_next_visible_line_start (struct it *it, bool 
on_newline_p)
   bool skipped_p = false;
   struct bidi_it bidi_it_prev;
   bool newline_found_p
-    = forward_to_next_line_start (it, &skipped_p, &bidi_it_prev);
+    = forward_to_next_line_start (it, &skipped_p,
+                                 on_newline_p ? &bidi_it_prev : NULL);
 
   /* Skip over lines that are invisible because they are indented
      more than the value of IT->selective.  */
@@ -7243,7 +7460,8 @@ reseat_at_next_visible_line_start (struct it *it, bool 
on_newline_p)
        eassert (IT_BYTEPOS (*it) == BEGV
                 || FETCH_BYTE (IT_BYTEPOS (*it) - 1) == '\n');
        newline_found_p =
-         forward_to_next_line_start (it, &skipped_p, &bidi_it_prev);
+         forward_to_next_line_start (it, &skipped_p,
+                                     on_newline_p ? &bidi_it_prev : NULL);
       }
 
   /* Position on the newline if that's what's requested.  */
@@ -7311,6 +7529,21 @@ reseat (struct it *it, struct text_pos pos, bool force_p)
 
   reseat_1 (it, pos, false);
 
+  if (current_buffer->long_line_optimizations_p)
+    {
+      if (!it->narrowed_begv)
+       {
+         it->narrowed_begv = get_narrowed_begv (it->w, window_point (it->w));
+         it->narrowed_zv = get_narrowed_zv (it->w, window_point (it->w));
+       }
+      else if ((pos.charpos < it->narrowed_begv || pos.charpos > 
it->narrowed_zv)
+               && (!redisplaying_p || it->line_wrap == TRUNCATE))
+       {
+         it->narrowed_begv = get_narrowed_begv (it->w, pos.charpos);
+         it->narrowed_zv = get_narrowed_zv (it->w, pos.charpos);
+       }
+    }
+
   /* Determine where to check text properties.  Avoid doing it
      where possible because text property lookup is very expensive.  */
   if (force_p
@@ -7609,15 +7842,14 @@ lookup_glyphless_char_display (int c, struct it *it)
       && CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (Vglyphless_char_display)) >= 1)
     {
       if (c >= 0)
-       {
-         glyphless_method = CHAR_TABLE_REF (Vglyphless_char_display, c);
-      if (CONSP (glyphless_method))
-       glyphless_method = FRAME_WINDOW_P (it->f)
-             ? XCAR (glyphless_method)
-             : XCDR (glyphless_method);
-       }
+       glyphless_method = CHAR_TABLE_REF (Vglyphless_char_display, c);
       else
        glyphless_method = XCHAR_TABLE (Vglyphless_char_display)->extras[0];
+
+      if (CONSP (glyphless_method))
+       glyphless_method = FRAME_WINDOW_P (it->f)
+         ? XCAR (glyphless_method)
+         : XCDR (glyphless_method);
     }
 
  retry:
@@ -8175,6 +8407,9 @@ void
 set_iterator_to_next (struct it *it, bool reseat_p)
 {
 
+  if (max_redisplay_ticks > 0)
+    update_redisplay_ticks (1, it->w);
+
   switch (it->method)
     {
     case GET_FROM_BUFFER:
@@ -8608,7 +8843,13 @@ get_visually_first_element (struct it *it)
 {
   bool string_p = STRINGP (it->string) || it->s;
   ptrdiff_t eob = (string_p ? it->bidi_it.string.schars : ZV);
-  ptrdiff_t bob = (string_p ? 0 : BEGV);
+  ptrdiff_t bob;
+  ptrdiff_t obegv = BEGV;
+
+  SET_WITH_NARROWED_BEGV (it, bob,
+                         string_p ? 0 :
+                         IT_CHARPOS (*it) < BEGV ? obegv : BEGV,
+                         it->narrowed_begv);
 
   if (STRINGP (it->string))
     {
@@ -8648,9 +8889,11 @@ get_visually_first_element (struct it *it)
       if (string_p)
        it->bidi_it.charpos = it->bidi_it.bytepos = 0;
       else
-       it->bidi_it.charpos = find_newline_no_quit (IT_CHARPOS (*it),
-                                                   IT_BYTEPOS (*it), -1,
-                                                   &it->bidi_it.bytepos);
+       SET_WITH_NARROWED_BEGV (it, it->bidi_it.charpos,
+                               find_newline_no_quit (IT_CHARPOS (*it),
+                                                     IT_BYTEPOS (*it), -1,
+                                                     &it->bidi_it.bytepos),
+                               it->narrowed_begv);
       bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it, true);
       do
        {
@@ -9186,13 +9429,6 @@ next_element_from_buffer (struct it *it)
         previously seen overlays is no longer valid.  */
       it->ignore_overlay_strings_at_pos_p = false;
 
-      /* Maybe run the redisplay end trigger hook.  Performance note:
-        This doesn't seem to cost measurable time.  */
-      if (it->redisplay_end_trigger_charpos
-         && it->glyph_row
-         && IT_CHARPOS (*it) >= it->redisplay_end_trigger_charpos)
-       run_redisplay_end_trigger_hook (it);
-
       if (composition_break_at_point
          && !NILP (BVAR (current_buffer, enable_multibyte_characters))
          && !NILP (Vauto_composition_mode))
@@ -9260,29 +9496,6 @@ next_element_from_buffer (struct it *it)
 }
 
 
-/* Run the redisplay end trigger hook for IT.  */
-
-static void
-run_redisplay_end_trigger_hook (struct it *it)
-{
-  /* IT->glyph_row should be non-null, i.e. we should be actually
-     displaying something, or otherwise we should not run the hook.  */
-  eassert (it->glyph_row);
-
-  ptrdiff_t charpos = it->redisplay_end_trigger_charpos;
-  it->redisplay_end_trigger_charpos = 0;
-
-  /* Since we are *trying* to run these functions, don't try to run
-     them again, even if they get an error.  */
-  wset_redisplay_end_trigger (it->w, Qnil);
-  CALLN (Frun_hook_with_args, Qredisplay_end_trigger_functions, it->window,
-        make_fixnum (charpos));
-
-  /* Notice if it changed the face of the character we are on.  */
-  handle_face_prop (it);
-}
-
-
 /* Deliver a composition display element.  Unlike the other
    next_element_from_XXX, this function is not registered in the array
    get_next_element[].  It is called from next_element_from_buffer and
@@ -10497,6 +10710,11 @@ move_it_vertically_backward (struct it *it, int dy)
   while (nlines-- && IT_CHARPOS (*it) > pos_limit)
     back_to_previous_visible_line_start (it);
 
+  /* Move one line more back, for the (rare) situation where we have
+     bidi-reordered continued lines, and we start from the top-most
+     screen line, which is the last in logical order.  */
+  if (it->bidi_p && dy == 0)
+    back_to_previous_visible_line_start (it);
   /* Reseat the iterator here.  When moving backward, we don't want
      reseat to skip forward over invisible text, set up the iterator
      to deliver from overlay strings at the new position etc.  So,
@@ -10568,7 +10786,9 @@ move_it_vertically_backward (struct it *it, int dy)
          ptrdiff_t cp = IT_CHARPOS (*it), bp = IT_BYTEPOS (*it);
 
          dec_both (&cp, &bp);
-         cp = find_newline_no_quit (cp, bp, -1, NULL);
+         SET_WITH_NARROWED_BEGV (it, cp,
+                                 find_newline_no_quit (cp, bp, -1, NULL),
+                                 get_closer_narrowed_begv (it->w, IT_CHARPOS 
(*it)));
          move_it_to (it, cp, -1, -1, -1, MOVE_TO_POS);
        }
       bidi_unshelve_cache (it3data, true);
@@ -10746,6 +10966,7 @@ move_it_by_lines (struct it *it, ptrdiff_t dvpos)
         position.  This may actually move vertically backwards,
          in case of overlays, so adjust dvpos accordingly.  */
       dvpos += it->vpos;
+      start_charpos = IT_CHARPOS (*it);
       move_it_vertically_backward (it, 0);
       dvpos -= it->vpos;
 
@@ -10799,7 +11020,7 @@ move_it_by_lines (struct it *it, ptrdiff_t dvpos)
          SAVE_IT (it2, *it, it2data);
          move_it_to (it, -1, -1, -1, it->vpos + delta, MOVE_TO_VPOS);
          /* Move back again if we got too far ahead.  */
-         if (IT_CHARPOS (*it) >= start_charpos)
+         if (it->vpos - it2.vpos > delta)
            RESTORE_IT (it, &it2, it2data);
          else
            bidi_unshelve_cache (it2data, true);
@@ -10832,6 +11053,15 @@ move_it_by_lines (struct it *it, ptrdiff_t dvpos)
 int
 partial_line_height (struct it *it_origin)
 {
+  /* In a buffer with very long and truncated lines, we ignore the
+     possibly-partial height of the last line in the window: it is too
+     expensive to compute that (since in most cases that involves
+     going all the way to ZV), and the effect of ignoring it is
+     relatively minor.  */
+  if (XBUFFER (it_origin->w->contents)->long_line_optimizations_p
+      && it_origin->line_wrap == TRUNCATE)
+    return 0;
+
   int partial_height;
   void *it_data = NULL;
   struct it it;
@@ -10855,6 +11085,51 @@ partial_line_height (struct it *it_origin)
   return partial_height;
 }
 
+/* Approximate move_it_in_display_line_to for very long and truncated
+   display lines, when moving horizontally.  This is used when the
+   buffer's long_line_optimizations_p flag is set.  It ignores various
+   complications, like different font sizes, invisible text, display
+   and overlay strings, and, to some degree, bidirectional text.  So
+   caveat emptor!
+
+   Starting from IT's position, reseat IT after skipping NCHARS
+   characters or to the next newline/ZV, whichever comes first.  Return
+   what move_it_in_display_line_to would have returned in this case.  */
+
+static enum move_it_result
+fast_move_it_horizontally (struct it *it, ptrdiff_t nchars)
+{
+  ptrdiff_t nl_bytepos;
+  ptrdiff_t nl_pos = find_newline_no_quit (IT_CHARPOS (*it), IT_BYTEPOS (*it),
+                                          1, &nl_bytepos);
+  struct text_pos new_pos;
+  enum move_it_result move_result;
+
+  if (nl_pos - IT_CHARPOS (*it) > nchars)
+    {
+      SET_TEXT_POS (new_pos,
+                   IT_CHARPOS (*it) + nchars,
+                   CHAR_TO_BYTE (IT_CHARPOS (*it) + nchars));
+      move_result = MOVE_X_REACHED;
+    }
+  else
+    {
+      if (nl_bytepos < ZV_BYTE
+         || (nl_bytepos > BEGV_BYTE
+             && FETCH_BYTE (nl_bytepos - 1) == '\n'))
+       {
+         nl_pos--;
+         nl_bytepos--;
+         move_result = MOVE_NEWLINE_OR_CR;
+       }
+      else
+       move_result = MOVE_POS_MATCH_OR_ZV;
+      SET_TEXT_POS (new_pos, nl_pos, nl_bytepos);
+    }
+  reseat (it, new_pos, false);
+  return move_result;
+}
+
 /* Return true if IT points into the middle of a display vector.  */
 
 bool
@@ -10957,6 +11232,7 @@ window_text_pixel_size (Lisp_Object window, Lisp_Object 
from, Lisp_Object to,
     max_y = XFIXNUM (y_limit);
 
   itdata = bidi_shelve_cache ();
+
   start_display (&it, w, startp);
 
   int start_y = it.current_y;
@@ -13452,9 +13728,6 @@ update_menu_bar (struct frame *f, bool save_match_data, 
bool hooks_run)
 
              /* If it has changed current-menubar from previous value,
                 really recompute the menu-bar from the value.  */
-             if (! NILP (Vlucid_menu_bar_dirty_flag))
-               call0 (Qrecompute_lucid_menubar);
-
              safe_run_hooks (Qmenu_bar_update_hook);
 
              hooks_run = true;
@@ -14041,15 +14314,41 @@ redisplay_tab_bar (struct frame *f)
       return false;
     }
 
+  /* Build a string that represents the contents of the tab-bar.  */
+  build_desired_tab_bar_string (f);
+
+  int new_nrows;
+  int new_height = tab_bar_height (f, &new_nrows, true);
+
+  if (f->n_tab_bar_rows == 0)
+    {
+      f->n_tab_bar_rows = new_nrows;
+      if (new_height != WINDOW_PIXEL_HEIGHT (w))
+       frame_default_tab_bar_height = new_height;
+    }
+
+  /* If new_height or new_nrows indicate that we need to enlarge the
+     tab-bar window, we can return right away.  */
+  if (new_nrows > f->n_tab_bar_rows
+      || (EQ (Vauto_resize_tab_bars, Qgrow_only)
+         && !f->minimize_tab_bar_window_p
+         && new_height > WINDOW_PIXEL_HEIGHT (w)))
+    {
+      if (FRAME_TERMINAL (f)->change_tab_bar_height_hook)
+       FRAME_TERMINAL (f)->change_tab_bar_height_hook (f, new_height);
+      if (new_nrows != f->n_tab_bar_rows)
+       f->n_tab_bar_rows = new_nrows;
+      clear_glyph_matrix (w->desired_matrix);
+      f->fonts_changed = true;
+      return true;
+    }
+
   /* Set up an iterator for the tab-bar window.  */
   init_iterator (&it, w, -1, -1, w->desired_matrix->rows, TAB_BAR_FACE_ID);
   it.first_visible_x = 0;
   it.last_visible_x = WINDOW_PIXEL_WIDTH (w);
   row = it.glyph_row;
   row->reversed_p = false;
-
-  /* Build a string that represents the contents of the tab-bar.  */
-  build_desired_tab_bar_string (f);
   reseat_to_string (&it, NULL, f->desired_tab_bar_string, 0, 0, 0,
                     STRING_MULTIBYTE (f->desired_tab_bar_string));
   /* FIXME: This should be controlled by a user option.  But it
@@ -14061,22 +14360,6 @@ redisplay_tab_bar (struct frame *f)
      do.  */
   it.paragraph_embedding = L2R;
 
-  if (f->n_tab_bar_rows == 0)
-    {
-      int new_height = tab_bar_height (f, &f->n_tab_bar_rows, true);
-
-      if (new_height != WINDOW_PIXEL_HEIGHT (w))
-       {
-          if (FRAME_TERMINAL (f)->change_tab_bar_height_hook)
-            FRAME_TERMINAL (f)->change_tab_bar_height_hook (f, new_height);
-         frame_default_tab_bar_height = new_height;
-         /* Always do that now.  */
-         clear_glyph_matrix (w->desired_matrix);
-         f->fonts_changed = true;
-         return true;
-       }
-    }
-
   /* Display as many lines as needed to display all tab-bar items.  */
 
   if (f->n_tab_bar_rows > 0)
@@ -14122,7 +14405,7 @@ redisplay_tab_bar (struct frame *f)
 
   if (!NILP (Vauto_resize_tab_bars))
     {
-      bool change_height_p = true;
+      bool change_height_p = false;
 
       /* If we couldn't display everything, change the tab-bar's
         height if there is room for more.  */
@@ -14678,7 +14961,7 @@ build_desired_tool_bar_string (struct frame *f)
             selected.  */
          if (selected_p)
            {
-             plist = Fplist_put (plist, QCrelief, make_fixnum (-relief));
+             plist = plist_put (plist, QCrelief, make_fixnum (-relief));
              hmargin -= relief;
              vmargin -= relief;
            }
@@ -14688,10 +14971,10 @@ build_desired_tool_bar_string (struct frame *f)
          /* If image is selected, display it pressed, i.e. with a
             negative relief.  If it's not selected, display it with a
             raised relief.  */
-         plist = Fplist_put (plist, QCrelief,
-                             (selected_p
-                              ? make_fixnum (-relief)
-                              : make_fixnum (relief)));
+         plist = plist_put (plist, QCrelief,
+                            (selected_p
+                             ? make_fixnum (-relief)
+                             : make_fixnum (relief)));
          hmargin -= relief;
          vmargin -= relief;
        }
@@ -14700,18 +14983,18 @@ build_desired_tool_bar_string (struct frame *f)
       if (hmargin || vmargin)
        {
          if (hmargin == vmargin)
-           plist = Fplist_put (plist, QCmargin, make_fixnum (hmargin));
+           plist = plist_put (plist, QCmargin, make_fixnum (hmargin));
          else
-           plist = Fplist_put (plist, QCmargin,
-                               Fcons (make_fixnum (hmargin),
-                                      make_fixnum (vmargin)));
+           plist = plist_put (plist, QCmargin,
+                              Fcons (make_fixnum (hmargin),
+                                     make_fixnum (vmargin)));
        }
 
       /* If button is not enabled, and we don't have special images
         for the disabled state, make the image appear disabled by
         applying an appropriate algorithm to it.  */
       if (!enabled_p && idx < 0)
-       plist = Fplist_put (plist, QCconversion, Qdisabled);
+       plist = plist_put (plist, QCconversion, Qdisabled);
 
       /* Put a `display' text property on the string for the image to
         display.  Put a `menu-item' property on the string that gives
@@ -15050,7 +15333,7 @@ redisplay_tool_bar (struct frame *f)
 
   if (!NILP (Vauto_resize_tool_bars))
     {
-      bool change_height_p = true;
+      bool change_height_p = false;
 
       /* If we couldn't display everything, change the tool-bar's
         height if there is room for more.  */
@@ -15559,7 +15842,20 @@ hscroll_window_tree (Lisp_Object window)
                it.first_visible_x = window_hscroll_limited (w, it.f)
                                     * FRAME_COLUMN_WIDTH (it.f);
              it.last_visible_x = DISP_INFINITY;
-             move_it_in_display_line_to (&it, pt, -1, MOVE_TO_POS);
+
+             ptrdiff_t nchars = pt - IT_CHARPOS (it);
+             if (current_buffer->long_line_optimizations_p
+                 && nchars > large_hscroll_threshold)
+               {
+                 /* Special optimization for very long and truncated
+                    lines which need to be hscrolled far to the left:
+                    jump directly to the (approximate) first position
+                    that is visible, instead of slowly walking there.  */
+                 fast_move_it_horizontally (&it, nchars);
+                 it.current_x += nchars * FRAME_COLUMN_WIDTH (it.f);
+               }
+             else
+               move_it_in_display_line_to (&it, pt, -1, MOVE_TO_POS);
              /* If the line ends in an overlay string with a newline,
                 we might infloop, because displaying the window will
                 want to put the cursor after the overlay, i.e. at X
@@ -15572,7 +15868,14 @@ hscroll_window_tree (Lisp_Object window)
                  if (hscl)
                    it.first_visible_x = (window_hscroll_limited (w, it.f)
                                          * FRAME_COLUMN_WIDTH (it.f));
-                 move_it_in_display_line_to (&it, pt - 1, -1, MOVE_TO_POS);
+                 if (current_buffer->long_line_optimizations_p
+                     && nchars > large_hscroll_threshold)
+                   {
+                     fast_move_it_horizontally (&it, nchars - 1);
+                     it.current_x += (nchars - 1) * FRAME_COLUMN_WIDTH (it.f);
+                   }
+                 else
+                   move_it_in_display_line_to (&it, pt - 1, -1, MOVE_TO_POS);
                }
              current_buffer = saved_current_buffer;
 
@@ -16510,9 +16813,23 @@ redisplay_internal (void)
          it.current_y = this_line_y;
          it.vpos = this_line_vpos;
 
-         /* The call to move_it_to stops in front of PT, but
-            moves over before-strings.  */
-         move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
+         if (current_buffer->long_line_optimizations_p
+             && it.line_wrap == TRUNCATE
+             && PT - CHARPOS (tlbufpos) > large_hscroll_threshold)
+           {
+             /* When lines are very long and truncated, jumping to
+                the next visible line is much faster than slowly
+                iterating there.  */
+             reseat_at_next_visible_line_start (&it, false);
+             if (IT_CHARPOS (it) <= PT) /* point moved off this line */
+               it.vpos = this_line_vpos + 1;
+           }
+         else
+           {
+             /* The call to move_it_to stops in front of PT, but
+                moves over before-strings.  */
+             move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
+           }
 
          if (it.vpos == this_line_vpos
              && (row = MATRIX_ROW (w->current_matrix, this_line_vpos),
@@ -16724,9 +17041,14 @@ redisplay_internal (void)
                                 list_of_error,
                                 redisplay_window_error);
       if (update_miniwindow_p)
-       internal_condition_case_1 (redisplay_window_1,
-                                  FRAME_MINIBUF_WINDOW (sf), list_of_error,
-                                  redisplay_window_error);
+       {
+         Lisp_Object mini_window = FRAME_MINIBUF_WINDOW (sf);
+
+         displayed_buffer = XBUFFER (XWINDOW (mini_window)->contents);
+         internal_condition_case_1 (redisplay_window_1, mini_window,
+                                    list_of_error,
+                                    redisplay_window_error);
+       }
 
       /* Compare desired and current matrices, perform output.  */
 
@@ -16904,6 +17226,11 @@ redisplay_internal (void)
   if (interrupt_input && interrupts_deferred)
     request_sigio ();
 
+  /* We're done with this redisplay cycle, so reset the tick count in
+     preparation for the next redisplay cycle.  */
+  if (max_redisplay_ticks > 0)
+    update_redisplay_ticks (0, NULL);
+
   unbind_to (count, Qnil);
   RESUME_POLLING;
 }
@@ -16961,6 +17288,13 @@ unwind_redisplay (void)
   unblock_buffer_flips ();
 }
 
+/* Function registered with record_unwind_protect before calling
+   start_display outside of redisplay_internal.  */
+void
+unwind_display_working_on_window (void)
+{
+  display_working_on_window_p = false;
+}
 
 /* Mark the display of leaf window W as accurate or inaccurate.
    If ACCURATE_P, mark display of W as accurate.
@@ -16988,6 +17322,7 @@ 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);
 
@@ -17135,9 +17470,19 @@ redisplay_windows (Lisp_Object window)
 }
 
 static Lisp_Object
-redisplay_window_error (Lisp_Object ignore)
+redisplay_window_error (Lisp_Object error_data)
 {
   displayed_buffer->display_error_modiff = BUF_MODIFF (displayed_buffer);
+
+  /* When in redisplay, the error is captured and not shown.  Arrange
+     for it to be shown later.  */
+  if (max_redisplay_ticks > 0
+      && CONSP (error_data)
+      && EQ (XCAR (error_data), Qerror)
+      && STRINGP (XCAR (XCDR (error_data))))
+    Vdelayed_warnings_list = Fcons (list2 (XCAR (error_data),
+                                          XCAR (XCDR (error_data))),
+                                   Vdelayed_warnings_list);
   return Qnil;
 }
 
@@ -17156,6 +17501,73 @@ redisplay_window_1 (Lisp_Object window)
     redisplay_window (window, true);
   return Qnil;
 }
+
+
+/***********************************************************************
+                     Aborting runaway redisplay
+ ***********************************************************************/
+
+/* Update the redisplay-tick count for window W, and signal an error
+   if the tick count is above some threshold, indicating that
+   redisplay of the window takes "too long".
+
+   TICKS is the amount of ticks to add to the W's current count; zero
+   means to initialize the tick count to zero.
+
+   W can be NULL if TICKS is zero: that means unconditionally
+   re-initialize the current tick count to zero.
+
+   W can also be NULL if the caller doesn't know which window is being
+   processed by the display code.  In that case, if TICKS is non-zero,
+   we assume it's the last window that shows the current buffer.  */
+void
+update_redisplay_ticks (int ticks, struct window *w)
+{
+  /* This keeps track of the window on which redisplay is working.  */
+  static struct window *cwindow;
+  static EMACS_INT window_ticks;
+
+  /* We only initialize the count if this is a different window or
+     NULL.  Otherwise, this is a call from init_iterator for the same
+     window we tracked before, and we should keep the count.  */
+  if (!ticks && w != cwindow)
+    {
+      cwindow = w;
+      window_ticks = 0;
+    }
+  /* Some callers can be run in contexts unrelated to display code, so
+     don't abort them and don't update the tick count in those cases.  */
+  if ((!w && !redisplaying_p && !display_working_on_window_p)
+      /* We never disable redisplay of a mini-window, since that is
+        absolutely essential for communicating with Emacs.  */
+      || (w && MINI_WINDOW_P (w)))
+    return;
+
+  if (ticks > 0)
+    window_ticks += ticks;
+  if (max_redisplay_ticks > 0 && window_ticks > max_redisplay_ticks)
+    {
+      /* In addition to a buffer, this could be a window (for non-leaf
+        windows, not expected here) or nil (for pseudo-windows like
+        the one used for the native tool bar).  */
+      Lisp_Object contents = w ? w->contents : Qnil;
+      char *bufname =
+       NILP (contents)
+       ? SSDATA (BVAR (current_buffer, name))
+       : (BUFFERP (contents)
+          ? SSDATA (BVAR (XBUFFER (contents), name))
+          : (char *) "<unknown>");
+
+      windows_or_buffers_changed = 177;
+      /* scrolling_window depends too much on the glyph matrices being
+        correct, and we cannot guarantee that if we abort the
+        redisplay of this window.  */
+      if (w && w->desired_matrix)
+       w->desired_matrix->no_scrolling_p = true;
+      error ("Window showing buffer %s takes too long to redisplay", bufname);
+    }
+}
+
 
 
 /* Set cursor position of W.  PT is assumed to be displayed in ROW.
@@ -17808,8 +18220,8 @@ run_window_scroll_functions (Lisp_Object window, struct 
text_pos startp)
     {
       specpdl_ref count = SPECPDL_INDEX ();
       specbind (Qinhibit_quit, Qt);
-      run_hook_with_args_2 (Qwindow_scroll_functions, window,
-                           make_fixnum (CHARPOS (startp)));
+      safe_run_hooks_2
+       (Qwindow_scroll_functions, window, make_fixnum (CHARPOS (startp)));
       unbind_to (count, Qnil);
       SET_TEXT_POS_FROM_MARKER (startp, w->start);
       /* In case the hook functions switch buffers.  */
@@ -18518,6 +18930,8 @@ try_cursor_movement (Lisp_Object window, struct 
text_pos startp,
            {
              /* Cursor has to be moved backward.  Note that PT >=
                 CHARPOS (startp) because of the outer if-statement.  */
+             struct glyph_row *row0 = row;
+
              while (!row->mode_line_p
                     && (MATRIX_ROW_START_CHARPOS (row) > PT
                         || (MATRIX_ROW_START_CHARPOS (row) == PT
@@ -18532,6 +18946,23 @@ try_cursor_movement (Lisp_Object window, struct 
text_pos startp,
                  --row;
                }
 
+             /* With bidi-reordered rows we can have buffer positions
+                _decrease_ when going down by rows.  If we haven't
+                found our row in the loop above, give it another try
+                now going in the other direction from the original row.  */
+             if (!(MATRIX_ROW_START_CHARPOS (row) <= PT
+                   && PT <= MATRIX_ROW_END_CHARPOS (row))
+                 && row0->continued_p)
+               {
+                 row = row0;
+                 while (MATRIX_ROW_START_CHARPOS (row) > PT
+                        && MATRIX_ROW_BOTTOM_Y (row) < last_y)
+                   {
+                     eassert (row->enabled_p);
+                     ++row;
+                   }
+               }
+
              /* Consider the following case: Window starts at BEGV,
                 there is invisible, intangible text at BEGV, so that
                 display starts at some point START > BEGV.  It can
@@ -18555,9 +18986,16 @@ try_cursor_movement (Lisp_Object window, struct 
text_pos startp,
                     && !cursor_row_p (row))
                ++row;
 
-             /* If within the scroll margin, scroll.  */
-             if (row->y < top_scroll_margin
-                 && CHARPOS (startp) != BEGV)
+             /* If within the scroll margin, either the top one or
+                the bottom one, scroll.  */
+             if ((row->y < top_scroll_margin
+                  && CHARPOS (startp) != BEGV)
+                 || MATRIX_ROW_BOTTOM_Y (row) > last_y
+                 || PT > MATRIX_ROW_END_CHARPOS (row)
+                 || (MATRIX_ROW_BOTTOM_Y (row) == last_y
+                     && PT == MATRIX_ROW_END_CHARPOS (row)
+                     && !row->ends_at_zv_p
+                     && !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row)))
                scroll_p = true;
            }
          else
@@ -18762,12 +19200,31 @@ set_vertical_scroll_bar (struct window *w)
          && NILP (echo_area_buffer[0])))
     {
       struct buffer *buf = XBUFFER (w->contents);
+
       whole = BUF_ZV (buf) - BUF_BEGV (buf);
       start = marker_position (w->start) - BUF_BEGV (buf);
-      /* I don't think this is guaranteed to be right.  For the
-        moment, we'll pretend it is.  */
       end = BUF_Z (buf) - w->window_end_pos - BUF_BEGV (buf);
 
+      /* If w->window_end_pos cannot be trusted, recompute it "the
+        hard way".  But don't bother to be too accurate when
+        long-line shortcuts are in effect.  */
+      if (!w->window_end_valid && !buf->long_line_optimizations_p)
+       {
+         struct it it;
+         struct text_pos start_pos;
+         struct buffer *obuf = current_buffer;
+         /* When we display the scroll bar of a mini-window,
+            current_buffer is not guaranteed to be the mini-window's
+            buffer, see the beginning of redisplay_window.  */
+         set_buffer_internal_1 (XBUFFER (w->contents));
+         SET_TEXT_POS_FROM_MARKER (start_pos, w->start);
+         start_display (&it, w, start_pos);
+         move_it_to (&it, -1, it.last_visible_x, window_box_height (w), -1,
+                     MOVE_TO_X | MOVE_TO_Y);
+         end -= (BUF_Z (buf) - IT_CHARPOS (it)) - w->window_end_pos;
+         set_buffer_internal_1 (obuf);
+       }
+
       if (end < start)
        end = start;
       if (whole < (end - start))
@@ -18873,6 +19330,16 @@ window_start_acceptable_p (Lisp_Object window, 
ptrdiff_t startp)
   return true;
 }
 
+DEFUN ("long-line-optimizations-p", Flong_line_optimizations_p, 
Slong_line_optimizations_p,
+       0, 0, 0,
+       doc: /* Return non-nil if long-line optimizations are in effect in 
current buffer.
+See `long-line-threshold' and `large-hscroll-threshold' for what these
+optimizations mean and when they are in effect.  */)
+  (void)
+{
+  return current_buffer->long_line_optimizations_p ? Qt : Qnil;
+}
+
 /* Redisplay leaf window WINDOW.  JUST_THIS_ONE_P means only
    selected_window is redisplayed.
 
@@ -19115,6 +19582,24 @@ 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)
+    {
+      ptrdiff_t cur, next, found, max = 0, threshold;
+      threshold = XFIXNUM (Vlong_line_threshold);
+      for (cur = BEGV; cur < ZV; cur = next)
+       {
+         next = find_newline1 (cur, CHAR_TO_BYTE (cur), 0, -1, 1,
+                               &found, NULL, true);
+         if (next - cur > max) max = next - cur;
+         if (!found || max > threshold) break;
+       }
+      if (max > threshold)
+       current_buffer->long_line_optimizations_p = true;
+    }
+
   /* If window-start is screwed up, choose a new one.  */
   if (XMARKER (w->start)->buffer != current_buffer)
     goto recenter;
@@ -19130,33 +19615,36 @@ redisplay_window (Lisp_Object window, bool 
just_this_one_p)
       ptrdiff_t it_charpos;
 
       w->optional_new_start = false;
-      start_display (&it, w, startp);
-      move_it_to (&it, PT, 0, it.last_visible_y, -1,
-                 MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
-      /* Record IT's position now, since line_bottom_y might change
-        that.  */
-      it_charpos = IT_CHARPOS (it);
-      /* Make sure we set the force_start flag only if the cursor row
-        will be fully visible.  Otherwise, the code under force_start
-        label below will try to move point back into view, which is
-        not what the code which sets optional_new_start wants.  */
-      if ((it.current_y == 0 || line_bottom_y (&it) < it.last_visible_y)
-         && !w->force_start)
-       {
-         if (it_charpos == PT)
-           w->force_start = true;
-         /* IT may overshoot PT if text at PT is invisible.  */
-         else if (it_charpos > PT && CHARPOS (startp) <= PT)
-           w->force_start = true;
+      if (!w->force_start)
+       {
+         start_display (&it, w, startp);
+         move_it_to (&it, PT, 0, it.last_visible_y, -1,
+                     MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
+         /* Record IT's position now, since line_bottom_y might
+            change that.  */
+         it_charpos = IT_CHARPOS (it);
+         /* Make sure we set the force_start flag only if the cursor
+            row will be fully visible.  Otherwise, the code under
+            force_start label below will try to move point back into
+            view, which is not what the code which sets
+            optional_new_start wants.  */
+         if (it.current_y == 0 || line_bottom_y (&it) < it.last_visible_y)
+           {
+             if (it_charpos == PT)
+               w->force_start = true;
+             /* IT may overshoot PT if text at PT is invisible.  */
+             else if (it_charpos > PT && CHARPOS (startp) <= PT)
+               w->force_start = true;
 #ifdef GLYPH_DEBUG
-         if (w->force_start)
-           {
-             if (window_frozen_p (w))
-               debug_method_add (w, "set force_start from frozen window 
start");
-             else
-               debug_method_add (w, "set force_start from optional_new_start");
-           }
+             if (w->force_start)
+               {
+                 if (window_frozen_p (w))
+                   debug_method_add (w, "set force_start from frozen window 
start");
+                 else
+                   debug_method_add (w, "set force_start from 
optional_new_start");
+               }
 #endif
+           }
        }
     }
 
@@ -20064,11 +20552,19 @@ redisplay_window (Lisp_Object window, bool 
just_this_one_p)
    buffer position POS.
 
    Value is 1 if successful.  It is zero if fonts were loaded during
-   redisplay which makes re-adjusting glyph matrices necessary, and -1
-   if point would appear in the scroll margins.
-   (We check the former only if TRY_WINDOW_IGNORE_FONTS_CHANGE is
-   unset in FLAGS, and the latter only if TRY_WINDOW_CHECK_MARGINS is
-   set in FLAGS.)  */
+   redisplay or the dimensions of the desired matrix were found
+   insufficient, which makes re-adjusting glyph matrices necessary.
+   Value is -1 if point would appear in the scroll margins.  (We check
+   the former only if TRY_WINDOW_IGNORE_FONTS_CHANGE is unset in
+   FLAGS, and the latter only if TRY_WINDOW_CHECK_MARGINS is set in
+   FLAGS.)
+
+   Note that 'x-show-tip' invokes this function in a special way, and
+   in that case the return value of zero doesn't necessarily mean the
+   glyph matrices need to be re-adjusted, if the entire text of the
+   tooltip was processed and has its glyphs in the matrix's glyph
+   rows, i.e. if the dimensions of the matrix were found insufficient
+   while producing empty glyph rows beyond ZV.  */
 
 int
 try_window (Lisp_Object window, struct text_pos pos, int flags)
@@ -20093,9 +20589,16 @@ try_window (Lisp_Object window, struct text_pos pos, 
int flags)
   /* Display all lines of W.  */
   while (it.current_y < it.last_visible_y)
     {
+      int last_row_scale = it.w->nrows_scale_factor;
+      int last_col_scale = it.w->ncols_scale_factor;
       if (display_line (&it, cursor_vpos))
        last_text_row = it.glyph_row - 1;
-      if (f->fonts_changed && !(flags & TRY_WINDOW_IGNORE_FONTS_CHANGE))
+      if (f->fonts_changed
+         && !((flags & TRY_WINDOW_IGNORE_FONTS_CHANGE)
+              /* If the matrix dimensions are insufficient, we _must_
+                 fail and let dispnew.c reallocate the matrix.  */
+              && last_row_scale == it.w->nrows_scale_factor
+              && last_col_scale == it.w->ncols_scale_factor))
        return 0;
     }
 
@@ -21082,6 +21585,12 @@ try_window_id (struct window *w)
                                                w->frame))))
     GIVE_UP (24);
 
+  /* composition-break-at-point is incompatible with the optimizations
+     in this function, because we need to recompose characters when
+     point moves off their positions.  */
+  if (composition_break_at_point)
+    GIVE_UP (27);
+
   /* Make sure beg_unchanged and end_unchanged are up to date.  Do it
      only if buffer has really changed.  The reason is that the gap is
      initially at Z for freshly visited files.  The code below would
@@ -24067,7 +24576,7 @@ display_line (struct it *it, int cursor_vpos)
   row->displays_text_p = true;
   row->starts_in_middle_of_char_p = it->starts_in_middle_of_char_p;
   it->starts_in_middle_of_char_p = false;
-  it->tab_offset = 0;
+  it->stretch_adjust = 0;
   it->line_number_produced_p = false;
 
   /* Arrange the overlays nicely for our purposes.  Usually, we call
@@ -24100,8 +24609,26 @@ display_line (struct it *it, int cursor_vpos)
          it->first_visible_x += x_incr;
          it->last_visible_x  += x_incr;
        }
-      move_result = move_it_in_display_line_to (it, ZV, it->first_visible_x,
-                                               MOVE_TO_POS | MOVE_TO_X);
+      if (current_buffer->long_line_optimizations_p
+         && it->line_wrap == TRUNCATE
+         && window_hscroll_limited (it->w, it->f) > large_hscroll_threshold)
+       {
+         /* Special optimization for very long and truncated lines
+            which are hscrolled far to the left: jump directly to the
+            (approximate) position that is visible, instead of slowly
+            walking there.  */
+         ptrdiff_t chars_to_skip =
+           it->first_visible_x / FRAME_COLUMN_WIDTH (it->f);
+         move_result = fast_move_it_horizontally (it, chars_to_skip);
+
+         if (move_result == MOVE_X_REACHED)
+           it->current_x = it->first_visible_x;
+         else  /* use arbitrary value < first_visible_x */
+           it->current_x = it->first_visible_x - FRAME_COLUMN_WIDTH (it->f);
+       }
+      else
+       move_result = move_it_in_display_line_to (it, ZV, it->first_visible_x,
+                                                 MOVE_TO_POS | MOVE_TO_X);
       /* If we are under a large hscroll, move_it_in_display_line_to
         could hit the end of the line without reaching
         first_visible_x.  Pretend that we did reach it.  This is
@@ -26394,8 +26921,8 @@ display_mode_element (struct it *it, int depth, int 
field_width, int precision,
                    tem = props;
                    while (CONSP (tem))
                      {
-                       oprops = Fplist_put (oprops, XCAR (tem),
-                                            XCAR (XCDR (tem)));
+                       oprops = plist_put (oprops, XCAR (tem),
+                                           XCAR (XCDR (tem)));
                        tem = XCDR (XCDR (tem));
                      }
                    props = oprops;
@@ -26846,13 +27373,13 @@ store_mode_line_string (const char *string, 
Lisp_Object lisp_string,
        props = mode_line_string_face_prop;
       else if (!NILP (mode_line_string_face))
        {
-         Lisp_Object face = Fplist_get (props, Qface);
+         Lisp_Object face = plist_get (props, Qface);
          props = Fcopy_sequence (props);
          if (NILP (face))
            face = mode_line_string_face;
          else
            face = list2 (face, mode_line_string_face);
-         props = Fplist_put (props, Qface, face);
+         props = plist_put (props, Qface, face);
        }
       Fadd_text_properties (make_fixnum (0), make_fixnum (len),
                            props, lisp_string);
@@ -26871,7 +27398,7 @@ store_mode_line_string (const char *string, Lisp_Object 
lisp_string,
          Lisp_Object face;
          if (NILP (props))
            props = Ftext_properties_at (make_fixnum (0), lisp_string);
-         face = Fplist_get (props, Qface);
+         face = plist_get (props, Qface);
          if (NILP (face))
            face = mode_line_string_face;
          else
@@ -27921,7 +28448,7 @@ display_string (const char *string, Lisp_Object 
lisp_string, Lisp_Object face_st
                                                    face_string);
          if (!NILP (display))
            {
-             Lisp_Object min_width = Fplist_get (display, Qmin_width);
+             Lisp_Object min_width = plist_get (display, Qmin_width);
              if (!NILP (min_width))
                display_min_width (it, 0, face_string, min_width);
            }
@@ -28255,6 +28782,11 @@ static bool
 calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop,
                            struct font *font, bool width_p, int *align_to)
 {
+  /* Don't adjust for line number if we didn't yet produce it for this
+     screen line.  This is for when this function is called from
+     move_it_in_display_line_to that was called by display_line to get
+     past the glyphs hscrolled off the left side of the window.  */
+  int lnum_pixel_width = it->line_number_produced_p ? it->lnum_pixel_width : 0;
   double pixels;
 
 # define OK_PIXELS(val) (*res = (val), true)
@@ -28311,7 +28843,7 @@ calc_pixel_width_or_height (double *res, struct it *it, 
Lisp_Object prop,
       if (EQ (prop, Qtext))
          return OK_PIXELS (width_p
                            ? (window_box_width (it->w, TEXT_AREA)
-                              - it->lnum_pixel_width)
+                              - lnum_pixel_width)
                            : WINDOW_BOX_HEIGHT_NO_MODE_LINE (it->w));
 
       /* ':align_to'.  First time we compute the value, window
@@ -28323,14 +28855,14 @@ calc_pixel_width_or_height (double *res, struct it 
*it, Lisp_Object prop,
          /* 'left': left edge of the text area.  */
          if (EQ (prop, Qleft))
            return OK_ALIGN_TO (window_box_left_offset (it->w, TEXT_AREA)
-                               + it->lnum_pixel_width);
+                               + lnum_pixel_width);
          /* 'right': right edge of the text area.  */
          if (EQ (prop, Qright))
            return OK_ALIGN_TO (window_box_right_offset (it->w, TEXT_AREA));
          /* 'center': the center of the text area.  */
          if (EQ (prop, Qcenter))
            return OK_ALIGN_TO (window_box_left_offset (it->w, TEXT_AREA)
-                               + it->lnum_pixel_width
+                               + lnum_pixel_width
                                + window_box_width (it->w, TEXT_AREA) / 2);
          /* 'left-fringe': left edge of the left fringe.  */
          if (EQ (prop, Qleft_fringe))
@@ -28383,7 +28915,7 @@ calc_pixel_width_or_height (double *res, struct it *it, 
Lisp_Object prop,
                       ? FRAME_COLUMN_WIDTH (it->f)
                       : FRAME_LINE_HEIGHT (it->f));
       if (width_p && align_to && *align_to < 0)
-       return OK_PIXELS (XFLOATINT (prop) * base_unit + it->lnum_pixel_width);
+       return OK_PIXELS (XFLOATINT (prop) * base_unit + lnum_pixel_width);
       return OK_PIXELS (XFLOATINT (prop) * base_unit);
     }
 
@@ -28445,7 +28977,7 @@ calc_pixel_width_or_height (double *res, struct it *it, 
Lisp_Object prop,
        {
          double fact;
          int offset =
-           width_p && align_to && *align_to < 0 ? it->lnum_pixel_width : 0;
+           width_p && align_to && *align_to < 0 ? lnum_pixel_width : 0;
          pixels = XFLOATINT (car);
          if (NILP (cdr))
            return OK_PIXELS (pixels + offset);
@@ -30614,14 +31146,14 @@ produce_stretch_glyph (struct it *it)
   plist = XCDR (it->object);
 
   /* Compute the width of the stretch.  */
-  if ((prop = Fplist_get (plist, QCwidth), !NILP (prop))
+  if ((prop = plist_get (plist, QCwidth), !NILP (prop))
       && calc_pixel_width_or_height (&tem, it, prop, font, true, NULL))
     {
       /* Absolute width `:width WIDTH' specified and valid.  */
       zero_width_ok_p = true;
       width = (int)tem;
     }
-  else if (prop = Fplist_get (plist, QCrelative_width), NUMVAL (prop) > 0)
+  else if (prop = plist_get (plist, QCrelative_width), NUMVAL (prop) > 0)
     {
       /* Relative width `:relative-width FACTOR' specified and valid.
         Compute the width of the characters having this `display'
@@ -30658,17 +31190,43 @@ produce_stretch_glyph (struct it *it)
       PRODUCE_GLYPHS (&it2);
       width = NUMVAL (prop) * it2.pixel_width;
     }
-  else if ((prop = Fplist_get (plist, QCalign_to), !NILP (prop))
+  else if ((prop = plist_get (plist, QCalign_to), !NILP (prop))
           && calc_pixel_width_or_height (&tem, it, prop, font, true,
                                          &align_to))
     {
+      int x = it->current_x + it->continuation_lines_width;
+      int x0 = x;
+      /* Adjust for line numbers, if needed.   */
+      if (!NILP (Vdisplay_line_numbers) && it->line_number_produced_p)
+       {
+         x -= it->lnum_pixel_width;
+         /* Restore the original width, if required.  */
+         if (x + it->stretch_adjust >= it->first_visible_x)
+           x += it->stretch_adjust;
+       }
+
       if (it->glyph_row == NULL || !it->glyph_row->mode_line_p)
        align_to = (align_to < 0
                    ? 0
                    : align_to - window_box_left_offset (it->w, TEXT_AREA));
       else if (align_to < 0)
        align_to = window_box_left_offset (it->w, TEXT_AREA);
-      width = max (0, (int)tem + align_to - it->current_x);
+      width = max (0, (int)tem + align_to - x);
+
+      int next_x = x + width;
+      if (!NILP (Vdisplay_line_numbers) && it->line_number_produced_p)
+       {
+         /* If the line is hscrolled, and the stretch starts before
+            the first visible pixel, simulate negative row->x.  */
+         if (x < it->first_visible_x)
+           {
+             next_x -= it->first_visible_x - x;
+             it->stretch_adjust = it->first_visible_x - x;
+           }
+         else
+           next_x -= it->stretch_adjust;
+       }
+      width = next_x - x0;
       zero_width_ok_p = true;
     }
   else
@@ -30684,13 +31242,13 @@ produce_stretch_glyph (struct it *it)
     {
       int default_height = normal_char_height (font, ' ');
 
-      if ((prop = Fplist_get (plist, QCheight), !NILP (prop))
+      if ((prop = plist_get (plist, QCheight), !NILP (prop))
          && calc_pixel_width_or_height (&tem, it, prop, font, false, NULL))
        {
          height = (int)tem;
          zero_height_ok_p = true;
        }
-      else if (prop = Fplist_get (plist, QCrelative_height),
+      else if (prop = plist_get (plist, QCrelative_height),
               NUMVAL (prop) > 0)
        height = default_height * NUMVAL (prop);
       else
@@ -30702,7 +31260,7 @@ produce_stretch_glyph (struct it *it)
       /* Compute percentage of height used for ascent.  If
         `:ascent ASCENT' is present and valid, use that.  Otherwise,
         derive the ascent from the font in use.  */
-      if (prop = Fplist_get (plist, QCascent),
+      if (prop = plist_get (plist, QCascent),
           NUMVAL (prop) > 0 && NUMVAL (prop) <= 100)
        ascent = height * NUMVAL (prop) / 100.0;
       else if (!NILP (prop)
@@ -31458,8 +32016,8 @@ gui_produce_glyphs (struct it *it)
                {
                  x -= it->lnum_pixel_width;
                  /* Restore the original TAB width, if required.  */
-                 if (x + it->tab_offset >= it->first_visible_x)
-                   x += it->tab_offset;
+                 if (x + it->stretch_adjust >= it->first_visible_x)
+                   x += it->stretch_adjust;
                }
 
              int next_tab_x = ((1 + x + tab_width - 1) / tab_width) * 
tab_width;
@@ -31477,10 +32035,10 @@ gui_produce_glyphs (struct it *it)
                  if (x < it->first_visible_x)
                    {
                      next_tab_x -= it->first_visible_x - x;
-                     it->tab_offset = it->first_visible_x - x;
+                     it->stretch_adjust = it->first_visible_x - x;
                    }
                  else
-                   next_tab_x -= it->tab_offset;
+                   next_tab_x -= it->stretch_adjust;
                }
 
              it->pixel_width = next_tab_x - x0;
@@ -34049,7 +34607,7 @@ note_mode_line_or_margin_highlight (Lisp_Object window, 
int x, int y,
   if (IMAGEP (object))
     {
       Lisp_Object image_map, hotspot;
-      if ((image_map = Fplist_get (XCDR (object), QCmap),
+      if ((image_map = plist_get (XCDR (object), QCmap),
           !NILP (image_map))
          && (hotspot = find_hot_spot (image_map, dx, dy),
              CONSP (hotspot))
@@ -34064,10 +34622,10 @@ note_mode_line_or_margin_highlight (Lisp_Object 
window, int x, int y,
          if (CONSP (hotspot)
              && (plist = XCAR (hotspot), CONSP (plist)))
            {
-             pointer = Fplist_get (plist, Qpointer);
+             pointer = plist_get (plist, Qpointer);
              if (NILP (pointer))
                pointer = Qhand;
-             help = Fplist_get (plist, Qhelp_echo);
+             help = plist_get (plist, Qhelp_echo);
              if (!NILP (help))
                {
                  help_echo_string = help;
@@ -34078,7 +34636,7 @@ note_mode_line_or_margin_highlight (Lisp_Object window, 
int x, int y,
            }
        }
       if (NILP (pointer))
-       pointer = Fplist_get (XCDR (object), QCpointer);
+       pointer = plist_get (XCDR (object), QCpointer);
     }
 #endif /* HAVE_WINDOW_SYSTEM */
 
@@ -34564,7 +35122,7 @@ note_mouse_highlight (struct frame *f, int x, int y)
          if (img != NULL && IMAGEP (img->spec))
            {
              Lisp_Object image_map, hotspot;
-             if ((image_map = Fplist_get (XCDR (img->spec), QCmap),
+             if ((image_map = plist_get (XCDR (img->spec), QCmap),
                   !NILP (image_map))
                  && (hotspot = find_hot_spot (image_map,
                                               glyph->slice.img.x + dx,
@@ -34582,10 +35140,10 @@ note_mouse_highlight (struct frame *f, int x, int y)
                  if (CONSP (hotspot)
                      && (plist = XCAR (hotspot), CONSP (plist)))
                    {
-                     pointer = Fplist_get (plist, Qpointer);
+                     pointer = plist_get (plist, Qpointer);
                      if (NILP (pointer))
                        pointer = Qhand;
-                     help_echo_string = Fplist_get (plist, Qhelp_echo);
+                     help_echo_string = plist_get (plist, Qhelp_echo);
                      if (!NILP (help_echo_string))
                        {
                          help_echo_window = window;
@@ -34595,7 +35153,7 @@ note_mouse_highlight (struct frame *f, int x, int y)
                    }
                }
              if (NILP (pointer))
-               pointer = Fplist_get (XCDR (img->spec), QCpointer);
+               pointer = plist_get (XCDR (img->spec), QCpointer);
            }
        }
 #endif /* HAVE_WINDOW_SYSTEM */
@@ -35674,12 +36232,12 @@ be let-bound around code that needs to disable 
messages temporarily. */);
   defsubr (&Sbidi_find_overridden_directionality);
   defsubr (&Sdisplay__line_is_continued_p);
   defsubr (&Sget_display_property);
+  defsubr (&Slong_line_optimizations_p);
 
   DEFSYM (Qmenu_bar_update_hook, "menu-bar-update-hook");
   DEFSYM (Qoverriding_terminal_local_map, "overriding-terminal-local-map");
   DEFSYM (Qoverriding_local_map, "overriding-local-map");
   DEFSYM (Qwindow_scroll_functions, "window-scroll-functions");
-  DEFSYM (Qredisplay_end_trigger_functions, "redisplay-end-trigger-functions");
   DEFSYM (Qinhibit_point_motion_hooks, "inhibit-point-motion-hooks");
   DEFSYM (Qeval, "eval");
   DEFSYM (QCdata, ":data");
@@ -35777,7 +36335,7 @@ be let-bound around code that needs to disable messages 
temporarily. */);
 
   DEFSYM (Qinhibit_free_realized_faces, "inhibit-free-realized-faces");
 
-  list_of_error = list1 (list2 (Qerror, Qvoid_variable));
+  list_of_error = list1 (Qerror);
   staticpro (&list_of_error);
 
   /* Values of those variables at last redisplay are stored as
@@ -36083,12 +36641,6 @@ is scrolled.  It is not designed for that, and such 
use probably won't
 work.  */);
   Vwindow_scroll_functions = Qnil;
 
-  DEFVAR_LISP ("redisplay-end-trigger-functions", 
Vredisplay_end_trigger_functions,
-    doc: /* Functions called when redisplay of a window reaches the end 
trigger.
-Each function is called with two arguments, the window and the end trigger 
value.
-See `set-window-redisplay-end-trigger'.  */);
-  Vredisplay_end_trigger_functions = Qnil;
-
   DEFVAR_LISP ("mouse-autoselect-window", Vmouse_autoselect_window,
      doc: /* Non-nil means autoselect window with mouse pointer.
 If nil, do not autoselect windows.
@@ -36217,7 +36769,13 @@ The tool bar style must also show labels for this to 
have any effect, see
     doc: /* List of functions to call to fontify regions of text.
 Each function is called with one argument POS.  Functions must
 fontify a region starting at POS in the current buffer, and give
-fontified regions the property `fontified'.  */);
+fontified regions the property `fontified' with a non-nil value.
+
+Note that, when the buffer contains one or more lines whose length is
+above `long-line-threshold', these functions are called with the buffer
+narrowed to a small portion around POS, and the narrowing is locked (see
+`narrow-to-region'), so that these functions cannot use `widen' to gain
+access to other portions of buffer text.  */);
   Vfontification_functions = Qnil;
   Fmake_variable_buffer_local (Qfontification_functions);
 
@@ -36558,7 +37116,9 @@ GRAPHICAL and TEXT should each have one of the values 
listed above.
 The char-table has one extra slot to control the display of a character for
 which no font is found.  This slot only takes effect on graphical terminals.
 Its value should be an ASCII acronym string, `hex-code', `empty-box', or
-`thin-space'.  The default is `empty-box'.
+`thin-space'.  It could also be a cons cell of any two of these, to specify
+separate values for graphical and text terminals.
+The default is `empty-box'.
 
 If a character has a non-nil entry in an active display table, the
 display table takes effect; in this case, Emacs does not consult
@@ -36667,6 +37227,22 @@ and display the most important part of the minibuffer. 
  */);
 This makes it easier to edit character sequences that are
 composed on display.  */);
   composition_break_at_point = false;
+
+  DEFVAR_INT ("max-redisplay-ticks", max_redisplay_ticks,
+    doc: /* Maximum number of redisplay ticks before aborting redisplay of a 
window.
+
+This allows to abort the display of a window if the amount of low-level
+redisplay operations exceeds the value of this variable.  When display of
+a window is aborted due to this reason, the buffer shown in that window
+will not have its windows redisplayed until the buffer is modified or until
+you type \\[recenter-top-bottom] with one of its windows selected.
+You can also decide to kill the buffer and visit it in some
+other way, like under `so-long-mode' or literally.
+
+The default value is zero, which disables this feature.
+The recommended non-zero value is between 100000 and 1000000,
+depending on your patience and the speed of your system.  */);
+  max_redisplay_ticks = 0;
 }
 
 
diff --git a/src/xfaces.c b/src/xfaces.c
index 7395ce157e..70d5cbeb4c 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -295,6 +295,10 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 
 #define IGNORE_DEFFACE_P(ATTR) EQ ((ATTR), QCignore_defface)
 
+/* True if face attribute ATTR is `reset'.  */
+
+#define RESET_P(ATTR) EQ ((ATTR), Qreset)
+
 /* Size of hash table of realized faces in face caches (should be a
    prime number).  */
 
@@ -961,7 +965,7 @@ DEFUN ("color-values-from-color-spec",
        Scolor_values_from_color_spec,
        1, 1, 0,
        doc: /* Parse color SPEC as a numeric color and return (RED GREEN BLUE).
-This function recognises the following formats for SPEC:
+This function recognizes the following formats for SPEC:
 
  #RGB, where R, G and B are hex numbers of equal length, 1-4 digits each.
  rgb:R/G/B, where R, G, and B are hex numbers, 1-4 digits each.
@@ -1584,8 +1588,9 @@ the face font sort order, see 
`face-font-selection-order'.  */)
                              /* If the font was specified in a way
                                 different from XLFD (e.g., on MS-Windows),
                                 we will have a number there, not 'p'.  */
-                             || EQ (spacing,
-                                    make_fixnum (FONT_SPACING_PROPORTIONAL)))
+                             || BASE_EQ (spacing,
+                                         make_fixnum
+                                         (FONT_SPACING_PROPORTIONAL)))
                             ? Qnil : Qt,
                             Ffont_xlfd_name (font, Qnil),
                             AREF (font, FONT_REGISTRY_INDEX));
@@ -1756,57 +1761,72 @@ check_lface_attrs (Lisp_Object attrs[LFACE_VECTOR_SIZE])
 {
   eassert (UNSPECIFIEDP (attrs[LFACE_FAMILY_INDEX])
           || IGNORE_DEFFACE_P (attrs[LFACE_FAMILY_INDEX])
+          || RESET_P (attrs[LFACE_FAMILY_INDEX])
           || STRINGP (attrs[LFACE_FAMILY_INDEX]));
   eassert (UNSPECIFIEDP (attrs[LFACE_FOUNDRY_INDEX])
           || IGNORE_DEFFACE_P (attrs[LFACE_FOUNDRY_INDEX])
+          || RESET_P (attrs[LFACE_FOUNDRY_INDEX])
           || STRINGP (attrs[LFACE_FOUNDRY_INDEX]));
   eassert (UNSPECIFIEDP (attrs[LFACE_SWIDTH_INDEX])
           || IGNORE_DEFFACE_P (attrs[LFACE_SWIDTH_INDEX])
+          || RESET_P (attrs[LFACE_SWIDTH_INDEX])
           || SYMBOLP (attrs[LFACE_SWIDTH_INDEX]));
   eassert (UNSPECIFIEDP (attrs[LFACE_HEIGHT_INDEX])
           || IGNORE_DEFFACE_P (attrs[LFACE_HEIGHT_INDEX])
+          || RESET_P (attrs[LFACE_HEIGHT_INDEX])
           || NUMBERP (attrs[LFACE_HEIGHT_INDEX])
           || FUNCTIONP (attrs[LFACE_HEIGHT_INDEX]));
   eassert (UNSPECIFIEDP (attrs[LFACE_WEIGHT_INDEX])
           || IGNORE_DEFFACE_P (attrs[LFACE_WEIGHT_INDEX])
+          || RESET_P (attrs[LFACE_WEIGHT_INDEX])
           || SYMBOLP (attrs[LFACE_WEIGHT_INDEX]));
   eassert (UNSPECIFIEDP (attrs[LFACE_SLANT_INDEX])
           || IGNORE_DEFFACE_P (attrs[LFACE_SLANT_INDEX])
+          || RESET_P (attrs[LFACE_SLANT_INDEX])
           || SYMBOLP (attrs[LFACE_SLANT_INDEX]));
   eassert (UNSPECIFIEDP (attrs[LFACE_UNDERLINE_INDEX])
           || IGNORE_DEFFACE_P (attrs[LFACE_UNDERLINE_INDEX])
+          || RESET_P (attrs[LFACE_UNDERLINE_INDEX])
           || SYMBOLP (attrs[LFACE_UNDERLINE_INDEX])
           || STRINGP (attrs[LFACE_UNDERLINE_INDEX])
           || CONSP (attrs[LFACE_UNDERLINE_INDEX]));
   eassert (UNSPECIFIEDP (attrs[LFACE_EXTEND_INDEX])
           || IGNORE_DEFFACE_P (attrs[LFACE_EXTEND_INDEX])
+          || RESET_P (attrs[LFACE_EXTEND_INDEX])
           || SYMBOLP (attrs[LFACE_EXTEND_INDEX])
           || STRINGP (attrs[LFACE_EXTEND_INDEX]));
   eassert (UNSPECIFIEDP (attrs[LFACE_OVERLINE_INDEX])
           || IGNORE_DEFFACE_P (attrs[LFACE_OVERLINE_INDEX])
+          || RESET_P (attrs[LFACE_OVERLINE_INDEX])
           || SYMBOLP (attrs[LFACE_OVERLINE_INDEX])
           || STRINGP (attrs[LFACE_OVERLINE_INDEX]));
   eassert (UNSPECIFIEDP (attrs[LFACE_STRIKE_THROUGH_INDEX])
           || IGNORE_DEFFACE_P (attrs[LFACE_STRIKE_THROUGH_INDEX])
+          || RESET_P (attrs[LFACE_STRIKE_THROUGH_INDEX])
           || SYMBOLP (attrs[LFACE_STRIKE_THROUGH_INDEX])
           || STRINGP (attrs[LFACE_STRIKE_THROUGH_INDEX]));
   eassert (UNSPECIFIEDP (attrs[LFACE_BOX_INDEX])
           || IGNORE_DEFFACE_P (attrs[LFACE_BOX_INDEX])
+          || RESET_P (attrs[LFACE_BOX_INDEX])
           || SYMBOLP (attrs[LFACE_BOX_INDEX])
           || STRINGP (attrs[LFACE_BOX_INDEX])
           || FIXNUMP (attrs[LFACE_BOX_INDEX])
           || CONSP (attrs[LFACE_BOX_INDEX]));
   eassert (UNSPECIFIEDP (attrs[LFACE_INVERSE_INDEX])
           || IGNORE_DEFFACE_P (attrs[LFACE_INVERSE_INDEX])
+          || RESET_P (attrs[LFACE_INVERSE_INDEX])
           || SYMBOLP (attrs[LFACE_INVERSE_INDEX]));
   eassert (UNSPECIFIEDP (attrs[LFACE_FOREGROUND_INDEX])
           || IGNORE_DEFFACE_P (attrs[LFACE_FOREGROUND_INDEX])
+          || RESET_P (attrs[LFACE_FOREGROUND_INDEX])
           || STRINGP (attrs[LFACE_FOREGROUND_INDEX]));
   eassert (UNSPECIFIEDP (attrs[LFACE_DISTANT_FOREGROUND_INDEX])
           || IGNORE_DEFFACE_P (attrs[LFACE_DISTANT_FOREGROUND_INDEX])
+          || RESET_P (attrs[LFACE_DISTANT_FOREGROUND_INDEX])
           || STRINGP (attrs[LFACE_DISTANT_FOREGROUND_INDEX]));
   eassert (UNSPECIFIEDP (attrs[LFACE_BACKGROUND_INDEX])
           || IGNORE_DEFFACE_P (attrs[LFACE_BACKGROUND_INDEX])
+          || RESET_P (attrs[LFACE_BACKGROUND_INDEX])
           || STRINGP (attrs[LFACE_BACKGROUND_INDEX]));
   eassert (UNSPECIFIEDP (attrs[LFACE_INHERIT_INDEX])
           || IGNORE_DEFFACE_P (attrs[LFACE_INHERIT_INDEX])
@@ -1816,13 +1836,16 @@ check_lface_attrs (Lisp_Object attrs[LFACE_VECTOR_SIZE])
 #ifdef HAVE_WINDOW_SYSTEM
   eassert (UNSPECIFIEDP (attrs[LFACE_STIPPLE_INDEX])
           || IGNORE_DEFFACE_P (attrs[LFACE_STIPPLE_INDEX])
+          || RESET_P (attrs[LFACE_STIPPLE_INDEX])
           || SYMBOLP (attrs[LFACE_STIPPLE_INDEX])
           || !NILP (Fbitmap_spec_p (attrs[LFACE_STIPPLE_INDEX])));
   eassert (UNSPECIFIEDP (attrs[LFACE_FONT_INDEX])
           || IGNORE_DEFFACE_P (attrs[LFACE_FONT_INDEX])
+          || RESET_P (attrs[LFACE_FONT_INDEX])
           || FONTP (attrs[LFACE_FONT_INDEX]));
   eassert (UNSPECIFIEDP (attrs[LFACE_FONTSET_INDEX])
           || STRINGP (attrs[LFACE_FONTSET_INDEX])
+          || RESET_P (attrs[LFACE_FONTSET_INDEX])
           || NILP (attrs[LFACE_FONTSET_INDEX]));
 #endif
 }
@@ -1942,7 +1965,7 @@ resolve_face_name (Lisp_Object face_name, bool signal_p)
        break;
 
       tortoise = Fget (tortoise, Qface_alias);
-      if (EQ (hare, tortoise))
+      if (BASE_EQ (hare, tortoise))
        {
          if (signal_p)
            circular_list (orig_face);
@@ -2082,7 +2105,7 @@ lface_fully_specified_p (Lisp_Object 
attrs[LFACE_VECTOR_SIZE])
 #ifdef HAVE_WINDOW_SYSTEM
 
 /* Set font-related attributes of Lisp face LFACE from FONT-OBJECT.
-   If FORCE_P, set only unspecified attributes of LFACE.  The
+   If FORCE_P is zero, set only unspecified attributes of LFACE.  The
    exception is `font' attribute.  It is set to FONT_OBJECT regardless
    of FORCE_P.  */
 
@@ -2338,6 +2361,14 @@ merge_named_face (struct window *w,
       Lisp_Object from[LFACE_VECTOR_SIZE], val;
       bool ok = get_lface_attributes (w, f, face_name, from, false,
                                       named_merge_points);
+      if (ok && !EQ (face_name, Qdefault))
+       {
+         struct face *deflt = FACE_FROM_ID (f, DEFAULT_FACE_ID);
+         int i;
+         for (i = 1; i < LFACE_VECTOR_SIZE; i++)
+           if (EQ (from[i], Qreset))
+             from[i] = deflt->lface[i];
+       }
 
       if (ok && (attr_filter == 0             /* No filter.  */
                  || (!NILP (from[attr_filter]) /* Filter, but specified.  */
@@ -3086,7 +3117,9 @@ FRAME 0 means change the face on all frames, and change 
the default
 
   if (EQ (attr, QCfamily))
     {
-      if (!UNSPECIFIEDP (value) && !IGNORE_DEFFACE_P (value))
+      if (!UNSPECIFIEDP (value)
+         && !IGNORE_DEFFACE_P (value)
+         && !RESET_P (value))
        {
          CHECK_STRING (value);
          if (SCHARS (value) == 0)
@@ -3098,7 +3131,9 @@ FRAME 0 means change the face on all frames, and change 
the default
     }
   else if (EQ (attr, QCfoundry))
     {
-      if (!UNSPECIFIEDP (value) && !IGNORE_DEFFACE_P (value))
+      if (!UNSPECIFIEDP (value)
+         && !IGNORE_DEFFACE_P (value)
+         && !RESET_P (value))
        {
          CHECK_STRING (value);
          if (SCHARS (value) == 0)
@@ -3110,7 +3145,9 @@ FRAME 0 means change the face on all frames, and change 
the default
     }
   else if (EQ (attr, QCheight))
     {
-      if (!UNSPECIFIEDP (value) && !IGNORE_DEFFACE_P (value))
+      if (!UNSPECIFIEDP (value)
+         && !IGNORE_DEFFACE_P (value)
+         && !RESET_P (value))
        {
          if (EQ (face, Qdefault))
            {
@@ -3138,7 +3175,9 @@ FRAME 0 means change the face on all frames, and change 
the default
     }
   else if (EQ (attr, QCweight))
     {
-      if (!UNSPECIFIEDP (value) && !IGNORE_DEFFACE_P (value))
+      if (!UNSPECIFIEDP (value)
+         && !IGNORE_DEFFACE_P (value)
+         && !RESET_P (value))
        {
          CHECK_SYMBOL (value);
          if (FONT_WEIGHT_NAME_NUMERIC (value) < 0)
@@ -3150,7 +3189,9 @@ FRAME 0 means change the face on all frames, and change 
the default
     }
   else if (EQ (attr, QCslant))
     {
-      if (!UNSPECIFIEDP (value) && !IGNORE_DEFFACE_P (value))
+      if (!UNSPECIFIEDP (value)
+         && !IGNORE_DEFFACE_P (value)
+         && !RESET_P (value))
        {
          CHECK_SYMBOL (value);
          if (FONT_SLANT_NAME_NUMERIC (value) < 0)
@@ -3164,7 +3205,7 @@ FRAME 0 means change the face on all frames, and change 
the default
     {
       bool valid_p = false;
 
-      if (UNSPECIFIEDP (value) || IGNORE_DEFFACE_P (value))
+      if (UNSPECIFIEDP (value) || IGNORE_DEFFACE_P (value) || RESET_P (value))
        valid_p = true;
       else if (NILP (value) || EQ (value, Qt))
         valid_p = true;
@@ -3222,7 +3263,9 @@ FRAME 0 means change the face on all frames, and change 
the default
     }
   else if (EQ (attr, QCoverline))
     {
-      if (!UNSPECIFIEDP (value) && !IGNORE_DEFFACE_P (value))
+      if (!UNSPECIFIEDP (value)
+         && !IGNORE_DEFFACE_P (value)
+         && !RESET_P (value))
        if ((SYMBOLP (value)
             && !EQ (value, Qt)
             && !NILP (value))
@@ -3236,7 +3279,9 @@ FRAME 0 means change the face on all frames, and change 
the default
     }
   else if (EQ (attr, QCstrike_through))
     {
-      if (!UNSPECIFIEDP (value) && !IGNORE_DEFFACE_P (value))
+      if (!UNSPECIFIEDP (value)
+         && !IGNORE_DEFFACE_P (value)
+         && !RESET_P (value))
        if ((SYMBOLP (value)
             && !EQ (value, Qt)
             && !NILP (value))
@@ -3257,7 +3302,7 @@ FRAME 0 means change the face on all frames, and change 
the default
       if (EQ (value, Qt))
        value = make_fixnum (1);
 
-      if (UNSPECIFIEDP (value) || IGNORE_DEFFACE_P (value))
+      if (UNSPECIFIEDP (value) || IGNORE_DEFFACE_P (value) || RESET_P (value))
        valid_p = true;
       else if (NILP (value))
        valid_p = true;
@@ -3319,7 +3364,9 @@ FRAME 0 means change the face on all frames, and change 
the default
   else if (EQ (attr, QCinverse_video)
           || EQ (attr, QCreverse_video))
     {
-      if (!UNSPECIFIEDP (value) && !IGNORE_DEFFACE_P (value))
+      if (!UNSPECIFIEDP (value)
+         && !IGNORE_DEFFACE_P (value)
+         && !RESET_P (value))
        {
          CHECK_SYMBOL (value);
          if (!EQ (value, Qt) && !NILP (value))
@@ -3330,7 +3377,9 @@ FRAME 0 means change the face on all frames, and change 
the default
     }
   else if (EQ (attr, QCextend))
     {
-      if (!UNSPECIFIEDP (value) && !IGNORE_DEFFACE_P (value))
+      if (!UNSPECIFIEDP (value)
+         && !IGNORE_DEFFACE_P (value)
+         && !RESET_P (value))
        {
          CHECK_SYMBOL (value);
          if (!EQ (value, Qt) && !NILP (value))
@@ -3344,7 +3393,9 @@ FRAME 0 means change the face on all frames, and change 
the default
       /* Compatibility with 20.x.  */
       if (NILP (value))
        value = Qunspecified;
-      if (!UNSPECIFIEDP (value) && !IGNORE_DEFFACE_P (value))
+      if (!UNSPECIFIEDP (value)
+         && !IGNORE_DEFFACE_P (value)
+         && !RESET_P (value))
        {
          /* Don't check for valid color names here because it depends
             on the frame (display) whether the color will be valid
@@ -3361,7 +3412,9 @@ FRAME 0 means change the face on all frames, and change 
the default
       /* Compatibility with 20.x.  */
       if (NILP (value))
        value = Qunspecified;
-      if (!UNSPECIFIEDP (value) && !IGNORE_DEFFACE_P (value))
+      if (!UNSPECIFIEDP (value)
+         && !IGNORE_DEFFACE_P (value)
+         && !RESET_P (value))
        {
          /* Don't check for valid color names here because it depends
             on the frame (display) whether the color will be valid
@@ -3378,7 +3431,9 @@ FRAME 0 means change the face on all frames, and change 
the default
       /* Compatibility with 20.x.  */
       if (NILP (value))
        value = Qunspecified;
-      if (!UNSPECIFIEDP (value) && !IGNORE_DEFFACE_P (value))
+      if (!UNSPECIFIEDP (value)
+         && !IGNORE_DEFFACE_P (value)
+         && !RESET_P (value))
        {
          /* Don't check for valid color names here because it depends
             on the frame (display) whether the color will be valid
@@ -3393,7 +3448,9 @@ FRAME 0 means change the face on all frames, and change 
the default
   else if (EQ (attr, QCstipple))
     {
 #if defined (HAVE_WINDOW_SYSTEM)
-      if (!UNSPECIFIEDP (value) && !IGNORE_DEFFACE_P (value)
+      if (!UNSPECIFIEDP (value)
+         && !IGNORE_DEFFACE_P (value)
+         && !RESET_P (value)
          && !NILP (value)
          && NILP (Fbitmap_spec_p (value)))
        signal_error ("Invalid stipple attribute", value);
@@ -3403,7 +3460,9 @@ FRAME 0 means change the face on all frames, and change 
the default
     }
   else if (EQ (attr, QCwidth))
     {
-      if (!UNSPECIFIEDP (value) && !IGNORE_DEFFACE_P (value))
+      if (!UNSPECIFIEDP (value)
+         && !IGNORE_DEFFACE_P (value)
+         && !RESET_P (value))
        {
          CHECK_SYMBOL (value);
          if (FONT_WIDTH_NAME_NUMERIC (value) < 0)
@@ -3418,7 +3477,9 @@ FRAME 0 means change the face on all frames, and change 
the default
 #ifdef HAVE_WINDOW_SYSTEM
       if (EQ (frame, Qt) || FRAME_WINDOW_P (f))
        {
-         if (!UNSPECIFIEDP (value) && !IGNORE_DEFFACE_P (value))
+         if (!UNSPECIFIEDP (value)
+             && !IGNORE_DEFFACE_P (value)
+             && !RESET_P (value))
            {
              struct frame *f1;
 
@@ -3475,12 +3536,15 @@ FRAME 0 means change the face on all frames, and change 
the default
 #ifdef HAVE_WINDOW_SYSTEM
       if (EQ (frame, Qt) || FRAME_WINDOW_P (f))
        {
-         Lisp_Object tmp;
+         Lisp_Object tmp = value;
 
          old_value = LFACE_FONTSET (lface);
-         tmp = Fquery_fontset (value, Qnil);
-         if (NILP (tmp))
-           signal_error ("Invalid fontset name", value);
+         if (!RESET_P (value))
+           {
+             tmp = Fquery_fontset (value, Qnil);
+             if (NILP (tmp))
+               signal_error ("Invalid fontset name", value);
+           }
          ASET (lface, LFACE_FONTSET_INDEX, value = tmp);
        }
 #endif /* HAVE_WINDOW_SYSTEM */
@@ -3502,14 +3566,20 @@ FRAME 0 means change the face on all frames, and change 
the default
   else if (EQ (attr, QCbold))
     {
       old_value = LFACE_WEIGHT (lface);
-      ASET (lface, LFACE_WEIGHT_INDEX, NILP (value) ? Qnormal : Qbold);
+      if (RESET_P (value))
+       ASET (lface, LFACE_WEIGHT_INDEX, value);
+      else
+       ASET (lface, LFACE_WEIGHT_INDEX, NILP (value) ? Qnormal : Qbold);
       prop_index = FONT_WEIGHT_INDEX;
     }
   else if (EQ (attr, QCitalic))
     {
       attr = QCslant;
       old_value = LFACE_SLANT (lface);
-      ASET (lface, LFACE_SLANT_INDEX, NILP (value) ? Qnormal : Qitalic);
+      if (RESET_P (value))
+       ASET (lface, LFACE_SLANT_INDEX, value);
+      else
+       ASET (lface, LFACE_SLANT_INDEX, NILP (value) ? Qnormal : Qitalic);
       prop_index = FONT_SLANT_INDEX;
     }
   else
@@ -4119,6 +4189,7 @@ Default face attributes override any local face 
attributes.  */)
          /* Ensure that the face vector is fully specified by merging
             the previously-cached vector.  */
          memcpy (attrs, oldface->lface, sizeof attrs);
+
          merge_face_vectors (NULL, f, lvec, attrs, 0);
          vcopy (local_lface, 0, attrs, LFACE_VECTOR_SIZE);
          newface = realize_face (c, lvec, DEFAULT_FACE_ID);
@@ -4885,6 +4956,13 @@ lookup_named_face (struct window *w, struct frame *f,
     return -1;
 
   memcpy (attrs, default_face->lface, sizeof attrs);
+
+  /* Make explicit any attributes whose value is 'reset'.  */
+  int i;
+  for (i = 1; i < LFACE_VECTOR_SIZE; i++)
+    if (EQ (symbol_attrs[i], Qreset))
+      symbol_attrs[i] = attrs[i];
+
   merge_face_vectors (w, f, symbol_attrs, attrs, 0);
 
   return lookup_face (f, attrs);
@@ -5055,6 +5133,13 @@ lookup_derived_face (struct window *w,
 
   default_face = FACE_FROM_ID (f, face_id);
   memcpy (attrs, default_face->lface, sizeof attrs);
+
+  /* Make explicit any attributes whose value is 'reset'.  */
+  int i;
+  for (i = 1; i < LFACE_VECTOR_SIZE; i++)
+    if (EQ (symbol_attrs[i], Qreset))
+      symbol_attrs[i] = attrs[i];
+
   merge_face_vectors (w, f, symbol_attrs, attrs, 0);
   return lookup_face (f, attrs);
 }
@@ -5102,49 +5187,60 @@ gui_supports_face_attributes_p (struct frame *f,
                                 struct face *def_face)
 {
   Lisp_Object *def_attrs = def_face->lface;
+  Lisp_Object lattrs[LFACE_VECTOR_SIZE];
+
+  /* Make explicit any attributes whose value is 'reset'.  */
+  int i;
+  for (i = 1; i < LFACE_VECTOR_SIZE; i++)
+    {
+      if (EQ (attrs[i], Qreset))
+       lattrs[i] = def_attrs[i];
+      else
+       lattrs[i] = attrs[i];
+    }
 
   /* Check that other specified attributes are different from the
      default face.  */
-  if ((!UNSPECIFIEDP (attrs[LFACE_UNDERLINE_INDEX])
-       && face_attr_equal_p (attrs[LFACE_UNDERLINE_INDEX],
+  if ((!UNSPECIFIEDP (lattrs[LFACE_UNDERLINE_INDEX])
+       && face_attr_equal_p (lattrs[LFACE_UNDERLINE_INDEX],
                             def_attrs[LFACE_UNDERLINE_INDEX]))
-      || (!UNSPECIFIEDP (attrs[LFACE_INVERSE_INDEX])
-         && face_attr_equal_p (attrs[LFACE_INVERSE_INDEX],
+      || (!UNSPECIFIEDP (lattrs[LFACE_INVERSE_INDEX])
+         && face_attr_equal_p (lattrs[LFACE_INVERSE_INDEX],
                                def_attrs[LFACE_INVERSE_INDEX]))
-      || (!UNSPECIFIEDP (attrs[LFACE_EXTEND_INDEX])
-         && face_attr_equal_p (attrs[LFACE_EXTEND_INDEX],
+      || (!UNSPECIFIEDP (lattrs[LFACE_EXTEND_INDEX])
+         && face_attr_equal_p (lattrs[LFACE_EXTEND_INDEX],
                                def_attrs[LFACE_EXTEND_INDEX]))
-      || (!UNSPECIFIEDP (attrs[LFACE_FOREGROUND_INDEX])
-         && face_attr_equal_p (attrs[LFACE_FOREGROUND_INDEX],
+      || (!UNSPECIFIEDP (lattrs[LFACE_FOREGROUND_INDEX])
+         && face_attr_equal_p (lattrs[LFACE_FOREGROUND_INDEX],
                                def_attrs[LFACE_FOREGROUND_INDEX]))
-      || (!UNSPECIFIEDP (attrs[LFACE_DISTANT_FOREGROUND_INDEX])
-         && face_attr_equal_p (attrs[LFACE_DISTANT_FOREGROUND_INDEX],
+      || (!UNSPECIFIEDP (lattrs[LFACE_DISTANT_FOREGROUND_INDEX])
+         && face_attr_equal_p (lattrs[LFACE_DISTANT_FOREGROUND_INDEX],
                                def_attrs[LFACE_DISTANT_FOREGROUND_INDEX]))
-      || (!UNSPECIFIEDP (attrs[LFACE_BACKGROUND_INDEX])
-         && face_attr_equal_p (attrs[LFACE_BACKGROUND_INDEX],
+      || (!UNSPECIFIEDP (lattrs[LFACE_BACKGROUND_INDEX])
+         && face_attr_equal_p (lattrs[LFACE_BACKGROUND_INDEX],
                                def_attrs[LFACE_BACKGROUND_INDEX]))
-      || (!UNSPECIFIEDP (attrs[LFACE_STIPPLE_INDEX])
-         && face_attr_equal_p (attrs[LFACE_STIPPLE_INDEX],
+      || (!UNSPECIFIEDP (lattrs[LFACE_STIPPLE_INDEX])
+         && face_attr_equal_p (lattrs[LFACE_STIPPLE_INDEX],
                                def_attrs[LFACE_STIPPLE_INDEX]))
-      || (!UNSPECIFIEDP (attrs[LFACE_OVERLINE_INDEX])
-         && face_attr_equal_p (attrs[LFACE_OVERLINE_INDEX],
+      || (!UNSPECIFIEDP (lattrs[LFACE_OVERLINE_INDEX])
+         && face_attr_equal_p (lattrs[LFACE_OVERLINE_INDEX],
                                def_attrs[LFACE_OVERLINE_INDEX]))
-      || (!UNSPECIFIEDP (attrs[LFACE_STRIKE_THROUGH_INDEX])
-         && face_attr_equal_p (attrs[LFACE_STRIKE_THROUGH_INDEX],
+      || (!UNSPECIFIEDP (lattrs[LFACE_STRIKE_THROUGH_INDEX])
+         && face_attr_equal_p (lattrs[LFACE_STRIKE_THROUGH_INDEX],
                                def_attrs[LFACE_STRIKE_THROUGH_INDEX]))
-      || (!UNSPECIFIEDP (attrs[LFACE_BOX_INDEX])
-         && face_attr_equal_p (attrs[LFACE_BOX_INDEX],
+      || (!UNSPECIFIEDP (lattrs[LFACE_BOX_INDEX])
+         && face_attr_equal_p (lattrs[LFACE_BOX_INDEX],
                                def_attrs[LFACE_BOX_INDEX])))
     return false;
 
   /* Check font-related attributes, as those are the most commonly
      "unsupported" on a window-system (because of missing fonts).  */
-  if (!UNSPECIFIEDP (attrs[LFACE_FAMILY_INDEX])
-      || !UNSPECIFIEDP (attrs[LFACE_FOUNDRY_INDEX])
-      || !UNSPECIFIEDP (attrs[LFACE_HEIGHT_INDEX])
-      || !UNSPECIFIEDP (attrs[LFACE_WEIGHT_INDEX])
-      || !UNSPECIFIEDP (attrs[LFACE_SLANT_INDEX])
-      || !UNSPECIFIEDP (attrs[LFACE_SWIDTH_INDEX]))
+  if (!UNSPECIFIEDP (lattrs[LFACE_FAMILY_INDEX])
+      || !UNSPECIFIEDP (lattrs[LFACE_FOUNDRY_INDEX])
+      || !UNSPECIFIEDP (lattrs[LFACE_HEIGHT_INDEX])
+      || !UNSPECIFIEDP (lattrs[LFACE_WEIGHT_INDEX])
+      || !UNSPECIFIEDP (lattrs[LFACE_SLANT_INDEX])
+      || !UNSPECIFIEDP (lattrs[LFACE_SWIDTH_INDEX]))
     {
       int face_id;
       struct face *face;
@@ -5176,8 +5272,9 @@ gui_supports_face_attributes_p (struct frame *f,
              return true;
            s1 = SYMBOL_NAME (face->font->props[i]);
            s2 = SYMBOL_NAME (def_face->font->props[i]);
-           if (! EQ (Fcompare_strings (s1, make_fixnum (0), Qnil,
-                                       s2, make_fixnum (0), Qnil, Qt), Qt))
+           if (! BASE_EQ (Fcompare_strings (s1, make_fixnum (0), Qnil,
+                                            s2, make_fixnum (0), Qnil, Qt),
+                          Qt))
              return true;
          }
       return false;
@@ -5809,8 +5906,16 @@ realize_named_face (struct frame *f, Lisp_Object symbol, 
int id)
       lface = Finternal_make_lisp_face (symbol, frame);
     }
 
-  /* Merge SYMBOL's face with the default face.  */
+
   get_lface_attributes_no_remap (f, symbol, symbol_attrs, true);
+
+  /* Handle the 'reset' pseudo-value of any attribute by replacing it
+     with the corresponding value of the default face.  */
+  int i;
+  for (i = 1; i < LFACE_VECTOR_SIZE; i++)
+    if (EQ (symbol_attrs[i], Qreset))
+      symbol_attrs[i] = attrs[i];
+  /* Merge SYMBOL's face with the default face.  */
   merge_face_vectors (NULL, f, symbol_attrs, attrs, 0);
 
   /* Realize the face.  */
@@ -5950,7 +6055,7 @@ realize_gui_face (struct face_cache *cache, Lisp_Object 
attrs[LFACE_VECTOR_SIZE]
        }
       if (! FONT_OBJECT_P (attrs[LFACE_FONT_INDEX]))
        attrs[LFACE_FONT_INDEX]
-         = font_load_for_lface (f, attrs, Ffont_spec (0, NULL));
+         = font_load_for_lface (f, attrs, attrs[LFACE_FONT_INDEX]);
       if (FONT_OBJECT_P (attrs[LFACE_FONT_INDEX]))
        {
          face->font = XFONT_OBJECT (attrs[LFACE_FONT_INDEX]);
@@ -6727,7 +6832,21 @@ merge_faces (struct window *w, Lisp_Object face_name, 
int face_id,
       if (!face)
        return base_face_id;
 
-      merge_face_vectors (w, f, face->lface, attrs, 0);
+      if (face_id != DEFAULT_FACE_ID)
+       {
+         struct face *deflt = FACE_FROM_ID (f, DEFAULT_FACE_ID);
+         Lisp_Object lface_attrs[LFACE_VECTOR_SIZE];
+         int i;
+
+         memcpy (lface_attrs, face->lface, LFACE_VECTOR_SIZE);
+         /* Make explicit any attributes whose value is 'reset'.  */
+         for (i = 1; i < LFACE_VECTOR_SIZE; i++)
+           if (EQ (lface_attrs[i], Qreset))
+             lface_attrs[i] = deflt->lface[i];
+         merge_face_vectors (w, f, lface_attrs, attrs, 0);
+       }
+      else
+       merge_face_vectors (w, f, face->lface, attrs, 0);
     }
 
   /* Look up a realized face with the given face attributes,
@@ -6996,6 +7115,7 @@ syms_of_xfaces (void)
   DEFSYM (Qblack, "black");
   DEFSYM (Qoblique, "oblique");
   DEFSYM (Qitalic, "italic");
+  DEFSYM (Qreset, "reset");
 
   /* The symbols `foreground-color' and `background-color' which can be
      used as part of a `face' property.  This is for compatibility with
diff --git a/src/xfns.c b/src/xfns.c
index 05023524a7..0b1f707e9f 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -609,24 +609,24 @@ x_relative_mouse_position (struct frame *f, int *x, int 
*y)
 
   block_input ();
 
-  XQueryPointer (FRAME_X_DISPLAY (f),
-                 FRAME_DISPLAY_INFO (f)->root_window,
+  x_query_pointer (FRAME_X_DISPLAY (f),
+                  FRAME_DISPLAY_INFO (f)->root_window,
 
-                 /* The root window which contains the pointer.  */
-                 &root,
+                  /* The root window which contains the pointer.  */
+                  &root,
 
-                 /* Window pointer is on, not used  */
-                 &dummy_window,
+                  /* Window pointer is on, not used  */
+                  &dummy_window,
 
-                 /* The position on that root window.  */
-                 x, y,
+                  /* The position on that root window.  */
+                  x, y,
 
-                 /* x/y in dummy_window coordinates, not used.  */
-                 &dummy, &dummy,
+                  /* x/y in dummy_window coordinates, not used.  */
+                  &dummy, &dummy,
 
-                 /* Modifier keys and pointer buttons, about which
-                    we don't care.  */
-                 (unsigned int *) &dummy);
+                  /* Modifier keys and pointer buttons, about which
+                     we don't care.  */
+                  (unsigned int *) &dummy);
 
   XTranslateCoordinates (FRAME_X_DISPLAY (f),
 
@@ -838,21 +838,9 @@ x_set_inhibit_double_buffering (struct frame *f,
 
       block_input ();
       if (want_double_buffering != was_double_buffered)
-       {
-         /* Force XftDraw etc to be recreated with the new double
-            buffered drawable.  */
-         font_drop_xrender_surfaces (f);
-
-         /* Scroll bars decide whether or not to use a back buffer
-            based on the value of this frame parameter, so destroy
-            all scroll bars.  */
-#ifndef USE_TOOLKIT_SCROLL_BARS
-         if (FRAME_TERMINAL (f)->condemn_scroll_bars_hook)
-           FRAME_TERMINAL (f)->condemn_scroll_bars_hook (f);
-         if (FRAME_TERMINAL (f)->judge_scroll_bars_hook)
-           FRAME_TERMINAL (f)->judge_scroll_bars_hook (f);
-#endif
-       }
+       /* Force XftDraw etc to be recreated with the new double
+          buffered drawable.  */
+       font_drop_xrender_surfaces (f);
       if (FRAME_X_DOUBLE_BUFFERED_P (f) && !want_double_buffering)
         tear_down_x_back_buffer (f);
       else if (!FRAME_X_DOUBLE_BUFFERED_P (f) && want_double_buffering)
@@ -976,6 +964,16 @@ x_set_parent_frame (struct frame *f, Lisp_Object 
new_value, Lisp_Object old_valu
          gdk_x11_window_set_frame_sync_enabled (window, FALSE);
        }
 #endif
+
+#if defined HAVE_XSYNC && !defined USE_GTK && defined HAVE_CLOCK_GETTIME
+      /* Frame synchronization can't be used in child frames since
+        they are not directly managed by the compositing manager.
+        Re-enabling vsync in former child frames also leads to
+        inconsistent display.  In addition, they can only be updated
+        outside of a toplevel frame.  */
+      FRAME_X_OUTPUT (f)->use_vsync_p = false;
+      FRAME_X_WAITING_FOR_DRAW (f) = false;
+#endif
       unblock_input ();
 
       fset_parent_frame (f, new_value);
@@ -1204,20 +1202,6 @@ x_set_background_color (struct frame *f, Lisp_Object 
arg, Lisp_Object oldval)
       xg_set_background_color (f, bg);
 #endif
 
-#ifndef USE_TOOLKIT_SCROLL_BARS /* Turns out to be annoying with
-                                  toolkit scroll bars.  */
-      {
-       Lisp_Object bar;
-       for (bar = FRAME_SCROLL_BARS (f);
-            !NILP (bar);
-            bar = XSCROLL_BAR (bar)->next)
-         {
-           Window window = XSCROLL_BAR (bar)->x_window;
-           XSetWindowBackground (dpy, window, bg);
-         }
-      }
-#endif /* USE_TOOLKIT_SCROLL_BARS */
-
       unblock_input ();
       update_face_from_frame_parameter (f, Qbackground_color, arg);
 
@@ -1584,7 +1568,7 @@ x_set_icon_type (struct frame *f, Lisp_Object arg, 
Lisp_Object oldval)
 
   if (STRINGP (arg))
     {
-      if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
+      if (STRINGP (oldval) && BASE_EQ (Fstring_equal (oldval, arg), Qt))
        return;
     }
   else if (!STRINGP (oldval) && NILP (oldval) == NILP (arg))
@@ -1616,7 +1600,7 @@ x_set_icon_name (struct frame *f, Lisp_Object arg, 
Lisp_Object oldval)
 
   if (STRINGP (arg))
     {
-      if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
+      if (STRINGP (oldval) && BASE_EQ (Fstring_equal (oldval, arg), Qt))
        return;
     }
   else if (!NILP (arg) || NILP (oldval))
@@ -2433,6 +2417,28 @@ x_set_alpha (struct frame *f, Lisp_Object arg, 
Lisp_Object oldval)
     }
 }
 
+static void
+x_set_use_frame_synchronization (struct frame *f, Lisp_Object arg,
+                                Lisp_Object oldval)
+{
+#if defined HAVE_XSYNC && !defined USE_GTK && defined HAVE_CLOCK_GETTIME
+  struct x_display_info *dpyinfo;
+
+  dpyinfo = FRAME_DISPLAY_INFO (f);
+
+  if (!NILP (arg) && FRAME_X_EXTENDED_COUNTER (f))
+    FRAME_X_OUTPUT (f)->use_vsync_p
+      = x_wm_supports (f, dpyinfo->Xatom_net_wm_frame_drawn);
+  else
+    FRAME_X_OUTPUT (f)->use_vsync_p = false;
+
+  store_frame_param (f, Quse_frame_synchronization,
+                    FRAME_X_OUTPUT (f)->use_vsync_p ? Qt : Qnil);
+#else
+  store_frame_param (f, Quse_frame_synchronization, Qnil);
+#endif
+}
+
 
 /* Record in frame F the specified or default value according to ALIST
    of the parameter named PROP (a Lisp symbol).  If no value is
@@ -3712,6 +3718,16 @@ setup_xi_event_mask (struct frame *f)
   XIEventMask mask;
   ptrdiff_t l = XIMaskLen (XI_LASTEVENT);
   unsigned char *m;
+#ifndef HAVE_XINPUT2_1
+  /* Set up fallback values, since XIGetSelectedEvents doesn't work
+     with this version of libXi.  */
+  XIEventMask *selected;
+
+  selected = xzalloc (sizeof *selected + l);
+  selected->mask = ((unsigned char *) selected) + sizeof *selected;
+  selected->mask_len = l;
+  selected->deviceid = XIAllMasterDevices;
+#endif
 
   mask.mask = m = alloca (l);
   memset (m, 0, l);
@@ -3736,6 +3752,12 @@ setup_xi_event_mask (struct frame *f)
                  FRAME_X_WINDOW (f),
                  &mask, 1);
 
+  /* Fortunately `xi_masks' isn't used on GTK 3, where we really have
+     to get the event mask from the X server.  */
+#ifndef HAVE_XINPUT2_1
+  memcpy (selected->mask, m, l);
+#endif
+
   memset (m, 0, l);
 #endif /* !HAVE_GTK3 */
 
@@ -3751,14 +3773,11 @@ setup_xi_event_mask (struct frame *f)
   memset (m, 0, l);
 #endif
 
-  mask.deviceid = XIAllDevices;
-
-  XISetMask (m, XI_PropertyEvent);
-  XISetMask (m, XI_HierarchyChanged);
-  XISetMask (m, XI_DeviceChanged);
 #ifdef HAVE_XINPUT2_2
   if (FRAME_DISPLAY_INFO (f)->xi2_version >= 2)
     {
+      mask.deviceid = XIAllDevices;
+
       XISetMask (m, XI_TouchBegin);
       XISetMask (m, XI_TouchUpdate);
       XISetMask (m, XI_TouchEnd);
@@ -3770,11 +3789,18 @@ setup_xi_event_mask (struct frame *f)
          XISetMask (m, XI_GesturePinchEnd);
        }
 #endif
+
+      XISelectEvents (FRAME_X_DISPLAY (f),
+                     FRAME_X_WINDOW (f),
+                     &mask, 1);
     }
 #endif
-  XISelectEvents (FRAME_X_DISPLAY (f),
-                 FRAME_X_WINDOW (f),
-                 &mask, 1);
+
+#ifndef HAVE_XINPUT2_1
+  FRAME_X_OUTPUT (f)->xi_masks = selected;
+  FRAME_X_OUTPUT (f)->num_xi_masks = 1;
+#endif
+
   unblock_input ();
 }
 #endif
@@ -4935,7 +4961,10 @@ This function is an internal primitive--use `make-frame' 
instead.  */)
   x_icon (f, parms);
   x_make_gc (f);
 
-#ifdef HAVE_XINPUT2
+  /* While this function is present in versions of libXi that only
+     support 2.0, it does not release the display lock after
+     finishing, leading to a deadlock.  */
+#if defined HAVE_XINPUT2 && defined HAVE_XINPUT2_1
   if (dpyinfo->supports_xi2)
     FRAME_X_OUTPUT (f)->xi_masks
       = XIGetSelectedEvents (dpyinfo->display, FRAME_X_WINDOW (f),
@@ -5088,7 +5117,10 @@ This function is an internal primitive--use `make-frame' 
instead.  */)
     }
 
 #ifdef HAVE_XSYNC
-  if (dpyinfo->xsync_supported_p)
+  if (dpyinfo->xsync_supported_p
+      /* Frame synchronization isn't supported in child frames.  */
+      && NILP (parent_frame)
+      && !f->output_data.x->explicit_parent)
     {
 #ifndef HAVE_GTK3
       XSyncValue initial_value;
@@ -5123,12 +5155,21 @@ This function is an internal primitive--use 
`make-frame' instead.  */)
                       (unsigned char *) &counters,
                       ((STRINGP (value)
                         && !strcmp (SSDATA (value), "extended")) ? 2 : 1));
+
+#if defined HAVE_XSYNCTRIGGERFENCE && !defined USE_GTK \
+  && defined HAVE_CLOCK_GETTIME
+      x_sync_init_fences (f);
+#endif
 #endif
     }
 #endif
 
   unblock_input ();
 
+  /* Set whether or not frame synchronization is enabled.  */
+  gui_default_parameter (f, parms, Quse_frame_synchronization, Qt,
+                        NULL, NULL, RES_TYPE_BOOLEAN);
+
   /* Works iff frame has been already mapped.  */
   gui_default_parameter (f, parms, Qskip_taskbar, Qnil,
                          NULL, NULL, RES_TYPE_BOOLEAN);
@@ -5387,9 +5428,9 @@ DEFUN ("x-server-input-extension-version", 
Fx_server_input_extension_version,
        doc: /* Return the version of the X Input Extension supported by 
TERMINAL.
 The value is nil if TERMINAL's X server doesn't support the X Input
 Extension extension, or if Emacs doesn't support the version present
-on that server.  Otherwise, the return value is a list of the the
-major and minor versions of the X Input Extension extension running on
-that server.  */)
+on that server.  Otherwise, the return value is a list of the major
+and minor versions of the X Input Extension extension running on that
+server.  */)
   (Lisp_Object terminal)
 {
 #ifdef HAVE_XINPUT2
@@ -6781,10 +6822,10 @@ selected frame's display.  */)
     return Qnil;
 
   block_input ();
-  XQueryPointer (FRAME_X_DISPLAY (f),
-                FRAME_DISPLAY_INFO (f)->root_window,
-                 &root, &dummy_window, &x, &y, &dummy, &dummy,
-                 (unsigned int *) &dummy);
+  x_query_pointer (FRAME_X_DISPLAY (f),
+                  FRAME_DISPLAY_INFO (f)->root_window,
+                  &root, &dummy_window, &x, &y, &dummy, &dummy,
+                  (unsigned int *) &dummy);
   unblock_input ();
 
   return Fcons (make_fixnum (x), make_fixnum (y));
@@ -6809,17 +6850,16 @@ The coordinates X and Y are interpreted in pixels 
relative to a position
 #ifdef HAVE_XINPUT2
   int deviceid;
 
-  if (FRAME_DISPLAY_INFO (f)->supports_xi2)
+  deviceid = FRAME_DISPLAY_INFO (f)->client_pointer_device;
+
+  if (FRAME_DISPLAY_INFO (f)->supports_xi2
+      && deviceid != -1)
     {
-      XGrabServer (FRAME_X_DISPLAY (f));
-      if (XIGetClientPointer (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                             &deviceid))
-       {
-         XIWarpPointer (FRAME_X_DISPLAY (f), deviceid, None,
-                        FRAME_DISPLAY_INFO (f)->root_window,
-                        0, 0, 0, 0, xval, yval);
-       }
-      XUngrabServer (FRAME_X_DISPLAY (f));
+      x_catch_errors_for_lisp (FRAME_DISPLAY_INFO (f));
+      XIWarpPointer (FRAME_X_DISPLAY (f), deviceid, None,
+                    FRAME_DISPLAY_INFO (f)->root_window,
+                    0, 0, 0, 0, xval, yval);
+      x_uncatch_errors_for_lisp (FRAME_DISPLAY_INFO (f));
     }
   else
 #endif
@@ -6899,7 +6939,7 @@ that mouse buttons are being held down, such as 
immediately after a
   int ntargets = 0, nnames = 0;
   char *target_names[2048];
   Atom *target_atoms;
-  Lisp_Object lval, original, tem, t1, t2;
+  Lisp_Object lval, original, targets_arg, tem, t1, t2;
   Atom xaction;
   Atom action_list[2048];
   char *name_list[2048];
@@ -6908,11 +6948,11 @@ that mouse buttons are being held down, such as 
immediately after a
 
   CHECK_LIST (targets);
   original = targets;
+  targets_arg = targets;
 
-  for (; CONSP (targets); targets = XCDR (targets))
+  FOR_EACH_TAIL (targets)
     {
       CHECK_STRING (XCAR (targets));
-      maybe_quit ();
 
       if (ntargets < 2048)
        {
@@ -6936,15 +6976,19 @@ that mouse buttons are being held down, such as 
immediately after a
     xaction = FRAME_DISPLAY_INFO (f)->Xatom_XdndActionPrivate;
   else if (EQ (action, QXdndActionAsk))
     xaction = FRAME_DISPLAY_INFO (f)->Xatom_XdndActionAsk;
+  else if (SYMBOLP (action))
+    /* This is to accommodate non-standard DND protocols such as XDS
+       that are explicitly implemented by Emacs, and is not documented
+       for that reason.  */
+    xaction = symbol_to_x_atom (FRAME_DISPLAY_INFO (f), action);
   else if (CONSP (action))
     {
       xaction = FRAME_DISPLAY_INFO (f)->Xatom_XdndActionAsk;
       original = action;
 
       CHECK_LIST (action);
-      for (; CONSP (action); action = XCDR (action))
+      FOR_EACH_TAIL (action)
        {
-         maybe_quit ();
          tem = XCAR (action);
          CHECK_CONS (tem);
          t1 = XCAR (tem);
@@ -6995,7 +7039,7 @@ that mouse buttons are being held down, such as 
immediately after a
                                    xaction, return_frame, action_list,
                                    (const char **) &name_list, nnames,
                                    !NILP (allow_current_frame), target_atoms,
-                                   ntargets, original, !NILP (follow_tooltip));
+                                   ntargets, targets_arg, !NILP 
(follow_tooltip));
 
   SAFE_FREE ();
   return lval;
@@ -7335,18 +7379,23 @@ If VALUE is a string and FORMAT is 32, then the format 
of VALUE is
 system-specific.  VALUE must contain unsigned integer data in native
 endian-ness in multiples of the size of the C type 'long': the low 32
 bits of each such number are used as the value of each element of the
-property.  */)
+property.
+
+Wait for the request to complete and signal any error, unless
+`x-fast-protocol-requests' is non-nil, in which case errors will be
+silently ignored.  */)
   (Lisp_Object prop, Lisp_Object value, Lisp_Object frame,
    Lisp_Object type, Lisp_Object format, Lisp_Object outer_p,
    Lisp_Object window_id)
 {
-  struct frame *f = decode_window_system_frame (frame);
+  struct frame *f;
   Atom prop_atom;
   Atom target_type = XA_STRING;
   int element_format = 8;
   unsigned char *data;
   int nelements;
   Window target_window;
+  struct x_display_info *dpyinfo;
 #ifdef USE_XCB
   bool intern_prop;
   bool intern_target;
@@ -7357,6 +7406,9 @@ property.  */)
   bool rc;
 #endif
 
+  f = decode_window_system_frame (frame);
+  dpyinfo = FRAME_DISPLAY_INFO (f);
+
   CHECK_STRING (prop);
 
   if (! NILP (format))
@@ -7408,7 +7460,7 @@ property.  */)
     {
       CONS_TO_INTEGER (window_id, Window, target_window);
       if (! target_window)
-        target_window = FRAME_DISPLAY_INFO (f)->root_window;
+        target_window = dpyinfo->root_window;
     }
   else
     {
@@ -7420,47 +7472,47 @@ property.  */)
 
   block_input ();
 #ifndef USE_XCB
-  prop_atom = x_intern_cached_atom (FRAME_DISPLAY_INFO (f),
-                                   SSDATA (prop), false);
+  prop_atom = x_intern_cached_atom (dpyinfo, SSDATA (prop),
+                                   false);
   if (! NILP (type))
     {
       CHECK_STRING (type);
-      target_type = x_intern_cached_atom (FRAME_DISPLAY_INFO (f),
-                                         SSDATA (type), false);
+      target_type = x_intern_cached_atom (dpyinfo, SSDATA (type),
+                                         false);
     }
 #else
   rc = true;
   intern_target = true;
   intern_prop = true;
 
-  prop_atom = x_intern_cached_atom (FRAME_DISPLAY_INFO (f),
-                                   SSDATA (prop), true);
+  prop_atom = x_intern_cached_atom (dpyinfo, SSDATA (prop),
+                                   true);
 
   if (prop_atom != None)
     intern_prop = false;
   else
     prop_atom_cookie
-      = xcb_intern_atom (FRAME_DISPLAY_INFO (f)->xcb_connection,
+      = xcb_intern_atom (dpyinfo->xcb_connection,
                         0, SBYTES (prop), SSDATA (prop));
 
   if (!NILP (type))
     {
       CHECK_STRING (type);
 
-      target_type = x_intern_cached_atom (FRAME_DISPLAY_INFO (f),
-                                         SSDATA (type), true);
+      target_type = x_intern_cached_atom (dpyinfo, SSDATA (type),
+                                         true);
 
       if (target_type)
        intern_target = false;
       else
        target_type_cookie
-         = xcb_intern_atom (FRAME_DISPLAY_INFO (f)->xcb_connection,
+         = xcb_intern_atom (dpyinfo->xcb_connection,
                             0, SBYTES (type), SSDATA (type));
     }
 
   if (intern_prop)
     {
-      reply = xcb_intern_atom_reply (FRAME_DISPLAY_INFO (f)->xcb_connection,
+      reply = xcb_intern_atom_reply (dpyinfo->xcb_connection,
                                     prop_atom_cookie, &generic_error);
 
       if (reply)
@@ -7477,7 +7529,7 @@ property.  */)
 
   if (!NILP (type) && intern_target)
     {
-      reply = xcb_intern_atom_reply (FRAME_DISPLAY_INFO (f)->xcb_connection,
+      reply = xcb_intern_atom_reply (dpyinfo->xcb_connection,
                                     target_type_cookie, &generic_error);
 
       if (reply)
@@ -7496,15 +7548,18 @@ property.  */)
     error ("Failed to intern type or property atom");
 #endif
 
-  x_catch_errors (FRAME_X_DISPLAY (f));
-  XChangeProperty (FRAME_X_DISPLAY (f), target_window,
-                  prop_atom, target_type, element_format, PropModeReplace,
-                  data, nelements);
+  x_catch_errors_for_lisp (dpyinfo);
 
-  if (CONSP (value)) xfree (data);
-  x_check_errors (FRAME_X_DISPLAY (f),
-                 "Couldn't change window property: %s");
-  x_uncatch_errors_after_check ();
+  XChangeProperty (dpyinfo->display, target_window,
+                  prop_atom, target_type, element_format,
+                  PropModeReplace, data, nelements);
+
+  if (CONSP (value))
+    xfree (data);
+
+  x_check_errors_for_lisp (dpyinfo,
+                          "Couldn't change window property: %s");
+  x_uncatch_errors_for_lisp (dpyinfo);
 
   unblock_input ();
   return value;
@@ -7521,7 +7576,11 @@ If WINDOW-ID is non-nil, remove property from that 
window instead
  across X displays or screens on the same display, so FRAME provides
  context for the window ID.
 
-Value is PROP.  */)
+Value is PROP.
+
+Wait for the request to complete and signal any error, unless
+`x-fast-protocol-requests' is non-nil, in which case errors will be
+silently ignored.  */)
   (Lisp_Object prop, Lisp_Object frame, Lisp_Object window_id)
 {
   struct frame *f = decode_window_system_frame (frame);
@@ -7541,11 +7600,11 @@ Value is PROP.  */)
   prop_atom = x_intern_cached_atom (FRAME_DISPLAY_INFO (f),
                                    SSDATA (prop), false);
 
-  x_catch_errors (FRAME_X_DISPLAY (f));
+  x_catch_errors_for_lisp (FRAME_DISPLAY_INFO (f));
   XDeleteProperty (FRAME_X_DISPLAY (f), target_window, prop_atom);
-  x_check_errors (FRAME_X_DISPLAY (f),
-                 "Couldn't delete window property: %s");
-  x_uncatch_errors_after_check ();
+  x_check_errors_for_lisp (FRAME_DISPLAY_INFO (f),
+                          "Couldn't delete window property: %s");
+  x_uncatch_errors_for_lisp (FRAME_DISPLAY_INFO (f));
 
   unblock_input ();
   return prop;
@@ -7789,6 +7848,92 @@ Otherwise, the return value is a vector with the 
following fields:
   return prop_attr;
 }
 
+
+/***********************************************************************
+                          Coordinate management
+ ***********************************************************************/
+
+DEFUN ("x-translate-coordinates", Fx_translate_coordinates,
+       Sx_translate_coordinates,
+       1, 5, 0, doc: /* Translate coordinates from FRAME.
+Translate the given coordinates SOURCE-X and SOURCE-Y from
+SOURCE-WINDOW's coordinate space to that of DEST-WINDOW, on FRAME.
+
+If SOURCE-X and SOURCE-Y are nil, use 0 instead.
+
+FRAME can either be a terminal or a frame.  If nil, it defaults to the
+selected frame.  SOURCE-WINDOW must be an X window ID, 0 (which means
+to use the root window), or nil, which means to use FRAME's inner
+window.  DEST-WINDOW must be another X window ID, or nil (which means
+to use the root window).
+
+Return a list of (X Y CHILD) if the given coordinates are on the same
+screen, or nil otherwise, where X and Y are the coordinates in
+DEST-WINDOW's coordinate space, and CHILD is the window ID of any
+mapped child in DEST-WINDOW at those coordinates, or nil if there is
+no such window.  */)
+  (Lisp_Object frame, Lisp_Object source_window,
+   Lisp_Object dest_window, Lisp_Object source_x,
+   Lisp_Object source_y)
+{
+  struct x_display_info *dpyinfo;
+  struct frame *source_frame;
+  int dest_x, dest_y;
+  Window child_return, src, dest;
+  Bool rc;
+
+  dpyinfo = check_x_display_info (frame);
+  dest_x = 0;
+  dest_y = 0;
+
+  if (!NILP (source_x))
+    {
+      CHECK_FIXNUM (source_x);
+      dest_x = XFIXNUM (source_x);
+    }
+
+  if (!NILP (source_y))
+    {
+      CHECK_FIXNUM (source_y);
+      dest_y = XFIXNUM (source_y);
+    }
+
+  if (!NILP (source_window))
+    CONS_TO_INTEGER (source_window, Window, src);
+  else
+    {
+      source_frame = decode_window_system_frame (frame);
+      src = FRAME_X_WINDOW (source_frame);
+    }
+
+  if (!src)
+    src = dpyinfo->root_window;
+
+  if (!NILP (dest_window))
+    CONS_TO_INTEGER (dest_window, Window, dest);
+  else
+    dest = dpyinfo->root_window;
+
+  block_input ();
+  x_catch_errors (dpyinfo->display);
+  rc = XTranslateCoordinates (dpyinfo->display, src, dest,
+                             dest_x, dest_y, &dest_x, &dest_y,
+                             &child_return);
+  x_check_errors (dpyinfo->display,
+                 "Couldn't translate coordinates: %s");
+  x_uncatch_errors_after_check ();
+  unblock_input ();
+
+  if (!rc)
+    return Qnil;
+
+  return list3 (make_int (dest_x),
+               make_int (dest_y),
+               (child_return != None
+                ? make_uint (child_return)
+                : Qnil));
+}
+
 /***********************************************************************
                                Tool tips
  ***********************************************************************/
@@ -8235,8 +8380,8 @@ compute_tip_xy (struct frame *f, Lisp_Object parms, 
Lisp_Object dx,
       Lisp_Object frame, attributes, monitor, geometry;
 
       block_input ();
-      XQueryPointer (FRAME_X_DISPLAY (f), FRAME_DISPLAY_INFO (f)->root_window,
-                    &root, &child, root_x, root_y, &win_x, &win_y, &pmask);
+      x_query_pointer (FRAME_X_DISPLAY (f), FRAME_DISPLAY_INFO 
(f)->root_window,
+                      &root, &child, root_x, root_y, &win_x, &win_y, &pmask);
       unblock_input ();
 
       XSETFRAME (frame, f);
@@ -8493,6 +8638,10 @@ Text larger than the specified size is clipped.  */)
   Window child;
   XWindowAttributes child_attrs;
   int dest_x_return, dest_y_return;
+  bool displayed;
+#ifdef ENABLE_CHECKING
+  struct glyph_row *row, *end;
+#endif
   AUTO_STRING (tip, " *tip*");
 
   specbind (Qinhibit_redisplay, Qt);
@@ -8547,7 +8696,8 @@ Text larger than the specified size is clipped.  */)
   if (!NILP (tip_frame) && FRAME_LIVE_P (XFRAME (tip_frame)))
     {
       if (FRAME_VISIBLE_P (XFRAME (tip_frame))
-         && BASE_EQ (frame, tip_last_frame)
+         && (FRAME_X_DISPLAY (XFRAME (frame))
+             == FRAME_X_DISPLAY (XFRAME (tip_last_frame)))
          && !NILP (Fequal_including_properties (tip_last_string, string))
          && !NILP (Fequal (tip_last_parms, parms)))
        {
@@ -8705,7 +8855,26 @@ Text larger than the specified size is clipped.  */)
   clear_glyph_matrix (w->desired_matrix);
   clear_glyph_matrix (w->current_matrix);
   SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
-  try_window (window, pos, TRY_WINDOW_IGNORE_FONTS_CHANGE);
+  displayed = try_window (window, pos, TRY_WINDOW_IGNORE_FONTS_CHANGE);
+
+  if (!displayed && NILP (Vx_max_tooltip_size))
+    {
+#ifdef ENABLE_CHECKING
+      row = w->desired_matrix->rows;
+      end = w->desired_matrix->rows + w->desired_matrix->nrows;
+
+      while (row < end)
+       {
+         if (!row->displays_text_p
+             || row->ends_at_zv_p)
+           break;
+         ++row;
+       }
+
+      eassert (row < end && row->ends_at_zv_p);
+#endif
+    }
+
   /* Calculate size of tooltip window.  */
   size = Fwindow_text_pixel_size (window, Qnil, Qnil, Qnil,
                                  make_fixnum (w->pixel_height), Qnil,
@@ -8806,9 +8975,8 @@ DEFUN ("x-double-buffered-p", Fx_double_buffered_p, 
Sx_double_buffered_p,
        doc: /* Return t if FRAME is being double buffered.  */)
      (Lisp_Object frame)
 {
-  struct frame *f = decode_live_frame (frame);
-
 #ifdef HAVE_XDBE
+  struct frame *f = decode_live_frame (frame);
   return FRAME_X_DOUBLE_BUFFERED_P (f) ? Qt : Qnil;
 #else
   return Qnil;
@@ -9297,6 +9465,24 @@ present and mapped to the usual X keysyms.  */)
 #endif
 }
 
+DEFUN ("x-get-modifier-masks", Fx_get_modifier_masks, Sx_get_modifier_masks,
+       0, 1, 0,
+       doc: /* Return the X modifier masks corresponding to keyboard modifiers.
+The optional second argument TERMINAL specifies which display to fetch
+modifier masks from.  TERMINAL should be a terminal object, a frame or
+a display name (a string).  If TERMINAL is omitted or nil, that stands
+for the selected frame's display.
+
+Return a list of (HYPER SUPER ALT SHIFT-LOCK META), each element being
+a number describing the modifier mask for the corresponding Emacs
+modifier.  */)
+  (Lisp_Object terminal)
+{
+  struct x_display_info *dpyinfo;
+
+  dpyinfo = check_x_display_info (terminal);
+  return x_get_keyboard_modifiers (dpyinfo);
+}
 
 
 /***********************************************************************
@@ -9472,6 +9658,28 @@ DEFUN ("x-gtk-debug", Fx_gtk_debug, Sx_gtk_debug, 1, 1, 
0,
 #endif /* HAVE_GTK3 */
 #endif /* USE_GTK */
 
+DEFUN ("x-display-set-last-user-time", Fx_display_last_user_time,
+       Sx_display_set_last_user_time, 1, 2, 0,
+       doc: /* Set the last user time of TERMINAL to TIME-OBJECT.
+TIME-OBJECT is the X server time, in milliseconds, of the last user
+interaction.  This is the timestamp that `x-get-selection-internal'
+will use by default to fetch selection data.
+The optional second argument TERMINAL specifies which display to act
+on.  TERMINAL should be a terminal object, a frame or a display name
+(a string).  If TERMINAL is omitted or nil, that stands for the
+selected frame's display.  */)
+  (Lisp_Object time_object, Lisp_Object terminal)
+{
+  struct x_display_info *dpyinfo;
+  Time time;
+
+  dpyinfo = check_x_display_info (terminal);
+  CONS_TO_INTEGER (time_object, Time, time);
+
+  x_set_last_user_time_from_lisp (dpyinfo, time);
+  return Qnil;
+}
+
 DEFUN ("x-internal-focus-input-context", Fx_internal_focus_input_context,
        Sx_internal_focus_input_context, 1, 1, 0,
        doc: /* Focus and set the client window of all focused frames' GTK 
input context.
@@ -9575,6 +9783,7 @@ frame_parm_handler x_frame_parm_handlers[] =
   x_set_override_redirect,
   gui_set_no_special_glyphs,
   x_set_alpha_background,
+  x_set_use_frame_synchronization,
   x_set_shaded,
 };
 
@@ -9780,7 +9989,7 @@ or when you set the mouse color.  */);
   DEFVAR_LISP ("x-max-tooltip-size", Vx_max_tooltip_size,
     doc: /* Maximum size for tooltips.
 Value is a pair (COLUMNS . ROWS).  Text larger than this is clipped.  */);
-  Vx_max_tooltip_size = Fcons (make_fixnum (80), make_fixnum (40));
+  Vx_max_tooltip_size = Qnil;
 
   DEFVAR_LISP ("x-no-window-manager", Vx_no_window_manager,
     doc: /* Non-nil if no X window manager is in use.
@@ -9937,6 +10146,10 @@ eliminated in future versions of Emacs.  */);
   defsubr (&Sx_hide_tip);
   defsubr (&Sx_double_buffered_p);
   defsubr (&Sx_begin_drag);
+  defsubr (&Sx_display_set_last_user_time);
+  defsubr (&Sx_translate_coordinates);
+  defsubr (&Sx_get_modifier_masks);
+
   tip_timer = Qnil;
   staticpro (&tip_timer);
   tip_frame = Qnil;
diff --git a/src/xmenu.c b/src/xmenu.c
index 7134bf22c8..1452b3c6d1 100644
--- a/src/xmenu.c
+++ b/src/xmenu.c
@@ -232,6 +232,7 @@ static void
 x_menu_translate_generic_event (XEvent *event)
 {
   struct x_display_info *dpyinfo;
+  struct xi_device_t *device;
   XEvent copy;
   XIDeviceEvent *xev;
 
@@ -241,45 +242,52 @@ x_menu_translate_generic_event (XEvent *event)
     {
       eassert (!event->xcookie.data);
 
-      if (XGetEventData (dpyinfo->display, &event->xcookie))
+      switch (event->xcookie.evtype)
        {
-         switch (event->xcookie.evtype)
-           {
-           case XI_ButtonPress:
-           case XI_ButtonRelease:
-             xev = (XIDeviceEvent *) event->xcookie.data;
-             copy.xbutton.type = (event->xcookie.evtype == XI_ButtonPress
-                                  ? ButtonPress : ButtonRelease);
-             copy.xbutton.serial = xev->serial;
-             copy.xbutton.send_event = xev->send_event;
-             copy.xbutton.display = dpyinfo->display;
-             copy.xbutton.window = xev->event;
-             copy.xbutton.root = xev->root;
-             copy.xbutton.subwindow = xev->child;
-             copy.xbutton.time = xev->time;
-             copy.xbutton.x = lrint (xev->event_x);
-             copy.xbutton.y = lrint (xev->event_y);
-             copy.xbutton.x_root = lrint (xev->root_x);
-             copy.xbutton.y_root = lrint (xev->root_y);
-             copy.xbutton.state = xev->mods.effective;
-             copy.xbutton.button = xev->detail;
-             copy.xbutton.same_screen = True;
-
-             if (xev->buttons.mask_len)
-               {
-                 if (XIMaskIsSet (xev->buttons.mask, 1))
-                   copy.xbutton.state |= Button1Mask;
-                 if (XIMaskIsSet (xev->buttons.mask, 2))
-                   copy.xbutton.state |= Button2Mask;
-                 if (XIMaskIsSet (xev->buttons.mask, 3))
-                   copy.xbutton.state |= Button3Mask;
-               }
+       case XI_ButtonPress:
+       case XI_ButtonRelease:
 
-             XPutBackEvent (dpyinfo->display, &copy);
+         if (!XGetEventData (dpyinfo->display, &event->xcookie))
+           break;
 
-             break;
-           }
+         xev = (XIDeviceEvent *) event->xcookie.data;
+         copy.xbutton.type = (event->xcookie.evtype == XI_ButtonPress
+                              ? ButtonPress : ButtonRelease);
+         copy.xbutton.serial = xev->serial;
+         copy.xbutton.send_event = xev->send_event;
+         copy.xbutton.display = dpyinfo->display;
+         copy.xbutton.window = xev->event;
+         copy.xbutton.root = xev->root;
+         copy.xbutton.subwindow = xev->child;
+         copy.xbutton.time = xev->time;
+         copy.xbutton.x = lrint (xev->event_x);
+         copy.xbutton.y = lrint (xev->event_y);
+         copy.xbutton.x_root = lrint (xev->root_x);
+         copy.xbutton.y_root = lrint (xev->root_y);
+         copy.xbutton.state = xi_convert_event_state (xev);
+         copy.xbutton.button = xev->detail;
+         copy.xbutton.same_screen = True;
+
+         device = xi_device_from_id (dpyinfo, xev->deviceid);
+
+         /* I don't know the repercussions of changing
+            device->grab on XI_ButtonPress events, so be safe and
+            only do what is necessary to prevent the grab from
+            being left invalid as XMenuActivate swallows
+            events.  */
+         if (device && xev->evtype == XI_ButtonRelease)
+           device->grab &= ~(1 << xev->detail);
+
+         XPutBackEvent (dpyinfo->display, &copy);
          XFreeEventData (dpyinfo->display, &event->xcookie);
+
+         break;
+
+       case XI_HierarchyChanged:
+       case XI_DeviceChanged:
+         /* These events must always be handled.  */
+         x_dispatch_event (event, dpyinfo->display);
+         break;
        }
     }
 }
@@ -397,7 +405,7 @@ popup_get_selection (XEvent *initial_event, struct 
x_display_info *dpyinfo,
                    copy.xbutton.y = lrint (xev->event_y);
                    copy.xbutton.x_root = lrint (xev->root_x);
                    copy.xbutton.y_root = lrint (xev->root_y);
-                   copy.xbutton.state = xev->mods.effective;
+                   copy.xbutton.state = xi_convert_event_state (xev);
                    copy.xbutton.button = xev->detail;
                    copy.xbutton.same_screen = True;
 
@@ -412,16 +420,6 @@ popup_get_selection (XEvent *initial_event, struct 
x_display_info *dpyinfo,
                    copy.xbutton.state = 0;
 #endif
 
-                   if (xev->buttons.mask_len)
-                     {
-                       if (XIMaskIsSet (xev->buttons.mask, 1))
-                         copy.xbutton.state |= Button1Mask;
-                       if (XIMaskIsSet (xev->buttons.mask, 2))
-                         copy.xbutton.state |= Button2Mask;
-                       if (XIMaskIsSet (xev->buttons.mask, 3))
-                         copy.xbutton.state |= Button3Mask;
-                     }
-
                    break;
                  }
                case XI_KeyPress:
@@ -442,7 +440,7 @@ popup_get_selection (XEvent *initial_event, struct 
x_display_info *dpyinfo,
                    copy.xkey.y = lrint (xev->event_y);
                    copy.xkey.x_root = lrint (xev->root_x);
                    copy.xkey.y_root = lrint (xev->root_y);
-                   copy.xkey.state = xev->mods.effective;
+                   copy.xkey.state = xi_convert_event_state (xev);
                    copy.xkey.keycode = xev->detail;
                    copy.xkey.same_screen = True;
 
@@ -996,8 +994,6 @@ set_frame_menubar (struct frame *f, bool deep_p)
 
       /* If it has changed current-menubar from previous value,
         really recompute the menubar from the value.  */
-      if (! NILP (Vlucid_menu_bar_dirty_flag))
-       call0 (Qrecompute_lucid_menubar);
       safe_run_hooks (Qmenu_bar_update_hook);
       fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
 
@@ -2529,6 +2525,10 @@ pop_down_menu (void *arg)
   struct pop_down_menu *data = arg;
   struct frame *f = data->frame;
   XMenu *menu = data->menu;
+#ifdef HAVE_XINPUT2
+  int i;
+  struct xi_device_t *device;
+#endif
 
   block_input ();
 #ifndef MSDOS
@@ -2548,6 +2548,17 @@ pop_down_menu (void *arg)
      results, and it is a pain to ask which are actually held now.  */
   FRAME_DISPLAY_INFO (f)->grabbed = 0;
 
+#ifdef HAVE_XINPUT2
+  /* Likewise for XI grabs when the mouse is released on top of the
+     menu itself.  */
+
+  for (i = 0; i < FRAME_DISPLAY_INFO (f)->num_devices; ++i)
+    {
+      device = &FRAME_DISPLAY_INFO (f)->devices[i];
+      device->grab = 0;
+    }
+#endif
+
 #endif /* HAVE_X_WINDOWS */
 
   unblock_input ();
@@ -2558,6 +2569,9 @@ Lisp_Object
 x_menu_show (struct frame *f, int x, int y, int menuflags,
             Lisp_Object title, const char **error_name)
 {
+#ifdef HAVE_X_WINDOWS
+  Window dummy_window;
+#endif
   Window root;
   XMenu *menu;
   int pane, selidx, lpane, status;
@@ -2606,20 +2620,22 @@ x_menu_show (struct frame *f, int x, int y, int 
menuflags,
   inhibit_garbage_collection ();
 
 #ifdef HAVE_X_WINDOWS
-  {
-    /* Adjust coordinates to relative to the outer (window manager) window. */
-    int left_off, top_off;
+  XTranslateCoordinates (FRAME_X_DISPLAY (f),
 
-    x_real_pos_and_offsets (f, &left_off, NULL, &top_off, NULL,
-                            NULL, NULL, NULL, NULL, NULL);
+                         /* From-window, to-window.  */
+                         FRAME_X_WINDOW (f),
+                         FRAME_DISPLAY_INFO (f)->root_window,
 
-    x += left_off;
-    y += top_off;
-  }
-#endif /* HAVE_X_WINDOWS */
+                         /* From-position, to-position.  */
+                         x, y, &x, &y,
 
+                         /* Child of win.  */
+                         &dummy_window);
+#else
+  /* MSDOS without X support.  */
   x += f->left_pos;
   y += f->top_pos;
+#endif
 
   /* Create all the necessary panes and their items.  */
   maxwidth = maxlines = lines = i = 0;
@@ -2774,6 +2790,9 @@ x_menu_show (struct frame *f, int x, int y, int menuflags,
   DEFER_SELECTIONS;
 
   XMenuActivateSetWaitFunction (x_menu_wait_for_event, FRAME_X_DISPLAY (f));
+  /* When the input extension is in use, the owner_events grab will
+     report extension events on frames, which the XMenu library does
+     not normally understand.  */
 #ifdef HAVE_XINPUT2
   XMenuActivateSetTranslateFunction (x_menu_translate_generic_event);
 #endif
diff --git a/src/xml.c b/src/xml.c
index 522efd224c..2cccff1233 100644
--- a/src/xml.c
+++ b/src/xml.c
@@ -186,6 +186,12 @@ parse_region (Lisp_Object start, Lisp_Object end, 
Lisp_Object base_url,
 
   xmlCheckVersion (LIBXML_VERSION);
 
+  if (NILP (start))
+    start = Fpoint_min ();
+
+  if (NILP (end))
+    end = Fpoint_max ();
+
   validate_region (&start, &end);
 
   istart = XFIXNUM (start);
@@ -269,8 +275,11 @@ xml_cleanup_parser (void)
 
 DEFUN ("libxml-parse-html-region", Flibxml_parse_html_region,
        Slibxml_parse_html_region,
-       2, 4, 0,
+       0, 4, 0,
        doc: /* Parse the region as an HTML document and return the parse tree.
+If START is nil, it defaults to `point-min'.  If END is nil, it
+defaults to `point-max'.
+
 If BASE-URL is non-nil, it is used to expand relative URLs.
 
 If you want comments to be stripped, use the `xml-remove-comments'
@@ -284,8 +293,11 @@ function to strip comments before calling this function.  
*/)
 
 DEFUN ("libxml-parse-xml-region", Flibxml_parse_xml_region,
        Slibxml_parse_xml_region,
-       2, 4, 0,
+       0, 4, 0,
        doc: /* Parse the region as an XML document and return the parse tree.
+If START is nil, it defaults to `point-min'.  If END is nil, it
+defaults to `point-max'.
+
 If BASE-URL is non-nil, it is used to expand relative URLs.
 
 If you want comments to be stripped, use the `xml-remove-comments'
diff --git a/src/xselect.c b/src/xselect.c
index 96c1e9830f..bab0400540 100644
--- a/src/xselect.c
+++ b/src/xselect.c
@@ -36,17 +36,16 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #include "termhooks.h"
 #include "keyboard.h"
 #include "pdumper.h"
+#include "atimer.h"
 
 #include <X11/Xproto.h>
 
-static Time pending_dnd_time;
-
 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,
-                                struct x_display_info *);
+                                struct x_display_info *, bool);
 static bool waiting_for_other_props_on_window (Display *, Window);
 static struct prop_location *expect_property_change (Display *, Window,
                                                      Atom, int);
@@ -120,7 +119,7 @@ selection_quantum (Display *display)
 /* This converts a Lisp symbol to a server Atom, avoiding a server
    roundtrip whenever possible.  */
 
-static Atom
+Atom
 symbol_to_x_atom (struct x_display_info *dpyinfo, Lisp_Object sym)
 {
   Atom val;
@@ -164,6 +163,12 @@ symbol_to_x_atom (struct x_display_info *dpyinfo, 
Lisp_Object sym)
     return dpyinfo->Xatom_XmTRANSFER_SUCCESS;
   if (EQ (sym, QXmTRANSFER_FAILURE))
     return dpyinfo->Xatom_XmTRANSFER_FAILURE;
+  if (EQ (sym, QXdndDirectSave0))
+    return dpyinfo->Xatom_XdndDirectSave0;
+  if (EQ (sym, Qtext_plain))
+    return dpyinfo->Xatom_text_plain;
+  if (EQ (sym, QXdndActionDirectSave))
+    return dpyinfo->Xatom_XdndActionDirectSave;
 
   if (!SYMBOLP (sym))
     emacs_abort ();
@@ -232,6 +237,12 @@ x_atom_to_symbol (struct x_display_info *dpyinfo, Atom 
atom)
     return QXmTRANSFER_SUCCESS;
   if (atom == dpyinfo->Xatom_XmTRANSFER_FAILURE)
     return QXmTRANSFER_FAILURE;
+  if (atom == dpyinfo->Xatom_XdndDirectSave0)
+    return QXdndDirectSave0;
+  if (atom == dpyinfo->Xatom_text_plain)
+    return Qtext_plain;
+  if (atom == dpyinfo->Xatom_XdndActionDirectSave)
+    return QXdndActionDirectSave;
 
   x_catch_errors (dpyinfo->display);
   str = x_get_atom_name (dpyinfo, atom, NULL);
@@ -249,20 +260,26 @@ x_atom_to_symbol (struct x_display_info *dpyinfo, Atom 
atom)
 
 /* Do protocol to assert ourself as a selection owner.
    FRAME shall be the owner; it must be a valid X frame.
+   TIMESTAMP should be the timestamp where selection ownership will be
+   assumed.
+   DND_DATA is the local value that will be used for selection requests
+   with `dpyinfo->pending_dnd_time'.
    Update the Vselection_alist so that we can reply to later requests for
    our selection.  */
 
 void
 x_own_selection (Lisp_Object selection_name, Lisp_Object selection_value,
-                Lisp_Object frame)
+                Lisp_Object frame, Lisp_Object dnd_data, Time timestamp)
 {
   struct frame *f = XFRAME (frame);
   Window selecting_window = FRAME_X_WINDOW (f);
   struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
   Display *display = dpyinfo->display;
-  Time timestamp = dpyinfo->last_user_time;
   Atom selection_atom = symbol_to_x_atom (dpyinfo, selection_name);
 
+  if (!timestamp)
+    timestamp = dpyinfo->last_user_time;
+
   block_input ();
   x_catch_errors (display);
   XSetSelectionOwner (display, selection_atom, selecting_window, timestamp);
@@ -275,8 +292,9 @@ x_own_selection (Lisp_Object selection_name, Lisp_Object 
selection_value,
     Lisp_Object selection_data;
     Lisp_Object prev_value;
 
-    selection_data = list4 (selection_name, selection_value,
-                           INT_TO_INTEGER (timestamp), frame);
+    selection_data = list5 (selection_name, selection_value,
+                           INT_TO_INTEGER (timestamp), frame,
+                           dnd_data);
     prev_value = LOCAL_SELECTION (selection_name, dpyinfo);
 
     tset_selection_alist
@@ -306,18 +324,33 @@ x_own_selection (Lisp_Object selection_name, Lisp_Object 
selection_value,
    This function is used both for remote requests (LOCAL_REQUEST is zero)
    and for local x-get-selection-internal (LOCAL_REQUEST is nonzero).
 
+   If LOCAL_VALUE is non-nil, use it as the local copy.  Also allow
+   quitting in that case, and let DPYINFO be NULL.
+
+   If NEED_ALTERNATE is true, use the drag-and-drop local value
+   instead.
+
    This calls random Lisp code, and may signal or gc.  */
 
 static Lisp_Object
 x_get_local_selection (Lisp_Object selection_symbol, Lisp_Object target_type,
-                      bool local_request, struct x_display_info *dpyinfo)
+                      bool local_request, struct x_display_info *dpyinfo,
+                      Lisp_Object local_value, bool need_alternate)
 {
-  Lisp_Object local_value, tem;
+  Lisp_Object tem;
   Lisp_Object handler_fn, value, check;
+  bool may_quit;
+  specpdl_ref count;
 
-  local_value = LOCAL_SELECTION (selection_symbol, dpyinfo);
+  may_quit = false;
 
-  if (NILP (local_value)) return Qnil;
+  if (NILP (local_value))
+    local_value = LOCAL_SELECTION (selection_symbol, dpyinfo);
+  else
+    may_quit = true;
+
+  if (NILP (local_value))
+    return Qnil;
 
   /* TIMESTAMP is a special case.  */
   if (EQ (target_type, QTIMESTAMP))
@@ -330,8 +363,10 @@ x_get_local_selection (Lisp_Object selection_symbol, 
Lisp_Object target_type,
       /* Don't allow a quit within the converter.
         When the user types C-g, he would be surprised
         if by luck it came during a converter.  */
-      specpdl_ref count = SPECPDL_INDEX ();
-      specbind (Qinhibit_quit, Qt);
+      count = SPECPDL_INDEX ();
+
+      if (!may_quit)
+       specbind (Qinhibit_quit, Qt);
 
       CHECK_SYMBOL (target_type);
       handler_fn = Fcdr (Fassq (target_type, Vselection_converter_alist));
@@ -339,7 +374,10 @@ x_get_local_selection (Lisp_Object selection_symbol, 
Lisp_Object target_type,
       if (CONSP (handler_fn))
        handler_fn = XCDR (handler_fn);
 
-      tem = XCAR (XCDR (local_value));
+      if (!need_alternate)
+       tem = XCAR (XCDR (local_value));
+      else
+       tem = XCAR (XCDR (XCDR (XCDR (XCDR (local_value)))));
 
       if (STRINGP (tem))
        {
@@ -399,10 +437,19 @@ static void
 x_decline_selection_request (struct selection_input_event *event)
 {
   XEvent reply_base;
-  XSelectionEvent *reply = &(reply_base.xselection);
+  XSelectionEvent *reply;
+  Display *dpy;
+  struct x_display_info *dpyinfo;
+
+  reply = &(reply_base.xselection);
+  dpy = SELECTION_EVENT_DISPLAY (event);
+  dpyinfo = x_display_info_for_display (dpy);
+
+  if (!dpyinfo)
+    return;
 
   reply->type = SelectionNotify;
-  reply->display = SELECTION_EVENT_DISPLAY (event);
+  reply->display = dpy;
   reply->requestor = SELECTION_EVENT_REQUESTOR (event);
   reply->selection = SELECTION_EVENT_SELECTION (event);
   reply->time = SELECTION_EVENT_TIME (event);
@@ -412,10 +459,12 @@ 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_catch_errors (reply->display);
-  XSendEvent (reply->display, reply->requestor, False, 0, &reply_base);
-  XFlush (reply->display);
-  x_uncatch_errors ();
+  x_ignore_errors_for_next_request (dpyinfo);
+  XSendEvent (dpyinfo->display, reply->requestor,
+             False, 0, &reply_base);
+  x_stop_ignoring_errors (dpyinfo);
+
+  XFlush (dpyinfo->display);
   unblock_input ();
 }
 
@@ -773,18 +822,31 @@ x_handle_selection_request (struct selection_input_event 
*event)
   Lisp_Object local_selection_data;
   bool success = false;
   specpdl_ref count = SPECPDL_INDEX ();
-  bool pushed;
+  bool pushed, use_alternate;
+  Lisp_Object alias, tem;
+
+  alias = Vx_selection_alias_alist;
+
+  FOR_EACH_TAIL_SAFE (alias)
+    {
+      tem = Qnil;
+
+      if (CONSP (alias))
+       tem = XCAR (alias);
+
+      if (CONSP (tem)
+         && EQ (XCAR (tem), selection_symbol)
+         && SYMBOLP (XCDR (tem)))
+       {
+         selection_symbol = XCDR (tem);
+         break;
+       }
+    }
 
   pushed = false;
 
   if (!dpyinfo)
-    goto DONE;
-
-  /* This is how the XDND protocol recommends dropping text onto a
-     target that doesn't support XDND.  */
-  if (SELECTION_EVENT_TIME (event) == pending_dnd_time + 1
-      || SELECTION_EVENT_TIME (event) == pending_dnd_time + 2)
-    selection_symbol = QXdndSelection;
+    goto REALLY_DONE;
 
   local_selection_data = LOCAL_SELECTION (selection_symbol, dpyinfo);
 
@@ -798,6 +860,17 @@ x_handle_selection_request (struct selection_input_event 
*event)
       && local_selection_time > SELECTION_EVENT_TIME (event))
     goto DONE;
 
+  use_alternate = false;
+
+  /* This is how the XDND protocol recommends dropping text onto a
+     target that doesn't support XDND.  */
+  if (dpyinfo->pending_dnd_time
+      && ((SELECTION_EVENT_TIME (event)
+          == dpyinfo->pending_dnd_time + 1)
+         || (SELECTION_EVENT_TIME (event)
+             == dpyinfo->pending_dnd_time + 2)))
+    use_alternate = true;
+
   block_input ();
   pushed = true;
   x_push_current_selection_request (event, dpyinfo);
@@ -838,7 +911,8 @@ x_handle_selection_request (struct selection_input_event 
*event)
 
          if (subproperty != None)
            subsuccess = x_convert_selection (selection_symbol, subtarget,
-                                             subproperty, true, dpyinfo);
+                                             subproperty, true, dpyinfo,
+                                             use_alternate);
          if (!subsuccess)
            ASET (multprop, 2*j+1, Qnil);
        }
@@ -855,7 +929,8 @@ x_handle_selection_request (struct selection_input_event 
*event)
        property = SELECTION_EVENT_TARGET (event);
       success = x_convert_selection (selection_symbol,
                                     target_symbol, property,
-                                    false, dpyinfo);
+                                    false, dpyinfo,
+                                    use_alternate);
     }
 
  DONE:
@@ -874,6 +949,9 @@ x_handle_selection_request (struct selection_input_event 
*event)
     CALLN (Frun_hook_with_args, Qx_sent_selection_functions,
           selection_symbol, target_symbol, success ? Qt : Qnil);
 
+  /* Used to punt when dpyinfo is NULL.  */
+ REALLY_DONE:
+
   unbind_to (count, Qnil);
 }
 
@@ -887,7 +965,8 @@ x_handle_selection_request (struct selection_input_event 
*event)
 static bool
 x_convert_selection (Lisp_Object selection_symbol,
                     Lisp_Object target_symbol, Atom property,
-                    bool for_multiple, struct x_display_info *dpyinfo)
+                    bool for_multiple, struct x_display_info *dpyinfo,
+                    bool use_alternate)
 {
   Lisp_Object lisp_selection;
   struct selection_data *cs;
@@ -895,7 +974,7 @@ x_convert_selection (Lisp_Object selection_symbol,
 
   lisp_selection
     = x_get_local_selection (selection_symbol, target_symbol,
-                            false, dpyinfo);
+                            false, dpyinfo, Qnil, use_alternate);
 
   frame = selection_request_stack;
 
@@ -1005,6 +1084,26 @@ x_handle_selection_event (struct selection_input_event 
*event)
     x_handle_selection_request (event);
 }
 
+static bool
+x_should_preserve_selection (Lisp_Object selection)
+{
+  Lisp_Object tem;
+
+  tem = Vx_auto_preserve_selections;
+
+  if (CONSP (Vx_auto_preserve_selections))
+    {
+      FOR_EACH_TAIL_SAFE (tem)
+       {
+         if (EQ (XCAR (tem), selection))
+           return true;
+       }
+
+      return false;
+    }
+
+  return !NILP (tem);
+}
 
 /* Clear all selections that were made from frame F.
    We do this when about to delete a frame.  */
@@ -1012,20 +1111,25 @@ x_handle_selection_event (struct selection_input_event 
*event)
 void
 x_clear_frame_selections (struct frame *f)
 {
-  Lisp_Object frame;
-  Lisp_Object rest;
+  Lisp_Object frame, rest, lost, selection;
   struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
   struct terminal *t = dpyinfo->terminal;
 
   XSETFRAME (frame, f);
+  lost = Qnil;
 
   /* Delete elements from the beginning of Vselection_alist.  */
   while (CONSP (t->Vselection_alist)
         && EQ (frame, XCAR (XCDR (XCDR (XCDR (XCAR (t->Vselection_alist)))))))
     {
-      /* Run the `x-lost-selection-functions' abnormal hook.  */
-      CALLN (Frun_hook_with_args, Qx_lost_selection_functions,
-            Fcar (Fcar (t->Vselection_alist)));
+      selection = Fcar (Fcar (t->Vselection_alist));
+
+      if (!x_should_preserve_selection (selection))
+       /* Run the `x-lost-selection-functions' abnormal hook.  */
+       CALLN (Frun_hook_with_args, Qx_lost_selection_functions,
+              selection);
+      else
+       lost = Fcons (Fcar (t->Vselection_alist), lost);
 
       tset_selection_alist (t, XCDR (t->Vselection_alist));
     }
@@ -1035,11 +1139,20 @@ x_clear_frame_selections (struct frame *f)
     if (CONSP (XCDR (rest))
        && EQ (frame, XCAR (XCDR (XCDR (XCDR (XCAR (XCDR (rest))))))))
       {
-       CALLN (Frun_hook_with_args, Qx_lost_selection_functions,
-              XCAR (XCAR (XCDR (rest))));
+       selection = XCAR (XCAR (XCDR (rest)));
+
+       if (!x_should_preserve_selection (selection))
+         CALLN (Frun_hook_with_args, Qx_lost_selection_functions,
+                selection);
+       else
+         lost = Fcons (XCAR (XCDR (rest)), lost);
+
        XSETCDR (rest, XCDR (XCDR (rest)));
        break;
       }
+
+  if (!NILP (lost))
+    x_preserve_selections (dpyinfo, lost, frame);
 }
 
 /* True if any properties for DISPLAY and WINDOW
@@ -1179,6 +1292,20 @@ x_handle_property_notify (const XPropertyEvent *event)
     }
 }
 
+static void
+x_display_selection_waiting_message (struct atimer *timer)
+{
+  Lisp_Object val;
+
+  val = build_string ("Waiting for reply from selection owner...");
+  message3_nolog (val);
+}
+
+static void
+x_cancel_atimer (void *atimer)
+{
+  cancel_atimer (atimer);
+}
 
 
 /* Variables for communication with x_handle_selection_notify.  */
@@ -1204,9 +1331,14 @@ x_get_foreign_selection (Lisp_Object selection_symbol, 
Lisp_Object target_type,
   Atom type_atom = (CONSP (target_type)
                    ? symbol_to_x_atom (dpyinfo, XCAR (target_type))
                    : symbol_to_x_atom (dpyinfo, target_type));
+  struct atimer *delayed_message;
+  struct timespec message_interval;
+  specpdl_ref count;
+
+  count = SPECPDL_INDEX ();
 
   if (!FRAME_LIVE_P (f))
-    return Qnil;
+    return unbind_to (count, Qnil);
 
   if (! NILP (time_stamp))
     CONS_TO_INTEGER (time_stamp, Time, requestor_time);
@@ -1238,11 +1370,23 @@ x_get_foreign_selection (Lisp_Object selection_symbol, 
Lisp_Object target_type,
 
   unblock_input ();
 
+  message_interval = make_timespec (1, 0);
+  delayed_message = start_atimer (ATIMER_RELATIVE, message_interval,
+                                 x_display_selection_waiting_message,
+                                 NULL);
+  record_unwind_protect_ptr (x_cancel_atimer, delayed_message);
+
   /* This allows quits.  Also, don't wait forever.  */
   intmax_t timeout = max (0, x_selection_timeout);
   intmax_t secs = timeout / 1000;
   int nsecs = (timeout % 1000) * 1000000;
-  TRACE1 ("  Start waiting %"PRIdMAX" secs for SelectionNotify", secs);
+  TRACE1 ("  Start waiting %"PRIdMAX" secs for SelectionNotify.", secs);
+
+  if (input_blocked_p ())
+    TRACE0 ("    Input is blocked.");
+  else
+    TRACE1 ("    Waiting for %d nsecs in addition.", nsecs);
+
   /* This function can be called with input blocked inside Xt or GTK
      timeouts run inside popup menus, so use a function that works
      when input is blocked.  Prefer wait_reading_process_output
@@ -1263,13 +1407,16 @@ x_get_foreign_selection (Lisp_Object selection_symbol, 
Lisp_Object target_type,
   if (NILP (XCAR (reading_selection_reply)))
     error ("Timed out waiting for reply from selection owner");
   if (EQ (XCAR (reading_selection_reply), Qlambda))
-    return Qnil;
+    return unbind_to (count, Qnil);
 
   /* Otherwise, the selection is waiting for us on the requested property.  */
-  return
-    x_get_window_property_as_lisp_data (dpyinfo, requestor_window,
-                                       target_property, target_type,
-                                       selection_atom, false);
+  return unbind_to (count,
+                   x_get_window_property_as_lisp_data (dpyinfo,
+                                                       requestor_window,
+                                                       target_property,
+                                                       target_type,
+                                                       selection_atom,
+                                                       false));
 }
 
 /* Subroutines of x_get_window_property_as_lisp_data */
@@ -1607,8 +1754,7 @@ x_get_window_property_as_lisp_data (struct x_display_info 
*dpyinfo,
        ATOM    32      > 1             Vector of Symbols
        *       16      1               Integer
        *       16      > 1             Vector of Integers
-       *       32      1               if small enough: fixnum
-                                       otherwise: bignum
+       *       32      1               Integer
        *       32      > 1             Vector of the above
 
    When converting an object to C, it may be of the form (SYMBOL . <data>)
@@ -1920,9 +2066,9 @@ clean_local_selection_data (Lisp_Object obj)
       && INTEGERP (XCAR (obj))
       && FIXNUMP (XCDR (obj)))
     {
-      if (EQ (XCAR (obj), make_fixnum (0)))
+      if (BASE_EQ (XCAR (obj), make_fixnum (0)))
        return XCDR (obj);
-      if (EQ (XCAR (obj), make_fixnum (-1)))
+      if (BASE_EQ (XCAR (obj), make_fixnum (-1)))
        return make_fixnum (- XFIXNUM (XCDR (obj)));
     }
   if (VECTORP (obj))
@@ -2027,7 +2173,7 @@ On Nextstep, FRAME is unused.  */)
 
   CHECK_SYMBOL (selection);
   if (NILP (value)) error ("VALUE may not be nil");
-  x_own_selection (selection, value, frame);
+  x_own_selection (selection, value, frame, Qnil, 0);
   return value;
 }
 
@@ -2055,17 +2201,29 @@ On Nextstep, TIME-STAMP and TERMINAL are unused.  */)
    Lisp_Object time_stamp, Lisp_Object terminal)
 {
   Lisp_Object val = Qnil;
+  Lisp_Object maybe_alias;
   struct frame *f = frame_for_x_selection (terminal);
 
   CHECK_SYMBOL (selection_symbol);
   CHECK_SYMBOL (target_type);
+
   if (EQ (target_type, QMULTIPLE))
     error ("Retrieving MULTIPLE selections is currently unimplemented");
   if (!f)
     error ("X selection unavailable for this frame");
 
+  /* Quitting inside this function is okay, so we don't have to use
+     FOR_EACH_TAIL_SAFE.  */
+  maybe_alias = Fassq (selection_symbol, Vx_selection_alias_alist);
+
+  if (!NILP (maybe_alias))
+    {
+      selection_symbol = XCDR (maybe_alias);
+      CHECK_SYMBOL (selection_symbol);
+    }
+
   val = x_get_local_selection (selection_symbol, target_type, true,
-                              FRAME_DISPLAY_INFO (f));
+                              FRAME_DISPLAY_INFO (f), Qnil, false);
 
   if (NILP (val) && FRAME_LIVE_P (f))
     {
@@ -2207,6 +2365,49 @@ On Nextstep, TERMINAL is unused.  */)
   return (owner ? Qt : Qnil);
 }
 
+DEFUN ("x-get-local-selection", Fx_get_local_selection, Sx_get_local_selection,
+       0, 2, 0,
+       doc: /* Run selection converters for VALUE, and return the result.
+TARGET is the selection target that is used to find a suitable
+converter.  VALUE is a list of 4 values NAME, SELECTION-VALUE,
+TIMESTAMP and FRAME.  NAME is the name of the selection that will be
+passed to selection converters, SELECTION-VALUE is the value of the
+selection used by the converter, TIMESTAMP is not meaningful (but must
+be a number that fits in an X timestamp), and FRAME is the frame
+describing the terminal for which the selection converter will be
+run.  */)
+  (Lisp_Object value, Lisp_Object target)
+{
+  Time time;
+  Lisp_Object name, timestamp, frame, result;
+
+  CHECK_SYMBOL (target);
+
+  /* Check that VALUE has 4 elements, for x_get_local_selection.  */
+  Lisp_Object v = value; CHECK_CONS (v);
+  name = XCAR (v); v = XCDR (v); CHECK_CONS (v);
+  v = XCDR (v); CHECK_CONS (v);
+  timestamp = XCAR (v); v = XCDR (v); CHECK_CONS (v);
+  frame = XCAR (v);
+
+  CHECK_SYMBOL (name);
+  CONS_TO_INTEGER (timestamp, Time, time);
+  check_window_system (decode_live_frame (frame));
+
+  result = x_get_local_selection (name, target, true,
+                                 NULL, value, false);
+
+  if (CONSP (result) && SYMBOLP (XCAR (result)))
+    {
+      result = XCDR (result);
+
+      if (CONSP (result) && NILP (XCDR (result)))
+       result = XCAR (result);
+    }
+
+  return clean_local_selection_data (result);
+}
+
 
 /* Send clipboard manager a SAVE_TARGETS request with a UTF8_STRING
    property (https://www.freedesktop.org/wiki/ClipboardManager/).  */
@@ -2609,7 +2810,11 @@ to send.  If a value is a string, it is converted to an 
Atom and the value of
 the Atom is sent.  If a value is a cons, it is converted to a 32 bit number
 with the high 16 bits from the car and the lower 16 bit from the cdr.
 If more values than fits into the event is given, the excessive values
-are ignored.  */)
+are ignored.
+
+Wait for the event to be sent and signal any error, unless
+`x-fast-protocol-requests' is non-nil, in which case errors will be
+silently ignored.  */)
   (Lisp_Object display, Lisp_Object dest, Lisp_Object from,
    Lisp_Object message_type, Lisp_Object format, Lisp_Object values)
 {
@@ -2690,7 +2895,7 @@ x_send_client_event (Lisp_Object display, Lisp_Object 
dest, Lisp_Object from,
      the destination window.  But if we are sending to the root window,
      there is no such client.  Then we set the event mask to 0xffffff.  The
      event then goes to clients selecting for events on the root window.  */
-  x_catch_errors (dpyinfo->display);
+  x_catch_errors_for_lisp (dpyinfo);
   {
     bool propagate = !to_root;
     long mask = to_root ? 0xffffff : 0;
@@ -2698,7 +2903,8 @@ x_send_client_event (Lisp_Object display, Lisp_Object 
dest, Lisp_Object from,
     XSendEvent (dpyinfo->display, wdest, propagate, mask, &event);
     XFlush (dpyinfo->display);
   }
-  x_uncatch_errors ();
+  x_check_errors_for_lisp (dpyinfo, "Failed to send client event: %s");
+  x_uncatch_errors_for_lisp (dpyinfo);
   unblock_input ();
 }
 
@@ -2723,12 +2929,6 @@ x_timestamp_for_selection (struct x_display_info 
*dpyinfo,
   return value;
 }
 
-void
-x_set_pending_dnd_time (Time time)
-{
-  pending_dnd_time = time;
-}
-
 static void syms_of_xselect_for_pdumper (void);
 
 void
@@ -2743,6 +2943,7 @@ syms_of_xselect (void)
   defsubr (&Sx_get_atom_name);
   defsubr (&Sx_send_client_message);
   defsubr (&Sx_register_dnd_atom);
+  defsubr (&Sx_get_local_selection);
 
   reading_selection_reply = Fcons (Qnil, Qnil);
   staticpro (&reading_selection_reply);
@@ -2818,6 +3019,15 @@ If non-nil, selection converters for string types 
(`STRING',
 when Emacs itself is converting the selection.  */);
   Vx_treat_local_requests_remotely = Qnil;
 
+  DEFVAR_LISP ("x-selection-alias-alist", Vx_selection_alias_alist,
+    doc: /* List of selections to alias to another.
+It should be an alist of a selection name to another.  When a
+selection request arrives for the first selection, Emacs will respond
+as if the request was meant for the other.
+
+Note that this does not affect setting or owning selections.  */);
+  Vx_selection_alias_alist = Qnil;
+
   /* QPRIMARY is defined in keyboard.c.  */
   DEFSYM (QSECONDARY, "SECONDARY");
   DEFSYM (QSTRING, "STRING");
@@ -2839,6 +3049,9 @@ when Emacs itself is converting the selection.  */);
   DEFSYM (QCLIPBOARD_MANAGER, "CLIPBOARD_MANAGER");
   DEFSYM (QSAVE_TARGETS, "SAVE_TARGETS");
   DEFSYM (QNULL, "NULL");
+  DEFSYM (QXdndDirectSave0, "XdndDirectSave0");
+  DEFSYM (QXdndActionDirectSave, "XdndActionDirectSave");
+  DEFSYM (Qtext_plain, "text/plain");
   DEFSYM (Qforeign_selection, "foreign-selection");
   DEFSYM (Qx_lost_selection_functions, "x-lost-selection-functions");
   DEFSYM (Qx_sent_selection_functions, "x-sent-selection-functions");
diff --git a/src/xsettings.c b/src/xsettings.c
index c29a844e0a..9c60ff825a 100644
--- a/src/xsettings.c
+++ b/src/xsettings.c
@@ -964,9 +964,10 @@ read_and_apply_settings (Display_Info *dpyinfo, bool 
send_event_p)
 #endif
 
 #ifndef HAVE_PGTK
-/* Check if EVENT for the display in DPYINFO is XSettings related.  */
+/* Check if EVENT for the display in DPYINFO is XSettings related.
+   Return true if it is, after performing associated side effects.  */
 
-void
+bool
 xft_settings_event (Display_Info *dpyinfo, const XEvent *event)
 {
   bool check_window_p = false, apply_settings_p = false;
@@ -1004,6 +1005,8 @@ xft_settings_event (Display_Info *dpyinfo, const XEvent 
*event)
 
   if (apply_settings_p)
     read_and_apply_settings (dpyinfo, true);
+
+  return check_window_p || apply_settings_p;
 }
 #endif
 
diff --git a/src/xsettings.h b/src/xsettings.h
index 5e5df37062..833c2b367d 100644
--- a/src/xsettings.h
+++ b/src/xsettings.h
@@ -36,7 +36,7 @@ typedef struct pgtk_display_info Display_Info;
 
 extern void xsettings_initialize (Display_Info *);
 #ifndef HAVE_PGTK
-extern void xft_settings_event (Display_Info *, const XEvent *);
+extern bool xft_settings_event (Display_Info *, const XEvent *);
 #endif
 extern const char *xsettings_get_system_font (void);
 #ifdef USE_LUCID
diff --git a/src/xterm.c b/src/xterm.c
index 2cc17b455d..7a0a21b136 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -233,18 +233,19 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
        EMACS_CHECK_MODULES([XFIXES], [$XFIXES_MODULES])
        if test $HAVE_XFIXES = no; then
         # Test old way in case pkg-config doesn't have it (older machines).
-        AC_CHECK_HEADER(X11/extensions/Xfixes.h,
-          [AC_CHECK_LIB(Xfixes, XFixesHideCursor, HAVE_XFIXES=yes)])
+        AC_CHECK_HEADER([X11/extensions/Xfixes.h],
+          [AC_CHECK_LIB([Xfixes], [XFixesHideCursor], [HAVE_XFIXES=yes])])
         if test $HAVE_XFIXES = yes; then
           XFIXES_LIBS=-lXfixes
         fi
        fi
        if test $HAVE_XFIXES = yes; then
-        AC_DEFINE(HAVE_XFIXES, 1, [Define to 1 if you have the Xfixes 
extension.])
+        AC_DEFINE([HAVE_XFIXES], [1],
+          [Define to 1 if you have the Xfixes extension.])
        fi
      fi
-     AC_SUBST(XFIXES_CFLAGS)
-     AC_SUBST(XFIXES_LIBS)
+     AC_SUBST([XFIXES_CFLAGS])
+     AC_SUBST([XFIXES_LIBS])
 
   Then, make sure to adjust CFLAGS and LIBES in src/Makefile.in and
   add the new XFIXES_CFLAGS and XFIXES_LIBS variables to
@@ -497,7 +498,7 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
     data.l[1] = timestamp
     data.l[2] = low 32 bits of a provided frame counter value
     data.l[3] = high 32 bits of a provided frame counter value
-    data.l[4] = 1 if the the extended frame counter should be updated,
+    data.l[4] = 1 if the extended frame counter should be updated,
     otherwise 0
 
   Upon receiving such an event, Emacs constructs and saves a counter
@@ -520,9 +521,9 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
   replying to the initiating client) is performed from Lisp inside
   `x-dnd.el'.
 
-  However, dragging contents from Emacs is implemented entirely in C.
-  X Windows has several competing drag-and-drop protocols, of which
-  Emacs supports two: the XDND protocol (see
+  However, dragging contents from Emacs is implemented almost entirely
+  in C.  X Windows has several competing drag-and-drop protocols, of
+  which Emacs supports two on the C level: the XDND protocol (see
   https://freedesktop.org/wiki/Specifications/XDND) and the Motif drag
   and drop protocols.  These protocols are based on the initiator
   owning a special selection, specifying an action the recipient
@@ -545,7 +546,16 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
   released over the recipient window, Emacs sends a "drop" message to
   the target window, waits for a reply, and returns the action
   selected by the recipient to the Lisp code that initiated the
-  drag-and-drop operation.  */
+  drag-and-drop operation.
+
+  When a drop happens on a window not supporting any protocol
+  implemented on the C level, the function inside
+  `x-dnd-unsupported-drop-function' is called with some parameters of
+  the drop.  If it returns non-nil, then Emacs tries to simulate a
+  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.  */
 
 #include <config.h>
 #include <stdlib.h>
@@ -710,6 +720,12 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #include <X11/XKBlib.h>
 #endif
 
+/* Although X11/Xlib.h commonly defines the types XErrorHandler and
+   XIOErrorHandler, they are not in the Xlib spec, so for portability
+   define and use names with an Emacs_ prefix instead.  */
+typedef int (*Emacs_XErrorHandler) (Display *, XErrorEvent *);
+typedef int (*Emacs_XIOErrorHandler) (Display *);
+
 #if defined USE_XCB && defined USE_CAIRO_XCB
 #define USE_CAIRO_XCB_SURFACE
 #endif
@@ -789,10 +805,28 @@ static int current_finish;
 static struct input_event *current_hold_quit;
 #endif
 
+#ifdef HAVE_XINPUT2
+#ifndef X_XIGrabDevice
+#define X_XIGrabDevice 51
+#endif
+
+#ifndef X_XIUngrabDevice
+#define X_XIUngrabDevice 52
+#endif
+
+#ifndef X_XIAllowEvents
+#define X_XIAllowEvents 53
+#endif
+#endif
+
 /* Queue selection requests in `pending_selection_requests' if more
    than 0.  */
 static int x_use_pending_selection_requests;
 
+/* Like `next_kbd_event', but for use in X code.  */
+#define X_NEXT_KBD_EVENT(ptr) \
+  ((ptr) == kbd_buffer + KBD_BUFFER_SIZE - 1 ? kbd_buffer : (ptr) + 1)
+
 static void x_push_selection_request (struct selection_input_event *);
 
 /* Defer selection requests.  Between this and
@@ -829,14 +863,18 @@ x_defer_selection_requests (void)
                 avoids exhausting the keyboard buffer with some
                 over-enthusiastic clipboard managers.  */
              if (!between)
-               kbd_fetch_ptr = (event == kbd_buffer + KBD_BUFFER_SIZE - 1
-                                ? kbd_buffer : event + 1);
+               {
+                 kbd_fetch_ptr = X_NEXT_KBD_EVENT (event);
+
+                 /* `detect_input_pending' will then recompute
+                    whether or not pending input events exist.  */
+                 input_pending = false;
+               }
            }
          else
            between = true;
 
-         event = (event == kbd_buffer + KBD_BUFFER_SIZE - 1
-                  ? kbd_buffer : event + 1);
+         event = X_NEXT_KBD_EVENT (event);
        }
     }
 
@@ -914,7 +952,7 @@ static const struct x_atom_ref x_atom_refs[] =
     ATOM_REFS_INIT ("MULTIPLE", Xatom_MULTIPLE)
     ATOM_REFS_INIT ("INCR", Xatom_INCR)
     ATOM_REFS_INIT ("_EMACS_TMP_",  Xatom_EMACS_TMP)
-    ATOM_REFS_INIT ("EMACS_SERVER_TIME_PROP", Xatom_EMACS_SERVER_TIME_PROP)
+    ATOM_REFS_INIT ("_EMACS_SERVER_TIME_PROP", Xatom_EMACS_SERVER_TIME_PROP)
     ATOM_REFS_INIT ("TARGETS", Xatom_TARGETS)
     ATOM_REFS_INIT ("NULL", Xatom_NULL)
     ATOM_REFS_INIT ("ATOM", Xatom_ATOM)
@@ -922,6 +960,7 @@ static const struct x_atom_ref x_atom_refs[] =
     ATOM_REFS_INIT ("CLIPBOARD_MANAGER", Xatom_CLIPBOARD_MANAGER)
     ATOM_REFS_INIT ("_XEMBED_INFO", Xatom_XEMBED_INFO)
     ATOM_REFS_INIT ("_MOTIF_WM_HINTS", Xatom_MOTIF_WM_HINTS)
+    ATOM_REFS_INIT ("_EMACS_DRAG_ATOM", Xatom_EMACS_DRAG_ATOM)
     /* For properties of font.  */
     ATOM_REFS_INIT ("PIXEL_SIZE", Xatom_PIXEL_SIZE)
     ATOM_REFS_INIT ("AVERAGE_WIDTH", Xatom_AVERAGE_WIDTH)
@@ -958,7 +997,9 @@ static const struct x_atom_ref x_atom_refs[] =
     ATOM_REFS_INIT ("_NET_WORKAREA", Xatom_net_workarea)
     ATOM_REFS_INIT ("_NET_WM_SYNC_REQUEST", Xatom_net_wm_sync_request)
     ATOM_REFS_INIT ("_NET_WM_SYNC_REQUEST_COUNTER", 
Xatom_net_wm_sync_request_counter)
+    ATOM_REFS_INIT ("_NET_WM_SYNC_FENCES", Xatom_net_wm_sync_fences)
     ATOM_REFS_INIT ("_NET_WM_FRAME_DRAWN", Xatom_net_wm_frame_drawn)
+    ATOM_REFS_INIT ("_NET_WM_FRAME_TIMINGS", Xatom_net_wm_frame_timings)
     ATOM_REFS_INIT ("_NET_WM_USER_TIME", Xatom_net_wm_user_time)
     ATOM_REFS_INIT ("_NET_WM_USER_TIME_WINDOW", Xatom_net_wm_user_time_window)
     ATOM_REFS_INIT ("_NET_CLIENT_LIST_STACKING", 
Xatom_net_client_list_stacking)
@@ -997,6 +1038,10 @@ static const struct x_atom_ref x_atom_refs[] =
     ATOM_REFS_INIT ("XdndLeave", Xatom_XdndLeave)
     ATOM_REFS_INIT ("XdndDrop", Xatom_XdndDrop)
     ATOM_REFS_INIT ("XdndFinished", Xatom_XdndFinished)
+    /* XDS source and target.  */
+    ATOM_REFS_INIT ("XdndDirectSave0", Xatom_XdndDirectSave0)
+    ATOM_REFS_INIT ("XdndActionDirectSave", Xatom_XdndActionDirectSave)
+    ATOM_REFS_INIT ("text/plain", Xatom_text_plain)
     /* Motif drop protocol support.  */
     ATOM_REFS_INIT ("_MOTIF_DRAG_WINDOW", Xatom_MOTIF_DRAG_WINDOW)
     ATOM_REFS_INIT ("_MOTIF_DRAG_TARGETS", Xatom_MOTIF_DRAG_TARGETS)
@@ -1008,6 +1053,9 @@ static const struct x_atom_ref x_atom_refs[] =
                    Xatom_MOTIF_DRAG_RECEIVER_INFO)
     ATOM_REFS_INIT ("XmTRANSFER_SUCCESS", Xatom_XmTRANSFER_SUCCESS)
     ATOM_REFS_INIT ("XmTRANSFER_FAILURE", Xatom_XmTRANSFER_FAILURE)
+    /* Old OffiX (a.k.a. old KDE) drop protocol support.  */
+    ATOM_REFS_INIT ("DndProtocol", Xatom_DndProtocol)
+    ATOM_REFS_INIT ("_DND_PROTOCOL", Xatom_DND_PROTOCOL)
   };
 
 enum
@@ -1050,6 +1098,7 @@ static void x_frame_rehighlight (struct x_display_info *);
 static void x_clip_to_row (struct window *, struct glyph_row *,
                           enum glyph_row_area, GC);
 static struct scroll_bar *x_window_to_scroll_bar (Display *, Window, int);
+static struct frame *x_window_to_frame (struct x_display_info *, int);
 static void x_scroll_bar_report_motion (struct frame **, Lisp_Object *,
                                         enum scroll_bar_part *,
                                         Lisp_Object *, Lisp_Object *,
@@ -1081,27 +1130,24 @@ static void x_initialize (void);
 static bool x_get_current_wm_state (struct frame *, Window, int *, bool *, 
bool *);
 static void x_update_opaque_region (struct frame *, XEvent *);
 
-#if !defined USE_TOOLKIT_SCROLL_BARS && defined HAVE_XDBE
-static void x_scroll_bar_end_update (struct x_display_info *, struct 
scroll_bar *);
-#endif
-
 #ifdef HAVE_X_I18N
 static int x_filter_event (struct x_display_info *, XEvent *);
 #endif
+static void x_clean_failable_requests (struct x_display_info *);
 
 static struct frame *x_tooltip_window_to_frame (struct x_display_info *,
                                                Window, bool *);
 static Window x_get_window_below (Display *, Window, int, int, int *, int *);
 
+#ifndef USE_TOOLKIT_SCROLL_BARS
+static void x_scroll_bar_redraw (struct scroll_bar *);
+#endif
+
 /* Global state maintained during a drag-and-drop operation.  */
 
 /* Flag that indicates if a drag-and-drop operation is in progress.  */
 bool x_dnd_in_progress;
 
-/* Number that indicates the last "generation" of
-   UNSUPPORTED_DROP_EVENTs handled.  */
-unsigned x_dnd_unsupported_event_level;
-
 /* The frame where the drag-and-drop operation originated.  */
 struct frame *x_dnd_frame;
 
@@ -1116,6 +1162,20 @@ struct frame *x_dnd_finish_frame;
    important information.  */
 bool x_dnd_waiting_for_finish;
 
+/* Flag that means (when set in addition to
+   `x_dnd_waiting_for_finish') to run the unsupported drop function
+   with the given arguments.  */
+static bool x_dnd_run_unsupported_drop_function;
+
+/* The "before"-time of the unsupported drop.  */
+static Time x_dnd_unsupported_drop_time;
+
+/* The target window of the unsupported drop.  */
+static Window x_dnd_unsupported_drop_window;
+
+/* The Lisp data associated with the unsupported drop function.  */
+static Lisp_Object x_dnd_unsupported_drop_data;
+
 /* Whether or not to move the tooltip along with the mouse pointer
    during drag-and-drop.  */
 static bool x_dnd_update_tooltip;
@@ -1151,6 +1211,9 @@ static bool x_dnd_xm_use_help;
 /* Whether or not Motif drag initiator info was set up.  */
 static bool x_dnd_motif_setup_p;
 
+/* The Motif drag atom used during the drag-and-drop operation.  */
+static Atom x_dnd_motif_atom;
+
 /* The target window we are waiting for an XdndFinished message
    from.  */
 static Window x_dnd_pending_finish_target;
@@ -1216,6 +1279,30 @@ static Window x_dnd_mouse_rect_target;
    drop target if the mouse pointer lies within.  */
 static XRectangle x_dnd_mouse_rect;
 
+/* If not None, Emacs is waiting for an XdndStatus event from this
+   window.  */
+static Window x_dnd_waiting_for_status_window;
+
+/* If .type != 0, an event that should be sent to .xclient.window
+   upon receiving an XdndStatus event from said window.  */
+static XEvent x_dnd_pending_send_position;
+
+/* Whether or not that event corresponds to a button press.  */
+static bool x_dnd_pending_send_position_button;
+
+/* The root-window position of that event.  */
+static int x_dnd_pending_send_position_root_x;
+
+/* Likewise.  */
+static int x_dnd_pending_send_position_root_y;
+
+/* If true, send a drop from `x_dnd_finish_frame' to the pending
+   status window after receiving all pending XdndStatus events.  */
+static bool x_dnd_need_send_drop;
+
+/* The protocol version of any such drop.  */
+static int x_dnd_send_drop_proto;
+
 /* The action the drop target actually chose to perform.
 
    Under XDND, this is set upon receiving the XdndFinished or
@@ -1268,6 +1355,21 @@ static struct frame *x_dnd_movement_frame;
    with.  */
 static int x_dnd_movement_x, x_dnd_movement_y;
 
+/* The frame for which `x-dnd-wheel-function' should be called.  */
+static struct frame *x_dnd_wheel_frame;
+
+/* The coordinates which the wheel function should be called with.  */
+static int x_dnd_wheel_x, x_dnd_wheel_y;
+
+/* The button that was pressed.  */
+static int x_dnd_wheel_button;
+
+/* The modifier state when the button was pressed.  */
+static int x_dnd_wheel_state;
+
+/* When the button was pressed.  */
+static Time x_dnd_wheel_time;
+
 #ifdef HAVE_XKB
 /* The keyboard state during the drag-and-drop operation.  */
 static unsigned int x_dnd_keyboard_state;
@@ -1285,6 +1387,26 @@ static bool x_dnd_inside_handle_one_xevent;
    started.  */
 static int x_dnd_recursion_depth;
 
+/* The cons cell containing the selection alias between the Motif drag
+   selection and `XdndSelection'.  The car and cdr are only set when
+   initiating Motif drag-and-drop for the first time.  */
+static Lisp_Object x_dnd_selection_alias_cell;
+
+/* The last known position of the tooltip window.  */
+static int x_dnd_last_tooltip_x, x_dnd_last_tooltip_y;
+
+/* Whether or not those values are actually known yet.  */
+static bool x_dnd_last_tooltip_valid;
+
+#ifdef HAVE_XINPUT2
+/* The master pointer device being used for the drag-and-drop
+   operation.  */
+static int x_dnd_pointer_device;
+
+/* The keyboard device attached to that pointer device.  */
+static int x_dnd_keyboard_device;
+#endif
+
 /* Structure describing a single window that can be the target of
    drag-and-drop operations.  */
 struct x_client_list_window
@@ -1352,7 +1474,7 @@ static bool x_dnd_use_toplevels;
 /* Motif drag-and-drop protocol support.  */
 
 /* Pointer to a variable which stores whether or not an X error
-   occured while trying to create the Motif drag window.  */
+   occurred while trying to create the Motif drag window.  */
 static volatile bool *xm_drag_window_error;
 
 typedef enum xm_byte_order
@@ -1471,6 +1593,17 @@ typedef struct xm_drag_motion_message
   /* CARD16 */ uint16_t x, y;
 } xm_drag_motion_message;
 
+typedef struct xm_drag_motion_reply
+{
+  /* BYTE   */ uint8_t reason;
+  /* BYTE   */ uint8_t byte_order;
+
+  /* CARD16 */ uint16_t side_effects;
+  /* CARD32 */ uint32_t timestamp;
+  /* CARD16 */ uint16_t better_x;
+  /* CARD16 */ uint16_t better_y;
+} xm_drag_motion_reply;
+
 typedef struct xm_top_level_leave_message
 {
   /* BYTE   */ uint8_t reason;
@@ -1493,12 +1626,16 @@ typedef struct xm_top_level_leave_message
 
 enum xm_drag_operation
   {
-    XM_DRAG_NOOP = 0,
-    XM_DRAG_MOVE = (1L << 0),
-    XM_DRAG_COPY = (1L << 1),
-    XM_DRAG_LINK = (1L << 2),
+    XM_DRAG_NOOP     = 0,
+    XM_DRAG_MOVE     = (1L << 0),
+    XM_DRAG_COPY     = (1L << 1),
+    XM_DRAG_LINK     = (1L << 2),
+    XM_DRAG_LINK_REC = 3,
   };
 
+#define XM_DRAG_OPERATION_IS_LINK(op)  ((op) == XM_DRAG_LINK           \
+                                        || (op) == XM_DRAG_LINK_REC)
+
 enum xm_drag_action
   {
     XM_DROP_ACTION_DROP               = 0,
@@ -1627,12 +1764,12 @@ xm_read_targets_table_rec (uint8_t *bytes, ptrdiff_t 
length,
 
   nitems = *(uint16_t *) bytes;
 
-  if (length < 2 + nitems * 4)
-    return NULL;
-
   if (byteorder != XM_BYTE_ORDER_CUR_FIRST)
     SWAPCARD16 (nitems);
 
+  if (length < 2 + nitems * 4)
+    return NULL;
+
   rec = xmalloc (FLEXSIZEOF (struct xm_targets_table_rec,
                             targets, nitems * 4));
   rec->n_targets = nitems;
@@ -1767,20 +1904,59 @@ xm_drag_window_io_error_handler (Display *dpy)
   siglongjmp (x_dnd_disconnect_handler, 1);
 }
 
+/* Determine whether or not WINDOW exists on DPYINFO by selecting for
+   input from it.  */
+static bool
+x_special_window_exists_p (struct x_display_info *dpyinfo,
+                          Window window)
+{
+  bool rc;
+
+  x_catch_errors (dpyinfo->display);
+  XSelectInput (dpyinfo->display, window,
+               StructureNotifyMask);
+  rc = !x_had_errors_p (dpyinfo->display);
+  x_uncatch_errors_after_check ();
+
+  return rc;
+}
+
+/* Drag window creation strategy (very tricky, but race-free):
+
+   First look for _MOTIF_DRAG_WINDOW.  If it is already present,
+   return it immediately to avoid the overhead of new display
+   connections.
+
+   Otherwise, create a new connection to the display. In that
+   connection, create a window, which will be the new drag window. Set
+   the client disconnect mode of the new connection to
+   RetainPermanent, and close it.
+
+   Grab the current display.  Look up _MOTIF_DRAG_WINDOW, the current
+   drag window.  If it exists (which means _MOTIF_DRAG_WINDOW was
+   created between the first step and now), kill the client that
+   created the new drag window to free the client slot on the X
+   server.  Otherwise, set _MOTIF_DRAG_WINDOW to the new drag window.
+
+   Ungrab the display and return whichever window is currently in
+   _MOTIF_DRAG_WINDOW.  */
+
 static Window
-xm_get_drag_window (struct x_display_info *dpyinfo)
+xm_get_drag_window_1 (struct x_display_info *dpyinfo)
 {
-  Atom actual_type, _MOTIF_DRAG_WINDOW;
+  Atom actual_type;
   int rc, actual_format;
   unsigned long nitems, bytes_remaining;
   unsigned char *tmp_data = NULL;
   Window drag_window;
   XSetWindowAttributes attrs;
   Display *temp_display;
-  void *old_handler, *old_io_handler;
-  /* These are volatile because GCC mistakenly warns about them being
+  Emacs_XErrorHandler old_handler;
+  Emacs_XIOErrorHandler old_io_handler;
+
+  /* This is volatile because GCC mistakenly warns about them being
      clobbered by longjmp.  */
-  volatile bool error, created;
+  volatile bool error;
 
   drag_window = None;
   rc = XGetWindowProperty (dpyinfo->display, dpyinfo->root_window,
@@ -1789,28 +1965,20 @@ xm_get_drag_window (struct x_display_info *dpyinfo)
                           &actual_format, &nitems, &bytes_remaining,
                           &tmp_data) == Success;
 
-  if (rc)
+  if (rc && actual_type == XA_WINDOW
+      && actual_format == 32 && nitems == 1
+      && tmp_data)
     {
-      if (actual_type == XA_WINDOW
-         && actual_format == 32 && nitems == 1)
-       {
-         drag_window = *(Window *) tmp_data;
-         x_catch_errors (dpyinfo->display);
-         /* We use ButtonPressMask since it's one of the events an
-            input-only window can never get.  */
-         XSelectInput (dpyinfo->display, drag_window,
-                       ButtonPressMask);
-         rc = !x_had_errors_p (dpyinfo->display);
-         x_uncatch_errors_after_check ();
-
-         if (!rc)
-           drag_window = None;
-       }
+      drag_window = *(Window *) tmp_data;
+      rc = x_special_window_exists_p (dpyinfo, drag_window);
 
-      if (tmp_data)
-       XFree (tmp_data);
+      if (!rc)
+       drag_window = None;
     }
 
+  if (tmp_data)
+    XFree (tmp_data);
+
   if (drag_window == None)
     {
       block_input ();
@@ -1839,74 +2007,22 @@ xm_get_drag_window (struct x_display_info *dpyinfo)
       error = false;
       xm_drag_window_error = &error;
 
-      XGrabServer (temp_display);
       XSetCloseDownMode (temp_display, RetainPermanent);
+      old_handler = XSetErrorHandler (xm_drag_window_error_handler);
 
-      /* We can't use XErrorHandler since it's not in the Xlib
-        specification, and Emacs tries to be portable.  */
-      old_handler = (void *) XSetErrorHandler (xm_drag_window_error_handler);
-
-      _MOTIF_DRAG_WINDOW = XInternAtom (temp_display,
-                                       "_MOTIF_DRAG_WINDOW", False);
-
-      if (error)
-       goto give_up;
-
-      /* Some other program might've created a drag window between now
-        and when we first looked.  Use that if it exists.  */
-
-      tmp_data = NULL;
-      rc = XGetWindowProperty (temp_display, DefaultRootWindow (temp_display),
-                              _MOTIF_DRAG_WINDOW, 0, 1, False, XA_WINDOW,
-                              &actual_type, &actual_format, &nitems,
-                              &bytes_remaining, &tmp_data) == Success;
-
-      if (rc && actual_type == XA_WINDOW
-         && actual_format == 32 && nitems == 1
-         && tmp_data)
-       drag_window = *(Window *) tmp_data;
-
-      if (tmp_data)
-       XFree (tmp_data);
-
-      error = false;
-
-      if (drag_window == None)
-       {
-         created = true;
-
-         attrs.override_redirect = True;
-         drag_window = XCreateWindow (temp_display, DefaultRootWindow 
(temp_display),
-                                      -1, -1, 1, 1, 0, CopyFromParent, 
InputOnly,
-                                      CopyFromParent, CWOverrideRedirect, 
&attrs);
-         XChangeProperty (temp_display, DefaultRootWindow (temp_display),
-                          _MOTIF_DRAG_WINDOW, XA_WINDOW, 32, PropModeReplace,
-                          (unsigned char *) &drag_window, 1);
-       }
-      else
-       created = false;
+      attrs.override_redirect = True;
+      drag_window = XCreateWindow (temp_display, DefaultRootWindow 
(temp_display),
+                                  -1, -1, 1, 1, 0, CopyFromParent, InputOnly,
+                                  CopyFromParent, CWOverrideRedirect, &attrs);
 
       /* Handle all errors now.   */
       XSync (temp_display, False);
 
-    give_up:
-
       /* Some part of the drag window creation process failed, so
-        punt.  */
+        punt.  Release all resources too.  */
       if (error)
        {
-         /* If the drag window was actually created, delete it now.
-            Probably, a BadAlloc happened during the XChangeProperty
-            request.  */
-         if (created)
-           {
-             if (drag_window != None)
-               XDestroyWindow (temp_display, drag_window);
-
-             XDeleteProperty (temp_display, DefaultRootWindow (temp_display),
-                              _MOTIF_DRAG_WINDOW);
-           }
-
+         XSetCloseDownMode (temp_display, DestroyAll);
          drag_window = None;
        }
 
@@ -1924,23 +2040,64 @@ xm_get_drag_window (struct x_display_info *dpyinfo)
       /* Make sure the drag window created is actually valid for the
         current display, and the XOpenDisplay above didn't
         accidentally connect to some other display.  */
-      x_catch_errors (dpyinfo->display);
-      /* We use ButtonPressMask since it's one of the events an
-        input-only window can never get.  */
-      XSelectInput (dpyinfo->display, drag_window,
-                   ButtonPressMask);
-      rc = !x_had_errors_p (dpyinfo->display);
-      x_uncatch_errors_after_check ();
+      if (!x_special_window_exists_p (dpyinfo, drag_window))
+       drag_window = None;
       unblock_input ();
 
-      /* We connected to the wrong display, so just give up.  */
-      if (!rc)
-       drag_window = None;
+      if (drag_window != None)
+       {
+         XGrabServer (dpyinfo->display);
+
+         x_catch_errors (dpyinfo->display);
+         tmp_data = NULL;
+
+         rc = XGetWindowProperty (dpyinfo->display, dpyinfo->root_window,
+                                  dpyinfo->Xatom_MOTIF_DRAG_WINDOW,
+                                  0, 1, False, XA_WINDOW, &actual_type,
+                                  &actual_format, &nitems, &bytes_remaining,
+                                  &tmp_data) == Success;
+
+         if (rc && actual_type == XA_WINDOW
+             && actual_format == 32 && nitems == 1
+             && tmp_data
+             && x_special_window_exists_p (dpyinfo,
+                                           *(Window *) tmp_data))
+           {
+             /* Kill the client now to avoid leaking a client slot,
+                which is a limited resource.  */
+             XKillClient (dpyinfo->display, drag_window);
+             drag_window = *(Window *) tmp_data;
+           }
+         else
+           XChangeProperty (dpyinfo->display, dpyinfo->root_window,
+                            dpyinfo->Xatom_MOTIF_DRAG_WINDOW,
+                            XA_WINDOW, 32, PropModeReplace,
+                            (unsigned char *) &drag_window, 1);
+
+         if (tmp_data)
+           XFree (tmp_data);
+
+         if (x_had_errors_p (dpyinfo->display))
+           drag_window = None;
+         x_uncatch_errors ();
+
+         XUngrabServer (dpyinfo->display);
+       }
     }
 
   return drag_window;
 }
 
+static Window
+xm_get_drag_window (struct x_display_info *dpyinfo)
+{
+  if (dpyinfo->motif_drag_window != None)
+    return dpyinfo->motif_drag_window;
+
+  dpyinfo->motif_drag_window = xm_get_drag_window_1 (dpyinfo);
+  return dpyinfo->motif_drag_window;
+}
+
 static int
 xm_setup_dnd_targets (struct x_display_info *dpyinfo,
                      Atom *targets, int ntargets)
@@ -1950,13 +2107,16 @@ xm_setup_dnd_targets (struct x_display_info *dpyinfo,
   unsigned char *tmp_data = NULL;
   unsigned long nitems, bytes_remaining;
   int rc, actual_format, idx;
+  bool had_errors;
   xm_targets_table_header header;
-  xm_targets_table_rec **recs;
+  xm_targets_table_rec **recs UNINIT;
   xm_byte_order byteorder;
   uint8_t *data;
   ptrdiff_t total_bytes, total_items, i;
   uint32_t size, target_count;
 
+ retry_drag_window:
+
   drag_window = xm_get_drag_window (dpyinfo);
 
   if (drag_window == None || ntargets > 64)
@@ -1969,12 +2129,26 @@ xm_setup_dnd_targets (struct x_display_info *dpyinfo,
         sizeof (Atom), x_atoms_compare);
 
   XGrabServer (dpyinfo->display);
+
+  x_catch_errors (dpyinfo->display);
   rc = XGetWindowProperty (dpyinfo->display, drag_window,
                           dpyinfo->Xatom_MOTIF_DRAG_TARGETS,
                           0L, LONG_MAX, False,
                           dpyinfo->Xatom_MOTIF_DRAG_TARGETS,
                           &actual_type, &actual_format, &nitems,
                           &bytes_remaining, &tmp_data) == Success;
+  had_errors = x_had_errors_p (dpyinfo->display);
+  x_uncatch_errors_after_check ();
+
+  /* The drag window is probably invalid, so remove our record of
+     it.  */
+  if (had_errors)
+    {
+      dpyinfo->motif_drag_window = None;
+      XUngrabServer (dpyinfo->display);
+
+      goto retry_drag_window;
+    }
 
   if (rc && tmp_data && !bytes_remaining
       && actual_type == dpyinfo->Xatom_MOTIF_DRAG_TARGETS
@@ -2145,13 +2319,155 @@ xm_setup_dnd_targets (struct x_display_info *dpyinfo,
   return idx;
 }
 
+/* Allocate an atom that will be used for the Motif selection during
+   the drag-and-drop operation.
+
+   Grab the server, and then retrieve a list of atoms named
+   _EMACS_DRAG_ATOM from the root window.  Find the first atom that
+   has no selection owner, own it and return it.  If there is no such
+   atom, add a unique atom to the end of the list and return that
+   instead.  */
+
+static Atom
+xm_get_drag_atom_1 (struct x_display_info *dpyinfo,
+                   struct frame *source_frame)
+{
+  Atom actual_type, *atoms, atom;
+  unsigned long nitems, bytes_remaining;
+  unsigned char *tmp_data;
+  int rc, actual_format;
+  unsigned long i;
+  char *buffer;
+  Window owner;
+
+  /* Make sure this operation is done atomically.  */
+  XGrabServer (dpyinfo->display);
+
+  rc = XGetWindowProperty (dpyinfo->display, dpyinfo->root_window,
+                          dpyinfo->Xatom_EMACS_DRAG_ATOM,
+                          0, LONG_MAX, False, XA_ATOM, &actual_type,
+                          &actual_format, &nitems, &bytes_remaining,
+                          &tmp_data);
+  atom = None;
+  /* GCC thinks i is used uninitialized, but it's always initialized if
+     `atoms' exists at that particular spot.  */
+  i = 0;
+
+  if (rc == Success
+      && actual_format == 32 && nitems
+      && actual_type == XA_ATOM)
+    {
+      atoms = (Atom *) tmp_data;
+
+      x_catch_errors (dpyinfo->display);
+
+      for (i = 0; i < nitems; ++i)
+       {
+         owner = XGetSelectionOwner (dpyinfo->display, atoms[i]);
+
+         if (!x_had_errors_p (dpyinfo->display)
+             && (owner == None
+                 /* If we already own this selection (even if another
+                    frame owns it), use it.  There is no way of
+                    knowing when ownership was asserted, so it still
+                    has to be owned again.  */
+                 || x_window_to_frame (dpyinfo, owner)))
+           {
+             atom = atoms[i];
+
+             break;
+           }
+       }
+
+      x_uncatch_errors ();
+    }
+
+  if (tmp_data)
+    XFree (tmp_data);
+
+  buffer = dpyinfo->motif_drag_atom_name;
+
+  if (atom)
+    {
+      sprintf (buffer, "_EMACS_ATOM_%lu", i + 1);
+      XSetSelectionOwner (dpyinfo->display, atom,
+                         FRAME_X_WINDOW (source_frame),
+                         dpyinfo->last_user_time);
+
+      /* The selection's last-change time is newer than our
+        last_user_time, so create a new selection instead.  */
+      if (XGetSelectionOwner (dpyinfo->display, atom)
+         != FRAME_X_WINDOW (source_frame))
+       atom = None;
+    }
+
+  while (!atom)
+    {
+      sprintf (buffer, "_EMACS_ATOM_%lu", nitems + 1);
+      atom = XInternAtom (dpyinfo->display, buffer, False);
+
+      XSetSelectionOwner (dpyinfo->display, atom,
+                         FRAME_X_WINDOW (source_frame),
+                         dpyinfo->last_user_time);
+
+      XChangeProperty (dpyinfo->display, dpyinfo->root_window,
+                      dpyinfo->Xatom_EMACS_DRAG_ATOM, XA_ATOM, 32,
+                      (rc != Success
+                       || (actual_format != 32
+                           || actual_type != XA_ATOM)
+                       ? PropModeReplace : PropModeAppend),
+                      (unsigned char *) &atom, 1);
+
+      actual_format = 32;
+      actual_type = XA_ATOM;
+      rc = Success;
+      nitems += 1;
+
+      /* The selection's last-change time is newer than our
+        last_user_time, so create a new selection (again).  */
+      if (XGetSelectionOwner (dpyinfo->display, atom)
+         != FRAME_X_WINDOW (source_frame))
+       atom = None;
+    }
+
+  dpyinfo->motif_drag_atom_time = dpyinfo->last_user_time;
+  dpyinfo->motif_drag_atom_owner = source_frame;
+
+  XUngrabServer (dpyinfo->display);
+  return atom;
+}
+
+static Atom
+xm_get_drag_atom (struct x_display_info *dpyinfo)
+{
+  Atom atom;
+
+  if (dpyinfo->motif_drag_atom != None)
+    atom = dpyinfo->motif_drag_atom;
+  else
+    atom = xm_get_drag_atom_1 (dpyinfo, x_dnd_frame);
+
+  dpyinfo->motif_drag_atom = atom;
+  return atom;
+}
+
 static void
 xm_setup_drag_info (struct x_display_info *dpyinfo,
                    struct frame *source_frame)
 {
+  Atom atom;
   xm_drag_initiator_info drag_initiator_info;
   int idx;
 
+  atom = xm_get_drag_atom (dpyinfo);
+
+  if (atom == None)
+    return;
+
+  XSETCAR (x_dnd_selection_alias_cell,
+          x_atom_to_symbol (dpyinfo, atom));
+  XSETCDR (x_dnd_selection_alias_cell, QXdndSelection);
+
   idx = xm_setup_dnd_targets (dpyinfo, x_dnd_targets,
                              x_dnd_n_targets);
 
@@ -2160,14 +2476,15 @@ xm_setup_drag_info (struct x_display_info *dpyinfo,
       drag_initiator_info.byteorder = XM_BYTE_ORDER_CUR_FIRST;
       drag_initiator_info.protocol = XM_DRAG_PROTOCOL_VERSION;
       drag_initiator_info.table_index = idx;
-      drag_initiator_info.selection = dpyinfo->Xatom_XdndSelection;
+      drag_initiator_info.selection = atom;
 
-      xm_write_drag_initiator_info (dpyinfo->display, FRAME_X_WINDOW 
(source_frame),
-                                   dpyinfo->Xatom_XdndSelection,
+      xm_write_drag_initiator_info (dpyinfo->display,
+                                   FRAME_X_WINDOW (source_frame), atom,
                                    dpyinfo->Xatom_MOTIF_DRAG_INITIATOR_INFO,
                                    &drag_initiator_info);
 
       x_dnd_motif_setup_p = true;
+      x_dnd_motif_atom = atom;
     }
 }
 
@@ -2191,9 +2508,9 @@ 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_catch_errors (dpyinfo->display);
+  x_ignore_errors_for_next_request (dpyinfo);
   XSendEvent (dpyinfo->display, target, False, NoEventMask, &msg);
-  x_uncatch_errors ();
+  x_stop_ignoring_errors (dpyinfo);
 }
 
 static void
@@ -2218,9 +2535,9 @@ 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_catch_errors (dpyinfo->display);
+  x_ignore_errors_for_next_request (dpyinfo);
   XSendEvent (dpyinfo->display, target, False, NoEventMask, &msg);
-  x_uncatch_errors ();
+  x_stop_ignoring_errors (dpyinfo);
 }
 
 static void
@@ -2249,9 +2566,9 @@ 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_catch_errors (dpyinfo->display);
+  x_ignore_errors_for_next_request (dpyinfo);
   XSendEvent (dpyinfo->display, target, False, NoEventMask, &msg);
-  x_uncatch_errors ();
+  x_stop_ignoring_errors (dpyinfo);
 }
 
 static void
@@ -2278,8 +2595,13 @@ xm_send_top_level_leave_message (struct x_display_info 
*dpyinfo, Window source,
                                               XM_DROP_SITE_NONE, 
x_dnd_motif_operations,
                                               XM_DROP_ACTION_DROP_CANCEL);
       mmsg.timestamp = dmsg->timestamp;
-      mmsg.x = 65535;
-      mmsg.y = 65535;
+
+      /* Use X_SHRT_MAX instead of the max value of uint16_t since
+        that will be interpreted as a plausible position by Motif,
+        and as such breaks if the drop target is beneath that
+        position.  */
+      mmsg.x = X_SHRT_MAX;
+      mmsg.y = X_SHRT_MAX;
 
       xm_send_drag_motion_message (dpyinfo, source, target, &mmsg);
     }
@@ -2303,9 +2625,9 @@ 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_catch_errors (dpyinfo->display);
+  x_ignore_errors_for_next_request (dpyinfo);
   XSendEvent (dpyinfo->display, target, False, NoEventMask, &msg);
-  x_uncatch_errors ();
+  x_stop_ignoring_errors (dpyinfo);
 }
 
 static int
@@ -2467,6 +2789,39 @@ xm_read_drag_motion_message (const XEvent *msg,
   return 0;
 }
 
+static int
+xm_read_drag_motion_reply (const XEvent *msg, xm_drag_motion_reply *reply)
+{
+  const uint8_t *data;
+
+  data = (const uint8_t *) &msg->xclient.data.b[0];
+
+  if ((XM_DRAG_REASON_CODE (data[0])
+       != XM_DRAG_REASON_DRAG_MOTION)
+      || (XM_DRAG_REASON_ORIGINATOR (data[0])
+         != XM_DRAG_ORIGINATOR_RECEIVER))
+    return 1;
+
+  reply->reason = *(data++);
+  reply->byte_order = *(data++);
+  reply->side_effects = *(uint16_t *) data;
+  reply->timestamp = *(uint32_t *) (data + 2);
+  reply->better_x = *(uint16_t *) (data + 6);
+  reply->better_y = *(uint16_t *) (data + 8);
+
+  if (reply->byte_order != XM_BYTE_ORDER_CUR_FIRST)
+    {
+      SWAPCARD16 (reply->side_effects);
+      SWAPCARD32 (reply->timestamp);
+      SWAPCARD16 (reply->better_x);
+      SWAPCARD16 (reply->better_y);
+    }
+
+  reply->byte_order = XM_BYTE_ORDER_CUR_FIRST;
+
+  return 0;
+}
+
 static void
 x_dnd_send_xm_leave_for_drop (struct x_display_info *dpyinfo,
                              struct frame *f, Window wdesc,
@@ -2492,19 +2847,16 @@ x_dnd_free_toplevels (bool display_alive)
   struct x_client_list_window *last;
   struct x_client_list_window *tem = x_dnd_toplevels;
   ptrdiff_t n_windows, i, buffer_size;
-  Window *destroy_windows;
-  unsigned long *prev_masks;
+  Window *destroy_windows UNINIT;
+  unsigned long *prev_masks UNINIT;
   specpdl_ref count;
-  Display *dpy;
+  Display *dpy UNINIT;
+  struct x_display_info *dpyinfo;
 
   if (!x_dnd_toplevels)
     /* Probably called inside an IO error handler.  */
     return;
 
-  /* Pacify GCC.  */
-  prev_masks = NULL;
-  destroy_windows = NULL;
-
   if (display_alive)
     {
       buffer_size = 1024;
@@ -2563,18 +2915,24 @@ x_dnd_free_toplevels (bool display_alive)
 
   if (display_alive)
     {
-      x_catch_errors (dpy);
+      dpyinfo = x_display_info_for_display (dpy);
 
-      for (i = 0; i < n_windows; ++i)
+      if (n_windows)
        {
-         XSelectInput (dpy, destroy_windows[i], prev_masks[i]);
+         eassume (dpyinfo);
+         x_ignore_errors_for_next_request (dpyinfo);
+
+         for (i = 0; i < n_windows; ++i)
+           {
+             XSelectInput (dpy, destroy_windows[i], prev_masks[i]);
 #ifdef HAVE_XSHAPE
-         XShapeSelectInput (dpy, destroy_windows[i], None);
+             XShapeSelectInput (dpy, destroy_windows[i], None);
 #endif
+           }
+
+         x_stop_ignoring_errors (dpyinfo);
        }
-
-      x_uncatch_errors ();
-    }
+    }
 
   unbind_to (count, Qnil);
   unblock_input ();
@@ -2587,7 +2945,7 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo)
   Window *toplevels;
   int format, rc;
   unsigned long nitems, bytes_after;
-  unsigned long i;
+  unsigned long i, real_nitems;
   unsigned char *data = NULL;
   int frame_extents[4];
 
@@ -2651,6 +3009,16 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo)
 
   toplevels = (Window *) data;
 
+  for (i = 0, real_nitems = 0; i < nitems; ++i)
+    {
+      /* Some window managers with built in compositors end up putting
+        tooltips in the client list, which is silly.  */
+      if (!x_tooltip_window_to_frame (dpyinfo, toplevels[i], NULL))
+       toplevels[real_nitems++] = toplevels[i];
+    }
+
+  nitems = real_nitems;
+
 #ifdef USE_XCB
   USE_SAFE_ALLOCA;
 
@@ -2922,11 +3290,11 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo)
 
          if (dpyinfo->xshape_supported_p)
            {
-             x_catch_errors (dpyinfo->display);
+             x_ignore_errors_for_next_request (dpyinfo);
              XShapeSelectInput (dpyinfo->display,
                                 toplevels[i],
                                 ShapeNotifyMask);
-             x_uncatch_errors ();
+             x_stop_ignoring_errors (dpyinfo);
 
 #ifndef HAVE_XCB_SHAPE
              x_catch_errors (dpyinfo->display);
@@ -3087,12 +3455,12 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo)
            }
 #endif
 
-         x_catch_errors (dpyinfo->display);
+         x_ignore_errors_for_next_request (dpyinfo);
          XSelectInput (dpyinfo->display, toplevels[i],
                        (attrs.your_event_mask
                         | StructureNotifyMask
                         | PropertyChangeMask));
-         x_uncatch_errors ();
+         x_stop_ignoring_errors (dpyinfo);
 
          x_dnd_toplevels = tem;
        }
@@ -3281,6 +3649,7 @@ x_dnd_get_target_window_1 (struct x_display_info *dpyinfo,
      root_x and root_y are.  */
 
   *motif_out = XM_DRAG_STYLE_NONE;
+
   for (tem = x_dnd_toplevels; tem; tem = tem->next)
     {
       if (!tem->mapped_p || tem->wm_state != NormalState)
@@ -3355,7 +3724,9 @@ x_dnd_get_target_window_1 (struct x_display_info *dpyinfo,
 
   if (chosen)
     {
-      *motif_out = chosen->xm_protocol_style;
+      *motif_out = (x_dnd_disable_motif_protocol
+                   ? XM_DRAG_STYLE_NONE
+                   : chosen->xm_protocol_style);
       return chosen->window;
     }
   else
@@ -3537,7 +3908,17 @@ x_dnd_do_unsupported_drop (struct x_display_info 
*dpyinfo,
 {
   XEvent event;
   int dest_x, dest_y;
-  Window child_return, child;
+  Window child_return, child, owner;
+  Lisp_Object current_value;
+  struct frame *f;
+
+  f = decode_window_system_frame (frame);
+
+  if (NILP (value))
+    return;
+
+  if (!x_dnd_use_unsupported_drop)
+    return;
 
   event.xbutton.serial = 0;
   event.xbutton.send_event = True;
@@ -3558,11 +3939,27 @@ x_dnd_do_unsupported_drop (struct x_display_info 
*dpyinfo,
         && child_return != None)
     child = child_return;
 
-  if (CONSP (value))
-    x_own_selection (QPRIMARY, Fnth (make_fixnum (1), value),
-                    frame);
-  else
-    error ("Lost ownership of XdndSelection");
+  x_uncatch_errors ();
+
+  if (!CONSP (value))
+    return;
+
+  current_value = assq_no_quit (QPRIMARY,
+                               dpyinfo->terminal->Vselection_alist);
+
+  if (!NILP (current_value))
+    current_value = XCAR (XCDR (current_value));
+
+  x_own_selection (QPRIMARY, current_value, frame,
+                  XCAR (XCDR (value)), before);
+
+  owner = XGetSelectionOwner (dpyinfo->display, XA_PRIMARY);
+
+  /* If we didn't successfully obtain selection ownership, refrain
+     from generating events that will insert something else.  */
+
+  if (owner != FRAME_X_WINDOW (f))
+    return;
 
   event.xbutton.window = child;
   event.xbutton.subwindow = None;
@@ -3572,33 +3969,37 @@ x_dnd_do_unsupported_drop (struct x_display_info 
*dpyinfo,
   event.xbutton.button = 2;
   event.xbutton.same_screen = True;
 
-  x_set_pending_dnd_time (before);
+  dpyinfo->pending_dnd_time = before;
 
   event.xbutton.type = ButtonPress;
   event.xbutton.time = before + 1;
 
+  x_ignore_errors_for_next_request (dpyinfo);
   XSendEvent (dpyinfo->display, child,
              True, ButtonPressMask, &event);
+  x_stop_ignoring_errors (dpyinfo);
 
   event.xbutton.type = ButtonRelease;
   event.xbutton.time = before + 2;
 
+  x_ignore_errors_for_next_request (dpyinfo);
   XSendEvent (dpyinfo->display, child,
              True, ButtonReleaseMask, &event);
+  x_stop_ignoring_errors (dpyinfo);
 
-  x_uncatch_errors ();
+  x_dnd_action_symbol = QXdndActionPrivate;
+
+  return;
 }
 
 static void
 x_dnd_send_unsupported_drop (struct x_display_info *dpyinfo, Window 
target_window,
                             int root_x, int root_y, Time before)
 {
-  struct input_event ie;
   Lisp_Object targets, arg;
   int i;
   char **atom_names, *name;
 
-  EVENT_INIT (ie);
   targets = Qnil;
   atom_names = alloca (sizeof *atom_names * x_dnd_n_targets);
 
@@ -3606,8 +4007,6 @@ x_dnd_send_unsupported_drop (struct x_display_info 
*dpyinfo, Window target_windo
                      x_dnd_n_targets, atom_names))
       return;
 
-  x_dnd_action = dpyinfo->Xatom_XdndActionPrivate;
-
   for (i = x_dnd_n_targets; i > 0; --i)
     {
       targets = Fcons (build_string (atom_names[i - 1]),
@@ -3626,19 +4025,29 @@ x_dnd_send_unsupported_drop (struct x_display_info 
*dpyinfo, Window target_windo
   else
     arg = Qnil;
 
-  ie.kind = UNSUPPORTED_DROP_EVENT;
-  ie.code = (unsigned) target_window;
-  ie.modifiers = x_dnd_unsupported_event_level;
-  ie.arg = list3 (assq_no_quit (QXdndSelection,
-                               dpyinfo->terminal->Vselection_alist),
-                 targets, arg);
-  ie.timestamp = before;
+  x_dnd_run_unsupported_drop_function = true;
+  x_dnd_unsupported_drop_time = before;
+  x_dnd_unsupported_drop_window = target_window;
+  x_dnd_unsupported_drop_data
+    = listn (5, assq_no_quit (QXdndSelection,
+                             dpyinfo->terminal->Vselection_alist),
+            targets, arg, make_fixnum (root_x),
+            make_fixnum (root_y));
 
-  XSETINT (ie.x, root_x);
-  XSETINT (ie.y, root_y);
-  XSETFRAME (ie.frame_or_window, x_dnd_frame);
+  x_dnd_waiting_for_finish = true;
+  x_dnd_finish_display = dpyinfo->display;
+}
 
-  kbd_buffer_store_event (&ie);
+static Window
+x_dnd_fill_empty_target (int *proto_out, int *motif_out,
+                        Window *toplevel_out, bool *was_frame)
+{
+  *proto_out = -1;
+  *motif_out = XM_DRAG_STYLE_NONE;
+  *toplevel_out = None;
+  *was_frame = false;
+
+  return None;
 }
 
 static Window
@@ -3853,7 +4262,8 @@ x_dnd_get_target_window (struct x_display_info *dpyinfo,
              || proto != -1 || motif != XM_DRAG_STYLE_NONE)
            {
              *proto_out = proto;
-             *motif_out = motif;
+             *motif_out = (x_dnd_disable_motif_protocol
+                           ? XM_DRAG_STYLE_NONE : motif);
              *toplevel_out = child_return;
              x_uncatch_errors ();
 
@@ -4077,9 +4487,9 @@ x_dnd_send_enter (struct frame *f, Window target, int 
supported)
      so we don't have to set it again.  */
   x_dnd_init_type_lists = true;
 
-  x_catch_errors (dpyinfo->display);
+  x_ignore_errors_for_next_request (dpyinfo);
   XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg);
-  x_uncatch_errors ();
+  x_stop_ignoring_errors (dpyinfo);
 }
 
 static void
@@ -4091,19 +4501,6 @@ x_dnd_send_position (struct frame *f, Window target, int 
supported,
   struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
   XEvent msg;
 
-  if (target == x_dnd_mouse_rect_target
-      && x_dnd_mouse_rect.width
-      && x_dnd_mouse_rect.height)
-    {
-      if (root_x >= x_dnd_mouse_rect.x
-         && root_x < (x_dnd_mouse_rect.x
-                      + x_dnd_mouse_rect.width)
-         && root_y >= x_dnd_mouse_rect.y
-         && root_y < (x_dnd_mouse_rect.y
-                      + x_dnd_mouse_rect.height))
-       return;
-    }
-
   msg.xclient.type = ClientMessage;
   msg.xclient.message_type = dpyinfo->Xatom_XdndPosition;
   msg.xclient.format = 32;
@@ -4111,21 +4508,22 @@ x_dnd_send_position (struct frame *f, Window target, 
int supported,
   msg.xclient.data.l[0] = FRAME_X_WINDOW (f);
   msg.xclient.data.l[1] = 0;
 
-  if (supported >= 5)
+  /* This is problematic because it's not specified in the
+     freedesktop.org copy of the protocol specification, but the copy
+     maintained by the original author of the protocol specifies it
+     for all versions.  Since at least one program supports these
+     flags, but uses protocol v4 (and not v5), set them for all
+     protocool versions.  */
+  if (button >= 4 && button <= 7)
     {
-      if (button >= 4 && button <= 7)
-       {
-         msg.xclient.data.l[1] |= (1 << 9);
-         msg.xclient.data.l[1] |= (button - 4) << 7;
-       }
-      else if (button)
-       return;
-
-      msg.xclient.data.l[1] |= state & 0x3f;
+      msg.xclient.data.l[1] |= (1 << 10);
+      msg.xclient.data.l[1] |= (button - 4) << 8;
     }
   else if (button)
     return;
 
+  msg.xclient.data.l[1] |= state & 0xff;
+
   msg.xclient.data.l[2] = (root_x << 16) | root_y;
   msg.xclient.data.l[3] = 0;
   msg.xclient.data.l[4] = 0;
@@ -4136,9 +4534,37 @@ x_dnd_send_position (struct frame *f, Window target, int 
supported,
   if (supported >= 4)
     msg.xclient.data.l[4] = action;
 
-  x_catch_errors (dpyinfo->display);
-  XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg);
-  x_uncatch_errors ();
+  if (x_dnd_waiting_for_status_window == target)
+    {
+      x_dnd_pending_send_position = msg;
+      x_dnd_pending_send_position_button = button;
+      x_dnd_pending_send_position_root_x = root_x;
+      x_dnd_pending_send_position_root_y = root_y;
+    }
+  else
+    {
+      if (target == x_dnd_mouse_rect_target
+         && x_dnd_mouse_rect.width
+         && x_dnd_mouse_rect.height
+         /* Ignore the mouse rectangle if we're supposed to be sending a
+            button press instead.  */
+         && !button)
+       {
+         if (root_x >= x_dnd_mouse_rect.x
+             && root_x < (x_dnd_mouse_rect.x
+                          + x_dnd_mouse_rect.width)
+             && root_y >= x_dnd_mouse_rect.y
+             && root_y < (x_dnd_mouse_rect.y
+                          + x_dnd_mouse_rect.height))
+           return;
+       }
+
+      x_ignore_errors_for_next_request (dpyinfo);
+      XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg);
+      x_stop_ignoring_errors (dpyinfo);
+
+      x_dnd_waiting_for_status_window = target;
+    }
 }
 
 static void
@@ -4157,9 +4583,12 @@ x_dnd_send_leave (struct frame *f, Window target)
   msg.xclient.data.l[3] = 0;
   msg.xclient.data.l[4] = 0;
 
-  x_catch_errors (dpyinfo->display);
+  x_dnd_waiting_for_status_window = None;
+  x_dnd_pending_send_position.type = 0;
+
+  x_ignore_errors_for_next_request (dpyinfo);
   XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg);
-  x_uncatch_errors ();
+  x_stop_ignoring_errors (dpyinfo);
 }
 
 static bool
@@ -4190,9 +4619,22 @@ x_dnd_send_drop (struct frame *f, Window target, Time 
timestamp,
   if (supported >= 1)
     msg.xclient.data.l[2] = timestamp;
 
-  x_catch_errors (dpyinfo->display);
+  x_ignore_errors_for_next_request (dpyinfo);
   XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg);
-  x_uncatch_errors ();
+  x_stop_ignoring_errors (dpyinfo);
+  return true;
+}
+
+static bool
+x_dnd_do_drop (Window target, int supported)
+{
+  if (x_dnd_waiting_for_status_window != target)
+    return x_dnd_send_drop (x_dnd_frame, target,
+                           x_dnd_selection_timestamp, supported);
+
+  x_dnd_need_send_drop = true;
+  x_dnd_send_drop_proto = supported;
+
   return true;
 }
 
@@ -4222,10 +4664,14 @@ x_free_dnd_targets (void)
   x_dnd_n_targets = 0;
 }
 
+/* Clear some Lisp variables after the drop finishes, so they are
+   freed by the GC.  */
+
 static void
-x_clear_dnd_monitors (void)
+x_clear_dnd_variables (void)
 {
   x_dnd_monitors = Qnil;
+  x_dnd_unsupported_drop_data = Qnil;
 }
 
 static void
@@ -4240,6 +4686,95 @@ x_free_dnd_toplevels (void)
   x_dnd_free_toplevels (true);
 }
 
+/* Restore event masks and window properties changed during a
+   drag-and-drop operation, after it finishes.  */
+static void
+x_restore_events_after_dnd (struct frame *f, XWindowAttributes *wa)
+{
+  struct x_display_info *dpyinfo;
+
+  dpyinfo = FRAME_DISPLAY_INFO (f);
+
+  /* Restore the old event mask.  */
+  XSelectInput (dpyinfo->display, dpyinfo->root_window,
+               wa->your_event_mask);
+#ifdef HAVE_XKB
+  if (dpyinfo->supports_xkb)
+    XkbSelectEvents (dpyinfo->display, XkbUseCoreKbd,
+                    XkbStateNotifyMask, 0);
+#endif
+  /* Delete the Motif drag initiator info if it was set up.  */
+  if (x_dnd_motif_setup_p)
+    XDeleteProperty (dpyinfo->display, FRAME_X_WINDOW (f),
+                    x_dnd_motif_atom);
+
+  /* Remove any type list set as well.  */
+  if (x_dnd_init_type_lists && x_dnd_n_targets > 3)
+    XDeleteProperty (dpyinfo->display, FRAME_X_WINDOW (f),
+                    dpyinfo->Xatom_XdndTypeList);
+}
+
+#ifdef HAVE_XINPUT2
+
+/* Cancel the current drag-and-drop operation, sending leave messages
+   to any relevant toplevels.  This is called from the event loop when
+   an event is received telling Emacs to gracefully cancel the
+   drag-and-drop operation.  */
+
+static void
+x_dnd_cancel_dnd_early (void)
+{
+  struct frame *f;
+  xm_drop_start_message dmsg;
+
+  eassert (x_dnd_frame && x_dnd_in_progress);
+
+  f = x_dnd_frame;
+
+  if (x_dnd_last_seen_window != None
+      && x_dnd_last_protocol_version != -1)
+    x_dnd_send_leave (x_dnd_frame,
+                     x_dnd_last_seen_window);
+  else if (x_dnd_last_seen_window != None
+          && !XM_DRAG_STYLE_IS_DROP_ONLY (x_dnd_last_motif_style)
+          && x_dnd_last_motif_style != XM_DRAG_STYLE_NONE
+          && x_dnd_motif_setup_p)
+    {
+      dmsg.reason = XM_DRAG_REASON (XM_DRAG_ORIGINATOR_INITIATOR,
+                                   XM_DRAG_REASON_DROP_START);
+      dmsg.byte_order = XM_BYTE_ORDER_CUR_FIRST;
+      dmsg.timestamp = FRAME_DISPLAY_INFO (f)->last_user_time;
+      dmsg.side_effects
+       = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (FRAME_DISPLAY_INFO 
(f),
+                                                          x_dnd_wanted_action),
+                              XM_DROP_SITE_VALID, x_dnd_motif_operations,
+                              XM_DROP_ACTION_DROP_CANCEL);
+      dmsg.x = 0;
+      dmsg.y = 0;
+      dmsg.index_atom = x_dnd_motif_atom;
+      dmsg.source_window = FRAME_X_WINDOW (f);
+
+      x_dnd_send_xm_leave_for_drop (FRAME_DISPLAY_INFO (f), f,
+                                   x_dnd_last_seen_window,
+                                   FRAME_DISPLAY_INFO (f)->last_user_time);
+      xm_send_drop_message (FRAME_DISPLAY_INFO (f), FRAME_X_WINDOW (f),
+                           x_dnd_last_seen_window, &dmsg);
+    }
+
+  x_dnd_last_seen_window = None;
+  x_dnd_last_seen_toplevel = None;
+  x_dnd_in_progress = false;
+  x_dnd_waiting_for_finish = false;
+  x_dnd_return_frame_object = NULL;
+  x_dnd_movement_frame = NULL;
+  x_dnd_wheel_frame = NULL;
+  x_dnd_frame = NULL;
+  x_dnd_action = None;
+  x_dnd_action_symbol = Qnil;
+}
+
+#endif
+
 static void
 x_dnd_cleanup_drag_and_drop (void *frame)
 {
@@ -4274,7 +4809,7 @@ x_dnd_cleanup_drag_and_drop (void *frame)
                                   XM_DROP_ACTION_DROP_CANCEL);
          dmsg.x = 0;
          dmsg.y = 0;
-         dmsg.index_atom = FRAME_DISPLAY_INFO (f)->Xatom_XdndSelection;
+         dmsg.index_atom = x_dnd_motif_atom;
          dmsg.source_window = FRAME_X_WINDOW (f);
 
          x_dnd_send_xm_leave_for_drop (FRAME_DISPLAY_INFO (f), f,
@@ -4299,32 +4834,10 @@ x_dnd_cleanup_drag_and_drop (void *frame)
 #endif
   x_dnd_return_frame_object = NULL;
   x_dnd_movement_frame = NULL;
-
-  block_input ();
-  /* Restore the old event mask.  */
-  XSelectInput (FRAME_X_DISPLAY (f),
-               FRAME_DISPLAY_INFO (f)->root_window,
-               x_dnd_old_window_attrs.your_event_mask);
-
-#ifdef HAVE_XKB
-  if (FRAME_DISPLAY_INFO (f)->supports_xkb)
-    XkbSelectEvents (FRAME_X_DISPLAY (f), XkbUseCoreKbd,
-                    XkbStateNotifyMask, 0);
-#endif
-
-  /* Delete the Motif drag initiator info if it was set up.  */
-  if (x_dnd_motif_setup_p)
-    XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                    FRAME_DISPLAY_INFO (f)->Xatom_XdndSelection);
-
-  /* Remove any type list set as well.  */
-  if (x_dnd_init_type_lists && x_dnd_n_targets > 3)
-    XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                    FRAME_DISPLAY_INFO (f)->Xatom_XdndTypeList);
-
-  unblock_input ();
-
+  x_dnd_wheel_frame = NULL;
   x_dnd_frame = NULL;
+
+  x_restore_events_after_dnd (f, &x_dnd_old_window_attrs);
 }
 
 static void
@@ -4351,6 +4864,37 @@ x_dnd_note_self_position (struct x_display_info 
*dpyinfo, Window target,
     }
 }
 
+static void
+x_dnd_note_self_wheel (struct x_display_info *dpyinfo, Window target,
+                      unsigned short root_x, unsigned short root_y,
+                      int button, unsigned int state, Time time)
+{
+  struct frame *f;
+  int dest_x, dest_y;
+  Window child_return;
+
+  if (button < 4 || button > 7)
+    return;
+
+  f = x_top_window_to_frame (dpyinfo, target);
+
+  if (f && XTranslateCoordinates (dpyinfo->display,
+                                 dpyinfo->root_window,
+                                 FRAME_X_WINDOW (f),
+                                 root_x, root_y, &dest_x,
+                                 &dest_y, &child_return))
+    {
+      x_dnd_wheel_frame = f;
+      x_dnd_wheel_x = dest_x;
+      x_dnd_wheel_y = dest_y;
+      x_dnd_wheel_button = button;
+      x_dnd_wheel_state = state;
+      x_dnd_wheel_time = time;
+
+      return;
+    }
+}
+
 static void
 x_dnd_note_self_drop (struct x_display_info *dpyinfo, Window target,
                      unsigned short root_x, unsigned short root_y,
@@ -4421,6 +4965,9 @@ x_dnd_note_self_drop (struct x_display_info *dpyinfo, 
Window target,
       XFree (atom_names[i - 1]);
     }
 
+  lval = Fcons (assq_no_quit (QXdndSelection,
+                             FRAME_TERMINAL (f)->Vselection_alist),
+               lval);
   lval = Fcons (intern (name), lval);
   lval = Fcons (QXdndSelection, lval);
   ie.arg = lval;
@@ -4484,15 +5031,6 @@ x_xr_ensure_picture (struct frame *f)
 }
 #endif
 
-/* Remove calls to XFlush by defining XFlush to an empty replacement.
-   Calls to XFlush should be unnecessary because the X output buffer
-   is flushed automatically as needed by calls to XPending,
-   XNextEvent, or XWindowEvent according to the XFlush man page.
-   XTread_socket calls XPending.  Removing XFlush improves
-   performance.  */
-
-#define XFlush(DISPLAY)        (void) 0
-
 
 /***********************************************************************
                              Debugging
@@ -4644,6 +5182,14 @@ x_update_opaque_region (struct frame *f, XEvent 
*configure)
 
 
 #if defined USE_CAIRO || defined HAVE_XRENDER
+static int
+x_gc_free_ext_data_private (XExtData *extension)
+{
+  xfree (extension->private_data);
+
+  return 0;
+}
+
 static struct x_gc_ext_data *
 x_gc_get_ext_data (struct frame *f, GC gc, int create_if_not_found_p)
 {
@@ -4663,6 +5209,7 @@ x_gc_get_ext_data (struct frame *f, GC gc, int 
create_if_not_found_p)
          ext_data = xzalloc (sizeof (*ext_data));
          ext_data->number = dpyinfo->ext_codes->extension;
          ext_data->private_data = xzalloc (sizeof (struct x_gc_ext_data));
+         ext_data->free_private = x_gc_free_ext_data_private;
          XAddToExtensionList (head, ext_data);
        }
     }
@@ -4690,7 +5237,42 @@ x_extension_initialize (struct x_display_info *dpyinfo)
 
 #ifdef HAVE_XINPUT2
 
-/* Free all XI2 devices on dpyinfo.  */
+/* Convert XI2 button state IN to a standard X button modifier
+   mask, and place it in OUT.  */
+static void
+xi_convert_button_state (XIButtonState *in, unsigned int *out)
+{
+  int i;
+
+  if (in->mask_len)
+    {
+      for (i = 1; i <= 8; ++i)
+       {
+         if (XIMaskIsSet (in->mask, i))
+           *out |= (Button1Mask << (i - 1));
+       }
+    }
+}
+
+/* Return the modifier state in XEV as a standard X modifier mask.  */
+
+#ifdef USE_GTK
+static
+#endif
+unsigned int
+xi_convert_event_state (XIDeviceEvent *xev)
+{
+  unsigned int mods, buttons;
+
+  mods = xev->mods.effective;
+  buttons = 0;
+
+  xi_convert_button_state (&xev->buttons, &buttons);
+
+  return mods | buttons;
+}
+
+/* Free all XI2 devices on DPYINFO.  */
 static void
 x_free_xi_devices (struct x_display_info *dpyinfo)
 {
@@ -4770,15 +5352,15 @@ xi_populate_device_from_info (struct xi_device_t 
*xi_device,
                                  * device->num_classes);
   values = NULL;
 #endif
-#ifdef HAVE_XINPUT2_2
-  xi_device->touchpoints = NULL;
-#endif
 
   xi_device->use = device->use;
+  xi_device->name = build_string (device->name);
+  xi_device->attachment = device->attachment;
+
 #ifdef HAVE_XINPUT2_2
+  xi_device->touchpoints = NULL;
   xi_device->direct_p = false;
 #endif
-  xi_device->name = build_string (device->name);
 
   for (c = 0; c < device->num_classes; ++c)
     {
@@ -4851,12 +5433,16 @@ xi_populate_device_from_info (struct xi_device_t 
*xi_device,
 #endif
 }
 
-/* The code below handles the tracking of scroll valuators on XInput
-   2, in order to support scroll wheels that report information more
-   granular than a screen line.
+/* Populate our client-side record of all devices, which includes
+   basic information about the device and also touchscreen tracking
+   information and scroll valuators.
+
+   Keeping track of scroll valuators is required in order to support
+   scroll wheels that report information in a fashion more detailed
+   than a single turn of a "step" in the wheel.
 
-   On X, when the XInput 2 extension is being utilized, the states of
-   the mouse wheels in each axis are stored as absolute values inside
+   When the input extension is being utilized, the states of the mouse
+   wheels on each axis are stored as absolute values inside
    "valuators" attached to each mouse device.  To obtain the delta of
    the scroll wheel from a motion event (which is used to report that
    some valuator has changed), it is necessary to iterate over every
@@ -4870,22 +5456,15 @@ xi_populate_device_from_info (struct xi_device_t 
*xi_device,
    This delta however is still intermediate, to make driver
    implementations easier.  The XInput developers recommend (and most
    programs use) the following algorithm to convert from scroll unit
-   deltas to pixel deltas:
+   deltas to pixel deltas by which the display must actually be
+   scrolled:
 
      pixels_scrolled = pow (window_height, 2.0 / 3.0) * delta;  */
 
-/* Setup valuator tracking for XI2 master devices on
-   DPYINFO->display.  */
-
-/* This function's name is a misnomer: these days, it keeps a
-   client-side record of all devices, which includes basic information
-   about the device and also touchscreen tracking information, instead
-   of just scroll valuators.  */
-
 static void
-x_init_master_valuators (struct x_display_info *dpyinfo)
+x_cache_xi_devices (struct x_display_info *dpyinfo)
 {
-  int ndevices, actual_devices;
+  int ndevices, actual_devices, i;
   XIDeviceInfo *infos;
 
   actual_devices = 0;
@@ -4902,9 +5481,9 @@ x_init_master_valuators (struct x_display_info *dpyinfo)
       return;
     }
 
-  dpyinfo->devices = xmalloc (sizeof *dpyinfo->devices * ndevices);
+  dpyinfo->devices = xzalloc (sizeof *dpyinfo->devices * ndevices);
 
-  for (int i = 0; i < ndevices; ++i)
+  for (i = 0; i < ndevices; ++i)
     {
       if (infos[i].enabled)
        xi_populate_device_from_info (&dpyinfo->devices[actual_devices++],
@@ -6025,20 +6604,6 @@ x_set_frame_alpha (struct frame *f)
   unsigned long opac;
   Window parent;
 
-#ifndef USE_XCB
-  unsigned char *data = NULL;
-  Atom actual;
-  int rc, format;
-  unsigned long n, left;
-  unsigned long value;
-#else
-  xcb_get_property_cookie_t opacity_cookie;
-  xcb_get_property_reply_t *opacity_reply;
-  xcb_generic_error_t *error;
-  bool rc;
-  uint32_t value;
-#endif
-
   if (dpyinfo->highlight_frame == f)
     alpha = f->alpha[0];
   else
@@ -6059,8 +6624,6 @@ x_set_frame_alpha (struct frame *f)
 
   opac = alpha * OPAQUE;
 
-  x_catch_errors (dpy);
-
   /* If there is a parent from the window manager, put the property there
      also, to work around broken window managers that fail to do that.
      Do this unconditionally as this function is called on reparent when
@@ -6069,101 +6632,435 @@ x_set_frame_alpha (struct frame *f)
   if (!FRAME_PARENT_FRAME (f))
     {
       parent = x_find_topmost_parent (f);
+
       if (parent != None)
-       XChangeProperty (dpy, parent, dpyinfo->Xatom_net_wm_window_opacity,
-                        XA_CARDINAL, 32, PropModeReplace,
-                        (unsigned char *) &opac, 1);
+       {
+         x_ignore_errors_for_next_request (dpyinfo);
+         XChangeProperty (dpy, parent,
+                          dpyinfo->Xatom_net_wm_window_opacity,
+                          XA_CARDINAL, 32, PropModeReplace,
+                          (unsigned char *) &opac, 1);
+         x_stop_ignoring_errors (dpyinfo);
+       }
     }
 
-  /* return unless necessary */
-  {
-#ifndef USE_XCB
-    rc = XGetWindowProperty (dpy, win, dpyinfo->Xatom_net_wm_window_opacity,
-                            0, 1, False, XA_CARDINAL,
-                            &actual, &format, &n, &left,
-                            &data);
-
-    if (rc == Success && actual != None
-       && n && format == XA_CARDINAL && data)
-      {
-        value = *(unsigned long *) data;
-
-       /* Xlib sign-extends values greater than 0x7fffffff on 64-bit
-          machines.  Get the low bits by ourself.  */
-
-       value &= 0xffffffff;
-
-       if (value == opac)
-         {
-           x_uncatch_errors ();
-           XFree (data);
-           return;
-         }
-      }
-
-    if (data)
-      XFree (data);
-#else
-    /* Avoid the confusing Xlib sign-extension mess by using XCB
-       instead.  */
-    opacity_cookie
-      = xcb_get_property (dpyinfo->xcb_connection, 0, (xcb_window_t) win,
-                         (xcb_atom_t) dpyinfo->Xatom_net_wm_window_opacity,
-                         XCB_ATOM_CARDINAL, 0, 1);
-    opacity_reply
-      = xcb_get_property_reply (dpyinfo->xcb_connection,
-                               opacity_cookie, &error);
-
-    rc = opacity_reply;
-
-    if (!opacity_reply)
-      free (error);
-    else
-      {
-       rc = (opacity_reply->format == 32
-             && opacity_reply->type == XCB_ATOM_CARDINAL
-             && (xcb_get_property_value_length (opacity_reply) >= 4));
-
-       if (rc)
-         value = *(uint32_t *) xcb_get_property_value (opacity_reply);
-      }
-
-    if (opacity_reply)
-      free (opacity_reply);
-
-    if (rc && value == opac)
-      return;
-#endif
-  }
-
+  x_ignore_errors_for_next_request (dpyinfo);
   XChangeProperty (dpy, win, dpyinfo->Xatom_net_wm_window_opacity,
                   XA_CARDINAL, 32, PropModeReplace,
                   (unsigned char *) &opac, 1);
-  x_uncatch_errors ();
+  x_stop_ignoring_errors (dpyinfo);
 }
 
 /***********************************************************************
                    Starting and ending an update
  ***********************************************************************/
 
-/* Start an update of frame F.  This function is installed as a hook
-   for update_begin, i.e. it is called when update_begin is called.
-   This function is called prior to calls to gui_update_window_begin for
-   each window being updated.  Currently, there is nothing to do here
-   because all interesting stuff is done on a window basis.  */
+#if defined HAVE_XSYNC && !defined USE_GTK && defined HAVE_CLOCK_GETTIME
 
-static void
-x_update_begin (struct frame *f)
-{
-  /* Nothing to do.  */
-}
+/* Wait for an event matching PREDICATE to show up in the event
+   queue, or TIMEOUT to elapse.
 
-/* Draw a vertical window border from (x,y0) to (x,y1)  */
+   If TIMEOUT passes without an event being found, return 1.
+   Otherwise, return 0 and behave as XIfEvent would.  */
 
-static void
-x_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
+static int
+x_if_event (Display *dpy, XEvent *event_return,
+           Bool (*predicate) (Display *, XEvent *, XPointer),
+           XPointer arg, struct timespec timeout)
 {
-  struct frame *f = XFRAME (WINDOW_FRAME (w));
+  struct timespec current_time, target;
+  int fd;
+  fd_set fds;
+
+  fd = ConnectionNumber (dpy);
+  current_time = current_timespec ();
+  target = timespec_add (current_time, timeout);
+
+  /* Check if an event is already in the queue.  If it is, avoid
+     syncing.  */
+  if (XCheckIfEvent (dpy, event_return, predicate, arg))
+    return 0;
+
+  while (true)
+    {
+      /* Get events into the queue.  */
+      XSync (dpy, False);
+
+      /* Look for an event again.  */
+      if (XCheckIfEvent (dpy, event_return, predicate, arg))
+       return 0;
+
+      /* Calculate the timeout.  */
+      current_time = current_timespec ();
+      timeout = timespec_sub (target, current_time);
+
+      /* If not, wait for some input to show up on the X connection,
+        or for the timeout to elapse.  */
+      FD_ZERO (&fds);
+      FD_SET (fd, &fds);
+
+      /* If this fails due to an IO error, XSync will call the IO
+        error handler.  */
+      pselect (fd + 1, &fds, NULL, NULL, &timeout, NULL);
+
+      /* Timeout elapsed.  */
+      current_time = current_timespec ();
+      if (timespec_cmp (target, current_time) < 0)
+       return 1;
+    }
+}
+
+/* Return the monotonic time corresponding to the high-resolution
+   server timestamp TIMESTAMP.  Return 0 if the necessary information
+   is not available.  */
+
+static uint_fast64_t
+x_sync_get_monotonic_time (struct x_display_info *dpyinfo,
+                          uint_fast64_t timestamp)
+{
+  if (dpyinfo->server_time_monotonic_p)
+    return timestamp;
+
+  /* This means we haven't yet initialized the server time offset.  */
+  if (!dpyinfo->server_time_offset)
+    return 0;
+
+  uint_fast64_t t;
+  return (INT_SUBTRACT_WRAPV (timestamp, dpyinfo->server_time_offset, &t)
+         ? 0 : t);
+}
+
+# ifndef CLOCK_MONOTONIC
+#  define CLOCK_MONOTONIC CLOCK_REALTIME
+# endif
+
+/* Return the current monotonic time in the same format as a
+   high-resolution server timestamp, or 0 if not available.  */
+
+static uint_fast64_t
+x_sync_current_monotonic_time (void)
+{
+  struct timespec time;
+  uint_fast64_t t;
+  return (((clock_gettime (CLOCK_MONOTONIC, &time) != 0
+           && (CLOCK_MONOTONIC == CLOCK_REALTIME
+               || clock_gettime (CLOCK_REALTIME, &time) != 0))
+          || INT_MULTIPLY_WRAPV (time.tv_sec, 1000000, &t)
+          || INT_ADD_WRAPV (t, time.tv_nsec / 1000, &t))
+         ? 0 : t);
+}
+
+/* Decode a _NET_WM_FRAME_DRAWN message and calculate the time it took
+   to draw the last frame.  */
+
+static void
+x_sync_note_frame_times (struct x_display_info *dpyinfo,
+                        struct frame *f, XEvent *event)
+{
+  uint_fast64_t low, high, time;
+  struct x_output *output;
+
+  low = event->xclient.data.l[2];
+  high = event->xclient.data.l[3];
+  output = FRAME_X_OUTPUT (f);
+
+  time = x_sync_get_monotonic_time (dpyinfo, low | (high << 32));
+
+  if (!time || !output->temp_frame_time
+      || INT_SUBTRACT_WRAPV (time, output->temp_frame_time,
+                            &output->last_frame_time))
+    output->last_frame_time = 0;
+
+#ifdef FRAME_DEBUG
+  uint_fast64_t last_frame_ms = output->last_frame_time / 1000;
+  fprintf (stderr,
+          "Drawing the last frame took: %"PRIuFAST64" ms (%"PRIuFAST64")\n",
+          last_frame_ms, time);
+#endif
+}
+
+static Bool
+x_sync_is_frame_drawn_event (Display *dpy, XEvent *event,
+                            XPointer user_data)
+{
+  struct frame *f;
+  struct x_display_info *dpyinfo;
+
+  f = (struct frame *) user_data;
+  dpyinfo = FRAME_DISPLAY_INFO (f);
+
+  if (event->type == ClientMessage
+      && (event->xclient.message_type
+         == dpyinfo->Xatom_net_wm_frame_drawn)
+      && event->xclient.window == FRAME_OUTER_WINDOW (f))
+    return True;
+
+  return False;
+}
+
+/* Wait for the compositing manager to finish drawing the last frame.
+   If the compositing manager has already drawn everything, do
+   nothing.  */
+
+static void
+x_sync_wait_for_frame_drawn_event (struct frame *f)
+{
+  XEvent event;
+
+  if (!FRAME_X_WAITING_FOR_DRAW (f)
+      /* The compositing manager can't draw a frame if it is
+        unmapped.  */
+      || !FRAME_VISIBLE_P (f))
+    return;
+
+  /* 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,
+                 make_timespec (1, 0)))
+    {
+      /* TODO: display this warning in the echo area.  */
+      fprintf (stderr, "Warning: compositing manager spent more than 1 second "
+              "drawing a frame.  Frame synchronization has been disabled\n");
+      FRAME_X_OUTPUT (f)->use_vsync_p = false;
+
+      /* Also change the frame parameter to reflect the new state.  */
+      store_frame_param (f, Quse_frame_synchronization, Qnil);
+    }
+  else
+    x_sync_note_frame_times (FRAME_DISPLAY_INFO (f), f, &event);
+
+  FRAME_X_WAITING_FOR_DRAW (f) = false;
+}
+
+/* Tell the compositing manager to postpone updates of F until a frame
+   has finished drawing.  */
+
+static void
+x_sync_update_begin (struct frame *f)
+{
+  XSyncValue value, add;
+  Bool overflow;
+
+  if (FRAME_X_EXTENDED_COUNTER (f) == None)
+    return;
+
+  value = FRAME_X_COUNTER_VALUE (f);
+
+  if (FRAME_X_OUTPUT (f)->ext_sync_end_pending_p)
+    {
+      FRAME_X_COUNTER_VALUE (f)
+       = FRAME_X_OUTPUT (f)->resize_counter_value;
+
+      value = FRAME_X_COUNTER_VALUE (f);
+
+      if (XSyncValueLow32 (value) % 2)
+       {
+         XSyncIntToValue (&add, 1);
+         XSyncValueAdd (&value, value, add, &overflow);
+
+         if (overflow)
+           XSyncIntToValue (&value, 0);
+       }
+
+      FRAME_X_OUTPUT (f)->ext_sync_end_pending_p = false;
+    }
+
+  /* Since a frame is already in progress, there is no point in
+     continuing.  */
+  if (XSyncValueLow32 (value) % 2)
+    return;
+
+  /* Wait for the last frame to be drawn before drawing this one.  */
+  x_sync_wait_for_frame_drawn_event (f);
+
+  /* Make a note of the time at which we started to draw this
+     frame.  */
+  FRAME_X_OUTPUT (f)->temp_frame_time = x_sync_current_monotonic_time ();
+
+  /* Since Emacs needs a non-urgent redraw, ensure that value % 4 ==
+     1.  Later, add 3 to create the even counter value.  */
+  if (XSyncValueLow32 (value) % 4 == 2)
+    XSyncIntToValue (&add, 3);
+  else
+    XSyncIntToValue (&add, 1);
+
+  XSyncValueAdd (&FRAME_X_COUNTER_VALUE (f),
+                value, add, &overflow);
+
+  if (overflow)
+    XSyncIntToValue (&FRAME_X_COUNTER_VALUE (f), 3);
+
+  eassert (XSyncValueLow32 (FRAME_X_COUNTER_VALUE (f)) % 4 == 1);
+
+  XSyncSetCounter (FRAME_X_DISPLAY (f),
+                  FRAME_X_EXTENDED_COUNTER (f),
+                  FRAME_X_COUNTER_VALUE (f));
+}
+
+#ifdef HAVE_XSYNCTRIGGERFENCE
+
+/* Trigger the sync fence for counter VALUE immediately before a frame
+   finishes.  */
+
+static void
+x_sync_trigger_fence (struct frame *f, XSyncValue value)
+{
+  uint_fast64_t n, low, high, idx;
+
+  /* Sync fences aren't supported by the X server.  */
+  if (FRAME_DISPLAY_INFO (f)->xsync_major < 3
+      || (FRAME_DISPLAY_INFO (f)->xsync_major == 3
+         && FRAME_DISPLAY_INFO (f)->xsync_minor < 1))
+    return;
+
+  low = XSyncValueLow32 (value);
+  high = XSyncValueHigh32 (value);
+
+  n = low | (high << 32);
+  idx = (n / 4) % 2;
+
+#ifdef FRAME_DEBUG
+  fprintf (stderr, "Triggering synchronization fence: %lu\n", idx);
+#endif
+
+  XSyncTriggerFence (FRAME_X_DISPLAY (f),
+                    FRAME_X_OUTPUT (f)->sync_fences[idx]);
+}
+
+/* Initialize the sync fences on F.  */
+
+void
+x_sync_init_fences (struct frame *f)
+{
+  struct x_output *output;
+  struct x_display_info *dpyinfo;
+
+  output = FRAME_X_OUTPUT (f);
+  dpyinfo = FRAME_DISPLAY_INFO (f);
+
+  /* Sync fences aren't supported by the X server.  */
+  if (dpyinfo->xsync_major < 3
+      || (dpyinfo->xsync_major == 3
+         && dpyinfo->xsync_minor < 1))
+    return;
+
+  output->sync_fences[0]
+    = XSyncCreateFence (FRAME_X_DISPLAY (f),
+                       /* The drawable given below is only used to
+                          determine the screen on which the fence is
+                          created.  */
+                       FRAME_X_WINDOW (f),
+                       False);
+  output->sync_fences[1]
+    = XSyncCreateFence (FRAME_X_DISPLAY (f),
+                       FRAME_X_WINDOW (f),
+                       False);
+
+  XChangeProperty (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
+                  dpyinfo->Xatom_net_wm_sync_fences, XA_CARDINAL,
+                  32, PropModeReplace,
+                  (unsigned char *) &output->sync_fences, 2);
+}
+
+static void
+x_sync_free_fences (struct frame *f)
+{
+  if (FRAME_X_OUTPUT (f)->sync_fences[0] != None)
+    XSyncDestroyFence (FRAME_X_DISPLAY (f),
+                      FRAME_X_OUTPUT (f)->sync_fences[0]);
+
+  if (FRAME_X_OUTPUT (f)->sync_fences[1] != None)
+    XSyncDestroyFence (FRAME_X_DISPLAY (f),
+                      FRAME_X_OUTPUT (f)->sync_fences[1]);
+}
+
+#endif
+
+/* Tell the compositing manager that FRAME has been drawn and can be
+   updated.  */
+
+static void
+x_sync_update_finish (struct frame *f)
+{
+  XSyncValue value, add;
+  Bool overflow;
+
+  if (FRAME_X_EXTENDED_COUNTER (f) == None)
+    return;
+
+  value = FRAME_X_COUNTER_VALUE (f);
+
+  if (!(XSyncValueLow32 (value) % 2))
+    return;
+
+  if ((XSyncValueLow32 (value) % 4) == 1)
+    /* This means the frame is non-urgent and should be drawn at the
+       next redraw point.  */
+    XSyncIntToValue (&add, 3);
+  else
+    /* Otherwise, the frame is urgent and should be drawn as soon as
+       possible.  */
+    XSyncIntToValue (&add, 1);
+
+  XSyncValueAdd (&FRAME_X_COUNTER_VALUE (f),
+                value, add, &overflow);
+
+  if (overflow)
+    XSyncIntToValue (&FRAME_X_COUNTER_VALUE (f), 0);
+
+  /* Trigger any sync fences if necessary.  */
+#ifdef HAVE_XSYNCTRIGGERFENCE
+  x_sync_trigger_fence (f, FRAME_X_COUNTER_VALUE (f));
+#endif
+
+  XSyncSetCounter (FRAME_X_DISPLAY (f),
+                  FRAME_X_EXTENDED_COUNTER (f),
+                  FRAME_X_COUNTER_VALUE (f));
+
+  if (FRAME_OUTPUT_DATA (f)->use_vsync_p)
+    FRAME_X_WAITING_FOR_DRAW (f) = true;
+}
+
+/* Handle a _NET_WM_FRAME_DRAWN message from the compositor.  */
+
+static void
+x_sync_handle_frame_drawn (struct x_display_info *dpyinfo,
+                          XEvent *message, struct frame *f)
+{
+  if (FRAME_OUTER_WINDOW (f) == message->xclient.window)
+    FRAME_X_WAITING_FOR_DRAW (f) = false;
+
+  x_sync_note_frame_times (dpyinfo, f, message);
+}
+#endif
+
+/* Start an update of frame F.  This function is installed as a hook
+   for update_begin, i.e. it is called when update_begin is called.
+   This function is called prior to calls to gui_update_window_begin for
+   each window being updated.  Currently, there is nothing to do here
+   because all interesting stuff is done on a window basis.  */
+
+static void
+x_update_begin (struct frame *f)
+{
+#if defined HAVE_XSYNC && !defined USE_GTK && defined HAVE_CLOCK_GETTIME
+  /* If F is double-buffered, we can make the entire frame center
+     around XdbeSwapBuffers.  */
+#ifdef HAVE_XDBE
+  if (!FRAME_X_DOUBLE_BUFFERED_P (f))
+#endif
+    x_sync_update_begin (f);
+#else
+  /* Nothing to do.  */
+#endif
+}
+
+/* Draw a vertical window border from (x,y0) to (x,y1)  */
+
+static void
+x_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
+{
+  struct frame *f = XFRAME (WINDOW_FRAME (w));
   struct face *face;
 
   face = FACE_FROM_ID_OR_NULL (f, VERTICAL_BORDER_FACE_ID);
@@ -6237,33 +7134,54 @@ x_draw_window_divider (struct window *w, int x0, int 
x1, int y0, int y1)
     }
 }
 
+#ifdef HAVE_XDBE
+
 /* Show the frame back buffer.  If frame is double-buffered,
    atomically publish to the user's screen graphics updates made since
    the last call to show_back_buffer.  */
 
-#ifdef HAVE_XDBE
 static void
 show_back_buffer (struct frame *f)
 {
+  XdbeSwapInfo swap_info;
+#ifdef USE_CAIRO
+  cairo_t *cr;
+#endif
+
   block_input ();
 
   if (FRAME_X_DOUBLE_BUFFERED_P (f))
     {
+#if defined HAVE_XSYNC && !defined USE_GTK && defined HAVE_CLOCK_GETTIME
+      /* Wait for drawing of the previous frame to complete before
+        displaying this new frame.  */
+      x_sync_wait_for_frame_drawn_event (f);
+
+      /* Begin a new frame.  */
+      x_sync_update_begin (f);
+#endif
+
 #ifdef USE_CAIRO
-      cairo_t *cr = FRAME_CR_CONTEXT (f);
+      cr = FRAME_CR_CONTEXT (f);
       if (cr)
        cairo_surface_flush (cairo_get_target (cr));
 #endif
-      XdbeSwapInfo swap_info;
       memset (&swap_info, 0, sizeof (swap_info));
       swap_info.swap_window = FRAME_X_WINDOW (f);
       swap_info.swap_action = XdbeCopied;
       XdbeSwapBuffers (FRAME_X_DISPLAY (f), &swap_info, 1);
+
+#if defined HAVE_XSYNC && !defined USE_GTK && defined HAVE_CLOCK_GETTIME
+      /* Finish the frame here.  */
+      x_sync_update_finish (f);
+#endif
     }
+
   FRAME_X_NEED_BUFFER_FLIP (f) = false;
 
   unblock_input ();
 }
+
 #endif
 
 /* Updates back buffer and flushes changes to display.  Called from
@@ -6301,17 +7219,17 @@ x_update_end (struct frame *f)
 
 #ifdef USE_CAIRO
   if (!FRAME_X_DOUBLE_BUFFERED_P (f) && FRAME_CR_CONTEXT (f))
-    {
-      block_input ();
-      cairo_surface_flush (cairo_get_target (FRAME_CR_CONTEXT (f)));
-      unblock_input ();
-    }
+    cairo_surface_flush (cairo_get_target (FRAME_CR_CONTEXT (f)));
 #endif
 
-#ifndef XFlush
-  block_input ();
-  XFlush (FRAME_X_DISPLAY (f));
-  unblock_input ();
+  /* If double buffering is disabled, finish the update here.
+     Otherwise, finish the update when the back buffer is next
+     displayed.  */
+#if defined HAVE_XSYNC && !defined USE_GTK && defined HAVE_CLOCK_GETTIME
+#ifdef HAVE_XDBE
+  if (!FRAME_X_DOUBLE_BUFFERED_P (f))
+#endif
+    x_sync_update_finish (f);
 #endif
 }
 
@@ -6321,11 +7239,7 @@ x_update_end (struct frame *f)
 static void
 XTframe_up_to_date (struct frame *f)
 {
-#if defined HAVE_XSYNC && !defined HAVE_GTK3
-  XSyncValue add;
-  XSyncValue current;
-  Bool overflow_p;
-#elif defined HAVE_XSYNC
+#if defined HAVE_XSYNC && defined HAVE_GTK3
   GtkWidget *widget;
   GdkWindow *window;
   GdkFrameClock *clock;
@@ -6351,29 +7265,6 @@ XTframe_up_to_date (struct frame *f)
                       FRAME_X_OUTPUT (f)->pending_basic_counter_value);
       FRAME_X_OUTPUT (f)->sync_end_pending_p = false;
     }
-
-  if (FRAME_X_OUTPUT (f)->ext_sync_end_pending_p
-      && FRAME_X_EXTENDED_COUNTER (f) != None)
-    {
-      current = FRAME_X_OUTPUT (f)->current_extended_counter_value;
-
-      if (XSyncValueLow32 (current) % 2)
-       XSyncIntToValue (&add, 1);
-      else
-       XSyncIntToValue (&add, 2);
-
-      XSyncValueAdd (&FRAME_X_OUTPUT (f)->current_extended_counter_value,
-                    current, add, &overflow_p);
-
-      if (overflow_p)
-       emacs_abort ();
-
-      XSyncSetCounter (FRAME_X_DISPLAY (f),
-                      FRAME_X_EXTENDED_COUNTER (f),
-                      FRAME_X_OUTPUT (f)->current_extended_counter_value);
-
-      FRAME_X_OUTPUT (f)->ext_sync_end_pending_p = false;
-    }
 #else
   if (FRAME_X_OUTPUT (f)->xg_sync_end_pending_p)
     {
@@ -6710,72 +7601,66 @@ static void x_scroll_bar_clear (struct frame *);
 static void x_check_font (struct frame *, struct font *);
 #endif
 
+/* If SEND_EVENT, make sure that TIME is larger than the current last
+   user time.  We don't sanitize timestamps from events sent by the X
+   server itself because some Lisp might have set the user time to a
+   ridiculously large value, and this way a more reasonable timestamp
+   can be obtained upon the next event.  */
+
 static void
-x_display_set_last_user_time (struct x_display_info *dpyinfo, Time time)
+x_display_set_last_user_time (struct x_display_info *dpyinfo, Time time,
+                             bool send_event)
 {
 #ifndef USE_GTK
-  struct frame *focus_frame = dpyinfo->x_focus_frame;
-  struct x_output *output;
+  struct frame *focus_frame;
+  Time old_time;
+
+  focus_frame = dpyinfo->x_focus_frame;
+  old_time = dpyinfo->last_user_time;
 #endif
 
 #ifdef ENABLE_CHECKING
   eassert (time <= X_ULONG_MAX);
 #endif
-  dpyinfo->last_user_time = time;
 
-#ifndef USE_GTK
-  if (focus_frame
-      && (dpyinfo->last_user_time
-         > (dpyinfo->last_user_check_time + 2000)))
+  if (!send_event || time > dpyinfo->last_user_time)
+    dpyinfo->last_user_time = time;
+
+#if defined HAVE_XSYNC && !defined USE_GTK && defined HAVE_CLOCK_GETTIME
+  if (!send_event)
     {
-      output = FRAME_X_OUTPUT (focus_frame);
+      /* See if the current CLOCK_MONOTONIC time is reasonably close
+        to the X server time.  */
+      uint_fast64_t monotonic_time = x_sync_current_monotonic_time ();
+      uint_fast64_t monotonic_ms = monotonic_time / 1000;
+      int_fast64_t diff_ms;
 
-      if (!x_wm_supports (focus_frame,
-                         dpyinfo->Xatom_net_wm_user_time_window))
-       {
-         if (output->user_time_window == None)
-           output->user_time_window = FRAME_OUTER_WINDOW (focus_frame);
-         else if (output->user_time_window != FRAME_OUTER_WINDOW (focus_frame))
-           {
-             XDestroyWindow (dpyinfo->display,
-                             output->user_time_window);
-             XDeleteProperty (dpyinfo->display,
-                              FRAME_OUTER_WINDOW (focus_frame),
-                              dpyinfo->Xatom_net_wm_user_time_window);
-             output->user_time_window = FRAME_OUTER_WINDOW (focus_frame);
-           }
-       }
-      else
+      dpyinfo->server_time_monotonic_p
+       = (monotonic_time != 0
+          && !INT_SUBTRACT_WRAPV (time, monotonic_ms, &diff_ms)
+          && -500 < diff_ms && diff_ms < 500);
+
+      if (!dpyinfo->server_time_monotonic_p)
        {
-         if (output->user_time_window == FRAME_OUTER_WINDOW (focus_frame)
-             || output->user_time_window == None)
-           {
-             XSetWindowAttributes attrs;
-             memset (&attrs, 0, sizeof attrs);
-
-             output->user_time_window
-               = XCreateWindow (dpyinfo->display,
-                                FRAME_X_WINDOW (focus_frame),
-                                -1, -1, 1, 1, 0, 0, InputOnly,
-                                CopyFromParent, 0, &attrs);
-
-             XDeleteProperty (dpyinfo->display,
-                              FRAME_OUTER_WINDOW (focus_frame),
-                              dpyinfo->Xatom_net_wm_user_time);
-             XChangeProperty (dpyinfo->display,
-                              FRAME_OUTER_WINDOW (focus_frame),
-                              dpyinfo->Xatom_net_wm_user_time_window,
-                              XA_WINDOW, 32, PropModeReplace,
-                              (unsigned char *) &output->user_time_window,
-                              1);
-           }
+         /* Compute an offset that can be subtracted from the server
+            time to estimate the monotonic time on the X server.  */
+
+         if (!monotonic_time
+             || INT_MULTIPLY_WRAPV (time, 1000, &dpyinfo->server_time_offset)
+             || INT_SUBTRACT_WRAPV (dpyinfo->server_time_offset,
+                                    monotonic_time,
+                                    &dpyinfo->server_time_offset))
+           dpyinfo->server_time_offset = 0;
        }
-
-      dpyinfo->last_user_check_time = time;
     }
+#endif
 
-  if (focus_frame)
+#ifndef USE_GTK
+  /* Don't waste bandwidth if the time hasn't actually changed.  */
+  if (focus_frame && old_time != dpyinfo->last_user_time)
     {
+      time = dpyinfo->last_user_time;
+
       while (FRAME_PARENT_FRAME (focus_frame))
        focus_frame = FRAME_PARENT_FRAME (focus_frame);
 
@@ -6789,35 +7674,131 @@ x_display_set_last_user_time (struct x_display_info 
*dpyinfo, Time time)
 #endif
 }
 
-
-/* Set S->gc to a suitable GC for drawing glyph string S in cursor
-   face.  */
+#ifdef USE_GTK
 
 static void
-x_set_cursor_gc (struct glyph_string *s)
+x_set_gtk_user_time (struct frame *f, Time time)
 {
-  if (s->font == FRAME_FONT (s->f)
-      && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
-      && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
-      && !s->cmp)
-    s->gc = s->f->output_data.x->cursor_gc;
-  else
-    {
-      /* Cursor on non-default face: must merge.  */
-      XGCValues xgcv;
-      unsigned long mask;
-      Display *display = FRAME_X_DISPLAY (s->f);
+  GtkWidget *widget;
+  GdkWindow *window;
 
-      xgcv.background = s->f->output_data.x->cursor_pixel;
-      xgcv.foreground = s->face->background;
+  widget = FRAME_GTK_OUTER_WIDGET (f);
+  window = gtk_widget_get_window (widget);
 
-      /* If the glyph would be invisible, try a different foreground.  */
-      if (xgcv.foreground == xgcv.background)
-       xgcv.foreground = s->face->foreground;
-      if (xgcv.foreground == xgcv.background)
-       xgcv.foreground = s->f->output_data.x->cursor_foreground_pixel;
-      if (xgcv.foreground == xgcv.background)
-       xgcv.foreground = s->face->foreground;
+  /* This widget isn't realized yet.  */
+  if (!window)
+    return;
+
+  gdk_x11_window_set_user_time (window, time);
+}
+
+#endif
+
+/* Not needed on GTK because GTK handles reporting the user time
+   itself.  */
+
+#ifndef USE_GTK
+static void
+x_update_frame_user_time_window (struct frame *f)
+{
+  struct x_output *output;
+  struct x_display_info *dpyinfo;
+  XSetWindowAttributes attrs;
+
+  output = FRAME_X_OUTPUT (f);
+  dpyinfo = FRAME_DISPLAY_INFO (f);
+
+  if (!NILP (Vx_no_window_manager)
+      || !x_wm_supports (f, dpyinfo->Xatom_net_wm_user_time))
+    {
+      if (output->user_time_window != None
+         && output->user_time_window != FRAME_OUTER_WINDOW (f))
+       {
+         XDestroyWindow (dpyinfo->display, output->user_time_window);
+         XDeleteProperty (dpyinfo->display, FRAME_OUTER_WINDOW (f),
+                          dpyinfo->Xatom_net_wm_user_time_window);
+       }
+      else
+       XDeleteProperty (dpyinfo->display, FRAME_OUTER_WINDOW (f),
+                        dpyinfo->Xatom_net_wm_user_time);
+
+      output->user_time_window = None;
+      return;
+    }
+
+  if (!x_wm_supports (f, dpyinfo->Xatom_net_wm_user_time_window))
+    {
+      if (output->user_time_window == None)
+       output->user_time_window = FRAME_OUTER_WINDOW (f);
+      else if (output->user_time_window != FRAME_OUTER_WINDOW (f))
+       {
+         XDestroyWindow (dpyinfo->display,
+                         output->user_time_window);
+         XDeleteProperty (dpyinfo->display,
+                          FRAME_OUTER_WINDOW (f),
+                          dpyinfo->Xatom_net_wm_user_time_window);
+         output->user_time_window = FRAME_OUTER_WINDOW (f);
+       }
+    }
+  else
+    {
+      if (output->user_time_window == FRAME_OUTER_WINDOW (f)
+         || output->user_time_window == None)
+       {
+         memset (&attrs, 0, sizeof attrs);
+
+         output->user_time_window
+           = XCreateWindow (dpyinfo->display, FRAME_X_WINDOW (f),
+                            -1, -1, 1, 1, 0, 0, InputOnly,
+                            CopyFromParent, 0, &attrs);
+
+         XDeleteProperty (dpyinfo->display, FRAME_OUTER_WINDOW (f),
+                          dpyinfo->Xatom_net_wm_user_time);
+         XChangeProperty (dpyinfo->display, FRAME_OUTER_WINDOW (f),
+                          dpyinfo->Xatom_net_wm_user_time_window,
+                          XA_WINDOW, 32, PropModeReplace,
+                          (unsigned char *) &output->user_time_window, 1);
+       }
+    }
+}
+#endif
+
+void
+x_set_last_user_time_from_lisp (struct x_display_info *dpyinfo,
+                               Time time)
+{
+  x_display_set_last_user_time (dpyinfo, time, true);
+}
+
+
+/* Set S->gc to a suitable GC for drawing glyph string S in cursor
+   face.  */
+
+static void
+x_set_cursor_gc (struct glyph_string *s)
+{
+  if (s->font == FRAME_FONT (s->f)
+      && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
+      && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
+      && !s->cmp)
+    s->gc = s->f->output_data.x->cursor_gc;
+  else
+    {
+      /* Cursor on non-default face: must merge.  */
+      XGCValues xgcv;
+      unsigned long mask;
+      Display *display = FRAME_X_DISPLAY (s->f);
+
+      xgcv.background = s->f->output_data.x->cursor_pixel;
+      xgcv.foreground = s->face->background;
+
+      /* If the glyph would be invisible, try a different foreground.  */
+      if (xgcv.foreground == xgcv.background)
+       xgcv.foreground = s->face->foreground;
+      if (xgcv.foreground == xgcv.background)
+       xgcv.foreground = s->f->output_data.x->cursor_foreground_pixel;
+      if (xgcv.foreground == xgcv.background)
+       xgcv.foreground = s->face->foreground;
 
       /* Make sure the cursor is distinct from text in this face.  */
       if (xgcv.background == s->face->background
@@ -7335,6 +8316,8 @@ x_draw_glyphless_glyph_string_foreground (struct 
glyph_string *s)
                   ? CHAR_TABLE_REF (Vglyphless_char_display,
                                     glyph->u.glyphless.ch)
                   : XCHAR_TABLE (Vglyphless_char_display)->extras[0]);
+             if (CONSP (acronym))
+               acronym = XCAR (acronym);
              if (STRINGP (acronym))
                str = SSDATA (acronym);
            }
@@ -8602,9 +9585,7 @@ x_composite_image (struct glyph_string *s, Pixmap dest,
     {
       Picture destination;
       XRenderPictFormat *default_format;
-      XRenderPictureAttributes attr;
-      /* Pacify GCC.  */
-      memset (&attr, 0, sizeof attr);
+      XRenderPictureAttributes attr UNINIT;
 
       default_format = FRAME_X_PICTURE_FORMAT (s->f);
       destination = XRenderCreatePicture (display, dest,
@@ -9760,16 +10741,12 @@ x_clear_frame (struct frame *f)
   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
 
   block_input ();
-
   font_drop_xrender_surfaces (f);
   x_clear_window (f);
 
   /* We have to clear the scroll bars.  If we have changed colors or
      something like that, then they should be notified.  */
   x_scroll_bar_clear (f);
-
-  XFlush (FRAME_X_DISPLAY (f));
-
   unblock_input ();
 }
 
@@ -10147,7 +11124,6 @@ x_scroll_run (struct window *w, struct run *run)
                                                   view->clip_bottom - 
view->clip_top);
                    }
                  xwidget_expose (view);
-                 XFlush (dpy);
                }
             }
        }
@@ -10237,6 +11213,10 @@ x_scroll_run (struct window *w, struct run *run)
 static void
 x_frame_highlight (struct frame *f)
 {
+  struct x_display_info *dpyinfo;
+
+  dpyinfo = FRAME_DISPLAY_INFO (f);
+
   /* We used to only do this if Vx_no_window_manager was non-nil, but
      the ICCCM (section 4.1.6) says that the window's border pixmap
      and border pixel are window attributes which are "private to the
@@ -10246,10 +11226,10 @@ 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_catch_errors (FRAME_X_DISPLAY (f));
+  x_ignore_errors_for_next_request (dpyinfo);
   XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
                    f->output_data.x->border_pixel);
-  x_uncatch_errors ();
+  x_stop_ignoring_errors (dpyinfo);
   unblock_input ();
   gui_update_cursor (f, true);
   x_set_frame_alpha (f);
@@ -10258,17 +11238,23 @@ x_frame_highlight (struct frame *f)
 static void
 x_frame_unhighlight (struct frame *f)
 {
+  struct x_display_info *dpyinfo;
+
+  dpyinfo = FRAME_DISPLAY_INFO (f);
+
   /* We used to only do this if Vx_no_window_manager was non-nil, but
      the ICCCM (section 4.1.6) says that the window's border pixmap
      and border pixel are window attributes which are "private to the
      client", so we can always change it to whatever we want.  */
+
   block_input ();
   /* Same as above for XSetWindowBorder (bug#9310).  */
-  x_catch_errors (FRAME_X_DISPLAY (f));
+  x_ignore_errors_for_next_request (dpyinfo);
   XSetWindowBorderPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
                          f->output_data.x->border_tile);
-  x_uncatch_errors ();
+  x_stop_ignoring_errors (dpyinfo);
   unblock_input ();
+
   gui_update_cursor (f, true);
   x_set_frame_alpha (f);
 }
@@ -10579,7 +11565,8 @@ x_tooltip_window_to_frame (struct x_display_info 
*dpyinfo,
   GdkWindow *tooltip_window;
 #endif
 
-  *unrelated_tooltip_p = false;
+  if (unrelated_tooltip_p)
+    *unrelated_tooltip_p = false;
 
   FOR_EACH_FRAME (tail, frame)
     {
@@ -10608,14 +11595,16 @@ x_tooltip_window_to_frame (struct x_display_info 
*dpyinfo,
       if (tooltip_window
          && (gdk_x11_window_get_xid (tooltip_window) == wdesc))
        {
-         *unrelated_tooltip_p = true;
+         if (unrelated_tooltip_p)
+           *unrelated_tooltip_p = true;
          break;
        }
 #else
       if (tooltip_window
          && (GDK_WINDOW_XID (tooltip_window) == wdesc))
        {
-         *unrelated_tooltip_p = true;
+         if (unrelated_tooltip_p)
+           *unrelated_tooltip_p = true;
          break;
        }
 #endif
@@ -10867,7 +11856,7 @@ x_push_selection_request (struct selection_input_event 
*se)
 bool
 x_detect_pending_selection_requests (void)
 {
-  return pending_selection_requests;
+  return !!pending_selection_requests;
 }
 
 static void
@@ -10876,6 +11865,95 @@ x_clear_dnd_action (void)
   x_dnd_action_symbol = Qnil;
 }
 
+/* Delete action descriptions from F after drag-and-drop.  */
+static void
+x_dnd_delete_action_list (Lisp_Object frame)
+{
+  struct frame *f;
+
+  /* Delete those two properties, since some clients look at them and
+     not the action to decide whether or not the user should be
+     prompted to select an action.  This can be called with FRAME no
+     longer alive (or its display dead).  */
+
+  f = XFRAME (frame);
+
+  if (!FRAME_LIVE_P (f) || !FRAME_DISPLAY_INFO (f)->display)
+    return;
+
+  block_input ();
+  XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                  FRAME_DISPLAY_INFO (f)->Xatom_XdndActionList);
+  XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                  FRAME_DISPLAY_INFO (f)->Xatom_XdndActionDescription);
+  unblock_input ();
+}
+
+static void
+x_dnd_lose_ownership (Lisp_Object timestamp_and_frame)
+{
+  struct frame *f;
+
+  f = XFRAME (XCDR (timestamp_and_frame));
+
+  if (FRAME_LIVE_P (f))
+    Fx_disown_selection_internal (QXdndSelection,
+                                 XCAR (timestamp_and_frame),
+                                 XCDR (timestamp_and_frame));
+}
+
+/* Clean up an existing drag-and-drop operation in preparation for its
+   sudden termination.  */
+
+static void
+x_dnd_process_quit (struct frame *f, Time timestamp)
+{
+  xm_drop_start_message dmsg;
+
+  if (x_dnd_in_progress)
+    {
+      if (x_dnd_last_seen_window != None
+         && x_dnd_last_protocol_version != -1)
+       x_dnd_send_leave (f, x_dnd_last_seen_window);
+      else if (x_dnd_last_seen_window != None
+              && !XM_DRAG_STYLE_IS_DROP_ONLY (x_dnd_last_motif_style)
+              && x_dnd_last_motif_style != XM_DRAG_STYLE_NONE
+              && x_dnd_motif_setup_p)
+       {
+         dmsg.reason = XM_DRAG_REASON (XM_DRAG_ORIGINATOR_INITIATOR,
+                                       XM_DRAG_REASON_DROP_START);
+         dmsg.byte_order = XM_BYTE_ORDER_CUR_FIRST;
+         dmsg.timestamp = timestamp;
+         dmsg.side_effects
+           = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action 
(FRAME_DISPLAY_INFO (f),
+                                                              
x_dnd_wanted_action),
+                                  XM_DROP_SITE_VALID, x_dnd_motif_operations,
+                                  XM_DROP_ACTION_DROP_CANCEL);
+         dmsg.x = 0;
+         dmsg.y = 0;
+         dmsg.index_atom = x_dnd_motif_atom;
+         dmsg.source_window = FRAME_X_WINDOW (f);
+
+         x_dnd_send_xm_leave_for_drop (FRAME_DISPLAY_INFO (f), f,
+                                       x_dnd_last_seen_window,
+                                       timestamp);
+         xm_send_drop_message (FRAME_DISPLAY_INFO (f), FRAME_X_WINDOW (f),
+                               x_dnd_last_seen_window, &dmsg);
+       }
+
+      x_dnd_end_window = x_dnd_last_seen_window;
+      x_dnd_last_seen_window = None;
+      x_dnd_last_seen_toplevel = None;
+      x_dnd_in_progress = false;
+      x_dnd_frame = NULL;
+    }
+
+  x_dnd_waiting_for_finish = false;
+  x_dnd_return_frame_object = NULL;
+  x_dnd_movement_frame = NULL;
+  x_dnd_wheel_frame = NULL;
+}
+
 /* This function is defined far away from the rest of the XDND code so
    it can utilize `x_any_window_to_frame'.  */
 
@@ -10908,11 +11986,10 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time 
time, Atom xaction,
   XWindowAttributes root_window_attrs;
   struct input_event hold_quit;
   char *atom_name, *ask_actions;
-  Lisp_Object action, ltimestamp;
+  Lisp_Object action, ltimestamp, val;
   specpdl_ref ref, count, base;
   ptrdiff_t i, end, fill;
   XTextProperty prop;
-  xm_drop_start_message dmsg;
   Lisp_Object frame_object, x, y, frame, local_value;
   bool signals_were_pending, need_sync;
 #ifdef HAVE_XKB
@@ -10921,9 +11998,10 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, 
Atom xaction,
 #ifndef USE_GTK
   struct x_display_info *event_display;
 #endif
-  union buffered_input_event *events, *event;
-  int n_events;
-  struct frame *event_frame;
+  unsigned int additional_mask;
+#ifdef HAVE_XINPUT2
+  struct xi_device_t *device;
+#endif
 
   base = SPECPDL_INDEX ();
 
@@ -10931,66 +12009,6 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, 
Atom xaction,
      Fx_begin_drag.  */
   specbind (Qx_dnd_targets_list, selection_target_list);
 
-  /* Before starting drag-and-drop, walk through the keyboard buffer
-     to see if there are any UNSUPPORTED_DROP_EVENTs, and run them now
-     if they exist, to prevent race conditions from happening due to
-     multiple unsupported drops running at once.  */
-
-  block_input ();
-  events = alloca (sizeof *events * KBD_BUFFER_SIZE);
-  n_events = 0;
-  event = kbd_fetch_ptr;
-
-  while (event != kbd_store_ptr)
-    {
-      if (event->ie.kind == UNSUPPORTED_DROP_EVENT
-         && event->ie.modifiers < x_dnd_unsupported_event_level)
-       events[n_events++] = *event;
-
-      event = (event == kbd_buffer + KBD_BUFFER_SIZE - 1
-              ? kbd_buffer : event + 1);
-    }
-
-  x_dnd_unsupported_event_level += 1;
-  unblock_input ();
-
-  for (i = 0; i < n_events; ++i)
-    {
-      maybe_quit ();
-
-      event = &events[i];
-      event_frame = XFRAME (event->ie.frame_or_window);
-
-      if (!FRAME_LIVE_P (event_frame))
-       continue;
-
-      if (!NILP (Vx_dnd_unsupported_drop_function))
-       {
-         if (!NILP (call7 (Vx_dnd_unsupported_drop_function,
-                           XCAR (XCDR (event->ie.arg)), event->ie.x,
-                           event->ie.y, XCAR (XCDR (XCDR (event->ie.arg))),
-                           make_uint (event->ie.code),
-                           event->ie.frame_or_window,
-                           make_int (event->ie.timestamp))))
-           continue;
-       }
-
-      /* `x-dnd-unsupported-drop-function' could have deleted the
-        event frame.  */
-      if (!FRAME_LIVE_P (event_frame))
-       continue;
-
-      x_dnd_do_unsupported_drop (FRAME_DISPLAY_INFO (event_frame),
-                                event->ie.frame_or_window,
-                                XCAR (event->ie.arg),
-                                XCAR (XCDR (event->ie.arg)),
-                                (Window) event->ie.code,
-                                XFIXNUM (event->ie.x),
-                                XFIXNUM (event->ie.y),
-                                event->ie.timestamp);
-      break;
-    }
-
   if (!FRAME_VISIBLE_P (f))
     error ("Frame must be visible");
 
@@ -11006,12 +12024,6 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, 
Atom xaction,
   /* If local_value is nil, then we lost ownership of XdndSelection.
      Signal a more informative error than args-out-of-range.  */
   if (NILP (local_value))
-    error ("Lost ownership of XdndSelection");
-
-  if (CONSP (local_value))
-    x_own_selection (QXdndSelection,
-                    Fnth (make_fixnum (1), local_value), frame);
-  else
     error ("No local value for XdndSelection");
 
   if (popup_activated ())
@@ -11024,11 +12036,22 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time 
time, Atom xaction,
   ltimestamp = x_timestamp_for_selection (FRAME_DISPLAY_INFO (f),
                                          QXdndSelection);
 
+  if (NILP (ltimestamp))
+    error ("No local value for XdndSelection");
+
   if (BIGNUMP (ltimestamp))
     x_dnd_selection_timestamp = bignum_to_intmax (ltimestamp);
   else
     x_dnd_selection_timestamp = XFIXNUM (ltimestamp);
 
+  /* Release ownership of XdndSelection after this function returns.
+     VirtualBox uses the owner of XdndSelection to determine whether
+     or not mouse motion is part of a drag-and-drop operation.  */
+
+  if (!x_dnd_preserve_selection_data)
+    record_unwind_protect (x_dnd_lose_ownership,
+                          Fcons (ltimestamp, frame));
+
   x_dnd_motif_operations
     = xm_side_effect_from_action (FRAME_DISPLAY_INFO (f), xaction);
 
@@ -11044,6 +12067,8 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, 
Atom xaction,
        = xm_side_effect_from_action (FRAME_DISPLAY_INFO (f),
                                      ask_action_list[0]);
 
+      record_unwind_protect (x_dnd_delete_action_list, frame);
+
       ask_actions = NULL;
       end = 0;
       count = SPECPDL_INDEX ();
@@ -11088,19 +12113,8 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, 
Atom xaction,
 
       unbind_to (count, Qnil);
     }
-  else
-    {
-      /* Delete those two properties, since some clients look at them
-        and not the action to decide whether or not the user should
-        be prompted to select an action.  */
 
-      block_input ();
-      XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                      FRAME_DISPLAY_INFO (f)->Xatom_XdndActionList);
-      XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                      FRAME_DISPLAY_INFO (f)->Xatom_XdndActionDescription);
-      unblock_input ();
-    }
+  record_unwind_protect_void (x_clear_dnd_variables);
 
   if (follow_tooltip)
     {
@@ -11112,8 +12126,6 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, 
Atom xaction,
 #endif
        x_dnd_monitors
          = Fx_display_monitor_attributes_list (frame);
-
-      record_unwind_protect_void (x_clear_dnd_monitors);
     }
 
   x_dnd_update_tooltip = follow_tooltip;
@@ -11129,6 +12141,16 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, 
Atom xaction,
   record_unwind_protect_void (release_xg_select);
 #endif
 
+  /* Set up a meaningless alias.  */
+  XSETCAR (x_dnd_selection_alias_cell, QSECONDARY);
+  XSETCDR (x_dnd_selection_alias_cell, QSECONDARY);
+
+  /* Bind this here.  The cell doesn't actually alias between
+     anything until `xm_setup_dnd_targets' is called.  */
+  specbind (Qx_selection_alias_alist,
+           Fcons (x_dnd_selection_alias_cell,
+                  Vx_selection_alias_alist));
+
   /* Initialize most of the state for the drag-and-drop operation.  */
   x_dnd_in_progress = true;
   x_dnd_recursion_depth = command_loop_level + minibuf_level;
@@ -11145,15 +12167,53 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time 
time, Atom xaction,
   x_dnd_return_frame = 0;
   x_dnd_waiting_for_finish = false;
   x_dnd_waiting_for_motif_finish = 0;
+  x_dnd_waiting_for_status_window = None;
+  x_dnd_pending_send_position.type = 0;
   x_dnd_xm_use_help = false;
   x_dnd_motif_setup_p = false;
   x_dnd_end_window = None;
+  x_dnd_run_unsupported_drop_function = false;
   x_dnd_use_toplevels
     = x_wm_supports (f, FRAME_DISPLAY_INFO 
(f)->Xatom_net_client_list_stacking);
+  x_dnd_last_tooltip_valid = false;
   x_dnd_toplevels = NULL;
   x_dnd_allow_current_frame = allow_current_frame;
   x_dnd_movement_frame = NULL;
+  x_dnd_wheel_frame = NULL;
   x_dnd_init_type_lists = false;
+  x_dnd_need_send_drop = false;
+
+#ifdef HAVE_XINPUT2
+
+  if (FRAME_DISPLAY_INFO (f)->supports_xi2)
+    {
+      /* Only accept input from the last master pointer to have interacted
+        with Emacs.  This prevents another pointer device getting our
+        idea of the button state messed up.  */
+      if (FRAME_DISPLAY_INFO (f)->client_pointer_device != -1)
+       x_dnd_pointer_device
+         = FRAME_DISPLAY_INFO (f)->client_pointer_device;
+      else
+       /* This returns Bool but cannot actually fail.  */
+       XIGetClientPointer (FRAME_X_DISPLAY (f), None,
+                           &x_dnd_pointer_device);
+
+      x_dnd_keyboard_device = -1;
+
+      device = xi_device_from_id (FRAME_DISPLAY_INFO (f),
+                                 x_dnd_pointer_device);
+
+      if (device)
+       x_dnd_keyboard_device = device->attachment;
+    }
+  else
+    {
+      x_dnd_pointer_device = -1;
+      x_dnd_keyboard_device = -1;
+    }
+
+#endif
+
 #ifdef HAVE_XKB
   x_dnd_keyboard_state = 0;
 
@@ -11186,7 +12246,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, 
Atom xaction,
   if (EQ (return_frame, Qnow))
     x_dnd_return_frame = 2;
 
-  /* Now select for SubstructureNotifyMask and PropertyNotifyMask on
+  /* Now select for SubstructureNotifyMask and PropertyChangeMask on
      the root window, so we can get notified when window stacking
      changes, a common operation during drag-and-drop.  */
 
@@ -11194,11 +12254,15 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time 
time, Atom xaction,
                        FRAME_DISPLAY_INFO (f)->root_window,
                        &root_window_attrs);
 
+  additional_mask = SubstructureNotifyMask;
+
+  if (x_dnd_use_toplevels)
+    additional_mask |= PropertyChangeMask;
+
   XSelectInput (FRAME_X_DISPLAY (f),
                FRAME_DISPLAY_INFO (f)->root_window,
                root_window_attrs.your_event_mask
-               | SubstructureNotifyMask
-               | PropertyChangeMask);
+               | additional_mask);
 
   if (EQ (return_frame, Qnow))
     x_dnd_update_state (FRAME_DISPLAY_INFO (f), CurrentTime);
@@ -11259,6 +12323,9 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, 
Atom xaction,
 #endif
       x_dnd_inside_handle_one_xevent = false;
 
+      /* Clean up any event handlers that are now out of date.  */
+      x_clean_failable_requests (FRAME_DISPLAY_INFO (f));
+
       /* The unblock_input below might try to read input, but
         XTread_socket does nothing inside a drag-and-drop event
         loop, so don't let it clear the pending_signals flag.  */
@@ -11306,77 +12373,59 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time 
time, Atom xaction,
                         Fposn_at_x_y (x, y, frame_object, Qnil));
                  x_dnd_unwind_flag = false;
                  unbind_to (ref, Qnil);
+
+                 /* Redisplay this way to preserve the echo area.
+                    Otherwise, the contents will abruptly disappear
+                    when the mouse moves over a frame.  */
+                 redisplay_preserve_echo_area (33);
                }
            }
 
-         if (hold_quit.kind != NO_EVENT)
+         if (x_dnd_wheel_frame
+             && (x_dnd_in_progress || x_dnd_waiting_for_finish))
            {
-             if (x_dnd_in_progress)
-               {
-                 if (x_dnd_last_seen_window != None
-                     && x_dnd_last_protocol_version != -1)
-                   x_dnd_send_leave (f, x_dnd_last_seen_window);
-                 else if (x_dnd_last_seen_window != None
-                          && !XM_DRAG_STYLE_IS_DROP_ONLY 
(x_dnd_last_motif_style)
-                          && x_dnd_last_motif_style != XM_DRAG_STYLE_NONE
-                          && x_dnd_motif_setup_p)
-                   {
-                     dmsg.reason = XM_DRAG_REASON 
(XM_DRAG_ORIGINATOR_INITIATOR,
-                                                   XM_DRAG_REASON_DROP_START);
-                     dmsg.byte_order = XM_BYTE_ORDER_CUR_FIRST;
-                     dmsg.timestamp = hold_quit.timestamp;
-                     dmsg.side_effects
-                       = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action 
(FRAME_DISPLAY_INFO (f),
-                                                                          
x_dnd_wanted_action),
-                                              XM_DROP_SITE_VALID, 
x_dnd_motif_operations,
-                                              XM_DROP_ACTION_DROP_CANCEL);
-                     dmsg.x = 0;
-                     dmsg.y = 0;
-                     dmsg.index_atom = FRAME_DISPLAY_INFO 
(f)->Xatom_XdndSelection;
-                     dmsg.source_window = FRAME_X_WINDOW (f);
-
-                     x_dnd_send_xm_leave_for_drop (FRAME_DISPLAY_INFO (f), f,
-                                                   x_dnd_last_seen_window,
-                                                   hold_quit.timestamp);
-                     xm_send_drop_message (FRAME_DISPLAY_INFO (f), 
FRAME_X_WINDOW (f),
-                                           x_dnd_last_seen_window, &dmsg);
-                   }
+             XSETFRAME (frame_object, x_dnd_wheel_frame);
+             XSETINT (x, x_dnd_wheel_x);
+             XSETINT (y, x_dnd_wheel_y);
+             x_dnd_wheel_frame = NULL;
 
-                 x_dnd_end_window = x_dnd_last_seen_window;
-                 x_dnd_last_seen_window = None;
-                 x_dnd_last_seen_toplevel = None;
-                 x_dnd_in_progress = false;
-                 x_dnd_frame = NULL;
-               }
+             if (!NILP (Vx_dnd_wheel_function)
+                 && FRAME_LIVE_P (XFRAME (frame_object))
+                 && !FRAME_TOOLTIP_P (XFRAME (frame_object))
+                 && x_dnd_movement_x >= 0
+                 && x_dnd_movement_y >= 0
+                 && x_dnd_frame
+                 && (XFRAME (frame_object) != x_dnd_frame
+                     || x_dnd_allow_current_frame))
+               {
+                 x_dnd_old_window_attrs = root_window_attrs;
+                 x_dnd_unwind_flag = true;
 
-             x_dnd_waiting_for_finish = false;
-             x_dnd_return_frame_object = NULL;
-             x_dnd_movement_frame = NULL;
+                 ref = SPECPDL_INDEX ();
+                 record_unwind_protect_ptr (x_dnd_cleanup_drag_and_drop, f);
+                 call4 (Vx_dnd_wheel_function,
+                        Fposn_at_x_y (x, y, frame_object, Qnil),
+                        make_fixnum (x_dnd_wheel_button),
+                        make_uint (x_dnd_wheel_state),
+                        make_uint (x_dnd_wheel_time));
+                 x_dnd_unwind_flag = false;
+                 unbind_to (ref, Qnil);
 
-             /* Don't clear dpyinfo->grabbed if we're quitting.  */
+                 /* Redisplay this way to preserve the echo area.
+                    Otherwise, the contents will abruptly disappear
+                    when the mouse moves over a frame.  */
+                 redisplay_preserve_echo_area (33);
+               }
+           }
 
+         if (hold_quit.kind != NO_EVENT)
+           {
+             x_dnd_process_quit (f, hold_quit.timestamp);
 #ifdef USE_GTK
              current_hold_quit = NULL;
 #endif
              /* Restore the old event mask.  */
-             XSelectInput (FRAME_X_DISPLAY (f),
-                           FRAME_DISPLAY_INFO (f)->root_window,
-                           root_window_attrs.your_event_mask);
-#ifdef HAVE_XKB
-             if (FRAME_DISPLAY_INFO (f)->supports_xkb)
-               XkbSelectEvents (FRAME_X_DISPLAY (f), XkbUseCoreKbd,
-                                XkbStateNotifyMask, 0);
-#endif
-             /* Delete the Motif drag initiator info if it was set up.  */
-             if (x_dnd_motif_setup_p)
-               XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                                FRAME_DISPLAY_INFO (f)->Xatom_XdndSelection);
-
-
-             /* Remove any type list set as well.  */
-             if (x_dnd_init_type_lists && x_dnd_n_targets > 3)
-               XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                                FRAME_DISPLAY_INFO (f)->Xatom_XdndTypeList);
+             x_restore_events_after_dnd (f, &root_window_attrs);
 
              /* Call kbd_buffer_store event, which calls
                 handle_interrupt and sets `last-event-frame' along
@@ -11399,173 +12448,646 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time 
time, Atom xaction,
              unbind_to (ref, Qnil);
            }
 
-#ifdef USE_GTK
-         if (xg_pending_quit_event.kind != NO_EVENT)
+         /* Sometimes C-g can be pressed inside a selection
+            converter, where quitting is inhibited.  We want
+            to quit after the converter exits.  */
+         if (!NILP (Vquit_flag) && !NILP (Vinhibit_quit))
            {
-             xg_pending_quit_event.kind = NO_EVENT;
-
-             if (x_dnd_in_progress)
-               {
-                 if (x_dnd_last_seen_window != None
-                     && x_dnd_last_protocol_version != -1)
-                   x_dnd_send_leave (f, x_dnd_last_seen_window);
-                 else if (x_dnd_last_seen_window != None
-                          && !XM_DRAG_STYLE_IS_DROP_ONLY 
(x_dnd_last_motif_style)
-                          && x_dnd_last_motif_style != XM_DRAG_STYLE_NONE
-                          && x_dnd_motif_setup_p)
-                   {
-                     dmsg.reason = XM_DRAG_REASON 
(XM_DRAG_ORIGINATOR_INITIATOR,
-                                                   XM_DRAG_REASON_DROP_START);
-                     dmsg.byte_order = XM_BYTE_ORDER_CUR_FIRST;
-                     dmsg.timestamp = xg_pending_quit_event.timestamp;
-                     dmsg.side_effects
-                       = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action 
(FRAME_DISPLAY_INFO (f),
-                                                                          
x_dnd_wanted_action),
-                                              XM_DROP_SITE_VALID, 
x_dnd_motif_operations,
-                                              XM_DROP_ACTION_DROP_CANCEL);
-                     dmsg.x = 0;
-                     dmsg.y = 0;
-                     dmsg.index_atom = FRAME_DISPLAY_INFO 
(f)->Xatom_XdndSelection;
-                     dmsg.source_window = FRAME_X_WINDOW (f);
-
-                     x_dnd_send_xm_leave_for_drop (FRAME_DISPLAY_INFO (f), f,
-                                                   x_dnd_last_seen_window,
-                                                   
xg_pending_quit_event.timestamp);
-                     xm_send_drop_message (FRAME_DISPLAY_INFO (f), 
FRAME_X_WINDOW (f),
-                                           x_dnd_last_seen_window, &dmsg);
-                   }
-
-                 x_dnd_end_window = x_dnd_last_seen_window;
-                 x_dnd_last_seen_window = None;
-                 x_dnd_last_seen_toplevel = None;
-                 x_dnd_in_progress = false;
-                 x_dnd_frame = NULL;
-               }
+             x_dnd_process_quit (f, FRAME_DISPLAY_INFO (f)->last_user_time);
+#ifdef USE_GTK
+             current_hold_quit = NULL;
+#endif
+             x_restore_events_after_dnd (f, &root_window_attrs);
+             quit ();
+           }
 
+         if (x_dnd_run_unsupported_drop_function
+             && x_dnd_waiting_for_finish)
+           {
+             x_dnd_run_unsupported_drop_function = false;
              x_dnd_waiting_for_finish = false;
-             x_dnd_return_frame_object = NULL;
-             x_dnd_movement_frame = NULL;
+             x_dnd_unwind_flag = true;
+
+             ref = SPECPDL_INDEX ();
+             record_unwind_protect_ptr (x_dnd_cleanup_drag_and_drop, f);
+
+             if (!NILP (Vx_dnd_unsupported_drop_function))
+               val = call8 (Vx_dnd_unsupported_drop_function,
+                            XCAR (XCDR (x_dnd_unsupported_drop_data)),
+                            Fnth (make_fixnum (3), 
x_dnd_unsupported_drop_data),
+                            Fnth (make_fixnum (4), 
x_dnd_unsupported_drop_data),
+                            Fnth (make_fixnum (2), 
x_dnd_unsupported_drop_data),
+                            make_uint (x_dnd_unsupported_drop_window),
+                            frame, make_uint (x_dnd_unsupported_drop_time),
+                            Fcopy_sequence (XCAR 
(x_dnd_unsupported_drop_data)));
+             else
+               val = Qnil;
+
+             if (NILP (val))
+               x_dnd_do_unsupported_drop (FRAME_DISPLAY_INFO (f),
+                                          frame, XCAR 
(x_dnd_unsupported_drop_data),
+                                          XCAR (XCDR 
(x_dnd_unsupported_drop_data)),
+                                          x_dnd_unsupported_drop_window,
+                                          XFIXNUM (Fnth (make_fixnum (3),
+                                                         
x_dnd_unsupported_drop_data)),
+                                          XFIXNUM (Fnth (make_fixnum (4),
+                                                         
x_dnd_unsupported_drop_data)),
+                                          x_dnd_unsupported_drop_time);
+             else if (SYMBOLP (val))
+               x_dnd_action_symbol = val;
+
+             x_dnd_unwind_flag = false;
+             unbind_to (ref, Qnil);
+
+             /* Break out of the loop now, since DND has
+                completed.  */
+             break;
+           }
+
+#ifdef USE_GTK
+         if (xg_pending_quit_event.kind != NO_EVENT)
+           {
+             xg_pending_quit_event.kind = NO_EVENT;
+             current_hold_quit = NULL;
+
+             x_dnd_process_quit (f, FRAME_DISPLAY_INFO (f)->last_user_time);
+             x_restore_events_after_dnd (f, &root_window_attrs);
+             quit ();
+           }
+#else
+       }
+      else
+       {
+         if (x_dnd_movement_frame)
+           x_dnd_movement_frame = NULL;
+
+         if (x_dnd_wheel_frame)
+           x_dnd_wheel_frame = NULL;
+
+         if (hold_quit.kind != NO_EVENT)
+           EVENT_INIT (hold_quit);
+       }
+#endif
+    }
+
+  x_dnd_waiting_for_finish = false;
+
+#ifdef USE_GTK
+  current_hold_quit = NULL;
+#endif
+  x_dnd_movement_frame = NULL;
+  x_dnd_wheel_frame = NULL;
+  x_restore_events_after_dnd (f, &root_window_attrs);
+
+  if (x_dnd_return_frame == 3
+      && FRAME_LIVE_P (x_dnd_return_frame_object))
+    {
+      /* Deliberately preserve the last device if
+        x_dnd_return_frame_object is the drag source.  */
+
+      if (x_dnd_return_frame_object != x_dnd_frame)
+       x_dnd_return_frame_object->last_mouse_device = Qnil;
+
+      x_dnd_return_frame_object->mouse_moved = true;
+
+      XSETFRAME (action, x_dnd_return_frame_object);
+      x_dnd_return_frame_object = NULL;
+
+      return unbind_to (base, action);
+    }
+
+  x_dnd_return_frame_object = NULL;
+  FRAME_DISPLAY_INFO (f)->grabbed = 0;
+
+  if (!NILP (x_dnd_action_symbol))
+    return unbind_to (base, x_dnd_action_symbol);
+
+  if (x_dnd_action != None)
+    {
+      block_input ();
+      x_catch_errors (FRAME_X_DISPLAY (f));
+      atom_name = x_get_atom_name (FRAME_DISPLAY_INFO (f),
+                                  x_dnd_action, &need_sync);
+
+      if (need_sync)
+       x_uncatch_errors ();
+      else
+       /* No protocol request actually happened, so avoid the extra
+          sync by calling x_uncatch_errors_after_check instead.  */
+       x_uncatch_errors_after_check ();
+
+      if (atom_name)
+       {
+         action = intern (atom_name);
+         xfree (atom_name);
+       }
+      else
+       action = Qnil;
+      unblock_input ();
+
+      return unbind_to (base, action);
+    }
+
+  return unbind_to (base, Qnil);
+}
+
+#ifdef HAVE_XINPUT2
+
+/* Since the input extension assigns a keyboard focus to each master
+   device, there is no longer a 1:1 correspondence between the
+   selected frame and the focus frame immediately after the keyboard
+   focus is switched to a given frame.  This situation is handled by
+   keeping track of each master device's focus frame, the time of the
+   last interaction with that frame, and always keeping the focus on
+   the most recently selected frame.  We also use the pointer of the
+   device that is keeping the current frame focused in functions like
+   `mouse-position'.  */
+
+static void
+xi_handle_focus_change (struct x_display_info *dpyinfo)
+{
+  struct input_event ie;
+  struct frame *focus, *new;
+  struct xi_device_t *device, *source = NULL;
+  ptrdiff_t i;
+  Time time;
+#ifdef USE_GTK
+  struct x_output *output;
+  GtkWidget *widget;
+#endif
+
+  focus = dpyinfo->x_focus_frame;
+  new = NULL;
+  time = 0;
+
+  dpyinfo->client_pointer_device = -1;
+
+  for (i = 0; i < dpyinfo->num_devices; ++i)
+    {
+      device = &dpyinfo->devices[i];
+
+      if (device->focus_frame
+         && device->focus_frame_time > time)
+       {
+         new = device->focus_frame;
+         time = device->focus_frame_time;
+         source = device;
+
+         /* Use this device for future calls to `mouse-position' etc.
+            If it is a keyboard, use its attached pointer.  */
+
+         if (device->use == XIMasterKeyboard)
+           dpyinfo->client_pointer_device = device->attachment;
+         else
+           dpyinfo->client_pointer_device = device->device_id;
+       }
+
+      if (device->focus_implicit_frame
+         && device->focus_implicit_time > time)
+       {
+         new = device->focus_implicit_frame;
+         time = device->focus_implicit_time;
+         source = device;
+
+         /* Use this device for future calls to `mouse-position' etc.
+            If it is a keyboard, use its attached pointer.  */
+
+         if (device->use == XIMasterKeyboard)
+           dpyinfo->client_pointer_device = device->attachment;
+         else
+           dpyinfo->client_pointer_device = device->device_id;
+       }
+    }
+
+  if (new != focus && focus)
+    {
+#ifdef HAVE_X_I18N
+      if (FRAME_XIC (focus))
+       XUnsetICFocus (FRAME_XIC (focus));
+#endif
+
+#ifdef USE_GTK
+      output = FRAME_X_OUTPUT (focus);
+
+      if (x_gtk_use_native_input)
+       {
+         gtk_im_context_focus_out (output->im_context);
+         gtk_im_context_set_client_window (output->im_context,
+                                           NULL);
+       }
+#endif
+
+      EVENT_INIT (ie);
+      ie.kind = FOCUS_OUT_EVENT;
+      XSETFRAME (ie.frame_or_window, focus);
+
+      kbd_buffer_store_event (&ie);
+    }
+
+  if (new != focus && new)
+    {
+#ifdef HAVE_X_I18N
+      if (FRAME_XIC (new))
+       XSetICFocus (FRAME_XIC (new));
+#endif
+
+#ifdef USE_GTK
+      output = FRAME_X_OUTPUT (new);
+
+      if (x_gtk_use_native_input)
+       {
+         widget = FRAME_GTK_OUTER_WIDGET (new);
+
+         gtk_im_context_focus_in (output->im_context);
+         gtk_im_context_set_client_window (output->im_context,
+                                           gtk_widget_get_window (widget));
+       }
+#endif
+
+      EVENT_INIT (ie);
+      ie.kind = FOCUS_IN_EVENT;
+      ie.device = source->name;
+      XSETFRAME (ie.frame_or_window, new);
+
+      kbd_buffer_store_event (&ie);
+    }
+
+  x_new_focus_frame (dpyinfo, new);
+}
+
+static void
+xi_focus_handle_for_device (struct x_display_info *dpyinfo,
+                           struct frame *mentioned_frame,
+                           XIEvent *base_event)
+{
+  struct xi_device_t *device;
+  XIEnterEvent *event;
+
+  /* XILeaveEvent, XIFocusInEvent, etc are just synonyms for
+     XIEnterEvent.  */
+  event = (XIEnterEvent *) base_event;
+  device = xi_device_from_id (dpyinfo, event->deviceid);
+
+  if (!device)
+    return;
+
+  switch (event->evtype)
+    {
+    case XI_FocusIn:
+      device->focus_frame = mentioned_frame;
+      device->focus_frame_time = event->time;
+      break;
+
+    case XI_FocusOut:
+      device->focus_frame = NULL;
+      break;
+
+    case XI_Enter:
+      if (!event->focus)
+       break;
+
+      if (device->use == XIMasterPointer)
+       device = xi_device_from_id (dpyinfo, device->attachment);
+
+      if (!device)
+       break;
+
+      device->focus_implicit_frame = mentioned_frame;
+      device->focus_implicit_time = event->time;
+      break;
+
+    case XI_Leave:
+      if (!event->focus)
+       break;
+
+      if (device->use == XIMasterPointer)
+       device = xi_device_from_id (dpyinfo, device->attachment);
+
+      if (!device)
+       break;
+
+      device->focus_implicit_frame = NULL;
+      break;
+    }
+
+  xi_handle_focus_change (dpyinfo);
+}
+
+static void
+xi_handle_delete_frame (struct x_display_info *dpyinfo,
+                       struct frame *f)
+{
+  struct xi_device_t *device;
+  ptrdiff_t i;
+
+  for (i = 0; i < dpyinfo->num_devices; ++i)
+    {
+      device = &dpyinfo->devices[i];
+
+      if (device->focus_frame == f)
+       device->focus_frame = NULL;
+
+      if (device->focus_implicit_frame == f)
+       device->focus_implicit_frame = NULL;
+    }
+}
+
+/* Handle an interaction by DEVICE on frame F.  TIME is the time of
+   the interaction; if F isn't currently the global focus frame, but
+   is the focus of DEVICE, make it the focus frame.  */
+
+static void
+xi_handle_interaction (struct x_display_info *dpyinfo,
+                      struct frame *f, struct xi_device_t *device,
+                      Time time)
+{
+  bool change;
+
+  /* If DEVICE is a pointer, use its attached keyboard device.  */
+  if (device->use == XIMasterPointer)
+    device = xi_device_from_id (dpyinfo, device->attachment);
+
+  if (!device)
+    return;
+
+  change = false;
+
+  if (device->focus_frame == f)
+    {
+      device->focus_frame_time = time;
+      change = true;
+    }
+
+  if (device->focus_implicit_frame == f)
+    {
+      device->focus_implicit_time = time;
+      change = true;
+    }
+
+  /* If F isn't currently focused, update the focus state.  */
+  if (change && f != dpyinfo->x_focus_frame)
+    xi_handle_focus_change (dpyinfo);
+}
+
+/* Return whether or not XEV actually represents a change in the
+   position of the pointer on DEVICE, with respect to the last event
+   received.  This is necessary because the input extension reports
+   motion events in very high resolution, while Emacs is only fast
+   enough to process motion events aligned to the pixel grid.  */
+
+static bool
+xi_position_changed (struct xi_device_t *device, XIDeviceEvent *xev)
+{
+  bool changed;
+
+  changed = true;
+
+  if (xev->event != device->last_motion_window)
+    goto out;
+
+  if (lrint (xev->event_x) == device->last_motion_x
+      && lrint (xev->event_y) == device->last_motion_y)
+    {
+      changed = false;
+      goto out;
+    }
+
+ out:
+  device->last_motion_x = lrint (xev->event_x);
+  device->last_motion_y = lrint (xev->event_y);
+  device->last_motion_window = xev->event;
+
+  return changed;
+}
+
+static void
+xi_report_motion_window_clear (struct xi_device_t *device)
+{
+  device->last_motion_window = None;
+}
+
+#ifdef HAVE_XINPUT2_1
+
+/* Look up a scroll valuator in DEVICE by NUMBER.  */
+
+static struct xi_scroll_valuator_t *
+xi_get_scroll_valuator (struct xi_device_t *device, int number)
+{
+  int i;
+
+  for (i = 0; i < device->scroll_valuator_count; ++i)
+    {
+      if (device->valuators[i].number == number)
+       return &device->valuators[i];
+    }
+
+  return NULL;
+}
+
+#endif
+
+/* Handle EVENT, a DeviceChanged event.  Look up the device that
+   changed, and update its information with the data in EVENT.  */
+
+static void
+xi_handle_device_changed (struct x_display_info *dpyinfo,
+                         struct xi_device_t *device,
+                         XIDeviceChangedEvent *event)
+{
+#ifdef HAVE_XINPUT2_1
+  XIDeviceInfo *info;
+  XIScrollClassInfo *scroll;
+  int i, ndevices;
+  struct xi_scroll_valuator_t *valuator;
+  XIValuatorClassInfo *valuator_info;
+#endif
+#ifdef HAVE_XINPUT2_2
+  struct xi_touch_point_t *tem, *last;
+  XITouchClassInfo *touch;
+#endif
+
+#ifdef HAVE_XINPUT2_1
+  /* When a DeviceChange event is received for a master device, we
+     don't get any scroll valuators along with it.  This is possibly
+     an X server bug but I really don't want to dig any further, so
+     fetch the scroll valuators manually.  (bug#57020) */
+
+  x_catch_errors (dpyinfo->display);
+  info = XIQueryDevice (dpyinfo->display, event->deviceid,
+                       /* ndevices is always 1 if a deviceid is
+                          specified.  If the request fails, NULL will
+                          be returned.  */
+                       &ndevices);
+  x_uncatch_errors ();
+
+  if (info)
+    {
+      device->valuators = xrealloc (device->valuators,
+                                   (info->num_classes
+                                    * sizeof *device->valuators));
+      device->scroll_valuator_count = 0;
+#ifdef HAVE_XINPUT2_2
+      device->direct_p = false;
+#endif
+
+      for (i = 0; i < info->num_classes; ++i)
+       {
+         switch (info->classes[i]->type)
+           {
+           case XIScrollClass:
+             scroll = (XIScrollClassInfo *) info->classes[i];
+
+             valuator = &device->valuators[device->scroll_valuator_count++];
+             valuator->horizontal = (scroll->scroll_type
+                                     == XIScrollTypeHorizontal);
+             valuator->invalid_p = true;
+             valuator->emacs_value = DBL_MIN;
+             valuator->increment = scroll->increment;
+             valuator->number = scroll->number;
+             break;
+
+#ifdef HAVE_XINPUT2_2
+           case XITouchClass:
+             touch = (XITouchClassInfo *) info->classes[i];
+
+             if (touch->mode == XIDirectTouch)
+               device->direct_p = true;
+             break;
+#endif
+           }
+       }
 
-             FRAME_DISPLAY_INFO (f)->grabbed = 0;
-             current_hold_quit = NULL;
+      /* Restore the values of any scroll valuators that we already
+        know about.  */
 
-             block_input ();
-             /* Restore the old event mask.  */
-             XSelectInput (FRAME_X_DISPLAY (f),
-                           FRAME_DISPLAY_INFO (f)->root_window,
-                           root_window_attrs.your_event_mask);
-#ifdef HAVE_XKB
-             if (FRAME_DISPLAY_INFO (f)->supports_xkb)
-               XkbSelectEvents (FRAME_X_DISPLAY (f), XkbUseCoreKbd,
-                                XkbStateNotifyMask, 0);
-#endif
-             /* Delete the Motif drag initiator info if it was set up.  */
-             if (x_dnd_motif_setup_p)
-               XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                                FRAME_DISPLAY_INFO (f)->Xatom_XdndSelection);
+      for (i = 0; i < info->num_classes; ++i)
+       {
+         switch (info->classes[i]->type)
+           {
+           case XIValuatorClass:
+             valuator_info = (XIValuatorClassInfo *) info->classes[i];
 
+             valuator = xi_get_scroll_valuator (device,
+                                                valuator_info->number);
+             if (valuator)
+               {
+                 valuator->invalid_p = false;
+                 valuator->current_value = valuator_info->value;
 
-             /* Remove any type list set as well.  */
-             if (x_dnd_init_type_lists && x_dnd_n_targets > 3)
-               XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                                FRAME_DISPLAY_INFO (f)->Xatom_XdndTypeList);
-             unblock_input ();
+                 /* Make sure that this is reset if the pointer moves
+                    into a window of ours.
 
-             quit ();
+                    Otherwise the valuator state could be left
+                    invalid if the DeviceChange event happened with
+                    the pointer outside any Emacs frame. */
+                 valuator->pending_enter_reset = true;
+               }
+
+             break;
            }
-#else
        }
-      else
+
+#ifdef HAVE_XINPUT2_2
+      /* The device is no longer a DirectTouch device, so
+        remove any touchpoints that we might have
+        recorded.  */
+      if (!device->direct_p)
        {
-         if (x_dnd_movement_frame)
-           x_dnd_movement_frame = NULL;
+         tem = device->touchpoints;
 
-         if (hold_quit.kind != NO_EVENT)
-           EVENT_INIT (hold_quit);
+         while (tem)
+           {
+             last = tem;
+             tem = tem->next;
+             xfree (last);
+           }
+
+         device->touchpoints = NULL;
        }
 #endif
+
+      XIFreeDeviceInfo (info);
     }
+#endif
+}
 
-  x_dnd_waiting_for_finish = false;
+/* Remove the client-side record of every device in TO_DISABLE.
+   Called while processing XI_HierarchyChanged events.  We batch up
+   multiple disabled devices because it is more efficient to disable
+   them at once.  */
 
-#ifdef USE_GTK
-  current_hold_quit = NULL;
+static void
+xi_disable_devices (struct x_display_info *dpyinfo,
+                   int *to_disable, int n_disabled)
+{
+  struct xi_device_t *devices;
+  int ndevices, i, j;
+#ifdef HAVE_XINPUT2_2
+  struct xi_touch_point_t *tem, *last;
 #endif
-  x_dnd_movement_frame = NULL;
 
-  block_input ();
-  /* Restore the old event mask.  */
-  XSelectInput (FRAME_X_DISPLAY (f),
-               FRAME_DISPLAY_INFO (f)->root_window,
-               root_window_attrs.your_event_mask);
-#ifdef HAVE_XKB
-  if (FRAME_DISPLAY_INFO (f)->supports_xkb)
-    XkbSelectEvents (FRAME_X_DISPLAY (f), XkbUseCoreKbd,
-                    XkbStateNotifyMask, 0);
-#endif
-  /* Delete the Motif drag initiator info if it was set up.  */
-  if (x_dnd_motif_setup_p)
-    XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                    FRAME_DISPLAY_INFO (f)->Xatom_XdndSelection);
+  /* Don't pointlessly copy dpyinfo->devices if there are no devices
+     to disable.  */
+  if (!n_disabled)
+    return;
 
-  /* Remove any type list set as well.  */
-  if (x_dnd_init_type_lists && x_dnd_n_targets > 3)
-    XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                    FRAME_DISPLAY_INFO (f)->Xatom_XdndTypeList);
-  unblock_input ();
+  ndevices = 0;
+  devices = xzalloc (sizeof *devices * dpyinfo->num_devices);
 
-  if (x_dnd_return_frame == 3
-      && FRAME_LIVE_P (x_dnd_return_frame_object))
+  /* Loop through every device currently in DPYINFO, and copy it to
+     DEVICES if it is not in TO_DISABLE.  Note that this function
+     should be called with input blocked, since xfree can otherwise
+     call GC, which will call mark_xterm with invalid state.  */
+  for (i = 0; i < dpyinfo->num_devices; ++i)
     {
-      /* Deliberately preserve the last device if
-        x_dnd_return_frame_object is the drag source.  */
-
-      if (x_dnd_return_frame_object != x_dnd_frame)
-       x_dnd_return_frame_object->last_mouse_device = Qnil;
-
-      x_dnd_return_frame_object->mouse_moved = true;
-
-      XSETFRAME (action, x_dnd_return_frame_object);
-      x_dnd_return_frame_object = NULL;
-
-      return unbind_to (base, action);
-    }
-
-  x_dnd_return_frame_object = NULL;
-  FRAME_DISPLAY_INFO (f)->grabbed = 0;
+      for (j = 0; j < n_disabled; ++j)
+       {
+         if (to_disable[j] == dpyinfo->devices[i].device_id)
+           {
+             if (x_dnd_in_progress
+                 /* If the drag-and-drop pointer device is being
+                    disabled, then cancel the drag and drop
+                    operation.  */
+                 && to_disable[j] == x_dnd_pointer_device)
+               x_dnd_cancel_dnd_early ();
+
+             /* Free any scroll valuators that might be on this
+                device.  */
+#ifdef HAVE_XINPUT2_1
+             xfree (dpyinfo->devices[i].valuators);
+#endif
 
-  if (!NILP (x_dnd_action_symbol))
-    return unbind_to (base, x_dnd_action_symbol);
+             /* Free any currently active touch points on this
+                device.  */
+#ifdef HAVE_XINPUT2_2
+             tem = dpyinfo->devices[i].touchpoints;
+             while (tem)
+               {
+                 last = tem;
+                 tem = tem->next;
+                 xfree (last);
+               }
+#endif
 
-  if (x_dnd_action != None)
-    {
-      block_input ();
-      x_catch_errors (FRAME_X_DISPLAY (f));
-      atom_name = x_get_atom_name (FRAME_DISPLAY_INFO (f),
-                                  x_dnd_action, &need_sync);
+             goto out;
+           }
 
-      if (need_sync)
-       x_uncatch_errors ();
-      else
-       /* No protocol request actually happened, so avoid the extra
-          sync by calling x_uncatch_errors_after_check instead.  */
-       x_uncatch_errors_after_check ();
+         devices[ndevices++] = dpyinfo->devices[i];
 
-      if (atom_name)
-       {
-         action = intern (atom_name);
-         xfree (atom_name);
+       out:
+         continue;
        }
-      else
-       action = Qnil;
-      unblock_input ();
-
-      return unbind_to (base, action);
     }
 
-  return unbind_to (base, Qnil);
+  /* Free the old devices array and replace it with ndevices.  */
+  xfree (dpyinfo->devices);
+
+  dpyinfo->devices = devices;
+  dpyinfo->num_devices = ndevices;
 }
 
+#endif
+
 /* The focus may have changed.  Figure out if it is a real focus change,
    by checking both FocusIn/Out and Enter/LeaveNotify events.
 
@@ -11596,37 +13118,6 @@ x_detect_focus_change (struct x_display_info *dpyinfo, 
struct frame *frame,
       }
       break;
 
-#ifdef HAVE_XINPUT2
-    case GenericEvent:
-      {
-       XIEvent *xi_event = event->xcookie.data;
-       XIEnterEvent *enter_or_focus = event->xcookie.data;
-
-        struct frame *focus_frame = dpyinfo->x_focus_event_frame;
-        int focus_state
-          = focus_frame ? focus_frame->output_data.x->focus_state : 0;
-
-       if (xi_event->evtype == XI_FocusIn
-           || xi_event->evtype == XI_FocusOut)
-         x_focus_changed ((xi_event->evtype == XI_FocusIn
-                           ? FocusIn : FocusOut),
-                          ((enter_or_focus->detail
-                            == XINotifyPointer)
-                           ? FOCUS_IMPLICIT : FOCUS_EXPLICIT),
-                            dpyinfo, frame, bufp);
-       else if ((xi_event->evtype == XI_Enter
-                 || xi_event->evtype == XI_Leave)
-                && (enter_or_focus->detail != XINotifyInferior)
-                && enter_or_focus->focus
-                && !(focus_state & FOCUS_EXPLICIT))
-         x_focus_changed ((xi_event->evtype == XI_Enter
-                           ? FocusIn : FocusOut),
-                          FOCUS_IMPLICIT,
-                          dpyinfo, frame, bufp);
-       break;
-      }
-#endif
-
     case FocusIn:
     case FocusOut:
       /* Ignore transient focus events from hotkeys, window manager
@@ -11636,8 +13127,8 @@ x_detect_focus_change (struct x_display_info *dpyinfo, 
struct frame *frame,
          really has focus, and these kinds of focus event don't
          correspond to real user input changes.  GTK+ uses the same
          filtering. */
-      if (event->xfocus.mode == NotifyGrab ||
-          event->xfocus.mode == NotifyUngrab)
+      if (event->xfocus.mode == NotifyGrab
+          || event->xfocus.mode == NotifyUngrab)
         return;
       x_focus_changed (event->type,
                       (event->xfocus.detail == NotifyPointer ?
@@ -11972,6 +13463,105 @@ get_keysym_name (int keysym)
   return value;
 }
 
+static Bool
+x_query_pointer_1 (struct x_display_info *dpyinfo,
+                  int client_pointer_device, Window w,
+                  Window *root_return, Window *child_return,
+                  int *root_x_return, int *root_y_return,
+                  int *win_x_return, int *win_y_return,
+                  unsigned int *mask_return)
+{
+  Bool rc;
+  Display *dpy;
+#ifdef HAVE_XINPUT2
+  bool had_errors;
+  XIModifierState modifiers;
+  XIButtonState buttons;
+  XIGroupState group; /* Unused.  */
+  double root_x, root_y, win_x, win_y;
+  unsigned int state;
+#endif
+
+  dpy = dpyinfo->display;
+
+#ifdef HAVE_XINPUT2
+  if (client_pointer_device != -1)
+    {
+      /* Catch errors caused by the device going away.  This is not
+        very expensive, since XIQueryPointer will sync anyway.  */
+      x_catch_errors (dpy);
+      rc = XIQueryPointer (dpyinfo->display,
+                          dpyinfo->client_pointer_device,
+                          w, root_return, child_return,
+                          &root_x, &root_y, &win_x, &win_y,
+                          &buttons, &modifiers, &group);
+      had_errors = x_had_errors_p (dpy);
+      x_uncatch_errors_after_check ();
+
+      if (had_errors)
+       {
+         /* If the specified client pointer is the display's client
+            pointer, clear it now.  A new client pointer might not be
+            found before the next call to x_query_pointer_1 and
+            waiting for the error leads to excessive syncing.  */
+
+         if (client_pointer_device == dpyinfo->client_pointer_device)
+           dpyinfo->client_pointer_device = -1;
+
+         rc = XQueryPointer (dpyinfo->display, w, root_return,
+                             child_return, root_x_return,
+                             root_y_return, win_x_return,
+                             win_y_return, mask_return);
+       }
+      else
+       {
+         state = 0;
+
+         xi_convert_button_state (&buttons, &state);
+         *mask_return = state | modifiers.effective;
+
+         XFree (buttons.mask);
+
+         *root_x_return = lrint (root_x);
+         *root_y_return = lrint (root_y);
+         *win_x_return = lrint (win_x);
+         *win_y_return = lrint (win_y);
+       }
+    }
+  else
+#endif
+    rc = XQueryPointer (dpy, w, root_return, child_return,
+                       root_x_return, root_y_return, win_x_return,
+                       win_y_return, mask_return);
+
+  return rc;
+}
+
+Bool
+x_query_pointer (Display *dpy, Window w, Window *root_return,
+                Window *child_return, int *root_x_return,
+                int *root_y_return, int *win_x_return,
+                int *win_y_return, unsigned int *mask_return)
+{
+  struct x_display_info *dpyinfo;
+
+  dpyinfo = x_display_info_for_display (dpy);
+
+  if (!dpyinfo)
+    emacs_abort ();
+
+#ifdef HAVE_XINPUT2
+  return x_query_pointer_1 (dpyinfo, dpyinfo->client_pointer_device,
+                           w, root_return, child_return, root_x_return,
+                           root_y_return, win_x_return, win_y_return,
+                           mask_return);
+#else
+  return x_query_pointer_1 (dpyinfo, -1, w, root_return, child_return,
+                           root_x_return, root_y_return, win_x_return,
+                           win_y_return, mask_return);
+#endif
+}
+
 /* Mouse clicks and mouse movement.  Rah.
 
    Formerly, we used PointerMotionHintMask (in standard_event_mask)
@@ -12052,10 +13642,11 @@ x_construct_mouse_click (struct input_event *result,
    The XMotionEvent structure passed as EVENT might not come from the
    X server, and instead be artificially constructed from input
    extension events.  In these special events, the only fields that
-   are initialized are `time', `window', and `x' and `y'.  This
-   function should not access any other fields in EVENT without also
-   initializing the corresponding fields in `ev' under the XI_Motion,
-   XI_Enter and XI_Leave labels inside `handle_one_xevent'.  */
+   are initialized are `time', `window', `send_event', `x' and `y'.
+   This function should not access any other fields in EVENT without
+   also initializing the corresponding fields in `ev' under the
+   XI_Motion, XI_Enter and XI_Leave labels inside
+   `handle_one_xevent'.  */
 
 static bool
 x_note_mouse_movement (struct frame *frame, const XMotionEvent *event,
@@ -12069,6 +13660,7 @@ x_note_mouse_movement (struct frame *frame, const 
XMotionEvent *event,
 
   dpyinfo = FRAME_DISPLAY_INFO (frame);
   dpyinfo->last_mouse_movement_time = event->time;
+  dpyinfo->last_mouse_movement_time_send_event = event->send_event;
   dpyinfo->last_mouse_motion_frame = frame;
   dpyinfo->last_mouse_motion_x = event->x;
   dpyinfo->last_mouse_motion_y = event->y;
@@ -12236,20 +13828,20 @@ XTmouse_position (struct frame **fp, int insist, 
Lisp_Object *bar_window,
       dpyinfo->last_mouse_scroll_bar = NULL;
 
       /* Figure out which root window we're on.  */
-      XQueryPointer (FRAME_X_DISPLAY (*fp),
-                    DefaultRootWindow (FRAME_X_DISPLAY (*fp)),
-                    /* The root window which contains the pointer.  */
-                    &root,
-                    /* Trash which we can't trust if the pointer is on
-                       a different screen.  */
-                    &dummy_window,
-                    /* The position on that root window.  */
-                    &root_x, &root_y,
-                    /* More trash we can't trust.  */
-                    &dummy, &dummy,
-                    /* Modifier keys and pointer buttons, about which
-                       we don't care.  */
-                    (unsigned int *) &dummy);
+      x_query_pointer (FRAME_X_DISPLAY (*fp),
+                      DefaultRootWindow (FRAME_X_DISPLAY (*fp)),
+                      /* The root window which contains the pointer.  */
+                      &root,
+                      /* Trash which we can't trust if the pointer is on
+                         a different screen.  */
+                      &dummy_window,
+                      /* The position on that root window.  */
+                      &root_x, &root_y,
+                      /* More trash we can't trust.  */
+                      &dummy, &dummy,
+                      /* Modifier keys and pointer buttons, about which
+                         we don't care.  */
+                      (unsigned int *) &dummy);
 
       /* Now we have a position on the root; find the innermost window
         containing the pointer.  */
@@ -12384,7 +13976,8 @@ XTmouse_position (struct frame **fp, int insist, 
Lisp_Object *bar_window,
            && (dpyinfo->last_user_time
                < dpyinfo->last_mouse_movement_time))
          x_display_set_last_user_time (dpyinfo,
-                                       dpyinfo->last_mouse_movement_time);
+                                       dpyinfo->last_mouse_movement_time,
+                                       
dpyinfo->last_mouse_movement_time_send_event);
 
        if ((!f1 || FRAME_TOOLTIP_P (f1))
            && (EQ (track_mouse, Qdropping)
@@ -12483,6 +14076,37 @@ XTmouse_position (struct frame **fp, int insist, 
Lisp_Object *bar_window,
 
 /* Scroll bar support.  */
 
+#if defined HAVE_XINPUT2
+
+/* Select for input extension events used by scroll bars.  This will
+   result in the corresponding core events not being generated for
+   SCROLL_BAR.  */
+
+MAYBE_UNUSED static void
+xi_select_scroll_bar_events (struct x_display_info *dpyinfo,
+                            Window scroll_bar)
+{
+  XIEventMask mask;
+  unsigned char *m;
+  ptrdiff_t length;
+
+  length = XIMaskLen (XI_LASTEVENT);
+  mask.mask = m = alloca (length);
+  memset (m, 0, length);
+  mask.mask_len = length;
+
+  mask.deviceid = XIAllMasterDevices;
+  XISetMask (m, XI_ButtonPress);
+  XISetMask (m, XI_ButtonRelease);
+  XISetMask (m, XI_Motion);
+  XISetMask (m, XI_Enter);
+  XISetMask (m, XI_Leave);
+
+  XISelectEvents (dpyinfo->display, scroll_bar, &mask, 1);
+}
+
+#endif
+
 /* Given an X window ID and a DISPLAY, find the struct scroll_bar which
    manages it.
    This can be called in GC, so we have to make sure to strip off mark
@@ -12564,15 +14188,26 @@ static void x_send_scroll_bar_event (Lisp_Object, 
enum scroll_bar_part,
 
 static Lisp_Object window_being_scrolled;
 
-/* Whether this is an Xaw with arrow-scrollbars.  This should imply
-   that movements of 1/20 of the screen size are mapped to up/down.  */
+static Time
+x_get_last_toolkit_time (struct x_display_info *dpyinfo)
+{
+#ifdef USE_X_TOOLKIT
+  return XtLastTimestampProcessed (dpyinfo->display);
+#else
+  return dpyinfo->last_user_time;
+#endif
+}
 
 #ifndef USE_GTK
-/* Id of action hook installed for scroll bars.  */
+/* Id of action hook installed for scroll bars and horizontal scroll
+   bars.  */
 
 static XtActionHookId action_hook_id;
 static XtActionHookId horizontal_action_hook_id;
 
+/* Whether this is an Xaw with arrow-scrollbars.  This should imply
+   that movements of 1/20 of the screen size are mapped to up/down.  */
+
 static Boolean xaw3d_arrow_scroll;
 
 /* Whether the drag scrolling maintains the mouse at the top of the
@@ -12735,11 +14370,13 @@ 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 on a 64-bit X server can pass a window pointer
-     as-is.  A 64-bit client on a 32-bit X server is in trouble
-     because a pointer does not fit and would be truncated while
-     passing through the server.  So use two slots and hope that X12
-     will resolve such issues someday.  */
+  /* 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;
   ev->data.l[2] = part;
@@ -12783,12 +14420,8 @@ x_scroll_bar_to_input_event (const XEvent *event,
   ievent->kind = SCROLL_BAR_CLICK_EVENT;
   ievent->frame_or_window = window;
   ievent->arg = Qnil;
-#ifdef USE_GTK
-  ievent->timestamp = CurrentTime;
-#else
-  ievent->timestamp =
-    XtLastTimestampProcessed (FRAME_X_DISPLAY (XFRAME (w->frame)));
-#endif
+  ievent->timestamp
+    = x_get_last_toolkit_time (FRAME_DISPLAY_INFO (XFRAME (w->frame)));
   ievent->code = 0;
   ievent->part = ev->data.l[2];
   ievent->x = make_fixnum (ev->data.l[3]);
@@ -12818,12 +14451,8 @@ x_horizontal_scroll_bar_to_input_event (const XEvent 
*event,
   ievent->kind = HORIZONTAL_SCROLL_BAR_CLICK_EVENT;
   ievent->frame_or_window = window;
   ievent->arg = Qnil;
-#ifdef USE_GTK
-  ievent->timestamp = CurrentTime;
-#else
-  ievent->timestamp =
-    XtLastTimestampProcessed (FRAME_X_DISPLAY (XFRAME (w->frame)));
-#endif
+  ievent->timestamp
+    = x_get_last_toolkit_time (FRAME_DISPLAY_INFO (XFRAME (w->frame)));
   ievent->code = 0;
   ievent->part = ev->data.l[2];
   ievent->x = make_fixnum (ev->data.l[3]);
@@ -12927,19 +14556,31 @@ xm_scroll_callback (Widget widget, XtPointer 
client_data, XtPointer call_data)
    bar widget.  DATA is a pointer to the scroll_bar structure. */
 
 static gboolean
-xg_scroll_callback (GtkRange     *range,
-                    GtkScrollType scroll,
-                    gdouble       value,
-                    gpointer      user_data)
+xg_scroll_callback (GtkRange *range, GtkScrollType scroll,
+                    gdouble value, gpointer user_data)
 {
-  int whole = 0, portion = 0;
-  struct scroll_bar *bar = user_data;
-  enum scroll_bar_part part = scroll_bar_nowhere;
-  GtkAdjustment *adj = GTK_ADJUSTMENT (gtk_range_get_adjustment (range));
-  struct frame *f = g_object_get_data (G_OBJECT (range), XG_FRAME_DATA);
+  int whole, portion;
+  struct scroll_bar *bar;
+  enum scroll_bar_part part;
+  GtkAdjustment *adj;
+  struct frame *f;
+  guint32 time;
+  struct x_display_info *dpyinfo;
 
   if (xg_ignore_gtk_scrollbar) return false;
 
+  whole = 0;
+  portion = 0;
+  bar = user_data;
+  part = scroll_bar_nowhere;
+  adj = GTK_ADJUSTMENT (gtk_range_get_adjustment (range));
+  f = g_object_get_data (G_OBJECT (range), XG_FRAME_DATA);
+  time = gtk_get_current_event_time ();
+  dpyinfo = FRAME_DISPLAY_INFO (f);
+
+  if (time != GDK_CURRENT_TIME)
+    x_display_set_last_user_time (dpyinfo, time, true);
+
   switch (scroll)
     {
     case GTK_SCROLL_JUMP:
@@ -13006,8 +14647,11 @@ xg_end_scroll_callback (GtkWidget *widget,
                         GdkEventButton *event,
                         gpointer user_data)
 {
-  struct scroll_bar *bar = user_data;
+  struct scroll_bar *bar;
+
+  bar = user_data;
   bar->dragging = -1;
+
   if (WINDOWP (window_being_scrolled))
     {
       x_send_scroll_bar_event (window_being_scrolled,
@@ -13255,25 +14899,8 @@ x_create_toolkit_scroll_bar (struct frame *f, struct 
scroll_bar *bar)
   /* Ask for input extension button and motion events.  This lets us
      send the proper `wheel-up' or `wheel-down' events to Emacs.  */
   if (FRAME_DISPLAY_INFO (f)->supports_xi2)
-    {
-      XIEventMask mask;
-      ptrdiff_t l = XIMaskLen (XI_LASTEVENT);
-      unsigned char *m;
-
-      mask.mask = m = alloca (l);
-      memset (m, 0, l);
-      mask.mask_len = l;
-
-      mask.deviceid = XIAllMasterDevices;
-      XISetMask (m, XI_ButtonPress);
-      XISetMask (m, XI_ButtonRelease);
-      XISetMask (m, XI_Motion);
-      XISetMask (m, XI_Enter);
-      XISetMask (m, XI_Leave);
-
-      XISelectEvents (XtDisplay (widget), XtWindow (widget),
-                     &mask, 1);
-    }
+    xi_select_scroll_bar_events (FRAME_DISPLAY_INFO (f),
+                                XtWindow (widget));
 #endif
 #else /* !USE_MOTIF i.e. use Xaw */
 
@@ -13480,25 +15107,8 @@ x_create_horizontal_toolkit_scroll_bar (struct frame 
*f, struct scroll_bar *bar)
   /* Ask for input extension button and motion events.  This lets us
      send the proper `wheel-up' or `wheel-down' events to Emacs.  */
   if (FRAME_DISPLAY_INFO (f)->supports_xi2)
-    {
-      XIEventMask mask;
-      ptrdiff_t l = XIMaskLen (XI_LASTEVENT);
-      unsigned char *m;
-
-      mask.mask = m = alloca (l);
-      memset (m, 0, l);
-      mask.mask_len = l;
-
-      mask.deviceid = XIAllMasterDevices;
-      XISetMask (m, XI_ButtonPress);
-      XISetMask (m, XI_ButtonRelease);
-      XISetMask (m, XI_Motion);
-      XISetMask (m, XI_Enter);
-      XISetMask (m, XI_Leave);
-
-      XISelectEvents (XtDisplay (widget), XtWindow (widget),
-                     &mask, 1);
-    }
+    xi_select_scroll_bar_events (FRAME_DISPLAY_INFO (f),
+                                XtWindow (widget));
 #endif
 #else /* !USE_MOTIF i.e. use Xaw */
 
@@ -13886,20 +15496,12 @@ x_scroll_bar_create (struct window *w, int top, int 
left,
     XSetWindowAttributes a;
     unsigned long mask;
     Window window;
-#ifdef HAVE_XDBE
-    Drawable drawable;
-#endif
-
-    a.background_pixel = f->output_data.x->scroll_bar_background_pixel;
-    if (a.background_pixel == -1)
-      a.background_pixel = FRAME_BACKGROUND_PIXEL (f);
 
     a.event_mask = (ButtonPressMask | ButtonReleaseMask
-                   | ButtonMotionMask | PointerMotionHintMask
-                   | ExposureMask);
+                   | ButtonMotionMask | PointerMotionHintMask);
     a.cursor = FRAME_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
 
-    mask = (CWBackPixel | CWEventMask | CWCursor);
+    mask = (CWEventMask | CWCursor);
 
     /* Clear the area of W that will serve as a scroll bar.  This is
        for the case that a window has been split horizontally.  In
@@ -13907,61 +15509,32 @@ x_scroll_bar_create (struct window *w, int top, int 
left,
     if (width > 0 && window_box_height (w) > 0)
       x_clear_area (f, left, top, width, window_box_height (w));
 
+    /* Create an input only window.  Scroll bar contents are drawn to
+       the frame window itself, so they can be double buffered and
+       synchronized using the same mechanism as the frame.  */
     window = XCreateWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
                            /* Position and size of scroll bar.  */
                            left, top, width, height,
-                           /* Border width, depth, class, and visual.  */
+                           /* Border width.  */
                            0,
+                           /* Depth.  */
                            CopyFromParent,
-                           CopyFromParent,
+                           /* Class.  */
+                           InputOnly,
+                           /* Visual class.  */
                            CopyFromParent,
                             /* Attributes.  */
                            mask, &a);
-#ifdef HAVE_XDBE
-    if (FRAME_DISPLAY_INFO (f)->supports_xdbe
-       && FRAME_X_DOUBLE_BUFFERED_P (f))
-      {
-       x_catch_errors (FRAME_X_DISPLAY (f));
-       drawable = XdbeAllocateBackBufferName (FRAME_X_DISPLAY (f),
-                                              window, XdbeCopied);
-       if (x_had_errors_p (FRAME_X_DISPLAY (f)))
-         drawable = window;
-       else
-         XSetWindowBackgroundPixmap (FRAME_X_DISPLAY (f), window, None);
-       x_uncatch_errors_after_check ();
-      }
-    else
-      drawable = window;
-#endif
 
 #ifdef HAVE_XINPUT2
   /* Ask for input extension button and motion events.  This lets us
      send the proper `wheel-up' or `wheel-down' events to Emacs.  */
   if (FRAME_DISPLAY_INFO (f)->supports_xi2)
-    {
-      XIEventMask mask;
-      ptrdiff_t l = XIMaskLen (XI_LASTEVENT);
-      unsigned char *m;
-
-      mask.mask = m = alloca (l);
-      memset (m, 0, l);
-      mask.mask_len = l;
-
-      mask.deviceid = XIAllMasterDevices;
-      XISetMask (m, XI_ButtonPress);
-      XISetMask (m, XI_ButtonRelease);
-      XISetMask (m, XI_Motion);
-      XISetMask (m, XI_Enter);
-      XISetMask (m, XI_Leave);
-
-      XISelectEvents (FRAME_X_DISPLAY (f), window, &mask, 1);
-    }
+    xi_select_scroll_bar_events (FRAME_DISPLAY_INFO (f),
+                                window);
 #endif
 
     bar->x_window = window;
-#ifdef HAVE_XDBE
-    bar->x_drawable = drawable;
-#endif
   }
 #endif /* not USE_TOOLKIT_SCROLL_BARS */
 
@@ -14034,14 +15607,11 @@ static void
 x_scroll_bar_set_handle (struct scroll_bar *bar, int start, int end,
                         bool rebuild)
 {
-  bool dragging = bar->dragging != -1;
-#ifndef HAVE_XDBE
-  Window w = bar->x_window;
-#else
-  Drawable w = bar->x_drawable;
-#endif
-  struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
-  GC gc = f->output_data.x->normal_gc;
+  bool dragging;
+  struct frame *f;
+  Drawable w;
+  GC gc;
+  int inside_width, inside_height, top_range, length;
 
   /* If the display is already accurate, do nothing.  */
   if (! rebuild
@@ -14049,106 +15619,102 @@ x_scroll_bar_set_handle (struct scroll_bar *bar, 
int start, int end,
       && end == bar->end)
     return;
 
-  block_input ();
-
-  {
-    int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (f, bar->width);
-    int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, bar->height);
-    int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, bar->height);
+  f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
+  dragging = bar->dragging != -1;
+  gc = f->output_data.x->normal_gc;
+  w = FRAME_X_DRAWABLE (f);
 
-    /* Make sure the values are reasonable, and try to preserve
-       the distance between start and end.  */
-    {
-      int length = end - start;
+  block_input ();
 
-      if (start < 0)
-       start = 0;
-      else if (start > top_range)
-       start = top_range;
-      end = start + length;
+  inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (f, bar->width);
+  inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, bar->height);
+  top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, bar->height);
 
-      if (end < start)
-       end = start;
-      else if (end > top_range && ! dragging)
-       end = top_range;
-    }
+  /* Make sure the values are reasonable, and try to preserve
+     the distance between start and end.  */
+  length = end - start;
 
-    /* Store the adjusted setting in the scroll bar.  */
-    bar->start = start;
-    bar->end = end;
+  if (start < 0)
+    start = 0;
+  else if (start > top_range)
+    start = top_range;
+  end = start + length;
 
-    /* Clip the end position, just for display.  */
-    if (end > top_range)
-      end = top_range;
+  if (end < start)
+    end = start;
+  else if (end > top_range && ! dragging)
+    end = top_range;
 
-    /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
-       below top positions, to make sure the handle is always at least
-       that many pixels tall.  */
-    end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
+  /* Store the adjusted setting in the scroll bar.  */
+  bar->start = start;
+  bar->end = end;
 
-    /* Draw the empty space above the handle.  Note that we can't clear
-       zero-height areas; that means "clear to end of window."  */
-    if ((inside_width > 0) && (start > 0))
-      {
-       if (f->output_data.x->scroll_bar_background_pixel != -1)
-         XSetForeground (FRAME_X_DISPLAY (f), gc,
-                         f->output_data.x->scroll_bar_background_pixel);
-       else
-         XSetForeground (FRAME_X_DISPLAY (f), gc,
-                         FRAME_BACKGROUND_PIXEL (f));
+  /* Clip the end position, just for display.  */
+  if (end > top_range)
+    end = top_range;
 
-       XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
-                       VERTICAL_SCROLL_BAR_LEFT_BORDER,
-                       VERTICAL_SCROLL_BAR_TOP_BORDER,
-                       inside_width, start);
+  /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
+     below top positions, to make sure the handle is always at least
+     that many pixels tall.  */
+  end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
 
+  /* Draw the empty space above the handle.  Note that we can't clear
+     zero-height areas; that means "clear to end of window."  */
+  if ((inside_width > 0) && (start > 0))
+    {
+      if (f->output_data.x->scroll_bar_background_pixel != -1)
+       XSetForeground (FRAME_X_DISPLAY (f), gc,
+                       f->output_data.x->scroll_bar_background_pixel);
+      else
        XSetForeground (FRAME_X_DISPLAY (f), gc,
-                       FRAME_FOREGROUND_PIXEL (f));
-      }
+                       FRAME_BACKGROUND_PIXEL (f));
 
-    /* Change to proper foreground color if one is specified.  */
-    if (f->output_data.x->scroll_bar_foreground_pixel != -1)
-      XSetForeground (FRAME_X_DISPLAY (f), gc,
-                     f->output_data.x->scroll_bar_foreground_pixel);
+      XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
+                     bar->left + VERTICAL_SCROLL_BAR_LEFT_BORDER,
+                     bar->top + VERTICAL_SCROLL_BAR_TOP_BORDER,
+                     inside_width, start);
 
-    /* Draw the handle itself.  */
-    XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
-                   /* x, y, width, height */
-                   VERTICAL_SCROLL_BAR_LEFT_BORDER,
-                   VERTICAL_SCROLL_BAR_TOP_BORDER + start,
-                   inside_width, end - start);
+      XSetForeground (FRAME_X_DISPLAY (f), gc,
+                     FRAME_FOREGROUND_PIXEL (f));
+    }
 
+  /* Change to proper foreground color if one is specified.  */
+  if (f->output_data.x->scroll_bar_foreground_pixel != -1)
+    XSetForeground (FRAME_X_DISPLAY (f), gc,
+                   f->output_data.x->scroll_bar_foreground_pixel);
 
-    /* Draw the empty space below the handle.  Note that we can't
-       clear zero-height areas; that means "clear to end of window." */
-    if ((inside_width > 0) && (end < inside_height))
-      {
-       if (f->output_data.x->scroll_bar_background_pixel != -1)
-         XSetForeground (FRAME_X_DISPLAY (f), gc,
-                         f->output_data.x->scroll_bar_background_pixel);
-       else
-         XSetForeground (FRAME_X_DISPLAY (f), gc,
-                         FRAME_BACKGROUND_PIXEL (f));
+  /* Draw the handle itself.  */
+  XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
+                 /* x, y, width, height */
+                 bar->left + VERTICAL_SCROLL_BAR_LEFT_BORDER,
+                 bar->top + VERTICAL_SCROLL_BAR_TOP_BORDER + start,
+                 inside_width, end - start);
 
-       XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
-                       VERTICAL_SCROLL_BAR_LEFT_BORDER,
-                       VERTICAL_SCROLL_BAR_TOP_BORDER + end,
-                       inside_width, inside_height - end);
 
+  /* Draw the empty space below the handle.  Note that we can't
+     clear zero-height areas; that means "clear to end of window." */
+  if ((inside_width > 0) && (end < inside_height))
+    {
+      if (f->output_data.x->scroll_bar_background_pixel != -1)
        XSetForeground (FRAME_X_DISPLAY (f), gc,
-                       FRAME_FOREGROUND_PIXEL (f));
-      }
+                       f->output_data.x->scroll_bar_background_pixel);
+      else
+       XSetForeground (FRAME_X_DISPLAY (f), gc,
+                       FRAME_BACKGROUND_PIXEL (f));
+
+      XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
+                     bar->left + VERTICAL_SCROLL_BAR_LEFT_BORDER,
+                     bar->top + VERTICAL_SCROLL_BAR_TOP_BORDER + end,
+                     inside_width, inside_height - end);
 
-    /* Restore the foreground color of the GC if we changed it above.  */
-    if (f->output_data.x->scroll_bar_foreground_pixel != -1)
       XSetForeground (FRAME_X_DISPLAY (f), gc,
                      FRAME_FOREGROUND_PIXEL (f));
-  }
+    }
 
-#ifdef HAVE_XDBE
-  if (!rebuild)
-    x_scroll_bar_end_update (FRAME_DISPLAY_INFO (f), bar);
-#endif
+  /* Restore the foreground color of the GC if we changed it above.  */
+  if (f->output_data.x->scroll_bar_foreground_pixel != -1)
+    XSetForeground (FRAME_X_DISPLAY (f), gc,
+                   FRAME_FOREGROUND_PIXEL (f));
 
   unblock_input ();
 }
@@ -14171,11 +15737,6 @@ x_scroll_bar_remove (struct scroll_bar *bar)
   XtDestroyWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar));
 #endif /* not USE_GTK */
 #else
-#ifdef HAVE_XDBE
-  if (bar->x_window != bar->x_drawable)
-    XdbeDeallocateBackBufferName (FRAME_X_DISPLAY (f),
-                                 bar->x_drawable);
-#endif
   XDestroyWindow (FRAME_X_DISPLAY (f), bar->x_window);
 #endif
 
@@ -14221,6 +15782,12 @@ XTset_vertical_scroll_bar (struct window *w, int 
portion, int whole, int positio
        }
 
       bar = x_scroll_bar_create (w, top, left, width, max (height, 1), false);
+#ifndef USE_TOOLKIT_SCROLL_BARS
+      /* Since non-toolkit scroll bars don't display their contents to
+        a dedicated window, no expose event will be generated.
+        Redraw the scroll bar manually.  */
+      x_scroll_bar_redraw (bar);
+#endif
     }
   else
     {
@@ -14280,6 +15847,11 @@ XTset_vertical_scroll_bar (struct window *w, int 
portion, int whole, int positio
       bar->width = width;
       bar->height = height;
 
+#ifndef USE_TOOLKIT_SCROLL_BARS
+      /* Redraw the scroll bar.  */
+      x_scroll_bar_redraw (bar);
+#endif
+
       unblock_input ();
     }
 
@@ -14587,60 +16159,84 @@ XTjudge_scroll_bars (struct frame *f)
 
 
 #ifndef USE_TOOLKIT_SCROLL_BARS
-/* Handle an Expose or GraphicsExpose event on a scroll bar.  This
-   is a no-op when using toolkit scroll bars.
-
-   This may be called from a signal handler, so we have to ignore GC
-   mark bits.  */
+/* Handle exposure event EVENT generated for F, by redrawing all
+   intersecting scroll bars.  */
 
 static void
-x_scroll_bar_expose (struct scroll_bar *bar, const XEvent *event)
+x_scroll_bar_handle_exposure (struct frame *f, XEvent *event)
 {
-#ifndef HAVE_XDBE
-  Window w = bar->x_window;
-#else
-  Drawable w = bar->x_drawable;
-#endif
   int x, y, width, height;
+  XRectangle rect, scroll_bar_rect, intersection;
+  Lisp_Object bar, condemned;
+  struct scroll_bar *b;
 
-  if (event->type == Expose)
+  if (event->type == GraphicsExpose)
+    {
+      x = event->xgraphicsexpose.x;
+      y = event->xgraphicsexpose.y;
+      width = event->xgraphicsexpose.width;
+      height = event->xgraphicsexpose.height;
+    }
+  else
     {
       x = event->xexpose.x;
       y = event->xexpose.y;
       width = event->xexpose.width;
       height = event->xexpose.height;
     }
-  else
+
+  rect.x = x;
+  rect.y = y;
+  rect.width = width;
+  rect.height = height;
+
+  /* Scan this frame's scroll bar list for intersecting scroll
+     bars.  */
+  condemned = FRAME_CONDEMNED_SCROLL_BARS (f);
+  for (bar = FRAME_SCROLL_BARS (f);
+       /* This trick allows us to search both the ordinary and
+         condemned scroll bar lists with one loop.  */
+       !NILP (bar) || (bar = condemned,
+                      condemned = Qnil,
+                      !NILP (bar));
+       bar = XSCROLL_BAR (bar)->next)
     {
-      x = event->xgraphicsexpose.x;
-      y = event->xgraphicsexpose.y;
-      width = event->xgraphicsexpose.width;
-      height = event->xgraphicsexpose.height;
+      b = XSCROLL_BAR (bar);
+
+      scroll_bar_rect.x = b->left;
+      scroll_bar_rect.y = b->top;
+      scroll_bar_rect.width = b->width;
+      scroll_bar_rect.height = b->height;
+
+      if (gui_intersect_rectangles (&rect,
+                                   &scroll_bar_rect,
+                                   &intersection))
+       x_scroll_bar_redraw (b);
     }
+}
+
+/* Redraw the scroll bar BAR.  Draw its border and set its thumb.
+   This is usually called from x_clear_frame, but is also used to
+   handle exposure events that overlap scroll bars.  */
 
+static void
+x_scroll_bar_redraw (struct scroll_bar *bar)
+{
   struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
   GC gc = f->output_data.x->normal_gc;
 
-  block_input ();
-
-#ifdef HAVE_XDBE
-  if (w != bar->x_window)
-    {
-      if (f->output_data.x->scroll_bar_background_pixel != -1)
-       XSetForeground (FRAME_X_DISPLAY (f), gc,
-                       f->output_data.x->scroll_bar_background_pixel);
-      else
-       XSetForeground (FRAME_X_DISPLAY (f), gc,
-                       FRAME_BACKGROUND_PIXEL (f));
+  if (f->output_data.x->scroll_bar_background_pixel != -1)
+    XSetForeground (FRAME_X_DISPLAY (f), gc,
+                   f->output_data.x->scroll_bar_background_pixel);
+  else
+    XSetForeground (FRAME_X_DISPLAY (f), gc,
+                   FRAME_BACKGROUND_PIXEL (f));
 
-      XFillRectangle (FRAME_X_DISPLAY (f),
-                     bar->x_drawable,
-                     gc, x, y, width, height);
+  XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f), gc,
+                 bar->left, bar->top, bar->width, bar->height);
 
-      XSetForeground (FRAME_X_DISPLAY (f), gc,
-                     FRAME_FOREGROUND_PIXEL (f));
-    }
-#endif
+  XSetForeground (FRAME_X_DISPLAY (f), gc,
+                 FRAME_FOREGROUND_PIXEL (f));
 
   x_scroll_bar_set_handle (bar, bar->start, bar->end, true);
 
@@ -14650,27 +16246,13 @@ x_scroll_bar_expose (struct scroll_bar *bar, const 
XEvent *event)
                    f->output_data.x->scroll_bar_foreground_pixel);
 
   /* Draw a one-pixel border just inside the edges of the scroll bar.  */
-  XDrawRectangle (FRAME_X_DISPLAY (f), w, gc,
-                 /* x, y, width, height */
-                 0, 0, bar->width - 1, bar->height - 1);
-
-  /* XDrawPoint (FRAME_X_DISPLAY (f), w, gc,
-                bar->width - 1, bar->height - 1);
-
-     This code is no longer required since the normal GC now uses the
-     regular line width.  */
+  XDrawRectangle (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f), gc,
+                 bar->left, bar->top, bar->width - 1, bar->height - 1);
 
   /* Restore the foreground color of the GC if we changed it above.  */
   if (f->output_data.x->scroll_bar_foreground_pixel != -1)
     XSetForeground (FRAME_X_DISPLAY (f), gc,
                    FRAME_FOREGROUND_PIXEL (f));
-
-#ifdef HAVE_XDBE
-  x_scroll_bar_end_update (FRAME_DISPLAY_INFO (f), bar);
-#endif
-
-   unblock_input ();
-
 }
 #endif /* not USE_TOOLKIT_SCROLL_BARS */
 
@@ -14792,6 +16374,7 @@ x_scroll_bar_note_movement (struct scroll_bar *bar,
   struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
 
   dpyinfo->last_mouse_movement_time = event->time;
+  dpyinfo->last_mouse_movement_time_send_event = event->send_event;
   dpyinfo->last_mouse_scroll_bar = bar;
   f->mouse_moved = true;
 
@@ -14810,24 +16393,6 @@ x_scroll_bar_note_movement (struct scroll_bar *bar,
     }
 }
 
-#ifdef HAVE_XDBE
-static void
-x_scroll_bar_end_update (struct x_display_info *dpyinfo,
-                        struct scroll_bar *bar)
-{
-  XdbeSwapInfo swap_info;
-
-  /* This means the scroll bar is double-buffered.  */
-  if (bar->x_drawable != bar->x_window)
-    {
-      memset (&swap_info, 0, sizeof swap_info);
-      swap_info.swap_window = bar->x_window;
-      swap_info.swap_action = XdbeCopied;
-      XdbeSwapBuffers (dpyinfo->display, &swap_info, 1);
-    }
-}
-#endif
-
 #endif /* !USE_TOOLKIT_SCROLL_BARS */
 
 /* Return information to the user about the current position of the mouse
@@ -14851,17 +16416,17 @@ x_scroll_bar_report_motion (struct frame **fp, 
Lisp_Object *bar_window,
 
   /* Get the mouse's position relative to the scroll bar window, and
      report that.  */
-  if (XQueryPointer (FRAME_X_DISPLAY (f), w,
+  if (x_query_pointer (FRAME_X_DISPLAY (f), w,
 
-                    /* Root, child, root x and root y.  */
-                    &dummy_window, &dummy_window,
-                    &dummy_coord, &dummy_coord,
+                      /* Root, child, root x and root y.  */
+                      &dummy_window, &dummy_window,
+                      &dummy_coord, &dummy_coord,
 
-                    /* Position relative to scroll bar.  */
-                    &win_x, &win_y,
+                      /* Position relative to scroll bar.  */
+                      &win_x, &win_y,
 
-                    /* Mouse buttons and modifier keys.  */
-                    &dummy_mask))
+                      /* Mouse buttons and modifier keys.  */
+                      &dummy_mask))
     {
       int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, bar->height);
 
@@ -14920,17 +16485,17 @@ x_horizontal_scroll_bar_report_motion (struct frame 
**fp, Lisp_Object *bar_windo
 
   /* Get the mouse's position relative to the scroll bar window, and
      report that.  */
-  if (XQueryPointer (FRAME_X_DISPLAY (f), w,
+  if (x_query_pointer (FRAME_X_DISPLAY (f), w,
 
-                    /* Root, child, root x and root y.  */
-                    &dummy_window, &dummy_window,
-                    &dummy_coord, &dummy_coord,
+                      /* Root, child, root x and root y.  */
+                      &dummy_window, &dummy_window,
+                      &dummy_coord, &dummy_coord,
 
-                    /* Position relative to scroll bar.  */
-                    &win_x, &win_y,
+                      /* Position relative to scroll bar.  */
+                      &win_x, &win_y,
 
-                    /* Mouse buttons and modifier keys.  */
-                    &dummy_mask))
+                      /* Mouse buttons and modifier keys.  */
+                      &dummy_mask))
     {
       int left_range = HORIZONTAL_SCROLL_BAR_LEFT_RANGE (f, bar->width);
 
@@ -14968,17 +16533,15 @@ x_horizontal_scroll_bar_report_motion (struct frame 
**fp, Lisp_Object *bar_windo
 }
 
 
-/* The screen has been cleared so we may have changed foreground or
-   background colors, and the scroll bars may need to be redrawn.
-   Clear out the scroll bars, and ask for expose events, so we can
-   redraw them.  */
+/* The screen has been cleared and foreground or background colors may
+   have changed, so the scroll bars need to be redrawn.  Clear the
+   scroll bars and redraw them.  */
 
 static void
 x_scroll_bar_clear (struct frame *f)
 {
 #ifndef USE_TOOLKIT_SCROLL_BARS
-  Lisp_Object bar;
-#ifdef HAVE_XDBE
+  Lisp_Object bar, condemned;
   GC gc = f->output_data.x->normal_gc;
 
   if (f->output_data.x->scroll_bar_background_pixel != -1)
@@ -14987,35 +16550,25 @@ x_scroll_bar_clear (struct frame *f)
   else
     XSetForeground (FRAME_X_DISPLAY (f), gc,
                    FRAME_BACKGROUND_PIXEL (f));
-#endif
 
   /* We can have scroll bars even if this is 0,
      if we just turned off scroll bar mode.
      But in that case we should not clear them.  */
   if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
-    for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
-        bar = XSCROLL_BAR (bar)->next)
-      {
-#ifdef HAVE_XDBE
-       if (XSCROLL_BAR (bar)->x_window
-           == XSCROLL_BAR (bar)->x_drawable)
-#endif
-         XClearArea (FRAME_X_DISPLAY (f),
-                     XSCROLL_BAR (bar)->x_window,
-                     0, 0, 0, 0, True);
-#ifdef HAVE_XDBE
-       else
-         XFillRectangle (FRAME_X_DISPLAY (f),
-                         XSCROLL_BAR (bar)->x_drawable,
-                         gc, 0, 0, XSCROLL_BAR (bar)->width,
-                         XSCROLL_BAR (bar)->height);
-#endif
-      }
+    {
+      condemned = FRAME_CONDEMNED_SCROLL_BARS (f);
+      for (bar = FRAME_SCROLL_BARS (f);
+          /* This trick allows us to search both the ordinary and
+              condemned scroll bar lists with one loop.  */
+          !NILP (bar) || (bar = condemned,
+                          condemned = Qnil,
+                          !NILP (bar));
+          bar = XSCROLL_BAR (bar)->next)
+       x_scroll_bar_redraw (XSCROLL_BAR (bar));
+    }
 
-#ifdef HAVE_XDBE
   XSetForeground (FRAME_X_DISPLAY (f), gc,
                  FRAME_FOREGROUND_PIXEL (f));
-#endif
 #endif /* not USE_TOOLKIT_SCROLL_BARS */
 }
 
@@ -15419,6 +16972,15 @@ x_dnd_update_tooltip_position (int root_x, int root_y)
       x_dnd_compute_tip_xy (&root_x, &root_y,
                            x_dnd_monitors);
 
+      if (x_dnd_last_tooltip_valid
+         && root_x == x_dnd_last_tooltip_x
+         && root_y == x_dnd_last_tooltip_y)
+       return;
+
+      x_dnd_last_tooltip_x = root_x;
+      x_dnd_last_tooltip_y = root_y;
+      x_dnd_last_tooltip_valid = true;
+
       XMoveWindow (FRAME_X_DISPLAY (x_dnd_frame),
                   tip_window, root_x, root_y);
     }
@@ -15439,11 +17001,19 @@ x_dnd_update_tooltip_now (void)
 
   dpyinfo = FRAME_DISPLAY_INFO (x_dnd_frame);
 
+#ifndef HAVE_XINPUT2
   rc = XQueryPointer (dpyinfo->display,
                      dpyinfo->root_window,
                      &root, &child, &root_x,
                      &root_y, &win_x, &win_y,
                      &mask);
+#else
+  rc = x_query_pointer_1 (dpyinfo, x_dnd_pointer_device,
+                         dpyinfo->root_window,
+                         &root, &child, &root_x,
+                         &root_y, &win_x, &win_y,
+                         &mask);
+#endif
 
   if (rc)
     x_dnd_update_tooltip_position (root_x, root_y);
@@ -15463,12 +17033,17 @@ x_dnd_update_state (struct x_display_info *dpyinfo, 
Time timestamp)
   xm_drop_start_message dsmsg;
   bool was_frame;
 
-  if (XQueryPointer (dpyinfo->display,
-                    dpyinfo->root_window,
-                    &dummy, &dummy_child,
-                    &root_x, &root_y,
-                    &dummy_x, &dummy_y,
-                    &dummy_mask))
+  if (x_query_pointer_1 (dpyinfo,
+#ifdef HAVE_XINPUT2
+                        x_dnd_pointer_device,
+#else
+                        -1,
+#endif
+                        dpyinfo->root_window,
+                        &dummy, &dummy_child,
+                        &root_x, &root_y,
+                        &dummy_x, &dummy_y,
+                        &dummy_mask))
     {
       target = x_dnd_get_target_window (dpyinfo, root_x,
                                        root_y, &target_proto,
@@ -15569,7 +17144,7 @@ x_dnd_update_state (struct x_display_info *dpyinfo, 
Time timestamp)
              emsg.zero = 0;
              emsg.timestamp = timestamp;
              emsg.source_window = FRAME_X_WINDOW (x_dnd_frame);
-             emsg.index_atom = dpyinfo->Xatom_XdndSelection;
+             emsg.index_atom = x_dnd_motif_atom;
 
              if (x_dnd_motif_setup_p)
                xm_send_top_level_enter_message (dpyinfo, FRAME_X_WINDOW 
(x_dnd_frame),
@@ -15641,8 +17216,7 @@ x_dnd_update_state (struct x_display_info *dpyinfo, 
Time timestamp)
                                   XM_DROP_ACTION_DROP_CANCEL);
          dsmsg.x = 0;
          dsmsg.y = 0;
-         dsmsg.index_atom
-           = FRAME_DISPLAY_INFO (x_dnd_frame)->Xatom_XdndSelection;
+         dsmsg.index_atom = x_dnd_motif_atom;
          dsmsg.source_window = FRAME_X_WINDOW (x_dnd_frame);
 
          x_dnd_send_xm_leave_for_drop (dpyinfo, x_dnd_frame,
@@ -15793,6 +17367,29 @@ x_wait_for_cell_change (Lisp_Object cell, struct 
timespec timeout)
     }
 }
 
+/* Find whether or not an undelivered MONITORS_CHANGED_EVENT is
+   already on the event queue.  DPYINFO is the display any such event
+   must apply to.  */
+
+static bool
+x_find_monitors_changed_event (struct x_display_info *dpyinfo)
+{
+  union buffered_input_event *event;
+
+  event = kbd_fetch_ptr;
+
+  while (event != kbd_store_ptr)
+    {
+      if (event->ie.kind == MONITORS_CHANGED_EVENT
+         && XTERMINAL (event->ie.arg) == dpyinfo->terminal)
+       return true;
+
+      event = X_NEXT_KBD_EVENT (event);
+    }
+
+  return false;
+}
+
 #ifdef USE_GTK
 static void
 x_monitors_changed_cb (GdkScreen *gscr, gpointer user_data)
@@ -15810,6 +17407,9 @@ x_monitors_changed_cb (GdkScreen *gscr, gpointer 
user_data)
   if (!dpyinfo)
     return;
 
+  if (x_find_monitors_changed_event (dpyinfo))
+    return;
+
   XSETTERMINAL (terminal, dpyinfo->terminal);
 
   current_monitors
@@ -15842,8 +17442,10 @@ x_coords_from_dnd_message (struct x_display_info 
*dpyinfo,
                           XEvent *event, int *x_out, int *y_out)
 {
   xm_drag_motion_message dmsg;
+  xm_drag_motion_reply dreply;
   xm_drop_start_message smsg;
   xm_drop_start_reply reply;
+  unsigned long kde_data;
 
   if (event->type != ClientMessage)
     return false;
@@ -15869,6 +17471,13 @@ x_coords_from_dnd_message (struct x_display_info 
*dpyinfo,
          *x_out = dmsg.x;
          *y_out = dmsg.y;
 
+         return true;
+       }
+      else if (!xm_read_drag_motion_reply (event, &dreply))
+       {
+         *x_out = dreply.better_x;
+         *y_out = dreply.better_y;
+
          return true;
        }
       else if (!xm_read_drop_start_message (event, &smsg))
@@ -15887,6 +17496,23 @@ x_coords_from_dnd_message (struct x_display_info 
*dpyinfo,
        }
     }
 
+  if (((event->xclient.message_type
+       == dpyinfo->Xatom_DndProtocol)
+       || (event->xclient.message_type
+          == dpyinfo->Xatom_DND_PROTOCOL))
+      && event->xclient.format == 32
+      /* Check that the version of the old KDE protocol is new
+        enough to include coordinates.  */
+      && event->xclient.data.l[4])
+    {
+      kde_data = (unsigned long) event->xclient.data.l[3];
+
+      *x_out = (kde_data & 0xffff);
+      *y_out = (kde_data >> 16 & 0xffff);
+
+      return true;
+    }
+
   return false;
 }
 
@@ -15911,6 +17537,10 @@ handle_one_xevent (struct x_display_info *dpyinfo,
   union buffered_input_event inev;
   int count = 0;
   int do_help = 0;
+#ifdef HAVE_XINPUT2
+  struct xi_device_t *gen_help_device;
+  Time gen_help_time;
+#endif
   ptrdiff_t nbytes = 0;
   struct frame *any, *f = NULL;
   Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight;
@@ -15940,6 +17570,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
   EVENT_INIT (inev.ie);
   inev.ie.kind = NO_EVENT;
   inev.ie.arg = Qnil;
+#ifdef HAVE_XINPUT2
+  gen_help_device = NULL;
+#endif
 
   /* Ignore events coming from various extensions, such as XFIXES and
      XKB.  */
@@ -15966,21 +17599,31 @@ handle_one_xevent (struct x_display_info *dpyinfo,
       {
        int rc;
 
-       if (x_dnd_in_progress
-           && FRAME_DISPLAY_INFO (x_dnd_frame) == dpyinfo
+       if (((x_dnd_in_progress
+             && FRAME_DISPLAY_INFO (x_dnd_frame) == dpyinfo)
+            || (x_dnd_waiting_for_finish
+                && FRAME_DISPLAY_INFO (x_dnd_finish_frame) == dpyinfo))
            && event->xclient.message_type == dpyinfo->Xatom_XdndStatus)
          {
            Window target;
            unsigned long r1, r2;
+           int root_x, root_y;
+           bool button;
 
            target = event->xclient.data.l[0];
 
            if (x_dnd_last_protocol_version != -1
+               && x_dnd_in_progress
                && target == x_dnd_last_seen_window
-               && event->xclient.data.l[1] & 2)
+               /* The XDND documentation is not very clearly worded.
+                  But this should be the correct behavior, since
+                  "kDNDStatusSendHereFlag" in the reference
+                  implementation is 2, and means the mouse rect
+                  should be ignored.  */
+               && !(event->xclient.data.l[1] & 2))
              {
                r1 = event->xclient.data.l[2];
-               r2 = event->xclient.data.l[2];
+               r2 = event->xclient.data.l[3];
 
                x_dnd_mouse_rect_target = target;
                x_dnd_mouse_rect.x = (r1 & 0xffff0000) >> 16;
@@ -15992,7 +17635,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
              x_dnd_mouse_rect_target = None;
 
            if (x_dnd_last_protocol_version != -1
-               && target == x_dnd_last_seen_window)
+               && (x_dnd_in_progress
+                   && target == x_dnd_last_seen_window))
              {
                if (event->xclient.data.l[1] & 1)
                  {
@@ -16005,6 +17649,73 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                  x_dnd_action = None;
              }
 
+           /* Send any pending XdndPosition message.  */
+           if (x_dnd_waiting_for_status_window == target)
+             {
+               if (x_dnd_pending_send_position.type != 0)
+                 {
+                   /* If the last XdndStatus specified a mouse
+                      rectangle and this event falls inside, don't
+                      send the event, but clear
+                      x_dnd_waiting_for_status_window instead.  */
+
+                   root_x = x_dnd_pending_send_position_root_x;
+                   root_y = x_dnd_pending_send_position_root_y;
+                   button = x_dnd_pending_send_position_button;
+
+                   if (target == x_dnd_mouse_rect_target
+                       && x_dnd_mouse_rect.width
+                       && x_dnd_mouse_rect.height
+                       /* Ignore the mouse rectangle if we're
+                          supposed to be sending a button press
+                          instead.  */
+                       && !button
+                       && (root_x >= x_dnd_mouse_rect.x
+                           && root_x < (x_dnd_mouse_rect.x
+                                        + x_dnd_mouse_rect.width)
+                           && root_y >= x_dnd_mouse_rect.y
+                           && root_y < (x_dnd_mouse_rect.y
+                                        + x_dnd_mouse_rect.height)))
+                     x_dnd_waiting_for_status_window = None;
+                   else
+                     {
+                       x_ignore_errors_for_next_request (dpyinfo);
+                       XSendEvent (dpyinfo->display, target,
+                                   False, NoEventMask,
+                                   &x_dnd_pending_send_position);
+                       x_stop_ignoring_errors (dpyinfo);
+                       x_dnd_pending_send_position.type = 0;
+
+                       /* Since we sent another XdndPosition message, we
+                          have to wait for another one in reply, so don't
+                          reset `x_dnd_waiting_for_status_window'
+                          here.  */
+                     }
+                 }
+               else
+                 x_dnd_waiting_for_status_window = None;
+
+               /* Send any pending drop if warranted.  */
+               if (x_dnd_waiting_for_finish && x_dnd_need_send_drop
+                   && x_dnd_waiting_for_status_window == None)
+                 {
+                   if (event->xclient.data.l[1] & 1)
+                     {
+                       if (x_dnd_send_drop_proto >= 2)
+                         x_dnd_action = event->xclient.data.l[4];
+                       else
+                         x_dnd_action = dpyinfo->Xatom_XdndActionCopy;
+                     }
+                   else
+                     x_dnd_action = None;
+
+                   x_dnd_waiting_for_finish
+                     = x_dnd_send_drop (x_dnd_finish_frame,
+                                        target, x_dnd_selection_timestamp,
+                                        x_dnd_send_drop_proto);
+                 }
+             }
+
            goto done;
          }
 
@@ -16045,7 +17756,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
                if (operation != XM_DRAG_MOVE
                    && operation != XM_DRAG_COPY
-                   && operation != XM_DRAG_LINK)
+                   && XM_DRAG_OPERATION_IS_LINK (operation))
                  {
                    x_dnd_waiting_for_finish = false;
                    goto done;
@@ -16062,15 +17773,16 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                switch (operation)
                  {
                  case XM_DRAG_MOVE:
-                   x_dnd_action = dpyinfo->Xatom_XdndActionMove;
+                   x_dnd_action_symbol = QXdndActionMove;
                    break;
 
                  case XM_DRAG_COPY:
-                   x_dnd_action = dpyinfo->Xatom_XdndActionCopy;
+                   x_dnd_action_symbol = QXdndActionCopy;
                    break;
 
-                 case XM_DRAG_LINK:
-                   x_dnd_action = dpyinfo->Xatom_XdndActionLink;
+                   /* This means XM_DRAG_OPERATION_IS_LINK (operation).  */
+                 default:
+                   x_dnd_action_symbol = QXdndActionLink;
                    break;
                  }
 
@@ -16160,11 +17872,14 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
             if (event->xclient.data.l[0] == dpyinfo->Xatom_wm_delete_window)
               {
-                f = any;
+                f = x_top_window_to_frame (dpyinfo,
+                                          event->xclient.window);
+
                 if (!f)
                  goto OTHER; /* May be a dialog that is to be removed  */
 
                inev.ie.kind = DELETE_WINDOW_EVENT;
+               inev.ie.timestamp = event->xclient.data.l[1];
                XSETFRAME (inev.ie.frame_or_window, f);
                goto done;
               }
@@ -16219,8 +17934,10 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                      }
                    else if (event->xclient.data.l[4] == 1)
                      {
-                       XSyncIntsToValue (&FRAME_X_OUTPUT 
(f)->current_extended_counter_value,
-                                         event->xclient.data.l[2], 
event->xclient.data.l[3]);
+                       XSyncIntsToValue (&FRAME_X_OUTPUT 
(f)->resize_counter_value,
+                                         event->xclient.data.l[2],
+                                         event->xclient.data.l[3]);
+
                        FRAME_X_OUTPUT (f)->ext_sync_end_pending_p = true;
                      }
 
@@ -16337,10 +18054,29 @@ handle_one_xevent (struct x_display_info *dpyinfo,
             goto done;
           }
 
-        xft_settings_event (dpyinfo, event);
+#if defined HAVE_XSYNC && !defined USE_GTK && defined HAVE_CLOCK_GETTIME
+       /* These messages are sent by the compositing manager after a
+          frame is drawn under extended synchronization.  */
+       if (event->xclient.message_type
+           == dpyinfo->Xatom_net_wm_frame_drawn)
+         {
+           if (any)
+             x_sync_handle_frame_drawn (dpyinfo, (XEvent *) event, any);
+
+           goto done;
+         }
+
+       if (event->xclient.message_type
+           == dpyinfo->Xatom_net_wm_frame_timings)
+         goto done;
+#endif
+
+        if (xft_settings_event (dpyinfo, event))
+         goto done;
 
        f = any;
-       if (!f)
+       /* We don't want to ever leak tooltip frames to Lisp code.  */
+       if (!f || FRAME_TOOLTIP_P (f))
          goto OTHER;
 
        /* These values are always used initialized, but GCC doesn't
@@ -16362,6 +18098,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
       if (!x_window_to_frame (dpyinfo, event->xselection.requestor))
         goto OTHER;
 #endif /* not USE_X_TOOLKIT and not USE_GTK */
+#ifdef HAVE_GTK3
+      /* GTK 3 apparently chokes on these events since they have no
+        associated device.  (bug#56869, another bug as well that I
+        can't find) */
+      *finish = X_EVENT_DROP;
+#endif
       x_handle_selection_notify (&event->xselection);
       break;
 
@@ -16370,9 +18112,17 @@ handle_one_xevent (struct x_display_info *dpyinfo,
       if (!x_window_to_frame (dpyinfo, event->xselectionclear.window))
         goto OTHER;
 #endif /* not USE_X_TOOLKIT and not USE_GTK */
+#ifdef HAVE_GTK3
+      *finish = X_EVENT_DROP;
+#endif
       {
         const XSelectionClearEvent *eventp = &event->xselectionclear;
 
+       if (eventp->selection == dpyinfo->motif_drag_atom
+           && (eventp->time == CurrentTime
+               || dpyinfo->motif_drag_atom_time <= eventp->time))
+         dpyinfo->motif_drag_atom = None;
+
         inev.sie.kind = SELECTION_CLEAR_EVENT;
         SELECTION_EVENT_DPYINFO (&inev.sie) = dpyinfo;
         SELECTION_EVENT_SELECTION (&inev.sie) = eventp->selection;
@@ -16391,6 +18141,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
       if (!x_window_to_frame (dpyinfo, event->xselectionrequest.owner))
         goto OTHER;
 #endif /* USE_X_TOOLKIT */
+#ifdef HAVE_GTK3
+      *finish = X_EVENT_DROP;
+#endif
       {
        const XSelectionRequestEvent *eventp = &event->xselectionrequest;
 
@@ -16402,9 +18155,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
        SELECTION_EVENT_PROPERTY (&inev.sie) = eventp->property;
        SELECTION_EVENT_TIME (&inev.sie) = eventp->time;
 
-       /* If drag-and-drop is in progress, handle SelectionRequest
-          events immediately, by setting hold_quit to the input
-          event.  */
+       /* If drag-and-drop or another modal dialog/menu is in
+          progress, handle SelectionRequest events immediately, by
+          pushing it onto the selecction queue.  */
 
        if (x_use_pending_selection_requests)
          {
@@ -16415,7 +18168,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
        if (x_dnd_waiting_for_finish
            && x_dnd_waiting_for_motif_finish == 2
            && dpyinfo == x_dnd_waiting_for_motif_finish_display
-           && eventp->selection == dpyinfo->Xatom_XdndSelection
+           && eventp->selection == x_dnd_motif_atom
            && (eventp->target == dpyinfo->Xatom_XmTRANSFER_SUCCESS
                || eventp->target == dpyinfo->Xatom_XmTRANSFER_FAILURE))
          {
@@ -16665,8 +18418,26 @@ handle_one_xevent (struct x_display_info *dpyinfo,
         {
          /* Maybe we shouldn't set this for child frames ??  */
          f->output_data.x->parent_desc = event->xreparent.parent;
+
          if (!FRAME_PARENT_FRAME (f))
-           x_real_positions (f, &f->left_pos, &f->top_pos);
+           {
+             x_real_positions (f, &f->left_pos, &f->top_pos);
+
+             /* Perhaps reparented due to a WM restart.  Reset this.  */
+             FRAME_DISPLAY_INFO (f)->wm_type = X_WMTYPE_UNKNOWN;
+             FRAME_DISPLAY_INFO (f)->net_supported_window = 0;
+
+#ifndef USE_GTK
+             /* The window manager could have restarted and the new
+                window manager might not support user time windows,
+                so update what is used accordingly.
+
+                Note that this doesn't handle changes between
+                non-reparenting window managers.  */
+             if (FRAME_X_OUTPUT (f)->has_been_visible)
+               x_update_frame_user_time_window (f);
+#endif
+           }
          else
            {
              Window root;
@@ -16679,10 +18450,6 @@ handle_one_xevent (struct x_display_info *dpyinfo,
              unblock_input ();
            }
 
-          /* Perhaps reparented due to a WM restart.  Reset this.  */
-          FRAME_DISPLAY_INFO (f)->wm_type = X_WMTYPE_UNKNOWN;
-          FRAME_DISPLAY_INFO (f)->net_supported_window = 0;
-
           x_set_frame_alpha (f);
         }
       goto OTHER;
@@ -16746,7 +18513,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
           if (!FRAME_GARBAGED_P (f))
             {
-#ifdef USE_X_TOOLKIT
+#if defined USE_X_TOOLKIT && defined USE_TOOLKIT_SCROLL_BARS
              if (f->output_data.x->edit_widget)
                /* The widget's expose proc will be run in this
                   case.  */
@@ -16761,10 +18528,17 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 #endif
               expose_frame (f, event->xexpose.x, event->xexpose.y,
                            event->xexpose.width, event->xexpose.height);
+#ifndef USE_TOOLKIT_SCROLL_BARS
+             x_scroll_bar_handle_exposure (f, (XEvent *) event);
+#endif
 #ifdef USE_GTK
              x_clear_under_internal_border (f);
 #endif
             }
+#ifndef USE_TOOLKIT_SCROLL_BARS
+         else
+           x_scroll_bar_handle_exposure (f, (XEvent *) event);
+#endif
 
 #ifdef HAVE_XDBE
           if (!FRAME_GARBAGED_P (f))
@@ -16773,9 +18547,6 @@ handle_one_xevent (struct x_display_info *dpyinfo,
         }
       else
         {
-#ifndef USE_TOOLKIT_SCROLL_BARS
-          struct scroll_bar *bar;
-#endif
 #if defined USE_LUCID
           /* Submenus of the Lucid menu bar aren't widgets
              themselves, so there's no way to dispatch events
@@ -16787,20 +18558,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
           }
 #endif /* USE_LUCID */
 
-#ifdef USE_TOOLKIT_SCROLL_BARS
           /* Dispatch event to the widget.  */
           goto OTHER;
-#else /* not USE_TOOLKIT_SCROLL_BARS */
-          bar = x_window_to_scroll_bar (event->xexpose.display,
-                                        event->xexpose.window, 2);
-
-          if (bar)
-            x_scroll_bar_expose (bar, event);
-#ifdef USE_X_TOOLKIT
-          else
-            goto OTHER;
-#endif /* USE_X_TOOLKIT */
-#endif /* not USE_TOOLKIT_SCROLL_BARS */
         }
       break;
 
@@ -16814,6 +18573,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                         event->xgraphicsexpose.y,
                         event->xgraphicsexpose.width,
                         event->xgraphicsexpose.height);
+#ifndef USE_TOOLKIT_SCROLL_BARS
+         x_scroll_bar_handle_exposure (f, (XEvent *) event);
+#endif
 #ifdef USE_GTK
          x_clear_under_internal_border (f);
 #endif
@@ -16821,16 +18583,6 @@ handle_one_xevent (struct x_display_info *dpyinfo,
          show_back_buffer (f);
 #endif
         }
-#ifndef USE_TOOLKIT_SCROLL_BARS
-      struct scroll_bar *bar
-       = x_window_to_scroll_bar (dpyinfo->display,
-                                 /* Hopefully this is just a window,
-                                    not the back buffer.  */
-                                 event->xgraphicsexpose.drawable, 2);
-
-      if (bar)
-       x_scroll_bar_expose (bar, event);
-#endif
 #ifdef USE_X_TOOLKIT
       else
         goto OTHER;
@@ -16934,6 +18686,11 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 #endif
 
       if (x_dnd_in_progress
+         /* When _NET_WM_CLIENT_LIST stacking is being used, changes
+            in that property are watched for, and it's not necessary
+            to update the state in response to ordinary window
+            substructure events.  */
+         && !x_dnd_use_toplevels
          && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame))
        x_dnd_update_state (dpyinfo, dpyinfo->last_user_time);
 
@@ -17030,8 +18787,10 @@ handle_one_xevent (struct x_display_info *dpyinfo,
       goto OTHER;
 
     case KeyPress:
-      x_display_set_last_user_time (dpyinfo, event->xkey.time);
+      x_display_set_last_user_time (dpyinfo, event->xkey.time,
+                                   event->xkey.send_event);
       ignore_next_mouse_click_timeout = 0;
+
       coding = Qlatin_1;
 
 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
@@ -17042,6 +18801,11 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
       f = any;
 
+#ifdef USE_GTK
+      if (f)
+       x_set_gtk_user_time (f, event->xkey.time);
+#endif
+
       /* If mouse-highlight is an integer, input clears out
         mouse highlighting.  */
       if (!hlinfo->mouse_face_hidden && FIXNUMP (Vmouse_highlight)
@@ -17093,7 +18857,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
          /* `xkey' will be modified, but it's not important to modify
             `event' itself.  */
          XKeyEvent xkey = event->xkey;
-         int i;
+
 #ifdef HAVE_XINPUT2
          Time pending_keystroke_time;
          struct xi_device_t *source;
@@ -17141,28 +18905,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
              this enables ComposeCharacter to work whether or
              not it is combined with Meta.  */
           if (modifiers & dpyinfo->meta_mod_mask)
-            memset (&compose_status, 0, sizeof (compose_status));
-
-#ifdef HAVE_XKB
-         if (dpyinfo->xkb_desc)
-           {
-             XkbDescRec *rec = dpyinfo->xkb_desc;
-
-             if (rec->map->modmap && rec->map->modmap[xkey.keycode])
-               goto done_keysym;
-           }
-         else
-#endif
-           {
-             if (dpyinfo->modmap)
-               {
-                 for (i = 0; i < 8 * dpyinfo->modmap->max_keypermod; i++)
-                   {
-                     if (xkey.keycode == dpyinfo->modmap->modifiermap[i])
-                         goto done_keysym;
-                   }
-               }
-           }
+            memset (&compose_status, 0, sizeof (compose_status));
 
 #ifdef HAVE_X_I18N
           if (FRAME_XIC (f))
@@ -17196,14 +18939,49 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                 emacs_abort ();
             }
           else
-            nbytes = XLookupString (&xkey, (char *) copy_bufptr,
-                                    copy_bufsiz, &keysym,
-                                    &compose_status);
-#else
-          nbytes = XLookupString (&xkey, (char *) copy_bufptr,
-                                  copy_bufsiz, &keysym,
-                                  &compose_status);
 #endif
+           {
+#ifdef HAVE_XKB
+             int overflow;
+             unsigned int consumed;
+
+             if (dpyinfo->xkb_desc)
+               {
+                 if (!XkbTranslateKeyCode (dpyinfo->xkb_desc,
+                                           xkey.keycode, xkey.state,
+                                           &consumed, &keysym))
+                   goto done_keysym;
+
+                 overflow = 0;
+
+                 nbytes = XkbTranslateKeySym (dpyinfo->display, &keysym,
+                                              xkey.state & ~consumed,
+                                              (char *) copy_bufptr,
+                                              copy_bufsiz, &overflow);
+
+                 if (overflow)
+                   {
+                     copy_bufptr = SAFE_ALLOCA ((copy_bufsiz += overflow)
+                                                * sizeof *copy_bufptr);
+                     overflow = 0;
+                     nbytes = XkbTranslateKeySym (dpyinfo->display, &keysym,
+                                                  xkey.state & ~consumed,
+                                                  (char *) copy_bufptr,
+                                                  copy_bufsiz, &overflow);
+
+                     if (overflow)
+                       nbytes = 0;
+                   }
+
+                 if (nbytes)
+                   coding = Qnil;
+               }
+             else
+#endif
+               nbytes = XLookupString (&xkey, (char *) copy_bufptr,
+                                       copy_bufsiz, &keysym,
+                                       &compose_status);
+           }
 
 #ifdef XK_F1
          if (x_dnd_in_progress && keysym == XK_F1)
@@ -17481,7 +19259,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 #endif
 
     case EnterNotify:
-      x_display_set_last_user_time (dpyinfo, event->xcrossing.time);
+      x_display_set_last_user_time (dpyinfo, event->xcrossing.time,
+                                   event->xcrossing.send_event);
 
       if (x_top_window_to_frame (dpyinfo, event->xcrossing.window))
        x_detect_focus_change (dpyinfo, any, event, &inev.ie);
@@ -17534,6 +19313,21 @@ handle_one_xevent (struct x_display_info *dpyinfo,
       goto OTHER;
 
     case FocusIn:
+#if defined HAVE_XINPUT2                                               \
+  && (defined HAVE_GTK3 || (!defined USE_GTK && !defined USE_X_TOOLKIT))
+      /* If a FocusIn event is received (because the window manager
+        sent us one), don't set the core focus if XInput 2 is
+        enabled, since that would mess up the device-specific focus
+        tracking.
+
+        The long looking preprocessor conditional only enables this
+        code on GTK 3 and no toolkit builds, since those are the only
+        builds where focus is tracked specific to each master device.
+        Other builds use core events and the client pointer to handle
+        focus, much like on a build without XInput 2.  */
+      if (dpyinfo->supports_xi2)
+       goto OTHER;
+#endif
 #ifdef USE_GTK
       /* Some WMs (e.g. Mutter in Gnome Shell), don't unmap
          minimized/iconified windows; thus, for those WMs we won't get
@@ -17566,7 +19360,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
       goto OTHER;
 
     case LeaveNotify:
-      x_display_set_last_user_time (dpyinfo, event->xcrossing.time);
+      x_display_set_last_user_time (dpyinfo, event->xcrossing.time,
+                                   event->xcrossing.send_event);
 
 #ifdef HAVE_XWIDGETS
       {
@@ -17603,6 +19398,19 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 #endif
       if (f)
         {
+         /* Now clear dpyinfo->last_mouse_motion_frame, or
+            gui_redo_mouse_highlight will end up highlighting the
+            last known position of the mouse if a tooltip frame is
+            later unmapped.  */
+
+         if (f == dpyinfo->last_mouse_motion_frame)
+           dpyinfo->last_mouse_motion_frame = NULL;
+
+         /* Something similar applies to
+            dpyinfo->last_mouse_glyph_frame.  */
+         if (f == dpyinfo->last_mouse_glyph_frame)
+           dpyinfo->last_mouse_glyph_frame = NULL;
+
           if (f == hlinfo->mouse_face_mouse_frame)
             {
               /* If we move outside the frame, then we're
@@ -17633,6 +19441,21 @@ handle_one_xevent (struct x_display_info *dpyinfo,
       goto OTHER;
 
     case FocusOut:
+#if defined HAVE_XINPUT2                                               \
+  && (defined HAVE_GTK3 || (!defined USE_GTK && !defined USE_X_TOOLKIT))
+      /* If a FocusIn event is received (because the window manager
+        sent us one), don't set the core focus if XInput 2 is
+        enabled, since that would mess up the device-specific focus
+        tracking.
+
+        The long looking preprocessor conditional only enables this
+        code on GTK 3 and no toolkit builds, since those are the only
+        builds where focus is tracked specific to each master device.
+        Other builds use core events and the client pointer to handle
+        focus, much like on a build without XInput 2.  */
+      if (dpyinfo->supports_xi2)
+       goto OTHER;
+#endif
       x_detect_focus_change (dpyinfo, any, event, &inev.ie);
       goto OTHER;
 
@@ -17702,12 +19525,16 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                  }
              }
 
-           target = x_dnd_get_target_window (dpyinfo,
-                                             event->xmotion.x_root,
-                                             event->xmotion.y_root,
-                                             &target_proto,
-                                             &motif_style, &toplevel,
-                                             &was_frame);
+           if (event->xmotion.same_screen)
+             target = x_dnd_get_target_window (dpyinfo,
+                                               event->xmotion.x_root,
+                                               event->xmotion.y_root,
+                                               &target_proto,
+                                               &motif_style, &toplevel,
+                                               &was_frame);
+           else
+             target = x_dnd_fill_empty_target (&target_proto, &motif_style,
+                                               &toplevel, &was_frame);
 
            if (toplevel != x_dnd_last_seen_toplevel)
              {
@@ -17824,7 +19651,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                    emsg.zero = 0;
                    emsg.timestamp = event->xbutton.time;
                    emsg.source_window = FRAME_X_WINDOW (x_dnd_frame);
-                   emsg.index_atom = dpyinfo->Xatom_XdndSelection;
+                   emsg.index_atom = x_dnd_motif_atom;
 
                    if (x_dnd_motif_setup_p)
                      xm_send_top_level_enter_message (dpyinfo, FRAME_X_WINDOW 
(x_dnd_frame),
@@ -18011,13 +19838,24 @@ handle_one_xevent (struct x_display_info *dpyinfo,
          if (configureEvent.xconfigure.width != dpyinfo->screen_width
              || configureEvent.xconfigure.height != dpyinfo->screen_height)
            {
-             inev.ie.kind = MONITORS_CHANGED_EVENT;
-             XSETTERMINAL (inev.ie.arg, dpyinfo->terminal);
+             /* Also avoid storing duplicate events here, since
+                Fx_display_monitor_attributes_list will return the
+                same information for both invocations of the
+                hook.  */
+             if (!x_find_monitors_changed_event (dpyinfo))
+               {
+                 inev.ie.kind = MONITORS_CHANGED_EVENT;
+                 XSETTERMINAL (inev.ie.arg, dpyinfo->terminal);
+
+                 /* Store this event now since inev.ie.type could be set to
+                    MOVE_FRAME_EVENT later.  */
+                 kbd_buffer_store_event (&inev.ie);
+                 inev.ie.kind = NO_EVENT;
+               }
 
-             /* Store this event now since inev.ie.type could be set to
-                MOVE_FRAME_EVENT later.  */
-             kbd_buffer_store_event (&inev.ie);
-             inev.ie.kind = NO_EVENT;
+             /* Also update the position of the drag-and-drop
+                tooltip.  */
+             x_dnd_update_tooltip_now ();
            }
 #endif
 
@@ -18160,10 +19998,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
               configureEvent.xconfigure.height,
               f->new_width, f->new_height);
 
+#ifdef HAVE_XDBE
          block_input ();
           if (FRAME_X_DOUBLE_BUFFERED_P (f))
             x_drop_xrender_surfaces (f);
           unblock_input ();
+#endif
           xg_frame_resized (f, configureEvent.xconfigure.width,
                             configureEvent.xconfigure.height);
 #ifdef USE_CAIRO
@@ -18279,6 +20119,28 @@ handle_one_xevent (struct x_display_info *dpyinfo,
            }
 #endif
 
+#ifdef HAVE_XINPUT2
+         if (f && dpyinfo->supports_xi2)
+           {
+             Mouse_HLInfo *hlinfo;
+
+             /* The input extension doesn't report motion events when
+                the part of the window below the pointer changes.  To
+                avoid outdated information from keeping
+                i.e. mouse-highlight at the wrong position after the
+                frame is moved or resized, reset the mouse highlight
+                and last_mouse_motion_frame.  */
+
+             if (dpyinfo->last_mouse_motion_frame == f)
+               dpyinfo->last_mouse_motion_frame = NULL;
+
+             hlinfo = MOUSE_HL_INFO (f);
+
+             if (hlinfo->mouse_face_mouse_frame == f)
+               reset_mouse_highlight (hlinfo);
+           }
+#endif
+
        }
 
       if (x_dnd_in_progress
@@ -18290,7 +20152,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
     case ButtonPress:
       {
        if (event->xbutton.type == ButtonPress)
-         x_display_set_last_user_time (dpyinfo, event->xbutton.time);
+         x_display_set_last_user_time (dpyinfo, event->xbutton.time,
+                                       event->xbutton.send_event);
 
 #ifdef HAVE_XWIDGETS
        struct xwidget_view *xvw = xwidget_view_from_window 
(event->xbutton.window);
@@ -18333,12 +20196,16 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
            if (event->type == ButtonPress)
              {
+               x_display_set_last_user_time (dpyinfo, event->xbutton.time,
+                                             event->xbutton.send_event);
+
                dpyinfo->grabbed |= (1 << event->xbutton.button);
                dpyinfo->last_mouse_frame = f;
-               if (f && !tab_bar_p)
+
+               if (f)
                  f->last_tab_bar_item = -1;
 #if ! defined (USE_GTK)
-               if (f && !tool_bar_p)
+               if (f)
                  f->last_tool_bar_item = -1;
 #endif /* not USE_GTK */
              }
@@ -18346,18 +20213,26 @@ handle_one_xevent (struct x_display_info *dpyinfo,
              dpyinfo->grabbed &= ~(1 << event->xbutton.button);
 
            if (event->xbutton.type == ButtonPress
-               && x_dnd_last_seen_window != None
-               && x_dnd_last_protocol_version != -1)
+               && x_dnd_last_seen_window != None)
              {
-               x_dnd_send_position (x_dnd_frame,
-                                    x_dnd_last_seen_window,
-                                    x_dnd_last_protocol_version,
-                                    event->xbutton.x_root,
-                                    event->xbutton.y_root,
-                                    x_dnd_selection_timestamp,
-                                    x_dnd_wanted_action,
-                                    event->xbutton.button,
-                                    event->xbutton.state);
+               if (x_dnd_last_window_is_frame)
+                 x_dnd_note_self_wheel (dpyinfo,
+                                        x_dnd_last_seen_window,
+                                        event->xbutton.x_root,
+                                        event->xbutton.y_root,
+                                        event->xbutton.button,
+                                        event->xbutton.state,
+                                        event->xbutton.time);
+               else if (x_dnd_last_protocol_version != -1)
+                 x_dnd_send_position (x_dnd_frame,
+                                      x_dnd_last_seen_window,
+                                      x_dnd_last_protocol_version,
+                                      event->xbutton.x_root,
+                                      event->xbutton.y_root,
+                                      event->xbutton.time,
+                                      x_dnd_wanted_action,
+                                      event->xbutton.button,
+                                      event->xbutton.state);
 
                goto OTHER;
              }
@@ -18402,9 +20277,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                        x_dnd_waiting_for_finish_proto = 
x_dnd_last_protocol_version;
 
                        x_dnd_waiting_for_finish
-                         = x_dnd_send_drop (x_dnd_frame, 
x_dnd_last_seen_window,
-                                            x_dnd_selection_timestamp,
-                                            x_dnd_last_protocol_version);
+                         = x_dnd_do_drop (x_dnd_last_seen_window,
+                                          x_dnd_last_protocol_version);
                        x_dnd_finish_display = dpyinfo->display;
                      }
                    else if (x_dnd_last_seen_window != None)
@@ -18414,6 +20288,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
                        if (!xm_read_drag_receiver_info (dpyinfo, 
x_dnd_last_seen_window,
                                                         &drag_receiver_info)
+                           && !x_dnd_disable_motif_protocol
                            && drag_receiver_info.protocol_style != 
XM_DRAG_STYLE_NONE
                            && (x_dnd_allow_current_frame
                                || x_dnd_last_seen_window != FRAME_OUTER_WINDOW 
(x_dnd_frame)))
@@ -18438,7 +20313,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                                dmsg.timestamp = event->xbutton.time;
                                dmsg.x = event->xbutton.x_root;
                                dmsg.y = event->xbutton.y_root;
-                               dmsg.index_atom = dpyinfo->Xatom_XdndSelection;
+                               dmsg.index_atom = x_dnd_motif_atom;
                                dmsg.source_window = FRAME_X_WINDOW 
(x_dnd_frame);
 
                                if (!XM_DRAG_STYLE_IS_DROP_ONLY 
(drag_receiver_info.protocol_style))
@@ -18456,23 +20331,17 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                              }
                          }
                        else
-                         {
-                           x_set_pending_dnd_time (event->xbutton.time);
-                           x_dnd_send_unsupported_drop (dpyinfo, 
(x_dnd_last_seen_toplevel != None
-                                                                  ? 
x_dnd_last_seen_toplevel
-                                                                  : 
x_dnd_last_seen_window),
-                                                        event->xbutton.x_root, 
event->xbutton.y_root,
-                                                        event->xbutton.time);
-                         }
+                         x_dnd_send_unsupported_drop (dpyinfo, 
(x_dnd_last_seen_toplevel != None
+                                                                ? 
x_dnd_last_seen_toplevel
+                                                                : 
x_dnd_last_seen_window),
+                                                      event->xbutton.x_root, 
event->xbutton.y_root,
+                                                      event->xbutton.time);
                      }
                    else if (x_dnd_last_seen_toplevel != None)
-                     {
-                       x_set_pending_dnd_time (event->xbutton.time);
-                       x_dnd_send_unsupported_drop (dpyinfo, 
x_dnd_last_seen_toplevel,
-                                                    event->xbutton.x_root,
-                                                    event->xbutton.y_root,
-                                                    event->xbutton.time);
-                     }
+                     x_dnd_send_unsupported_drop (dpyinfo, 
x_dnd_last_seen_toplevel,
+                                                  event->xbutton.x_root,
+                                                  event->xbutton.y_root,
+                                                  event->xbutton.time);
 
 
                    x_dnd_last_protocol_version = -1;
@@ -18512,7 +20381,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
              {
                block_input ();
                XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
-                               RevertToParent, CurrentTime);
+                               RevertToParent, event->xbutton.time);
                if (FRAME_PARENT_FRAME (f))
                  XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f));
                unblock_input ();
@@ -18708,6 +20577,11 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
     case CirculateNotify:
       if (x_dnd_in_progress
+         /* When _NET_WM_CLIENT_LIST stacking is being used, changes
+            in that property are watched for, and it's not necessary
+            to update the state in response to ordinary window
+            substructure events.  */
+         && !x_dnd_use_toplevels
          && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame))
        x_dnd_update_state (dpyinfo, dpyinfo->last_user_time);
       goto OTHER;
@@ -18737,6 +20611,10 @@ handle_one_xevent (struct x_display_info *dpyinfo,
       goto OTHER;
 
     case DestroyNotify:
+      if (event->xdestroywindow.window
+         == dpyinfo->net_supported_window)
+       dpyinfo->net_supported_window = None;
+
       xft_settings_event (dpyinfo, event);
       break;
 
@@ -18752,11 +20630,14 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
        bool must_free_data = false;
        XIEvent *xi_event = (XIEvent *) event->xcookie.data;
+
        /* Sometimes the event is already claimed by GTK, which
           will free its data in due course. */
-       if (!xi_event && XGetEventData (dpyinfo->display, &event->xcookie))
+       if (!xi_event)
          {
-           must_free_data = true;
+           if (XGetEventData (dpyinfo->display, &event->xcookie))
+             must_free_data = true;
+
            xi_event = (XIEvent *) event->xcookie.data;
          }
 
@@ -18764,7 +20645,25 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
        if (!xi_event)
          {
-           eassert (!must_free_data);
+           /* It may turn out that the event data has already been
+              implicitly freed for various reasons up to and
+              including XMenuActivate pushing some other event onto
+              the foreign-event queue, or x_menu_wait_for_events
+              calling XNextEvent through a timer that tries to wait
+              for input.
+
+              In that case, XGetEventData will return True, but
+              cookie->data will be NULL.  Since handling such input
+              events is not really important, we can afford to
+              discard them.
+
+              The way Xlib is currently implemented makes calling
+              XFreeEventData unnecessary in this case, but call it
+              anyway, since not doing so may lead to a memory leak in
+              the future.  */
+
+           if (must_free_data)
+             XFreeEventData (dpyinfo->display, &event->xcookie);
            goto OTHER;
          }
 
@@ -18772,11 +20671,11 @@ handle_one_xevent (struct x_display_info *dpyinfo,
          {
          case XI_FocusIn:
            {
-             XIFocusInEvent *focusin = (XIFocusInEvent *) xi_event;
-             struct xi_device_t *source;
+             XIFocusInEvent *focusin;
 
+             focusin = (XIFocusInEvent *) xi_event;
              any = x_any_window_to_frame (dpyinfo, focusin->event);
-             source = xi_device_from_id (dpyinfo, focusin->sourceid);
+
 #ifdef USE_GTK
              /* Some WMs (e.g. Mutter in Gnome Shell), don't unmap
                 minimized/iconified windows; thus, for those WMs we won't get
@@ -18805,24 +20704,19 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                    }
                }
 
-             x_detect_focus_change (dpyinfo, any, event, &inev.ie);
+             xi_focus_handle_for_device (dpyinfo, any, xi_event);
 
-             if (inev.ie.kind != NO_EVENT && source)
-               inev.ie.device = source->name;
              goto XI_OTHER;
            }
 
          case XI_FocusOut:
            {
-             XIFocusOutEvent *focusout = (XIFocusOutEvent *) xi_event;
-             struct xi_device_t *source;
+             XIFocusOutEvent *focusout;
 
+             focusout = (XIFocusOutEvent *) xi_event;
              any = x_any_window_to_frame (dpyinfo, focusout->event);
-             source = xi_device_from_id (dpyinfo, focusout->sourceid);
-             x_detect_focus_change (dpyinfo, any, event, &inev.ie);
+             xi_focus_handle_for_device (dpyinfo, any, xi_event);
 
-             if (inev.ie.kind != NO_EVENT && source)
-               inev.ie.device = source->name;
              goto XI_OTHER;
            }
 
@@ -18834,12 +20728,15 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
              any = x_top_window_to_frame (dpyinfo, enter->event);
              source = xi_device_from_id (dpyinfo, enter->sourceid);
+
              ev.x = lrint (enter->event_x);
              ev.y = lrint (enter->event_y);
              ev.window = enter->event;
              ev.time = enter->time;
+             ev.send_event = enter->send_event;
 
-             x_display_set_last_user_time (dpyinfo, enter->time);
+             x_display_set_last_user_time (dpyinfo, enter->time,
+                                           enter->send_event);
 
 #ifdef USE_MOTIF
              use_copy = true;
@@ -18868,7 +20765,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                 are an inferiors of the frame's top window, which will
                 get virtual events.  */
              if (any)
-               x_detect_focus_change (dpyinfo, any, event, &inev.ie);
+               xi_focus_handle_for_device (dpyinfo, any, xi_event);
 
              if (!any)
                any = x_any_window_to_frame (dpyinfo, enter->event);
@@ -18918,7 +20815,10 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
          case XI_Leave:
            {
-             XILeaveEvent *leave = (XILeaveEvent *) xi_event;
+             XILeaveEvent *leave;
+             struct xi_device_t *device;
+
+             leave = (XILeaveEvent *) xi_event;
 #ifdef USE_GTK
              struct xi_device_t *source;
              XMotionEvent ev;
@@ -18927,6 +20827,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
              ev.y = lrint (leave->event_y);
              ev.window = leave->event;
              ev.time = leave->time;
+             ev.send_event = leave->send_event;
 #endif
 
              any = x_top_window_to_frame (dpyinfo, leave->event);
@@ -18934,6 +20835,10 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 #ifdef USE_GTK
              source = xi_device_from_id (dpyinfo, leave->sourceid);
 #endif
+             device = xi_device_from_id (dpyinfo, leave->deviceid);
+
+             if (device)
+               xi_report_motion_window_clear (device);
 
              /* This allows us to catch LeaveNotify events generated by
                 popup menu grabs.  FIXME: this is right when there is a
@@ -18988,7 +20893,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                                                         leave->deviceid, 
false);
 #endif
 
-             x_display_set_last_user_time (dpyinfo, leave->time);
+             x_display_set_last_user_time (dpyinfo, leave->time,
+                                           leave->send_event);
 
 #ifdef HAVE_XWIDGETS
              {
@@ -19006,7 +20912,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 #endif
 
              if (any)
-               x_detect_focus_change (dpyinfo, any, event, &inev.ie);
+               xi_focus_handle_for_device (dpyinfo, any, xi_event);
 
 #ifndef USE_X_TOOLKIT
              f = x_top_window_to_frame (dpyinfo, leave->event);
@@ -19028,8 +20934,22 @@ handle_one_xevent (struct x_display_info *dpyinfo,
              if (!f)
                f = x_top_window_to_frame (dpyinfo, leave->event);
 #endif
+
              if (f)
                {
+                 /* Now clear dpyinfo->last_mouse_motion_frame, or
+                    gui_redo_mouse_highlight will end up highlighting
+                    the last known position of the mouse if a
+                    tooltip frame is later unmapped.  */
+
+                 if (f == dpyinfo->last_mouse_motion_frame)
+                   dpyinfo->last_mouse_motion_frame = NULL;
+
+                 /* Something similar applies to
+                    dpyinfo->last_mouse_glyph_frame.  */
+                 if (f == dpyinfo->last_mouse_glyph_frame)
+                   dpyinfo->last_mouse_glyph_frame = NULL;
+
                  if (f == hlinfo->mouse_face_mouse_frame)
                    {
                      /* If we move outside the frame, then we're
@@ -19075,7 +20995,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
              xm_top_level_leave_message lmsg;
              xm_top_level_enter_message emsg;
              xm_drag_motion_message dmsg;
-             int dnd_state;
+             unsigned int dnd_state;
 
              source = xi_device_from_id (dpyinfo, xev->sourceid);
 
@@ -19119,9 +21039,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
                      bar = NULL;
 
-                     /* See the comment on top of
-                        x_init_master_valuators for more details on how
-                        scroll wheel movement is reported on XInput 2.  */
+                     /* See the comment on top of x_cache_xi_devices
+                        for more details on how scroll wheel movement
+                        is reported on XInput 2.  */
                      delta = x_get_scroll_valuator_delta (dpyinfo, device,
                                                           i, *values, &val);
                      values++;
@@ -19241,18 +21161,11 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 #ifdef HAVE_XWIDGETS
              if (xv)
                {
-                 uint state = xev->mods.effective;
-                 x_display_set_last_user_time (dpyinfo, xev->time);
+                 unsigned int state;
 
-                 if (xev->buttons.mask_len)
-                   {
-                     if (XIMaskIsSet (xev->buttons.mask, 1))
-                       state |= Button1Mask;
-                     if (XIMaskIsSet (xev->buttons.mask, 2))
-                       state |= Button2Mask;
-                     if (XIMaskIsSet (xev->buttons.mask, 3))
-                       state |= Button3Mask;
-                   }
+                 state = xi_convert_event_state (xev);
+                 x_display_set_last_user_time (dpyinfo, xev->time,
+                                               xev->send_event);
 
                  if (found_valuator)
                    xwidget_scroll (xv, xev->event_x, xev->event_y,
@@ -19271,7 +21184,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 #endif
                  if (found_valuator)
                    {
-                     x_display_set_last_user_time (dpyinfo, xev->time);
+                     x_display_set_last_user_time (dpyinfo, xev->time,
+                                                   xev->send_event);
+
 
 #if defined USE_GTK && !defined HAVE_GTK3
                      /* Unlike on Motif, we can't select for XI
@@ -19287,6 +21202,21 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                        goto XI_OTHER;
 #endif
 
+                     /* If this happened during a drag-and-drop
+                        operation, don't send an event.  We only have
+                        to set the user time.  */
+                     if (x_dnd_in_progress
+                         /* If another master device moved the
+                            pointer, we should put a wheel event on
+                            the keyboard buffer as usual.  It will be
+                            run once the drag-and-drop operation
+                            completes.  */
+                         && xev->deviceid == x_dnd_pointer_device
+                         && (command_loop_level + minibuf_level
+                             <= x_dnd_recursion_depth)
+                         && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame))
+                       goto XI_OTHER;
+
                      if (fabs (total_x) > 0 || fabs (total_y) > 0)
                        {
                          inev.ie.kind = (fabs (total_y) >= fabs (total_x)
@@ -19328,10 +21258,14 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 #endif
 #endif /* HAVE_XINPUT2_1 */
 
+             if (!xi_position_changed (device, xev))
+               goto XI_OTHER;
+
              ev.x = lrint (xev->event_x);
              ev.y = lrint (xev->event_y);
              ev.window = xev->event;
              ev.time = xev->time;
+             ev.send_event = xev->send_event;
 
 #ifdef USE_MOTIF
              use_copy = true;
@@ -19348,17 +21282,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
              copy.xmotion.y = lrint (xev->event_y);
              copy.xmotion.x_root = lrint (xev->root_x);
              copy.xmotion.y_root = lrint (xev->root_y);
-             copy.xmotion.state = 0;
-
-             if (xev->buttons.mask_len)
-               {
-                 if (XIMaskIsSet (xev->buttons.mask, 1))
-                   copy.xmotion.state |= Button1Mask;
-                 if (XIMaskIsSet (xev->buttons.mask, 2))
-                   copy.xmotion.state |= Button2Mask;
-                 if (XIMaskIsSet (xev->buttons.mask, 3))
-                   copy.xmotion.state |= Button3Mask;
-               }
+             copy.xmotion.state = xi_convert_event_state (xev);
 
              copy.xmotion.is_hint = False;
              copy.xmotion.same_screen = True;
@@ -19383,6 +21307,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                     `x-dnd-movement-function`.  */
                  && (command_loop_level + minibuf_level
                      <= x_dnd_recursion_depth)
+                 && xev->deviceid == x_dnd_pointer_device
                  && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame))
                {
                  Window target, toplevel;
@@ -19424,13 +21349,19 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                        }
                    }
 
-                 target = x_dnd_get_target_window (dpyinfo,
-                                                   xev->root_x,
-                                                   xev->root_y,
-                                                   &target_proto,
-                                                   &motif_style,
-                                                   &toplevel,
-                                                   &was_frame);
+                 if (xev->root == dpyinfo->root_window)
+                   target = x_dnd_get_target_window (dpyinfo,
+                                                     xev->root_x,
+                                                     xev->root_y,
+                                                     &target_proto,
+                                                     &motif_style,
+                                                     &toplevel,
+                                                     &was_frame);
+                 else
+                   target = x_dnd_fill_empty_target (&target_proto,
+                                                     &motif_style,
+                                                     &toplevel,
+                                                     &was_frame);
 
                  if (toplevel != x_dnd_last_seen_toplevel)
                    {
@@ -19457,7 +21388,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                                                            
XM_DRAG_REASON_TOP_LEVEL_LEAVE);
                              lmsg.byteorder = XM_BYTE_ORDER_CUR_FIRST;
                              lmsg.zero = 0;
-                             lmsg.timestamp = event->xmotion.time;
+                             lmsg.timestamp = xev->time;
                              lmsg.source_window = FRAME_X_WINDOW (x_dnd_frame);
 
                              if (x_dnd_motif_setup_p)
@@ -19549,7 +21480,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                          emsg.zero = 0;
                          emsg.timestamp = xev->time;
                          emsg.source_window = FRAME_X_WINDOW (x_dnd_frame);
-                         emsg.index_atom = dpyinfo->Xatom_XdndSelection;
+                         emsg.index_atom = x_dnd_motif_atom;
 
                          if (x_dnd_motif_setup_p)
                            xm_send_top_level_enter_message (dpyinfo, 
FRAME_X_WINDOW (x_dnd_frame),
@@ -19562,17 +21493,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                                              xev->root_x, xev->root_y);
                  else if (x_dnd_last_protocol_version != -1 && target != None)
                    {
-                     dnd_state = xev->mods.effective;
-
-                     if (xev->buttons.mask_len)
-                       {
-                         if (XIMaskIsSet (xev->buttons.mask, 1))
-                           dnd_state |= Button1Mask;
-                         if (XIMaskIsSet (xev->buttons.mask, 2))
-                           dnd_state |= Button2Mask;
-                         if (XIMaskIsSet (xev->buttons.mask, 3))
-                           dnd_state |= Button3Mask;
-                       }
+                     dnd_state = xi_convert_event_state (xev);
 
                      x_dnd_send_position (x_dnd_frame, target,
                                           x_dnd_last_protocol_version,
@@ -19689,7 +21610,15 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                 has changed, generate a HELP_EVENT.  */
              if (!NILP (help_echo_string)
                  || !NILP (previous_help_echo_string))
-               do_help = 1;
+               {
+                 /* Also allow the focus and client pointer to be
+                    adjusted accordingly, in case a help tooltip is
+                    shown.  */
+                 gen_help_device = device;
+                 gen_help_time = xev->time;
+
+                 do_help = 1;
+               }
              goto XI_OTHER;
            }
 
@@ -19713,46 +21642,82 @@ handle_one_xevent (struct x_display_info *dpyinfo,
              if (x_dnd_in_progress
                  && (command_loop_level + minibuf_level
                      <= x_dnd_recursion_depth)
+                 && xev->deviceid == x_dnd_pointer_device
                  && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame))
                {
                  f = mouse_or_wdesc_frame (dpyinfo, xev->event);
+                 device = xi_device_from_id (dpyinfo, xev->deviceid);
 
-                 if (xev->evtype == XI_ButtonPress)
+                 /* Don't track grab status for emulated pointer
+                    events, because they are ignored by the regular
+                    mouse click processing code.  */
+#ifdef XIPointerEmulated
+                 if (!(xev->flags & XIPointerEmulated))
                    {
-                     dpyinfo->grabbed |= (1 << xev->detail);
-                     dpyinfo->last_mouse_frame = f;
-                     if (f && !tab_bar_p)
-                       f->last_tab_bar_item = -1;
+#endif
+                     if (xev->evtype == XI_ButtonPress)
+                       {
+                         x_display_set_last_user_time (dpyinfo, xev->time,
+                                                       xev->send_event);
+
+                         dpyinfo->grabbed |= (1 << xev->detail);
+                         dpyinfo->last_mouse_frame = f;
+
+                         if (device)
+                           device->grab |= (1 << xev->detail);
+
+                         if (f)
+                           f->last_tab_bar_item = -1;
 #if ! defined (USE_GTK)
-                     if (f && !tool_bar_p)
-                       f->last_tool_bar_item = -1;
+                         if (f)
+                           f->last_tool_bar_item = -1;
 #endif /* not USE_GTK */
+                       }
+                     else
+                       {
+                         dpyinfo->grabbed &= ~(1 << xev->detail);
+                         if (device)
+                           device->grab &= ~(1 << xev->detail);
+                       }
+#ifdef XIPointerEmulated
                    }
-                 else
-                   dpyinfo->grabbed &= ~(1 << xev->detail);
+#endif
+
+                 if (f && device)
+                   xi_handle_interaction (dpyinfo, f, device,
+                                          xev->time);
 
                  if (xev->evtype == XI_ButtonPress
-                     && x_dnd_last_seen_window != None
-                     && x_dnd_last_protocol_version != -1)
+                     && x_dnd_last_seen_window != None)
                    {
-                     dnd_state = xev->mods.effective;
+                     dnd_state = xi_convert_event_state (xev);
 
-                     if (xev->buttons.mask_len)
+                     if (x_dnd_last_window_is_frame)
                        {
-                         if (XIMaskIsSet (xev->buttons.mask, 1))
-                           dnd_state |= Button1Mask;
-                         if (XIMaskIsSet (xev->buttons.mask, 2))
-                           dnd_state |= Button2Mask;
-                         if (XIMaskIsSet (xev->buttons.mask, 3))
-                           dnd_state |= Button3Mask;
+#ifdef XI_PointerEmulated
+                         /* Set the last user time here even if this
+                            is an emulated button event, since
+                            something happened in response.  */
+
+                         if (xev->flags & XIPointerEmulated)
+                           x_display_set_last_user_time (dpyinfo, xev->time,
+                                                         xev->send_event);
+#endif
+                         x_dnd_note_self_wheel (dpyinfo,
+                                                x_dnd_last_seen_window,
+                                                xev->root_x, xev->root_y,
+                                                xev->detail, dnd_state,
+                                                xev->time);
                        }
-
-                     x_dnd_send_position (x_dnd_frame, x_dnd_last_seen_window,
-                                          x_dnd_last_protocol_version, 
xev->root_x,
-                                          xev->root_y, 
x_dnd_selection_timestamp,
-                                          x_dnd_wanted_action, xev->detail, 
dnd_state);
-
-                     goto XI_OTHER;
+                     else
+                       x_dnd_send_position (x_dnd_frame,
+                                            x_dnd_last_seen_window,
+                                            x_dnd_last_protocol_version,
+                                            xev->root_x, xev->root_y,
+                                            xev->time, x_dnd_wanted_action,
+                                            xev->detail, dnd_state);
+
+                     goto OTHER;
                    }
 
                  if (xev->evtype == XI_ButtonRelease)
@@ -19800,9 +21765,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                              x_dnd_waiting_for_finish_proto = 
x_dnd_last_protocol_version;
 
                              x_dnd_waiting_for_finish
-                               = x_dnd_send_drop (x_dnd_frame, 
x_dnd_last_seen_window,
-                                                  x_dnd_selection_timestamp,
-                                                  x_dnd_last_protocol_version);
+                               = x_dnd_do_drop (x_dnd_last_seen_window,
+                                                x_dnd_last_protocol_version);
                              x_dnd_finish_display = dpyinfo->display;
                            }
                          else if (x_dnd_last_seen_window != None)
@@ -19812,6 +21776,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
                              if (!xm_read_drag_receiver_info (dpyinfo, 
x_dnd_last_seen_window,
                                                               
&drag_receiver_info)
+                                 && !x_dnd_disable_motif_protocol
                                  && drag_receiver_info.protocol_style != 
XM_DRAG_STYLE_NONE
                                  && (x_dnd_allow_current_frame
                                      || x_dnd_last_seen_window != 
FRAME_OUTER_WINDOW (x_dnd_frame)))
@@ -19845,7 +21810,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                                         instances of Emacs try to drag
                                         into the same window at the same
                                         time.  */
-                                     dmsg.index_atom = 
dpyinfo->Xatom_XdndSelection;
+                                     dmsg.index_atom = x_dnd_motif_atom;
                                      dmsg.source_window = FRAME_X_WINDOW 
(x_dnd_frame);
 
                                      if (!XM_DRAG_STYLE_IS_DROP_ONLY 
(drag_receiver_info.protocol_style))
@@ -19863,22 +21828,16 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                                    }
                                }
                              else
-                               {
-                                 x_set_pending_dnd_time (xev->time);
-                                 x_dnd_send_unsupported_drop (dpyinfo, 
(x_dnd_last_seen_toplevel != None
-                                                                        ? 
x_dnd_last_seen_toplevel
-                                                                        : 
x_dnd_last_seen_window),
-                                                              xev->root_x, 
xev->root_y, xev->time);
-                               }
+                               x_dnd_send_unsupported_drop (dpyinfo, 
(x_dnd_last_seen_toplevel != None
+                                                                      ? 
x_dnd_last_seen_toplevel
+                                                                      : 
x_dnd_last_seen_window),
+                                                            xev->root_x, 
xev->root_y, xev->time);
                            }
                          else if (x_dnd_last_seen_toplevel != None)
-                           {
-                             x_set_pending_dnd_time (xev->time);
-                             x_dnd_send_unsupported_drop (dpyinfo,
-                                                          
x_dnd_last_seen_toplevel,
-                                                          xev->root_x, 
xev->root_y,
-                                                          xev->time);
-                           }
+                           x_dnd_send_unsupported_drop (dpyinfo,
+                                                        
x_dnd_last_seen_toplevel,
+                                                        xev->root_x, 
xev->root_y,
+                                                        xev->time);
 
                          x_dnd_last_protocol_version = -1;
                          x_dnd_last_motif_style = XM_DRAG_STYLE_NONE;
@@ -19918,19 +21877,10 @@ handle_one_xevent (struct x_display_info *dpyinfo,
              copy.xbutton.y = lrint (xev->event_y);
              copy.xbutton.x_root = lrint (xev->root_x);
              copy.xbutton.y_root = lrint (xev->root_y);
-             copy.xbutton.state = xev->mods.effective;
+             copy.xbutton.state = xi_convert_event_state (xev);
              copy.xbutton.button = xev->detail;
              copy.xbutton.same_screen = True;
 
-             if (xev->buttons.mask_len)
-               {
-                 if (XIMaskIsSet (xev->buttons.mask, 1))
-                   copy.xbutton.state |= Button1Mask;
-                 if (XIMaskIsSet (xev->buttons.mask, 2))
-                   copy.xbutton.state |= Button2Mask;
-                 if (XIMaskIsSet (xev->buttons.mask, 3))
-                   copy.xbutton.state |= Button3Mask;
-               }
 #elif defined USE_GTK && !defined HAVE_GTK3
              copy = gdk_event_new (xev->evtype == XI_ButtonPress
                                    ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE);
@@ -19942,19 +21892,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
              copy->button.y = xev->event_y;
              copy->button.x_root = xev->root_x;
              copy->button.y_root = xev->root_y;
-             copy->button.state = xev->mods.effective;
+             copy->button.state = xi_convert_event_state (xev);
              copy->button.button = xev->detail;
 
-             if (xev->buttons.mask_len)
-               {
-                 if (XIMaskIsSet (xev->buttons.mask, 1))
-                   copy->button.state |= GDK_BUTTON1_MASK;
-                 if (XIMaskIsSet (xev->buttons.mask, 2))
-                   copy->button.state |= GDK_BUTTON2_MASK;
-                 if (XIMaskIsSet (xev->buttons.mask, 3))
-                   copy->button.state |= GDK_BUTTON3_MASK;
-               }
-
              if (!copy->button.window)
                emacs_abort ();
 
@@ -19989,17 +21929,27 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 #endif
 
              if (xev->evtype == XI_ButtonPress)
-               x_display_set_last_user_time (dpyinfo, xev->time);
+               x_display_set_last_user_time (dpyinfo, xev->time,
+                                             xev->send_event);
 
              source = xi_device_from_id (dpyinfo, xev->sourceid);
+             device = xi_device_from_id (dpyinfo, xev->deviceid);
 
 #ifdef HAVE_XWIDGETS
              xvw = xwidget_view_from_window (xev->event);
              if (xvw)
                {
+                 /* If the user interacts with a frame that's focused
+                    on another device, but not the current focus
+                    frame, make it the focus frame.  */
+                 if (device)
+                   xi_handle_interaction (dpyinfo, xvw->frame,
+                                          device, xev->time);
+
                  xwidget_button (xvw, xev->evtype == XI_ButtonPress,
                                  lrint (xev->event_x), lrint (xev->event_y),
-                                 xev->detail, xev->mods.effective, xev->time);
+                                 xev->detail, xi_convert_event_state (xev),
+                                 xev->time);
 
                  if (!EQ (selected_window, xvw->w) && (xev->detail < 4))
                    {
@@ -20015,8 +21965,6 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                }
 #endif
 
-             device = xi_device_from_id (dpyinfo, xev->deviceid);
-
              if (!device)
                goto XI_OTHER;
 
@@ -20025,7 +21973,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
              bv.x = lrint (xev->event_x);
              bv.y = lrint (xev->event_y);
              bv.window = xev->event;
-             bv.state = xev->mods.effective;
+             bv.state = xi_convert_event_state (xev);
              bv.time = xev->time;
 
              dpyinfo->last_mouse_glyph_frame = NULL;
@@ -20046,14 +21994,42 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                  if (FRAME_PARENT_FRAME (f) || (hf && frame_ancestor_p (f, 
hf)))
                    {
                      block_input ();
+#if defined HAVE_GTK3 || (!defined USE_GTK && !defined USE_X_TOOLKIT)
+                     if (device)
+                       {
+                         /* This can generate XI_BadDevice if the
+                            device's attachment was destroyed
+                            server-side.  */
+                         x_ignore_errors_for_next_request (dpyinfo);
+                         XISetFocus (dpyinfo->display, device->attachment,
+                                     /* Note that the input extension
+                                        only supports RevertToParent-type
+                                        behavior.  */
+                                     FRAME_OUTER_WINDOW (f), xev->time);
+                         x_stop_ignoring_errors (dpyinfo);
+                       }
+#else
+                     /* Non-no toolkit builds without GTK 3 use core
+                        events to handle focus.  */
                      XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW 
(f),
-                                     RevertToParent, CurrentTime);
+                                     RevertToParent, xev->time);
+#endif
                      if (FRAME_PARENT_FRAME (f))
                        XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW 
(f));
                      unblock_input ();
                    }
                }
 
+             if (f)
+               {
+                 /* If the user interacts with a frame that's focused
+                    on another device, but not the current focus
+                    frame, make it the focus frame.  */
+                 if (device)
+                   xi_handle_interaction (dpyinfo, f, device,
+                                          xev->time);
+               }
+
 #ifdef USE_GTK
              if (!f)
                {
@@ -20316,22 +22292,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                  copy.xkey.time = xev->time;
                  copy.xkey.state = ((xev->mods.effective & ~(1 << 13 | 1 << 
14))
                                     | (xev->group.effective << 13));
+                 xi_convert_button_state (&xev->buttons, &copy.xkey.state);
 
                  copy.xkey.x = lrint (xev->event_x);
                  copy.xkey.y = lrint (xev->event_y);
                  copy.xkey.x_root = lrint (xev->root_x);
                  copy.xkey.y_root = lrint (xev->root_y);
-
-                 if (xev->buttons.mask_len)
-                   {
-                     if (XIMaskIsSet (xev->buttons.mask, 1))
-                       copy.xkey.state |= Button1Mask;
-                     if (XIMaskIsSet (xev->buttons.mask, 2))
-                       copy.xkey.state |= Button2Mask;
-                     if (XIMaskIsSet (xev->buttons.mask, 3))
-                       copy.xkey.state |= Button3Mask;
-                   }
-
                  copy.xkey.keycode = xev->detail;
                  copy.xkey.same_screen = True;
 #endif
@@ -20339,11 +22305,31 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                }
 #endif
 
-             x_display_set_last_user_time (dpyinfo, xev->time);
+             x_display_set_last_user_time (dpyinfo, xev->time,
+                                           xev->send_event);
              ignore_next_mouse_click_timeout = 0;
 
              f = x_any_window_to_frame (dpyinfo, xev->event);
 
+             /* GTK handles TAB events in an undesirable manner, so
+                keyboard events are always dropped.  But as a side
+                effect, the user time will no longer be set by GDK,
+                so do that manually.  */
+#ifdef USE_GTK
+             if (f)
+               x_set_gtk_user_time (f, xev->time);
+#endif
+
+             if (f)
+               {
+                 /* If the user interacts with a frame that's focused
+                    on another device, but not the current focus
+                    frame, make it the focus frame.  */
+                 if (device)
+                   xi_handle_interaction (dpyinfo, f, device,
+                                          xev->time);
+               }
+
              XKeyPressedEvent xkey;
 
              memset (&xkey, 0, sizeof xkey);
@@ -20366,15 +22352,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
              /* Some input methods react differently depending on the
                 buttons that are pressed.  */
-             if (xev->buttons.mask_len)
-               {
-                 if (XIMaskIsSet (xev->buttons.mask, 1))
-                   xkey.state |= Button1Mask;
-                 if (XIMaskIsSet (xev->buttons.mask, 2))
-                   xkey.state |= Button2Mask;
-                 if (XIMaskIsSet (xev->buttons.mask, 3))
-                   xkey.state |= Button3Mask;
-               }
+             xi_convert_button_state (&xev->buttons, &xkey.state);
 
              xkey.keycode = xev->detail;
              xkey.same_screen = True;
@@ -20426,27 +22404,6 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
              state |= x_emacs_to_x_modifiers (dpyinfo, 
extra_keyboard_modifiers);
 
-#ifdef HAVE_XKB
-             if (dpyinfo->xkb_desc)
-               {
-                 XkbDescRec *rec = dpyinfo->xkb_desc;
-
-                 if (rec->map->modmap && rec->map->modmap[xev->detail])
-                   goto xi_done_keysym;
-               }
-             else
-#endif
-               {
-                 if (dpyinfo->modmap)
-                   {
-                     for (i = 0; i < 8 * dpyinfo->modmap->max_keypermod; i++)
-                       {
-                         if (xev->detail == dpyinfo->modmap->modifiermap[i])
-                           goto xi_done_keysym;
-                       }
-                   }
-               }
-
 #ifdef HAVE_XKB
              if (dpyinfo->xkb_desc)
                {
@@ -20502,8 +22459,6 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 #endif
 
                  XSETFRAME (inev.ie.frame_or_window, f);
-                 inev.ie.modifiers
-                   = x_x_to_emacs_modifiers (FRAME_DISPLAY_INFO (f), state);
                  inev.ie.timestamp = xev->time;
 
 #ifdef HAVE_X_I18N
@@ -20582,8 +22537,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                        }
                    }
 
+                 inev.ie.modifiers = x_x_to_emacs_modifiers (dpyinfo, state);
+
 #ifdef XK_F1
-                 if (x_dnd_in_progress && keysym == XK_F1)
+                 if (x_dnd_in_progress
+                     && xev->deviceid == x_dnd_keyboard_device
+                     && keysym == XK_F1)
                    {
                      x_dnd_xm_use_help = true;
                      goto xi_done_keysym;
@@ -20806,15 +22765,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
              /* Some input methods react differently depending on the
                 buttons that are pressed.  */
-             if (xev->buttons.mask_len)
-               {
-                 if (XIMaskIsSet (xev->buttons.mask, 1))
-                   xkey.state |= Button1Mask;
-                 if (XIMaskIsSet (xev->buttons.mask, 2))
-                   xkey.state |= Button2Mask;
-                 if (XIMaskIsSet (xev->buttons.mask, 3))
-                   xkey.state |= Button3Mask;
-               }
+             xi_convert_button_state (&xev->buttons, &xkey.state);
 
              xkey.keycode = xev->detail;
              xkey.same_screen = True;
@@ -20855,14 +22806,14 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
          case XI_HierarchyChanged:
            {
-             XIHierarchyEvent *hev = (XIHierarchyEvent *) xi_event;
+             XIHierarchyEvent *hev;
              XIDeviceInfo *info;
-             int i, j, ndevices, n_disabled, *disabled;
-             struct xi_device_t *device, *devices;
-#ifdef HAVE_XINPUT2_2
-             struct xi_touch_point_t *tem, *last;
-#endif
+             int i, ndevices, n_disabled, *disabled;
+             struct xi_device_t *device;
+             bool any_changed;
 
+             any_changed = false;
+             hev = (XIHierarchyEvent *) xi_event;
              disabled = SAFE_ALLOCA (sizeof *disabled * hev->num_info);
              n_disabled = 0;
 
@@ -20872,44 +22823,16 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                    {
                      /* Handle all disabled devices now, to prevent
                         things happening out-of-order later.  */
-                     if (n_disabled)
-                       {
-                         ndevices = 0;
-                         devices = xmalloc (sizeof *devices * 
dpyinfo->num_devices);
-
-                         for (i = 0; i < dpyinfo->num_devices; ++i)
-                           {
-                             for (j = 0; j < n_disabled; ++j)
-                               {
-                                 if (disabled[j] == 
dpyinfo->devices[i].device_id)
-                                   {
-#ifdef HAVE_XINPUT2_1
-                                     xfree (dpyinfo->devices[i].valuators);
-#endif
-#ifdef HAVE_XINPUT2_2
-                                     tem = dpyinfo->devices[i].touchpoints;
-                                     while (tem)
-                                       {
-                                         last = tem;
-                                         tem = tem->next;
-                                         xfree (last);
-                                       }
-#endif
-                                     goto continue_detachment;
-                                   }
-                               }
-
-                             devices[ndevices++] = dpyinfo->devices[i];
-
-                           continue_detachment:
-                             continue;
-                           }
-
-                         xfree (dpyinfo->devices);
-                         dpyinfo->devices = devices;
-                         dpyinfo->num_devices = ndevices;
 
+                     if (ndevices)
+                       {
+                         xi_disable_devices (dpyinfo, disabled, n_disabled);
                          n_disabled = 0;
+
+                         /* This flag really just means that disabled
+                            devices were handled early and should be
+                            used in conjunction with n_disabled.  */
+                         any_changed = true;
                        }
 
                      x_catch_errors (dpyinfo->display);
@@ -20922,6 +22845,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                          dpyinfo->devices
                            = xrealloc (dpyinfo->devices, (sizeof 
*dpyinfo->devices
                                                           * 
++dpyinfo->num_devices));
+                         memset (dpyinfo->devices + dpyinfo->num_devices - 1,
+                                 0, sizeof *dpyinfo->devices);
                          device = &dpyinfo->devices[dpyinfo->num_devices - 1];
                          xi_populate_device_from_info (device, info);
                        }
@@ -20942,184 +22867,53 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
                      if (info)
                        {
-                         if (device && info->enabled)
-                           device->use = info->use;
-                         else if (device)
-                           disabled[n_disabled++] = hev->info[i].deviceid;
+                         if (device)
+                           {
+                             device->use = info->use;
+                             device->attachment = info->attachment;
+                           }
+
+                         /* device could have been disabled by now.
+                            But instead of removing it immediately,
+                            wait for XIDeviceDisabled, or internal
+                            state could be left inconsistent.  */
 
                          XIFreeDeviceInfo (info);
                        }
                    }
                }
 
-             if (n_disabled)
-               {
-                 ndevices = 0;
-                 devices = xmalloc (sizeof *devices * dpyinfo->num_devices);
-
-                 for (i = 0; i < dpyinfo->num_devices; ++i)
-                   {
-                     for (j = 0; j < n_disabled; ++j)
-                       {
-                         if (disabled[j] == dpyinfo->devices[i].device_id)
-                           {
-#ifdef HAVE_XINPUT2_1
-                             xfree (dpyinfo->devices[i].valuators);
-#endif
-#ifdef HAVE_XINPUT2_2
-                             tem = dpyinfo->devices[i].touchpoints;
-                             while (tem)
-                               {
-                                 last = tem;
-                                 tem = tem->next;
-                                 xfree (last);
-                               }
-#endif
-                             goto break_detachment;
-                           }
-                       }
-
-                     devices[ndevices++] = dpyinfo->devices[i];
-
-                   break_detachment:
-                     continue;
-                   }
+             /* Delete all devices that were disabled by this
+                event.  */
+             xi_disable_devices (dpyinfo, disabled, n_disabled);
 
-                 xfree (dpyinfo->devices);
-                 dpyinfo->devices = devices;
-                 dpyinfo->num_devices = ndevices;
-               }
+             /* If the device hierarchy has been changed, recompute
+                focus.  This might seem like a micro-optimization but
+                it actually keeps the focus from changing in some
+                cases where it would be undesierable.  */
+             if (any_changed || n_disabled)
+               xi_handle_focus_change (dpyinfo);
 
              goto XI_OTHER;
            }
 
          case XI_DeviceChanged:
-           {
-             XIDeviceChangedEvent *device_changed = (XIDeviceChangedEvent *) 
xi_event;
-             struct xi_device_t *device;
-#ifdef HAVE_XINPUT2_2
-             struct xi_touch_point_t *tem, *last;
-#endif
-             int c;
-#ifdef HAVE_XINPUT2_1
-             int i;
-#endif
-
-             device = xi_device_from_id (dpyinfo, device_changed->deviceid);
-
-             if (!device)
-               {
-                 /* An existing device might have been enabled.  */
-                 x_init_master_valuators (dpyinfo);
-
-                 /* Now try to find the device again, in case it was
-                    just enabled.  */
-                 device = xi_device_from_id (dpyinfo, 
device_changed->deviceid);
-               }
-
-             /* If it wasn't enabled, then stop handling this event.  */
-             if (!device)
-               goto XI_OTHER;
-
-             /* Free data that we will regenerate from new
-                information.  */
-#ifdef HAVE_XINPUT2_1
-             device->valuators = xrealloc (device->valuators,
-                                           (device_changed->num_classes
-                                            * sizeof *device->valuators));
-             device->scroll_valuator_count = 0;
-#endif
-#ifdef HAVE_XINPUT2_2
-             device->direct_p = false;
-#endif
-
-             for (c = 0; c < device_changed->num_classes; ++c)
-               {
-                 switch (device_changed->classes[c]->type)
-                   {
-#ifdef HAVE_XINPUT2_1
-                   case XIScrollClass:
-                     {
-                       XIScrollClassInfo *info;
-
-                       info = (XIScrollClassInfo *) device_changed->classes[c];
-                       struct xi_scroll_valuator_t *valuator;
-
-                       valuator = 
&device->valuators[device->scroll_valuator_count++];
-                       valuator->horizontal
-                         = (info->scroll_type == XIScrollTypeHorizontal);
-                       valuator->invalid_p = true;
-                       valuator->emacs_value = DBL_MIN;
-                       valuator->increment = info->increment;
-                       valuator->number = info->number;
-
-                       break;
-                     }
-#endif
-
-#ifdef HAVE_XINPUT2_2
-                   case XITouchClass:
-                     {
-                       XITouchClassInfo *info;
-
-                       info = (XITouchClassInfo *) device_changed->classes[c];
-                       device->direct_p = info->mode == XIDirectTouch;
-                     }
-#endif
-                   default:
-                     break;
-                   }
-               }
-
-#ifdef HAVE_XINPUT2_1
-             for (c = 0; c < device_changed->num_classes; ++c)
-               {
-                 if (device_changed->classes[c]->type == XIValuatorClass)
-                   {
-                     XIValuatorClassInfo *info;
-
-                     info = (XIValuatorClassInfo *) device_changed->classes[c];
-
-                     for (i = 0; i < device->scroll_valuator_count; ++i)
-                       {
-                         if (device->valuators[i].number == info->number)
-                           {
-                             device->valuators[i].invalid_p = false;
-                             device->valuators[i].current_value = info->value;
-
-                             /* Make sure that this is reset if the
-                                pointer moves into a window of ours.
-
-                                Otherwise the valuator state could be
-                                left invalid if the DeviceChange
-                                event happened with the pointer
-                                outside any Emacs frame. */
-                             device->valuators[i].pending_enter_reset = true;
-                           }
-                       }
-                   }
-               }
-#endif
-
-#ifdef HAVE_XINPUT2_2
-             /* The device is no longer a DirectTouch device, so
-                remove any touchpoints that we might have
-                recorded.  */
-             if (!device->direct_p)
-               {
-                 tem = device->touchpoints;
+           {
+             XIDeviceChangedEvent *device_changed;
+             struct xi_device_t *device;
 
-                 while (tem)
-                   {
-                     last = tem;
-                     tem = tem->next;
-                     xfree (last);
-                   }
+             device_changed = (XIDeviceChangedEvent *) xi_event;
+             device = xi_device_from_id (dpyinfo, device_changed->deviceid);
 
-                 device->touchpoints = NULL;
-               }
-#endif
+             /* If the device isn't enabled, then stop handling this
+                event.  A HierarchyChanged event will be sent if it
+                is enabled afterwards.  */
+             if (!device)
+               goto XI_OTHER;
 
+             /* Now handle the event by retrieving scroll valuators
+                and touch info.  */
+             xi_handle_device_changed (dpyinfo, device, device_changed);
              goto XI_OTHER;
            }
 
@@ -21133,7 +22927,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 #endif
              device = xi_device_from_id (dpyinfo, xev->deviceid);
              source = xi_device_from_id (dpyinfo, xev->sourceid);
-             x_display_set_last_user_time (dpyinfo, xev->time);
+             x_display_set_last_user_time (dpyinfo, xev->time,
+                                           xev->send_event);
 
              if (!device)
                goto XI_OTHER;
@@ -21141,7 +22936,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
              if (xi_find_touch_point (device, xev->detail))
                emacs_abort ();
 
-             f = x_any_window_to_frame (dpyinfo, xev->event);
+             f = x_window_to_frame (dpyinfo, xev->event);
 
 #ifdef HAVE_GTK3
              menu_bar_p = (f && FRAME_X_OUTPUT (f)->menubar_widget
@@ -21162,11 +22957,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
              if (!menu_bar_p && !tool_bar_p)
                {
-                 x_catch_errors (dpyinfo->display);
-
                  if (f && device->direct_p)
                    {
                      *finish = X_EVENT_DROP;
+
+                     x_catch_errors (dpyinfo->display);
+
                      if (x_input_grab_touch_events)
                        XIAllowTouchEvents (dpyinfo->display, xev->deviceid,
                                            xev->detail, xev->event, 
XIAcceptTouch);
@@ -21186,13 +22982,18 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                          if (source)
                            inev.ie.device = source->name;
                        }
+
+                     x_uncatch_errors ();
                    }
 #ifndef HAVE_GTK3
                  else if (x_input_grab_touch_events)
-                   XIAllowTouchEvents (dpyinfo->display, xev->deviceid,
-                                       xev->detail, xev->event, XIRejectTouch);
+                   {
+                     x_ignore_errors_for_next_request (dpyinfo);
+                     XIAllowTouchEvents (dpyinfo->display, xev->deviceid,
+                                         xev->detail, xev->event, 
XIRejectTouch);
+                     x_stop_ignoring_errors (dpyinfo);
+                   }
 #endif
-                 x_uncatch_errors ();
                }
              else
                {
@@ -21219,7 +23020,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
              device = xi_device_from_id (dpyinfo, xev->deviceid);
              source = xi_device_from_id (dpyinfo, xev->sourceid);
-             x_display_set_last_user_time (dpyinfo, xev->time);
+             x_display_set_last_user_time (dpyinfo, xev->time,
+                                           xev->send_event);
 
              if (!device)
                goto XI_OTHER;
@@ -21232,7 +23034,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
              touchpoint->x = xev->event_x;
              touchpoint->y = xev->event_y;
 
-             f = x_any_window_to_frame (dpyinfo, xev->event);
+             f = x_window_to_frame (dpyinfo, xev->event);
 
              if (f && device->direct_p)
                {
@@ -21265,7 +23067,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
              device = xi_device_from_id (dpyinfo, xev->deviceid);
              source = xi_device_from_id (dpyinfo, xev->sourceid);
-             x_display_set_last_user_time (dpyinfo, xev->time);
+             x_display_set_last_user_time (dpyinfo, xev->time,
+                                           xev->send_event);
 
              if (!device)
                goto XI_OTHER;
@@ -21274,7 +23077,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
              if (unlinked_p)
                {
-                 f = x_any_window_to_frame (dpyinfo, xev->event);
+                 f = x_window_to_frame (dpyinfo, xev->event);
 
                  if (f && device->direct_p)
                    {
@@ -21305,7 +23108,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
              device = xi_device_from_id (dpyinfo, pev->deviceid);
              source = xi_device_from_id (dpyinfo, pev->sourceid);
-             x_display_set_last_user_time (dpyinfo, pev->time);
+             x_display_set_last_user_time (dpyinfo, pev->time,
+                                           pev->send_event);
 
              if (!device)
                goto XI_OTHER;
@@ -21321,7 +23125,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                }
 #endif
 
-             any = x_any_window_to_frame (dpyinfo, pev->event);
+             any = x_window_to_frame (dpyinfo, pev->event);
              if (any)
                {
                  inev.ie.kind = PINCH_EVENT;
@@ -21394,6 +23198,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
          if (xkbevent->any.xkb_type == XkbNewKeyboardNotify
              || xkbevent->any.xkb_type == XkbMapNotify)
            {
+             XkbRefreshKeyboardMapping (&xkbevent->map);
+
              if (dpyinfo->xkb_desc)
                {
                  if (XkbGetUpdatedMap (dpyinfo->display,
@@ -21402,11 +23208,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                                         | XkbModifierMapMask
                                         | XkbVirtualModsMask),
                                        dpyinfo->xkb_desc) == Success)
-                   {
-                     XkbGetNames (dpyinfo->display,
-                                  XkbGroupNamesMask | XkbVirtualModNamesMask,
-                                  dpyinfo->xkb_desc);
-                   }
+                   XkbGetNames (dpyinfo->display,
+                                XkbGroupNamesMask | XkbVirtualModNamesMask,
+                                dpyinfo->xkb_desc);
                  else
                    {
                      XkbFreeKeyboard (dpyinfo->xkb_desc, XkbAllComponentsMask, 
True);
@@ -21428,7 +23232,6 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                                 dpyinfo->xkb_desc);
                }
 
-             XkbRefreshKeyboardMapping (&xkbevent->map);
              x_find_modifier_meanings (dpyinfo);
            }
          else if (x_dnd_in_progress
@@ -21661,14 +23464,13 @@ handle_one_xevent (struct x_display_info *dpyinfo,
              || event->type == (dpyinfo->xrandr_event_base
                                 + RRNotify)))
        {
-         union buffered_input_event *ev;
          Time timestamp;
          Lisp_Object current_monitors;
          XRRScreenChangeNotifyEvent *notify;
 
          if (event->type == (dpyinfo->xrandr_event_base
                              + RRScreenChangeNotify))
-           XRRUpdateConfiguration (event);
+           XRRUpdateConfiguration ((XEvent *) event);
 
          if (event->type == (dpyinfo->xrandr_event_base
                              + RRScreenChangeNotify))
@@ -21689,13 +23491,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
          else
            timestamp = 0;
 
-         ev = (kbd_store_ptr == kbd_buffer
-               ? kbd_buffer + KBD_BUFFER_SIZE - 1
-               : kbd_store_ptr - 1);
-
-         if (kbd_store_ptr != kbd_fetch_ptr
-             && ev->ie.kind == MONITORS_CHANGED_EVENT
-             && XTERMINAL (ev->ie.arg) == dpyinfo->terminal)
+         if (x_find_monitors_changed_event (dpyinfo))
            /* Don't store a MONITORS_CHANGED_EVENT if there is
               already an undelivered event on the queue.  */
            goto OTHER;
@@ -21783,6 +23579,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
       if (do_help > 0)
        {
          any_help_event_p = true;
+#ifdef HAVE_XINPUT2
+         if (gen_help_device)
+           xi_handle_interaction (dpyinfo, f,
+                                  gen_help_device,
+                                  gen_help_time);
+#endif
          gen_help_event (help_echo_string, frame, help_echo_window,
                          help_echo_object, help_echo_pos);
        }
@@ -21866,6 +23668,8 @@ XTread_socket (struct terminal *terminal, struct 
input_event *hold_quit)
              && dpyinfo->display == x_dnd_finish_display)))
     return 0;
 
+  x_clean_failable_requests (dpyinfo);
+
   block_input ();
 
   /* For debugging, this gives a way to fake an I/O error.  */
@@ -22258,8 +24062,6 @@ x_draw_window_cursor (struct window *w, struct 
glyph_row *glyph_row, int x,
        xic_set_preeditarea (w, x, y);
 #endif
     }
-
-  XFlush (FRAME_X_DISPLAY (f));
 }
 
 
@@ -22488,7 +24290,13 @@ x_error_catcher (Display *display, XErrorEvent *event,
    always skips an XSync to the server, and should be used only
    immediately after x_had_errors_p or x_check_errors, or when it is
    known that no requests have been made since the last x_catch_errors
-   call for DPY.  */
+   call for DPY.
+
+   There is no need to use this mechanism for ignoring errors from
+   single asynchronous requests, such as sending a ClientMessage to a
+   window that might no longer exist.  Use
+   x_ignore_errors_for_next_request (paired with
+   x_stop_ignoring_errors) instead.  */
 
 void
 x_catch_errors_with_handler (Display *dpy, x_special_error_handler handler,
@@ -22501,7 +24309,7 @@ x_catch_errors_with_handler (Display *dpy, 
x_special_error_handler handler,
   data->handler = handler;
   data->handler_data = handler_data;
   data->prev = x_error_message;
-  data->first_request = NextRequest (dpy);
+  data->first_request = XNextRequest (dpy);
   x_error_message = data;
 
   ++x_error_message_count;
@@ -22513,6 +24321,135 @@ x_catch_errors (Display *dpy)
   x_catch_errors_with_handler (dpy, NULL, NULL);
 }
 
+/* Return if errors for REQUEST should be ignored even if there is no
+   error handler applied.  */
+static struct x_failable_request *
+x_request_can_fail (struct x_display_info *dpyinfo,
+                   unsigned long request)
+{
+  struct x_failable_request *failable_requests;
+
+  for (failable_requests = dpyinfo->failable_requests;
+       failable_requests < dpyinfo->next_failable_request;
+       failable_requests++)
+    {
+      if (X_COMPARE_SERIALS (request, >=,
+                            failable_requests->start)
+         && (!failable_requests->end
+             || X_COMPARE_SERIALS (request, <=,
+                                   failable_requests->end)))
+       return failable_requests;
+    }
+
+  return NULL;
+}
+
+/* Remove outdated request serials from
+   dpyinfo->failable_requests.  */
+static void
+x_clean_failable_requests (struct x_display_info *dpyinfo)
+{
+  struct x_failable_request *first, *last;
+
+  last = dpyinfo->next_failable_request;
+
+  for (first = dpyinfo->failable_requests; first < last; first++)
+    {
+      if (X_COMPARE_SERIALS (first->start, >,
+                            LastKnownRequestProcessed (dpyinfo->display))
+         || !first->end
+         || X_COMPARE_SERIALS (first->end, >,
+                               LastKnownRequestProcessed (dpyinfo->display)))
+       break;
+    }
+
+  if (first != last)
+    memmove (&dpyinfo->failable_requests, first,
+            sizeof *first * (last - first));
+
+  dpyinfo->next_failable_request = (dpyinfo->failable_requests
+                                   + (last - first));
+}
+
+void
+x_ignore_errors_for_next_request (struct x_display_info *dpyinfo)
+{
+  struct x_failable_request *request, *max;
+  unsigned long next_request;
+#ifdef HAVE_GTK3
+  GdkDisplay *gdpy;
+
+  /* GTK 3 tends to override our own error handler inside certain
+     callbacks, which this can be called from.  Instead of trying to
+     restore our own, add a trap for the following requests with
+     GDK as well.  */
+
+  gdpy = gdk_x11_lookup_xdisplay (dpyinfo->display);
+
+  if (gdpy)
+    gdk_x11_display_error_trap_push (gdpy);
+#endif
+
+  if ((dpyinfo->next_failable_request
+       != dpyinfo->failable_requests)
+      && (dpyinfo->next_failable_request - 1)->end == 0)
+    /* A new sequence should never be started before an old one
+       finishes.  Use `x_catch_errors' to nest error handlers.  */
+    emacs_abort ();
+
+  request = dpyinfo->next_failable_request;
+  max = dpyinfo->failable_requests + N_FAILABLE_REQUESTS;
+  next_request = XNextRequest (dpyinfo->display);
+
+  if (request >= max)
+    {
+      /* There is no point in making this extra sync if all requests
+        are known to have been fully processed.  */
+      if ((LastKnownRequestProcessed (dpyinfo->display)
+          != next_request - 1))
+       XSync (dpyinfo->display, False);
+
+      x_clean_failable_requests (dpyinfo);
+      request = dpyinfo->next_failable_request;
+    }
+
+  if (request >= max)
+    /* A request should always be made immediately after calling this
+       function.  */
+    emacs_abort ();
+
+  request->start = next_request;
+  request->end = 0;
+
+  dpyinfo->next_failable_request++;
+}
+
+void
+x_stop_ignoring_errors (struct x_display_info *dpyinfo)
+{
+  struct x_failable_request *range;
+#ifdef HAVE_GTK3
+  GdkDisplay *gdpy;
+#endif
+
+  range = dpyinfo->next_failable_request - 1;
+  range->end = XNextRequest (dpyinfo->display) - 1;
+
+  /* Abort if no request was made since
+     `x_ignore_errors_for_next_request'.  */
+
+  if (X_COMPARE_SERIALS (range->end, <,
+                        range->start))
+    emacs_abort ();
+
+#ifdef HAVE_GTK3
+  gdpy = gdk_x11_lookup_xdisplay (dpyinfo->display);
+
+  if (gdpy)
+    gdk_x11_display_error_trap_pop_ignored (gdpy);
+#endif
+}
+
 /* Undo the last x_catch_errors call.
    DPY should be the display that was passed to x_catch_errors.
 
@@ -22541,6 +24478,7 @@ void
 x_uncatch_errors (void)
 {
   struct x_error_message_stack *tmp;
+  struct x_display_info *dpyinfo;
 
   /* In rare situations when running Emacs run in daemon mode,
      shutting down an emacsclient via delete-frame can cause
@@ -22551,18 +24489,23 @@ x_uncatch_errors (void)
 
   block_input ();
 
+  dpyinfo = x_display_info_for_display (x_error_message->dpy);
+
   /* The display may have been closed before this function is called.
      Check if it is still open before calling XSync.  */
-  if (x_display_info_for_display (x_error_message->dpy) != 0
+  if (dpyinfo != 0
       /* There is no point in making this extra sync if all requests
         are known to have been fully processed.  */
       && (LastKnownRequestProcessed (x_error_message->dpy)
-         != NextRequest (x_error_message->dpy) - 1)
+         != XNextRequest (x_error_message->dpy) - 1)
       /* Likewise if no request was made since the trap was
         installed.  */
       && (NextRequest (x_error_message->dpy)
          > x_error_message->first_request))
-    XSync (x_error_message->dpy, False);
+    {
+      XSync (x_error_message->dpy, False);
+      x_clean_failable_requests (dpyinfo);
+    }
 
   tmp = x_error_message;
   x_error_message = x_error_message->prev;
@@ -22580,6 +24523,7 @@ x_uncatch_errors (void)
 void
 x_check_errors (Display *dpy, const char *format)
 {
+  struct x_display_info *dpyinfo;
   char *string;
 
   /* This shouldn't happen, since x_check_errors should be called
@@ -22590,11 +24534,17 @@ x_check_errors (Display *dpy, const char *format)
   /* There is no point in making this extra sync if all requests
      are known to have been fully processed.  */
   if ((LastKnownRequestProcessed (dpy)
-       != NextRequest (dpy) - 1)
+       != XNextRequest (dpy) - 1)
       && (NextRequest (dpy)
          > x_error_message->first_request))
     XSync (dpy, False);
 
+  dpyinfo = x_display_info_for_display (dpy);
+
+  /* Clean the array of failable requests, since a sync happened.  */
+  if (dpyinfo)
+    x_clean_failable_requests (dpyinfo);
+
   if (x_error_message->string)
     {
       string = alloca (strlen (x_error_message->string) + 1);
@@ -22610,6 +24560,8 @@ x_check_errors (Display *dpy, const char *format)
 bool
 x_had_errors_p (Display *dpy)
 {
+  struct x_display_info *dpyinfo;
+
   /* This shouldn't happen, since x_check_errors should be called
      immediately inside an x_catch_errors block.  */
   if (dpy != x_error_message->dpy)
@@ -22617,12 +24569,18 @@ x_had_errors_p (Display *dpy)
 
   /* Make sure to catch any errors incurred so far.  */
   if ((LastKnownRequestProcessed (dpy)
-       != NextRequest (dpy) - 1)
+       != XNextRequest (dpy) - 1)
       && (NextRequest (dpy)
          > x_error_message->first_request))
     XSync (dpy, False);
 
-  return x_error_message->string;
+  dpyinfo = x_display_info_for_display (dpy);
+
+  /* Clean the array of failable requests, since a sync happened.  */
+  if (dpyinfo)
+    x_clean_failable_requests (dpyinfo);
+
+  return !!x_error_message->string;
 }
 
 /* Forget about any errors we have had, since we did x_catch_errors on
@@ -22673,18 +24631,46 @@ x_trace_wire (Display *dpy)
 
 static char *error_msg;
 
+/* Try to find a frame in Vframe_list, and make it the selected frame.
+   `delete_frame' sometimes misses the initial frame for an unknown
+   reason when Emacs is running as a background daemon.  */
+
+static void
+x_try_restore_frame (void)
+{
+  Lisp_Object tail, frame;
+
+  FOR_EACH_FRAME (tail, frame)
+    {
+      if (!NILP (do_switch_frame (frame, 1, Qnil)))
+       return;
+    }
+}
+
 /* Handle the loss of connection to display DPY.  ERROR_MESSAGE is
    the text of an error message that lead to the connection loss.  */
 
-static AVOID
+static void
 x_connection_closed (Display *dpy, const char *error_message, bool ioerror)
 {
   struct x_display_info *dpyinfo;
   Lisp_Object frame, tail;
   specpdl_ref idx = SPECPDL_INDEX ();
-  void *io_error_handler;
+  Emacs_XIOErrorHandler io_error_handler;
   xm_drop_start_message dmsg;
   struct frame *f;
+  Lisp_Object minibuf_frame, tmp;
+  struct x_failable_request *failable;
+  struct x_error_message_stack *stack;
+  static Display *current_display;
+
+  /* Prevent recursive calls of this function for the same display.
+     This is because destroying a frame might still cause an IO error
+     in some cases.  (bug#56528) */
+  if (current_display == dpy)
+    return;
+
+  current_display = dpy;
 
   dpyinfo = x_display_info_for_display (dpy);
   error_msg = alloca (strlen (error_message) + 1);
@@ -22736,7 +24722,7 @@ x_connection_closed (Display *dpy, const char 
*error_message, bool ioerror)
                                           XM_DROP_ACTION_DROP_CANCEL);
                  dmsg.x = 0;
                  dmsg.y = 0;
-                 dmsg.index_atom = FRAME_DISPLAY_INFO (f)->Xatom_XdndSelection;
+                 dmsg.index_atom = x_dnd_motif_atom;
                  dmsg.source_window = FRAME_X_WINDOW (f);
 
                  x_dnd_send_xm_leave_for_drop (FRAME_DISPLAY_INFO (f), f,
@@ -22761,6 +24747,7 @@ x_connection_closed (Display *dpy, const char 
*error_message, bool ioerror)
 
       x_dnd_return_frame_object = NULL;
       x_dnd_movement_frame = NULL;
+      x_dnd_wheel_frame = NULL;
       x_dnd_frame = NULL;
     }
 
@@ -22784,9 +24771,14 @@ x_connection_closed (Display *dpy, const char 
*error_message, bool ioerror)
      that are on the dead display.  */
   FOR_EACH_FRAME (tail, frame)
     {
-      Lisp_Object minibuf_frame;
+      /* Tooltip frames don't have these, so avoid crashing.  */
+
+      if (FRAME_TOOLTIP_P (XFRAME (frame)))
+       continue;
+
       minibuf_frame
        = WINDOW_FRAME (XWINDOW (FRAME_MINIBUF_WINDOW (XFRAME (frame))));
+
       if (FRAME_X_P (XFRAME (frame))
          && FRAME_X_P (XFRAME (minibuf_frame))
          && ! EQ (frame, minibuf_frame)
@@ -22837,20 +24829,55 @@ For details, see etc/PROBLEMS.\n",
         /* We have just closed all frames on this display. */
         emacs_abort ();
 
-      {
-       Lisp_Object tmp;
-       XSETTERMINAL (tmp, dpyinfo->terminal);
-       Fdelete_terminal (tmp, Qnoelisp);
-      }
+      /* This was the last terminal remaining, so print the error
+        message and associated error handlers and kill Emacs.  */
+      if (dpyinfo->terminal == terminal_list
+         && !terminal_list->next_terminal)
+       {
+         fprintf (stderr, "%s\n", error_msg);
+
+         if (!ioerror && dpyinfo)
+           {
+             /* Dump the list of error handlers for debugging
+                purposes.  */
+
+             fprintf (stderr, "X error handlers currently installed:\n");
+
+             for (failable = dpyinfo->failable_requests;
+                  failable < dpyinfo->next_failable_request;
+                  ++failable)
+               {
+                 if (failable->end)
+                   fprintf (stderr, "Ignoring errors between %lu to %lu\n",
+                            failable->start, failable->end);
+                 else
+                   fprintf (stderr, "Ignoring errors from %lu onwards\n",
+                            failable->start);
+               }
+
+             for (stack = x_error_message; stack; stack = stack->prev)
+               fprintf (stderr, "Trapping errors from %lu\n",
+                        stack->first_request);
+           }
+       }
+
+      XSETTERMINAL (tmp, dpyinfo->terminal);
+      Fdelete_terminal (tmp, Qnoelisp);
     }
 
+  /* The initial "daemon" frame is sometimes not selected by
+     `delete_frame' when Emacs is a background daemon.  */
+  if (NILP (selected_frame))
+    x_try_restore_frame ();
+
   unblock_input ();
 
-  if (terminal_list == 0)
-    {
-      fprintf (stderr, "%s\n", error_msg);
-      Fkill_emacs (make_fixnum (70), Qnil);
-    }
+  /* Sometimes another terminal is still alive, but deleting this
+     terminal caused all frames to vanish.  In that case, simply kill
+     Emacs, since the next redisplay will abort as there is no more
+     selected frame.  (bug#56528) */
+  if (terminal_list == 0 || NILP (selected_frame))
+    Fkill_emacs (make_fixnum (70), Qnil);
 
   totally_unblock_input ();
 
@@ -22860,6 +24887,7 @@ For details, see etc/PROBLEMS.\n",
   /* Here, we absolutely have to use a non-local exit (e.g. signal, throw,
      longjmp), because returning from this function would get us back into
      Xlib's code which will directly call `exit'.  */
+  current_display = NULL;
   error ("%s", error_msg);
 }
 
@@ -22872,9 +24900,8 @@ static int
 x_error_handler (Display *display, XErrorEvent *event)
 {
   struct x_error_message_stack *stack;
-#ifdef HAVE_XINPUT2
   struct x_display_info *dpyinfo;
-#endif
+  struct x_failable_request *fail, *last;
 
 #if defined USE_GTK && defined HAVE_GTK3
   if ((event->error_code == BadMatch
@@ -22883,21 +24910,41 @@ x_error_handler (Display *display, XErrorEvent *event)
     return 0;
 #endif
 
+  dpyinfo = x_display_info_for_display (display);
+
+  if (dpyinfo)
+    {
+      fail = x_request_can_fail (dpyinfo, event->serial);
+
+      if (fail)
+       {
+         /* Now that this request sequence has been fully handled,
+            remove it from the list of requests that can fail.  */
+
+         if (event->serial == fail->end)
+           {
+             last = dpyinfo->next_failable_request;
+             memmove (&dpyinfo->failable_requests, fail,
+                      sizeof *fail * (last - fail));
+             dpyinfo->next_failable_request = (dpyinfo->failable_requests
+                                               + (last - fail));
+           }
+
+         return 0;
+       }
+    }
+
   /* If we try to ungrab or grab a device that doesn't exist anymore
      (that happens a lot in xmenu.c), just ignore the error.  */
 
 #ifdef HAVE_XINPUT2
-  dpyinfo = x_display_info_for_display (display);
-
-  /* 51 is X_XIGrabDevice and 52 is X_XIUngrabDevice.
-
-     53 is X_XIAllowEvents.  We handle errors from that here to avoid
-     a sync in handle_one_xevent.  */
+  /* Handle errors from some specific XI2 requests here to avoid a
+     sync in handle_one_xevent.  */
   if (dpyinfo && dpyinfo->supports_xi2
       && event->request_code == dpyinfo->xi2_opcode
-      && (event->minor_code == 51
-         || event->minor_code == 52
-         || event->minor_code == 53))
+      && (event->minor_code == X_XIGrabDevice
+         || event->minor_code == X_XIUngrabDevice
+         || event->minor_code == X_XIAllowEvents))
     return 0;
 #endif
 
@@ -22919,7 +24966,8 @@ x_error_handler (Display *display, XErrorEvent *event)
 static void NO_INLINE
 x_error_quitter (Display *display, XErrorEvent *event)
 {
-  char buf[256], buf1[356];
+  char buf[256], buf1[400 + INT_STRLEN_BOUND (int)
+                     + INT_STRLEN_BOUND (unsigned long)];
 
   /* Ignore BadName errors.  They can happen because of fonts
      or colors that are not defined.  */
@@ -22931,8 +24979,9 @@ x_error_quitter (Display *display, XErrorEvent *event)
      original error handler.  */
 
   XGetErrorText (display, event->error_code, buf, sizeof (buf));
-  sprintf (buf1, "X protocol error: %s on protocol request %d",
-          buf, event->request_code);
+  sprintf (buf1, "X protocol error: %s on protocol request %d\n"
+          "Serial no: %lu\n", buf, event->request_code,
+          event->serial);
   x_connection_closed (display, buf1, false);
 }
 
@@ -22941,7 +24990,7 @@ x_error_quitter (Display *display, XErrorEvent *event)
    It kills all frames on the display that we lost touch with.
    If that was the only one, it prints an error message and kills Emacs.  */
 
-static _Noreturn ATTRIBUTE_COLD int
+static int NO_INLINE
 x_io_error_quitter (Display *display)
 {
   char buf[256];
@@ -22949,6 +24998,8 @@ x_io_error_quitter (Display *display)
   snprintf (buf, sizeof buf, "Connection lost to X server '%s'",
            DisplayString (display));
   x_connection_closed (display, buf, true);
+
+  return 0;
 }
 
 
@@ -23077,14 +25128,14 @@ xim_open_dpy (struct x_display_info *dpyinfo, char 
*resource_name)
 
       if (xim)
        {
-#ifdef HAVE_X11R6
+#ifdef HAVE_X11R6_XIM
          XIMCallback destroy;
 #endif
 
          /* Get supported styles and XIM values.  */
          XGetIMValues (xim, XNQueryInputStyle, &dpyinfo->xim_styles, NULL);
 
-#ifdef HAVE_X11R6
+#ifdef HAVE_X11R6_XIM
          destroy.callback = xim_destroy_callback;
          destroy.client_data = (XPointer)dpyinfo;
          XSetIMValues (xim, XNDestroyCallback, &destroy, NULL);
@@ -23377,7 +25428,11 @@ x_set_offset (struct frame *f, int xoff, int yoff, int 
change_gravity)
 #endif
 
   /* 'x_sync_with_move' is too costly for dragging child frames.  */
-  if (!FRAME_PARENT_FRAME (f))
+  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);
@@ -23399,10 +25454,45 @@ x_set_offset (struct frame *f, int xoff, int yoff, 
int change_gravity)
                      && 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 ();
 }
 
+static Window
+x_get_wm_check_window (struct x_display_info *dpyinfo)
+{
+  Window result;
+  unsigned char *tmp_data = NULL;
+  int rc, actual_format;
+  unsigned long actual_size, bytes_remaining;
+  Atom actual_type;
+
+  rc = XGetWindowProperty (dpyinfo->display, dpyinfo->root_window,
+                          dpyinfo->Xatom_net_supporting_wm_check,
+                           0, 1, False, XA_WINDOW, &actual_type,
+                          &actual_format, &actual_size,
+                           &bytes_remaining, &tmp_data);
+
+  if (rc != Success || actual_type != XA_WINDOW
+      || actual_format != 32 || actual_size != 1)
+    {
+      if (tmp_data)
+       XFree (tmp_data);
+
+      return None;
+    }
+
+  result = *(Window *) tmp_data;
+  XFree (tmp_data);
+
+  return result;
+}
+
 /* Return true if _NET_SUPPORTING_WM_CHECK window exists and _NET_SUPPORTED
    on the root window for frame F contains ATOMNAME.
    This is how a WM check shall be done according to the Window Manager
@@ -23423,33 +25513,40 @@ x_wm_supports_1 (struct x_display_info *dpyinfo, Atom 
want_atom)
   unsigned char *tmp_data = NULL;
   Atom target_type = XA_WINDOW;
 
+  /* The user says there's no window manager, so take him up on
+     it.  */
+  if (!NILP (Vx_no_window_manager))
+    return false;
+
   block_input ();
 
   x_catch_errors (dpy);
-  rc = XGetWindowProperty (dpy, target_window,
-                           dpyinfo->Xatom_net_supporting_wm_check,
-                           0, max_len, False, target_type,
-                           &actual_type, &actual_format, &actual_size,
-                           &bytes_remaining, &tmp_data);
 
-  if (rc != Success || actual_type != XA_WINDOW || x_had_errors_p (dpy))
-    {
-      if (tmp_data) XFree (tmp_data);
-      x_uncatch_errors ();
-      unblock_input ();
-      return false;
-    }
+  wmcheck_window = dpyinfo->net_supported_window;
 
-  wmcheck_window = *(Window *) tmp_data;
-  XFree (tmp_data);
+  if (wmcheck_window == None)
+    wmcheck_window = x_get_wm_check_window (dpyinfo);
 
-  /* Check if window exists. */
-  XSelectInput (dpy, wmcheck_window, StructureNotifyMask);
-  if (x_had_errors_p (dpy))
+  if (!x_special_window_exists_p (dpyinfo, wmcheck_window))
     {
-      x_uncatch_errors_after_check ();
-      unblock_input ();
-      return false;
+      if (dpyinfo->net_supported_window != None)
+       {
+         dpyinfo->net_supported_window = None;
+         wmcheck_window = x_get_wm_check_window (dpyinfo);
+
+         if (!x_special_window_exists_p (dpyinfo, wmcheck_window))
+           {
+             x_uncatch_errors ();
+             unblock_input ();
+             return false;
+           }
+       }
+      else
+       {
+         x_uncatch_errors ();
+         unblock_input ();
+         return false;
+       }
     }
 
   if (dpyinfo->net_supported_window != wmcheck_window)
@@ -24068,11 +26165,9 @@ x_sync_with_move (struct frame *f, int left, int top, 
bool fuzzy)
       current_left = 0;
       current_top = 0;
 
-      /* In theory, this call to XSync only needs to happen once, but in
-         practice, it doesn't seem to work, hence the need for the surrounding
-         loop.  */
-
-      XSync (FRAME_X_DISPLAY (f), False);
+      /* There is no need to call XSync (even when no window manager
+        is present) because x_real_positions already does that
+        implicitly.  */
       x_real_positions (f, &current_left, &current_top);
 
       if (fuzzy)
@@ -24101,7 +26196,6 @@ x_sync_with_move (struct frame *f, int left, int top, 
bool fuzzy)
     wait_reading_process_output (0, 500000000, 0, false, Qnil, NULL, 0);
 }
 
-
 /* Wait for an event on frame F matching EVENTTYPE.  */
 void
 x_wait_for_event (struct frame *f, int eventtype)
@@ -24256,41 +26350,68 @@ x_set_window_size (struct frame *f, bool 
change_gravity,
 void
 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
 {
-  block_input ();
 #ifdef HAVE_XINPUT2
   int deviceid;
 
-  if (FRAME_DISPLAY_INFO (f)->supports_xi2)
+  deviceid = FRAME_DISPLAY_INFO (f)->client_pointer_device;
+
+  if (FRAME_DISPLAY_INFO (f)->supports_xi2
+      && deviceid != -1)
     {
-      if (XIGetClientPointer (FRAME_X_DISPLAY (f),
-                             FRAME_X_WINDOW (f),
-                             &deviceid))
-       {
-         x_catch_errors (FRAME_X_DISPLAY (f));
-         XIWarpPointer (FRAME_X_DISPLAY (f),
-                        deviceid, None,
-                        FRAME_X_WINDOW (f),
-                        0, 0, 0, 0, pix_x, pix_y);
-         x_uncatch_errors ();
-       }
+      block_input ();
+      x_ignore_errors_for_next_request (FRAME_DISPLAY_INFO (f));
+      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));
+      unblock_input ();
     }
   else
 #endif
     XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
                  0, 0, 0, 0, pix_x, pix_y);
-  unblock_input ();
 }
 
 /* Raise frame F.  */
 
-static void
-x_raise_frame (struct frame *f)
-{
-  block_input ();
-  if (FRAME_VISIBLE_P (f))
-    XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f));
-  XFlush (FRAME_X_DISPLAY (f));
-  unblock_input ();
+static void
+x_raise_frame (struct frame *f)
+{
+  block_input ();
+  if (FRAME_VISIBLE_P (f))
+    XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f));
+  XFlush (FRAME_X_DISPLAY (f));
+  unblock_input ();
+}
+
+static void
+x_lower_frame_1 (struct frame *f)
+{
+  Window *windows;
+  Lisp_Object frame, tail;
+  struct frame *sibling;
+
+  windows = alloca (2 * sizeof *windows);
+
+  /* Lowering a child frame leads to the window being put below any
+     scroll bars on the parent.  To avoid that, restack the child
+     frame below all of its siblings instead of just lowering it.  */
+
+  FOR_EACH_FRAME (tail, frame)
+    {
+      sibling = XFRAME (frame);
+
+      if (sibling == f)
+       continue;
+
+      if (FRAME_PARENT_FRAME (sibling)
+         != FRAME_PARENT_FRAME (f))
+       continue;
+
+      windows[0] = FRAME_OUTER_WINDOW (sibling);
+      windows[1] = FRAME_OUTER_WINDOW (f);
+
+      XRestackWindows (FRAME_X_DISPLAY (f), windows, 2);
+    }
 }
 
 /* Lower frame F.  */
@@ -24298,13 +26419,16 @@ x_raise_frame (struct frame *f)
 static void
 x_lower_frame (struct frame *f)
 {
-  if (FRAME_VISIBLE_P (f))
-    {
-      block_input ();
-      XLowerWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f));
-      XFlush (FRAME_X_DISPLAY (f));
-      unblock_input ();
-    }
+  if (FRAME_PARENT_FRAME (f)
+      && (FRAME_HAS_VERTICAL_SCROLL_BARS (FRAME_PARENT_FRAME (f))
+         || FRAME_HAS_HORIZONTAL_SCROLL_BARS (FRAME_PARENT_FRAME (f))))
+    x_lower_frame_1 (f);
+  else
+    XLowerWindow (FRAME_X_DISPLAY (f),
+                 FRAME_OUTER_WINDOW (f));
+
+  XFlush (FRAME_X_DISPLAY (f));
+
 #ifdef HAVE_XWIDGETS
   /* Make sure any X windows owned by xwidget views of the parent
      still display below the lowered frame.  */
@@ -24385,7 +26509,7 @@ x_get_focus_frame (struct frame *f)
 
 /* In certain situations, when the window manager follows a
    click-to-focus policy, there seems to be no way around calling
-   XSetInputFocus to give another frame the input focus .
+   XSetInputFocus to give another frame the input focus.
 
    In an ideal world, XSetInputFocus should generally be avoided so
    that applications don't interfere with the window manager's focus
@@ -24395,28 +26519,26 @@ x_get_focus_frame (struct frame *f)
 static void
 x_focus_frame (struct frame *f, bool noactivate)
 {
-  Display *dpy = FRAME_X_DISPLAY (f);
+  struct x_display_info *dpyinfo;
 
-  block_input ();
-  x_catch_errors (dpy);
+  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
-        https://freedesktop.org/wiki/Specifications/xembed-spec/  */
-      xembed_request_focus (f);
-    }
+    /* For Xembedded frames, normally the embedder forwards key
+       events.  See XEmbed Protocol Specification at
+       https://freedesktop.org/wiki/Specifications/xembed-spec/  */
+    xembed_request_focus (f);
   else
     {
+      /* Ignore any BadMatch error this request might result in.  */
+      x_ignore_errors_for_next_request (dpyinfo);
       XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
                      RevertToParent, CurrentTime);
+      x_stop_ignoring_errors (dpyinfo);
+
       if (!noactivate)
        x_ewmh_activate_frame (f);
     }
-
-  x_uncatch_errors ();
-  unblock_input ();
 }
 
 
@@ -24459,9 +26581,14 @@ xembed_send_message (struct frame *f, Time t, enum 
xembed_message msg,
   event.xclient.data.l[3] = data1;
   event.xclient.data.l[4] = data2;
 
+  /* XXX: the XEmbed spec tells us to trap errors around this request,
+     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));
   XSendEvent (FRAME_X_DISPLAY (f), FRAME_X_OUTPUT (f)->parent_desc,
              False, NoEventMask, &event);
-  XSync (FRAME_X_DISPLAY (f), False);
+  x_stop_ignoring_errors (FRAME_DISPLAY_INFO (f));
 }
 
 /* Change of visibility.  */
@@ -24481,6 +26608,7 @@ x_make_frame_visible (struct frame *f)
   struct x_display_info *dpyinfo;
   struct x_output *output;
 #endif
+  bool output_flushed;
 
   if (FRAME_PARENT_FRAME (f))
     {
@@ -24523,56 +26651,21 @@ x_make_frame_visible (struct frame *f)
 
 #ifndef USE_GTK
       output = FRAME_X_OUTPUT (f);
+      x_update_frame_user_time_window (f);
 
-      if (!x_wm_supports (f, dpyinfo->Xatom_net_wm_user_time_window))
-       {
-         if (output->user_time_window == None)
-           output->user_time_window = FRAME_OUTER_WINDOW (f);
-         else if (output->user_time_window != FRAME_OUTER_WINDOW (f))
-           {
-             XDestroyWindow (dpyinfo->display,
-                             output->user_time_window);
-             XDeleteProperty (dpyinfo->display,
-                              FRAME_OUTER_WINDOW (f),
-                              dpyinfo->Xatom_net_wm_user_time_window);
-             output->user_time_window = FRAME_OUTER_WINDOW (f);
-           }
-       }
-      else
+      /* It's been a while since I wrote that code...  I don't
+        remember if it can leave `user_time_window' unset or not.  */
+      if (output->user_time_window != None)
        {
-         if (output->user_time_window == FRAME_OUTER_WINDOW (f)
-             || output->user_time_window == None)
-           {
-             XSetWindowAttributes attrs;
-             memset (&attrs, 0, sizeof attrs);
-
-             output->user_time_window
-               = XCreateWindow (dpyinfo->display, FRAME_X_WINDOW (f),
-                                -1, -1, 1, 1, 0, 0, InputOnly,
-                                CopyFromParent, 0, &attrs);
-
-             XDeleteProperty (dpyinfo->display,
-                              FRAME_OUTER_WINDOW (f),
-                              dpyinfo->Xatom_net_wm_user_time);
-             XChangeProperty (dpyinfo->display,
-                              FRAME_OUTER_WINDOW (f),
-                              dpyinfo->Xatom_net_wm_user_time_window,
-                              XA_WINDOW, 32, PropModeReplace,
-                              (unsigned char *) &output->user_time_window,
-                              1);
-           }
+         if (dpyinfo->last_user_time)
+           XChangeProperty (dpyinfo->display, output->user_time_window,
+                            dpyinfo->Xatom_net_wm_user_time,
+                            XA_CARDINAL, 32, PropModeReplace,
+                            (unsigned char *) &dpyinfo->last_user_time, 1);
+         else
+           XDeleteProperty (dpyinfo->display, output->user_time_window,
+                            dpyinfo->Xatom_net_wm_user_time);
        }
-
-      if (dpyinfo->last_user_time)
-       XChangeProperty (dpyinfo->display,
-                        output->user_time_window,
-                        dpyinfo->Xatom_net_wm_user_time,
-                        XA_CARDINAL, 32, PropModeReplace,
-                        (unsigned char *) &dpyinfo->last_user_time, 1);
-      else
-       XDeleteProperty (dpyinfo->display,
-                        output->user_time_window,
-                        dpyinfo->Xatom_net_wm_user_time);
 #endif
 
       f->output_data.x->asked_for_visible = true;
@@ -24606,8 +26699,6 @@ x_make_frame_visible (struct frame *f)
        }
     }
 
-  XFlush (FRAME_X_DISPLAY (f));
-
   /* Synchronize to ensure Emacs knows the frame is visible
      before we do anything else.  We do this loop with input not blocked
      so that incoming events are handled.  */
@@ -24626,6 +26717,10 @@ x_make_frame_visible (struct frame *f)
     /* This must come after we set COUNT.  */
     unblock_input ();
 
+    /* Keep track of whether or not the output buffer was flushed, to
+       avoid any extra flushes.  */
+    output_flushed = false;
+
     /* We unblock here so that arriving X events are processed.  */
 
     /* Now move the window back to where it was "supposed to be".
@@ -24659,6 +26754,7 @@ x_make_frame_visible (struct frame *f)
           there, and take the potential window manager hit.  */
        XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
                      &rootw, &x, &y, &width, &height, &border, &depth);
+       output_flushed = true;
 
        if (original_left != x || original_top != y)
          XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
@@ -24693,7 +26789,11 @@ x_make_frame_visible (struct frame *f)
            (f, build_string ("x_make_frame_visible"));
 
        x_wait_for_event (f, MapNotify);
+       output_flushed = true;
       }
+
+    if (!output_flushed)
+      x_flush (f);
   }
 }
 
@@ -24913,6 +27013,11 @@ x_free_frame_resources (struct frame *f)
 
   block_input ();
 
+#ifdef HAVE_XINPUT2
+  /* Remove any record of this frame being focused.  */
+  xi_handle_delete_frame (dpyinfo, f);
+#endif
+
   /* If a display connection is dead, don't try sending more
      commands to the X server.  */
   if (dpyinfo->display)
@@ -25060,7 +27165,10 @@ x_free_frame_resources (struct frame *f)
       if (f->output_data.x->bottom_left_corner_cursor != 0)
        XFreeCursor (FRAME_X_DISPLAY (f), 
f->output_data.x->bottom_left_corner_cursor);
 
-      XFlush (FRAME_X_DISPLAY (f));
+      /* Free sync fences.  */
+#if defined HAVE_XSYNCTRIGGERFENCE && !defined USE_GTK && defined 
HAVE_CLOCK_GETTIME
+      x_sync_free_fences (f);
+#endif
     }
 
 #ifdef HAVE_GTK3
@@ -25071,6 +27179,12 @@ x_free_frame_resources (struct frame *f)
     g_object_unref (FRAME_OUTPUT_DATA (f)->scrollbar_foreground_css_provider);
 #endif
 
+  if (f == dpyinfo->motif_drag_atom_owner)
+    {
+      dpyinfo->motif_drag_atom_owner = NULL;
+      dpyinfo->motif_drag_atom = None;
+    }
+
   if (f == dpyinfo->x_focus_frame)
     dpyinfo->x_focus_frame = 0;
   if (f == dpyinfo->x_focus_event_frame)
@@ -25104,8 +27218,15 @@ x_destroy_window (struct frame *f)
 #endif
 
 #ifdef HAVE_XINPUT2
+#ifdef HAVE_XINPUT2_1
   if (f->output_data.x->xi_masks)
     XFree (f->output_data.x->xi_masks);
+#else
+  /* This is allocated by us under very old versions of libXi; see
+     `setup_xi_event_mask'.  */
+  if (f->output_data.x->xi_masks)
+    xfree (f->output_data.x->xi_masks);
+#endif
 #endif
 
   xfree (f->output_data.x);
@@ -25160,11 +27281,30 @@ x_intern_cached_atom (struct x_display_info *dpyinfo,
   if (!strcmp (name, "ATOM"))
     return XA_ATOM;
 
+  if (!strcmp (name, "WINDOW"))
+    return XA_WINDOW;
+
+  if (!strcmp (name, "DRAWABLE"))
+    return XA_DRAWABLE;
+
+  if (!strcmp (name, "BITMAP"))
+    return XA_BITMAP;
+
   if (!strcmp (name, "CARDINAL"))
     return XA_CARDINAL;
 
-  if (!strcmp (name, "WINDOW"))
-    return XA_WINDOW;
+  if (!strcmp (name, "COLORMAP"))
+    return XA_COLORMAP;
+
+  if (!strcmp (name, "CURSOR"))
+    return XA_CURSOR;
+
+  if (!strcmp (name, "FONT"))
+    return XA_FONT;
+
+  if (dpyinfo->motif_drag_atom != None
+      && !strcmp (name, dpyinfo->motif_drag_atom_name))
+    return dpyinfo->motif_drag_atom;
 
   for (i = 0; i < ARRAYELTS (x_atom_refs); ++i)
     {
@@ -25223,7 +27363,23 @@ x_get_atom_name (struct x_display_info *dpyinfo, Atom 
atom,
     case XA_WINDOW:
       return xstrdup ("WINDOW");
 
+    case XA_DRAWABLE:
+      return xstrdup ("DRAWABLE");
+
+    case XA_BITMAP:
+      return xstrdup ("BITMAP");
+
+    case XA_COLORMAP:
+      return xstrdup ("COLORMAP");
+
+    case XA_FONT:
+      return xstrdup ("FONT");
+
     default:
+      if (dpyinfo->motif_drag_atom
+         && atom == dpyinfo->motif_drag_atom)
+       return xstrdup (dpyinfo->motif_drag_atom_name);
+
       if (atom == dpyinfo->Xatom_xsettings_sel)
        {
          sprintf (buffer, "_XSETTINGS_S%d",
@@ -25694,6 +27850,71 @@ my_log_handler (const gchar *log_domain, 
GLogLevelFlags log_level,
    connection established.  */
 static unsigned x_display_id;
 
+#if defined HAVE_XINPUT2 && !defined HAVE_GTK3
+
+/* Select for device change events on the root window of DPYINFO.
+   These include device change and hierarchy change notifications.  */
+
+static void
+xi_select_hierarchy_events (struct x_display_info *dpyinfo)
+{
+  XIEventMask mask;
+  ptrdiff_t l;
+  unsigned char *m;
+
+  l = XIMaskLen (XI_LASTEVENT);
+  mask.mask = m = alloca (l);
+  memset (m, 0, l);
+  mask.mask_len = l;
+
+  mask.deviceid = XIAllDevices;
+
+  XISetMask (m, XI_PropertyEvent);
+  XISetMask (m, XI_HierarchyChanged);
+  XISetMask (m, XI_DeviceChanged);
+
+  XISelectEvents (dpyinfo->display, dpyinfo->root_window,
+                 &mask, 1);
+}
+
+#endif
+
+#if defined HAVE_XINPUT2 && defined HAVE_GTK3
+
+/* Look up whether or not GTK already initialized the X input
+   extension.
+
+   Value is 0 if GTK was not built with the input extension, or if it
+   was explictly disabled, 1 if GTK enabled the input extension and
+   the version was successfully determined, and 2 if that information
+   could not be determined.  */
+
+static int
+xi_check_toolkit (Display *display)
+{
+  GdkDisplay *gdpy;
+  GdkDeviceManager *manager;
+
+  gdpy = gdk_x11_lookup_xdisplay (display);
+  eassume (gdpy);
+  manager = gdk_display_get_device_manager (gdpy);
+
+  if (!strcmp (G_OBJECT_TYPE_NAME (manager),
+              "GdkX11DeviceManagerXI2"))
+    return 1;
+
+  if (!strcmp (G_OBJECT_TYPE_NAME (manager),
+              "GdkX11DeviceManagerCore"))
+    return 0;
+
+  /* Something changed in GDK so this information is no longer
+     available.  */
+
+  return 2;
+}
+
+#endif
+
 /* Open a connection to X display DISPLAY_NAME, and return
    the structure that describes the open display.
    If we cannot contact the display, return null.  */
@@ -25885,6 +28106,8 @@ x_term_init (Lisp_Object display_name, char 
*xrm_option, char *resource_name)
   dpyinfo = xzalloc (sizeof *dpyinfo);
   terminal = x_create_terminal (dpyinfo);
 
+  dpyinfo->next_failable_request = dpyinfo->failable_requests;
+
   {
     struct x_display_info *share;
 
@@ -26234,6 +28457,19 @@ x_term_init (Lisp_Object display_name, char 
*xrm_option, char *resource_name)
   int minor = 0;
 #endif
 
+  dpyinfo->client_pointer_device = -1;
+
+#ifdef HAVE_GTK3
+  /* GTK gets a chance to request use of the input extension first.
+     If we later try to enable it if GDK did not, then GTK will not
+     get the resulting extension events.  */
+
+  rc = xi_check_toolkit (dpyinfo->display);
+
+  if (!rc)
+    goto skip_xi_setup;
+#endif
+
   if (XQueryExtension (dpyinfo->display, "XInputExtension",
                       &dpyinfo->xi2_opcode, &xi_first_event,
                       &xi_first_error))
@@ -26302,6 +28538,13 @@ x_term_init (Lisp_Object display_name, char 
*xrm_option, char *resource_name)
        }
       else
        x_uncatch_errors_after_check ();
+
+      /* But don't delude ourselves into thinking that we can use
+        features provided by a version of the input extension that
+        libXi itself doesn't support.  */
+
+      if (minor > original_minor)
+       minor = original_minor;
 #else
       if (x_had_errors_p (dpyinfo->display))
        rc = BadRequest;
@@ -26312,14 +28555,18 @@ x_term_init (Lisp_Object display_name, char 
*xrm_option, char *resource_name)
       if (rc == Success)
        {
          dpyinfo->supports_xi2 = true;
-         x_init_master_valuators (dpyinfo);
+#ifndef HAVE_GTK3
+         /* Select for hierarchy events on the root window.  GTK 3.x
+            does this itself.  */
+         xi_select_hierarchy_events (dpyinfo);
+#endif
+
+         x_cache_xi_devices (dpyinfo);
        }
     }
 
   dpyinfo->xi2_version = minor;
-#ifndef HAVE_GTK3
  skip_xi_setup:
-#endif
   ;
 #endif
 
@@ -26493,7 +28740,7 @@ x_term_init (Lisp_Object display_name, char 
*xrm_option, char *resource_name)
   x_find_modifier_meanings (dpyinfo);
 #endif
 
-  dpyinfo->x_dnd_atoms_size = 8;
+  dpyinfo->x_dnd_atoms_size = 16;
   dpyinfo->x_dnd_atoms = xmalloc (sizeof *dpyinfo->x_dnd_atoms
                                   * dpyinfo->x_dnd_atoms_size);
   dpyinfo->gray
@@ -26626,7 +28873,54 @@ x_term_init (Lisp_Object display_name, char 
*xrm_option, char *resource_name)
 
   return dpyinfo;
 }
+
 
+
+/* Remove all the selection input events on the keyboard buffer
+   intended for DPYINFO.  */
+
+static void
+x_delete_selection_requests (struct x_display_info *dpyinfo)
+{
+  union buffered_input_event *event;
+  int moved_events;
+
+  for (event = kbd_fetch_ptr; event != kbd_store_ptr;
+       event = X_NEXT_KBD_EVENT (event))
+    {
+      if (event->kind == SELECTION_REQUEST_EVENT
+         || event->kind == SELECTION_CLEAR_EVENT)
+       {
+         if (SELECTION_EVENT_DPYINFO (&event->sie) != dpyinfo)
+           continue;
+
+         /* Remove the event from the fifo buffer before processing;
+            otherwise swallow_events called recursively could see it
+            and process it again.  To do this, we move the events
+            between kbd_fetch_ptr and EVENT one slot to the right,
+            cyclically.  */
+
+         if (event < kbd_fetch_ptr)
+           {
+             memmove (kbd_buffer + 1, kbd_buffer,
+                      (event - kbd_buffer) * sizeof *kbd_buffer);
+             kbd_buffer[0] = kbd_buffer[KBD_BUFFER_SIZE - 1];
+             moved_events = kbd_buffer + KBD_BUFFER_SIZE - 1 - kbd_fetch_ptr;
+           }
+         else
+           moved_events = event - kbd_fetch_ptr;
+
+         memmove (kbd_fetch_ptr + 1, kbd_fetch_ptr,
+                  moved_events * sizeof *kbd_fetch_ptr);
+         kbd_fetch_ptr = X_NEXT_KBD_EVENT (kbd_fetch_ptr);
+
+         /* `detect_input_pending' will then recompute whether or not
+            pending input events exist.  */
+         input_pending = false;
+       }
+    }
+}
+
 /* Get rid of display DPYINFO, deleting all frames on it,
    and without sending any more commands to the X server.  */
 
@@ -26676,6 +28970,8 @@ x_delete_display (struct x_display_info *dpyinfo)
       last = ie;
     }
 
+  x_delete_selection_requests (dpyinfo);
+
   if (next_noop_dpyinfo == dpyinfo)
     next_noop_dpyinfo = dpyinfo->next;
 
@@ -26852,6 +29148,7 @@ x_delete_terminal (struct terminal *terminal)
 
          x_dnd_return_frame_object = NULL;
          x_dnd_movement_frame = NULL;
+         x_dnd_wheel_frame = NULL;
          x_dnd_frame = NULL;
        }
 
@@ -26918,6 +29215,25 @@ x_delete_terminal (struct terminal *terminal)
   unblock_input ();
 }
 
+#ifdef HAVE_XINPUT2
+static bool
+x_have_any_grab (struct x_display_info *dpyinfo)
+{
+  int i;
+
+  if (!dpyinfo->supports_xi2)
+    return false;
+
+  for (i = 0; i < dpyinfo->num_devices; ++i)
+    {
+      if (dpyinfo->devices[i].grab)
+       return true;
+    }
+
+  return false;
+}
+#endif
+
 /* Create a struct terminal, initialize it with the X11 specific
    functions and make DISPLAY->TERMINAL point to it.  */
 
@@ -26985,6 +29301,9 @@ x_create_terminal (struct x_display_info *dpyinfo)
   terminal->delete_frame_hook = x_destroy_window;
   terminal->delete_terminal_hook = x_delete_terminal;
   terminal->toolkit_position_hook = x_toolkit_position;
+#ifdef HAVE_XINPUT2
+  terminal->any_grab_hook = x_have_any_grab;
+#endif
   /* Other hooks are NULL by default.  */
 
   return terminal;
@@ -27068,9 +29387,12 @@ void
 mark_xterm (void)
 {
   Lisp_Object val;
-#if defined HAVE_XINPUT2 || defined USE_TOOLKIT_SCROLL_BARS
+#if defined HAVE_XINPUT2 || defined USE_TOOLKIT_SCROLL_BARS \
+  || defined HAVE_XRANDR || defined USE_GTK
   struct x_display_info *dpyinfo;
+#if defined HAVE_XINPUT2 || defined USE_TOOLKIT_SCROLL_BARS
   int i;
+#endif
 #endif
 
   if (x_dnd_return_frame_object)
@@ -27085,6 +29407,12 @@ mark_xterm (void)
       mark_object (val);
     }
 
+  if (x_dnd_wheel_frame)
+    {
+      XSETFRAME (val, x_dnd_wheel_frame);
+      mark_object (val);
+    }
+
 #if defined HAVE_XINPUT2 || defined USE_TOOLKIT_SCROLL_BARS \
   || defined HAVE_XRANDR || defined USE_GTK
   for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
@@ -27104,6 +29432,193 @@ mark_xterm (void)
 #endif
 }
 
+/* Error handling functions for Lisp functions that expose X protocol
+   requests.  They are mostly like `x_catch_errors' and friends, but
+   respect `x-fast-protocol-requests'.  */
+
+void
+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);
+}
+
+void
+x_check_errors_for_lisp (struct x_display_info *dpyinfo,
+                        const char *format)
+{
+  if (!x_fast_protocol_requests)
+    x_check_errors (dpyinfo->display, format);
+}
+
+void
+x_uncatch_errors_for_lisp (struct x_display_info *dpyinfo)
+{
+  if (!x_fast_protocol_requests)
+    x_uncatch_errors ();
+  else
+    x_stop_ignoring_errors (dpyinfo);
+}
+
+/* Preserve the selections in LOST in another frame on DPYINFO.  LOST
+   is a list of local selections that were lost, due to their frame
+   being deleted.  */
+
+void
+x_preserve_selections (struct x_display_info *dpyinfo, Lisp_Object lost,
+                      Lisp_Object current_owner)
+{
+  Lisp_Object tail, frame, new_owner;
+  Time timestamp;
+  Window *owners;
+  Atom *names;
+  ptrdiff_t nowners, counter;
+  struct selection_input_event clear;
+#ifdef USE_XCB
+  xcb_get_selection_owner_cookie_t *cookies;
+  xcb_generic_error_t *error;
+  xcb_get_selection_owner_reply_t *reply;
+#endif
+
+  new_owner = Qnil;
+
+  FOR_EACH_FRAME (tail, frame)
+    {
+      if (FRAME_X_P (XFRAME (frame))
+         && !EQ (frame, current_owner)
+         && FRAME_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
+       {
+         new_owner = frame;
+         break;
+       }
+    }
+
+  tail = lost;
+  nowners = 0;
+
+  FOR_EACH_TAIL_SAFE (tail)
+    {
+      Lisp_Object tem = XCAR (tail);
+      ++nowners;
+
+      /* The selection is really lost (since we cannot find a new
+        owner), so run the appropriate hooks.  */
+      if (NILP (new_owner))
+       CALLN (Frun_hook_with_args, Qx_lost_selection_functions,
+              XCAR (tem));
+      else
+       {
+         CONS_TO_INTEGER (XCAR (XCDR (XCDR (tem))), Time, timestamp);
+
+         /* This shouldn't be able to signal any errors, despite the
+            call to `x_check_errors' inside.  */
+         x_own_selection (XCAR (tem), XCAR (XCDR (tem)),
+                          new_owner, XCAR (XCDR (XCDR (XCDR (XCDR (tem))))),
+                          timestamp);
+       }
+    }
+
+  if (!NILP (new_owner))
+    {
+      owners = alloca (sizeof *owners * nowners);
+      names = alloca (sizeof *names * nowners);
+#ifdef USE_XCB
+      cookies = alloca (sizeof *cookies * nowners);
+#endif
+
+      tail = lost;
+      nowners = 0;
+      counter = 0;
+
+      FOR_EACH_TAIL_SAFE (tail)
+       {
+         Lisp_Object tem = XCAR (tail);
+
+         /* Now check if we still don't own that selection, which can
+            happen if another program set itself as the owner.  */
+         names[counter++] = symbol_to_x_atom (dpyinfo, XCAR (tem));
+
+#ifndef USE_XCB
+         owners[nowners++] = XGetSelectionOwner (dpyinfo->display,
+                                                 names[counter - 1]);
+#else
+         cookies[nowners++]
+           = xcb_get_selection_owner (dpyinfo->xcb_connection,
+                                      names[counter - 1]);
+       }
+
+      nowners = 0;
+      tail = lost;
+
+      FOR_EACH_TAIL_SAFE (tail)
+       {
+         Lisp_Object tem = XCAR (tail);
+
+         reply = xcb_get_selection_owner_reply (dpyinfo->xcb_connection,
+                                                cookies[nowners++], &error);
+         if (reply)
+           owners[nowners - 1] = reply->owner;
+         else
+           owners[nowners - 1] = None;
+
+         free (reply ? (void *) reply : (void *) error);
+#endif
+
+         if (owners[nowners - 1] != FRAME_X_WINDOW (XFRAME (new_owner)))
+           {
+             /* Clear the local selection, since we know we don't own
+                it any longer.  */
+             CONS_TO_INTEGER (XCAR (XCDR (XCDR (tem))), Time, timestamp);
+
+             clear.kind = SELECTION_CLEAR_EVENT;
+
+             SELECTION_EVENT_DPYINFO (&clear) = dpyinfo;
+             SELECTION_EVENT_SELECTION (&clear) = names[nowners - 1];
+             SELECTION_EVENT_TIME (&clear) = timestamp;
+
+             x_handle_selection_event (&clear);
+           }
+       }
+
+      tail = lost;
+      nowners = 0;
+
+      FOR_EACH_TAIL_SAFE (tail)
+       {
+         Lisp_Object tem = XCAR (tail);
+
+         /* If the selection isn't owned by us anymore, note that the
+            selection was lost.  */
+         if (owners[nowners++] != FRAME_X_WINDOW (XFRAME (new_owner)))
+           CALLN (Frun_hook_with_args, Qx_lost_selection_functions,
+                  XCAR (tem));
+       }
+    }
+}
+
+/* Return a list of the keyboard modifier masks in DPYINFO.
+
+   Value is a list of (HYPER SUPER ALT SHIFT-LOCK META), each element
+   being the appropriate modifier mask.  */
+
+Lisp_Object
+x_get_keyboard_modifiers (struct x_display_info *dpyinfo)
+{
+  /* This sometimes happens when the function is called during display
+     initialization, which can happen while obtaining vendor specific
+     keysyms.  */
+  if (!dpyinfo->xkb_desc && !dpyinfo->modmap)
+    x_find_modifier_meanings (dpyinfo);
+
+  return list5 (make_uint (dpyinfo->hyper_mod_mask),
+               make_uint (dpyinfo->super_mod_mask),
+               make_uint (dpyinfo->alt_mod_mask),
+               make_uint (dpyinfo->shift_lock_mask),
+               make_uint (dpyinfo->meta_mod_mask));
+}
+
 void
 syms_of_xterm (void)
 {
@@ -27116,10 +29631,17 @@ syms_of_xterm (void)
   x_dnd_action_symbol = Qnil;
   staticpro (&x_dnd_action_symbol);
 
+  x_dnd_selection_alias_cell = Fcons (Qnil, Qnil);
+  staticpro (&x_dnd_selection_alias_cell);
+
+  x_dnd_unsupported_drop_data = Qnil;
+  staticpro (&x_dnd_unsupported_drop_data);
+
   DEFSYM (Qvendor_specific_keysyms, "vendor-specific-keysyms");
   DEFSYM (Qlatin_1, "latin-1");
   DEFSYM (Qnow, "now");
   DEFSYM (Qx_dnd_targets_list, "x-dnd-targets-list");
+  DEFSYM (Qx_auto_preserve_selections, "x-auto-preserve-selections");
 
 #ifdef USE_GTK
   xg_default_icon_file = build_pure_c_string 
("icons/hicolor/scalable/apps/emacs.svg");
@@ -27166,7 +29688,7 @@ you, try increasing the value of
   x_mouse_click_focus_ignore_position = false;
 
   DEFVAR_INT ("x-mouse-click-focus-ignore-time", 
x_mouse_click_focus_ignore_time,
-    doc: /* Number of miliseconds for which to ignore buttons after focus 
change.
+    doc: /* Number of milliseconds for which to ignore buttons after focus 
change.
 This variable only takes effect if
 `x-mouse-click-focus-ignore-position' is non-nil, and should be
 adjusted if the default value does not work for whatever reason.  */);
@@ -27204,6 +29726,7 @@ With MS Windows, Haiku windowing or Nextstep, the value 
is t.  */);
   DEFSYM (Qsuper, "super");
   Fput (Qsuper, Qmodifier_value, make_fixnum (super_modifier));
   DEFSYM (QXdndSelection, "XdndSelection");
+  DEFSYM (Qx_selection_alias_alist, "x-selection-alias-alist");
 
   DEFVAR_LISP ("x-ctrl-keysym", Vx_ctrl_keysym,
     doc: /* Which keys Emacs uses for the ctrl modifier.
@@ -27337,19 +29860,34 @@ where FRAME is the frame the mouse is on top of, and 
POSITION is a
 mouse position list.  */);
   Vx_dnd_movement_function = Qnil;
 
+  DEFVAR_LISP ("x-dnd-wheel-function", Vx_dnd_wheel_function,
+    doc: /* Function called upon wheel movement on a frame during 
drag-and-drop.
+It should either be nil, or accept four arguments POSITION, BUTTON,
+STATE and TIME, where POSITION is a mouse position list describing
+where the wheel moved, BUTTON is the wheel button that was pressed,
+STATE is the X modifier state at the time of the wheel movement, and
+TIME is the X server time at which the wheel moved.  */);
+  Vx_dnd_wheel_function = Qnil;
+
   DEFVAR_LISP ("x-dnd-unsupported-drop-function", 
Vx_dnd_unsupported_drop_function,
     doc: /* Function called when trying to drop on an unsupported window.
 This function is called whenever the user tries to drop something on a
 window that does not support either the XDND or Motif protocols for
 drag-and-drop.  It should return a non-nil value if the drop was
 handled by the function, and nil if it was not.  It should accept
-several arguments TARGETS, X, Y, ACTION, WINDOW-ID, FRAME and TIME,
-where TARGETS is the list of targets that was passed to
-`x-begin-drag', WINDOW-ID is the numeric XID of the window that is
+several arguments TARGETS, X, Y, ACTION, WINDOW-ID, FRAME, TIME and
+LOCAL-SELECTION, where TARGETS is the list of targets that was passed
+to `x-begin-drag', WINDOW-ID is the numeric XID of the window that is
 being dropped on, X and Y are the root window-relative coordinates
 where the drop happened, ACTION is the action that was passed to
 `x-begin-drag', FRAME is the frame which initiated the drag-and-drop
-operation, and TIME is the X server time when the drop happened.  */);
+operation, TIME is the X server time when the drop happened, and
+LOCAL-SELECTION is the contents of the `XdndSelection' when
+`x-begin-drag' was run; its contents can be retrieved by calling the
+function `x-get-local-selection'.
+
+If a symbol is returned, then it will be used as the return value of
+`x-begin-drag'.  */);
   Vx_dnd_unsupported_drop_function = Qnil;
 
   DEFVAR_INT ("x-color-cache-bucket-size", x_color_cache_bucket_size,
@@ -27376,4 +29914,43 @@ should return a symbol describing what to return from
 If the value is nil, or the function returns a value that is not
 a symbol, a drop on an Emacs frame will be canceled.  */);
   Vx_dnd_native_test_function = Qnil;
+
+  DEFVAR_BOOL ("x-dnd-preserve-selection-data", x_dnd_preserve_selection_data,
+    doc: /* Preserve selection data after `x-begin-drag' returns.
+This lets you inspect the contents of `XdndSelection' after a
+drag-and-drop operation, which is useful when writing tests for
+drag-and-drop code.  */);
+  x_dnd_preserve_selection_data = false;
+
+  DEFVAR_BOOL ("x-dnd-disable-motif-protocol", x_dnd_disable_motif_protocol,
+    doc: /* Disable the Motif drag-and-drop protocols.
+When non-nil, `x-begin-drag' will not drop onto any window that only
+supports the Motif drag-and-drop protocols.  */);
+  x_dnd_disable_motif_protocol = false;
+
+  DEFVAR_BOOL ("x-dnd-use-unsupported-drop", x_dnd_use_unsupported_drop,
+    doc: /* Enable the emulation of drag-and-drop based on the primary 
selection.
+When nil, do not use the primary selection and synthetic mouse clicks
+to emulate the drag-and-drop of `STRING', `UTF8_STRING',
+`COMPOUND_TEXT' or `TEXT'.  */);
+  x_dnd_use_unsupported_drop = true;
+
+  DEFVAR_BOOL ("x-fast-protocol-requests", x_fast_protocol_requests,
+    doc: /* Whether or not X protocol-related functions should wait for errors.
+When this is nil, functions such as `x-delete-window-property',
+`x-change-window-property' and `x-send-client-message' will wait for a
+reply from the X server, and signal any errors that occurred while
+executing the protocol request.  Otherwise, errors will be silently
+ignored without waiting, which is generally faster.  */);
+  x_fast_protocol_requests = false;
+
+  DEFVAR_LISP ("x-auto-preserve-selections", Vx_auto_preserve_selections,
+    doc: /* Whether or not to transfer selection ownership when deleting a 
frame.
+When non-nil, deleting a frame that is currently the owner of a
+selection will cause its ownership to be transferred to another frame
+on the same display.
+
+In addition, when this variable is a list, only preserve the
+selections whose names are contained within.  */);
+  Vx_auto_preserve_selections = list2 (QCLIPBOARD, QPRIMARY);
 }
diff --git a/src/xterm.h b/src/xterm.h
index 82b4308041..a0ae3a330a 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -75,6 +75,9 @@ typedef GtkWidget *xt_or_gtk_widget;
 #endif
 #endif /* USE_GTK */
 
+/* Number of "failable requests" to store.  */
+#define N_FAILABLE_REQUESTS 128
+
 #ifdef USE_CAIRO
 #include <cairo-xlib.h>
 #ifdef CAIRO_HAS_PDF_SURFACE
@@ -235,29 +238,76 @@ struct xi_touch_point_t
 
 struct xi_device_t
 {
+  /* The numerical ID of this device.  */
   int device_id;
+
 #ifdef HAVE_XINPUT2_1
+  /* The number of scroll valuators in `valuators'.  */
   int scroll_valuator_count;
 #endif
+
+  /* Whether or not the device is grabbed and its use.  */
   int grab, use;
+
+  /* The attached device.  Only valid if USE is some kind of master
+     device.  */
+  int attachment;
+
 #ifdef HAVE_XINPUT2_2
+  /* Whether or not this device is a direct touch device.  */
   bool direct_p;
 #endif
 
 #ifdef HAVE_XINPUT2_1
+  /* An array of scroll valuators Emacs knows about.  */
   struct xi_scroll_valuator_t *valuators;
 #endif
+
 #ifdef HAVE_XINPUT2_2
+  /* An array of in-progress touchscreen events.  */
   struct xi_touch_point_t *touchpoints;
 #endif
 
+  /* The name of this device.  */
   Lisp_Object name;
+
+  /* The time at which `focus_frame' became the keyboard focus (only
+     applies to master devices).  */
+  Time focus_frame_time;
+
+  /* The frame that is currently this device's keyboard focus, or
+     NULL.  */
+  struct frame *focus_frame;
+
+  /* The time at which `focus_frame' became the implicit keyboard
+     focus.  */
+  Time focus_implicit_time;
+
+  /* The frame that is currently this device's implicit keyboard
+     focus, or NULL.  */
+  struct frame *focus_implicit_frame;
+
+  /* The window on which the last motion event happened.  */
+  Window last_motion_window;
+
+  /* The rounded integer coordinates of the last motion event.  */
+  int last_motion_x, last_motion_y;
 };
 #endif
 
 Status x_parse_color (struct frame *f, const char *color_name,
                      XColor *color);
 
+struct x_failable_request
+{
+  /* The first request making up this sequence.  */
+  unsigned long start;
+
+  /* If this is zero, then the request has not yet been made.
+     Otherwise, this is the request that ends this sequence.  */
+  unsigned long end;
+};
+
 
 /* For each X display, we have a structure that records
    information about it.  */
@@ -428,8 +478,8 @@ struct x_display_info
   /* More atoms for font properties.  The last three are private
      properties, see the comments in src/fontset.h.  */
   Atom Xatom_PIXEL_SIZE, Xatom_AVERAGE_WIDTH,
-  Xatom_MULE_BASELINE_OFFSET, Xatom_MULE_RELATIVE_COMPOSE,
-  Xatom_MULE_DEFAULT_ASCENT;
+    Xatom_MULE_BASELINE_OFFSET, Xatom_MULE_RELATIVE_COMPOSE,
+    Xatom_MULE_DEFAULT_ASCENT;
 
   /* More atoms for Ghostscript support.  */
   Atom Xatom_DONE, Xatom_PAGE;
@@ -443,12 +493,22 @@ struct x_display_info
   /* Atom used to determine whether or not the screen is composited.  */
   Atom Xatom_NET_WM_CM_Sn;
 
+  /* Atoms used by the Motif drag and drop protocols.  */
   Atom Xatom_MOTIF_WM_HINTS, Xatom_MOTIF_DRAG_WINDOW,
     Xatom_MOTIF_DRAG_TARGETS, Xatom_MOTIF_DRAG_AND_DROP_MESSAGE,
     Xatom_MOTIF_DRAG_INITIATOR_INFO, Xatom_MOTIF_DRAG_RECEIVER_INFO;
 
+  /* Atoms used by Emacs internally.  */
+  Atom Xatom_EMACS_DRAG_ATOM;
+
+  /* Special selections used by the Motif drop protocol to indicate
+     success or failure.  */
   Atom Xatom_XmTRANSFER_SUCCESS, Xatom_XmTRANSFER_FAILURE;
 
+  /* Atoms used by both versions of the OffiX DND protocol (the "old
+     KDE" protocol in x-dnd.el). */
+  Atom Xatom_DndProtocol, Xatom_DND_PROTOCOL;
+
   /* The frame (if any) which has the X window that has keyboard focus.
      Zero if none.  This is examined by Ffocus_frame in xfns.c.  Note
      that a mere EnterNotify event can set this; if you need to know the
@@ -459,7 +519,10 @@ struct x_display_info
   /* The last frame mentioned in a FocusIn or FocusOut event.  This is
      separate from x_focus_frame, because whether or not LeaveNotify
      events cause us to lose focus depends on whether or not we have
-     received a FocusIn event for it.  */
+     received a FocusIn event for it.
+
+     This field is not used when the input extension is being
+     utilized.  */
   struct frame *x_focus_event_frame;
 
   /* The frame which currently has the visual highlight, and should get
@@ -485,9 +548,8 @@ struct x_display_info
   struct scroll_bar *last_mouse_scroll_bar;
 
   /* Time of last user interaction as returned in X events on this
-     display, and time where WM support for `_NET_WM_USER_TIME_WINDOW'
-     was last checked.  */
-  Time last_user_time, last_user_check_time;
+     display.  */
+  Time last_user_time;
 
   /* Position where the mouse was last time we reported a motion.
      This is a position on last_mouse_motion_frame.  */
@@ -506,6 +568,9 @@ struct x_display_info
      received, and return that in hopes that it's somewhat accurate.  */
   Time last_mouse_movement_time;
 
+  /* Whether or not the last mouse motion was synthetic.  */
+  bool last_mouse_movement_time_send_event;
+
   /* The gray pixmap.  */
   Pixmap gray;
 
@@ -555,6 +620,23 @@ struct x_display_info
   ptrdiff_t x_dnd_atoms_size;
   ptrdiff_t x_dnd_atoms_length;
 
+  /* The unique drag and drop atom used on Motif.  None if it was not
+     already computed.  */
+  Atom motif_drag_atom;
+
+  /* Its name.  */
+  char motif_drag_atom_name[sizeof "_EMACS_ATOM_%lu" - 3
+                           + INT_STRLEN_BOUND (unsigned long)];
+
+  /* When it was owned.  */
+  Time motif_drag_atom_time;
+
+  /* The frame that currently owns `motif_drag_atom'.  */
+  struct frame *motif_drag_atom_owner;
+
+  /* The drag window for this display.  */
+  Window motif_drag_window;
+
   /* Extended window manager hints, Atoms supported by the window manager and
      atoms for setting the window type.  */
   Atom Xatom_net_supported, Xatom_net_supporting_wm_check;
@@ -572,9 +654,9 @@ struct x_display_info
     Xatom_net_wm_state_shaded, Xatom_net_frame_extents, 
Xatom_net_current_desktop,
     Xatom_net_workarea, Xatom_net_wm_opaque_region, Xatom_net_wm_ping,
     Xatom_net_wm_sync_request, Xatom_net_wm_sync_request_counter,
-    Xatom_net_wm_frame_drawn, Xatom_net_wm_user_time,
-    Xatom_net_wm_user_time_window, Xatom_net_client_list_stacking,
-    Xatom_net_wm_pid;
+    Xatom_net_wm_sync_fences, Xatom_net_wm_frame_drawn, 
Xatom_net_wm_frame_timings,
+    Xatom_net_wm_user_time, Xatom_net_wm_user_time_window,
+    Xatom_net_client_list_stacking, Xatom_net_wm_pid;
 
   /* XSettings atoms and windows.  */
   Atom Xatom_xsettings_sel, Xatom_xsettings_prop, Xatom_xsettings_mgr;
@@ -596,6 +678,9 @@ struct x_display_info
     Xatom_XdndPosition, Xatom_XdndStatus, Xatom_XdndLeave, Xatom_XdndDrop,
     Xatom_XdndFinished;
 
+  /* XDS source and target.  */
+  Atom Xatom_XdndDirectSave0, Xatom_XdndActionDirectSave, Xatom_text_plain;
+
 #ifdef HAVE_XKB
   /* Virtual modifiers */
   Atom Xatom_Meta, Xatom_Super, Xatom_Hyper, Xatom_ShiftLock, Xatom_Alt;
@@ -633,13 +718,27 @@ struct x_display_info
 
 #ifdef HAVE_XINPUT2
   bool supports_xi2;
+
+  /* The minor version of the input extension.  (Major is always
+     2.x.) */
   int xi2_version;
+
+  /* The generic event opcode of XI2 events.  */
   int xi2_opcode;
 
+  /* The number of devices on this display known to Emacs.  */
   int num_devices;
+
+  /* Array of all input extension devices on this display known to
+     Emacs.  */
   struct xi_device_t *devices;
 
+  /* Pending keystroke time.  */
   Time pending_keystroke_time;
+
+  /* Pending keystroke source.  If a core KeyPress event arrives with
+     the same timestamp as pending_keystroke_time, it will be treated
+     as originating from this device.  */
   int pending_keystroke_source;
 
 #if defined USE_GTK && !defined HAVE_GTK3
@@ -649,6 +748,10 @@ struct x_display_info
      input method) core key event.  */
   bool pending_keystroke_time_special_p;
 #endif
+
+  /* The client pointer.  We keep a record client-side to avoid
+     calling XISetClientPointer all the time.  */
+  int client_pointer_device;
 #endif
 
 #ifdef HAVE_XKB
@@ -713,6 +816,28 @@ struct x_display_info
      RRScreenChangeNotify.  */
   int screen_mm_width;
   int screen_mm_height;
+
+  /* Circular buffer of request serial ranges to ignore inside an
+     error handler in increasing order.  */
+  struct x_failable_request failable_requests[N_FAILABLE_REQUESTS];
+
+  /* Pointer to the next request in `failable_requests'.  */
+  struct x_failable_request *next_failable_request;
+
+  /* The pending drag-and-drop time for middle-click based
+     drag-and-drop emulation.  */
+  Time pending_dnd_time;
+
+#if defined HAVE_XSYNC && !defined USE_GTK && defined HAVE_CLOCK_GETTIME
+  /* Whether or not the server time is probably the same as
+     "clock_gettime (CLOCK_MONOTONIC, ...)".  */
+  bool server_time_monotonic_p;
+
+  /* The time difference between the X server clock and the monotonic
+     clock, or 0 if unknown (if the difference is legitimately 0,
+     server_time_monotonic_p will be true).  */
+  int_fast64_t server_time_offset;
+#endif
 };
 
 #ifdef HAVE_X_I18N
@@ -970,15 +1095,54 @@ struct x_output
 #endif
 
 #ifdef HAVE_XSYNC
+  /* The "basic frame counter" used for resize synchronization.  */
   XSyncCounter basic_frame_counter;
+
+  /* The "extended frame counter" used for frame synchronization.  */
   XSyncCounter extended_frame_counter;
+
+  /* The pending value of the basic counter.  */
   XSyncValue pending_basic_counter_value;
+
+  /* The current value of the extended counter.  */
   XSyncValue current_extended_counter_value;
 
+  /* The configure event value of the extended counter.  */
+  XSyncValue resize_counter_value;
+
+  /* Whether or not basic resize synchronization is in progress.  */
   bool_bf sync_end_pending_p : 1;
+
+  /* Whether or not extended resize synchronization is in
+     progress.  */
   bool_bf ext_sync_end_pending_p : 1;
+
 #ifdef HAVE_GTK3
+  /* Whether or not GDK resize synchronization is in progress.  */
   bool_bf xg_sync_end_pending_p : 1;
+#endif
+
+  /* Whether or Emacs is waiting for the compositing manager to draw a
+     frame.  */
+  bool_bf waiting_for_frame_p : 1;
+
+#if !defined USE_GTK && defined HAVE_CLOCK_GETTIME
+  /* Whether or not Emacs should wait for the compositing manager to
+     draw frames before starting a new frame.  */
+  bool_bf use_vsync_p : 1;
+
+  /* The time (in microseconds) it took to draw the last frame.  */
+  uint_fast64_t last_frame_time;
+
+  /* A temporary time used to calculate that value.  */
+  uint_fast64_t temp_frame_time;
+
+#ifdef HAVE_XSYNCTRIGGERFENCE
+  /* An array of two sync fences that are triggered in order after a
+     frame completes.  Not initialized if the XSync extension is too
+     old to support sync fences.  */
+  XSyncFence sync_fences[2];
+#endif
 #endif
 #endif
 
@@ -996,7 +1160,9 @@ struct x_output
 
   /* Keep track of focus.  May be EXPLICIT if we received a FocusIn for this
      frame, or IMPLICIT if we received an EnterNotify.
-     FocusOut and LeaveNotify clears EXPLICIT/IMPLICIT. */
+     FocusOut and LeaveNotify clears EXPLICIT/IMPLICIT.
+
+     Not used when the input extension is being utilized.  */
   int focus_state;
 
   /* The offset we need to add to compensate for type A WMs.  */
@@ -1155,8 +1321,14 @@ extern void x_mark_frame_dirty (struct frame *f);
 #endif
 
 #ifdef HAVE_XSYNC
-#define FRAME_X_BASIC_COUNTER(f) FRAME_X_OUTPUT (f)->basic_frame_counter
-#define FRAME_X_EXTENDED_COUNTER(f) FRAME_X_OUTPUT (f)->extended_frame_counter
+#define FRAME_X_BASIC_COUNTER(f)               \
+  FRAME_X_OUTPUT (f)->basic_frame_counter
+#define FRAME_X_EXTENDED_COUNTER(f)            \
+  FRAME_X_OUTPUT (f)->extended_frame_counter
+#define FRAME_X_WAITING_FOR_DRAW(f)            \
+  FRAME_X_OUTPUT (f)->waiting_for_frame_p
+#define FRAME_X_COUNTER_VALUE(f)               \
+  FRAME_X_OUTPUT (f)->current_extended_counter_value
 #endif
 
 /* This is the Colormap which frame F uses.  */
@@ -1194,11 +1366,6 @@ struct scroll_bar
   /* The X window representing this scroll bar.  */
   Window x_window;
 
-#if defined HAVE_XDBE && !defined USE_TOOLKIT_SCROLL_BARS
-  /* The X drawable representing this scroll bar.  */
-  Drawable x_drawable;
-#endif
-
   /* The position and size of the scroll bar in pixels, relative to the
      frame.  */
   int top, left, width, height;
@@ -1396,19 +1563,31 @@ extern bool x_text_icon (struct frame *, const char *);
 extern void x_catch_errors (Display *);
 extern void x_catch_errors_with_handler (Display *, x_special_error_handler,
                                         void *);
+extern void x_catch_errors_for_lisp (struct x_display_info *);
+extern void x_uncatch_errors_for_lisp (struct x_display_info *);
+extern void x_check_errors_for_lisp (struct x_display_info *,
+                                    const char *)
+  ATTRIBUTE_FORMAT_PRINTF (2, 0);
 extern void x_check_errors (Display *, const char *)
   ATTRIBUTE_FORMAT_PRINTF (2, 0);
 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_stop_ignoring_errors (struct x_display_info *);
 extern void x_clear_errors (Display *);
-extern void x_set_window_size (struct frame *f, bool, int, int);
-extern void x_make_frame_visible (struct frame *f);
-extern void x_make_frame_invisible (struct frame *f);
-extern void x_iconify_frame (struct frame *f);
+extern void x_set_window_size (struct frame *, bool, int, int);
+extern void x_set_last_user_time_from_lisp (struct x_display_info *, Time);
+extern void x_make_frame_visible (struct frame *);
+extern void x_make_frame_invisible (struct frame *);
+extern void x_iconify_frame (struct frame *);
 extern void x_free_frame_resources (struct frame *);
 extern void x_wm_set_size_hint (struct frame *, long, bool);
+#if defined HAVE_XSYNCTRIGGERFENCE && !defined USE_GTK \
+  && defined HAVE_CLOCK_GETTIME
+extern void x_sync_init_fences (struct frame *);
+#endif
 
 extern void x_delete_terminal (struct terminal *);
 extern Cursor x_create_font_cursor (struct x_display_info *, int);
@@ -1450,11 +1629,14 @@ extern Lisp_Object x_cr_export_frames (Lisp_Object, 
cairo_surface_type_t);
 #ifdef HAVE_XRENDER
 extern void x_xrender_color_from_gc_background (struct frame *, GC,
                                                XRenderColor *, bool);
-extern void x_xr_ensure_picture (struct frame *f);
-extern void x_xr_apply_ext_clip (struct frame *f, GC gc);
-extern void x_xr_reset_ext_clip (struct frame *f);
+extern void x_xr_ensure_picture (struct frame *);
+extern void x_xr_apply_ext_clip (struct frame *, GC);
+extern void x_xr_reset_ext_clip (struct frame *);
 #endif
 
+extern Bool x_query_pointer (Display *, Window, Window *, Window *, int *,
+                            int *, int *, int *, unsigned int *);
+
 #ifdef HAVE_GTK3
 extern void x_scroll_bar_configure (GdkEvent *);
 #endif
@@ -1536,6 +1718,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 Lisp_Object x_atom_to_symbol (struct x_display_info *, Atom);
+extern Atom symbol_to_x_atom (struct x_display_info *, Lisp_Object);
 
 extern bool x_handle_dnd_message (struct frame *,
                                  const XClientMessageEvent *,
@@ -1558,8 +1741,8 @@ extern void x_clipboard_manager_save_all (void);
 
 extern Lisp_Object x_timestamp_for_selection (struct x_display_info *,
                                              Lisp_Object);
-extern void x_set_pending_dnd_time (Time);
-extern void x_own_selection (Lisp_Object, Lisp_Object, Lisp_Object);
+extern void x_own_selection (Lisp_Object, Lisp_Object, Lisp_Object,
+                            Lisp_Object, Time);
 extern Atom x_intern_cached_atom (struct x_display_info *, const char *,
                                  bool);
 extern char *x_get_atom_name (struct x_display_info *, Atom, bool *)
@@ -1578,6 +1761,9 @@ extern void xic_set_statusarea (struct frame *);
 extern void xic_set_xfontset (struct frame *, const char *);
 extern bool x_defined_color (struct frame *, const char *, Emacs_Color *,
                              bool, bool);
+extern void x_preserve_selections (struct x_display_info *, Lisp_Object,
+                                  Lisp_Object);
+extern Lisp_Object x_get_keyboard_modifiers (struct x_display_info *);
 #ifdef HAVE_X_I18N
 extern void free_frame_xic (struct frame *);
 # if defined HAVE_X_WINDOWS && defined USE_X_TOOLKIT
@@ -1627,12 +1813,14 @@ extern bool x_dnd_in_progress;
 extern bool x_dnd_waiting_for_finish;
 extern struct frame *x_dnd_frame;
 extern struct frame *x_dnd_finish_frame;
-extern unsigned x_dnd_unsupported_event_level;
 extern int x_error_message_count;
 
 #ifdef HAVE_XINPUT2
 extern struct xi_device_t *xi_device_from_id (struct x_display_info *, int);
 extern bool xi_frame_selected_for (struct frame *, unsigned long);
+#ifndef USE_GTK
+extern unsigned int xi_convert_event_state (XIDeviceEvent *);
+#endif
 #endif
 
 extern void mark_xterm (void);
diff --git a/test/ChangeLog.1 b/test/ChangeLog.1
index fe7e6626cb..328609038a 100644
--- a/test/ChangeLog.1
+++ b/test/ChangeLog.1
@@ -65,7 +65,7 @@
 
 2015-03-10  Paul Eggert  <eggert@cs.ucla.edu>
 
-       Prefer "initialize" to "initialise"
+       Prefer "initialize"
        * indent/js-indent-init-t.js: Rename from
        indent/js-indent-first-initialiser-t.js.
        * indent/js-indent-init-dynamic.js: Rename from
diff --git a/test/Makefile.in b/test/Makefile.in
index 3b6e116e65..1fa9d5f7d9 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -151,13 +151,13 @@ endif
 %.elc: %.el
        $(AM_V_ELC)$(emacs) --batch -f batch-byte-compile $<
 
+ifdef EMACS_HYDRA_CI
+WRITE_LOG = 2>&1 | tee $@
+else
 ## Save logs, and show logs for failed tests.
 WRITE_LOG = > $@ 2>&1 || { STAT=$$?; cat $@; exit $$STAT; }
-## On Hydra or Emba, always show logs for certain problematic tests.
-ifdef EMACS_HYDRA_CI
-lisp/net/tramp-tests.log \
-: WRITE_LOG = 2>&1 | tee $@
 endif
+## On Emba, always show logs for certain problematic tests.
 ifdef EMACS_EMBA_CI
 lisp/filenotify-tests.log lisp/net/tramp-tests.log src/emacs-module-tests.log \
 : WRITE_LOG = 2>&1 | tee $@
@@ -240,7 +240,8 @@ $(foreach test,${TESTS},$(eval $(call 
test_template,${test})))
 
 ## Get the tests for only a specific directory.
 SUBDIRS = $(sort $(shell cd ${srcdir} && find lib-src lisp misc src -type d \
-                 ! \( -path "*resources*" -o -path "*auto-save-list" \) 
-print))
+               \( -name '*resources*' -prune \
+                  -o ! -name '*auto-save-list' -print \)))
 SUBDIR_TARGETS =
 
 define subdir_template
@@ -340,9 +341,17 @@ mostlyclean:
        -@for f in ${LOGFILES}; do test ! -f $$f || mv $$f $$f~; done
        rm -f ./*.tmp
 
+# If 'find' supports -delete, it also supports -path.  Otherwise, use
+# -prune and $(FIND_DELETE) instead.  -prune is incompatible with -delete.
+ifeq ($(FIND_DELETE),-delete)
+CLEAN_XML_FILES = '(' -name '*.xml' -a ! -path '*resources*' ')' -delete
+else
+CLEAN_XML_FILES = -name '*resources*' -prune -o -name '*.xml' $(FIND_DELETE)
+endif
+
 clean:
        find . '(' -name '*.log' -o -name '*.log~' ')' $(FIND_DELETE)
-       find . '(' -name '*.xml' -a ! -path '*resources*' ')' $(FIND_DELETE)
+       find . $(CLEAN_XML_FILES)
        rm -f ${srcdir}/lisp/gnus/mml-sec-resources/random_seed
        rm -f $(test_module_dir)/*.o $(test_module_dir)/*.so \
          $(test_module_dir)/*.dll gmp.h
diff --git a/test/lisp/net/netrc-resources/authinfo 
b/test/lisp/auth-source-resources/authinfo
similarity index 100%
rename from test/lisp/net/netrc-resources/authinfo
rename to test/lisp/auth-source-resources/authinfo
diff --git a/test/lisp/net/netrc-resources/netrc-folding 
b/test/lisp/auth-source-resources/netrc-folding
similarity index 100%
rename from test/lisp/net/netrc-resources/netrc-folding
rename to test/lisp/auth-source-resources/netrc-folding
diff --git a/test/lisp/auth-source-tests.el b/test/lisp/auth-source-tests.el
index 41f8b6d8c9..a76e4fb0d2 100644
--- a/test/lisp/auth-source-tests.el
+++ b/test/lisp/auth-source-tests.el
@@ -27,7 +27,7 @@
 ;;; Code:
 
 (require 'ert)
-(eval-when-compile (require 'ert-x))
+(require 'ert-x)
 (require 'cl-lib)
 (require 'auth-source)
 (require 'secrets)
@@ -410,5 +410,29 @@ machine c1 port c2 user c3 password c4\n"
       ;; this is actually the same as `auth-source-search'.
       (should (equal found expected)))))
 
+(ert-deftest test-netrc-credentials ()
+  (let ((data (auth-source-netrc-parse-all (ert-resource-file "authinfo"))))
+    (should data)
+    (let ((imap (seq-find (lambda (elem)
+                            (equal (cdr (assoc "machine" elem))
+                                   "imap.example.org"))
+                          data)))
+      (should (equal (cdr (assoc "login" imap)) "jrh@example.org"))
+      (should (equal (cdr (assoc "password" imap)) "*foobar*")))
+    (let ((imap (seq-find (lambda (elem)
+                            (equal (cdr (assoc "machine" elem))
+                                   "ftp.example.org"))
+                          data)))
+      (should (equal (cdr (assoc "login" imap)) "jrh"))
+      (should (equal (cdr (assoc "password" imap)) "*baz*")))))
+
+(ert-deftest test-netrc-credentials-2 ()
+  (let ((data (auth-source-netrc-parse-all
+               (ert-resource-file "netrc-folding"))))
+    (should
+     (equal data
+            '((("machine" . "XM") ("login" . "XL") ("password" . "XP"))
+              (("machine" . "YM") ("login" . "YL") ("password" . "YP")))))))
+
 (provide 'auth-source-tests)
 ;;; auth-source-tests.el ends here
diff --git a/test/lisp/autorevert-tests.el b/test/lisp/autorevert-tests.el
index 54b1a16b5d..4bbff6d057 100644
--- a/test/lisp/autorevert-tests.el
+++ b/test/lisp/autorevert-tests.el
@@ -105,7 +105,7 @@ This expects `auto-revert--messages' to be bound by
                    (auto-revert--timeout))
                 (null (string-match
                        (format-message
-                        "Reverting buffer `%s'\\." (buffer-name buffer))
+                        "Reverting buffer `%s'" (buffer-name buffer))
                        (or auto-revert--messages ""))))
       (if (and (or file-notify--library
                    (file-remote-p temporary-file-directory))
diff --git a/test/lisp/bookmark-tests.el b/test/lisp/bookmark-tests.el
index a2d8f2d260..3bea08bc37 100644
--- a/test/lisp/bookmark-tests.el
+++ b/test/lisp/bookmark-tests.el
@@ -301,7 +301,7 @@ the lexically-bound variable `buffer'."
        (bookmark-set "foo")
        (should (equal major-mode 'bookmark-edit-annotation-mode))
        ;; Should return to the original buffer
-       (bookmark-send-edited-annotation)
+       (bookmark-edit-annotation-confirm)
        (should (equal (current-buffer) buffer))))))
 
 (ert-deftest bookmark-tests-kill-line ()
@@ -334,7 +334,7 @@ the lexically-bound variable `buffer'."
   (with-bookmark-test
    (bookmark-edit-annotation "name")
    (insert "new text")
-   (bookmark-send-edited-annotation)
+   (bookmark-edit-annotation-confirm)
    (should (equal (bookmark-get-annotation "name") "new text"))))
 
 (ert-deftest bookmark-tests-jump ()
@@ -471,7 +471,7 @@ testing `bookmark-bmenu-list'."
   (with-bookmark-bmenu-test
    (bookmark-bmenu-edit-annotation)
    (insert "foo")
-   (bookmark-send-edited-annotation)
+   (bookmark-edit-annotation-confirm)
    (should (equal (bookmark-get-annotation "name") "foo"))))
 
 (ert-deftest bookmark-test-bmenu-send-edited-annotation/restore-focus ()
@@ -479,7 +479,7 @@ testing `bookmark-bmenu-list'."
   (with-bookmark-bmenu-test
    (bookmark-bmenu-edit-annotation)
    (insert "foo")
-   (bookmark-send-edited-annotation)
+   (bookmark-edit-annotation-confirm)
    (should (equal (buffer-name (current-buffer)) bookmark-bmenu-buffer))
    (beginning-of-line)
    (forward-char 4)
diff --git a/test/lisp/calc/calc-tests.el b/test/lisp/calc/calc-tests.el
index 56cb9057ed..cd984f7ff7 100644
--- a/test/lisp/calc/calc-tests.el
+++ b/test/lisp/calc/calc-tests.el
@@ -445,7 +445,7 @@ An existing calc stack is reused, otherwise a new one is 
created."
        (t  ; n<k<0
         0))))
    ((natnump k)
-    ;; Generalisation for any n, integral k≥0: use falling product
+    ;; Generalization for any n, integral k≥0: use falling product
     (/ (apply '* (number-sequence n (- n (1- k)) -1))
        (calc-tests--fac k)))
    (t (error "Case not covered"))))
@@ -818,7 +818,3 @@ An existing calc stack is reused, otherwise a new one is 
created."
 
 (provide 'calc-tests)
 ;;; calc-tests.el ends here
-
-;; Local Variables:
-;; bug-reference-url-format: "https://debbugs.gnu.org/%s";
-;; End:
diff --git a/test/lisp/calendar/icalendar-tests.el 
b/test/lisp/calendar/icalendar-tests.el
index c918b0f63f..7f8cd47914 100644
--- a/test/lisp/calendar/icalendar-tests.el
+++ b/test/lisp/calendar/icalendar-tests.el
@@ -651,8 +651,8 @@ Argument INPUT-AMERICAN american style diary string.
 Argument EXPECTED-OUTPUT expected iCalendar result string.
 Optional argument ALARMS the value of `icalendar-export-alarms' for this test.
 
-European style input data must use german month names.  American
-and ISO style input data must use english month names."
+European style input data must use German month names.  American
+and ISO style input data must use English month names."
   (let ((tz (getenv "TZ"))
        (calendar-date-style 'iso)
        (icalendar-recurring-start-year 2000)
@@ -1639,19 +1639,17 @@ SUMMARY:NNN Wwwwwwww Wwwww - Aaaaaa Pppppppp rrrrrr ddd 
oo Nnnnnnnn 30
                  "2004-09-17T03:09:10+0000"))
   (let ((orig (icalendar-test--format "20040917T050910")))
     (unwind-protect
-        (progn
-          (set-time-zone-rule "UTC-02:00")
-          (should (equal (icalendar-test--format "20040917T050910")
+       (let ((zone "XXX-02"))
+         (should (equal (icalendar-test--format "20040917T050910" nil zone)
                          "2004-09-17T03:09:10+0000"))
-          (should (equal (icalendar-test--format "20040917T0509")
+         (should (equal (icalendar-test--format "20040917T0509" nil zone)
                          "2004-09-17T03:09:00+0000"))
-          (should (equal (icalendar-test--format "20040917")
+         (should (equal (icalendar-test--format "20040917" nil zone)
                          "2004-09-16T22:00:00+0000"))
-          (should (equal (icalendar-test--format "20040917T050910" 1)
+         (should (equal (icalendar-test--format "20040917T050910" 1 zone)
                          "2004-09-18T03:09:10+0000"))
-          (should (equal (icalendar-test--format "20040917T050910" 30)
+         (should (equal (icalendar-test--format "20040917T050910" 30 zone)
                          "2004-10-17T03:09:10+0000")))
-      (set-time-zone-rule 'wall) ;; (set-time-zone-rule nil) is broken
       (should (equal orig (icalendar-test--format "20040917T050910")))))
   (should (equal (icalendar-test--format "20040917T050910Z")
                  "2004-09-17T05:09:10+0000"))
diff --git a/test/lisp/calendar/todo-mode-tests.el 
b/test/lisp/calendar/todo-mode-tests.el
index 0102b62c10..95855d1e63 100644
--- a/test/lisp/calendar/todo-mode-tests.el
+++ b/test/lisp/calendar/todo-mode-tests.el
@@ -459,7 +459,7 @@ the top done item should be the first done item."
                                  todo-date-pattern
                                 "\\( " diary-time-regexp "\\)?"
                                 (regexp-quote todo-nondiary-end) "?")
-                        (line-end-position) t)
+                         (pos-eol) t)
                         (forward-char)
                         (point)))
           (start1 (save-excursion (funcall find-start)))
@@ -854,7 +854,7 @@ item's date should be adjusted accordingly."
    (let ((current-prefix-arg t)         ; For todo-edit-item--header.
          (get-date (lambda ()
                      (save-excursion
-                       (todo-date-string-matcher (line-end-position))
+                       (todo-date-string-matcher (pos-eol))
                        (buffer-substring-no-properties (match-beginning 1)
                                                        (match-end 0))))))
      (should (equal (funcall get-date) "Jan 1, 2020"))
@@ -903,7 +903,7 @@ tab character."
      (todo-test--insert-item item 1)
      (re-search-forward (concat todo-date-string-start todo-date-pattern
                                (regexp-quote todo-nondiary-end) " ")
-                       (line-end-position) t)
+                       (pos-eol) t)
      (should (looking-at (regexp-quote (concat item0 "\n\t" item1)))))))
 
 (ert-deftest todo-test-multiline-item-indentation-2 () ; bug#43068
@@ -917,7 +917,7 @@ begin with a tab character."
      (todo-edit-item--text 'multiline)
      (insert (concat "\n" item1))
      (todo-edit-quit)
-     (goto-char (line-beginning-position))
+     (goto-char (pos-bol))
      (should (looking-at (regexp-quote (concat item0 "\n\t" item1)))))))
 
 (ert-deftest todo-test-multiline-item-indentation-3 ()
@@ -930,7 +930,7 @@ since all non-initial item lines must begin with 
whitespace."
           (item1 "Second line."))
      (todo-edit-file)
      (should (looking-at (regexp-quote item0)))
-     (goto-char (line-end-position))
+     (goto-char (pos-eol))
      (insert (concat "\n" item1))
      (should-error (todo-edit-quit) :type 'user-error))))
 
diff --git a/test/lisp/cedet/cedet-files-tests.el 
b/test/lisp/cedet/cedet-files-tests.el
index d264410e3c..daaf3edfc4 100644
--- a/test/lisp/cedet/cedet-files-tests.el
+++ b/test/lisp/cedet/cedet-files-tests.el
@@ -29,20 +29,17 @@
 (require 'cedet-files)
 
 (defvar cedet-files-utest-list
-  '(
-    ( "/home/me/src/myproj/src/foo.c" . "!home!me!src!myproj!src!foo.c" )
-    ( "c:/work/myproj/foo.el" . "!drive_c!work!myproj!foo.el" )
-    ( "//windows/proj/foo.java" . "!!windows!proj!foo.java" )
-    ( "/home/me/proj!bang/foo.c" . "!home!me!proj!!bang!foo.c" )
-    )
-  "List of different file names to test.
-Each entry is a cons cell of ( FNAME . CONVERTED )
+  '(("/home/me/src/myproj/src/foo.c" . "!home!me!src!myproj!src!foo.c")
+    ("c:/work/myproj/foo.el" . "!drive_c!work!myproj!foo.el")
+    ("//windows/proj/foo.java" . "!!windows!proj!foo.java")
+    ("/home/me/proj!bang/foo.c" . "!home!me!proj!!bang!foo.c"))
+  "List of file names to test.
+Each entry is a cons cell of (FNAME . CONVERTED)
 where FNAME is some file name, and CONVERTED is what it should be
 converted into.")
 
 (ert-deftest cedet-files-utest ()
-  "Test out some file name conversions."
-  (interactive)
+  "Test some file name conversions."
   (dolist (FT cedet-files-utest-list)
     (let ((dir->file (cedet-directory-name-to-file-name (car FT) t))
           (file->dir (cedet-file-name-to-directory-name (cdr FT) t)))
diff --git a/test/lisp/cedet/semantic-utest-c.el 
b/test/lisp/cedet/semantic-utest-c.el
index 2da450c273..87d754968f 100644
--- a/test/lisp/cedet/semantic-utest-c.el
+++ b/test/lisp/cedet/semantic-utest-c.el
@@ -94,7 +94,7 @@ Target: i486-linux-gnu
 Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.3.1-9ubuntu1' 
--with-bugurl=file:///usr/share/doc/gcc-4.3/README.Bugs 
--enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --enable-shared 
--with-system-zlib --libexecdir=/usr/lib --without-included-gettext 
--enable-threads=posix --enable-nls --with-gxx-include-dir=/usr/include/c++/4.3 
--program-suffix=-4.3 --enable-clocale=gnu --enable-libstdcxx-debug 
--enable-objc-gc --enable-mpfr --enable-targets=all --enable-chec [...]
 Thread model: posix
 gcc version 4.3.1 (Ubuntu 4.3.1-9ubuntu1)"
-    ;; My debian box:
+    ;; My Debian box:
     "Using built-in specs.
 Target: x86_64-unknown-linux-gnu
 Configured with: ../../../sources/gcc/configure 
--prefix=/usr/local/glibc-2.3.6/x86_64/apps/gcc-4.2.3 
--with-gmp=/usr/local/gcc/gmp --with-mpfr=/usr/local/gcc/mpfr 
--enable-languages=c,c++,fortran 
--with-as=/usr/local/glibc-2.3.6/x86_64/apps/gcc-4.2.3/bin/as 
--with-ld=/usr/local/glibc-2.3.6/x86_64/apps/gcc-4.2.3/bin/ld --disable-multilib
@@ -123,13 +123,13 @@ Target: x86_64-redhat-linux
 Configured with: ../configure --prefix=/usr --mandir=/usr/share/man 
--infodir=/usr/share/info --enable-shared --enable-threads=posix 
--enable-checking=release --with-system-zlib --enable-__cxa_atexit 
--disable-libunwind-exceptions --enable-libgcj-multifile 
--enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk 
--disable-dssi --enable-plugin 
--with-java-home=/usr/lib/jvm/java-1.4.2-gcj-1.4.2.0/jre --with-cpu=generic 
--host=x86_64-redhat-linux
 Thread model: posix
 gcc version 4.1.2 20080704 (Red Hat 4.1.2-44)"
-    ;; David Engster's german gcc on ubuntu 4.3
+    ;; David Engster's German gcc on Ubuntu 4.3
     "Es werden eingebaute Spezifikationen verwendet.
 Ziel: i486-linux-gnu
 Konfiguriert mit: ../src/configure -v --with-pkgversion='Ubuntu 
4.3.2-1ubuntu12' --with-bugurl=file:///usr/share/doc/gcc-4.3/README.Bugs 
--enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --enable-shared 
--with-system-zlib --libexecdir=/usr/lib --without-included-gettext 
--enable-threads=posix --enable-nls --with-gxx-include-dir=/usr/include/c++/4.3 
--program-suffix=-4.3 --enable-clocale=gnu --enable-libstdcxx-debug 
--enable-objc-gc --enable-mpfr --enable-targets=all --enable-ch [...]
 Thread-Modell: posix
 gcc-Version 4.3.2 (Ubuntu 4.3.2-1ubuntu12)"
-    ;; Damien Deville bsd
+    ;; Damien Deville BSD
     "Using built-in specs.
 Target: i386-undermydesk-freebsd
 Configured with: FreeBSD/i386 system compiler
@@ -139,7 +139,7 @@ gcc version 4.2.1 20070719  [FreeBSD]"
   "A bunch of sample gcc -v outputs from different machines.")
 
 (defvar semantic-gcc-test-strings-fail
-  '(;; A really old solaris box I found
+  '(;; A really old Solaris box I found
     "Reading specs from 
/usr/local/gcc-2.95.2/lib/gcc-lib/sparc-sun-solaris2.6/2.95.2/specs
 gcc version 2.95.2 19991024 (release)"
     )
diff --git a/test/lisp/cedet/semantic-utest-ia-resources/teststruct.cpp 
b/test/lisp/cedet/semantic-utest-ia-resources/teststruct.cpp
index e7d85101a1..f5b6d64184 100644
--- a/test/lisp/cedet/semantic-utest-ia-resources/teststruct.cpp
+++ b/test/lisp/cedet/semantic-utest-ia-resources/teststruct.cpp
@@ -20,7 +20,7 @@
 // along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 
-// Note: initially provided by by Alex Ott.
+// Note: initially provided by Alex Ott.
 
 template <typename DerivedT>
 struct grammar {
diff --git a/test/lisp/cedet/semantic-utest-ia.el 
b/test/lisp/cedet/semantic-utest-ia.el
index caf20fa8e0..fa3b3185ed 100644
--- a/test/lisp/cedet/semantic-utest-ia.el
+++ b/test/lisp/cedet/semantic-utest-ia.el
@@ -194,7 +194,7 @@
 
        (goto-char a)
 
-       (let ((bss (buffer-substring-no-properties (point) (point-at-eol))))
+        (let ((bss (buffer-substring-no-properties (point) (pos-eol))))
          (condition-case nil
              (setq desired (read bss))
            (error (setq desired (format "  FAILED TO PARSE: %S"
@@ -215,8 +215,8 @@
                        )
                       fail)))
 
-      (setq p nil a nil)
-      (setq idx (1+ idx)))
+        (setq p nil a nil)
+        (setq idx (1+ idx)))
       )
 
     (when fail
@@ -353,7 +353,7 @@
               (when (re-search-forward regex-p nil t)
                 (setq tag (semantic-current-tag))
                 (goto-char (match-end 0))
-                (setq desired (read (buffer-substring (point) (point-at-eol))))
+                 (setq desired (read (buffer-substring (point) (pos-eol))))
                 ))
             tag)
 
@@ -451,7 +451,7 @@ tag that contains point, and return that."
               (when (re-search-forward regex-p nil t)
                 (goto-char (match-end 0))
                 (skip-syntax-backward "w")
-                (setq desired (read (buffer-substring (point) (point-at-eol))))
+                 (setq desired (read (buffer-substring (point) (pos-eol))))
                 (setq start (match-beginning 0))
                 (goto-char start)
                 (setq actual (semantic-symref-test-count-hits-in-tag))
@@ -463,7 +463,7 @@ tag that contains point, and return that."
                         (list
                         (format
                          "Symref id %d: No results." idx))
-                         fail))
+                        fail))
 
            )
 
diff --git a/test/lisp/cedet/semantic-utest.el 
b/test/lisp/cedet/semantic-utest.el
index 78bbbbf459..24a467474b 100644
--- a/test/lisp/cedet/semantic-utest.el
+++ b/test/lisp/cedet/semantic-utest.el
@@ -736,8 +736,8 @@ JAVE this thing would need to be recursive to handle java 
and csharp"
   (beginning-of-line)
   (setq semantic-utest-last-kill-pos (point))
   (setq semantic-utest-last-kill-text
-       (buffer-substring (point) (point-at-eol)))
-  (delete-region (point) (point-at-eol))
+        (buffer-substring (point) (pos-eol)))
+  (delete-region (point) (pos-eol))
   (insert insertme)
   (sit-for 0)
 )
@@ -745,7 +745,7 @@ JAVE this thing would need to be recursive to handle java 
and csharp"
 (defun semantic-utest-unkill-indicator ()
   "Unkill the last indicator."
   (goto-char semantic-utest-last-kill-pos)
-  (delete-region (point) (point-at-eol))
+  (delete-region (point) (pos-eol))
   (insert semantic-utest-last-kill-text)
   (sit-for 0)
   )
diff --git a/test/lisp/cedet/srecode/document-tests.el 
b/test/lisp/cedet/srecode/document-tests.el
index 71c4cd7410..5341bb0936 100644
--- a/test/lisp/cedet/srecode/document-tests.el
+++ b/test/lisp/cedet/srecode/document-tests.el
@@ -35,8 +35,6 @@
   "Test old comment extraction.
 Dump out the extracted dictionary."
   :tags '(:unstable)
-  (interactive)
-
   (srecode-load-tables-for-mode major-mode)
   (srecode-load-tables-for-mode major-mode 'document)
 
diff --git a/test/lisp/comint-tests.el b/test/lisp/comint-tests.el
index 2885aaa914..8402c13daf 100644
--- a/test/lisp/comint-tests.el
+++ b/test/lisp/comint-tests.el
@@ -95,8 +95,4 @@ flow.  Hook function returns alternative password."
 password flow if it returns a nil value."
   (comint-tests/test-password-function #'ignore))
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; comint-tests.el ends here
diff --git a/test/lisp/custom-tests.el b/test/lisp/custom-tests.el
index 77bb337d6a..d1effaa72a 100644
--- a/test/lisp/custom-tests.el
+++ b/test/lisp/custom-tests.el
@@ -24,6 +24,7 @@
 
 (require 'wid-edit)
 (require 'cus-edit)
+(require 'bytecomp)
 
 (ert-deftest custom-theme--load-path ()
   "Test `custom-theme--load-path' behavior."
diff --git a/test/lisp/dired-aux-tests.el b/test/lisp/dired-aux-tests.el
index 694deaae4c..e70898ab74 100644
--- a/test/lisp/dired-aux-tests.el
+++ b/test/lisp/dired-aux-tests.el
@@ -154,5 +154,18 @@
     (should (string-match (regexp-quote command) (nth 0 lines)))
     (dired-test--check-highlighting (nth 0 lines) '(8))))
 
+(ert-deftest dired-guess-default ()
+  (let ((dired-guess-shell-alist-user nil)
+        (dired-guess-shell-alist-default
+         '(("\\.png\\'" "display")
+           ("\\.gif\\'" "display" "xloadimage")
+           ("\\.gif\\'" "feh")
+           ("\\.jpe?g\\'" "xloadimage"))))
+    (should (equal (dired-guess-default '("/tmp/foo.png")) "display"))
+    (should (equal (dired-guess-default '("/tmp/foo.gif"))
+                   '("display" "xloadimage" "feh")))
+    (should (equal (dired-guess-default '("/tmp/foo.png" "/tmp/foo.txt"))
+                   nil))))
+
 (provide 'dired-aux-tests)
 ;;; dired-aux-tests.el ends here
diff --git a/test/lisp/dired-tests.el b/test/lisp/dired-tests.el
index 0e89325907..9cf0151905 100644
--- a/test/lisp/dired-tests.el
+++ b/test/lisp/dired-tests.el
@@ -313,7 +313,7 @@
                             (save-excursion
                               (goto-char 1)
                               (forward-line 1)
-                              (- (point-at-eol) (point)))))
+                              (- (pos-eol) (point)))))
            orig-len len diff pos line-nb)
       (make-directory subdir 'parents)
       (with-current-buffer (dired-noselect subdir)
@@ -331,7 +331,7 @@
           (forward-line 1)
           (let ((inhibit-read-only t)
                 (new-header "  test-bug27968"))
-            (delete-region (point) (point-at-eol))
+            (delete-region (point) (pos-eol))
             (when (= orig-len (length new-header))
               ;; Wow lucky guy! I must buy lottery today.
               (setq new-header (concat new-header " :-)")))
diff --git a/test/lisp/dired-x-tests.el b/test/lisp/dired-x-tests.el
index cec266b0ef..7acaa3c131 100644
--- a/test/lisp/dired-x-tests.el
+++ b/test/lisp/dired-x-tests.el
@@ -47,19 +47,6 @@
       (should (equal all-but-c
                      (sort (dired-get-marked-files 'local) #'string<))))))
 
-(ert-deftest dired-guess-default ()
-  (let ((dired-guess-shell-alist-user nil)
-        (dired-guess-shell-alist-default
-         '(("\\.png\\'" "display")
-           ("\\.gif\\'" "display" "xloadimage")
-           ("\\.gif\\'" "feh")
-           ("\\.jpe?g\\'" "xloadimage"))))
-    (should (equal (dired-guess-default '("/tmp/foo.png")) "display"))
-    (should (equal (dired-guess-default '("/tmp/foo.gif"))
-                   '("display" "xloadimage" "feh")))
-    (should (equal (dired-guess-default '("/tmp/foo.png" "/tmp/foo.txt"))
-                   nil))))
-
 (ert-deftest dired-x--string-to-number ()
   (should (= (dired-x--string-to-number "2.4K") 2457.6))
   (should (= (dired-x--string-to-number "2400") 2400))
diff --git a/test/lisp/dnd-tests.el b/test/lisp/dnd-tests.el
index dfd441b56d..88f6e69457 100644
--- a/test/lisp/dnd-tests.el
+++ b/test/lisp/dnd-tests.el
@@ -38,6 +38,7 @@
   "Alist of selection names to their values.")
 
 (defvar x-treat-local-requests-remotely)
+(defvar x-dnd-preserve-selection-data)
 
 ;; Define some replacements for functions used by the drag-and-drop
 ;; code on X when running under something else.
@@ -152,7 +153,8 @@ This function only tries to handle strings."
   ;; program with reasonably correct behavior, such as dtpad, gedit,
   ;; or Mozilla.
   ;;                ASCII            Latin-1       UTF-8
-  (let ((test-text "hello, everyone! sæl öllsömul! всем привет"))
+  (let ((test-text "hello, everyone! sæl öllsömul! всем привет")
+        (x-dnd-preserve-selection-data t))
     ;; Verify that dragging works.
     (should (eq (dnd-begin-text-drag test-text) 'copy))
     (should (eq (dnd-begin-text-drag test-text nil 'move) 'move))
@@ -187,7 +189,8 @@ This function only tries to handle strings."
         (normal-multibyte-file (expand-file-name
                                 (make-temp-name "тест-на-перетаскивание")
                                 temporary-file-directory))
-        (remote-temp-file (dnd-tests-make-temp-name)))
+        (remote-temp-file (dnd-tests-make-temp-name))
+        (x-dnd-preserve-selection-data t))
     ;; Touch those files if they don't exist.
     (unless (file-exists-p normal-temp-file)
       (write-region "" 0 normal-temp-file))
@@ -239,10 +242,17 @@ This function only tries to handle strings."
           ;; Test that the remote file was added to the list of files
           ;; to remove later.
           (should dnd-last-dragged-remote-file)
+          ;; Make sure the appropriate hook is added so the remote
+          ;; files are removed when Emacs exits.
+          (should (memq #'dnd-remove-last-dragged-remote-file
+                        kill-emacs-hook))
           ;; Test that the remote file was removed.
           (should (progn
                     (dnd-begin-file-drag normal-temp-file)
                     (not dnd-last-dragged-remote-file)))
+          ;; Make sure the remote file removal hook was deleted.
+          (should-not (memq #'dnd-remove-last-dragged-remote-file
+                            kill-emacs-hook))
           ;; Test that links to remote files can't be created.
           (should-error (dnd-begin-file-drag remote-temp-file nil 'link))
           ;; Test dragging a file with a multibyte filename.
@@ -273,7 +283,8 @@ This function only tries to handle strings."
          (expand-file-name (make-temp-name "dnd-test")
                            temporary-file-directory))
         (nonexistent-remote-file (dnd-tests-make-temp-name))
-        (nonexistent-remote-file-1 (dnd-tests-make-temp-name)))
+        (nonexistent-remote-file-1 (dnd-tests-make-temp-name))
+        (x-dnd-preserve-selection-data t))
     ;; Touch those files if they don't exist.
     (unless (file-exists-p normal-temp-file)
       (write-region "" 0 normal-temp-file))
@@ -294,12 +305,19 @@ This function only tries to handle strings."
           ;; Test that the remote file produced was added to the list
           ;; of files to remove upon the next call.
           (should dnd-last-dragged-remote-file)
+          ;; Make sure the appropriate hook is added so the remote
+          ;; files are removed when Emacs exits.
+          (should (memq #'dnd-remove-last-dragged-remote-file
+                        kill-emacs-hook))
           ;; Two local files at the same time.
           (should (eq (dnd-begin-drag-files (list normal-temp-file
                                                   normal-temp-file-1))
                       'copy))
           ;; Test that the remote files were removed.
           (should-not dnd-last-dragged-remote-file)
+          ;; And so was the hook.
+          (should-not (memq #'dnd-remove-last-dragged-remote-file
+                            kill-emacs-hook))
           ;; Test the selection data is correct.
           (let ((uri-list-data (cdr (dnd-tests-verify-selection-data 
'text/uri-list)))
                 (username-data (dnd-tests-verify-selection-data 
'text/x-xdnd-username))
@@ -343,6 +361,10 @@ This function only tries to handle strings."
                        ;; Make sure exactly two valid remote files
                        ;; were downloaded.
                        (eq (length dnd-last-dragged-remote-file) 2)))
+          ;; Make sure the appropriate hook is added so the remote
+          ;; files are removed when Emacs exits.
+          (should (memq #'dnd-remove-last-dragged-remote-file
+                        kill-emacs-hook))
           ;; Make sure links can't be created to remote files.
           (should-error (dnd-begin-drag-files (list normal-temp-file
                                                     remote-temp-file
@@ -353,6 +375,9 @@ This function only tries to handle strings."
                                                   normal-temp-file-1)
                                             nil 'link)
                       'link))
+          ;; Make sure the remote file removal hook was deleted.
+          (should-not (memq #'dnd-remove-last-dragged-remote-file
+                            kill-emacs-hook))
           ;; Make sure you can't drag an empty list of files.
           (should-error (dnd-begin-drag-files nil))
           ;; And when all remote files are inaccessible.
@@ -371,5 +396,46 @@ This function only tries to handle strings."
   (should-not (dnd-get-local-file-uri "file://some-remote-host/path/to/foo"))
   (should-not (dnd-get-local-file-uri "file:///path/to/foo")))
 
+(ert-deftest dnd-tests-open-remote-url ()
+  ;; Expensive test to make sure opening an FTP URL during
+  ;; drag-and-drop works.
+  :tags '(:expensive-test)
+  ;; Don't run if there is no ftp client.
+  (skip-unless (executable-find "ftp"))
+  ;; Don't run this test if the FTP server isn't reachable.
+  (skip-unless (and (fboundp 'network-lookup-address-info)
+                    (network-lookup-address-info "ftp.gnu.org")))
+  ;; Make sure bug#56078 doesn't happen again.
+  (let ((url "ftp://anonymous@ftp.gnu.org/";)
+        ;; This prints a bunch of annoying spaces to stdout.
+        (inhibit-message t))
+    (should (prog1 t (dnd-open-remote-url url 'private)))))
+
+(ert-deftest dnd-tests-direct-save ()
+  ;; This test just verifies that a direct save works; the window
+  ;; system specific test is in x-dnd-tests.el.  When running this
+  ;; interactively, keep in mind that there are only two file managers
+  ;; which are known to implement XDS correctly: System G (see
+  ;; http://nps-systemg.sourceforge.net), and Emacs itself.  GTK file
+  ;; managers such as Nautilus will not work, since they prefer the
+  ;; `text/uri-list' selection target to `XdndDirectSave0', contrary
+  ;; to the XDS specification.
+  (let ((window-system window-system)
+        (normal-temp-file (expand-file-name (make-temp-name "dnd-test")
+                                            temporary-file-directory)))
+    (unwind-protect
+        (progn
+          (unless (file-exists-p normal-temp-file)
+            (write-region "" 0 normal-temp-file))
+          (unless (eq window-system 'x)
+            ;; Use a window system that isn't X, since we only want to test
+            ;; the fallback code when run non-interactively.
+            (setq window-system 'haiku))
+          (should (eq (dnd-direct-save normal-temp-file
+                                       (make-temp-name "target-file-name"))
+                      'copy)))
+      (ignore-errors
+        (delete-file normal-temp-file)))))
+
 (provide 'dnd-tests)
 ;;; dnd-tests.el ends here
diff --git a/test/lisp/emacs-lisp/backtrace-tests.el 
b/test/lisp/emacs-lisp/backtrace-tests.el
index b08695a22b..b42de06776 100644
--- a/test/lisp/emacs-lisp/backtrace-tests.el
+++ b/test/lisp/emacs-lisp/backtrace-tests.el
@@ -274,16 +274,16 @@ line contains the strings \"lambda\" and \"number\"."
   ;; Verify the form now spans multiple lines.
   (let ((pos (point)))
     (search-forward "number")
-    (should-not (= pos (point-at-bol))))
+    (should-not (= pos (pos-bol))))
   ;; Collapse the form.
   (backtrace-single-line)
   ;; Verify that the form is now back on one line,
   ;; and that point is at the same place.
   (should (string= (backtrace-tests--get-substring
                     (- (point) 6) (point)) "number"))
-  (should-not (= (point) (point-at-bol)))
+  (should-not (= (point) (pos-bol)))
   (should (string= (backtrace-tests--get-substring
-                    (point-at-bol) (1+ (point-at-eol)))
+                    (pos-bol) (1+ (pos-eol)))
                    line)))
 
 (ert-deftest backtrace-tests--print-circle ()
diff --git a/test/lisp/emacs-lisp/bindat-tests.el 
b/test/lisp/emacs-lisp/bindat-tests.el
index 7d1233ded7..0c03c51e2e 100644
--- a/test/lisp/emacs-lisp/bindat-tests.el
+++ b/test/lisp/emacs-lisp/bindat-tests.el
@@ -172,18 +172,18 @@
                 ((((x str 2)) ((x . "a"))) . "ax")
                 ((((x str 2)) ((x . "ab"))) . "ab")
                 ((((x str 2)) ((x . "abc"))) . "ab")
-                ((,(bindat-type strz 1) "") . "xx")
-                ((,(bindat-type strz 2) "") . "xx")
-                ((,(bindat-type strz 2) "a") . "ax")
+                ((,(bindat-type strz 1) "") . "\0x")
+                ((,(bindat-type strz 2) "") . "\0x")
+                ((,(bindat-type strz 2) "a") . "a\0")
                 ((,(bindat-type strz 2) "ab") . "ab")
                 ((,(bindat-type strz 2) "abc") . "ab")
-                ((((x strz 1)) ((x . ""))) . "xx")
-                ((((x strz 2)) ((x . ""))) . "xx")
-                ((((x strz 2)) ((x . "a"))) . "ax")
+                ((((x strz 1)) ((x . ""))) . "\0x")
+                ((((x strz 2)) ((x . ""))) . "\0x")
+                ((((x strz 2)) ((x . "a"))) . "a\0")
                 ((((x strz 2)) ((x . "ab"))) . "ab")
                 ((((x strz 2)) ((x . "abc"))) . "ab")
-                ((,(bindat-type strz) "") . "xx")
-                ((,(bindat-type strz) "a") . "ax")))
+                ((,(bindat-type strz) "") . "\0x")
+                ((,(bindat-type strz) "a") . "a\0")))
     (let ((prealloc (make-string 2 ?x)))
       (apply #'bindat-pack (append (car tc) (list prealloc)))
       (should (equal prealloc (cdr tc))))))
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/fun-attr-warn.el 
b/test/lisp/emacs-lisp/bytecomp-resources/fun-attr-warn.el
new file mode 100644
index 0000000000..be907b32f4
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/fun-attr-warn.el
@@ -0,0 +1,266 @@
+;;; -*- lexical-binding: t -*-
+
+;; Correct
+
+(defun faw-str-decl-code (x)
+  "something"
+  (declare (pure t))
+  (print x))
+
+(defun faw-doc-decl-code (x)
+  (:documentation "something")
+  (declare (pure t))
+  (print x))
+
+(defun faw-str-int-code (x)
+  "something"
+  (interactive "P")
+  (print x))
+
+(defun faw-doc-int-code (x)
+  (:documentation "something")
+  (interactive "P")
+  (print x))
+
+(defun faw-decl-int-code (x)
+  (declare (pure t))
+  (interactive "P")
+  (print x))
+
+(defun faw-str-decl-int-code (x)
+  "something"
+  (declare (pure t))
+  (interactive "P")
+  (print x))
+
+(defun faw-doc-decl-int-code (x)
+  (:documentation "something")
+  (declare (pure t))
+  (interactive "P")
+  (print x))
+
+
+;; Correct (last string is return value)
+
+(defun faw-str ()
+  "something")
+
+(defun faw-decl-str ()
+  (declare (pure t))
+  "something")
+
+(defun faw-decl-int-str ()
+  (declare (pure t))
+  (interactive)
+  "something")
+
+(defun faw-str-str ()
+  "something"
+  "something else")
+
+(defun faw-doc-str ()
+  (:documentation "something")
+  "something else")
+
+
+;; Incorrect (bad order)
+
+(defun faw-int-decl-code (x)
+  (interactive "P")
+  (declare (pure t))
+  (print x))
+
+(defun faw-int-str-code (x)
+  (interactive "P")
+  "something"
+  (print x))
+
+(defun faw-int-doc-code (x)
+  (interactive "P")
+  (:documentation "something")
+  (print x))
+
+(defun faw-decl-str-code (x)
+  (declare (pure t))
+  "something"
+  (print x))
+
+(defun faw-decl-doc-code (x)
+  (declare (pure t))
+  (:documentation "something")
+  (print x))
+
+(defun faw-str-int-decl-code (x)
+  "something"
+  (interactive "P")
+  (declare (pure t))
+  (print x))
+
+(defun faw-doc-int-decl-code (x)
+  (:documentation "something")
+  (interactive "P")
+  (declare (pure t))
+  (print x))
+
+(defun faw-int-str-decl-code (x)
+  (interactive "P")
+  "something"
+  (declare (pure t))
+  (print x))
+
+(defun faw-int-doc-decl-code (x)
+  (interactive "P")
+  (:documentation "something")
+  (declare (pure t))
+  (print x))
+
+(defun faw-int-decl-str-code (x)
+  (interactive "P")
+  (declare (pure t))
+  "something"
+  (print x))
+
+(defun faw-int-decl-doc-code (x)
+  (interactive "P")
+  (declare (pure t))
+  (:documentation "something")
+  (print x))
+
+(defun faw-decl-int-str-code (x)
+  (declare (pure t))
+  (interactive "P")
+  "something"
+  (print x))
+
+(defun faw-decl-int-doc-code (x)
+  (declare (pure t))
+  (interactive "P")
+  (:documentation "something")
+  (print x))
+
+(defun faw-decl-str-int-code (x)
+  (declare (pure t))
+  "something"
+  (interactive "P")
+  (print x))
+
+(defun faw-decl-doc-int-code (x)
+  (declare (pure t))
+  (:documentation "something")
+  (interactive "P")
+  (print x))
+
+
+;; Incorrect (duplication)
+
+(defun faw-str-str-decl-int-code (x)
+  "something"
+  "something else"
+  (declare (pure t))
+  (interactive "P")
+  (print x))
+
+(defun faw-str-doc-decl-int-code (x)
+  "something"
+  (:documentation "something else")
+  (declare (pure t))
+  (interactive "P")
+  (print x))
+
+(defun faw-doc-str-decl-int-code (x)
+  (:documentation "something")
+  "something else"
+  (declare (pure t))
+  (interactive "P")
+  (print x))
+
+(defun faw-doc-doc-decl-int-code (x)
+  (:documentation "something")
+  (:documentation "something else")
+  (declare (pure t))
+  (interactive "P")
+  (print x))
+
+(defun faw-str-decl-str-int-code (x)
+  "something"
+  (declare (pure t))
+  "something else"
+  (interactive "P")
+  (print x))
+
+(defun faw-doc-decl-str-int-code (x)
+  (:documentation "something")
+  (declare (pure t))
+  "something else"
+  (interactive "P")
+  (print x))
+
+(defun faw-str-decl-doc-int-code (x)
+  "something"
+  (declare (pure t))
+  (:documentation "something else")
+  (interactive "P")
+  (print x))
+
+(defun faw-doc-decl-doc-int-code (x)
+  (:documentation "something")
+  (declare (pure t))
+  (:documentation "something else")
+  (interactive "P")
+  (print x))
+
+(defun faw-str-decl-decl-int-code (x)
+  "something"
+  (declare (pure t))
+  (declare (indent 1))
+  (interactive "P")
+  (print x))
+
+(defun faw-doc-decl-decl-int-code (x)
+  (:documentation "something")
+  (declare (pure t))
+  (declare (indent 1))
+  (interactive "P")
+  (print x))
+
+(defun faw-str-decl-int-decl-code (x)
+  "something"
+  (declare (pure t))
+  (interactive "P")
+  (declare (indent 1))
+  (print x))
+
+(defun faw-doc-decl-int-decl-code (x)
+  (:documentation "something")
+  (declare (pure t))
+  (interactive "P")
+  (declare (indent 1))
+  (print x))
+
+(defun faw-str-decl-int-int-code (x)
+  "something"
+  (declare (pure t))
+  (interactive "P")
+  (interactive "p")
+  (print x))
+
+(defun faw-doc-decl-int-int-code (x)
+  (:documentation "something")
+  (declare (pure t))
+  (interactive "P")
+  (interactive "p")
+  (print x))
+
+(defun faw-str-int-decl-int-code (x)
+  "something"
+  (interactive "P")
+  (declare (pure t))
+  (interactive "p")
+  (print x))
+
+(defun faw-doc-int-decl-int-code (x)
+  (:documentation "something")
+  (interactive "P")
+  (declare (pure t))
+  (interactive "p")
+  (print x))
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/no-byte-compile.el 
b/test/lisp/emacs-lisp/bytecomp-resources/no-byte-compile.el
new file mode 100644
index 0000000000..00ad194750
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/no-byte-compile.el
@@ -0,0 +1 @@
+;; -*- no-byte-compile: t; -*-
diff --git a/test/lisp/emacs-lisp/bytecomp-tests.el 
b/test/lisp/emacs-lisp/bytecomp-tests.el
index 9abc17a1c4..a246c25e24 100644
--- a/test/lisp/emacs-lisp/bytecomp-tests.el
+++ b/test/lisp/emacs-lisp/bytecomp-tests.el
@@ -38,7 +38,7 @@
   bytecomp-test-var)
 
 (defun bytecomp-test-identity (x)
-  "Identity, but hidden from some optimisations."
+  "Identity, but hidden from some optimizations."
   x)
 
 (defmacro bytecomp-test-loop (outer1 outer2 inner1 inner2)
@@ -556,7 +556,7 @@ inner loops respectively."
                               ((not x) 3)))
             '("a" "b" "c" "d" nil))
 
-    ;; `let' and `let*' optimisations with body being constant or variable
+    ;; `let' and `let*' optimizations with body being constant or variable
     (let* (a
            (b (progn (setq a (cons 1 a)) 2))
            (c (1+ b))
@@ -582,7 +582,7 @@ inner loops respectively."
     (let* (x y)
       'a)
 
-    ;; Check empty-list optimisations.
+    ;; Check empty-list optimizations.
     (mapcar (lambda (x) (member x nil)) '("a" 2 nil))
     (mapcar (lambda (x) (memql x nil)) '(a 2 nil))
     (mapcar (lambda (x) (memq x nil)) '(a nil))
@@ -597,7 +597,7 @@ inner loops respectively."
       (list (mapcar (lambda (x) (assoc (setq n (1+ n)) nil)) '(a "nil"))
             n))
 
-    ;; Exercise variable-aliasing optimisations.
+    ;; Exercise variable-aliasing optimizations.
     (let ((a (list 1)))
       (let ((b a))
         (let ((a (list 2)))
@@ -1580,6 +1580,76 @@ EXPECTED-POINT BINDINGS (MODES \\='\\='(ruby-mode 
js-mode python-mode)) \
       (should (equal (get fname 'lisp-indent-function) 1))
       (should (equal (aref bc 4) "tata\n\n(fn X)")))))
 
+(ert-deftest bytecomp-fun-attr-warn ()
+  ;; Check that warnings are emitted when doc strings, `declare' and
+  ;; `interactive' forms don't come in the proper order, or more than once.
+  (let* ((filename "fun-attr-warn.el")
+         (el (ert-resource-file filename))
+         (elc (concat el "c"))
+         (text-quoting-style 'grave))
+    (with-current-buffer (get-buffer-create "*Compile-Log*")
+      (let ((inhibit-read-only t))
+        (erase-buffer))
+      (byte-compile-file el)
+      (let ((expected
+             '("70:4: Warning: `declare' after `interactive'"
+               "74:4: Warning: Doc string after `interactive'"
+               "79:4: Warning: Doc string after `interactive'"
+               "84:4: Warning: Doc string after `declare'"
+               "89:4: Warning: Doc string after `declare'"
+               "96:4: Warning: `declare' after `interactive'"
+               "102:4: Warning: `declare' after `interactive'"
+               "108:4: Warning: `declare' after `interactive'"
+               "106:4: Warning: Doc string after `interactive'"
+               "114:4: Warning: `declare' after `interactive'"
+               "112:4: Warning: Doc string after `interactive'"
+               "118:4: Warning: Doc string after `interactive'"
+               "119:4: Warning: `declare' after `interactive'"
+               "124:4: Warning: Doc string after `interactive'"
+               "125:4: Warning: `declare' after `interactive'"
+               "130:4: Warning: Doc string after `declare'"
+               "136:4: Warning: Doc string after `declare'"
+               "142:4: Warning: Doc string after `declare'"
+               "148:4: Warning: Doc string after `declare'"
+               "159:4: Warning: More than one doc string"
+               "165:4: Warning: More than one doc string"
+               "171:4: Warning: More than one doc string"
+               "178:4: Warning: More than one doc string"
+               "186:4: Warning: More than one doc string"
+               "192:4: Warning: More than one doc string"
+               "200:4: Warning: More than one doc string"
+               "206:4: Warning: More than one doc string"
+               "215:4: Warning: More than one `declare' form"
+               "222:4: Warning: More than one `declare' form"
+               "230:4: Warning: More than one `declare' form"
+               "237:4: Warning: More than one `declare' form"
+               "244:4: Warning: More than one `interactive' form"
+               "251:4: Warning: More than one `interactive' form"
+               "258:4: Warning: More than one `interactive' form"
+               "257:4: Warning: `declare' after `interactive'"
+               "265:4: Warning: More than one `interactive' form"
+               "264:4: Warning: `declare' after `interactive'")))
+        (goto-char (point-min))
+        (let ((actual nil))
+          (while (re-search-forward
+                  (rx bol (* (not ":")) ":"
+                      (group (+ digit) ":" (+ digit) ": Warning: "
+                             (or "More than one " (+ nonl) " form"
+                                 (: (+ nonl) " after " (+ nonl))))
+                      eol)
+                  nil t)
+            (push (match-string 1) actual))
+          (setq actual (nreverse actual))
+          (should (equal actual expected)))))))
+
+(ert-deftest byte-compile-file/no-byte-compile ()
+  (let* ((src-file (ert-resource-file "no-byte-compile.el"))
+         (dest-file (make-temp-file "bytecomp-tests-" nil ".elc"))
+         (byte-compile-dest-file-function (lambda (_) dest-file)))
+    (should (eq (byte-compile-file src-file) 'no-byte-compile))
+    (should-not (file-exists-p dest-file))))
+
+
 ;; Local Variables:
 ;; no-byte-compile: t
 ;; End:
diff --git a/test/lisp/emacs-lisp/cconv-tests.el 
b/test/lisp/emacs-lisp/cconv-tests.el
index 0668e44ba5..9904c6a969 100644
--- a/test/lisp/emacs-lisp/cconv-tests.el
+++ b/test/lisp/emacs-lisp/cconv-tests.el
@@ -24,6 +24,7 @@
 (require 'ert)
 (require 'cl-lib)
 (require 'generator)
+(require 'bytecomp)
 
 (ert-deftest cconv-tests-lambda-:documentation ()
   "Docstring for lambda can be specified with :documentation."
diff --git a/test/lisp/emacs-lisp/edebug-tests.el 
b/test/lisp/emacs-lisp/edebug-tests.el
index 35259a796a..008e1e467b 100644
--- a/test/lisp/emacs-lisp/edebug-tests.el
+++ b/test/lisp/emacs-lisp/edebug-tests.el
@@ -1104,5 +1104,14 @@ This avoids potential duplicate definitions (Bug#41988)."
           (edebug-initial-mode 'Go-nonstop))
       (eval-buffer))))
 
+(ert-deftest edebug-test-dot-reader ()
+  (with-temp-buffer
+    (insert "(defun x () `(t .,t))")
+    (goto-char (point-min))
+    (should (equal (save-excursion
+                     (edebug-read-storing-offsets (current-buffer)))
+                   (save-excursion
+                     (read (current-buffer)))))))
+
 (provide 'edebug-tests)
 ;;; edebug-tests.el ends here
diff --git a/test/lisp/emacs-lisp/find-func-tests.el 
b/test/lisp/emacs-lisp/find-func-tests.el
index 420c61acb5..d18a9dc1a9 100644
--- a/test/lisp/emacs-lisp/find-func-tests.el
+++ b/test/lisp/emacs-lisp/find-func-tests.el
@@ -109,9 +109,7 @@ expected function symbol and function library, 
respectively."
       (skip-chars-backward "\n")
       (should (string-match-p
                ".join-line. is an alias for .delete-indentation."
-               (buffer-substring
-                (line-beginning-position)
-                (point)))))))
+               (buffer-substring (pos-bol) (point)))))))
 
 ;; Avoid a byte-compilation warning that may confuse people reading
 ;; the result of the following test.
diff --git a/test/lisp/emacs-lisp/icons-tests.el 
b/test/lisp/emacs-lisp/icons-tests.el
new file mode 100644
index 0000000000..e6e71a8e4f
--- /dev/null
+++ b/test/lisp/emacs-lisp/icons-tests.el
@@ -0,0 +1,63 @@
+;;; icons-tests.el --- Tests for icons.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/>.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+(require 'icons)
+(require 'ert)
+(require 'ert-x)
+(require 'cus-edit)
+
+(define-icon icon-test1 nil
+  '((symbol ">")
+    (text "great"))
+  "Test icon"
+  :version "29.1")
+
+(define-icon icon-test2 icon-test1
+  '((text "child"))
+  "Test icon"
+  :version "29.1")
+
+(deftheme test-icons-theme "")
+
+(ert-deftest test-icon-theme ()
+  (let ((icon-preference '(image emoji symbol text)))
+    (should (equal (icon-string 'icon-test1) ">")))
+  (let ((icon-preference '(text)))
+    (should (equal (icon-string 'icon-test1) "great")))
+  (custom-theme-set-icons
+   'test-icons-theme
+   '(icon-test1 ((symbol "<") (text "less"))))
+  (let ((icon-preference '(image emoji symbol text)))
+    (should (equal (icon-string 'icon-test1) ">"))
+    (enable-theme 'test-icons-theme)
+    (should (equal (icon-string 'icon-test1) "<"))))
+
+(ert-deftest test-icon-inheretance ()
+  (let ((icon-preference '(image emoji symbol text)))
+    (should (equal (icon-string 'icon-test2) ">")))
+  (let ((icon-preference '(text)))
+    (should (equal (icon-string 'icon-test2) "child"))))
+
+;;; icons-tests.el ends here
diff --git a/test/lisp/emacs-lisp/lisp-mode-tests.el 
b/test/lisp/emacs-lisp/lisp-mode-tests.el
index fd1af75ba3..996ea201fb 100644
--- a/test/lisp/emacs-lisp/lisp-mode-tests.el
+++ b/test/lisp/emacs-lisp/lisp-mode-tests.el
@@ -330,5 +330,30 @@ Expected initialization file: `%s'\"
       (faceup-clean-buffer)
       (should (faceup-test-font-lock-buffer 'emacs-lisp-mode faceup)))))
 
+(ert-deftest test-lisp-current-defun-name ()
+  (require 'edebug)
+  (with-temp-buffer
+    (emacs-lisp-mode)
+    (insert "(defun foo ()\n'bar)\n")
+    (goto-char 5)
+    (should (equal (lisp-current-defun-name) "foo")))
+  (with-temp-buffer
+    (emacs-lisp-mode)
+    (insert "(define-flabbergast-test zot ()\n'bar)\n")
+    (goto-char 5)
+    (should (equal (lisp-current-defun-name) "zot")))
+  ;; These tests should probably work after bug#49592 has been fixed.
+  ;; (with-temp-buffer
+  ;;   (emacs-lisp-mode)
+  ;;   (insert "(progn\n ;; comment\n ;; about that\n (define-key ...)\n )")
+  ;;   (goto-char 5)
+  ;;   (should (equal (lisp-current-defun-name) "progn")))
+  ;; (with-temp-buffer
+  ;;   (emacs-lisp-mode)
+  ;;   (insert "(defblarg \"a\" 'b)")
+  ;;   (goto-char 5)
+  ;;   (should (equal (lisp-current-defun-name) "defblarg")))
+  )
+
 (provide 'lisp-mode-tests)
 ;;; lisp-mode-tests.el ends here
diff --git a/test/lisp/emacs-lisp/oclosure-tests.el 
b/test/lisp/emacs-lisp/oclosure-tests.el
index b3a921826b..00b008845c 100644
--- a/test/lisp/emacs-lisp/oclosure-tests.el
+++ b/test/lisp/emacs-lisp/oclosure-tests.el
@@ -69,6 +69,7 @@
     ))
 
 (ert-deftest oclosure-test-limits ()
+  (defvar byte-compile-debug)
   (should
    (condition-case err
        (let ((lexical-binding t)
diff --git a/test/lisp/emacs-lisp/package-tests.el 
b/test/lisp/emacs-lisp/package-tests.el
index d7a55998c2..b903cd781b 100644
--- a/test/lisp/emacs-lisp/package-tests.el
+++ b/test/lisp/emacs-lisp/package-tests.el
@@ -638,6 +638,21 @@ but with a different end of line convention (bug#48137)."
       (package-refresh-contents)
       (should (equal (length package-archive-contents) 2)))))
 
+(ert-deftest package-test-package-installed-p ()
+  "Test package-installed-p before and after package initialization."
+  (with-package-test ()
+    ;; Verify that `package-installed-p' evaluates true for a built-in
+    ;; package, in this case `project', before package initialization.
+    (should (not package--initialized))
+    (should (package-installed-p 'project nil))
+    (should (not (package-installed-p 'imaginary-package nil)))
+
+    ;; The results don't change after package initialization.
+    (package-initialize)
+    (should package--initialized)
+    (should (package-installed-p 'project nil))
+    (should (not (package-installed-p 'imaginary-package nil)))))
+
 (ert-deftest package-test-describe-package ()
   "Test displaying help for a package."
 
diff --git a/test/lisp/emacs-lisp/seq-tests.el 
b/test/lisp/emacs-lisp/seq-tests.el
index 9e5d59163f..1a27467d29 100644
--- a/test/lisp/emacs-lisp/seq-tests.el
+++ b/test/lisp/emacs-lisp/seq-tests.el
@@ -257,6 +257,19 @@ Evaluate BODY for each created sequence.
   (with-test-sequences (seq '())
     (should (equal (seq-uniq seq) '()))))
 
+(defun seq-tests--list-subseq-ref (list start &optional end)
+  "Reference implementation of `seq-subseq' for lists."
+  (let ((len (length list)))
+    (when (< start 0)
+      (setq start (+ start len)))
+    (unless end
+      (setq end len))
+    (when (< end 0)
+      (setq end (+ end len)))
+    (if (<= 0 start end len)
+        (take (- end start) (nthcdr start list))
+      (error "bad args"))))
+
 (ert-deftest test-seq-subseq ()
   (with-test-sequences (seq '(2 3 4 5))
     (should (equal (seq-subseq seq 0 4) seq))
@@ -275,7 +288,21 @@ Evaluate BODY for each created sequence.
   (should-error (seq-subseq [] -1))
   (should-error (seq-subseq "" -1))
   (should-not (seq-subseq '() 0))
-  (should-error (seq-subseq '() 0 -1)))
+  (should-error (seq-subseq '() 0 -1))
+
+  (dolist (list '(() (a b c d)))
+    (ert-info ((prin1-to-string list) :prefix "list: ")
+      (let ((len (length list)))
+        (dolist (start (number-sequence (- -2 len) (+ 2 len)))
+          (ert-info ((prin1-to-string start) :prefix "start: ")
+            (dolist (end (cons nil (number-sequence (- -2 len) (+ 2 len))))
+              (ert-info ((prin1-to-string end) :prefix "end: ")
+                (condition-case res
+                    (seq-tests--list-subseq-ref list start end)
+                  (error
+                   (should-error (seq-subseq list start end)))
+                  (:success
+                   (should (equal (seq-subseq list start end) res))))))))))))
 
 (ert-deftest test-seq-concatenate ()
   (with-test-sequences (seq '(2 4 6))
@@ -511,5 +538,44 @@ Evaluate BODY for each created sequence.
     (should (equal (seq-difference '(1 nil) '(2 nil))
                    '(1)))))
 
+(ert-deftest test-seq-split ()
+  (let ((seq [0 1 2 3 4 5 6 7 8 9 10]))
+    (should (equal seq (car (seq-split seq 20))))
+    (should (equal seq (car (seq-split seq 11))))
+    (should (equal (seq-split seq 10)
+                   '([0 1 2 3 4 5 6 7 8 9] [10])))
+    (should (equal (seq-split seq 5)
+                   '([0 1 2 3 4] [5 6 7 8 9] [10])))
+    (should (equal (seq-split seq 1)
+                   '([0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10])))
+    (should-error (seq-split seq 0))
+    (should-error (seq-split seq -10)))
+  (let ((seq '(0 1 2 3 4 5 6 7 8 9)))
+    (should (equal (seq-split seq 5)
+                   '((0 1 2 3 4) (5 6 7 8 9)))))
+  (let ((seq "0123456789"))
+    (should (equal (seq-split seq 2)
+                   '("01" "23" "45" "67" "89")))
+    (should (equal (seq-split seq 3)
+                   '("012" "345" "678" "9")))))
+
+(ert-deftest test-seq-uniq-list ()
+  (let ((list '(1 2 3)))
+    (should (equal (seq-uniq (append list list)) '(1 2 3))))
+  (let ((list '(1 2 3 2 1)))
+    (should (equal (seq-uniq list) '(1 2 3))))
+  (let ((list (list (substring "1")
+                    (substring "2")
+                    (substring "3")
+                    (substring "2")
+                    (substring "1"))))
+    (should (equal (seq-uniq list) '("1" "2" "3")))
+    (should (equal (seq-uniq list #'eq) '("1" "2" "3" "2" "1"))))
+  ;; Long lists have a different code path.
+  (let ((list (seq-map-indexed (lambda (_ i) i)
+                              (make-list 10000 nil))))
+    (should (= (length list) 10000))
+    (should (= (length (seq-uniq (append list list))) 10000))))
+
 (provide 'seq-tests)
 ;;; seq-tests.el ends here
diff --git a/test/lisp/emacs-lisp/subr-x-tests.el 
b/test/lisp/emacs-lisp/subr-x-tests.el
index 7f3916c2c0..7a3efe9db6 100644
--- a/test/lisp/emacs-lisp/subr-x-tests.el
+++ b/test/lisp/emacs-lisp/subr-x-tests.el
@@ -607,21 +607,36 @@
   (should (equal (string-limit "foó" 4 nil 'utf-8) "fo\303\263"))
   (should (equal (string-limit "foóa" 4 nil 'utf-8) "fo\303\263"))
   (should (equal (string-limit "foóá" 4 nil 'utf-8) "fo\303\263"))
+  (should (equal (string-limit "foóá" 2 nil 'utf-8-with-signature)
+                 ""))
   (should (equal (string-limit "foóá" 4 nil 'utf-8-with-signature)
-                 "fo\303\263"))
+                 "\357\273\277f"))
   (should (equal (string-limit "foóa" 4 nil 'iso-8859-1) "fo\363a"))
   (should (equal (string-limit "foóá" 4 nil 'iso-8859-1) "fo\363\341"))
-  (should (equal (string-limit "foóá" 4 nil 'utf-16) "\000f\000o"))
+  (should (equal (string-limit "foóá" 3 nil 'utf-16) ""))
+  (should (equal (string-limit "foóá" 6 nil 'utf-16) "\376\377\000f\000o"))
 
   (should (equal (string-limit "foó" 10 t 'utf-8) "fo\303\263"))
   (should (equal (string-limit "foó" 3 t 'utf-8) "o\303\263"))
   (should (equal (string-limit "foó" 4 t 'utf-8) "fo\303\263"))
   (should (equal (string-limit "foóa" 4 t 'utf-8) "o\303\263a"))
   (should (equal (string-limit "foóá" 4 t 'utf-8) "\303\263\303\241"))
-  (should (equal (string-limit "foóá" 2 t 'utf-8-with-signature) "\303\241"))
+  (should (equal (string-limit "foóá" 2 t 'utf-8-with-signature)
+                 ""))
   (should (equal (string-limit "foóa" 4 t 'iso-8859-1) "fo\363a"))
   (should (equal (string-limit "foóá" 4 t 'iso-8859-1) "fo\363\341"))
-  (should (equal (string-limit "foóá" 4 t 'utf-16) "\000\363\000\341")))
+  (should (equal (string-limit "foóá" 6 t 'utf-16) 
"\376\377\000\363\000\341")))
+
+(ert-deftest subr-string-limit-glyphs ()
+  (should (equal (encode-coding-string "Hello, 👼🏻🧑🏼‍🤝‍🧑🏻" 'utf-8)
+                 "Hello, 
\360\237\221\274\360\237\217\273\360\237\247\221\360\237\217\274\342\200\215\360\237\244\235\342\200\215\360\237\247\221\360\237\217\273"))
+  (should (= (length (encode-coding-string "Hello, 👼🏻🧑🏼‍🤝‍🧑🏻" 'utf-8)) 41))
+  (should (equal (string-limit "Hello, 👼🏻🧑🏼‍🤝‍🧑🏻" 100 nil 'utf-8)
+                 "Hello, 
\360\237\221\274\360\237\217\273\360\237\247\221\360\237\217\274\342\200\215\360\237\244\235\342\200\215\360\237\247\221\360\237\217\273"))
+  (should (equal (string-limit "Hello, 👼🏻🧑🏼‍🤝‍🧑🏻" 15 nil 'utf-8)
+                 "Hello, \360\237\221\274\360\237\217\273"))
+  (should (equal (string-limit "Hello, 👼🏻🧑🏼‍🤝‍🧑🏻" 10 nil 'utf-8)
+                 "Hello, ")))
 
 (ert-deftest subr-string-lines ()
   (should (equal (string-lines "foo") '("foo")))
@@ -743,6 +758,18 @@
           (with-current-buffer inner
             (should-not (buffer-modified-p))))))))
 
+(ert-deftest subr-x--hash-table-keys-and-values ()
+  (let ((h (make-hash-table)))
+    (puthash 'a 1 h)
+    (puthash 'c 3 h)
+    (puthash 'b 2 h)
+    (should (equal (sort (hash-table-keys h) #'string<) '(a b c)))
+    (should (equal (sort (hash-table-values h) #'<) '(1 2 3)))))
+
+(ert-deftest test-string-truncate-left ()
+  (should (equal (string-truncate-left "band" 3) "...d"))
+  (should (equal (string-truncate-left "band" 2) "...d"))
+  (should (equal (string-truncate-left "longstring" 8) "...tring")))
 
 (provide 'subr-x-tests)
 ;;; subr-x-tests.el ends here
diff --git a/test/lisp/emacs-lisp/syntax-tests.el 
b/test/lisp/emacs-lisp/syntax-tests.el
index 53812c0c80..f266db5c70 100644
--- a/test/lisp/emacs-lisp/syntax-tests.el
+++ b/test/lisp/emacs-lisp/syntax-tests.el
@@ -60,8 +60,4 @@
   (should-error
    (syntax-propertize--shift-groups-and-backrefs "\\(a\\)\\3" 7)))
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; syntax-tests.el ends here.
diff --git a/test/lisp/emacs-lisp/text-property-search-tests.el 
b/test/lisp/emacs-lisp/text-property-search-tests.el
index d137572f30..98fdd55e85 100644
--- a/test/lisp/emacs-lisp/text-property-search-tests.el
+++ b/test/lisp/emacs-lisp/text-property-search-tests.el
@@ -156,20 +156,19 @@
 
 ;;;; Position after search.
 
-(defun text-property-search--pos-test (fun pos &optional reverse)
+(ert-deftest text-property-search-forward/point-at-beginning ()
   (with-temp-buffer
-    (insert (concat "foo "
-                  (propertize "bar" 'x t)
-                  " baz"))
-    (goto-char (if reverse (point-max) (point-min)))
-    (funcall fun 'x t)
-    (should (= (point) pos))))
-
-(ert-deftest text-property-search-forward-point-at-beginning ()
-  (text-property-search--pos-test #'text-property-search-forward 5))
-
-(ert-deftest text-property-search-backward-point-at-end ()
-  (text-property-search--pos-test #'text-property-search-backward 8 t))
+    (insert (concat "1234" (propertize "567" 'x t) "890"))
+    (goto-char (point-min))
+    (text-property-search-forward 'x t)
+    (should (= (point) 5))))
+
+(ert-deftest text-property-search-backward/point-at-end ()
+  (with-temp-buffer
+    (insert (concat "1234" (propertize "567" 'x t) "890"))
+    (goto-char (point-max))
+    (text-property-search-backward 'x t)
+    (should (= (point) 8))))
 
 (provide 'text-property-search-tests)
 
diff --git a/test/lisp/env-tests.el b/test/lisp/env-tests.el
new file mode 100644
index 0000000000..fd3d3cb273
--- /dev/null
+++ b/test/lisp/env-tests.el
@@ -0,0 +1,40 @@
+;;; env-tests.el --- Tests for env.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 'env)
+(require 'ert)
+
+(ert-deftest test-substitute-env-in-file-name ()
+  (should (equal (substitute-env-in-file-name "foo_${HOME}_bar")
+                 (concat "foo_" (getenv "HOME") "_bar"))))
+
+(ert-deftest test-getenv-setenv ()
+  (should (equal (setenv "EMACS_ENV_EL_TEST_VAR" "foobar") "foobar"))
+  (should (equal (getenv "EMACS_ENV_EL_TEST_VAR") "foobar"))
+  (should-not (getenv "LIKELY_TO_BE_NON_EXISTENT_FOO_BAR_BAZ")))
+
+(ert-deftest test-with-environment-variables ()
+  (let ((A "TEST") (B "/foo/bar"))
+    (with-environment-variables ((A B))
+      (should (equal (getenv A) B)))))
+
+(provide 'env-tests)
+;;; env-tests.el ends here
diff --git a/test/lisp/erc/erc-join-tests.el b/test/lisp/erc/erc-join-tests.el
new file mode 100644
index 0000000000..8210defbfb
--- /dev/null
+++ b/test/lisp/erc/erc-join-tests.el
@@ -0,0 +1,361 @@
+;;; erc-join-tests.el --- Tests for erc-join.  -*- lexical-binding:t -*-
+
+;; Copyright (C) 2020-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)
+(require 'erc-join)
+(require 'erc-networks)
+
+(ert-deftest erc-autojoin-channels--connect ()
+  (should (eq erc-autojoin-timing 'connect))
+  (should (= erc-autojoin-delay 30))
+  (should-not erc--autojoin-timer)
+
+  (let (calls
+        common
+        erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook)
+
+    (cl-letf (((symbol-function 'erc-server-send)
+               (lambda (line) (push line calls))))
+
+      (setq common
+            (lambda ()
+              (ert-with-test-buffer (:name "foonet")
+                (erc-mode)
+                (setq erc-server-process
+                      (start-process "true" (current-buffer) "true")
+                      erc-network 'FooNet
+                      erc-session-server "irc.gnu.chat"
+                      erc-server-current-nick "tester"
+                      erc-networks--id (erc-networks--id-create nil)
+                      erc-server-announced-name "foo.gnu.chat")
+                (set-process-query-on-exit-flag erc-server-process nil)
+                (erc-autojoin-channels erc-server-announced-name
+                                       "tester")
+                (should-not erc--autojoin-timer))))
+
+      (ert-info ("Join immediately on connect; server")
+        (let ((erc-autojoin-channels-alist '(("\\.gnu\\.chat\\'" "#chan"))))
+          (funcall common))
+        (should (equal (pop calls) "JOIN #chan")))
+
+      (ert-info ("Join immediately on connect; network")
+        (let ((erc-autojoin-channels-alist '((FooNet "#chan"))))
+          (funcall common))
+        (should (equal (pop calls) "JOIN #chan")))
+
+      (ert-info ("Do nothing; server")
+        (let ((erc-autojoin-channels-alist '(("bar\\.gnu\\.chat" "#chan"))))
+          (funcall common))
+        (should-not calls))
+
+      (ert-info ("Do nothing; network")
+        (let ((erc-autojoin-channels-alist '((BarNet "#chan"))))
+          (funcall common))
+        (should-not calls)))))
+
+(ert-deftest erc-autojoin-channels--delay ()
+  (should (eq erc-autojoin-timing 'connect))
+  (should (= erc-autojoin-delay 30))
+  (should-not erc--autojoin-timer)
+
+  (let (calls
+        common
+        erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook
+        (erc-autojoin-timing 'ident)
+        (erc-autojoin-delay 0.05))
+
+    (cl-letf (((symbol-function 'erc-server-send)
+               (lambda (line) (push line calls)))
+              ((symbol-function 'erc-autojoin-after-ident)
+               (lambda (&rest _r) (error "I ran but shouldn't have"))))
+
+      (setq common
+            (lambda ()
+              (ert-with-test-buffer (:name "foonet")
+                (erc-mode)
+                (setq erc-server-process
+                      (start-process "true" (current-buffer) "true")
+                      erc-network 'FooNet
+                      erc-session-server "irc.gnu.chat"
+                      erc-server-current-nick "tester"
+                      erc-networks--id (erc-networks--id-create nil)
+                      erc-server-announced-name "foo.gnu.chat")
+                (set-process-query-on-exit-flag erc-server-process nil)
+                (should-not erc--autojoin-timer)
+                (erc-autojoin-channels erc-server-announced-name "tester")
+                (should erc--autojoin-timer)
+                (should-not calls)
+                (sleep-for 0.1))))
+
+      (ert-info ("Deferred on connect; server")
+        (let ((erc-autojoin-channels-alist '(("\\.gnu\\.chat\\'" "#chan"))))
+          (funcall common))
+        (should (equal (pop calls) "JOIN #chan")))
+
+      (ert-info ("Deferred on connect; network")
+        (let ((erc-autojoin-channels-alist '((FooNet "#chan"))))
+          (funcall common))
+        (should (equal (pop calls) "JOIN #chan")))
+
+      (ert-info ("Do nothing; server")
+        (let ((erc-autojoin-channels-alist '(("bar\\.gnu\\.chat" "#chan"))))
+          (funcall common))
+        (should-not calls)))))
+
+(ert-deftest erc-autojoin-channels--ident ()
+  (should (eq erc-autojoin-timing 'connect))
+  (should (= erc-autojoin-delay 30))
+  (should-not erc--autojoin-timer)
+
+  (let (calls
+        common
+        erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook
+        (erc-autojoin-timing 'ident))
+
+    (cl-letf (((symbol-function 'erc-server-send)
+               (lambda (line) (push line calls))))
+
+      (setq common
+            (lambda ()
+              (ert-with-test-buffer (:name "foonet")
+                (erc-mode)
+                (setq erc-server-process
+                      (start-process "true" (current-buffer) "true")
+                      erc-network 'FooNet
+                      erc-server-current-nick "tester"
+                      erc-networks--id (erc-networks--id-create nil)
+                      erc-server-announced-name "foo.gnu.chat")
+                (set-process-query-on-exit-flag erc-server-process nil)
+                (erc-autojoin-after-ident 'FooNet "tester")
+                (should-not erc--autojoin-timer))))
+
+      (ert-info ("Join on NickServ hook; server")
+        (let ((erc-autojoin-channels-alist '(("\\.gnu\\.chat\\'" "#chan"))))
+          (funcall common))
+        (should (equal (pop calls) "JOIN #chan")))
+
+      (ert-info ("Join on NickServ hook; network")
+        (let ((erc-autojoin-channels-alist '((FooNet "#chan"))))
+          (funcall common))
+        (should (equal (pop calls) "JOIN #chan"))))))
+
+(defun erc-join-tests--autojoin-add--common (setup &optional fwd)
+  (let (calls
+        erc-autojoin-channels-alist
+        erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook)
+
+    (cl-letf (((symbol-function 'erc-handle-parsed-server-response)
+               (lambda (_p m) (push m calls))))
+
+      (ert-with-test-buffer (:name "foonet")
+        (erc-mode)
+        (setq erc-server-process
+              (start-process "true" (current-buffer) "true")
+              erc-server-current-nick "tester"
+              erc--isupport-params (make-hash-table)
+              erc-server-announced-name "foo.gnu.chat")
+        (puthash 'CHANTYPES '("&#") erc--isupport-params)
+        (funcall setup)
+        (set-process-query-on-exit-flag erc-server-process nil)
+        (should-not calls)
+
+        (ert-info ("Add #chan")
+          (erc-parse-server-response erc-server-process
+                                     (concat ":tester!~i@c.u JOIN #chan"
+                                             (and fwd " * :Tes Ter")))
+          (should calls)
+          (erc-autojoin-add erc-server-process (pop calls))
+          (should (equal erc-autojoin-channels-alist '((FooNet "#chan")))))
+
+        (ert-info ("More recently joined chans are prepended")
+          (erc-parse-server-response
+           erc-server-process ; with account username
+           (concat ":tester!~i@c.u JOIN #spam" (and fwd " tester :Tes Ter")))
+          (should calls)
+          (erc-autojoin-add erc-server-process (pop calls))
+          (should (equal erc-autojoin-channels-alist
+                         '((FooNet "#spam" "#chan")))))
+
+        (ert-info ("Duplicates skipped")
+          (erc-parse-server-response erc-server-process
+                                     (concat ":tester!~i@c.u JOIN #chan"
+                                             (and fwd " * :Tes Ter")))
+          (should calls)
+          (erc-autojoin-add erc-server-process (pop calls))
+          (should (equal erc-autojoin-channels-alist
+                         '((FooNet "#spam" "#chan")))))
+
+        (ert-info ("Server used for local channel")
+          (erc-parse-server-response erc-server-process
+                                     (concat ":tester!~i@c.u JOIN &local"
+                                             (and fwd " * :Tes Ter")))
+          (should calls)
+          (erc-autojoin-add erc-server-process (pop calls))
+          (should (equal erc-autojoin-channels-alist
+                         '(("foo\\.gnu\\.chat" "&local")
+                           (FooNet "#spam" "#chan")))))))))
+
+(ert-deftest erc-autojoin-add--network ()
+  (erc-join-tests--autojoin-add--common
+   (lambda () (setq erc-network 'FooNet
+                    erc-networks--id (erc-networks--id-create nil)))))
+
+(ert-deftest erc-autojoin-add--network-extended-syntax ()
+  (erc-join-tests--autojoin-add--common
+   (lambda () (setq erc-network 'FooNet
+                    erc-networks--id (erc-networks--id-create nil)))
+   'forward-compatible))
+
+(ert-deftest erc-autojoin-add--network-id ()
+  (erc-join-tests--autojoin-add--common
+   (lambda () (setq erc-network 'invalid
+                    erc-networks--id (erc-networks--id-create 'FooNet)))))
+
+(ert-deftest erc-autojoin-add--server ()
+  (let (calls
+        erc-autojoin-channels-alist
+        erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook)
+
+    (cl-letf (((symbol-function 'erc-handle-parsed-server-response)
+               (lambda (_p m) (push m calls))))
+
+      (ert-info ("Network unavailable, announced name used")
+        (setq erc-autojoin-channels-alist nil)
+        (ert-with-test-buffer (:name "foonet")
+          (erc-mode)
+          (setq erc-server-process
+                (start-process "true" (current-buffer) "true")
+                erc-server-current-nick "tester"
+                erc-server-announced-name "foo.gnu.chat"
+                erc-networks--id (make-erc-networks--id)) ; assume too early
+          (set-process-query-on-exit-flag erc-server-process nil)
+          (should-not calls)
+          (erc-parse-server-response erc-server-process
+                                     ":tester!~u@q6ddatxcq6txy.irc JOIN #chan")
+          (should calls)
+          (erc-autojoin-add erc-server-process (pop calls))
+          (should (equal erc-autojoin-channels-alist
+                         '(("gnu.chat" "#chan")))))))))
+
+(defun erc-join-tests--autojoin-remove--common (setup)
+  (let (calls
+        erc-autojoin-channels-alist
+        erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook)
+
+    (cl-letf (((symbol-function 'erc-handle-parsed-server-response)
+               (lambda (_p m) (push m calls))))
+
+      (setq erc-autojoin-channels-alist ; mutated, so can't quote whole thing
+            (list '(FooNet "#spam" "##chan")
+                  '(BarNet "#bar" "##bar")
+                  '("foo\\.gnu\\.chat" "&local")))
+
+      (ert-with-test-buffer (:name "foonet")
+        (erc-mode)
+        (setq erc-server-process
+              (start-process "true" (current-buffer) "true")
+              erc-server-current-nick "tester"
+              erc--isupport-params (make-hash-table)
+              erc-server-announced-name "foo.gnu.chat")
+        (puthash 'CHANTYPES '("&#") erc--isupport-params)
+        (funcall setup)
+        (set-process-query-on-exit-flag erc-server-process nil)
+        (should-not calls)
+
+        (ert-info ("Remove #chan")
+          (erc-parse-server-response erc-server-process
+                                     ":tester!~i@c.u PART ##chan")
+          (should calls)
+          (erc-autojoin-remove erc-server-process (pop calls))
+          (should (equal erc-autojoin-channels-alist
+                         '((FooNet "#spam")
+                           (BarNet "#bar" "##bar")
+                           ("foo\\.gnu\\.chat" "&local")))))
+
+        (ert-info ("Wrong network, nothing done")
+          (erc-parse-server-response erc-server-process
+                                     ":tester!~i@c.u PART #bar")
+          (should calls)
+          (erc-autojoin-remove erc-server-process (pop calls))
+          (should (equal erc-autojoin-channels-alist
+                         '((FooNet "#spam")
+                           (BarNet "#bar" "##bar")
+                           ("foo\\.gnu\\.chat" "&local")))))
+
+        (ert-info ("Local channel keyed by server found")
+          (erc-parse-server-response erc-server-process
+                                     ":tester!~i@c.u PART &local")
+          (should calls)
+          (erc-autojoin-remove erc-server-process (pop calls))
+          (should (equal erc-autojoin-channels-alist
+                         '((FooNet "#spam") (BarNet "#bar" "##bar")))))))))
+
+(ert-deftest erc-autojoin-remove--network ()
+  (erc-join-tests--autojoin-remove--common
+   (lambda () (setq erc-network 'FooNet
+                    erc-networks--id (erc-networks--id-create nil)))))
+
+(ert-deftest erc-autojoin-remove--network-id ()
+  (erc-join-tests--autojoin-remove--common
+   (lambda () (setq erc-network 'fake-a-roo
+                    erc-networks--id (erc-networks--id-create 'FooNet)))))
+
+(ert-deftest erc-autojoin-remove--server ()
+  (let (calls
+        erc-autojoin-channels-alist
+        erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook)
+
+    (cl-letf (((symbol-function 'erc-handle-parsed-server-response)
+               (lambda (_p m) (push m calls))))
+
+      (setq erc-autojoin-channels-alist (list '("gnu.chat" "#spam" "##chan")
+                                              '("fsf.chat" "#bar" "##bar")))
+
+      (ert-with-test-buffer (:name "foonet")
+        (erc-mode)
+        (setq erc-server-process
+              (start-process "true" (current-buffer) "true")
+              erc-server-current-nick "tester"
+              erc-server-announced-name "foo.gnu.chat"
+              ;; Assume special case w/o known network
+              erc-networks--id (make-erc-networks--id))
+        (set-process-query-on-exit-flag erc-server-process nil)
+        (should-not calls)
+
+        (ert-info ("Announced name matched, #chan removed")
+          (erc-parse-server-response erc-server-process
+                                     ":tester!~i@c.u PART ##chan")
+          (should calls)
+          (erc-autojoin-remove erc-server-process (pop calls))
+          (should (equal erc-autojoin-channels-alist
+                         '(("gnu.chat" "#spam")
+                           ("fsf.chat" "#bar" "##bar")))))
+
+        (ert-info ("Wrong announced name, nothing done")
+          (erc-parse-server-response erc-server-process
+                                     ":tester!~i@c.u PART #bar")
+          (should calls)
+          (erc-autojoin-remove erc-server-process (pop calls))
+          (should (equal erc-autojoin-channels-alist
+                         '(("gnu.chat" "#spam")
+                           ("fsf.chat" "#bar" "##bar")))))))))
+
+;;; erc-join-tests.el ends here
diff --git a/test/lisp/erc/erc-networks-tests.el 
b/test/lisp/erc/erc-networks-tests.el
new file mode 100644
index 0000000000..66a334b709
--- /dev/null
+++ b/test/lisp/erc/erc-networks-tests.el
@@ -0,0 +1,1707 @@
+;;; erc-networks-tests.el --- Tests for erc-networks.  -*- lexical-binding:t 
-*-
+
+;; Copyright (C) 2020-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) ; cl-lib
+(require 'erc-networks)
+
+(defun erc-networks-tests--create-dead-proc (&optional buf)
+  (let ((p (start-process "true" (or buf (current-buffer)) "true")))
+    (while (process-live-p p) (sit-for 0.1))
+    p))
+
+(defun erc-networks-tests--create-live-proc (&optional buf)
+  (let ((proc (start-process "sleep" (or buf (current-buffer)) "sleep" "1")))
+    (set-process-query-on-exit-flag proc nil)
+    proc))
+
+;; When we drop 27, call `get-buffer-create with INHIBIT-BUFFER-HOOKS.
+(defun erc-networks-tests--clean-bufs ()
+  (let (erc-kill-channel-hook
+        erc-kill-server-hook
+        erc-kill-buffer-hook)
+    (dolist (buf (erc-buffer-list))
+      (kill-buffer buf))))
+
+(defun erc-networks-tests--bufnames (prefix)
+  (let* ((case-fold-search)
+         (pred (lambda (b) (string-prefix-p prefix (buffer-name b))))
+         (prefixed (seq-filter pred (buffer-list))))
+    (sort (mapcar #'buffer-name prefixed) #'string<)))
+
+(ert-deftest erc-networks--id ()
+  (cl-letf (((symbol-function 'float-time)
+             (lambda (&optional _) 0.0)))
+
+    ;; Fixed
+    (should (equal (erc-networks--id-fixed-create 'foo)
+                   (make-erc-networks--id-fixed :ts (float-time)
+                                                :symbol 'foo)))
+
+    ;; Eliding
+    (let* ((erc-network 'FooNet)
+           (erc-server-current-nick "Joe")
+           (identity (erc-networks--id-create nil)))
+
+      (should (equal identity #s(erc-networks--id-qualifying
+                                 0.0 FooNet [FooNet "joe"] 1)))
+      (should (equal (erc-networks--id-qualifying-grow-id identity)
+                     'FooNet/joe))
+      (should (equal identity #s(erc-networks--id-qualifying
+                                 0.0 FooNet/joe [FooNet "joe"] 2)))
+      (should-not (erc-networks--id-qualifying-grow-id identity))
+      (should (equal identity #s(erc-networks--id-qualifying
+                                 0.0 FooNet/joe [FooNet "joe"] 2))))
+
+    ;; Compat
+    (with-current-buffer (get-buffer-create "fake.chat")
+      (with-suppressed-warnings ((obsolete erc-rename-buffers))
+        (let (erc-rename-buffers)
+          (should (equal (erc-networks--id-create nil)
+                         (make-erc-networks--id-fixed :ts (float-time)
+                                                      :symbol 'fake.chat)))))
+      (kill-buffer))))
+
+(ert-deftest erc-networks--id-create ()
+  (cl-letf (((symbol-function 'float-time)
+             (lambda (&optional _) 0.0)))
+
+    (should (equal (erc-networks--id-create 'foo)
+                   (make-erc-networks--id-fixed :ts (float-time)
+                                                :symbol 'foo)))
+    (should (equal (erc-networks--id-create "foo")
+                   (make-erc-networks--id-fixed :ts (float-time)
+                                                :symbol 'foo)))
+    (should (equal (erc-networks--id-create [h i])
+                   (make-erc-networks--id-fixed :ts (float-time)
+                                                :symbol (quote \[h\ \i\]))))
+
+    (with-current-buffer (get-buffer-create "foo")
+      (let ((expected (make-erc-networks--id-fixed :ts (float-time)
+                                                   :symbol 'foo)))
+        (with-suppressed-warnings ((obsolete erc-rename-buffers))
+          (let (erc-rename-buffers)
+            (should (equal (erc-networks--id-create nil) expected))))
+        (with-suppressed-warnings ((obsolete erc-reuse-buffers))
+          (let (erc-reuse-buffers)
+            (should (equal (erc-networks--id-create nil) expected))
+            (should (equal (erc-networks--id-create 'bar) expected)))))
+      (kill-buffer))))
+
+(ert-deftest erc-networks--id-qualifying-prefix-length ()
+  (should-not (erc-networks--id-qualifying-prefix-length
+               (make-erc-networks--id-qualifying)
+               (make-erc-networks--id-qualifying)))
+
+  (should-not (erc-networks--id-qualifying-prefix-length
+               (make-erc-networks--id-qualifying :parts [1 2])
+               (make-erc-networks--id-qualifying :parts [2 3])))
+
+  (should (= 1 (erc-networks--id-qualifying-prefix-length
+                (make-erc-networks--id-qualifying :parts [1])
+                (make-erc-networks--id-qualifying :parts [1 2]))))
+
+  (should (= 1 (erc-networks--id-qualifying-prefix-length
+                (make-erc-networks--id-qualifying :parts [1 2])
+                (make-erc-networks--id-qualifying :parts [1 3]))))
+
+  (should (= 2 (erc-networks--id-qualifying-prefix-length
+                (make-erc-networks--id-qualifying :parts [1 2])
+                (make-erc-networks--id-qualifying :parts [1 2]))))
+
+  (should (= 1 (erc-networks--id-qualifying-prefix-length
+                (make-erc-networks--id-qualifying :parts ["1"])
+                (make-erc-networks--id-qualifying :parts ["1"])))))
+
+(ert-deftest erc-networks--id-sort-buffers ()
+  (let (oldest middle newest)
+
+    (with-temp-buffer
+      (setq erc-networks--id (erc-networks--id-fixed-create 'oldest)
+            oldest (current-buffer))
+
+      (with-temp-buffer
+        (setq erc-networks--id (erc-networks--id-fixed-create 'middle)
+              middle (current-buffer))
+
+        (with-temp-buffer
+          (setq erc-networks--id (erc-networks--id-fixed-create 'newest)
+                newest (current-buffer))
+
+          (should (equal (erc-networks--id-sort-buffers
+                          (list oldest newest middle))
+                         (list newest middle oldest))))))))
+
+(ert-deftest erc-networks-rename-surviving-target-buffer--channel ()
+  (should (memq #'erc-networks-rename-surviving-target-buffer
+                erc-kill-channel-hook))
+
+  (let ((chan-foonet-buffer (get-buffer-create "#chan@foonet")))
+
+    (with-current-buffer chan-foonet-buffer
+      (erc-mode)
+      (setq erc-networks--id (make-erc-networks--id-qualifying
+                              :parts [foonet "bob"] :len 1)
+            erc--target (erc--target-from-string "#chan")))
+
+    (with-current-buffer (get-buffer-create "#chan@barnet")
+      (erc-mode)
+      (setq erc-networks--id (make-erc-networks--id-qualifying
+                              :parts [barnet "bob"] :len 1)
+            erc--target (erc--target-from-string "#chan")))
+
+    (kill-buffer "#chan@barnet")
+    (should (equal (erc-networks-tests--bufnames "#chan") '("#chan")))
+    (should (eq chan-foonet-buffer (get-buffer "#chan"))))
+
+  (erc-networks-tests--clean-bufs))
+
+(ert-deftest erc-networks-rename-surviving-target-buffer--query ()
+  (should (memq #'erc-networks-rename-surviving-target-buffer
+                erc-kill-buffer-hook))
+
+  (let ((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 (equal (erc-networks-tests--bufnames "bob") '("bob")))
+    (should (eq bob-foonet (get-buffer "bob"))))
+
+  (erc-networks-tests--clean-bufs))
+
+(ert-deftest erc-networks-rename-surviving-target-buffer--multi ()
+
+  (ert-info ("Multiple leftover channels untouched")
+    (with-current-buffer (get-buffer-create "#chan@foonet")
+      (erc-mode)
+      (setq erc--target (erc--target-from-string "#chan")))
+    (with-current-buffer (get-buffer-create "#chan@barnet")
+      (erc-mode)
+      (setq erc--target (erc--target-from-string "#chan")))
+    (with-current-buffer (get-buffer-create "#chan@baznet")
+      (erc-mode)
+      (setq erc--target (erc--target-from-string "#chan")))
+    (kill-buffer "#chan@baznet")
+    (should (equal (erc-networks-tests--bufnames "#chan")
+                   '("#chan@barnet" "#chan@foonet")))
+    (erc-networks-tests--clean-bufs))
+
+  (ert-info ("Multiple leftover queries untouched")
+    (with-current-buffer (get-buffer-create "bob@foonet")
+      (erc-mode)
+      (setq erc--target (erc--target-from-string "bob")))
+    (with-current-buffer (get-buffer-create "bob@barnet")
+      (erc-mode)
+      (setq erc--target (erc--target-from-string "bob")))
+    (with-current-buffer (get-buffer-create "bob@baznet")
+      (erc-mode)
+      (setq erc--target (erc--target-from-string "bob")))
+    (kill-buffer "bob@baznet")
+    (should (equal (erc-networks-tests--bufnames "bob")
+                   '("bob@barnet" "bob@foonet")))
+    (erc-networks-tests--clean-bufs)))
+
+;; As of May 2022, this "shrink" stuff runs whenever an ERC buffer is
+;; killed because `erc-networks-shrink-ids-and-buffer-names' is a
+;; default member of all three erc-kill-* functions.
+
+;; Note: this overlaps a fair bit with the "hook" variants, i.e.,
+;; `erc-networks--shrink-ids-and-buffer-names--hook-outstanding-*' If
+;; this ever fails, just delete this and fix those.  But please copy
+;; over and adapt the comments first.
+
+(ert-deftest erc-networks--shrink-ids-and-buffer-names--perform-outstanding ()
+  ;; While some buffer #a@barnet/dummy is being killed, its display ID
+  ;; is not collapsed because collisions still exist.
+  ;;
+  ;; Note that we don't have to set `erc-server-connected' because
+  ;; this function is intentionally connectivity agnostic.
+  (with-current-buffer (get-buffer-create "foonet/tester")
+    (erc-mode)
+    (setq erc-server-current-nick "tester" ; Always set (`erc-open')
+          ;; Set when transport connected
+          erc-server-process (erc-networks-tests--create-live-proc)
+          ;; Both set just before IRC (logically) connected (post MOTD)
+          erc-network 'foonet
+          erc-networks--id (make-erc-networks--id-qualifying
+                            :symbol 'foonet/tester
+                            :parts [foonet "tester"]
+                            :len 2))) ; is/was a plain foonet collision
+
+  ;; Presumably, some server buffer named foonet/dummy was just
+  ;; killed, hence the length 2 display ID.
+
+  ;; A target buffer for chan #a exists for foonet/tester.  The
+  ;; precise form of its name should not affect shrinking.
+  (with-current-buffer (get-buffer-create
+                        (elt ["#a" "#a@foonet" "#a@foonet/tester"] (random 3)))
+    (erc-mode)
+    (setq erc-server-process (buffer-local-value 'erc-server-process
+                                                 (get-buffer "foonet/tester"))
+          erc-network 'foonet
+          erc-server-current-nick "tester"
+          erc-networks--id (buffer-local-value 'erc-networks--id
+                                               (get-buffer "foonet/tester"))
+          erc--target (erc--target-from-string "#a")))
+
+  ;; Another network context exists (so we have buffers to iterate
+  ;; over), and it's also part of a collision group.
+  (with-current-buffer (get-buffer-create "barnet/tester")
+    (erc-mode)
+    (setq erc-network 'barnet
+          erc-server-current-nick "tester"
+          erc-networks--id (make-erc-networks--id-qualifying
+                            :symbol 'barnet/tester
+                            :parts [barnet "tester"]
+                            :len 2)
+          erc-server-process (erc-networks-tests--create-live-proc)))
+
+  (with-current-buffer (get-buffer-create "barnet/dummy")
+    (erc-mode)
+    (setq erc-network 'barnet
+          erc-server-current-nick "dummy"
+          erc-networks--id (make-erc-networks--id-qualifying
+                            :symbol 'barnet/dummy
+                            :parts [barnet "dummy"]
+                            :len 2)
+          erc-server-process (erc-networks-tests--create-live-proc)))
+
+  ;; The buffer being killed is not part of the foonet collision
+  ;; group, which contains one display ID eligible for shrinkage.
+  (with-current-buffer (get-buffer-create
+                        (elt ["#a@barnet" "#a@barnet/tester"] (random 2)))
+    (erc-mode)
+    (setq erc-network 'barnet
+          erc-server-current-nick "tester"
+          erc-server-process (buffer-local-value 'erc-server-process
+                                                 (get-buffer "barnet/tester"))
+          erc-networks--id (buffer-local-value 'erc-networks--id
+                                               (get-buffer "barnet/tester"))
+          erc--target (erc--target-from-string "#a")))
+
+  (with-temp-buffer ; doesn't matter what the current buffer is
+    (setq erc-networks--id (make-erc-networks--id-qualifying)) ; mock
+    (erc-networks--shrink-ids-and-buffer-names))
+
+  (should (equal (mapcar #'buffer-name (erc-buffer-list))
+                 '("foonet" ; shrunk
+                   "#a@foonet" ; shrunk
+                   "barnet/tester"
+                   "barnet/dummy"
+                   "#a@barnet/tester")))
+
+  (erc-networks-tests--clean-bufs))
+
+;; This likewise overlaps with the "hook" variants below.  If this
+;; should ever fail, just delete it and optionally fix those.
+
+(ert-deftest erc-networks--shrink-ids-and-buffer-names--perform-collapse ()
+  ;; This is similar to the "outstanding" variant above, but both
+  ;; groups are eligible for renaming, which is abnormal but possible
+  ;; when recovering from some mishap.
+  (with-current-buffer (get-buffer-create "foonet/tester")
+    (erc-mode)
+    (setq erc-network 'foonet
+          erc-server-current-nick "tester"
+          erc-networks--id (make-erc-networks--id-qualifying
+                            :symbol 'foonet/tester
+                            :parts [foonet "tester"]
+                            :len 2)
+          erc-server-process (erc-networks-tests--create-live-proc)))
+
+  (with-current-buffer
+      (get-buffer-create (elt ["#a" "#a@foonet/tester"] (random 2)))
+    (erc-mode)
+    (setq erc-server-process (buffer-local-value 'erc-server-process
+                                                 (get-buffer "foonet/tester"))
+          erc-network 'foonet
+          erc-server-current-nick "tester"
+          erc-networks--id (buffer-local-value 'erc-networks--id
+                                               (get-buffer "foonet/tester"))
+          erc--target (erc--target-from-string "#a")))
+
+  (with-current-buffer (get-buffer-create "barnet/tester")
+    (erc-mode)
+    (setq erc-network 'barnet
+          erc-server-current-nick "tester"
+          erc-networks--id (make-erc-networks--id-qualifying
+                            :symbol 'barnet/tester
+                            :parts [barnet "tester"]
+                            :len 2)
+          erc-server-process (erc-networks-tests--create-live-proc)))
+
+  (with-current-buffer
+      (get-buffer-create (elt ["#b" "#b@foonet/tester"] (random 2)))
+    (erc-mode)
+    (setq erc-network 'barnet
+          erc-server-current-nick "tester"
+          erc-server-process (buffer-local-value 'erc-server-process
+                                                 (get-buffer "barnet/tester"))
+          erc-networks--id (buffer-local-value 'erc-networks--id
+                                               (get-buffer "barnet/tester"))
+          erc--target (erc--target-from-string "#b")))
+
+  (with-temp-buffer
+    (setq erc-networks--id (make-erc-networks--id-qualifying))
+    (erc-networks--shrink-ids-and-buffer-names))
+
+  (should (equal (mapcar #'buffer-name (erc-buffer-list))
+                 '("foonet" "#a" "barnet" "#b")))
+
+  (erc-networks-tests--clean-bufs))
+
+(defun erc-networks--shrink-ids-and-buffer-names--hook-outstanding-common ()
+
+  (with-current-buffer (get-buffer-create "foonet/tester")
+    (erc-mode)
+    (setq erc-network 'foonet
+          erc-server-current-nick "tester"
+          erc-networks--id (make-erc-networks--id-qualifying
+                            :symbol 'foonet/tester
+                            :parts [foonet "tester"]
+                            :len 2)
+          erc-server-process (erc-networks-tests--create-live-proc)))
+
+  (with-current-buffer (get-buffer-create "#a@foonet/tester")
+    (erc-mode)
+    (setq erc-server-process (buffer-local-value 'erc-server-process
+                                                 (get-buffer "foonet/tester"))
+          erc-network 'foonet
+          erc-server-current-nick "tester"
+          erc-networks--id (buffer-local-value 'erc-networks--id
+                                               (get-buffer "foonet/tester"))
+          erc--target (erc--target-from-string "#a")))
+
+  (with-current-buffer (get-buffer-create "barnet/tester")
+    (erc-mode)
+    (setq erc-network 'barnet
+          erc-server-current-nick "tester"
+          erc-networks--id (make-erc-networks--id-qualifying
+                            :symbol 'barnet/tester
+                            :parts [barnet "tester"]
+                            :len 2)
+          erc-server-process (erc-networks-tests--create-live-proc)))
+
+  (with-current-buffer (get-buffer-create "barnet/dummy")
+    (erc-mode)
+    (setq erc-network 'barnet
+          erc-server-current-nick "dummy"
+          erc-networks--id (make-erc-networks--id-qualifying
+                            :symbol 'barnet/dummy
+                            :parts [barnet "dummy"]
+                            :len 2)
+          erc-server-process (erc-networks-tests--create-live-proc)))
+
+  (with-current-buffer (get-buffer-create "#a@barnet/tester")
+    (erc-mode)
+    (setq erc-network 'barnet
+          erc-server-current-nick "tester"
+          erc-server-process (buffer-local-value 'erc-server-process
+                                                 (get-buffer "barnet/tester"))
+          erc-networks--id (buffer-local-value 'erc-networks--id
+                                               (get-buffer "barnet/tester"))
+          erc--target (erc--target-from-string "#a"))))
+
+(ert-deftest erc-networks--shrink-ids-and-buffer-names--hook-outstanding-srv ()
+  (erc-networks--shrink-ids-and-buffer-names--hook-outstanding-common)
+  (with-current-buffer (get-buffer-create "foonet/dummy")
+    (erc-mode)
+    (setq erc-network 'foonet
+          erc-server-current-nick "dummy"
+          erc-networks--id (make-erc-networks--id-qualifying
+                            :symbol 'foonet/dummy
+                            :parts [foonet "dummy"]
+                            :len 2)
+          erc-server-process (erc-networks-tests--create-live-proc))
+    (kill-buffer))
+
+  (should (equal (mapcar #'buffer-name (erc-buffer-list))
+                 '("foonet"
+                   "#a@foonet"
+                   "barnet/tester"
+                   "barnet/dummy"
+                   "#a@barnet/tester")))
+  (erc-networks-tests--clean-bufs))
+
+(ert-deftest erc-networks--shrink-ids-and-buffer-names--hook-outstanding-tgt ()
+  (erc-networks--shrink-ids-and-buffer-names--hook-outstanding-common)
+  (with-current-buffer (get-buffer-create "#a@foonet/dummy")
+    (erc-mode)
+    (setq erc-network 'foonet
+          erc-server-current-nick "dummy"
+          erc-networks--id (make-erc-networks--id-qualifying
+                            :symbol 'foonet/dummy
+                            :parts [foonet "dummy"]
+                            :len 2)
+          erc--target (erc--target-from-string "#a")
+          erc-server-process (with-temp-buffer
+                               (erc-networks-tests--create-dead-proc))))
+
+  (with-current-buffer "#a@foonet/dummy" (kill-buffer))
+
+  ;; Identical to *-server variant above
+  (should (equal (mapcar #'buffer-name (erc-buffer-list))
+                 '("foonet"
+                   "#a@foonet"
+                   "barnet/tester"
+                   "barnet/dummy"
+                   "#a@barnet/tester")))
+  (erc-networks-tests--clean-bufs))
+
+(ert-deftest erc-networks-rename-surviving-target-buffer--shrink ()
+  (erc-networks--shrink-ids-and-buffer-names--hook-outstanding-common)
+
+  ;; This buffer isn't "#a@foonet" (yet) because the shrink-ids hook
+  ;; hasn't run.  However, when it's the rename hook runs, its network
+  ;; id *is* "foonet", not "foonet/tester".
+  (with-current-buffer "#a@foonet/tester" (kill-buffer))
+
+  (should (equal (mapcar #'buffer-name (erc-buffer-list))
+                 '("foonet"
+                   "barnet/tester"
+                   "barnet/dummy"
+                   "#a")))
+
+  (erc-networks-tests--clean-bufs))
+
+(ert-deftest erc-networks--shrink-ids-and-buffer-names--server ()
+
+  (with-current-buffer (get-buffer-create "foonet/tester")
+    (erc-mode)
+    (setq erc-network 'foonet
+          erc-server-current-nick "tester"
+          erc-networks--id (make-erc-networks--id-qualifying
+                            :symbol 'foonet/tester
+                            :parts [foonet "tester"]
+                            :len 2)
+          erc-server-process (erc-networks-tests--create-live-proc)))
+
+  (with-current-buffer (get-buffer-create "foonet/dummy")
+    (erc-mode)
+    (setq erc-network 'foonet
+          erc-server-current-nick "dummy"
+          erc-networks--id (make-erc-networks--id-qualifying
+                            :symbol 'foonet/dummy
+                            :parts [foonet "dummy"]
+                            :len 2)
+          erc-server-process (erc-networks-tests--create-dead-proc))
+    (kill-buffer))
+
+  (should (equal (mapcar #'buffer-name (erc-buffer-list)) '("foonet")))
+
+  (erc-networks-tests--clean-bufs))
+
+(defun erc-networks--shrink-ids-and-buffer-names--hook-collapse (check)
+
+  (with-current-buffer (get-buffer-create "foonet/tester")
+    (erc-mode)
+    (setq erc-network 'foonet
+          erc-server-current-nick "tester"
+          erc-networks--id (make-erc-networks--id-qualifying
+                            :symbol 'foonet/tester
+                            :parts [foonet "tester"]
+                            :len 2)
+          erc-server-process (erc-networks-tests--create-live-proc)))
+
+  (with-current-buffer (get-buffer-create "#a@foonet/tester")
+    (erc-mode)
+    (setq erc-server-process (buffer-local-value 'erc-server-process
+                                                 (get-buffer "foonet/tester"))
+          erc-network 'foonet
+          erc-server-current-nick "tester"
+          erc-networks--id (buffer-local-value 'erc-networks--id
+                                               (get-buffer "foonet/tester"))
+          erc--target (erc--target-from-string "#a")))
+
+  (with-current-buffer (get-buffer-create "barnet/tester")
+    (erc-mode)
+    (setq erc-network 'barnet
+          erc-server-current-nick "tester"
+          erc-networks--id (make-erc-networks--id-qualifying
+                            :symbol 'barnet/tester
+                            :parts [barnet "tester"]
+                            :len 2)
+          erc-server-process (erc-networks-tests--create-live-proc)))
+
+  (with-current-buffer (get-buffer-create  "#b@foonet/tester")
+    (erc-mode)
+    (setq erc-network 'barnet
+          erc-server-current-nick "tester"
+          erc-server-process (buffer-local-value 'erc-server-process
+                                                 (get-buffer "barnet/tester"))
+          erc-networks--id (buffer-local-value 'erc-networks--id
+                                               (get-buffer "barnet/tester"))
+          erc--target (erc--target-from-string "#b")))
+
+  (funcall check)
+
+  (should (equal (mapcar #'buffer-name (erc-buffer-list))
+                 '("foonet" "#a" "barnet" "#b")))
+
+  (erc-networks-tests--clean-bufs))
+
+(ert-deftest erc-networks--shrink-ids-and-buffer-names--hook-collapse-server ()
+  (erc-networks--shrink-ids-and-buffer-names--hook-collapse
+   (lambda ()
+     (with-current-buffer (get-buffer-create "foonet/dummy")
+       (erc-mode)
+       (setq erc-network 'foonet
+             erc-server-current-nick "dummy"
+             erc-networks--id (make-erc-networks--id-qualifying
+                               :symbol 'foonet/dummy
+                               :parts [foonet "dummy"]
+                               :len 2)
+             erc-server-process (erc-networks-tests--create-live-proc))
+       (kill-buffer)))))
+
+(ert-deftest erc-networks--shrink-ids-and-buffer-names--hook-collapse-target ()
+  (erc-networks--shrink-ids-and-buffer-names--hook-collapse
+   (lambda ()
+     (with-current-buffer (get-buffer-create "#a@foonet/dummy")
+       (erc-mode)
+       (setq erc-network 'foonet
+             erc-server-current-nick "dummy"
+             erc-networks--id (make-erc-networks--id-qualifying
+                               :symbol 'foonet/dummy
+                               :parts [foonet "dummy"]
+                               :len 2)
+             ;; `erc-kill-buffer-function' uses legacy target detection
+             ;; but falls back on buffer name, so no need for:
+             ;;
+             ;;   erc-default-recipients '("#a")
+             ;;
+             erc--target (erc--target-from-string "#a")
+             erc-server-process (with-temp-buffer
+                                  (erc-networks-tests--create-dead-proc)))
+       (kill-buffer)))))
+
+;; FIXME this test is old and may describe impossible states:
+;; leftover identities being qual-equal but not eq (implies
+;; `erc-networks--reclaim-orphaned-target-buffers' is somehow broken).
+;;
+;; Otherwise, the point of this test is to show that server process
+;; identity does not impact the hunt for duplicates.
+
+(defun erc-tests--prep-erc-networks--reconcile-buffer-names--duplicates (start)
+
+  (with-current-buffer (get-buffer-create "foonet")
+    (erc-mode)
+    (setq erc-network 'foonet
+          erc-server-current-nick "tester"
+          erc-networks--id (erc-networks--id-create nil)
+          erc-server-process (funcall start)))
+
+  (with-current-buffer (get-buffer-create "#chan") ; prior session
+    (erc-mode)
+    (setq erc-server-process (buffer-local-value 'erc-server-process
+                                                 (get-buffer "foonet"))
+          erc--target (erc--target-from-string "#chan")
+          erc-networks--id (erc-networks--id-create nil)))
+
+  (ert-info ("Conflicts not recognized as ERC buffers and not renamed")
+    (get-buffer-create "#chan@foonet")
+    (should (equal (erc-networks-tests--bufnames "#chan")
+                   '("#chan" "#chan@foonet"))))
+
+  ;; These are dupes (not "collisions")
+
+  (with-current-buffer "#chan@foonet" ; same proc
+    (erc-mode)
+    (setq erc--target (erc--target-from-string "#chan")
+          erc-network 'foonet
+          erc-server-current-nick "tester"
+          erc-server-process (buffer-local-value 'erc-server-process
+                                                 (get-buffer "foonet"))
+          erc-networks--id (erc-networks--id-create nil)))
+
+  (with-current-buffer (get-buffer-create "#chan@foonet<dead>")
+    (erc-mode)
+    (setq erc--target (erc--target-from-string "#chan")
+          erc-server-process (erc-networks-tests--create-dead-proc)
+          erc-network 'foonet
+          erc-server-current-nick "tester"
+          erc-networks--id (erc-networks--id-create nil)))
+
+  (with-current-buffer (get-buffer-create "#chan@foonet<live>")
+    (erc-mode)
+    (setq erc--target (erc--target-from-string "#chan")
+          erc-server-process (erc-networks-tests--create-live-proc)
+          erc-network 'foonet
+          erc-server-current-nick "tester"
+          erc-networks--id (erc-networks--id-create nil)))
+
+  (let ((created (list (get-buffer "#chan@foonet<live>")
+                       (get-buffer "#chan@foonet<dead>")
+                       (get-buffer "#chan@foonet"))))
+
+    (with-current-buffer "foonet"
+      (should (string= (erc-networks--reconcile-buffer-names
+                        (erc--target-from-string "#chan") erc-networks--id)
+                       "#chan")))
+
+    (ert-info ("All buffers considered dupes renamed")
+      (should (equal (erc-networks-tests--bufnames "#chan")
+                     '("#chan" "#chan<2>" "#chan<3>" "#chan<4>"))))
+
+    (ert-info ("All buffers renamed from newest to oldest")
+      (should (equal created (list (get-buffer "#chan<2>")
+                                   (get-buffer "#chan<3>")
+                                   (get-buffer "#chan<4>"))))))
+
+  (erc-networks-tests--clean-bufs))
+
+(defun erc-tests--prep-erc-networks--reconcile-buffer-names--dupes-given (go)
+
+  ;; The connection's network is discovered before target buffers are
+  ;; created.  This shows that the network doesn't matter when only
+  ;; "given" IDs are present.
+  (with-current-buffer (get-buffer-create "oofnet")
+    (erc-mode)
+    (setq erc-networks--id (erc-networks--id-create 'oofnet)
+          erc-network 'foonet
+          erc-server-current-nick "tester"
+          erc-server-process (funcall go)))
+
+  (with-current-buffer (get-buffer-create "#chan") ; prior session
+    (erc-mode)
+    (setq erc-networks--id (erc-networks--id-create 'oofnet)
+          erc-server-process (buffer-local-value 'erc-server-process
+                                                 (get-buffer "oofnet"))
+          erc--target (erc--target-from-string "#chan")))
+
+  (with-current-buffer (get-buffer-create "#chan@oofnet") ;dupe/not collision
+    (erc-mode)
+    (setq erc-networks--id (erc-networks--id-create 'oofnet)
+          erc-server-process (buffer-local-value 'erc-server-process
+                                                 (get-buffer "oofnet"))
+          erc--target (erc--target-from-string "#chan")))
+
+  (with-current-buffer "oofnet"
+    (should (string= (erc-networks--reconcile-buffer-names
+                      (erc--target-from-string "#chan") erc-networks--id)
+                     "#chan")))
+
+  (ert-info ("All buffers matching target and network renamed")
+    (should (equal (erc-networks-tests--bufnames "#chan")
+                   '("#chan" "#chan<2>"))))
+
+  (erc-networks-tests--clean-bufs))
+
+(ert-deftest erc-networks--reconcile-buffer-names--duplicates ()
+  (ert-info ("Process live, no error")
+    (erc-tests--prep-erc-networks--reconcile-buffer-names--duplicates
+     #'erc-networks-tests--create-live-proc))
+
+  (ert-info ("Process live, no error, given ID")
+    (erc-tests--prep-erc-networks--reconcile-buffer-names--dupes-given
+     #'erc-networks-tests--create-live-proc))
+
+  (ert-info ("Process dead")
+    (erc-tests--prep-erc-networks--reconcile-buffer-names--duplicates
+     #'erc-networks-tests--create-dead-proc))
+
+  (ert-info ("Process dead, given ID")
+    (erc-tests--prep-erc-networks--reconcile-buffer-names--dupes-given
+     #'erc-networks-tests--create-dead-proc)))
+
+(defun erc-tests--prep-erc-networks--reconcile-buffer-names--no-srv-buf (check)
+  (let ((foonet-proc (with-temp-buffer
+                       (erc-networks-tests--create-dead-proc))))
+    (with-current-buffer (get-buffer-create "barnet")
+      (erc-mode)
+      (setq erc-network 'barnet
+            erc-server-current-nick "tester"
+            erc-networks--id (erc-networks--id-create nil)
+            erc-server-process (erc-networks-tests--create-dead-proc)))
+
+    ;; Different proc and not "qual-equal" (different elts)
+    (with-current-buffer (get-buffer-create "#chan")
+      (erc-mode)
+      (setq erc-network 'foonet
+            erc-server-current-nick "tester"
+            erc-networks--id (erc-networks--id-create nil)
+            erc--target (erc--target-from-string "#chan")
+            erc-server-process foonet-proc))
+    (funcall check)
+    (erc-networks-tests--clean-bufs)))
+
+(ert-deftest erc-networks--reconcile-buffer-names--no-server-buf ()
+  (ert-info ("Existing #chan buffer respected")
+    (erc-tests--prep-erc-networks--reconcile-buffer-names--no-srv-buf
+     (lambda ()
+       (with-current-buffer "barnet"
+         (should (string= (erc-networks--reconcile-buffer-names
+                           (erc--target-from-string "#chan") erc-networks--id)
+                          "#chan@barnet")))
+       (ert-info ("Existing #chan buffer found and renamed")
+         (should (equal (erc-networks-tests--bufnames "#chan")
+                        '("#chan@foonet")))))))
+
+  (ert-info ("Existing #chan buffer")
+    (erc-tests--prep-erc-networks--reconcile-buffer-names--no-srv-buf
+     (lambda ()
+       (with-current-buffer (get-buffer-create "foonet")
+         (erc-mode)
+         (setq erc-network 'foonet
+               erc-server-current-nick "tester"
+               erc-networks--id (erc-networks--id-create nil)
+               erc-server-process (erc-networks-tests--create-dead-proc))
+         (should (string= (erc-networks--reconcile-buffer-names
+                           (erc--target-from-string "#chan") erc-networks--id)
+                          "#chan")))
+       (ert-info ("Nothing renamed")
+         (should (equal (erc-networks-tests--bufnames "#chan") '("#chan")))))))
+
+  (ert-info ("Existing #chan@foonet and #chan@barnet buffers")
+    (erc-tests--prep-erc-networks--reconcile-buffer-names--no-srv-buf
+     (lambda ()
+       (with-current-buffer "#chan"
+         (rename-buffer "#chan@foonet"))
+       (should-not (get-buffer "#chan@barnet"))
+       (with-current-buffer (get-buffer-create "#chan@barnet")
+         (erc-mode)
+         (setq erc--target (erc--target-from-string "#chan")
+               erc-server-process (buffer-local-value 'erc-server-process
+                                                      (get-buffer "barnet"))
+               erc-networks--id (erc-networks--id-create nil)))
+       (with-current-buffer (get-buffer-create "foonet")
+         (erc-mode)
+         (setq erc-network 'foonet
+               erc-server-current-nick "tester"
+               erc-server-process (erc-networks-tests--create-live-proc)
+               erc-networks--id (erc-networks--id-create nil))
+         (set-process-query-on-exit-flag erc-server-process nil)
+         (should (string= (erc-networks--reconcile-buffer-names
+                           (erc--target-from-string "#chan") erc-networks--id)
+                          "#chan@foonet")))
+       (ert-info ("Nothing renamed")
+         (should (equal (erc-networks-tests--bufnames "#chan")
+                        '("#chan@barnet" "#chan@foonet"))))))))
+
+(defun erc-tests--prep-erc-networks--reconcile-buffer-names--no-srv-buf-given
+    (check)
+  (let ((oofnet-proc (with-temp-buffer
+                       (erc-networks-tests--create-dead-proc))))
+
+    (with-current-buffer (get-buffer-create "rabnet")
+      (erc-mode)
+      ;; Again, given name preempts network lookup (unrealistic but
+      ;; highlights priorities)
+      (setq erc-networks--id (erc-networks--id-create 'rabnet)
+            erc-network 'barnet
+            erc-server-current-nick "tester"
+            erc-server-process (erc-networks-tests--create-dead-proc)))
+
+    ;; Identity is not "qual-equal" to above
+    (with-current-buffer (get-buffer-create "#chan")
+      (erc-mode)
+      (setq erc-networks--id (erc-networks--id-create 'oofnet)
+            erc-network 'foonet
+            erc--target (erc--target-from-string "#chan")
+            erc-server-process oofnet-proc))
+    (funcall check)
+    (erc-networks-tests--clean-bufs)))
+
+(ert-deftest erc-networks--reconcile-buffer-names--no-server-buf-given ()
+
+  (ert-info ("Existing #chan buffer respected")
+    (erc-tests--prep-erc-networks--reconcile-buffer-names--no-srv-buf-given
+     (lambda ()
+       (with-current-buffer "rabnet"
+         (should (string= (erc-networks--reconcile-buffer-names
+                           (erc--target-from-string "#chan") erc-networks--id)
+                          "#chan@rabnet")))
+
+       (ert-info ("Existing #chan buffer found and renamed")
+         (should (equal (erc-networks-tests--bufnames "#chan")
+                        '("#chan@oofnet")))))))
+
+  (ert-info ("Existing #chan@oofnet and #chan@rabnet buffers")
+    (erc-tests--prep-erc-networks--reconcile-buffer-names--no-srv-buf-given
+     (lambda ()
+       ;; #chan has already been uniquified (but not grown)
+       (with-current-buffer "#chan" (rename-buffer "#chan@oofnet"))
+       (should-not (get-buffer "#chan@rabnet"))
+
+       (with-current-buffer (get-buffer-create "#chan@rabnet")
+         (erc-mode)
+         (setq erc--target (erc--target-from-string "#chan")
+               erc-server-process (buffer-local-value 'erc-server-process
+                                                      (get-buffer "rabnet"))
+               erc-networks--id (buffer-local-value 'erc-networks--id
+                                                    (get-buffer "rabnet"))))
+
+       (with-current-buffer (get-buffer-create "oofnet")
+         (erc-mode)
+         (setq erc-network 'oofnet
+               erc-server-current-nick "tester"
+               erc-server-process (erc-networks-tests--create-live-proc)
+               erc-networks--id (erc-networks--id-create 'oofnet)) ; given
+         (set-process-query-on-exit-flag erc-server-process nil)
+         (should (string= (erc-networks--reconcile-buffer-names
+                           (erc--target-from-string "#chan") erc-networks--id)
+                          "#chan@oofnet")))
+
+       (ert-info ("Nothing renamed")
+         (should (equal (erc-networks-tests--bufnames "#chan")
+                        '("#chan@oofnet" "#chan@rabnet"))))))))
+
+;; This shows a corner case where a user explicitly assigns a "given"
+;; ID via `erc-tls' but later connects again without one.  It would
+;; actually probably be better if the given identity were to win and
+;; the derived one got an <n>-suffix.
+;;
+;; If we just compared net identities, the two would match, but they
+;; don't here because one has a given name and the other a
+;; discovered/assembled one; so they are *not* qual-equal.
+(ert-deftest erc-networks--reconcile-buffer-names--no-srv-buf-given-mismatch ()
+  ;; Existing #chan buffer *not* respected
+  (erc-tests--prep-erc-networks--reconcile-buffer-names--no-srv-buf-given
+   (lambda ()
+     (with-current-buffer (get-buffer-create "oofnet")
+       (erc-mode)
+       (setq erc-network 'oofnet
+             erc-server-current-nick "tester"
+             erc-server-process (erc-networks-tests--create-dead-proc)
+             erc-networks--id (erc-networks--id-create nil)) ; derived
+       (should (string= (erc-networks--reconcile-buffer-names
+                         (erc--target-from-string "#chan") erc-networks--id)
+                        "#chan@oofnet")))
+
+     (ert-info ("Collision renamed but not grown (because it's a given)")
+       ;; Original chan uniquified and moved out of the way
+       (should (equal (erc-networks-tests--bufnames "#chan")
+                      '("#chan@oofnet<2>")))))))
+
+(defun erc-tests--prep-erc-networks--reconcile-buffer-names--multi-net (check)
+
+  (with-current-buffer (get-buffer-create "foonet")
+    (erc-mode)
+    (setq erc-network 'foonet
+          erc-server-current-nick "tester"
+          erc-server-process (erc-networks-tests--create-dead-proc)
+          erc-networks--id (erc-networks--id-create nil))) ; derived
+
+  (with-current-buffer (get-buffer-create "barnet")
+    (erc-mode)
+    (setq erc-network 'barnet
+          erc-server-current-nick "tester"
+          erc-server-process (erc-networks-tests--create-dead-proc)
+          erc-networks--id (erc-networks--id-create nil))) ; derived
+
+  (with-current-buffer
+      (get-buffer-create (elt ["#chan" "#chan@foonet"] (random 2)))
+    (erc-mode)
+    (setq erc--target (erc--target-from-string "#chan"))
+    (cl-multiple-value-setq (erc-server-process erc-networks--id)
+      (with-current-buffer "foonet"
+        (list erc-server-process erc-networks--id))))
+
+  (with-current-buffer (get-buffer-create "#chan@barnet")
+    (erc-mode)
+    (setq erc--target (erc--target-from-string "#chan"))
+    (cl-multiple-value-setq (erc-server-process erc-networks--id)
+      (with-current-buffer "barnet"
+        (list erc-server-process erc-networks--id))))
+
+  (funcall check)
+  (erc-networks-tests--clean-bufs))
+
+(ert-deftest erc-networks--reconcile-buffer-names--multi-net ()
+  (ert-info ("Same network rename")
+    (erc-tests--prep-erc-networks--reconcile-buffer-names--multi-net
+     (lambda ()
+       (with-current-buffer "foonet"
+         (let ((result (erc-networks--reconcile-buffer-names
+                        (erc--target-from-string "#chan") erc-networks--id)))
+           (should (string= result "#chan@foonet"))))
+
+       (should (equal (erc-networks-tests--bufnames "#chan")
+                      '("#chan@barnet" "#chan@foonet"))))))
+
+  (ert-info ("Same network keep name")
+    (erc-tests--prep-erc-networks--reconcile-buffer-names--multi-net
+     (lambda ()
+       (with-current-buffer "barnet"
+         (let ((result (erc-networks--reconcile-buffer-names
+                        (erc--target-from-string "#chan") erc-networks--id)))
+           (should (string= result "#chan@barnet"))))
+
+       (should (equal (erc-networks-tests--bufnames "#chan")
+                      '("#chan@barnet" "#chan@foonet")))))))
+
+(defun erc-tests--prep-erc-networks--reconcile-buffer-names--multi-net-given
+    (check)
+
+  (with-current-buffer (get-buffer-create "oofnet")
+    (erc-mode)
+    (setq erc-network 'foonet
+          erc-server-current-nick "tester"
+          erc-networks--id (erc-networks--id-create 'oofnet) ; one given
+          erc-server-process (erc-networks-tests--create-dead-proc)))
+
+  (with-current-buffer (get-buffer-create "rabnet")
+    (erc-mode)
+    (setq erc-network 'barnet
+          erc-server-current-nick "tester"
+          erc-networks--id (erc-networks--id-create 'rabnet) ; another given
+          erc-server-process (erc-networks-tests--create-dead-proc)))
+
+  (with-current-buffer (get-buffer-create (elt ["chan" "#chan@oofnet"]
+                                               (random 2)))
+    (erc-mode)
+    (setq erc--target (erc--target-from-string "#chan"))
+    (cl-multiple-value-setq (erc-server-process erc-networks--id)
+      (with-current-buffer "oofnet"
+        (list erc-server-process erc-networks--id))))
+
+  (with-current-buffer (get-buffer-create "#chan@barnet")
+    (erc-mode)
+    (setq erc--target (erc--target-from-string "#chan"))
+    (cl-multiple-value-setq (erc-server-process erc-networks--id)
+      (with-current-buffer "rabnet"
+        (list erc-server-process erc-networks--id))))
+
+  (funcall check)
+  (erc-networks-tests--clean-bufs))
+
+(ert-deftest erc-networks--reconcile-buffer-names--multi-net-given ()
+  (ert-info ("Same network rename")
+    (erc-tests--prep-erc-networks--reconcile-buffer-names--multi-net-given
+     (lambda ()
+       (with-current-buffer "oofnet"
+         (let ((result (erc-networks--reconcile-buffer-names
+                        (erc--target-from-string "#chan") erc-networks--id)))
+           (should (string= result "#chan@oofnet"))))
+
+       (should (equal (erc-networks-tests--bufnames "#chan")
+                      '("#chan@oofnet" "#chan@rabnet"))))))
+
+  (ert-info ("Same network keep name")
+    (erc-tests--prep-erc-networks--reconcile-buffer-names--multi-net-given
+     (lambda ()
+       (with-current-buffer "rabnet"
+         (let ((result (erc-networks--reconcile-buffer-names
+                        (erc--target-from-string "#chan") erc-networks--id)))
+           (should (string= result "#chan@rabnet"))))
+
+       (should (equal (erc-networks-tests--bufnames "#chan")
+                      '("#chan@oofnet" "#chan@rabnet")))))))
+
+(defun erc-tests--prep-erc-networks--reconcile-buffer-names--multi-net-mixed
+    (check)
+
+  (with-current-buffer (get-buffer-create "foonet")
+    (erc-mode)
+    (setq erc-network 'foonet
+          erc-server-current-nick "tester"
+          erc-networks--id (erc-networks--id-create nil) ; one derived
+          erc-server-process (erc-networks-tests--create-dead-proc)))
+
+  (with-current-buffer (get-buffer-create "my-conn")
+    (erc-mode)
+    (setq erc-network 'barnet
+          erc-server-current-nick "tester"
+          erc-networks--id (erc-networks--id-create 'my-conn) ; one given
+          erc-server-process (erc-networks-tests--create-dead-proc)))
+
+  (with-current-buffer (get-buffer-create (elt ["#chan" "#chan@foonet"]
+                                               (random 2)))
+    (erc-mode)
+    (setq erc--target (erc--target-from-string "#chan"))
+    (cl-multiple-value-setq (erc-server-process erc-networks--id)
+      (with-current-buffer "foonet"
+        (list erc-server-process erc-networks--id))))
+
+  (with-current-buffer (get-buffer-create "#chan@my-conn")
+    (erc-mode)
+    (setq erc--target (erc--target-from-string "#chan"))
+    (cl-multiple-value-setq (erc-server-process erc-networks--id)
+      (with-current-buffer "my-conn"
+        (list erc-server-process erc-networks--id))))
+
+  (funcall check)
+  (erc-networks-tests--clean-bufs))
+
+(ert-deftest erc-networks--reconcile-buffer-names--multi-net-existing ()
+
+  (ert-info ("Buf name derived from network")
+    (erc-tests--prep-erc-networks--reconcile-buffer-names--multi-net-mixed
+     (lambda ()
+       (with-current-buffer "foonet"
+         (let ((result (erc-networks--reconcile-buffer-names
+                        (erc--target-from-string "#chan") erc-networks--id)))
+           (should (string= result "#chan@foonet"))))
+
+       (should (equal (erc-networks-tests--bufnames "#chan")
+                      '("#chan@foonet" "#chan@my-conn"))))))
+
+  (ert-info ("Buf name given")
+    (erc-tests--prep-erc-networks--reconcile-buffer-names--multi-net-mixed
+     (lambda ()
+       (with-current-buffer "my-conn"
+         (let ((result (erc-networks--reconcile-buffer-names
+                        (erc--target-from-string "#chan") erc-networks--id)))
+           (should (string= result "#chan@my-conn"))))
+
+       (should (equal (erc-networks-tests--bufnames "#chan")
+                      '("#chan@foonet" "#chan@my-conn")))))))
+
+(ert-deftest erc-networks--reconcile-buffer-names--multi-net-suffixed ()
+  ;; Two networks, same channel.  One network has two connections.
+  ;; When the same channel is joined on the latter under a different
+  ;; nick, all buffer names involving that network are suffixed with
+  ;; the network identity.
+
+  (with-current-buffer (get-buffer-create "foonet/bob")
+    (erc-mode)
+    (setq erc-network 'foonet
+          erc-server-current-nick "bob"
+          erc-networks--id (make-erc-networks--id-qualifying
+                            :symbol 'foonet/bob
+                            :parts [foonet "bob"]
+                            :len 2)
+          erc-server-process (erc-networks-tests--create-live-proc)))
+
+  (with-current-buffer (get-buffer-create
+                        (elt ["#chan@foonet" "#chan@foonet/bob"] (random 2)))
+    (erc-mode)
+    (setq erc--target (erc--target-from-string "#chan")
+          erc-server-process (buffer-local-value 'erc-server-process
+                                                 (get-buffer "foonet/bob"))
+          erc-networks--id (buffer-local-value 'erc-networks--id
+                                               (get-buffer "foonet/bob"))))
+
+  (with-current-buffer (get-buffer-create "barnet")
+    (erc-mode)
+    (setq erc-network 'barnet
+          erc-server-current-nick (elt ["alice" "bob"] (random 2))
+          erc-networks--id (erc-networks--id-create 'barnet)
+          erc-server-process (erc-networks-tests--create-live-proc)))
+
+  (with-current-buffer (get-buffer-create "#chan@barnet")
+    (erc-mode)
+    (setq erc--target (erc--target-from-string "#chan")
+          erc-server-process (buffer-local-value 'erc-server-process
+                                                 (get-buffer "barnet"))
+          erc-networks--id (buffer-local-value 'erc-networks--id
+                                               (get-buffer "barnet"))))
+
+  (with-current-buffer (get-buffer-create "foonet/alice")
+    (erc-mode)
+    (setq erc-network 'foonet
+          erc-server-current-nick "alice"
+          erc-networks--id (make-erc-networks--id-qualifying
+                            :symbol 'foonet/alice
+                            :parts [foonet "alice"]
+                            :len 2)
+          erc-server-process (erc-networks-tests--create-live-proc)))
+
+  (with-current-buffer "foonet/alice"
+    (let ((result (erc-networks--reconcile-buffer-names
+                   (erc--target-from-string "#chan") erc-networks--id)))
+      (should (string= result "#chan@foonet/alice"))))
+
+  (should (equal (erc-networks-tests--bufnames "#chan")
+                 '("#chan@barnet" "#chan@foonet/bob")))
+
+  (erc-networks-tests--clean-bufs))
+
+(ert-deftest erc-networks--reconcile-buffer-names--local ()
+  (with-current-buffer (get-buffer-create "DALnet")
+    (erc-mode)
+    (setq erc-network 'DALnet
+          erc-server-announced-name "elysium.ga.us.dal.net"
+          erc-server-process (erc-networks-tests--create-dead-proc)
+          erc--isupport-params (make-hash-table)
+          erc-networks--id (erc-networks--id-create nil))
+    (puthash 'CHANTYPES '("&#") erc--isupport-params))
+
+  (ert-info ("Local chan buffer from older, disconnected identity")
+    (with-current-buffer (get-buffer-create "&chan")
+      (erc-mode)
+      ;; Cheat here because localp is determined on identity init
+      (setq erc--target (with-current-buffer "DALnet"
+                          (erc--target-from-string "&chan"))
+            erc-network 'DALnet
+            erc-server-announced-name "twisted.ma.us.dal.net"
+            erc-server-process (erc-networks-tests--create-dead-proc)
+            erc-networks--id (erc-networks--id-create nil))))
+
+  (ert-info ("Local channels renamed using network server names")
+    (with-current-buffer "DALnet"
+      (let ((result (erc-networks--reconcile-buffer-names
+                     (erc--target-from-string "&chan") erc-networks--id)))
+        (should (string= result "&chan@elysium.ga.us.dal.net")))))
+
+  (should (get-buffer "&chan@twisted.ma.us.dal.net"))
+  (should-not (get-buffer "&chan"))
+  (erc-networks-tests--clean-bufs))
+
+(ert-deftest erc-networks--set-name ()
+  (with-current-buffer (get-buffer-create "localhost:6667")
+    (let (erc-server-announced-name
+          (erc--isupport-params (make-hash-table))
+          erc-network
+          calls)
+      (erc-mode)
+
+      (cl-letf (((symbol-function 'erc-display-line)
+                 (lambda (&rest r) (push r calls))))
+
+        (ert-info ("Signals when `erc-server-announced-name' unset")
+          (should-error (erc-networks--set-name nil (make-erc-response)))
+          (should-not calls))
+
+        (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 (string-match-p (rx "*** Failed") (car (pop calls)))))))
+
+    (erc-networks-tests--clean-bufs)))
+
+(ert-deftest erc-networks--ensure-announced ()
+  (with-current-buffer (get-buffer-create "localhost:6667")
+    (should (local-variable-if-set-p 'erc-server-announced-name))
+    (let (erc-insert-modify-hook
+          (erc-server-process (erc-networks-tests--create-live-proc))
+          (parsed (make-erc-response
+                   :unparsed ":irc.barnet.org 422 tester :MOTD File is missing"
+                   :sender "irc.barnet.org"
+                   :command "422"
+                   :command-args '("tester" "MOTD File is missing")
+                   :contents "MOTD File is missing")))
+
+      (erc-mode) ; boilerplate displayable start (needs `erc-server-process')
+      (insert "\n\n")
+      (setq erc-input-marker (make-marker) erc-insert-marker (make-marker))
+      (set-marker erc-insert-marker (point-max))
+      (erc-display-prompt) ; boilerplate displayable end
+
+      (erc-networks--ensure-announced erc-server-process parsed)
+      (goto-char (point-min))
+      (search-forward "Failed")
+      (should (string= erc-server-announced-name "irc.barnet.org")))
+    (when noninteractive (kill-buffer))))
+
+(ert-deftest erc-networks--rename-server-buffer--no-existing--orphan ()
+  (with-current-buffer (get-buffer-create "#chan")
+    (erc-mode)
+    (setq erc-network 'FooNet
+          erc-server-current-nick "tester"
+          erc--target (erc--target-from-string "#chan")
+          erc-networks--id (erc-networks--id-create nil)))
+
+  (with-current-buffer (get-buffer-create "irc.foonet.org")
+    (erc-mode)
+    (setq erc-network 'FooNet
+          erc-server-current-nick "tester"
+          erc-server-process (erc-networks-tests--create-live-proc)
+          erc-networks--id (erc-networks--id-create nil))
+    (should-not (erc-networks--rename-server-buffer erc-server-process))
+    (should (string= (buffer-name) "FooNet")))
+
+  (ert-info ("Channel buffer reassociated")
+    (erc-server-process-alive "#chan")
+    (with-current-buffer "#chan"
+      (should erc-server-connected)
+      (erc-with-server-buffer
+        (should (string= (buffer-name) "FooNet")))))
+
+  (erc-networks-tests--clean-bufs))
+
+(ert-deftest erc-networks--rename-server-buffer--existing--reuse ()
+  (let* ((old-buf (get-buffer-create "FooNet"))
+         (old-proc (erc-networks-tests--create-dead-proc old-buf)))
+
+    (with-current-buffer old-buf
+      (erc-mode)
+      (insert "*** Old buf")
+      (setq erc-network 'FooNet
+            erc-server-current-nick "tester"
+            erc-insert-marker (set-marker (make-marker) (point-max))
+            erc-server-process old-proc
+            erc-networks--id (erc-networks--id-create nil)))
+
+    (with-current-buffer (get-buffer-create "#chan")
+      (erc-mode)
+      (setq erc-network 'FooNet
+            erc-server-process old-proc
+            erc-networks--id (erc-networks--id-create nil)
+            erc--target (erc--target-from-string "#chan")))
+
+    (ert-info ("New buffer steals name, content")
+      (with-current-buffer (get-buffer-create "irc.foonet.org")
+        (erc-mode)
+        (setq erc-network 'FooNet
+              erc-server-current-nick "tester"
+              erc-server-process (erc-networks-tests--create-live-proc)
+              erc-networks--id (erc-networks--id-create nil))
+        (should-not (erc-networks--rename-server-buffer erc-server-process))
+        (should (string= (buffer-name) "FooNet"))
+        (goto-char (point-min))
+        (should (search-forward "Old buf"))))
+
+    (ert-info ("Channel buffer reassociated")
+      (erc-server-process-alive "#chan")
+      (with-current-buffer "#chan"
+        (should erc-server-connected)
+        (should-not (eq erc-server-process old-proc))
+        (erc-with-server-buffer
+          (should (string= (buffer-name) "FooNet")))))
+
+    (ert-info ("Original buffer killed off")
+      (should-not (buffer-live-p old-buf))))
+
+  (erc-networks-tests--clean-bufs))
+
+;; This is for compatibility with pre-28.1 behavior.  Basically, we're
+;; trying to match the behavior bug for bug.  All buffers were always
+;; suffixed and never reassociated.  28.1 introduced a regression that
+;; reversed the latter, but we've reverted that.
+
+(ert-deftest erc-networks--rename-server-buffer--existing--noreuse ()
+  (with-suppressed-warnings ((obsolete erc-reuse-buffers))
+    (should erc-reuse-buffers) ; default
+    (let* ((old-buf (get-buffer-create "irc.foonet.org:6697/irc.foonet.org"))
+           (old-proc (erc-networks-tests--create-dead-proc old-buf))
+           erc-reuse-buffers)
+      (with-current-buffer old-buf
+        (erc-mode)
+        (insert "*** Old buf")
+        (setq erc-network 'FooNet
+              erc-server-current-nick "tester"
+              erc-insert-marker (set-marker (make-marker) (point-max))
+              erc-server-process old-proc
+              erc-networks--id (erc-networks--id-create nil)))
+      (with-current-buffer (get-buffer-create "#chan")
+        (erc-mode)
+        (setq erc-network 'FooNet
+              erc-server-process old-proc
+              erc-networks--id (buffer-local-value 'erc-networks--id old-buf)
+              erc--target (erc--target-from-string "#chan"))
+        (rename-buffer (erc-networks--construct-target-buffer-name 
erc--target)))
+
+      (ert-info ("Server buffer uniquely renamed")
+        (with-current-buffer
+            (get-buffer-create "irc.foonet.org:6697/irc.foonet.org<2>")
+          (erc-mode)
+          (setq erc-network 'FooNet
+                erc-server-current-nick "tester"
+                erc-server-process (erc-networks-tests--create-live-proc)
+                erc-networks--id (erc-networks--id-create nil))
+          (should-not (erc-networks--rename-server-buffer erc-server-process))
+          (should (string= (buffer-name)
+                           "irc.foonet.org:6697/irc.foonet.org<2>"))
+          (goto-char (point-min))
+          (should-not (search-forward "Old buf" nil t))))
+
+      (ert-info ("Channel buffer not reassociated")
+        (should-not
+         (erc-server-process-alive
+          (should (get-buffer "#chan/irc.foonet.org"))))
+        (with-current-buffer (get-buffer "#chan/irc.foonet.org")
+          (should-not erc-server-connected)
+          (should (eq erc-server-process old-proc))
+          (erc-with-server-buffer
+            (should (string= (buffer-name)
+                             "irc.foonet.org:6697/irc.foonet.org")))))
+
+      (ert-info ("Old buffer still around")
+        (should (buffer-live-p old-buf)))))
+  (erc-networks-tests--clean-bufs))
+
+(ert-deftest erc-networks--rename-server-buffer--reconnecting ()
+  (let* ((old-buf (get-buffer-create "FooNet"))
+         (old-proc (erc-networks-tests--create-dead-proc old-buf)))
+
+    (with-current-buffer old-buf
+      (erc-mode)
+      (insert "*** Old buf")
+      (setq erc-network 'FooNet
+            erc-server-current-nick "tester"
+            erc-insert-marker (set-marker (make-marker) (point-max))
+            erc-server-process old-proc
+            erc-networks--id (erc-networks--id-create nil)))
+
+    (with-current-buffer (get-buffer-create "#chan")
+      (erc-mode)
+      (setq erc-network 'FooNet
+            erc-server-process old-proc
+            erc--target (erc--target-from-string "#chan")
+            erc-networks--id (erc-networks--id-create nil)))
+
+    (ert-info ("No new buffer")
+      (with-current-buffer old-buf
+        (setq erc-server-process (erc-networks-tests--create-live-proc))
+        (should-not (erc-networks--rename-server-buffer erc-server-process))
+        (should (string= (buffer-name) "FooNet"))
+        (goto-char (point-min))
+        (should (search-forward "Old buf"))))
+
+    (ert-info ("Channel buffer updated with live proc")
+      (erc-server-process-alive "#chan")
+      (with-current-buffer "#chan"
+        (should erc-server-connected)
+        (should-not (eq erc-server-process old-proc))
+        (erc-with-server-buffer
+          (should (string= (buffer-name) "FooNet"))))))
+
+  (erc-networks-tests--clean-bufs))
+
+(ert-deftest erc-networks--rename-server-buffer--id ()
+  (let* ((old-buf (get-buffer-create "MySession"))
+         (old-proc (erc-networks-tests--create-dead-proc old-buf)))
+
+    (with-current-buffer old-buf
+      (erc-mode)
+      (insert "*** Old buf")
+      (setq erc-network 'FooNet
+            erc-networks--id (erc-networks--id-create 'MySession)
+            erc-insert-marker (set-marker (make-marker) (point-max))
+            erc-server-process old-proc))
+
+    (with-current-buffer (get-buffer-create "#chan")
+      (erc-mode)
+      (setq erc-network 'FooNet
+            erc-networks--id (erc-networks--id-create 'MySession)
+            erc-server-process old-proc
+            erc--target (erc--target-from-string "#chan")))
+
+    (ert-info ("No new buffer")
+      (with-current-buffer old-buf
+        (setq erc-server-process (erc-networks-tests--create-live-proc))
+        (should-not (erc-networks--rename-server-buffer erc-server-process))
+        (should (string= (buffer-name) "MySession"))
+        (goto-char (point-min))
+        (should (search-forward "Old buf"))))
+
+    (ert-info ("Channel buffer updated with live proc")
+      (erc-server-process-alive "#chan")
+      (with-current-buffer "#chan"
+        (should erc-server-connected)
+        (should-not (eq erc-server-process old-proc))
+        (erc-with-server-buffer
+          (should (string= (buffer-name) "MySession"))))))
+
+  (erc-networks-tests--clean-bufs))
+
+(ert-deftest erc-networks--rename-server-buffer--existing--live ()
+  (let* (erc-kill-server-hook
+         erc-insert-modify-hook
+         (old-buf (get-buffer-create "FooNet"))
+         (old-proc (erc-networks-tests--create-live-proc old-buf))) ; live
+
+    (with-current-buffer old-buf
+      (erc-mode)
+      (insert "*** Old buf")
+      (setq erc-network 'FooNet
+            erc-server-current-nick "tester"
+            erc-insert-marker (set-marker (make-marker) (point-max))
+            erc-server-process old-proc
+            erc-networks--id (erc-networks--id-create nil))
+      (should (erc-server-process-alive)))
+
+    (with-current-buffer (get-buffer-create "#chan")
+      (erc-mode)
+      (setq erc-network 'FooNet
+            erc-server-process old-proc
+            erc-networks--id (erc-networks--id-create nil)
+            erc-server-connected t
+            erc--target (erc--target-from-string "#chan")))
+
+    (ert-info ("New buffer rejected, abandoned, not killed")
+      (with-current-buffer (get-buffer-create "irc.foonet.org")
+        (erc-mode)
+        (setq erc-network 'FooNet
+              erc-server-current-nick "tester"
+              erc-insert-marker (set-marker (make-marker) (point-max))
+              erc-server-process (erc-networks-tests--create-live-proc)
+              erc-networks--id (erc-networks--id-create nil))
+        (should-not (erc-networks--rename-server-buffer erc-server-process))
+        (should (eq erc-active-buffer old-buf))
+        (should-not (erc-server-process-alive))
+        (should (string= (buffer-name) "irc.foonet.org"))
+        (goto-char (point-min))
+        (search-forward "still connected")))
+
+    (ert-info ("Channel buffer updated with live proc")
+      (should (erc-server-process-alive "#chan"))
+      (with-current-buffer "#chan"
+        (should erc-server-connected)
+        (should (erc-server-buffer-live-p))
+        (should (eq erc-server-process old-proc))
+        (should (buffer-live-p (process-buffer erc-server-process)))
+        (with-current-buffer (process-buffer erc-server-process)
+          (should (eq (current-buffer) (get-buffer "FooNet")))
+          (should (eq (current-buffer) old-buf))))))
+
+  (should (get-buffer "FooNet"))
+  (should (get-buffer "irc.foonet.org"))
+
+  (erc-networks-tests--clean-bufs))
+
+(ert-deftest erc-networks--rename-server-buffer--local-match ()
+  (let* ((old-buf (get-buffer-create "FooNet"))
+         (old-proc (erc-networks-tests--create-dead-proc old-buf)))
+
+    (with-current-buffer old-buf
+      (erc-mode)
+      (insert "*** Old buf")
+      (setq erc-network 'FooNet
+            erc-server-current-nick "tester"
+            erc-server-announced-name "us-east.foonet.org"
+            erc-insert-marker (set-marker (make-marker) (point-max))
+            erc-server-process old-proc
+            erc--isupport-params (make-hash-table)
+            erc-networks--id (erc-networks--id-create nil))
+      (puthash 'CHANTYPES '("&#") erc--isupport-params))
+
+    (with-current-buffer (get-buffer-create "&chan")
+      (erc-mode)
+      (setq erc-network 'FooNet
+            erc-server-process old-proc
+            erc-server-announced-name "us-east.foonet.org"
+            erc--target (erc--target-from-string "&chan")
+            erc-networks--id (erc-networks--id-create nil)))
+
+    (ert-info ("New server buffer steals name, content")
+      (with-current-buffer (get-buffer-create "irc.foonet.org")
+        (erc-mode)
+        (setq erc-network 'FooNet
+              erc-server-current-nick "tester"
+              erc-server-announced-name "us-east.foonet.org"
+              erc-server-process (erc-networks-tests--create-live-proc)
+              erc--isupport-params (make-hash-table)
+              erc-networks--id (erc-networks--id-create nil))
+        (puthash 'CHANTYPES '("&#") erc--isupport-params)
+        (should-not (erc-networks--rename-server-buffer erc-server-process))
+        (should (string= (buffer-name) "FooNet"))
+        (goto-char (point-min))
+        (should (search-forward "Old buf"))))
+
+    (ert-info ("Channel buffer reassociated when &local server matches")
+      (should (erc-server-process-alive "&chan"))
+      (with-current-buffer "&chan"
+        (should erc-server-connected)
+        (should-not (eq erc-server-process old-proc))
+        (erc-with-server-buffer
+          (should (string= (buffer-name) "FooNet")))))
+
+    (ert-info ("Original buffer killed off")
+      (should-not (buffer-live-p old-buf)))
+
+    (erc-networks-tests--clean-bufs)))
+
+(ert-deftest erc-networks--rename-server-buffer--local-nomatch ()
+  (let* ((old-buf (get-buffer-create "FooNet"))
+         (old-proc (erc-networks-tests--create-dead-proc old-buf)))
+
+    (with-current-buffer old-buf
+      (erc-mode)
+      (insert "*** Old buf")
+      (setq erc-network 'FooNet
+            erc-server-current-nick "tester"
+            erc-server-announced-name "us-west.foonet.org"
+            erc-insert-marker (set-marker (make-marker) (point-max))
+            erc-server-process old-proc
+            erc--isupport-params (make-hash-table)
+            erc-networks--id (erc-networks--id-create nil))
+      (puthash 'CHANTYPES '("&#") erc--isupport-params))
+
+    (with-current-buffer (get-buffer-create "&chan")
+      (erc-mode)
+      (setq erc-network 'FooNet
+            erc-server-process old-proc
+            erc-server-announced-name "us-west.foonet.org" ; west
+            erc--target (erc--target-from-string "&chan")
+            erc-networks--id (erc-networks--id-create nil)))
+
+    (ert-info ("New server buffer steals name, content")
+      (with-current-buffer (get-buffer-create "irc.foonet.org")
+        (erc-mode)
+        (setq erc-network 'FooNet
+              erc-server-current-nick "tester"
+              erc-server-announced-name "us-east.foonet.org" ; east
+              erc-server-process (erc-networks-tests--create-live-proc)
+              erc--isupport-params (make-hash-table)
+              erc-networks--id (erc-networks--id-create nil))
+
+        (puthash 'CHANTYPES '("&#") erc--isupport-params)
+        (should-not (erc-networks--rename-server-buffer erc-server-process))
+        (should (string= (buffer-name) "FooNet"))
+        (goto-char (point-min))
+        (should (search-forward "Old buf"))))
+
+    (ert-info ("Channel buffer now orphaned even though network matches")
+      (should-not (erc-server-process-alive "&chan"))
+      (with-current-buffer "&chan"
+        (should-not erc-server-connected)
+        (should (eq erc-server-process old-proc))
+        (erc-with-server-buffer
+          (should (string= (buffer-name) "FooNet")))))
+
+    (ert-info ("Original buffer killed off")
+      (should-not (buffer-live-p old-buf)))
+
+    (erc-networks-tests--clean-bufs)))
+
+(ert-deftest erc-networks--update-server-identity--double-existing ()
+  (with-temp-buffer
+    (erc-mode)
+    (setq erc-networks--id (make-erc-networks--id-qualifying
+                            :parts [foonet "bob"] :len 1))
+
+    (with-current-buffer (get-buffer-create "#chan@foonet/bob")
+      (erc-mode)
+      (setq erc-networks--id (make-erc-networks--id-qualifying
+                              :parts [foonet "bob"] :len 2)))
+    (with-current-buffer (get-buffer-create "foonet/alice")
+      (erc-mode)
+      (setq erc-networks--id
+            (make-erc-networks--id-qualifying :parts [foonet "alice"] :len 2)))
+
+    (ert-info ("Adopt equivalent identity")
+      (should (eq (erc-networks--update-server-identity)
+                  (buffer-local-value 'erc-networks--id
+                                      (get-buffer "#chan@foonet/bob")))))
+
+    (ert-info ("Ignore non-matches")
+      (should-not (erc-networks--update-server-identity))
+      (should (eq erc-networks--id
+                  (buffer-local-value 'erc-networks--id
+                                      (get-buffer "#chan@foonet/bob"))))))
+
+  (erc-networks-tests--clean-bufs))
+
+(ert-deftest erc-networks--update-server-identity--double-new ()
+  (with-temp-buffer
+    (erc-mode)
+    (setq erc-networks--id (make-erc-networks--id-qualifying
+                            :parts [foonet "bob"] :len 1))
+
+    (with-current-buffer (get-buffer-create "foonet/alice")
+      (erc-mode)
+      (setq erc-networks--id
+            (make-erc-networks--id-qualifying :parts [foonet "alice"] :len 2)))
+    (with-current-buffer (get-buffer-create "#chan@foonet/alice")
+      (erc-mode)
+      (setq erc-networks--id (buffer-local-value 'erc-networks--id
+                                                 (get-buffer "foonet/alice"))))
+
+    (ert-info ("Evolve identity to prevent ambiguity")
+      (should-not (erc-networks--update-server-identity))
+      (should (= (erc-networks--id-qualifying-len erc-networks--id) 2))
+      (should (eq (erc-networks--id-symbol erc-networks--id) 'foonet/bob))))
+
+  (erc-networks-tests--clean-bufs))
+
+(ert-deftest erc-networks--update-server-identity--double-bounded ()
+  (with-temp-buffer
+    (erc-mode)
+    (setq erc-networks--id (make-erc-networks--id-qualifying
+                            :parts [foonet "bob"] :len 1))
+
+    (with-current-buffer (get-buffer-create "foonet/alice/home")
+      (erc-mode)
+      (setq erc-networks--id (make-erc-networks--id-qualifying
+                              :parts [foonet "alice" home] :len 3)))
+    (with-current-buffer (get-buffer-create "#chan@foonet/alice/home")
+      (erc-mode)
+      (setq erc-networks--id
+            (buffer-local-value 'erc-networks--id
+                                (get-buffer "foonet/alice/home"))))
+
+    (ert-info ("Evolve identity to prevent ambiguity")
+      (should-not (erc-networks--update-server-identity))
+      (should (= (erc-networks--id-qualifying-len erc-networks--id) 2))
+      (should (eq (erc-networks--id-symbol erc-networks--id) 'foonet/bob))))
+
+  (erc-networks-tests--clean-bufs))
+
+(ert-deftest erc-networks--update-server-identity--double-even ()
+  (with-temp-buffer
+    (erc-mode)
+    (setq erc-networks--id
+          (make-erc-networks--id-qualifying :parts [foonet "bob"] :len 1))
+
+    (with-current-buffer (get-buffer-create "foonet")
+      (erc-mode)
+      (setq erc-networks--id
+            (make-erc-networks--id-qualifying :parts [foonet "alice"] :len 1)))
+    (with-current-buffer (get-buffer-create "#chan")
+      (erc-mode)
+      (setq erc--target (erc--target-from-string "#chan")
+            erc-networks--id (buffer-local-value 'erc-networks--id
+                                                 (get-buffer "foonet"))))
+
+    (ert-info ("Evolve identity to prevent ambiguity")
+      (should-not (erc-networks--update-server-identity))
+      (should (= (erc-networks--id-qualifying-len erc-networks--id) 2))
+      (should (eq (erc-networks--id-symbol erc-networks--id) 'foonet/bob)))
+
+    (ert-info ("Collision renamed")
+      (with-current-buffer "foonet/alice"
+        (should (eq (erc-networks--id-symbol erc-networks--id) 'foonet/alice)))
+
+      (with-current-buffer "#chan@foonet/alice"
+        (should (eq (erc-networks--id-symbol erc-networks--id)
+                    'foonet/alice)))))
+
+  (erc-networks-tests--clean-bufs))
+
+(ert-deftest erc-networks--update-server-identity--triple-new ()
+  (with-temp-buffer
+    (erc-mode)
+    (setq erc-networks--id
+          (make-erc-networks--id-qualifying :parts [foonet "bob" home] :len 1))
+
+    (with-current-buffer (get-buffer-create "foonet/bob/office")
+      (erc-mode)
+      (setq erc-networks--id
+            (make-erc-networks--id-qualifying :parts [foonet "bob" office]
+                                              :len 3)))
+    (with-current-buffer (get-buffer-create "#chan@foonet/bob/office")
+      (erc-mode)
+      (setq erc-networks--id
+            (buffer-local-value 'erc-networks--id
+                                (get-buffer "foonet/bob/office"))))
+
+    (ert-info ("Extend our identity's canonical ID so that it's unique")
+      (should-not (erc-networks--update-server-identity))
+      (should (= (erc-networks--id-qualifying-len erc-networks--id) 3))))
+
+  (erc-networks-tests--clean-bufs))
+
+;;; erc-networks-tests.el ends here
diff --git a/test/lisp/erc/erc-scenarios-auth-source.el 
b/test/lisp/erc/erc-scenarios-auth-source.el
new file mode 100644
index 0000000000..3d399a1815
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-auth-source.el
@@ -0,0 +1,178 @@
+;;; 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.
+;;
+;; 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:
+;;
+;; For practical reasons (mainly lack of imagination), this file
+;; contains tests for both server-password and NickServ contexts.
+
+(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)
+                   (require 'erc-services))
+
+(defun erc-scenarios-common--auth-source (id dialog &rest rest)
+  (push "machine GNU.chat port %d user \"#chan\" password spam" rest)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/auth-source")
+       (dumb-server (erc-d-run "localhost" t dialog))
+       (port (process-contact dumb-server :service))
+       (ents `(,@(mapcar (lambda (fmt) (format fmt port)) rest)
+               "machine MyHost port irc password 123"))
+       (netrc-file (make-temp-file "auth-source-test" nil nil
+                                   (string-join ents "\n")))
+       (auth-sources (list netrc-file))
+       (auth-source-do-cache nil)
+       (erc-scenarios-common-extra-teardown (lambda ()
+                                              (delete-file netrc-file))))
+
+    (ert-info ("Connect")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :nick "tester"
+                                :full-name "tester"
+                                :id id)
+        (should (string= (buffer-name) (if id
+                                           (symbol-name id)
+                                         (format "127.0.0.1:%d" port))))
+        (erc-d-t-wait-for 5 (eq erc-network 'FooNet))))))
+
+(ert-deftest erc-scenarios-base-auth-source-server--dialed ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--auth-source
+   nil 'foonet
+   "machine GNU.chat port %d user tester password fake"
+   "machine FooNet port %d user tester password fake"
+   "machine 127.0.0.1 port %d user tester password changeme"
+   "machine 127.0.0.1 port %d user imposter password fake"))
+
+(ert-deftest erc-scenarios-base-auth-source-server--netid ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--auth-source
+   'MySession 'foonet
+   "machine MySession port %d user tester password changeme"
+   "machine 127.0.0.1 port %d user tester password fake"
+   "machine FooNet port %d user tester password fake"))
+
+(ert-deftest erc-scenarios-base-auth-source-server--netid-custom ()
+  :tags '(:expensive-test)
+  (let ((erc-auth-source-server-function
+         (lambda (&rest _) (erc-auth-source-search :host "MyHost"))))
+    (erc-scenarios-common--auth-source
+     'MySession 'foonet
+     "machine 127.0.0.1 port %d user tester password fake"
+     "machine MyHost port %d user tester password changeme"
+     "machine MySession port %d user tester password fake")))
+
+(ert-deftest erc-scenarios-base-auth-source-server--nopass ()
+  :tags '(:expensive-test)
+  (let (erc-auth-source-server-function)
+    (erc-scenarios-common--auth-source nil 'nopass)))
+
+(ert-deftest erc-scenarios-base-auth-source-server--nopass-netid ()
+  :tags '(:expensive-test)
+  (let (erc-auth-source-server-function)
+    (erc-scenarios-common--auth-source 'MySession 'nopass)))
+
+;; Identify via auth source with no initial password
+
+(defun erc-scenarios-common--services-auth-source (&rest rest)
+  (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 'libera))
+       (port (process-contact dumb-server :service))
+       (ents `(,@(mapcar (lambda (fmt) (format fmt port)) rest)
+               "machine MyHost port irc password 123"))
+       (netrc-file (make-temp-file "auth-source-test" nil nil
+                                   (string-join ents "\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 for NickServ
+       (expect (erc-d-t-make-expecter))
+       (erc-scenarios-common-extra-teardown (lambda ()
+                                              (delete-file netrc-file))))
+
+    (cl-letf (((symbol-function 'read-passwd)
+               (lambda (&rest _) (error "Unexpected read-passwd call"))))
+      (ert-info ("Connect without password")
+        (with-current-buffer (erc :server "127.0.0.1"
+                                  :port port
+                                  :nick "tester"
+                                  :full-name "tester")
+          (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
+          (erc-d-t-wait-for 8 (eq erc-network 'Libera.Chat))
+          (funcall expect 3 "This nickname is registered.")
+          (funcall expect 3 "You are now identified")
+          (funcall expect 3 "Last login from")
+          (erc-cmd-QUIT ""))))
+
+    (erc-services-mode -1)
+
+    (should-not (memq 'services erc-modules))))
+
+;; These tests are about authenticating to nick services
+
+(ert-deftest erc-scenarios-services-auth-source--network ()
+  :tags '(:expensive-test)
+  ;; Skip consulting auth-source for the server password (PASS).
+  (let (erc-auth-source-server-function)
+    (erc-scenarios-common--services-auth-source
+     "machine 127.0.0.1 port %d user tester password spam"
+     "machine zirconium.libera.chat port %d user tester password fake"
+     "machine Libera.Chat port %d user tester password changeme")))
+
+(ert-deftest erc-scenarios-services-auth-source--network-connect-lookup ()
+  :tags '(:expensive-test)
+  ;; Do consult auth-source for the server password (and find nothing)
+  (erc-scenarios-common--services-auth-source
+   "machine zirconium.libera.chat port %d user tester password fake"
+   "machine Libera.Chat port %d user tester password changeme"))
+
+(ert-deftest erc-scenarios-services-auth-source--announced ()
+  :tags '(:expensive-test)
+  (let (erc-auth-source-server-function)
+    (erc-scenarios-common--services-auth-source
+     "machine 127.0.0.1 port %d user tester password spam"
+     "machine zirconium.libera.chat port %d user tester password changeme")))
+
+(ert-deftest erc-scenarios-services-auth-source--dialed ()
+  :tags '(:expensive-test)
+  ;; Support legacy host -> domain name
+  ;; (likely most common in real configs)
+  (let (erc-auth-source-server-function)
+    (erc-scenarios-common--services-auth-source
+     "machine 127.0.0.1 port %d user tester password changeme")))
+
+(ert-deftest erc-scenarios-services-auth-source--custom ()
+  :tags '(:expensive-test)
+  (let (erc-auth-source-server-function
+        (erc-auth-source-services-function
+         (lambda (&rest _) (erc-auth-source-search :host "MyAccount"))))
+    (erc-scenarios-common--services-auth-source
+     "machine zirconium.libera.chat port %d user tester password spam"
+     "machine MyAccount port %d user tester password changeme"
+     "machine 127.0.0.1 port %d user tester password fake")))
+
+;;; erc-scenarios-auth-source.el ends here
diff --git a/test/lisp/erc/erc-scenarios-base-association-nick.el 
b/test/lisp/erc/erc-scenarios-base-association-nick.el
new file mode 100644
index 0000000000..3e848be4df
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-association-nick.el
@@ -0,0 +1,163 @@
+;;; 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.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(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))
+
+;; You register a new nick, disconnect, and log back in, but your nick
+;; is not granted, so ERC obtains a backtick'd version.  You open a
+;; query buffer for NickServ, and ERC names it using the net-ID (which
+;; includes the backtick'd nick) as a suffix.  The original
+;; (disconnected) NickServ buffer gets renamed with *its* net-ID as
+;; well.  You then identify to NickServ, and the dead session is no
+;; longer considered distinct.
+
+(ert-deftest erc-scenarios-base-association-nick-bumped ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/assoc/bumped")
+       (dumb-server (erc-d-run "localhost" t 'renicked 'again))
+       (port (process-contact dumb-server :service))
+       (expect (erc-d-t-make-expecter))
+       (erc-server-flood-penalty 0.5)
+       (erc-server-flood-margin 30))
+
+    (ert-info ("Connect to foonet with nick tester")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :nick "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 ("Create an account for tester and quit")
+      (with-current-buffer "foonet"
+        (funcall expect 3 "debug mode")
+
+        (erc-cmd-QUERY "NickServ")
+        (with-current-buffer "NickServ"
+          (erc-scenarios-common-say "REGISTER changeme")
+          (funcall expect 5 "Account created")
+          (funcall expect 1 "You're now logged in as tester"))
+
+        (with-current-buffer "foonet"
+          (erc-cmd-QUIT "")
+          (erc-d-t-wait-for 4 (not (erc-server-process-alive)))
+          (funcall expect 5 "ERC finished"))))
+
+    (with-current-buffer "foonet"
+      (erc-cmd-RECONNECT))
+
+    (erc-d-t-wait-for 10 "Nick request rejection prevents reassociation (good)"
+      (get-buffer "foonet/tester`"))
+
+    (ert-info ("Ask NickServ to change nick")
+      (with-current-buffer "foonet/tester`"
+        (funcall expect 3 "already in use")
+        (funcall expect 3 "debug mode")
+        (erc-cmd-QUERY "NickServ"))
+
+      (erc-d-t-wait-for 1 "Dead NickServ query buffer renamed, now qualified"
+        (get-buffer "NickServ@foonet/tester"))
+
+      (with-current-buffer "NickServ@foonet/tester`" ; new one
+        (erc-scenarios-common-say "IDENTIFY tester changeme")
+        (funcall expect 5 "You're now logged in as tester")
+        (ert-info ("Original buffer found, reused")
+          (erc-d-t-wait-for 2 (equal (buffer-name) "NickServ")))))
+
+    (ert-info ("Ours is the only NickServ buffer that remains")
+      (should-not (cdr (erc-scenarios-common-buflist "NickServ"))))
+
+    (ert-info ("Visible network ID truncated to one component")
+      (should (not (get-buffer "foonet/tester`")))
+      (should (not (get-buffer "foonet/tester")))
+      (should (get-buffer "foonet")))))
+
+;; A less common variant is when your bouncer switches to an alternate
+;; nick while you're disconnected, and upon reconnecting, you get
+;; a new nick.
+
+(ert-deftest erc-scenarios-base-association-nick-bumped-mandated-renick ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/assoc/bumped")
+       (dumb-server (erc-d-run "localhost" t 'foisted 'refoisted))
+       (port (process-contact dumb-server :service))
+       (expect (erc-d-t-make-expecter))
+       (erc-server-flood-penalty 0.5)
+       (erc-server-flood-margin 30))
+
+    (ert-info ("Connect to foonet with nick tester")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :nick "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 ("Greet bob and quit")
+      (with-current-buffer "foonet"
+        (funcall expect 3 "debug mode")
+
+        (erc-cmd-QUERY "bob")
+        (with-current-buffer "bob"
+          (erc-scenarios-common-say "hi")
+          (funcall expect 5 "hola")
+          (funcall expect 1 "how r u?"))
+
+        (with-current-buffer "foonet"
+          (erc-cmd-QUIT "")
+          (erc-d-t-wait-for 4 (not (erc-server-process-alive)))
+          (funcall expect 5 "ERC finished"))))
+
+    ;; Since we use reconnect, a new buffer won't be created
+    ;; TODO add variant with clean `erc' invocation
+    (with-current-buffer "foonet"
+      (erc-cmd-RECONNECT))
+
+    (ert-info ("Server-initiated renick")
+      (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "foonet/dummy"))
+        (should-not (get-buffer "foonet/tester"))
+        (funcall expect 15 "debug mode"))
+
+      (erc-d-t-wait-for 1 "Old query renamed, now qualified"
+        (get-buffer "bob@foonet/tester"))
+
+      (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "bob@foonet/dummy"))
+        (erc-cmd-NICK "tester")
+        (ert-info ("Buffers combined")
+          (erc-d-t-wait-for 2 (equal (buffer-name) "bob")))))
+
+    (with-current-buffer "foonet"
+      (funcall expect 5 "You're now logged in as tester"))
+
+    (ert-info ("Ours is the only bob buffer that remains")
+      (should-not (cdr (erc-scenarios-common-buflist "bob"))))
+
+    (ert-info ("Visible network ID truncated to one component")
+      (should (not (get-buffer "foonet/dummy")))
+      (should (get-buffer "foonet")))))
+
+;;; erc-scenarios-base-association-nick.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
new file mode 100644
index 0000000000..b7c7079df3
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-association-samenet.el
@@ -0,0 +1,144 @@
+;;; 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.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(declare-function erc-network-name "erc-networks")
+(declare-function erc-network "erc-networks")
+(defvar erc-autojoin-channels-alist)
+(defvar erc-network)
+
+;; One network, two simultaneous connections, no IDs.
+;; Reassociates on reconnect with and without server buffer.
+
+(defun erc-scenarios-common--base-association-samenet (after)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/assoc/samenet")
+       (dumb-server (erc-d-run "localhost" t 'tester 'chester 'tester2))
+       (port (process-contact dumb-server :service))
+       (expect (erc-d-t-make-expecter))
+       (erc-server-flood-penalty 0.5)
+       (erc-server-flood-margin 30))
+
+    (ert-info ("Connect to foonet with nick tester")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :nick "tester"
+                                :password "changeme"
+                                :full-name "tester")
+        (erc-scenarios-common-assert-initial-buf-name nil port)
+        (erc-d-t-wait-for 5 (eq erc-network 'foonet))))
+
+    (ert-info ("Connect to foonet with nick chester")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :nick "chester"
+                                :password "changeme"
+                                :full-name "chester")
+        (erc-scenarios-common-assert-initial-buf-name nil port)))
+
+    (erc-d-t-wait-for 3 "Dialed Buflist is Empty"
+      (not (erc-scenarios-common-buflist "127.0.0.1")))
+
+    (with-current-buffer "foonet/tester"
+      (funcall expect 3 "debug mode")
+      (erc-cmd-JOIN "#chan"))
+
+    (erc-d-t-wait-for 10 (get-buffer "#chan@foonet/tester"))
+    (with-current-buffer "foonet/chester" (funcall expect 3 "debug mode"))
+    (erc-d-t-wait-for 10 (get-buffer "#chan@foonet/chester"))
+
+    (ert-info ("Nick tester sees other nick chester in channel")
+      (with-current-buffer "#chan@foonet/tester"
+        (funcall expect 5 "chester")
+        (funcall expect 5 "find the forester")
+        (erc-cmd-QUIT "")))
+
+    (ert-info ("Nick chester sees other nick tester in same channel")
+      (with-current-buffer  "#chan@foonet/chester"
+        (funcall expect 5 "tester")
+        (funcall expect 5 "find the forester")))
+
+    (funcall after expect)))
+
+(ert-deftest erc-scenarios-base-association-samenet--reconnect-one ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--base-association-samenet
+   (lambda (expect)
+
+     (ert-info ("Connection tester reconnects")
+       (with-current-buffer "foonet/tester"
+         (erc-d-t-wait-for 10 (not (erc-server-process-alive)))
+         (funcall expect 10 "*** ERC finished")
+         (erc-cmd-RECONNECT)
+         (funcall expect 5 "debug mode")))
+
+     (ert-info ("Reassociated to same channel")
+       (with-current-buffer "#chan@foonet/tester"
+         (funcall expect 5 "chester")
+         (funcall expect 5 "welcome again")
+         (erc-cmd-QUIT "")))
+
+     (with-current-buffer "#chan@foonet/chester"
+       (funcall expect 5 "tester")
+       (funcall expect 5 "welcome again")
+       (funcall expect 5 "welcome again")
+       (erc-cmd-QUIT "")))))
+
+(ert-deftest erc-scenarios-base-association-samenet--new-buffer ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--base-association-samenet
+   (lambda (expect)
+
+     (ert-info ("Tester kills buffer and connects from scratch")
+
+       (let (port)
+         (with-current-buffer "foonet/tester"
+           (erc-d-t-wait-for 10 (not (erc-server-process-alive)))
+           (funcall expect 10 "*** ERC finished")
+           (setq port erc-session-port)
+           (kill-buffer))
+
+         (with-current-buffer (erc :server "127.0.0.1"
+                                   :port port
+                                   :nick "tester"
+                                   :password "changeme"
+                                   :full-name "tester")
+
+           (erc-d-t-wait-for 5 (eq erc-network 'foonet)))))
+
+     (with-current-buffer "foonet/tester" (funcall expect 3 "debug mode"))
+
+     (ert-info ("Reassociated to same channel")
+       (with-current-buffer "#chan@foonet/tester"
+         (funcall expect 5 "chester")
+         (funcall expect 5 "welcome again")
+         (erc-cmd-QUIT "")))
+
+     (with-current-buffer "#chan@foonet/chester"
+       (funcall expect 5 "tester")
+       (funcall expect 5 "welcome again")
+       (funcall expect 5 "welcome again")
+       (erc-cmd-QUIT "")))))
+
+;;; erc-scenarios-base-association-samenet.el ends here
diff --git a/test/lisp/erc/erc-scenarios-base-association.el 
b/test/lisp/erc/erc-scenarios-base-association.el
new file mode 100644
index 0000000000..83e5101e3a
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-association.el
@@ -0,0 +1,192 @@
+;;; 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.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(declare-function erc-network-name "erc-networks")
+(declare-function erc-network "erc-networks")
+(defvar erc-autojoin-channels-alist)
+(defvar erc-network)
+
+;; Two networks, same channel name, no confusion (no bouncer).  Some
+;; of this draws from bug#47522 "foil-in-server-buf".  It shows that
+;; disambiguation-related changes added for bug#48598 are not specific
+;; to bouncers.
+
+(defun erc-scenarios-common--base-association-multi-net (second-join)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/assoc/multi-net")
+       (erc-server-flood-penalty 0.1)
+       (dumb-server-foonet-buffer (get-buffer-create "*server-foonet*"))
+       (dumb-server-barnet-buffer (get-buffer-create "*server-barnet*"))
+       (dumb-server-foonet (erc-d-run "localhost" t "server-foonet" 'foonet))
+       (dumb-server-barnet (erc-d-run "localhost" t "server-barnet" 'barnet))
+       (expect (erc-d-t-make-expecter)))
+
+    (ert-info ("Connect to foonet, join #chan")
+      (with-current-buffer
+          (erc :server "127.0.0.1"
+               :port (process-contact dumb-server-foonet :service)
+               :nick "tester"
+               :password "changeme"
+               :full-name "tester")
+        (funcall expect 3 "debug mode")
+        (erc-cmd-JOIN "#chan")))
+
+    (erc-d-t-wait-for 2 (get-buffer "#chan"))
+
+    (ert-info ("Connect to barnet, join #chan")
+      (with-current-buffer
+          (erc :server "127.0.0.1"
+               :port (process-contact dumb-server-barnet :service)
+               :nick "tester"
+               :password "changeme"
+               :full-name "tester")
+        (funcall expect 5 "debug mode")))
+
+    (funcall second-join)
+
+    (erc-d-t-wait-for 3 (get-buffer "#chan@barnet"))
+
+    (erc-d-t-wait-for 2 "Buf #chan now #chan@foonet"
+      (and (get-buffer "#chan@foonet") (not (get-buffer "#chan"))))
+
+    (ert-info ("All #chan@foonet output consumed")
+      (with-current-buffer "#chan@foonet"
+        (funcall expect 3 "bob")
+        (funcall expect 3 "was created on")
+        (funcall expect 3 "prosperous")))
+
+    (ert-info ("All #chan@barnet output consumed")
+      (with-current-buffer "#chan@barnet"
+        (funcall expect 3 "mike")
+        (funcall expect 3 "was created on")
+        (funcall expect 20 "ingenuous")))))
+
+(ert-deftest erc-scenarios-base-association-multi-net--baseline ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--base-association-multi-net
+   (lambda () (with-current-buffer "barnet" (erc-cmd-JOIN "#chan")))))
+
+;; The /join command only targets the current buffer's process.  This
+;; recasts scenario bug#48598 "ambiguous-join" (which was based on
+;; bug#47522) to show that issuing superfluous /join commands
+;; (apparently fairly common) is benign.
+
+(ert-deftest erc-scenarios-base-association-multi-net--ambiguous-join ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--base-association-multi-net
+   (lambda ()
+     (ert-info ("Nonsensical JOIN attempts silently dropped.")
+       (with-current-buffer "foonet" (erc-cmd-JOIN "#chan"))
+       (sit-for 0.1)
+       (with-current-buffer "#chan" (erc-cmd-JOIN "#chan"))
+       (sit-for 0.1)
+       (erc-d-t-wait-for 2 (get-buffer "#chan"))
+       (erc-d-t-wait-for 1 "Only one #chan buffer exists"
+         (should (equal (erc-scenarios-common-buflist "#chan")
+                        (list (get-buffer "#chan")))))
+       (with-current-buffer "*server-barnet*"
+         (erc-d-t-absent-for 0.1 "JOIN"))
+       (with-current-buffer "barnet" (erc-cmd-JOIN "#chan"))))))
+
+;; Playback for same channel on two networks routed correctly.
+;; Originally from Bug#48598: 28.0.50; buffer-naming collisions
+;; involving bouncers in ERC.
+
+(ert-deftest erc-scenarios-base-association-bouncer-history ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/assoc/bouncer-history")
+       (erc-d-t-cleanup-sleep-secs 1)
+       (dumb-server (erc-d-run "localhost" t 'foonet 'barnet))
+       (port (process-contact dumb-server :service))
+       (erc-server-flood-penalty 0.5)
+       (expect (erc-d-t-make-expecter))
+       erc-autojoin-channels-alist
+       erc-server-buffer-foo erc-server-process-foo
+       erc-server-buffer-bar erc-server-process-bar)
+
+    (ert-info ("Connect to foonet")
+      (with-current-buffer
+          (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+                                           :port port
+                                           :nick "tester"
+                                           :password "foonet:changeme"
+                                           :full-name "tester"))
+        (setq erc-server-process-foo erc-server-process)
+        (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
+        (funcall expect 5 "foonet")))
+
+    (erc-d-t-wait-for 5 (get-buffer "#chan"))
+
+    (ert-info ("Connect to barnet")
+      (with-current-buffer
+          (setq erc-server-buffer-bar (erc :server "127.0.0.1"
+                                           :port port
+                                           :nick "tester"
+                                           :password "barnet:changeme"
+                                           :full-name "tester"))
+        (setq erc-server-process-bar erc-server-process)
+        (erc-d-t-wait-for 5 "Temporary name assigned"
+          (string= (buffer-name) (format "127.0.0.1:%d" port)))
+        (funcall expect 5 "barnet")))
+
+    (ert-info ("Server buffers are unique")
+      (should-not (eq erc-server-buffer-foo erc-server-buffer-bar)))
+
+    (ert-info ("Networks correctly determined and adopted as buffer names")
+      (with-current-buffer erc-server-buffer-foo
+        (erc-d-t-wait-for 3 "network name foonet becomes buffer name"
+          (and (eq (erc-network) 'foonet) (string= (buffer-name) "foonet"))))
+      (with-current-buffer erc-server-buffer-bar
+        (erc-d-t-wait-for 3 "network name barnet becomes buffer name"
+          (and (eq (erc-network) 'barnet) (string= (buffer-name) "barnet")))))
+
+    (erc-d-t-wait-for 5 (get-buffer "#chan@barnet"))
+
+    (ert-info ("Two channel buffers created, original #chan renamed")
+      (should (= 4 (length (erc-buffer-list))))
+      (should (equal (list (get-buffer "#chan@barnet")
+                           (get-buffer "#chan@foonet"))
+                     (erc-scenarios-common-buflist "#chan"))))
+
+    (ert-info ("#chan@foonet is exclusive, no cross-contamination")
+      (with-current-buffer "#chan@foonet"
+        (erc-d-t-search-for 1 "<bob>")
+        (erc-d-t-absent-for 0.1 "<joe>")
+        (should (eq erc-server-process erc-server-process-foo))))
+
+    (ert-info ("#chan@barnet is exclusive, no cross-contamination")
+      (with-current-buffer "#chan@barnet"
+        (erc-d-t-search-for 1 "<joe>")
+        (erc-d-t-absent-for 0.1 "<bob>")
+        (should (eq erc-server-process erc-server-process-bar))))
+
+    (ert-info ("All output sent")
+      (with-current-buffer "#chan@foonet"
+        (erc-d-t-search-for 10 "please your lordship"))
+      (with-current-buffer "#chan@barnet"
+        (erc-d-t-search-for 10 "I'll bid adieu")))))
+
+;;; erc-scenarios-base-association.el ends here
diff --git a/test/lisp/erc/erc-scenarios-base-compat-rename-bouncer.el 
b/test/lisp/erc/erc-scenarios-base-compat-rename-bouncer.el
new file mode 100644
index 0000000000..474739d01b
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-compat-rename-bouncer.el
@@ -0,0 +1,171 @@
+;;; 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.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(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))
+
+;; Ensure deprecated option still respected when old default value
+;; explicitly set ("respected" in the sense of having names reflect
+;; dialed TCP endpoints with possible uniquifiers but without any of
+;; the old issues, pre-bug#48598).
+
+(defun erc-scenarios-common--base-compat-no-rename-bouncer (dialogs auto more)
+  (erc-scenarios-common-with-cleanup
+      ;; These actually *are* (assigned-)network-id related because
+      ;; our kludge assigns one after the fact.
+      ((erc-scenarios-common-dialog "base/netid/bouncer")
+       (erc-d-t-cleanup-sleep-secs 1)
+       (erc-server-flood-penalty 0.1)
+       (dumb-server (apply #'erc-d-run "localhost" t dialogs))
+       (port (process-contact dumb-server :service))
+       (chan-buf-foo (format "#chan@127.0.0.1:%d" port))
+       (chan-buf-bar (format "#chan@127.0.0.1:%d<2>" port))
+       (expect (erc-d-t-make-expecter))
+       (erc-server-auto-reconnect auto)
+       erc-server-buffer-foo erc-server-process-foo
+       erc-server-buffer-bar erc-server-process-bar)
+
+    (ert-info ("Connect to foonet")
+      (with-current-buffer
+          (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+                                           :port port
+                                           :nick "tester"
+                                           :password "foonet:changeme"
+                                           :full-name "tester"
+                                           :id nil))
+        (setq erc-server-process-foo erc-server-process)
+        (erc-d-t-wait-for 3 (eq (erc-network) 'foonet))
+        (erc-d-t-wait-for 3 "Final buffer name determined"
+          (string= (buffer-name) (format "127.0.0.1:%d" port)))
+        (funcall expect 5 "foonet")))
+
+    (ert-info ("Join #chan@foonet")
+      (with-current-buffer erc-server-buffer-foo (erc-cmd-JOIN "#chan"))
+      (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan"))
+        (funcall expect 5 "<alice>")))
+
+    (ert-info ("Connect to barnet")
+      (with-current-buffer
+          (setq erc-server-buffer-bar (erc :server "127.0.0.1"
+                                           :port port
+                                           :nick "tester"
+                                           :password "barnet:changeme"
+                                           :full-name "tester"
+                                           :id nil))
+        (setq erc-server-process-bar erc-server-process)
+        (erc-d-t-wait-for 3 (eq (erc-network) 'barnet))
+        (erc-d-t-wait-for 3 "Final buffer name determined"
+          (string= (buffer-name) (format "127.0.0.1:%d<2>" port)))
+        (funcall expect 5 "barnet")))
+
+    (ert-info ("Server buffers are unique, no names based on IPs")
+      (should-not (eq erc-server-buffer-foo erc-server-buffer-bar))
+      (should (equal (erc-scenarios-common-buflist "127.0.0.1")
+                     (list (get-buffer (format "127.0.0.1:%d<2>" port))
+                           (get-buffer (format "127.0.0.1:%d" port))))))
+
+    (ert-info ("Join #chan@barnet")
+      (with-current-buffer erc-server-buffer-bar (erc-cmd-JOIN "#chan")))
+
+    (erc-d-t-wait-for 5 "Exactly 2 #chan-prefixed buffers exist"
+      (equal (list (get-buffer chan-buf-bar)
+                   (get-buffer chan-buf-foo))
+             (erc-scenarios-common-buflist "#chan")))
+
+    (ert-info ("#chan@127.0.0.1:$port is exclusive to foonet")
+      (with-current-buffer chan-buf-foo
+        (erc-d-t-search-for 1 "<bob>")
+        (erc-d-t-absent-for 0.1 "<joe>")
+        (should (eq erc-server-process erc-server-process-foo))
+        (erc-d-t-search-for 10 "ape is dead")
+        (erc-d-t-wait-for 5 (not (erc-server-process-alive)))))
+
+    (ert-info ("#chan@127.0.0.1:$port<2> is exclusive to barnet")
+      (with-current-buffer chan-buf-bar
+        (erc-d-t-search-for 1 "<joe>")
+        (erc-d-t-absent-for 0.1 "<bob>")
+        (should (eq erc-server-process erc-server-process-bar))
+        (erc-d-t-search-for 10 "keeps you from dishonour")
+        (erc-d-t-wait-for 5 (not (erc-server-process-alive)))))
+
+    (when more (funcall more))))
+
+(ert-deftest erc-scenarios-base-compat-no-rename-bouncer--basic ()
+  :tags '(:expensive-test)
+  (with-suppressed-warnings ((obsolete erc-rename-buffers))
+    (let (erc-rename-buffers)
+      (erc-scenarios-common--base-compat-no-rename-bouncer
+       '(foonet barnet) nil nil))))
+
+(ert-deftest erc-scenarios-base-compat-no-rename-bouncer--reconnect ()
+  :tags '(:expensive-test)
+  (let ((erc-d-tmpl-vars '((token . (group (| "barnet" "foonet")))))
+        (erc-d-match-handlers
+         (list :pass #'erc-scenarios-common--clash-rename-pass-handler))
+        (dialogs '(foonet-drop barnet-drop stub-again stub-again
+                               foonet-again barnet-again))
+        (after
+         (lambda ()
+           (pcase-let* ((`(,barnet ,foonet)
+                         (erc-scenarios-common-buflist "127.0.0.1"))
+                        (port (process-contact (with-current-buffer foonet
+                                                 erc-server-process)
+                                               :service)))
+
+             (ert-info ("Sanity check: barnet retains uniquifying suffix")
+               (should (string-suffix-p "<2>" (buffer-name barnet))))
+
+             ;; Simulate disconnection and `erc-server-auto-reconnect'
+             (ert-info ("Reconnect to foonet and barnet back-to-back")
+               (with-current-buffer foonet
+                 (erc-d-t-wait-for 5 (erc-server-process-alive)))
+               (with-current-buffer barnet
+                 (erc-d-t-wait-for 5 (erc-server-process-alive))))
+
+             (ert-info ("#chan@127.0.0.1:<port> is exclusive to foonet")
+               (with-current-buffer  (format "#chan@127.0.0.1:%d" port)
+                 (erc-d-t-search-for 1 "<alice>")
+                 (erc-d-t-absent-for 0.1 "<joe>")
+                 (erc-d-t-search-for 10 "please your lordship")))
+
+             (ert-info ("#chan@barnet is exclusive to barnet")
+               (with-current-buffer  (format "#chan@127.0.0.1:%d<2>" port)
+                 (erc-d-t-search-for 1 "<joe>")
+                 (erc-d-t-absent-for 0.1 "<bob>")
+                 (erc-d-t-search-for 1 "much in private")))
+
+             ;; Ordering deterministic here even though not so for reconnect
+             (should (equal (list barnet foonet)
+                            (erc-scenarios-common-buflist "127.0.0.1")))
+             (should (equal (list
+                             (get-buffer (format "#chan@127.0.0.1:%d<2>" port))
+                             (get-buffer (format "#chan@127.0.0.1:%d" port)))
+                            (erc-scenarios-common-buflist "#chan")))))))
+
+    (with-suppressed-warnings ((obsolete erc-rename-buffers))
+      (let (erc-rename-buffers)
+        (erc-scenarios-common--base-compat-no-rename-bouncer dialogs
+                                                             'auto after)))))
+
+;;; erc-scenarios-compat-rename-bouncer.el ends here
diff --git a/test/lisp/erc/erc-scenarios-base-misc-regressions.el 
b/test/lisp/erc/erc-scenarios-base-misc-regressions.el
new file mode 100644
index 0000000000..8f5700df14
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-misc-regressions.el
@@ -0,0 +1,126 @@
+;;; 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.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(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))
+
+(defun erc-scenarios--rebuffed-gapless-pass-handler (dialog exchange)
+  (when (eq (erc-d-dialog-name dialog) 'pass-stub)
+    (let* ((match (erc-d-exchange-match exchange 1))
+           (sym (if (string= match "foonet") 'foonet 'barnet)))
+      (should (member match (list "foonet" "barnet")))
+      (erc-d-load-replacement-dialog dialog sym 1))))
+
+(ert-deftest erc-scenarios-base-gapless-connect ()
+  "Back-to-back entry-point invocations happen successfully.
+Originally from scenario rebuffed/gapless as explained in Bug#48598:
+28.0.50; buffer-naming collisions involving bouncers in ERC."
+  :tags '(:expensive-test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/gapless-connect")
+       (erc-server-flood-penalty 0.1)
+       (erc-server-flood-penalty erc-server-flood-penalty)
+       (erc-d-tmpl-vars '((token . (group (| "barnet" "foonet")))))
+       (erc-d-match-handlers
+        (list :pass #'erc-scenarios--rebuffed-gapless-pass-handler))
+       (dumb-server (erc-d-run "localhost" t
+                               'pass-stub 'pass-stub 'barnet 'foonet))
+       (port (process-contact dumb-server :service))
+       (expect (erc-d-t-make-expecter))
+       erc-autojoin-channels-alist
+       erc-server-buffer-foo
+       erc-server-buffer-bar)
+
+    (ert-info ("Connect twice to same endpoint without pausing")
+      (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+                                       :port port
+                                       :nick "tester"
+                                       :password "foonet:changeme"
+                                       :full-name "tester")
+            erc-server-buffer-bar (erc :server "127.0.0.1"
+                                       :port port
+                                       :nick "tester"
+                                       :password "barnet:changeme"
+                                       :full-name "tester")))
+
+    (ert-info ("Returned server buffers are unique")
+      (should-not (eq erc-server-buffer-foo erc-server-buffer-bar)))
+
+    (ert-info ("Both connections still alive")
+      (should (get-process (format "erc-127.0.0.1-%d" port)))
+      (should (get-process (format "erc-127.0.0.1-%d<1>" port))))
+
+    (with-current-buffer erc-server-buffer-bar
+      (funcall expect 2 "marked as being away"))
+
+    (with-current-buffer (erc-d-t-wait-for 20 (get-buffer "#bar"))
+      (funcall expect 10 "was created on")
+      (funcall expect 2 "his second fit"))
+
+    (with-current-buffer (erc-d-t-wait-for 20 (get-buffer "#foo"))
+      (funcall expect 10 "was created on")
+      (funcall expect 2 "no use of him"))))
+
+;; This defends against a regression in `erc-server-PRIVMSG' caused by
+;; the removal of `erc-auto-query'.  When an active channel buffer is
+;; killed off and PRIVMSGs arrive targeting it, the buffer should be
+;; recreated.  See elsewhere for NOTICE logic, which is more complex.
+
+(ert-deftest erc-scenarios-base-channel-buffer-revival ()
+  :tags '(:expensive-test)
+
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/channel-buffer-revival")
+       (dumb-server (erc-d-run "localhost" t 'foonet))
+       (port (process-contact dumb-server :service))
+       erc-autojoin-channels-alist
+       erc-server-buffer-foo)
+
+    (ert-info ("Connect to foonet")
+      (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+                                       :port port
+                                       :nick "tester"
+                                       :password "changeme"
+                                       :full-name "tester"))
+      (with-current-buffer erc-server-buffer-foo
+        (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
+
+    (ert-info ("Server buffer is unique and temp name is absent")
+      (erc-d-t-wait-for 1 (get-buffer "FooNet"))
+      (should-not (erc-scenarios-common-buflist "127.0.0.1"))
+      (with-current-buffer erc-server-buffer-foo
+        (erc-cmd-JOIN "#chan")))
+
+    (ert-info ("Channel buffer #chan alive and well")
+      (with-current-buffer (erc-d-t-wait-for 8 (get-buffer "#chan"))
+        (erc-d-t-search-for 10 "Our queen and all her elves")
+        (kill-buffer)))
+
+    (should-not (get-buffer "#chan"))
+
+    (ert-info ("Channel buffer #chan revived")
+      (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan"))
+        (erc-d-t-search-for 10 "and be prosperous")))))
+
+;;; erc-scenarios-base-misc-regressions.el ends here
diff --git a/test/lisp/erc/erc-scenarios-base-netid-bouncer-id.el 
b/test/lisp/erc/erc-scenarios-base-netid-bouncer-id.el
new file mode 100644
index 0000000000..6c6568cad6
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-netid-bouncer-id.el
@@ -0,0 +1,34 @@
+;;; 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.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(ert-deftest erc-scenarios-base-netid-bouncer--id-foo ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--base-network-id-bouncer '(:foo-id t) 'foonet 'barnet))
+
+(ert-deftest erc-scenarios-base-netid-bouncer--id-bar ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--base-network-id-bouncer '(:bar-id t) 'foonet 'barnet))
+
+;;; erc-scenarios-base-netid-bouncer-id.el ends here
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
new file mode 100644
index 0000000000..f48e1ef394
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-netid-bouncer-recon-base.el
@@ -0,0 +1,30 @@
+;;; 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.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(ert-deftest erc-scenarios-base-netid-bouncer--recon-base ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--base-network-id-bouncer--reconnect nil nil))
+
+;;; erc-scenarios-base-netid-bouncer-recon-base.el ends here
diff --git a/test/lisp/erc/erc-scenarios-base-netid-bouncer-recon-both.el 
b/test/lisp/erc/erc-scenarios-base-netid-bouncer-recon-both.el
new file mode 100644
index 0000000000..2f58c3269e
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-netid-bouncer-recon-both.el
@@ -0,0 +1,32 @@
+;;; erc-scenarios-base-netid-bouncer-recon-both.el --- net-id both 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.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(require 'erc-scenarios-common)
+
+(ert-deftest erc-scenarios-base-netid-bouncer--recon-both ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--base-network-id-bouncer--reconnect 'foo-id 'bar-id))
+
+;;; erc-scenarios-base-netid-bouncer-recon-both.el ends here
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
new file mode 100644
index 0000000000..72510809ab
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-netid-bouncer-recon-id.el
@@ -0,0 +1,35 @@
+;;; 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.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(ert-deftest erc-scenarios-base-netid-bouncer--reconnect-id-foo ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--base-network-id-bouncer--reconnect 'foo-id nil))
+
+(ert-deftest erc-scenarios-base-netid-bouncer--reconnect-id-bar ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--base-network-id-bouncer--reconnect nil 'bar-id))
+
+
+;;; erc-scenarios-base-netid-bouncer-recon-id.el ends here
diff --git a/test/lisp/erc/erc-scenarios-base-netid-bouncer.el 
b/test/lisp/erc/erc-scenarios-base-netid-bouncer.el
new file mode 100644
index 0000000000..d171e1f9f9
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-netid-bouncer.el
@@ -0,0 +1,35 @@
+;;; 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.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(ert-deftest erc-scenarios-base-netid-bouncer--base ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--base-network-id-bouncer () 'foonet 'barnet))
+
+(ert-deftest erc-scenarios-base-netid-bouncer--both ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--base-network-id-bouncer '(:foo-id t :bar-id t)
+                                                 'foonet 'barnet))
+
+;;; erc-scenarios-base-netid-bouncer.el ends here
diff --git a/test/lisp/erc/erc-scenarios-base-netid-samenet.el 
b/test/lisp/erc/erc-scenarios-base-netid-samenet.el
new file mode 100644
index 0000000000..248144d6f9
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-netid-samenet.el
@@ -0,0 +1,147 @@
+;;; 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.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(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))
+
+(cl-defun erc-scenarios-common--base-network-id-same-network
+    ((&key nick id server chan
+           &aux (nick-a nick) (id-a id) (serv-buf-a server) (chan-buf-a chan))
+     (&key nick id server chan
+           &aux (nick-b nick) (id-b id) (serv-buf-b server) (chan-buf-b chan)))
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/netid/samenet")
+       (dumb-server (erc-d-run "localhost" t 'tester 'chester))
+       (port (process-contact dumb-server :service))
+       (expect (erc-d-t-make-expecter))
+       (erc-server-flood-penalty 0.1)
+       (erc-server-flood-margin 30)
+       erc-serv-buf-a erc-serv-buf-b)
+
+    (ert-info ("Connect to foonet with nick tester")
+      (with-current-buffer
+          (setq erc-serv-buf-a (erc :server "127.0.0.1"
+                                    :port port
+                                    :nick nick-a
+                                    :password "changeme"
+                                    :full-name nick-a
+                                    :id id-a))
+        (erc-scenarios-common-assert-initial-buf-name id-a port)
+        (erc-d-t-wait-for 5 (eq erc-network 'foonet))))
+
+    (ert-info ("Connect to foonet with nick chester")
+      (with-current-buffer
+          (setq erc-serv-buf-b (erc :server "127.0.0.1"
+                                    :port port
+                                    :nick nick-b
+                                    :password "changeme"
+                                    :full-name nick-b
+                                    :id id-b))
+        (erc-scenarios-common-assert-initial-buf-name id-b port)))
+
+    (erc-d-t-wait-for 3 (not (erc-scenarios-common-buflist "127.0.0.1")))
+
+    (with-current-buffer erc-serv-buf-a
+      (should (string= (buffer-name) serv-buf-a))
+      (funcall expect 8 "debug mode")
+      (erc-cmd-JOIN "#chan"))
+
+    (with-current-buffer erc-serv-buf-b
+      (should (string= (buffer-name) serv-buf-b))
+      (funcall expect 8 "debug mode")
+      (erc-cmd-JOIN "#chan"))
+
+    (erc-d-t-wait-for 10 (get-buffer chan-buf-a))
+    (erc-d-t-wait-for 10 (get-buffer chan-buf-b))
+
+    (ert-info ("Greets other nick in same channel")
+      (with-current-buffer chan-buf-a
+        (funcall expect 5 "chester")
+        (funcall expect 5 "find the forester")
+        (erc-cmd-MSG "#chan chester: hi")))
+
+    (ert-info ("Sees other nick in same channel")
+      (with-current-buffer chan-buf-b
+        (funcall expect 5 "tester")
+        (funcall expect 10 "<tester> chester: hi")
+        (funcall expect 5 "This was lofty")
+        (erc-cmd-MSG "#chan hi tester")))
+
+    (with-current-buffer chan-buf-a
+      (funcall expect 5 "To employ you towards")
+      (erc-cmd-QUIT ""))
+
+    (with-current-buffer chan-buf-b
+      (funcall expect 5 "To employ you towards")
+      (erc-cmd-QUIT ""))))
+
+(ert-deftest erc-scenarios-base-network-id-same-network--two-ids ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--base-network-id-same-network
+   (list :nick "tester"
+         :id 'tester/foonet
+         :server "tester/foonet"
+         :chan "#chan@tester/foonet")
+   (list :nick "chester"
+         :id 'chester/foonet
+         :server "chester/foonet"
+         :chan "#chan@chester/foonet")))
+
+(ert-deftest erc-scenarios-base-network-id-same-network--one-id-tester ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--base-network-id-same-network
+   (list :nick "tester"
+         :id 'tester/foonet
+         :server "tester/foonet"
+         :chan "#chan@tester/foonet")
+   (list :nick "chester"
+         :id nil
+         :server "foonet"
+         :chan "#chan@foonet")))
+
+(ert-deftest erc-scenarios-base-network-id-same-network--one-id-chester ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--base-network-id-same-network
+   (list :nick "tester"
+         :id nil
+         :server "foonet"
+         :chan "#chan@foonet")
+   (list :nick "chester"
+         :id 'chester/foonet
+         :server "chester/foonet"
+         :chan "#chan@chester/foonet")))
+
+(ert-deftest erc-scenarios-base-network-id-same-network--no-ids ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--base-network-id-same-network
+   (list :nick "tester"
+         :id nil
+         :server "foonet/tester"
+         :chan "#chan@foonet/tester") ; <- note net before nick
+   (list :nick "chester"
+         :id nil
+         :server "foonet/chester"
+         :chan "#chan@foonet/chester")))
+
+;;; erc-scenarios-base-network-id-samenet.el ends here
diff --git a/test/lisp/erc/erc-scenarios-base-reconnect.el 
b/test/lisp/erc/erc-scenarios-base-reconnect.el
new file mode 100644
index 0000000000..30d692058d
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-reconnect.el
@@ -0,0 +1,226 @@
+;;; 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.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(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))
+
+;; This ensures we only reconnect `erc-server-reconnect-attempts'
+;; (rather than infinitely many) times, which can easily happen when
+;; tweaking code related to process sentinels in erc-backend.el.
+
+(ert-deftest erc-scenarios-base-reconnect-timer ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/reconnect")
+       (dumb-server (erc-d-run "localhost" t 'timer 'timer 'timer-last))
+       (port (process-contact dumb-server :service))
+       (expect (erc-d-t-make-expecter))
+       (erc-server-auto-reconnect t)
+       erc-autojoin-channels-alist
+       erc-server-buffer)
+
+    (ert-info ("Connect to foonet")
+      (setq erc-server-buffer (erc :server "127.0.0.1"
+                                   :port port
+                                   :nick "tester"
+                                   :password "changeme"
+                                   :full-name "tester"))
+      (with-current-buffer erc-server-buffer
+        (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
+
+    (ert-info ("Server tries to connect thrice (including initial attempt)")
+      (with-current-buffer erc-server-buffer
+        (dotimes (n 3)
+          (ert-info ((format "Attempt %d" n))
+            (funcall expect 3 "Opening connection")
+            (funcall expect 2 "Password incorrect")
+            (funcall expect 2 "Connection failed!")
+            (funcall expect 2 "Re-establishing connection")))
+        (ert-info ("Prev attempt was final")
+          (erc-d-t-absent-for 1 "Opening connection" (point)))))
+
+    (ert-info ("Server buffer is unique and temp name is absent")
+      (should (equal (list (get-buffer (format "127.0.0.1:%d" port)))
+                     (erc-scenarios-common-buflist "127.0.0.1"))))))
+
+(defun erc-scenarios-common--base-reconnect-options (test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/reconnect")
+       (dumb-server (erc-d-run "localhost" t 'options 'options-again))
+       (port (process-contact dumb-server :service))
+       (expect (erc-d-t-make-expecter))
+       (erc-server-flood-penalty 0.1)
+       (erc-server-auto-reconnect t)
+       erc-autojoin-channels-alist
+       erc-server-buffer)
+
+    (should (memq 'autojoin erc-modules))
+
+    (ert-info ("Connect to foonet")
+      (setq erc-server-buffer (erc :server "127.0.0.1"
+                                   :port port
+                                   :nick "tester"
+                                   :password "changeme"
+                                   :full-name "tester"))
+      (with-current-buffer erc-server-buffer
+        (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
+        (funcall expect 10 "debug mode")))
+
+    (ert-info ("Wait for some output in channels")
+      (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan"))
+        (funcall expect 10 "welcome")))
+
+    (ert-info ("Server buffer shows connection failed")
+      (with-current-buffer erc-server-buffer
+        (funcall expect 10 "Connection failed!  Re-establishing")))
+
+    (should (equal erc-autojoin-channels-alist '((FooNet "#chan"))))
+
+    (funcall test)
+
+    (with-current-buffer "FooNet" (erc-cmd-JOIN "#spam"))
+
+    (erc-d-t-wait-for 5 "Channel #spam shown when autojoined"
+      (eq (window-buffer) (get-buffer "#spam")))
+
+    (ert-info ("Wait for auto reconnect")
+      (with-current-buffer erc-server-buffer
+        (funcall expect 10 "still in debug mode")))
+
+    (ert-info ("Wait for activity to recommence in channels")
+      (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan"))
+        (funcall expect 10 "forest of Arden"))
+      (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#spam"))
+        (funcall expect 10 "her elves come here anon")))))
+
+(ert-deftest erc-scenarios-base-reconnect-options--default ()
+  :tags '(:expensive-test)
+  (should (eq erc-join-buffer 'buffer))
+  (should-not erc-reconnect-display)
+
+  ;; FooNet (the server buffer) is not switched to because it's
+  ;; already current (but not shown) when `erc-open' is called.  See
+  ;; related conditional guard towards the end of that function.
+
+  (erc-scenarios-common--base-reconnect-options
+   (lambda ()
+     (pop-to-buffer-same-window "*Messages*")
+
+     (erc-d-t-ensure-for 1 "Server buffer not shown"
+       (not (eq (window-buffer) (get-buffer "FooNet"))))
+
+     (erc-d-t-wait-for 5 "Channel #chan shown when autojoined"
+       (eq (window-buffer) (get-buffer "#chan"))))))
+
+(ert-deftest erc-scenarios-base-reconnect-options--bury ()
+  :tags '(:expensive-test)
+  (should (eq erc-join-buffer 'buffer))
+  (should-not erc-reconnect-display)
+
+  (let ((erc-reconnect-display 'bury))
+    (erc-scenarios-common--base-reconnect-options
+
+     (lambda ()
+       (pop-to-buffer-same-window "*Messages*")
+
+       (erc-d-t-ensure-for 1 "Server buffer not shown"
+         (not (eq (window-buffer) (get-buffer "FooNet"))))
+
+       (erc-d-t-ensure-for 3 "Channel #chan not shown"
+         (not (eq (window-buffer) (get-buffer "#chan"))))
+
+       (eq (window-buffer) (messages-buffer))))))
+
+;; Upon reconnecting, playback for channel and target buffers is
+;; routed correctly.  Autojoin is irrelevant here, but for the
+;; skeptical, see `erc-scenarios-common--join-network-id', which
+;; overlaps with this and includes spurious JOINs ignored by the
+;; server.
+
+(ert-deftest erc-scenarios-base-association-reconnect-playback ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/assoc/reconplay")
+       (erc-server-flood-penalty 0.1)
+       (erc-server-flood-margin 30)
+       (dumb-server (erc-d-run "localhost" t 'foonet 'again))
+       (port (process-contact dumb-server :service))
+       (expect (erc-d-t-make-expecter))
+       erc-autojoin-channels-alist
+       erc-server-buffer-foo)
+
+    (ert-info ("Connect to foonet")
+      (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+                                       :port port
+                                       :nick "tester"
+                                       :password "changeme"
+                                       :full-name "tester"))
+      (with-current-buffer erc-server-buffer-foo
+        (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
+
+    (ert-info ("Setup")
+
+      (ert-info ("Server buffer is unique and temp name is absent")
+        (erc-d-t-wait-for 3 (get-buffer "foonet"))
+        (should-not (erc-scenarios-common-buflist "127.0.0.1")))
+
+      (ert-info ("Channel buffer #chan playback received")
+        (with-current-buffer (erc-d-t-wait-for 8 (get-buffer "#chan"))
+          (funcall expect 10 "But purgatory")))
+
+      (ert-info ("Ask for help from services or bouncer bot")
+        (with-current-buffer erc-server-buffer-foo
+          (erc-cmd-MSG "*status help")))
+
+      (ert-info ("Help received")
+        (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "*status"))
+          (funcall expect 10 "Rehash")))
+
+      (ert-info ("#chan convo done")
+        (with-current-buffer "#chan"
+          (funcall expect 10 "most egregious indignity"))))
+
+    ;; KLUDGE (see note above test)
+    (should erc-autojoin-channels-alist)
+    (setq erc-autojoin-channels-alist nil)
+
+    (with-current-buffer erc-server-buffer-foo
+      (erc-cmd-QUIT "")
+      (erc-d-t-wait-for 4 (not (erc-server-process-alive)))
+      (erc-cmd-RECONNECT))
+
+    (ert-info ("Channel buffer found and associated")
+      (with-current-buffer "#chan"
+        (funcall expect 10 "Wilt thou rest damned")))
+
+    (ert-info ("Help buffer found and associated")
+      (with-current-buffer "*status"
+        (erc-scenarios-common-say "help")
+        (funcall expect 10 "Restart ZNC")))
+
+    (ert-info ("#chan convo done")
+      (with-current-buffer "#chan"
+        (funcall expect 10 "here comes the lady")))))
+
+;;; erc-scenarios-base-reconnect.el ends here
diff --git a/test/lisp/erc/erc-scenarios-base-renick.el 
b/test/lisp/erc/erc-scenarios-base-renick.el
new file mode 100644
index 0000000000..bf27f61b3f
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-renick.el
@@ -0,0 +1,305 @@
+;;; 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.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(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))
+
+;; The server changes your nick just after registration.
+
+(ert-deftest erc-scenarios-base-renick-self-auto ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/renick/self")
+       (erc-server-flood-penalty 0.1)
+       (dumb-server (erc-d-run "localhost" t 'auto))
+       (port (process-contact dumb-server :service))
+       erc-autojoin-channels-alist
+       erc-server-buffer-foo)
+
+    (ert-info ("Connect to foonet")
+      (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+                                       :port port
+                                       :nick "tester"
+                                       :password "foonet:changeme"
+                                       :full-name "tester"))
+      (with-current-buffer erc-server-buffer-foo
+        (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
+
+    (with-current-buffer (erc-d-t-wait-for 3 (get-buffer "foonet"))
+      (erc-d-t-search-for 10 "Your new nickname is dummy"))
+
+    (ert-info ("Joined by bouncer to #foo, own nick present")
+      (with-current-buffer (erc-d-t-wait-for 1 (get-buffer "#foo"))
+        (erc-d-t-search-for 10 "dummy")
+        (erc-d-t-search-for 10 "On Thursday")))))
+
+;; You change your nickname manually in a server buffer; a message is
+;; printed in channel buffers.
+
+(ert-deftest erc-scenarios-base-renick-self-manual ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/renick/self")
+       (erc-server-flood-penalty 0.1)
+       (dumb-server (erc-d-run "localhost" t 'manual))
+       (port (process-contact dumb-server :service))
+       (expect (erc-d-t-make-expecter))
+       erc-autojoin-channels-alist
+       erc-server-buffer-foo)
+
+    (ert-info ("Connect to foonet")
+      (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+                                       :port port
+                                       :nick "tester"
+                                       :password "foonet:changeme"
+                                       :full-name "tester"))
+      (with-current-buffer erc-server-buffer-foo
+        (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
+
+    (erc-d-t-wait-for 3 (get-buffer "foonet"))
+
+    (ert-info ("Joined by bouncer to #foo, own nick present")
+      (with-current-buffer (erc-d-t-wait-for 1 (get-buffer "#foo"))
+        (funcall expect 5 "tester")
+        (funcall expect 5 "On Thursday")
+        (erc-with-server-buffer (erc-cmd-NICK "dummy"))
+        (funcall expect 5 "Your new nickname is dummy")
+        (funcall expect 5 "<bob> dummy: Hi")
+        ;; Regression in which changing a nick would trigger #foo@foonet
+        (erc-d-t-ensure-for 0.4 (equal (buffer-name) "#foo"))))))
+
+;; You connect to the same network with two different nicks.  You
+;; manually change the first nick at some point, and buffer names are
+;; updated correctly.
+
+(ert-deftest erc-scenarios-base-renick-self-qualified ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/renick/self")
+       (dumb-server (erc-d-run "localhost" t 'qual-tester 'qual-chester))
+       (port (process-contact dumb-server :service))
+       (expect (erc-d-t-make-expecter))
+       (erc-server-flood-penalty 0.1)
+       (erc-server-flood-margin 30)
+       erc-serv-buf-a erc-serv-buf-b)
+
+    (ert-info ("Connect to foonet with nick tester")
+      (with-current-buffer
+          (setq erc-serv-buf-a (erc :server "127.0.0.1"
+                                    :port port
+                                    :nick "tester"
+                                    :password "changeme"
+                                    :full-name "tester"))
+        (erc-d-t-wait-for 5 (eq erc-network 'foonet))))
+
+    (ert-info ("Connect to foonet with nick chester")
+      (with-current-buffer
+          (setq erc-serv-buf-b (erc :server "127.0.0.1"
+                                    :port port
+                                    :nick "chester"
+                                    :password "changeme"
+                                    :full-name "chester"))))
+
+    (erc-d-t-wait-for 3 "Dialed Buflist is Empty"
+      (not (erc-scenarios-common-buflist "127.0.0.1")))
+
+    (with-current-buffer  "foonet/tester"
+      (funcall expect 3 "debug mode")
+      (erc-cmd-JOIN "#chan"))
+
+    (with-current-buffer  "foonet/chester"
+      (funcall expect 3 "debug mode")
+      (erc-cmd-JOIN "#chan"))
+
+    (erc-d-t-wait-for 10 (get-buffer "#chan@foonet/tester"))
+    (erc-d-t-wait-for 10 (get-buffer "#chan@foonet/chester"))
+
+    (ert-info ("Greets other nick in same channel")
+      (with-current-buffer "#chan@foonet/tester"
+        (funcall expect 5 "<bob> chester, welcome!")
+        (erc-cmd-NICK "dummy")
+        (funcall expect 5 "Your new nickname is dummy")
+        (funcall expect 5 "find the forester")
+        (erc-d-t-wait-for 5 (string= (buffer-name) "#chan@foonet/dummy"))))
+
+    (ert-info ("Renick propagated throughout all buffers of process")
+      (should-not (get-buffer "#chan@foonet/tester"))
+      (should-not (get-buffer "foonet/tester"))
+      (should (get-buffer "foonet/dummy")))))
+
+;; When a channel user changes their nick, any query buffers for them
+;; are updated.
+
+(ert-deftest erc-scenarios-base-renick-queries-solo ()
+  :tags '(:expensive-test)
+
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/renick/queries")
+       (erc-server-flood-penalty 0.1)
+       (erc-server-flood-margin 20)
+       (dumb-server (erc-d-run "localhost" t 'solo))
+       (port (process-contact dumb-server :service))
+       erc-autojoin-channels-alist
+       erc-server-buffer-foo)
+
+    (ert-info ("Connect to foonet")
+      (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+                                       :port port
+                                       :nick "tester"
+                                       :password "foonet:changeme"
+                                       :full-name "tester"))
+      (with-current-buffer erc-server-buffer-foo
+        (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
+
+    (erc-d-t-wait-for 1 (get-buffer "foonet"))
+
+    (ert-info ("Joined by bouncer to #foo, pal persent")
+      (with-current-buffer (erc-d-t-wait-for 1 (get-buffer "#foo"))
+        (erc-d-t-search-for 1 "On Thursday")
+        (erc-scenarios-common-say "hi")))
+
+    (erc-d-t-wait-for 10 "Query buffer appears with message from pal"
+      (get-buffer "Lal"))
+
+    (ert-info ("Chat with pal, who changes name")
+      (with-current-buffer "Lal"
+        (erc-d-t-search-for 3 "hello")
+        (erc-scenarios-common-say "hi")
+        (erc-d-t-search-for 10 "is now known as Linguo")
+        (should-not (search-forward "is now known as Linguo" nil t))))
+
+    (erc-d-t-wait-for 1 (get-buffer "Linguo"))
+    (should-not (get-buffer "Lal"))
+
+    (with-current-buffer "Linguo" (erc-scenarios-common-say "howdy Linguo"))
+
+    (with-current-buffer "#foo"
+      (erc-d-t-search-for 10 "is now known as Linguo")
+      (should-not (search-forward "is now known as Linguo" nil t))
+      (erc-cmd-PART ""))
+
+    (with-current-buffer "Linguo"
+      (erc-d-t-search-for 10 "get along"))))
+
+;; You share a channel and a query buffer with a user on two different
+;; networks (through a proxy).  The user changes their nick on both
+;; networks at the same time.  Query buffers are updated accordingly.
+
+(ert-deftest erc-scenarios-base-renick-queries-bouncer ()
+  :tags '(:expensive-test)
+
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/renick/queries")
+       (erc-server-flood-penalty 0.1)
+       (erc-server-flood-margin 30)
+       (dumb-server (erc-d-run "localhost" t 'bouncer-foonet 'bouncer-barnet))
+       (port (process-contact dumb-server :service))
+       (expect (erc-d-t-make-expecter))
+       erc-accidental-paste-threshold-seconds
+       erc-autojoin-channels-alist
+       erc-server-buffer-foo
+       erc-server-buffer-bar)
+
+    (ert-info ("Connect to foonet")
+      (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+                                       :port port
+                                       :nick "tester"
+                                       :password "foonet:changeme"
+                                       :full-name "tester"))
+      (with-current-buffer erc-server-buffer-foo
+        (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
+
+    (erc-d-t-wait-for 5 (get-buffer "foonet"))
+
+    (ert-info ("Connect to barnet")
+      (setq erc-server-buffer-bar (erc :server "127.0.0.1"
+                                       :port port
+                                       :nick "tester"
+                                       :password "barnet:changeme"
+                                       :full-name "tester"))
+      (with-current-buffer erc-server-buffer-bar
+        (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
+
+    (erc-d-t-wait-for 5 (get-buffer "barnet"))
+    (should-not (erc-scenarios-common-buflist "127.0.0.1"))
+
+    (ert-info ("Joined by bouncer to #chan@foonet, pal persent")
+      (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan@foonet"))
+        (funcall expect 1 "rando")
+        (funcall expect 1 "simply misused")))
+
+    (ert-info ("Joined by bouncer to #chan@barnet, pal persent")
+      (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan@barnet"))
+        (funcall expect 1 "rando")
+        (funcall expect 2 "come, sir, I am")))
+
+    (ert-info ("Query buffer exists for rando@foonet")
+      (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "rando@foonet"))
+        (funcall expect 1 "guess not")
+        (erc-scenarios-common-say "I here")))
+
+    (ert-info ("Query buffer exists for rando@barnet")
+      (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "rando@barnet"))
+        (funcall expect 2 "rentacop")
+        (erc-scenarios-common-say "Linda said you were gonna kill me.")))
+
+    (ert-info ("Sync convo for rando@foonet")
+      (with-current-buffer "rando@foonet"
+        (funcall expect 1 "u are dumb")
+        (erc-scenarios-common-say "not so")))
+
+    (ert-info ("Sync convo for rando@barnet")
+      (with-current-buffer "rando@barnet"
+        (funcall expect 3 "I never saw her before")
+        (erc-scenarios-common-say "You aren't with Wage?")))
+
+    (erc-d-t-wait-for 3 (get-buffer "frenemy@foonet"))
+    (erc-d-t-wait-for 3 (get-buffer "frenemy@barnet"))
+    (should-not (get-buffer "rando@foonet"))
+    (should-not (get-buffer "rando@barnet"))
+
+    (with-current-buffer "frenemy@foonet"
+      (funcall expect 1 "now known as")
+      (funcall expect 1 "doubly so"))
+
+    (with-current-buffer "frenemy@barnet"
+      (funcall expect 1 "now known as")
+      (funcall expect 1 "reality picture"))
+
+    (when noninteractive
+      (with-current-buffer "frenemy@barnet" (kill-buffer))
+      (erc-d-t-wait-for 2 (get-buffer "frenemy"))
+      (should-not (get-buffer "frenemy@foonet")))
+
+    (with-current-buffer "#chan@foonet"
+      (funcall expect 10 "is now known as frenemy")
+      (should-not (search-forward "now known as frenemy" nil t)) ; regression
+      (funcall expect 10 "words are razors"))
+
+    (with-current-buffer "#chan@barnet"
+      (funcall expect 10 "is now known as frenemy")
+      (should-not (search-forward "now known as frenemy" nil t))
+      (erc-d-t-search-for 25 "I have lost"))))
+
+;;; erc-scenarios-base-renick.el ends here
diff --git a/test/lisp/erc/erc-scenarios-base-reuse-buffers.el 
b/test/lisp/erc/erc-scenarios-base-reuse-buffers.el
new file mode 100644
index 0000000000..f134f3ffb6
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-reuse-buffers.el
@@ -0,0 +1,238 @@
+;;; 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.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(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))
+
+(defun erc-scenarios-common--base-reuse-buffers-server-buffers (&optional more)
+  "Show that `erc-reuse-buffers' doesn't affect server buffers.
+Overlaps some with `clash-of-chans/uniquify'.  Adapted from
+rebuffed/reuseless, described in Bug#48598: 28.0.50; buffer-naming
+collisions involving bouncers in ERC.  Run EXTRA."
+  (erc-scenarios-common-with-cleanup
+      ((dumb-server (erc-d-run "localhost" t 'foonet 'barnet))
+       (port (process-contact dumb-server :service))
+       erc-autojoin-channels-alist)
+
+    (ert-info ("Connect to foonet")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :nick "tester"
+                                :password "foonet:changeme"
+                                :full-name "tester")
+        (should (string= (buffer-name)
+                         (format "127.0.0.1:%d/127.0.0.1" port)))
+        (erc-d-t-search-for 12 "marked as being away")))
+
+    (ert-info ("Connect to barnet")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :nick "tester"
+                                :password "barnet:changeme"
+                                :full-name "tester")
+        (should (string= (buffer-name)
+                         (format "127.0.0.1:%d/127.0.0.1<2>" port)))
+        (erc-d-t-search-for 45 "marked as being away")))
+
+    (erc-d-t-wait-for 2 (get-buffer (format "127.0.0.1:%d/127.0.0.1" port)))
+    (erc-d-t-wait-for 2 (get-buffer (format "127.0.0.1:%d/127.0.0.1<2>" port)))
+
+    (ert-info ("Server buffers are unique, no IP-based names")
+      (should (cdr (erc-scenarios-common-buflist "127.0.0.1"))))
+    (when more (funcall more port))))
+
+;; XXX maybe remove: already covered many times over by other scenarios
+(ert-deftest erc-scenarios-base-reuse-buffers-server-buffers--enabled ()
+  :tags '(:expensive-test)
+  (with-suppressed-warnings ((obsolete erc-reuse-buffers))
+    (should erc-reuse-buffers))
+  (let ((erc-scenarios-common-dialog "base/reuse-buffers/server"))
+    (erc-scenarios-common-with-cleanup
+        ((dumb-server (erc-d-run "localhost" t 'foonet 'barnet))
+         (port (process-contact dumb-server :service))
+         erc-autojoin-channels-alist)
+
+      (ert-info ("Connect to foonet")
+        (with-current-buffer (erc :server "127.0.0.1"
+                                  :port port
+                                  :nick "tester"
+                                  :password "foonet:changeme"
+                                  :full-name "tester")
+          (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
+          (erc-d-t-search-for 12 "marked as being away")))
+
+      (ert-info ("Connect to barnet")
+        (with-current-buffer (erc :server "127.0.0.1"
+                                  :port port
+                                  :nick "tester"
+                                  :password "barnet:changeme"
+                                  :full-name "tester")
+          (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
+          (erc-d-t-search-for 45 "marked as being away")))
+
+      (erc-d-t-wait-for 2 (get-buffer "foonet"))
+      (erc-d-t-wait-for 2 (get-buffer "barnet"))
+
+      (ert-info ("Server buffers are unique, no IP-based names")
+        (should-not (eq (get-buffer "foonet") (get-buffer "barnet")))
+        (should-not (erc-scenarios-common-buflist "127.0.0.1"))))))
+
+;; FIXME no sense in running this twice (JOIN variant includes this)
+(ert-deftest erc-scenarios-base-reuse-buffers-server-buffers--disabled ()
+  :tags '(:expensive-test)
+  (with-suppressed-warnings ((obsolete erc-reuse-buffers))
+    (should erc-reuse-buffers)
+    (let ((erc-scenarios-common-dialog "base/reuse-buffers/server")
+          erc-reuse-buffers)
+      (erc-scenarios-common--base-reuse-buffers-server-buffers nil))))
+
+;; This also asserts that `erc-cmd-JOIN' is no longer susceptible to a
+;; regression introduced in 28.1 (ERC 5.4) that caused phantom target
+;; buffers of the form target/server to be created via
+;; `switch-to-buffer' ("phantom" because they would go unused").  This
+;; would happen (in place of a JOIN being sent out) when a previously
+;; used (parted) target buffer existed and `erc-reuse-buffers' was
+;; nil.
+;;
+;; Note: All the `erc-get-channel-user' calls have to do with the fact
+;; that `erc-default-target' relies on the ambiguously defined
+;; `erc-default-recipients' (meaning it's overloaded in the sense of
+;; being used both for retrieving a target name and checking if a
+;; channel has been PARTed).  While not ideal, `erc-get-channel-user'
+;; can (also) be used to detect the latter.
+
+(defun erc-scenarios-common--base-reuse-buffers-channel-buffers (port)
+  "The option `erc-reuse-buffers' is still respected when nil.
+Adapted from scenario clash-of-chans/uniquify described in Bug#48598:
+28.0.50; buffer-naming collisions involving bouncers in ERC."
+  (let* ((expect (erc-d-t-make-expecter))
+         (server-buffer-foo
+          (get-buffer (format "127.0.0.1:%d/127.0.0.1" port)))
+         (server-buffer-bar
+          (get-buffer (format "127.0.0.1:%d/127.0.0.1<2>" port)))
+         (chan-buffer-foo (get-buffer "#chan/127.0.0.1"))
+         (chan-buffer-bar (get-buffer "#chan/127.0.0.1<2>"))
+         (server-process-foo (with-current-buffer server-buffer-foo
+                               erc-server-process))
+         (server-process-bar (with-current-buffer server-buffer-bar
+                               erc-server-process)))
+
+    (ert-info ("Unique #chan buffers exist")
+      (let ((chan-bufs (erc-scenarios-common-buflist "#chan"))
+            (known (list chan-buffer-bar chan-buffer-foo)))
+        (should (memq (pop chan-bufs) known))
+        (should (memq (pop chan-bufs) known))
+        (should-not chan-bufs)))
+
+    (ert-info ("#chan@foonet is exclusive and not contaminated")
+      (with-current-buffer chan-buffer-foo
+        (funcall expect 1 "<bob>")
+        (erc-d-t-absent-for 0.1 "<joe>")
+        (funcall expect 1 "strength to climb")
+        (should (eq erc-server-process server-process-foo))))
+
+    (ert-info ("#chan@barnet is exclusive and not contaminated")
+      (with-current-buffer chan-buffer-bar
+        (funcall expect 1 "<joe>")
+        (erc-d-t-absent-for 0.1 "<bob>")
+        (funcall expect 1 "the loudest noise")
+        (should (eq erc-server-process server-process-bar))))
+
+    (ert-info ("Part #chan@foonet")
+      (with-current-buffer chan-buffer-foo
+        (erc-d-t-search-for 1 "shake my sword")
+        (erc-cmd-PART "#chan")
+        (funcall expect 3 "You have left channel #chan")
+        (erc-cmd-JOIN "#chan")))
+
+    (ert-info ("Part #chan@barnet")
+      (with-current-buffer chan-buffer-bar
+        (funcall expect 10 "Arm it in rags")
+        (should (erc-get-channel-user (erc-current-nick)))
+        (erc-cmd-PART "#chan")
+        (funcall expect 3 "You have left channel #chan")
+        (should-not (erc-get-channel-user (erc-current-nick)))
+        (erc-cmd-JOIN "#chan")))
+
+    (erc-d-t-wait-for 3 "New unique target buffer for #chan@foonet created"
+      (get-buffer "#chan/127.0.0.1<3>"))
+
+    (ert-info ("Activity continues in new, <n>-suffixed #chan@foonet buffer")
+      (with-current-buffer chan-buffer-foo
+        (should-not (erc-get-channel-user (erc-current-nick))))
+      (with-current-buffer "#chan/127.0.0.1<3>"
+        (should (erc-get-channel-user (erc-current-nick)))
+        (funcall expect 2 "You have joined channel #chan")
+        (funcall expect 2 "#chan was created on")
+        (funcall expect 2 "<alice>")
+        (should (eq erc-server-process server-process-foo))
+        (erc-d-t-absent-for 0.2 "<joe>")))
+
+    (sit-for 3)
+    (erc-d-t-wait-for 5 "New unique target buffer for #chan@barnet created"
+      (get-buffer "#chan/127.0.0.1<4>"))
+
+    (ert-info ("Activity continues in new, <n>-suffixed #chan@barnet buffer")
+      (with-current-buffer chan-buffer-bar
+        (should-not (erc-get-channel-user (erc-current-nick))))
+      (with-current-buffer "#chan/127.0.0.1<4>"
+        (funcall expect 2 "You have joined channel #chan")
+        (funcall expect 1 "Users on #chan: @mike joe tester")
+        (funcall expect 2 "<mike>")
+        (should (eq erc-server-process server-process-bar))
+        (erc-d-t-absent-for 0.2 "<bob>")))
+
+    (ert-info ("Two new chans created for a total of four")
+      (let* ((bufs (erc-scenarios-common-buflist "#chan"))
+             (names (sort (mapcar #'buffer-name bufs) #'string<)))
+        (should
+         (equal names (mapcar (lambda (f) (concat "#chan/127.0.0.1" f))
+                              '("" "<2>" "<3>" "<4>"))))))
+
+    (ert-info ("All output sent")
+      (with-current-buffer "#chan/127.0.0.1<3>"
+        (funcall expect 10 "most lively"))
+      (with-current-buffer "#chan/127.0.0.1<4>"
+        (funcall expect 10 "soul black")))
+
+    ;; TODO ensure the exact <N>'s aren't reassigned during killing as
+    ;; they are when the option is on.
+    (ert-info ("Buffers are exempt from shortening")
+      (kill-buffer "#chan/127.0.0.1<4>")
+      (kill-buffer "#chan/127.0.0.1<3>")
+      (kill-buffer chan-buffer-bar)
+      (should-not (get-buffer "#chan"))
+      (should chan-buffer-foo))))
+
+(ert-deftest erc-scenarios-base-reuse-buffers-channel-buffers--disabled ()
+  :tags '(:expensive-test :unstable)
+  (with-suppressed-warnings ((obsolete erc-reuse-buffers))
+    (should erc-reuse-buffers)
+    (let ((erc-scenarios-common-dialog "base/reuse-buffers/channel")
+          (erc-server-flood-penalty 0.1)
+          erc-reuse-buffers)
+      (erc-scenarios-common--base-reuse-buffers-server-buffers
+       #'erc-scenarios-common--base-reuse-buffers-channel-buffers))))
+
+;;; erc-scenarios-base-reuse-buffers.el ends here
diff --git a/test/lisp/erc/erc-scenarios-base-unstable.el 
b/test/lisp/erc/erc-scenarios-base-unstable.el
new file mode 100644
index 0000000000..2313a15842
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-unstable.el
@@ -0,0 +1,134 @@
+;;; 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.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(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))
+
+;; Not unstable, but stashed here for now
+
+(ert-deftest erc-scenarios-aux-unix-socket ()
+  :tags '(:expensive-test)
+  (skip-unless (featurep 'make-network-process '(:family local)))
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/renick/self")
+       (erc-server-flood-penalty 0.1)
+       (sock (expand-file-name "erc-d.sock" temporary-file-directory))
+       (erc-scenarios-common-extra-teardown (lambda () (delete-file sock)))
+       (erc-server-connect-function
+        (lambda (n b _ p &rest r)
+          (apply #'make-network-process
+                 `(:name ,n :buffer ,b :service ,p :family local ,@r))))
+       (dumb-server (erc-d-run nil sock 'auto))
+       erc-autojoin-channels-alist
+       erc-server-buffer-foo)
+
+    (ert-info ("Connect to foonet")
+      (setq erc-server-buffer-foo (erc :server "fake"
+                                       :port sock
+                                       :nick "tester"
+                                       :password "foonet:changeme"
+                                       :full-name "tester"))
+      (with-current-buffer erc-server-buffer-foo
+        (should (string= (buffer-name) (format "fake:%s" sock)))))
+
+    (with-current-buffer (erc-d-t-wait-for 3 (get-buffer "foonet"))
+      (erc-d-t-search-for 10 "Your new nickname is dummy"))
+
+    (ert-info ("Joined by bouncer to #foo, own nick present")
+      (with-current-buffer (erc-d-t-wait-for 3 (get-buffer "#foo"))
+        (erc-d-t-search-for 10 "dummy")
+        (erc-d-t-search-for 10 "On Thursday")))))
+
+;; See `erc-networks--rename-server-buffer'.  A perceived loss in
+;; network connectivity turns out to be a false alarm, but the bouncer
+;; has already accepted the second connection
+
+(defun erc-scenarios--base-aborted-reconnect ()
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/reconnect")
+       (erc-d-t-cleanup-sleep-secs 1)
+       (dumb-server (erc-d-run "localhost" t 'aborted 'aborted-dupe))
+       (port (process-contact dumb-server :service))
+       erc-autojoin-channels-alist
+       erc-server-buffer-foo)
+
+    (ert-info ("Connect to foonet")
+      (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+                                       :port port
+                                       :nick "tester"
+                                       :password "changeme"
+                                       :full-name "tester"))
+      (with-current-buffer erc-server-buffer-foo
+        (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
+
+    (ert-info ("Server buffer is unique and temp name is absent")
+      (erc-d-t-wait-for 10 (get-buffer "FooNet"))
+      (should-not (erc-scenarios-common-buflist "127.0.0.1"))
+      (with-current-buffer erc-server-buffer-foo
+        (erc-cmd-JOIN "#chan")))
+
+    (ert-info ("Channel buffer #chan alive and well")
+      (with-current-buffer (erc-d-t-wait-for 4 (get-buffer "#chan"))
+        (erc-d-t-search-for 10 "welcome")))
+
+    (ert-info ("Connect to foonet again")
+      (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+                                       :port port
+                                       :nick "tester"
+                                       :password "changeme"
+                                       :full-name "tester"))
+      (let ((inhibit-message noninteractive))
+        (with-current-buffer erc-server-buffer-foo
+          (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
+          (erc-d-t-wait-for 5 (not (erc-server-process-alive)))
+          (erc-d-t-search-for 10 "FooNet still connected"))))
+
+    (ert-info ("Server buffer is unique and temp name is absent")
+      (should (equal (list (get-buffer "FooNet"))
+                     (erc-scenarios-common-buflist "FooNet")))
+      (should (equal (list (get-buffer (format "127.0.0.1:%d" port)))
+                     (erc-scenarios-common-buflist "127.0.0.1"))))
+
+    (ert-info ("Channel buffer #chan still going")
+      (with-current-buffer "#chan"
+        (erc-d-t-search-for 10 "and be prosperous")))))
+
+(ert-deftest erc-scenarios-base-aborted-reconnect ()
+  :tags '(:unstable)
+  (let ((tries 3)
+        (timeout 1)
+        failed)
+    (while (condition-case _err
+               (progn
+                 (erc-scenarios--base-aborted-reconnect)
+                 nil)
+             (ert-test-failed
+              (message "Test %S failed; %s attempt(s) remaining."
+                       (ert-test-name (ert-running-test))
+                       tries)
+              (sleep-for (cl-incf timeout))
+              (not (setq failed (zerop (cl-decf tries)))))))
+    (should-not failed)))
+
+;;; erc-scenarios-base-unstable.el ends here
diff --git a/test/lisp/erc/erc-scenarios-base-upstream-recon-soju.el 
b/test/lisp/erc/erc-scenarios-base-upstream-recon-soju.el
new file mode 100644
index 0000000000..5a5b363f31
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-upstream-recon-soju.el
@@ -0,0 +1,43 @@
+;;; 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.
+;;
+;; 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:
+;;
+;; These concern the loss and recovery of a proxy's IRC-side connection.
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(ert-deftest erc-scenarios-upstream-recon--soju ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--upstream-reconnect
+   (lambda ()
+     (with-current-buffer "foonet"
+       (erc-d-t-search-for 1 "disconnected from foonet")
+       (erc-d-t-search-for 1 "connected from foonet"))
+     (with-current-buffer "barnet"
+       (erc-d-t-search-for 1 "disconnected from barnet")
+       (erc-d-t-search-for 1 "connected from barnet")))
+   'soju-foonet
+   'soju-barnet))
+
+;;; erc-scenarios-upstream-recon-soju.el ends here
diff --git a/test/lisp/erc/erc-scenarios-base-upstream-recon-znc.el 
b/test/lisp/erc/erc-scenarios-base-upstream-recon-znc.el
new file mode 100644
index 0000000000..6e9a217245
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-upstream-recon-znc.el
@@ -0,0 +1,43 @@
+;;; 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.
+;;
+;; 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:
+;;
+;; These concern the loss and recovery of a proxy's IRC-side connection.
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(ert-deftest erc-scenarios-upstream-recon--znc ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--upstream-reconnect
+   (lambda ()
+     (with-current-buffer "*status@foonet"
+       (erc-d-t-search-for 1 "Disconnected from IRC")
+       (erc-d-t-search-for 1 "Connected!"))
+     (with-current-buffer "*status@barnet"
+       (erc-d-t-search-for 1 "Disconnected from IRC")
+       (erc-d-t-search-for 1 "Connected!")))
+   'znc-foonet
+   'znc-barnet))
+
+;;; erc-scenarios-upstream-recon-znc.el ends here
diff --git a/test/lisp/erc/erc-scenarios-internal.el 
b/test/lisp/erc/erc-scenarios-internal.el
new file mode 100644
index 0000000000..e4e1edb97e
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-internal.el
@@ -0,0 +1,27 @@
+;;; 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.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (expand-file-name "erc-d" (ert-resource-directory))
+                         load-path)))
+    (load "erc-d-tests" nil 'silent)))
+
+;;; erc-scenarios-internal.el ends here
diff --git a/test/lisp/erc/erc-scenarios-join-auth-source.el 
b/test/lisp/erc/erc-scenarios-join-auth-source.el
new file mode 100644
index 0000000000..94336db07c
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-join-auth-source.el
@@ -0,0 +1,67 @@
+;;; 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.
+;;
+;; 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:
+
+;; TODO add another test with autojoin and channel keys
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(ert-deftest erc-scenarios-join-auth-source--network ()
+  :tags '(:expensive-test)
+  (should erc-auth-source-join-function)
+  (erc-scenarios-common-with-cleanup
+      ((entries
+        '("machine 127.0.0.1 port %d login \"#foo\" password spam"
+          "machine irc.foonet.org port %d login tester password fake"
+          "machine irc.foonet.org login \"#spam\" password secret"
+          "machine foonet port %d login dummy password fake"
+          "machine 127.0.0.1 port %d login dummy password changeme"))
+       (erc-scenarios-common-dialog "join/auth-source")
+       (erc-server-flood-penalty 0.1)
+       (dumb-server (erc-d-run "localhost" t 'foonet))
+       (port (process-contact dumb-server :service))
+       (ents (mapcar (lambda (fmt) (format fmt port)) entries))
+       (netrc-file (make-temp-file "auth-source-test" nil nil
+                                   (string-join ents "\n")))
+       (auth-sources (list netrc-file))
+       (auth-source-do-cache nil)
+       (expect (erc-d-t-make-expecter))
+       (erc-scenarios-common-extra-teardown (lambda ()
+                                              (delete-file netrc-file))))
+
+    (ert-info ("Connect without password")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :nick "dummy"
+                                :full-name "dummy")
+        (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
+        (erc-d-t-wait-for 8 (eq erc-network 'foonet))
+        (funcall expect 10 "user modes")
+        (erc-scenarios-common-say "/JOIN #spam")))
+
+    (ert-info ("Join #spam")
+      (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#spam"))
+        (funcall expect 10 "#spam was created on")))))
+
+;;; erc-scenarios-join-auth-source.el ends here
diff --git a/test/lisp/erc/erc-scenarios-join-netid-newcmd-id.el 
b/test/lisp/erc/erc-scenarios-join-netid-newcmd-id.el
new file mode 100644
index 0000000000..e2e437321d
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-join-netid-newcmd-id.el
@@ -0,0 +1,50 @@
+;;; 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.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(ert-deftest erc-scenarios-join-netid--newcmd-id ()
+  :tags '(:expensive-test)
+  (let ((connect (lambda ()
+                   (erc :server "127.0.0.1"
+                        :port (with-current-buffer "oofnet"
+                                (process-contact erc-server-process :service))
+                        :nick "tester"
+                        :password "foonet:changeme"
+                        :full-name "tester"
+                        :id 'oofnet))))
+    (erc-scenarios-common--join-network-id connect 'oofnet nil)))
+
+(ert-deftest erc-scenarios-join-netid--newcmd-ids ()
+  :tags '(:expensive-test)
+  (let ((connect (lambda ()
+                   (erc :server "127.0.0.1"
+                        :port (with-current-buffer "oofnet"
+                                (process-contact erc-server-process :service))
+                        :nick "tester"
+                        :password "foonet:changeme"
+                        :full-name "tester"
+                        :id 'oofnet))))
+    (erc-scenarios-common--join-network-id connect 'oofnet 'rabnet)))
+
+;;; erc-scenarios-join-netid-newcmd-id.el ends here
diff --git a/test/lisp/erc/erc-scenarios-join-netid-newcmd.el 
b/test/lisp/erc/erc-scenarios-join-netid-newcmd.el
new file mode 100644
index 0000000000..1a541a46b3
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-join-netid-newcmd.el
@@ -0,0 +1,37 @@
+;;; 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.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(ert-deftest erc-scenarios-join-netid--newcmd ()
+  :tags '(:expensive-test)
+  (let ((connect (lambda ()
+                   (erc :server "127.0.0.1"
+                        :port (with-current-buffer "foonet"
+                                (process-contact erc-server-process :service))
+                        :nick "tester"
+                        :password "foonet:changeme"
+                        :full-name "tester"))))
+    (erc-scenarios-common--join-network-id connect nil nil)))
+
+;;; erc-scenarios-join-netid-newcmd.el ends here
diff --git a/test/lisp/erc/erc-scenarios-join-netid-recon-id.el 
b/test/lisp/erc/erc-scenarios-join-netid-recon-id.el
new file mode 100644
index 0000000000..92bdd643de
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-join-netid-recon-id.el
@@ -0,0 +1,46 @@
+;;; 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.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(ert-deftest erc-scenarios-join-netid--recon-id ()
+  :tags '(:expensive-test)
+  (let ((connect (lambda ()
+                   (with-current-buffer "oofnet"
+                     (erc-cmd-RECONNECT)
+                     (should (eq (current-buffer)
+                                 (process-buffer erc-server-process)))
+                     (current-buffer)))))
+    (erc-scenarios-common--join-network-id connect 'oofnet nil)))
+
+(ert-deftest erc-scenarios-join-netid--recon-ids ()
+  :tags '(:expensive-test)
+  (let ((connect (lambda ()
+                   (with-current-buffer "oofnet"
+                     (erc-cmd-RECONNECT)
+                     (should (eq (current-buffer)
+                                 (process-buffer erc-server-process)))
+                     (current-buffer)))))
+    (erc-scenarios-common--join-network-id connect 'oofnet 'rabnet)))
+
+;;; erc-scenarios-join-netid-recon-id.el ends here
diff --git a/test/lisp/erc/erc-scenarios-join-netid-recon.el 
b/test/lisp/erc/erc-scenarios-join-netid-recon.el
new file mode 100644
index 0000000000..cbdba07e25
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-join-netid-recon.el
@@ -0,0 +1,36 @@
+;;; 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.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(ert-deftest erc-scenarios-join-netid--recon ()
+  :tags '(:expensive-test)
+  (let ((connect (lambda ()
+                   (with-current-buffer "foonet"
+                     (erc-cmd-RECONNECT)
+                     (should (eq (current-buffer)
+                                 (process-buffer erc-server-process)))
+                     (current-buffer)))))
+    (erc-scenarios-common--join-network-id connect nil nil)))
+
+;;; erc-scenarios-join-netid-recon.el ends here
diff --git a/test/lisp/erc/erc-scenarios-misc.el 
b/test/lisp/erc/erc-scenarios-misc.el
new file mode 100644
index 0000000000..ded620ccc1
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-misc.el
@@ -0,0 +1,180 @@
+;;; 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.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(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))
+
+(ert-deftest erc-scenarios-base-flood ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/flood")
+       (dumb-server (erc-d-run "localhost" t 'soju))
+       (port (process-contact dumb-server :service))
+       (erc-server-flood-penalty 0.5) ; this ratio MUST match
+       (erc-server-flood-margin 1.5) ;  the default of 3:10
+       (expect (erc-d-t-make-expecter))
+       erc-autojoin-channels-alist)
+
+    (ert-info ("Connect to bouncer")
+      (with-current-buffer
+          (erc :server "127.0.0.1"
+               :port port
+               :nick "tester"
+               :password "changeme"
+               :full-name "tester")
+        (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
+        (funcall expect 5 "Soju")))
+
+    (ert-info ("#chan@foonet exists")
+      (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan/foonet"))
+        (erc-d-t-search-for 2 "<bob/foonet>")
+        (erc-d-t-absent-for 0.1 "<joe")
+        (funcall expect 3 "was created on")))
+
+    (ert-info ("#chan@barnet exists")
+      (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan/barnet"))
+        (erc-d-t-search-for 2 "<joe/barnet>")
+        (erc-d-t-absent-for 0.1 "<bob")
+        (funcall expect 3 "was created on")
+        (funcall expect 5 "To get good guard")))
+
+    (ert-info ("Message not held in queue limbo")
+      (with-current-buffer "#chan/foonet"
+        ;; Without 'no-penalty param in `erc-server-send', should fail
+        ;; after ~10 secs with:
+        ;;
+        ;;   (erc-d-timeout "Timed out awaiting request: (:name ~privmsg
+        ;;    :pattern \\`PRIVMSG #chan/foonet :alice: hi :timeout 2
+        ;;    :dialog soju)")
+        ;;
+        ;; Try reversing commit and spying on queue interactively
+        (erc-cmd-MSG "#chan/foonet alice: hi")
+        (funcall expect 5 "tester: Good, very good")))
+
+    (ert-info ("All output sent")
+      (with-current-buffer "#chan/foonet"
+        (funcall expect 8 "Some man or other"))
+      (with-current-buffer "#chan/barnet"
+        (funcall expect 10 "That's he that was Othello")))))
+
+;; Corner case demoing fallback behavior for an absent 004 RPL but a
+;; present 422 or 375.  If this is unlikely enough, remove or guard
+;; with `ert-skip' plus some condition so it only runs when explicitly
+;; named via ERT specifier
+
+(ert-deftest erc-scenarios-networks-announced-missing ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "networks/announced-missing")
+       (expect (erc-d-t-make-expecter))
+       (dumb-server (erc-d-run "localhost" t 'foonet))
+       (port (process-contact dumb-server :service)))
+
+    (ert-info ("Connect without password")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :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)
+        (should (string= erc-server-announced-name "irc.foonet.org"))))))
+
+;; Targets that are host/server masks like $*, $$*, and #* are routed
+;; to the server buffer: https://github.com/ircdocs/wooooms/issues/5
+
+(ert-deftest erc-scenarios-base-mask-target-routing ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/mask-target-routing")
+       (dumb-server (erc-d-run "localhost" t 'foonet))
+       (port (process-contact dumb-server :service))
+       (expect (erc-d-t-make-expecter)))
+
+    (ert-info ("Connect to foonet")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :nick "tester"
+                                :password "changeme"
+                                :full-name "tester")
+        (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
+
+    (erc-d-t-wait-for 10 (get-buffer "foonet"))
+
+    (ert-info ("Channel buffer #foo playback received")
+      (with-current-buffer (erc-d-t-wait-for 3 (get-buffer "#foo"))
+        (funcall expect 10 "Excellent workman")))
+
+    (ert-info ("Global notices routed to server buffer")
+      (with-current-buffer "foonet"
+        (funcall expect 10 "going down soon")
+        (funcall expect 10 "this is a warning")
+        (funcall expect 10 "second warning")
+        (funcall expect 10 "final warning")))
+
+    (should-not (get-buffer "$*"))))
+
+(ert-deftest erc-scenarios-dcc-chat-accept ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "dcc/chat")
+       (dcc-server (erc-d-run "127.0.0.1" t "erc-dcc-server" 'accept-dcc
+                              :ending "\n"))
+       (dcc-port (process-contact dcc-server :service))
+       (dumb-server (erc-d-run "localhost" t 'accept :tmpl-vars
+                               `((port . ,(number-to-string dcc-port)))))
+       (port (process-contact dumb-server :service))
+       (expect (erc-d-t-make-expecter)))
+
+    (ert-info ("Connect to foonet")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :nick "tester"
+                                :password "changeme"
+                                :full-name "tester")
+        (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
+
+    (ert-info ("Offer received")
+      (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "foonet"))
+        (funcall expect 10 "DCC: chat offered by dummy")
+        (erc-cmd-DCC "CHAT" "dummy")))
+
+    ;; Regression
+    (erc-d-t-ensure-for 1 (not (get-buffer "tester")))
+
+    ;; Becomes current buffer by default (because `erc-join-buffer')
+    (erc-d-t-wait-for 10 (get-buffer "DCC-CHAT-dummy"))
+
+    (with-current-buffer "foonet"
+      (funcall expect 10 "*** DCC: accepting chat from dummy"))
+
+    (ert-info ("Chat with dummy")
+      (with-current-buffer "DCC-CHAT-dummy"
+        (erc-scenarios-common-say "Hi")
+        (funcall expect 10 "Hola")))))
+
+;;; erc-scenarios-misc.el ends here
diff --git a/test/lisp/erc/erc-scenarios-services-misc.el 
b/test/lisp/erc/erc-scenarios-services-misc.el
new file mode 100644
index 0000000000..cb1aa6ff32
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-services-misc.el
@@ -0,0 +1,86 @@
+;;; 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.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(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)
+                   (require 'erc-services))
+
+(ert-deftest erc-scenarios-services-password ()
+  :tags '(:expensive-test)
+
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "services/password")
+       (erc-server-flood-penalty 0.1)
+       (erc-modules (cons 'services erc-modules))
+       (erc-nickserv-passwords '((Libera.Chat (("joe" . "bar")
+                                               ("tester" . "changeme")))))
+       (expect (erc-d-t-make-expecter))
+       (dumb-server (erc-d-run "localhost" t 'libera))
+       (port (process-contact dumb-server :service)))
+
+    (ert-info ("Connect without password")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :nick "tester"
+                                :full-name "tester")
+        (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
+        (erc-d-t-wait-for 5 (eq erc-network 'Libera.Chat))
+        (funcall expect 5 "This nickname is registered.")
+        (funcall expect 2 "You are now identified")
+        (funcall expect 1 "Last login from")
+        (erc-cmd-QUIT "")))
+
+    (erc-services-mode -1)
+
+    (should-not (memq 'services erc-modules))))
+
+(ert-deftest erc-scenarios-services-prompt ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "services/password")
+       (erc-server-flood-penalty 0.1)
+       (inhibit-interaction nil)
+       (erc-modules (cons 'services erc-modules))
+       (expect (erc-d-t-make-expecter))
+       (dumb-server (erc-d-run "localhost" t 'libera))
+       (port (process-contact dumb-server :service)))
+
+    (ert-info ("Connect without password")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :nick "tester"
+                                :full-name "tester")
+        (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
+        (ert-simulate-keys "changeme\r"
+          (erc-d-t-wait-for 10 (eq erc-network 'Libera.Chat))
+          (funcall expect 3 "This nickname is registered.")
+          (funcall expect 3 "You are now identified")
+          (funcall expect 3 "Last login from"))
+        (erc-cmd-QUIT "")))
+
+    (erc-services-mode -1)
+
+    (should-not (memq 'services erc-modules))))
+
+;;; erc-scenarios-services-misc.el ends here
diff --git a/test/lisp/erc/erc-services-tests.el 
b/test/lisp/erc/erc-services-tests.el
new file mode 100644
index 0000000000..8e2b8d2927
--- /dev/null
+++ b/test/lisp/erc/erc-services-tests.el
@@ -0,0 +1,574 @@
+;;; erc-services-tests.el --- Tests for erc-services.  -*- lexical-binding:t 
-*-
+
+;; Copyright (C) 2020-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:
+
+;; TODO: move the auth-source tests somewhere else.  They've been
+;; stashed here for pragmatic reasons.
+
+;;; Code:
+
+(require 'ert-x)
+(require 'erc-services)
+(require 'erc-compat)
+(require 'secrets)
+
+;;;; Core auth-source
+
+(ert-deftest erc--auth-source-determine-params-merge ()
+  (let ((erc-session-server "irc.gnu.org")
+        (erc-server-announced-name "my.gnu.org")
+        (erc-session-port 6697)
+        (erc-network 'fake)
+        (erc-server-current-nick "tester")
+        (erc-networks--id (erc-networks--id-create 'GNU.chat)))
+
+    (should (equal (erc--auth-source-determine-params-merge)
+                   '(:host ("GNU.chat" "my.gnu.org" "irc.gnu.org")
+                           :port ("6697" "irc")
+                           :require (:secret))))
+
+    (should (equal (erc--auth-source-determine-params-merge :host "fake")
+                   '(:host ("fake" "GNU.chat" "my.gnu.org" "irc.gnu.org")
+                           :port ("6697" "irc")
+                           :require (:secret))))
+
+    (should (equal (erc--auth-source-determine-params-merge
+                    :host '("fake") :require :host)
+                   '(:host ("fake" "GNU.chat" "my.gnu.org" "irc.gnu.org")
+                           :require (:host :secret)
+                           :port ("6697" "irc"))))
+
+    (should (equal (erc--auth-source-determine-params-merge
+                    :host '("fake" "GNU.chat") :port "1234" :x "x")
+                   '(:host ("fake" "GNU.chat" "my.gnu.org" "irc.gnu.org")
+                           :port ("1234" "6697" "irc")
+                           :x ("x")
+                           :require (:secret))))))
+
+;; Some of the following may be related to bug#23438.
+
+(defun erc-services-tests--auth-source-standard (search)
+
+  (ert-info ("Session wins")
+    (let ((erc-session-server "irc.gnu.org")
+          (erc-server-announced-name "my.gnu.org")
+          (erc-session-port 6697)
+          (erc-network 'fake)
+          (erc-server-current-nick "tester")
+          (erc-networks--id (erc-networks--id-create 'GNU.chat)))
+      (should (string= (funcall search :user "#chan") "foo"))))
+
+  (ert-info ("Network wins")
+    (let* ((erc-session-server "irc.gnu.org")
+           (erc-server-announced-name "my.gnu.org")
+           (erc-session-port 6697)
+           (erc-network 'GNU.chat)
+           (erc-server-current-nick "tester")
+           (erc-networks--id (erc-networks--id-create nil)))
+      (should (string= (funcall search :user "#chan") "foo"))))
+
+  (ert-info ("Announced wins")
+    (let ((erc-session-server "irc.gnu.org")
+          (erc-server-announced-name "my.gnu.org")
+          (erc-session-port 6697)
+          erc-network
+          (erc-networks--id (erc-networks--id-create nil)))
+      (should (string= (funcall search :user "#chan") "baz")))))
+
+(defun erc-services-tests--auth-source-announced (search)
+  (let* ((erc--isupport-params (make-hash-table))
+         (erc-server-parameters '(("CHANTYPES" . "&#")))
+         (erc--target (erc--target-from-string "&chan")))
+
+    (ert-info ("Announced prioritized")
+
+      (ert-info ("Announced wins")
+        (let* ((erc-session-server "irc.gnu.org")
+               (erc-server-announced-name "my.gnu.org")
+               (erc-session-port 6697)
+               (erc-network 'GNU.chat)
+               (erc-server-current-nick "tester")
+               (erc-networks--id (erc-networks--id-create nil)))
+          (should (string= (funcall search :user "#chan") "baz"))))
+
+      (ert-info ("Peer next")
+        (let* ((erc-server-announced-name "irc.gnu.org")
+               (erc-session-port 6697)
+               (erc-network 'GNU.chat)
+               (erc-server-current-nick "tester")
+               (erc-networks--id (erc-networks--id-create nil)))
+          (should (string= (funcall search :user "#chan") "bar"))))
+
+      (ert-info ("Network used as fallback")
+        (let* ((erc-session-port 6697)
+               (erc-network 'GNU.chat)
+               (erc-server-current-nick "tester")
+               (erc-networks--id (erc-networks--id-create nil)))
+          (should (string= (funcall search :user "#chan") "foo")))))))
+
+(defun erc-services-tests--auth-source-overrides (search)
+  (let* ((erc-session-server "irc.gnu.org")
+         (erc-server-announced-name "my.gnu.org")
+         (erc-network 'GNU.chat)
+         (erc-server-current-nick "tester")
+         (erc-networks--id (erc-networks--id-create nil))
+         (erc-session-port 6667))
+
+    (ert-info ("Specificity and overrides")
+
+      (ert-info ("More specific port")
+        (let ((erc-session-port 6697))
+          (should (string= (funcall search :user "#chan") "spam"))))
+
+      (ert-info ("More specific user (network loses)")
+        (should (string= (funcall search :user '("#fsf")) "42")))
+
+      (ert-info ("Actual override")
+        (should (string= (funcall search :port "6667") "sesame")))
+
+      (ert-info ("Overrides don't interfere with post-processing")
+        (should (string= (funcall search :host "MyHost") "123"))))))
+
+;; auth-source netrc backend
+
+(defvar erc-services-tests--auth-source-entries
+  '("machine irc.gnu.org port irc user \"#chan\" password bar"
+    "machine my.gnu.org port irc user \"#chan\" password baz"
+    "machine GNU.chat port irc user \"#chan\" password foo"))
+
+;; FIXME explain what this is for
+(defun erc-services-tests--auth-source-shuffle (&rest extra)
+  (string-join `(,@(sort (append erc-services-tests--auth-source-entries extra)
+                         (lambda (&rest _) (zerop (random 2))))
+                 "")
+               "\n"))
+
+(ert-deftest erc--auth-source-search--netrc-standard ()
+  (ert-with-temp-file netrc-file
+    :prefix "erc--auth-source-search--standard"
+    :text (erc-services-tests--auth-source-shuffle)
+
+    (let ((auth-sources (list netrc-file))
+          (auth-source-do-cache nil))
+      (erc-services-tests--auth-source-standard #'erc-auth-source-search))))
+
+(ert-deftest erc--auth-source-search--netrc-announced ()
+  (ert-with-temp-file netrc-file
+    :prefix "erc--auth-source-search--announced"
+    :text (erc-services-tests--auth-source-shuffle)
+
+    (let ((auth-sources (list netrc-file))
+          (auth-source-do-cache nil))
+      (erc-services-tests--auth-source-announced #'erc-auth-source-search))))
+
+(ert-deftest erc--auth-source-search--netrc-overrides ()
+  (ert-with-temp-file netrc-file
+    :prefix "erc--auth-source-search--overrides"
+    :text (erc-services-tests--auth-source-shuffle
+           "machine GNU.chat port 6697 user \"#chan\" password spam"
+           "machine my.gnu.org port irc user \"#fsf\" password 42"
+           "machine irc.gnu.org port 6667 password sesame"
+           "machine MyHost port irc password 456"
+           "machine MyHost port 6667 password 123")
+
+    (let ((auth-sources (list netrc-file))
+          (auth-source-do-cache nil))
+      (erc-services-tests--auth-source-overrides #'erc-auth-source-search))))
+
+;; auth-source plstore backend
+
+(defun erc-services-test--call-with-plstore (&rest args)
+  (advice-add 'epg-decrypt-string :override
+              (lambda (&rest r) (prin1-to-string (cadr r)))
+              '((name . erc--auth-source-plstore)))
+  (advice-add 'epg-find-configuration :override
+              (lambda (&rest _) "" '((program . "/bin/true")))
+              '((name . erc--auth-source-plstore)))
+  (unwind-protect
+      (apply #'erc-auth-source-search args)
+    (advice-remove 'epg-decrypt-string 'erc--auth-source-plstore)
+    (advice-remove 'epg-find-configuration 'erc--auth-source-plstore)))
+
+(defvar erc-services-tests--auth-source-plstore-standard-entries
+  '(("ba950d38118a76d71f9f0591bb373d6cb366a512"
+     :secret-secret t
+     :host "irc.gnu.org"
+     :user "#chan"
+     :port "irc")
+    ("7f17ca445d11158065e911a6d0f4cbf52ca250e3"
+     :secret-secret t
+     :host "my.gnu.org"
+     :user "#chan"
+     :port "irc")
+    ("fcd3c8bd6daf4509de0ad6ee98e744ce0fca9377"
+     :secret-secret t
+     :host "GNU.chat"
+     :user "#chan"
+     :port "irc")))
+
+(defvar erc-services-tests--auth-source-plstore-standard-secrets
+  '(("ba950d38118a76d71f9f0591bb373d6cb366a512" :secret "bar")
+    ("7f17ca445d11158065e911a6d0f4cbf52ca250e3" :secret "baz")
+    ("fcd3c8bd6daf4509de0ad6ee98e744ce0fca9377" :secret "foo")))
+
+(ert-deftest erc--auth-source-search--plstore-standard ()
+  (ert-with-temp-file plstore-file
+    :suffix ".plist"
+    :text (concat ";;; public entries -*- mode: plstore -*- \n"
+                  (prin1-to-string
+                   erc-services-tests--auth-source-plstore-standard-entries)
+                  "\n;;; secret entries\n"
+                  (prin1-to-string
+                   erc-services-tests--auth-source-plstore-standard-secrets)
+                  "\n")
+
+    (let ((auth-sources (list plstore-file))
+          (auth-source-do-cache nil))
+      (erc-services-tests--auth-source-standard
+       #'erc-services-test--call-with-plstore))))
+
+(ert-deftest erc--auth-source-search--plstore-announced ()
+  (ert-with-temp-file plstore-file
+    :suffix ".plist"
+    :text (concat ";;; public entries -*- mode: plstore -*- \n"
+                  (prin1-to-string
+                   erc-services-tests--auth-source-plstore-standard-entries)
+                  "\n;;; secret entries\n"
+                  (prin1-to-string
+                   erc-services-tests--auth-source-plstore-standard-secrets)
+                  "\n")
+
+    (let ((auth-sources (list plstore-file))
+          (auth-source-do-cache nil))
+      (erc-services-tests--auth-source-announced
+       #'erc-services-test--call-with-plstore))))
+
+(ert-deftest erc--auth-source-search--plstore-overrides ()
+  (ert-with-temp-file plstore-file
+    :suffix ".plist"
+    :text (concat
+           ";;; public entries -*- mode: plstore -*- \n"
+           (prin1-to-string
+            `(,@erc-services-tests--auth-source-plstore-standard-entries
+              ("1b3fab249a8dff77a4d8fe7eb4b0171b25cc711a"
+               :secret-secret t :host "GNU.chat" :user "#chan" :port "6697")
+              ("6cbcdc39476b8cfcca6f3e9a7876f41ec3f708cc"
+               :secret-secret t :host "my.gnu.org" :user "#fsf" :port "irc")
+              ("a33e2b3bd2d6f33995a4b88710a594a100c5e41d"
+               :secret-secret t :host "irc.gnu.org" :port "6667")
+              ("ab2fd349b2b7d6a9215bb35a92d054261b0b1537"
+               :secret-secret t :host "MyHost" :port "irc")
+              ("61a6bd552059494f479ff720e8de33e22574650a"
+               :secret-secret t :host "MyHost" :port "6667")))
+           "\n;;; secret entries\n"
+           (prin1-to-string
+            `(,@erc-services-tests--auth-source-plstore-standard-secrets
+              ("1b3fab249a8dff77a4d8fe7eb4b0171b25cc711a" :secret "spam")
+              ("6cbcdc39476b8cfcca6f3e9a7876f41ec3f708cc" :secret "42")
+              ("a33e2b3bd2d6f33995a4b88710a594a100c5e41d" :secret "sesame")
+              ("ab2fd349b2b7d6a9215bb35a92d054261b0b1537" :secret "456")
+              ("61a6bd552059494f479ff720e8de33e22574650a" :secret "123")))
+           "\n")
+
+    (let ((auth-sources (list plstore-file))
+          (auth-source-do-cache nil))
+      (erc-services-tests--auth-source-overrides
+       #'erc-services-test--call-with-plstore))))
+
+;; auth-source JSON backend
+
+(defvar erc-services-tests--auth-source-json-standard-entries
+  [(:host "irc.gnu.org" :port "irc" :user "#chan" :secret "bar")
+   (:host "my.gnu.org" :port "irc" :user "#chan" :secret "baz")
+   (:host "GNU.chat" :port "irc" :user "#chan" :secret "foo")])
+
+(ert-deftest erc--auth-source-search--json-standard ()
+  (ert-with-temp-file json-store
+    :suffix ".json"
+    :text (let ((json-object-type 'plist))
+            (json-encode
+             erc-services-tests--auth-source-json-standard-entries))
+    (let ((auth-sources (list json-store))
+          (auth-source-do-cache nil))
+      (erc-services-tests--auth-source-standard #'erc-auth-source-search))))
+
+(ert-deftest erc--auth-source-search--json-announced ()
+  (ert-with-temp-file plstore-file
+    :suffix ".json"
+    :text (let ((json-object-type 'plist))
+            (json-encode
+             erc-services-tests--auth-source-json-standard-entries))
+
+    (let ((auth-sources (list plstore-file))
+          (auth-source-do-cache nil))
+      (erc-services-tests--auth-source-announced #'erc-auth-source-search))))
+
+(ert-deftest erc--auth-source-search--json-overrides ()
+  (ert-with-temp-file json-file
+    :suffix ".json"
+    :text (let ((json-object-type 'plist))
+            (json-encode
+             (vconcat
+              erc-services-tests--auth-source-json-standard-entries
+              [(:secret "spam" :host "GNU.chat" :user "#chan" :port "6697")
+               (:secret "42" :host "my.gnu.org" :user "#fsf" :port "irc")
+               (:secret "sesame" :host "irc.gnu.org" :port "6667")
+               (:secret "456" :host "MyHost" :port "irc")
+               (:secret "123" :host "MyHost" :port "6667")])))
+
+    (let ((auth-sources (list json-file))
+          (auth-source-do-cache nil))
+      (erc-services-tests--auth-source-overrides #'erc-auth-source-search))))
+
+;; auth-source-secrets backend
+
+(defvar erc-services-tests--auth-source-secrets-standard-entries
+  '(("#chan@irc.gnu.org:irc" ; label
+     (:host . "irc.gnu.org")
+     (:user . "#chan")
+     (:port . "irc")
+     (:xdg:schema . "org.freedesktop.Secret.Generic"))
+    ("#chan@my.gnu.org:irc"
+     (:host . "my.gnu.org")
+     (:user . "#chan")
+     (:port . "irc")
+     (:xdg:schema . "org.freedesktop.Secret.Generic"))
+    ("#chan@GNU.chat:irc"
+     (:host . "GNU.chat")
+     (:user . "#chan")
+     (:port . "irc")
+     (:xdg:schema . "org.freedesktop.Secret.Generic"))))
+
+(defvar erc-services-tests--auth-source-secrets-standard-secrets
+  '(("#chan@irc.gnu.org:irc" . "bar")
+    ("#chan@my.gnu.org:irc" . "baz")
+    ("#chan@GNU.chat:irc" . "foo")))
+
+(ert-deftest erc--auth-source-search--secrets-standard ()
+  (skip-unless (bound-and-true-p secrets-enabled))
+  (let ((auth-sources '("secrets:Test"))
+        (auth-source-do-cache nil)
+        (entries erc-services-tests--auth-source-secrets-standard-entries)
+        (secrets erc-services-tests--auth-source-secrets-standard-secrets))
+
+    (cl-letf (((symbol-function 'secrets-search-items)
+               (lambda (col &rest r)
+                 (should (equal col "Test"))
+                 (should (plist-get r :user))
+                 (map-keys entries)))
+              ((symbol-function 'secrets-get-secret)
+               (lambda (col label)
+                 (should (equal col "Test"))
+                 (assoc-default label secrets)))
+              ((symbol-function 'secrets-get-attributes)
+               (lambda (col label)
+                 (should (equal col "Test"))
+                 (assoc-default label entries))))
+
+      (erc-services-tests--auth-source-standard #'erc-auth-source-search))))
+
+(ert-deftest erc--auth-source-search--secrets-announced ()
+  (skip-unless (bound-and-true-p secrets-enabled))
+  (let ((auth-sources '("secrets:Test"))
+        (auth-source-do-cache nil)
+        (entries erc-services-tests--auth-source-secrets-standard-entries)
+        (secrets erc-services-tests--auth-source-secrets-standard-secrets))
+
+    (cl-letf (((symbol-function 'secrets-search-items)
+               (lambda (col &rest r)
+                 (should (equal col "Test"))
+                 (should (plist-get r :user))
+                 (map-keys entries)))
+              ((symbol-function 'secrets-get-secret)
+               (lambda (col label)
+                 (should (equal col "Test"))
+                 (assoc-default label secrets)))
+              ((symbol-function 'secrets-get-attributes)
+               (lambda (col label)
+                 (should (equal col "Test"))
+                 (assoc-default label entries))))
+
+      (erc-services-tests--auth-source-announced #'erc-auth-source-search))))
+
+(ert-deftest erc--auth-source-search--secrets-overrides ()
+  (skip-unless (bound-and-true-p secrets-enabled))
+  (let ((auth-sources '("secrets:Test"))
+        (auth-source-do-cache nil)
+        (entries `(,@erc-services-tests--auth-source-secrets-standard-entries
+                   ("#chan@GNU.chat:6697"
+                    (:host . "GNU.chat") (:user . "#chan") (:port . "6697")
+                    (:xdg:schema . "org.freedesktop.Secret.Generic"))
+                   ("#fsf@my.gnu.org:irc"
+                    (:host . "my.gnu.org") (:user . "#fsf") (:port . "irc")
+                    (:xdg:schema . "org.freedesktop.Secret.Generic"))
+                   ("irc.gnu.org:6667"
+                    (:host . "irc.gnu.org") (:port . "6667")
+                    (:xdg:schema . "org.freedesktop.Secret.Generic"))
+                   ("MyHost:irc"
+                    (:host . "MyHost") (:port . "irc")
+                    (:xdg:schema . "org.freedesktop.Secret.Generic"))
+                   ("MyHost:6667"
+                    (:host . "MyHost") (:port . "6667")
+                    (:xdg:schema . "org.freedesktop.Secret.Generic"))))
+        (secrets `(,@erc-services-tests--auth-source-secrets-standard-secrets
+                   ("#chan@GNU.chat:6697" . "spam")
+                   ("#fsf@my.gnu.org:irc" . "42" )
+                   ("irc.gnu.org:6667" . "sesame")
+                   ("MyHost:irc" . "456")
+                   ("MyHost:6667" . "123"))))
+
+    (cl-letf (((symbol-function 'secrets-search-items)
+               (lambda (col &rest _)
+                 (should (equal col "Test"))
+                 (map-keys entries)))
+              ((symbol-function 'secrets-get-secret)
+               (lambda (col label)
+                 (should (equal col "Test"))
+                 (assoc-default label secrets)))
+              ((symbol-function 'secrets-get-attributes)
+               (lambda (col label)
+                 (should (equal col "Test"))
+                 (assoc-default label entries))))
+
+      (erc-services-tests--auth-source-overrides #'erc-auth-source-search))))
+
+;; auth-source-pass backend
+
+(require 'auth-source-pass)
+
+;; `auth-source-pass--find-match-unambiguous' returns something like:
+;;
+;;   (list :host "irc.gnu.org"
+;;         :port "6697"
+;;         :user "rms"
+;;         :secret
+;;         #[0 "\301\302\300\"\207"
+;;             [((secret . "freedom")) auth-source-pass--get-attr secret] 3])
+;;
+;; This function gives ^ (faked here to avoid gpg and file IO).  See
+;; `auth-source-pass--with-store' in ../auth-source-pass-tests.el
+(defun erc-services-tests--asp-parse-entry (store entry)
+  (when-let ((found (cl-find entry store :key #'car :test #'string=)))
+    (list (assoc 'secret (cdr found)))))
+
+(defvar erc-join-tests--auth-source-pass-entries
+  '(("irc.gnu.org:irc/#chan"
+     ("port" . "irc") ("user" . "#chan") (secret . "bar"))
+    ("my.gnu.org:irc/#chan"
+     ("port" . "irc") ("user" . "#chan") (secret . "baz"))
+    ("GNU.chat:irc/#chan"
+     ("port" . "irc") ("user" . "#chan") (secret . "foo"))))
+
+(ert-deftest erc--auth-source-search--pass-standard ()
+  (ert-skip "Pass backend not yet supported")
+  (let ((store erc-join-tests--auth-source-pass-entries)
+        (auth-sources '(password-store))
+        (auth-source-do-cache nil))
+
+    (cl-letf (((symbol-function 'auth-source-pass-parse-entry)
+               (apply-partially #'erc-services-tests--asp-parse-entry store))
+              ((symbol-function 'auth-source-pass-entries)
+               (lambda () (mapcar #'car store))))
+
+      (erc-services-tests--auth-source-standard #'erc-auth-source-search))))
+
+(ert-deftest erc--auth-source-search--pass-announced ()
+  (ert-skip "Pass backend not yet supported")
+  (let ((store erc-join-tests--auth-source-pass-entries)
+        (auth-sources '(password-store))
+        (auth-source-do-cache nil))
+
+    (cl-letf (((symbol-function 'auth-source-pass-parse-entry)
+               (apply-partially #'erc-services-tests--asp-parse-entry store))
+              ((symbol-function 'auth-source-pass-entries)
+               (lambda () (mapcar #'car store))))
+
+      (erc-services-tests--auth-source-announced #'erc-auth-source-search))))
+
+(ert-deftest erc--auth-source-search--pass-overrides ()
+  (ert-skip "Pass backend not yet supported")
+  (let ((store
+         `(,@erc-join-tests--auth-source-pass-entries
+           ("GNU.chat:6697/#chan"
+            ("port" . "6697") ("user" . "#chan") (secret . "spam"))
+           ("my.gnu.org:irc/#fsf"
+            ("port" . "irc") ("user" . "#fsf") (secret . "42"))
+           ("irc.gnu.org:6667"
+            ("port" . "6667") (secret . "sesame"))
+           ("MyHost:irc"
+            ("port" . "irc") (secret . "456"))
+           ("MyHost:6667"
+            ("port" . "6667") (secret . "123"))))
+        (auth-sources '(password-store))
+        (auth-source-do-cache nil))
+
+    (cl-letf (((symbol-function 'auth-source-pass-parse-entry)
+               (apply-partially #'erc-services-tests--asp-parse-entry store))
+              ((symbol-function 'auth-source-pass-entries)
+               (lambda () (mapcar #'car store))))
+
+      (erc-services-tests--auth-source-overrides #'erc-auth-source-search))))
+
+;;;; The services module
+
+(ert-deftest erc-nickserv-get-password ()
+  (should erc-prompt-for-nickserv-password)
+  (ert-with-temp-file netrc-file
+    :prefix "erc-nickserv-get-password"
+    :text (mapconcat 'identity
+                     '("machine GNU/chat port 6697 user bob password spam"
+                       "machine FSF.chat port 6697 user bob password sesame"
+                       "machine MyHost port irc password 123")
+                     "\n")
+
+    (let* ((auth-sources (list netrc-file))
+           (auth-source-do-cache nil)
+           (erc-nickserv-passwords '((FSF.chat (("alice" . "foo")
+                                                ("joe" . "bar")))))
+           (erc-use-auth-source-for-nickserv-password t)
+           (erc-session-server "irc.gnu.org")
+           (erc-server-announced-name "my.gnu.org")
+           (erc-network 'FSF.chat)
+           (erc-server-current-nick "tester")
+           (erc-networks--id (erc-networks--id-create nil))
+           (erc-session-port 6697))
+
+      (ert-info ("Lookup custom option")
+        (should (string= (erc-nickserv-get-password "alice") "foo")))
+
+      (ert-info ("Auth source")
+        (ert-info ("Network")
+          (should (string= (erc-nickserv-get-password "bob") "sesame")))
+
+        (ert-info ("Network ID")
+          (let ((erc-networks--id (erc-networks--id-create 'GNU/chat)))
+            (should (string= (erc-nickserv-get-password "bob") "spam")))))
+
+      (ert-info ("Read input")
+        (should (string=
+                 (ert-simulate-keys "baz\r" (erc-nickserv-get-password "mike"))
+                 "baz")))
+
+      (ert-info ("Failed")
+        (should-not (ert-simulate-keys "\r"
+                      (erc-nickserv-get-password "fake")))))))
+
+
+;;; erc-services-tests.el ends here
diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el
index 520f10dd4e..55efe2fd2d 100644
--- a/test/lisp/erc/erc-tests.el
+++ b/test/lisp/erc/erc-tests.el
@@ -48,6 +48,27 @@
   (cl-letf (((symbol-function 'read-string) (lambda (&rest _) "1d")))
     (should (equal (erc--read-time-period "foo: ") 86400))))
 
+(ert-deftest erc--meta--backend-dependencies ()
+  (with-temp-buffer
+    (insert-file-contents-literally
+     (concat (file-name-sans-extension (symbol-file 'erc)) ".el"))
+    (let ((beg (search-forward ";; Defined in erc-backend"))
+          (end (search-forward "\n\n"))
+          vars)
+      (save-excursion
+        (save-restriction
+          (narrow-to-region beg end)
+          (goto-char (point-min))
+          (with-syntax-table lisp-data-mode-syntax-table
+            (condition-case _
+                (while (push (cadr (read (current-buffer))) vars))
+              (end-of-file)))))
+      (should (= (point) end))
+      (dolist (var vars)
+        (setq var (concat "\\_<" (symbol-name var) "\\_>"))
+        (ert-info (var)
+          (should (save-excursion (search-forward-regexp var nil t))))))))
+
 (ert-deftest erc-with-all-buffers-of-server ()
   (let (proc-exnet
         proc-onet
@@ -114,6 +135,150 @@
     (should (get-buffer "#spam"))
     (kill-buffer "#spam")))
 
+(defun erc-tests--send-prep ()
+  ;; Caller should probably shadow `erc-insert-modify-hook' or
+  ;; populate user tables for erc-button.
+  (erc-mode)
+  (insert "\n\n")
+  (setq erc-input-marker (make-marker)
+        erc-insert-marker (make-marker))
+  (set-marker erc-insert-marker (point-max))
+  (erc-display-prompt)
+  (should (= (point) erc-input-marker)))
+
+(defun erc-tests--set-fake-server-process (&rest args)
+  (setq erc-server-process
+        (apply #'start-process (car args) (current-buffer) args))
+  (set-process-query-on-exit-flag erc-server-process nil))
+
+(ert-deftest erc-hide-prompt ()
+  (let (erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook)
+
+    (with-current-buffer (get-buffer-create "ServNet")
+      (erc-tests--send-prep)
+      (goto-char erc-insert-marker)
+      (should (looking-at-p (regexp-quote erc-prompt)))
+      (erc-tests--set-fake-server-process "sleep" "1")
+      (set-process-sentinel erc-server-process #'ignore)
+      (setq erc-network 'ServNet)
+      (set-process-query-on-exit-flag erc-server-process nil))
+
+    (with-current-buffer (get-buffer-create "#chan")
+      (erc-tests--send-prep)
+      (goto-char erc-insert-marker)
+      (should (looking-at-p (regexp-quote erc-prompt)))
+      (setq erc-server-process (buffer-local-value 'erc-server-process
+                                                   (get-buffer "ServNet"))
+            erc-default-recipients '("#chan")))
+
+    (with-current-buffer (get-buffer-create "bob")
+      (erc-tests--send-prep)
+      (goto-char erc-insert-marker)
+      (should (looking-at-p (regexp-quote erc-prompt)))
+      (setq erc-server-process (buffer-local-value 'erc-server-process
+                                                   (get-buffer "ServNet"))
+            erc-default-recipients '("bob")))
+
+    (ert-info ("Value: t (default)")
+      (should (eq erc-hide-prompt t))
+      (with-current-buffer "ServNet"
+        (should (= (point) erc-insert-marker))
+        (erc--hide-prompt erc-server-process)
+        (should (string= ">" (get-text-property (point) 'display))))
+
+      (with-current-buffer "#chan"
+        (goto-char erc-insert-marker)
+        (should (string= ">" (get-text-property (point) 'display)))
+        (should (memq #'erc--unhide-prompt-on-self-insert pre-command-hook))
+        (goto-char erc-input-marker)
+        (ert-simulate-command '(self-insert-command 1 ?/))
+        (goto-char erc-insert-marker)
+        (should-not (get-text-property (point) 'display))
+        (should-not (memq #'erc--unhide-prompt-on-self-insert
+                          pre-command-hook)))
+
+      (with-current-buffer "bob"
+        (goto-char erc-insert-marker)
+        (should (string= ">" (get-text-property (point) 'display)))
+        (should (memq #'erc--unhide-prompt-on-self-insert pre-command-hook))
+        (goto-char erc-input-marker)
+        (ert-simulate-command '(self-insert-command 1 ?/))
+        (goto-char erc-insert-marker)
+        (should-not (get-text-property (point) 'display))
+        (should-not (memq #'erc--unhide-prompt-on-self-insert
+                          pre-command-hook)))
+
+      (with-current-buffer "ServNet"
+        (should (get-text-property erc-insert-marker 'display))
+        (should (memq #'erc--unhide-prompt-on-self-insert pre-command-hook))
+        (erc--unhide-prompt)
+        (should-not (memq #'erc--unhide-prompt-on-self-insert
+                          pre-command-hook))
+        (should-not (get-text-property erc-insert-marker 'display))))
+
+    (ert-info ("Value: server")
+      (setq erc-hide-prompt '(server))
+      (with-current-buffer "ServNet"
+        (erc--hide-prompt erc-server-process)
+        (should (string= ">" (get-text-property erc-insert-marker 'display))))
+
+      (with-current-buffer "#chan"
+        (should-not (get-text-property erc-insert-marker 'display)))
+
+      (with-current-buffer "bob"
+        (should-not (get-text-property erc-insert-marker 'display)))
+
+      (with-current-buffer "ServNet"
+        (erc--unhide-prompt)
+        (should-not (get-text-property erc-insert-marker 'display))))
+
+    (ert-info ("Value: channel")
+      (setq erc-hide-prompt '(channel))
+      (with-current-buffer "ServNet"
+        (erc--hide-prompt erc-server-process)
+        (should-not (get-text-property erc-insert-marker 'display)))
+
+      (with-current-buffer "bob"
+        (should-not (get-text-property erc-insert-marker 'display)))
+
+      (with-current-buffer "#chan"
+        (should (string= ">" (get-text-property erc-insert-marker 'display)))
+        (erc--unhide-prompt)
+        (should-not (get-text-property erc-insert-marker 'display))))
+
+    (ert-info ("Value: query")
+      (setq erc-hide-prompt '(query))
+      (with-current-buffer "ServNet"
+        (erc--hide-prompt erc-server-process)
+        (should-not (get-text-property erc-insert-marker 'display)))
+
+      (with-current-buffer "bob"
+        (should (string= ">" (get-text-property erc-insert-marker 'display)))
+        (erc--unhide-prompt)
+        (should-not (get-text-property erc-insert-marker 'display)))
+
+      (with-current-buffer "#chan"
+        (should-not (get-text-property erc-insert-marker 'display))))
+
+    (ert-info ("Value: nil")
+      (setq erc-hide-prompt nil)
+      (with-current-buffer "ServNet"
+        (erc--hide-prompt erc-server-process)
+        (should-not (get-text-property erc-insert-marker 'display)))
+
+      (with-current-buffer "bob"
+        (should-not (get-text-property erc-insert-marker 'display)))
+
+      (with-current-buffer "#chan"
+        (should-not (get-text-property erc-insert-marker 'display))
+        (erc--unhide-prompt) ; won't blow up when prompt already showing
+        (should-not (get-text-property erc-insert-marker 'display))))
+
+    (when noninteractive
+      (kill-buffer "#chan")
+      (kill-buffer "bob")
+      (kill-buffer "ServNet"))))
+
 (ert-deftest erc--switch-to-buffer ()
   (defvar erc-modified-channels-alist) ; lisp/erc/erc-track.el
 
@@ -184,6 +349,147 @@
     (setq erc-lurker-ignore-chars "_-`") ; set of chars, not character alts
     (should (string= "nick" (erc-lurker-maybe-trim "nick-_`")))))
 
+(ert-deftest erc--parse-isupport-value ()
+  (should (equal (erc--parse-isupport-value "a,b") '("a" "b")))
+  (should (equal (erc--parse-isupport-value "a,b,c") '("a" "b" "c")))
+
+  (should (equal (erc--parse-isupport-value "abc") '("abc")))
+  (should (equal (erc--parse-isupport-value "\\x20foo") '(" foo")))
+  (should (equal (erc--parse-isupport-value "foo\\x20") '("foo ")))
+  (should (equal (erc--parse-isupport-value "a\\x20b\\x20c") '("a b c")))
+  (should (equal (erc--parse-isupport-value "a\\x20b\\x20c\\x20") '("a b c ")))
+  (should (equal (erc--parse-isupport-value "\\x20a\\x20b\\x20c") '(" a b c")))
+  (should (equal (erc--parse-isupport-value "a\\x20\\x20c") '("a  c")))
+  (should (equal (erc--parse-isupport-value "\\x20\\x20\\x20") '("   ")))
+  (should (equal (erc--parse-isupport-value "\\x5Co/") '("\\o/")))
+  (should (equal (erc--parse-isupport-value "\\x7F,\\x19") '("\\x7F" "\\x19")))
+  (should (equal (erc--parse-isupport-value "a\\x2Cb,c") '("a,b" "c"))))
+
+(ert-deftest erc--get-isupport-entry ()
+  (let ((erc--isupport-params (make-hash-table))
+        (erc-server-parameters '(("FOO" . "1") ("BAR") ("BAZ" . "A,B,C")))
+        (items (lambda ()
+                 (cl-loop for k being the hash-keys of erc--isupport-params
+                          using (hash-values v) collect (cons k v)))))
+
+    (should-not (erc--get-isupport-entry 'FAKE))
+    (should-not (erc--get-isupport-entry 'FAKE 'single))
+    (should (zerop (hash-table-count erc--isupport-params)))
+
+    (should (equal (erc--get-isupport-entry 'BAR) '(BAR)))
+    (should-not (erc--get-isupport-entry 'BAR 'single))
+    (should (= 1 (hash-table-count erc--isupport-params)))
+
+    (should (equal (erc--get-isupport-entry 'BAZ) '(BAZ "A" "B" "C")))
+    (should (equal (erc--get-isupport-entry 'BAZ 'single) "A"))
+    (should (= 2 (hash-table-count erc--isupport-params)))
+
+    (should (equal (erc--get-isupport-entry 'FOO 'single) "1"))
+    (should (equal (erc--get-isupport-entry 'FOO) '(FOO "1")))
+
+    (should (equal (funcall items)
+                   '((BAR . --empty--) (BAZ "A" "B" "C") (FOO "1"))))))
+
+(ert-deftest erc-server-005 ()
+  (let* ((hooked 0)
+         (verify #'ignore)
+         (hook (lambda (_ _) (funcall verify) (cl-incf hooked)))
+         (erc-server-005-functions (list #'erc-server-005 hook #'ignore))
+         erc-server-parameters
+         erc--isupport-params
+         erc-timer-hook
+         calls
+         args
+         parsed)
+
+    (cl-letf (((symbol-function 'erc-display-message)
+               (lambda (_ _ _ line) (push line calls))))
+
+      (ert-info ("Baseline")
+        (setq args '("tester" "BOT=B" "EXCEPTS" "PREFIX=(ov)@+" "are supp...")
+              parsed (make-erc-response :command-args args :command "005"))
+
+        (setq verify
+              (lambda ()
+                (should (equal erc-server-parameters
+                               '(("PREFIX" . "(ov)@+") ("EXCEPTS")
+                                 ("BOT" . "B"))))
+                (should (zerop (hash-table-count erc--isupport-params)))
+                (should (equal "(ov)@+" (erc--get-isupport-entry 'PREFIX t)))
+                (should (equal '(EXCEPTS) (erc--get-isupport-entry 'EXCEPTS)))
+                (should (equal "B" (erc--get-isupport-entry 'BOT t)))
+                (should (string= (pop calls)
+                                 "BOT=B EXCEPTS PREFIX=(ov)@+ are supp..."))
+                (should (equal args (erc-response.command-args parsed)))))
+
+        (erc-call-hooks nil parsed))
+
+      (ert-info ("Negated, updated")
+        (setq args '("tester" "-EXCEPTS" "-FAKE" "PREFIX=(ohv)@%+" "are su...")
+              parsed (make-erc-response :command-args args :command "005"))
+
+        (setq verify
+              (lambda ()
+                (should (equal erc-server-parameters
+                               '(("PREFIX" . "(ohv)@%+") ("BOT" . "B"))))
+                (should (string= (pop calls)
+                                 "-EXCEPTS -FAKE PREFIX=(ohv)@%+ are su..."))
+                (should (equal "(ohv)@%+" (erc--get-isupport-entry 'PREFIX t)))
+                (should (equal "B" (erc--get-isupport-entry 'BOT t)))
+                (should-not (erc--get-isupport-entry 'EXCEPTS))
+                (should (equal args (erc-response.command-args parsed)))))
+
+        (erc-call-hooks nil parsed))
+      (should (= hooked 2)))))
+
+(ert-deftest erc-downcase ()
+  (let ((erc--isupport-params (make-hash-table)))
+
+    (puthash 'PREFIX '("(ov)@+") erc--isupport-params)
+    (puthash 'BOT '("B") erc--isupport-params)
+
+    (ert-info ("ascii")
+      (puthash 'CASEMAPPING  '("ascii") erc--isupport-params)
+      (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 "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 "Bob[m]`") "bob{m}`"))
+      (should (equal (erc-downcase "Tilde~") "tilde~" ))
+      (should (equal (erc-downcase "\\O/") "|o/" )))))
+
+(ert-deftest erc--valid-local-channel-p ()
+  (ert-info ("Local channels not supported")
+    (let ((erc--isupport-params (make-hash-table)))
+      (puthash 'CHANTYPES  '("#") erc--isupport-params)
+      (should-not (erc--valid-local-channel-p "#chan"))
+      (should-not (erc--valid-local-channel-p "&local"))))
+  (ert-info ("Local channels supported")
+    (let ((erc--isupport-params (make-hash-table)))
+      (puthash 'CHANTYPES  '("&#") erc--isupport-params)
+      (should-not (erc--valid-local-channel-p "#chan"))
+      (should (erc--valid-local-channel-p "&local")))))
+
+(ert-deftest erc--target-from-string ()
+  (should (equal (erc--target-from-string "#chan")
+                 #s(erc--target-channel "#chan" \#chan)))
+
+  (should (equal (erc--target-from-string "Bob")
+                 #s(erc--target "Bob" bob)))
+
+  (let ((erc--isupport-params (make-hash-table)))
+    (puthash 'CHANTYPES  '("&#") erc--isupport-params)
+    (should (equal (erc--target-from-string "&Bitlbee")
+                   #s(erc--target-channel-local "&Bitlbee" &bitlbee)))))
+
 (ert-deftest erc-ring-previous-command-base-case ()
   (ert-info ("Create ring when nonexistent and do nothing")
     (let (erc-input-ring
@@ -197,14 +503,10 @@
 (ert-deftest erc-ring-previous-command ()
   (with-current-buffer (get-buffer-create "*#fake*")
     (erc-mode)
-    (insert "\n\n")
+    (erc-tests--send-prep)
+    (setq-local erc-last-input-time 0)
     (should-not (local-variable-if-set-p 'erc-send-completed-hook))
     (set (make-local-variable 'erc-send-completed-hook) nil) ; skip t (globals)
-    (setq erc-input-marker (make-marker)
-          erc-insert-marker (make-marker))
-    (set-marker erc-insert-marker (point-max))
-    (erc-display-prompt)
-    (should (= (point) erc-input-marker))
     ;; Just in case erc-ring-mode is already on
     (setq-local erc-pre-send-functions nil)
     (add-hook 'erc-pre-send-functions #'erc-add-to-input-ring)
@@ -220,7 +522,7 @@
         (erc-send-current-line)
         (should (ring-p erc-input-ring))
         (should (zerop (ring-member erc-input-ring "/one"))) ; equal
-        (should (save-excursion (forward-line -1) (goto-char (point-at-bol))
+        (should (save-excursion (forward-line -1) (goto-char (pos-bol))
                                 (looking-at-p "[*]+ echo: one")))
         (should-not erc-input-ring-index)
         (erc-bol)
@@ -264,27 +566,262 @@
       (erc-log-irc-protocol ":irc.gnu.org 001 tester :Welcome")
       (erc-log-irc-protocol ":irc.gnu.org 002 tester :Your host is 
irc.gnu.org")
       (setq erc-network 'FooNet)
+      (setq erc-networks--id (erc-networks--id-create nil))
       (erc-log-irc-protocol ":irc.gnu.org 422 tester :MOTD missing")
-      (setq erc-network 'BarNet)
+      (setq erc-networks--id (erc-networks--id-create 'BarNet))
       (erc-log-irc-protocol ":irc.gnu.org 221 tester +i")
       (set-process-query-on-exit-flag erc-server-process nil)))
   (with-current-buffer "*erc-protocol*"
     (goto-char (point-min))
     (search-forward "Version")
     (search-forward "\r\n\r\n")
-    (search-forward "myproxy.localhost:6667 >> PASS" (line-end-position))
+    (search-forward "myproxy.localhost:6667 >> PASS" (pos-eol))
     (forward-line)
-    (search-forward "irc.gnu.org << :irc.gnu.org 001" (line-end-position))
+    (search-forward "irc.gnu.org << :irc.gnu.org 001" (pos-eol))
     (forward-line)
-    (search-forward "irc.gnu.org << :irc.gnu.org 002" (line-end-position))
+    (search-forward "irc.gnu.org << :irc.gnu.org 002" (pos-eol))
     (forward-line)
-    (search-forward "FooNet << :irc.gnu.org 422" (line-end-position))
+    (search-forward "FooNet << :irc.gnu.org 422" (pos-eol))
     (forward-line)
-    (search-forward "BarNet << :irc.gnu.org 221" (line-end-position)))
+    (search-forward "BarNet << :irc.gnu.org 221" (pos-eol)))
   (when noninteractive
     (kill-buffer "*erc-protocol*")
     (should-not erc-debug-irc-protocol)))
 
+(ert-deftest erc--input-line-delim-regexp ()
+  (let ((p erc--input-line-delim-regexp))
+    ;; none
+    (should (equal '("a" "b") (split-string "a\r\nb" p)))
+    (should (equal '("a" "b") (split-string "a\nb" p)))
+    (should (equal '("a" "b") (split-string "a\rb" p)))
+
+    ;; one
+    (should (equal '("") (split-string "" p)))
+    (should (equal '("a" "" "b") (split-string "a\r\rb" p)))
+    (should (equal '("a" "" "b") (split-string "a\n\rb" p)))
+    (should (equal '("a" "" "b") (split-string "a\n\nb" p)))
+    (should (equal '("a" "" "b") (split-string "a\r\r\nb" p)))
+    (should (equal '("a" "" "b") (split-string "a\n\r\nb" p)))
+    (should (equal '("a" "") (split-string "a\n" p)))
+    (should (equal '("a" "") (split-string "a\r" p)))
+    (should (equal '("a" "") (split-string "a\r\n" p)))
+    (should (equal '("" "b") (split-string "\nb" p)))
+    (should (equal '("" "b") (split-string "\rb" p)))
+    (should (equal '("" "b") (split-string "\r\nb" p)))
+
+    ;; two
+    (should (equal '("" "") (split-string "\r" p)))
+    (should (equal '("" "") (split-string "\n" p)))
+    (should (equal '("" "") (split-string "\r\n" p)))
+
+    ;; three
+    (should (equal '("" "" "") (split-string "\r\r" p)))
+    (should (equal '("" "" "") (split-string "\n\n" p)))
+    (should (equal '("" "" "") (split-string "\n\r" p)))))
+
+(ert-deftest erc--blank-in-multiline-input-p ()
+  (let ((check (lambda (s)
+                 (erc--blank-in-multiline-input-p
+                  (split-string s erc--input-line-delim-regexp)))))
+
+    (ert-info ("With `erc-send-whitespace-lines'")
+      (let ((erc-send-whitespace-lines t))
+        (should (funcall check ""))
+        (should-not (funcall check "\na"))
+        (should-not (funcall check "/msg a\n")) ; real /cmd
+        (should-not (funcall check "a\n\nb")) ; "" allowed
+        (should-not (funcall check "/msg a\n\nb")) ; non-/cmd
+        (should-not (funcall check " "))
+        (should-not (funcall check "\t"))
+        (should-not (funcall check "a\nb"))
+        (should-not (funcall check "a\n "))
+        (should-not (funcall check "a\n \t"))
+        (should-not (funcall check "a\n \f"))
+        (should-not (funcall check "a\n \nb"))
+        (should-not (funcall check "a\n \t\nb"))
+        (should-not (funcall check "a\n \f\nb"))))
+
+    (should (funcall check ""))
+    (should (funcall check " "))
+    (should (funcall check "\t"))
+    (should (funcall check "a\n\nb"))
+    (should (funcall check "a\n\nb"))
+    (should (funcall check "a\n "))
+    (should (funcall check "a\n \t"))
+    (should (funcall check "a\n \f"))
+    (should (funcall check "a\n \nb"))
+    (should (funcall check "a\n \t\nb"))
+
+    (should-not (funcall check "a\rb"))
+    (should-not (funcall check "a\nb"))
+    (should-not (funcall check "a\r\nb"))))
+
+(defun erc-tests--with-process-input-spy (test)
+  (with-current-buffer (get-buffer-create "FakeNet")
+    (let* ((erc-pre-send-functions
+            (remove #'erc-add-to-input-ring erc-pre-send-functions)) ; for now
+           (inhibit-message noninteractive)
+           (erc-server-current-nick "tester")
+           (erc-last-input-time 0)
+           erc-accidental-paste-threshold-seconds
+           erc-send-modify-hook
+           ;;
+           calls)
+      (cl-letf (((symbol-function 'erc-process-input-line)
+                 (lambda (&rest r) (push r calls)))
+                ((symbol-function 'erc-server-buffer)
+                 (lambda () (current-buffer))))
+        (erc-tests--send-prep)
+        (funcall test (lambda () (pop calls)))))
+    (when noninteractive (kill-buffer))))
+
+(ert-deftest erc--check-prompt-input-functions ()
+  (erc-tests--with-process-input-spy
+   (lambda (next)
+
+     (ert-info ("Errors when point not in prompt area") ; actually just dings
+       (insert "/msg #chan hi")
+       (forward-line -1)
+       (let ((e (should-error (erc-send-current-line))))
+         (should (equal "Point is not in the input area" (cadr e))))
+       (goto-char (point-max))
+       (ert-info ("Input remains untouched")
+         (should (save-excursion (erc-bol) (looking-at "/msg #chan hi")))))
+
+     (ert-info ("Errors when no process running")
+       (let ((e (should-error (erc-send-current-line))))
+         (should (equal "ERC: No process running" (cadr e))))
+       (ert-info ("Input remains untouched")
+         (should (save-excursion (erc-bol) (looking-at "/msg #chan hi")))))
+
+     (ert-info ("Errors when line contains empty newline")
+       (erc-bol)
+       (delete-region (point) (point-max))
+       (insert "one\n")
+       (let ((e (should-error (erc-send-current-line))))
+         (should (equal "Blank line - ignoring..." (cadr e))))
+       (goto-char (point-max))
+       (ert-info ("Input remains untouched")
+         (should (save-excursion (goto-char erc-input-marker)
+                                 (looking-at "one\n")))))
+
+     (should (= 0 erc-last-input-time))
+     (should-not (funcall next)))))
+
+;; These also indirectly tests `erc-send-input'
+
+(ert-deftest erc-send-current-line ()
+  (erc-tests--with-process-input-spy
+   (lambda (next)
+     (erc-tests--set-fake-server-process "sleep" "1")
+     (should (= 0 erc-last-input-time))
+
+     (ert-info ("Simple command")
+       (insert "/msg #chan hi")
+       (erc-send-current-line)
+       (ert-info ("Prompt restored")
+         (forward-line 0)
+         (should (looking-at-p erc-prompt)))
+       (ert-info ("Input cleared")
+         (erc-bol)
+         (should (eq (point) (point-max))))
+       ;; Commands are forced (no flood protection)
+       (should (equal (funcall next) '("/msg #chan hi\n" t nil))))
+
+     (ert-info ("Simple non-command")
+       (insert "hi")
+       (erc-send-current-line)
+       (should (eq (point) (point-max)))
+       (should (save-excursion (forward-line -1)
+                               (search-forward "<tester> hi")))
+       ;; Non-ommands are forced only when `erc-flood-protect' is nil
+       (should (equal (funcall next) '("hi\n" nil t))))
+
+     (should (consp erc-last-input-time)))))
+
+(ert-deftest erc-send-whitespace-lines ()
+  (erc-tests--with-process-input-spy
+   (lambda (next)
+     (erc-tests--set-fake-server-process "sleep" "1")
+     (setq-local erc-send-whitespace-lines t)
+
+     (ert-info ("Multiline hunk with blank line correctly split")
+       (insert "one\n\ntwo")
+       (erc-send-current-line)
+       (ert-info ("Prompt restored")
+         (forward-line 0)
+         (should (looking-at-p erc-prompt)))
+       (ert-info ("Input cleared")
+         (erc-bol)
+         (should (eq (point) (point-max))))
+       (should (equal (funcall next) '("two\n" nil t)))
+       (should (equal (funcall next) '("\n" nil t)))
+       (should (equal (funcall next) '("one\n" nil t))))
+
+     (ert-info ("Multiline hunk with trailing newline filtered")
+       (insert "hi\n")
+       (erc-send-current-line)
+       (ert-info ("Input cleared")
+         (erc-bol)
+         (should (eq (point) (point-max))))
+       (should (equal (funcall next) '("hi\n" nil t)))
+       (should-not (funcall next)))
+
+     (ert-info ("Multiline hunk with trailing carriage filtered")
+       (insert "hi\r")
+       (erc-send-current-line)
+       (ert-info ("Input cleared")
+         (erc-bol)
+         (should (eq (point) (point-max))))
+       (should (equal (funcall next) '("hi\n" nil t)))
+       (should-not (funcall next)))
+
+     (ert-info ("Multiline command with trailing blank filtered")
+       (pcase-dolist (`(,p . ,q)
+                      '(("/a b\r" "/a b\n") ("/a b\n" "/a b\n")
+                        ("/a b\n\n" "/a b\n") ("/a b\r\n" "/a b\n")
+                        ("a b\nc\n\n" "c\n" "a b\n")
+                        ("/a b\nc\n\n" "c\n" "/a b\n")
+                        ("/a b\n\nc\n\n" "c\n" "\n" "/a b\n")))
+         (insert p)
+         (erc-send-current-line)
+         (erc-bol)
+         (should (eq (point) (point-max)))
+         (while q
+           (should (equal (funcall next) (list (pop q) nil t))))
+         (should-not (funcall next))))
+
+     (ert-info ("Multiline hunk with trailing whitespace not filtered")
+       (insert "there\n ")
+       (erc-send-current-line)
+       (should (equal (funcall next) '(" \n" nil t)))
+       (should (equal (funcall next) '("there\n" nil t)))
+       (should-not (funcall next))))))
+
+(ert-deftest erc--check-prompt-input-for-excess-lines ()
+  (ert-info ("Without `erc-inhibit-multiline-input'")
+    (should-not erc-inhibit-multiline-input)
+    (should-not (erc--check-prompt-input-for-excess-lines "" '("a" "b"))))
+
+  (ert-info ("With `erc-inhibit-multiline-input' as t (2)")
+    (let ((erc-inhibit-multiline-input t))
+      (should-not (erc--check-prompt-input-for-excess-lines "" '("a")))
+      (should-not (erc--check-prompt-input-for-excess-lines "" '("a" "")))
+      (should (erc--check-prompt-input-for-excess-lines "" '("a" "b")))))
+
+  (ert-info ("With `erc-inhibit-multiline-input' as 3")
+    (let ((erc-inhibit-multiline-input 3))
+      (should-not (erc--check-prompt-input-for-excess-lines "" '("a" "b")))
+      (should-not (erc--check-prompt-input-for-excess-lines "" '("a" "b" "")))
+      (should (erc--check-prompt-input-for-excess-lines "" '("a" "b" "c")))))
+
+  (ert-info ("With `erc-ask-about-multiline-input'")
+    (let ((erc-inhibit-multiline-input t)
+          (erc-ask-about-multiline-input t))
+      (ert-simulate-keys '(?n ?\r ?y ?\r)
+        (should (erc--check-prompt-input-for-excess-lines "" '("a" "b")))
+        (should-not (erc--check-prompt-input-for-excess-lines "" '("a" "b")))))
+    (should-not erc-ask-about-multiline-input)))
 
 ;; The point of this test is to ensure output is handled identically
 ;; regardless of whether a command handler is summoned.
@@ -340,20 +877,102 @@
         (ert-info ("Implicit cmd via `erc-send-input-line-function'")
 
           (ert-info ("Baseline")
-            (erc-process-input-line "hi")
+            (erc-process-input-line "hi\n")
             (should (equal (pop erc-server-flood-queue)
                            '("PRIVMSG #chan :hi\r\n" . utf-8))))
 
           (ert-info ("Spaces preserved")
-            (erc-process-input-line "hi you")
+            (erc-process-input-line "hi you\n")
             (should (equal (pop erc-server-flood-queue)
                            '("PRIVMSG #chan :hi you\r\n" . utf-8))))
 
-          (ert-info ("Empty line transmitted without injected-space kludge")
-            (erc-process-input-line "")
+          (ert-info ("Empty line transmitted with injected-space kludge")
+            (erc-process-input-line "\n")
             (should (equal (pop erc-server-flood-queue)
-                           '("PRIVMSG #chan :\r\n" . utf-8))))
+                           '("PRIVMSG #chan : \r\n" . utf-8))))
 
           (should-not calls))))))
 
+;; Note: if adding an erc-backend-tests.el, please relocate this there.
+
+(ert-deftest erc-message ()
+  (should-not erc-server-last-peers)
+  (let (server-proc
+        calls
+        erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook)
+    (cl-letf (((symbol-function 'erc-display-message)
+               (lambda (_ _ _ line) (push line calls)))
+              ((symbol-function 'erc-server-send)
+               (lambda (line _) (push line calls)))
+              ((symbol-function 'erc-server-buffer)
+               (lambda () (process-buffer server-proc))))
+      (with-current-buffer (get-buffer-create "ExampleNet")
+        (erc-mode)
+        (setq erc-server-current-nick "tester"
+              server-proc (start-process "sleep" (current-buffer) "sleep" "1")
+              erc-server-process server-proc
+              erc-server-last-peers (cons nil nil)
+              erc-server-users (make-hash-table :test 'equal)
+              erc-network 'ExampleNet)
+        (set-process-query-on-exit-flag erc-server-process nil))
+
+      (with-current-buffer (get-buffer-create "#chan")
+        (erc-mode)
+        (setq erc-server-process (buffer-local-value 'erc-server-process
+                                                     (get-buffer "ExampleNet"))
+              erc-default-recipients '("#chan")
+              erc-channel-users (make-hash-table :test 'equal)
+              erc-network 'ExampleNet)
+        (erc-update-current-channel-member "alice" "alice")
+        (erc-update-current-channel-member "tester" "tester"))
+
+      (with-current-buffer "ExampleNet"
+        (erc-server-PRIVMSG erc-server-process
+                            (make-erc-response
+                             :sender "alice!~u@fsf.org"
+                             :command "PRIVMSG"
+                             :command-args '("#chan" "hi")
+                             :unparsed ":alice!~u@fsf.org PRIVMSG #chan :hi"))
+        (should (equal erc-server-last-peers '("alice")))
+        (should (string-match "<alice>" (pop calls))))
+
+      (with-current-buffer "#chan"
+        (ert-info ("Shortcuts usable in target buffers")
+          (should-not (local-variable-p 'erc-server-last-peers))
+          (should-not erc-server-last-peers)
+          (erc-message "PRIVMSG" ". hi")
+          (should-not erc-server-last-peers)
+          (should (eq 'no-target (pop calls)))
+          (erc-message "PRIVMSG" ", hi")
+          (should-not erc-server-last-peers)
+          (should (string-match "alice :hi" (pop calls)))))
+
+      (with-current-buffer "ExampleNet"
+        (ert-info ("Shortcuts local in server bufs")
+          (should (equal erc-server-last-peers '("alice" . "alice")))
+          (erc-message "PRIVMSG" ", hi")
+          (should (equal erc-server-last-peers '("alice" . "alice")))
+          (should (string-match "PRIVMSG alice :hi" (pop calls)))
+          (setcdr erc-server-last-peers "bob")
+          (erc-message "PRIVMSG" ". hi")
+          (should (equal erc-server-last-peers '("alice" . "bob")))
+          (should (string-match "PRIVMSG bob :hi" (pop calls)))))
+
+      (with-current-buffer "#chan"
+        (ert-info ("Non-shortcuts are local to server buffer")
+          (should-not (local-variable-p 'erc-server-last-peers))
+          (should-not erc-server-last-peers)
+          (erc-message "PRIVMSG" "#chan hola")
+          (should-not erc-server-last-peers)
+          (should-not (default-value 'erc-server-last-peers))
+          (should (equal (buffer-local-value 'erc-server-last-peers
+                                             (get-buffer "ExampleNet"))
+                         '("alice" . "#chan")))
+          (should (string-match "hola" (pop calls))))))
+
+    (should-not erc-server-last-peers)
+    (should-not calls)
+    (kill-buffer "ExampleNet")
+    (kill-buffer "#chan")))
+
 ;;; erc-tests.el ends here
diff --git a/test/lisp/erc/resources/base/assoc/bouncer-history/barnet.eld 
b/test/lisp/erc/resources/base/assoc/bouncer-history/barnet.eld
new file mode 100644
index 0000000000..35a9a570b6
--- /dev/null
+++ b/test/lisp/erc/resources/base/assoc/bouncer-history/barnet.eld
@@ -0,0 +1,44 @@
+;; -*- mode: lisp-data; -*-
+((pass 3 "PASS :barnet:changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.barnet.org 001 tester :Welcome to the barnet IRC Network tester")
+ (0 ":irc.barnet.org 002 tester :Your host is irc.barnet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.barnet.org 003 tester :This server was created Wed, 28 Apr 2021 
06:59:59 UTC")
+ (0 ":irc.barnet.org 004 tester irc.barnet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.barnet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.barnet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=barnet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.barnet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.barnet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.barnet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.barnet.org 254 tester 1 :channels formed")
+ (0 ":irc.barnet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.barnet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.barnet.org 422 tester :MOTD File is missing"))
+
+((mode-user 3.2 "MODE tester +i")
+ ;; No mode answer ^
+ (0 ":irc.znc.in 306 tester :You have been marked as being away")
+ (0 ":tester!~u@xrir8fpe4d7ak.irc JOIN #chan")
+ (0 ":irc.barnet.org 353 tester = #chan :joe @mike tester")
+ (0 ":irc.barnet.org 366 tester #chan :End of /NAMES list.")
+ (0 ":***!znc@znc.in PRIVMSG #chan :Buffer Playback...")
+ (0 ":joe!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :[07:04:25] mike: Belike, for joy 
the emperor hath a son.")
+ (0 ":mike!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :[07:04:27] joe: Protest their 
first of manhood.")
+ (0 ":joe!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :[07:04:29] mike: As frozen water 
to a starved snake.")
+ (0 ":mike!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :[07:04:34] joe: My mirth it 
much displeas'd, but pleas'd my woe.")
+ (0 ":joe!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :[07:04:38] mike: Why, Marcus, no 
man should be mad but I.")
+ (0 ":mike!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :[07:04:44] joe: Faith, I have 
heard too much, for your words and performances are no kin together.")
+ (0 ":***!znc@znc.in PRIVMSG #chan :Playback Complete.")
+ (0 ":irc.barnet.org NOTICE tester :[07:00:01] This server is in debug mode 
and is logging all user I/O. If you do not wish for everything you send to be 
readable by the server owner(s), please disconnect.")
+ (0 ":irc.barnet.org 305 tester :You are no longer marked as being away"))
+
+((mode 6 "MODE #chan")
+ (0 ":irc.barnet.org 324 tester #chan +nt")
+ (0 ":irc.barnet.org 329 tester #chan 1619593200")
+ (0.25 ":joe!~u@svpn88yjcdj42.irc PRIVMSG #chan :mike: But, in defense, by 
mercy, 'tis most just.")
+ (0.25 ":mike!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :joe: The Marshal of France, 
Monsieur la Far.")
+ (0.25 ":joe!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :mike: And bide the penance of 
each three years' day.")
+ (0.25 ":mike!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :joe: Madam, within; but 
never man so chang'd.")
+ (0.25 ":joe!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :mike: As much in private, and 
I'll bid adieu."))
diff --git a/test/lisp/erc/resources/base/assoc/bouncer-history/foonet.eld 
b/test/lisp/erc/resources/base/assoc/bouncer-history/foonet.eld
new file mode 100644
index 0000000000..58df79e19f
--- /dev/null
+++ b/test/lisp/erc/resources/base/assoc/bouncer-history/foonet.eld
@@ -0,0 +1,48 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :foonet:changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Wed, 28 Apr 2021 
07:00:00 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 3.2 "MODE tester +i")
+ ;; No mode answer ^
+ (0 ":irc.znc.in 306 tester :You have been marked as being away")
+ (0 ":tester!~u@nvfhxvqm92rm6.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :alice @bob tester")
+ (0 ":irc.foonet.org 366 tester #chan :End of /NAMES list.")
+ (0 ":***!znc@znc.in PRIVMSG #chan :Buffer Playback...")
+ (0 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:02] alice: Here come the 
lovers, full of joy and mirth.")
+ (0 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:07] bob: According to 
the fool's bolt, sir, and such dulcet diseases.")
+ (0 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:10] alice: And hang 
himself. I pray you, do my greeting.")
+ (0 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:18] bob: And you sat 
smiling at his cruel prey.")
+ (0 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:21] alice: Or never after 
look me in the face.")
+ (0 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:25] bob: If that may 
be, than all is well. Come, sit down, every mother's son, and rehearse your 
parts. Pyramus, you begin: when you have spoken your speech, enter into that 
brake; and so every one according to his cue.")
+ (0 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:30] alice: Where I espied 
the panther fast asleep.")
+ (0 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:32] bob: Alas! he is 
too young: yet he looks successfully.")
+ (0 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:37] alice: Here, at your 
lordship's service.")
+ (0 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:42] bob: By my troth, 
and in good earnest, and so God mend me, and by all pretty oaths that are not 
dangerous, if you break one jot of your promise or come one minute behind your 
hour, I will think you the most pathetical break-promise, and the most hollow 
lover, and the most unworthy of her you call Rosalind, that may be chosen out 
of the gross band of the unfaithful. Therefore, beware my censure, and keep 
your promise.")
+ (0 ":***!znc@znc.in PRIVMSG #chan :Playback Complete.")
+ (0 ":irc.foonet.org NOTICE tester :[07:00:32] This server is in debug mode 
and is logging all user I/O. If you do not wish for everything you send to be 
readable by the server owner(s), please disconnect.")
+ (0 ":irc.foonet.org 305 tester :You are no longer marked as being away"))
+
+((mode 6 "MODE #chan")
+ (0 ":irc.foonet.org 324 tester #chan +nt")
+ (0 ":irc.foonet.org 329 tester #chan 1619593200")
+ (0.9 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :bob: Grows, lives, and dies, 
in single blessedness.")
+ (0.25 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #chan :alice: For these two hours, 
Rosalind, I will leave thee.")
+ (0.25 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :bob: By this hand, it will 
not kill a fly. But come, now I will be your Rosalind in a more coming-on 
disposition; and ask me what you will, I will grant it.")
+ (0.25 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #chan :alice: That I must love a 
loathed enemy.")
+ (0.25 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :bob: As't please your 
lordship: I'll leave you."))
diff --git a/test/lisp/erc/resources/base/assoc/bumped/again.eld 
b/test/lisp/erc/resources/base/assoc/bumped/again.eld
new file mode 100644
index 0000000000..ab3c7b0621
--- /dev/null
+++ b/test/lisp/erc/resources/base/assoc/bumped/again.eld
@@ -0,0 +1,30 @@
+;; -*- mode: lisp-data; -*-
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0.0 ":irc.foonet.org 433 * tester :Nickname is reserved by a different 
account")
+ (0.0 ":irc.foonet.org FAIL NICK NICKNAME_RESERVED tester :Nickname is 
reserved by a different account"))
+
+((nick 3 "NICK tester`")
+ (0.1 ":irc.foonet.org 001 tester` :Welcome to the foonet IRC Network tester`")
+ (0.0 ":irc.foonet.org 002 tester` :Your host is irc.foonet.org, running 
version oragono-2.6.1-937b9b02368748e5")
+ (0.0 ":irc.foonet.org 003 tester` :This server was created Fri, 24 Sep 2021 
01:38:36 UTC")
+ (0.0 ":irc.foonet.org 004 tester` irc.foonet.org 
oragono-2.6.1-937b9b02368748e5 BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0.0 ":irc.foonet.org 005 tester` AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0.1 ":irc.foonet.org 005 tester` MAXLIST=beI:60 MAXTARGETS=4 MODES 
MONITOR=100 NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0.1 ":irc.foonet.org 005 tester` draft/CHATHISTORY=100 :are supported by 
this server")
+ (0.0 ":irc.foonet.org 251 tester` :There are 0 users and 3 invisible on 1 
server(s)")
+ (0.0 ":irc.foonet.org 252 tester` 0 :IRC Operators online")
+ (0.0 ":irc.foonet.org 253 tester` 0 :unregistered connections")
+ (0.0 ":irc.foonet.org 254 tester` 1 :channels formed")
+ (0.0 ":irc.foonet.org 255 tester` :I have 3 clients and 0 servers")
+ (0.0 ":irc.foonet.org 265 tester` 3 3 :Current local users 3, max 3")
+ (0.2 ":irc.foonet.org 266 tester` 3 3 :Current global users 3, max 3")
+ (0.0 ":irc.foonet.org 422 tester` :MOTD File is missing"))
+
+((mode-user 3.2 "MODE tester` +i")
+ (0.0 ":irc.foonet.org 221 tester` +i")
+ (0.0 ":irc.foonet.org NOTICE tester` :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect."))
+
+((privmsg 42.6 "PRIVMSG NickServ :IDENTIFY tester changeme")
+ (0.01 ":tester`!~u@rpaau95je67ci.irc NICK tester")
+ (0.0 ":NickServ!NickServ@localhost NOTICE tester :You're now logged in as 
tester"))
diff --git a/test/lisp/erc/resources/base/assoc/bumped/foisted.eld 
b/test/lisp/erc/resources/base/assoc/bumped/foisted.eld
new file mode 100644
index 0000000000..5c36e58d9d
--- /dev/null
+++ b/test/lisp/erc/resources/base/assoc/bumped/foisted.eld
@@ -0,0 +1,30 @@
+;; -*- mode: lisp-data; -*-
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0.0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0.0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running 
version oragono-2.6.1-937b9b02368748e5")
+ (0.0 ":irc.foonet.org 003 tester :This server was created Fri, 24 Sep 2021 
01:38:36 UTC")
+ (0.0 ":irc.foonet.org 004 tester irc.foonet.org 
oragono-2.6.1-937b9b02368748e5 BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0.0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0.01 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES 
MONITOR=100 NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0.01 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by 
this server")
+ (0.0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0.0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0.0 ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (0.0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0.0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0.0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0.0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0.0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 1.2 "MODE tester +i")
+ (0.0 ":irc.foonet.org 221 tester +i")
+ (0.0 ":irc.foonet.org NOTICE tester :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect."))
+
+((privmsg 17.21 "PRIVMSG bob :hi")
+ (0.02 ":bob!~u@ecnnh95wr67pv.net PRIVMSG tester :hola")
+ (0.01 ":bob!~u@ecnnh95wr67pv.net PRIVMSG tester :how r u?"))
+
+((quit 18.19 "QUIT :" quit)
+ (0.01 ":tester!~u@rpaau95je67ci.irc QUIT :Quit: " quit))
+((drop 1 DROP))
diff --git a/test/lisp/erc/resources/base/assoc/bumped/refoisted.eld 
b/test/lisp/erc/resources/base/assoc/bumped/refoisted.eld
new file mode 100644
index 0000000000..33e4168ac4
--- /dev/null
+++ b/test/lisp/erc/resources/base/assoc/bumped/refoisted.eld
@@ -0,0 +1,31 @@
+;; -*- mode: lisp-data; -*-
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0.1 ":irc.foonet.org 001 dummy :Welcome to the foonet IRC Network dummy")
+ (0.0 ":irc.foonet.org 002 dummy :Your host is irc.foonet.org, running version 
oragono-2.6.1-937b9b02368748e5")
+ (0.0 ":irc.foonet.org 003 dummy :This server was created Fri, 24 Sep 2021 
01:38:36 UTC")
+ (0.0 ":irc.foonet.org 004 dummy irc.foonet.org oragono-2.6.1-937b9b02368748e5 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0.0 ":irc.foonet.org 005 dummy 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.1 ":irc.foonet.org 005 dummy MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0.1 ":irc.foonet.org 005 dummy draft/CHATHISTORY=100 :are supported by this 
server")
+ (0.0 ":irc.foonet.org 251 dummy :There are 0 users and 3 invisible on 1 
server(s)")
+ (0.0 ":irc.foonet.org 252 dummy 0 :IRC Operators online")
+ (0.0 ":irc.foonet.org 253 dummy 0 :unregistered connections")
+ (0.0 ":irc.foonet.org 254 dummy 1 :channels formed")
+ (0.0 ":irc.foonet.org 255 dummy :I have 3 clients and 0 servers")
+ (0.0 ":irc.foonet.org 265 dummy 3 3 :Current local users 3, max 3")
+ (0.2 ":irc.foonet.org 266 dummy 3 3 :Current global users 3, max 3")
+ ;; Could arrive anytime around this point
+ (0.0 ":tester!~u@rpaau95je67ci.irc NICK :dummy")
+ (0.0 ":irc.foonet.org 422 dummy :MOTD File is missing")
+ ;; Playback
+ (0.01 ":bob!~u@ecnnh95wr67pv.net PRIVMSG dummy :back?")
+ )
+
+((mode-user 1.2 "MODE dummy +i")
+ (0.0 ":irc.foonet.org 221 dummy +i")
+ (0.0 ":irc.foonet.org NOTICE dummy :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."))
+
+((renick 42.6 "NICK tester")
+ (0.01 ":dummy!~u@rpaau95je67ci.irc NICK tester")
+ (0.0 ":NickServ!NickServ@localhost NOTICE dummy :You're now logged in as 
tester"))
diff --git a/test/lisp/erc/resources/base/assoc/bumped/renicked.eld 
b/test/lisp/erc/resources/base/assoc/bumped/renicked.eld
new file mode 100644
index 0000000000..4e96fd7304
--- /dev/null
+++ b/test/lisp/erc/resources/base/assoc/bumped/renicked.eld
@@ -0,0 +1,30 @@
+;; -*- mode: lisp-data; -*-
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0.0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0.0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running 
version oragono-2.6.1-937b9b02368748e5")
+ (0.0 ":irc.foonet.org 003 tester :This server was created Fri, 24 Sep 2021 
01:38:36 UTC")
+ (0.0 ":irc.foonet.org 004 tester irc.foonet.org 
oragono-2.6.1-937b9b02368748e5 BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0.0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0.01 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES 
MONITOR=100 NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0.01 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by 
this server")
+ (0.0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0.0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0.0 ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (0.0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0.0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0.0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0.0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0.0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 12 "MODE tester +i")
+ (0.0 ":irc.foonet.org 221 tester +i")
+ (0.0 ":irc.foonet.org NOTICE tester :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect."))
+
+((privmsg 17.21 "PRIVMSG NickServ :REGISTER changeme")
+ (0.02 ":NickServ!NickServ@localhost NOTICE tester :Account created")
+ (0.01 ":NickServ!NickServ@localhost NOTICE tester :You're now logged in as 
tester"))
+
+((quit 18.19 "QUIT :" quit)
+ (0.01 ":tester!~u@rpaau95je67ci.irc QUIT :Quit: " quit))
+((drop 1 DROP))
diff --git a/test/lisp/erc/resources/base/assoc/multi-net/barnet.eld 
b/test/lisp/erc/resources/base/assoc/multi-net/barnet.eld
new file mode 100644
index 0000000000..c62a22a11c
--- /dev/null
+++ b/test/lisp/erc/resources/base/assoc/multi-net/barnet.eld
@@ -0,0 +1,42 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.barnet.org 001 tester :Welcome to the barnet IRC Network tester")
+ (0 ":irc.barnet.org 002 tester :Your host is irc.barnet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.barnet.org 003 tester :This server was created Tue, 04 May 2021 
05:06:19 UTC")
+ (0 ":irc.barnet.org 004 tester irc.barnet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.barnet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.barnet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=barnet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.barnet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.barnet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.barnet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.barnet.org 253 tester 0 :unregistered connections")
+ (0 ":irc.barnet.org 254 tester 1 :channels formed")
+ (0 ":irc.barnet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.barnet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.barnet.org 422 tester :MOTD File is missing"))
+
+((mode-user 8 "MODE tester +i")
+ (0 ":irc.barnet.org 221 tester +i")
+ (0 ":irc.barnet.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 2 "JOIN #chan")
+ (0 ":tester!~u@jnu48g2wrycbw.irc JOIN #chan")
+ (0 ":irc.barnet.org 353 tester = #chan :@mike joe tester")
+ (0 ":irc.barnet.org 366 tester #chan :End of NAMES list"))
+
+((mode 2 "MODE #chan")
+ (0 ":irc.barnet.org 324 tester #chan +nt")
+ (0 ":irc.barnet.org 329 tester #chan 1620104779")
+ (0.1 ":mike!~u@kd7gmjbnbkn8c.irc PRIVMSG #chan :tester, welcome!")
+ (0.1 ":joe!~u@kd7gmjbnbkn8c.irc PRIVMSG #chan :tester, welcome!")
+ (0.1 ":mike!~u@kd7gmjbnbkn8c.irc PRIVMSG #chan :joe: Whipp'd first, sir, and 
hang'd after.")
+ (0.1 ":joe!~u@kd7gmjbnbkn8c.irc PRIVMSG #chan :mike: We have yet many among 
us can gripe as hard as Cassibelan; I do not say I am one, but I have a hand. 
Why tribute ? why should we pay tribute ? If C sar can hide the sun from us 
with a blanket, or put the moon in his pocket, we will pay him tribute for 
light; else, sir, no more tribute, pray you now.")
+ (0.1 ":mike!~u@kd7gmjbnbkn8c.irc PRIVMSG #chan :joe: Double and treble 
admonition, and still forfeit in the same kind ? This would make mercy swear, 
and play the tyrant.")
+ (0.1 ":joe!~u@kd7gmjbnbkn8c.irc PRIVMSG #chan :mike: And secretly to greet 
the empress' friends.")
+ (0.1 ":mike!~u@kd7gmjbnbkn8c.irc PRIVMSG #chan :joe: You have not been 
inquired after: I have sat here all day.")
+ (0.1 ":joe!~u@kd7gmjbnbkn8c.irc PRIVMSG #chan :mike: That same Berowne I'll 
torture ere I go.")
+ (0.1 ":mike!~u@kd7gmjbnbkn8c.irc PRIVMSG #chan :joe: For mine own part,no 
offence to the general, nor any man of quality,I hope to be saved.")
+ (0.1 ":joe!~u@kd7gmjbnbkn8c.irc PRIVMSG #chan :mike: Mehercle! if their sons 
be ingenuous, they shall want no instruction; if their daughters be capable, I 
will put it to them. But, vir sapit qui pauca loquitur. A soul feminine 
saluteth us."))
diff --git a/test/lisp/erc/resources/base/assoc/multi-net/foonet.eld 
b/test/lisp/erc/resources/base/assoc/multi-net/foonet.eld
new file mode 100644
index 0000000000..f30b7deca1
--- /dev/null
+++ b/test/lisp/erc/resources/base/assoc/multi-net/foonet.eld
@@ -0,0 +1,45 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Tue, 04 May 2021 
05:06:18 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 8 "MODE tester +i")
+ (0 ":irc.foonet.org 221 tester +i")
+ (0 ":irc.foonet.org NOTICE tester :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect."))
+
+((join 2 "JOIN #chan")
+ (0 ":tester!~u@9g6b728983yd2.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :alice tester @bob")
+ (0 ":irc.foonet.org 366 tester #chan :End of NAMES list"))
+
+((mode 2 "MODE #chan")
+ (0 ":irc.foonet.org 324 tester #chan +nt")
+ (0 ":irc.foonet.org 329 tester #chan 1620104779")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :tester, welcome!")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :tester, welcome!")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: But, as it seems, did 
violence on herself.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: Well, this is the 
forest of Arden.")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: Signior Iachimo will 
not from it. Pray, let us follow 'em.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: Our queen and all her 
elves come here anon.")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: The ground is bloody; 
search about the churchyard.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: You have discharged 
this honestly: keep it to yourself. Many likelihoods informed me of this 
before, which hung so tottering in the balance that I could neither believe nor 
misdoubt. Pray you, leave me: stall this in your bosom; and I thank you for 
your honest care. I will speak with you further anon.")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: Give me that mattock, 
and the wrenching iron.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: Stand you! You have 
land enough of your own; but he added to your having, gave you some ground.")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: Excellent workman! Thou 
canst not paint a man so bad as is thyself.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: And will you, being a 
man of your breeding, be married under a bush, like a beggar ? Get you to 
church, and have a good priest that can tell you what marriage is: this fellow 
will but join you together as they join wainscot; then one of you will prove a 
shrunk panel, and like green timber, warp, warp.")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: Live, and be 
prosperous; and farewell, good fellow."))
diff --git a/test/lisp/erc/resources/base/assoc/reconplay/again.eld 
b/test/lisp/erc/resources/base/assoc/reconplay/again.eld
new file mode 100644
index 0000000000..4210c07e41
--- /dev/null
+++ b/test/lisp/erc/resources/base/assoc/reconplay/again.eld
@@ -0,0 +1,42 @@
+;; -*- mode: lisp-data; -*-
+((pass 4.0 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0.0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0.0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running 
version oragono-2.6.0-7481bf0385b95b16")
+ (0.0 ":irc.foonet.org 003 tester :This server was created Wed, 16 Jun 2021 
04:15:00 UTC")
+ (0.0 ":irc.foonet.org 004 tester irc.foonet.org 
oragono-2.6.0-7481bf0385b95b16 BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0.0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0.0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES 
MONITOR=100 NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0.0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0.0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0.0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0.0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0.0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0.0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0.0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0.0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 10 "MODE tester +i")
+ ;; No mode answer
+ (0.0 ":tester!~u@mw6kegwt77kwe.irc JOIN #chan")
+ (0.0 ":irc.foonet.org 353 tester = #chan :alice @bob tester")
+ (0.0 ":irc.foonet.org 366 tester #chan :End of /NAMES list.")
+ (0.0 ":***!znc@znc.in PRIVMSG #chan :Buffer Playback...")
+ (0.0 ":alice!~u@mw6kegwt77kwe.irc PRIVMSG #chan :[10:37:52] bob: Thou pout'st 
upon thy fortune and thy love.")
+ (0.0 ":bob!~u@mw6kegwt77kwe.irc PRIVMSG #chan :[10:37:56] alice: With these 
mortals on the ground.")
+ (0.0 ":***!znc@znc.in PRIVMSG #chan :Playback Complete."))
+
+((mode 10 "MODE #chan")
+ (0.0 ":irc.foonet.org 324 tester #chan +nt")
+ (0.0 ":irc.foonet.org 329 tester #chan 1623816901")
+ (0.1 ":bob!~u@mw6kegwt77kwe.irc PRIVMSG #chan :alice: My name, my good lord, 
is Parolles.")
+ (0.1 ":alice!~u@mw6kegwt77kwe.irc PRIVMSG #chan :bob: Wilt thou rest damned ? 
God help thee, shallow man! God make incision in thee! thou art raw."))
+
+((privmsg 3.0 "PRIVMSG *status :help")
+ (0.0 ":*status!znc@znc.in PRIVMSG tester :In the following list all 
occurrences of <#chan> support wildcards (* and ?) except ListNicks")
+ (0.0 ":*status!znc@znc.in PRIVMSG tester :\2Version\17: Print which version 
of ZNC this is")
+ (0.0 ":*status!znc@znc.in PRIVMSG tester :\2Shutdown [message]\17: Shut down 
ZNC completely")
+ (0.0 ":*status!znc@znc.in PRIVMSG tester :\2Restart [message]\17: Restart 
ZNC")
+ (0.1 ":bob!~u@mw6kegwt77kwe.irc PRIVMSG #chan :alice: In that word's death; 
no words can that woe sound.")
+ (0.1 ":alice!~u@mw6kegwt77kwe.irc PRIVMSG #chan :bob: Look, sir, here comes 
the lady towards my cell."))
diff --git a/test/lisp/erc/resources/base/assoc/reconplay/foonet.eld 
b/test/lisp/erc/resources/base/assoc/reconplay/foonet.eld
new file mode 100644
index 0000000000..f916fea237
--- /dev/null
+++ b/test/lisp/erc/resources/base/assoc/reconplay/foonet.eld
@@ -0,0 +1,52 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0.0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0.0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running 
version oragono-2.6.0-7481bf0385b95b16")
+ (0.0 ":irc.foonet.org 003 tester :This server was created Wed, 16 Jun 2021 
04:15:00 UTC")
+ (0.0 ":irc.foonet.org 004 tester irc.foonet.org 
oragono-2.6.0-7481bf0385b95b16 BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0.0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0.0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES 
MONITOR=100 NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0.0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0.0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0.0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0.0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0.0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0.0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0.0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0.0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 5 "MODE tester +i")
+ ;; No mode answer
+ (0.0 ":irc.znc.in 306 tester :You have been marked as being away")
+ (0.0 ":tester!~u@mw6kegwt77kwe.irc JOIN #chan")
+ (0.0 ":irc.foonet.org 353 tester = #chan :alice @bob tester")
+ (0.0 ":irc.foonet.org 366 tester #chan :End of /NAMES list.")
+ (0.0 ":***!znc@znc.in PRIVMSG #chan :Buffer Playback...")
+ (0.0 ":alice!~u@mw6kegwt77kwe.irc PRIVMSG #chan :[10:35:50] bob: To Laced mon 
did my land extend.")
+ (0.0 ":bob!~u@mw6kegwt77kwe.irc PRIVMSG #chan :[10:35:55] alice: This is but 
a custom in your tongue; you bear a graver purpose, I hope.")
+ (0.0 ":alice!~u@mw6kegwt77kwe.irc PRIVMSG #chan :[10:37:16] bob: To imitate 
them; faults that are rich are fair.")
+ (0.0 ":bob!~u@mw6kegwt77kwe.irc PRIVMSG #chan :[10:37:18] alice: Our Romeo 
hath not been in bed to-night.")
+ (0.0 ":alice!~u@mw6kegwt77kwe.irc PRIVMSG #chan :[10:37:21] bob: But, in 
defense, by mercy, 'tis most just.")
+ (0.0 ":bob!~u@mw6kegwt77kwe.irc PRIVMSG #chan :[10:37:25] alice: Younger than 
she are happy mothers made.")
+ (0.0 ":***!znc@znc.in PRIVMSG #chan :Playback Complete.")
+ (0.0 ":irc.foonet.org 305 tester :You are no longer marked as being away"))
+
+((mode 3 "MODE #chan")
+ (1.0 ":irc.foonet.org 324 tester #chan +nt")
+ (0.0 ":irc.foonet.org 329 tester #chan 1623816901")
+ (0.1 ":alice!~u@mw6kegwt77kwe.irc PRIVMSG #chan :bob: At thy good heart's 
oppression.")
+ (0.1 ":bob!~u@mw6kegwt77kwe.irc PRIVMSG #chan :alice: But purgatory, torture, 
hell itself."))
+
+((privmsg 3 "PRIVMSG *status :help")
+ (0.0 ":*status!znc@znc.in PRIVMSG tester :In the following list all 
occurrences of <#chan> support wildcards (* and ?) except ListNicks")
+ (0.0 ":*status!znc@znc.in PRIVMSG tester :\2AddPort <[+]port> <ipv4|ipv6|all> 
<web|irc|all> [bindhost [uriprefix]]\17: Add another port for ZNC to listen on")
+ (0.0 ":*status!znc@znc.in PRIVMSG tester :\2DelPort <port> <ipv4|ipv6|all> 
[bindhost]\17: Remove a port from ZNC")
+ (0.0 ":*status!znc@znc.in PRIVMSG tester :\2Rehash\17: Reload global 
settings, modules, and listeners from znc.conf")
+ (0.1 ":alice!~u@mw6kegwt77kwe.irc PRIVMSG #chan :bob: And at my suit, sweet, 
pardon what is past.")
+ (0.1 ":bob!~u@mw6kegwt77kwe.irc PRIVMSG #chan :alice: My lord, you give me 
most egregious indignity."))
+
+((quit 2 "QUIT :\2ERC\2"))
+
+((drop 0 DROP))
diff --git a/test/lisp/erc/resources/base/assoc/samenet/chester.eld 
b/test/lisp/erc/resources/base/assoc/samenet/chester.eld
new file mode 100644
index 0000000000..f1aed2836c
--- /dev/null
+++ b/test/lisp/erc/resources/base/assoc/samenet/chester.eld
@@ -0,0 +1,40 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK chester"))
+((user 1 "USER user 0 * :chester")
+ (0 ":irc.foonet.org 001 chester :Welcome to the foonet IRC Network chester")
+ (0 ":irc.foonet.org 002 chester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 chester :This server was created Sun, 13 Jun 2021 
05:45:20 UTC")
+ (0 ":irc.foonet.org 004 chester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 chester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 chester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 chester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 chester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 chester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 253 chester 1 :unregistered connections")
+ (0 ":irc.foonet.org 254 chester 1 :channels formed")
+ (0 ":irc.foonet.org 255 chester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 chester 3 4 :Current local users 3, max 4")
+ (0 ":irc.foonet.org 266 chester 3 4 :Current global users 3, max 4")
+ (0 ":irc.foonet.org 422 chester :MOTD File is missing"))
+
+((mode-user 12 "MODE chester +i")
+ (0 ":irc.foonet.org 221 chester +i")
+ (0 ":chester!~u@yuvqisyu7m7qs.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 chester = #chan :tester chester @alice bob")
+ (0 ":irc.foonet.org 366 chester #chan :End of NAMES list")
+ (0 ":irc.foonet.org NOTICE chester :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect."))
+
+((mode 10 "MODE #chan")
+ (0.0 ":irc.foonet.org 324 chester #chan +nt")
+ (0.0 ":irc.foonet.org 329 chester #chan 1623563121")
+ (0.0 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :chester, welcome!")
+ (0.0 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :chester, welcome!")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :alice: Dispatch, I say, and 
find the forester.")
+ (0.0 ":tester!~u@yuvqisyu7m7qs.irc QUIT :Quit: " quit)
+ (0.5 ":tester!~u@yuvqisyu7m7qs.irc JOIN #chan")
+ (0.1 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :tester, welcome again!")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :tester, welcome again!"))
+
+((quit 20 "QUIT :" quit)
+ (0.0 ":chester!~u@yuvqisyu7m7qs.irc QUIT :Quit: " quit))
diff --git a/test/lisp/erc/resources/base/assoc/samenet/tester.eld 
b/test/lisp/erc/resources/base/assoc/samenet/tester.eld
new file mode 100644
index 0000000000..cd9cacbe5d
--- /dev/null
+++ b/test/lisp/erc/resources/base/assoc/samenet/tester.eld
@@ -0,0 +1,42 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Sun, 13 Jun 2021 
05:45:20 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 4 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 4 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 4 4 :Current local users 4, max 4")
+ (0 ":irc.foonet.org 266 tester 4 4 :Current global users 4, max 4")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 12 "MODE tester +i")
+ (0 ":irc.foonet.org 221 tester +i")
+ (0 ":irc.foonet.org NOTICE tester :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect."))
+
+((join 15 "JOIN #chan")
+ (0 ":tester!~u@yuvqisyu7m7qs.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :tester @alice bob")
+ (0 ":irc.foonet.org 366 tester #chan :End of NAMES list"))
+
+((mode 10 "MODE #chan")
+ (0.0 ":irc.foonet.org 324 tester #chan +nt")
+ (0.0 ":irc.foonet.org 329 tester #chan 1623563121")
+ (0.0 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :tester, welcome!")
+ (0.0 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :tester, welcome!")
+ (0.0 ":chester!~u@yuvqisyu7m7qs.irc JOIN #chan")
+ (0.1 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :chester, welcome!")
+ (0.0 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :chester, welcome!")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :alice: Dispatch, I say, and 
find the forester."))
+
+((quit 4 "QUIT "))
+
+((drop 0 DROP))
diff --git a/test/lisp/erc/resources/base/assoc/samenet/tester2.eld 
b/test/lisp/erc/resources/base/assoc/samenet/tester2.eld
new file mode 100644
index 0000000000..67c3a94a26
--- /dev/null
+++ b/test/lisp/erc/resources/base/assoc/samenet/tester2.eld
@@ -0,0 +1,39 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Sun, 13 Jun 2021 
05:45:20 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 4 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 4 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 4 4 :Current local users 4, max 4")
+ (0 ":irc.foonet.org 266 tester 4 4 :Current global users 4, max 4")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 4.2 "MODE tester +i")
+ (0 ":irc.foonet.org 221 tester +i")
+ (0 ":irc.foonet.org NOTICE tester :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect.")
+ (0 ":tester!~u@yuvqisyu7m7qs.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :tester @alice bob chester")
+ (0 ":irc.foonet.org 366 tester #chan :End of NAMES list"))
+
+((~useless-join 10 "JOIN #chan"))
+
+((mode 10 "MODE #chan")
+ (0.0 ":irc.foonet.org 324 tester #chan +nt")
+ (0.0 ":irc.foonet.org 329 tester #chan 1623563121")
+ (0.0 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :tester, welcome again!")
+ (0.0 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :tester, welcome again!"))
+
+((quit 4 "QUIT :" quit)
+ (0 ":tester!~u@yuvqisyu7m7qs.irc QUIT :Quit: " quit))
+
+((linger 5 LINGER))
diff --git a/test/lisp/erc/resources/base/auth-source/foonet.eld 
b/test/lisp/erc/resources/base/auth-source/foonet.eld
new file mode 100644
index 0000000000..1fe772c7e2
--- /dev/null
+++ b/test/lisp/erc/resources/base/auth-source/foonet.eld
@@ -0,0 +1,23 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Tue, 04 May 2021 
05:06:18 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=FooNet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 1.2 "MODE tester +i")
+ (0 ":irc.foonet.org 221 tester +i")
+ (0 ":irc.foonet.org NOTICE tester :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect."))
diff --git a/test/lisp/erc/resources/base/auth-source/nopass.eld 
b/test/lisp/erc/resources/base/auth-source/nopass.eld
new file mode 100644
index 0000000000..3fdb4ecf7b
--- /dev/null
+++ b/test/lisp/erc/resources/base/auth-source/nopass.eld
@@ -0,0 +1,22 @@
+;; -*- mode: lisp-data; -*-
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Tue, 04 May 2021 
05:06:18 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=FooNet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 1.2 "MODE tester +i")
+ (0 ":irc.foonet.org 221 tester +i")
+ (0 ":irc.foonet.org NOTICE tester :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect."))
diff --git a/test/lisp/erc/resources/base/channel-buffer-revival/foonet.eld 
b/test/lisp/erc/resources/base/channel-buffer-revival/foonet.eld
new file mode 100644
index 0000000000..b09692327c
--- /dev/null
+++ b/test/lisp/erc/resources/base/channel-buffer-revival/foonet.eld
@@ -0,0 +1,45 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Tue, 04 May 2021 
05:06:18 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=FooNet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 12 "MODE tester +i")
+ (0 ":irc.foonet.org 221 tester +i")
+ (0 ":irc.foonet.org NOTICE tester :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect."))
+
+((join 6 "JOIN #chan")
+ (0 ":tester!~u@9g6b728983yd2.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :alice tester @bob")
+ (0 ":irc.foonet.org 366 tester #chan :End of NAMES list"))
+
+((mode 8 "MODE #chan")
+ (0 ":irc.foonet.org 324 tester #chan +nt")
+ (0 ":irc.foonet.org 329 tester #chan 1620104779")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :tester, welcome!")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :tester, welcome!")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: But, as it seems, did 
violence on herself.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: Well, this is the 
forest of Arden.")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: Signior Iachimo will 
not from it. Pray, let us follow 'em.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: Our queen and all her 
elves come here anon.")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: The ground is bloody; 
search about the churchyard.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: You have discharged 
this honestly: keep it to yourself. Many likelihoods informed me of this 
before, which hung so tottering in the balance that I could neither believe nor 
misdoubt. Pray you, leave me: stall this in your bosom; and I thank you for 
your honest care. I will speak with you further anon.")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: Give me that mattock, 
and the wrenching iron.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: Stand you! You have 
land enough of your own; but he added to your having, gave you some ground.")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: Excellent workman! Thou 
canst not paint a man so bad as is thyself.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: And will you, being a 
man of your breeding, be married under a bush, like a beggar ? Get you to 
church, and have a good priest that can tell you what marriage is: this fellow 
will but join you together as they join wainscot; then one of you will prove a 
shrunk panel, and like green timber, warp, warp.")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: Live, and be 
prosperous; and farewell, good fellow."))
diff --git a/test/lisp/erc/resources/base/flood/soju.eld 
b/test/lisp/erc/resources/base/flood/soju.eld
new file mode 100644
index 0000000000..05266ca941
--- /dev/null
+++ b/test/lisp/erc/resources/base/flood/soju.eld
@@ -0,0 +1,87 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0.13 ":soju.im 001 tester :Welcome to soju, tester")
+ (0.0 ":soju.im 002 tester :Your host is soju.im")
+ (0.0 ":soju.im 004 tester soju.im soju aiwroO OovaimnqpsrtklbeI")
+ (0.0 ":soju.im 005 tester CHATHISTORY=1000 CASEMAPPING=ascii NETWORK=Soju 
:are supported")
+ (0.0 ":soju.im 422 tester :No MOTD"))
+
+((mode 1 "MODE tester +i")
+ (0.0 ":tester!tester@10.0.2.100 JOIN #chan/foonet")
+ (0.25 ":soju.im 331 tester #chan/foonet :No topic is set")
+ (0.0 ":soju.im 353 tester = #chan/foonet :@bob/foonet alice/foonet tester")
+ (0.01 ":soju.im 366 tester #chan/foonet :End of /NAMES list")
+ (0.0 ":tester!tester@10.0.2.100 JOIN #chan/barnet")
+ (0.04 ":soju.im 331 tester #chan/barnet :No topic is set")
+ (0.0 ":soju.im 353 tester = #chan/barnet :tester @mike/barnet joe/barnet")
+ (0.01 ":soju.im 366 tester #chan/barnet :End of /NAMES list")
+ (0.01 ":bob/foonet PRIVMSG #chan/foonet :alice: Then this breaking of his has 
been but a try for his friends.")
+ (0.16 ":alice/foonet PRIVMSG #chan/foonet :bob: By my troth, I take my young 
lord to be a very melancholy man.")
+ (0.91 ":bob/foonet PRIVMSG #chan/foonet :alice: No, truly, for the truest 
poetry is the most feigning; and lovers are given to poetry, and what they 
swear in poetry may be said as lovers they do feign.")
+ (0.01 ":alice/foonet PRIVMSG #chan/foonet :bob: Sir, his wife some two months 
since fled from his house: her pretence is a pilgrimage to Saint Jaques le 
Grand; which holy undertaking with most austere sanctimony she accomplished; 
and, there residing, the tenderness of her nature became as a prey to her 
grief; in fine, made a groan of her last breath, and now she sings in heaven.")
+ (0.0 ":mike/barnet PRIVMSG #chan/barnet :joe: Who ? not the duke ? yes, your 
beggar of fifty, and his use was to put a ducat in her clack-dish; the duke had 
crotchets in him. He would be drunk too; that let me inform you.")
+ (0.01 ":joe/barnet PRIVMSG #chan/barnet :mike: Prove it before these varlets 
here, thou honourable man, prove it.")
+ (0.0 ":mike/barnet PRIVMSG #chan/barnet :joe: That my report is just and full 
of truth.")
+ (0.0 ":joe/barnet PRIVMSG #chan/barnet :mike: It is impossible they bear it 
out.")
+ ;; Expected, since we blindly send +i
+ (0.0 ":soju.im 501 tester :Cannot change user mode in multi-upstream mode"))
+
+((~mode-foonet 5 "MODE #chan/foonet")
+ (0.0 ":soju.im 324 tester #chan/foonet +nt")
+ (0.16 ":soju.im 329 tester #chan/foonet 1647158643")
+ ;; Start frantic pinging
+ (0.0 "PING :soju-msgid-1"))
+
+((~mode-barnet 5 "MODE #chan/barnet")
+ (0.0 ":soju.im 324 tester #chan/barnet +nt")
+ (0.0 ":soju.im 329 tester #chan/barnet 1647158643"))
+
+((pong-1 5 "PONG :soju-msgid-1")
+ (0.0 ":bob/foonet!~u@g56t7uz8xjj4e.irc PRIVMSG #chan/foonet :alice: The 
king's coming; I know by his trumpets. Sirrah, inquire further after me; I had 
talk of you last night: though you are a fool and a knave, you shall eat: go 
to, follow.")
+ (0.0 ":mike/barnet!~u@qsidzk5cytcai.irc PRIVMSG #chan/barnet :joe: Up: so. 
How is 't ? Feel you your legs ? You stand.")
+ (0.0 ":alice/foonet!~u@g56t7uz8xjj4e.irc PRIVMSG #chan/foonet :bob: Consider 
then we come but in despite.")
+ (0.1 "PING :soju-msgid-2"))
+
+((pong-2 2 "PONG :soju-msgid-2")
+ (0.1 ":joe/barnet!~u@qsidzk5cytcai.irc PRIVMSG #chan/barnet :mike: All hail, 
Macbeth! that shalt be king hereafter.")
+ (0.1 "PING :soju-msgid-3"))
+
+((pong-3 2 "PONG :soju-msgid-3")
+ (0.1 ":bob/foonet!~u@g56t7uz8xjj4e.irc PRIVMSG #chan/foonet :alice: And that 
at my bidding you could so stand up.")
+ (0.1 "PING :soju-msgid-4"))
+
+((pong-4 2 "PONG :soju-msgid-4")
+ (0.03 ":mike/barnet!~u@qsidzk5cytcai.irc PRIVMSG #chan/barnet :joe: Now he 
tells how she plucked him to my chamber. O! I see that nose of yours, but not 
the dog I shall throw it to.")
+ (0.1 "PING :soju-msgid-5"))
+
+((pong-5 2 "PONG :soju-msgid-5")
+ (0.1 ":alice/foonet!~u@g56t7uz8xjj4e.irc PRIVMSG #chan/foonet :bob: For 
policy sits above conscience.")
+ (0.1 "PING :soju-msgid-6"))
+
+((pong-6 2 "PONG :soju-msgid-6")
+ (0.0 ":joe/barnet!~u@qsidzk5cytcai.irc PRIVMSG #chan/barnet :mike: Take heed 
o' the foul fiend. Obey thy parents; keep thy word justly; swear not; commit 
not with man's sworn spouse; set not thy sweet heart on proud array. Tom's 
a-cold.")
+ (0.1 "PING :soju-msgid-7"))
+
+((pong-7 2 "PONG :soju-msgid-7")
+ (0.08 ":mike/barnet!~u@qsidzk5cytcai.irc PRIVMSG #chan/barnet :joe: To suffer 
with him. Good love, call him back.")
+ (0.1 "PING :soju-msgid-8"))
+
+((pong-9 2 "PONG :soju-msgid-8")
+ (0.1 ":bob/foonet!~u@g56t7uz8xjj4e.irc PRIVMSG #chan/foonet :alice: Be not 
obdurate, open thy deaf ears.")
+ (0.0 "PING :soju-msgid-9"))
+
+((pong-10 2 "PONG :soju-msgid-9")
+ (0.04 ":joe/barnet!~u@qsidzk5cytcai.irc PRIVMSG #chan/barnet :mike: To get 
good guard and go along with me.")
+ (0.1 "PING :soju-msgid-10"))
+
+((~privmsg 2 "PRIVMSG #chan/foonet :alice: hi")
+ (0.1 ":alice/foonet!~u@g56t7uz8xjj4e.irc PRIVMSG #chan/foonet :tester: Good, 
very good; it is so then: good, very good. Let it be concealed awhile."))
+
+((pong-11 2 "PONG :soju-msgid-10")
+ (0.1 ":alice/foonet!~u@g56t7uz8xjj4e.irc PRIVMSG #chan/foonet :bob: Some man 
or other must present Wall; and let him have some plaster, or some loam, or 
some rough-cast about him, to signify wall; and let him hold his fingers thus, 
and through that cranny shall Pyramus and Thisby whisper.")
+ (0.0 "PING :soju-msgid-11"))
+
+((pong-12 5 "PONG :soju-msgid-11")
+ (0.1 ":mike/barnet!~u@qsidzk5cytcai.irc PRIVMSG #chan/barnet :joe: That's he 
that was Othello; here I am."))
diff --git a/test/lisp/erc/resources/base/gapless-connect/barnet.eld 
b/test/lisp/erc/resources/base/gapless-connect/barnet.eld
new file mode 100644
index 0000000000..4e658802ef
--- /dev/null
+++ b/test/lisp/erc/resources/base/gapless-connect/barnet.eld
@@ -0,0 +1,40 @@
+;; -*- mode: lisp-data; -*-
+((pass 10 "PASS :barnet:changeme"))
+((nick 10 "NICK tester"))
+((user 0.2 "USER user 0 * :tester")
+ (0 ":irc.barnet.org 001 tester :Welcome to the barnet IRC Network tester")
+ (0 ":irc.barnet.org 002 tester :Your host is irc.barnet.org, running version 
oragono-2.5.1-4860c5cad0179db1")
+ (0 ":irc.barnet.org 003 tester :This server was created Fri, 19 Mar 2021 
10:23:19 UTC")
+ (0 ":irc.barnet.org 004 tester irc.barnet.org oragono-2.5.1-4860c5cad0179db1 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.barnet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m INVEX KICKLEN=390 MAXLIST=beI:60 :are supported by 
this server")
+ (0 ":irc.barnet.org 005 tester MAXTARGETS=4 MODES MONITOR=100 NETWORK=barnet 
NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX draft/CHATHISTORY=100 :are 
supported by this server")
+ (0 ":irc.barnet.org 251 tester :There are 0 users and 1 invisible on 1 
server(s)")
+ (0 ":irc.barnet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.barnet.org 254 tester 0 :channels formed")
+ (0 ":irc.barnet.org 255 tester :I have 1 clients and 0 servers")
+ (0 ":irc.barnet.org 265 tester 1 1 :Current local users 1, max 1")
+ (0 ":irc.barnet.org 266 tester 1 1 :Current global users 1, max 1")
+ (0 ":irc.barnet.org 422 tester :MOTD File is missing"))
+
+((mode-user 10.2 "MODE tester +i")
+ ;; No mode answer
+ (0 ":irc.znc.in 306 tester :You have been marked as being away")
+ (0 ":tester!~u@8cgjyczyrjgby.irc JOIN #bar")
+ (0 ":irc.barnet.org 353 tester = #bar :@mike joe tester")
+ (0 ":irc.barnet.org 366 tester #bar :End of /NAMES list.")
+ (0 ":***!znc@znc.in PRIVMSG #bar :Buffer Playback...")
+ (0 ":joe!~u@8cgjyczyrjgby.irc PRIVMSG #bar :[10:23:28] tester, welcome!")
+ (0 ":mike!~u@8cgjyczyrjgby.irc PRIVMSG #bar :[10:23:28] tester, welcome!")
+ (0 ":joe!~u@8cgjyczyrjgby.irc PRIVMSG #bar :[10:24:49] mike: Bid me farewell, 
and let me hear thee going.")
+ (0 ":mike!~u@8cgjyczyrjgby.irc PRIVMSG #bar :[10:24:54] joe: By heaven, thy 
love is black as ebony.")
+ (0 ":***!znc@znc.in PRIVMSG #bar :Playback Complete.")
+ (0 ":irc.barnet.org NOTICE tester :[10:23:22] This server is in debug mode 
and is logging all user I/O. If you do not wish for everything you send to be 
readable by the server owner(s), please disconnect.")
+ (0 ":irc.barnet.org 305 tester :You are no longer marked as being away"))
+
+((mode 20 "MODE #bar")
+ (0 ":irc.barnet.org 324 tester #bar +nt")
+ (0 ":irc.barnet.org 329 tester #bar 1616149403")
+ (0.1 ":mike!~u@8cgjyczyrjgby.irc PRIVMSG #bar :joe: To ask of whence you are: 
report it.")
+ (0.1 ":joe!~u@8cgjyczyrjgby.irc PRIVMSG #bar :mike: Friar, thou knowest not 
the duke so well as I do: he's a better woodman than thou takest him for.")
+ (0.1 ":mike!~u@8cgjyczyrjgby.irc PRIVMSG #bar :joe: Like the sequel, I. 
Signior Costard, adieu.")
+ (0.1 ":joe!~u@8cgjyczyrjgby.irc PRIVMSG #bar :mike: This is his second fit; 
he had one yesterday."))
diff --git a/test/lisp/erc/resources/base/gapless-connect/foonet.eld 
b/test/lisp/erc/resources/base/gapless-connect/foonet.eld
new file mode 100644
index 0000000000..4ac4a3e596
--- /dev/null
+++ b/test/lisp/erc/resources/base/gapless-connect/foonet.eld
@@ -0,0 +1,41 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :foonet:changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Sun, 25 Apr 2021 
11:28:28 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 10.2 "MODE tester +i")
+ ;; No mode answer
+ (0 ":irc.znc.in 306 tester :You have been marked as being away")
+ (0 ":tester!~u@xrir8fpe4d7ak.irc JOIN #foo")
+ (0 ":irc.foonet.org 353 tester = #foo :joe @mike tester")
+ (0 ":irc.foonet.org 366 tester #foo :End of /NAMES list.")
+ (0 ":***!znc@znc.in PRIVMSG #foo :Buffer Playback...")
+ (0 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #foo :[07:02:41] bob: To-morrow is 
the joyful day, Audrey; to-morrow will we be married.")
+ (0 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #foo :[07:02:44] alice: Why dost thou 
call them knaves ? thou know'st them not.")
+ (0 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #foo :[07:03:05] bob: Now, by the 
faith of my love, I will: tell me where it is.")
+ (0 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #foo :[07:03:09] alice: Give me the 
letter; I will look on it.")
+ (0 ":***!znc@znc.in PRIVMSG #foo :Playback Complete.")
+ (0 ":irc.foonet.org NOTICE tester :[11:29:00] This server is in debug mode 
and is logging all user I/O. If you do not wish for everything you send to be 
readable by the server owner(s), please disconnect.")
+ (0 ":irc.foonet.org 305 tester :You are no longer marked as being away"))
+
+((mode 8 "MODE #foo")
+ (0 ":irc.foonet.org 324 tester #foo +nt")
+ (0 ":irc.foonet.org 329 tester #foo 1619593200")
+ (0.1 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #foo :bob: By this hand, it will 
not kill a fly. But come, now I will be your Rosalind in a more coming-on 
disposition; and ask me what you will, I will grant it.")
+ (0.1 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #foo :alice: That I must love a 
loathed enemy.")
+ (0.1 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #foo :bob: His discretion, I am 
sure, cannot carry his valour, for the goose carries not the fox. It is well: 
leave it to his discretion, and let us listen to the moon.")
+ (0.1 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #foo :alice: As living here and you 
no use of him."))
diff --git a/test/lisp/erc/resources/base/gapless-connect/pass-stub.eld 
b/test/lisp/erc/resources/base/gapless-connect/pass-stub.eld
new file mode 100644
index 0000000000..0c8dfd19d0
--- /dev/null
+++ b/test/lisp/erc/resources/base/gapless-connect/pass-stub.eld
@@ -0,0 +1,4 @@
+;; -*- mode: lisp-data; -*-
+((pass 3 "PASS :" token ":changeme"))
+
+((fake 1 "FAKE no op"))
diff --git a/test/lisp/erc/resources/base/mask-target-routing/foonet.eld 
b/test/lisp/erc/resources/base/mask-target-routing/foonet.eld
new file mode 100644
index 0000000000..796d5566b6
--- /dev/null
+++ b/test/lisp/erc/resources/base/mask-target-routing/foonet.eld
@@ -0,0 +1,45 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Mon, 31 May 2021 
09:56:24 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 4 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 254 tester 2 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 4 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 4 4 :Current local users 4, max 4")
+ (0 ":irc.foonet.org 266 tester 4 4 :Current global users 4, max 4")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 1.2 "MODE tester +i")
+ ;; No mode answer
+ (0 ":irc.znc.in 306 tester :You have been marked as being away")
+ (0 ":tester!~u@gq7yjr7gsu7nn.irc JOIN #foo")
+ (0 ":irc.foonet.org 353 tester = #foo :alice @bob rando tester")
+ (0 ":irc.foonet.org 366 tester #foo :End of /NAMES list.")
+ (0 ":***!znc@znc.in PRIVMSG #foo :Buffer Playback...")
+ (0 ":alice!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :[10:00:02] bob: All that he is 
hath reference to your highness.")
+ (0 ":bob!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :[10:00:06] alice: Excellent 
workman! Thou canst not paint a man so bad as is thyself.")
+ (0 ":***!znc@znc.in PRIVMSG #foo :Playback Complete.")
+ (0 ":irc.foonet.org NOTICE tester :[09:56:57] This server is in debug mode 
and is logging all user I/O. If you do not wish for everything you send to be 
readable by the server owner(s), please disconnect.")
+ (0 ":irc.foonet.org 305 tester :You are no longer marked as being away"))
+
+((mode 5 "MODE #foo")
+ (0 ":irc.foonet.org 324 tester #foo +nt")
+ (0 ":irc.foonet.org 329 tester #foo 1622454985")
+ ;; Invalid msg
+ (0.1 ":rando!~u@em2i467d4ejul.irc PRIVMSG :")
+ (0.1 ":alice!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :bob: Farewell, pretty lady: 
you must hold the credit of your father.")
+ (0.1 ":bob!~u@gq7yjr7gsu7nn.irc NOTICE $* :[Global notice] going down soon.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #foo :bob: Well, this is the forest 
of Arden.")
+ (0.1 ":bob!~u@gq7yjr7gsu7nn.irc NOTICE $$* :[Global notice] this is a 
warning.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #foo :bob: Be married under a bush, 
like a beggar ? Get you to church, and have a good priest that can tell you 
what marriage is: this fellow will but join you together as they join wainscot; 
then one of you will prove a shrunk panel, and like green timber, warp, warp.")
+ (0.1 ":bob!~u@gq7yjr7gsu7nn.irc PRIVMSG $* :[Global msg] second warning.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #foo :bob: And will you, being a 
man of your breeding.")
+ (0.1 ":bob!~u@gq7yjr7gsu7nn.irc NOTICE #* :[Global notice] final warning."))
diff --git a/test/lisp/erc/resources/base/netid/bouncer/barnet-again.eld 
b/test/lisp/erc/resources/base/netid/bouncer/barnet-again.eld
new file mode 100644
index 0000000000..e2fe143028
--- /dev/null
+++ b/test/lisp/erc/resources/base/netid/bouncer/barnet-again.eld
@@ -0,0 +1,50 @@
+;; -*- mode: lisp-data; -*-
+((pass 10 "PASS :barnet:changeme"))
+((nick 3 "NICK tester"))
+((user 3 "USER user 0 * :tester")
+ (0 ":irc.barnet.org 001 tester :Welcome to the barnet IRC Network tester")
+ (0 ":irc.barnet.org 002 tester :Your host is irc.barnet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.barnet.org 003 tester :This server was created Wed, 12 May 2021 
07:41:08 UTC")
+ (0 ":irc.barnet.org 004 tester irc.barnet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.barnet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.barnet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=barnet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.barnet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.barnet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.barnet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.barnet.org 254 tester 1 :channels formed")
+ (0 ":irc.barnet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.barnet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.barnet.org 422 tester :MOTD File is missing"))
+
+((mode-user 10.2 "MODE tester +i")
+ ;; No mode answer ^
+
+ (0 ":tester!~u@xrir8fpe4d7ak.irc JOIN #chan")
+ (0 ":irc.barnet.org 353 tester = #chan :joe @mike tester")
+ (0 ":irc.barnet.org 366 tester #chan :End of /NAMES list.")
+ (0 ":***!znc@znc.in PRIVMSG #chan :Buffer Playback...")
+ (0 ":joe!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :[07:04:25] mike: Belike, for joy 
the emperor hath a son.")
+ (0 ":mike!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :[07:04:27] joe: Protest their 
first of manhood.")
+ (0 ":joe!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :[07:04:29] mike: As frozen water 
to a starved snake.")
+ (0 ":mike!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :[07:04:34] joe: My mirth it 
much displeas'd, but pleas'd my woe.")
+ (0 ":joe!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :[07:04:38] mike: Why, Marcus, no 
man should be mad but I.")
+ (0 ":mike!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :[07:04:44] joe: Faith, I have 
heard too much, for your words and performances are no kin together.")
+ (0 ":***!znc@znc.in PRIVMSG #chan :Playback Complete.")
+ (0 ":irc.barnet.org NOTICE tester :[07:00:01] This server is in debug mode 
and is logging all user I/O. If you do not wish for everything you send to be 
readable by the server owner(s), please disconnect.")
+
+ (0 ":irc.znc.in 306 tester :You have been marked as being away")
+ (0 ":irc.barnet.org 305 tester :You are no longer marked as being away"))
+
+((~join 3 "JOIN #chan"))
+
+((mode 5 "MODE #chan")
+ (0 ":irc.barnet.org 324 tester #chan +nt")
+ (0 ":irc.barnet.org 329 tester #chan 1620805269")
+ (0.1 ":joe!~u@svpn88yjcdj42.irc PRIVMSG #chan :mike: But, in defense, by 
mercy, 'tis most just.")
+ (0.1 ":mike!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :joe: The Marshal of France, 
Monsieur la Far.")
+ (0.1 ":joe!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :mike: And bide the penance of 
each three years' day.")
+ (0.1 ":mike!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :joe: Madam, within; but never 
man so chang'd.")
+ (0.1 ":joe!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :mike: As much in private, and 
I'll bid adieu."))
+
+((linger 10 LINGER))
diff --git a/test/lisp/erc/resources/base/netid/bouncer/barnet-drop.eld 
b/test/lisp/erc/resources/base/netid/bouncer/barnet-drop.eld
new file mode 100644
index 0000000000..2c3d297b9c
--- /dev/null
+++ b/test/lisp/erc/resources/base/netid/bouncer/barnet-drop.eld
@@ -0,0 +1,41 @@
+;; -*- mode: lisp-data; -*-
+((pass 10 "PASS :barnet:changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.barnet.org 001 tester :Welcome to the barnet IRC Network tester")
+ (0 ":irc.barnet.org 002 tester :Your host is irc.barnet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.barnet.org 003 tester :This server was created Wed, 12 May 2021 
07:41:08 UTC")
+ (0 ":irc.barnet.org 004 tester irc.barnet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.barnet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.barnet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=barnet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.barnet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.barnet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.barnet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.barnet.org 254 tester 1 :channels formed")
+ (0 ":irc.barnet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.barnet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.barnet.org 422 tester :MOTD File is missing"))
+
+((mode-user 10.2 "MODE tester +i")
+ ;; No mode answer ^
+ (0 ":irc.znc.in 306 tester :You have been marked as being away")
+ (0 ":irc.barnet.org 305 tester :You are no longer marked as being away"))
+
+((join 1 "JOIN #chan")
+ (0 ":tester!~u@awyxgybtkx7uq.irc JOIN #chan")
+ (0 ":irc.barnet.org 353 tester = #chan :@joe mike tester")
+ (0 ":irc.barnet.org 366 tester #chan :End of NAMES list")
+ (0.1 ":joe!~u@awyxgybtkx7uq.irc PRIVMSG #chan :tester, welcome!")
+ (0 ":mike!~u@awyxgybtkx7uq.irc PRIVMSG #chan :tester, welcome!"))
+
+((mode 1 "MODE #chan")
+ (0 ":irc.barnet.org 324 tester #chan +nt")
+ (0 ":irc.barnet.org 329 tester #chan 1620805269")
+ (0.1 ":mike!~u@awyxgybtkx7uq.irc PRIVMSG #chan :joe: But you have outfaced 
them all.")
+ (0.1 ":joe!~u@awyxgybtkx7uq.irc PRIVMSG #chan :mike: Why, will shall break 
it; will, and nothing else.")
+ (0.1 ":mike!~u@awyxgybtkx7uq.irc PRIVMSG #chan :joe: Yes, a dozen; and as 
many to the vantage, as would store the world they played for.")
+ (0.05 ":joe!~u@awyxgybtkx7uq.irc PRIVMSG #chan :mike: As he regards his aged 
father's life.")
+ (0.05 ":mike!~u@awyxgybtkx7uq.irc PRIVMSG #chan :joe: It is a rupture that 
you may easily heal; and the cure of it not only saves your brother, but keeps 
you from dishonour in doing it."))
+
+((drop 0 DROP))
diff --git a/test/lisp/erc/resources/base/netid/bouncer/barnet.eld 
b/test/lisp/erc/resources/base/netid/bouncer/barnet.eld
new file mode 100644
index 0000000000..abfcc6ed48
--- /dev/null
+++ b/test/lisp/erc/resources/base/netid/bouncer/barnet.eld
@@ -0,0 +1,41 @@
+;; -*- mode: lisp-data; -*-
+((pass 3 "PASS :barnet:changeme"))
+((nick 3 "NICK tester"))
+((user 3 "USER user 0 * :tester")
+ (0 ":irc.barnet.org 001 tester :Welcome to the barnet IRC Network tester")
+ (0 ":irc.barnet.org 002 tester :Your host is irc.barnet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.barnet.org 003 tester :This server was created Wed, 12 May 2021 
07:41:08 UTC")
+ (0 ":irc.barnet.org 004 tester irc.barnet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.barnet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.barnet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=barnet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.barnet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.barnet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.barnet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.barnet.org 254 tester 1 :channels formed")
+ (0 ":irc.barnet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.barnet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.barnet.org 422 tester :MOTD File is missing"))
+
+((mode-user 10.2 "MODE tester +i")
+ ;; No mode answer ^
+ (0 ":irc.znc.in 306 tester :You have been marked as being away")
+ (0 ":irc.barnet.org 305 tester :You are no longer marked as being away"))
+
+((join 1 "JOIN #chan")
+ (0 ":tester!~u@awyxgybtkx7uq.irc JOIN #chan")
+ (0 ":irc.barnet.org 353 tester = #chan :@joe mike tester")
+ (0 ":irc.barnet.org 366 tester #chan :End of NAMES list")
+ (0.1 ":joe!~u@awyxgybtkx7uq.irc PRIVMSG #chan :tester, welcome!")
+ (0 ":mike!~u@awyxgybtkx7uq.irc PRIVMSG #chan :tester, welcome!"))
+
+((mode 3 "MODE #chan")
+ (0 ":irc.barnet.org 324 tester #chan +nt")
+ (0 ":irc.barnet.org 329 tester #chan 1620805269")
+ (0.1 ":mike!~u@awyxgybtkx7uq.irc PRIVMSG #chan :joe: But you have outfaced 
them all.")
+ (0.1 ":joe!~u@awyxgybtkx7uq.irc PRIVMSG #chan :mike: Why, will shall break 
it; will, and nothing else.")
+ (0.1 ":mike!~u@awyxgybtkx7uq.irc PRIVMSG #chan :joe: Yes, a dozen; and as 
many to the vantage, as would store the world they played for.")
+ (0.05 ":joe!~u@awyxgybtkx7uq.irc PRIVMSG #chan :mike: As he regards his aged 
father's life.")
+ (0.05 ":mike!~u@awyxgybtkx7uq.irc PRIVMSG #chan :joe: It is a rupture that 
you may easily heal; and the cure of it not only saves your brother, but keeps 
you from dishonour in doing it."))
+
+((linger 1 LINGER))
diff --git a/test/lisp/erc/resources/base/netid/bouncer/foonet-again.eld 
b/test/lisp/erc/resources/base/netid/bouncer/foonet-again.eld
new file mode 100644
index 0000000000..bf8712305a
--- /dev/null
+++ b/test/lisp/erc/resources/base/netid/bouncer/foonet-again.eld
@@ -0,0 +1,50 @@
+;; -*- mode: lisp-data; -*-
+((pass 10 "PASS :foonet:changeme"))
+((nick 3 "NICK tester"))
+((user 3 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Wed, 12 May 2021 
07:41:09 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 10.2 "MODE tester +i")
+ ;; No mode answer ^
+ (0 ":tester!~u@nvfhxvqm92rm6.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :alice @bob tester")
+ (0 ":irc.foonet.org 366 tester #chan :End of /NAMES list.")
+ (0 ":***!znc@znc.in PRIVMSG #chan :Buffer Playback...")
+ (0 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:02] alice: Here come the 
lovers, full of joy and mirth.")
+ (0 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:07] bob: According to 
the fool's bolt, sir, and such dulcet diseases.")
+ (0 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:10] alice: And hang 
himself. I pray you, do my greeting.")
+ (0 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:18] bob: And you sat 
smiling at his cruel prey.")
+ (0 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:21] alice: Or never after 
look me in the face.")
+ (0 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:25] bob: If that may 
be, than all is well. Come, sit down, every mother's son, and rehearse your 
parts. Pyramus, you begin: when you have spoken your speech, enter into that 
brake; and so every one according to his cue.")
+ (0 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:30] alice: Where I espied 
the panther fast asleep.")
+ (0 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:32] bob: Alas! he is 
too young: yet he looks successfully.")
+ (0 ":***!znc@znc.in PRIVMSG #chan :Playback Complete.")
+
+ (0 ":irc.foonet.org NOTICE tester :[07:00:32] This server is in debug mode 
and is logging all user I/O. If you do not wish for everything you send to be 
readable by the server owner(s), please disconnect.")
+ (0 ":irc.foonet.org 305 tester :You are no longer marked as being away"))
+
+((~join 3 "JOIN #chan"))
+
+((mode 8 "MODE #chan")
+ (0 ":irc.foonet.org 324 tester #chan +nt")
+ (0 ":irc.foonet.org 329 tester #chan 1620805271")
+ (0.1 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :bob: Grows, lives, and dies, 
in single blessedness.")
+ (0.1 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #chan :alice: For these two hours, 
Rosalind, I will leave thee.")
+ (0.1 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :bob: By this hand, it will 
not kill a fly. But come, now I will be your Rosalind in a more coming-on 
disposition; and ask me what you will, I will grant it.")
+ (0.1 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #chan :alice: That I must love a 
loathed enemy.")
+ (0.1 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :bob: As't please your 
lordship: I'll leave you."))
+
+((linger 10 LINGER))
diff --git a/test/lisp/erc/resources/base/netid/bouncer/foonet-drop.eld 
b/test/lisp/erc/resources/base/netid/bouncer/foonet-drop.eld
new file mode 100644
index 0000000000..b99621cc31
--- /dev/null
+++ b/test/lisp/erc/resources/base/netid/bouncer/foonet-drop.eld
@@ -0,0 +1,46 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :foonet:changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Wed, 12 May 2021 
07:41:09 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 10.2 "MODE tester +i")
+ ;; No mode answer ^
+ (0 ":irc.znc.in 306 tester :You have been marked as being away")
+ (0 ":irc.foonet.org 305 tester :You are no longer marked as being away"))
+
+((join 1 "JOIN #chan")
+ (0 ":tester!~u@ertp7idh9jtgi.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :@alice bob tester")
+ (0 ":irc.foonet.org 366 tester #chan :End of NAMES list")
+ (0.1 ":alice!~u@ertp7idh9jtgi.irc PRIVMSG #chan :tester, welcome!")
+ (0 ":bob!~u@ertp7idh9jtgi.irc PRIVMSG #chan :tester, welcome!"))
+
+((mode 1 "MODE #chan")
+ (0 ":irc.foonet.org 324 tester #chan +nt")
+ (0 ":irc.foonet.org 329 tester #chan 1620805271")
+ (0.1 ":alice!~u@ertp7idh9jtgi.irc PRIVMSG #chan :bob: He cannot be heard of. 
Out of doubt he is transported.")
+ (0.1 ":bob!~u@ertp7idh9jtgi.irc PRIVMSG #chan :alice: More evident than this; 
for this was stol'n.")
+ (0.1 ":alice!~u@ertp7idh9jtgi.irc PRIVMSG #chan :bob: Sell when you can; you 
are not for all markets.")
+ (0.1 ":bob!~u@ertp7idh9jtgi.irc PRIVMSG #chan :alice: There's the fool hangs 
on your back already.")
+ (0.1 ":alice!~u@ertp7idh9jtgi.irc PRIVMSG #chan :bob: Why, if you have a 
stomach to't, monsieur, if you think your mystery in stratagem can bring this 
instrument of honor again into its native quarter, be magnanimous in the 
enterprise and go on; I will grace the attempt for a worthy exploit: if you 
speed well in it, the duke shall both speak of it, and extend to you what 
further becomes his greatness, even to the utmost syllable of your worthiness.")
+ (0.1 ":bob!~u@ertp7idh9jtgi.irc PRIVMSG #chan :alice: For he hath still been 
tried a holy man.")
+ (0.1 ":alice!~u@ertp7idh9jtgi.irc PRIVMSG #chan :bob: To have the touches 
dearest priz'd.")
+ (0.1 ":bob!~u@ertp7idh9jtgi.irc PRIVMSG #chan :alice: And must advise the 
emperor for his good.")
+ (0.1 ":alice!~u@ertp7idh9jtgi.irc PRIVMSG #chan :bob: Orlando, my liege; the 
youngest son of Sir Rowland de Boys.")
+ (0.1 ":bob!~u@ertp7idh9jtgi.irc PRIVMSG #chan :alice: The ape is dead, and I 
must conjure him."))
+
+((drop 0 DROP))
diff --git a/test/lisp/erc/resources/base/netid/bouncer/foonet.eld 
b/test/lisp/erc/resources/base/netid/bouncer/foonet.eld
new file mode 100644
index 0000000000..b0964fb953
--- /dev/null
+++ b/test/lisp/erc/resources/base/netid/bouncer/foonet.eld
@@ -0,0 +1,46 @@
+;; -*- mode: lisp-data; -*-
+((pass 3 "PASS :foonet:changeme"))
+((nick 3 "NICK tester"))
+((user 3 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Wed, 12 May 2021 
07:41:09 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 4.2 "MODE tester +i")
+ ;; No mode answer ^
+ (0 ":irc.znc.in 306 tester :You have been marked as being away")
+ (0 ":irc.foonet.org 305 tester :You are no longer marked as being away"))
+
+((join 1 "JOIN #chan")
+ (0 ":tester!~u@ertp7idh9jtgi.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :@alice bob tester")
+ (0 ":irc.foonet.org 366 tester #chan :End of NAMES list")
+ (0.1 ":alice!~u@ertp7idh9jtgi.irc PRIVMSG #chan :tester, welcome!")
+ (0 ":bob!~u@ertp7idh9jtgi.irc PRIVMSG #chan :tester, welcome!"))
+
+((mode 3 "MODE #chan")
+ (0 ":irc.foonet.org 324 tester #chan +nt")
+ (0 ":irc.foonet.org 329 tester #chan 1620805271")
+ (0.1 ":alice!~u@ertp7idh9jtgi.irc PRIVMSG #chan :bob: He cannot be heard of. 
Out of doubt he is transported.")
+ (0.1 ":bob!~u@ertp7idh9jtgi.irc PRIVMSG #chan :alice: More evident than this; 
for this was stol'n.")
+ (0.1 ":alice!~u@ertp7idh9jtgi.irc PRIVMSG #chan :bob: Sell when you can; you 
are not for all markets.")
+ (0.1 ":bob!~u@ertp7idh9jtgi.irc PRIVMSG #chan :alice: There's the fool hangs 
on your back already.")
+ (0.1 ":alice!~u@ertp7idh9jtgi.irc PRIVMSG #chan :bob: Why, if you have a 
stomach to't, monsieur, if you think your mystery in stratagem can bring this 
instrument of honor again into its native quarter, be magnanimous in the 
enterprise and go on; I will grace the attempt for a worthy exploit: if you 
speed well in it, the duke shall both speak of it, and extend to you what 
further becomes his greatness, even to the utmost syllable of your worthiness.")
+ (0.1 ":bob!~u@ertp7idh9jtgi.irc PRIVMSG #chan :alice: For he hath still been 
tried a holy man.")
+ (0.1 ":alice!~u@ertp7idh9jtgi.irc PRIVMSG #chan :bob: To have the touches 
dearest priz'd.")
+ (0.1 ":bob!~u@ertp7idh9jtgi.irc PRIVMSG #chan :alice: And must advise the 
emperor for his good.")
+ (0.1 ":alice!~u@ertp7idh9jtgi.irc PRIVMSG #chan :bob: Orlando, my liege; the 
youngest son of Sir Rowland de Boys.")
+ (0.1 ":bob!~u@ertp7idh9jtgi.irc PRIVMSG #chan :alice: The ape is dead, and I 
must conjure him."))
+
+((linger 1 LINGER))
diff --git a/test/lisp/erc/resources/base/netid/bouncer/stub-again.eld 
b/test/lisp/erc/resources/base/netid/bouncer/stub-again.eld
new file mode 100644
index 0000000000..c666ee4fa0
--- /dev/null
+++ b/test/lisp/erc/resources/base/netid/bouncer/stub-again.eld
@@ -0,0 +1,4 @@
+;; -*- mode: lisp-data; -*-
+((pass 10 "PASS :" token ":changeme"))
+
+((fake 1 "FAKE no op"))
diff --git a/test/lisp/erc/resources/base/netid/samenet/chester.eld 
b/test/lisp/erc/resources/base/netid/samenet/chester.eld
new file mode 100644
index 0000000000..8c2448733c
--- /dev/null
+++ b/test/lisp/erc/resources/base/netid/samenet/chester.eld
@@ -0,0 +1,48 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK chester"))
+((user 1 "USER user 0 * :chester")
+ (0 ":irc.foonet.org 001 chester :Welcome to the foonet IRC Network chester")
+ (0 ":irc.foonet.org 002 chester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 chester :This server was created Sun, 13 Jun 2021 
05:45:20 UTC")
+ (0 ":irc.foonet.org 004 chester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 chester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 chester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 chester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 chester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 chester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 253 chester 1 :unregistered connections")
+ (0 ":irc.foonet.org 254 chester 1 :channels formed")
+ (0 ":irc.foonet.org 255 chester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 chester 3 4 :Current local users 3, max 4")
+ (0 ":irc.foonet.org 266 chester 3 4 :Current global users 3, max 4")
+ (0 ":irc.foonet.org 422 chester :MOTD File is missing"))
+
+((mode-user 10.2 "MODE chester +i")
+ (0 ":irc.foonet.org 221 chester +i")
+ (0 ":irc.foonet.org NOTICE chester :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 14 "JOIN #chan")
+ (0 ":chester!~u@yuvqisyu7m7qs.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 chester = #chan :tester chester @alice bob")
+ (0 ":irc.foonet.org 366 chester #chan :End of NAMES list"))
+
+((mode 10 "MODE #chan")
+ (0.0 ":irc.foonet.org 324 chester #chan +nt")
+ (0.0 ":irc.foonet.org 329 chester #chan 1623563121")
+ (0.0 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :chester, welcome!")
+ (0.0 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :chester, welcome!")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :alice: That ever eye with 
sight made heart lament.")
+ (0.1 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :bob: The bitter past, more 
welcome is the sweet.")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :alice: Dispatch, I say, and 
find the forester.")
+ (0.1 ":tester!~u@yuvqisyu7m7qs.irc PRIVMSG #chan :chester: hi")
+ (0.1 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :bob: This was lofty! Now 
name the rest of the players. This is Ercles' vein, a tyrant's vein; a lover is 
more condoling."))
+
+((privmsg 4 "PRIVMSG #chan :hi tester")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :alice: As the ox hath his bow, 
sir, the horse his curb, and the falcon her bells, so man hath his desires; and 
as pigeons bill, so wedlock would be nibbling.")
+ (0.1 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :bob: Most friendship is 
feigning, most loving mere folly.")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :alice: To employ you towards 
this Roman. Come, our queen."))
+
+((quit 5 "QUIT :" quit)
+ (0.0 ":tester!~u@yuvqisyu7m7qs.irc QUIT :Quit: " quit)
+ (0.0 ":chester!~u@yuvqisyu7m7qs.irc QUIT :Quit: " quit))
diff --git a/test/lisp/erc/resources/base/netid/samenet/tester.eld 
b/test/lisp/erc/resources/base/netid/samenet/tester.eld
new file mode 100644
index 0000000000..76312a7a14
--- /dev/null
+++ b/test/lisp/erc/resources/base/netid/samenet/tester.eld
@@ -0,0 +1,52 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Sun, 13 Jun 2021 
05:45:20 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 4 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 4 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 4 4 :Current local users 4, max 4")
+ (0 ":irc.foonet.org 266 tester 4 4 :Current global users 4, max 4")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 10.2 "MODE tester +i")
+ (0 ":irc.foonet.org 221 tester +i")
+ (0 ":irc.foonet.org NOTICE tester :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect."))
+
+((join 15 "JOIN #chan")
+ (0 ":tester!~u@yuvqisyu7m7qs.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :tester @alice bob")
+ (0 ":irc.foonet.org 366 tester #chan :End of NAMES list"))
+
+((mode 10 "MODE #chan")
+ (0.0 ":irc.foonet.org 324 tester #chan +nt")
+ (0.0 ":irc.foonet.org 329 tester #chan 1623563121")
+ (0.0 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :tester, welcome!")
+ (0.0 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :tester, welcome!")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :alice: Marry, that, I think, 
be young Petruchio.")
+ (0.4 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :bob: You speak of him when 
he was less furnished than now he is with that which makes him both without and 
within.")
+ (0.2 ":chester!~u@yuvqisyu7m7qs.irc JOIN #chan")
+ (0.1 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :chester, welcome!")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :chester, welcome!")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :alice: That ever eye with 
sight made heart lament.")
+ (0.1 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :bob: The bitter past, more 
welcome is the sweet.")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :alice: Dispatch, I say, and 
find the forester."))
+
+((privmsg 3 "PRIVMSG #chan :chester: hi")
+ (0.1 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :bob: This was lofty! Now 
name the rest of the players. This is Ercles' vein, a tyrant's vein; a lover is 
more condoling.")
+ (0.1 ":chester!~u@yuvqisyu7m7qs.irc PRIVMSG #chan :hi tester")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :alice: As the ox hath his bow, 
sir, the horse his curb, and the falcon her bells, so man hath his desires; and 
as pigeons bill, so wedlock would be nibbling.")
+ (0.1 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :bob: Most friendship is 
feigning, most loving mere folly.")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :alice: To employ you towards 
this Roman. Come, our queen."))
+
+((quit 4 "QUIT :" quit)
+ (0 ":tester!~u@yuvqisyu7m7qs.irc QUIT :Quit: " quit))
diff --git a/test/lisp/erc/resources/base/reconnect/aborted-dupe.eld 
b/test/lisp/erc/resources/base/reconnect/aborted-dupe.eld
new file mode 100644
index 0000000000..8e299ec44c
--- /dev/null
+++ b/test/lisp/erc/resources/base/reconnect/aborted-dupe.eld
@@ -0,0 +1,28 @@
+;; -*- mode: lisp-data; -*-
+((pass 3 "PASS :changeme"))
+((nick 1 "NICK tester"))
+
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Tue, 04 May 2021 
05:06:18 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=FooNet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (-0.02 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (-0.02 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (-0.02 ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (-0.02 ":irc.foonet.org 254 tester 1 :channels formed")
+ (-0.02 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (-0.02 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (-0.02 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (-0.02 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((~mode-user 3.2 "MODE tester +i")
+ (-0.02 ":irc.foonet.org 221 tester +i")
+ (-0.02 ":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"))
+((eof 5 EOF))
+((drop 0 DROP))
diff --git a/test/lisp/erc/resources/base/reconnect/aborted.eld 
b/test/lisp/erc/resources/base/reconnect/aborted.eld
new file mode 100644
index 0000000000..5c32070d85
--- /dev/null
+++ b/test/lisp/erc/resources/base/reconnect/aborted.eld
@@ -0,0 +1,45 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Tue, 04 May 2021 
05:06:18 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=FooNet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 3.2 "MODE tester +i")
+ (0 ":irc.foonet.org 221 tester +i")
+ (0 ":irc.foonet.org NOTICE tester :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect."))
+
+((join 12 "JOIN #chan")
+ (0 ":tester!~u@9g6b728983yd2.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :alice tester @bob")
+ (0 ":irc.foonet.org 366 tester #chan :End of NAMES list"))
+
+((mode 10 "MODE #chan")
+ (0 ":irc.foonet.org 324 tester #chan +nt")
+ (0 ":irc.foonet.org 329 tester #chan 1620104779")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :tester, welcome!")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :tester, welcome!")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: But, as it seems, did 
violence on herself.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: Well, this is the 
forest of Arden.")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: Signior Iachimo will 
not from it. Pray, let us follow 'em.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: Our queen and all her 
elves come here anon.")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: The ground is bloody; 
search about the churchyard.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: You have discharged 
this honestly: keep it to yourself. Many likelihoods informed me of this 
before, which hung so tottering in the balance that I could neither believe nor 
misdoubt. Pray you, leave me: stall this in your bosom; and I thank you for 
your honest care. I will speak with you further anon.")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: Give me that mattock, 
and the wrenching iron.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: Stand you! You have 
land enough of your own; but he added to your having, gave you some ground.")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: Excellent workman! Thou 
canst not paint a man so bad as is thyself.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: And will you, being a 
man of your breeding, be married under a bush, like a beggar ? Get you to 
church, and have a good priest that can tell you what marriage is: this fellow 
will but join you together as they join wainscot; then one of you will prove a 
shrunk panel, and like green timber, warp, warp.")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: Live, and be 
prosperous; and farewell, good fellow."))
diff --git a/test/lisp/erc/resources/base/reconnect/options-again.eld 
b/test/lisp/erc/resources/base/reconnect/options-again.eld
new file mode 100644
index 0000000000..f1fcc439cc
--- /dev/null
+++ b/test/lisp/erc/resources/base/reconnect/options-again.eld
@@ -0,0 +1,45 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Tue, 04 May 2021 
05:06:18 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=FooNet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 3.2 "MODE tester +i")
+ (0 ":irc.foonet.org 221 tester +i")
+ (0 ":irc.foonet.org NOTICE tester :This server is still in debug mode."))
+
+((~join-chan 12 "JOIN #chan")
+ (0 ":tester!~u@9g6b728983yd2.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :alice tester @bob")
+ (0 ":irc.foonet.org 366 tester #chan :End of NAMES list"))
+
+((~join-spam 12 "JOIN #spam")
+ (0 ":tester!~u@9g6b728983yd2.irc JOIN #spam")
+ (0 ":irc.foonet.org 353 tester = #spam :alice tester @bob")
+ (0 ":irc.foonet.org 366 tester #spam :End of NAMES list"))
+
+((~mode-chan 4 "MODE #chan")
+ (0 ":irc.foonet.org 324 tester #chan +nt")
+ (0 ":irc.foonet.org 329 tester #chan 1620104779")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: But, as it seems, did 
violence on herself.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: Well, this is the 
forest of Arden."))
+
+((mode-spam 4 "MODE #spam")
+ (0 ":irc.foonet.org 324 tester #spam +nt")
+ (0 ":irc.foonet.org 329 tester #spam 1620104779")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #spam :alice: Signior Iachimo will 
not from it. Pray, let us follow 'em.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #spam :bob: Our queen and all her 
elves come here anon."))
diff --git a/test/lisp/erc/resources/base/reconnect/options.eld 
b/test/lisp/erc/resources/base/reconnect/options.eld
new file mode 100644
index 0000000000..3b305d8559
--- /dev/null
+++ b/test/lisp/erc/resources/base/reconnect/options.eld
@@ -0,0 +1,35 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Tue, 04 May 2021 
05:06:18 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=FooNet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 3.2 "MODE tester +i")
+ (0 ":irc.foonet.org 221 tester +i")
+ (0 ":irc.foonet.org NOTICE tester :This server is in debug mode.")
+
+ (0 ":tester!~u@9g6b728983yd2.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :alice tester @bob")
+ (0 ":irc.foonet.org 366 tester #chan :End of NAMES list"))
+
+((mode-chan 4 "MODE #chan")
+ (0 ":irc.foonet.org 324 tester #chan +nt")
+ (0 ":irc.foonet.org 329 tester #chan 1620104779")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :tester, welcome!")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :tester, welcome!"))
+
+((drop 0 DROP))
diff --git a/test/lisp/erc/resources/base/reconnect/timer-last.eld 
b/test/lisp/erc/resources/base/reconnect/timer-last.eld
new file mode 100644
index 0000000000..23849bc1ba
--- /dev/null
+++ b/test/lisp/erc/resources/base/reconnect/timer-last.eld
@@ -0,0 +1,6 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.znc.in 464 tester :Invalid Password"))
+((linger 1 LINGER))
diff --git a/test/lisp/erc/resources/base/reconnect/timer.eld 
b/test/lisp/erc/resources/base/reconnect/timer.eld
new file mode 100644
index 0000000000..95c6af8d88
--- /dev/null
+++ b/test/lisp/erc/resources/base/reconnect/timer.eld
@@ -0,0 +1,6 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.znc.in 464 tester :Invalid Password"))
+((drop 0 DROP))
diff --git a/test/lisp/erc/resources/base/renick/queries/bouncer-barnet.eld 
b/test/lisp/erc/resources/base/renick/queries/bouncer-barnet.eld
new file mode 100644
index 0000000000..0c8cdac037
--- /dev/null
+++ b/test/lisp/erc/resources/base/renick/queries/bouncer-barnet.eld
@@ -0,0 +1,54 @@
+;; -*- mode: lisp-data; -*-
+((pass 3 "PASS :barnet:changeme"))
+((nick 3 "NICK tester"))
+((user 3 "USER user 0 * :tester")
+ (0 ":irc.barnet.org 001 tester :Welcome to the barnet IRC Network tester")
+ (0 ":irc.barnet.org 002 tester :Your host is irc.barnet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.barnet.org 003 tester :This server was created Tue, 01 Jun 2021 
07:49:23 UTC")
+ (0 ":irc.barnet.org 004 tester irc.barnet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.barnet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.barnet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=barnet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.barnet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.barnet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.barnet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.barnet.org 254 tester 1 :channels formed")
+ (0 ":irc.barnet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.barnet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.barnet.org 422 tester :MOTD File is missing"))
+
+((mode-user 3.2 "MODE tester +i")
+ ;; No mode answer
+ (0 ":irc.znc.in 306 tester :You have been marked as being away")
+ (0 ":tester!~u@286u8jcpis84e.irc JOIN #chan")
+ (0 ":irc.barnet.org 353 tester = #chan :@joe mike rando tester")
+ (0 ":irc.barnet.org 366 tester #chan :End of /NAMES list.")
+ (0 ":***!znc@znc.in PRIVMSG #chan :Buffer Playback...")
+ (0 ":joe!~u@286u8jcpis84e.irc PRIVMSG #chan :[09:19:19] mike: Chi non te 
vede, non te pretia.")
+ (0 ":mike!~u@286u8jcpis84e.irc PRIVMSG #chan :[09:19:28] joe: The valiant 
heart's not whipt out of his trade.")
+ (0 ":***!znc@znc.in PRIVMSG #chan :Playback Complete.")
+ (0 ":rando!~u@95i756tt32ym8.irc PRIVMSG tester :[09:18:20] Why'd you pull 
that scene at the arcade?")
+ (0 ":rando!~u@95i756tt32ym8.irc PRIVMSG tester :[09:18:32] I had to mess up 
this rentacop came after me with nunchucks.")
+ (0 ":irc.barnet.org NOTICE tester :[09:13:24] This server is in debug mode 
and is logging all user I/O. If you do not wish for everything you send to be 
readable by the server owner(s), please disconnect.")
+ (0 ":irc.barnet.org 305 tester :You are no longer marked as being away"))
+
+((mode 5 "MODE #chan")
+ (0 ":irc.barnet.org 324 tester #chan +nt")
+ (0 ":irc.barnet.org 329 tester #chan 1622538742")
+ (0.1 ":joe!~u@286u8jcpis84e.irc PRIVMSG #chan :mike: By favors several which 
they did bestow.")
+ (0.1 ":mike!~u@286u8jcpis84e.irc PRIVMSG #chan :joe: You, Roderigo! come, 
sir, I am for you."))
+
+((privmsg-a 5 "PRIVMSG rando :Linda said you were gonna kill me.")
+ (0.1 ":joe!~u@286u8jcpis84e.irc PRIVMSG #chan :mike: Play, music, then! Nay, 
you must do it soon.")
+ (0.1 ":rando!~u@95i756tt32ym8.irc PRIVMSG tester :Linda said? I never saw her 
before I came up here.")
+ (0.1 ":mike!~u@286u8jcpis84e.irc PRIVMSG #chan :joe: Of arts inhibited and 
out of warrant."))
+
+((privmsg-b 3 "PRIVMSG rando :You aren't with Wage?")
+ (0.1 ":joe!~u@286u8jcpis84e.irc PRIVMSG #chan :mike: But most of all, 
agreeing with the proclamation.")
+ (0.1 ":rando!~u@95i756tt32ym8.irc PRIVMSG tester :I think you screwed up, 
Case.")
+ (0.1 ":mike!~u@286u8jcpis84e.irc PRIVMSG #chan :joe: Good gentleman, go your 
gait, and let poor volk pass. An chud ha' bin zwaggered out of my life, 'twould 
not ha' bin zo long as 'tis by a vortnight. Nay, come not near th' old man; 
keep out, che vor ye, or ise try whether your costard or my ballow be the 
harder. Chill be plain with you.")
+ ;; Nick change
+ (0.1 ":rando!~u@95i756tt32ym8.irc NICK frenemy")
+ (0.1 ":joe!~u@286u8jcpis84e.irc PRIVMSG #chan :mike: Till time beget some 
careful remedy.")
+ (0.1 ":frenemy!~u@95i756tt32ym8.irc PRIVMSG tester :I showed up and you just 
fit me right into your reality picture.")
+ (0.1 ":mike!~u@286u8jcpis84e.irc PRIVMSG #chan :joe: For I have lost him on a 
dangerous sea."))
diff --git a/test/lisp/erc/resources/base/renick/queries/bouncer-foonet.eld 
b/test/lisp/erc/resources/base/renick/queries/bouncer-foonet.eld
new file mode 100644
index 0000000000..162e8bf965
--- /dev/null
+++ b/test/lisp/erc/resources/base/renick/queries/bouncer-foonet.eld
@@ -0,0 +1,52 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :foonet:changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Tue, 01 Jun 2021 
07:49:22 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 5.2 "MODE tester +i")
+ ;; No mode answer
+ (0 ":irc.znc.in 306 tester :You have been marked as being away")
+ (0 ":tester!~u@u4mvbswyw8gbg.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :alice @bob rando tester")
+ (0 ":irc.foonet.org 366 tester #chan :End of /NAMES list.")
+ (0 ":***!znc@znc.in PRIVMSG #chan :Buffer Playback...")
+ (0 ":bob!~u@u4mvbswyw8gbg.irc PRIVMSG #chan :[09:19:28] alice: Great men 
should drink with harness on their throats.")
+ (0 ":alice!~u@u4mvbswyw8gbg.irc PRIVMSG #chan :[09:19:31] bob: Your lips will 
feel them the sooner: shallow again. A more sounder instance; come.")
+ (0 ":***!znc@znc.in PRIVMSG #chan :Playback Complete.")
+ (0 ":rando!~u@bivkhq8yav938.irc PRIVMSG tester :[09:17:51] u thur?")
+ (0 ":rando!~u@bivkhq8yav938.irc PRIVMSG tester :[09:17:58] guess not")
+ (0 ":irc.foonet.org NOTICE tester :[09:12:53] This server is in debug mode 
and is logging all user I/O. If you do not wish for everything you send to be 
readable by the server owner(s), please disconnect.")
+ (0 ":irc.foonet.org 305 tester :You are no longer marked as being away"))
+
+((mode 10 "MODE #chan")
+ (0 ":irc.foonet.org 324 tester #chan +nt")
+ (0 ":irc.foonet.org 329 tester #chan 1622538742")
+ (0.1 ":bob!~u@u4mvbswyw8gbg.irc PRIVMSG #chan :alice: When there is nothing 
living but thee, thou shalt be welcome. I had rather be a beggar's dog than 
Apemantus.")
+ (0.1 ":alice!~u@u4mvbswyw8gbg.irc PRIVMSG #chan :bob: You have simply misused 
our sex in your love-prate: we must have your doublot and hose plucked over 
your head, and show the world what the bird hath done to her own nest."))
+
+((privmsg-a 6 "PRIVMSG rando :I here")
+ (0.1 ":bob!~u@u4mvbswyw8gbg.irc PRIVMSG #chan :alice: And I will make thee 
think thy swan a crow.")
+ (0.1 ":rando!~u@bivkhq8yav938.irc PRIVMSG tester :u are dumb")
+ (0.1 ":alice!~u@u4mvbswyw8gbg.irc PRIVMSG #chan :bob: Lie not, to say mine 
eyes are murderers."))
+
+((privmsg-b 3 "PRIVMSG rando :not so")
+ (0.1 ":bob!~u@u4mvbswyw8gbg.irc PRIVMSG #chan :alice: Commit myself, my 
person, and the cause.")
+ ;; Nick change
+ (0.1 ":rando!~u@bivkhq8yav938.irc NICK frenemy")
+ (0.1 ":alice!~u@u4mvbswyw8gbg.irc PRIVMSG #chan :bob: Of raging waste! It 
cannot hold; it will not.")
+ (0.1 ":frenemy!~u@bivkhq8yav938.irc PRIVMSG tester :doubly so")
+ (0.1 ":bob!~u@u4mvbswyw8gbg.irc PRIVMSG #chan :alice: These words are razors 
to my wounded heart."))
diff --git a/test/lisp/erc/resources/base/renick/queries/solo.eld 
b/test/lisp/erc/resources/base/renick/queries/solo.eld
new file mode 100644
index 0000000000..12fa7d264e
--- /dev/null
+++ b/test/lisp/erc/resources/base/renick/queries/solo.eld
@@ -0,0 +1,55 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :foonet:changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Mon, 31 May 2021 
09:56:24 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 4 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 254 tester 2 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 4 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 4 4 :Current local users 4, max 4")
+ (0 ":irc.foonet.org 266 tester 4 4 :Current global users 4, max 4")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 8 "MODE tester +i")
+ ;; No mode answer
+ (0 ":irc.znc.in 306 tester :You have been marked as being away")
+ (0 ":tester!~u@gq7yjr7gsu7nn.irc JOIN #foo")
+ (0 ":irc.foonet.org 353 tester = #foo :alice @bob Lal tester")
+ (0 ":irc.foonet.org 366 tester #foo :End of /NAMES list.")
+ (0 ":***!znc@znc.in PRIVMSG #foo :Buffer Playback...")
+ (0 ":alice!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :[10:00:02] bob: All that he is 
hath reference to your highness.")
+ (0 ":bob!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :[10:00:06] alice: Excellent 
workman! Thou canst not paint a man so bad as is thyself.")
+ (0 ":***!znc@znc.in PRIVMSG #foo :Playback Complete.")
+ (0 ":irc.foonet.org NOTICE tester :[09:56:57] This server is in debug mode 
and is logging all user I/O. If you do not wish for everything you send to be 
readable by the server owner(s), please disconnect.")
+ (0 ":irc.foonet.org 305 tester :You are no longer marked as being away"))
+
+((mode 1 "MODE #foo")
+ (0 ":irc.foonet.org 324 tester #foo +nt")
+ (0 ":irc.foonet.org 329 tester #foo 1622454985")
+ (0.1 ":alice!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :bob: Farewell, pretty lady: 
you must hold the credit of your father.")
+ (0.1 ":bob!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :alice: On Thursday, sir ? the 
time is very short."))
+
+((privmsg-a 10 "PRIVMSG #foo :hi")
+ (0.2 ":Lal!~u@b82mytupn2t5k.irc PRIVMSG tester :hello")
+ (0.2 ":bob!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :alice: And brought to yoke, the 
enemies of Rome.")
+ (0.2 ":alice!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :bob: Thou art thy father's 
daughter; there's enough."))
+
+((privmsg-b 10 "PRIVMSG Lal :hi")
+ (0.2 ":bob!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :alice: Here are the beetle 
brows shall blush for me.")
+ (0.2 ":Lal!~u@b82mytupn2t5k.irc NICK Linguo")
+ (0.2 ":alice!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :bob: He hath abandoned his 
physicians, madam; under whose practices he hath persecuted time with hope, and 
finds no other advantage in the process but only the losing of hope by time."))
+
+((privmsg-c 10 "PRIVMSG Linguo :howdy Linguo")
+ (0.1 ":bob!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :alice: And brought to yoke, the 
enemies of Rome.")
+ (0.2 ":Linguo!~u@b82mytupn2t5k.irc PART #foo"))
+
+((part 10 "PART #foo :\2ERC\2")
+ (0 ":tester!~u@gq7yjr7gsu7nn.irc PART #foo :\2ERC\2")
+ (0.1 ":Linguo!~u@b82mytupn2t5k.irc PRIVMSG tester :get along little doggie"))
diff --git a/test/lisp/erc/resources/base/renick/self/auto.eld 
b/test/lisp/erc/resources/base/renick/self/auto.eld
new file mode 100644
index 0000000000..851db7f1cf
--- /dev/null
+++ b/test/lisp/erc/resources/base/renick/self/auto.eld
@@ -0,0 +1,46 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :foonet:changeme"))
+((nick 1 "NICK tester"))
+((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 002 tester :Your host is 
irc.foonet.org[188.240.145.101/6697], running version solanum-1.0-dev")
+ (0 ":irc.foonet.org 003 tester :This server was created Sat May 22 2021 at 
19:04:17 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org solanum-1.0-dev 
DGQRSZaghilopsuwz CFILMPQSbcefgijklmnopqrstuvz bkloveqjfI")
+ (0 ":irc.foonet.org 005 tester WHOX FNC KNOCK SAFELIST ELIST=CTU CALLERID=g 
MONITOR=100 ETRACE CHANTYPES=# EXCEPTS INVEX 
CHANMODES=eIbq,k,flj,CFLMPQScgimnprstuz :are supported by this server")
+ (0 ":irc.foonet.org 005 tester CHANLIMIT=#:250 PREFIX=(ov)@+ MAXLIST=bqeI:100 
MODES=4 NETWORK=foonet STATUSMSG=@+ CASEMAPPING=rfc1459 NICKLEN=16 
MAXNICKLEN=16 CHANNELLEN=50 TOPICLEN=390 DEAF=D :are supported by this server")
+ (0 ":irc.foonet.org 005 tester 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,PRIVMSG:4,NOTICE:4,ACCEPT:,MONITOR: 
EXTBAN=$,ajrxz CLIENTVER=3.0 :are supported by this server")
+ (0 ":irc.foonet.org 251 tester :There are 33 users and 14113 invisible on 17 
servers")
+ (0 ":irc.foonet.org 252 tester 34 :IRC Operators online")
+ (0 ":irc.foonet.org 254 tester 12815 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 726 clients and 1 servers")
+ (0 ":irc.foonet.org 265 tester 726 739 :Current local users 726, max 739")
+ (0 ":irc.foonet.org 266 tester 14146 14541 :Current global users 14146, max 
14541")
+ (0 ":irc.foonet.org 250 tester :Highest connection count: 740 (739 clients) 
(3790 connections received)")
+ (0 ":tester!~u@gq7yjr7gsu7nn.irc NICK :dummy")
+ (0 ":irc.foonet.org 375 dummy :- irc.foonet.org Message of the Day - ")
+ (0 ":irc.foonet.org 372 dummy :- This server provided by NORDUnet/SUNET")
+ (0 ":irc.foonet.org 372 dummy :- Welcome to foonet, the IRC network for free 
& open-source software")
+ (0 ":irc.foonet.org 372 dummy :- and peer directed projects.")
+ (0 ":irc.foonet.org 372 dummy :-  ")
+ (0 ":irc.foonet.org 372 dummy :- Please visit us in #libera for questions and 
support.")
+ (0 ":irc.foonet.org 376 dummy :End of /MOTD command."))
+
+((mode-user 10.2 "MODE dummy +i")
+ (0 ":dummy!~u@gq7yjr7gsu7nn.irc MODE dummy :+RZi")
+ (0 ":irc.znc.in 306 dummy :You have been marked as being away")
+ (0 ":dummy!~u@gq7yjr7gsu7nn.irc JOIN #foo")
+
+ (0 ":irc.foonet.org 353 dummy = #foo :alice @bob Lal dummy")
+ (0 ":irc.foonet.org 366 dummy #foo :End of /NAMES list.")
+ (0 ":***!znc@znc.in PRIVMSG #foo :Buffer Playback...")
+ (0 ":alice!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :[10:00:02] bob: All that he is 
hath reference to your highness.")
+ (0 ":bob!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :[10:00:06] alice: Excellent 
workman! Thou canst not paint a man so bad as is thyself.")
+ (0 ":***!znc@znc.in PRIVMSG #foo :Playback Complete.")
+ (0 ":irc.foonet.org NOTICE dummy :[09:56:57] This server is in debug mode and 
is logging all user I/O. If you do not wish for everything you send to be 
readable by the server owner(s), please disconnect.")
+ (0 ":irc.foonet.org 305 dummy :You are no longer marked as being away"))
+
+((mode 10 "MODE #foo")
+ (0 ":irc.foonet.org 324 dummy #foo +nt")
+ (0 ":irc.foonet.org 329 dummy #foo 1622454985")
+ (0.1 ":alice!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :bob: Farewell, pretty lady: 
you must hold the credit of your father.")
+ (0.1 ":bob!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :alice: On Thursday, sir ? the 
time is very short."))
diff --git a/test/lisp/erc/resources/base/renick/self/manual.eld 
b/test/lisp/erc/resources/base/renick/self/manual.eld
new file mode 100644
index 0000000000..dd107b806d
--- /dev/null
+++ b/test/lisp/erc/resources/base/renick/self/manual.eld
@@ -0,0 +1,50 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :foonet:changeme"))
+((nick 1 "NICK tester"))
+((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 002 tester :Your host is 
irc.foonet.org[188.240.145.101/6697], running version solanum-1.0-dev")
+ (0 ":irc.foonet.org 003 tester :This server was created Sat May 22 2021 at 
19:04:17 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org solanum-1.0-dev 
DGQRSZaghilopsuwz CFILMPQSbcefgijklmnopqrstuvz bkloveqjfI")
+ (0 ":irc.foonet.org 005 tester WHOX FNC KNOCK SAFELIST ELIST=CTU CALLERID=g 
MONITOR=100 ETRACE CHANTYPES=# EXCEPTS INVEX 
CHANMODES=eIbq,k,flj,CFLMPQScgimnprstuz :are supported by this server")
+ (0 ":irc.foonet.org 005 tester CHANLIMIT=#:250 PREFIX=(ov)@+ MAXLIST=bqeI:100 
MODES=4 NETWORK=foonet STATUSMSG=@+ CASEMAPPING=rfc1459 NICKLEN=16 
MAXNICKLEN=16 CHANNELLEN=50 TOPICLEN=390 DEAF=D :are supported by this server")
+ (0 ":irc.foonet.org 005 tester 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,PRIVMSG:4,NOTICE:4,ACCEPT:,MONITOR: 
EXTBAN=$,ajrxz CLIENTVER=3.0 :are supported by this server")
+ (0 ":irc.foonet.org 251 tester :There are 33 users and 14113 invisible on 17 
servers")
+ (0 ":irc.foonet.org 252 tester 34 :IRC Operators online")
+ (0 ":irc.foonet.org 254 tester 12815 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 726 clients and 1 servers")
+ (0 ":irc.foonet.org 265 tester 726 739 :Current local users 726, max 739")
+ (0 ":irc.foonet.org 266 tester 14146 14541 :Current global users 14146, max 
14541")
+ (0 ":irc.foonet.org 250 tester :Highest connection count: 740 (739 clients) 
(3790 connections received)")
+ (0 ":irc.foonet.org 375 tester :- irc.foonet.org Message of the Day - ")
+ (0 ":irc.foonet.org 372 tester :- This server provided by NORDUnet/SUNET")
+ (0 ":irc.foonet.org 372 tester :- Welcome to foonet, the IRC network for free 
& open-source software")
+ (0 ":irc.foonet.org 372 tester :- and peer directed projects.")
+ (0 ":irc.foonet.org 372 tester :-  ")
+ (0 ":irc.foonet.org 372 tester :- Please visit us in #libera for questions 
and support.")
+ (0 ":irc.foonet.org 376 tester :End of /MOTD command."))
+
+((mode-user 1.2 "MODE tester +i")
+ (0 ":tester!~u@gq7yjr7gsu7nn.irc MODE tester :+RZi")
+ (0 ":irc.znc.in 306 tester :You have been marked as being away")
+ (0 ":tester!~u@gq7yjr7gsu7nn.irc JOIN #foo")
+
+ (0 ":irc.foonet.org 353 tester = #foo :alice @bob Lal tester")
+ (0 ":irc.foonet.org 366 tester #foo :End of /NAMES list.")
+ (0 ":***!znc@znc.in PRIVMSG #foo :Buffer Playback...")
+ (0 ":alice!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :[10:00:02] bob: All that he is 
hath reference to your highness.")
+ (0 ":bob!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :[10:00:06] alice: Excellent 
workman! Thou canst not paint a man so bad as is thyself.")
+ (0 ":***!znc@znc.in PRIVMSG #foo :Playback Complete.")
+ (0 ":irc.foonet.org NOTICE tester :[09:56:57] This server is in debug mode 
and is logging all user I/O. If you do not wish for everything you send to be 
readable by the server owner(s), please disconnect.")
+ (0 ":irc.foonet.org 305 tester :You are no longer marked as being away"))
+
+((mode 1 "MODE #foo")
+ (0 ":irc.foonet.org 324 tester #foo +nt")
+ (0 ":irc.foonet.org 329 tester #foo 1622454985")
+ (0.1 ":alice!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :bob: Farewell, pretty lady: 
you must hold the credit of your father.")
+ (0.1 ":bob!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :alice: On Thursday, sir ? the 
time is very short."))
+
+((nick 2 "NICK dummy")
+ (0 ":tester!~u@gq7yjr7gsu7nn.irc NICK :dummy")
+ (0.1 ":dummy!~u@gq7yjr7gsu7nn.irc MODE dummy :+RZi")
+ (0.1 ":bob!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :dummy: Hi."))
diff --git a/test/lisp/erc/resources/base/renick/self/qual-chester.eld 
b/test/lisp/erc/resources/base/renick/self/qual-chester.eld
new file mode 100644
index 0000000000..75b50fe68b
--- /dev/null
+++ b/test/lisp/erc/resources/base/renick/self/qual-chester.eld
@@ -0,0 +1,40 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK chester"))
+((user 1 "USER user 0 * :chester")
+ (0 ":irc.foonet.org 001 chester :Welcome to the foonet IRC Network chester")
+ (0 ":irc.foonet.org 002 chester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 chester :This server was created Sun, 13 Jun 2021 
05:45:20 UTC")
+ (0 ":irc.foonet.org 004 chester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 chester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 chester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 chester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 chester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 chester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 253 chester 1 :unregistered connections")
+ (0 ":irc.foonet.org 254 chester 1 :channels formed")
+ (0 ":irc.foonet.org 255 chester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 chester 3 4 :Current local users 3, max 4")
+ (0 ":irc.foonet.org 266 chester 3 4 :Current global users 3, max 4")
+ (0 ":irc.foonet.org 422 chester :MOTD File is missing"))
+
+((mode-user 1.2 "MODE chester +i")
+ (0 ":irc.foonet.org 221 chester +i")
+ (0 ":irc.foonet.org NOTICE chester :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 14 "JOIN #chan")
+ (0 ":chester!~u@yuvqisyu7m7qs.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 chester = #chan :tester chester @alice bob")
+ (0 ":irc.foonet.org 366 chester #chan :End of NAMES list"))
+
+((mode 10 "MODE #chan")
+ (0.0 ":irc.foonet.org 324 chester #chan +nt")
+ (0.0 ":irc.foonet.org 329 chester #chan 1623563121")
+ (0.0 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :chester, welcome!")
+ (0.0 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :chester, welcome!")
+ (0 ":tester!~u@gq7yjr7gsu7nn.irc NICK :dummy")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :alice: That ever eye with 
sight made heart lament.")
+ (0.1 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :bob: The bitter past, more 
welcome is the sweet.")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :alice: Dispatch, I say, and 
find the forester."))
+
+((linger 10 LINGER))
diff --git a/test/lisp/erc/resources/base/renick/self/qual-tester.eld 
b/test/lisp/erc/resources/base/renick/self/qual-tester.eld
new file mode 100644
index 0000000000..2519922665
--- /dev/null
+++ b/test/lisp/erc/resources/base/renick/self/qual-tester.eld
@@ -0,0 +1,46 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Sun, 13 Jun 2021 
05:45:20 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 4 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 4 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 4 4 :Current local users 4, max 4")
+ (0 ":irc.foonet.org 266 tester 4 4 :Current global users 4, max 4")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 1.2 "MODE tester +i")
+ (0 ":irc.foonet.org 221 tester +i")
+ (0 ":irc.foonet.org NOTICE tester :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect."))
+
+((join 15 "JOIN #chan")
+ (0 ":tester!~u@yuvqisyu7m7qs.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :tester @alice bob")
+ (0 ":irc.foonet.org 366 tester #chan :End of NAMES list"))
+
+((mode 10 "MODE #chan")
+ (0.0 ":irc.foonet.org 324 tester #chan +nt")
+ (0.0 ":irc.foonet.org 329 tester #chan 1623563121")
+ (0.0 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :tester, welcome!")
+ (0.0 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :tester, welcome!")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :alice: Marry, that, I think, 
be young Petruchio.")
+ (0.4 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :bob: You speak of him when 
he was less furnished than now he is with that which makes him both without and 
within.")
+ (0.2 ":chester!~u@yuvqisyu7m7qs.irc JOIN #chan")
+ (0.1 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :chester, welcome!")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :chester, welcome!"))
+
+((nick 5 "NICK dummy")
+ (0 ":tester!~u@gq7yjr7gsu7nn.irc NICK :dummy")
+ (0.1 ":dummy!~u@gq7yjr7gsu7nn.irc MODE dummy :+RZi")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :alice: That ever eye with 
sight made heart lament.")
+ (0.1 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :bob: The bitter past, more 
welcome is the sweet.")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :alice: Dispatch, I say, and 
find the forester."))
diff --git a/test/lisp/erc/resources/base/reuse-buffers/channel/barnet.eld 
b/test/lisp/erc/resources/base/reuse-buffers/channel/barnet.eld
new file mode 100644
index 0000000000..efc2506fd6
--- /dev/null
+++ b/test/lisp/erc/resources/base/reuse-buffers/channel/barnet.eld
@@ -0,0 +1,68 @@
+;; -*- mode: lisp-data; -*-
+((pass 3 "PASS :barnet:changeme"))
+((nick 3 "NICK tester"))
+((user 3 "USER user 0 * :tester")
+ (0 ":irc.barnet.org 001 tester :Welcome to the barnet IRC Network tester")
+ (0 ":irc.barnet.org 002 tester :Your host is irc.barnet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.barnet.org 003 tester :This server was created Wed, 05 May 2021 
09:05:33 UTC")
+ (0 ":irc.barnet.org 004 tester irc.barnet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.barnet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.barnet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=barnet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.barnet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.barnet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.barnet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.barnet.org 254 tester 1 :channels formed")
+ (0 ":irc.barnet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.barnet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.barnet.org 422 tester :MOTD File is missing"))
+
+((mode-user 10.2 "MODE tester +i")
+ ;; No mode answer
+ (0 ":irc.znc.in 306 tester :You have been marked as being away")
+ (0 ":tester!~u@wvys46tx8tpmk.irc JOIN #chan")
+ (0 ":irc.barnet.org 353 tester = #chan :joe @mike tester")
+ (0 ":irc.barnet.org 366 tester #chan :End of /NAMES list.")
+ (0 ":***!znc@znc.in PRIVMSG #chan :Buffer Playback...")
+ (0 ":mike!~u@wvys46tx8tpmk.irc PRIVMSG #chan :[09:09:16] joe: Tush! none but 
minstrels like of sonneting.")
+ (0 ":joe!~u@wvys46tx8tpmk.irc PRIVMSG #chan :[09:09:19] mike: Prithee, 
nuncle, be contented; 'tis a naughty night to swim in. Now a little fire in a 
wide field were like an old lecher's heart; a small spark, all the rest on's 
body cold. Look! here comes a walking fire.")
+ (0 ":mike!~u@wvys46tx8tpmk.irc PRIVMSG #chan :[09:09:22] joe: My name is 
Edgar, and thy father's son.")
+ (0 ":joe!~u@wvys46tx8tpmk.irc PRIVMSG #chan :[09:09:26] mike: Good my lord, 
be good to me; your honor is accounted a merciful man; good my lord.")
+ (0 ":mike!~u@wvys46tx8tpmk.irc PRIVMSG #chan :[09:09:31] joe: Thy child shall 
live, and I will see it nourish'd.")
+ (0 ":joe!~u@wvys46tx8tpmk.irc PRIVMSG #chan :[09:09:33] mike: Quick, quick; 
fear nothing; I'll be at thy elbow.")
+ (0 ":***!znc@znc.in PRIVMSG #chan :Playback Complete.")
+ (0 ":irc.barnet.org NOTICE tester :[09:05:35] This server is in debug mode 
and is logging all user I/O. If you do not wish for everything you send to be 
readable by the server owner(s), please disconnect.")
+ (0 ":irc.barnet.org 305 tester :You are no longer marked as being away"))
+
+((mode 3 "MODE #chan")
+ (0 ":irc.barnet.org 324 tester #chan +nt")
+ (0 ":irc.barnet.org 329 tester #chan 1620205534")
+ (0.1 ":mike!~u@wvys46tx8tpmk.irc PRIVMSG #chan :joe: That will be given to 
the loudest noise we make.")
+ (0.1 ":joe!~u@wvys46tx8tpmk.irc PRIVMSG #chan :mike: If it please your honor, 
I am the poor duke's constable, and my name is Elbow: I do lean upon justice, 
sir; and do bring in here before your good honor two notorious benefactors.")
+ (0.1 ":mike!~u@wvys46tx8tpmk.irc PRIVMSG #chan :joe: Following the signs, 
woo'd but the sign of she.")
+ (0.5 ":joe!~u@wvys46tx8tpmk.irc PRIVMSG #chan :mike: That, sir, which I will 
not report after her.")
+ (0.1 ":mike!~u@wvys46tx8tpmk.irc PRIVMSG #chan :joe: Boyet, prepare: I will 
away to-night.")
+ (0.1 ":joe!~u@wvys46tx8tpmk.irc PRIVMSG #chan :mike: If the man be a 
bachelor, sir, I can; but if he be a married man, he is his wife's head, and I 
can never cut off a woman's head.")
+ (0.1 ":mike!~u@wvys46tx8tpmk.irc PRIVMSG #chan :joe: Thyself upon thy 
virtues, they on thee.")
+ (0.1 ":joe!~u@wvys46tx8tpmk.irc PRIVMSG #chan :mike: Arm it in rags, a 
pigmy's straw doth pierce it."))
+
+((part 5.1 "PART #chan :" quit)
+ (0 ":tester!~u@wvys46tx8tpmk.irc PART #chan :" quit))
+
+((join 10.1 "JOIN #chan")
+ (0 ":tester!~u@wvys46tx8tpmk.irc JOIN #chan")
+ (0 ":irc.barnet.org 353 tester = #chan :@mike joe tester")
+ (0 ":irc.barnet.org 366 tester #chan :End of NAMES list")
+ (0.1 ":mike!~u@wvys46tx8tpmk.irc PRIVMSG #chan :tester, welcome!")
+ (0 ":joe!~u@wvys46tx8tpmk.irc PRIVMSG #chan :tester, welcome!"))
+
+((mode 1 "MODE #chan")
+ (0 ":irc.barnet.org 324 tester #chan +nt")
+ (0 ":irc.barnet.org 329 tester #chan 1620205534")
+ (0.1 ":mike!~u@wvys46tx8tpmk.irc PRIVMSG #chan :joe: Chi non te vede, non te 
pretia.")
+ (0.1 ":joe!~u@wvys46tx8tpmk.irc PRIVMSG #chan :mike: Well, if ever thou dost 
fall from this faith, thou wilt prove a notable argument.")
+ (0.1 ":mike!~u@wvys46tx8tpmk.irc PRIVMSG #chan :joe: Of heavenly oaths, vow'd 
with integrity.")
+ (0.1 ":joe!~u@wvys46tx8tpmk.irc PRIVMSG #chan :mike: These herblets shall, 
which we upon you strew.")
+ (0.1 ":mike!~u@wvys46tx8tpmk.irc PRIVMSG #chan :joe: Aaron will have his soul 
black like his face."))
+
+((linger 0.5 LINGER))
diff --git a/test/lisp/erc/resources/base/reuse-buffers/channel/foonet.eld 
b/test/lisp/erc/resources/base/reuse-buffers/channel/foonet.eld
new file mode 100644
index 0000000000..a11cfac2e7
--- /dev/null
+++ b/test/lisp/erc/resources/base/reuse-buffers/channel/foonet.eld
@@ -0,0 +1,66 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :foonet:changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Wed, 05 May 2021 
09:05:34 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 12 "MODE tester +i")
+ ;; No mode answer
+ (0 ":irc.znc.in 306 tester :You have been marked as being away")
+ (0 ":tester!~u@247eaxkrufj44.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :alice @bob tester")
+ (0 ":irc.foonet.org 366 tester #chan :End of /NAMES list.")
+ (0 ":***!znc@znc.in PRIVMSG #chan :Buffer Playback...")
+ (0 ":alice!~u@yppdd5tt4admc.irc PRIVMSG #chan :[09:07:19] bob: Is this; she 
hath bought the name of whore thus dearly.")
+ (0 ":bob!~u@yppdd5tt4admc.irc PRIVMSG #chan :[09:07:24] alice: He sent to me, 
sir,Here he comes.")
+ (0 ":alice!~u@yppdd5tt4admc.irc PRIVMSG #chan :[09:07:26] bob: Till I torment 
thee for this injury.")
+ (0 ":bob!~u@yppdd5tt4admc.irc PRIVMSG #chan :[09:07:29] alice: There's an 
Italian come; and 'tis thought, one of Leonatus' friends.")
+ (0 ":alice!~u@yppdd5tt4admc.irc PRIVMSG #chan :[09:09:33] bob: Ay, and the 
particular confirmations, point from point, to the full arming of the verity.")
+ (0 ":bob!~u@yppdd5tt4admc.irc PRIVMSG #chan :[09:09:35] alice: Kneel in the 
streets and beg for grace in vain.")
+ (0 ":***!znc@znc.in PRIVMSG #chan :Playback Complete.")
+ (0 ":irc.foonet.org NOTICE tester :[09:06:05] This server is in debug mode 
and is logging all user I/O. If you do not wish for everything you send to be 
readable by the server owner(s), please disconnect.")
+ (0 ":irc.foonet.org 305 tester :You are no longer marked as being away"))
+
+((mode 10 "MODE #chan")
+ (0 ":irc.foonet.org 324 tester #chan +nt")
+ (0 ":irc.foonet.org 329 tester #chan 1620205534")
+ (0.5 ":bob!~u@yppdd5tt4admc.irc PRIVMSG #chan :alice: Nor I no strength to 
climb without thy help.")
+ (0.1 ":alice!~u@yppdd5tt4admc.irc PRIVMSG #chan :bob: Nothing, but let him 
have thanks. Demand of him my condition, and what credit I have with the duke.")
+ (0.1 ":bob!~u@yppdd5tt4admc.irc PRIVMSG #chan :alice: Show me this piece. I 
am joyful of your sights.")
+ (0.2 ":alice!~u@yppdd5tt4admc.irc PRIVMSG #chan :bob: Whilst I can shake my 
sword or hear the drum."))
+
+((part 5 "PART #chan :" quit)
+ (0 ":tester!~u@247eaxkrufj44.irc PART #chan :" quit))
+
+((join 10 "JOIN #chan")
+ (0 ":tester!~u@247eaxkrufj44.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :@bob alice tester")
+ (0 ":irc.foonet.org 366 tester #chan :End of NAMES list")
+ (0.1 ":alice!~u@yppdd5tt4admc.irc PRIVMSG #chan :tester, welcome!")
+ (0 ":bob!~u@yppdd5tt4admc.irc PRIVMSG #chan :tester, welcome!"))
+
+((mode 1 "MODE #chan")
+ (0 ":irc.foonet.org 324 tester #chan +nt")
+ (0 ":irc.foonet.org 329 tester #chan 1620205534")
+ (0.1 ":bob!~u@yppdd5tt4admc.irc PRIVMSG #chan :alice: Thou desirest me to 
stop in my tale against the hair.")
+ (0.1 ":alice!~u@yppdd5tt4admc.irc PRIVMSG #chan :bob: And dar'st not stand, 
nor look me in the face.")
+ (0.1 ":bob!~u@yppdd5tt4admc.irc PRIVMSG #chan :alice: It should not be, by 
the persuasion of his new feasting.")
+ (0.1 ":alice!~u@yppdd5tt4admc.irc PRIVMSG #chan :bob: It was not given me, 
nor I did not buy it.")
+ (0.1 ":bob!~u@yppdd5tt4admc.irc PRIVMSG #chan :alice: He that would vouch it 
in any place but here.")
+ (0.1 ":alice!~u@yppdd5tt4admc.irc PRIVMSG #chan :bob: In everything I wait 
upon his will.")
+ (0.1 ":bob!~u@yppdd5tt4admc.irc PRIVMSG #chan :alice: Thou counterfeit'st 
most lively."))
+
+((linger 8 LINGER))
diff --git a/test/lisp/erc/resources/base/reuse-buffers/server/barnet.eld 
b/test/lisp/erc/resources/base/reuse-buffers/server/barnet.eld
new file mode 100644
index 0000000000..cc7aff1007
--- /dev/null
+++ b/test/lisp/erc/resources/base/reuse-buffers/server/barnet.eld
@@ -0,0 +1,24 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :barnet:changeme"))
+((nick 1 "NICK tester"))
+((user 2 "USER user 0 * :tester")
+ (0 ":irc.barnet.org 001 tester :Welcome to the barnet IRC Network tester")
+ (0 ":irc.barnet.org 002 tester :Your host is irc.barnet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.barnet.org 003 tester :This server was created Sun, 25 Apr 2021 
11:28:28 UTC")
+ (0 ":irc.barnet.org 004 tester irc.barnet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.barnet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.barnet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=barnet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.barnet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.barnet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.barnet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.barnet.org 254 tester 1 :channels formed")
+ (0 ":irc.barnet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.barnet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.barnet.org 422 tester :MOTD File is missing"))
+
+((mode-user 10.2 "MODE tester +i")
+ ;; No mode answer
+ (0 ":irc.znc.in 306 tester :You have been marked as being away")
+ (0 ":irc.barnet.org NOTICE tester :[11:29:00] This server is in debug mode 
and is logging all user I/O. If you do not wish for everything you send to be 
readable by the server owner(s), please disconnect.")
+ (0 ":irc.barnet.org 305 tester :You are no longer marked as being away"))
diff --git a/test/lisp/erc/resources/base/reuse-buffers/server/foonet.eld 
b/test/lisp/erc/resources/base/reuse-buffers/server/foonet.eld
new file mode 100644
index 0000000000..3a84610846
--- /dev/null
+++ b/test/lisp/erc/resources/base/reuse-buffers/server/foonet.eld
@@ -0,0 +1,24 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :foonet:changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Sun, 25 Apr 2021 
11:28:28 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 10.2 "MODE tester +i")
+ ;; No mode answer
+ (0 ":irc.znc.in 306 tester :You have been marked as being away")
+ (0 ":irc.foonet.org NOTICE tester :[11:29:00] This server is in debug mode 
and is logging all user I/O. If you do not wish for everything you send to be 
readable by the server owner(s), please disconnect.")
+ (0 ":irc.foonet.org 305 tester :You are no longer marked as being away"))
diff --git a/test/lisp/erc/resources/base/upstream-reconnect/soju-barnet.eld 
b/test/lisp/erc/resources/base/upstream-reconnect/soju-barnet.eld
new file mode 100644
index 0000000000..3711eb8f8e
--- /dev/null
+++ b/test/lisp/erc/resources/base/upstream-reconnect/soju-barnet.eld
@@ -0,0 +1,64 @@
+;; -*- mode: lisp-data; -*-
+((pass 6 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER tester@vanilla/barnet 0 * :tester")
+ (0.01 ":soju.im 001 tester :Welcome to soju, tester")
+ (0.01 ":soju.im 002 tester :Your host is soju.im")
+ (0.00 ":soju.im 004 tester soju.im soju aiwroO OovaimnqpsrtklbeI")
+ (0.53 ":soju.im 005 tester CHATHISTORY=1000 CASEMAPPING=ascii BOUNCER_NETID=2 
AWAYLEN=390 CHANLIMIT=#:100 INVEX NETWORK=barnet NICKLEN=32 WHOX MODES BOT=B 
ELIST=U MAXLIST=beI:60 :are supported")
+ (0.01 ":soju.im 005 tester TOPICLEN=390 CHANMODES=Ibe,k,fl,CEMRUimnstu 
CHANNELLEN=64 EXCEPTS EXTBAN=,m KICKLEN=390 
TARGMAX=NAMES:1,LIST:1,KICK:,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 MAXTARGETS=4 MONITOR=100 CHANTYPES=# PREFIX=(qaohv)~&@%+ UTF8ONLY :are 
supported")
+ (0.22 ":soju.im 221 tester +Zi")
+ (0.00 ":soju.im 422 tester :Use /motd to read the message of the day"))
+
+((mode 5 "MODE tester +i")
+ (0.00 ":tester!tester@10.0.2.100 JOIN #chan")
+ (0.06 ":soju.im 353 tester = #chan :tester @mike joe")
+ (0.01 ":soju.im 366 tester #chan :End of /NAMES list")
+ (0.23 ":irc.barnet.org 221 tester +Zi"))
+
+((mode 5 "MODE #chan")
+ (0.00 ":soju.im 324 tester #chan +tn")
+ (0.01 ":soju.im 329 tester #chan 1652878846")
+ (0.01 ":joe!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :mike: There is five in the 
first show.")
+ (0.00 ":mike!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :joe: Sir, I was an inward of 
his. A shy fellow was the duke; and, I believe I know the cause of his 
withdrawing.")
+ (0.00 ":joe!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :mike: Proud of employment, 
willingly I go.")
+ (0.09 ":mike!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :joe: Dull not device by 
coldness and delay.")
+ (0.09 ":joe!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :mike: Our states are forfeit: 
seek not to undo us.")
+ (0.06 ":mike!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :joe: Come, you are too 
severe a moraler. As the time, the place, and the condition of this country 
stands, I could heartily wish this had not befallen, but since it is as it is, 
mend it for your own good.")
+ (0.06 ":joe!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :mike: Who hath upon him still 
that natural stamp.")
+ (0.07 ":mike!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :joe: Arraign her first; 'tis 
Goneril. I here take my oath before this honourable assembly, she kicked the 
poor king her father.")
+ (0.06 ":joe!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :mike: Lady, I will commend 
you to mine own heart.")
+ (0.08 ":mike!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :joe: Look, what I will not, 
that I cannot do.")
+ (0.08 ":joe!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :mike: That he would wed me, 
or else die my lover.")
+ (0.08 ":mike!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :joe: Come your way, sir. 
Bless you, good father friar.")
+ (0.08 ":joe!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :mike: Under correction, sir, 
we know whereuntil it doth amount.")
+ (0.08 ":mike!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :joe: For I am nothing if not 
critical.")
+ (0.06 ":joe!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :mike: Once more I'll read the 
ode that I have writ.")
+ (0.06 ":mike!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :joe: This is the foul fiend 
Flibbertigibbet: he begins at curfew, and walks till the first cock; he gives 
the web and the pin, squints the eye, and makes the harelip; mildews the white 
wheat, and hurts the poor creature of earth.")
+ (0.06 ":joe!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :mike: Sir, I praise the Lord 
for you, and so may my parishioners; for their sons are well tutored by you, 
and their daughters profit very greatly under you: you are a good member of the 
commonwealth.")
+ (0.08 ":mike!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :joe: If it please your 
honor, I know not well what they are; but precise villains they are, that I am 
sure of, and void of all profanation in the world that good Christians ought to 
have.")
+ ;; Unexpected disconnect
+ (0.03 ":BouncerServ!BouncerServ@BouncerServ NOTICE tester :disconnected from 
barnet: failed to handle messages: failed to read IRC command: read tcp 
[::1]:54990->[::1]:6668: read: software caused connection abort")
+ ;; Eventual reconnect
+ (0.79 ":BouncerServ!BouncerServ@BouncerServ NOTICE tester :connected to 
barnet")
+ ;; No MOTD or other numerics
+ (0.01 ":soju.im 005 tester AWAYLEN=390 BOT=B CHANLIMIT=#:100 
CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# ELIST=U EXCEPTS 
EXTBAN=,m INVEX KICKLEN=390 :are supported")
+ (0.01 ":soju.im 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=barnet NICKLEN=32 PREFIX=(qaohv)~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8ONLY WHOX :are supported")
+ (0.22 ":irc.barnet.org 221 tester +Zi")
+ (0.01 ":irc.barnet.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.")
+ ;; Server-initialed join
+ (0.01 ":tester!tester@10.0.2.100 JOIN #chan"))
+
+((mode 5 "MODE #chan")
+ (0.22 ":soju.im 353 tester = #chan :@mike joe tester")
+ (0.00 ":soju.im 366 tester #chan :End of /NAMES list")
+ (0.00 ":soju.im 324 tester #chan +nt")
+ (0.00 ":soju.im 329 tester #chan 1652878846")
+ (0.00 ":mike!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :tester, welcome!")
+ (0.00 ":joe!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :tester, welcome!")
+ (0.06 ":soju.im 324 tester #chan +nt")
+ (0.00 ":soju.im 329 tester #chan 1652878846")
+ (0.62 ":joe!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :mike: Thou art my brother; so 
we'll hold thee ever.")
+ (0.00 ":mike!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :joe: Very well! go to! I 
cannot go to, man; nor 'tis not very well: by this hand, I say, it is very 
scurvy, and begin to find myself fobbed in it.")
+ (0.00 ":joe!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :mike: The heir of Alen on, 
Katharine her name.")
+ (0.09 ":mike!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :joe: Go to; farewell! put 
money enough in your purse."))
diff --git a/test/lisp/erc/resources/base/upstream-reconnect/soju-foonet.eld 
b/test/lisp/erc/resources/base/upstream-reconnect/soju-foonet.eld
new file mode 100644
index 0000000000..63dfcb184c
--- /dev/null
+++ b/test/lisp/erc/resources/base/upstream-reconnect/soju-foonet.eld
@@ -0,0 +1,72 @@
+;; -*- mode: lisp-data; -*-
+((pass 5 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER tester@vanilla/foonet 0 * :tester")
+ (0.01 ":soju.im 001 tester :Welcome to soju, tester")
+ (0.02 ":soju.im 002 tester :Your host is soju.im")
+ (0.01 ":soju.im 004 tester soju.im soju aiwroO OovaimnqpsrtklbeI")
+ (0.00 ":soju.im 005 tester CHATHISTORY=1000 CASEMAPPING=ascii BOUNCER_NETID=1 
CHANTYPES=# PREFIX=(qaohv)~&@%+ UTF8ONLY AWAYLEN=390 NICKLEN=32 WHOX 
CHANLIMIT=#:100 INVEX NETWORK=foonet MODES :are supported")
+ (0.00 ":soju.im 005 tester TOPICLEN=390 BOT=B ELIST=U MAXLIST=beI:60 
CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 
TARGMAX=NAMES:1,LIST:1,KICK:,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 EXCEPTS EXTBAN=,m KICKLEN=390 MAXTARGETS=4 MONITOR=100 :are supported")
+ (0.00 ":soju.im 221 tester +Zi")
+ (0.00 ":soju.im 422 tester :Use /motd to read the message of the day"))
+
+((mode 5 "MODE tester +i")
+ (0.2 ":irc.foonet.org 221 tester +Zi")
+ (0.0 ":tester!tester@10.0.2.100 JOIN #chan")
+ (0.0 ":soju.im 353 tester = #chan :tester @alice bob")
+ (0.1 ":soju.im 366 tester #chan :End of /NAMES list")
+ (0.0 ":bob!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :alice: Princely shall be thy 
usage every way.")
+ (0.1 ":alice!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :bob: Tell me thy reason why 
thou wilt marry."))
+
+((mode 5 "MODE #chan")
+ (0.00 ":soju.im 324 tester #chan +nt")
+ (0.01 ":soju.im 329 tester #chan 1652878847")
+ (0.02 ":bob!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :alice: There is no leprosy 
but what thou speak'st.")
+ (0.09 ":alice!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :bob: For I upon this bank 
will rest my head.")
+ (0.01 ":bob!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :alice: To ruffle in the 
commonwealth of Rome.")
+ (0.08 ":alice!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :bob: For I can nowhere find 
him like a man.")
+ (0.09 ":bob!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :alice: Ay, sir; but she will 
none, she gives you thanks.")
+ (0.05 ":alice!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :bob: That man should be at 
woman's command, and yet no hurt done! Though honesty be no puritan, yet it 
will do no hurt; it will wear the surplice of humility over the black gown of a 
big heart. I am going, forsooth: the business is for Helen to come hither.")
+ (0.07 ":bob!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :alice: Indeed, I should have 
asked you that before.")
+ (0.09 ":alice!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :bob: Faith, we met, and 
found the quarrel was upon the seventh cause.")
+ (0.05 ":bob!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :alice: And then, I hope, thou 
wilt be satisfied.")
+ (0.06 ":alice!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :bob: Well, I will forget 
the condition of my estate, to rejoice in yours.")
+ (0.05 ":bob!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :alice: Ah! sirrah, this 
unlook'd-for sport comes well.")
+ (0.01 ":alice!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :bob: Mayst thou inherit 
too! Welcome to Paris.")
+ (0.04 ":bob!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :alice: That I would choose, 
were I to choose anew.")
+ (0.08 ":alice!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :bob: Good Tom Drum, lend me 
a handkercher: so, I thank thee. Wait on me home, I'll make sport with thee: 
let thy curtsies alone, they are scurvy ones.")
+ (0.06 ":bob!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :alice: Excellent workman! 
Thou canst not paint a man so bad as is thyself.")
+ (0.07 ":alice!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :bob: That every braggart 
shall be found an ass.")
+ (0.07 ":bob!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :alice: This is but a custom 
in your tongue; you bear a graver purpose, I hope.")
+ (0.02 ":alice!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :bob: Well, we will have 
such a prologue, and it shall be written in eight and six.")
+ (0.01 ":bob!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :alice: Tell me thy reason why 
thou wilt marry.")
+ (0.06 ":alice!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :bob: According to the 
measure of their states.")
+
+ ;; Unexpected disconnect
+ (0.07 ":BouncerServ!BouncerServ@BouncerServ NOTICE tester :disconnected from 
foonet: failed to handle messages: failed to read IRC command: read tcp 
[::1]:57224->[::1]:6667: read: software caused connection abort")
+ ;; Eventual reconnect
+ (1.02 ":BouncerServ!BouncerServ@BouncerServ NOTICE tester :connected to 
foonet")
+ ;; No MOTD or other numerics
+ (0.01 ":soju.im 005 tester AWAYLEN=390 BOT=B CHANLIMIT=#:100 
CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# ELIST=U EXCEPTS 
EXTBAN=,m INVEX KICKLEN=390 :are supported")
+ (0.02 ":soju.im 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8ONLY WHOX :are supported")
+ (0.02 ":irc.foonet.org 221 tester +Zi")
+ (0.23 ":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.")
+ ;; Server-initialed join
+ (0.02 ":tester!tester@10.0.2.100 JOIN #chan"))
+
+((mode 5 "MODE #chan")
+ (0.03 ":soju.im 353 tester = #chan :@alice bob tester")
+ (0.03 ":soju.im 366 tester #chan :End of /NAMES list")
+ (0.00 ":soju.im 324 tester #chan +nt")
+ (0.00 ":soju.im 329 tester #chan 1652878847")
+ (0.00 ":bob!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :tester, welcome!")
+ (0.00 ":alice!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :tester, welcome!")
+ (0.46 ":soju.im 324 tester #chan +nt")
+ (0.01 ":soju.im 329 tester #chan 1652878847")
+ (0.00 ":bob!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :alice: Thou desirest me to 
stop in my tale against the hair.")
+ (0.07 ":alice!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :bob: But my intents are 
fix'd and will not leave me.")
+ (0.09 ":bob!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :alice: That last is true; the 
sweeter rest was mine.")
+ (0.09 ":alice!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :bob: No matter whither, so 
you come not here.")
+ (0.09 ":bob!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :alice: My lord, in heart; and 
let the health go round."))
+
+((linger 12 LINGER))
diff --git a/test/lisp/erc/resources/base/upstream-reconnect/znc-barnet.eld 
b/test/lisp/erc/resources/base/upstream-reconnect/znc-barnet.eld
new file mode 100644
index 0000000000..bf5c2b5a74
--- /dev/null
+++ b/test/lisp/erc/resources/base/upstream-reconnect/znc-barnet.eld
@@ -0,0 +1,93 @@
+;; -*- mode: lisp-data; -*-
+((pass 6 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER tester@vanilla/barnet 0 * :tester")
+ (0.00 ":irc.barnet.org 001 tester :Welcome to the barnet IRC Network tester")
+ (0.01 ":irc.barnet.org 002 tester :Your host is irc.barnet.org, running 
version ergo-v2.8.0")
+ (0.01 ":irc.barnet.org 003 tester :This server was created Thu, 19 May 2022 
05:33:02 UTC")
+ (0.00 ":irc.barnet.org 004 tester irc.barnet.org ergo-v2.8.0 BERTZios 
CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0.00 ":irc.barnet.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.01 ":irc.barnet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES 
MONITOR=100 NETWORK=barnet 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.barnet.org 005 tester draft/CHATHISTORY=100 :are supported by 
this server")
+ (0.00 ":irc.barnet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0.00 ":irc.barnet.org 252 tester 0 :IRC Operators online")
+ (0.11 ":irc.barnet.org 254 tester 1 :channels formed")
+ (0.00 ":irc.barnet.org 255 tester :I have 3 clients and 0 servers")
+ (0.00 ":irc.barnet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0.00 ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0.00 ":irc.barnet.org 422 tester :MOTD File is missing"))
+
+((mode 5 "MODE tester +i")
+ (0.0 ":tester!~u@fsr9fwzfeeybc.irc JOIN #chan")
+ (0.05 ":irc.barnet.org 353 tester = #chan :@joe mike tester")
+ (0.01 ":irc.barnet.org 366 tester #chan :End of /NAMES list.")
+ (0.0 ":***!znc@znc.in PRIVMSG #chan :Buffer Playback...")
+ (0.0 ":joe!~u@6t6jcije78we2.irc PRIVMSG #chan :[05:48:13] mike: But send the 
midwife presently to me.")
+ (0.01 ":mike!~u@6t6jcije78we2.irc PRIVMSG #chan :[05:48:18] joe: Alas! poor 
rogue, I think, i' faith, she loves me.")
+ (0.01 ":joe!~u@6t6jcije78we2.irc PRIVMSG #chan :[05:48:20] mike: They did not 
bless us with one happy word.")
+ (0.01 ":mike!~u@6t6jcije78we2.irc PRIVMSG #chan :[05:48:24] joe: And hear the 
sentence of your moved prince.")
+ (0.21 ":joe!~u@6t6jcije78we2.irc PRIVMSG #chan :[05:48:29] mike: Swear me to 
this, and I will ne'er say no.")
+ (0.01 ":mike!~u@6t6jcije78we2.irc PRIVMSG #chan :[05:48:32] joe: As they had 
seen me with these hangman's hands.")
+ (0.01 ":joe!~u@6t6jcije78we2.irc PRIVMSG #chan :[05:48:34] mike: Boyet, 
prepare: I will away to-night.")
+ (0.01 ":mike!~u@6t6jcije78we2.irc PRIVMSG #chan :[05:48:36] joe: For being a 
little bad: so may my husband.")
+ (0.04 ":***!znc@znc.in PRIVMSG #chan :Playback Complete.")
+ (0.0 ":irc.barnet.org 221 tester +Zi")
+ (2.55 ":joe!~u@6t6jcije78we2.irc PRIVMSG #chan :mike: And whirl along with 
thee about the globe."))
+
+((mode 5 "MODE #chan")
+ (0.00 ":irc.barnet.org 324 tester #chan +nt")
+ (0.00 ":irc.barnet.org 329 tester #chan 1652938384")
+ (0.06 ":mike!~u@6t6jcije78we2.irc PRIVMSG #chan :joe: Unless good-counsel may 
the cause remove.")
+ (0.00 ":joe!~u@6t6jcije78we2.irc PRIVMSG #chan :mike: Thyself domestic 
officers thine enemy.")
+ (0.01 ":mike!~u@6t6jcije78we2.irc PRIVMSG #chan :joe: Go after her: she's 
desperate; govern her.")
+ (0.30 ":joe!~u@6t6jcije78we2.irc PRIVMSG #chan :mike: Or else to heaven she 
heaves them for revenge.")
+ (0.01 ":mike!~u@6t6jcije78we2.irc PRIVMSG #chan :joe: Keep up your bright 
swords, for the dew will rust them.")
+ (0.04 ":*status!znc@znc.in PRIVMSG tester :Disconnected from IRC (Connection 
aborted). Reconnecting...")
+ (0.41 ":*status!znc@znc.in PRIVMSG tester :Disconnected from IRC. 
Reconnecting...")
+ (0.59 ":*status!znc@znc.in PRIVMSG tester :Connected!")
+ (0.02 ":irc.barnet.org 001 tester :Welcome to the barnet IRC Network tester")
+ (0.01 ":irc.barnet.org 002 tester :Your host is irc.barnet.org, running 
version ergo-v2.8.0")
+ (0.01 ":irc.barnet.org 003 tester :This server was created Thu, 19 May 2022 
05:33:02 UTC")
+ (0.01 ":irc.barnet.org 004 tester irc.barnet.org ergo-v2.8.0 BERTZios 
CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0.01 ":irc.barnet.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.01 ":irc.barnet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES 
MONITOR=100 NETWORK=barnet 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.22 ":irc.barnet.org 005 tester draft/CHATHISTORY=100 :are supported by 
this server")
+ (0.00 ":irc.barnet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0.01 ":irc.barnet.org 252 tester 0 :IRC Operators online")
+ (0.00 ":irc.barnet.org 253 tester 0 :unregistered connections")
+ (0.00 ":irc.barnet.org 254 tester 1 :channels formed")
+ (0.00 ":irc.barnet.org 255 tester :I have 3 clients and 0 servers")
+ (0.00 ":irc.barnet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0.17 ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0.00 ":irc.barnet.org 422 tester :MOTD File is missing")
+ (0.01 ":irc.barnet.org 221 tester +Zi")
+ (0.00 ":irc.barnet.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.05 ":irc.barnet.org 352 tester * ~u fsr9fwzfeeybc.irc irc.barnet.org 
tester H :0 ZNC - https://znc.in";)
+ (0.02 ":irc.barnet.org 315 tester tester!*@* :End of WHO list")
+ (0.08 ":tester!~u@fsr9fwzfeeybc.irc JOIN #chan"))
+
+((mode 5 "MODE #chan")
+ (0.05 ":irc.barnet.org 353 tester = #chan :mike tester @joe")
+ (0.01 ":irc.barnet.org 366 tester #chan :End of NAMES list")
+ (0.00 ":mike!~u@6t6jcije78we2.irc PRIVMSG #chan :tester, welcome!")
+ (0.00 ":joe!~u@6t6jcije78we2.irc PRIVMSG #chan :tester, welcome!")
+ (0.02 ":irc.barnet.org 324 tester #chan +nt")
+ (0.01 ":irc.barnet.org 329 tester #chan 1652938384")
+ (0.00 ":joe!~u@6t6jcije78we2.irc PRIVMSG #chan :mike: See, here he comes, and 
I must ply my theme.")
+ (0.00 ":mike!~u@6t6jcije78we2.irc PRIVMSG #chan :joe: Confine yourself but in 
a patient list.")
+ (0.00 ":joe!~u@6t6jcije78we2.irc PRIVMSG #chan :mike: And bide the penance of 
each three years' day.")
+ (0.00 ":mike!~u@6t6jcije78we2.irc PRIVMSG #chan :joe: Bid me farewell, and 
let me hear thee going.")
+ (0.00 ":joe!~u@6t6jcije78we2.irc PRIVMSG #chan :mike: Nor shall not, if I do 
as I intend.")
+ (0.00 ":mike!~u@6t6jcije78we2.irc PRIVMSG #chan :joe: Our corn's to reap, for 
yet our tithe's to sow.")
+ (0.00 ":joe!~u@6t6jcije78we2.irc PRIVMSG #chan :mike: And almost broke my 
heart with extreme laughter.")
+ (0.00 ":mike!~u@6t6jcije78we2.irc PRIVMSG #chan :joe: Of modern seeming do 
prefer against him.")
+ (0.00 ":joe!~u@6t6jcije78we2.irc PRIVMSG #chan :mike: Like humble-visag'd 
suitors, his high will.")
+ (0.00 ":mike!~u@6t6jcije78we2.irc PRIVMSG #chan :joe: But yet, poor Claudio! 
There's no remedy.")
+ (0.00 ":joe!~u@6t6jcije78we2.irc PRIVMSG #chan :mike: Let him make treble 
satisfaction.")
+ (0.00 ":mike!~u@6t6jcije78we2.irc PRIVMSG #chan :joe: He's that he is; I may 
not breathe my censure.")
+ (0.00 ":joe!~u@6t6jcije78we2.irc PRIVMSG #chan :mike: To check their folly, 
passion's solemn tears.")
+ (0.00 ":mike!~u@6t6jcije78we2.irc PRIVMSG #chan :joe: Villain, I have done 
thy mother.")
+ (0.00 ":joe!~u@6t6jcije78we2.irc PRIVMSG #chan :mike: Please you, therefore, 
draw nigh, and take your places.")
+ (0.00 ":mike!~u@6t6jcije78we2.irc PRIVMSG #chan :joe: You shall not be 
admitted to his sight.")
+ (0.00 ":joe!~u@6t6jcije78we2.irc PRIVMSG #chan :mike: Sir, you shall present 
before her the Nine Worthies. Sir Nathaniel, as concerning some entertainment 
of time, some show in the posterior of this day, to be rendered by our 
assistance, at the king's command, and this most gallant, illustrate, and 
learned gentleman, before the princess; I say, none so fit as to present the 
Nine Worthies.")
+ (0.00 ":mike!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :joe: Go to; farewell! put 
money enough in your purse."))
diff --git a/test/lisp/erc/resources/base/upstream-reconnect/znc-foonet.eld 
b/test/lisp/erc/resources/base/upstream-reconnect/znc-foonet.eld
new file mode 100644
index 0000000000..39c2950aa0
--- /dev/null
+++ b/test/lisp/erc/resources/base/upstream-reconnect/znc-foonet.eld
@@ -0,0 +1,86 @@
+;; -*- mode: lisp-data; -*-
+((pass 6 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER tester@vanilla/foonet 0 * :tester")
+ (0.16 ":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 Thu, 19 May 2022 
05:33:02 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.01 ":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 3 invisible on 1 
server(s)")
+ (0.00 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0.00 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0.00 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0.00 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0.00 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0.00 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode 6 "MODE tester +i")
+ (0.00 ":tester!~u@rmtvrz9zcwbdq.irc JOIN #chan")
+ (0.09 ":irc.foonet.org 353 tester = #chan :@alice bob tester")
+ (0.00 ":irc.foonet.org 366 tester #chan :End of /NAMES list.")
+ (0.00 ":***!znc@znc.in PRIVMSG #chan :Buffer Playback...")
+ (0.00 ":bob!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :[05:48:11] alice: And be 
aveng'd on cursed Tamora.")
+ (0.00 ":alice!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :[05:48:13] bob: The 
stronger part of it by her own letters, which make her story true, even to the 
point of her death: her death itself, which could not be her office to say is 
come, was faithfully confirmed by the rector of the place.")
+ (0.01 ":bob!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :[05:48:15] alice: The ape is 
dead, and I must conjure him.")
+ (0.00 ":alice!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :[05:48:17] bob: Not so; but 
I answer you right painted cloth, from whence you have studied your questions.")
+ (0.01 ":bob!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :[05:48:21] alice: The valiant 
Paris seeks you for his love.")
+ (0.00 ":alice!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :[05:48:26] bob: To prison 
with her; and away with him.")
+ (0.00 ":bob!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :[05:48:30] alice: Tell them 
there I have gold; look, so I have.")
+ (0.00 ":alice!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :[05:48:35] bob: Will even 
weigh, and both as light as tales.")
+ (0.00 ":***!znc@znc.in PRIVMSG #chan :Playback Complete.")
+ (0.00 ":irc.foonet.org 221 tester +Zi")
+ (0.08 ":bob!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :alice: By some vile forfeit 
of untimely death."))
+
+((mode 3.51 "MODE #chan")
+ (0.1 ":irc.foonet.org 324 tester #chan +nt")
+ (0.0 ":irc.foonet.org 329 tester #chan 1652938384")
+ (0.0 ":alice!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :bob: What does this knave 
here ? Get you gone, sirrah: the complaints I have heard of you I do not all 
believe: 'tis my slowness that I do not; for I know you lack not folly to 
commit them, and have ability enough to make such knaveries yours.")
+ (0.0 ":bob!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :alice: When sects and factions 
were newly born.")
+ (0.1 ":alice!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :bob: Fall, when Love please! 
marry, to each, but one.")
+ (0.1 ":bob!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :alice: For I ne'er saw true 
beauty till this night.")
+ (0.1 ":alice!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :bob: Or say, sweet love, 
what thou desir'st to eat.")
+ (0.1 ":bob!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :alice: Yes, and will nobly him 
remunerate.")
+ (0.1 ":*status!znc@znc.in PRIVMSG tester :Disconnected from IRC (Connection 
aborted). Reconnecting...")
+ (0.4 ":*status!znc@znc.in PRIVMSG tester :Disconnected from IRC. 
Reconnecting...")
+ (0.9 ":*status!znc@znc.in PRIVMSG tester :Connected!")
+ (0.0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0.0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running 
version ergo-v2.8.0")
+ (0.0 ":irc.foonet.org 003 tester :This server was created Thu, 19 May 2022 
05:33:02 UTC")
+ (0.0 ":irc.foonet.org 004 tester irc.foonet.org ergo-v2.8.0 BERTZios 
CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0.1 ":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.0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES 
MONITOR=100 NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0.0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0.0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0.0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0.0 ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (0.1 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0.0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0.0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0.0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0.0 ":irc.foonet.org 422 tester :MOTD File is missing")
+ (0.0 ":irc.foonet.org 221 tester +Zi")
+ (0.0 ":irc.foonet.org NOTICE tester :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect.")
+ (0.6 ":irc.foonet.org 352 tester * ~u rmtvrz9zcwbdq.irc irc.foonet.org tester 
H :0 ZNC - https://znc.in";)
+ (0.0 ":irc.foonet.org 315 tester tester!*@* :End of WHO list")
+ (0.0 ":tester!~u@rmtvrz9zcwbdq.irc JOIN #chan"))
+
+((mode 6 "MODE #chan")
+ (0.0 ":irc.foonet.org 353 tester = #chan :@alice bob tester")
+ (0.0 ":irc.foonet.org 366 tester #chan :End of NAMES list")
+ (0.0 ":alice!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :tester, welcome!")
+ (0.0 ":bob!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :tester, welcome!")
+ (0.0 ":alice!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :bob: Being of no power to 
make his wishes good.")
+ (0.0 ":irc.foonet.org 324 tester #chan +nt")
+ (0.0 ":irc.foonet.org 329 tester #chan 1652938384")
+ (0.0 ":bob!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :alice: In everything I wait 
upon his will.")
+ (0.0 ":alice!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :bob: Make choice of which 
your highness will see first.")
+ (0.0 ":bob!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :alice: We waste our lights in 
vain, like lamps by day.")
+ (0.0 ":alice!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :bob: No, I know that; but it 
is fit I should commit offence to my inferiors.")
+ (0.1 ":bob!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :alice: By my head, here come 
the Capulets.")
+ (0.0 ":alice!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :bob: Well, I will forget the 
condition of my estate, to rejoice in yours.")
+ (0.0 ":bob!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :alice: My lord, in heart; and 
let the health go round."))
+
+((linger 12 LINGER))
diff --git a/test/lisp/erc/resources/dcc/chat/accept-dcc.eld 
b/test/lisp/erc/resources/dcc/chat/accept-dcc.eld
new file mode 100644
index 0000000000..23828a8115
--- /dev/null
+++ b/test/lisp/erc/resources/dcc/chat/accept-dcc.eld
@@ -0,0 +1,3 @@
+;; -*- mode: lisp-data; -*-
+((open 10 "Hi")
+ (0 "Hola"))
diff --git a/test/lisp/erc/resources/dcc/chat/accept.eld 
b/test/lisp/erc/resources/dcc/chat/accept.eld
new file mode 100644
index 0000000000..a23e9580bc
--- /dev/null
+++ b/test/lisp/erc/resources/dcc/chat/accept.eld
@@ -0,0 +1,23 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Mon, 31 May 2021 
09:56:24 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 4 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 254 tester 2 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 4 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 4 4 :Current local users 4, max 4")
+ (0 ":irc.foonet.org 266 tester 4 4 :Current global users 4, max 4")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 1.2 "MODE tester +i")
+ ;; No mode answer
+ (0 ":irc.foonet.org NOTICE tester :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect.")
+ (0.2 ":dummy!~u@34n9brushbpj2.irc PRIVMSG tester :\C-aDCC CHAT chat 
2130706433 " port "\C-a"))
diff --git a/test/lisp/erc/resources/erc-d/erc-d-i.el 
b/test/lisp/erc/resources/erc-d/erc-d-i.el
new file mode 100644
index 0000000000..db113335a8
--- /dev/null
+++ b/test/lisp/erc/resources/erc-d/erc-d-i.el
@@ -0,0 +1,124 @@
+;;; 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.
+;;
+;; 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:
+
+;;; Code:
+
+(require 'cl-lib)
+
+(cl-defstruct (erc-d-i-message (:conc-name erc-d-i-message.))
+  "Identical to `erc-response'.
+When member `compat' is nil, it means the raw message was decoded as
+UTF-8 text before parsing, which is nonstandard."
+  (unparsed "" :type string)
+  (sender "" :type string)
+  (command "" :type string)
+  (command-args nil :type (list-of string))
+  (contents "" :type string)
+  (tags nil :type (list-of (cons symbol string)))
+  (compat t :type boolean))
+
+(defconst erc-d-i--tag-escapes
+  '((";" . "\\:") (" " . "\\s") ("\\" . "\\\\") ("\r" . "\\r") ("\n" . "\\n")))
+
+;; These are not mirror inverses; unescaping may drop stranded or
+;; misplaced backslashes.
+
+(defconst erc-d-i--tag-escaped-regexp (rx (or ?\; ?\  ?\\ ?\r ?\n)))
+
+(defconst erc-d-i--tag-unescaped-regexp
+  (rx (or "\\:" "\\s" "\\\\" "\\r" "\\n"
+          (seq "\\" (or string-end (not (or ":" "s" "n" "r" "\\")))))))
+
+(defun erc-d-i--unescape-tag-value (str)
+  "Undo substitution of char placeholders in raw tag value STR."
+  (replace-regexp-in-string erc-d-i--tag-unescaped-regexp
+                            (lambda (s)
+                              (or (car (rassoc s erc-d-i--tag-escapes))
+                                  (substring s 1)))
+                            str t t))
+
+(defun erc-d-i--escape-tag-value (str)
+  "Swap out banned chars in tag value STR with message representation."
+  (replace-regexp-in-string erc-d-i--tag-escaped-regexp
+                            (lambda (s)
+                              (cdr (assoc s erc-d-i--tag-escapes)))
+                            str t t))
+
+(defconst erc-d-i--invalid-tag-regexp (rx (any "\0\7\r\n; ")))
+
+(defun erc-d-i--validate-tags (raw)
+  "Validate tags portion of some RAW incoming message.
+RAW must not have a leading \"@\" or a trailing space.  The spec says
+validation shouldn't be performed on keys and that undecodeable values
+or ones with illegal (unescaped) chars may be dropped.  This does not
+respect any of that.  Its purpose is to catch bad input created by us."
+  (unless (> 4094 (string-bytes raw))
+    ;; 417 ERR_INPUTTOOLONG Input line was too long
+    (error "Message tags exceed 4094 bytes: %S" raw))
+  (let (tags
+        (tag-strings (split-string raw ";")))
+    (dolist (s tag-strings (nreverse tags))
+      (let* ((m (if (>= emacs-major-version 28)
+                    (string-search "=" s)
+                  (string-match-p "=" s)))
+             (key (if m (substring s 0 m) s))
+             (val (when-let* (m ; check first, like (m), but shadow
+                              (v (substring s (1+ m)))
+                              ((not (string-equal v ""))))
+                    (when (string-match-p erc-d-i--invalid-tag-regexp v)
+                      (error "Bad tag: %s" s))
+                    (thread-first v
+                                  (decode-coding-string 'utf-8 t)
+                                  (erc-d-i--unescape-tag-value)))))
+        (when (string-empty-p key)
+          (error "Tag missing key: %S" s))
+        (setf (alist-get (intern key) tags) val)))))
+
+(defun erc-d-i--parse-message (s &optional decode)
+  "Parse string S into `erc-d-i-message' object.
+With DECODE, decode as UTF-8 text."
+  (when (string-suffix-p "\r\n" s)
+    (error "Unstripped message encountered"))
+  (when decode
+    (setq s (decode-coding-string s 'utf-8 t)))
+  (let ((mes (make-erc-d-i-message :unparsed s :compat (not decode)))
+        tokens)
+    (when-let* (((not (string-empty-p s)))
+                ((eq ?@ (aref s 0)))
+                (m (string-match " " s))
+                (u (substring s 1 m)))
+      (setf (erc-d-i-message.tags mes) (erc-d-i--validate-tags u)
+            s (substring s (1+ m))))
+    (if-let* ((m (string-match " :" s))
+              (other-toks (split-string (substring s 0 m) " " t))
+              (rest (substring s (+ 2 m))))
+        (setf (erc-d-i-message.contents mes) rest
+              tokens (nconc other-toks (list rest)))
+      (setq tokens (split-string s " " t " ")))
+    (when (and tokens (eq ?: (aref (car tokens) 0)))
+      (setf (erc-d-i-message.sender mes) (substring (pop tokens) 1)))
+    (setf (erc-d-i-message.command mes) (or (pop tokens) "")
+          (erc-d-i-message.command-args mes) tokens)
+    mes))
+
+(provide 'erc-d-i)
+;;; erc-d-i.el ends here
diff --git a/test/lisp/erc/resources/erc-d/erc-d-t.el 
b/test/lisp/erc/resources/erc-d/erc-d-t.el
new file mode 100644
index 0000000000..a1a7e7e88d
--- /dev/null
+++ b/test/lisp/erc/resources/erc-d/erc-d-t.el
@@ -0,0 +1,170 @@
+;;; 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:
+
+;;; 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)))
+    (require 'erc-d-u)))
+
+(require 'ert)
+
+(defun erc-d-t-kill-related-buffers ()
+  "Kill all erc- or erc-d- related buffers."
+  (let (buflist)
+    (dolist (buf (buffer-list))
+      (with-current-buffer buf
+        (when (or erc-d-u--process-buffer
+                  (derived-mode-p 'erc-mode))
+          (push buf buflist))))
+    (dolist (buf buflist)
+      (when (and (boundp 'erc-server-flood-timer)
+                 (timerp erc-server-flood-timer))
+        (cancel-timer erc-server-flood-timer))
+      (when-let ((proc (get-buffer-process buf)))
+        (delete-process proc))
+      (when (buffer-live-p buf)
+        (kill-buffer buf))))
+  (while (when-let ((buf (pop erc-d-u--canned-buffers)))
+           (kill-buffer buf))))
+
+(defun erc-d-t-silence-around (orig &rest args)
+  "Run ORIG function with ARGS silently.
+Use this on `erc-handle-login' and `erc-server-connect'."
+  (let ((inhibit-message t))
+    (apply orig args)))
+
+(defvar erc-d-t-cleanup-sleep-secs 0.1)
+
+(defmacro erc-d-t-with-cleanup (bindings cleanup &rest body)
+  "Execute BODY and run CLEANUP form regardless of outcome.
+`let*'-bind BINDINGS and make them available in BODY and CLEANUP.
+After CLEANUP, destroy any values in BINDINGS that remain bound to
+buffers or processes.  Sleep `erc-d-t-cleanup-sleep-secs' before
+returning."
+  (declare (indent 2))
+  `(let* ,bindings
+     (unwind-protect
+         (progn ,@body)
+       ,cleanup
+       (when noninteractive
+         (let (bufs procs)
+           (dolist (o (list ,@(mapcar (lambda (b) (or (car-safe b) b))
+                                      bindings)))
+             (when (bufferp o)
+               (push o bufs))
+             (when (processp o)
+               (push o procs)))
+           (dolist (proc procs)
+             (delete-process proc)
+             (when-let ((buf (process-buffer proc)))
+               (push buf bufs)))
+           (dolist (buf bufs)
+             (when-let ((proc (get-buffer-process buf)))
+               (delete-process proc))
+             (when (bufferp buf)
+               (ignore-errors (kill-buffer buf)))))
+         (sleep-for erc-d-t-cleanup-sleep-secs)))))
+
+(defmacro erc-d-t-wait-for (max-secs msg &rest body)
+  "Wait for BODY to become non-nil.
+Or signal error with MSG after MAX-SECS.  When MAX-SECS is negative,
+signal if BODY is ever non-nil before MAX-SECS elapses.  On success,
+return BODY's value.
+
+Note: this assumes BODY is waiting on a peer's output.  It tends to
+artificially accelerate consumption of all process output, which may not
+be desirable."
+  (declare (indent 2))
+  (unless (or (stringp msg) (memq (car-safe msg) '(format concat)))
+    (push msg body)
+    (setq msg (prin1-to-string body)))
+  (let ((inverted (make-symbol "inverted"))
+        (time-out (make-symbol "time-out"))
+        (result (make-symbol "result")))
+    `(ert-info ((concat "Awaiting: " ,msg))
+       (let ((,time-out (abs ,max-secs))
+             (,inverted (< ,max-secs 0))
+             (,result ',result))
+         (with-timeout (,time-out (if ,inverted
+                                      (setq ,inverted nil)
+                                    (error "Failed awaiting: %s" ,msg)))
+           (while (not (setq ,result (progn ,@body)))
+             (when (and (accept-process-output nil 0.1) (not noninteractive))
+               (redisplay))))
+         (when ,inverted
+           (error "Failed awaiting: %s" ,msg))
+         ,result))))
+
+(defmacro erc-d-t-ensure-for (max-secs msg &rest body)
+  "Ensure BODY remains non-nil for MAX-SECS.
+On failure, emit MSG."
+  (declare (indent 2))
+  (unless (or (stringp msg) (memq (car-safe msg) '(format concat)))
+    (push msg body)
+    (setq msg (prin1-to-string body)))
+  `(erc-d-t-wait-for (- (abs ,max-secs)) ,msg (not (progn ,@body))))
+
+(defun erc-d-t-search-for (timeout text &optional from on-success)
+  "Wait for TEXT to appear in current buffer before TIMEOUT secs.
+With marker or number FROM, only consider the portion of the buffer from
+that point forward.  If TEXT is a cons, interpret it as an RX regular
+expression.  If ON-SUCCESS is a function, call it when TEXT is found."
+  (save-restriction
+    (widen)
+    (let* ((rxp (consp text))
+           (fun (if rxp #'search-forward-regexp #'search-forward))
+           (pat (if rxp (rx-to-string text) text))
+           res)
+      (erc-d-t-wait-for timeout (format "string: %s" text)
+        (goto-char (or from (point-min)))
+        (setq res (funcall fun pat nil t))
+        (if (and on-success res)
+            (funcall on-success)
+          res)))))
+
+(defun erc-d-t-absent-for (timeout text &optional from on-success)
+  "Assert TEXT doesn't appear in current buffer for TIMEOUT secs."
+  (erc-d-t-search-for (- (abs timeout)) text from on-success))
+
+(defun erc-d-t-make-expecter ()
+  "Return function to search for new output in buffer.
+Assume new text is only inserted at or after `erc-insert-marker'.
+
+The returned function works like `erc-d-t-search-for', but it never
+revisits previously covered territory, and the optional fourth argument,
+ON-SUCCESS, is nonexistent.  To reset, specify a FROM argument."
+  (let (positions)
+    (lambda (timeout text &optional reset-from)
+      (let* ((pos (cdr (assq (current-buffer) positions)))
+             (cb (lambda ()
+                   (unless pos
+                     (push (cons (current-buffer) (setq pos (make-marker)))
+                           positions))
+                   (marker-position
+                    (set-marker pos (min (point) (1- (point-max))))))))
+        (when reset-from
+          (set-marker pos reset-from))
+        (erc-d-t-search-for timeout text pos cb)))))
+
+(provide 'erc-d-t)
+;;; erc-d-t.el ends here
diff --git a/test/lisp/erc/resources/erc-d/erc-d-tests.el 
b/test/lisp/erc/resources/erc-d/erc-d-tests.el
new file mode 100644
index 0000000000..357bc48b08
--- /dev/null
+++ b/test/lisp/erc/resources/erc-d/erc-d-tests.el
@@ -0,0 +1,1373 @@
+;;; 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:
+
+;;; Code:
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (expand-file-name ".." (ert-resource-directory))
+                         load-path)))
+    (require 'erc-d)
+    (require 'erc-d-t)))
+
+(require 'erc)
+
+;; Temporary kludge to silence warning
+(put 'erc-parse-tags 'erc-v3-warned-p t)
+
+(ert-deftest erc-d-u--canned-load-dialog--basic ()
+  (should-not (get-buffer "basic.eld"))
+  (should-not erc-d-u--canned-buffers)
+  (let* ((exes (erc-d-u--canned-load-dialog 'basic))
+         (reap (lambda ()
+                 (cl-loop with e = (erc-d-u--read-dialog exes)
+                          for s = (erc-d-u--read-exchange e)
+                          while s collect s))))
+    (should (get-buffer "basic.eld"))
+    (should (memq (get-buffer "basic.eld") erc-d-u--canned-buffers))
+    (should (equal (funcall reap) '((pass 10.0 "PASS " (? ?:) "changeme"))))
+    (should (equal (funcall reap) '((nick 0.2 "NICK tester"))))
+    (let ((r (funcall reap)))
+      (should (equal (car r) '(user 0.2 "USER user 0 * :tester")))
+      (should (equal
+               (car (last r))
+               '(0 ":irc.example.org 422 tester :MOTD File is missing"))))
+    (should (equal (car (funcall reap)) '(mode-user 5 "MODE tester +i")))
+    (should (equal (funcall reap)
+                   '((mode-chan 1.2 "MODE #chan")
+                     (0.1 ":bob!~bob@example.org PRIVMSG #chan :hey"))))
+    ;; See `define-error' site for `iter-end-of-sequence'
+    (ert-info ("EOB detected") (should-not (erc-d-u--read-dialog exes))))
+  (should-not (get-buffer "basic.eld"))
+  (should-not erc-d-u--canned-buffers))
+
+(defun erc-d-tests--make-hunk-reader (hunks)
+  (let ((p (erc-d-u--read-dialog hunks)))
+    (lambda () (erc-d-u--read-exchange p))))
+
+;; Fuzzies need to be able to access any non-exhausted genny.
+(ert-deftest erc-d-u--canned-load-dialog--intermingled ()
+  (should-not (get-buffer "basic.eld"))
+  (should-not erc-d-u--canned-buffers)
+  (let* ((exes (erc-d-u--canned-load-dialog 'basic))
+         (pass (erc-d-tests--make-hunk-reader exes))
+         (nick (erc-d-tests--make-hunk-reader exes))
+         (user (erc-d-tests--make-hunk-reader exes))
+         (modu (erc-d-tests--make-hunk-reader exes))
+         (modc (erc-d-tests--make-hunk-reader exes)))
+
+    (should (equal (funcall user) '(user 0.2 "USER user 0 * :tester")))
+    (should (equal (funcall modu) '(mode-user 5 "MODE tester +i")))
+    (should (equal (funcall modc) '(mode-chan 1.2 "MODE #chan")))
+
+    (cl-loop repeat 8 do (funcall user)) ; skip a few
+    (should (equal (funcall user)
+                   '(0 ":irc.example.org 254 tester 1 :channels formed")))
+    (should (equal (funcall modu)
+                   '(0 ":irc.example.org 221 tester +Zi")))
+    (should (equal (cl-loop for s = (funcall modc) while s collect s) ; done
+                   '((0.1 ":bob!~bob@example.org PRIVMSG #chan :hey"))))
+
+    (cl-loop repeat 3 do (funcall user))
+    (cl-loop repeat 3 do (funcall modu))
+
+    (ert-info ("Change up the order")
+      (should
+       (equal (funcall modu)
+              '(0 ":irc.example.org 366 alice #chan :End of NAMES list")))
+      (should
+       (equal (funcall user)
+              '(0 ":irc.example.org 422 tester :MOTD File is missing"))))
+
+    ;; Exhaust these
+    (should (equal (cl-loop for s = (funcall pass) while s collect s) ; done
+                   '((pass 10.0 "PASS " (? ?:) "changeme"))))
+    (should (equal (cl-loop for s = (funcall nick) while s collect s) ; done
+                   '((nick 0.2 "NICK tester"))))
+
+    (ert-info ("End of file but no teardown because hunks outstanding")
+      (should-not (erc-d-u--read-dialog exes))
+      (should (get-buffer "basic.eld")))
+
+    ;; Finish
+    (should-not (funcall user))
+    (should-not (funcall modu)))
+
+  (should-not (get-buffer "basic.eld"))
+  (should-not erc-d-u--canned-buffers))
+
+;; This indirectly tests `erc-d-u--canned-read' cleanup/teardown
+
+(ert-deftest erc-d-u--rewrite-for-slow-mo ()
+  (should-not (get-buffer "basic.eld"))
+  (should-not (get-buffer "basic.eld<2>"))
+  (should-not (get-buffer "basic.eld<3>"))
+  (should-not erc-d-u--canned-buffers)
+  (let ((exes (erc-d-u--canned-load-dialog 'basic))
+        (exes-lower (erc-d-u--canned-load-dialog 'basic))
+        (exes-custom (erc-d-u--canned-load-dialog 'basic))
+        (reap (lambda (e) (cl-loop with p = (erc-d-u--read-dialog e)
+                                   for s = (erc-d-u--read-exchange p)
+                                   while s collect s))))
+    (should (get-buffer "basic.eld"))
+    (should (get-buffer "basic.eld<2>"))
+    (should (get-buffer "basic.eld<3>"))
+    (should (equal (list (get-buffer "basic.eld<3>")
+                         (get-buffer "basic.eld<2>")
+                         (get-buffer "basic.eld"))
+                   erc-d-u--canned-buffers))
+
+    (ert-info ("Rewrite for slowmo basic")
+      (setq exes (erc-d-u--rewrite-for-slow-mo 10 exes))
+      (should (equal (funcall reap exes)
+                     '((pass 20.0 "PASS " (? ?:) "changeme"))))
+      (should (equal (funcall reap exes)
+                     '((nick 10.2 "NICK tester"))))
+      (let ((r (funcall reap exes)))
+        (should (equal (car r) '(user 10.2 "USER user 0 * :tester")))
+        (should (equal
+                 (car (last r))
+                 '(0 ":irc.example.org 422 tester :MOTD File is missing"))))
+      (should (equal (car (funcall reap exes))
+                     '(mode-user 15 "MODE tester +i")))
+      (should (equal (car (funcall reap exes))
+                     '(mode-chan 11.2 "MODE #chan")))
+      (should-not (erc-d-u--read-dialog exes)))
+
+    (ert-info ("Rewrite for slowmo bounded")
+      (setq exes-lower (erc-d-u--rewrite-for-slow-mo -5 exes-lower))
+      (should (equal (funcall reap exes-lower)
+                     '((pass 10.0 "PASS " (? ?:) "changeme"))))
+      (should (equal (funcall reap exes-lower)
+                     '((nick 5 "NICK tester"))))
+      (should (equal (car (funcall reap exes-lower))
+                     '(user 5 "USER user 0 * :tester")))
+      (should (equal (car (funcall reap exes-lower))
+                     '(mode-user 5 "MODE tester +i")))
+      (should (equal (car (funcall reap exes-lower))
+                     '(mode-chan 5 "MODE #chan")))
+      (should-not (erc-d-u--read-dialog exes-lower)))
+
+    (ert-info ("Rewrite for slowmo custom")
+      (setq exes-custom (erc-d-u--rewrite-for-slow-mo
+                         (lambda (n) (* 2 n)) exes-custom))
+      (should (equal (funcall reap exes-custom)
+                     '((pass 20.0 "PASS " (? ?:) "changeme"))))
+      (should (equal (funcall reap exes-custom)
+                     '((nick 0.4 "NICK tester"))))
+      (should (equal (car (funcall reap exes-custom))
+                     '(user 0.4 "USER user 0 * :tester")))
+      (should (equal (car (funcall reap exes-custom))
+                     '(mode-user 10 "MODE tester +i")))
+      (should (equal (car (funcall reap exes-custom))
+                     '(mode-chan 2.4 "MODE #chan")))
+      (should-not (erc-d-u--read-dialog exes-custom))))
+
+  (should-not (get-buffer "basic.eld"))
+  (should-not (get-buffer "basic.eld<2>"))
+  (should-not (get-buffer "basic.eld<3>"))
+  (should-not erc-d-u--canned-buffers))
+
+(ert-deftest erc-d--active-ex-p ()
+  (let ((ring (make-ring 5)))
+    (ert-info ("Empty ring returns nil for not active")
+      (should-not (erc-d--active-ex-p ring)))
+    (ert-info ("One fuzzy member returns nil for not active")
+      (ring-insert ring (make-erc-d-exchange :tag '~foo))
+      (should-not (erc-d--active-ex-p ring)))
+    (ert-info ("One active member returns t for active")
+      (ring-insert-at-beginning ring (make-erc-d-exchange :tag 'bar))
+      (should (erc-d--active-ex-p ring)))))
+
+(defun erc-d-tests--parse-message-upstream (raw)
+  "Hack shim for parsing RAW line recvd from peer."
+  (cl-letf (((symbol-function #'erc-handle-parsed-server-response)
+             (lambda (_ p) p)))
+    (let ((erc-active-buffer nil))
+      (erc-parse-server-response nil raw))))
+
+(ert-deftest erc-d-i--validate-tags ()
+  (should (erc-d-i--validate-tags
+           (concat "batch=4cc99692bf24a4bec4aa03da437364f5;"
+                   "time=2021-01-04T00:32:13.839Z")))
+  (should (erc-d-i--validate-tags "+foo=bar;baz=spam"))
+  (should (erc-d-i--validate-tags "foo=\\:ok;baz=\\s"))
+  (should (erc-d-i--validate-tags "foo=\303\247edilla"))
+  (should (erc-d-i--validate-tags "foo=\\"))
+  (should (erc-d-i--validate-tags "foo=bar\\baz"))
+  (should-error (erc-d-i--validate-tags "foo=\\\\;baz=\\\r\\\n"))
+  (should-error (erc-d-i--validate-tags "foo=\n"))
+  (should-error (erc-d-i--validate-tags "foo=\0ok"))
+  (should-error (erc-d-i--validate-tags "foo=bar baz"))
+  (should-error (erc-d-i--validate-tags "foo=bar\r"))
+  (should-error (erc-d-i--validate-tags "foo=bar;")))
+
+(ert-deftest erc-d-i--parse-message ()
+  (let* ((raw (concat "@time=2020-11-23T09:10:33.088Z "
+                      ":tilde.chat BATCH +1 chathistory :#meta"))
+         (upstream (erc-d-tests--parse-message-upstream raw))
+         (ours (erc-d-i--parse-message raw)))
+
+    (ert-info ("Baseline upstream")
+      (should (equal (erc-response.unparsed upstream) raw))
+      (should (equal (erc-response.sender upstream) "tilde.chat"))
+      (should (equal (erc-response.command upstream) "BATCH"))
+      (should (equal (erc-response.command-args upstream)
+                     '("+1" "chathistory" "#meta")))
+      (should (equal (erc-response.contents upstream) "#meta")))
+
+    (ert-info ("Ours my not compare cl-equalp but is otherwise the same")
+      (should (equal (erc-d-i-message.unparsed ours) raw))
+      (should (equal (erc-d-i-message.sender ours) "tilde.chat"))
+      (should (equal (erc-d-i-message.command ours) "BATCH"))
+      (should (equal (erc-d-i-message.command-args ours)
+                     '("+1" "chathistory" "#meta")))
+      (should (equal (erc-d-i-message.contents ours) "#meta"))
+      (should (equal (erc-d-i-message.tags ours)
+                     '((time . "2020-11-23T09:10:33.088Z")))))
+
+    (ert-info ("No compat decodes the whole message as utf-8")
+      (setq ours (erc-d-i--parse-message
+                  "@foo=\303\247edilla TAGMSG #ch\303\240n"
+                  'decode))
+      (should-not (erc-d-i-message.compat ours))
+      (should (equal (erc-d-i-message.command-args ours) '("#chàn")))
+      (should (equal (erc-d-i-message.contents ours) ""))
+      (should (equal (erc-d-i-message.tags ours) '((foo . "çedilla")))))))
+
+(ert-deftest erc-d-i--unescape-tag-value ()
+  (should (equal (erc-d-i--unescape-tag-value
+                  "\\sabc\\sdef\\s\\sxyz\\s")
+                 " abc def  xyz "))
+  (should (equal (erc-d-i--unescape-tag-value
+                  "\\\\abc\\\\def\\\\\\\\xyz\\\\")
+                 "\\abc\\def\\\\xyz\\"))
+  (should (equal (erc-d-i--unescape-tag-value "a\\bc") "abc"))
+  (should (equal (erc-d-i--unescape-tag-value
+                  "\\\\abc\\\\def\\\\\\\\xyz\\")
+                 "\\abc\\def\\\\xyz"))
+  (should (equal (erc-d-i--unescape-tag-value "a\\:b\\r\\nc\\sd")
+                 "a;b\r\nc d")))
+
+(ert-deftest erc-d-i--escape-tag-value ()
+  (should (equal (erc-d-i--escape-tag-value " abc def  xyz ")
+                 "\\sabc\\sdef\\s\\sxyz\\s"))
+  (should (equal (erc-d-i--escape-tag-value "\\abc\\def\\\\xyz\\")
+                 "\\\\abc\\\\def\\\\\\\\xyz\\\\"))
+  (should (equal (erc-d-i--escape-tag-value "a;b\r\nc d")
+                 "a\\:b\\r\\nc\\sd")))
+
+;; TODO add tests for msg-join, mask-match, userhost-split,
+;; validate-hostname
+
+(ert-deftest erc-d-i--parse-message--irc-parser-tests ()
+  (let* ((data (with-temp-buffer
+                 (insert-file-contents
+                  (expand-file-name "irc-parser-tests.eld"
+                                    (ert-resource-directory)))
+                 (read (current-buffer))))
+         (tests (assoc-default 'tests (assoc-default 'msg-split data)))
+         input atoms m ours)
+    (dolist (test tests)
+      (setq input (assoc-default 'input test)
+            atoms (assoc-default 'atoms test)
+            m (erc-d-i--parse-message input))
+      (ert-info ("Parses tags correctly")
+        (setq ours (erc-d-i-message.tags m))
+        (if-let ((tags (assoc-default 'tags atoms)))
+            (pcase-dolist (`(,key . ,value) ours)
+              (should (string= (cdr (assq key tags)) (or value ""))))
+          (should-not ours)))
+      (ert-info ("Parses verbs correctly")
+        (setq ours (erc-d-i-message.command m))
+        (if-let ((verbs (assoc-default 'verb atoms)))
+            (should (string= (downcase verbs) (downcase ours)))
+          (should (string-empty-p ours))))
+      (ert-info ("Parses sources correctly")
+        (setq ours (erc-d-i-message.sender m))
+        (if-let ((source (assoc-default 'source atoms)))
+            (should (string= source ours))
+          (should (string-empty-p ours))))
+      (ert-info ("Parses params correctly")
+        (setq ours (erc-d-i-message.command-args m))
+        (if-let ((params (assoc-default 'params atoms)))
+            (should (equal ours params))
+          (should-not ours))))))
+
+(defun erc-d-tests--new-ex (existing raw-hunk)
+  (let* ((f (lambda (_) (pop raw-hunk)))
+         (sd (make-erc-d-u-scan-d :f f)))
+    (setf (erc-d-exchange-hunk existing) (make-erc-d-u-scan-e :sd sd)
+          (erc-d-exchange-spec existing) (make-erc-d-spec)))
+  (erc-d--iter existing))
+
+(ert-deftest erc-d--render-entries ()
+  (let* ((erc-nick "foo")
+         (dialog (make-erc-d-dialog :vars `((:a . 1)
+                                            (c . ((a b) (: a space b)))
+                                            (d . (c alpha digit))
+                                            (bee . 2)
+                                            (f . ,(lambda () "3"))
+                                            (i . erc-nick))))
+         (exchange (make-erc-d-exchange :dialog dialog))
+         (mex (apply-partially #'erc-d-tests--new-ex exchange))
+         it)
+
+    (erc-d-exchange-reload dialog exchange)
+
+    (ert-info ("Baseline Outgoing")
+      (setq it (funcall mex '((0 "abc"))))
+      (should (equal (funcall it) 0))
+      (should (equal (funcall it) "abc")))
+
+    (ert-info ("Incoming are regexp escaped")
+      (setq it (funcall mex '((i 0.0 "fsf" ".org"))))
+      (should (equal (cons (funcall it) (funcall it)) '(i . 0.0)))
+      (should (equal (funcall it) "\\`fsf\\.org")))
+
+    (ert-info ("Incoming can access vars via rx-let")
+      (setq it (funcall mex '((i 0.0 bee))))
+      (should (equal (cons (funcall it) (funcall it)) '(i . 0.0)))
+      (should (equal (funcall it) "\\`\002")))
+
+    (ert-info ("Incoming rx-let params")
+      (setq it (funcall mex '((i 0.0 d))))
+      (should (equal (cons (funcall it) (funcall it)) '(i . 0.0)))
+      (should (equal (funcall it) "\\`[[:alpha:]][[:space:]][[:digit:]]")))
+
+    (ert-info ("Incoming literal rx forms")
+      (setq it (funcall mex '((i 0.0 (= 3 alpha) ".org"))))
+      (should (equal (cons (funcall it) (funcall it)) '(i . 0.0)))
+      (should (equal (funcall it) "\\`[[:alpha:]]\\{3\\}\\.org")))
+
+    (ert-info ("Self-quoting disallowed")
+      (setq it (funcall mex '((0 :a "abc"))))
+      (should (equal (funcall it) 0))
+      (should-error (funcall it)))
+
+    (ert-info ("Global vars and short vars")
+      (setq it (funcall mex '((0 i f erc-nick))))
+      (should (equal (funcall it) 0))
+      (should (equal (funcall it) "foo3foo")))
+
+    (ert-info ("Exits clean")
+      (when (listp (alist-get 'f (erc-d-dialog-vars dialog))) ; may be compiled
+        (should (eq 'closure (car (alist-get 'f (erc-d-dialog-vars dialog))))))
+      (should-not (funcall it))
+      (should (equal (erc-d-dialog-vars dialog)
+                     `((:a . 1)
+                       (c . ((a b) (: a space b)))
+                       (d . (c alpha digit))
+                       (bee . 2)
+                       (f . ,(alist-get 'f (erc-d-dialog-vars dialog)))
+                       (i . erc-nick)))))))
+
+(ert-deftest erc-d--render-entries--matches ()
+  (let* ((alist (list
+                 (cons 'f (lambda (a) (funcall a :match 1)))
+                 (cons 'g (lambda () (match-string 2 "foo bar baz")))
+                 (cons 'h (lambda (a) (concat (funcall a :match 0)
+                                              (funcall a :request))))
+                 (cons 'i (lambda (_ e) (erc-d-exchange-request e)))
+                 (cons 'j (lambda ()
+                            (set-match-data '(0 1))
+                            (match-string 0 "j")))))
+         (dialog (make-erc-d-dialog :vars alist))
+         (exchange (make-erc-d-exchange :dialog dialog
+                                        :request "foo bar baz"
+                                        ;;            11  222
+                                        :match-data '(4 11 4 6 8 11)))
+         (mex (apply-partially #'erc-d-tests--new-ex exchange))
+         it)
+
+    (erc-d-exchange-reload dialog exchange)
+
+    (ert-info ("One arg, match")
+      (setq it (funcall mex '((0 f))))
+      (should (equal (funcall it) 0))
+      (should (equal (funcall it) "ba")))
+
+    (ert-info ("No args")
+      (setq it (funcall mex '((0 g))))
+      (should (equal (funcall it) 0))
+      (should (equal (funcall it) "baz")))
+
+    (ert-info ("Second arg is exchange object")
+      (setq it (funcall mex '((0 i))))
+      (should (equal (funcall it) 0))
+      (should (equal (funcall it) "foo bar baz")))
+
+    (ert-info ("One arg, multiple calls")
+      (setq it (funcall mex '((0 h))))
+      (should (equal (funcall it) 0))
+      (should (equal (funcall it) "bar bazfoo bar baz")))
+
+    (ert-info ("Match data restored")
+      (setq it (funcall mex '((0 j))))
+      (should (equal (funcall it) 0))
+      (should (equal (funcall it) "j"))
+
+      (setq it (funcall mex '((0 g))))
+      (should (equal (funcall it) 0))
+      (should (equal (funcall it) "baz")))
+
+    (ert-info ("Bad signature")
+      (let ((qlist (list 'f '(lambda (p q x) (ignore)))))
+        (setf (erc-d-dialog-vars dialog) qlist)
+        (should-error (erc-d-exchange-reload dialog exchange))))))
+
+(ert-deftest erc-d--render-entries--dynamic ()
+  (let* ((alist (list
+                 (cons 'foo "foo")
+                 (cons 'f (lambda (a) (funcall a :get-binding 'foo)))
+                 (cons 'h (lambda (a) (upcase (funcall a :get-var 'foo))))
+                 (cons 'g (lambda (a)
+                            (funcall a :rebind 'g (funcall a :get-var 'f))
+                            "bar"))
+                 (cons 'j (lambda (a) (funcall a :set "123") "abc"))
+                 (cons 'k (lambda () "abc"))))
+         (dialog (make-erc-d-dialog :vars alist))
+         (exchange (make-erc-d-exchange :dialog dialog))
+         (mex (apply-partially #'erc-d-tests--new-ex exchange))
+         it)
+
+    (erc-d-exchange-reload dialog exchange)
+
+    (ert-info ("Initial reference calls function")
+      (setq it (funcall mex '((0 j) (0 j))))
+      (should (equal (funcall it) 0))
+      (should (equal (funcall it) "abc")))
+
+    (ert-info ("Subsequent reference expands to string")
+      (should (equal (funcall it) 0))
+      (should (equal (funcall it) "123")))
+
+    (ert-info ("Outside manipulation: initial reference calls function")
+      (setq it (funcall mex '((0 k) (0 k))))
+      (should (equal (funcall it) 0))
+      (should (equal (funcall it) "abc")))
+
+    (ert-info ("Outside manipulation: subsequent reference expands to string")
+      (erc-d-exchange-rebind dialog exchange 'k "123")
+      (should (equal (funcall it) 0))
+      (should (equal (funcall it) "123")))
+
+    (ert-info ("Swap one function for another")
+      (setq it (funcall mex '((0 g) (0 g))))
+      (should (equal (funcall it) 0))
+      (should (equal (funcall it) "bar"))
+      (should (equal (funcall it) 0))
+      (should (equal (funcall it) "foo")))
+
+    (ert-info ("Bindings accessible inside functions")
+      (setq it (funcall mex '((0 f h))))
+      (should (equal (funcall it) 0))
+      (should (equal (funcall it) "fooFOO")))
+
+    (ert-info ("Rebuild alist by sending flag")
+      (setq it (funcall mex '((0 f) (1 f) (2 f) (i 3 f))))
+      (should (equal (funcall it) 0))
+      (should (equal (funcall it) "foo"))
+      (erc-d-exchange-rebind dialog exchange 'f "bar")
+      (should (equal (funcall it) 1))
+      (should (equal (funcall it) "bar"))
+      (setq alist (setf (alist-get 'f (erc-d-dialog-vars dialog))
+                        (lambda nil "baz")))
+      (should (eq (funcall it) 2))
+      (should (equal (funcall it 'reload) "baz"))
+      (setq alist (setf (alist-get 'f (erc-d-dialog-vars dialog)) "spam"))
+      (should (eq (funcall it) 'i))
+      (should (eq (funcall it 'reload) 3))
+      (should (equal (funcall it) "\\`spam")))))
+
+(ert-deftest erc-d-t-with-cleanup ()
+  (should-not (get-buffer "*echo*"))
+  (should-not (get-buffer "*foo*"))
+  (should-not (get-buffer "*bar*"))
+  (should-not (get-buffer "*baz*"))
+  (erc-d-t-with-cleanup
+      ((echo (start-process "echo" (get-buffer-create "*echo*") "sleep" "1"))
+       (buffer-foo (get-buffer-create "*foo*"))
+       (buffer-bar (get-buffer-create "*bar*"))
+       (clean-up (list (intern (process-name echo)))) ; let*
+       buffer-baz)
+      (ert-info ("Clean Up")
+        (should (equal clean-up '(ran echo)))
+        (should (bufferp buffer-baz))
+        (should (bufferp buffer-foo))
+        (setq buffer-foo nil))
+    (setq buffer-baz (get-buffer-create "*baz*"))
+    (push 'ran clean-up))
+  (ert-info ("Buffers and procs destroyed")
+    (should-not (get-buffer "*echo*"))
+    (should-not (get-buffer "*bar*"))
+    (should-not (get-buffer "*baz*")))
+  (ert-info ("Buffer foo spared")
+    (should (get-buffer "*foo*"))
+    (kill-buffer "*foo*")))
+
+(ert-deftest erc-d-t-wait-for ()
+  :tags '(:unstable)
+  (let (v)
+    (run-at-time 0.2 nil (lambda () (setq v t)))
+    (should (erc-d-t-wait-for 0.4 "result becomes non-nil" v))
+    (should-error (erc-d-t-wait-for 0.4 "result stays nil" (not v)))
+    (setq v nil)
+    (should-not (erc-d-t-wait-for -0.4 "inverted stays nil" v))
+    (run-at-time 0.2 nil (lambda () (setq v t)))
+    (setq v nil)
+    (should-error (erc-d-t-wait-for -0.4 "inverted becomes non-nil" v))))
+
+(defvar erc-d-tests-with-server-password "changeme")
+
+;; Compromise between removing `autojoin' from `erc-modules' entirely
+;; and allowing side effects to meddle excessively
+(defvar erc-autojoin-channels-alist)
+
+;; This is only meant to be used by tests in this file.
+(cl-defmacro erc-d-tests-with-server ((dumb-server-var erc-server-buffer-var)
+                                      dialog &rest body)
+  "Create server for DIALOG and run BODY.
+DIALOG may also be a list of dialogs.  ERC-SERVER-BUFFER-VAR and
+DUMB-SERVER-VAR are bound accordingly in BODY."
+  (declare (indent 2))
+  (when (eq '_ dumb-server-var)
+    (setq dumb-server-var (make-symbol "dumb-server-var")))
+  (when (eq '_ erc-server-buffer-var)
+    (setq erc-server-buffer-var (make-symbol "erc-server-buffer-var")))
+  (if (listp dialog)
+      (setq dialog (mapcar (lambda (f) (list 'quote f)) dialog))
+    (setq dialog `((quote ,dialog))))
+  `(let* (auth-source-do-cache
+          (,dumb-server-var (erc-d-run "localhost" t ,@dialog))
+          ,erc-server-buffer-var
+          ;;
+          (erc-server-flood-penalty 0.05)
+          erc-autojoin-channels-alist
+          erc-server-auto-reconnect)
+     (should-not erc-d--slow-mo)
+     (with-current-buffer "*erc-d-server*" (erc-d-t-search-for 4 "Starting"))
+     ;; Allow important messages through, even in -batch mode.
+     (advice-add #'erc-handle-login :around #'erc-d-t-silence-around)
+     (advice-add #'erc-server-connect :around #'erc-d-t-silence-around)
+     (unless (or noninteractive erc-debug-irc-protocol)
+       (erc-toggle-debug-irc-protocol))
+     (setq ,erc-server-buffer-var
+           (erc :server "localhost"
+                :password erc-d-tests-with-server-password
+                :port (process-contact ,dumb-server-var :service)
+                :nick "tester"
+                :full-name "tester"))
+     (unwind-protect
+         (progn
+           ,@body
+           (erc-d-t-wait-for 1 "dumb-server death"
+             (not (process-live-p ,dumb-server-var))))
+       (when (process-live-p erc-server-process)
+         (delete-process erc-server-process))
+       (advice-remove #'erc-handle-login #'erc-d-t-silence-around)
+       (advice-remove #'erc-server-connect #'erc-d-t-silence-around)
+       (when noninteractive
+         (kill-buffer ,erc-server-buffer-var)
+         (erc-d-t-kill-related-buffers)))))
+
+(defmacro erc-d-tests-with-failure-spy (found func-syms &rest body)
+  "Wrap functions with advice for inspecting errors caused by BODY.
+Do this for functions whose names appear in FUNC-SYMS.  When running
+advice code, add errors to list FOUND.  Note: the teardown finalizer is
+not added by default.  Also, `erc-d-linger-secs' likely has to be
+nonzero for this to work."
+  (declare (indent 2))
+  ;; Catch errors thrown by timers that `should-error'ignores
+  `(progn
+     (let ((ad (lambda (f o &rest r)
+                 (condition-case err
+                     (apply o r)
+                   (error (push err ,found)
+                          (advice-remove f 'spy))))))
+       (dolist (sym ,func-syms)
+         (advice-add sym :around (apply-partially ad sym) '((name . spy)))))
+     (progn ,@body)
+     (dolist (sym ,func-syms)
+       (advice-remove sym 'spy))
+     (setq ,found (nreverse ,found))))
+
+(ert-deftest erc-d-run-nonstandard-messages ()
+  :tags '(:expensive-test)
+  (let* ((erc-d-linger-secs 0.2)
+         (dumb-server (erc-d-run "localhost" t 'nonstandard))
+         (dumb-server-buffer (get-buffer "*erc-d-server*"))
+         (expect (erc-d-t-make-expecter))
+         client)
+    (with-current-buffer "*erc-d-server*" (erc-d-t-search-for 4 "Starting"))
+    (setq client (open-network-stream "erc-d-client" nil
+                                      "localhost"
+                                      (process-contact dumb-server :service)
+                                      :coding 'binary))
+    (ert-info ("Server splits CRLF delimited lines")
+      (process-send-string client "ONE one\r\nTWO two\r\n")
+      (with-current-buffer dumb-server-buffer
+        (funcall expect 1 '(: "<- nonstandard:" (+ digit) " ONE one" eol))
+        (funcall expect 1 '(regex "<- nonstandard:[[:digit:]]+ TWO two$"))))
+    (ert-info ("Server doesn't discard empty lines")
+      (process-send-string client "\r\n")
+      (with-current-buffer dumb-server-buffer
+        (funcall expect 1 '(regex "<- nonstandard:[[:digit:]]+ $"))))
+    (ert-info ("Server preserves spaces")
+      (process-send-string client " \r\n")
+      (with-current-buffer dumb-server-buffer
+        (funcall expect 1 '(regex "<- nonstandard:[[:digit:]]+ \\{2\\}$")))
+      (process-send-string client "  \r\n")
+      (with-current-buffer dumb-server-buffer
+        (funcall expect 1 '(regex "<- nonstandard:[[:digit:]]+ \\{3\\}$"))))
+    (erc-d-t-wait-for 3 "dumb-server death"
+      (not (process-live-p dumb-server)))
+    (delete-process client)
+    (when noninteractive
+      (kill-buffer dumb-server-buffer))))
+
+(ert-deftest erc-d-run-basic ()
+  :tags '(:expensive-test)
+  (erc-d-tests-with-server (_ _) basic
+    (with-current-buffer (erc-d-t-wait-for 3 (get-buffer "#chan"))
+      (erc-d-t-search-for 2 "hey"))
+    (when noninteractive
+      (kill-buffer "#chan"))))
+
+(ert-deftest erc-d-run-eof ()
+  :tags '(:expensive-test)
+  (skip-unless noninteractive)
+  (erc-d-tests-with-server (_ erc-s-buf) eof
+    (with-current-buffer (erc-d-t-wait-for 3 (get-buffer "#chan"))
+      (erc-d-t-search-for 2 "hey"))
+    (with-current-buffer erc-s-buf
+      (process-send-eof erc-server-process))))
+
+(ert-deftest erc-d-run-eof-fail ()
+  :tags '(:expensive-test)
+  (let (errors)
+    (erc-d-tests-with-failure-spy errors '(erc-d--teardown)
+      (erc-d-tests-with-server (_ _) eof
+        (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan"))
+          (erc-d-t-search-for 2 "hey"))
+        (erc-d-t-wait-for 10 errors)))
+    (should (string-match-p "Timed out awaiting request.*__EOF__"
+                            (cadr (pop errors))))))
+
+(ert-deftest erc-d-run-linger ()
+  :tags '(:expensive-test)
+  (erc-d-tests-with-server (dumb-s _) linger
+    (with-current-buffer (erc-d-t-wait-for 6 (get-buffer "#chan"))
+      (erc-d-t-search-for 2 "hey"))
+    (with-current-buffer (process-buffer dumb-s)
+      (erc-d-t-search-for 2 "Lingering for 1.00 seconds"))
+    (with-current-buffer (process-buffer dumb-s)
+      (erc-d-t-search-for 3 "Lingered for 1.00 seconds"))))
+
+(ert-deftest erc-d-run-linger-fail ()
+  :tags '(:expensive-test)
+  (let ((erc-server-flood-penalty 0.1)
+        errors)
+    (erc-d-tests-with-failure-spy
+        errors '(erc-d--teardown erc-d-command)
+      (erc-d-tests-with-server (_ _) linger
+        (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan"))
+          (erc-d-t-search-for 2 "hey")
+          (erc-cmd-MSG "#chan hi"))
+        (erc-d-t-wait-for 10 "Bad match" errors)))
+    (should (string-match-p "Match failed.*hi" (cadr (pop errors))))))
+
+(ert-deftest erc-d-run-linger-direct ()
+  :tags '(:expensive-test)
+  (let* ((dumb-server (erc-d-run "localhost" t
+                                 'linger-multi-a 'linger-multi-b))
+         (port (process-contact dumb-server :service))
+         (dumb-server-buffer (get-buffer "*erc-d-server*"))
+         (client-buffer-a (get-buffer-create "*erc-d-client-a*"))
+         (client-buffer-b (get-buffer-create "*erc-d-client-b*"))
+         (start (current-time))
+         client-a client-b)
+    (with-current-buffer "*erc-d-server*" (erc-d-t-search-for 4 "Starting"))
+    (setq client-a (open-network-stream "erc-d-client-a" client-buffer-a
+                                        "localhost" port
+                                        :coding 'binary)
+          client-b (open-network-stream "erc-d-client-b" client-buffer-b
+                                        "localhost" port
+                                        :coding 'binary))
+    (process-send-string client-a "PASS :a\r\n")
+    (sleep-for 0.01)
+    (process-send-string client-b "PASS :b\r\n")
+    (sleep-for 0.01)
+    (erc-d-t-wait-for 3 "dumb-server death"
+      (not (process-live-p dumb-server)))
+    (ert-info ("Ensure linger of one second")
+      (should (time-less-p 1 (time-subtract (current-time) start)))
+      (should (time-less-p (time-subtract (current-time) start) 1.5)))
+    (delete-process client-a)
+    (delete-process client-b)
+    (when noninteractive
+      (kill-buffer client-buffer-a)
+      (kill-buffer client-buffer-b)
+      (kill-buffer dumb-server-buffer))))
+
+(ert-deftest erc-d-run-drop-direct ()
+  :tags '(:unstable)
+  (let* ((dumb-server (erc-d-run "localhost" t 'drop-a 'drop-b))
+         (port (process-contact dumb-server :service))
+         (dumb-server-buffer (get-buffer "*erc-d-server*"))
+         (client-buffer-a (get-buffer-create "*erc-d-client-a*"))
+         (client-buffer-b (get-buffer-create "*erc-d-client-b*"))
+         (start (current-time))
+         client-a client-b)
+    (with-current-buffer "*erc-d-server*" (erc-d-t-search-for 4 "Starting"))
+    (setq client-a (open-network-stream "erc-d-client-a" client-buffer-a
+                                        "localhost" port
+                                        :coding 'binary)
+          client-b (open-network-stream "erc-d-client-b" client-buffer-b
+                                        "localhost" port
+                                        :coding 'binary))
+    (process-send-string client-a "PASS :a\r\n")
+    (sleep-for 0.01)
+    (process-send-string client-b "PASS :b\r\n")
+    (erc-d-t-wait-for 3 "client-a dies" (not (process-live-p client-a)))
+    (should (time-less-p (time-subtract (current-time) start) 0.32))
+    (erc-d-t-wait-for 3 "dumb-server death"
+      (not (process-live-p dumb-server)))
+    (ert-info ("Ensure linger of one second")
+      (should (time-less-p 1 (time-subtract (current-time) start))))
+    (delete-process client-a)
+    (delete-process client-b)
+    (when noninteractive
+      (kill-buffer client-buffer-a)
+      (kill-buffer client-buffer-b)
+      (kill-buffer dumb-server-buffer))))
+
+(ert-deftest erc-d-run-no-match ()
+  :tags '(:expensive-test)
+  (let ((erc-d-linger-secs 1)
+        erc-server-auto-reconnect
+        errors)
+    (erc-d-tests-with-failure-spy errors '(erc-d--teardown erc-d-command)
+      (erc-d-tests-with-server (_ erc-server-buffer) no-match
+        (with-current-buffer erc-server-buffer
+          (erc-d-t-search-for 2 "away")
+          (erc-cmd-JOIN "#foo")
+          (erc-d-t-wait-for 10 "Bad match" errors))))
+    (should (string-match-p "Match failed.*foo.*chan" (cadr (pop errors))))
+    (should-not (get-buffer "#foo"))))
+
+(ert-deftest erc-d-run-timeout ()
+  :tags '(:expensive-test)
+  (let ((erc-d-linger-secs 1)
+        err errors)
+    (erc-d-tests-with-failure-spy errors '(erc-d--teardown)
+      (erc-d-tests-with-server (_ _) timeout
+        (erc-d-t-wait-for 10 "error caught" errors)))
+    (setq err (pop errors))
+    (should (eq (car err) 'erc-d-timeout))
+    (should (string-match-p "Timed out" (cadr err)))))
+
+(ert-deftest erc-d-run-unexpected ()
+  :tags '(:expensive-test)
+  (let ((erc-d-linger-secs 2)
+        errors)
+    (erc-d-tests-with-failure-spy
+        errors '(erc-d--teardown erc-d-command)
+      (erc-d-tests-with-server (_ _) unexpected
+        (ert-info ("All specs consumed when more input arrives")
+          (erc-d-t-wait-for 10 "error caught" (cdr errors)))))
+    (should (string-match-p "unexpected.*MODE" (cadr (pop errors))))
+    ;; Nonsensical normally because func would have already exited when
+    ;; first error was thrown
+    (should (string-match-p "Match failed" (cadr (pop errors))))))
+
+(ert-deftest erc-d-run-unexpected-depleted ()
+  :tags '(:expensive-test)
+  (let ((erc-d-linger-secs 3)
+        errors)
+    (erc-d-tests-with-failure-spy errors '(erc-d--teardown erc-d-command)
+      (let* ((dumb-server-buffer (get-buffer-create "*erc-d-server*"))
+             (dumb-server (erc-d-run "localhost" t 'depleted))
+             (expect (erc-d-t-make-expecter))
+             (client-buf (get-buffer-create "*erc-d-client*"))
+             client-proc)
+        (with-current-buffer dumb-server-buffer
+          (erc-d-t-search-for 3 "Starting"))
+        (setq client-proc (make-network-process
+                           :buffer client-buf
+                           :name "erc-d-client"
+                           :family 'ipv4
+                           :noquery t
+                           :coding 'binary
+                           :service (process-contact dumb-server :service)
+                           :host "localhost"))
+        (with-current-buffer dumb-server-buffer
+          (funcall expect 3 "open from"))
+        (process-send-string client-proc "PASS :changeme\r\n")
+        (sleep-for 0.01)
+        (process-send-string client-proc "NICK tester\r\n")
+        (sleep-for 0.01)
+        (process-send-string client-proc "USER user 0 * :tester\r\n")
+        (sleep-for 0.01)
+        (when (process-live-p client-proc)
+          (process-send-string client-proc "BLAH :too much\r\n")
+          (sleep-for 0.01))
+        (with-current-buffer client-buf
+          (funcall expect 3 "Welcome to the Internet"))
+        (erc-d-t-wait-for 2 "dumb-server death"
+          (not (process-live-p dumb-server)))
+        (delete-process client-proc)
+        (when noninteractive
+          (kill-buffer client-buf)
+          (kill-buffer dumb-server-buffer))))
+    (should (string-match-p "unexpected.*BLAH" (cadr (pop errors))))
+    ;; Wouldn't happen IRL
+    (should (string-match-p "unexpected.*BLAH" (cadr (pop errors))))
+    (should-not errors)))
+
+(defun erc-d-tests--dynamic-match-user (_dialog exchange)
+  "Shared pattern/response handler for canned dynamic DIALOG test."
+  (should (string= (match-string 1 (erc-d-exchange-request exchange))
+                   "tester")))
+
+(defun erc-d-tests--run-dynamic ()
+  "Perform common assertions for \"dynamic\" dialog."
+  (erc-d-tests-with-server (dumb-server erc-server-buffer) dynamic
+    (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan"))
+      (erc-d-t-search-for 2 "tester: hey"))
+    (with-current-buffer erc-server-buffer
+      (let ((expect (erc-d-t-make-expecter)))
+        (funcall expect 2 "host is irc.fsf.org")
+        (funcall expect 2 "modes for tester")))
+    (with-current-buffer (process-buffer dumb-server)
+      (erc-d-t-search-for 2 "irc.fsf.org"))
+    (when noninteractive
+      (kill-buffer "#chan"))))
+
+(ert-deftest erc-d-run-dynamic-default-match ()
+  :tags '(:expensive-test)
+  (let* (dynamic-tally
+         (erc-d-tmpl-vars '((user . "user")
+                            (ignored . ((a b) (: a space b)))
+                            (realname . (group (+ graph)))))
+         (nick (lambda (a)
+                 (push '(nick . match-user) dynamic-tally)
+                 (funcall a :set (funcall a :match 1) 'export)))
+         (dom (lambda (a)
+                (push '(dom . match-user) dynamic-tally)
+                (funcall a :set erc-d-server-fqdn)))
+         (erc-d-match-handlers
+          (list :user (lambda (d e)
+                        (erc-d-exchange-rebind d e 'nick nick)
+                        (erc-d-exchange-rebind d e 'dom dom)
+                        (erc-d-tests--dynamic-match-user d e))
+                :mode-user (lambda (d e)
+                             (erc-d-exchange-rebind d e 'nick "tester")
+                             (erc-d-exchange-rebind d e 'dom dom))))
+         (erc-d-server-fqdn "irc.fsf.org"))
+    (erc-d-tests--run-dynamic)
+    (should (equal '((dom . match-user) (nick . match-user) (dom . match-user))
+                   dynamic-tally))))
+
+(ert-deftest erc-d-run-dynamic-default-match-rebind ()
+  :tags '(:expensive-test)
+  (let* (tally
+         ;;
+         (erc-d-tmpl-vars '((user . "user")
+                            (ignored . ((a b) (: a space b)))
+                            (realname . (group (+ graph)))))
+         (erc-d-match-handlers
+          (list :user
+                (lambda (d e)
+                  (erc-d-exchange-rebind
+                   d e 'nick
+                   (lambda (a)
+                     (push 'bind-nick tally)
+                     (funcall a :rebind 'nick (funcall a :match 1) 'export)))
+                  (erc-d-exchange-rebind
+                   d e 'dom
+                   (lambda ()
+                     (push 'bind-dom tally)
+                     (erc-d-exchange-rebind d e 'dom erc-d-server-fqdn)))
+                  (erc-d-tests--dynamic-match-user d e))
+                :mode-user
+                (lambda (d e)
+                  (erc-d-exchange-rebind d e 'nick "tester")
+                  (erc-d-exchange-rebind d e 'dom erc-d-server-fqdn))))
+         (erc-d-server-fqdn "irc.fsf.org"))
+    (erc-d-tests--run-dynamic)
+    (should (equal '(bind-nick bind-dom) tally))))
+
+(ert-deftest erc-d-run-dynamic-runtime-stub ()
+  :tags '(:expensive-test)
+  (let ((erc-d-tmpl-vars '((token . (group (or "barnet" "foonet")))))
+        (erc-d-match-handlers
+         (list :pass (lambda (d _e)
+                       (erc-d-load-replacement-dialog d 'dynamic-foonet))))
+        (erc-d-tests-with-server-password "foonet:changeme"))
+    (erc-d-tests-with-server (_ erc-server-buffer)
+        (dynamic-stub dynamic-foonet)
+      (with-current-buffer (erc-d-t-wait-for 3 (get-buffer "#chan"))
+        (erc-d-t-search-for 2 "alice:")
+        (erc-d-t-absent-for 0.1 "joe"))
+      (with-current-buffer erc-server-buffer
+        (let ((expect (erc-d-t-make-expecter)))
+          (funcall expect 2 "host is irc.foonet.org")
+          (funcall expect 2 "NETWORK=FooNet")))
+      (when noninteractive
+        (kill-buffer "#chan")))))
+
+(ert-deftest erc-d-run-dynamic-runtime-stub-skip ()
+  :tags '(:expensive-test)
+  (let ((erc-d-tmpl-vars '((token . "barnet")))
+        (erc-d-match-handlers
+         (list :pass (lambda (d _e)
+                       (erc-d-load-replacement-dialog
+                        d 'dynamic-barnet 1))))
+        (erc-d-tests-with-server-password "barnet:changeme"))
+    (erc-d-tests-with-server (_ erc-server-buffer)
+        (dynamic-stub dynamic-barnet)
+      (with-current-buffer (erc-d-t-wait-for 3 (get-buffer "#chan"))
+        (erc-d-t-search-for 2 "joe:")
+        (erc-d-t-absent-for 0.1 "alice"))
+      (with-current-buffer erc-server-buffer
+        (let ((expect (erc-d-t-make-expecter)))
+          (funcall expect 2 "host is irc.barnet.org")
+          (funcall expect 2 "NETWORK=BarNet")))
+      (when noninteractive
+        (kill-buffer "#chan")))))
+
+;; Two servers, in-process, one client per
+(ert-deftest erc-d-run-dual-direct ()
+  :tags '(:expensive-test)
+  (let* ((erc-d--slow-mo -1)
+         (server-a (erc-d-run "localhost" t "erc-d-server-a" 'dynamic-foonet))
+         (server-b (erc-d-run "localhost" t "erc-d-server-b" 'dynamic-barnet))
+         (server-a-buffer (get-buffer "*erc-d-server-a*"))
+         (server-b-buffer (get-buffer "*erc-d-server-b*"))
+         (client-a-buffer (get-buffer-create "*erc-d-client-a*"))
+         (client-b-buffer (get-buffer-create "*erc-d-client-b*"))
+         client-a client-b)
+    (with-current-buffer server-a-buffer (erc-d-t-search-for 4 "Starting"))
+    (with-current-buffer server-b-buffer (erc-d-t-search-for 4 "Starting"))
+    (setq client-a (make-network-process
+                    :buffer client-a-buffer
+                    :name "erc-d-client-a"
+                    :family 'ipv4
+                    :noquery t
+                    :coding 'binary
+                    :service (process-contact server-a :service)
+                    :host "localhost")
+          client-b (make-network-process
+                    :buffer client-b-buffer
+                    :name "erc-d-client-b"
+                    :family 'ipv4
+                    :noquery t
+                    :coding 'binary
+                    :service (process-contact server-b :service)
+                    :host "localhost"))
+    ;; Also tests slo-mo indirectly because FAKE would fail without it
+    (process-send-string client-a "NICK tester\r\n")
+    (process-send-string client-b "FAKE noop\r\nNICK tester\r\n")
+    (sleep-for 0.01)
+    (process-send-string client-a "USER user 0 * :tester\r\n")
+    (process-send-string client-b "USER user 0 * :tester\r\n")
+    (sleep-for 0.01)
+    (process-send-string client-a "MODE tester +i\r\n")
+    (process-send-string client-b "MODE tester +i\r\n")
+    (sleep-for 0.01)
+    (process-send-string client-a "MODE #chan\r\n")
+    (process-send-string client-b "MODE #chan\r\n")
+    (sleep-for 0.01)
+    (erc-d-t-wait-for 2 "server-a death" (not (process-live-p server-a)))
+    (erc-d-t-wait-for 2 "server-b death" (not (process-live-p server-b)))
+    (when noninteractive
+      (kill-buffer client-a-buffer)
+      (kill-buffer client-b-buffer)
+      (kill-buffer server-a-buffer)
+      (kill-buffer server-b-buffer))))
+
+;; This can be removed; only exists to get a baseline for next test
+(ert-deftest erc-d-run-fuzzy-direct ()
+  :tags '(:expensive-test)
+  (let* ((erc-d-tmpl-vars
+          `((now . ,(lambda () (format-time-string "%FT%T.%3NZ" nil t)))))
+         (dumb-server (erc-d-run "localhost" t 'fuzzy))
+         (dumb-server-buffer (get-buffer "*erc-d-server*"))
+         (client-buffer (get-buffer-create "*erc-d-client*"))
+         client)
+    (with-current-buffer "*erc-d-server*" (erc-d-t-search-for 4 "Starting"))
+    (setq client (make-network-process
+                  :buffer client-buffer
+                  :name "erc-d-client"
+                  :family 'ipv4
+                  :noquery t
+                  :coding 'binary
+                  :service (process-contact dumb-server :service)
+                  :host "localhost"))
+    ;; We could also just send this as a single fatty
+    (process-send-string client "PASS :changeme\r\n")
+    (sleep-for 0.01)
+    (process-send-string client "NICK tester\r\n")
+    (sleep-for 0.01)
+    (process-send-string client "USER user 0 * :tester\r\n")
+    (sleep-for 0.01)
+    (process-send-string client "MODE tester +i\r\n")
+    (sleep-for 0.01)
+    (process-send-string client "JOIN #bar\r\n")
+    (sleep-for 0.01)
+    (process-send-string client "JOIN #foo\r\n")
+    (sleep-for 0.01)
+    (process-send-string client "MODE #bar\r\n")
+    (sleep-for 0.01)
+    (process-send-string client "MODE #foo\r\n")
+    (sleep-for 0.01)
+    (erc-d-t-wait-for 1 "dumb-server death"
+      (not (process-live-p dumb-server)))
+    (when noninteractive
+      (kill-buffer client-buffer)
+      (kill-buffer dumb-server-buffer))))
+
+;; Without adjusting penalty, takes ~15 secs. With is comparable to direct ^.
+(ert-deftest erc-d-run-fuzzy ()
+  :tags '(:expensive-test)
+  (let ((erc-server-flood-penalty 1.2) ; penalty < margin/sends is basically 0
+        (erc-d-linger-secs 0.1)
+        (erc-d-tmpl-vars
+         `((now . ,(lambda () (format-time-string "%FT%T.%3NZ" nil t)))))
+        erc-server-auto-reconnect)
+    (erc-d-tests-with-server (_ erc-server-buffer) fuzzy
+      (with-current-buffer erc-server-buffer
+        (erc-d-t-search-for 2 "away")
+        (goto-char erc-input-marker)
+        (erc-cmd-JOIN "#bar"))
+      (erc-d-t-wait-for 2 (get-buffer "#bar"))
+      (with-current-buffer erc-server-buffer
+        (erc-cmd-JOIN "#foo"))
+      (erc-d-t-wait-for 20 (get-buffer "#foo"))
+      (with-current-buffer "#bar"
+        (erc-d-t-search-for 1 "was created on"))
+      (with-current-buffer "#foo"
+        (erc-d-t-search-for 5 "was created on")))))
+
+(ert-deftest erc-d-run-no-block ()
+  :tags '(:expensive-test)
+  (let ((erc-server-flood-penalty 1)
+        (erc-d-linger-secs 1.2)
+        (expect (erc-d-t-make-expecter))
+        erc-server-auto-reconnect)
+    (erc-d-tests-with-server (_ erc-server-buffer) no-block
+      (with-current-buffer erc-server-buffer
+        (funcall expect 2 "away")
+        (funcall expect 1 erc-prompt)
+        (with-current-buffer erc-server-buffer (erc-cmd-JOIN "#foo")))
+      (with-current-buffer (erc-d-t-wait-for 2 (get-buffer "#foo"))
+        (funcall expect 2 "was created on"))
+
+      (ert-info ("Join #bar")
+        (with-current-buffer erc-server-buffer (erc-cmd-JOIN "#bar"))
+        (erc-d-t-wait-for 2 (get-buffer "#bar")))
+
+      (with-current-buffer "#bar" (funcall expect 1 "was created on"))
+
+      (ert-info ("Server expects next pattern but keeps sending")
+        (with-current-buffer "#foo" (funcall expect 2 "Rosalind, I will "))
+        (with-current-buffer "#bar" (funcall expect 1 "hi 123"))
+        (with-current-buffer "#foo"
+          (should-not (search-forward "<bob> I am heard" nil t))
+          (funcall expect 1.5 "<bob> I am heard"))))))
+
+(defun erc-d-tests--run-proxy-direct (dumb-server dumb-server-buffer port)
+  "Start DUMB-SERVER with DUMB-SERVER-BUFFER and PORT.
+These are steps shared by in-proc and subproc variants testing a
+bouncer-like setup."
+  (when (version< emacs-version "28") (ert-skip "TODO connection refused"))
+  (let ((client-buffer-foo (get-buffer-create "*erc-d-client-foo*"))
+        (client-buffer-bar (get-buffer-create "*erc-d-client-bar*"))
+        (expect (erc-d-t-make-expecter))
+        client-foo
+        client-bar)
+    (setq client-foo (make-network-process
+                      :buffer client-buffer-foo
+                      :name "erc-d-client-foo"
+                      :family 'ipv4
+                      :noquery t
+                      :coding 'binary
+                      :service port
+                      :host "localhost")
+          client-bar (make-network-process
+                      :buffer client-buffer-bar
+                      :name "erc-d-client-bar"
+                      :family 'ipv4
+                      :noquery t
+                      :coding 'binary
+                      :service port
+                      :host "localhost"))
+    (with-current-buffer dumb-server-buffer
+      (funcall expect 3 "open from"))
+    (process-send-string client-foo "PASS :foo:changeme\r\n")
+    (process-send-string client-bar "PASS :bar:changeme\r\n")
+    (sleep-for 0.01)
+    (process-send-string client-foo "NICK tester\r\n")
+    (process-send-string client-bar "NICK tester\r\n")
+    (sleep-for 0.01)
+    (process-send-string client-foo "USER user 0 * :tester\r\n")
+    (process-send-string client-bar "USER user 0 * :tester\r\n")
+    (sleep-for 0.01)
+    (process-send-string client-foo "MODE tester +i\r\n")
+    (process-send-string client-bar "MODE tester +i\r\n")
+    (sleep-for 0.01)
+    (with-current-buffer client-buffer-foo
+      (funcall expect 3 "FooNet")
+      (funcall expect 3 "irc.foo.net")
+      (funcall expect 3 "marked as being away")
+      (goto-char (point-min))
+      (should-not (search-forward "bar" nil t)))
+    (with-current-buffer client-buffer-bar
+      (funcall expect 3 "BarNet")
+      (funcall expect 3 "irc.bar.net")
+      (funcall expect 3 "marked as being away")
+      (goto-char (point-min))
+      (should-not (search-forward "foo" nil t)))
+    (erc-d-t-wait-for 2 "dumb-server death"
+      (not (process-live-p dumb-server)))
+    (delete-process client-foo)
+    (delete-process client-bar)
+    (when noninteractive
+      (kill-buffer client-buffer-foo)
+      (kill-buffer client-buffer-bar)
+      (kill-buffer dumb-server-buffer))))
+
+;; This test shows the simplest way to set up template variables: put
+;; everything needed for the whole session in `erc-d-tmpl-vars' before
+;; starting the server.
+
+(ert-deftest erc-d-run-proxy-direct-spec-vars ()
+  :tags '(:expensive-test)
+  (let* ((dumb-server-buffer (get-buffer-create "*erc-d-server*"))
+         (erc-d-linger-secs 0.5)
+         (erc-d-tmpl-vars
+          `((network . (group (+ alpha)))
+            (fqdn . ,(lambda (a)
+                       (let ((network (funcall a :match 1 'pass)))
+                         (should (member network '("foo" "bar")))
+                         (funcall a :set (concat "irc." network ".net")))))
+            (net . ,(lambda (a)
+                      (let ((network (funcall a :match 1 'pass)))
+                        (should (member network '("foo" "bar")))
+                        (concat (capitalize network) "Net"))))))
+         (dumb-server (erc-d-run "localhost" t 'proxy-foonet 'proxy-barnet))
+         (port (process-contact dumb-server :service)))
+    (with-current-buffer dumb-server-buffer
+      (erc-d-t-search-for 3 "Starting"))
+    (erc-d-tests--run-proxy-direct dumb-server dumb-server-buffer port)))
+
+(cl-defun erc-d-tests--start-server (&key dialogs buffer linger program libs)
+  "Start and return a server in a subprocess using BUFFER and PORT.
+DIALOGS are symbols representing the base names of dialog files in
+`erc-d-u-canned-dialog-dir'.  LIBS are extra files to load."
+  (push (locate-library "erc-d" nil (list erc-d-u--library-directory)) libs)
+  (cl-assert (car libs))
+  (let* ((args `("erc-d-server" ,buffer
+                 ,(concat invocation-directory invocation-name)
+                 "-Q" "-batch" "-L" ,erc-d-u--library-directory
+                 ,@(let (o) (while libs (push (pop libs) o) (push "-l" o)) o)
+                 "-eval" ,(format "%S" program) "-f" "erc-d-serve"
+                 ,@(when linger (list "--linger" (number-to-string linger)))
+                 ,@(mapcar #'erc-d-u--expand-dialog-symbol dialogs)))
+         (proc (apply #'start-process args)))
+    (set-process-query-on-exit-flag proc nil)
+    (with-current-buffer buffer
+      (erc-d-t-search-for 5 "Starting")
+      (search-forward " (")
+      (backward-char))
+    (let ((pair (read buffer)))
+      (cons proc (cdr pair)))))
+
+(ert-deftest erc-d-run-proxy-direct-subprocess ()
+  :tags '(:expensive-test)
+  (let* ((buffer (get-buffer-create "*erc-d-server*"))
+         ;; These are quoted because they're passed as printed forms to subproc
+         (fqdn '(lambda (a e)
+                  (let* ((d (erc-d-exchange-dialog e))
+                         (name (erc-d-dialog-name d)))
+                    (funcall a :set (if (eq name 'proxy-foonet)
+                                        "irc.foo.net"
+                                      "irc.bar.net")))))
+         (net '(lambda (a)
+                 (funcall a :rebind 'net
+                          (if (eq (funcall a :dialog-name) 'proxy-foonet)
+                              "FooNet"
+                            "BarNet"))))
+         (program `(setq erc-d-tmpl-vars '((fqdn . ,fqdn)
+                                           (net . ,net)
+                                           (network . (group (+ alpha))))))
+         (port (erc-d-tests--start-server
+                :linger 0.3
+                :program program
+                :buffer buffer
+                :dialogs '(proxy-foonet proxy-barnet)))
+         (server (pop port)))
+    (erc-d-tests--run-proxy-direct server buffer port)))
+
+(ert-deftest erc-d-run-proxy-direct-subprocess-lib ()
+  :tags '(:expensive-test)
+  (let* ((buffer (get-buffer-create "*erc-d-server*"))
+         (lib (expand-file-name "proxy-subprocess.el"
+                                (ert-resource-directory)))
+         (port (erc-d-tests--start-server :linger 0.3
+                                          :buffer buffer
+                                          :dialogs '(proxy-foonet proxy-barnet)
+                                          :libs (list lib)))
+         (server (pop port)))
+    (erc-d-tests--run-proxy-direct server buffer port)))
+
+(ert-deftest erc-d-run-no-pong ()
+  :tags '(:expensive-test)
+  (let* (erc-d-auto-pong
+         ;;
+         (erc-d-tmpl-vars
+          `((nonce . (group (: digit digit)))
+            (echo . ,(lambda (a)
+                       (should (string= (funcall a :match 1) "42")) "42"))))
+         (dumb-server-buffer (get-buffer-create "*erc-d-server*"))
+         (dumb-server (erc-d-run "localhost" t 'no-pong))
+         (expect (erc-d-t-make-expecter))
+         (client-buf (get-buffer-create "*erc-d-client*"))
+         client-proc)
+    (with-current-buffer dumb-server-buffer
+      (erc-d-t-search-for 3 "Starting"))
+    (setq client-proc (make-network-process
+                       :buffer client-buf
+                       :name "erc-d-client"
+                       :family 'ipv4
+                       :noquery t
+                       :coding 'binary
+                       :service (process-contact dumb-server :service)
+                       :host "localhost"))
+    (with-current-buffer dumb-server-buffer
+      (funcall expect 3 "open from"))
+    (process-send-string client-proc "PASS :changeme\r\nNICK tester\r\n")
+    (sleep-for 0.01)
+    (process-send-string client-proc "USER user 0 * :tester\r\n")
+    (sleep-for 0.01)
+    (process-send-string client-proc "MODE tester +i\r\n")
+    (sleep-for 0.01)
+    (with-current-buffer client-buf
+      (funcall expect 3 "ExampleOrg")
+      (funcall expect 3 "irc.example.org")
+      (funcall expect 3 "marked as being away"))
+    (ert-info ("PING is not intercepted by specialized method")
+      (process-send-string client-proc "PING 42\r\n")
+      (with-current-buffer client-buf
+        (funcall expect 3 "PONG")))
+    (erc-d-t-wait-for 2 "dumb-server death"
+      (not (process-live-p dumb-server)))
+    (delete-process client-proc)
+    (when noninteractive
+      (kill-buffer client-buf)
+      (kill-buffer dumb-server-buffer))))
+
+;; Inspect replies as they arrive within a single exchange, i.e., ensure we
+;; don't regress to prior buggy version in which inspection wasn't possible
+;; until all replies had been sent by the server.
+(ert-deftest erc-d-run-incremental ()
+  :tags '(:expensive-test)
+  (let ((erc-server-flood-penalty 0)
+        (expect (erc-d-t-make-expecter))
+        erc-d-linger-secs)
+    (erc-d-tests-with-server (_ erc-server-buffer) incremental
+      (with-current-buffer erc-server-buffer
+        (funcall expect 3 "marked as being away"))
+      (with-current-buffer erc-server-buffer
+        (erc-cmd-JOIN "#foo"))
+      (with-current-buffer (erc-d-t-wait-for 1 (get-buffer "#foo"))
+        (funcall expect 1 "Users on #foo")
+        (funcall expect 1 "Look for me")
+        (not (search-forward "Done" nil t))
+        (funcall expect 10 "Done")
+        (erc-send-message "Hi")))))
+
+(ert-deftest erc-d-unix-socket-direct ()
+  :tags '(:expensive-test)
+  (skip-unless (featurep 'make-network-process '(:family local)))
+  (let* ((erc-d-linger-secs 0.1)
+         (sock (expand-file-name "erc-d.sock" temporary-file-directory))
+         (dumb-server (erc-d-run nil sock 'basic))
+         (dumb-server-buffer (get-buffer "*erc-d-server*"))
+         (client-buffer (get-buffer-create "*erc-d-client*"))
+         client)
+    (with-current-buffer "*erc-d-server*"
+      (erc-d-t-search-for 4 "Starting"))
+    (unwind-protect
+        (progn
+          (setq client (make-network-process
+                        :buffer client-buffer
+                        :name "erc-d-client"
+                        :family 'local
+                        :noquery t
+                        :coding 'binary
+                        :service sock))
+          (process-send-string client "PASS :changeme\r\n")
+          (sleep-for 0.01)
+          (process-send-string client "NICK tester\r\n")
+          (sleep-for 0.01)
+          (process-send-string client "USER user 0 * :tester\r\n")
+          (sleep-for 0.1)
+          (process-send-string client "MODE tester +i\r\n")
+          (sleep-for 0.01)
+          (process-send-string client "MODE #chan\r\n")
+          (sleep-for 0.01)
+          (erc-d-t-wait-for 1 "dumb-server death"
+            (not (process-live-p dumb-server)))
+          (when noninteractive
+            (kill-buffer client-buffer)
+            (kill-buffer dumb-server-buffer)))
+      (delete-file sock))))
+
+(ert-deftest erc-d-run-direct-foreign-protocol ()
+  :tags '(:expensive-test)
+  (let* ((server (erc-d-run "localhost" t "erc-d-server" 'foreign
+                            :ending "\n"))
+         (server-buffer (get-buffer "*erc-d-server*"))
+         (client-buffer (get-buffer-create "*erc-d-client*"))
+         client)
+    (with-current-buffer server-buffer (erc-d-t-search-for 4 "Starting"))
+    (setq client (make-network-process
+                  :buffer client-buffer
+                  :name "erc-d-client"
+                  :family 'ipv4
+                  :noquery t
+                  :coding 'binary
+                  :service (process-contact server :service)
+                  :host "localhost"))
+    (process-send-string client "ONE one\n")
+    (with-current-buffer client-buffer
+      (erc-d-t-search-for 5 "echo ONE one"))
+    (process-send-string client "TWO two\n")
+    (with-current-buffer client-buffer
+      (erc-d-t-search-for 2 "echo TWO two"))
+    (erc-d-t-wait-for 2 "server death" (not (process-live-p server)))
+    (when noninteractive
+      (kill-buffer client-buffer)
+      (kill-buffer server-buffer))))
+
+;;; erc-d-tests.el ends here
diff --git a/test/lisp/erc/resources/erc-d/erc-d-u.el 
b/test/lisp/erc/resources/erc-d/erc-d-u.el
new file mode 100644
index 0000000000..ce13efef62
--- /dev/null
+++ b/test/lisp/erc/resources/erc-d/erc-d-u.el
@@ -0,0 +1,213 @@
+;;; 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.
+;;
+;; 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:
+
+;; The utilities here are kept separate from those in `erc-d' so that
+;; tests running the server in a subprocess can use them without
+;; having to require the main lib.  If migrating outside of test/lisp,
+;; there may be no reason to continue this.
+;;
+;; Another (perhaps misguided) goal here is to avoid having ERC itself
+;; as a dependency.
+;;
+;; FIXME this ^ is no longer the case (ERC is not a dependency)
+
+;;; Code:
+(require 'rx)
+(require 'subr-x)
+(eval-when-compile (require 'ert))
+
+(defvar erc-d-u--canned-buffers nil
+  "List of canned dialog buffers currently open for reading.")
+
+(cl-defstruct (erc-d-u-scan-d) ; dialog scanner
+  (buf nil :type buffer)
+  (done nil :type boolean)
+  (last nil :type integer)
+  (hunks nil :type (list-of marker))
+  (f #'erc-d-u--read-exchange-default :type function))
+
+(cl-defstruct (erc-d-u-scan-e) ; exchange scanner
+  (sd nil :type erc-d-u-scan-d)
+  (pos nil :type marker))
+
+(defun erc-d-u--read-dialog (info)
+  "Read dialog file and stash relevant state in `erc-d-u-scan-d' INFO."
+  (if (and (buffer-live-p (erc-d-u-scan-d-buf info))
+           (with-current-buffer (erc-d-u-scan-d-buf info)
+             (condition-case _err
+                 (progn
+                   (when (erc-d-u-scan-d-last info)
+                     (goto-char (erc-d-u-scan-d-last info))
+                     (forward-list))
+                   (setf (erc-d-u-scan-d-last info) (point))
+                   (down-list)
+                   (push (set-marker (make-marker) (point))
+                         (erc-d-u-scan-d-hunks info)))
+               ((end-of-buffer scan-error)
+                (setf (erc-d-u-scan-d-done info) t)
+                nil))))
+      (make-erc-d-u-scan-e :sd info :pos (car (erc-d-u-scan-d-hunks info)))
+    (unless (erc-d-u-scan-d-hunks info)
+      (kill-buffer (erc-d-u-scan-d-buf info))
+      nil)))
+
+(defun erc-d-u--read-exchange-default (info)
+  "Read from marker in exchange `erc-d-u-scan-e' object INFO."
+  (let ((hunks (erc-d-u-scan-e-sd info))
+        (pos (erc-d-u-scan-e-pos info)))
+    (or (and (erc-d-u-scan-d-hunks hunks)
+             (with-current-buffer (erc-d-u-scan-d-buf hunks)
+               (goto-char pos)
+               (condition-case _err
+                   (read pos)
+                 ;; Raised unless malformed
+                 (invalid-read-syntax
+                  nil))))
+        (unless (or (cl-callf (lambda (s) (delq pos s)) ; flip
+                        (erc-d-u-scan-d-hunks hunks))
+                    (not (erc-d-u-scan-d-done hunks)))
+          (kill-buffer (erc-d-u-scan-d-buf hunks))
+          nil))))
+
+(defun erc-d-u--read-exchange (info)
+  "Call exchange reader assigned in `erc-d-u-scan-e' object INFO."
+  (funcall (erc-d-u-scan-d-f (erc-d-u-scan-e-sd info)) info))
+
+(defun erc-d-u--canned-read (file)
+  "Dispense a reader for each exchange in dialog FILE."
+  (let ((buf (generate-new-buffer (file-name-nondirectory file))))
+    (push buf erc-d-u--canned-buffers)
+    (with-current-buffer buf
+      (setq-local parse-sexp-ignore-comments t
+                  coding-system-for-read 'utf-8)
+      (add-hook 'kill-buffer-hook
+                (lambda () (setq erc-d-u--canned-buffers
+                                 (delq buf erc-d-u--canned-buffers)))
+                nil 'local)
+      (insert-file-contents-literally file)
+      (lisp-data-mode))
+    (make-erc-d-u-scan-d :buf buf)))
+
+(defvar erc-d-u--library-directory (file-name-directory load-file-name))
+(defvar erc-d-u-canned-dialog-dir
+  (file-name-as-directory (expand-file-name "resources"
+                                            erc-d-u--library-directory)))
+
+(defun erc-d-u--normalize-canned-name (dialog)
+  "Return DIALOG name as a symbol without validating it."
+  (if (symbolp dialog)
+      dialog
+    (intern (file-name-base dialog))))
+
+(defvar erc-d-u-canned-file-name-extension ".eld")
+
+(defun erc-d-u--expand-dialog-symbol (dialog)
+  "Return filename based on symbol DIALOG."
+  (let ((name (symbol-name dialog)))
+    (unless (equal (file-name-extension name)
+                   erc-d-u-canned-file-name-extension)
+      (setq name (concat name erc-d-u-canned-file-name-extension)))
+    (expand-file-name name erc-d-u-canned-dialog-dir)))
+
+(defun erc-d-u--massage-canned-name (dialog)
+  "Return DIALOG in a form acceptable to `erc-d-run'."
+  (if (or (symbolp dialog) (file-exists-p dialog))
+      dialog
+    (erc-d-u--expand-dialog-symbol (intern dialog))))
+
+(defun erc-d-u--canned-load-dialog (dialog)
+  "Load dispensing exchanges from DIALOG.
+If DIALOG is a string, consider it a filename.  Otherwise find a file
+in `erc-d-u-canned-dialog-dir' with a base name matching the symbol's
+name.
+
+Return an iterator that yields exchanges, each one an iterator of spec
+forms.  The first is a so-called request spec and the rest are composed
+of zero or more response specs."
+  (when (symbolp dialog)
+    (setq dialog (erc-d-u--expand-dialog-symbol dialog)))
+  (unless (file-exists-p dialog)
+    (error "File not found: %s" dialog))
+  (erc-d-u--canned-read dialog))
+
+(defun erc-d-u--read-exchange-slowly (num orig info)
+  (when-let ((spec (funcall orig info)))
+    (when (symbolp (car spec))
+      (setf spec (copy-sequence spec)
+            (nth 1 spec) (cond ((functionp num) (funcall num (nth 1 spec)))
+                               ((< num 0) (max (nth 1 spec) (- num)))
+                               (t (+ (nth 1 spec) num)))))
+    spec))
+
+(defun erc-d-u--rewrite-for-slow-mo (num read-info)
+  "Return READ-INFO with a modified reader.
+When NUM is a positive number, delay incoming requests by NUM more
+seconds.  If NUM is negative, raise insufficient incoming delays to at
+least -NUM seconds.  If NUM is a function, set each delay to whatever it
+returns when called with the existing value."
+  (let ((orig (erc-d-u-scan-d-f read-info)))
+    (setf (erc-d-u-scan-d-f read-info)
+          (apply-partially #'erc-d-u--read-exchange-slowly num orig))
+    read-info))
+
+(defun erc-d-u--get-remote-port (process)
+  "Return peer TCP port for client PROCESS.
+When absent, just generate an id."
+  (let ((remote (plist-get (process-contact process t) :remote)))
+    (if (vectorp remote)
+        (aref remote (1- (length remote)))
+      (format "%s:%d" (process-contact process :local)
+              (logand 1023 (time-convert nil 'integer))))))
+
+(defun erc-d-u--format-bind-address (process)
+  "Return string or (STRING . INT) for bind address of network PROCESS."
+  (let ((local (process-contact process :local)))
+    (if (vectorp local) ; inet
+        (cons (mapconcat #'number-to-string (seq-subseq local 0 -1) ".")
+              (aref local (1- (length local))))
+      local)))
+
+(defun erc-d-u--unkeyword (plist)
+  "Return a copy of PLIST with keywords keys converted to non-keywords."
+  (cl-loop for (key value) on plist by #'cddr
+           when (keywordp key)
+           do (setq key (intern (substring (symbol-name key) 1)))
+           append (list key value)))
+
+(defun erc-d-u--massage-rx-args (key val)
+  " Massage val so it's suitable for an `rx-let' binding.
+Handle cases in which VAL is ([ARGLIST] RX-FORM) rather than just
+RX-FORM.  KEY becomes the binding name."
+  (if (and (listp val)
+           (cdr val)
+           (not (cddr val))
+           (consp (car val)))
+      (cons key val)
+    (list key val)))
+
+(defvar-local erc-d-u--process-buffer nil
+  "Beacon for erc-d process buffers.
+The server process is usually deleted first, but we may want to examine
+the buffer afterward.")
+
+(provide 'erc-d-u)
+;;; erc-d-u.el ends here
diff --git a/test/lisp/erc/resources/erc-d/erc-d.el 
b/test/lisp/erc/resources/erc-d/erc-d.el
new file mode 100644
index 0000000000..d6082227c5
--- /dev/null
+++ b/test/lisp/erc/resources/erc-d/erc-d.el
@@ -0,0 +1,1009 @@
+;;; 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.
+;;
+;; 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:
+
+;; This is a netcat style server for testing ERC.  The "d" in the name
+;; stands for "daemon" as well as for "dialog" (as well as for "dumb"
+;; because this server isn't very smart).  It either spits out a
+;; canned reply when an incoming request matches the expected regexp
+;; or signals an error and dies.  The entry point function is
+;; `erc-d-run'.
+;;
+;; Canned scripts, or "dialogs," should be Lisp-Data files containing
+;; one or more request/reply forms like this:
+;;
+;; |  ((mode-chan 1.5 "MODE #chan")          ; request: tag, expr, regex
+;; |   (0.1 ":irc.org 324 bob #chan +Cint")  ; reply: delay, content
+;; |   (0.0 ":irc.org 329 bob #chan 12345")) ; reply: ...
+;;
+;; These are referred to as "exchanges."  The first element is a list
+;; whose CAR is a descriptive "tag" and whose CDR is an incoming
+;; "spec" representing an inbound message from the client.  The rest
+;; of the exchange is composed of outgoing specs representing
+;; server-to-client messages.  A tag can be any symbol (ideally unique
+;; in the dialog), but a leading tilde means the request should be
+;; allowed to arrive out of order (within the allotted time).
+;;
+;; The first element in an incoming spec is a number indicating the
+;; maximum number of seconds to wait for a match before raising an
+;; error.  The CDR is interpreted as the collective arguments of an
+;; `rx' form to be matched against the raw request (stripped of its
+;; CRLF line ending).  A "string-start" backslash assertion, "\\`", is
+;; prepended to all patterns.
+;;
+;; Similarly, the leading number in an *outgoing* spec indicates how
+;; many seconds to wait before sending the line, which is rendered by
+;; concatenating the other members after evaluating each in place.
+;; CRLF line endings are appended on the way out and should be absent.
+;;
+;; Recall that IRC is "asynchronous," meaning some flow intervals
+;; don't jibe with lockstep request-reply semantics.  However, for our
+;; purposes, grouping things as [input, output1, ..., outputN] makes
+;; sense, even though input and output may be completely unrelated.
+;;
+;; Template interpolation:
+;;
+;; A rudimentary templating facility is provided for additional
+;; flexibility.  However, it's best to keep things simple (even if
+;; overly verbose), so others can easily tell what's going on at a
+;; glance.  If necessary, consult existing tests for examples (grep
+;; for the variables `erc-d-tmpl-vars' and `erc-d-match-handlers').
+;;
+;; Subprocess or in-process?:
+;;
+;; Running in-process confers better visibility and easier setup at
+;; the cost of additional cleanup and resource wrangling.  With a
+;; subprocess, cleanup happens by pulling the plug, but configuration
+;; means loading a separate file or passing -eval "(forms...)" during
+;; invocation.  In some cases, a subprocess may be the only option,
+;; like when trying to avoid `require'ing this file.
+;;
+;; Dialog objects:
+;;
+;; For a given exchange, the first argument passed to a request
+;; handler is the `erc-d-dialog' object representing the overall
+;; conversation with the connecting peer.  It can be used to pass
+;; information between handlers during a session.  Some important
+;; items are:
+;;
+;; * name (symbol); name of the current dialog
+;;
+;; * queue (ring); a backlog of unhandled raw requests, minus CRLF
+;; endings.
+;;
+;; * timers (list of timers); when run, these send messages originally
+;; deferred as per the most recently matched exchange's delay info.
+;; Normally, all outgoing messages must be sent before another request
+;; is considered.  (See `erc-d--send-outgoing' for an escape hatch.)
+;;
+;; * hunks (iterator of iterators); unconsumed exchanges as read from
+;; a Lisp-Data dialog file.  The exchange iterators being dispensed
+;; themselves yield portions of member forms as a 2- or 3-part
+;; sequence: [tag] spec.  (Here, "hunk" just means "list of raw,
+;; unrendered exchange elements")
+;;
+;; * vars (alist of cons pairs); for sharing state among template
+;; functions during the lifetime of an exchange.  Initially populated
+;; by `erc-d-tmpl-vars', these KEY/VALUE pairs are expanded in the
+;; templates and optionally updated by "exchange handlers" (see
+;; `erc-d-match-handlers').  When VALUE is a function, occurrences of
+;; KEY in an outgoing spec are replaced with the result of calling
+;; VALUE with match data set appropriately.  See
+;; `erc-d--render-entries' for details.
+;;
+;; * exchanges (ring of erc-d-exchange objects); activated hunks
+;; allowed to match out of order, plus the current active exchange
+;; being yielded from, if any. See `erc-d-exchange'.
+;;
+;; TODO
+;;
+;; - Remove un(der)used functionality and simplify API
+;; - Maybe migrate d-u and d-i dependencies here
+
+;;; 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)))
+    (require 'erc-d-i)
+    (require 'erc-d-u)))
+
+(require 'ring)
+
+(defvar erc-d-server-name "erc-d-server"
+  "Default name of a server process and basis for its buffer name.
+Only relevant when starting a server with `erc-d-run'.")
+
+(defvar erc-d-server-fqdn "irc.example.org"
+  "Usually the same as the server's RPL_MYINFO \"announced name\".
+Possibly used by overriding handlers, like the one for PING, and/or
+dialog templates for the sender portion of a reply message.")
+
+(defvar erc-d-line-ending "\r\n"
+  "Protocol line delimiter for sending and receiving.")
+
+(defvar erc-d-linger-secs nil
+  "Seconds to wait before quitting for all dialogs.
+For more granular control, use the provided LINGER `rx' variable (alone)
+as the incoming template spec of a dialog's last exchange.")
+
+(defvar erc-d-tmpl-vars nil
+  "An alist of template bindings available to client dialogs.
+Populate it when calling `erc-d-run', and the contents will be made
+available to all client dialogs through the `erc-d-dialog' \"vars\"
+field and (therefore) to all templates as variables when rendering.  For
+example, a key/value pair like (network . \"oftc\") will cause instances
+of the (unquoted) symbol `network' to be replaced with \"oftc\" in the
+rendered template string.
+
+This list provides default template bindings common to all dialogs.
+Each new client-connection process makes a shallow copy on init, but the
+usual precautions apply when mutating member items.  Within the span of
+a dialog, updates not applicable to all exchanges should die with their
+exchange.  See `erc-d--render-entries' for details.  In the unlikely
+event that an exchange-specific handler is needed, see
+`erc-d-match-handlers'.")
+
+(defvar erc-d-match-handlers nil
+  "A plist of exchange-tag symbols mapped to request-handler functions.
+This is meant to address edge cases for which `erc-d-tmpl-vars' comes up
+short.  These may include (1) needing access to the client process
+itself and/or (2) adding or altering outgoing response templates before
+rendering.  Note that (2) requires using `erc-d-exchange-rebind' instead
+of manipulating exchange bindings directly.
+
+The hook-like function `erc-d-on-match' calls any handler whose key is
+`eq' to the tag of the currently matched exchange (passing the client
+`erc-d-dialog' as the first argument and the current `erc-d-exchange'
+object as the second).  The handler runs just prior to sending the first
+response.")
+
+(defvar erc-d-auto-pong t
+  "Handle PING requests automatically.")
+
+(defvar erc-d--in-process t
+  "Whether the server is running in the same Emacs as ERT.")
+
+(defvar erc-d--slow-mo nil
+  "Adjustment for all incoming timeouts.
+This is to allow for human interaction or a slow Emacs or CI runner.
+The value is the number of seconds to extend all incoming spec timeouts
+by on init.  If the value is a negative number, it's negated and
+interpreted as a lower bound to raise all incoming timeouts to.  If the
+value is a function, it should take an existing timeout in seconds and
+return a replacement.")
+
+(defconst erc-d--eof-sentinel "__EOF__")
+(defconst erc-d--linger-sentinel "__LINGER__")
+(defconst erc-d--drop-sentinel "__DROP__")
+
+(defvar erc-d--clients nil
+  "List containing all clients for this server session.")
+
+;; Some :type names may just be made up (not actual CL types)
+
+(cl-defstruct (erc-d-spec) ; see `erc-d--render-entries'
+  (head nil :type symbol) ; or number?
+  (entry nil :type list)
+  (state 0 :type integer))
+
+(cl-defstruct (erc-d-exchange)
+  "Object representing a request/response unit from a canned dialog."
+  (dialog nil :type erc-d-dialog) ; owning dialog
+  (tag nil :type symbol) ;  a.k.a. tag, the caar
+  (pattern nil :type string) ; regexp to match requests against
+  (inspec nil :type list) ; original unrendered incoming spec
+  (hunk nil :type erc-d-u-scan-e) ; active raw exchange hunk being yielded
+  (spec nil :type erc-d-spec) ; active spec, see `erc-d--render-entries'
+  (timeout nil :type number) ; time allotted for current request
+  (timer nil :type timer) ; match timer fires when timeout expires
+  (bindings nil :type list) ; `eval'-style env pairs (KEY . VAL) ...
+  (rx-bindings nil :type list) ; rx-let bindings
+  (deferred nil :type boolean) ; whether sender is paused
+  ;; Post-match
+  (match-data nil :type match-data) ; from the latest matched request
+  (request nil :type string)) ; the original request sans CRLF
+
+(cl-defstruct (erc-d-dialog)
+  "Session state for managing a client conversation."
+  (process nil :type process) ; client-connection process
+  (name nil :type symbol) ; likely the interned stem of the file
+  (queue nil :type ring) ; backlog of incoming lines to process
+  (hunks nil :type erc-d-u-scan-d) ; nil when done; info on raw exchange hunks
+  (timers nil :type list) ; unsent replies
+  (vars nil :type list) ; template bindings for rendering
+  (exchanges nil :type ring) ; ring of erc-d-exchange objects
+  (state nil :type symbol) ; handler's last recorded control state
+  (matched nil :type erc-d-exchange) ; currently matched exchange
+  (message nil :type erc-d-i-message) ; `erc-d-i-message'
+  (match-handlers nil :type list) ; copy of `erc-d-match-handlers'
+  (server-fqdn nil :type string) ; copy of `erc-d-server-fqdn'
+  (finalizer nil :type function) ; custom teardown, passed dialog and exchange
+  ;; Post-match history is a plist whose keys are exchange tags
+  ;; (symbols) and whose values are a cons of match-data and request
+  ;; values from prior matches.
+  (history nil :type list))
+
+(defun erc-d--initialize-client (process)
+  "Initialize state variables used by a client PROCESS."
+  ;; Discard server-only/owned props
+  (process-put process :dialog-dialogs nil)
+  (let* ((server (process-get process :server))
+         (reader (pop (process-get server :dialog-dialogs)))
+         (name (pop reader))
+         ;; Copy handlers so they can self-mutate per process
+         (mat-h (copy-sequence (process-get process :dialog-match-handlers)))
+         (fqdn (copy-sequence (process-get process :dialog-server-fqdn)))
+         (vars (copy-sequence (process-get process :dialog-vars)))
+         (ending (process-get process :dialog-ending))
+         (dialog (make-erc-d-dialog :name name
+                                    :process process
+                                    :queue (make-ring 5)
+                                    :exchanges (make-ring 10)
+                                    :match-handlers mat-h
+                                    :server-fqdn fqdn)))
+    ;; Add items expected by convenience commands like `erc-d-exchange-reload'.
+    (setf (alist-get 'EOF vars) `(: ,erc-d--eof-sentinel eot)
+          (alist-get 'LINGER vars) `(: ,erc-d--linger-sentinel eot)
+          (alist-get 'DROP vars) `(: ,erc-d--drop-sentinel eot)
+          (erc-d-dialog-vars dialog) vars
+          (erc-d-dialog-hunks dialog) reader)
+    ;; Add reverse link, register client, launch
+    (process-put process :dialog dialog)
+    (process-put process :ending ending)
+    (process-put process :ending-regexp (rx-to-string `(+ ,ending)))
+    (push process erc-d--clients)
+    (erc-d--command-refresh dialog nil)
+    (erc-d--on-request process)))
+
+(defun erc-d-load-replacement-dialog (dialog replacement &optional skip)
+  "Find REPLACEMENT among backlog and swap out current DIALOG's iterator.
+With int SKIP, advance past that many exchanges."
+  (let* ((process (erc-d-dialog-process dialog))
+         (server (process-get process :server))
+         (reader (assoc-default replacement
+                                (process-get server :dialog-dialogs)
+                                #'eq)))
+    (when skip (while (not (zerop skip))
+                 (erc-d-u--read-dialog reader)
+                 (cl-decf skip)))
+    (dolist (timer (erc-d-dialog-timers dialog))
+      (cancel-timer timer))
+    (dolist (exchange (ring-elements (erc-d-dialog-exchanges dialog)))
+      (cancel-timer (erc-d-exchange-timer exchange)))
+    (setf (erc-d-dialog-hunks dialog) reader)
+    (erc-d--command-refresh dialog nil)))
+
+(defvar erc-d--m-debug (getenv "ERC_D_DEBUG"))
+
+(defmacro erc-d--m (process format-string &rest args)
+  "Output ARGS using FORMAT-STRING somewhere depending on context.
+PROCESS should be a client connection or a server network process."
+  `(let ((format-string (if erc-d--m-debug
+                            (concat (format-time-string "%s.%N: ")
+                                    ,format-string)
+                          ,format-string))
+         (want-insert (and ,process erc-d--in-process)))
+     (when want-insert
+       (with-current-buffer (process-buffer (process-get ,process :server))
+         (goto-char (point-max))
+         (insert (concat (format ,format-string ,@args) "\n"))))
+     (when (or erc-d--m-debug (not want-insert))
+       (message format-string ,@args))))
+
+(defmacro erc-d--log (process string &optional outbound)
+  "Log STRING sent to (OUTBOUND) or received from PROCESS peer."
+  `(let ((id (or (process-get ,process :log-id)
+                 (let ((port (erc-d-u--get-remote-port ,process)))
+                   (process-put ,process :log-id port)
+                   port)))
+         (name (erc-d-dialog-name (process-get ,process :dialog))))
+     (if ,outbound
+         (erc-d--m process "-> %s:%s %s" name id ,string)
+       (dolist (line (split-string ,string (process-get process :ending)))
+         (erc-d--m process "<- %s:%s %s" name id line)))))
+
+(defun erc-d--log-process-event (server process msg)
+  (erc-d--m server "%s: %s" process (string-trim-right msg)))
+
+(defun erc-d--send (process string)
+  "Send STRING to PROCESS peer."
+  (erc-d--log process string 'outbound)
+  (process-send-string process (concat string (process-get process :ending))))
+
+(define-inline erc-d--fuzzy-p (exchange)
+  (inline-letevals (exchange)
+    (inline-quote
+     (let ((tag (symbol-name (erc-d-exchange-tag ,exchange))))
+       (eq ?~ (aref tag 0))))))
+
+(define-error 'erc-d-timeout "Timed out awaiting expected request")
+
+(defun erc-d--finalize-dialog (dialog)
+  "Delete client-connection and finalize DIALOG.
+Return associated server."
+  (let ((process (erc-d-dialog-process dialog)))
+    (setq erc-d--clients (delq process erc-d--clients))
+    (dolist (timer (erc-d-dialog-timers dialog))
+      (cancel-timer timer))
+    (dolist (exchange (ring-elements (erc-d-dialog-exchanges dialog)))
+      (cancel-timer (erc-d-exchange-timer exchange)))
+    (prog1 (process-get process :server)
+      (delete-process process))))
+
+(defun erc-d--teardown (&optional sig &rest msg)
+  "Clean up processes and maybe send signal SIG using MSG."
+  (unless erc-d--in-process
+    (when sig
+      (erc-d--m nil "%s %s" sig (apply #'format-message msg)))
+    (kill-emacs (if msg 1 0)))
+  (let (process servers)
+    (while (setq process (pop erc-d--clients))
+      (push (erc-d--finalize-dialog (process-get process :dialog)) servers))
+    (dolist (server servers)
+      (delete-process server)))
+  (dolist (timer timer-list)
+    (when (memq (timer--function timer)
+                '(erc-d--send erc-d--command-handle-all))
+      (erc-d--m nil "Stray timer found: %S" (timer--function timer))
+      (cancel-timer timer)))
+  (when sig
+    (dolist (buf erc-d-u--canned-buffers)
+      (kill-buffer buf))
+    (setq erc-d-u--canned-buffers nil)
+    (signal sig (list (apply #'format-message msg)))))
+
+(defun erc-d--teardown-this-dialog-at-least (dialog)
+  "Run `erc-d--teardown' after destroying DIALOG if it's the last one."
+  (let ((server (process-get (erc-d-dialog-process dialog) :server))
+        (us (erc-d-dialog-process dialog)))
+    (erc-d--finalize-dialog dialog)
+    (cl-assert (not (memq us erc-d--clients)))
+    (unless (or (process-get server :dialog-dialogs)
+                (catch 'other
+                  (dolist (process erc-d--clients)
+                    (when (eq (process-get process :server) server)
+                      (throw 'other process)))))
+      (push us erc-d--clients)
+      (erc-d--teardown))))
+
+(defun erc-d--expire (dialog exchange)
+  "Raise timeout error for EXCHANGE.
+This will start the teardown for DIALOG."
+  (setf (erc-d-exchange-spec exchange) nil)
+  (if-let ((finalizer (erc-d-dialog-finalizer dialog)))
+      (funcall finalizer dialog exchange)
+    (erc-d--teardown 'erc-d-timeout "Timed out awaiting request: %s"
+                     (list :name (erc-d-exchange-tag exchange)
+                           :pattern (erc-d-exchange-pattern exchange)
+                           :timeout (erc-d-exchange-timeout exchange)
+                           :dialog (erc-d-dialog-name dialog)))))
+
+;; Using `run-at-time' here allows test cases to examine replies as
+;; they arrive instead of forcing tests to wait until an exchange
+;; completes.  The `run-at-time' in `erc-d--command-meter-replies'
+;; does the same.  When running as a subprocess, a normal while loop
+;; with a `sleep-for' works fine (including with multiple dialogs).
+;; FYI, this issue was still present in older versions that called
+;; this directly from `erc-d--filter'.
+
+(defun erc-d--on-request (process)
+  "Handle one request for client-connection PROCESS."
+  (when (process-live-p process)
+    (let* ((dialog (process-get process :dialog))
+           (queue (erc-d-dialog-queue dialog)))
+      (unless (ring-empty-p queue)
+        (let* ((parsed (ring-remove queue))
+               (cmd (intern (erc-d-i-message.command parsed))))
+          (setf (erc-d-dialog-message dialog) parsed)
+          (erc-d-command dialog cmd)))
+      (run-at-time nil nil #'erc-d--on-request process))))
+
+(defun erc-d--drop-p (exchange)
+  (memq 'DROP (erc-d-exchange-inspec exchange)))
+
+(defun erc-d--linger-p (exchange)
+  (memq 'LINGER (erc-d-exchange-inspec exchange)))
+
+(defun erc-d--fake-eof (dialog)
+  "Simulate receiving a fictitious \"EOF\" message from peer."
+  (setf (erc-d-dialog-message dialog) ; use downcase for internal cmds
+        (make-erc-d-i-message :command "eof" :unparsed erc-d--eof-sentinel))
+  (run-at-time nil nil #'erc-d-command dialog 'eof))
+
+(defun erc-d--process-sentinel (process event)
+  "Set up or tear down client-connection PROCESS depending on EVENT."
+  (erc-d--log-process-event process process event)
+  (if (eq 'open (process-status process))
+      (erc-d--initialize-client process)
+    (let* ((dialog (process-get process :dialog))
+           (exes (and dialog (erc-d-dialog-exchanges dialog))))
+      (if (and exes (not (ring-empty-p exes)))
+          (cond ((string-prefix-p "connection broken" event)
+                 (erc-d--fake-eof dialog))
+                ;; Ignore disconnecting peer when pattern is DROP
+                ((and (string-prefix-p "deleted" event)
+                      (erc-d--drop-p (ring-ref exes -1))))
+                (t (erc-d--teardown)))
+        (erc-d--teardown)))))
+
+(defun erc-d--filter (process string)
+  "Handle input received from peer.
+PROCESS represents a client peer connection and STRING is a raw request
+including line delimiters."
+  (let ((queue (erc-d-dialog-queue (process-get process :dialog)))
+        (delim (process-get process :ending-regexp)))
+    (setq string (concat (process-get process :stashed-input) string))
+    (while (and string (string-match delim string))
+      (let ((line (substring string 0 (match-beginning 0))))
+        (setq string (unless (= (match-end 0) (length string))
+                       (substring string (match-end 0))))
+        (erc-d--log process line nil)
+        (ring-insert queue (erc-d-i--parse-message line 'decode))))
+    (when string
+      (setf (process-get process :stashed-input) string))))
+
+;; Misc process properties:
+;;
+;; The server property `:dialog-dialogs' is an alist of (symbol
+;; . erc-d-u-scan-d) conses, each of which pairs a dialogs name with
+;; info on its read progress (described above in the Commentary).
+;; This list is populated by `erc-d-run' at the start of each session.
+;;
+;; Client-connection processes keep a reference to their server via a
+;; `:server' property, which can be used to share info with other
+;; clients.  There is currently no built-in way to do the same with
+;; clients of other servers.  Clients also keep references to their
+;; dialogs and raw messages via `:dialog' and `:stashed-input'.
+;;
+;; The logger stores a unique, human-friendly process name in the
+;; client-process property `:log-id'.
+
+(defun erc-d--start (host service name &rest plist)
+  "Serve canned replies on HOST at SERVICE.
+Return the new server process immediately when `erc-d--in-process' is
+non-nil.  Otherwise, serve forever.  PLIST becomes the plist of the
+server process and is used to initialize the plists of connection
+processes.  NAME is used for the process and the buffer."
+  (let* ((buf (get-buffer-create (concat "*" name "*")))
+         (proc (make-network-process :server t
+                                     :buffer buf
+                                     :noquery t
+                                     :filter #'erc-d--filter
+                                     :log #'erc-d--log-process-event
+                                     :sentinel #'erc-d--process-sentinel
+                                     :name name
+                                     :family (if host 'ipv4 'local)
+                                     :coding 'binary
+                                     :service (or service t)
+                                     :host host
+                                     :plist plist)))
+    (process-put proc :server proc)
+    ;; We don't have a minor mode, so use an arbitrary variable to mark
+    ;; buffers owned by us instead
+    (with-current-buffer buf (setq erc-d-u--process-buffer t))
+    (erc-d--m proc "Starting network process: %S %S"
+              proc (erc-d-u--format-bind-address proc))
+    (if erc-d--in-process
+        proc
+      (while (process-live-p proc)
+        (accept-process-output nil 0.01)))))
+
+(defun erc-d--wrap-func-val (dialog exchange key func)
+  "Return a form invoking FUNC when evaluated.
+Arrange for FUNC to be called with the args it expects based on
+the description in `erc-d--render-entries'."
+  (let (args)
+    ;; Ignore &rest or &optional
+    (pcase-let ((`(,n . ,_) (func-arity func)))
+      (pcase n
+        (0)
+        (1 (push (apply-partially #'erc-d-exchange-multi dialog exchange key)
+                 args))
+        (2 (push exchange args)
+           (push (apply-partially #'erc-d-exchange-multi dialog exchange key)
+                 args))
+        (_ (error "Incompatible function: %s" func))))
+    (lambda () (apply func args))))
+
+(defun erc-d-exchange-reload (dialog exchange)
+  "Rebuild all bindings for EXCHANGE from those in DIALOG."
+  (cl-loop for (key . val) in (erc-d-dialog-vars dialog)
+           unless (keywordp key)
+           do (push (erc-d-u--massage-rx-args key val)
+                    (erc-d-exchange-rx-bindings exchange))
+           when (functionp val) do
+           (setq val (erc-d--wrap-func-val dialog exchange key val))
+           do (push (cons key val) (erc-d-exchange-bindings exchange))))
+
+(defun erc-d-exchange-rebind (dialog exchange key val &optional export)
+  "Modify a binding between renders.
+
+Bind symbol KEY to VAL, replacing whatever existed before, which may
+have been a function.  A third, optional argument, if present and
+non-nil, results in the DIALOG's bindings for all EXCHANGEs adopting
+this binding.  VAL can either be a function of the type described in
+`erc-d--render-entries' or any value acceptable as an argument to the
+function `concat'.
+
+DIALOG and EXCHANGE are the current `erc-d-dialog' and `erc-d-exchange'
+objects for the request context."
+  (when export
+    (setf (alist-get key (erc-d-dialog-vars dialog)) val))
+  (if (functionp val)
+      (setf (alist-get key (erc-d-exchange-bindings exchange))
+            (erc-d--wrap-func-val dialog exchange key val))
+    (setf (alist-get key (erc-d-exchange-rx-bindings exchange)) (list val)
+          (alist-get key (erc-d-exchange-bindings exchange)) val))
+  val)
+
+(defun erc-d-exchange-match (exchange match-number &optional tag)
+  "Return match portion of current or previous request.
+MATCH-NUMBER is the match group number.  TAG, if provided, means the
+exchange tag (name) from some previously matched request."
+  (if tag
+      (pcase-let* ((dialog (erc-d-exchange-dialog exchange))
+                   (`(,m-d . ,req) (plist-get (erc-d-dialog-history dialog)
+                                              tag)))
+        (set-match-data m-d)
+        (match-string match-number req))
+    (match-string match-number (erc-d-exchange-request exchange))))
+
+(defun erc-d-exchange-multi (dialog exchange key cmd &rest args)
+  "Call CMD with ARGS.
+This is a utility passed as the first argument to all template
+functions.  DIALOG and EXCHANGE are pre-applied.  A few pseudo
+commands, like `:request', are provided for convenience so that
+the caller's definition doesn't have to include this file.  The
+rest are access and mutation utilities, such as `:set', which
+assigns KEY a new value, `:get-binding', which looks up KEY in
+`erc-d-exchange-bindings', and `:get-var', which looks up KEY in
+`erc-d-dialog-vars'."
+  (pcase cmd
+    (:set (apply #'erc-d-exchange-rebind dialog exchange key args))
+    (:reload (apply #'erc-d-exchange-reload dialog exchange args))
+    (:rebind (apply #'erc-d-exchange-rebind dialog exchange args))
+    (:match (apply #'erc-d-exchange-match exchange args))
+    (:request (erc-d-exchange-request exchange))
+    (:match-data (erc-d-exchange-match-data exchange))
+    (:dialog-name (erc-d-dialog-name dialog))
+    (:get-binding (cdr (assq (car args) (erc-d-exchange-bindings exchange))))
+    (:get-var (alist-get (car args) (erc-d-dialog-vars dialog)))))
+
+(defun erc-d--render-incoming-entry (exchange spec)
+  (let ((rx--local-definitions (rx--extend-local-defs
+                                (erc-d-exchange-rx-bindings exchange))))
+    (rx-to-string `(: bos ,@(erc-d-spec-entry spec)) 'no-group)))
+
+(defun erc-d--render-outgoing-entry (exchange entry)
+  (let (out this)
+    (while (setq this (pop entry))
+      (set-match-data (erc-d-exchange-match-data exchange))
+      (unless (stringp this)
+        (cl-assert (symbolp this))
+        (setq this (or (alist-get this (erc-d-exchange-bindings exchange))
+                       (symbol-value this)))
+        ;; Allow reference to overlong var name unbecoming of a template
+        (when this
+          (when (symbolp this) (setq this (symbol-value this)))
+          (when (functionp this) (setq this (save-match-data (funcall this))))
+          (unless (stringp this) (error "Unexpected token %S" this))))
+      (push this out))
+    (apply #'concat (nreverse out))))
+
+(defun erc-d--render-entries (exchange &optional yield-result)
+  "Act as an iterator producing rendered strings from EXCHANGE hunks.
+When an entry's CAR is an arbitrary symbol, yield that back first, and
+consider the entry an \"incoming\" entry.  Then, regardless of the
+entry's type (incoming or outgoing), yield back the next element, which
+should be a number representing either a timeout (incoming) or a
+delay (outgoing).  After that, yield a rendered template (outgoing) or a
+regular expression (incoming); both should be treated as immutable.
+
+When evaluating a template, bind the keys in the alist stored in the
+dialog's `vars' field to its values, but skip any self-quoters, like
+:foo.  When an entry is incoming, replace occurrences of a key with its
+value, which can be any valid `rx' form (see Info node `(elisp)
+Extending Rx').  Do the same when an entry is outgoing, but expect a
+value's form to be (anything that evaluates to) something acceptable by
+`concat' or, alternatively, a function that returns a string or nil.
+
+Repeat the last two steps for the remaining entries, all of which are
+assumed to be outgoing.  That is, continue yielding a timeout/delay and
+a rendered string for each entry, and yield nil when exhausted.
+
+Once again, for an incoming entry, the yielded string is a regexp to be
+matched against the raw request.  For outgoing, it's the final response,
+ready to be sent out (after adding the appropriate line ending).
+
+To help with testing, bindings are not automatically created from
+DIALOG's \"vars\" alist when this function is invoked.  But this can be
+forced by sending a non-nil YIELD-RESULT into the generator on the
+second \"next\" invocation of a given iteration.  This clobbers any
+temporary bindings that don't exist in the DIALOG's `vars' alist, such
+as those added via `erc-d-exchange-rebind' (unless \"exported\").
+
+As noted earlier, template symbols can be bound to functions.  When
+called during rendering, the match data from the current (matched)
+request is accessible by calling the function `match-data'.
+
+A function may ask for up to two required args, which are provided as
+needed.  When applicable, the first required arg is a `funcall'-able
+helper that accepts various keyword-based commands, like :rebind, and a
+variable number of args.  See `erc-d-exchange-multi' for details.  When
+specified, the second required arg is the current `erc-d-exchange'
+object, which has among its members its owning `erc-d-dialog' object.
+This should suffice as a safety valve for any corner-case needs.
+Non-required args are ignored."
+  (let ((spec (erc-d-exchange-spec exchange))
+        (dialog (erc-d-exchange-dialog exchange))
+        (entries (erc-d-exchange-hunk exchange)))
+    (unless (erc-d-spec-entry spec)
+      (setf (erc-d-spec-entry spec) (erc-d-u--read-exchange entries)))
+    (catch 'yield
+      (while (erc-d-spec-entry spec)
+        (pcase (erc-d-spec-state spec)
+          (0 (cl-incf (erc-d-spec-state spec))
+             (throw 'yield (setf (erc-d-spec-head spec)
+                                 (pop (erc-d-spec-entry spec)))))
+          (1 (cl-incf (erc-d-spec-state spec))
+             (when yield-result
+               (erc-d-exchange-reload dialog exchange))
+             (unless (numberp (erc-d-spec-head spec))
+               (setf (erc-d-exchange-inspec exchange) (erc-d-spec-entry spec))
+               (throw 'yield
+                      (prog1 (pop (erc-d-spec-entry spec))
+                        (setf (erc-d-spec-entry spec)
+                              (erc-d--render-incoming-entry exchange spec))))))
+          (2 (setf (erc-d-spec-state spec) 0)
+             (throw 'yield
+                    (let ((entry (erc-d-spec-entry spec)))
+                      (setf (erc-d-spec-entry spec) nil)
+                      (if (stringp entry)
+                          entry
+                        (erc-d--render-outgoing-entry exchange entry))))))))))
+
+(defun erc-d--iter (exchange)
+  (apply-partially #'erc-d--render-entries exchange))
+
+(defun erc-d-on-match (dialog exchange)
+  "Handle matched exchange request.
+Allow the first handler in `erc-d-match-handlers' whose key matches TAG
+to manipulate replies before they're sent to the DIALOG peer."
+  (when-let* ((tag (erc-d-exchange-tag exchange))
+              (handler (plist-get (erc-d-dialog-match-handlers dialog) tag)))
+    (let ((md (erc-d-exchange-match-data exchange)))
+      (set-match-data md)
+      (funcall handler dialog exchange))))
+
+(defun erc-d--send-outgoing (dialog exchange)
+  "Send outgoing lines for EXCHANGE to DIALOG peer.
+Assume the next spec is outgoing.  If its delay value is zero, render
+the template and send the resulting message straight away.  Do the same
+when DELAY is negative, only arrange for its message to be sent (abs
+DELAY) seconds later, and then keep on processing.  If DELAY is
+positive, pause processing and yield DELAY."
+  (let ((specs (erc-d--iter exchange))
+        (process (erc-d-dialog-process dialog))
+        (deferred (erc-d-exchange-deferred exchange))
+        delay)
+    ;; Could stash/pass thunk instead to ensure specs can't be mutated
+    ;; between calls (by temporarily replacing dialog member with a fugazi)
+    (when deferred
+      (erc-d--send process (funcall specs))
+      (setf deferred nil (erc-d-exchange-deferred exchange) deferred))
+    (while (and (not deferred) (setq delay (funcall specs)))
+      (cond ((zerop delay) (erc-d--send process (funcall specs)))
+            ((< delay 0) (push (run-at-time (- delay) nil #'erc-d--send
+                                            process (funcall specs))
+                               (erc-d-dialog-timers dialog)))
+            ((setf deferred t (erc-d-exchange-deferred exchange) deferred))))
+    delay))
+
+(defun erc-d--add-dialog-linger (dialog exchange)
+  "Add finalizer for EXCHANGE in DIALOG."
+  (erc-d--m (erc-d-dialog-process dialog)
+            "Lingering for %.2f seconds" (erc-d-exchange-timeout exchange))
+  (let ((start (current-time)))
+    (setf (erc-d-dialog-finalizer dialog)
+          (lambda (&rest _)
+            (erc-d--m (erc-d-dialog-process dialog)
+                      "Lingered for %.2f seconds"
+                      (float-time (time-subtract (current-time) start)))
+            (erc-d--teardown-this-dialog-at-least dialog)))))
+
+(defun erc-d--add-dialog-drop (dialog exchange)
+  "Add finalizer for EXCHANGE in DIALOG."
+  (erc-d--m (erc-d-dialog-process dialog)
+            "Dropping in %.2f seconds" (erc-d-exchange-timeout exchange))
+  (setf (erc-d-dialog-finalizer dialog)
+        (lambda (&rest _)
+          (erc-d--m (erc-d-dialog-process dialog)
+                    "Dropping %S" (erc-d-dialog-name dialog))
+          (erc-d--finalize-dialog dialog))))
+
+(defun erc-d--create-exchange (dialog hunk)
+  "Initialize next exchange HUNK for DIALOG."
+  (let* ((spec (make-erc-d-spec))
+         (exchange (make-erc-d-exchange :dialog dialog :hunk hunk :spec spec))
+         (specs (erc-d--iter exchange)))
+    (setf (erc-d-exchange-tag exchange) (funcall specs)
+          (erc-d-exchange-timeout exchange) (funcall specs t)
+          (erc-d-exchange-pattern exchange) (funcall specs))
+    (cond ((erc-d--linger-p exchange)
+           (erc-d--add-dialog-linger dialog exchange))
+          ((erc-d--drop-p exchange)
+           (erc-d--add-dialog-drop dialog exchange)))
+    (setf (erc-d-exchange-timer exchange)
+          (run-at-time (erc-d-exchange-timeout exchange)
+                       nil #'erc-d--expire dialog exchange))
+    exchange))
+
+(defun erc-d--command-consider-prep-fail (dialog line exes)
+  (list 'error "Match failed: %S %S" line
+        (list :exes (mapcar #'erc-d-exchange-pattern
+                            (ring-elements exes))
+              :dialog (erc-d-dialog-name dialog))))
+
+(defun erc-d--command-consider-prep-success (dialog line exes matched)
+  (setf (erc-d-exchange-request matched) line
+        (erc-d-exchange-match-data matched) (match-data)
+        ;; Also add current to match history, indexed by exchange tag
+        (plist-get (erc-d-dialog-history dialog)
+                   (erc-d-exchange-tag matched))
+        (cons (match-data) line)) ; do we need to make a copy of this?
+  (cancel-timer (erc-d-exchange-timer matched))
+  (ring-remove exes (ring-member exes matched)))
+
+(cl-defun erc-d--command-consider (dialog)
+  "Maybe return next matched exchange for DIALOG.
+Upon encountering a mismatch, return an error of the form (ERROR-SYMBOL
+DATA).  But when only fuzzies remain in the exchange pool, return nil."
+  (let* ((parsed (erc-d-dialog-message dialog))
+         (line (erc-d-i-message.unparsed parsed))
+         (exes (erc-d-dialog-exchanges dialog))
+         ;;
+         matched)
+    (let ((elts (ring-elements exes)))
+      (while (and (setq matched (pop elts))
+                  (not (string-match (erc-d-exchange-pattern matched) line)))
+        (if (and (not elts) (erc-d--fuzzy-p matched))
+            ;; Nothing to do, so advance
+            (cl-return-from erc-d--command-consider nil)
+          (cl-assert (or (not elts) (erc-d--fuzzy-p matched))))))
+    (if matched
+        (erc-d--command-consider-prep-success dialog line exes matched)
+      (erc-d--command-consider-prep-fail dialog line exes))))
+
+(defun erc-d--active-ex-p (ring)
+  "Return non-nil when RING has a non-fuzzy exchange.
+That is, return nil when RING is empty or when it only has exchanges
+with leading-tilde tags."
+  (let ((i 0)
+        (len (ring-length ring))
+        ex found)
+    (while (and (not found) (< i len))
+      (unless (erc-d--fuzzy-p (setq ex (ring-ref ring i)))
+        (setq found ex))
+      (cl-incf i))
+    found))
+
+(defun erc-d--finalize-done (dialog)
+  ;; Linger logic for individual dialogs is handled elsewhere
+  (if-let ((finalizer (erc-d-dialog-finalizer dialog)))
+      (funcall finalizer dialog)
+    (let ((d (process-get (erc-d-dialog-process dialog) :dialog-linger-secs)))
+      (push (run-at-time d nil #'erc-d--teardown)
+            (erc-d-dialog-timers dialog)))))
+
+(defun erc-d--advance-or-die (dialog)
+  "Govern the lifetime of DIALOG.
+Replenish exchanges from reader and insert them into the pool of
+expected matches, as produced.  Return a symbol indicating session
+status: deferring, matching, depleted, or done."
+  (let ((exes (erc-d-dialog-exchanges dialog))
+        hunk)
+    (cond ((erc-d--active-ex-p exes) 'deferring)
+          ((setq hunk (erc-d-u--read-dialog (erc-d-dialog-hunks dialog)))
+           (let ((exchange (erc-d--create-exchange dialog hunk)))
+             (if (erc-d--fuzzy-p exchange)
+                 (ring-insert exes exchange)
+               (ring-insert-at-beginning exes exchange)))
+           'matching)
+          ((not (ring-empty-p exes)) 'depleted)
+          (t 'done))))
+
+(defun erc-d--command-meter-replies (dialog exchange &optional cmd)
+  "Ignore requests until all replies have been sent.
+Do this for some previously matched EXCHANGE in DIALOG based on CMD, a
+symbol.  As a side effect, maybe schedule the resumption of the main
+loop after some delay."
+  (let (delay)
+    (if (or (not cmd) (eq 'resume cmd))
+        (when (setq delay (erc-d--send-outgoing dialog exchange))
+          (push (run-at-time delay nil #'erc-d--command-handle-all
+                             dialog 'resume)
+                (erc-d-dialog-timers dialog))
+          (erc-d-dialog-state dialog))
+      (setf (erc-d-dialog-state dialog) 'sending))))
+
+(defun erc-d--die-unexpected (dialog)
+  (erc-d--teardown 'error "Received unexpected input: %S"
+                   (erc-d-i-message.unparsed (erc-d-dialog-message dialog))))
+
+(defun erc-d--command-refresh (dialog matched)
+  (let ((state (erc-d--advance-or-die dialog)))
+    (when (eq state 'done)
+      (erc-d--finalize-done dialog))
+    (unless matched
+      (when (eq state 'depleted)
+        (erc-d--die-unexpected dialog))
+      (cl-assert (memq state '(matching depleted)) t))
+    (setf (erc-d-dialog-state dialog) state)))
+
+(defun erc-d--command-handle-all (dialog cmd)
+  "Create handler to act as control agent and process DIALOG requests.
+Have it ingest internal control commands (lowercase symbols) and yield
+back others indicating the lifecycle stage of the current dialog."
+  (let ((matched (erc-d-dialog-matched dialog)))
+    (cond
+     (matched
+      (or (erc-d--command-meter-replies dialog matched cmd)
+          (setf (erc-d-dialog-matched dialog) nil)
+          (erc-d--command-refresh dialog t)))
+     ((pcase cmd ; FIXME remove command facility or make extensible
+        ('resume nil)
+        ('eof (erc-d--m (erc-d-dialog-process dialog) "Received an EOF") nil)))
+     (t ; matching
+      (setq matched nil)
+      (catch 'yield
+        (while (not matched)
+          (when (ring-empty-p (erc-d-dialog-exchanges dialog))
+            (erc-d--die-unexpected dialog))
+          (when (setq matched (erc-d--command-consider dialog))
+            (if (eq (car-safe matched) 'error)
+                (apply #'erc-d--teardown matched)
+              (erc-d-on-match dialog matched)
+              (setf (erc-d-dialog-matched dialog) matched)
+              (if-let ((s (erc-d--command-meter-replies dialog matched nil)))
+                  (throw 'yield s)
+                (setf (erc-d-dialog-matched dialog) nil))))
+          (erc-d--command-refresh dialog matched)))))))
+
+;;;; Handlers for IRC commands
+
+(cl-defgeneric erc-d-command (dialog cmd)
+  "Handle new CMD from client for DIALOG.
+By default, defer to this dialog's `erc-d--command-handle-all' instance,
+which is stored in its `handler' field.")
+
+(cl-defmethod erc-d-command ((dialog erc-d-dialog) cmd)
+  (when (eq 'sending (erc-d--command-handle-all dialog cmd))
+    (ring-insert-at-beginning (erc-d-dialog-queue dialog)
+                              (erc-d-dialog-message dialog))))
+
+;; A similar PONG handler would be useless because we know when to
+;; expect them
+
+(cl-defmethod erc-d-command ((dialog erc-d-dialog) (_cmd (eql PING))
+                             &context (erc-d-auto-pong (eql t)))
+  "Respond to PING request from DIALOG peer when ERC-D-AUTO-PONG is t."
+  (let* ((parsed (erc-d-dialog-message dialog))
+         (process (erc-d-dialog-process dialog))
+         (nonce (car (erc-d-i-message.command-args parsed)))
+         (fqdn (erc-d-dialog-server-fqdn dialog)))
+    (erc-d--send process (format ":%s PONG %s :%s" fqdn fqdn nonce))))
+
+
+;;;; Entry points
+
+(defun erc-d-run (host service &optional server-name &rest dialogs)
+  "Start serving DIALOGS on HOST at SERVICE.
+Pass HOST and SERVICE directly to `make-network-process'.  When present,
+use string SERVER-NAME for the server-process name as well as that of
+its buffer (w. surrounding asterisks).  When absent, do the same with
+`erc-d-server-name'.  When running \"in process,\" return the server
+process; otherwise sleep until it dies.
+
+A dialog must be a symbol matching the base name of a dialog file in
+`erc-d-u-canned-dialog-dir'.  Global variables `erc-d-server-fqdn',
+`erc-d-linger-secs', and `erc-d-tmpl-vars' determine the process's
+`erc-d-dialog' fields `:server-fqdn', `:linger-secs', and `:vars',
+respectively.  The latter may also be populated via keyword pairs
+appearing among DIALOGS."
+  (when (and server-name (symbolp server-name))
+    (push server-name dialogs)
+    (setq server-name nil))
+  (let (loaded kwds defaults args)
+    (while dialogs
+      (if-let* ((dlog (pop dialogs))
+                ((keywordp dlog)))
+          (progn (push (pop dialogs) kwds) (push dlog kwds))
+        (let ((reader (erc-d-u--canned-load-dialog dlog)))
+          (when erc-d--slow-mo
+            (setq reader (erc-d-u--rewrite-for-slow-mo erc-d--slow-mo reader)))
+          (push (cons (erc-d-u--normalize-canned-name dlog) reader) loaded))))
+    (setq kwds (erc-d-u--unkeyword kwds)
+          defaults `((ending . ,erc-d-line-ending)
+                     (server-fqdn . ,erc-d-server-fqdn)
+                     (linger-secs . ,erc-d-linger-secs)
+                     (vars . ,(or (plist-get kwds 'tmpl-vars) erc-d-tmpl-vars))
+                     (dialogs . ,(nreverse loaded)))
+          args (list :dialog-match-handlers
+                     (erc-d-u--unkeyword (or (plist-get kwds 'match-handlers)
+                                             erc-d-match-handlers))))
+    (pcase-dolist (`(,var . ,def) defaults)
+      (push (or (plist-get kwds var) def) args)
+      (push (intern (format ":dialog-%s" var)) args))
+    (apply #'erc-d--start host service (or server-name erc-d-server-name)
+           args)))
+
+(defun erc-d-serve ()
+  "Start serving canned dialogs from the command line.
+Although not autoloaded, this function is meant to be summoned via the
+Emacs -f flag while starting a batch session.  It prints incoming and
+outgoing messages to standard out.
+
+The main options are --host HOST and --port PORT, which default to
+localhost and auto, respectively.  The args are the dialogs to run.
+Unlike with `erc-d-run', dialogs here *must* be files, meaning Lisp-Data
+files adhering to the required format.  (These consist of \"specs\"
+detailing timing and template info; see commentary for specifics.)
+
+An optional --add-time N option can also be passed to hike up timeouts
+by some number of seconds N.  For example, you might run:
+
+  $ emacs -Q -batch -L . \\
+  >   -l erc-d.el \\
+  >   -f erc-d-serve \\
+  >   --host 192.168.124.1 \\
+  >   --port 16667 \\
+  >   --add-time 10 \\
+  >   ./my-dialog.eld
+
+from a Makefile or manually with \\<global-map>\\[compile]. And then in
+another terminal, do:
+
+  $ nc -C 192.168.124.1 16667 ; or telnet if your nc doesn't have -C
+  > PASS changeme
+  ...
+
+Use `erc-d-run' instead to start the server from within Emacs."
+  (unless noninteractive
+    (error "Command-line func erc-d-serve not run in -batch session"))
+  (setq erc-d--in-process nil)
+  (let (port host dialogs erc-d--slow-mo)
+    (while command-line-args-left
+      (pcase (pop command-line-args-left)
+        ("--add-time" (setq erc-d--slow-mo
+                            (string-to-number (pop command-line-args-left))))
+        ("--linger" (setq erc-d-linger-secs
+                          (string-to-number (pop command-line-args-left))))
+        ("--host" (setq host (pop command-line-args-left)))
+        ("--port" (setq port (string-to-number (pop command-line-args-left))))
+        (dialog (push dialog dialogs))))
+    (setq dialogs (mapcar #'erc-d-u--massage-canned-name dialogs))
+    (when erc-d--slow-mo
+      (message "Slow mo is ON"))
+    (apply #'erc-d-run (or host "localhost") port nil (nreverse dialogs))))
+
+(provide 'erc-d)
+
+;;; erc-d.el ends here
diff --git a/test/lisp/erc/resources/erc-d/resources/basic.eld 
b/test/lisp/erc/resources/erc-d/resources/basic.eld
new file mode 100644
index 0000000000..a020eec3ff
--- /dev/null
+++ b/test/lisp/erc/resources/erc-d/resources/basic.eld
@@ -0,0 +1,32 @@
+;;; -*- mode: lisp-data -*-
+
+((pass 10.0 "PASS " (? ?:) "changeme"))
+((nick 0.2 "NICK tester"))
+
+((user 0.2 "USER user 0 * :tester")
+ (0 ":irc.example.org 001 tester :Welcome to the Internet Relay Network 
tester")
+ (0 ":irc.example.org 002 tester :Your host is irc.example.org")
+ (0 ":irc.example.org 003 tester :This server was created just now")
+ (0 ":irc.example.org 004 tester irc.example.org BERios CEIRabehiklmnoqstv 
Iabehkloqv")
+ (0 ":irc.example.org 005 tester MODES NETWORK=ExampleOrg NICKLEN=32 
PREFIX=(qaohv)~&@%+"
+    " :are supported by this server")
+ (0 ":irc.example.org 251 tester :There are 3 users and 0 invisible on 1 
server(s)")
+ ;; Just to mix thing's up (force handler to schedule timer)
+ (0.1 ":irc.example.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.example.org 253 tester 0 :unregistered connections")
+ (0 ":irc.example.org 254 tester 1 :channels formed")
+ (0 ":irc.example.org 255 tester :I have 3 clients and 0 servers")
+ (0.1 ":irc.example.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.example.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.example.org 422 tester :MOTD File is missing"))
+
+((mode-user 5 "MODE tester +i")
+ (0 ":irc.example.org 221 tester +Zi")
+ (0 ":irc.example.org 306 tester :You have been marked as being away")
+ (0 ":tester!~tester@localhost JOIN #chan")
+ (0 ":irc.example.org 353 alice = #chan :+alice!~alice@example.com 
@%+bob!~bob@example.org")
+ (0 ":irc.example.org 366 alice #chan :End of NAMES list"))
+
+;; Some comment (to prevent regression)
+((mode-chan 1.2 "MODE #chan")
+ (0.1 ":bob!~bob@example.org PRIVMSG #chan :hey"))
diff --git a/test/lisp/erc/resources/erc-d/resources/depleted.eld 
b/test/lisp/erc/resources/erc-d/resources/depleted.eld
new file mode 100644
index 0000000000..e5a7f03efb
--- /dev/null
+++ b/test/lisp/erc/resources/erc-d/resources/depleted.eld
@@ -0,0 +1,12 @@
+;;; -*- mode: lisp-data -*-
+
+((pass 10.0 "PASS :changeme"))
+
+((~fake 3.2 "FAKE ")
+ (0.1 ":irc.example.org FAKE irc.example.com :ok"))
+
+((nick 0.2 "NICK tester"))
+
+((user 0.2 "USER user 0 * :tester")
+ (0 ":irc.example.org 001 tester :Welcome to the Internet tester")
+ (0 ":irc.example.org 422 tester :MOTD File is missing"))
diff --git a/test/lisp/erc/resources/erc-d/resources/drop-a.eld 
b/test/lisp/erc/resources/erc-d/resources/drop-a.eld
new file mode 100644
index 0000000000..2e23eeb20f
--- /dev/null
+++ b/test/lisp/erc/resources/erc-d/resources/drop-a.eld
@@ -0,0 +1,4 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS " (? ?:) "a")
+ (0 "hi"))
+((drop 0.01 DROP))
diff --git a/test/lisp/erc/resources/erc-d/resources/drop-b.eld 
b/test/lisp/erc/resources/erc-d/resources/drop-b.eld
new file mode 100644
index 0000000000..facecd5e81
--- /dev/null
+++ b/test/lisp/erc/resources/erc-d/resources/drop-b.eld
@@ -0,0 +1,4 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS " (? ?:) "b")
+ (0 "hi"))
+((linger 1 LINGER))
diff --git a/test/lisp/erc/resources/erc-d/resources/dynamic-barnet.eld 
b/test/lisp/erc/resources/erc-d/resources/dynamic-barnet.eld
new file mode 100644
index 0000000000..36b1cc2308
--- /dev/null
+++ b/test/lisp/erc/resources/erc-d/resources/dynamic-barnet.eld
@@ -0,0 +1,33 @@
+;;; -*- mode: lisp-data -*-
+((fake 0 "FAKE noop"))
+
+((nick 1.2 "NICK tester"))
+
+((user 2.2 "USER user 0 * :tester")
+ (0. ":irc.barnet.org 001 tester :Welcome to the BAR Network tester")
+ (0. ":irc.barnet.org 002 tester :Your host is irc.barnet.org")
+ (0. ":irc.barnet.org 003 tester :This server was created just now")
+ (0. ":irc.barnet.org 004 tester irc.barnet.org BERios CEIRabehiklmnoqstv 
Iabehkloqv")
+ (0. ":irc.barnet.org 005 tester MODES NETWORK=BarNet NICKLEN=32 
PREFIX=(qaohv)~&@%+ :are supported by this server")
+ (0. ":irc.barnet.org 251 tester :There are 3 users and 0 invisible on 1 
server(s)")
+ (0. ":irc.barnet.org 252 tester 0 :IRC Operators online")
+ (0. ":irc.barnet.org 253 tester 0 :unregistered connections")
+ (0. ":irc.barnet.org 254 tester 1 :channels formed")
+ (0. ":irc.barnet.org 255 tester :I have 3 clients and 0 servers")
+ (0. ":irc.barnet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0. ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0. ":irc.barnet.org 422 tester :MOTD File is missing"))
+
+((mode-user 1.2 "MODE tester +i")
+ (0. ":irc.barnet.org 221 tester +Zi")
+ (0. ":irc.barnet.org 306 tester :You have been marked as being away")
+ (0 ":tester!~u@awyxgybtkx7uq.irc JOIN #chan")
+ (0 ":irc.barnet.org 353 joe = #chan :+joe!~joe@example.com 
@%+mike!~mike@example.org")
+ (0 ":irc.barnet.org 366 joe #chan :End of NAMES list"))
+
+((mode 1 "MODE #chan")
+ (0 ":irc.barnet.org 324 tester #chan +nt")
+ (0 ":irc.barnet.org 329 tester #chan 1620805269")
+ (0.1 ":joe!~u@awyxgybtkx7uq.irc PRIVMSG #chan :mike: Yes, a dozen; and as 
many to the vantage, as would store the world they played for.")
+ (0.05 ":mike!~u@awyxgybtkx7uq.irc PRIVMSG #chan :joe: As he regards his aged 
father's life.")
+ (0.05 ":joe!~u@awyxgybtkx7uq.irc PRIVMSG #chan :mike: It is a rupture that 
you may easily heal; and the cure of it not only saves your brother, but keeps 
you from dishonour in doing it."))
diff --git a/test/lisp/erc/resources/erc-d/resources/dynamic-foonet.eld 
b/test/lisp/erc/resources/erc-d/resources/dynamic-foonet.eld
new file mode 100644
index 0000000000..5dbea50f86
--- /dev/null
+++ b/test/lisp/erc/resources/erc-d/resources/dynamic-foonet.eld
@@ -0,0 +1,32 @@
+;;; -*- mode: lisp-data -*-
+
+((nick 1.2 "NICK tester"))
+
+((user 2.2 "USER user 0 * :tester")
+ (0. ":irc.foonet.org 001 tester :Welcome to the FOO Network tester")
+ (0. ":irc.foonet.org 002 tester :Your host is irc.foonet.org")
+ (0. ":irc.foonet.org 003 tester :This server was created just now")
+ (0. ":irc.foonet.org 004 tester irc.foonet.org BERios CEIRabehiklmnoqstv 
Iabehkloqv")
+ (0. ":irc.foonet.org 005 tester MODES NETWORK=FooNet NICKLEN=32 
PREFIX=(qaohv)~&@%+ :are supported by this server")
+ (0. ":irc.foonet.org 251 tester :There are 3 users and 0 invisible on 1 
server(s)")
+ (0. ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0. ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (0. ":irc.foonet.org 254 tester 1 :channels formed")
+ (0. ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0. ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0. ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0. ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 1.2 "MODE tester +i")
+ (0. ":irc.foonet.org 221 tester +Zi")
+ (0. ":irc.foonet.org 306 tester :You have been marked as being away")
+ (0 ":tester!~u@awyxgybtkx7uq.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 alice = #chan :+alice!~alice@example.com 
@%+bob!~bob@example.org")
+ (0 ":irc.foonet.org 366 alice #chan :End of NAMES list"))
+
+((mode 2 "MODE #chan")
+ (0 ":irc.foonet.org 324 tester #chan +nt")
+ (0 ":irc.foonet.org 329 tester #chan 1620805269")
+ (0.1 ":alice!~u@awyxgybtkx7uq.irc PRIVMSG #chan :bob: Yes, a dozen; and as 
many to the vantage, as would store the world they played for.")
+ (0.05 ":bob!~u@awyxgybtkx7uq.irc PRIVMSG #chan :alice: As he regards his aged 
father's life.")
+ (0.05 ":alice!~u@awyxgybtkx7uq.irc PRIVMSG #chan :bob: It is a rupture that 
you may easily heal; and the cure of it not only saves your brother, but keeps 
you from dishonour in doing it."))
diff --git a/test/lisp/erc/resources/erc-d/resources/dynamic-stub.eld 
b/test/lisp/erc/resources/erc-d/resources/dynamic-stub.eld
new file mode 100644
index 0000000000..d93313023d
--- /dev/null
+++ b/test/lisp/erc/resources/erc-d/resources/dynamic-stub.eld
@@ -0,0 +1,4 @@
+;;; -*- mode: lisp-data -*-
+((pass 10.0 "PASS " (? ?:) token ":changeme"))
+
+((fake 0 "FAKE"))
diff --git a/test/lisp/erc/resources/erc-d/resources/dynamic.eld 
b/test/lisp/erc/resources/erc-d/resources/dynamic.eld
new file mode 100644
index 0000000000..459b6e52bf
--- /dev/null
+++ b/test/lisp/erc/resources/erc-d/resources/dynamic.eld
@@ -0,0 +1,30 @@
+;;; -*- mode: lisp-data -*-
+((pass 10.0 "PASS " (? ?:) "changeme"))
+((nick 2.2 "NICK tester"))
+
+((user 2.2 "USER " user " " (ignored digit "*") " :" realname)
+ (0.0 ":" dom " 001 " nick " :Welcome to the Internet Relay Network tester")
+ (0.0 ":" dom " 002 " nick " :Your host is " dom)
+ (0.0 ":" dom " 003 " nick " :This server was created just now")
+ (0.0 ":" dom " 004 " nick " " dom " BERios CEIRabehiklmnoqstv Iabehkloqv")
+ (0.0 ":" dom " 005 " nick " MODES NETWORK=ExampleOrg NICKLEN=32 
PREFIX=(qaohv)~&@%+"
+      " :are supported by this server")
+ (0.0 ":" dom " 251 " nick " :There are 3 users and 0 invisible on 1 
server(s)")
+ (0.0 ":" dom " 252 " nick " 0 :IRC Operators online")
+ (0.0 ":" dom " 253 " nick " 0 :unregistered connections")
+ (0.0 ":" dom " 254 " nick " 1 :channels formed")
+ (0.0 ":" dom " 255 " nick " :I have 3 clients and 0 servers")
+ (0.0 ":" dom " 265 " nick " 3 3 :Current local users 3, max 3")
+ (0.0 ":" dom " 266 " nick " 3 3 :Current global users 3, max 3")
+ (0.0 ":" dom " 422 " nick " :MOTD File is missing"))
+
+((mode-user 2.2 "MODE tester +i")
+ (0.0 ":" dom " 221 " nick " +Zi")
+
+ (0.0 ":" dom " 306 " nick " :You have been marked as being away")
+ (0.0 ":" nick "!~" nick "@localhost JOIN #chan")
+ (0.0 ":" dom " 353 alice = #chan :+alice!~alice@example.com 
@%+bob!~bob@example.org")
+ (0.0 ":" dom " 366 alice #chan :End of NAMES list"))
+
+((mode 2.2 "MODE #chan")
+ (0.1 ":bob!~bob@example.org PRIVMSG #chan :" nick ": hey"))
diff --git a/test/lisp/erc/resources/erc-d/resources/eof.eld 
b/test/lisp/erc/resources/erc-d/resources/eof.eld
new file mode 100644
index 0000000000..5da84b2e74
--- /dev/null
+++ b/test/lisp/erc/resources/erc-d/resources/eof.eld
@@ -0,0 +1,33 @@
+;;; -*- mode: lisp-data -*-
+
+((pass 10.0 "PASS " (? ?:) "changeme"))
+((nick 0.2 "NICK tester"))
+
+((user 0.2 "USER user 0 * :tester")
+ (0 ":irc.example.org 001 tester :Welcome to the Internet Relay Network 
tester")
+ (0 ":irc.example.org 002 tester :Your host is irc.example.org")
+ (0 ":irc.example.org 003 tester :This server was created just now")
+ (0 ":irc.example.org 004 tester irc.example.org BERios CEIRabehiklmnoqstv 
Iabehkloqv")
+ (0 ":irc.example.org 005 tester MODES NETWORK=ExampleOrg NICKLEN=32 
PREFIX=(qaohv)~&@%+"
+    " :are supported by this server")
+ (0 ":irc.example.org 251 tester :There are 3 users and 0 invisible on 1 
server(s)")
+ ;; Just to mix thing's up (force handler to schedule timer)
+ (0.1 ":irc.example.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.example.org 253 tester 0 :unregistered connections")
+ (0 ":irc.example.org 254 tester 1 :channels formed")
+ (0 ":irc.example.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.example.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.example.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.example.org 422 tester :MOTD File is missing"))
+
+((mode-user 1.2 "MODE tester +i")
+ (0 ":irc.example.org 221 tester +Zi")
+ (0 ":irc.example.org 306 tester :You have been marked as being away")
+ (0 ":tester!~tester@localhost JOIN #chan")
+ (0 ":irc.example.org 353 alice = #chan :+alice!~alice@example.com 
@%+bob!~bob@example.org")
+ (0 ":irc.example.org 366 alice #chan :End of NAMES list"))
+
+((mode-chan 1.2 "MODE #chan")
+ (0.1 ":bob!~bob@example.org PRIVMSG #chan :hey"))
+
+((eof 1.0 EOF))
diff --git a/test/lisp/erc/resources/erc-d/resources/foreign.eld 
b/test/lisp/erc/resources/erc-d/resources/foreign.eld
new file mode 100644
index 0000000000..64a5dca8b1
--- /dev/null
+++ b/test/lisp/erc/resources/erc-d/resources/foreign.eld
@@ -0,0 +1,5 @@
+;;; -*- mode: lisp-data -*-
+((one 5 "ONE one")
+ (0 "echo ONE one"))
+((two 5 "TWO two")
+ (0 "echo TWO two"))
diff --git a/test/lisp/erc/resources/erc-d/resources/fuzzy.eld 
b/test/lisp/erc/resources/erc-d/resources/fuzzy.eld
new file mode 100644
index 0000000000..0504b6a668
--- /dev/null
+++ b/test/lisp/erc/resources/erc-d/resources/fuzzy.eld
@@ -0,0 +1,42 @@
+;;; -*- mode: lisp-data -*-
+((pass 10.0 "PASS " (? ?:) "changeme"))
+((nick 0.2 "NICK tester"))
+
+((user 0.5 "USER user 0 * :tester")
+ (0.0 "@time=" now " :irc.org 001 tester :Welcome to the Internet Relay 
Network tester")
+ (0.0 "@time=" now " :irc.org 002 tester :Your host is irc.org")
+ (0.0 "@time=" now " :irc.org 003 tester :This server was created just now")
+ (0.0 "@time=" now " :irc.org 004 tester irc.org BERios CEIRabehiklmnoqstv 
Iabehkloqv")
+ (0.0 "@time=" now " :irc.org 005 tester MODES NETWORK=ExampleOrg NICKLEN=32 
PREFIX=(qaohv)~&@%+ :are supported by this server")
+ (0.0 "@time=" now " :irc.org 251 tester :There are 3 users and 0 invisible on 
1 server(s)")
+ (0.0 "@time=" now " :irc.org 252 tester 0 :IRC Operators online")
+ (0.0 "@time=" now " :irc.org 253 tester 0 :unregistered connections")
+ (0.0 "@time=" now " :irc.org 254 tester 1 :channels formed")
+ (0.0 "@time=" now " :irc.org 255 tester :I have 3 clients and 0 servers")
+ (0.0 "@time=" now " :irc.org 265 tester 3 3 :Current local users 3, max 3")
+ (0.0 "@time=" now " :irc.org 266 tester 3 3 :Current global users 3, max 3")
+ (0.0 "@time=" now " :irc.org 422 tester :MOTD File is missing"))
+
+((mode-user 1.2 "MODE tester +i")
+ (0.0 "@time=" now " :irc.org 221 tester +Zi")
+ (0.0 "@time=" now " :irc.org 306 tester :You have been marked as being away"))
+
+((~join-foo 3.2 "JOIN #foo")
+ (0 "@time=" now " :tester!~tester@localhost JOIN #foo")
+ (0 "@time=" now " :irc.example.org 353 alice = #foo 
:+alice!~alice@example.com @%+bob!~bob@example.org")
+ (0 "@time=" now " :irc.example.org 366 alice #foo :End of NAMES list"))
+
+((~join-bar 1.2 "JOIN #bar")
+ (0 "@time=" now " :tester!~tester@localhost JOIN #bar")
+ (0 "@time=" now " :irc.example.org 353 alice = #bar 
:+alice!~alice@example.com @%+bob!~bob@example.org")
+ (0 "@time=" now " :irc.example.org 366 alice #bar :End of NAMES list"))
+
+((~mode-foo 3.2 "MODE #foo")
+ (0.0 "@time=" now " :irc.example.org 324 tester #foo +Cint")
+ (0.0 "@time=" now " :irc.example.org 329 tester #foo 1519850102")
+ (0.1 "@time=" now " :bob!~bob@example.org PRIVMSG #foo :hey"))
+
+((mode-bar 10.2 "MODE #bar")
+ (0.0 "@time=" now " :irc.example.org 324 tester #bar +HMfnrt 50:5h :10:5")
+ (0.0 "@time=" now " :irc.example.org 329 tester #bar :1602642829")
+ (0.1 "@time=" now " :alice!~alice@example.com PRIVMSG #bar :hi"))
diff --git a/test/lisp/erc/resources/erc-d/resources/incremental.eld 
b/test/lisp/erc/resources/erc-d/resources/incremental.eld
new file mode 100644
index 0000000000..a1b48495ec
--- /dev/null
+++ b/test/lisp/erc/resources/erc-d/resources/incremental.eld
@@ -0,0 +1,43 @@
+;;; -*- mode: lisp-data -*-
+((pass 10.0 "PASS " (? ?:) "changeme"))
+((nick 0.2 "NICK tester"))
+
+((user 0.2 "USER user 0 * :tester")
+ (0.0 ":irc.foo.net 001 tester :Welcome to the Internet Relay Network tester")
+ (0.0 ":irc.foo.net 002 tester :Your host is irc.foo.net")
+ (0.0 ":irc.foo.net 003 tester :This server was created just now")
+ (0.0 ":irc.foo.net 004 tester irc.foo.net BERios CEIRabehiklmnoqstv 
Iabehkloqv")
+ (0.0 ":irc.foo.net 005 tester MODES NETWORK=FooNet NICKLEN=32 
PREFIX=(qaohv)~&@%+"
+              " :are supported by this server")
+ (0.0 ":irc.foo.net 251 tester :There are 3 users and 0 invisible on 1 
server(s)")
+ (0.0 ":irc.foo.net 252 tester 0 :IRC Operators online")
+ (0.0 ":irc.foo.net 253 tester 0 :unregistered connections")
+ (0.0 ":irc.foo.net 254 tester 1 :channels formed")
+ (0.0 ":irc.foo.net 255 tester :I have 3 clients and 0 servers")
+ (0.0 ":irc.foo.net 265 tester 3 3 :Current local users 3, max 3")
+ (0.0 ":irc.foo.net 266 tester 3 3 :Current global users 3, max 3")
+ (0.0 ":irc.foo.net 422 tester :MOTD File is missing"))
+
+((mode-user 1.2 "MODE tester +i")
+ (0.0 ":irc.foo.net 221 tester +Zi")
+ (0.0 ":irc.foo.net 306 tester :You have been marked as being away"))
+
+((join 3 "JOIN #foo")
+ (0 ":tester!~tester@localhost JOIN #foo")
+ (0 ":irc.foo.net 353 alice = #foo :+alice!~alice@example.com 
@%+bob!~bob@example.org")
+ (0 ":irc.foo.net 366 alice #foo :End of NAMES list"))
+
+((mode 3 "MODE #foo")
+ (0.0 ":irc.foo.net 324 tester #foo +Cint")
+ (0.0 ":irc.foo.net 329 tester #foo 1519850102")
+ (0.1 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #foo :alice: But, in defense, by 
mercy, 'tis most just.")
+ (0.1 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #foo :bob: Grows, lives, and dies, 
in single blessedness.")
+ (0.1 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #foo :Look for me.")
+ (0.1 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #foo :bob: By this hand, it will 
not kill a fly. But come, now I will be your Rosalind in a more coming-on 
disposition; and ask me what you will, I will grant it.")
+ (0.1 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #foo :alice: That I must love a 
loathed enemy.")
+ (0.1 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #foo :bob: As't please your 
lordship: I'll leave you.")
+ (0.1 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #foo :alice: Then there is no true 
lover in the forest; else sighing every minute and groaning every hour would 
detect the lazy foot of Time as well as a clock.")
+ (0.1 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #foo :bob: His discretion, I am 
sure, cannot carry his valour, for the goose carries not the fox. It is well: 
leave it to his discretion, and let us listen to the moon.")
+ (0.1 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #foo :Done"))
+
+((hi 10 "PRIVMSG #foo :Hi"))
diff --git a/test/lisp/erc/resources/erc-d/resources/irc-parser-tests.eld 
b/test/lisp/erc/resources/erc-d/resources/irc-parser-tests.eld
new file mode 100644
index 0000000000..168569f548
--- /dev/null
+++ b/test/lisp/erc/resources/erc-d/resources/irc-parser-tests.eld
@@ -0,0 +1,380 @@
+;;; -*- mode: lisp-data; -*-
+
+;; https://github.com/DanielOaks/irc-parser-tests
+((mask-match
+  (tests
+   ((mask . "*@127.0.0.1")
+    (matches "coolguy!ab@127.0.0.1" "cooldud3!~bc@127.0.0.1")
+    (fails "coolguy!ab@127.0.0.5" "cooldud3!~d@124.0.0.1"))
+   ((mask . "cool*@*")
+    (matches "coolguy!ab@127.0.0.1" "cooldud3!~bc@127.0.0.1" 
"cool132!ab@example.com")
+    (fails "koolguy!ab@127.0.0.5" "cooodud3!~d@124.0.0.1"))
+   ((mask . "cool!*@*")
+    (matches "cool!guyab@127.0.0.1" "cool!~dudebc@127.0.0.1" 
"cool!312ab@example.com")
+    (fails "coolguy!ab@127.0.0.1" "cooldud3!~bc@127.0.0.1" 
"koolguy!ab@127.0.0.5" "cooodud3!~d@124.0.0.1"))
+   ((mask . "cool!?username@*")
+    (matches "cool!ausername@127.0.0.1" "cool!~username@127.0.0.1")
+    (fails "cool!username@127.0.0.1"))
+   ((mask . "cool!a?*@*")
+    (matches "cool!ab@127.0.0.1" "cool!abc@127.0.0.1")
+    (fails "cool!a@127.0.0.1"))
+   ((mask . "cool[guy]!*@*")
+    (matches "cool[guy]!guy@127.0.0.1" "cool[guy]!a@example.com")
+    (fails "coolg!ab@127.0.0.1" "cool[!ac@127.0.1.1"))))
+ (msg-join
+  (tests
+   ((desc . "Simple test with verb and params.")
+    (atoms
+     (verb . "foo")
+     (params "bar" "baz" "asdf"))
+    (matches "foo bar baz asdf" "foo bar baz :asdf"))
+   ((desc . "Simple test with source and no params.")
+    (atoms
+     (source . "src")
+     (verb . "AWAY"))
+    (matches ":src AWAY"))
+   ((desc . "Simple test with source and empty trailing param.")
+    (atoms
+     (source . "src")
+     (verb . "AWAY")
+     (params ""))
+    (matches ":src AWAY :"))
+   ((desc . "Simple test with source.")
+    (atoms
+     (source . "coolguy")
+     (verb . "foo")
+     (params "bar" "baz" "asdf"))
+    (matches ":coolguy foo bar baz asdf" ":coolguy foo bar baz :asdf"))
+   ((desc . "Simple test with trailing param.")
+    (atoms
+     (verb . "foo")
+     (params "bar" "baz" "asdf quux"))
+    (matches "foo bar baz :asdf quux"))
+   ((desc . "Simple test with empty trailing param.")
+    (atoms
+     (verb . "foo")
+     (params "bar" "baz" ""))
+    (matches "foo bar baz :"))
+   ((desc . "Simple test with trailing param containing colon.")
+    (atoms
+     (verb . "foo")
+     (params "bar" "baz" ":asdf"))
+    (matches "foo bar baz ::asdf"))
+   ((desc . "Test with source and trailing param.")
+    (atoms
+     (source . "coolguy")
+     (verb . "foo")
+     (params "bar" "baz" "asdf quux"))
+    (matches ":coolguy foo bar baz :asdf quux"))
+   ((desc . "Test with trailing containing beginning+end whitespace.")
+    (atoms
+     (source . "coolguy")
+     (verb . "foo")
+     (params "bar" "baz" "  asdf quux "))
+    (matches ":coolguy foo bar baz :  asdf quux "))
+   ((desc . "Test with trailing containing what looks like another trailing 
param.")
+    (atoms
+     (source . "coolguy")
+     (verb . "PRIVMSG")
+     (params "bar" "lol :) "))
+    (matches ":coolguy PRIVMSG bar :lol :) "))
+   ((desc . "Simple test with source and empty trailing.")
+    (atoms
+     (source . "coolguy")
+     (verb . "foo")
+     (params "bar" "baz" ""))
+    (matches ":coolguy foo bar baz :"))
+   ((desc . "Trailing contains only spaces.")
+    (atoms
+     (source . "coolguy")
+     (verb . "foo")
+     (params "bar" "baz" "  "))
+    (matches ":coolguy foo bar baz :  "))
+   ((desc . "Param containing tab (tab is not considered SPACE for message 
splitting).")
+    (atoms
+     (source . "coolguy")
+     (verb . "foo")
+     (params "b        ar" "baz"))
+    (matches ":coolguy foo b   ar baz" ":coolguy foo b ar :baz"))
+   ((desc . "Tag with no value and space-filled trailing.")
+    (atoms
+     (tags
+      (asd . ""))
+     (source . "coolguy")
+     (verb . "foo")
+     (params "bar" "baz" "  "))
+    (matches "@asd :coolguy foo bar baz :  "))
+   ((desc . "Tags with escaped values.")
+    (atoms
+     (verb . "foo")
+     (tags
+      (a . "b\\and\nk")
+      (d . "gh;764")))
+    (matches "@a=b\\\\and\\nk;d=gh\\:764 foo" "@d=gh\\:764;a=b\\\\and\\nk 
foo"))
+   ((desc . "Tags with escaped values and params.")
+    (atoms
+     (verb . "foo")
+     (tags
+      (a . "b\\and\nk")
+      (d . "gh;764"))
+     (params "par1" "par2"))
+    (matches "@a=b\\\\and\\nk;d=gh\\:764 foo par1 par2" 
"@a=b\\\\and\\nk;d=gh\\:764 foo par1 :par2" "@d=gh\\:764;a=b\\\\and\\nk foo 
par1 par2" "@d=gh\\:764;a=b\\\\and\\nk foo par1 :par2"))
+   ((desc . "Tag with long, strange values (including LF and newline).")
+    (atoms
+     (tags
+      (foo . "\\\\;\\s 
\n"))
+     (verb . "COMMAND"))
+    (matches "@foo=\\\\\\\\\\:\\\\s\\s\\r\\n COMMAND"))))
+ (msg-split
+  (tests
+   ((input . "foo bar baz asdf")
+    (atoms
+     (verb . "foo")
+     (params "bar" "baz" "asdf")))
+   ((input . ":coolguy foo bar baz asdf")
+    (atoms
+     (source . "coolguy")
+     (verb . "foo")
+     (params "bar" "baz" "asdf")))
+   ((input . "foo bar baz :asdf quux")
+    (atoms
+     (verb . "foo")
+     (params "bar" "baz" "asdf quux")))
+   ((input . "foo bar baz :")
+    (atoms
+     (verb . "foo")
+     (params "bar" "baz" "")))
+   ((input . "foo bar baz ::asdf")
+    (atoms
+     (verb . "foo")
+     (params "bar" "baz" ":asdf")))
+   ((input . ":coolguy foo bar baz :asdf quux")
+    (atoms
+     (source . "coolguy")
+     (verb . "foo")
+     (params "bar" "baz" "asdf quux")))
+   ((input . ":coolguy foo bar baz :  asdf quux ")
+    (atoms
+     (source . "coolguy")
+     (verb . "foo")
+     (params "bar" "baz" "  asdf quux ")))
+   ((input . ":coolguy PRIVMSG bar :lol :) ")
+    (atoms
+     (source . "coolguy")
+     (verb . "PRIVMSG")
+     (params "bar" "lol :) ")))
+   ((input . ":coolguy foo bar baz :")
+    (atoms
+     (source . "coolguy")
+     (verb . "foo")
+     (params "bar" "baz" "")))
+   ((input . ":coolguy foo bar baz :  ")
+    (atoms
+     (source . "coolguy")
+     (verb . "foo")
+     (params "bar" "baz" "  ")))
+   ((input . "@a=b;c=32;k;rt=ql7 foo")
+    (atoms
+     (verb . "foo")
+     (tags
+      (a . "b")
+      (c . "32")
+      (k . "")
+      (rt . "ql7"))))
+   ((input . "@a=b\\\\and\\nk;c=72\\s45;d=gh\\:764 foo")
+    (atoms
+     (verb . "foo")
+     (tags
+      (a . "b\\and\nk")
+      (c . "72 45")
+      (d . "gh;764"))))
+   ((input . "@c;h=;a=b :quux ab cd")
+    (atoms
+     (tags
+      (c . "")
+      (h . "")
+      (a . "b"))
+     (source . "quux")
+     (verb . "ab")
+     (params "cd")))
+   ((input . ":src JOIN #chan")
+    (atoms
+     (source . "src")
+     (verb . "JOIN")
+     (params "#chan")))
+   ((input . ":src JOIN :#chan")
+    (atoms
+     (source . "src")
+     (verb . "JOIN")
+     (params "#chan")))
+   ((input . ":src AWAY")
+    (atoms
+     (source . "src")
+     (verb . "AWAY")))
+   ((input . ":src AWAY ")
+    (atoms
+     (source . "src")
+     (verb . "AWAY")))
+   ((input . ":cool    guy foo bar baz")
+    (atoms
+     (source . "cool   guy")
+     (verb . "foo")
+     (params "bar" "baz")))
+   ((input . ":coolguy!ag@net5work.admin PRIVMSG foo :bar baz")
+    (atoms
+     (source . "coolguy!ag@net5work.admin")
+     (verb . "PRIVMSG")
+     (params "foo" "bar baz")))
+   ((input . ":coolguy!~ag@net05work.admin PRIVMSG foo :bar baz")
+    (atoms
+     (source . "coolguy!~ag@net05work.admin")
+     (verb . "PRIVMSG")
+     (params "foo" "bar baz")))
+   ((input . "@tag1=value1;tag2;vendor1/tag3=value2;vendor2/tag4= 
:irc.example.com COMMAND param1 param2 :param3 param3")
+    (atoms
+     (tags
+      (tag1 . "value1")
+      (tag2 . "")
+      (vendor1/tag3 . "value2")
+      (vendor2/tag4 . ""))
+     (source . "irc.example.com")
+     (verb . "COMMAND")
+     (params "param1" "param2" "param3 param3")))
+   ((input . ":irc.example.com COMMAND param1 param2 :param3 param3")
+    (atoms
+     (source . "irc.example.com")
+     (verb . "COMMAND")
+     (params "param1" "param2" "param3 param3")))
+   ((input . "@tag1=value1;tag2;vendor1/tag3=value2;vendor2/tag4 COMMAND 
param1 param2 :param3 param3")
+    (atoms
+     (tags
+      (tag1 . "value1")
+      (tag2 . "")
+      (vendor1/tag3 . "value2")
+      (vendor2/tag4 . ""))
+     (verb . "COMMAND")
+     (params "param1" "param2" "param3 param3")))
+   ((input . "COMMAND")
+    (atoms
+     (verb . "COMMAND")))
+   ((input . "@foo=\\\\\\\\\\:\\\\s\\s\\r\\n COMMAND")
+    (atoms
+     (tags
+      (foo . "\\\\;\\s 
\n"))
+     (verb . "COMMAND")))
+   ((input . ":gravel.mozilla.org 432  #momo :Erroneous Nickname: Illegal 
characters")
+    (atoms
+     (source . "gravel.mozilla.org")
+     (verb . "432")
+     (params "#momo" "Erroneous Nickname: Illegal characters")))
+   ((input . ":gravel.mozilla.org MODE #tckk +n ")
+    (atoms
+     (source . "gravel.mozilla.org")
+     (verb . "MODE")
+     (params "#tckk" "+n")))
+   ((input . ":services.esper.net MODE #foo-bar +o foobar  ")
+    (atoms
+     (source . "services.esper.net")
+     (verb . "MODE")
+     (params "#foo-bar" "+o" "foobar")))
+   ((input . "@tag1=value\\\\ntest COMMAND")
+    (atoms
+     (tags
+      (tag1 . "value\\ntest"))
+     (verb . "COMMAND")))
+   ((input . "@tag1=value\\1 COMMAND")
+    (atoms
+     (tags
+      (tag1 . "value1"))
+     (verb . "COMMAND")))
+   ((input . "@tag1=value1\\ COMMAND")
+    (atoms
+     (tags
+      (tag1 . "value1"))
+     (verb . "COMMAND")))
+   ((input . "@tag1=1;tag2=3;tag3=4;tag1=5 COMMAND")
+    (atoms
+     (tags
+      (tag1 . "5")
+      (tag2 . "3")
+      (tag3 . "4"))
+     (verb . "COMMAND")))
+   ((input . "@tag1=1;tag2=3;tag3=4;tag1=5;vendor/tag2=8 COMMAND")
+    (atoms
+     (tags
+      (tag1 . "5")
+      (tag2 . "3")
+      (tag3 . "4")
+      (vendor/tag2 . "8"))
+     (verb . "COMMAND")))
+   ((input . ":SomeOp MODE #channel :+i")
+    (atoms
+     (source . "SomeOp")
+     (verb . "MODE")
+     (params "#channel" "+i")))
+   ((input . ":SomeOp MODE #channel +oo SomeUser :AnotherUser")
+    (atoms
+     (source . "SomeOp")
+     (verb . "MODE")
+     (params "#channel" "+oo" "SomeUser" "AnotherUser")))))
+ (userhost-split
+  (tests
+   ((source . "coolguy")
+    (atoms
+     (nick . "coolguy")))
+   ((source . "coolguy!ag@127.0.0.1")
+    (atoms
+     (nick . "coolguy")
+     (user . "ag")
+     (host . "127.0.0.1")))
+   ((source . "coolguy!~ag@localhost")
+    (atoms
+     (nick . "coolguy")
+     (user . "~ag")
+     (host . "localhost")))
+   ((source . "coolguy@127.0.0.1")
+    (atoms
+     (nick . "coolguy")
+     (host . "127.0.0.1")))
+   ((source . "coolguy!ag")
+    (atoms
+     (nick . "coolguy")
+     (user . "ag")))
+   ((source . "coolguy!ag@net5work.admin")
+    (atoms
+     (nick . "coolguy")
+     (user . "ag")
+     (host . "net5work.admin")))
+   ((source . "coolguy!~ag@net05work.admin")
+    (atoms
+     (nick . "coolguy")
+     (user . "~ag")
+     (host . "net05work.admin")))))
+ (validate-hostname
+  (tests
+   ((host . "irc.example.com")
+    (valid . t))
+   ((host . "i.coolguy.net")
+    (valid . t))
+   ((host . "irc-srv.net.uk")
+    (valid . t))
+   ((host . "iRC.CooLguY.NeT")
+    (valid . t))
+   ((host . "gsf.ds342.co.uk")
+    (valid . t))
+   ((host . "324.net.uk")
+    (valid . t))
+   ((host . "xn--bcher-kva.ch")
+    (valid . t))
+   ((host . "-lol-.net.uk")
+    (valid . :false))
+   ((host . "-lol.net.uk")
+    (valid . :false))
+   ((host . "_irc._sctp.lol.net.uk")
+    (valid . :false))
+   ((host . "irc")
+    (valid . :false))
+   ((host . "com")
+    (valid . :false))
+   ((host . "")
+    (valid . :false)))))
diff --git a/test/lisp/erc/resources/erc-d/resources/linger-multi-a.eld 
b/test/lisp/erc/resources/erc-d/resources/linger-multi-a.eld
new file mode 100644
index 0000000000..751500537d
--- /dev/null
+++ b/test/lisp/erc/resources/erc-d/resources/linger-multi-a.eld
@@ -0,0 +1,3 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS " (? ?:) "a"))
+((linger 100 LINGER))
\ No newline at end of file
diff --git a/test/lisp/erc/resources/erc-d/resources/linger-multi-b.eld 
b/test/lisp/erc/resources/erc-d/resources/linger-multi-b.eld
new file mode 100644
index 0000000000..c906c9e649
--- /dev/null
+++ b/test/lisp/erc/resources/erc-d/resources/linger-multi-b.eld
@@ -0,0 +1,3 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS " (? ?:) "b"))
+((linger 1 LINGER))
diff --git a/test/lisp/erc/resources/erc-d/resources/linger.eld 
b/test/lisp/erc/resources/erc-d/resources/linger.eld
new file mode 100644
index 0000000000..36c81a3af4
--- /dev/null
+++ b/test/lisp/erc/resources/erc-d/resources/linger.eld
@@ -0,0 +1,33 @@
+;;; -*- mode: lisp-data -*-
+
+((pass 10.0 "PASS " (? ?:) "changeme"))
+((nick 0.2 "NICK tester"))
+
+((user 0.2 "USER user 0 * :tester")
+ (0 ":irc.example.org 001 tester :Welcome to the Internet Relay Network 
tester")
+ (0 ":irc.example.org 002 tester :Your host is irc.example.org")
+ (0 ":irc.example.org 003 tester :This server was created just now")
+ (0 ":irc.example.org 004 tester irc.example.org BERios CEIRabehiklmnoqstv 
Iabehkloqv")
+ (0 ":irc.example.org 005 tester MODES NETWORK=ExampleOrg NICKLEN=32 
PREFIX=(qaohv)~&@%+"
+    " :are supported by this server")
+ (0 ":irc.example.org 251 tester :There are 3 users and 0 invisible on 1 
server(s)")
+ ;; Just to mix thing's up (force handler to schedule timer)
+ (0.1 ":irc.example.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.example.org 253 tester 0 :unregistered connections")
+ (0 ":irc.example.org 254 tester 1 :channels formed")
+ (0 ":irc.example.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.example.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.example.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.example.org 422 tester :MOTD File is missing"))
+
+((mode-user 1.2 "MODE tester +i")
+ (0 ":irc.example.org 221 tester +Zi")
+ (0 ":irc.example.org 306 tester :You have been marked as being away")
+ (0 ":tester!~tester@localhost JOIN #chan")
+ (0 ":irc.example.org 353 alice = #chan :+alice!~alice@example.com 
@%+bob!~bob@example.org")
+ (0 ":irc.example.org 366 alice #chan :End of NAMES list"))
+
+((mode-chan 1.2 "MODE #chan")
+ (0 ":bob!~bob@example.org PRIVMSG #chan :hey"))
+
+((linger 1.0 LINGER))
diff --git a/test/lisp/erc/resources/erc-d/resources/no-block.eld 
b/test/lisp/erc/resources/erc-d/resources/no-block.eld
new file mode 100644
index 0000000000..2811923d8a
--- /dev/null
+++ b/test/lisp/erc/resources/erc-d/resources/no-block.eld
@@ -0,0 +1,55 @@
+;;; -*- mode: lisp-data -*-
+((pass 10.0 "PASS " (? ?:) "changeme"))
+((nick 0.2 "NICK tester"))
+
+((user 0.2 "USER user 0 * :tester")
+ (0.0 ":irc.org 001 tester :Welcome to the Internet Relay Network tester")
+ (0.0 ":irc.org 002 tester :Your host is irc.org")
+ (0.0 ":irc.org 003 tester :This server was created just now")
+ (0.0 ":irc.org 004 tester irc.org BERios CEIRabehiklmnoqstv Iabehkloqv")
+ (0.0 ":irc.org 005 tester MODES NETWORK=ExampleOrg NICKLEN=32 
PREFIX=(qaohv)~&@%+"
+              " :are supported by this server")
+ (0.0 ":irc.org 251 tester :There are 3 users and 0 invisible on 1 server(s)")
+ (0.0 ":irc.org 252 tester 0 :IRC Operators online")
+ (0.0 ":irc.org 253 tester 0 :unregistered connections")
+ (0.0 ":irc.org 254 tester 1 :channels formed")
+ (0.0 ":irc.org 255 tester :I have 3 clients and 0 servers")
+ (0.0 ":irc.org 265 tester 3 3 :Current local users 3, max 3")
+ (0.0 ":irc.org 266 tester 3 3 :Current global users 3, max 3")
+ (0.0 ":irc.org 422 tester :MOTD File is missing"))
+
+((mode-user 1.2 "MODE tester +i")
+ (0.0 ":irc.org 221 tester +Zi")
+ (0.0 ":irc.org 306 tester :You have been marked as being away"))
+
+((join-foo 1.2 "JOIN #foo")
+ (0 ":tester!~tester@localhost JOIN #foo")
+ (0 ":irc.example.org 353 alice = #foo :+alice!~alice@example.com 
@%+bob!~bob@example.org")
+ (0 ":irc.example.org 366 alice #foo :End of NAMES list"))
+
+;; This would time out if the mode-foo's outgoing blocked (remove minus signs 
to see)
+((~join-bar 1.5 "JOIN #bar")
+ (0 ":tester!~tester@localhost JOIN #bar")
+ (0 ":irc.example.org 353 alice = #bar :+alice!~alice@example.com 
@%+bob!~bob@example.org")
+ (0 ":irc.example.org 366 alice #bar :End of NAMES list"))
+
+((mode-foo 1.2 "MODE #foo")
+ (0.0 ":irc.example.org 324 tester #foo +Cint")
+ (0.0 ":irc.example.org 329 tester #foo 1519850102")
+ (-0.1 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #foo :alice: But, in defense, by 
mercy, 'tis most just.")
+ (-0.2 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #foo :bob: Grows, lives, and dies, 
in single blessedness.")
+ (-0.3 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #foo :alice: For these two hours, 
Rosalind, I will leave thee.")
+ (-0.4 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #foo :bob: By this hand, it will 
not kill a fly. But come, now I will be your Rosalind in a more coming-on 
disposition; and ask me what you will, I will grant it.")
+ (-0.5 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #foo :alice: That I must love a 
loathed enemy.")
+ (-0.6 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #foo :bob: As't please your 
lordship: I'll leave you.")
+ (-0.7 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #foo :alice: Then there is no true 
lover in the forest; else sighing every minute and groaning every hour would 
detect the lazy foot of Time as well as a clock.")
+ (-0.8 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #foo :bob: His discretion, I am 
sure, cannot carry his valour, for the goose carries not the fox. It is well: 
leave it to his discretion, and let us listen to the moon.")
+ (-0.9 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #foo :alice: As living here and you 
no use of him.")
+ (-1.0 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #foo :bob: If there be truth in 
sight, you are my Rosalind.")
+ (-1.1 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #foo :alice: That is another's 
lawful promis'd love.")
+ (-1.1 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #foo :I am heard."))
+
+((mode-bar 1.5 "MODE #bar")
+ (0.0 ":irc.example.org 324 tester #bar +HMfnrt 50:5h :10:5")
+ (0.0 ":irc.example.org 329 tester #bar :1602642829")
+ (0.1 ":alice!~alice@example.com PRIVMSG #bar :hi 123"))
diff --git a/test/lisp/erc/resources/erc-d/resources/no-match.eld 
b/test/lisp/erc/resources/erc-d/resources/no-match.eld
new file mode 100644
index 0000000000..d147be1e08
--- /dev/null
+++ b/test/lisp/erc/resources/erc-d/resources/no-match.eld
@@ -0,0 +1,32 @@
+;;; -*- mode: lisp-data -*-
+
+((pass 10.0 "PASS " (? ?:) "changeme"))
+((nick 0.2 "NICK tester"))
+
+((user 0.2 "USER user 0 * :tester")
+ (0 ":irc.example.org 001 tester :Welcome to the Internet Relay Network 
tester")
+ (0 ":irc.example.org 002 tester :Your host is irc.example.org")
+ (0 ":irc.example.org 003 tester :This server was created just now")
+ (0 ":irc.example.org 004 tester irc.example.org BERios CEIRabehiklmnoqstv 
Iabehkloqv")
+ (0 ":irc.example.org 005 tester MODES NETWORK=ExampleOrg NICKLEN=32 
PREFIX=(qaohv)~&@%+"
+    " :are supported by this server")
+ (0 ":irc.example.org 251 tester :There are 3 users and 0 invisible on 1 
server(s)")
+ (0 ":irc.example.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.example.org 253 tester 0 :unregistered connections")
+ (0 ":irc.example.org 254 tester 1 :channels formed")
+ (0 ":irc.example.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.example.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.example.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.example.org 422 tester :MOTD File is missing"))
+
+((mode-user 1.2 "MODE tester +i")
+ (0 ":irc.example.org 221 tester +Zi")
+ (0 ":irc.example.org 306 tester :You have been marked as being away"))
+
+((join 1.2 "JOIN #chan")
+ (0 ":tester!~tester@localhost JOIN #chan")
+ (0 ":irc.example.org 353 alice = #chan :+alice!~alice@example.com 
@%+bob!~bob@example.org")
+ (0 ":irc.example.org 366 alice #chan :End of NAMES list"))
+
+((mode-chan 0.2 "MODE #chan")
+ (0.1 ":bob!~bob@example.org PRIVMSG #chan :hey"))
diff --git a/test/lisp/erc/resources/erc-d/resources/no-pong.eld 
b/test/lisp/erc/resources/erc-d/resources/no-pong.eld
new file mode 100644
index 0000000000..30cd805d76
--- /dev/null
+++ b/test/lisp/erc/resources/erc-d/resources/no-pong.eld
@@ -0,0 +1,27 @@
+;;; -*- mode: lisp-data -*-
+
+((pass 10.0 "PASS " (? ?:) "changeme"))
+((nick 0.2 "NICK tester"))
+
+((~ping 1.2 "PING " nonce)
+ (0.1 ":irc.example.org PONG irc.example.com " echo))
+
+((user 0.2 "USER user 0 * :tester")
+ (0 ":irc.example.org 001 tester :Welcome to the Internet Relay Network 
tester")
+ (0 ":irc.example.org 002 tester :Your host is irc.example.org")
+ (0 ":irc.example.org 003 tester :This server was created just now")
+ (0 ":irc.example.org 004 tester irc.example.org BERios CEIRabehiklmnoqstv 
Iabehkloqv")
+ (0 ":irc.example.org 005 tester MODES NETWORK=ExampleOrg NICKLEN=32 
PREFIX=(qaohv)~&@%+"
+    " :are supported by this server")
+ (0 ":irc.example.org 251 tester :There are 3 users and 0 invisible on 1 
server(s)")
+ (0 ":irc.example.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.example.org 253 tester 0 :unregistered connections")
+ (0 ":irc.example.org 254 tester 1 :channels formed")
+ (0 ":irc.example.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.example.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.example.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.example.org 422 tester :MOTD File is missing"))
+
+((mode-user 1.2 "MODE tester +i")
+ (0 ":irc.example.org 221 tester +Zi")
+ (0 ":irc.example.org 306 tester :You have been marked as being away"))
diff --git a/test/lisp/erc/resources/erc-d/resources/nonstandard.eld 
b/test/lisp/erc/resources/erc-d/resources/nonstandard.eld
new file mode 100644
index 0000000000..c9cd608e6b
--- /dev/null
+++ b/test/lisp/erc/resources/erc-d/resources/nonstandard.eld
@@ -0,0 +1,6 @@
+;;; -*- mode: lisp-data -*-
+((one 1 "ONE one"))
+((two 1 "TWO two"))
+((blank 1 ""))
+((one-space 1 " "))
+((two-spaces 1 "  "))
diff --git a/test/lisp/erc/resources/erc-d/resources/proxy-barnet.eld 
b/test/lisp/erc/resources/erc-d/resources/proxy-barnet.eld
new file mode 100644
index 0000000000..e74d20d5b3
--- /dev/null
+++ b/test/lisp/erc/resources/erc-d/resources/proxy-barnet.eld
@@ -0,0 +1,24 @@
+;;; -*- mode: lisp-data -*-
+
+((pass 10.0 "PASS " (? ?:) network ":changeme"))
+((nick 1.2 "NICK tester"))
+
+((user 1.2 "USER user 0 * :tester")
+ (0.001 ":" fqdn " 001 tester :Welcome to the BAR Network tester")
+ (0.002 ":" fqdn " 002 tester :Your host is " fqdn)
+ (0.003 ":" fqdn " 003 tester :This server was created just now")
+ (0.004 ":" fqdn " 004 tester " fqdn " BERios CEIRabehiklmnoqstv Iabehkloqv")
+ (0.005 ":" fqdn " 005 tester MODES NETWORK=" net " NICKLEN=32 
PREFIX=(qaohv)~&@%+"
+                 " :are supported by this server")
+ (0.006 ":" fqdn " 251 tester :There are 3 users and 0 invisible on 1 
server(s)")
+ (0.007 ":" fqdn " 252 tester 0 :IRC Operators online")
+ (0.008 ":" fqdn " 253 tester 0 :unregistered connections")
+ (0.009 ":" fqdn " 254 tester 1 :channels formed")
+ (0.010 ":" fqdn " 255 tester :I have 3 clients and 0 servers")
+ (0.011 ":" fqdn " 265 tester 3 3 :Current local users 3, max 3")
+ (0.012 ":" fqdn " 266 tester 3 3 :Current global users 3, max 3")
+ (0.013 ":" fqdn " 422 tester :MOTD File is missing"))
+
+((mode-user 1.2 "MODE tester +i")
+ (0.014 ":" fqdn " 221 tester +Zi")
+ (0.015 ":" fqdn " 306 tester :You have been marked as being away"))
diff --git a/test/lisp/erc/resources/erc-d/resources/proxy-foonet.eld 
b/test/lisp/erc/resources/erc-d/resources/proxy-foonet.eld
new file mode 100644
index 0000000000..cc2e9d253c
--- /dev/null
+++ b/test/lisp/erc/resources/erc-d/resources/proxy-foonet.eld
@@ -0,0 +1,24 @@
+;;; -*- mode: lisp-data -*-
+
+((pass 10.0 "PASS " (? ?:) network ":changeme"))
+((nick 1.2 "NICK tester"))
+
+((user 2.2 "USER user 0 * :tester")
+ (0.015 ":" fqdn " 001 tester :Welcome to the FOO Network tester")
+ (0.014 ":" fqdn " 002 tester :Your host is " fqdn)
+ (0.013 ":" fqdn " 003 tester :This server was created just now")
+ (0.012 ":" fqdn " 004 tester " fqdn " BERios CEIRabehiklmnoqstv Iabehkloqv")
+ (0.011 ":" fqdn " 005 tester MODES NETWORK=" net " NICKLEN=32 
PREFIX=(qaohv)~&@%+"
+                 " :are supported by this server")
+ (0.010 ":" fqdn " 251 tester :There are 3 users and 0 invisible on 1 
server(s)")
+ (0.009 ":" fqdn " 252 tester 0 :IRC Operators online")
+ (0.008 ":" fqdn " 253 tester 0 :unregistered connections")
+ (0.007 ":" fqdn " 254 tester 1 :channels formed")
+ (0.006 ":" fqdn " 255 tester :I have 3 clients and 0 servers")
+ (0.005 ":" fqdn " 265 tester 3 3 :Current local users 3, max 3")
+ (0.004 ":" fqdn " 266 tester 3 3 :Current global users 3, max 3")
+ (0.003 ":" fqdn " 422 tester :MOTD File is missing"))
+
+((mode-user 1.2 "MODE tester +i")
+ (0.002 ":" fqdn " 221 tester +Zi")
+ (0.001 ":" fqdn " 306 tester :You have been marked as being away"))
diff --git a/test/lisp/erc/resources/erc-d/resources/proxy-solo.eld 
b/test/lisp/erc/resources/erc-d/resources/proxy-solo.eld
new file mode 100644
index 0000000000..af216c80ed
--- /dev/null
+++ b/test/lisp/erc/resources/erc-d/resources/proxy-solo.eld
@@ -0,0 +1,9 @@
+;;; -*- mode: lisp-data -*-
+
+((pass 10.0 "PASS " (? ?:) "changeme"))
+((nick 0.2 "NICK tester"))
+
+((user 0.2 "USER user 0 * :" (group (+ alpha)) eos)
+ (0 ":*status!znc@znc.in NOTICE " nick " :You have no networks configured."
+    " Use /znc AddNetwork <network> to add one.")
+ (0 ":irc.znc.in 001 " nick " :Welcome " nick "!"))
diff --git a/test/lisp/erc/resources/erc-d/resources/proxy-subprocess.el 
b/test/lisp/erc/resources/erc-d/resources/proxy-subprocess.el
new file mode 100644
index 0000000000..bb8869dff6
--- /dev/null
+++ b/test/lisp/erc/resources/erc-d/resources/proxy-subprocess.el
@@ -0,0 +1,45 @@
+;;; 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.
+;;
+;; 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:
+;;; Code:
+
+(defvar erc-d-tmpl-vars)
+
+(setq erc-d-tmpl-vars
+
+      (list
+       (cons 'fqdn (lambda (helper)
+                     (let ((name (funcall helper :dialog-name)))
+                       (funcall helper :set
+                                (if (eq name 'proxy-foonet)
+                                    "irc.foo.net"
+                                  "irc.bar.net")))))
+
+       (cons 'net (lambda (helper)
+                    (let ((name (funcall helper :dialog-name)))
+                      (funcall helper :set
+                               (if (eq name 'proxy-foonet)
+                                   "FooNet"
+                                 "BarNet")))))
+
+       (cons 'network '(group (+ alpha)))))
+
+;;; proxy-subprocess.el ends here
diff --git a/test/lisp/erc/resources/erc-d/resources/timeout.eld 
b/test/lisp/erc/resources/erc-d/resources/timeout.eld
new file mode 100644
index 0000000000..9cfad4fa8c
--- /dev/null
+++ b/test/lisp/erc/resources/erc-d/resources/timeout.eld
@@ -0,0 +1,27 @@
+;;; -*- mode: lisp-data -*-
+
+((pass 10.0 "PASS " (? ?:) "changeme"))
+((nick 0.2 "NICK tester"))
+
+((user 0.2 "USER user 0 * :tester")
+ (0 ":irc.example.org 001 tester :Welcome to the Internet Relay Network 
tester")
+ (0 ":irc.example.org 002 tester :Your host is irc.example.org")
+ (0 ":irc.example.org 003 tester :This server was created just now")
+ (0 ":irc.example.org 004 tester irc.example.org BERios CEIRabehiklmnoqstv 
Iabehkloqv")
+ (0 ":irc.example.org 005 tester MODES NETWORK=ExampleOrg NICKLEN=32 
PREFIX=(qaohv)~&@%+"
+    " :are supported by this server")
+ (0 ":irc.example.org 251 tester :There are 3 users and 0 invisible on 1 
server(s)")
+ (0 ":irc.example.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.example.org 253 tester 0 :unregistered connections")
+ (0 ":irc.example.org 254 tester 1 :channels formed")
+ (0 ":irc.example.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.example.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.example.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.example.org 422 tester :MOTD File is missing"))
+
+((mode-user 1.2 "MODE tester +i")
+ (0 ":irc.example.org 221 tester +Zi")
+ (0 ":irc.example.org 306 tester :You have been marked as being away"))
+
+((mode 0.2 "MODE #chan")
+ (0.1 ":bob!~bob@example.org PRIVMSG #chan :hey"))
diff --git a/test/lisp/erc/resources/erc-d/resources/unexpected.eld 
b/test/lisp/erc/resources/erc-d/resources/unexpected.eld
new file mode 100644
index 0000000000..ac0a8fecfa
--- /dev/null
+++ b/test/lisp/erc/resources/erc-d/resources/unexpected.eld
@@ -0,0 +1,28 @@
+;;; -*- mode: lisp-data -*-
+((t 10.0 "PASS " (? ?:) "changeme"))
+((t 0.2 "NICK tester"))
+
+((t 0.2 "USER user 0 * :tester")
+ (0.0 ":irc.example.org 001 tester :Welcome to the Internet Relay Network 
tester")
+ (0.0 ":irc.example.org 002 tester :Your host is irc.example.org")
+ (0.0 ":irc.example.org 003 tester :This server was created just now")
+ (0.0 ":irc.example.org 004 tester irc.example.org BERios CEIRabehiklmnoqstv 
Iabehkloqv")
+ (0.0 ":irc.example.org 005 tester MODES NETWORK=ExampleOrg NICKLEN=32 
PREFIX=(qaohv)~&@%+"
+      " :are supported by this server")
+ (0.0 ":irc.example.org 251 tester :There are 3 users and 0 invisible on 1 
server(s)")
+ (0.0 ":irc.example.org 252 tester 0 :IRC Operators online")
+ (0.0 ":irc.example.org 253 tester 0 :unregistered connections")
+ (0.0 ":irc.example.org 254 tester 1 :channels formed")
+ (0.0 ":irc.example.org 255 tester :I have 3 clients and 0 servers")
+ (0.0 ":irc.example.org 265 tester 3 3 :Current local users 3, max 3")
+ (0.0 ":irc.example.org 266 tester 3 3 :Current global users 3, max 3")
+ (0.0 ":irc.example.org 422 tester :MOTD File is missing"))
+
+((mode-user 1.2 "MODE tester +i")
+ (0.0 ":irc.example.org 221 tester +Zi")
+
+ (0.0 ":irc.example.org 306 tester :You have been marked as being away")
+ (0.0 ":tester!~tester@localhost JOIN #chan")
+ (0.0 ":irc.example.org 353 alice = #chan :+alice!~alice@example.com 
@%+bob!~bob@example.org")
+ (0.0 ":irc.example.org 366 alice #chan :End of NAMES list")
+ (0.1 ":bob!~bob@example.org PRIVMSG #chan :hey"))
diff --git a/test/lisp/erc/resources/erc-scenarios-common.el 
b/test/lisp/erc/resources/erc-scenarios-common.el
new file mode 100644
index 0000000000..bc2cb68cd8
--- /dev/null
+++ b/test/lisp/erc/resources/erc-scenarios-common.el
@@ -0,0 +1,516 @@
+;;; 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.
+;;
+;; 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:
+
+;; These are e2e-ish test cases primarily intended to assert core,
+;; fundamental behavior expected of any modern IRC client.  Tests may
+;; also simulate specific scenarios drawn from bug reports.  Incoming
+;; messages are provided by playback scripts resembling I/O logs.  In
+;; place of time stamps, they have time deltas, which are used to
+;; govern the test server in a fashion reminiscent of music rolls (or
+;; the script(1) UNIX program).  These scripts can be found in the
+;; other directories under test/lisp/erc/resources.
+;;
+;; Isolation:
+;;
+;; The set of enabled modules is shared among all tests.  The function
+;; `erc-update-modules' activates them (as minor modes), but it never
+;; deactivates them.  So there's no going back, and let-binding
+;; `erc-modules' is useless.  The safest route is therefore to (1)
+;; assume the set of default modules is already activated or will be
+;; over the course of the test session and (2) let-bind relevant user
+;; options as needed.  For example, to limit the damage of
+;; `erc-autojoin-channels-alist' to a given test, assume the
+;; `erc-join' library has already been loaded or will be on the next
+;; call to `erc-open'.  And then just let-bind
+;; `erc-autojoin-channels-alist' for the duration of the test.
+;;
+;; Playing nice:
+;;
+;; Right now, these tests all rely on an ugly fixture macro named
+;; `erc-scenarios-common-with-cleanup', which is defined just below.
+;; It helps restore (but not really prepare) the environment by
+;; destroying any stray processes or buffers named in the first
+;; argument, a `let*'-style VAR-LIST.  Relying on such a macro is
+;; unfortunate because in many ways it actually hampers readability by
+;; favoring magic over verbosity.  But without it (or something
+;; similar), any failing test would cause all subsequent tests in this
+;; file to fail like dominoes (making all but the first backtrace
+;; useless).
+;;
+;; Misc:
+;;
+;; Note that in the following examples, nicknames Alice and Bob are
+;; always associated with the fake network FooNet, while nicks Joe and
+;; Mike are always on BarNet.  (Networks are sometimes downcased.)
+;;
+;; XXX This file should *not* contain any test cases.
+
+;;; Code:
+
+(require 'ert-x) ; cl-lib
+(eval-and-compile
+  (let* ((d (expand-file-name ".." (ert-resource-directory)))
+         (load-path (cons (concat d "/erc-d") load-path)))
+    (require 'erc-d-t)
+    (require 'erc-d)))
+
+(require 'erc-backend)
+
+(eval-when-compile (require 'erc-join)
+                   (require 'erc-services))
+
+(declare-function erc-network "erc-networks")
+(defvar erc-network)
+
+(defvar erc-scenarios-common--resources-dir
+  (expand-file-name "../" (ert-resource-directory)))
+
+;; Teardown is already inhibited when running interactively, which
+;; prevents subsequent tests from succeeding, so we might as well
+;; treat inspection as the goal.
+(unless noninteractive
+  (setq erc-server-auto-reconnect nil))
+
+(defvar erc-scenarios-common-dialog nil)
+(defvar erc-scenarios-common-extra-teardown nil)
+
+(defun erc-scenarios-common--add-silence ()
+  (advice-add #'erc-login :around #'erc-d-t-silence-around)
+  (advice-add #'erc-handle-login :around #'erc-d-t-silence-around)
+  (advice-add #'erc-server-connect :around #'erc-d-t-silence-around))
+
+(defun erc-scenarios-common--remove-silence ()
+  (advice-remove #'erc-login #'erc-d-t-silence-around)
+  (advice-remove #'erc-handle-login #'erc-d-t-silence-around)
+  (advice-remove #'erc-server-connect #'erc-d-t-silence-around))
+
+(defun erc-scenarios-common--print-trace ()
+  (when (and (boundp 'trace-buffer) (get-buffer trace-buffer))
+    (with-current-buffer trace-buffer
+      (message "%S" (buffer-string))
+      (kill-buffer))))
+
+(eval-and-compile
+  (defun erc-scenarios-common--make-bindings (bindings)
+    `((erc-d-u-canned-dialog-dir (expand-file-name
+                                  (or erc-scenarios-common-dialog
+                                      (cadr (assq 'erc-scenarios-common-dialog
+                                                  ',bindings)))
+                                  erc-scenarios-common--resources-dir))
+      (erc-d-tmpl-vars `(,@erc-d-tmpl-vars
+                         (quit . ,(erc-quit/part-reason-default))
+                         (erc-version . ,erc-version)))
+      (erc-modules (copy-sequence erc-modules))
+      (inhibit-interaction t)
+      (auth-source-do-cache nil)
+      (erc-auth-source-parameters-join-function nil)
+      (erc-autojoin-channels-alist nil)
+      (erc-server-auto-reconnect nil)
+      (erc-d-linger-secs 10)
+      ,@bindings)))
+
+(defmacro erc-scenarios-common-with-cleanup (bindings &rest body)
+  "Provide boilerplate cleanup tasks after calling BODY with BINDINGS.
+
+If an `erc-d' process exists, wait for it to start before running BODY.
+If `erc-autojoin-mode' mode is bound, restore it during cleanup if
+disabled by BODY.  Other defaults common to these test cases are added
+below and can be overridden, except when wanting the \"real\" default
+value, which must be looked up or captured outside of the calling form.
+
+Dialog resource directories are located by expanding the variable
+`erc-scenarios-common-dialog' or its value in BINDINGS."
+  (declare (indent 1))
+
+  (let* ((orig-autojoin-mode (make-symbol "orig-autojoin-mode"))
+         (combined `((,orig-autojoin-mode (bound-and-true-p erc-autojoin-mode))
+                    ,@(erc-scenarios-common--make-bindings bindings))))
+
+    `(erc-d-t-with-cleanup (,@combined)
+
+         (ert-info ("Restore autojoin, etc., kill ERC buffers")
+           (dolist (buf (buffer-list))
+             (when-let ((erc-d-u--process-buffer)
+                        (proc (get-buffer-process buf)))
+               (delete-process proc)))
+
+           (erc-scenarios-common--remove-silence)
+
+           (when erc-scenarios-common-extra-teardown
+             (ert-info ("Running extra teardown")
+               (funcall erc-scenarios-common-extra-teardown)))
+
+           (when (and (boundp 'erc-autojoin-mode)
+                      (not (eq erc-autojoin-mode ,orig-autojoin-mode)))
+             (erc-autojoin-mode (if ,orig-autojoin-mode +1 -1)))
+
+           (when noninteractive
+             (erc-scenarios-common--print-trace)
+             (erc-d-t-kill-related-buffers)
+             (delete-other-windows)))
+
+       (erc-scenarios-common--add-silence)
+
+       (ert-info ("Wait for dumb server")
+         (dolist (buf (buffer-list))
+           (with-current-buffer buf
+             (when erc-d-u--process-buffer
+               (erc-d-t-search-for 3 "Starting")))))
+
+       (ert-info ("Activate erc-debug-irc-protocol")
+         (unless (and noninteractive (not erc-debug-irc-protocol))
+           (erc-toggle-debug-irc-protocol)))
+
+       ,@body)))
+
+(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 "127.0.0.1:%d" port))
+                   (buffer-name))))
+
+(defun erc-scenarios-common-buflist (prefix)
+  "Return list of buffers with names sharing PREFIX."
+  (let (case-fold-search)
+    (erc-networks--id-sort-buffers
+     (delq nil
+           (mapcar (lambda (b)
+                     (when (string-prefix-p prefix (buffer-name b)) b))
+                   (buffer-list))))))
+
+;; This is more realistic than `erc-send-message' because it runs
+;; `erc-pre-send-functions', etc.  Keyboard macros may be preferable,
+;; but they sometimes experience complications when an earlier test
+;; has failed.
+(defun erc-scenarios-common-say (str)
+  (let (erc-accidental-paste-threshold-seconds)
+    (goto-char erc-input-marker)
+    (insert str)
+    (erc-send-current-line)))
+
+
+;;;; Fixtures
+
+(cl-defun erc-scenarios-common--base-network-id-bouncer
+    ((&key autop foo-id bar-id after
+           &aux
+           (foo-id (and foo-id 'oofnet))
+           (bar-id (and bar-id 'rabnet))
+           (serv-buf-foo (if foo-id "oofnet" "foonet"))
+           (serv-buf-bar (if bar-id "rabnet" "barnet"))
+           (chan-buf-foo (if foo-id "#chan@oofnet" "#chan@foonet"))
+           (chan-buf-bar (if bar-id "#chan@rabnet" "#chan@barnet")))
+     &rest dialogs)
+  "Ensure retired option `erc-rename-buffers' is now the default behavior.
+The option `erc-rename-buffers' is now deprecated and on by default, so
+this now just asserts baseline behavior.  Originally from scenario
+clash-of-chans/rename-buffers as explained in Bug#48598: 28.0.50;
+buffer-naming collisions involving bouncers in ERC."
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/netid/bouncer")
+       (erc-d-t-cleanup-sleep-secs 1)
+       (erc-server-flood-penalty 0.1)
+       (dumb-server (apply #'erc-d-run "localhost" t dialogs))
+       (port (process-contact dumb-server :service))
+       (expect (erc-d-t-make-expecter))
+       (erc-server-auto-reconnect autop)
+       erc-server-buffer-foo erc-server-process-foo
+       erc-server-buffer-bar erc-server-process-bar)
+
+    (ert-info ("Connect to foonet")
+      (with-current-buffer
+          (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+                                           :port port
+                                           :nick "tester"
+                                           :password "foonet:changeme"
+                                           :full-name "tester"
+                                           :id foo-id))
+        (setq erc-server-process-foo erc-server-process)
+        (erc-scenarios-common-assert-initial-buf-name foo-id port)
+        (erc-d-t-wait-for 3 (eq (erc-network) 'foonet))
+        (erc-d-t-wait-for 3 (string= (buffer-name) serv-buf-foo))
+        (funcall expect 5 "foonet")))
+
+    (ert-info ("Join #chan@foonet")
+      (with-current-buffer erc-server-buffer-foo (erc-cmd-JOIN "#chan"))
+      (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan"))
+        (funcall expect 5 "<alice>")))
+
+    (ert-info ("Connect to barnet")
+      (with-current-buffer
+          (setq erc-server-buffer-bar (erc :server "127.0.0.1"
+                                           :port port
+                                           :nick "tester"
+                                           :password "barnet:changeme"
+                                           :full-name "tester"
+                                           :id bar-id))
+        (setq erc-server-process-bar erc-server-process)
+        (erc-scenarios-common-assert-initial-buf-name bar-id port)
+        (erc-d-t-wait-for 6 (eq (erc-network) 'barnet))
+        (erc-d-t-wait-for 3 (string= (buffer-name) serv-buf-bar))
+        (funcall expect 5 "barnet")))
+
+    (ert-info ("Server buffers are unique, no names based on IPs")
+      (should-not (eq erc-server-buffer-foo erc-server-buffer-bar))
+      (should-not (erc-scenarios-common-buflist "127.0.0.1")))
+
+    (ert-info ("Join #chan@barnet")
+      (with-current-buffer erc-server-buffer-bar (erc-cmd-JOIN "#chan")))
+
+    (erc-d-t-wait-for 5 "Exactly 2 #chan-prefixed buffers exist"
+      (equal (list (get-buffer chan-buf-bar)
+                   (get-buffer chan-buf-foo))
+             (erc-scenarios-common-buflist "#chan")))
+
+    (ert-info ("#chan@<esid> is exclusive to foonet")
+      (with-current-buffer chan-buf-foo
+        (erc-d-t-search-for 1 "<bob>")
+        (erc-d-t-absent-for 0.1 "<joe>")
+        (should (eq erc-server-process erc-server-process-foo))
+        (erc-d-t-search-for 10 "ape is dead")
+        (erc-d-t-wait-for 5 (not (erc-server-process-alive)))))
+
+    (ert-info ("#chan@<esid> is exclusive to barnet")
+      (with-current-buffer chan-buf-bar
+        (erc-d-t-search-for 1 "<joe>")
+        (erc-d-t-absent-for 0.1 "<bob>")
+        (erc-d-t-wait-for 5 (eq erc-server-process erc-server-process-bar))
+        (erc-d-t-search-for 15 "keeps you from dishonour")
+        (erc-d-t-wait-for 5 (not (erc-server-process-alive)))))
+
+    (when after (funcall after))))
+
+(defun erc-scenarios-common--clash-rename-pass-handler (dialog exchange)
+  (when (eq (erc-d-dialog-name dialog) 'stub-again)
+    (let* ((match (erc-d-exchange-match exchange 1))
+           (sym (if (string= match "foonet") 'foonet-again 'barnet-again)))
+      (should (member match (list "foonet" "barnet")))
+      (erc-d-load-replacement-dialog dialog sym 1))))
+
+(defun erc-scenarios-common--base-network-id-bouncer--reconnect (foo-id bar-id)
+  (let ((erc-d-tmpl-vars '((token . (group (| "barnet" "foonet")))))
+        (erc-d-match-handlers
+         ;; Auto reconnect is nondeterministic, so let computer decide
+         (list :pass #'erc-scenarios-common--clash-rename-pass-handler))
+        (after
+         (lambda ()
+           ;; Simulate disconnection and `erc-server-auto-reconnect'
+           (ert-info ("Reconnect to foonet and barnet back-to-back")
+             (with-current-buffer (if foo-id "oofnet" "foonet")
+               (erc-d-t-wait-for 10 (erc-server-process-alive)))
+             (with-current-buffer (if bar-id "rabnet" "barnet")
+               (erc-d-t-wait-for 10 (erc-server-process-alive))))
+
+           (ert-info ("#chan@foonet is exclusive to foonet")
+             (with-current-buffer (if foo-id "#chan@oofnet" "#chan@foonet")
+               (erc-d-t-search-for 1 "<alice>")
+               (erc-d-t-absent-for 0.1 "<joe>")
+               (erc-d-t-search-for 20 "please your lordship")))
+
+           (ert-info ("#chan@barnet is exclusive to barnet")
+             (with-current-buffer (if bar-id "#chan@rabnet" "#chan@barnet")
+               (erc-d-t-search-for 1 "<joe>")
+               (erc-d-t-absent-for 0.1 "<bob>")
+               (erc-d-t-search-for 20 "much in private")))
+
+           ;; XXX this is important (reconnects overlapped, so we'd get
+           ;; chan@127.0.0.1:6667)
+           (should-not (erc-scenarios-common-buflist "127.0.0.1"))
+           ;; Reconnection order doesn't matter here because session objects
+           ;; are persisted, meaning original timestamps preserved.
+           (should (equal (list (get-buffer (if bar-id "#chan@rabnet"
+                                              "#chan@barnet"))
+                                (get-buffer (if foo-id "#chan@oofnet"
+                                              "#chan@foonet")))
+                          (erc-scenarios-common-buflist "#chan"))))))
+    (erc-scenarios-common--base-network-id-bouncer
+     (list :autop t :foo-id foo-id :bar-id bar-id :after after)
+     'foonet-drop 'barnet-drop
+     'stub-again 'stub-again
+     'foonet-again 'barnet-again)))
+
+(defun erc-scenarios-common--upstream-reconnect (test &rest dialogs)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/upstream-reconnect")
+       (erc-d-t-cleanup-sleep-secs 1)
+       (erc-server-flood-penalty 0.1)
+       (dumb-server (apply #'erc-d-run "localhost" t dialogs))
+       (port (process-contact dumb-server :service))
+       (expect (erc-d-t-make-expecter)))
+
+    (ert-info ("Connect to foonet")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :nick "tester"
+                                :user "tester@vanilla/foonet"
+                                :password "changeme"
+                                :full-name "tester")
+        (erc-scenarios-common-assert-initial-buf-name nil port)
+        (erc-d-t-wait-for 3 (eq (erc-network) 'foonet))
+        (erc-d-t-wait-for 3 (string= (buffer-name) "foonet"))
+        (funcall expect 5 "foonet")))
+
+    (ert-info ("Join #chan@foonet")
+      (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan"))
+        (funcall expect 5 "<alice>")))
+
+    (ert-info ("Connect to barnet")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :nick "tester"
+                                :user "tester@vanilla/barnet"
+                                :password "changeme"
+                                :full-name "tester")
+        (erc-scenarios-common-assert-initial-buf-name nil port)
+        (erc-d-t-wait-for 10 (eq (erc-network) 'barnet))
+        (erc-d-t-wait-for 3 (string= (buffer-name) "barnet"))
+        (funcall expect 5 "barnet")))
+
+    (ert-info ("Server buffers are unique, no names based on IPs")
+      (should-not (erc-scenarios-common-buflist "127.0.0.1")))
+
+    (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan@foonet"))
+      (funcall expect 5 "#chan was created on ")
+      (ert-info ("Joined again #chan@foonet")
+        (funcall expect 10 "#chan was created on "))
+      (funcall expect 10 "My lord, in heart"))
+
+    (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan@barnet"))
+      (funcall expect 5 "#chan was created on ")
+      (ert-info ("Joined again #chan@barnet")
+        (funcall expect 10 "#chan was created on "))
+      (funcall expect 10 "Go to; farewell"))
+
+    (funcall test)))
+
+;; XXX this is okay, but we also need to check that target buffers are
+;; already associated with a new process *before* a JOIN is sent by a
+;; server's playback burst.  This doesn't do that.
+;;
+;; This *does* check that superfluous JOINs sent by the autojoin
+;; module are harmless when they're not acked (superfluous because the
+;; bouncer/server intitates the JOIN).
+
+(defun erc-scenarios-common--join-network-id (foo-reconnector foo-id bar-id)
+  "Ensure channels rejoined by erc-join.el DTRT.
+Originally from scenario clash-of-chans/autojoin as described in
+Bug#48598: 28.0.50; buffer-naming collisions involving bouncers in ERC."
+  (erc-scenarios-common-with-cleanup
+      ((chan-buf-foo (format "#chan@%s" (or foo-id "foonet")))
+       (chan-buf-bar (format "#chan@%s" (or bar-id "barnet")))
+       (erc-scenarios-common-dialog "join/network-id")
+       (erc-d-t-cleanup-sleep-secs 1)
+       (erc-server-flood-penalty 0.5)
+       (dumb-server (erc-d-run "localhost" t 'foonet 'barnet 'foonet-again))
+       (port (process-contact dumb-server :service))
+       (expect (erc-d-t-make-expecter))
+       erc-server-buffer-foo erc-server-process-foo
+       erc-server-buffer-bar erc-server-process-bar)
+
+    (should (memq 'autojoin erc-modules))
+
+    (ert-info ("Connect to foonet")
+      (with-current-buffer
+          (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+                                           :port port
+                                           :nick "tester"
+                                           :password "foonet:changeme"
+                                           :full-name "tester"
+                                           :id foo-id))
+        (setq erc-server-process-foo erc-server-process)
+        (erc-scenarios-common-assert-initial-buf-name foo-id port)
+        (erc-d-t-wait-for 5 (eq (erc-network) 'foonet))
+        (funcall expect 5 "foonet")))
+
+    (ert-info ("Join #chan, find sentinel, quit")
+      (with-current-buffer erc-server-buffer-foo (erc-cmd-JOIN "#chan"))
+      (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan"))
+        (funcall expect 5 "vile thing")
+        (erc-cmd-QUIT "")))
+
+    (erc-d-t-wait-for 2 "Foonet connection deceased"
+      (not (erc-server-process-alive erc-server-buffer-foo)))
+
+    (should (equal erc-autojoin-channels-alist
+                   (if foo-id '((oofnet "#chan")) '((foonet "#chan")))))
+
+    (ert-info ("Connect to barnet")
+      (with-current-buffer
+          (setq erc-server-buffer-bar (erc :server "127.0.0.1"
+                                           :port port
+                                           :nick "tester"
+                                           :password "barnet:changeme"
+                                           :full-name "tester"
+                                           :id bar-id))
+        (setq erc-server-process-bar erc-server-process)
+        (erc-d-t-wait-for 5 (eq erc-network 'barnet))
+        (should (string= (buffer-name) (if bar-id "rabnet" "barnet")))))
+
+    (ert-info ("Server buffers are unique, no stray IP-based names")
+      (should-not (eq erc-server-buffer-foo erc-server-buffer-bar))
+      (should-not (erc-scenarios-common-buflist "127.0.0.1")))
+
+    (ert-info ("Only one #chan buffer exists")
+      (should (equal (list (get-buffer "#chan"))
+                     (erc-scenarios-common-buflist "#chan"))))
+
+    (ert-info ("#chan is not auto-joined")
+      (with-current-buffer "#chan"
+        (erc-d-t-absent-for 0.1 "<joe>")
+        (should-not (process-live-p erc-server-process))
+        (erc-d-t-ensure-for 0.1 "server buffer remains foonet"
+          (eq erc-server-process erc-server-process-foo))))
+
+    (with-current-buffer erc-server-buffer-bar
+      (erc-cmd-JOIN "#chan")
+      (erc-d-t-wait-for 3 (get-buffer chan-buf-foo))
+      (erc-d-t-wait-for 3 (get-buffer chan-buf-bar))
+      (with-current-buffer chan-buf-bar
+        (erc-d-t-wait-for 3 (eq erc-server-process erc-server-process-bar))
+        (funcall expect 5 "marry her instantly")))
+
+    (ert-info ("Reconnect to foonet")
+      (with-current-buffer (setq erc-server-buffer-foo
+                                 (funcall foo-reconnector))
+        (should (member (if foo-id '(oofnet "#chan") '(foonet "#chan"))
+                        erc-autojoin-channels-alist))
+        (erc-d-t-wait-for 3 (erc-server-process-alive))
+        (setq erc-server-process-foo erc-server-process)
+        (erc-d-t-wait-for 2 (eq erc-network 'foonet))
+        (should (string= (buffer-name) (if foo-id "oofnet" "foonet")))
+        (funcall expect 5 "foonet")))
+
+    (ert-info ("#chan@foonet is clean, no cross-contamination")
+      (with-current-buffer chan-buf-foo
+        (erc-d-t-wait-for 3 (eq erc-server-process erc-server-process-foo))
+        (funcall expect 3 "<bob>")
+        (erc-d-t-absent-for 0.1 "<joe>")
+        (funcall expect 10 "not given me")))
+
+    (ert-info ("All #chan@barnet output received")
+      (with-current-buffer chan-buf-bar
+        (funcall expect 10 "hath an uncle here")))))
+
+(provide 'erc-scenarios-common)
+
+;;; erc-scenarios-common.el ends here
diff --git a/test/lisp/erc/resources/join/auth-source/foonet.eld 
b/test/lisp/erc/resources/join/auth-source/foonet.eld
new file mode 100644
index 0000000000..32b9e3fa0b
--- /dev/null
+++ b/test/lisp/erc/resources/join/auth-source/foonet.eld
@@ -0,0 +1,33 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK dummy"))
+((user 1 "USER user 0 * :dummy")
+ (0.00 ":irc.foonet.org 001 dummy :Welcome to the foonet IRC Network dummy")
+ (0.01 ":irc.foonet.org 002 dummy :Your host is irc.foonet.org, running 
version ergo-v2.8.0")
+ (0.00 ":irc.foonet.org 003 dummy :This server was created Tue, 24 May 2022 
05:28:42 UTC")
+ (0.00 ":irc.foonet.org 004 dummy irc.foonet.org ergo-v2.8.0 BERTZios 
CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0.00 ":irc.foonet.org 005 dummy 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.01 ":irc.foonet.org 005 dummy 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 dummy draft/CHATHISTORY=100 :are supported by this 
server")
+ (0.00 ":irc.foonet.org 251 dummy :There are 0 users and 4 invisible on 1 
server(s)")
+ (0.00 ":irc.foonet.org 252 dummy 0 :IRC Operators online")
+ (0.00 ":irc.foonet.org 253 dummy 0 :unregistered connections")
+ (0.00 ":irc.foonet.org 254 dummy 2 :channels formed")
+ (0.00 ":irc.foonet.org 255 dummy :I have 4 clients and 0 servers")
+ (0.00 ":irc.foonet.org 265 dummy 4 4 :Current local users 4, max 4")
+ (0.00 ":irc.foonet.org 266 dummy 4 4 :Current global users 4, max 4")
+ (0.00 ":irc.foonet.org 422 dummy :MOTD File is missing"))
+
+((mode 6 "MODE dummy +i")
+ (0.00 ":irc.foonet.org 221 dummy +i")
+ (0.00 ":irc.foonet.org NOTICE dummy :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.02 ":irc.foonet.org 221 dummy +i"))
+
+((join 6.47 "JOIN #spam secret")
+ (0.03 ":dummy!~u@w9rfqveugz722.irc JOIN #spam"))
+
+((mode 1 "MODE #spam")
+ (0.01 ":irc.foonet.org 353 dummy = #spam :~tester dummy")
+ (0.00 ":irc.foonet.org 366 dummy #spam :End of NAMES list")
+ (0.01 ":irc.foonet.org 324 dummy #spam +knt secret")
+ (0.03 ":irc.foonet.org 329 dummy #spam 1653370308"))
diff --git a/test/lisp/erc/resources/join/legacy/foonet.eld 
b/test/lisp/erc/resources/join/legacy/foonet.eld
new file mode 100644
index 0000000000..344ba7c1da
--- /dev/null
+++ b/test/lisp/erc/resources/join/legacy/foonet.eld
@@ -0,0 +1,38 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Tue, 04 May 2021 
05:06:18 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=FooNet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 3.2 "MODE tester +i")
+ (0 ":irc.foonet.org 221 tester +i")
+ (0 ":irc.foonet.org NOTICE tester :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect."))
+
+((join 6 "JOIN #chan")
+ (0 ":tester!~u@9g6b728983yd2.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :alice tester @bob")
+ (0 ":irc.foonet.org 366 tester #chan :End of NAMES list"))
+
+((mode 5 "MODE #chan")
+ (0 ":irc.foonet.org 324 tester #chan +nt")
+ (0 ":irc.foonet.org 329 tester #chan 1620104779")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :tester, welcome!")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :tester, welcome!")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: But, as it seems, did 
violence on herself.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: Well, this is the 
forest of Arden.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: And will you, being a 
man of your breeding, be married under a bush, like a beggar ? Get you to 
church, and have a good priest that can tell you what marriage is: this fellow 
will but join you together as they join wainscot; then one of you will prove a 
shrunk panel, and like green timber, warp, warp.")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: Live, and be 
prosperous; and farewell, good fellow."))
diff --git a/test/lisp/erc/resources/join/network-id/barnet.eld 
b/test/lisp/erc/resources/join/network-id/barnet.eld
new file mode 100644
index 0000000000..e33dd6be29
--- /dev/null
+++ b/test/lisp/erc/resources/join/network-id/barnet.eld
@@ -0,0 +1,43 @@
+;; -*- mode: lisp-data; -*-
+((pass 2 "PASS :barnet:changeme"))
+((nick 2 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.barnet.org 001 tester :Welcome to the barnet IRC Network tester")
+ (0 ":irc.barnet.org 002 tester :Your host is irc.barnet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.barnet.org 003 tester :This server was created Mon, 10 May 2021 
00:58:22 UTC")
+ (0 ":irc.barnet.org 004 tester irc.barnet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.barnet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.barnet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=barnet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.barnet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.barnet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.barnet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.barnet.org 254 tester 1 :channels formed")
+ (0 ":irc.barnet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.barnet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.barnet.org 422 tester :MOTD File is missing"))
+
+((mode-user 12 "MODE tester +i"))
+;; No mode answer
+
+((join 2 "JOIN #chan")
+ (0 ":tester!~u@6yximxrnkg65a.irc JOIN #chan")
+ (0 ":irc.barnet.org 353 tester = #chan :@joe mike tester")
+ (0 ":irc.barnet.org 366 tester #chan :End of NAMES list")
+ (0.1 ":joe!~u@6yximxrnkg65a.irc PRIVMSG #chan :tester, welcome!")
+ (0 ":mike!~u@6yximxrnkg65a.irc PRIVMSG #chan :tester, welcome!"))
+
+((mode 1 "MODE #chan")
+ (0 ":irc.barnet.org 324 tester #chan +nt")
+ (0 ":irc.barnet.org 329 tester #chan 1620608304")
+ ;; Wait for foonet's buffer playback
+ (0.1 ":mike!~u@6yximxrnkg65a.irc PRIVMSG #chan :joe: Go take her hence, and 
marry her instantly.")
+ (0.1 ":joe!~u@6yximxrnkg65a.irc PRIVMSG #chan :mike: Of all the four, or the 
three, or the two, or one of the four.")
+ (0.1 ":mike!~u@6yximxrnkg65a.irc PRIVMSG #chan :joe: And gives the crutch the 
cradle's infancy.")
+ (0.1 ":joe!~u@6yximxrnkg65a.irc PRIVMSG #chan :mike: Such is the simplicity 
of man to hearken after the flesh.")
+ (0.05 ":mike!~u@6yximxrnkg65a.irc PRIVMSG #chan :joe: The leaf to read them. 
Let us toward the king.")
+ (0.05 ":joe!~u@6yximxrnkg65a.irc PRIVMSG #chan :mike: Many can brook the 
weather that love not the wind.")
+ (0.05 ":mike!~u@6yximxrnkg65a.irc PRIVMSG #chan :joe: And now, dear maid, be 
you as free to us.")
+ (0.00 ":joe!~u@6yximxrnkg65a.irc PRIVMSG #chan :mike: He hath an uncle here 
in Messina will be very much glad of it."))
+
+((linger 3.5 LINGER))
diff --git a/test/lisp/erc/resources/join/network-id/foonet-again.eld 
b/test/lisp/erc/resources/join/network-id/foonet-again.eld
new file mode 100644
index 0000000000..b230eff27c
--- /dev/null
+++ b/test/lisp/erc/resources/join/network-id/foonet-again.eld
@@ -0,0 +1,46 @@
+;; -*- mode: lisp-data; -*-
+((pass-redux 10 "PASS :foonet:changeme"))
+((nick-redux 1 "NICK tester"))
+
+((user-redux 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Mon, 10 May 2021 
00:58:22 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 10.2 "MODE tester +i")
+ ;; No mode answer ^
+
+ ;; History
+ (0 ":tester!~u@q6ddatxcq6txy.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :@alice bob tester")
+ (0 ":irc.foonet.org 366 tester #chan :End of /NAMES list.")
+ (0 ":***!znc@znc.in PRIVMSG #chan :Buffer Playback...")
+ (0 ":bob!~u@q6ddatxcq6txy.irc PRIVMSG #chan :[02:43:23] alice: And soar with 
them above a common bound.")
+ (0 ":alice!~u@q6ddatxcq6txy.irc PRIVMSG #chan :[02:43:27] bob: And be aveng'd 
on cursed Tamora.")
+ (0 ":bob!~u@q6ddatxcq6txy.irc PRIVMSG #chan :[02:43:29] alice: He did love 
her, sir, as a gentleman loves a woman.")
+ (0 ":***!znc@znc.in PRIVMSG #chan :Playback Complete."))
+
+;; As a server, we ignore useless join sent by autojoin module
+((~join 10 "JOIN #chan"))
+
+((mode-redux 10 "MODE #chan")
+ (0 ":irc.foonet.org 324 tester #chan +nt")
+ (0 ":irc.foonet.org 329 tester #chan 1620608304")
+ (0.1 ":alice!~u@q6ddatxcq6txy.irc PRIVMSG #chan :bob: Ay, madam, with the 
swiftest wing of speed.")
+ (0.1 ":bob!~u@q6ddatxcq6txy.irc PRIVMSG #chan :alice: Five times in that ere 
once in our five wits.")
+ (0.1 ":alice!~u@q6ddatxcq6txy.irc PRIVMSG #chan :bob: And bid him come to 
take his last farewell.")
+ (0.1 ":bob!~u@q6ddatxcq6txy.irc PRIVMSG #chan :alice: But we are spirits of 
another sort.")
+ (0.1 ":alice!~u@q6ddatxcq6txy.irc PRIVMSG #chan :bob: It was not given me, 
nor I did not buy it."))
+
+((linger 6 LINGER))
diff --git a/test/lisp/erc/resources/join/network-id/foonet.eld 
b/test/lisp/erc/resources/join/network-id/foonet.eld
new file mode 100644
index 0000000000..7d63f5f0c6
--- /dev/null
+++ b/test/lisp/erc/resources/join/network-id/foonet.eld
@@ -0,0 +1,39 @@
+;; -*- mode: lisp-data; -*-
+((pass 10 "PASS :foonet:changeme"))
+((nick 1 "NICK tester"))
+
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Mon, 10 May 2021 
00:58:22 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 10.2 "MODE tester +i"))
+;; No mode answer ^
+
+((join 3 "JOIN #chan")
+ (0 ":tester!~u@q6ddatxcq6txy.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :@alice bob tester")
+ (0 ":irc.foonet.org 366 tester #chan :End of NAMES list")
+ (0.1 ":bob!~u@q6ddatxcq6txy.irc PRIVMSG #chan :tester, welcome!")
+ (0 ":alice!~u@q6ddatxcq6txy.irc PRIVMSG #chan :tester, welcome!"))
+
+((mode 3 "MODE #chan")
+ (0 ":irc.foonet.org 324 tester #chan +nt")
+ (0 ":irc.foonet.org 329 tester #chan 1620608304")
+ (0.1 ":bob!~u@q6ddatxcq6txy.irc PRIVMSG #chan :alice: Pray you, sir, deliver 
me this paper.")
+ (0.1 ":alice!~u@q6ddatxcq6txy.irc PRIVMSG #chan :bob: Wake when some vile 
thing is near."))
+
+((quit 3 "QUIT :\2ERC\2"))
+
+((drop 0 DROP))
diff --git a/test/lisp/erc/resources/join/reconnect/foonet-again.eld 
b/test/lisp/erc/resources/join/reconnect/foonet-again.eld
new file mode 100644
index 0000000000..f1fcc439cc
--- /dev/null
+++ b/test/lisp/erc/resources/join/reconnect/foonet-again.eld
@@ -0,0 +1,45 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Tue, 04 May 2021 
05:06:18 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=FooNet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 3.2 "MODE tester +i")
+ (0 ":irc.foonet.org 221 tester +i")
+ (0 ":irc.foonet.org NOTICE tester :This server is still in debug mode."))
+
+((~join-chan 12 "JOIN #chan")
+ (0 ":tester!~u@9g6b728983yd2.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :alice tester @bob")
+ (0 ":irc.foonet.org 366 tester #chan :End of NAMES list"))
+
+((~join-spam 12 "JOIN #spam")
+ (0 ":tester!~u@9g6b728983yd2.irc JOIN #spam")
+ (0 ":irc.foonet.org 353 tester = #spam :alice tester @bob")
+ (0 ":irc.foonet.org 366 tester #spam :End of NAMES list"))
+
+((~mode-chan 4 "MODE #chan")
+ (0 ":irc.foonet.org 324 tester #chan +nt")
+ (0 ":irc.foonet.org 329 tester #chan 1620104779")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: But, as it seems, did 
violence on herself.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: Well, this is the 
forest of Arden."))
+
+((mode-spam 4 "MODE #spam")
+ (0 ":irc.foonet.org 324 tester #spam +nt")
+ (0 ":irc.foonet.org 329 tester #spam 1620104779")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #spam :alice: Signior Iachimo will 
not from it. Pray, let us follow 'em.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #spam :bob: Our queen and all her 
elves come here anon."))
diff --git a/test/lisp/erc/resources/join/reconnect/foonet.eld 
b/test/lisp/erc/resources/join/reconnect/foonet.eld
new file mode 100644
index 0000000000..efb269f5ae
--- /dev/null
+++ b/test/lisp/erc/resources/join/reconnect/foonet.eld
@@ -0,0 +1,45 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Tue, 04 May 2021 
05:06:18 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=FooNet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 3.2 "MODE tester +i")
+ (0 ":irc.foonet.org 221 tester +i")
+ (0 ":irc.foonet.org NOTICE tester :This server is in debug mode.")
+
+ (0 ":tester!~u@9g6b728983yd2.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :alice tester @bob")
+ (0 ":irc.foonet.org 366 tester #chan :End of NAMES list")
+
+ (0 ":tester!~u@9g6b728983yd2.irc JOIN #spam")
+ (0 ":irc.foonet.org 353 tester = #spam :alice tester @bob")
+ (0 ":irc.foonet.org 366 tester #spam :End of NAMES list"))
+
+((mode-chan 4 "MODE #chan")
+ (0 ":irc.foonet.org 324 tester #chan +nt")
+ (0 ":irc.foonet.org 329 tester #chan 1620104779")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :tester, welcome!")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :tester, welcome!"))
+
+((mode-spam 4 "MODE #spam")
+ (0 ":irc.foonet.org 324 tester #spam +nt")
+ (0 ":irc.foonet.org 329 tester #spam 1620104779")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #spam :tester, welcome!")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #spam :tester, welcome!"))
+
+((drop 0 DROP))
diff --git a/test/lisp/erc/resources/networks/announced-missing/foonet.eld 
b/test/lisp/erc/resources/networks/announced-missing/foonet.eld
new file mode 100644
index 0000000000..79b0fb462a
--- /dev/null
+++ b/test/lisp/erc/resources/networks/announced-missing/foonet.eld
@@ -0,0 +1,8 @@
+;; -*- mode: lisp-data; -*-
+((nick 1 "NICK tester"))
+((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/libera.eld 
b/test/lisp/erc/resources/services/auth-source/libera.eld
new file mode 100644
index 0000000000..c8dbc9d425
--- /dev/null
+++ b/test/lisp/erc/resources/services/auth-source/libera.eld
@@ -0,0 +1,49 @@
+;; -*- mode: lisp-data; -*-
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0.26 ":zirconium.libera.chat NOTICE * :*** Checking Ident")
+ (0.01 ":zirconium.libera.chat NOTICE * :*** Looking up your hostname...")
+ (0.01 ":zirconium.libera.chat NOTICE * :*** No Ident response")
+ (0.02 ":zirconium.libera.chat NOTICE * :*** Found your hostname: 
static-198-54-131-100.cust.tzulo.com")
+ (0.02 ":zirconium.libera.chat 001 tester :Welcome to the Libera.Chat Internet 
Relay Chat Network tester")
+ (0.01 ":zirconium.libera.chat 002 tester :Your host is 
zirconium.libera.chat[46.16.175.175/6697], running version solanum-1.0-dev")
+ (0.03 ":zirconium.libera.chat 003 tester :This server was created Wed Jun 9 
2021 at 01:38:28 UTC")
+ (0.02 ":zirconium.libera.chat 004 tester zirconium.libera.chat 
solanum-1.0-dev DGQRSZaghilopsuwz CFILMPQSbcefgijklmnopqrstuvz bkloveqjfI")
+ (0.00 ":zirconium.libera.chat 005 tester ETRACE WHOX FNC MONITOR=100 SAFELIST 
ELIST=CTU CALLERID=g KNOCK CHANTYPES=# EXCEPTS INVEX 
CHANMODES=eIbq,k,flj,CFLMPQScgimnprstuz :are supported by this server")
+ (0.03 ":zirconium.libera.chat 005 tester CHANLIMIT=#:250 PREFIX=(ov)@+ 
MAXLIST=bqeI:100 MODES=4 NETWORK=Libera.Chat STATUSMSG=@+ CASEMAPPING=rfc1459 
NICKLEN=16 MAXNICKLEN=16 CHANNELLEN=50 TOPICLEN=390 DEAF=D :are supported by 
this server")
+ (0.02 ":zirconium.libera.chat 005 tester 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,PRIVMSG:4,NOTICE:4,ACCEPT:,MONITOR: 
EXTBAN=$,ajrxz CLIENTVER=3.0 :are supported by this server")
+ (0.02 ":zirconium.libera.chat 251 tester :There are 68 users and 37640 
invisible on 25 servers")
+ (0.00 ":zirconium.libera.chat 252 tester 36 :IRC Operators online")
+ (0.01 ":zirconium.libera.chat 253 tester 5 :unknown connection(s)")
+ (0.00 ":zirconium.libera.chat 254 tester 19341 :channels formed")
+ (0.01 ":zirconium.libera.chat 255 tester :I have 3321 clients and 1 servers")
+ (0.01 ":zirconium.libera.chat 265 tester 3321 4289 :Current local users 3321, 
max 4289")
+ (0.00 ":zirconium.libera.chat 266 tester 37708 38929 :Current global users 
37708, max 38929")
+ (0.01 ":zirconium.libera.chat 250 tester :Highest connection count: 4290 
(4289 clients) (38580 connections received)")
+ (0.21 ":zirconium.libera.chat 375 tester :- zirconium.libera.chat Message of 
the Day - ")
+ (0.00 ":zirconium.libera.chat 372 tester :- This server provided by Seeweb 
<https://www.seeweb.it/>")
+ (0.01 ":zirconium.libera.chat 372 tester :- Welcome to Libera Chat, the IRC 
network for")
+ (0.01 ":zirconium.libera.chat 372 tester :- free & open-source software and 
peer directed projects.")
+ (0.00 ":zirconium.libera.chat 372 tester :-  ")
+ (0.00 ":zirconium.libera.chat 372 tester :- Use of Libera Chat is governed by 
our network policies.")
+ (0.00 ":zirconium.libera.chat 372 tester :-  ")
+ (0.01 ":zirconium.libera.chat 372 tester :- Please visit us in #libera for 
questions and support.")
+ (0.01 ":zirconium.libera.chat 372 tester :-  ")
+ (0.01 ":zirconium.libera.chat 372 tester :- Website and documentation:  
https://libera.chat";)
+ (0.01 ":zirconium.libera.chat 372 tester :- Webchat:                    
https://web.libera.chat";)
+ (0.01 ":zirconium.libera.chat 372 tester :- Network policies:           
https://libera.chat/policies";)
+ (0.01 ":zirconium.libera.chat 372 tester :- Email:                      
support@libera.chat")
+ (0.00 ":zirconium.libera.chat 376 tester :End of /MOTD command."))
+
+((mode-user 1.2 "MODE tester +i")
+ (0.02 ":tester MODE tester :+Zi")
+ (0.02 ":NickServ!NickServ@services.libera.chat NOTICE tester :This nickname 
is registered. Please choose a different nickname, or identify via \2/msg 
NickServ IDENTIFY tester <password>\2"))
+
+((privmsg 2 "PRIVMSG NickServ :IDENTIFY changeme")
+ (0.96 ":NickServ!NickServ@services.libera.chat NOTICE tester :You are now 
identified for \2tester\2.")
+ (0.25 ":NickServ!NickServ@services.libera.chat NOTICE tester :Last login 
from: \2~tester@school.edu/tester\2 on Jun 18 01:15:56 2021 +0000."))
+
+((quit 5 "QUIT :\2ERC\2")
+ (0.19 ":tester!~user@static-198-54-131-100.cust.tzulo.com QUIT :Client Quit"))
+
+((linger 1 LINGER))
diff --git a/test/lisp/erc/resources/services/password/libera.eld 
b/test/lisp/erc/resources/services/password/libera.eld
new file mode 100644
index 0000000000..c8dbc9d425
--- /dev/null
+++ b/test/lisp/erc/resources/services/password/libera.eld
@@ -0,0 +1,49 @@
+;; -*- mode: lisp-data; -*-
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0.26 ":zirconium.libera.chat NOTICE * :*** Checking Ident")
+ (0.01 ":zirconium.libera.chat NOTICE * :*** Looking up your hostname...")
+ (0.01 ":zirconium.libera.chat NOTICE * :*** No Ident response")
+ (0.02 ":zirconium.libera.chat NOTICE * :*** Found your hostname: 
static-198-54-131-100.cust.tzulo.com")
+ (0.02 ":zirconium.libera.chat 001 tester :Welcome to the Libera.Chat Internet 
Relay Chat Network tester")
+ (0.01 ":zirconium.libera.chat 002 tester :Your host is 
zirconium.libera.chat[46.16.175.175/6697], running version solanum-1.0-dev")
+ (0.03 ":zirconium.libera.chat 003 tester :This server was created Wed Jun 9 
2021 at 01:38:28 UTC")
+ (0.02 ":zirconium.libera.chat 004 tester zirconium.libera.chat 
solanum-1.0-dev DGQRSZaghilopsuwz CFILMPQSbcefgijklmnopqrstuvz bkloveqjfI")
+ (0.00 ":zirconium.libera.chat 005 tester ETRACE WHOX FNC MONITOR=100 SAFELIST 
ELIST=CTU CALLERID=g KNOCK CHANTYPES=# EXCEPTS INVEX 
CHANMODES=eIbq,k,flj,CFLMPQScgimnprstuz :are supported by this server")
+ (0.03 ":zirconium.libera.chat 005 tester CHANLIMIT=#:250 PREFIX=(ov)@+ 
MAXLIST=bqeI:100 MODES=4 NETWORK=Libera.Chat STATUSMSG=@+ CASEMAPPING=rfc1459 
NICKLEN=16 MAXNICKLEN=16 CHANNELLEN=50 TOPICLEN=390 DEAF=D :are supported by 
this server")
+ (0.02 ":zirconium.libera.chat 005 tester 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,PRIVMSG:4,NOTICE:4,ACCEPT:,MONITOR: 
EXTBAN=$,ajrxz CLIENTVER=3.0 :are supported by this server")
+ (0.02 ":zirconium.libera.chat 251 tester :There are 68 users and 37640 
invisible on 25 servers")
+ (0.00 ":zirconium.libera.chat 252 tester 36 :IRC Operators online")
+ (0.01 ":zirconium.libera.chat 253 tester 5 :unknown connection(s)")
+ (0.00 ":zirconium.libera.chat 254 tester 19341 :channels formed")
+ (0.01 ":zirconium.libera.chat 255 tester :I have 3321 clients and 1 servers")
+ (0.01 ":zirconium.libera.chat 265 tester 3321 4289 :Current local users 3321, 
max 4289")
+ (0.00 ":zirconium.libera.chat 266 tester 37708 38929 :Current global users 
37708, max 38929")
+ (0.01 ":zirconium.libera.chat 250 tester :Highest connection count: 4290 
(4289 clients) (38580 connections received)")
+ (0.21 ":zirconium.libera.chat 375 tester :- zirconium.libera.chat Message of 
the Day - ")
+ (0.00 ":zirconium.libera.chat 372 tester :- This server provided by Seeweb 
<https://www.seeweb.it/>")
+ (0.01 ":zirconium.libera.chat 372 tester :- Welcome to Libera Chat, the IRC 
network for")
+ (0.01 ":zirconium.libera.chat 372 tester :- free & open-source software and 
peer directed projects.")
+ (0.00 ":zirconium.libera.chat 372 tester :-  ")
+ (0.00 ":zirconium.libera.chat 372 tester :- Use of Libera Chat is governed by 
our network policies.")
+ (0.00 ":zirconium.libera.chat 372 tester :-  ")
+ (0.01 ":zirconium.libera.chat 372 tester :- Please visit us in #libera for 
questions and support.")
+ (0.01 ":zirconium.libera.chat 372 tester :-  ")
+ (0.01 ":zirconium.libera.chat 372 tester :- Website and documentation:  
https://libera.chat";)
+ (0.01 ":zirconium.libera.chat 372 tester :- Webchat:                    
https://web.libera.chat";)
+ (0.01 ":zirconium.libera.chat 372 tester :- Network policies:           
https://libera.chat/policies";)
+ (0.01 ":zirconium.libera.chat 372 tester :- Email:                      
support@libera.chat")
+ (0.00 ":zirconium.libera.chat 376 tester :End of /MOTD command."))
+
+((mode-user 1.2 "MODE tester +i")
+ (0.02 ":tester MODE tester :+Zi")
+ (0.02 ":NickServ!NickServ@services.libera.chat NOTICE tester :This nickname 
is registered. Please choose a different nickname, or identify via \2/msg 
NickServ IDENTIFY tester <password>\2"))
+
+((privmsg 2 "PRIVMSG NickServ :IDENTIFY changeme")
+ (0.96 ":NickServ!NickServ@services.libera.chat NOTICE tester :You are now 
identified for \2tester\2.")
+ (0.25 ":NickServ!NickServ@services.libera.chat NOTICE tester :Last login 
from: \2~tester@school.edu/tester\2 on Jun 18 01:15:56 2021 +0000."))
+
+((quit 5 "QUIT :\2ERC\2")
+ (0.19 ":tester!~user@static-198-54-131-100.cust.tzulo.com QUIT :Client Quit"))
+
+((linger 1 LINGER))
diff --git a/test/lisp/eshell/em-alias-tests.el 
b/test/lisp/eshell/em-alias-tests.el
new file mode 100644
index 0000000000..aca622220e
--- /dev/null
+++ b/test/lisp/eshell/em-alias-tests.el
@@ -0,0 +1,87 @@
+;;; em-alias-tests.el --- em-alias 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 alias module.
+
+;;; Code:
+
+(require 'ert)
+(require 'esh-mode)
+(require 'eshell)
+(require 'em-alias)
+
+(require 'eshell-tests-helpers
+         (expand-file-name "eshell-tests-helpers"
+                           (file-name-directory (or load-file-name
+                                                    default-directory))))
+;;; Tests:
+
+(ert-deftest em-alias-test/simple-alias ()
+  "Test a simple alias with no arguments"
+  (with-temp-eshell
+   (eshell-insert-command "alias say-hi 'echo hi'")
+   (eshell-match-command-output "say-hi" "hi\n")
+   (eshell-match-command-output "say-hi bye" "hi\n")))
+
+(ert-deftest em-alias-test/alias-arg-vars ()
+  "Test alias with $0, $1, ... variables"
+  (with-temp-eshell
+   (eshell-insert-command "alias show-args 'printnl $0 \"$1 $2\"'")
+   (eshell-match-command-output "show-args one two" "show-args\none two\n")))
+
+(ert-deftest em-alias-test/alias-arg-vars-indices ()
+  "Test alias with $1, $2, ... variables using indices"
+  (with-temp-eshell
+   (eshell-insert-command "alias funny-sum '+ $1[0] $2[1]'")
+   (eshell-match-command-output "funny-sum (list 1 2) (list 3 4)"
+                                "5\n")))
+
+(ert-deftest em-alias-test/alias-arg-vars-split-indices ()
+  "Test alias with $0, $1, ... variables using split indices"
+  (with-temp-eshell
+   (eshell-insert-command "alias my-prefix 'echo $0[- 0]'")
+   (eshell-match-command-output "my-prefix"
+                                "my\n")
+   (eshell-insert-command "alias funny-sum '+ $1[: 0] $2[: 1]'")
+   (eshell-match-command-output "funny-sum 1:2 3:4"
+                                "5\n")))
+
+(ert-deftest em-alias-test/alias-all-args-var ()
+  "Test alias with the $* variable"
+  (with-temp-eshell
+   (eshell-insert-command "alias show-all-args 'printnl $*'")
+   (eshell-match-command-output "show-all-args" "\\`\\'")
+   (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-indices ()
+  "Test alias with the $* variable using indices"
+  (with-temp-eshell
+   (eshell-insert-command "alias add-pair '+ $*[0] $*[1]'")
+   (eshell-match-command-output "add-pair 1 2" "3\n")))
+
+(ert-deftest em-alias-test/alias-all-args-var-split-indices ()
+  "Test alias with the $* variable using split indices"
+  (with-temp-eshell
+   (eshell-insert-command "alias add-funny-pair '+ $*[0][: 0] $*[1][: 1]'")
+   (eshell-match-command-output "add-funny-pair 1:2 3:4" "5\n")))
+
+;; em-alias-tests.el ends here
diff --git a/test/lisp/eshell/em-basic-tests.el 
b/test/lisp/eshell/em-basic-tests.el
index 7a24f8b46c..bc8baeaa03 100644
--- a/test/lisp/eshell/em-basic-tests.el
+++ b/test/lisp/eshell/em-basic-tests.el
@@ -36,25 +36,25 @@
 (ert-deftest em-basic-test/umask-print-numeric ()
   "Test printing umask numerically."
   (cl-letf (((symbol-function 'default-file-modes) (lambda () #o775)))
-    (should (equal (eshell-test-command-result "umask") "002\n")))
+    (eshell-command-result-equal "umask" "002\n"))
   (cl-letf (((symbol-function 'default-file-modes) (lambda () #o654)))
-    (should (equal (eshell-test-command-result "umask") "123\n")))
+    (eshell-command-result-equal "umask" "123\n"))
   ;; Make sure larger numbers don't cause problems.
   (cl-letf (((symbol-function 'default-file-modes) (lambda () #o1775)))
-    (should (equal (eshell-test-command-result "umask") "002\n"))))
+    (eshell-command-result-equal "umask" "002\n")))
 
 (ert-deftest em-basic-test/umask-read-symbolic ()
   "Test printing umask symbolically."
   (cl-letf (((symbol-function 'default-file-modes) (lambda () #o775)))
-    (should (equal (eshell-test-command-result "umask -S")
-                   "u=rwx,g=rwx,o=rx\n")))
+    (eshell-command-result-equal "umask -S"
+                                 "u=rwx,g=rwx,o=rx\n"))
   (cl-letf (((symbol-function 'default-file-modes) (lambda () #o654)))
-    (should (equal (eshell-test-command-result "umask -S")
-                   "u=wx,g=rx,o=x\n")))
+    (eshell-command-result-equal "umask -S"
+                                 "u=wx,g=rx,o=x\n"))
   ;; Make sure larger numbers don't cause problems.
   (cl-letf (((symbol-function 'default-file-modes) (lambda () #o1775)))
-    (should (equal (eshell-test-command-result "umask -S")
-                   "u=rwx,g=rwx,o=rx\n"))))
+    (eshell-command-result-equal "umask -S"
+                                 "u=rwx,g=rwx,o=rx\n")))
 
 (ert-deftest em-basic-test/umask-set ()
   "Test setting umask."
diff --git a/test/lisp/eshell/em-dirs-tests.el 
b/test/lisp/eshell/em-dirs-tests.el
new file mode 100644
index 0000000000..f72d708dca
--- /dev/null
+++ b/test/lisp/eshell/em-dirs-tests.el
@@ -0,0 +1,102 @@
+;;; em-dirs-tests.el --- em-dirs 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 dirs module.
+
+;;; Code:
+
+(require 'ert)
+(require 'esh-mode)
+(require 'eshell)
+(require 'em-dirs)
+
+(require 'eshell-tests-helpers
+         (expand-file-name "eshell-tests-helpers"
+                           (file-name-directory (or load-file-name
+                                                    default-directory))))
+;;; Tests:
+
+(ert-deftest em-dirs-test/pwd-var ()
+  "Test using the $PWD variable."
+  (let ((default-directory "/some/path"))
+    (eshell-command-result-equal "echo $PWD"
+                                 (expand-file-name default-directory))))
+
+(ert-deftest em-dirs-test/pwd-var-indices ()
+  "Test using the $PWD variable with indices."
+  (let ((default-directory "/some/path/here"))
+    (eshell-command-result-equal "echo $PWD[/ 1]"
+                                 "some")
+    (eshell-command-result-equal "echo $PWD[/ 1 3]"
+                                 '("some" "here"))))
+
+(ert-deftest em-dirs-test/short-pwd-var ()
+  "Test using the $+ (current directory) variable."
+  (let ((default-directory "/some/path"))
+    (eshell-command-result-equal "echo $+"
+                                 (expand-file-name default-directory))))
+
+(ert-deftest em-dirs-test/oldpwd-var ()
+  "Test using the $OLDPWD variable."
+  (let (eshell-last-dir-ring-file-name)
+    (with-temp-eshell
+     (eshell-match-command-output "echo $OLDPWD"
+                                  "\\`\\'")
+     (ring-insert eshell-last-dir-ring "/some/path")
+     (eshell-match-command-output "echo $OLDPWD"
+                                  "/some/path\n"))))
+
+(ert-deftest em-dirs-test/oldpwd-var-indices ()
+  "Test using the $OLDPWD variable with indices."
+  (let (eshell-last-dir-ring-file-name)
+    (with-temp-eshell
+     (ring-insert eshell-last-dir-ring "/some/path/here")
+     (eshell-match-command-output "echo $OLDPWD[/ 1]"
+                                  "some\n")
+     (eshell-match-command-output "echo $OLDPWD[/ 1 3]"
+                                  "(\"some\" \"here\")\n"))))
+
+(ert-deftest em-dirs-test/directory-ring-var ()
+  "Test using the $- (directory ring) variable."
+  (let (eshell-last-dir-ring-file-name)
+    (with-temp-eshell
+     (eshell-match-command-output "echo $-"
+                                  "\\`\\'")
+     (ring-insert eshell-last-dir-ring "/some/path")
+     (ring-insert eshell-last-dir-ring "/other/path")
+     (eshell-match-command-output "echo $-"
+                                  "/other/path\n")
+     (eshell-match-command-output "echo $-[0]"
+                                  "/other/path\n")
+     (eshell-match-command-output "echo $-[1]"
+                                  "/some/path\n"))))
+
+(ert-deftest em-dirs-test/directory-ring-var-indices ()
+  "Test using the $- (directory ring) variable with multiple indices."
+  (let (eshell-last-dir-ring-file-name)
+    (with-temp-eshell
+     (ring-insert eshell-last-dir-ring "/some/path/here")
+     (eshell-match-command-output "echo $-[0][/ 1]"
+                                  "some\n")
+     (eshell-match-command-output "echo $-[1][/ 1 3]"
+                                  "(\"some\" \"here\")\n"))))
+
+;; em-dirs-tests.el ends here
diff --git a/test/lisp/eshell/em-extpipe-tests.el 
b/test/lisp/eshell/em-extpipe-tests.el
index 3b84d763ac..04e7827942 100644
--- a/test/lisp/eshell/em-extpipe-tests.el
+++ b/test/lisp/eshell/em-extpipe-tests.el
@@ -71,7 +71,6 @@
        (skip-unless shell-file-name)
        (skip-unless shell-command-switch)
        (skip-unless (executable-find shell-file-name))
-       (skip-unless (not (getenv "EMACS_EMBA_CI")))
        (let ((input ,input))
          (with-temp-eshell ,@body)))))
 
@@ -81,7 +80,7 @@
   (should-parse '(eshell-named-command
                   "sh" (list "-c" "echo \"bar\" | rev >temp")))
   (with-substitute-for-temp
-   (eshell-command-result-p input "^$")
+   (eshell-match-command-output input "^$")
    (temp-should-string= "rab")))
 
 (em-extpipe-tests--deftest em-extpipe-test-2
@@ -92,7 +91,7 @@
      '((eshell-named-command "echo" (list (eshell-escape-arg "bar")))
        (eshell-named-command "sh" (list "-c" "rev >temp")))))
   (with-substitute-for-temp
-   (eshell-command-result-p input "^$")
+   (eshell-match-command-output input "^$")
    (temp-should-string= "rab")))
 
 (em-extpipe-tests--deftest em-extpipe-test-3 "foo *| bar | baz -d"
@@ -112,7 +111,7 @@
       (eshell-named-command "sh"
                            (list "-c" "echo \"bar\" | rev"))))
   (with-substitute-for-temp
-   (eshell-command-result-p input "^$")
+   (eshell-match-command-output input "^$")
    (temp-buffer-should-string= "rab")))
 
 (em-extpipe-tests--deftest em-extpipe-test-5
@@ -178,7 +177,7 @@
   (should-parse '(eshell-named-command "sh" (list "-c" "tac <temp")))
   (with-substitute-for-temp
    (with-temp-buffer (insert "bar\nbaz\n") (write-file temp))
-   (eshell-command-result-p input "baz\nbar")))
+   (eshell-match-command-output input "baz\nbar")))
 
 (em-extpipe-tests--deftest em-extpipe-test-15 "echo \"bar\" *| cat"
   (skip-unless (executable-find "cat"))
@@ -186,8 +185,8 @@
    '(eshell-named-command "sh" (list "-c" "echo \"bar\" | cat")))
   (cl-letf (((symbol-function 'eshell/cat)
              (lambda (&rest _args) (eshell-print "nonsense"))))
-    (eshell-command-result-p input "bar")
-    (eshell-command-result-p "echo \"bar\" | cat" "nonsense")))
+    (eshell-match-command-output input "bar")
+    (eshell-match-command-output "echo \"bar\" | cat" "nonsense")))
 
 (em-extpipe-tests--deftest em-extpipe-test-16 "echo \"bar\" *| rev"
   (skip-unless (executable-find "rev"))
@@ -196,11 +195,11 @@
   (let ((eshell-prefer-lisp-functions t))
     (cl-letf (((symbol-function 'rev)
                (lambda (&rest _args) (eshell-print "nonsense"))))
-      (eshell-command-result-p input "rab")
-      (eshell-command-result-p "echo \"bar\" | rev" "nonsense"))))
+      (eshell-match-command-output input "rab")
+      (eshell-match-command-output "echo \"bar\" | rev" "nonsense"))))
 
 ;; Confirm we don't break input of sharp-quoted symbols (Bug#53518).
 (em-extpipe-tests--deftest em-extpipe-test-17 "funcall #'upcase foo"
-  (eshell-command-result-p input "FOO"))
+  (eshell-match-command-output input "FOO"))
 
 ;;; em-extpipe-tests.el ends here
diff --git a/test/lisp/eshell/em-glob-tests.el 
b/test/lisp/eshell/em-glob-tests.el
index 9976b32ffe..b733be35d9 100644
--- a/test/lisp/eshell/em-glob-tests.el
+++ b/test/lisp/eshell/em-glob-tests.el
@@ -60,6 +60,12 @@ component ending in \"symlink\" is treated as a symbolic 
link."
     (should (equal (eshell-extended-glob "*.el")
                    '("a.el" "b.el")))))
 
+(ert-deftest em-glob-test/match-any-directory ()
+  "Test that \"*/\" pattern matches any directory."
+  (with-fake-files '("a.el" "b.el" "dir/a.el" "dir/sub/a.el" "symlink/")
+    (should (equal (eshell-extended-glob "*/")
+                   '("dir/" "symlink/")))))
+
 (ert-deftest em-glob-test/match-any-character ()
   "Test that \"?\" pattern matches any character."
   (with-fake-files '("a.el" "b.el" "ccc.el" "d.txt" "dir/a.el")
@@ -71,7 +77,9 @@ component ending in \"symlink\" is treated as a symbolic 
link."
   (with-fake-files '("a.el" "b.el" "ccc.el" "d.txt" "dir/a.el" "dir/sub/a.el"
                      "dir/symlink/a.el" "symlink/a.el" "symlink/sub/a.el")
     (should (equal (eshell-extended-glob "**/a.el")
-                   '("a.el" "dir/a.el" "dir/sub/a.el")))))
+                   '("a.el" "dir/a.el" "dir/sub/a.el")))
+    (should (equal (eshell-extended-glob "**/")
+                   '("dir/" "dir/sub/")))))
 
 (ert-deftest em-glob-test/match-recursive-follow-symlinks ()
   "Test that \"***/\" recursively matches directories, following symlinks."
@@ -79,7 +87,10 @@ component ending in \"symlink\" is treated as a symbolic 
link."
                      "dir/symlink/a.el" "symlink/a.el" "symlink/sub/a.el")
     (should (equal (eshell-extended-glob "***/a.el")
                    '("a.el" "dir/a.el" "dir/sub/a.el" "dir/symlink/a.el"
-                     "symlink/a.el" "symlink/sub/a.el")))))
+                     "symlink/a.el" "symlink/sub/a.el")))
+    (should (equal (eshell-extended-glob "***/")
+                   '("dir/" "dir/sub/" "dir/symlink/" "symlink/"
+                     "symlink/sub/")))))
 
 (ert-deftest em-glob-test/match-recursive-mixed ()
   "Test combination of \"**/\" and \"***/\"."
@@ -160,6 +171,21 @@ component ending in \"symlink\" is treated as a symbolic 
link."
     (should (equal (eshell-extended-glob "[[:digit:]]##~4?")
                    '("1" "12" "123")))))
 
+(ert-deftest em-glob-test/match-dot-files ()
+  "Test that dot files are matched correctly."
+  (with-fake-files '("foo.el" ".emacs")
+    (should (equal (eshell-extended-glob ".*")
+                   '("../" "./" ".emacs")))
+    (let (eshell-glob-include-dot-dot)
+      (should (equal (eshell-extended-glob ".*")
+                     '(".emacs"))))
+    (let ((eshell-glob-include-dot-files t))
+      (should (equal (eshell-extended-glob "*")
+                     '("../" "./" ".emacs" "foo.el")))
+      (let (eshell-glob-include-dot-dot)
+        (should (equal (eshell-extended-glob "*")
+                       '(".emacs" "foo.el")))))))
+
 (ert-deftest em-glob-test/no-matches ()
   "Test behavior when a glob fails to match any files."
   (with-fake-files '("foo.el" "bar.el")
diff --git a/test/lisp/eshell/em-pred-tests.el 
b/test/lisp/eshell/em-pred-tests.el
index 3b50543d69..0d6351ec82 100644
--- a/test/lisp/eshell/em-pred-tests.el
+++ b/test/lisp/eshell/em-pred-tests.el
@@ -26,6 +26,7 @@
 (require 'ert)
 (require 'esh-mode)
 (require 'eshell)
+(require 'em-glob)
 (require 'em-pred)
 
 (require 'eshell-tests-helpers
@@ -39,10 +40,9 @@
   "Evaluate PREDICATE on INITIAL-VALUE, returning the result.
 PREDICATE is an Eshell argument predicate/modifier."
   (let ((eshell-test-value initial-value))
-    (with-temp-eshell
-     (eshell-insert-command
-      (format "setq eshell-test-value $eshell-test-value(%s)" predicate)))
-    eshell-test-value))
+    (ignore-errors
+      (eshell-test-command-result
+       (format "echo $eshell-test-value(%s)" predicate)))))
 
 (defun eshell-parse-file-name-attributes (file)
   "Parse a fake FILE name to determine its attributes.
@@ -75,7 +75,7 @@ The following attributes are recognized:
               (`(,(and (or "links" "uid" "gid" "size") key) ,value)
                (cons (intern key) (string-to-number value)))
               (`(,(and (or "atime" "mtime" "ctime") key) ,value)
-               (cons (intern key) (time-convert (string-to-number value))))
+               (cons (intern key) (time-convert (string-to-number value) t)))
               (`(,key ,value)
                (cons (intern key) value))
               (_ (error "invalid format %S" i))))
@@ -545,4 +545,22 @@ PREDICATE is the predicate used to query that attribute."
   (should (equal (eshell-eval-predicate '("foo" "bar" "baz") ":j'\\\"'")
                  "foo\\\"bar\\\"baz")))
 
+(ert-deftest em-pred-test/no-matches ()
+  "Test behavior when a predicate fails to match any files."
+  (eshell-with-file-attributes-from-name
+    (let ((files '("/fake/modes=0666" "/fake/type=d,modes=0777"
+                   "/fake/type=l,modes=0777")))
+      (should (equal (eshell-eval-predicate files "*") nil))
+      (let ((eshell-error-if-no-glob t))
+        ;; Don't signal an error if the original list is empty.
+        (should (equal (eshell-eval-predicate nil "*") nil))
+        ;; Ensure this signals an error.  This test case is a bit
+        ;; clumsy, since `eshell-do-eval' makes it hard to catch
+        ;; errors otherwise.
+        (let ((modifiers (with-temp-eshell
+                          (eshell-with-temp-command "*"
+                            (eshell-parse-modifiers)))))
+          (should-error (eshell-apply-modifiers files (car modifiers)
+                                                (cdr modifiers) "*")))))))
+
 ;; em-pred-tests.el ends here
diff --git a/test/lisp/eshell/em-script-tests.el 
b/test/lisp/eshell/em-script-tests.el
new file mode 100644
index 0000000000..b837d464cc
--- /dev/null
+++ b/test/lisp/eshell/em-script-tests.el
@@ -0,0 +1,62 @@
+;;; em-script-tests.el --- em-script 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 script module.
+
+;;; Code:
+
+(require 'ert)
+(require 'esh-mode)
+(require 'eshell)
+(require 'em-script)
+
+(require 'eshell-tests-helpers
+         (expand-file-name "eshell-tests-helpers"
+                           (file-name-directory (or load-file-name
+                                                    default-directory))))
+;;; Tests:
+
+(ert-deftest em-script-test/source-script ()
+  "Test sourcing script with no argumentss"
+  (ert-with-temp-file temp-file :text "echo hi"
+    (with-temp-eshell
+     (eshell-match-command-output (format "source %s" temp-file)
+                                  "hi\n"))))
+
+(ert-deftest em-script-test/source-script-arg-vars ()
+  "Test sourcing script with $0, $1, ... variables"
+  (ert-with-temp-file temp-file :text "printnl $0 \"$1 $2\""
+    (with-temp-eshell
+     (eshell-match-command-output (format "source %s one two" temp-file)
+                                  (format "%s\none two\n" temp-file)))))
+
+(ert-deftest em-script-test/source-script-all-args-var ()
+  "Test sourcing script with the $* variable"
+  (ert-with-temp-file temp-file :text "printnl $*"
+    (with-temp-eshell
+     (eshell-match-command-output (format "source %s" temp-file)
+                                  "\\`\\'")
+     (eshell-match-command-output (format "source %s a" temp-file)
+                                  "a\n")
+     (eshell-match-command-output (format "source %s a b c" temp-file)
+                                  "a\nb\nc\n"))))
+
+;; em-script-tests.el ends here
diff --git a/test/lisp/eshell/esh-cmd-tests.el 
b/test/lisp/eshell/esh-cmd-tests.el
new file mode 100644
index 0000000000..3a582965d6
--- /dev/null
+++ b/test/lisp/eshell/esh-cmd-tests.el
@@ -0,0 +1,275 @@
+;;; esh-cmd-tests.el --- esh-cmd 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 command invocation.
+
+;;; 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:
+
+
+;; Command invocation
+
+(ert-deftest esh-cmd-test/simple-command-result ()
+  "Test invocation with a simple command."
+  (eshell-command-result-equal "+ 1 2" 3))
+
+(ert-deftest esh-cmd-test/lisp-command ()
+  "Test invocation with an elisp command."
+  (eshell-command-result-equal "(+ 1 2)" 3))
+
+(ert-deftest esh-cmd-test/lisp-command-with-quote ()
+  "Test invocation with an elisp command containing a quote."
+  (eshell-command-result-equal "(eq 'foo nil)" nil))
+
+(ert-deftest esh-cmd-test/lisp-command-args ()
+  "Test invocation with elisp and trailing args.
+Test that trailing arguments outside the S-expression are
+ignored.  e.g. \"(+ 1 2) 3\" => 3"
+  (eshell-command-result-equal "(+ 1 2) 3" 3))
+
+(ert-deftest esh-cmd-test/subcommand ()
+  "Test invocation with a simple subcommand."
+  (eshell-command-result-equal "{+ 1 2}" 3))
+
+(ert-deftest esh-cmd-test/subcommand-args ()
+  "Test invocation with a subcommand and trailing args.
+Test that trailing arguments outside the subcommand are ignored.
+e.g. \"{+ 1 2} 3\" => 3"
+  (eshell-command-result-equal "{+ 1 2} 3" 3))
+
+(ert-deftest esh-cmd-test/subcommand-lisp ()
+  "Test invocation with an elisp subcommand and trailing args.
+Test that trailing arguments outside the subcommand are ignored.
+e.g. \"{(+ 1 2)} 3\" => 3"
+  (eshell-command-result-equal "{(+ 1 2)} 3" 3))
+
+
+;; Logical operators
+
+(ert-deftest esh-cmd-test/and-operator ()
+  "Test logical && operator."
+  (skip-unless (executable-find "["))
+  (with-temp-eshell
+   (eshell-match-command-output "[ foo = foo ] && echo hi"
+                                "hi\n")
+   (eshell-match-command-output "[ foo = bar ] && echo hi"
+                                "\\`\\'")))
+
+(ert-deftest esh-cmd-test/or-operator ()
+  "Test logical || operator."
+  (skip-unless (executable-find "["))
+  (with-temp-eshell
+   (eshell-match-command-output "[ foo = foo ] || echo hi"
+                                "\\`\\'")
+   (eshell-match-command-output "[ foo = bar ] || echo hi"
+                                "hi\n")))
+
+
+;; Control flow statements
+
+(ert-deftest esh-cmd-test/for-loop ()
+  "Test invocation of a for loop."
+  (with-temp-eshell
+   (eshell-match-command-output "for i in 5 { echo $i }"
+                                "5\n")))
+
+(ert-deftest esh-cmd-test/for-loop-list ()
+  "Test invocation of a for loop iterating over a list."
+  (with-temp-eshell
+   (eshell-match-command-output "for i in (list 1 2 (list 3 4)) { echo $i }"
+                                "1\n2\n(3 4)\n")))
+
+(ert-deftest esh-cmd-test/for-loop-multiple-args ()
+  "Test invocation of a for loop iterating over multiple arguments."
+  (with-temp-eshell
+   (eshell-match-command-output "for i in 1 2 (list 3 4) { echo $i }"
+                                "1\n2\n3\n4\n")))
+
+(ert-deftest esh-cmd-test/for-name-loop () ; bug#15231
+  "Test invocation of a for loop using `name'."
+  (let ((process-environment (cons "name" process-environment)))
+    (eshell-command-result-equal "for name in 3 { echo $name }"
+                                 3)))
+
+(ert-deftest esh-cmd-test/for-name-shadow-loop () ; bug#15372
+  "Test invocation of a for loop using an env-var."
+  (let ((process-environment (cons "name=env-value" process-environment)))
+    (with-temp-eshell
+     (eshell-match-command-output
+      "echo $name; for name in 3 { echo $name }; echo $name"
+      "env-value\n3\nenv-value\n"))))
+
+(ert-deftest esh-cmd-test/while-loop ()
+  "Test invocation of a while loop."
+  (with-temp-eshell
+   (let ((eshell-test-value '(0 1 2)))
+     (eshell-match-command-output
+      (concat "while $eshell-test-value "
+              "{ setq eshell-test-value (cdr eshell-test-value) }")
+      "(1 2)\n(2)\n"))))
+
+(ert-deftest esh-cmd-test/while-loop-lisp-form ()
+  "Test invocation of a while loop using a Lisp form."
+  (with-temp-eshell
+   (let ((eshell-test-value 0))
+     (eshell-match-command-output
+      (concat "while (/= eshell-test-value 3) "
+              "{ setq eshell-test-value (1+ eshell-test-value) }")
+      "1\n2\n3\n"))))
+
+(ert-deftest esh-cmd-test/while-loop-ext-cmd ()
+  "Test invocation of a while loop using an external command."
+  (skip-unless (executable-find "["))
+  (with-temp-eshell
+   (let ((eshell-test-value 0))
+     (eshell-match-command-output
+      (concat "while {[ $eshell-test-value -ne 3 ]} "
+              "{ setq eshell-test-value (1+ eshell-test-value) }")
+      "1\n2\n3\n"))))
+
+(ert-deftest esh-cmd-test/until-loop ()
+  "Test invocation of an until loop."
+  (with-temp-eshell
+   (let ((eshell-test-value nil))
+     (eshell-match-command-output
+      (concat "until $eshell-test-value "
+              "{ setq eshell-test-value t }")
+      "t\n"))))
+
+(ert-deftest esh-cmd-test/until-loop-lisp-form ()
+  "Test invocation of an until loop using a Lisp form."
+  (skip-unless (executable-find "["))
+  (with-temp-eshell
+   (let ((eshell-test-value 0))
+     (eshell-match-command-output
+      (concat "until (= eshell-test-value 3) "
+              "{ setq eshell-test-value (1+ eshell-test-value) }")
+      "1\n2\n3\n"))))
+
+(ert-deftest esh-cmd-test/until-loop-ext-cmd ()
+  "Test invocation of an until loop using an external command."
+  (skip-unless (executable-find "["))
+  (with-temp-eshell
+   (let ((eshell-test-value 0))
+     (eshell-match-command-output
+      (concat "until {[ $eshell-test-value -eq 3 ]} "
+              "{ setq eshell-test-value (1+ eshell-test-value) }")
+      "1\n2\n3\n"))))
+
+(ert-deftest esh-cmd-test/if-statement ()
+  "Test invocation of an if statement."
+  (let ((eshell-test-value t))
+    (eshell-command-result-equal "if $eshell-test-value {echo yes}"
+                                 "yes"))
+  (let ((eshell-test-value nil))
+    (eshell-command-result-equal "if $eshell-test-value {echo yes}"
+                                 nil)))
+
+(ert-deftest esh-cmd-test/if-else-statement ()
+  "Test invocation of an if/else statement."
+  (let ((eshell-test-value t))
+    (eshell-command-result-equal "if $eshell-test-value {echo yes} {echo no}"
+                                 "yes"))
+  (let ((eshell-test-value nil))
+    (eshell-command-result-equal "if $eshell-test-value {echo yes} {echo no}"
+                                 "no")))
+
+(ert-deftest esh-cmd-test/if-else-statement-lisp-form ()
+  "Test invocation of an if/else statement using a Lisp form."
+  (eshell-command-result-equal "if (zerop 0) {echo yes} {echo no}"
+                               "yes")
+  (eshell-command-result-equal "if (zerop 1) {echo yes} {echo no}"
+                               "no")
+  (let ((debug-on-error nil))
+    (eshell-command-result-equal "if (zerop \"foo\") {echo yes} {echo no}"
+                                 "no")))
+
+(ert-deftest esh-cmd-test/if-else-statement-lisp-form-2 ()
+  "Test invocation of an if/else statement using a Lisp form.
+This tests when `eshell-lisp-form-nil-is-failure' is nil."
+  (let ((eshell-lisp-form-nil-is-failure nil))
+    (eshell-command-result-equal "if (zerop 0) {echo yes} {echo no}"
+                                 "yes")
+    (eshell-command-result-equal "if (zerop 1) {echo yes} {echo no}"
+                                 "yes")
+    (let ((debug-on-error nil))
+      (eshell-command-result-equal "if (zerop \"foo\") {echo yes} {echo no}"
+                                   "no"))))
+
+(ert-deftest esh-cmd-test/if-else-statement-ext-cmd ()
+  "Test invocation of an if/else statement using an external command."
+  (skip-unless (executable-find "["))
+  (eshell-command-result-equal "if {[ foo = foo ]} {echo yes} {echo no}"
+                               "yes")
+  (eshell-command-result-equal "if {[ foo = bar ]} {echo yes} {echo no}"
+                               "no"))
+
+(ert-deftest esh-cmd-test/unless-statement ()
+  "Test invocation of an unless statement."
+  (let ((eshell-test-value t))
+    (eshell-command-result-equal "unless $eshell-test-value {echo no}"
+                                 nil))
+  (let ((eshell-test-value nil))
+    (eshell-command-result-equal "unless $eshell-test-value {echo no}"
+                                 "no")))
+
+(ert-deftest esh-cmd-test/unless-else-statement ()
+  "Test invocation of an unless/else statement."
+  (let ((eshell-test-value t))
+    (eshell-command-result-equal
+     "unless $eshell-test-value {echo no} {echo yes}"
+     "yes"))
+  (let ((eshell-test-value nil))
+    (eshell-command-result-equal
+     "unless $eshell-test-value {echo no} {echo yes}"
+     "no")))
+
+(ert-deftest esh-cmd-test/unless-else-statement-lisp-form ()
+  "Test invocation of an unless/else statement using a Lisp form."
+  (eshell-command-result-equal "unless (zerop 0) {echo no} {echo yes}"
+                               "yes")
+  (eshell-command-result-equal "unless (zerop 1) {echo no} {echo yes}"
+                               "no")
+  (let ((debug-on-error nil))
+    (eshell-command-result-equal "unless (zerop \"foo\") {echo no} {echo yes}"
+                                 "no")))
+
+(ert-deftest esh-cmd-test/unless-else-statement-ext-cmd ()
+  "Test invocation of an unless/else statement using an external command."
+  (skip-unless (executable-find "["))
+  (eshell-command-result-equal "unless {[ foo = foo ]} {echo no} {echo yes}"
+                               "yes")
+  (eshell-command-result-equal "unless {[ foo = bar ]} {echo no} {echo yes}"
+                               "no"))
+
+;; esh-cmd-tests.el ends here
diff --git a/test/lisp/eshell/esh-proc-tests.el 
b/test/lisp/eshell/esh-proc-tests.el
index 7f461d1813..62e784e8f6 100644
--- a/test/lisp/eshell/esh-proc-tests.el
+++ b/test/lisp/eshell/esh-proc-tests.el
@@ -28,13 +28,22 @@
                            (file-name-directory (or load-file-name
                                                     default-directory))))
 
+(defvar esh-proc-test--detect-pty-cmd
+  (concat "sh -c '"
+          "if [ -t 0 ]; then echo stdin; fi; "
+          "if [ -t 1 ]; then echo stdout; fi; "
+          "if [ -t 2 ]; then echo stderr; fi"
+          "'"))
+
+;;; Tests:
+
 (ert-deftest esh-proc-test/sigpipe-exits-process ()
   "Test that a SIGPIPE is properly sent to a process if a pipe closes"
   (skip-unless (and (executable-find "sh")
                     (executable-find "echo")
                     (executable-find "sleep")))
   (with-temp-eshell
-   (eshell-command-result-p
+   (eshell-match-command-output
     ;; The first command is like `yes' but slower.  This is to prevent
     ;; it from taxing Emacs's process filter too much and causing a
     ;; hang.
@@ -44,6 +53,45 @@
    (eshell-wait-for-subprocess t)
    (should (eq (process-list) nil))))
 
+(ert-deftest esh-proc-test/pipeline-connection-type/no-pipeline ()
+  "Test that all streams are PTYs when a command is not in a pipeline."
+  (skip-unless (executable-find "sh"))
+  (eshell-command-result-equal
+   esh-proc-test--detect-pty-cmd
+   ;; PTYs aren't supported on MS-Windows.
+   (unless (eq system-type 'windows-nt)
+     "stdin\nstdout\nstderr\n")))
+
+(ert-deftest esh-proc-test/pipeline-connection-type/first ()
+  "Test that only stdin is a PTY when a command starts a pipeline."
+  (skip-unless (and (executable-find "sh")
+                    (executable-find "cat")))
+  (eshell-command-result-equal
+   (concat esh-proc-test--detect-pty-cmd " | cat")
+   (unless (eq system-type 'windows-nt)
+     "stdin\n")))
+
+(ert-deftest esh-proc-test/pipeline-connection-type/middle ()
+  "Test that all streams are pipes when a command is in the middle of a
+pipeline."
+  ;; Repeated unreproducible errors.
+  :tags '(:unstable)
+  (skip-unless (and (executable-find "sh")
+                    (executable-find "cat")))
+  (eshell-command-result-equal
+   (concat "echo | " esh-proc-test--detect-pty-cmd " | cat")
+   nil))
+
+(ert-deftest esh-proc-test/pipeline-connection-type/last ()
+  "Test that only output streams are PTYs when a command ends a pipeline."
+  ;; Repeated unreproducible errors.
+  :tags '(:unstable)
+  (skip-unless (executable-find "sh"))
+  (eshell-command-result-equal
+   (concat "echo | " esh-proc-test--detect-pty-cmd)
+   (unless (eq system-type 'windows-nt)
+     "stdout\nstderr\n")))
+
 (ert-deftest esh-proc-test/kill-pipeline ()
   "Test that killing a pipeline of processes only emits a single
 prompt.  See bug#54136."
@@ -93,4 +141,4 @@ prompt.  See bug#54136."
    (kill-process (caar eshell-process-list))
    ;; Give `eshell-sentinel' a chance to run.
    (sit-for 0.1)
-   (eshell-match-result "\\[sh\\(\\.exe\\)?\\] [[:digit:]]+\n")))
+   (should (eshell-match-output "\\[sh\\(\\.exe\\)?\\] [[:digit:]]+\n"))))
diff --git a/test/lisp/eshell/esh-var-tests.el 
b/test/lisp/eshell/esh-var-tests.el
index 3180fe7a5f..bebc57d359 100644
--- a/test/lisp/eshell/esh-var-tests.el
+++ b/test/lisp/eshell/esh-var-tests.el
@@ -41,311 +41,282 @@
 
 (ert-deftest esh-var-test/interp-var ()
   "Interpolate variable"
-  (should (equal (eshell-test-command-result "echo $user-login-name")
-                 user-login-name)))
+  (eshell-command-result-equal "echo $user-login-name"
+                               user-login-name))
 
 (ert-deftest esh-var-test/interp-quoted-var ()
   "Interpolate quoted variable"
-  (should (equal (eshell-test-command-result "echo $'user-login-name'")
-                 user-login-name))
-  (should (equal (eshell-test-command-result "echo $\"user-login-name\"")
-                 user-login-name)))
+  (eshell-command-result-equal "echo $'user-login-name'"
+                               user-login-name)
+  (eshell-command-result-equal "echo $\"user-login-name\""
+                               user-login-name))
 
 (ert-deftest esh-var-test/interp-quoted-var-concat ()
   "Interpolate and concat quoted variable"
-  (should (equal (eshell-test-command-result "echo $'user-login-name'-foo")
-                 (concat user-login-name "-foo")))
-  (should (equal (eshell-test-command-result "echo $\"user-login-name\"-foo")
-                 (concat user-login-name "-foo"))))
+  (eshell-command-result-equal "echo $'user-login-name'-foo"
+                               (concat user-login-name "-foo"))
+  (eshell-command-result-equal "echo $\"user-login-name\"-foo"
+                               (concat user-login-name "-foo")))
 
 (ert-deftest esh-var-test/interp-var-indices ()
   "Interpolate list variable with indices"
   (let ((eshell-test-value '("zero" "one" "two" "three" "four")))
-    (should (equal (eshell-test-command-result "echo $eshell-test-value[0]")
-                   "zero"))
-    (should (equal (eshell-test-command-result "echo $eshell-test-value[0 2]")
-                   '("zero" "two")))
-    (should (equal (eshell-test-command-result "echo $eshell-test-value[0 2 
4]")
-                   '("zero" "two" "four")))))
+    (eshell-command-result-equal "echo $eshell-test-value[0]"
+                                 "zero")
+    (eshell-command-result-equal "echo $eshell-test-value[0 2]"
+                                 '("zero" "two"))
+    (eshell-command-result-equal "echo $eshell-test-value[0 2 4]"
+                                 '("zero" "two" "four"))))
 
 (ert-deftest esh-var-test/interp-var-split-indices ()
   "Interpolate string variable with indices"
   (let ((eshell-test-value "zero one two three four"))
-    (should (equal (eshell-test-command-result "echo $eshell-test-value[0]")
-                   "zero"))
-    (should (equal (eshell-test-command-result "echo $eshell-test-value[0 2]")
-                   '("zero" "two")))
-    (should (equal (eshell-test-command-result "echo $eshell-test-value[0 2 
4]")
-                   '("zero" "two" "four")))))
+    (eshell-command-result-equal "echo $eshell-test-value[0]"
+                                 "zero")
+    (eshell-command-result-equal "echo $eshell-test-value[0 2]"
+                                 '("zero" "two"))
+    (eshell-command-result-equal "echo $eshell-test-value[0 2 4]"
+                                 '("zero" "two" "four"))))
 
 (ert-deftest esh-var-test/interp-var-string-split-indices ()
   "Interpolate string variable with string splitter and indices"
   (let ((eshell-test-value "zero:one:two:three:four"))
-    (should (equal (eshell-test-command-result "echo $eshell-test-value[: 0]")
-                   "zero"))
-    (should (equal (eshell-test-command-result "echo $eshell-test-value[: 0 
2]")
-                   '("zero" "two"))))
+    (eshell-command-result-equal "echo $eshell-test-value[: 0]"
+                                 "zero")
+    (eshell-command-result-equal "echo $eshell-test-value[: 0 2]"
+                                 '("zero" "two")))
   (let ((eshell-test-value "zeroXoneXtwoXthreeXfour"))
-    (should (equal (eshell-test-command-result "echo $eshell-test-value[X 0]")
-                   "zero"))
-    (should (equal (eshell-test-command-result "echo $eshell-test-value[X 0 
2]")
-                   '("zero" "two")))))
+    (eshell-command-result-equal "echo $eshell-test-value[X 0]"
+                                 "zero")
+    (eshell-command-result-equal "echo $eshell-test-value[X 0 2]"
+                                 '("zero" "two"))))
 
 (ert-deftest esh-var-test/interp-var-regexp-split-indices ()
   "Interpolate string variable with regexp splitter and indices"
   (let ((eshell-test-value "zero:one!two:three!four"))
-    (should (equal (eshell-test-command-result
-                    "echo $eshell-test-value['[:!]' 0]")
-                   "zero"))
-    (should (equal (eshell-test-command-result
-                    "echo $eshell-test-value['[:!]' 0 2]")
-                   '("zero" "two")))
-    (should (equal (eshell-test-command-result
-                    "echo $eshell-test-value[\"[:!]\" 0]")
-                   "zero"))
-    (should (equal (eshell-test-command-result
-                    "echo $eshell-test-value[\"[:!]\" 0 2]")
-                   '("zero" "two")))))
+    (eshell-command-result-equal "echo $eshell-test-value['[:!]' 0]"
+                                 "zero")
+    (eshell-command-result-equal "echo $eshell-test-value['[:!]' 0 2]"
+                                 '("zero" "two"))
+    (eshell-command-result-equal "echo $eshell-test-value[\"[:!]\" 0]"
+                                 "zero")
+    (eshell-command-result-equal "echo $eshell-test-value[\"[:!]\" 0 2]"
+                                 '("zero" "two"))))
 
 (ert-deftest esh-var-test/interp-var-assoc ()
   "Interpolate alist variable with index"
   (let ((eshell-test-value '(("foo" . 1))))
-    (should (eq (eshell-test-command-result "echo $eshell-test-value[foo]")
-                1))))
+    (eshell-command-result-equal "echo $eshell-test-value[foo]"
+                                 1)))
 
 (ert-deftest esh-var-test/interp-var-length-list ()
   "Interpolate length of list variable"
   (let ((eshell-test-value '((1 2) (3) (5 (6 7 8 9)))))
-    (should (eq (eshell-test-command-result "echo $#eshell-test-value") 3))
-    (should (eq (eshell-test-command-result "echo $#eshell-test-value[1]") 1))
-    (should (eq (eshell-test-command-result "echo $#eshell-test-value[2][1]")
-                4))))
+    (eshell-command-result-equal "echo $#eshell-test-value" 3)
+    (eshell-command-result-equal "echo $#eshell-test-value[1]" 1)
+    (eshell-command-result-equal "echo $#eshell-test-value[2][1]" 4)))
 
 (ert-deftest esh-var-test/interp-var-length-string ()
   "Interpolate length of string variable"
   (let ((eshell-test-value "foobar"))
-    (should (eq (eshell-test-command-result "echo $#eshell-test-value") 6))))
+    (eshell-command-result-equal "echo $#eshell-test-value" 6)))
 
 (ert-deftest esh-var-test/interp-var-length-alist ()
   "Interpolate length of alist variable"
   (let ((eshell-test-value '(("foo" . (1 2 3)))))
-    (should (eq (eshell-test-command-result "echo $#eshell-test-value") 1))
-    (should (eq (eshell-test-command-result "echo $#eshell-test-value[foo]")
-                3))))
+    (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-lisp ()
   "Interpolate Lisp form evaluation"
-  (should (equal (eshell-test-command-result "+ $(+ 1 2) 3") 6)))
+  (eshell-command-result-equal "+ $(+ 1 2) 3" 6))
 
 (ert-deftest esh-var-test/interp-lisp-indices ()
   "Interpolate Lisp form evaluation with index"
-  (should (equal (eshell-test-command-result "+ $(list 1 2)[1] 3") 5)))
+  (eshell-command-result-equal "+ $(list 1 2)[1] 3" 5))
 
 (ert-deftest esh-var-test/interp-cmd ()
   "Interpolate command result"
-  (should (equal (eshell-test-command-result "+ ${+ 1 2} 3") 6)))
+  (eshell-command-result-equal "+ ${+ 1 2} 3" 6))
 
 (ert-deftest esh-var-test/interp-cmd-indices ()
   "Interpolate command result with index"
-  (should (equal (eshell-test-command-result "+ ${listify 1 2}[1] 3") 5)))
+  (eshell-command-result-equal "+ ${listify 1 2}[1] 3" 5))
 
 (ert-deftest esh-var-test/interp-cmd-external ()
   "Interpolate command result from external command"
   (skip-unless (executable-find "echo"))
   (with-temp-eshell
-   (eshell-command-result-p "echo ${*echo hi}"
-                            "hi\n")))
+   (eshell-match-command-output "echo ${*echo hi}"
+                                "hi\n")))
 
 (ert-deftest esh-var-test/interp-cmd-external-indices ()
   "Interpolate command result from external command with index"
   (skip-unless (executable-find "echo"))
   (with-temp-eshell
-   (eshell-command-result-p "echo ${*echo \"hi\nbye\"}[1]"
-                            "bye\n")))
+   (eshell-match-command-output "echo ${*echo \"hi\nbye\"}[1]"
+                                "bye\n")))
 
 (ert-deftest esh-var-test/interp-temp-cmd ()
   "Interpolate command result redirected to temp file"
-  (should (equal (eshell-test-command-result "cat $<echo hi>") "hi")))
+  (eshell-command-result-equal "cat $<echo hi>" "hi"))
 
 (ert-deftest esh-var-test/interp-concat-lisp ()
   "Interpolate and concat Lisp form"
-  (should (equal (eshell-test-command-result "+ $(+ 1 2)3 3") 36)))
+  (eshell-command-result-equal "+ $(+ 1 2)3 3" 36))
 
 (ert-deftest esh-var-test/interp-concat-lisp2 ()
   "Interpolate and concat two Lisp forms"
-  (should (equal (eshell-test-command-result "+ $(+ 1 2)$(+ 1 2) 3") 36)))
+  (eshell-command-result-equal "+ $(+ 1 2)$(+ 1 2) 3" 36))
 
 (ert-deftest esh-var-test/interp-concat-cmd ()
   "Interpolate and concat command with literal"
-  (should (equal (eshell-test-command-result "+ ${+ 1 2}3 3") 36))
-  (should (equal (eshell-test-command-result "echo ${*echo \"foo\nbar\"}-baz")
-                 '("foo" "bar-baz")))
+  (eshell-command-result-equal "+ ${+ 1 2}3 3" 36)
+  (eshell-command-result-equal "echo ${*echo \"foo\nbar\"}-baz"
+                               '("foo" "bar-baz"))
   ;; Concatenating to a number in a list should produce a number...
-  (should (equal (eshell-test-command-result "echo ${*echo \"1\n2\"}3")
-                 '(1 23)))
+  (eshell-command-result-equal "echo ${*echo \"1\n2\"}3"
+                               '(1 23))
   ;; ... but concatenating to a string that looks like a number in a list
   ;; should produce a string.
-  (should (equal (eshell-test-command-result "echo ${*echo \"hi\n2\"}3")
-                 '("hi" "23"))))
+  (eshell-command-result-equal "echo ${*echo \"hi\n2\"}3"
+                               '("hi" "23")))
 
 (ert-deftest esh-var-test/interp-concat-cmd2 ()
   "Interpolate and concat two commands"
-  (should (equal (eshell-test-command-result "+ ${+ 1 2}${+ 1 2} 3") 36)))
+  (eshell-command-result-equal "+ ${+ 1 2}${+ 1 2} 3" 36))
 
 (ert-deftest esh-var-test/interp-concat-cmd-external ()
   "Interpolate command result from external command with concatenation"
   (skip-unless (executable-find "echo"))
   (with-temp-eshell
-   (eshell-command-result-p "echo ${echo hi}-${*echo there}"
-                            "hi-there\n")))
+   (eshell-match-command-output "echo ${echo hi}-${*echo there}"
+                                "hi-there\n")))
 
 (ert-deftest esh-var-test/quoted-interp-var ()
   "Interpolate variable inside double-quotes"
-  (should (equal (eshell-test-command-result "echo \"$user-login-name\"")
-                 user-login-name)))
+  (eshell-command-result-equal "echo \"$user-login-name\""
+                               user-login-name))
 
 (ert-deftest esh-var-test/quoted-interp-quoted-var ()
   "Interpolate quoted variable inside double-quotes"
-  (should (equal (eshell-test-command-result
-                  "echo \"hi, $'user-login-name'\"")
-                 (concat "hi, " user-login-name)))
-  (should (equal (eshell-test-command-result
-                  "echo \"hi, $\\\"user-login-name\\\"\"")
-                 (concat "hi, " user-login-name))))
+  (eshell-command-result-equal "echo \"hi, $'user-login-name'\""
+                               (concat "hi, " user-login-name))
+  (eshell-command-result-equal "echo \"hi, $\\\"user-login-name\\\"\""
+                               (concat "hi, " user-login-name)))
 
 (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")))
-    (should (equal (eshell-test-command-result
-                    "echo \"$eshell-test-value[0]\"")
-                   "zero"))
+    (eshell-command-result-equal "echo \"$eshell-test-value[0]\""
+                                 "zero")
     ;; FIXME: These tests would use the 0th index like the other tests
     ;; here, but evaluating the command just above adds an `escaped'
     ;; property to the string "zero".  This results in the output
     ;; printing the string properties, which is probably the wrong
     ;; behavior.  See bug#54486.
-    (should (equal (eshell-test-command-result
-                    "echo \"$eshell-test-value[1 2]\"")
-                   "(\"one\" \"two\")"))
-    (should (equal (eshell-test-command-result
-                    "echo \"$eshell-test-value[1 2 4]\"")
-                   "(\"one\" \"two\" \"four\")"))))
+    (eshell-command-result-equal "echo \"$eshell-test-value[1 2]\""
+                                 "(\"one\" \"two\")")
+    (eshell-command-result-equal "echo \"$eshell-test-value[1 2 4]\""
+                                 "(\"one\" \"two\" \"four\")")))
 
 (ert-deftest esh-var-test/quoted-interp-var-split-indices ()
   "Interpolate string variable with indices inside double-quotes"
   (let ((eshell-test-value "zero one two three four"))
-    (should (equal (eshell-test-command-result
-                    "echo \"$eshell-test-value[0]\"")
-                   "zero"))
-    (should (equal (eshell-test-command-result
-                    "echo \"$eshell-test-value[0 2]\"")
-                   "(\"zero\" \"two\")"))))
+    (eshell-command-result-equal "echo \"$eshell-test-value[0]\""
+                                 "zero")
+    (eshell-command-result-equal "echo \"$eshell-test-value[0 2]\""
+                                 "(\"zero\" \"two\")")))
 
 (ert-deftest esh-var-test/quoted-interp-var-string-split-indices ()
   "Interpolate string variable with string splitter and indices
 inside double-quotes"
   (let ((eshell-test-value "zero:one:two:three:four"))
-    (should (equal (eshell-test-command-result
-                    "echo \"$eshell-test-value[: 0]\"")
-                   "zero"))
-    (should (equal (eshell-test-command-result
-                    "echo \"$eshell-test-value[: 0 2]\"")
-                   "(\"zero\" \"two\")")))
+    (eshell-command-result-equal "echo \"$eshell-test-value[: 0]\""
+                                 "zero")
+    (eshell-command-result-equal "echo \"$eshell-test-value[: 0 2]\""
+                                 "(\"zero\" \"two\")"))
   (let ((eshell-test-value "zeroXoneXtwoXthreeXfour"))
-    (should (equal (eshell-test-command-result
-                    "echo \"$eshell-test-value[X 0]\"")
-                   "zero"))
-    (should (equal (eshell-test-command-result
-                    "echo \"$eshell-test-value[X 0 2]\"")
-                   "(\"zero\" \"two\")"))))
+    (eshell-command-result-equal "echo \"$eshell-test-value[X 0]\""
+                                 "zero")
+    (eshell-command-result-equal "echo \"$eshell-test-value[X 0 2]\""
+                                 "(\"zero\" \"two\")")))
 
 (ert-deftest esh-var-test/quoted-interp-var-regexp-split-indices ()
   "Interpolate string variable with regexp splitter and indices"
   (let ((eshell-test-value "zero:one!two:three!four"))
-    (should (equal (eshell-test-command-result
-                    "echo \"$eshell-test-value['[:!]' 0]\"")
-                   "zero"))
-    (should (equal (eshell-test-command-result
-                    "echo \"$eshell-test-value['[:!]' 0 2]\"")
-                   "(\"zero\" \"two\")"))
-    (should (equal (eshell-test-command-result
-                    "echo \"$eshell-test-value[\\\"[:!]\\\" 0]\"")
-                   "zero"))
-    (should (equal (eshell-test-command-result
-                    "echo \"$eshell-test-value[\\\"[:!]\\\" 0 2]\"")
-                   "(\"zero\" \"two\")"))))
+    (eshell-command-result-equal "echo \"$eshell-test-value['[:!]' 0]\""
+                                 "zero")
+    (eshell-command-result-equal "echo \"$eshell-test-value['[:!]' 0 2]\""
+                                 "(\"zero\" \"two\")")
+    (eshell-command-result-equal "echo \"$eshell-test-value[\\\"[:!]\\\" 0]\""
+                                 "zero")
+    (eshell-command-result-equal
+     "echo \"$eshell-test-value[\\\"[:!]\\\" 0 2]\""
+     "(\"zero\" \"two\")")))
 
 (ert-deftest esh-var-test/quoted-interp-var-assoc ()
   "Interpolate alist variable with index inside double-quotes"
   (let ((eshell-test-value '(("foo" . 1))))
-    (should (equal (eshell-test-command-result
-                    "echo \"$eshell-test-value[foo]\"")
-                   "1"))))
+    (eshell-command-result-equal "echo \"$eshell-test-value[foo]\""
+                                 "1")))
 
 (ert-deftest esh-var-test/quoted-interp-var-length-list ()
   "Interpolate length of list variable inside double-quotes"
   (let ((eshell-test-value '((1 2) (3) (5 (6 7 8 9)))))
-    (should (equal (eshell-test-command-result "echo \"$#eshell-test-value\"")
-                   "3"))
-    (should (equal (eshell-test-command-result
-                    "echo \"$#eshell-test-value[1]\"")
-                   "1"))
-    (should (equal (eshell-test-command-result
-                    "echo \"$#eshell-test-value[2][1]\"")
-                   "4"))))
+    (eshell-command-result-equal "echo \"$#eshell-test-value\""
+                                 "3")
+    (eshell-command-result-equal "echo \"$#eshell-test-value[1]\""
+                                 "1")
+    (eshell-command-result-equal "echo \"$#eshell-test-value[2][1]\""
+                                 "4")))
 
 (ert-deftest esh-var-test/quoted-interp-var-length-string ()
   "Interpolate length of string variable inside double-quotes"
   (let ((eshell-test-value "foobar"))
-    (should (equal (eshell-test-command-result "echo \"$#eshell-test-value\"")
-                   "6"))))
+    (eshell-command-result-equal "echo \"$#eshell-test-value\""
+                                 "6")))
 
 (ert-deftest esh-var-test/quoted-interp-var-length-alist ()
   "Interpolate length of alist variable inside double-quotes"
   (let ((eshell-test-value '(("foo" . (1 2 3)))))
-    (should (equal (eshell-test-command-result "echo \"$#eshell-test-value\"")
-                   "1"))
-    (should (equal (eshell-test-command-result
-                    "echo \"$#eshell-test-value[foo]\"")
-                   "3"))))
+    (eshell-command-result-equal "echo \"$#eshell-test-value\""
+                                 "1")
+    (eshell-command-result-equal "echo \"$#eshell-test-value[foo]\""
+                                 "3"))
 
 (ert-deftest esh-var-test/quoted-interp-lisp ()
   "Interpolate Lisp form evaluation inside double-quotes"
-  (should (equal (eshell-test-command-result
-                  "echo \"hi $(concat \\\"the\\\" \\\"re\\\")\"")
-                 "hi there")))
+  (eshell-command-result-equal "echo \"hi $(concat \\\"the\\\" \\\"re\\\")\""
+                               "hi there"))
 
 (ert-deftest esh-var-test/quoted-interp-lisp-indices ()
   "Interpolate Lisp form evaluation with index"
-  (should (equal (eshell-test-command-result "concat \"$(list 1 2)[1]\" cool")
-                 "2cool")))
+  (eshell-command-result-equal "concat \"$(list 1 2)[1]\" cool"
+                               "2cool"))
 
 (ert-deftest esh-var-test/quoted-interp-cmd ()
   "Interpolate command result inside double-quotes"
-  (should (equal (eshell-test-command-result
-                  "echo \"hi ${echo \\\"there\\\"}\"")
-                 "hi there")))
+  (eshell-command-result-equal "echo \"hi ${echo \\\"there\\\"}\""
+                               "hi there"))
 
 (ert-deftest esh-var-test/quoted-interp-cmd-indices ()
   "Interpolate command result with index inside double-quotes"
-  (should (equal (eshell-test-command-result
-                  "concat \"${listify 1 2}[1]\" cool")
-                 "2cool")))
+  (eshell-command-result-equal "concat \"${listify 1 2}[1]\" cool"
+                               "2cool"))
 
 (ert-deftest esh-var-test/quoted-interp-temp-cmd ()
   "Interpolate command result redirected to temp file inside double-quotes"
   (let ((temporary-file-directory
          (file-name-as-directory (make-temp-file "esh-vars-tests" t))))
     (unwind-protect
-        (should (equal (eshell-test-command-result "cat \"$<echo hi>\"")
-                       "hi"))
+        (eshell-command-result-equal "cat \"$<echo hi>\"" "hi"))
       (delete-directory temporary-file-directory t))))
 
 (ert-deftest esh-var-test/quoted-interp-concat-cmd ()
   "Interpolate and concat command with literal"
-  (should (equal (eshell-test-command-result
-                  "echo \"${echo \\\"foo\nbar\\\"} baz\"")
-                 "foo\nbar baz")))
+  (eshell-command-result-equal "echo \"${echo \\\"foo\nbar\\\"} baz\""
+                               "foo\nbar baz"))
 
 
 ;; Interpolated variable conversion
@@ -353,156 +324,242 @@ inside double-quotes"
 (ert-deftest esh-var-test/interp-convert-var-number ()
   "Interpolate numeric variable"
   (let ((eshell-test-value 123))
-    (should (equal (eshell-test-command-result "type-of $eshell-test-value")
-                   'integer))))
+    (eshell-command-result-equal "type-of $eshell-test-value"
+                                 'integer)))
 
 (ert-deftest esh-var-test/interp-convert-var-split-indices ()
   "Interpolate and convert string variable with indices"
   ;; Check that numeric forms are converted to numbers.
   (let ((eshell-test-value "000 010 020 030 040"))
-    (should (equal (eshell-test-command-result "echo $eshell-test-value[0]")
-                   0))
-    (should (equal (eshell-test-command-result "echo $eshell-test-value[0 2]")
-                   '(0 20))))
+    (eshell-command-result-equal "echo $eshell-test-value[0]"
+                                 0)
+    (eshell-command-result-equal "echo $eshell-test-value[0 2]"
+                                 '(0 20)))
   ;; Check that multiline forms are preserved as-is.
   (let ((eshell-test-value "foo\nbar:baz\n"))
-    (should (equal (eshell-test-command-result "echo $eshell-test-value[: 0]")
-                   "foo\nbar"))
-    (should (equal (eshell-test-command-result "echo $eshell-test-value[: 1]")
-                   "baz\n"))))
+    (eshell-command-result-equal "echo $eshell-test-value[: 0]"
+                                 "foo\nbar")
+    (eshell-command-result-equal "echo $eshell-test-value[: 1]"
+                                 "baz\n")))
 
 (ert-deftest esh-var-test/interp-convert-quoted-var-number ()
   "Interpolate numeric quoted numeric variable"
   (let ((eshell-test-value 123))
-    (should (equal (eshell-test-command-result "type-of $'eshell-test-value'")
-                   'integer))
-    (should (equal (eshell-test-command-result "type-of 
$\"eshell-test-value\"")
-                   'integer))))
+    (eshell-command-result-equal "type-of $'eshell-test-value'"
+                                 'integer)
+    (eshell-command-result-equal "type-of $\"eshell-test-value\""
+                                 'integer)))
 
 (ert-deftest esh-var-test/interp-convert-quoted-var-split-indices ()
   "Interpolate and convert quoted string variable with indices"
   (let ((eshell-test-value "000 010 020 030 040"))
-    (should (equal (eshell-test-command-result "echo $'eshell-test-value'[0]")
-                   0))
-    (should (equal (eshell-test-command-result "echo $'eshell-test-value'[0 
2]")
-                   '(0 20)))))
+    (eshell-command-result-equal "echo $'eshell-test-value'[0]"
+                                 0)
+    (eshell-command-result-equal "echo $'eshell-test-value'[0 2]"
+                                 '(0 20))))
 
 (ert-deftest esh-var-test/interp-convert-cmd-string-newline ()
   "Interpolate trailing-newline command result"
-  (should (equal (eshell-test-command-result "echo ${echo \"foo\n\"}") "foo")))
+  (eshell-command-result-equal "echo ${echo \"foo\n\"}" "foo"))
 
 (ert-deftest esh-var-test/interp-convert-cmd-multiline ()
   "Interpolate multi-line command result"
-  (should (equal (eshell-test-command-result "echo ${echo \"foo\nbar\"}")
-                 '("foo" "bar")))
+  (eshell-command-result-equal "echo ${echo \"foo\nbar\"}"
+                               '("foo" "bar"))
   ;; Numeric output should be converted to numbers...
-  (should (equal (eshell-test-command-result "echo ${echo \"01\n02\n03\"}")
-                 '(1 2 3)))
+  (eshell-command-result-equal "echo ${echo \"01\n02\n03\"}"
+                               '(1 2 3))
   ;; ... but only if every line is numeric.
-  (should (equal (eshell-test-command-result "echo ${echo \"01\n02\nhi\"}")
-                 '("01" "02" "hi"))))
+  (eshell-command-result-equal "echo ${echo \"01\n02\nhi\"}"
+                               '("01" "02" "hi")))
 
 (ert-deftest esh-var-test/interp-convert-cmd-number ()
   "Interpolate numeric command result"
-  (should (equal (eshell-test-command-result "echo ${echo \"1\"}") 1)))
+  (eshell-command-result-equal "echo ${echo \"1\"}" 1))
 
 (ert-deftest esh-var-test/interp-convert-cmd-split-indices ()
   "Interpolate command result with indices"
-  (should (equal (eshell-test-command-result "echo ${echo \"000 010 020\"}[0]")
-                 0))
-  (should (equal (eshell-test-command-result
-                  "echo ${echo \"000 010 020\"}[0 2]")
-                 '(0 20))))
+  (eshell-command-result-equal "echo ${echo \"000 010 020\"}[0]"
+                               0)
+  (eshell-command-result-equal "echo ${echo \"000 010 020\"}[0 2]"
+                               '(0 20)))
 
 (ert-deftest esh-var-test/quoted-interp-convert-var-number ()
   "Interpolate numeric variable inside double-quotes"
   (let ((eshell-test-value 123))
-    (should (equal (eshell-test-command-result "type-of 
\"$eshell-test-value\"")
-                   'string))))
+    (eshell-command-result-equal "type-of \"$eshell-test-value\""
+                                 'string)))
 
 (ert-deftest esh-var-test/quoted-interp-convert-var-split-indices ()
   "Interpolate string variable with indices inside double-quotes"
   (let ((eshell-test-value "000 010 020 030 040"))
-    (should (equal (eshell-test-command-result
-                    "echo \"$eshell-test-value[0]\"")
-                   "000"))
-    (should (equal (eshell-test-command-result
-                    "echo \"$eshell-test-value[0 2]\"")
-                   "(\"000\" \"020\")"))))
+    (eshell-command-result-equal "echo \"$eshell-test-value[0]\""
+                                 "000")
+    (eshell-command-result-equal "echo \"$eshell-test-value[0 2]\""
+                                 "(\"000\" \"020\")")))
 
 (ert-deftest esh-var-test/quoted-interp-convert-quoted-var-number ()
   "Interpolate numeric quoted variable inside double-quotes"
   (let ((eshell-test-value 123))
-    (should (equal (eshell-test-command-result
-                    "type-of \"$'eshell-test-value'\"")
-                   'string))
-    (should (equal (eshell-test-command-result
-                    "type-of \"$\\\"eshell-test-value\\\"\"")
-                   'string))))
+    (eshell-command-result-equal "type-of \"$'eshell-test-value'\""
+                                 'string)
+    (eshell-command-result-equal "type-of \"$\\\"eshell-test-value\\\"\""
+                                 'string)))
 
 (ert-deftest esh-var-test/quoted-interp-convert-quoted-var-split-indices ()
   "Interpolate quoted string variable with indices inside double-quotes"
   (let ((eshell-test-value "000 010 020 030 040"))
-    (should (equal (eshell-test-command-result
-                    "echo \"$eshell-test-value[0]\"")
-                   "000"))
-    (should (equal (eshell-test-command-result
-                    "echo \"$eshell-test-value[0 2]\"")
-                   "(\"000\" \"020\")"))))
+    (eshell-command-result-equal "echo \"$eshell-test-value[0]\""
+                                 "000")
+    (eshell-command-result-equal "echo \"$eshell-test-value[0 2]\""
+                                 "(\"000\" \"020\")")))
 
 (ert-deftest esh-var-test/quoted-interp-convert-cmd-string-newline ()
   "Interpolate trailing-newline command result inside double-quotes"
-  (should (equal (eshell-test-command-result "echo \"${echo \\\"foo\n\\\"}\"")
-                 "foo"))
-  (should (equal (eshell-test-command-result "echo \"${echo 
\\\"foo\n\n\\\"}\"")
-                 "foo")))
+  (eshell-command-result-equal "echo \"${echo \\\"foo\n\\\"}\""
+                               "foo")
+  (eshell-command-result-equal "echo \"${echo \\\"foo\n\n\\\"}\""
+                               "foo"))
 
 (ert-deftest esh-var-test/quoted-interp-convert-cmd-multiline ()
   "Interpolate multi-line command result inside double-quotes"
-  (should (equal (eshell-test-command-result
-                  "echo \"${echo \\\"foo\nbar\\\"}\"")
-                 "foo\nbar")))
+  (eshell-command-result-equal "echo \"${echo \\\"foo\nbar\\\"}\""
+                               "foo\nbar"))
 
 (ert-deftest esh-var-test/quoted-interp-convert-cmd-number ()
   "Interpolate numeric command result inside double-quotes"
-  (should (equal (eshell-test-command-result "echo \"${echo \\\"1\\\"}\"")
-                 "1")))
+  (eshell-command-result-equal "echo \"${echo \\\"1\\\"}\"" "1"))
 
 (ert-deftest esh-var-test/quoted-interp-convert-cmd-split-indices ()
   "Interpolate command result with indices inside double-quotes"
-  (should (equal (eshell-test-command-result
-                  "echo \"${echo \\\"000 010 020\\\"}[0]\"")
-                 "000")))
+  (eshell-command-result-equal "echo \"${echo \\\"000 010 020\\\"}[0]\""
+                               "000"))
 
 
 ;; Built-in variables
 
 (ert-deftest esh-var-test/lines-var ()
   "$LINES should equal (window-body-height nil 'remap)"
-  (should (equal (eshell-test-command-result "echo $LINES")
-                 (window-body-height nil 'remap))))
+  (eshell-command-result-equal "echo $LINES"
+                               (window-body-height nil 'remap)))
 
 (ert-deftest esh-var-test/columns-var ()
   "$COLUMNS should equal (window-body-width nil 'remap)"
-  (should (equal (eshell-test-command-result "echo $COLUMNS")
-                 (window-body-width nil 'remap))))
+  (eshell-command-result-equal "echo $COLUMNS"
+                               (window-body-width nil 'remap)))
+
+(ert-deftest esh-var-test/inside-emacs-var ()
+  "Test presence of \"INSIDE_EMACS\" in subprocesses"
+  (with-temp-eshell
+   (eshell-match-command-output "env"
+                                (format "INSIDE_EMACS=%s,eshell"
+                                        emacs-version))))
+
+(ert-deftest esh-var-test/inside-emacs-var-split-indices ()
+  "Test using \"INSIDE_EMACS\" with split indices"
+  (with-temp-eshell
+   (eshell-match-command-output "echo $INSIDE_EMACS[, 1]"
+                                "eshell")))
+
+(ert-deftest esh-var-test/last-status-var-lisp-command ()
+  "Test using the \"last exit status\" ($?) variable with a Lisp command"
+  (with-temp-eshell
+   (eshell-match-command-output "zerop 0; echo $?"
+                                "t\n0\n")
+   (eshell-match-command-output "zerop 1; echo $?"
+                                "0\n")
+   (let ((debug-on-error nil))
+     (eshell-match-command-output "zerop foo; echo $?"
+                                  "1\n"))))
+
+(ert-deftest esh-var-test/last-status-var-lisp-form ()
+  "Test using the \"last exit status\" ($?) variable with a Lisp form"
+  (let ((eshell-lisp-form-nil-is-failure t))
+    (with-temp-eshell
+     (eshell-match-command-output "(zerop 0); echo $?"
+                                  "t\n0\n")
+     (eshell-match-command-output "(zerop 1); echo $?"
+                                  "2\n")
+     (let ((debug-on-error nil))
+       (eshell-match-command-output "(zerop \"foo\"); echo $?"
+                                    "1\n")))))
+
+(ert-deftest esh-var-test/last-status-var-lisp-form-2 ()
+  "Test using the \"last exit status\" ($?) variable with a Lisp form.
+This tests when `eshell-lisp-form-nil-is-failure' is nil."
+  (let ((eshell-lisp-form-nil-is-failure nil))
+    (with-temp-eshell
+     (eshell-match-command-output "(zerop 0); echo $?"
+                                  "0\n")
+     (eshell-match-command-output "(zerop 0); echo $?"
+                                  "0\n")
+     (let ((debug-on-error nil))
+       (eshell-match-command-output "(zerop \"foo\"); echo $?"
+                                    "1\n")))))
+
+(ert-deftest esh-var-test/last-status-var-ext-cmd ()
+  "Test using the \"last exit status\" ($?) variable with an external command"
+  (skip-unless (executable-find "["))
+  (with-temp-eshell
+   (eshell-match-command-output "[ foo = foo ]; echo $?"
+                                "0\n")
+   (eshell-match-command-output "[ foo = bar ]; echo $?"
+                                "1\n")))
 
 (ert-deftest esh-var-test/last-result-var ()
   "Test using the \"last result\" ($$) variable"
   (with-temp-eshell
-   (eshell-command-result-p "+ 1 2; + $$ 2"
-                            "3\n5\n")))
+   (eshell-match-command-output "+ 1 2; + $$ 2"
+                                "3\n5\n")))
 
-(ert-deftest esh-var-test/last-result-var2 ()
+(ert-deftest esh-var-test/last-result-var-twice ()
   "Test using the \"last result\" ($$) variable twice"
   (with-temp-eshell
-   (eshell-command-result-p "+ 1 2; + $$ $$"
-                             "3\n6\n")))
+   (eshell-match-command-output "+ 1 2; + $$ $$"
+                                "3\n6\n")))
+
+(ert-deftest esh-var-test/last-result-var-ext-cmd ()
+  "Test using the \"last result\" ($$) variable with an external command"
+  (skip-unless (executable-find "["))
+  (with-temp-eshell
+   ;; MS-DOS/MS-Windows have an external command 'format', which we
+   ;; don't want here.
+   (let ((eshell-prefer-lisp-functions t))
+     (eshell-match-command-output "[ foo = foo ]; format \"%s\" $$"
+                                  "t\n")
+     (eshell-match-command-output "[ foo = bar ]; format \"%s\" $$"
+                                  "nil\n"))))
+
+(ert-deftest esh-var-test/last-result-var-split-indices ()
+  "Test using the \"last result\" ($$) variable with split indices"
+  (with-temp-eshell
+   (eshell-match-command-output
+    "string-join (list \"01\" \"02\") :; + $$[: 1] 3"
+    "01:02\n5\n")
+   (eshell-match-command-output
+    "string-join (list \"01\" \"02\") :; echo \"$$[: 1]\""
+    "01:02\n02\n")))
 
 (ert-deftest esh-var-test/last-arg-var ()
   "Test using the \"last arg\" ($_) variable"
   (with-temp-eshell
-   (eshell-command-result-p "+ 1 2; + $_ 4"
-                             "3\n6\n")))
+   (eshell-match-command-output "+ 1 2; + $_ 4"
+                                "3\n6\n")))
+
+(ert-deftest esh-var-test/last-arg-var-indices ()
+  "Test using the \"last arg\" ($_) variable with indices"
+  (with-temp-eshell
+   (eshell-match-command-output "+ 1 2; + $_[0] 4"
+                                "3\n5\n")
+   (eshell-match-command-output "+ 1 2; + $_[1] 4"
+                                "3\n6\n")))
+
+(ert-deftest esh-var-test/last-arg-var-split-indices ()
+  "Test using the \"last arg\" ($_) variable with split indices"
+  (with-temp-eshell
+   (eshell-match-command-output "concat 01:02 03:04; + $_[0][: 1] 5"
+                                "01:0203:04\n7\n")
+   (eshell-match-command-output "concat 01:02 03:04; echo \"$_[0][: 1]\""
+                                "01:0203:04\n02\n")))
 
 ;; esh-var-tests.el ends here
diff --git a/test/lisp/eshell/eshell-tests-helpers.el 
b/test/lisp/eshell/eshell-tests-helpers.el
index 4ad76ca697..8f0f993447 100644
--- a/test/lisp/eshell/eshell-tests-helpers.el
+++ b/test/lisp/eshell/eshell-tests-helpers.el
@@ -65,24 +65,36 @@ raise an error."
         (error "timed out waiting for subprocess(es)"))
       (sit-for 0.1))))
 
-(defun eshell-insert-command (text &optional func)
-  "Insert a command at the end of the buffer."
+(defun eshell-insert-command (command &optional func)
+  "Insert a COMMAND at the end of the buffer.
+After inserting, call FUNC.  If FUNC is nil, instead call
+`eshell-send-input'."
   (goto-char eshell-last-output-end)
-  (insert-and-inherit text)
+  (insert-and-inherit command)
   (funcall (or func 'eshell-send-input)))
 
-(defun eshell-match-result (regexp)
-  "Check that output of last command matches REGEXP."
-  (should
-   (string-match-p
+(defun eshell-match-output (regexp)
+  "Test whether the output of the last command matches REGEXP."
+  (string-match-p
     regexp (buffer-substring-no-properties
-            (eshell-beginning-of-output) (eshell-end-of-output)))))
-
-(defun eshell-command-result-p (text regexp &optional func)
-  "Insert a command at the end of the buffer."
-  (eshell-insert-command text func)
+            (eshell-beginning-of-output) (eshell-end-of-output))))
+
+(defun eshell-match-output--explainer (regexp)
+  "Explain the result of `eshell-match-output'."
+  `(mismatched-output
+    (command ,(buffer-substring-no-properties
+               eshell-last-input-start eshell-last-input-end))
+    (output ,(buffer-substring-no-properties
+              (eshell-beginning-of-output) (eshell-end-of-output)))
+    (regexp ,regexp)))
+
+(put 'eshell-match-output 'ert-explainer #'eshell-match-output--explainer)
+
+(defun eshell-match-command-output (command regexp &optional func)
+  "Insert a COMMAND at the end of the buffer and match the output with REGEXP."
+  (eshell-insert-command command func)
   (eshell-wait-for-subprocess)
-  (eshell-match-result regexp))
+  (should (eshell-match-output regexp)))
 
 (defvar eshell-history-file-name)
 
@@ -92,6 +104,27 @@ raise an error."
     (let ((eshell-history-file-name nil))
       (eshell-command-result command))))
 
+(defun eshell-command-result--equal (_command actual expected)
+  "Compare the ACTUAL result of a COMMAND with its EXPECTED value."
+  (equal actual expected))
+
+(defun eshell-command-result--equal-explainer (command actual expected)
+  "Explain the result of `eshell-command-result--equal'."
+  `(nonequal-result
+    (command ,command)
+    (result ,actual)
+    (expected ,expected)))
+
+(put 'eshell-command-result--equal 'ert-explainer
+     #'eshell-command-result--equal-explainer)
+
+(defun eshell-command-result-equal (command result)
+  "Execute COMMAND non-interactively and compare it to RESULT."
+  (should (eshell-command-result--equal
+           command
+           (eshell-test-command-result command)
+           result)))
+
 (provide 'eshell-tests-helpers)
 
 ;;; eshell-tests-helpers.el ends here
diff --git a/test/lisp/eshell/eshell-tests.el b/test/lisp/eshell/eshell-tests.el
index ab5d73d479..1845dba280 100644
--- a/test/lisp/eshell/eshell-tests.el
+++ b/test/lisp/eshell/eshell-tests.el
@@ -36,72 +36,19 @@
 
 ;;; Tests:
 
-(ert-deftest eshell-test/simple-command-result ()
-  "Test `eshell-command-result' with a simple command."
-  (should (equal (eshell-test-command-result "+ 1 2") 3)))
-
-(ert-deftest eshell-test/lisp-command ()
-  "Test `eshell-command-result' with an elisp command."
-  (should (equal (eshell-test-command-result "(+ 1 2)") 3)))
-
-(ert-deftest eshell-test/lisp-command-with-quote ()
-  "Test `eshell-command-result' with an elisp command containing a quote."
-  (should (equal (eshell-test-command-result "(eq 'foo nil)") nil)))
-
-(ert-deftest eshell-test/for-loop ()
-  "Test `eshell-command-result' with a for loop.."
-  (let ((process-environment (cons "foo" process-environment)))
-    (should (equal (eshell-test-command-result
-                    "for foo in 5 { echo $foo }") 5))))
-
-(ert-deftest eshell-test/for-name-loop () ;Bug#15231
-  "Test `eshell-command-result' with a for loop using `name'."
-  (let ((process-environment (cons "name" process-environment)))
-    (should (equal (eshell-test-command-result
-                    "for name in 3 { echo $name }") 3))))
-
-(ert-deftest eshell-test/for-name-shadow-loop () ; bug#15372
-  "Test `eshell-command-result' with a for loop using an env-var."
-  (let ((process-environment (cons "name=env-value" process-environment)))
-    (with-temp-eshell
-     (eshell-command-result-p "echo $name; for name in 3 { echo $name }; echo 
$name"
-                              "env-value\n3\nenv-value\n"))))
-
-(ert-deftest eshell-test/lisp-command-args ()
-  "Test `eshell-command-result' with elisp and trailing args.
-Test that trailing arguments outside the S-expression are
-ignored.  e.g. \"(+ 1 2) 3\" => 3"
-  (should (equal (eshell-test-command-result "(+ 1 2) 3") 3)))
-
-(ert-deftest eshell-test/subcommand ()
-  "Test `eshell-command-result' with a simple subcommand."
-  (should (equal (eshell-test-command-result "{+ 1 2}") 3)))
-
-(ert-deftest eshell-test/subcommand-args ()
-  "Test `eshell-command-result' with a subcommand and trailing args.
-Test that trailing arguments outside the subcommand are ignored.
-e.g. \"{+ 1 2} 3\" => 3"
-  (should (equal (eshell-test-command-result "{+ 1 2} 3") 3)))
-
-(ert-deftest eshell-test/subcommand-lisp ()
-  "Test `eshell-command-result' with an elisp subcommand and trailing args.
-Test that trailing arguments outside the subcommand are ignored.
-e.g. \"{(+ 1 2)} 3\" => 3"
-  (should (equal (eshell-test-command-result "{(+ 1 2)} 3") 3)))
-
 (ert-deftest eshell-test/pipe-headproc ()
   "Check that piping a non-process to a process command waits for the process"
   (skip-unless (executable-find "cat"))
   (with-temp-eshell
-   (eshell-command-result-p "echo hi | *cat"
-                            "hi")))
+   (eshell-match-command-output "echo hi | *cat"
+                                "hi")))
 
 (ert-deftest eshell-test/pipe-tailproc ()
   "Check that piping a process to a non-process command waits for the process"
   (skip-unless (executable-find "echo"))
   (with-temp-eshell
-   (eshell-command-result-p "*echo hi | echo bye"
-                            "bye\nhi\n")))
+   (eshell-match-command-output "*echo hi | echo bye"
+                                "bye\nhi\n")))
 
 (ert-deftest eshell-test/pipe-headproc-stdin ()
   "Check that standard input is sent to the head process in a pipeline"
@@ -112,23 +59,23 @@ e.g. \"{(+ 1 2)} 3\" => 3"
    (eshell-insert-command "hello")
    (eshell-send-eof-to-process)
    (eshell-wait-for-subprocess)
-   (eshell-match-result "OLLEH\n")))
+   (should (eshell-match-output "OLLEH\n"))))
 
 (ert-deftest eshell-test/pipe-subcommand ()
   "Check that piping with an asynchronous subcommand works"
   (skip-unless (and (executable-find "echo")
                     (executable-find "cat")))
   (with-temp-eshell
-   (eshell-command-result-p "echo ${*echo hi} | *cat"
-                            "hi")))
+   (eshell-match-command-output "echo ${*echo hi} | *cat"
+                                "hi")))
 
 (ert-deftest eshell-test/pipe-subcommand-with-pipe ()
   "Check that piping with an asynchronous subcommand with its own pipe works"
   (skip-unless (and (executable-find "echo")
                     (executable-find "cat")))
   (with-temp-eshell
-   (eshell-command-result-p "echo ${*echo hi | *cat} | *cat"
-                            "hi")))
+   (eshell-match-command-output "echo ${*echo hi | *cat} | *cat"
+                                "hi")))
 
 (ert-deftest eshell-test/subcommand-reset-in-pipeline ()
   "Check that subcommands reset `eshell-in-pipeline-p'."
@@ -136,28 +83,27 @@ e.g. \"{(+ 1 2)} 3\" => 3"
   (dolist (template '("echo {%s} | *cat"
                       "echo ${%s} | *cat"
                       "*cat $<%s> | *cat"))
-    (should (equal (eshell-test-command-result
-                    (format template "echo $eshell-in-pipeline-p"))
-                   nil))
-    (should (equal (eshell-test-command-result
-                    (format template "echo | echo $eshell-in-pipeline-p"))
-                   "last"))
-    (should (equal (eshell-test-command-result
-                    (format template "echo $eshell-in-pipeline-p | echo"))
-                   "first"))
-    (should (equal (eshell-test-command-result
-                    (format template
-                            "echo | echo $eshell-in-pipeline-p | echo"))
-                   "t"))))
+    (eshell-command-result-equal
+     (format template "echo $eshell-in-pipeline-p")
+     nil)
+    (eshell-command-result-equal
+     (format template "echo | echo $eshell-in-pipeline-p")
+     "last")
+    (eshell-command-result-equal
+     (format template "echo $eshell-in-pipeline-p | echo")
+     "first")
+    (eshell-command-result-equal
+     (format template "echo | echo $eshell-in-pipeline-p | echo")
+     "t")))
 
 (ert-deftest eshell-test/lisp-reset-in-pipeline ()
   "Check that interpolated Lisp forms reset `eshell-in-pipeline-p'."
   (skip-unless (executable-find "cat"))
   (dolist (template '("echo (%s) | *cat"
                       "echo $(%s) | *cat"))
-    (should (equal (eshell-test-command-result
-                    (format template "format \"%s\" eshell-in-pipeline-p"))
-                   "nil"))))
+    (eshell-command-result-equal
+     (format template "format \"%s\" eshell-in-pipeline-p")
+     "nil")))
 
 (ert-deftest eshell-test/redirect-buffer ()
   "Check that piping to a buffer works"
@@ -178,43 +124,36 @@ e.g. \"{(+ 1 2)} 3\" => 3"
                                       (string-replace "\\" "\\\\" bufname))))
       (should (equal (buffer-string) "hi")))))
 
-(ert-deftest eshell-test/inside-emacs-var ()
-  "Test presence of \"INSIDE_EMACS\" in subprocesses"
-  (with-temp-eshell
-   (eshell-command-result-p "env"
-                            (format "INSIDE_EMACS=%s,eshell"
-                                    emacs-version))))
-
 (ert-deftest eshell-test/escape-nonspecial ()
   "Test that \"\\c\" and \"c\" are equivalent when \"c\" is not a
 special character."
   (with-temp-eshell
-   (eshell-command-result-p "echo he\\llo"
-                            "hello\n")))
+   (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-command-result-p "echo Vid\\éos"
-                            "Vidéos\n")))
+   (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-command-result-p "echo \"h\\i\""
-                            ;; Backslashes are doubled for regexp.
-                            "h\\\\i\n")))
+   (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-command-result-p "echo \"\\\"hi\\\\\""
-                            ;; Backslashes are doubled for regexp.
-                            "\\\"hi\\\\\n")))
+   (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"
@@ -248,15 +187,15 @@ chars"
                  (> count 0))
        (sit-for 1)
        (setq count (1- count))))
-   (eshell-match-result "alpha\n")))
+   (should (eshell-match-output "alpha\n"))))
 
 (ert-deftest eshell-test/flush-output ()
   "Test flushing of previous output"
   (with-temp-eshell
    (eshell-insert-command "echo alpha")
    (eshell-kill-output)
-   (eshell-match-result
-    (concat "^" (regexp-quote "*** output flushed ***\n") "$"))))
+   (should (eshell-match-output
+            (concat "^" (regexp-quote "*** output flushed ***\n") "$")))))
 
 (ert-deftest eshell-test/run-old-command ()
   "Re-run an old command"
diff --git a/test/lisp/ffap-tests.el b/test/lisp/ffap-tests.el
index 4b580b5af5..076d825642 100644
--- a/test/lisp/ffap-tests.el
+++ b/test/lisp/ffap-tests.el
@@ -28,6 +28,30 @@
 (require 'ert-x)
 (require 'ffap)
 
+(ert-deftest ffap-replace-file-component ()
+  (should (equal
+           (ffap-replace-file-component "/ftp:who@foo.com:/whatever" "/new")
+           "/ftp:who@foo.com:/new")))
+
+(ert-deftest ffap-file-remote-p ()
+  (dolist (test '(("/user@foo.bar.com:/pub" .
+                   "/user@foo.bar.com:/pub")
+                  ("/cssun.mathcs.emory.edu://dir" .
+                   "/cssun.mathcs.emory.edu:/dir")
+                  ("/ffap.el:80" .
+                   "/ffap.el:80")))
+    (let ((A (car test))
+          (B (cdr test)))
+      (should (equal (ffap-file-remote-p A) B)))))
+
+(ert-deftest ffap-machine-p ()
+  (should-not (ffap-machine-p "ftp"))
+  (should-not (ffap-machine-p "nonesuch"))
+  (should (eq (ffap-machine-p "ftp.mathcs.emory.edu") 'accept))
+  (should-not (ffap-machine-p "mathcs" 5678))
+  (should-not (ffap-machine-p "foo.bonk"))
+  (should (eq (ffap-machine-p "foo.bonk.com") 'accept)))
+
 (ert-deftest ffap-tests-25243 ()
   "Test for https://debbugs.gnu.org/25243 ."
   (ert-with-temp-file file
diff --git a/test/lisp/filenotify-tests.el b/test/lisp/filenotify-tests.el
index ad0138b2e7..4ed1786a8e 100644
--- a/test/lisp/filenotify-tests.el
+++ b/test/lisp/filenotify-tests.el
@@ -178,10 +178,6 @@ Return nil when any other file notification watch is still 
active."
       tramp-allow-unsafe-temporary-files
       (or tramp-allow-unsafe-temporary-files noninteractive))
 
-;; This should happen on hydra only.
-(when (getenv "EMACS_HYDRA_CI")
-  (add-to-list 'tramp-remote-path 'tramp-own-remote-path))
-
 (defun file-notify--test-add-watch (file flags callback)
   "Like `file-notify-add-watch', but also passing FILE to CALLBACK."
   (file-notify-add-watch file flags
diff --git a/test/lisp/files-tests.el b/test/lisp/files-tests.el
index 54ada08800..20c712226e 100644
--- a/test/lisp/files-tests.el
+++ b/test/lisp/files-tests.el
@@ -221,8 +221,8 @@ form.")
                 ("x:/foo//bar/" "y:/bar/qux/" "z:/qux/foo/"))
                ("x:/foo/bar" "$FOO/baz/;z:/qux/foo/"
                 ("x:/foo/bar/baz/" "z:/qux/foo/"))
-               ("//foo/bar/" "$FOO/baz/;/qux/foo/"
-                ("/foo/bar//baz/" "/qux/foo/")))
+               ("///foo/bar/" "$FOO/baz/;/qux/foo/"
+                ("//foo/bar//baz/" "/qux/foo/")))
            '(("/foo/bar//baz/:/bar/foo/baz//" nil
               ("/foo/bar//baz/" "/bar/foo/baz//"))
              ("/foo/bar/:/bar/qux/:/qux/foo" nil
@@ -1504,7 +1504,11 @@ See <https://debbugs.gnu.org/36401>."
     (should (equal (parse-colon-path "/foo//bar/baz")
                    '("/foo//bar/baz/"))))
   (should (equal (parse-colon-path (concat "." path-separator "/tmp"))
-                 '("./" "/tmp/"))))
+                 '("./" "/tmp/")))
+  (should (equal (parse-colon-path (concat "/foo" path-separator "///bar"))
+                 (if (memq system-type '(windows-nt cygwin ms-dos))
+                     '("/foo/" "//bar/")
+                   '("/foo/" "/bar/")))))
 
 (ert-deftest files-test-magic-mode-alist-doctype ()
   "Test that DOCTYPE and variants put files in mhtml-mode."
diff --git a/test/lisp/gnus/message-tests.el b/test/lisp/gnus/message-tests.el
index 8f3c1250a9..a724428ecb 100644
--- a/test/lisp/gnus/message-tests.el
+++ b/test/lisp/gnus/message-tests.el
@@ -47,14 +47,10 @@
           (setq-local parse-sexp-lookup-properties t)
           (backward-sexp)
           (should (string= "here's an opener "
-                           (buffer-substring-no-properties
-                            (line-beginning-position)
-                            (point))))
+                           (buffer-substring-no-properties (pos-bol) (point))))
           (forward-sexp)
           (should (string= "and here's a closer )"
-                           (buffer-substring-no-properties
-                            (line-beginning-position)
-                            (point)))))
+                           (buffer-substring-no-properties (pos-bol) 
(point)))))
       (set-buffer-modified-p nil))))
 
 
diff --git a/test/lisp/help-fns-tests.el b/test/lisp/help-fns-tests.el
index e3fed60b4c..7ff7aa1ccd 100644
--- a/test/lisp/help-fns-tests.el
+++ b/test/lisp/help-fns-tests.el
@@ -64,13 +64,13 @@ Return first line of the output of (describe-function-1 
FUNC)."
 
 (ert-deftest help-fns-test-lisp-defun ()
   (let ((regexp (if (featurep 'native-compile)
-                    "a native compiled Lisp function in .+subr\\.el"
-                  "a compiled Lisp function in .+subr\\.el"))
+                    "a native-compiled Lisp function in .+subr\\.el"
+                  "a byte-compiled Lisp function in .+subr\\.el"))
         (result (help-fns-tests--describe-function 'last)))
     (should (string-match regexp result))))
 
 (ert-deftest help-fns-test-lisp-defsubst ()
-  (let ((regexp "a compiled Lisp function in .+subr\\.el")
+  (let ((regexp "a byte-compiled Lisp function in .+subr\\.el")
         (result (help-fns-tests--describe-function 'posn-window)))
     (should (string-match regexp result))))
 
diff --git a/test/lisp/help-tests.el b/test/lisp/help-tests.el
index 9c9dddcd19..833c32ffb2 100644
--- a/test/lisp/help-tests.el
+++ b/test/lisp/help-tests.el
@@ -55,18 +55,24 @@
     (should (equal (help-split-fundoc nil t 'usage)  nil))
     (should (equal (help-split-fundoc nil t 'doc)    nil))))
 
+(ert-deftest help--key-description-fontified ()
+  (should (equal (help--key-description-fontified
+                  (where-is-internal #'next-line nil t))
+                 "C-n"))
+  (should-not (help--key-description-fontified nil)))
+
 
 ;;; substitute-command-keys
 
 (defmacro with-substitute-command-keys-test (&rest body)
   `(cl-flet* ((test
-               (lambda (orig result)
-                 (should (equal (substitute-command-keys orig)
-                                result))))
+                (lambda (orig result)
+                  (should (equal (substitute-command-keys orig)
+                                 result))))
               (test-re
-               (lambda (orig regexp)
-                 (should (string-match (concat "\\`" regexp "\\'")
-                                       (substitute-command-keys orig))))))
+                (lambda (orig regexp)
+                  (should (string-match (concat "\\`" regexp "\\'")
+                                        (substitute-command-keys orig))))))
      ,@body))
 
 (ert-deftest help-tests-substitute-command-keys/no-change ()
@@ -93,18 +99,30 @@
   (with-substitute-command-keys-test
    (test "\\`C-m'" "C-m")
    (test "\\`C-m'\\`C-j'" "C-mC-j")
-   (test "foo\\`C-m'bar\\`C-j'baz" "fooC-mbarC-jbaz")))
-
-(ert-deftest help-tests-substitute-command-keys/literal-key-sequence-errors ()
-  (should-error (substitute-command-keys "\\`'"))
-  (should-error (substitute-command-keys "\\`c-c'"))
-  (should-error (substitute-command-keys "\\`<foo bar baz>'")))
-
-(ert-deftest help-tests-substitute-key-bindings/face-help-key-binding ()
-  (should (eq (get-text-property 0 'face (substitute-command-keys 
"\\[next-line]"))
-              'help-key-binding))
-  (should (eq (get-text-property 0 'face (substitute-command-keys "\\`f'"))
-              'help-key-binding)))
+   (test "foo\\`C-m'bar\\`C-j'baz" "fooC-mbarC-jbaz")
+   (test "\\`M-x next-line'" "M-x next-line")
+   (test "\\`mouse-1'" "mouse-1")))
+
+(ert-deftest 
help-tests-substitute-command-keys/literal-key-sequence-ignore-invalid ()
+  "Ignore any invalid literal key sequence."
+  (with-substitute-command-keys-test
+   (test-re "ab\\`'cd" "ab\\\\[`'‘]['’]cd")
+   (test-re "\\`c-c'" "\\\\[`'‘]c-c['’]")
+   (test-re "\\`<foo bar baz>'" "\\\\[`'‘]<foo bar baz>['’]")))
+
+(ert-deftest help-tests-substitute-key-bindings/help-key-binding-face ()
+  (let ((A (substitute-command-keys "\\[next-line]"))
+        (B (substitute-command-keys "\\`f'")))
+    (should (eq (get-text-property 0 'face A) 'help-key-binding))
+    (should (eq (get-text-property 0 'face B) 'help-key-binding))))
+
+(ert-deftest help-tests-substitute-key-bindings/help-key-binding-no-face ()
+  (let ((A (substitute-command-keys "\\[next-line]" t))
+        (B (substitute-command-keys "\\`f'" t)))
+    (should (eq (get-text-property 0 'face A) nil))
+    (should (eq (get-text-property 0 'face B) nil))
+    (should (equal A "C-n"))
+    (should (equal B "f"))))
 
 (defvar-keymap help-tests--test-keymap
   :doc "Just some keymap for testing."
diff --git a/test/lisp/ibuffer-tests.el b/test/lisp/ibuffer-tests.el
index 252d2c5d7f..d54718e297 100644
--- a/test/lisp/ibuffer-tests.el
+++ b/test/lisp/ibuffer-tests.el
@@ -132,7 +132,7 @@
           (ibuffer-switch-to-saved-filter-groups "saved-filters")
           (should (assoc "Elisp" (cdar ibuffer-saved-filter-groups))))
       (setq ibuffer-saved-filter-groups orig-filters)
-      (ibuffer-awhen (get-buffer "*Ibuffer*")
+      (when-let ((it (get-buffer "*Ibuffer*")))
         (and (buffer-live-p it) (kill-buffer it))))))
 
 
@@ -785,7 +785,7 @@
                                               (funcall tag
                                                        (funcall description
                                                                 'starred-name)
-                                                       ": " "nil"))
+                                                       "" ""))
                                      (funcall tag
                                               (funcall description 'directory)
                                               ": " "\\<org\\>")))))
@@ -806,7 +806,7 @@
                             (funcall tag "AND"
                                      (funcall tag
                                               (funcall description 
'starred-name)
-                                              ": " "nil")
+                                              "" "")
                                      (funcall tag
                                               (funcall description 'name)
                                               ": " "elisp"))
diff --git a/test/lisp/info-xref-tests.el b/test/lisp/info-xref-tests.el
index acfd6e82f1..117170ba33 100644
--- a/test/lisp/info-xref-tests.el
+++ b/test/lisp/info-xref-tests.el
@@ -161,8 +161,7 @@ text.
       (should (search-backward "done" nil t))
       (should (string-match-p
                " [0-9]\\{3,\\} good, 0 bad"
-               (buffer-substring-no-properties (line-beginning-position)
-                                               (line-end-position)))))))
+               (buffer-substring-no-properties (pos-bol) (pos-eol)))))))
 
 
 ;;; info-xref-tests.el ends here
diff --git a/test/lisp/international/ccl-tests.el 
b/test/lisp/international/ccl-tests.el
index 57ac74639b..cf472415c7 100644
--- a/test/lisp/international/ccl-tests.el
+++ b/test/lisp/international/ccl-tests.el
@@ -25,23 +25,25 @@
 
 
 (ert-deftest shift ()
-  ;; shift left +ve                      5628     #x00000000000015fc
-  (should (= (ash  5628  8)           1440768)) ; #x000000000015fc00
-  (should (= (lsh  5628  8)           1440768)) ; #x000000000015fc00
-
-  ;; shift left -ve                     -5628     #x3fffffffffffea04
-  (should (= (ash -5628  8)          -1440768)) ; #x3fffffffffea0400
-  (should (= (lsh -5628  8)          -1440768)) ; #x3fffffffffea0400
-
-  ;; shift right +ve                     5628     #x00000000000015fc
-  (should (= (ash  5628 -8)                21)) ; #x0000000000000015
-  (should (= (lsh  5628 -8)                21)) ; #x0000000000000015
-
-  ;; shift right -ve                    -5628     #x3fffffffffffea04
-  (should (= (ash -5628 -8)               -22)) ; #x3fffffffffffffea
-  (should (= (lsh -5628 -8)
-             (ash (- -5628 (ash most-negative-fixnum 1)) -8)
-             (ash (logand (ash -5628 -1) most-positive-fixnum) -7))))
+  (with-suppressed-warnings ((suspicious lsh))
+
+    ;; shift left +ve                      5628     #x00000000000015fc
+    (should (= (ash  5628  8)           1440768)) ; #x000000000015fc00
+    (should (= (lsh  5628  8)           1440768)) ; #x000000000015fc00
+
+    ;; shift left -ve                     -5628     #x3fffffffffffea04
+    (should (= (ash -5628  8)          -1440768)) ; #x3fffffffffea0400
+    (should (= (lsh -5628  8)          -1440768)) ; #x3fffffffffea0400
+
+    ;; shift right +ve                     5628     #x00000000000015fc
+    (should (= (ash  5628 -8)                21)) ; #x0000000000000015
+    (should (= (lsh  5628 -8)                21)) ; #x0000000000000015
+
+    ;; shift right -ve                    -5628     #x3fffffffffffea04
+    (should (= (ash -5628 -8)               -22)) ; #x3fffffffffffffea
+    (should (= (lsh -5628 -8)
+               (ash (- -5628 (ash most-negative-fixnum 1)) -8)
+               (ash (logand (ash -5628 -1) most-positive-fixnum) -7)))))
 
 ;; CCl program from `pgg-parse-crc24' in lisp/obsolete/pgg-parse.el
 (defconst prog-pgg-source
diff --git a/test/lisp/international/ucs-normalize-tests.el 
b/test/lisp/international/ucs-normalize-tests.el
index 27a4e70c78..774a3ea7ec 100644
--- a/test/lisp/international/ucs-normalize-tests.el
+++ b/test/lisp/international/ucs-normalize-tests.el
@@ -246,7 +246,7 @@ must be true for all conformant implementations:
                  ucs-normalize-tests--rule1-failing-for-partX
                  ucs-normalize-tests--rule1-holds-p
                  ucs-normalize-tests--rule2-holds-p))
-    (or (byte-code-function-p (symbol-function fun))
+    (or (compiled-function-p (symbol-function fun))
         (byte-compile fun)))
   (let ((ucs-normalize-tests--chars-part1 (make-char-table 
'ucs-normalize-tests t)))
     (setq ucs-normalize-tests--part1-rule1-failed-lines
diff --git a/test/lisp/isearch-tests.el b/test/lisp/isearch-tests.el
index 4600757d94..8cb5e5e454 100644
--- a/test/lisp/isearch-tests.el
+++ b/test/lisp/isearch-tests.el
@@ -38,5 +38,85 @@
   ;; Bug #21091: let `isearch-done' work without `isearch-update'.
   (isearch-done))
 
+
+;; Search functions.
+
+(defun isearch--test-search-within-boundaries (pairs)
+  (goto-char (point-min))
+  (let ((isearch-forward t)
+        (isearch-regexp nil))
+    (dolist (pos (append pairs nil))
+      (should (eq (cdr pos) (isearch-search-string "foo" nil t)))
+      (should (equal (match-string 0) "foo"))
+      (when (car pos) (should (eq (car pos) (match-beginning 0))))))
+
+  (goto-char (point-max))
+  (let ((isearch-forward nil)
+        (isearch-regexp nil))
+    (dolist (pos (append (reverse pairs) nil))
+      (should (eq (car pos) (isearch-search-string "foo" nil t)))
+      (should (equal (match-string 0) "foo"))
+      (when (cdr pos) (should (eq (cdr pos) (match-end 0))))))
+
+  (goto-char (point-min))
+  (let ((isearch-forward t)
+        (isearch-regexp t))
+    (dolist (pos (append pairs nil))
+      (should (eq (cdr pos) (isearch-search-string ".*" nil t)))
+      (should (equal (match-string 0) "foo"))
+      (when (car pos) (should (eq (car pos) (match-beginning 0))))))
+
+  (goto-char (point-min))
+  (let ((isearch-forward t)
+        (isearch-regexp t))
+    (dolist (pos (append pairs nil))
+      (should (eq (cdr pos) (isearch-search-string "^.*" nil t)))
+      (should (equal (match-string 0) "foo"))
+      (when (car pos) (should (eq (car pos) (match-beginning 0))))))
+
+  (goto-char (point-min))
+  (let ((isearch-forward t)
+        (isearch-regexp t))
+    (dolist (pos (append pairs nil))
+      (should (eq (cdr pos) (isearch-search-string ".*$" nil t)))
+      (should (equal (match-string 0) "foo"))
+      (when (car pos) (should (eq (car pos) (match-beginning 0))))))
+
+  (goto-char (point-max))
+  (let ((isearch-forward nil)
+        (isearch-regexp t))
+    (dolist (pos (append (reverse pairs) nil))
+      (should (eq (car pos) (isearch-search-string "^.*" nil t)))
+      (should (equal (match-string 0) "foo"))
+      (when (cdr pos) (should (eq (cdr pos) (match-end 0))))))
+
+  (goto-char (point-max))
+  (let ((isearch-forward nil)
+        (isearch-regexp t))
+    (dolist (pos (append (reverse pairs) nil))
+      (should (eq (car pos) (isearch-search-string "foo$" nil t)))
+      (should (equal (match-string 0) "foo"))
+      (when (cdr pos) (should (eq (cdr pos) (match-end 0)))))))
+
+(ert-deftest isearch--test-search-fun-in-text-property ()
+  (let* ((pairs '((4 . 7) (11 . 14) (21 . 24)))
+         (isearch-search-fun-function
+          (lambda () (isearch-search-fun-in-text-property nil 
'dired-filename))))
+    (with-temp-buffer
+      (insert "foo" (propertize "foo" 'dired-filename t) "foo\n")
+      (insert (propertize "foo" 'dired-filename t) "foo\n")
+      (insert "foo" (propertize "foo" 'dired-filename t) "\n")
+      (isearch--test-search-within-boundaries pairs))))
+
+(ert-deftest isearch--test-search-fun-in-noncontiguous-region ()
+  (let* ((pairs '((4 . 7) (11 . 14) (21 . 24)))
+         (isearch-search-fun-function
+          (lambda () (isearch-search-fun-in-noncontiguous-region nil pairs))))
+    (with-temp-buffer
+      (insert "foofoofoo\n")
+      (insert "foofoo\n")
+      (insert "foofoo\n")
+      (isearch--test-search-within-boundaries pairs))))
+
 (provide 'isearch-tests)
 ;;; isearch-tests.el ends here
diff --git a/test/lisp/json-tests.el b/test/lisp/json-tests.el
index ef7805a341..ab1f19fb6e 100644
--- a/test/lisp/json-tests.el
+++ b/test/lisp/json-tests.el
@@ -510,8 +510,8 @@ Point is moved to beginning of the buffer."
     (let ((json-key-type 'string))
       (setq obj (json-add-to-object obj "g" 7))
       (setq obj (json-add-to-object obj "h" 8))
-      (should (= (lax-plist-get obj "g") 7))
-      (should (= (lax-plist-get obj "h") 8)))))
+      (should (= (plist-get obj "g" #'equal) 7))
+      (should (= (plist-get obj "h" #'equal) 8)))))
 
 (ert-deftest test-json-add-to-hash-table ()
   (let* ((json-object-type 'hash-table)
diff --git a/test/lisp/mail/footnote-tests.el b/test/lisp/mail/footnote-tests.el
index e33b59bc41..f3a35e3dfc 100644
--- a/test/lisp/mail/footnote-tests.el
+++ b/test/lisp/mail/footnote-tests.el
@@ -40,7 +40,7 @@
     (footnote-back-to-message)
     (should (equal (buffer-substring (point-min) (point))
                    "hello[1]"))
-    (should (equal (buffer-substring (point-min) (line-end-position))
+    (should (equal (buffer-substring (point-min) (pos-eol))
                    "hello[1][2] world"))))
 
 (provide 'footnote-tests)
diff --git a/test/lisp/mail/mail-extr-tests.el 
b/test/lisp/mail/mail-extr-tests.el
new file mode 100644
index 0000000000..a8f0c605cb
--- /dev/null
+++ b/test/lisp/mail/mail-extr-tests.el
@@ -0,0 +1,41 @@
+;;; mail-extr-tests.el --- Tests for mail-extr.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/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'ert)
+(require 'mail-extr)
+
+(defconst mail-extract-test-cases
+  '(("foo@example.org" . (nil "foo@example.org"))
+    ("J. Random Hacker <foo@example.org>" . ("J. Random Hacker" 
"foo@example.org"))
+    ("\"J. Random Hacker\" <foo@example.org>" . ("J. Random Hacker" 
"foo@example.org"))
+    ("Ååå Äää <foo@example.org>" . ("Ååå Äää" "foo@example.org"))))
+
+(ert-deftest mail-extract-address-components ()
+  (dolist (test mail-extract-test-cases)
+    (should (equal (mail-extract-address-components (car test)) (cdr test)))))
+
+(ert-deftest what-domain ()
+  (should (equal (what-domain "cu") "CU: Cuba")))
+
+(provide 'mail-extr-tests)
+;;; mail-extr-tests.el ends here
diff --git a/test/lisp/mh-e/mh-utils-tests.el b/test/lisp/mh-e/mh-utils-tests.el
index 0708617259..72ee2fc474 100644
--- a/test/lisp/mh-e/mh-utils-tests.el
+++ b/test/lisp/mh-e/mh-utils-tests.el
@@ -48,8 +48,10 @@
 ;;; Code:
 
 (require 'ert)
-(eval-when-compile (require 'cl-lib))
 (require 'mh-utils)
+(eval-when-compile
+  (require 'cl-lib)
+  (require 'subr-x))
 
 (ert-deftest mh-quote-pick-expr ()
   "Test `mh-quote-pick-expr'."
diff --git a/test/lisp/misc-tests.el b/test/lisp/misc-tests.el
index 236223ef49..f84827ab02 100644
--- a/test/lisp/misc-tests.el
+++ b/test/lisp/misc-tests.el
@@ -80,5 +80,59 @@
     (backward-to-word 3)
     (should (equal (point) 1))))
 
+(ert-deftest misc--duplicate-line ()
+  ;; Duplicate a line (twice).
+  (with-temp-buffer
+    (insert "abc\ndefg\nh\n")
+    (goto-char 7)
+    (duplicate-line 2)
+    (should (equal (buffer-string) "abc\ndefg\ndefg\ndefg\nh\n"))
+    (should (equal (point) 7)))
+  ;; Duplicate a non-terminated line.
+  (with-temp-buffer
+    (insert "abc")
+    (goto-char 2)
+    (duplicate-line)
+    (should (equal (buffer-string) "abc\nabc\n"))
+    (should (equal (point) 2))))
+
+(require 'rect)
+
+(ert-deftest misc--duplicate-dwim ()
+  ;; Duplicate a line.
+  (with-temp-buffer
+    (insert "abc\ndefg\nh\n")
+    (goto-char 7)
+    (duplicate-dwim 2)
+    (should (equal (buffer-string) "abc\ndefg\ndefg\ndefg\nh\n"))
+    (should (equal (point) 7)))
+
+  ;; Duplicate a region.
+  (with-temp-buffer
+    (insert "abc\ndef\n")
+    (set-mark 2)
+    (goto-char 7)
+    (transient-mark-mode)
+    (should (use-region-p))
+    (duplicate-dwim)
+    (should (equal (buffer-string) "abc\ndebc\ndef\n"))
+    (should (equal (point) 7))
+    (should (region-active-p))
+    (should (equal (mark) 2)))
+
+  ;; Duplicate a rectangular region.
+  (with-temp-buffer
+    (insert "x\n>a\n>bcde\n>fg\nyz\n")
+    (goto-char 4)
+    (rectangle-mark-mode)
+    (goto-char 15)
+    (rectangle-forward-char 1)
+    (duplicate-dwim)
+    (should (equal (buffer-string) "x\n>a  a  \n>bcdbcde\n>fg fg \nyz\n"))
+    (should (equal (point) 24))
+    (should (region-active-p))
+    (should rectangle-mark-mode)
+    (should (equal (mark) 4))))
+
 (provide 'misc-tests)
 ;;; misc-tests.el ends here
diff --git a/test/lisp/net/browse-url-tests.el 
b/test/lisp/net/browse-url-tests.el
index 8fcc831d53..1c993958b8 100644
--- a/test/lisp/net/browse-url-tests.el
+++ b/test/lisp/net/browse-url-tests.el
@@ -31,7 +31,7 @@
 (require 'ert-x)
 
 (ert-deftest browse-url-tests-browser-kind ()
-  (should (eq (browse-url--browser-kind #'browse-url-w3 "gnu.org")
+  (should (eq (browse-url--browser-kind #'browse-url-emacs "gnu.org")
               'internal))
   (should
    (eq (browse-url--browser-kind #'browse-url-firefox "gnu.org")
diff --git a/test/lisp/net/netrc-resources/services 
b/test/lisp/net/netrc-resources/services
deleted file mode 100644
index fd8a0348df..0000000000
--- a/test/lisp/net/netrc-resources/services
+++ /dev/null
@@ -1,6 +0,0 @@
-tcpmux         1/tcp                           # TCP port service multiplexer
-smtp           25/tcp          mail
-http           80/tcp          www             # WorldWideWeb HTTP
-kerberos       88/tcp          kerberos5 krb5 kerberos-sec     # Kerberos v5
-kerberos       88/udp          kerberos5 krb5 kerberos-sec     # Kerberos v5
-rtmp           1/ddp                   # Routing Table Maintenance Protocol
diff --git a/test/lisp/net/netrc-tests.el b/test/lisp/net/netrc-tests.el
deleted file mode 100644
index 8e83f405bc..0000000000
--- a/test/lisp/net/netrc-tests.el
+++ /dev/null
@@ -1,60 +0,0 @@
-;;; netrc-tests.el --- Tests for netrc.el  -*- lexical-binding:t -*-
-
-;; Copyright (C) 2020-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/>.
-
-;;; Code:
-
-(require 'ert)
-(require 'ert-x)
-(require 'netrc)
-
-(ert-deftest test-netrc-parse-services ()
-  (let ((netrc-services-file (ert-resource-file "services")))
-    (should (equal (netrc-parse-services)
-                   '(("tcpmux" 1 tcp)
-                     ("smtp" 25 tcp)
-                     ("http" 80 tcp)
-                     ("kerberos" 88 tcp)
-                     ("kerberos" 88 udp)
-                     ("rtmp" 1 ddp))))))
-
-(ert-deftest test-netrc-find-service-name ()
-  (let ((netrc-services-file (ert-resource-file "services")))
-    (should (equal (netrc-find-service-name 25) "smtp"))
-    (should (equal (netrc-find-service-name 88 'udp) "kerberos"))
-    (should-not (netrc-find-service-name 12345))))
-
-(ert-deftest test-netrc-credentials ()
-  (let ((netrc-file (ert-resource-file "authinfo")))
-    (should (equal (netrc-credentials "imap.example.org")
-                   '("jrh@example.org" "*foobar*")))
-    (should (equal (netrc-credentials "ftp.example.org")
-                   '("jrh" "*baz*")))))
-
-(ert-deftest test-netrc-credentials-2 ()
-  (let ((netrc-file (ert-resource-file "netrc-folding")))
-    (should
-     (equal (netrc-parse netrc-file)
-            '((("machine" . "XM") ("login" . "XL") ("password" . "XP"))
-              (("machine" . "YM")) (("login" . "YL")) (("password" . 
"YP")))))))
-
-(provide 'netrc-tests)
-
-;;; netrc-tests.el ends here
diff --git a/test/lisp/net/shr-tests.el b/test/lisp/net/shr-tests.el
index 821ca5ca63..2254f9bc86 100644
--- a/test/lisp/net/shr-tests.el
+++ b/test/lisp/net/shr-tests.el
@@ -67,6 +67,21 @@
     (should-not
      (shr--use-cookies-p "http://www.gnu.org"; '("http://www.fsf.org";)))))
 
+(ert-deftest shr-srcset ()
+  (should (equal (shr--parse-srcset "") nil))
+
+  (should (equal (shr--parse-srcset "a 10w, b 20w")
+                 '(("b" 20) ("a" 10))))
+
+  (should (equal (shr--parse-srcset "a 10w b 20w")
+                 '(("a" 10))))
+
+  (should (equal (shr--parse-srcset "https://example.org/1\n\n 10w , 
https://example.org/2 20w      ")
+                '(("https://example.org/2"; 20) ("https://example.org/1"; 10))))
+
+  (should (equal (shr--parse-srcset "https://example.org/1,2\n\n 10w , 
https://example.org/2 20w      ")
+                '(("https://example.org/2"; 20) ("https://example.org/1,2"; 
10)))))
+
 (require 'shr)
 
 ;;; shr-tests.el ends here
diff --git a/test/lisp/net/tramp-archive-tests.el 
b/test/lisp/net/tramp-archive-tests.el
index 54d1ecf365..964404b4bf 100644
--- a/test/lisp/net/tramp-archive-tests.el
+++ b/test/lisp/net/tramp-archive-tests.el
@@ -31,7 +31,6 @@
 (require 'ert)
 (require 'ert-x)
 (require 'tramp-archive)
-(defvar tramp-copy-size-limit)
 (defvar tramp-persistency-file-name)
 
 ;; `ert-resource-file' was introduced in Emacs 28.1.
@@ -41,7 +40,8 @@
       "Format for `ert-resource-directory'.")
     (defvar ert-resource-directory-trim-left-regexp ""
       "Regexp for `string-trim' (left) used by `ert-resource-directory'.")
-    (defvar ert-resource-directory-trim-right-regexp "\\(-tests?\\)?\\.el"
+    (defvar ert-resource-directory-trim-right-regexp
+      (rx (? "-test" (? "s")) ".el")
       "Regexp for `string-trim' (right) used by `ert-resource-directory'.")
 
     (defmacro ert-resource-directory ()
@@ -96,7 +96,6 @@ Do not hexlify \"/\".  This hexlified string is used in 
`file:///' URLs."
 
 (setq password-cache-expiry nil
       tramp-cache-read-persistent-data t ;; For auth-sources.
-      tramp-copy-size-limit nil
       tramp-persistency-file-name nil
       tramp-verbose 0)
 
@@ -617,13 +616,13 @@ This checks also `file-name-as-directory', 
`file-name-directory',
            (insert-directory tramp-archive-test-archive nil)
            (goto-char (point-min))
            (should
-            (looking-at-p (regexp-quote tramp-archive-test-archive))))
+            (looking-at-p (rx (literal tramp-archive-test-archive)))))
          (with-temp-buffer
            (insert-directory tramp-archive-test-archive "-al")
            (goto-char (point-min))
            (should
             (looking-at-p
-             (format "^.+ %s$" (regexp-quote tramp-archive-test-archive)))))
+             (rx bol (+ nonl) " " (literal tramp-archive-test-archive) eol))))
          (with-temp-buffer
            (insert-directory
             (file-name-as-directory tramp-archive-test-archive)
@@ -631,15 +630,17 @@ This checks also `file-name-as-directory', 
`file-name-directory',
            (goto-char (point-min))
            (should
             (looking-at-p
-             (concat
-              ;; There might be a summary line.
-              "\\(total.+[[:digit:]]+ ?[kKMGTPEZY]?i?B?\n\\)?"
-              ;; We don't know in which order the files appear.
-              (format
-               "\\(.+ %s\\( ->.+\\)?\n\\)\\{%d\\}"
-               (regexp-opt (directory-files tramp-archive-test-archive))
-               (length (directory-files tramp-archive-test-archive)))))))
-
+             (rx-to-string
+              `(:
+                ;; There might be a summary line.
+                (? "total" (+ nonl) (+ digit) (? " ")
+                   (? (any "EGKMPTYZk")) (? "i") (? "B") "\n")
+                ;; We don't know in which order the files appear.
+                (= ,(length (directory-files tramp-archive-test-archive))
+                   (+ nonl) " "
+                   (regexp
+                    ,(regexp-opt (directory-files tramp-archive-test-archive)))
+                   (? " ->" (one-or-more nonl)) "\n"))))))
          ;; Check error case.
          (with-temp-buffer
            (should-error
@@ -729,7 +730,7 @@ This tests also `access-file', `file-readable-p' and 
`file-regular-p'."
          (setq attr (directory-files-and-attributes tmp-name 'full))
          (dolist (elt attr)
            (should (equal (file-attributes (car elt)) (cdr elt))))
-         (setq attr (directory-files-and-attributes tmp-name nil "\\`b"))
+         (setq attr (directory-files-and-attributes tmp-name nil (rx bos "b")))
          (should (equal (mapcar #'car attr) '("bar"))))
 
       ;; Cleanup.
@@ -916,11 +917,14 @@ This tests also `file-executable-p', `file-writable-p' 
and `set-file-modes'."
        (dolist (file `("/mock::foo" ,(concat tramp-archive-test-archive 
"foo")))
           (should
            (string-match
-           (format
-            "tramp-archive loaded: %s[[:ascii:]]+tramp-archive loaded: %s"
-            (tramp-archive-file-name-p default-directory)
-            (or (tramp-archive-file-name-p default-directory)
-                (and enabled (tramp-archive-file-name-p file))))
+           (rx "tramp-archive loaded: "
+               (literal (symbol-name
+                         (tramp-archive-file-name-p default-directory)))
+               (+ ascii)
+               "tramp-archive loaded: "
+               (literal (symbol-name
+                         (or (tramp-archive-file-name-p default-directory)
+                            (and enabled (tramp-archive-file-name-p file))))))
            (shell-command-to-string
             (format
              "%s -batch -Q -L %s --eval %s --eval %s"
@@ -957,9 +961,9 @@ This tests also `file-executable-p', `file-writable-p' and 
`set-file-modes'."
     (dolist (tae '(t nil))
       (should
        (string-match
-       (format
-        "tramp-archive loaded: nil[[:ascii:]]+tramp-archive loaded: 
nil[[:ascii:]]+tramp-archive loaded: %s"
-        tae)
+       (rx "tramp-archive loaded: nil" (+ ascii)
+           "tramp-archive loaded: nil" (+ ascii)
+           "tramp-archive loaded: " (literal (symbol-name tae)))
         (shell-command-to-string
          (format
          "%s -batch -Q -L %s --eval %s"
@@ -1007,7 +1011,8 @@ This tests also `file-executable-p', `file-writable-p' 
and `set-file-modes'."
             (apply
              'append
              (mapcar
-              (lambda (x) (directory-files (concat dir x) 'full "uu\\'" 'sort))
+              (lambda (x)
+                (directory-files (concat dir x) 'full (rx "uu" eos) 'sort))
               '("~/src/libarchive-3.2.2/libarchive/test"
                 "~/src/libarchive-3.2.2/cpio/test"
                 "~/src/libarchive-3.2.2/tar/test"))))
diff --git a/test/lisp/net/tramp-tests.el b/test/lisp/net/tramp-tests.el
index 87c8eb0ada..bc67ff2ace 100644
--- a/test/lisp/net/tramp-tests.el
+++ b/test/lisp/net/tramp-tests.el
@@ -91,7 +91,8 @@
       "Format for `ert-resource-directory'.")
     (defvar ert-resource-directory-trim-left-regexp ""
       "Regexp for `string-trim' (left) used by `ert-resource-directory'.")
-    (defvar ert-resource-directory-trim-right-regexp "\\(-tests?\\)?\\.el"
+    (defvar ert-resource-directory-trim-right-regexp
+      (rx (? "-test" (? "s")) ".el")
       "Regexp for `string-trim' (right) used by `ert-resource-directory'.")
 
     (defmacro ert-resource-directory ()
@@ -128,6 +129,7 @@ A resource file is in the resource directory as per
       `(expand-file-name ,file (ert-resource-directory)))))
 
 ;; `ert-remote-temporary-file-directory' was introduced in Emacs 29.1.
+;; Adapting `tramp-remote-path' happens also there.
 (unless (boundp 'ert-remote-temporary-file-directory)
   (eval-and-compile
     ;; There is no default value on w32 systems, which could work out
@@ -152,7 +154,11 @@ A resource file is in the resource directory as per
           (unless (and (null noninteractive) (file-directory-p "~/"))
             (setenv "HOME" temporary-file-directory))
           (format "/mock::%s" temporary-file-directory)))
-      "Temporary directory for remote file tests.")))
+      "Temporary directory for remote file tests.")
+
+    ;; This should happen on hydra only.
+    (when (getenv "EMACS_HYDRA_CI")
+      (add-to-list 'tramp-remote-path 'tramp-own-remote-path))))
 
 ;; Beautify batch mode.
 (when noninteractive
@@ -178,10 +184,6 @@ A resource file is in the resource directory as per
       tramp-persistency-file-name nil
       tramp-verbose 0)
 
-;; This should happen on hydra only.
-(when (getenv "EMACS_HYDRA_CI")
-  (add-to-list 'tramp-remote-path 'tramp-own-remote-path))
-
 (defvar tramp--test-enabled-checked nil
   "Cached result of `tramp--test-enabled'.
 If the function did run, the value is a cons cell, the `cdr'
@@ -200,6 +202,14 @@ being the result.")
           (file-writable-p ert-remote-temporary-file-directory))))))
 
   (when (cdr tramp--test-enabled-checked)
+    ;; Remove old test files.
+    (dolist (dir `(,temporary-file-directory
+                  ,ert-remote-temporary-file-directory))
+      (dolist (file (directory-files dir 'full (rx bos (? ".#") "tramp-test")))
+       (ignore-errors
+         (if (file-directory-p file)
+             (delete-directory file 'recursive)
+           (delete-file file)))))
     ;; Cleanup connection.
     (ignore-errors
       (tramp-cleanup-connection tramp-test-vec nil 'keep-password)))
@@ -378,15 +388,17 @@ Also see `ignore'."
          ;; `tramp-ignored-file-name-regexp' suppresses Tramp.
          (let ((tramp-ignored-file-name-regexp "^/method:user@host:"))
            (should-not (tramp-tramp-file-p "/method:user@host:")))
-         ;; Methods shall be at least two characters on MS Windows,
-         ;; except the default method.
+         ;; Methods shall be at least two characters, except the
+         ;; default method.
          (let ((system-type 'windows-nt))
            (should-not (tramp-tramp-file-p "/c:/path/to/file"))
            (should-not (tramp-tramp-file-p "/c::/path/to/file"))
-           (should (tramp-tramp-file-p "/-::/path/to/file")))
+           (should (tramp-tramp-file-p "/-::/path/to/file"))
+           (should (tramp-tramp-file-p "/mm::/path/to/file")))
          (let ((system-type 'gnu/linux))
+           (should-not (tramp-tramp-file-p "/m::/path/to/file"))
            (should (tramp-tramp-file-p "/-:h:/path/to/file"))
-           (should (tramp-tramp-file-p "/m::/path/to/file"))))
+           (should (tramp-tramp-file-p "/mm::/path/to/file"))))
 
       ;; Exit.
       (tramp-change-syntax syntax))))
@@ -1055,8 +1067,7 @@ Also see `ignore'."
                   (file-remote-p "/user@email@host:")
                   (format "/%s@%s:" "user@email" "host")))
          (should (string-equal
-                  (file-remote-p
-                   "/user@email@host:" 'method) "default-method"))
+                  (file-remote-p "/user@email@host:" 'method) 
"default-method"))
          (should (string-equal
                   (file-remote-p "/user@email@host:" 'user) "user@email"))
          (should (string-equal
@@ -1465,11 +1476,10 @@ Also see `ignore'."
                   (file-remote-p "/[method/user@email@host]")
                   (format "/[%s/%s@%s]" "method" "user@email" "host")))
          (should (string-equal
-                  (file-remote-p
-                   "/[method/user@email@host]" 'method) "method"))
+                  (file-remote-p "/[method/user@email@host]" 'method) 
"method"))
          (should (string-equal
-                  (file-remote-p
-                   "/[method/user@email@host]" 'user) "user@email"))
+                  (file-remote-p "/[method/user@email@host]" 'user)
+                  "user@email"))
          (should (string-equal
                   (file-remote-p "/[method/user@email@host]" 'host) "host"))
          (should (string-equal
@@ -1496,11 +1506,10 @@ Also see `ignore'."
                   (file-remote-p "/[/user@host#1234]")
                   (format "/[%s/%s@%s]" "default-method" "user" "host#1234")))
          (should (string-equal
-                  (file-remote-p
-                   "/[/user@host#1234]" 'method) "default-method"))
+                  (file-remote-p "/[/user@host#1234]" 'method)
+                  "default-method"))
          (should (string-equal
-                  (file-remote-p
-                   "/[/user@host#1234]" 'user) "user"))
+                  (file-remote-p "/[/user@host#1234]" 'user) "user"))
          (should (string-equal
                   (file-remote-p "/[/user@host#1234]" 'host) "host#1234"))
          (should (string-equal
@@ -1526,11 +1535,10 @@ Also see `ignore'."
                   (file-remote-p "/[-/user@host#1234]")
                   (format "/[%s/%s@%s]" "default-method" "user" "host#1234")))
          (should (string-equal
-                  (file-remote-p
-                   "/[-/user@host#1234]" 'method) "default-method"))
+                  (file-remote-p "/[-/user@host#1234]" 'method)
+                  "default-method"))
          (should (string-equal
-                  (file-remote-p
-                   "/[-/user@host#1234]" 'user) "user"))
+                  (file-remote-p "/[-/user@host#1234]" 'user) "user"))
          (should (string-equal
                   (file-remote-p "/[-/user@host#1234]" 'host) "host#1234"))
          (should (string-equal
@@ -1560,8 +1568,7 @@ Also see `ignore'."
          (should (string-equal
                   (file-remote-p "/[method/user@host#1234]" 'user) "user"))
          (should (string-equal
-                  (file-remote-p
-                   "/[method/user@host#1234]" 'host) "host#1234"))
+                  (file-remote-p "/[method/user@host#1234]" 'host) 
"host#1234"))
          (should (string-equal
                   (file-remote-p "/[method/user@host#1234]" 'localname) ""))
          (should (string-equal
@@ -1586,8 +1593,7 @@ Also see `ignore'."
                   (file-remote-p "/[/user@1.2.3.4]")
                   (format "/[%s/%s@%s]" "default-method" "user" "1.2.3.4")))
          (should (string-equal
-                  (file-remote-p
-                   "/[/user@1.2.3.4]" 'method) "default-method"))
+                  (file-remote-p "/[/user@1.2.3.4]" 'method) "default-method"))
          (should (string-equal
                   (file-remote-p "/[/user@1.2.3.4]" 'user) "user"))
          (should (string-equal
@@ -1615,8 +1621,7 @@ Also see `ignore'."
                   (file-remote-p "/[-/user@1.2.3.4]")
                   (format "/[%s/%s@%s]" "default-method" "user" "1.2.3.4")))
          (should (string-equal
-                  (file-remote-p
-                   "/[-/user@1.2.3.4]" 'method) "default-method"))
+                  (file-remote-p "/[-/user@1.2.3.4]" 'method) 
"default-method"))
          (should (string-equal
                   (file-remote-p "/[-/user@1.2.3.4]" 'user) "user"))
          (should (string-equal
@@ -2016,17 +2021,7 @@ Also see `ignore'."
      :type 'user-error)
     (should-error
      (expand-file-name "/method:user1@host1|ssh:user2@host2:/path/to/file")
-     :type 'user-error))
-
-  ;; Samba does not support file names with periods followed by
-  ;; spaces, and trailing periods or spaces.
-  (when (tramp--test-smb-p)
-    (dolist (file '("foo." "foo. bar" "foo "))
-      (should-error
-       (tramp-smb-get-localname
-       (tramp-dissect-file-name
-        (expand-file-name file ert-remote-temporary-file-directory)))
-       :type 'file-error))))
+     :type 'user-error)))
 
 (ert-deftest tramp-test04-substitute-in-file-name ()
   "Check `substitute-in-file-name'."
@@ -2300,9 +2295,9 @@ This checks also `file-name-as-directory', 
`file-name-directory',
 
     ;; Check `directory-abbrev-alist' abbreviation.
     (let ((directory-abbrev-alist
-           `((,(concat "\\`" (regexp-quote home-dir) "/foo")
+           `((,(rx bos (literal home-dir) "/foo")
               . ,(concat home-dir "/f"))
-             (,(concat "\\`" (regexp-quote remote-host) "/nowhere")
+             (,(rx bos (literal remote-host) "/nowhere")
               . ,(concat remote-host "/nw")))))
       (should (equal (abbreviate-file-name (concat home-dir "/foo/bar"))
                      (concat remote-host-nohop "~/f/bar")))
@@ -2334,8 +2329,8 @@ This checks also `file-name-as-directory', 
`file-name-directory',
       (should-not (file-exists-p tmp-name))
 
       ;; Trashing files doesn't work when `system-move-file-to-trash'
-      ;; is defined (on MS Windows and macOS), and for crypted remote
-      ;; files.
+      ;; is defined (on MS-Windows and macOS), and for encrypted
+      ;; remote files.
       (unless (or (fboundp 'system-move-file-to-trash) (tramp--test-crypt-p))
        (let ((trash-directory (tramp--test-make-temp-name 'local quoted))
              (delete-by-moving-to-trash t))
@@ -2482,6 +2477,19 @@ This checks also `file-name-as-directory', 
`file-name-directory',
              (insert-file-contents tmp-name)
              (should (string-equal (buffer-string) "foo")))
 
+           ;; Write empty string.  Used for creation of temporary files.
+           ;; Since Emacs 27.1.
+           (when (fboundp 'make-empty-file)
+             (with-no-warnings
+               (should-error
+                (make-empty-file tmp-name)
+                :type 'file-already-exists)
+               (delete-file tmp-name)
+               (make-empty-file tmp-name)
+               (with-temp-buffer
+                 (insert-file-contents tmp-name)
+                 (should (string-equal (buffer-string) "")))))
+
            ;; Write partly.
            (with-temp-buffer
              (insert "123456789")
@@ -2502,8 +2510,8 @@ This checks also `file-name-as-directory', 
`file-name-directory',
                     (string-match-p
                      (if (and (null noninteractive)
                               (or (eq visit t) (null visit) (stringp visit)))
-                         (format "^Wrote %s\n\\'" (regexp-quote tmp-name))
-                       "^\\'")
+                         (rx bol "Wrote " (literal tmp-name) "\n" eos)
+                       (rx bos))
                      tramp--test-messages))))))
 
            ;; We do not test lockname here.  See
@@ -2910,7 +2918,7 @@ This tests also `file-directory-p' and 
`file-accessible-directory-p'."
 
       ;; Trashing directories works only since Emacs 27.1.  It doesn't
       ;; work when `system-move-file-to-trash' is defined (on MS
-      ;; Windows and macOS), for crypted remote directories and for
+      ;; Windows and macOS), for encrypted remote directories and for
       ;; ange-ftp.
       (when (and (not (fboundp 'system-move-file-to-trash))
                 (not (tramp--test-crypt-p)) (not (tramp--test-ftp-p))
@@ -3183,8 +3191,8 @@ This tests also `file-directory-p' and 
`file-accessible-directory-p'."
   ;; (this is performed by `dired').  If FULL is nil, it shows just
   ;; one file.  So we refrain from testing.
   (skip-unless (not (tramp--test-ange-ftp-p)))
-  ;; `insert-directory' of crypted remote directories works only since
-  ;; Emacs 27.1.
+  ;; `insert-directory' of encrypted remote directories works only
+  ;; since Emacs 27.1.
   (skip-unless (or (not (tramp--test-crypt-p)) (tramp--test-emacs27-p)))
 
   (dolist (quoted (if (tramp--test-expensive-test-p) '(nil t) '(nil)))
@@ -3203,37 +3211,40 @@ This tests also `file-directory-p' and 
`file-accessible-directory-p'."
            (with-temp-buffer
              (insert-directory tmp-name1 nil)
              (goto-char (point-min))
-             (should (looking-at-p (regexp-quote tmp-name1))))
+             (should (looking-at-p (rx (literal tmp-name1)))))
            (with-temp-buffer
              (insert-directory (file-name-as-directory tmp-name1) nil)
              (goto-char (point-min))
              (should
                (looking-at-p
-                (regexp-quote (file-name-as-directory tmp-name1)))))
+                (rx (literal (file-name-as-directory tmp-name1))))))
            (with-temp-buffer
              (insert-directory tmp-name1 "-al")
              (goto-char (point-min))
              (should
-              (looking-at-p (format "^.+ %s$" (regexp-quote tmp-name1)))))
+              (looking-at-p (rx bol (+ nonl) " " (literal tmp-name1) eol))))
            (with-temp-buffer
              (insert-directory (file-name-as-directory tmp-name1) "-al")
              (goto-char (point-min))
              (should
-              (looking-at-p (format "^.+ %s/$" (regexp-quote tmp-name1)))))
+              (looking-at-p
+               (rx bol (+ nonl) " " (literal tmp-name1) "/" eol))))
            (with-temp-buffer
              (insert-directory
               (file-name-as-directory tmp-name1) "-al" nil 'full-directory-p)
              (goto-char (point-min))
              (should
               (looking-at-p
-               (concat
-                ;; There might be a summary line.
-                "\\(total.+[[:digit:]]+ ?[kKMGTPEZY]?i?B?\n\\)?"
-                ;; We don't know in which order ".", ".." and "foo" appear.
-                (format
-                 "\\(.+ %s\\( ->.+\\)?\n\\)\\{%d\\}"
-                 (regexp-opt (directory-files tmp-name1))
-                 (length (directory-files tmp-name1)))))))
+               (rx-to-string
+                `(:
+                  ;; There might be a summary line.
+                  (? "total" (+ nonl) (+ digit) (? " ")
+                     (? (any "EGKMPTYZk")) (? "i") (? "B") "\n")
+                  ;; We don't know in which order ".", ".." and "foo" appear.
+                  (= ,(length (directory-files tmp-name1))
+                     (+ nonl) " "
+                     (regexp ,(regexp-opt (directory-files tmp-name1)))
+                     (? " ->" (+ nonl)) "\n"))))))
 
            ;; Check error cases.
            (when (and (tramp--test-supports-set-file-modes-p)
@@ -3261,7 +3272,8 @@ This tests also `file-directory-p' and 
`file-accessible-directory-p'."
 (ert-deftest tramp-test17-dired-with-wildcards ()
   "Check `dired' with wildcards."
   ;; `separate' syntax and IPv6 host name syntax do not work.
-  (skip-unless (not (string-match-p "\\[" 
ert-remote-temporary-file-directory)))
+  (skip-unless
+   (not (string-match-p (rx "[") ert-remote-temporary-file-directory)))
   (skip-unless (tramp--test-enabled))
   (skip-unless (tramp--test-sh-p))
   (skip-unless (not (tramp--test-rsync-p)))
@@ -3300,15 +3312,15 @@ This tests also `file-directory-p' and 
`file-accessible-directory-p'."
              (goto-char (point-min))
              (should
               (re-search-forward
-               (regexp-quote
-                (file-relative-name
-                 tmp-name1 ert-remote-temporary-file-directory))))
+               (rx (literal
+                    (file-relative-name
+                     tmp-name1 ert-remote-temporary-file-directory)))))
              (goto-char (point-min))
              (should
               (re-search-forward
-               (regexp-quote
-                (file-relative-name
-                 tmp-name2 ert-remote-temporary-file-directory)))))
+               (rx (literal
+                    (file-relative-name
+                     tmp-name2 ert-remote-temporary-file-directory))))))
            (kill-buffer buffer)
 
            ;; Check for expanded directory and file names.
@@ -3320,16 +3332,16 @@ This tests also `file-directory-p' and 
`file-accessible-directory-p'."
              (goto-char (point-min))
              (should
               (re-search-forward
-               (regexp-quote
-                (file-relative-name
-                 tmp-name3 ert-remote-temporary-file-directory))))
+               (rx (literal
+                    (file-relative-name
+                     tmp-name3 ert-remote-temporary-file-directory)))))
              (goto-char (point-min))
              (should
               (re-search-forward
-               (regexp-quote
-                (file-relative-name
-                 tmp-name4
-                 ert-remote-temporary-file-directory)))))
+               (rx (literal
+                    (file-relative-name
+                     tmp-name4
+                     ert-remote-temporary-file-directory))))))
            (kill-buffer buffer)
 
            ;; Check for special characters.
@@ -3348,16 +3360,16 @@ This tests also `file-directory-p' and 
`file-accessible-directory-p'."
              (goto-char (point-min))
              (should
               (re-search-forward
-               (regexp-quote
-                (file-relative-name
-                 tmp-name3 ert-remote-temporary-file-directory))))
+               (rx (literal
+                    (file-relative-name
+                     tmp-name3 ert-remote-temporary-file-directory)))))
              (goto-char (point-min))
              (should
               (re-search-forward
-               (regexp-quote
-                (file-relative-name
-                 tmp-name4
-                 ert-remote-temporary-file-directory)))))
+               (rx (literal
+                    (file-relative-name
+                     tmp-name4
+                     ert-remote-temporary-file-directory))))))
            (kill-buffer buffer))
 
        ;; Cleanup.
@@ -3407,7 +3419,7 @@ This tests also `file-directory-p' and 
`file-accessible-directory-p'."
               (string-equal
                (dired-get-filename 'no-dir 'no-error)
                (file-name-nondirectory tmp-name2)))
-             (should-not (re-search-forward "dired" nil t))
+             (should-not (search-forward "dired" nil t))
              ;; The copied file has been inserted the line before.
              (forward-line -1)
              (should
@@ -3568,6 +3580,87 @@ This tests also `access-file', `file-readable-p',
        (ignore-errors (delete-file tmp-name1))
        (ignore-errors (delete-file tmp-name2))))))
 
+(defmacro tramp--test-deftest-with-stat (test)
+  "Define ert `TEST-with-stat'."
+  (declare (indent 1))
+  `(ert-deftest ,(intern (concat (symbol-name test) "-with-stat")) ()
+     ;; This is the docstring.  However, it must be expanded to a
+     ;; string inside the macro.  No idea.
+     ;; (concat (ert-test-documentation (get ',test 'ert--test))
+     ;;             "\nUse the \"stat\" command.")
+     :tags '(:expensive-test)
+     (skip-unless (tramp--test-enabled))
+     (skip-unless (tramp--test-sh-p))
+     (skip-unless (tramp-get-remote-stat tramp-test-vec))
+     (if-let ((default-directory ert-remote-temporary-file-directory)
+             (ert-test (ert-get-test ',test))
+             (result (ert-test-most-recent-result ert-test))
+             (tramp-connection-properties
+              (cons '(nil "perl" nil)
+                    tramp-connection-properties)))
+        (progn
+          (skip-unless (< (ert-test-result-duration result) 300))
+          (funcall (ert-test-body ert-test)))
+       (ert-skip (format "Test `%s' must run before" ',test)))))
+
+(defmacro tramp--test-deftest-with-perl (test)
+  "Define ert `TEST-with-perl'."
+  (declare (indent 1))
+  `(ert-deftest ,(intern (concat (symbol-name test) "-with-perl")) ()
+     ;; This is the docstring.  However, it must be expanded to a
+     ;; string inside the macro.  No idea.
+     ;; (concat (ert-test-documentation (get ',test 'ert--test))
+     ;;             "\nUse the \"perl\" command.")
+     :tags '(:expensive-test)
+     (skip-unless (tramp--test-enabled))
+     (skip-unless (tramp--test-sh-p))
+     (skip-unless (tramp-get-remote-perl tramp-test-vec))
+     (if-let ((default-directory ert-remote-temporary-file-directory)
+             (ert-test (ert-get-test ',test))
+             (result (ert-test-most-recent-result ert-test))
+             (tramp-connection-properties
+              (append
+               '((nil "stat" nil)
+                 ;; See `tramp-sh-handle-file-truename'.
+                 (nil "readlink" nil))
+               tramp-connection-properties)))
+        (progn
+          (skip-unless (< (ert-test-result-duration result) 300))
+          (funcall (ert-test-body ert-test)))
+       (ert-skip (format "Test `%s' must run before" ',test)))))
+
+(defmacro tramp--test-deftest-with-ls (test)
+  "Define ert `TEST-with-ls'."
+  (declare (indent 1))
+  `(ert-deftest ,(intern (concat (symbol-name test) "-with-ls")) ()
+     ;; This is the docstring.  However, it must be expanded to a
+     ;; string inside the macro.  No idea.
+     ;; (concat (ert-test-documentation (get ',test 'ert--test))
+     ;;             "\nUse the \"ls\" command.")
+     :tags '(:expensive-test)
+     (skip-unless (tramp--test-enabled))
+     (skip-unless (tramp--test-sh-p))
+     (if-let ((default-directory ert-remote-temporary-file-directory)
+             (ert-test (ert-get-test ',test))
+             (result (ert-test-most-recent-result ert-test))
+             (tramp-connection-properties
+              (append
+               '((nil "perl" nil)
+                 (nil "stat" nil)
+                 ;; See `tramp-sh-handle-file-truename'.
+                 (nil "readlink" nil))
+               tramp-connection-properties)))
+        (progn
+          (skip-unless (< (ert-test-result-duration result) 300))
+          (funcall (ert-test-body ert-test)))
+       (ert-skip (format "Test `%s' must run before" ',test)))))
+
+(tramp--test-deftest-with-stat tramp-test18-file-attributes)
+
+(tramp--test-deftest-with-perl tramp-test18-file-attributes)
+
+(tramp--test-deftest-with-ls tramp-test18-file-attributes)
+
 (defvar tramp--test-start-time nil
   "Keep the start time of the current test, a float number.")
 
@@ -3672,19 +3765,26 @@ They might differ only in time attributes or directory 
size."
               (tramp--test-file-attributes-equal-p
                (file-attributes (car elt)) (cdr elt))))
 
-           (setq attr (directory-files-and-attributes tmp-name2 nil "\\`b"))
+           (setq attr (directory-files-and-attributes
+                       tmp-name2 nil (rx bos "b")))
            (should (equal (mapcar #'car attr) '("bar" "boz")))
 
            ;; Check the COUNT arg.  It exists since Emacs 28.
            (when (tramp--test-emacs28-p)
              (with-no-warnings
                (setq attr (directory-files-and-attributes
-                           tmp-name2 nil "\\`b" nil nil 1))
+                           tmp-name2 nil (rx bos "b") nil nil 1))
                (should (equal (mapcar #'car attr) '("bar"))))))
 
        ;; Cleanup.
        (ignore-errors (delete-directory tmp-name1 'recursive))))))
 
+(tramp--test-deftest-with-stat tramp-test19-directory-files-and-attributes)
+
+(tramp--test-deftest-with-perl tramp-test19-directory-files-and-attributes)
+
+(tramp--test-deftest-with-ls tramp-test19-directory-files-and-attributes)
+
 (ert-deftest tramp-test20-file-modes ()
   "Check `file-modes'.
 This tests also `file-executable-p', `file-writable-p' and `set-file-modes'."
@@ -3716,7 +3816,11 @@ This tests also `file-executable-p', `file-writable-p' 
and `set-file-modes'."
            (when (tramp--test-emacs28-p)
              (with-no-warnings
                (set-file-modes tmp-name1 #o222 'nofollow)
-               (should (= (file-modes tmp-name1 'nofollow) #o222)))))
+               (should (= (file-modes tmp-name1 'nofollow) #o222))))
+           ;; Setting the mode for not existing files shall fail.
+           (should-error
+            (set-file-modes tmp-name2 #o777)
+            :type 'file-missing))
 
        ;; Cleanup.
        (ignore-errors (delete-file tmp-name1)))
@@ -3775,8 +3879,8 @@ This tests also `file-executable-p', `file-writable-p' 
and `set-file-modes'."
   `(condition-case err
        (progn ,@body)
      (file-error
-      (unless (string-match-p "^error with add-name-to-file"
-                             (error-message-string err))
+      (unless (string-prefix-p "error with add-name-to-file"
+                              (error-message-string err))
        (signal (car err) (cdr err))))))
 
 (ert-deftest tramp-test21-file-links ()
@@ -4012,9 +4116,9 @@ This tests also `make-symbolic-link', `file-truename' and 
`add-name-to-file'."
                (setq tmp-name3 (concat (file-remote-p tmp-name3) tmp-name2)))))
 
        ;; Cleanup.
-       (ignore-errors
-         (delete-file tmp-name3)
-         (delete-directory tmp-name1 'recursive)))
+       (ignore-errors (delete-file tmp-name2))
+       (ignore-errors (delete-file tmp-name3))
+       (ignore-errors (delete-directory tmp-name1 'recursive)))
 
       ;; Detect cyclic symbolic links.
       (unwind-protect
@@ -4068,7 +4172,8 @@ This tests also `make-symbolic-link', `file-truename' and 
`add-name-to-file'."
                            (file-attributes tmp-name1))))
            ;; Skip the test, if the remote handler is not able to set
            ;; the correct time.
-           (skip-unless (set-file-times tmp-name1 (seconds-to-time 1)))
+           ;; Some remote machines cannot resolve seconds.  So we use a minute.
+           (skip-unless (set-file-times tmp-name1 (seconds-to-time 60)))
            ;; Dumb remote shells without perl(1) or stat(1) are not
            ;; able to return the date correctly.  They say "don't know".
            (unless (tramp-compat-time-equal-p
@@ -4078,7 +4183,11 @@ This tests also `make-symbolic-link', `file-truename' 
and `add-name-to-file'."
              (should
               (tramp-compat-time-equal-p
                 (file-attribute-modification-time (file-attributes tmp-name1))
-               (seconds-to-time 1)))
+               (seconds-to-time 60)))
+             ;; Setting the time for not existing files shall fail.
+             (should-error
+              (set-file-times tmp-name2)
+              :type 'file-missing)
              (write-region "bla" nil tmp-name2)
              (should (file-exists-p tmp-name2))
              (should (file-newer-than-file-p tmp-name2 tmp-name1))
@@ -4089,12 +4198,12 @@ This tests also `make-symbolic-link', `file-truename' 
and `add-name-to-file'."
              ;; regular files, there shouldn't be a difference.
              (when (tramp--test-emacs28-p)
                (with-no-warnings
-                 (set-file-times tmp-name1 (seconds-to-time 1) 'nofollow)
+                 (set-file-times tmp-name1 (seconds-to-time 60) 'nofollow)
                  (should
                   (tramp-compat-time-equal-p
                     (file-attribute-modification-time
                     (file-attributes tmp-name1))
-                   (seconds-to-time 1)))))))
+                   (seconds-to-time 60)))))))
 
        ;; Cleanup.
        (ignore-errors
@@ -4501,7 +4610,10 @@ This tests also `make-symbolic-link', `file-truename' 
and `add-name-to-file'."
 
 (defun tramp--test-shell-file-name ()
   "Return default remote shell."
-  (if (tramp--test-adb-p) "/system/bin/sh" "/bin/sh"))
+  (if (file-exists-p
+       (concat
+       (file-remote-p ert-remote-temporary-file-directory) "/system/bin/sh"))
+      "/system/bin/sh" "/bin/sh"))
 
 (ert-deftest tramp-test28-process-file ()
   "Check `process-file'."
@@ -4541,7 +4653,7 @@ This tests also `make-symbolic-link', `file-truename' and 
`add-name-to-file'."
              (let ((process-file-return-signal-string t))
                (should
                 (string-match-p
-                 "Interrupt\\|Signal 2"
+                 (rx (| "Interrupt" "Signal 2"))
                  (process-file
                   (tramp--test-shell-file-name)
                   nil nil nil "-c" "kill -2 $$")))))
@@ -4621,7 +4733,8 @@ This tests also `make-symbolic-link', `file-truename' and 
`add-name-to-file'."
                (insert-file-contents tmp-name)
                (should
                 (string-match-p
-                 "cat:.* No such file or directory" (buffer-string)))
+                 (rx "cat:" (* nonl) " No such file or directory")
+                 (buffer-string)))
                (should-not (get-buffer-window (current-buffer) t))
                (delete-file tmp-name))))
 
@@ -4771,8 +4884,8 @@ This tests also `make-symbolic-link', `file-truename' and 
`add-name-to-file'."
                       ;; On macOS, there is always newline conversion.
                      ;; "telnet" converts \r to <CR><NUL> if `crlf'
                      ;; flag is FALSE.  See telnet(1) man page.
-                     "66\n6F\n6F\n0D\\(\n00\\)?\n0A\n"
-                   "66\n6F\n6F\n0A\\(\n00\\)?\n0A\n")
+                     (rx "66\n6F\n6F\n0D" (? "\n00") "\n0A\n")
+                   (rx "66\n6F\n6F\n0A" (? "\n00") "\n0A\n"))
                  (buffer-string))))
 
            ;; Cleanup.
@@ -4798,8 +4911,7 @@ This tests also `make-symbolic-link', `file-truename' and 
`add-name-to-file'."
        ;; Cleanup.
        (ignore-errors (delete-process proc))))))
 
-(defmacro tramp--test--deftest-direct-async-process
-    (test docstring &optional unstable)
+(defmacro tramp--test-deftest-direct-async-process (test &optional unstable)
   "Define ert test `TEST-direct-async' for direct async processes.
 If UNSTABLE is non-nil, the test is tagged as `:unstable'."
   (declare (indent 1))
@@ -4808,7 +4920,10 @@ If UNSTABLE is non-nil, the test is tagged as 
`:unstable'."
   (when (let ((file-name-handler-alist '(("" . (lambda (&rest _) t)))))
          (ignore-errors (make-process :file-handler t)))
     `(ert-deftest ,(intern (concat (symbol-name test) "-direct-async")) ()
-       ,docstring
+       ;; This is the docstring.  However, it must be expanded to a
+       ;; string inside the macro.  No idea.
+       ;; (concat (ert-test-documentation (get ',test 'ert--test))
+       ;;         "\nUse direct async process.")
        :tags (append '(:expensive-test :tramp-asynchronous-processes)
                     (and ,unstable '(:unstable)))
        (skip-unless (tramp--test-enabled))
@@ -4828,8 +4943,7 @@ If UNSTABLE is non-nil, the test is tagged as 
`:unstable'."
           (file-truename ert-remote-temporary-file-directory)
           (funcall (ert-test-body ert-test)))))))
 
-(tramp--test--deftest-direct-async-process tramp-test29-start-file-process
-  "Check direct async `start-file-process'.")
+(tramp--test-deftest-direct-async-process tramp-test29-start-file-process)
 
 (ert-deftest tramp-test30-make-process ()
   "Check `make-process'."
@@ -4968,7 +5082,9 @@ If UNSTABLE is non-nil, the test is tagged as 
`:unstable'."
            (with-timeout (10 (tramp--test-timeout-handler))
              (while (accept-process-output proc 0 nil t)))
            ;; On some MS Windows systems, it returns "unknown signal".
-           (should (string-match-p "unknown signal\\|killed" (buffer-string))))
+           (should
+            (string-match-p
+             (rx (| "unknown signal" "killed")) (buffer-string))))
 
        ;; Cleanup.
        (ignore-errors (delete-process proc)))
@@ -5001,7 +5117,8 @@ If UNSTABLE is non-nil, the test is tagged as 
`:unstable'."
                  (delete-process proc)
                  (should
                   (string-match-p
-                   "cat:.* No such file or directory" (buffer-string)))))
+                   (rx "cat:" (* nonl) " No such file or directory")
+                   (buffer-string)))))
 
            ;; Cleanup.
            (ignore-errors (delete-process proc))
@@ -5028,7 +5145,8 @@ If UNSTABLE is non-nil, the test is tagged as 
`:unstable'."
                (insert-file-contents tmp-name)
                (should
                 (string-match-p
-                 "cat:.* No such file or directory" (buffer-string)))))
+                 (rx "cat:" (* nonl) " No such file or directory")
+                 (buffer-string)))))
 
          ;; Cleanup.
          (ignore-errors (delete-process proc))
@@ -5079,15 +5197,14 @@ If UNSTABLE is non-nil, the test is tagged as 
`:unstable'."
                         ;; On macOS, there is always newline conversion.
                        ;; "telnet" converts \r to <CR><NUL> if `crlf'
                        ;; flag is FALSE.  See telnet(1) man page.
-                       "66\n6F\n6F\n0D\\(\n00\\)?\n0A\n"
-                     "66\n6F\n6F\n0A\\(\n00\\)?\n0A\n")
+                       (rx "66\n6F\n6F\n0D" (? "\n00") "\n0A\n")
+                     (rx "66\n6F\n6F\n0A" (? "\n00") "\n0A\n"))
                    (buffer-string))))
 
              ;; Cleanup.
              (ignore-errors (delete-process proc)))))))))
 
-(tramp--test--deftest-direct-async-process tramp-test30-make-process
-  "Check direct async `make-process'.")
+(tramp--test-deftest-direct-async-process tramp-test30-make-process)
 
 (ert-deftest tramp-test31-interrupt-process ()
   "Check `interrupt-process'."
@@ -5373,8 +5490,7 @@ INPUT, if non-nil, is a string sent to the process."
       (when (natnump cols)
        (should (= cols async-shell-command-width))))))
 
-(tramp--test--deftest-direct-async-process tramp-test32-shell-command
-  "Check direct async `shell-command'." 'unstable)
+(tramp--test-deftest-direct-async-process tramp-test32-shell-command 'unstable)
 
 ;; This test is inspired by Bug#39067.
 (ert-deftest tramp-test32-shell-command-dont-erase-buffer ()
@@ -5561,7 +5677,7 @@ INPUT, if non-nil, is a string sent to the process."
        ;; Variable is set.
        (should
         (string-match-p
-         (regexp-quote envvar)
+         (rx (literal envvar))
          (funcall this-shell-command-to-string "set"))))
 
       (unless (tramp-direct-async-process-p)
@@ -5588,16 +5704,14 @@ INPUT, if non-nil, is a string sent to the process."
            ;; Variable is unset.
            (should-not
             (string-match-p
-             (regexp-quote envvar)
+             (rx (literal envvar))
              ;; We must remove PS1, the output is truncated otherwise.
              ;; We must suppress "_=VAR...".
              (funcall
               this-shell-command-to-string
               "printenv | grep -v PS1 | grep -v _=")))))))))
 
-(tramp--test--deftest-direct-async-process tramp-test33-environment-variables
-  "Check that remote processes set / unset environment variables properly.
-Use direct async.")
+(tramp--test-deftest-direct-async-process tramp-test33-environment-variables)
 
 ;; This test is inspired by Bug#27009.
 (ert-deftest tramp-test33-environment-variables-and-port-numbers ()
@@ -5742,7 +5856,7 @@ Use direct async.")
            (with-timeout (10)
              (while (accept-process-output
                      (get-buffer-process (current-buffer)) nil nil t)))
-           (should (string-match-p "^foo$" (buffer-string)))))
+           (should (string-match-p (rx bol "foo" eol) (buffer-string)))))
 
       ;; Cleanup.
       (put 'explicit-shell-file-name 'permanent-local nil)
@@ -6260,7 +6374,7 @@ Use direct async.")
            ;; When `lock-file-name-transforms' is set, another lock
            ;; file is used.
            (tramp-cleanup-connection tramp-test-vec 'keep-debug 'keep-password)
-           (let ((lock-file-name-transforms `((".*" ,tmp-name2))))
+           (let ((lock-file-name-transforms `((,(rx (* nonl)) ,tmp-name2))))
              (should
               (string-equal
                (with-no-warnings (make-lock-file-name tmp-name1))
@@ -6386,10 +6500,12 @@ Use direct async.")
                      (insert "bar")
                      (when create-lockfiles
                        (should (string-match-p
-                                (format
-                                 "^%s changed on disk; really edit the 
buffer\\?"
-                                 (if (tramp--test-crypt-p)
-                                     ".+" (file-name-nondirectory tmp-name)))
+                                (rx-to-string
+                                 `(: bol
+                                     ,(if (tramp--test-crypt-p)
+                                          '(+ nonl)
+                                        (file-name-nondirectory tmp-name))
+                                     " changed on disk; really edit the 
buffer?"))
                                 captured-messages))
                        (should (file-locked-p tmp-name)))))
 
@@ -6480,10 +6596,10 @@ This is used in tests which we don't want to tag
                          :body nil :tags '(:tramp-asynchronous-processes))))
    ;; tramp-adb.el cannot apply multi-byte commands.
    (not (and (tramp--test-adb-p)
-            (string-match-p "[[:multibyte:]]" default-directory)))))
+            (string-match-p (rx multibyte) default-directory)))))
 
 (defun tramp--test-crypt-p ()
-  "Check, whether the remote directory is crypted."
+  "Check, whether the remote directory is encrypted."
   (tramp-crypt-file-name-p ert-remote-temporary-file-directory))
 
 (defun tramp--test-docker-p ()
@@ -6505,8 +6621,8 @@ completely."
   "Check, whether an FTP-like method is used.
 This does not support globbing characters in file names (yet)."
   ;; Globbing characters are ??, ?* and ?\[.
-  (string-match-p
-   "ftp$" (file-remote-p ert-remote-temporary-file-directory 'method)))
+  (string-suffix-p
+   "ftp" (file-remote-p ert-remote-temporary-file-directory 'method)))
 
 (defun tramp--test-fuse-p ()
   "Check, whether an FUSE file system isused."
@@ -6529,7 +6645,7 @@ If optional METHOD is given, it is checked first."
 Several special characters do not work properly there."
   ;; We must refill the cache.  `file-truename' does it.
   (file-truename ert-remote-temporary-file-directory)
-  (ignore-errors (tramp-check-remote-uname tramp-test-vec "^HP-UX")))
+  (ignore-errors (tramp-check-remote-uname tramp-test-vec (rx bol "HP-UX"))))
 
 (defun tramp--test-ksh-p ()
   "Check, whether the remote shell is ksh.
@@ -6537,8 +6653,9 @@ ksh93 makes some strange conversions of non-latin 
characters into
 a $'' syntax."
   ;; We must refill the cache.  `file-truename' does it.
   (file-truename ert-remote-temporary-file-directory)
-  (string-match-p
-   "ksh$" (tramp-get-connection-property tramp-test-vec "remote-shell" "")))
+  (string-suffix-p
+   "ksh"
+   (tramp-get-connection-property tramp-test-vec "remote-shell" "")))
 
 (defun tramp--test-macos-p ()
   "Check, whether the remote host runs macOS."
@@ -6580,13 +6697,13 @@ Additionally, ls does not support \"--dired\"."
         ;; This fails for tramp-crypt.el, so we ignore that.
         (ignore-errors
           (insert-directory ert-remote-temporary-file-directory "-al"))
-        (not (tramp-get-connection-property tramp-test-vec "ls--dired" nil)))))
+        (not (tramp-get-connection-property tramp-test-vec "ls--dired")))))
 
 (defun tramp--test-share-p ()
   "Check, whether the method needs a share."
   (and (tramp--test-gvfs-p)
        (string-match-p
-       "^\\(afp\\|davs?\\|smb\\)$"
+       (rx bol (or "afp" (: "dav" (opt "s")) "smb") eol)
        (file-remote-p ert-remote-temporary-file-directory 'method))))
 
 (defun tramp--test-sshfs-p ()
@@ -6638,7 +6755,7 @@ This requires restrictions of file name syntax."
       ;; Not all tramp-gvfs.el methods support changing the file mode.
       (and
        (tramp--test-gvfs-p)
-       (string-match-p
+       (string-suffix-p
        "ftp" (file-remote-p ert-remote-temporary-file-directory 'method)))))
 
 (defun tramp--test-check-files (&rest files)
@@ -6787,14 +6904,14 @@ This requires restrictions of file name syntax."
                    (should
                     (string-equal
                      (caar (directory-files-and-attributes
-                            file1 nil (regexp-quote elt1)))
+                            file1 nil (rx (literal elt1))))
                      elt1))
                    (should
                     (string-equal
                      (funcall
                       (if quoted #'tramp-compat-file-name-quote #'identity)
                       (cadr (car (directory-files-and-attributes
-                                  file1 nil (regexp-quote elt1)))))
+                                  file1 nil (rx (literal elt1))))))
                      (file-remote-p (file-truename file2) 'localname)))
                    (delete-file file3)
                    (should-not (file-exists-p file3))))
@@ -6849,18 +6966,22 @@ This requires restrictions of file name syntax."
                    (goto-char (point-min))
                    (should
                     (re-search-forward
-                     (format
-                      "^%s=%s$"
-                      (regexp-quote envvar)
-                      (regexp-quote (getenv envvar))))))))))
+                     (rx bol (literal envvar)
+                         "=" (literal (getenv envvar)) eol))))))))
 
        ;; Cleanup.
        (ignore-errors (kill-buffer buffer))
        (ignore-errors (delete-directory tmp-name1 'recursive))
        (ignore-errors (delete-directory tmp-name2 'recursive))))))
 
-(defun tramp--test-special-characters ()
-  "Perform the test in `tramp-test41-special-characters*'."
+;; These tests are inspired by Bug#17238.
+(ert-deftest tramp-test41-special-characters ()
+  "Check special characters in file names."
+  (skip-unless (tramp--test-enabled))
+  (skip-unless (not (getenv "EMACS_HYDRA_CI"))) ; SLOW ~ 245s
+  (skip-unless (not (tramp--test-rsync-p)))
+  (skip-unless (not (tramp--test-rclone-p)))
+
   ;; Newlines, slashes and backslashes in file names are not
   ;; supported.  So we don't test.  And we don't test the tab
   ;; character on Windows or Cygwin, because the backslash is
@@ -6917,80 +7038,24 @@ This requires restrictions of file name syntax."
           (if (tramp--test-expensive-test-p)
               files (list (mapconcat #'identity files ""))))))
 
-;; These tests are inspired by Bug#17238.
-(ert-deftest tramp-test41-special-characters ()
-  "Check special characters in file names."
-  (skip-unless (not (getenv "EMACS_HYDRA_CI"))) ; SLOW ~ 245s
-  (skip-unless (tramp--test-enabled))
-  (skip-unless (not (tramp--test-rsync-p)))
-  (skip-unless (not (tramp--test-rclone-p)))
+(tramp--test-deftest-with-stat tramp-test41-special-characters)
 
-  (tramp--test-special-characters))
+(tramp--test-deftest-with-perl tramp-test41-special-characters)
 
-(ert-deftest tramp-test41-special-characters-with-stat ()
-  "Check special characters in file names.
-Use the \"stat\" command."
-  :tags '(:expensive-test)
-  (skip-unless (not (getenv "EMACS_HYDRA_CI"))) ; SLOW ~ 287s
-  (skip-unless (tramp--test-enabled))
-  (skip-unless (tramp--test-sh-p))
-  (skip-unless (not (tramp--test-rsync-p)))
-  ;; We cannot use `tramp-test-vec', because this fails during compilation.
-  (with-parsed-tramp-file-name ert-remote-temporary-file-directory nil
-    (skip-unless (tramp-get-remote-stat v)))
-
-  (let ((tramp-connection-properties
-        (append
-         `((,(regexp-quote (file-remote-p ert-remote-temporary-file-directory))
-            "perl" nil))
-         tramp-connection-properties)))
-    (tramp--test-special-characters)))
-
-(ert-deftest tramp-test41-special-characters-with-perl ()
-  "Check special characters in file names.
-Use the \"perl\" command."
-  :tags '(:expensive-test)
-  (skip-unless (not (getenv "EMACS_HYDRA_CI"))) ; SLOW ~ 266s
-  (skip-unless (tramp--test-enabled))
-  (skip-unless (tramp--test-sh-p))
-  (skip-unless (not (tramp--test-rsync-p)))
-  ;; We cannot use `tramp-test-vec', because this fails during compilation.
-  (with-parsed-tramp-file-name ert-remote-temporary-file-directory nil
-    (skip-unless (tramp-get-remote-perl v)))
-
-  (let ((tramp-connection-properties
-        (append
-         `((,(regexp-quote (file-remote-p ert-remote-temporary-file-directory))
-            "stat" nil)
-           ;; See `tramp-sh-handle-file-truename'.
-           (,(regexp-quote (file-remote-p ert-remote-temporary-file-directory))
-            "readlink" nil))
-         tramp-connection-properties)))
-    (tramp--test-special-characters)))
-
-(ert-deftest tramp-test41-special-characters-with-ls ()
-  "Check special characters in file names.
-Use the \"ls\" command."
-  :tags '(:expensive-test)
-  (skip-unless (not (getenv "EMACS_HYDRA_CI"))) ; SLOW ~ 287s
+(tramp--test-deftest-with-ls tramp-test41-special-characters)
+
+(ert-deftest tramp-test42-utf8 ()
+  "Check UTF8 encoding in file names and file contents."
   (skip-unless (tramp--test-enabled))
-  (skip-unless (tramp--test-sh-p))
+  (skip-unless (not (getenv "EMACS_HYDRA_CI"))) ; SLOW ~ 620s
+  (skip-unless (not (tramp--test-docker-p)))
   (skip-unless (not (tramp--test-rsync-p)))
+  (skip-unless (not (tramp--test-windows-nt-and-out-of-band-p)))
+  (skip-unless (not (tramp--test-ksh-p)))
+  (skip-unless (not (tramp--test-gdrive-p)))
+  (skip-unless (not (tramp--test-crypt-p)))
+  (skip-unless (not (tramp--test-rclone-p)))
 
-  (let ((tramp-connection-properties
-        (append
-         `((,(regexp-quote (file-remote-p ert-remote-temporary-file-directory))
-            "perl" nil)
-           (,(regexp-quote (file-remote-p ert-remote-temporary-file-directory))
-            "stat" nil)
-           ;; See `tramp-sh-handle-file-truename'.
-           (,(regexp-quote (file-remote-p ert-remote-temporary-file-directory))
-            "readlink" nil))
-         tramp-connection-properties)))
-    (tramp--test-special-characters)))
-
-(defun tramp--test-utf8 ()
-  "Perform the test in `tramp-test42-utf8*'."
   (let* ((utf8 (if (and (eq system-type 'darwin)
                        (memq 'utf-8-hfs (coding-system-list)))
                   'utf-8-hfs 'utf-8))
@@ -7008,7 +7073,8 @@ Use the \"ls\" command."
        "银河系漫游指南系列"
        "Автостопом по гала́ктике"
        ;; Use codepoints without a name.  See Bug#31272.
-       "™›šbung"
+       ;; Works on some Android systems only.
+       (unless (tramp--test-adb-p) "™›šbung")
        ;; Use codepoints from Supplementary Multilingual Plane (U+10000
        ;; to U+1FFFF).
        "🌈🍒👋")
@@ -7033,96 +7099,14 @@ Use the \"ls\" command."
             ;; ?\n and ?/ shouldn't be part of any file name.  ?\t,
             ;; ?. and ?? do not work for "smb" method.  " " does not
             ;; work at begin or end of the string for MS Windows.
-            (replace-regexp-in-string "[ \t\n/.?]" "" x)))
+            (replace-regexp-in-string (rx (any " \t\n/.?")) "" x)))
          language-info-alist)))))))
 
-(ert-deftest tramp-test42-utf8 ()
-  "Check UTF8 encoding in file names and file contents."
-  (skip-unless (not (getenv "EMACS_HYDRA_CI"))) ; SLOW ~ 620s
-  (skip-unless (tramp--test-enabled))
-  (skip-unless (not (tramp--test-docker-p)))
-  (skip-unless (not (tramp--test-rsync-p)))
-  (skip-unless (not (tramp--test-windows-nt-and-out-of-band-p)))
-  (skip-unless (not (tramp--test-ksh-p)))
-  (skip-unless (not (tramp--test-gdrive-p)))
-  (skip-unless (not (tramp--test-crypt-p)))
-  (skip-unless (not (tramp--test-rclone-p)))
-
-  (tramp--test-utf8))
+(tramp--test-deftest-with-stat tramp-test42-utf8)
 
-(ert-deftest tramp-test42-utf8-with-stat ()
-  "Check UTF8 encoding in file names and file contents.
-Use the \"stat\" command."
-  :tags '(:expensive-test)
-  (skip-unless (not (getenv "EMACS_HYDRA_CI"))) ; SLOW ~ 595s
-  (skip-unless (tramp--test-enabled))
-  (skip-unless (tramp--test-sh-p))
-  (skip-unless (not (tramp--test-docker-p)))
-  (skip-unless (not (tramp--test-rsync-p)))
-  (skip-unless (not (tramp--test-out-of-band-p))) ; SLOW
-  (skip-unless (not (tramp--test-ksh-p)))
-  (skip-unless (not (tramp--test-crypt-p)))
-  ;; We cannot use `tramp-test-vec', because this fails during compilation.
-  (with-parsed-tramp-file-name ert-remote-temporary-file-directory nil
-    (skip-unless (tramp-get-remote-stat v)))
-
-  (let ((tramp-connection-properties
-        (append
-         `((,(regexp-quote (file-remote-p ert-remote-temporary-file-directory))
-            "perl" nil))
-         tramp-connection-properties)))
-    (tramp--test-utf8)))
-
-(ert-deftest tramp-test42-utf8-with-perl ()
-  "Check UTF8 encoding in file names and file contents.
-Use the \"perl\" command."
-  :tags '(:expensive-test)
-  (skip-unless (not (getenv "EMACS_HYDRA_CI"))) ; SLOW ~ 620s
-  (skip-unless (tramp--test-enabled))
-  (skip-unless (tramp--test-sh-p))
-  (skip-unless (not (tramp--test-docker-p)))
-  (skip-unless (not (tramp--test-rsync-p)))
-  (skip-unless (not (tramp--test-out-of-band-p))) ; SLOW
-  (skip-unless (not (tramp--test-ksh-p)))
-  (skip-unless (not (tramp--test-crypt-p)))
-  ;; We cannot use `tramp-test-vec', because this fails during compilation.
-  (with-parsed-tramp-file-name ert-remote-temporary-file-directory nil
-    (skip-unless (tramp-get-remote-perl v)))
-
-  (let ((tramp-connection-properties
-        (append
-         `((,(regexp-quote (file-remote-p ert-remote-temporary-file-directory))
-            "stat" nil)
-           ;; See `tramp-sh-handle-file-truename'.
-           (,(regexp-quote (file-remote-p ert-remote-temporary-file-directory))
-            "readlink" nil))
-         tramp-connection-properties)))
-    (tramp--test-utf8)))
-
-(ert-deftest tramp-test42-utf8-with-ls ()
-  "Check UTF8 encoding in file names and file contents.
-Use the \"ls\" command."
-  :tags '(:expensive-test)
-  (skip-unless (not (getenv "EMACS_HYDRA_CI"))) ; SLOW ~ 690s
-  (skip-unless (tramp--test-enabled))
-  (skip-unless (tramp--test-sh-p))
-  (skip-unless (not (tramp--test-docker-p)))
-  (skip-unless (not (tramp--test-rsync-p)))
-  (skip-unless (not (tramp--test-out-of-band-p))) ; SLOW
-  (skip-unless (not (tramp--test-ksh-p)))
-  (skip-unless (not (tramp--test-crypt-p)))
+(tramp--test-deftest-with-perl tramp-test42-utf8)
 
-  (let ((tramp-connection-properties
-        (append
-         `((,(regexp-quote (file-remote-p ert-remote-temporary-file-directory))
-            "perl" nil)
-           (,(regexp-quote (file-remote-p ert-remote-temporary-file-directory))
-            "stat" nil)
-           ;; See `tramp-sh-handle-file-truename'.
-           (,(regexp-quote (file-remote-p ert-remote-temporary-file-directory))
-            "readlink" nil))
-         tramp-connection-properties)))
-    (tramp--test-utf8)))
+(tramp--test-deftest-with-ls tramp-test42-utf8)
 
 (ert-deftest tramp-test43-file-system-info ()
   "Check that `file-system-info' returns proper values."
@@ -7151,13 +7135,13 @@ The values are derived from PROC.  Run BODY.
 This is needed in timer functions as well as process filters and sentinels."
   ;; FIXME: For tramp-sshfs.el, `processp' does not work.
   (declare (indent 1) (debug (processp body)))
-  `(let* ((v (tramp-get-connection-property ,proc "vector" nil))
-         (pname (tramp-get-connection-property v "process-name" nil))
-         (pbuffer (tramp-get-connection-property v "process-buffer" nil)))
+  `(let* ((v (tramp-get-connection-property ,proc "vector"))
+         (pname (tramp-get-connection-property v "process-name"))
+         (pbuffer (tramp-get-connection-property v "process-buffer")))
      (tramp--test-message
       "tramp--test-with-proper-process-name-and-buffer before %s %s"
-      (tramp-get-connection-property v "process-name" nil)
-      (tramp-get-connection-property v "process-buffer" nil))
+      (tramp-get-connection-property v "process-name")
+      (tramp-get-connection-property v "process-buffer"))
      (if (process-name ,proc)
         (tramp-set-connection-property v "process-name" (process-name ,proc))
        (tramp-flush-connection-property v "process-name"))
@@ -7167,8 +7151,8 @@ This is needed in timer functions as well as process 
filters and sentinels."
        (tramp-flush-connection-property v "process-buffer"))
      (tramp--test-message
       "tramp--test-with-proper-process-name-and-buffer changed %s %s"
-      (tramp-get-connection-property v "process-name" nil)
-      (tramp-get-connection-property v "process-buffer" nil))
+      (tramp-get-connection-property v "process-name")
+      (tramp-get-connection-property v "process-buffer"))
      (unwind-protect
         (progn ,@body)
        (if pname
@@ -7376,8 +7360,8 @@ process sentinels.  They shall not disturb each other."
         (ignore-errors (cancel-timer timer))
         (ignore-errors (delete-directory tmp-name 'recursive))))))
 
-;; (tramp--test--deftest-direct-async-process 
tramp-test44-asynchronous-requests
-;;   "Check parallel direct asynchronous requests." 'unstable)
+;; (tramp--test-deftest-direct-async-process tramp-test44-asynchronous-requests
+;;   'unstable)
 
 (ert-deftest tramp-test45-dired-compress-file ()
   "Check that Tramp (un)compresses normal files."
@@ -7498,7 +7482,7 @@ process sentinels.  They shall not disturb each other."
          ert-remote-temporary-file-directory)))
     (should
      (string-match-p
-      "Tramp loaded: t[\n\r]+"
+      (rx "Tramp loaded: t" (+ (any "\n\r")))
       (shell-command-to-string
        (format
        "%s -batch -Q -L %s --eval %s"
@@ -7525,9 +7509,9 @@ process sentinels.  They shall not disturb each other."
     (dolist (tm '(t nil))
       (should
        (string-match-p
-       (format
-       "Tramp loaded: nil[\n\r]+Tramp loaded: nil[\n\r]+Tramp loaded: 
%s[\n\r]+"
-        tm)
+       (rx "Tramp loaded: nil" (+ (any "\n\r"))
+           "Tramp loaded: nil" (+ (any "\n\r"))
+           "Tramp loaded: " (literal (symbol-name tm)) (+ (any "\n\r")))
        (shell-command-to-string
         (format
          "%s -batch -Q -L %s --eval %s"
@@ -7572,11 +7556,10 @@ process sentinels.  They shall not disturb each other."
            (tramp-cleanup-all-connections))"))
     (should
      (string-match-p
-      (format
-       "Loading %s"
-       (regexp-quote
-        (expand-file-name
-         "tramp-cmds" (file-name-directory (locate-library "tramp")))))
+      (rx "Loading "
+         (literal
+           (expand-file-name
+            "tramp-cmds" (file-name-directory (locate-library "tramp")))))
       (shell-command-to-string
        (format
        "%s -batch -Q -L %s -l tramp-sh --eval %s"
@@ -7617,11 +7600,13 @@ Since it unloads Tramp, it shall be the last test to 
run."
      (and (or (and (boundp x) (null (local-variable-if-set-p x)))
              (and (functionp x) (null (autoloadp (symbol-function x))))
              (macrop x))
-         (string-match-p "^tramp" (symbol-name x))
+         (string-prefix-p "tramp" (symbol-name x))
          ;; `tramp-completion-mode' is autoloaded in Emacs < 28.1.
          (not (eq 'tramp-completion-mode x))
-         (not (string-match-p "^tramp\\(-archive\\)?--?test" (symbol-name x)))
-         (not (string-match-p "unload-hook$" (symbol-name x)))
+         (not (string-match-p
+               (rx bol "tramp" (? "-archive") (** 1 2 "-") "test")
+               (symbol-name x)))
+         (not (string-suffix-p "unload-hook" (symbol-name x)))
          (not (get x 'tramp-autoload))
          (ert-fail (format "`%s' still bound" x)))))
 
@@ -7630,8 +7615,8 @@ Since it unloads Tramp, it shall be the last test to run."
   (should-not (cl--find-class 'tramp-file-name))
   (mapatoms
    (lambda (x)
-     (and (functionp x)
-          (string-match-p "tramp-file-name" (symbol-name x))
+     (and (functionp x) (null (autoloadp (symbol-function x)))
+          (string-prefix-p "tramp-file-name" (symbol-name x))
           (ert-fail (format "Structure function `%s' still exists" x)))))
 
   ;; There shouldn't be left a hook function containing a Tramp
@@ -7639,8 +7624,9 @@ Since it unloads Tramp, it shall be the last test to run."
   (mapatoms
    (lambda (x)
      (and (boundp x)
-         (string-match-p "-\\(hook\\|function\\)s?$" (symbol-name x))
-         (not (string-match-p "unload-hook$" (symbol-name x)))
+         (string-match-p
+          (rx "-" (| "hook" "function") (? "s") eol) (symbol-name x))
+         (not (string-suffix-p "unload-hook" (symbol-name x)))
          (consp (symbol-value x))
          (ignore-errors (all-completions "tramp" (symbol-value x)))
          (ert-fail (format "Hook `%s' still contains Tramp function" x)))))
@@ -7651,7 +7637,7 @@ Since it unloads Tramp, it shall be the last test to run."
      (and (functionp x)
          (advice-mapc
           (lambda (fun _symbol)
-            (and (string-match-p "^tramp" (symbol-name fun))
+            (and (string-prefix-p "tramp" (symbol-name fun))
                  (ert-fail
                   (format "Function `%s' still contains Tramp advice" x))))
           x))))
@@ -7668,7 +7654,7 @@ If INTERACTIVE is non-nil, the tests are run 
interactively."
   (interactive "p")
   (funcall
    (if interactive #'ert-run-tests-interactively #'ert-run-tests-batch)
-   "^tramp"))
+   (rx bol "tramp")))
 
 ;; TODO:
 
diff --git a/test/lisp/obsolete/inversion-tests.el 
b/test/lisp/obsolete/inversion-tests.el
index 7c8815c282..8af91d7d14 100644
--- a/test/lisp/obsolete/inversion-tests.el
+++ b/test/lisp/obsolete/inversion-tests.el
@@ -30,7 +30,6 @@
 
 (ert-deftest inversion-unit-test ()
   "Test inversion to make sure it can identify different version strings."
-  (interactive)
   (let ((c1 (inversion-package-version 'inversion))
         (c1i (inversion-package-incompatibility-version 'inversion))
         (c2 (inversion-decode-version  "1.3alpha2"))
diff --git a/test/lisp/makesum-tests.el b/test/lisp/obsolete/makesum-tests.el
similarity index 100%
rename from test/lisp/makesum-tests.el
rename to test/lisp/obsolete/makesum-tests.el
diff --git a/test/lisp/progmodes/autoconf-tests.el 
b/test/lisp/progmodes/autoconf-tests.el
index e383b4bb6c..7c609f3c2a 100644
--- a/test/lisp/progmodes/autoconf-tests.el
+++ b/test/lisp/progmodes/autoconf-tests.el
@@ -31,18 +31,18 @@
 
 (ert-deftest autoconf-tests-current-defun-function-define ()
   (with-temp-buffer
-    (insert "AC_DEFINE(HAVE_RSVG, 1, [Define to 1 if using librsvg.])")
+    (insert "AC_DEFINE([HAVE_RSVG], [1], [Define to 1 if using librsvg.])")
     (goto-char (point-min))
     (should-not (autoconf-current-defun-function))
-    (forward-char 10)
+    (forward-char 11)
     (should (equal (autoconf-current-defun-function) "HAVE_RSVG"))))
 
 (ert-deftest autoconf-tests-current-defun-function-subst ()
   (with-temp-buffer
-    (insert "AC_SUBST(srcdir)")
+    (insert "AC_SUBST([srcdir])")
     (goto-char (point-min))
     (should-not (autoconf-current-defun-function))
-    (forward-char 9)
+    (forward-char 10)
     (should (equal (autoconf-current-defun-function) "srcdir"))))
 
 (ert-deftest autoconf-tests-autoconf-mode-comment-syntax ()
diff --git a/test/lisp/progmodes/compile-tests.el 
b/test/lisp/progmodes/compile-tests.el
index 774370be4c..36bdbe4c91 100644
--- a/test/lisp/progmodes/compile-tests.el
+++ b/test/lisp/progmodes/compile-tests.el
@@ -260,6 +260,9 @@
      "e: e:\\src\\Test.kt: (34, 15): foo: bar" 4 15 34 "e:\\src\\Test.kt" 2)
     (gradle-kotlin
      "w: e:\\src\\Test.kt: (11, 98): foo: bar" 4 98 11 "e:\\src\\Test.kt" 1)
+    (gradle-android
+     "     
ERROR:/Users/salutis/src/AndroidSchemeExperiment/app/build/intermediates/incremental/debug/mergeDebugResources/stripped.dir/layout/item.xml:3:
 AAPT: error: '16dpw' is incompatible with attribute padding (attr) dimension."
+     1 nil 3 
"/Users/salutis/src/AndroidSchemeExperiment/app/build/intermediates/incremental/debug/mergeDebugResources/stripped.dir/layout/item.xml"
 2)
     ;; Guile
     (guile-file "In foo.scm:\n" 1 nil nil "foo.scm")
     (guile-line "  63:4 [call-with-prompt prompt0 ...]" 1 4 63 nil)
@@ -492,7 +495,7 @@ The test data is in `compile-tests--test-regexps-data'."
           (compilation-num-warnings-found 0)
           (compilation-num-infos-found 0))
       (mapc #'compile--test-error-line compile-tests--test-regexps-data)
-      (should (eq compilation-num-errors-found 97))
+      (should (eq compilation-num-errors-found 98))
       (should (eq compilation-num-warnings-found 35))
       (should (eq compilation-num-infos-found 28)))))
 
diff --git a/test/lisp/progmodes/cperl-mode-tests.el 
b/test/lisp/progmodes/cperl-mode-tests.el
index 4e0debffb6..7eb2d9be75 100644
--- a/test/lisp/progmodes/cperl-mode-tests.el
+++ b/test/lisp/progmodes/cperl-mode-tests.el
@@ -5,7 +5,7 @@
 ;; Author: Harald Jörg <haj@posteo.de>
 ;; Maintainer: Harald Jörg
 ;; Keywords: internal
-;; Homepage: https://github.com/HaraldJoerg/cperl-mode
+;; URL: https://github.com/HaraldJoerg/cperl-mode
 
 ;; This file is part of GNU Emacs.
 
@@ -747,7 +747,6 @@ without a statement terminator on the same line does not 
loop
 forever.  The test starts an asynchronous Emacs batch process
 under timeout control."
   :tags '(:expensive-test)
-  (interactive)
   (skip-unless (not (getenv "EMACS_HYDRA_CI"))) ; FIXME times out
   (skip-unless (not (< emacs-major-version 28))) ; times out in older Emacsen
   (skip-unless (eq cperl-test-mode #'cperl-mode))
diff --git a/test/lisp/progmodes/elisp-mode-tests.el 
b/test/lisp/progmodes/elisp-mode-tests.el
index 8e4dfa8bb8..e73be0db50 100644
--- a/test/lisp/progmodes/elisp-mode-tests.el
+++ b/test/lisp/progmodes/elisp-mode-tests.el
@@ -183,6 +183,16 @@
         (call-interactively #'eval-last-sexp)
         (should (equal (current-message) "66 (#o102, #x42, ?B)"))))))
 
+;;; eval-defun
+
+(ert-deftest eval-defun-prints-edebug-when-instrumented ()
+  (skip-unless (not noninteractive))
+  (with-temp-buffer
+    (let ((current-prefix-arg '(4)))
+      (erase-buffer) (insert "(defun foo ())") (message nil)
+      (call-interactively #'eval-defun)
+      (should (equal (current-message) "Edebug: foo")))))
+
 ;;; eldoc
 
 (defun elisp-mode-tests--face-propertized-string (string)
@@ -1084,7 +1094,7 @@ evaluation of BODY."
       (insert "f-test-compl")
       (completion-at-point)
       (goto-char (point-min))
-      (should (search-forward "f-test-complete-me" (line-end-position) t))
+      (should (search-forward "f-test-complete-me" (pos-eol) t))
       (goto-char (point-min))
       (should (string= (symbol-name (read (current-buffer)))
                        "elisp--foo-test-complete-me"))
diff --git a/test/lisp/progmodes/f90-tests.el b/test/lisp/progmodes/f90-tests.el
index 3fe5eecd1b..b857a25bf2 100644
--- a/test/lisp/progmodes/f90-tests.el
+++ b/test/lisp/progmodes/f90-tests.el
@@ -285,14 +285,14 @@ real :: x
 end")
     (f90-indent-line)
     (should (equal " function foo"
-                   (buffer-substring (point) (line-end-position))))
+                   (buffer-substring (point) (pos-eol))))
     (goto-char (point-max))
     (insert "\nmodule subroutine bar(x)
 real :: x
 end")
     (f90-indent-line)
     (should (equal " subroutine bar"
-                   (buffer-substring (point) (line-end-position))))))
+                   (buffer-substring (point) (pos-eol))))))
 
 
 ;;; f90-tests.el ends here
diff --git a/test/lisp/progmodes/hideshow-tests.el 
b/test/lisp/progmodes/hideshow-tests.el
new file mode 100644
index 0000000000..ee2a0c7c4c
--- /dev/null
+++ b/test/lisp/progmodes/hideshow-tests.el
@@ -0,0 +1,268 @@
+;;; hideshow-tests.el --- Test suite for hideshow.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/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'ert)
+(require 'ert-x)
+(require 'hideshow)
+
+;; Dependencies for testing:
+(require 'cc-mode)
+
+
+(defmacro hideshow-tests-with-temp-buffer (mode contents &rest body)
+  "Create a `hs-minor-mode' enabled MODE temp buffer with CONTENTS.
+BODY is code to be executed within the temp buffer.  Point is
+always located at the beginning of buffer."
+  (declare (indent 1) (debug t))
+  `(with-temp-buffer
+     (,mode)
+     (hs-minor-mode 1)
+     (insert ,contents)
+     (goto-char (point-min))
+     ,@body))
+
+(defun hideshow-tests-look-at (string &optional num restore-point)
+  "Move point at beginning of STRING in the current buffer.
+Optional argument NUM defaults to 1 and is an integer indicating
+how many occurrences must be found, when positive the search is
+done forwards, otherwise backwards.  When RESTORE-POINT is
+non-nil the point is not moved but the position found is still
+returned.  When searching forward and point is already looking at
+STRING, it is skipped so the next STRING occurrence is selected."
+  (let* ((num (or num 1))
+         (starting-point (point))
+         (string (regexp-quote string))
+         (search-fn (if (> num 0) #'re-search-forward #'re-search-backward))
+         (deinc-fn (if (> num 0) #'1- #'1+))
+         (found-point))
+    (prog2
+        (catch 'exit
+          (while (not (= num 0))
+            (when (and (> num 0)
+                       (looking-at string))
+              ;; Moving forward and already looking at STRING, skip it.
+              (forward-char (length (match-string-no-properties 0))))
+            (and (not (funcall search-fn string nil t))
+                 (throw 'exit t))
+            (when (> num 0)
+              ;; `re-search-forward' leaves point at the end of the
+              ;; occurrence, move back so point is at the beginning
+              ;; instead.
+              (forward-char (- (length (match-string-no-properties 0)))))
+            (setq
+             num (funcall deinc-fn num)
+             found-point (point))))
+        found-point
+      (and restore-point (goto-char starting-point)))))
+
+(defun hideshow-tests-visible-string (&optional min max)
+  "Return the buffer string excluding invisible overlays.
+Argument MIN and MAX delimit the region to be returned and
+default to `point-min' and `point-max' respectively."
+  (let* ((min (or min (point-min)))
+         (max (or max (point-max)))
+         (buffer-contents (buffer-substring-no-properties min max))
+         (overlays
+          (sort (overlays-in min max)
+                (lambda (a b)
+                  (let ((overlay-end-a (overlay-end a))
+                        (overlay-end-b (overlay-end b)))
+                    (> overlay-end-a overlay-end-b))))))
+    (with-temp-buffer
+      (insert buffer-contents)
+      (dolist (overlay overlays)
+        (if (overlay-get overlay 'invisible)
+            (delete-region (overlay-start overlay)
+                           (overlay-end overlay))))
+      (buffer-substring-no-properties (point-min) (point-max)))))
+
+(ert-deftest hideshow-hide-block-1 ()
+  "Should hide current block."
+  (let ((contents "
+int
+main()
+{
+  printf(\"Hello\\n\");
+}
+"))
+    (hideshow-tests-with-temp-buffer
+     c-mode
+     contents
+     (hideshow-tests-look-at "printf")
+     (hs-hide-block)
+     (should (string=
+              (hideshow-tests-visible-string)
+              "
+int
+main()
+{}
+"))
+     (hs-show-block)
+     (should (string= (hideshow-tests-visible-string) contents)))))
+
+(ert-deftest hideshow-hide-all-1 ()
+  "Should hide all blocks and comments."
+  (let ((contents "
+/*
+   Comments
+*/
+
+int
+main()
+{
+  sub();
+}
+
+void
+sub()
+{
+  printf(\"Hello\\n\");
+}
+"))
+    (hideshow-tests-with-temp-buffer
+     c-mode
+     contents
+     (hs-hide-all)
+     (should (string=
+              (hideshow-tests-visible-string)
+              "
+/*
+
+int
+main()
+{}
+
+void
+sub()
+{}
+"))
+     (hs-show-all)
+     (should (string= (hideshow-tests-visible-string) contents)))))
+
+(ert-deftest hideshow-hide-all-2 ()
+  "Should not hide comments when `hs-hide-comments-when-hiding-all' is nil."
+  (let ((contents "
+/*
+   Comments
+*/
+
+int
+main()
+{
+  sub();
+}
+
+void
+sub()
+{
+  printf(\"Hello\\n\");
+}
+"))
+    (hideshow-tests-with-temp-buffer
+     c-mode
+     contents
+     (let ((hs-hide-comments-when-hiding-all nil))
+       (hs-hide-all))
+     (should (string=
+              (hideshow-tests-visible-string)
+              "
+/*
+   Comments
+*/
+
+int
+main()
+{}
+
+void
+sub()
+{}
+"))
+     (hs-show-all)
+     (should (string= (hideshow-tests-visible-string) contents)))))
+
+(ert-deftest hideshow-hide-level-1 ()
+  "Should hide 1st level blocks."
+  (hideshow-tests-with-temp-buffer
+   c-mode
+   "
+/*
+   Comments
+*/
+
+int
+main(int argc, char **argv)
+{
+  if (argc > 1) {
+    printf(\"Hello\\n\");
+  }
+}
+"
+   (hs-hide-level 1)
+   (should (string=
+            (hideshow-tests-visible-string)
+            "
+/*
+   Comments
+*/
+
+int
+main(int argc, char **argv)
+{}
+"))))
+
+(ert-deftest hideshow-hide-level-2 ()
+  "Should hide 2nd level blocks."
+  (hideshow-tests-with-temp-buffer
+   c-mode
+   "
+/*
+   Comments
+*/
+
+int
+main(int argc, char **argv)
+{
+  if (argc > 1) {
+    printf(\"Hello\\n\");
+  }
+}
+"
+   (hs-hide-level 2)
+   (should (string=
+            (hideshow-tests-visible-string)
+            "
+/*
+   Comments
+*/
+
+int
+main(int argc, char **argv)
+{
+  if (argc > 1) {}
+}
+"))))
+
+(provide 'hideshow-tests)
+
+;;; hideshow-tests.el ends here
diff --git a/test/lisp/progmodes/python-tests.el 
b/test/lisp/progmodes/python-tests.el
index 8db0a07170..906f7eca7d 100644
--- a/test/lisp/progmodes/python-tests.el
+++ b/test/lisp/progmodes/python-tests.el
@@ -108,6 +108,20 @@ STRING, it is skipped so the next STRING occurrence is 
selected."
            while pos
            collect (cons pos (get-text-property pos 'face))))
 
+(defun python-tests-assert-faces-after-change (content faces search replace)
+  "Assert that font faces for CONTENT are equal to FACES after change.
+All occurrences of SEARCH are changed to REPLACE."
+  (python-tests-with-temp-buffer
+   content
+   ;; Force enable font-lock mode without jit-lock.
+   (rename-buffer "*python-font-lock-test*" t)
+   (let (noninteractive font-lock-support-mode)
+     (font-lock-mode))
+   (while
+       (re-search-forward search nil t)
+     (replace-match replace))
+   (should (equal faces (python-tests-get-buffer-faces)))))
+
 (defun python-tests-self-insert (char-or-str)
   "Call `self-insert-command' for chars in CHAR-OR-STR."
   (let ((chars
@@ -226,6 +240,13 @@ aliqua."
    "def 1func():"
    '((1 . font-lock-keyword-face) (4))))
 
+(ert-deftest python-font-lock-keywords-level-1-3 ()
+  (python-tests-assert-faces
+   "def \\
+        func():"
+   '((1 . font-lock-keyword-face) (4)
+     (15 . font-lock-function-name-face) (19))))
+
 (ert-deftest python-font-lock-assignment-statement-1 ()
   (python-tests-assert-faces
    "a, b, c = 1, 2, 3"
@@ -380,6 +401,254 @@ def f(x: CustomInt) -> CustomInt:
      (128 . font-lock-builtin-face) (131)
      (144 . font-lock-keyword-face) (150))))
 
+(ert-deftest python-font-lock-assignment-statement-multiline-1 ()
+  (python-tests-assert-faces-after-change
+   "
+[
+    a,
+    b
+] # (
+    1,
+    2
+)
+"
+   '((1)
+     (8 . font-lock-variable-name-face) (9)
+     (15 . font-lock-variable-name-face) (16))
+   "#" "="))
+
+(ert-deftest python-font-lock-assignment-statement-multiline-2 ()
+  (python-tests-assert-faces-after-change
+   "
+[
+    *a
+] # 5, 6
+"
+   '((1)
+     (9 . font-lock-variable-name-face) (10))
+   "#" "="))
+
+(ert-deftest python-font-lock-assignment-statement-multiline-3 ()
+  (python-tests-assert-faces-after-change
+   "a\\
+    ,\\
+    b\\
+    ,\\
+    c\\
+    #\\
+    1\\
+    ,\\
+    2\\
+    ,\\
+    3"
+   '((1 . font-lock-variable-name-face) (2)
+     (15 . font-lock-variable-name-face) (16)
+     (29 . font-lock-variable-name-face) (30))
+   "#" "="))
+
+(ert-deftest python-font-lock-assignment-statement-multiline-4 ()
+  (python-tests-assert-faces-after-change
+   "a\\
+    :\\
+    int\\
+    #\\
+    5"
+   '((1 . font-lock-variable-name-face) (2)
+     (15 . font-lock-builtin-face) (18))
+   "#" "="))
+
+(ert-deftest python-font-lock-assignment-statement-multiline-5 ()
+  (python-tests-assert-faces-after-change
+   "(\\
+    a\\
+)\\
+    #\\
+    5\\
+    ;\\
+    (\\
+    b\\
+    )\\
+    #\\
+    6"
+   '((1)
+     (8 . font-lock-variable-name-face) (9)
+     (46 . font-lock-variable-name-face) (47))
+   "#" "="))
+
+(ert-deftest python-font-lock-assignment-statement-multiline-6 ()
+  (python-tests-assert-faces-after-change
+   "(
+    a
+)\\
+    #\\
+    5\\
+    ;\\
+    (
+    b
+    )\\
+    #\\
+    6"
+   '((1)
+     (7 . font-lock-variable-name-face) (8)
+     (43 . font-lock-variable-name-face) (44))
+   "#" "="))
+
+(ert-deftest python-font-lock-escape-sequence-string-newline ()
+  (python-tests-assert-faces
+   "'\\n'
+\"\\n\"
+f'\\n'
+f\"\\n\"
+u'\\n'
+u\"\\n\""
+   '((1 . font-lock-doc-face)
+     (2 . font-lock-constant-face)
+     (4 . font-lock-doc-face) (5)
+     (6 . font-lock-doc-face)
+     (7 . font-lock-constant-face)
+     (9 . font-lock-doc-face) (10)
+     (12 . font-lock-string-face)
+     (13 . font-lock-constant-face)
+     (15 . font-lock-string-face) (16)
+     (18 . font-lock-string-face)
+     (19 . font-lock-constant-face)
+     (21 . font-lock-string-face) (22)
+     (24 . font-lock-string-face)
+     (25 . font-lock-constant-face)
+     (27 . font-lock-string-face) (28)
+     (30 . font-lock-string-face)
+     (31 . font-lock-constant-face)
+     (33 . font-lock-string-face))))
+
+(ert-deftest python-font-lock-escape-sequence-multiline-string ()
+  (python-tests-assert-faces
+   (let ((escape-sequences "\\x12 \123 \\n \\u1234 \\U00010348 \\N{Plus-Minus 
Sign}"))
+     (cl-loop for string-prefix in '("" "f" "rf" "fr" "r" "rb" "br" "b")
+              concat (cl-loop for quote-string in '("\"\"\"" "'''")
+                              concat (concat string-prefix
+                                             quote-string
+                                             escape-sequences
+                                             quote-string
+                                             "\n"))))
+   '((1 . font-lock-doc-face)
+     (4 . font-lock-constant-face)
+     (8 . font-lock-doc-face)
+     (11 . font-lock-constant-face)
+     (13 . font-lock-doc-face)
+     (14 . font-lock-constant-face)
+     (20 . font-lock-doc-face)
+     (21 . font-lock-constant-face)
+     (31 . font-lock-doc-face)
+     (32 . font-lock-constant-face)
+     (51 . font-lock-doc-face) (54)
+     (55 . font-lock-doc-face)
+     (58 . font-lock-constant-face)
+     (62 . font-lock-doc-face)
+     (65 . font-lock-constant-face)
+     (67 . font-lock-doc-face)
+     (68 . font-lock-constant-face)
+     (74 . font-lock-doc-face)
+     (75 . font-lock-constant-face)
+     (85 . font-lock-doc-face)
+     (86 . font-lock-constant-face)
+     (105 . font-lock-doc-face) (108)
+     (110 . font-lock-string-face)
+     (113 . font-lock-constant-face)
+     (117 . font-lock-string-face)
+     (120 . font-lock-constant-face)
+     (122 . font-lock-string-face)
+     (123 . font-lock-constant-face)
+     (129 . font-lock-string-face)
+     (130 . font-lock-constant-face)
+     (140 . font-lock-string-face)
+     (141 . font-lock-constant-face)
+     (160 . font-lock-string-face) (163)
+     (165 . font-lock-string-face)
+     (168 . font-lock-constant-face)
+     (172 . font-lock-string-face)
+     (175 . font-lock-constant-face)
+     (177 . font-lock-string-face)
+     (178 . font-lock-constant-face)
+     (184 . font-lock-string-face)
+     (185 . font-lock-constant-face)
+     (195 . font-lock-string-face)
+     (196 . font-lock-constant-face)
+     (215 . font-lock-string-face) (218)
+     (221 . font-lock-string-face) (274)
+     (277 . font-lock-string-face) (330)
+     (333 . font-lock-string-face) (386)
+     (389 . font-lock-string-face) (442)
+     (444 . font-lock-string-face) (497)
+     (499 . font-lock-string-face) (552)
+     (555 . font-lock-string-face) (608)
+     (611 . font-lock-string-face) (664)
+     (667 . font-lock-string-face) (720)
+     (723 . font-lock-string-face) (776)
+     (778 . font-lock-string-face)
+     (781 . font-lock-constant-face)
+     (785 . font-lock-string-face)
+     (788 . font-lock-constant-face)
+     (790 . font-lock-string-face) (831)
+     (833 . font-lock-string-face)
+     (836 . font-lock-constant-face)
+     (840 . font-lock-string-face)
+     (843 . font-lock-constant-face)
+     (845 . font-lock-string-face) (886))))
+
+(ert-deftest python-font-lock-escape-sequence-bytes-newline ()
+  (python-tests-assert-faces
+   "b'\\n'
+b\"\\n\""
+   '((1)
+     (2 . font-lock-doc-face)
+     (3 . font-lock-constant-face)
+     (5 . font-lock-doc-face) (6)
+     (8 . font-lock-doc-face)
+     (9 . font-lock-constant-face)
+     (11 . font-lock-doc-face))))
+
+(ert-deftest python-font-lock-escape-sequence-hex-octal ()
+  (python-tests-assert-faces
+   "b'\\x12 \\777 \\1\\23'
+'\\x12 \\777 \\1\\23'"
+   '((1)
+     (2 . font-lock-doc-face)
+     (3 . font-lock-constant-face)
+     (7 . font-lock-doc-face)
+     (8 . font-lock-constant-face)
+     (12 . font-lock-doc-face)
+     (13 . font-lock-constant-face)
+     (18 . font-lock-doc-face) (19)
+     (20 . font-lock-doc-face)
+     (21 . font-lock-constant-face)
+     (25 . font-lock-doc-face)
+     (26 . font-lock-constant-face)
+     (30 . font-lock-doc-face)
+     (31 . font-lock-constant-face)
+     (36 . font-lock-doc-face))))
+
+(ert-deftest python-font-lock-escape-sequence-unicode ()
+  (python-tests-assert-faces
+   "b'\\u1234 \\U00010348 \\N{Plus-Minus Sign}'
+'\\u1234 \\U00010348 \\N{Plus-Minus Sign}'"
+   '((1)
+     (2 . font-lock-doc-face) (41)
+     (42 . font-lock-doc-face)
+     (43 . font-lock-constant-face)
+     (49 . font-lock-doc-face)
+     (50 . font-lock-constant-face)
+     (60 . font-lock-doc-face)
+     (61 . font-lock-constant-face)
+     (80 . font-lock-doc-face))))
+
+(ert-deftest python-font-lock-raw-escape-sequence ()
+  (python-tests-assert-faces
+   "rb'\\x12 \123 \\n'
+r'\\x12 \123 \\n \\u1234 \\U00010348 \\N{Plus-Minus Sign}'"
+   '((1)
+     (3 . font-lock-doc-face) (14)
+     (16 . font-lock-doc-face))))
+
 
 ;;; Indentation
 
@@ -981,6 +1250,25 @@ def delete_all_things():
                :after-backslash-dotted-continuation))
    (should (= (python-indent-calculate-indentation) 16))))
 
+(ert-deftest python-indent-after-backslash-6 ()
+  "Backslash continuation from for block."
+  (python-tests-with-temp-buffer
+   "
+for long_variable_name \\
+        in (1, 2):
+    print(long_variable_name)
+"
+   (python-tests-look-at "for long_variable_name \\")
+   (should (eq (car (python-indent-context)) :no-indent))
+   (should (= (python-indent-calculate-indentation) 0))
+   (python-tests-look-at "in (1, 2):")
+   (should (eq (car (python-indent-context))
+               :after-backslash-block-continuation))
+   (should (= (python-indent-calculate-indentation) 8))
+   (python-tests-look-at "print(long_variable_name)")
+   (should (eq (car (python-indent-context)) :after-block-start))
+   (should (= (python-indent-calculate-indentation) 4))))
+
 (ert-deftest python-indent-block-enders-1 ()
   "Test de-indentation for pass keyword."
   (python-tests-with-temp-buffer
@@ -1122,6 +1410,35 @@ if save:
    (python-indent-line t)
    (should (= (python-indent-calculate-indentation t) 8))))
 
+(ert-deftest python-indent-dedenters-comment-else ()
+  "Test de-indentation for the else keyword with comments before it."
+  (python-tests-with-temp-buffer
+   "
+if save:
+    try:
+        write_to_disk(data)
+    except IOError:
+        msg = 'Error saving to disk'
+        message(msg)
+        logger.exception(msg)
+    except Exception:
+        if hide_details:
+            logger.exception('Unhandled exception')
+        # comment
+            else
+    finally:
+        data.free()
+"
+   (python-tests-look-at "else\n")
+   (should (eq (car (python-indent-context)) :at-dedenter-block-start))
+   (should (= (python-indent-calculate-indentation) 8))
+   (python-indent-line t)
+   (should (= (python-indent-calculate-indentation t) 4))
+   (python-indent-line t)
+   (should (= (python-indent-calculate-indentation t) 0))
+   (python-indent-line t)
+   (should (= (python-indent-calculate-indentation t) 8))))
+
 (ert-deftest python-indent-dedenters-3 ()
   "Test de-indentation for the except keyword."
   (python-tests-with-temp-buffer
@@ -1322,7 +1639,7 @@ a = (
 "
    (python-tests-look-at "- bar")
    (should (eq (car (python-indent-context)) :inside-string))
-   (goto-char (line-end-position))
+   (goto-char (pos-eol))
    (python-tests-self-insert ",")
    (should (= (current-indentation) 0))))
 
@@ -1337,7 +1654,7 @@ a = (
 "
    (python-tests-look-at "- bar'''")
    (should (eq (car (python-indent-context)) :inside-string))
-   (goto-char (line-end-position))
+   (goto-char (pos-eol))
    (python-tests-self-insert ",")
    (should (= (current-indentation) 0))))
 
@@ -1351,7 +1668,7 @@ def a():
 def b()
 "
    (python-tests-look-at "def b()")
-   (goto-char (line-end-position))
+   (goto-char (pos-eol))
    (python-tests-self-insert ":")
    (should (= (current-indentation) 0))))
 
@@ -1365,7 +1682,7 @@ if do:
 outside
 "
    (python-tests-look-at "else")
-   (goto-char (line-end-position))
+   (goto-char (pos-eol))
    (python-tests-self-insert ":")
    (should (= (current-indentation) 0))
    (python-tests-look-at "outside")
@@ -1382,7 +1699,7 @@ if do:
           that)
 "
    (python-tests-look-at "that)")
-   (goto-char (line-end-position))
+   (goto-char (pos-eol))
    (python-tests-self-insert ":")
    (python-tests-look-at "elif" -1)
    (should (= (current-indentation) 0))
@@ -1407,7 +1724,7 @@ def f():
 else
 "
    (python-tests-look-at "else")
-   (goto-char (line-end-position))
+   (goto-char (pos-eol))
    (python-tests-self-insert ":")
    (python-tests-look-at "else" -1)
    (should (= (current-indentation) 4))))
@@ -1667,7 +1984,7 @@ class C:
          (expected-mark-beginning-position
           (progn
             (python-tests-look-at "def __init__(self):")
-            (1- (line-beginning-position))))
+            (1- (pos-bol))))
          (expected-mark-end-position-1
           (save-excursion
             (python-tests-look-at "self.b = 'b'")
@@ -1724,7 +2041,7 @@ class C:
           (progn
             (python-tests-look-at "def fun(self):")
             (python-tests-look-at "(self):")
-            (1- (line-beginning-position))))
+            (1- (pos-bol))))
          (expected-mark-end-position
           (save-excursion
             (python-tests-look-at "return self.b")
@@ -1736,6 +2053,57 @@ class C:
      (should (= (marker-position (mark-marker))
                 expected-mark-end-position)))))
 
+(ert-deftest python-mark-defun-4 ()
+  "Test `python-mark-defun' with nested functions."
+  (python-tests-with-temp-buffer
+   "
+def foo(x):
+    def bar():
+        return x
+    if True:
+        return bar
+"
+   (let ((expected-mark-beginning-position
+          (progn
+            (python-tests-look-at "def foo(x):")
+            (1- (pos-bol))))
+         (expected-mark-end-position (point-max)))
+     (python-tests-look-at "return bar")
+     (python-mark-defun 1)
+     (should (= (point) expected-mark-beginning-position))
+     (should (= (marker-position (mark-marker))
+                expected-mark-end-position)))))
+
+(ert-deftest python-mark-defun-5 ()
+  "Test `python-mark-defun' with point inside backslash escaped defun."
+  (python-tests-with-temp-buffer
+   "
+def \\
+        foo(x):
+    return x
+"
+   (let ((transient-mark-mode t)
+         (expected-mark-beginning-position
+          (progn
+            (python-tests-look-at "def ")
+            (1- (pos-bol))))
+         (expected-mark-end-position
+          (save-excursion
+            (python-tests-look-at "return x")
+            (forward-line)
+            (point))))
+     (python-tests-look-at "def ")
+     (python-mark-defun 1)
+     (should (= (point) expected-mark-beginning-position))
+     (should (= (marker-position (mark-marker))
+                expected-mark-end-position))
+     (deactivate-mark)
+     (python-tests-look-at "foo(x)")
+     (python-mark-defun 1)
+     (should (= (point) expected-mark-beginning-position))
+     (should (= (marker-position (mark-marker))
+                expected-mark-end-position)))))
+
 
 ;;; Navigation
 
@@ -1762,12 +2130,20 @@ def decoratorFunctionWithArguments(arg1, arg2, arg3):
         return wrapped_f
     return wwrap
 "
-   (python-tests-look-at "return wrap")
+   (python-tests-look-at "return wwrap")
+   (should (= (save-excursion
+                (python-nav-beginning-of-defun)
+                (point))
+              (save-excursion
+                (python-tests-look-at "def decoratorFunctionWithArguments" -1)
+                (beginning-of-line)
+                (point))))
+   (python-tests-look-at "return wrap" -1)
    (should (= (save-excursion
                 (python-nav-beginning-of-defun)
                 (point))
               (save-excursion
-                (python-tests-look-at "def wrapped_f(*args):" -1)
+                (python-tests-look-at "def wwrap(f):" -1)
                 (beginning-of-line)
                 (point))))
    (python-tests-look-at "def wrapped_f(*args):" -1)
@@ -1801,11 +2177,23 @@ class C(object):
         def a():
             pass
 
+        if True:
+            return a
+
     def c(self):
         pass
 "
    ;; Nested defuns, are handled with care.
    (python-tests-look-at "def c(self):")
+   (should (= (save-excursion
+                (python-nav-beginning-of-defun)
+                (point))
+              (save-excursion
+                (python-tests-look-at "def m(self):" -1)
+                (beginning-of-line)
+                (point))))
+   ;; Nested defuns should be skipped.
+   (forward-line -1)
    (should (= (save-excursion
                 (python-nav-beginning-of-defun)
                 (point))
@@ -1814,6 +2202,15 @@ class C(object):
                 (beginning-of-line)
                 (point))))
    ;; Defuns on same levels should be respected.
+   (python-tests-look-at "if True:" -1)
+   (forward-line -1)
+   (should (= (save-excursion
+                (python-nav-beginning-of-defun)
+                (point))
+              (save-excursion
+                (python-tests-look-at "def a():" -1)
+                (beginning-of-line)
+                (point))))
    (python-tests-look-at "def a():" -1)
    (should (= (save-excursion
                 (python-nav-beginning-of-defun)
@@ -1822,8 +2219,16 @@ class C(object):
                 (python-tests-look-at "def b():" -1)
                 (beginning-of-line)
                 (point))))
-   ;; Jump to a top level defun.
+   ;; Jump to an upper level defun.
    (python-tests-look-at "def b():" -1)
+   (should (= (save-excursion
+                (python-nav-beginning-of-defun)
+                (point))
+              (save-excursion
+                (python-tests-look-at "def m(self):" -1)
+                (beginning-of-line)
+                (point))))
+   (forward-line -1)
    (should (= (save-excursion
                 (python-nav-beginning-of-defun)
                 (point))
@@ -1864,17 +2269,73 @@ class C(object):
 (ert-deftest python-nav-beginning-of-defun-4 ()
   (python-tests-with-temp-buffer
    "
+def a():
+    pass
+
 def \\
-        a():
+        b():
     return 0
+
+def c():
+    pass
+"
+   (python-tests-look-at "def c():")
+   (should (= (save-excursion
+                (python-nav-beginning-of-defun)
+                (point))
+              (save-excursion
+                (python-tests-look-at "def \\" -1)
+                (beginning-of-line)
+                (point))))
+   (python-tests-look-at "return 0" -1)
+   (should (= (save-excursion
+                (python-nav-beginning-of-defun)
+                (point))
+              (save-excursion
+                (python-tests-look-at "def \\" -1)
+                (beginning-of-line)
+                (point))))
+   (python-tests-look-at "b():" -1)
+   (should (= (save-excursion
+                (python-nav-beginning-of-defun)
+                (point))
+              (save-excursion
+                (python-tests-look-at "def \\" -1)
+                (beginning-of-line)
+                (point))))
+   (python-tests-look-at "def a():" -1)
+   (should (= (save-excursion
+                (python-nav-beginning-of-defun -1)
+                (point))
+              (save-excursion
+                (python-tests-look-at "def \\")
+                (beginning-of-line)
+                (point))))))
+
+(ert-deftest python-nav-beginning-of-defun-5 ()
+  (python-tests-with-temp-buffer
+   "
+class C:
+
+    def \\
+            m(self):
+        pass
 "
-   (python-tests-look-at "return 0")
+   (python-tests-look-at "m(self):")
    (should (= (save-excursion
                 (python-nav-beginning-of-defun)
                 (point))
               (save-excursion
                 (python-tests-look-at "def \\" -1)
                 (beginning-of-line)
+                (point))))
+   (python-tests-look-at "class C:" -1)
+   (should (= (save-excursion
+                (python-nav-beginning-of-defun -1)
+                (point))
+              (save-excursion
+                (python-tests-look-at "def \\")
+                (beginning-of-line)
                 (point))))))
 
 (ert-deftest python-nav-end-of-defun-1 ()
@@ -1908,6 +2369,15 @@ class C(object):
                 (python-tests-look-at "def c(self):")
                 (forward-line -1)
                 (point))))
+   (should (= (save-excursion
+                (python-tests-look-at "def b():")
+                (forward-line -1)
+                (python-nav-end-of-defun)
+                (point))
+              (save-excursion
+                (python-tests-look-at "def c(self):")
+                (forward-line -1)
+                (point))))
    (should (= (save-excursion
                 (python-tests-look-at "def b():")
                 (python-nav-end-of-defun)
@@ -1916,6 +2386,10 @@ class C(object):
                 (python-tests-look-at "def b():")
                 (forward-line 2)
                 (point))))
+   (should (not (save-excursion
+                  (python-tests-look-at "def a():")
+                  (forward-line -1)
+                  (python-nav-end-of-defun))))
    (should (= (save-excursion
                 (python-tests-look-at "def c(self):")
                 (python-nav-end-of-defun)
@@ -1964,21 +2438,21 @@ def decoratorFunctionWithArguments(arg1, arg2, arg3):
                 (point))
               (save-excursion
                 (python-tests-look-at "return wwrap")
-                (line-beginning-position))))
+                (pos-bol))))
    (should (= (save-excursion
                 (python-tests-look-at "def wrapped_f(*args):")
                 (python-nav-end-of-defun)
                 (point))
               (save-excursion
                 (python-tests-look-at "return wrapped_f")
-                (line-beginning-position))))
+                (pos-bol))))
    (should (= (save-excursion
                 (python-tests-look-at "f(*args)")
                 (python-nav-end-of-defun)
                 (point))
               (save-excursion
                 (python-tests-look-at "return wrapped_f")
-                (line-beginning-position))))))
+                (pos-bol))))))
 
 (ert-deftest python-nav-end-of-defun-3 ()
   (python-tests-with-temp-buffer
@@ -2291,14 +2765,14 @@ string
                 (point))
               (save-excursion
                 (python-tests-look-at "789")
-                (line-end-position))))
+                (pos-eol))))
    (python-tests-look-at "v2 =")
    (should (= (save-excursion
                 (python-nav-end-of-statement)
                 (point))
               (save-excursion
                 (python-tests-look-at "value4)")
-                (line-end-position))))
+                (pos-eol))))
    (python-tests-look-at "v3 =")
    (should (= (save-excursion
                 (python-nav-end-of-statement)
@@ -2306,7 +2780,7 @@ string
               (save-excursion
                 (python-tests-look-at
                  "'continue previous line')")
-                (line-end-position))))
+                (pos-eol))))
    (python-tests-look-at "v4 =")
    (should (= (save-excursion
                 (python-nav-end-of-statement)
@@ -2471,6 +2945,28 @@ def decoratorFunctionWithArguments(arg1, arg2, arg3):
                 (point))
               (python-tests-look-at "def wwrap(f):" -1)))))
 
+(ert-deftest python-nav-beginning-of-block-2 ()
+  (python-tests-with-temp-buffer
+   "
+if True:
+
+    pass
+if False:
+    # comment
+    pass
+"
+   (python-tests-look-at "if True:")
+   (forward-line)
+   (should (= (save-excursion
+                (python-nav-beginning-of-block)
+                (point))
+              (python-tests-look-at "if True:" -1)))
+   (python-tests-look-at "# comment")
+   (should (= (save-excursion
+                (python-nav-beginning-of-block)
+                (point))
+              (python-tests-look-at "if False:" -1)))))
+
 (ert-deftest python-nav-end-of-block-1 ()
   (python-tests-with-temp-buffer
    "
@@ -2508,21 +3004,33 @@ def decoratorFunctionWithArguments(arg1, arg2, arg3):
                 (point))
               (save-excursion
                 (python-tests-look-at "return wrapped_f")
-                (line-end-position))))
+                (pos-eol))))
    (end-of-line)
    (should (= (save-excursion
                 (python-nav-end-of-block)
                 (point))
               (save-excursion
                 (python-tests-look-at "return wrapped_f")
-                (line-end-position))))
+                (pos-eol))))
    (python-tests-look-at "f(*args)")
    (should (= (save-excursion
                 (python-nav-end-of-block)
                 (point))
               (save-excursion
                 (python-tests-look-at "print 'After f(*args)'")
-                (line-end-position))))))
+                (pos-eol))))))
+
+(ert-deftest python-nav-end-of-block-2 ()
+  "Ensure that `python-nav-end-of-block' does not enter an infinite loop."
+  (python-tests-with-temp-buffer
+   "def
+    =''
+ '
+\"\"\"\"\"\"
+ #
+''
+"
+   (python-nav-end-of-block)))
 
 (ert-deftest python-nav-forward-block-1 ()
   "This also accounts as a test for `python-nav-backward-block'."
@@ -2566,6 +3074,22 @@ if request.user.is_authenticated():
               (python-tests-look-at
                "if request.user.is_authenticated():" -1)))))
 
+(ert-deftest python-nav-forward-block-2 ()
+  (python-tests-with-temp-buffer
+   "
+if True:
+    pass
+"
+   (python-tests-look-at "if True:")
+   (should (not (save-excursion (python-nav-forward-block))))
+   (should (not (save-excursion (python-nav-forward-block -1))))
+   (forward-char)
+   (should (not (save-excursion (python-nav-forward-block))))
+   (should (= (save-excursion (python-nav-forward-block -1))
+              (progn
+                (end-of-line)
+                (python-tests-look-at "if True:" -1))))))
+
 (ert-deftest python-nav-forward-sexp-1 ()
   (python-tests-with-temp-buffer
    "
@@ -2784,11 +3308,11 @@ if x:
 \tabcdefg
 "
      (python-tests-look-at "abcdefg")
-     (goto-char (line-end-position))
+     (goto-char (pos-eol))
      (call-interactively #'python-indent-dedent-line-backspace)
      (should
       (string= (buffer-substring-no-properties
-                (line-beginning-position) (line-end-position))
+                (pos-bol) (pos-eol))
                "\tabcdef")))))
 
 (ert-deftest python-indent-dedent-line-backspace-3 ()
@@ -2801,27 +3325,27 @@ if x:
 \t abcdefg
 "
      (python-tests-look-at "abcdefg")
-     (goto-char (line-end-position))
+     (goto-char (pos-eol))
      (call-interactively #'python-indent-dedent-line-backspace)
      (should
       (string= (buffer-substring-no-properties
-                (line-beginning-position) (line-end-position))
+                (pos-bol) (pos-eol))
                "\t abcdef"))
      (back-to-indentation)
      (call-interactively #'python-indent-dedent-line-backspace)
      (should
       (string= (buffer-substring-no-properties
-                (line-beginning-position) (line-end-position))
+                (pos-bol) (pos-eol))
                "\tabcdef"))
      (call-interactively #'python-indent-dedent-line-backspace)
      (should
       (string= (buffer-substring-no-properties
-                (line-beginning-position) (line-end-position))
+                (pos-bol) (pos-eol))
                "    abcdef"))
      (call-interactively #'python-indent-dedent-line-backspace)
      (should
       (string= (buffer-substring-no-properties
-                (line-beginning-position) (line-end-position))
+                (pos-bol) (pos-eol))
                "abcdef")))))
 
 (ert-deftest python-bob-infloop-avoid ()
@@ -3834,11 +4358,11 @@ map(codecs.open('somefile'
 "
    (python-tests-look-at "ap(xx")
    (should (string= (python-eldoc--get-symbol-at-point) "map"))
-   (goto-char (line-end-position))
+   (goto-char (pos-eol))
    (should (string= (python-eldoc--get-symbol-at-point) "map"))
    (python-tests-look-at "('somefile'")
    (should (string= (python-eldoc--get-symbol-at-point) "map"))
-   (goto-char (line-end-position))
+   (goto-char (pos-eol))
    (should (string= (python-eldoc--get-symbol-at-point) "codecs.open"))))
 
 (ert-deftest python-eldoc--get-symbol-at-point-2 ()
@@ -4351,7 +4875,7 @@ def long_function_name(
    (should (not (python-info-beginning-of-statement-p)))
    (python-tests-look-at "print (var_one)")
    (should (python-info-beginning-of-statement-p))
-   (goto-char (line-beginning-position))
+   (goto-char (pos-bol))
    (should (not (python-info-beginning-of-statement-p)))))
 
 (ert-deftest python-info-beginning-of-statement-p-2 ()
@@ -4371,7 +4895,7 @@ if width == 0 and height == 0 and \\
    (should (not (python-info-beginning-of-statement-p)))
    (python-tests-look-at "raise ValueError(")
    (should (python-info-beginning-of-statement-p))
-   (goto-char (line-beginning-position))
+   (goto-char (pos-bol))
    (should (not (python-info-beginning-of-statement-p)))))
 
 (ert-deftest python-info-end-of-statement-p-1 ()
@@ -5189,6 +5713,56 @@ def decorat0r(deff):
    (python-tests-look-at "deff()")
    (should (not (python-info-looking-at-beginning-of-defun)))))
 
+(ert-deftest python-info-looking-at-beginning-of-defun-2 ()
+  (python-tests-with-temp-buffer
+   "
+def \\
+        foo(arg):
+    pass
+"
+   (python-tests-look-at "def \\")
+   (should (python-info-looking-at-beginning-of-defun))
+   (should (python-info-looking-at-beginning-of-defun nil t))
+   (python-tests-look-at "foo(arg):")
+   (should (not (python-info-looking-at-beginning-of-defun)))
+   (should (python-info-looking-at-beginning-of-defun nil t))
+   (python-tests-look-at "pass")
+   (should (not (python-info-looking-at-beginning-of-defun)))
+   (should (not (python-info-looking-at-beginning-of-defun nil t)))))
+
+(ert-deftest python-info-looking-at-beginning-of-block-1 ()
+  (python-tests-with-temp-buffer
+   "
+def f():
+    if True:
+        pass
+    l = [x * 2
+         for x in range(5)
+         if x < 3]
+# if False:
+\"\"\"
+if 0:
+\"\"\"
+"
+   (python-tests-look-at "def f():")
+   (should (python-info-looking-at-beginning-of-block))
+   (forward-char)
+   (should (not (python-info-looking-at-beginning-of-block)))
+   (python-tests-look-at "if True:")
+   (should (python-info-looking-at-beginning-of-block))
+   (forward-char)
+   (should (not (python-info-looking-at-beginning-of-block)))
+   (beginning-of-line)
+   (should (python-info-looking-at-beginning-of-block))
+   (python-tests-look-at "for x")
+   (should (not (python-info-looking-at-beginning-of-block)))
+   (python-tests-look-at "if x < 3")
+   (should (not (python-info-looking-at-beginning-of-block)))
+   (python-tests-look-at "if False:")
+   (should (not (python-info-looking-at-beginning-of-block)))
+   (python-tests-look-at "if 0:")
+   (should (not (python-info-looking-at-beginning-of-block)))))
+
 (ert-deftest python-info-current-line-comment-p-1 ()
   (python-tests-with-temp-buffer
    "
@@ -5642,8 +6216,11 @@ class SomeClass:
 class SomeClass:
 
     def __init__(self, arg, kwarg=1):
+
     def filter(self, nums):
-    def __str__(self):"))))
+
+    def __str__(self):
+"))))
       (or enabled (hs-minor-mode -1)))))
 
 (ert-deftest python-hideshow-hide-levels-2 ()
@@ -5689,6 +6266,165 @@ class SomeClass:
 "))))
       (or enabled (hs-minor-mode -1)))))
 
+(ert-deftest python-hideshow-hide-levels-3 ()
+  "Should hide all blocks."
+  (python-tests-with-temp-buffer
+   "
+def f():
+    if 0:
+        l = [i for i in range(5)
+             if i < 3]
+        abc = o.match(1, 2, 3)
+
+def g():
+    pass
+"
+   (hs-minor-mode 1)
+   (hs-hide-level 1)
+   (should
+    (string=
+     (python-tests-visible-string)
+     "
+def f():
+
+def g():
+"))))
+
+(ert-deftest python-hideshow-hide-levels-4 ()
+  "Should hide 2nd level block."
+  (python-tests-with-temp-buffer
+   "
+def f():
+    if 0:
+        l = [i for i in range(5)
+             if i < 3]
+        abc = o.match(1, 2, 3)
+
+def g():
+    pass
+"
+   (hs-minor-mode 1)
+   (hs-hide-level 2)
+   (should
+    (string=
+     (python-tests-visible-string)
+     "
+def f():
+    if 0:
+
+def g():
+    pass
+"))))
+
+(ert-deftest python-hideshow-hide-all-1 ()
+  "Should hide all blocks."
+  (python-tests-with-temp-buffer
+   "if 0:
+
+    aaa
+    l = [i for i in range(5)
+         if i < 3]
+    ccc
+    abc = o.match(1, 2, 3)
+    ddd
+
+def f():
+    pass
+"
+   (hs-minor-mode 1)
+   (hs-hide-all)
+   (should
+    (string=
+     (python-tests-visible-string)
+     "if 0:
+
+def f():
+"))))
+
+(ert-deftest python-hideshow-hide-all-2 ()
+  "Should hide comments."
+  (python-tests-with-temp-buffer
+   "
+# Multi line
+# comment
+
+\"\"\"
+# Multi line
+# string
+\"\"\"
+"
+   (hs-minor-mode 1)
+   (hs-hide-all)
+   (should
+    (string=
+     (python-tests-visible-string)
+     "
+# Multi line
+
+\"\"\"
+# Multi line
+# string
+\"\"\"
+"))))
+
+(ert-deftest python-hideshow-hide-all-3 ()
+  "Should not hide comments when `hs-hide-comments-when-hiding-all' is nil."
+  (python-tests-with-temp-buffer
+   "
+# Multi line
+# comment
+
+\"\"\"
+# Multi line
+# string
+\"\"\"
+"
+   (hs-minor-mode 1)
+   (let ((hs-hide-comments-when-hiding-all nil))
+     (hs-hide-all))
+   (should
+    (string=
+     (python-tests-visible-string)
+     "
+# Multi line
+# comment
+
+\"\"\"
+# Multi line
+# string
+\"\"\"
+"))))
+
+(ert-deftest python-hideshow-hide-block-1 ()
+  "Should hide current block."
+  (python-tests-with-temp-buffer
+   "
+if 0:
+
+    aaa
+    l = [i for i in range(5)
+         if i < 3]
+    ccc
+    abc = o.match(1, 2, 3)
+    ddd
+
+def f():
+    pass
+"
+   (hs-minor-mode 1)
+   (python-tests-look-at "ddd")
+   (forward-line)
+   (hs-hide-block)
+   (should
+    (string=
+     (python-tests-visible-string)
+     "
+if 0:
+
+def f():
+    pass
+"))))
+
 
 (ert-deftest python-tests--python-nav-end-of-statement--infloop ()
   "Checks that `python-nav-end-of-statement' doesn't infloop in a
@@ -5759,10 +6495,40 @@ buffer with overlapping strings."
     a = 1
 ")))
 
-(provide 'python-tests)
+
+;;; Flymake
+
+(ert-deftest python-tests--flymake-command-output-pattern ()
+  (pcase-let ((`(,patt ,line ,col ,type ,msg)
+               python-flymake-command-output-pattern))
+    ;; Pyflakes output as of version 2.4.0
+    (let ((output "<stdin>:12:34 'a.b.c as d' imported but unused"))
+      (string-match patt output)
+      (should (equal (match-string line output) "12"))
+      (when col (should (equal (match-string col output) "34")))
+      (should (equal (match-string msg output)
+                     "'a.b.c as d' imported but unused")))
+    ;; Flake8 output as of version 4.0.1
+    (let ((output "stdin:12:34: F401 'a.b.c as d' imported but unused"))
+      (string-match patt output)
+      (should (equal (match-string line output) "12"))
+      (when col (should (equal (match-string col output) "34")))
+      (when type (should (equal (match-string type output) "F401")))
+      (should (equal (match-string msg output)
+                     (if type
+                         "'a.b.c as d' imported but unused"
+                       "F401 'a.b.c as d' imported but unused"))))
+    ;; Pylint output as of version 2.14.5
+    (let ((output "stdin:12:34: W0611: Unused import a.b.c (unused-import)"))
+      (string-match patt output)
+      (should (equal (match-string line output) "12"))
+      (when col (should (equal (match-string col output) "34")))
+      (when type (should (equal (match-string type output) "W0611")))
+      (should (equal (match-string msg output)
+                     (if type
+                         "Unused import a.b.c (unused-import)"
+                       "W0611: Unused import a.b.c (unused-import)"))))))
 
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
+(provide 'python-tests)
 
 ;;; python-tests.el ends here
diff --git a/test/lisp/replace-tests.el b/test/lisp/replace-tests.el
index ef1e5c3eaf..23ec24840f 100644
--- a/test/lisp/replace-tests.el
+++ b/test/lisp/replace-tests.el
@@ -378,7 +378,7 @@ Each element has the format:
               (goto-char (point-min))
               (should (string-match "\\`2 matches for \"and\" in buffer: "
                                     (buffer-substring-no-properties
-                                     (point) (line-end-position)))))))
+                                     (point) (pos-eol)))))))
       (and (buffer-name temp-buffer)
            (kill-buffer temp-buffer)))))
 
@@ -401,7 +401,7 @@ Each element has the format:
               (goto-char (point-min))
               (should (string-match "\\`2 matches for \"and\" in buffer: "
                                     (buffer-substring-no-properties
-                                     (point) (line-end-position)))))))
+                                     (point) (pos-eol)))))))
       (and (buffer-name temp-buffer)
            (kill-buffer temp-buffer)))))
 
diff --git a/test/lisp/saveplace-tests.el b/test/lisp/saveplace-tests.el
index 6f66f3fa34..99318d295d 100644
--- a/test/lisp/saveplace-tests.el
+++ b/test/lisp/saveplace-tests.el
@@ -84,7 +84,7 @@
         (save-place-file
          (ert-resource-file "saveplace"))
         (save-place-alist nil))
-    (load-save-place-alist-from-file)
+    (save-place-load-alist-from-file)
     (should (equal save-place-alist
                    '(("/home/skangas/.emacs.d/cache/recentf" . 1306)
                      ("/home/skangas/wip/emacs/"
diff --git a/test/lisp/shadowfile-tests.el b/test/lisp/shadowfile-tests.el
index e822bc9eb6..0916f7ce68 100644
--- a/test/lisp/shadowfile-tests.el
+++ b/test/lisp/shadowfile-tests.el
@@ -55,10 +55,6 @@
       ert-remote-temporary-file-directory
       (ignore-errors (file-truename ert-remote-temporary-file-directory)))
 
-;; This should happen on hydra only.
-(when (getenv "EMACS_HYDRA_CI")
-  (add-to-list 'tramp-remote-path 'tramp-own-remote-path))
-
 (defconst shadow-test-info-file
   (expand-file-name "shadows_test" temporary-file-directory)
   "File to keep shadow information in during tests.")
diff --git a/test/lisp/simple-tests.el b/test/lisp/simple-tests.el
index b4576889dc..97f425f6f4 100644
--- a/test/lisp/simple-tests.el
+++ b/test/lisp/simple-tests.el
@@ -321,7 +321,7 @@ See bug#35036."
     ;; Stay at BOB.
     (forward-line -1)
     (save-restriction
-      (narrow-to-region (point) (line-end-position))
+      (narrow-to-region (point) (pos-eol))
       (should-not (delete-indentation))
       (should (equal (simple-test--buffer-substrings)
                      '("" . " second ")))
@@ -344,27 +344,23 @@ See bug#35036."
     (should (equal (simple-test--buffer-substrings)
                    '(" first " . "")))
     ;; Single line.
-    (should-not (delete-indentation
-                 nil (line-beginning-position) (1- (point))))
+    (should-not (delete-indentation nil (pos-bol) (1- (point))))
     (should (equal (simple-test--buffer-substrings)
                    '("" . " first ")))
-    (should-not (delete-indentation nil (1+ (point)) (line-end-position)))
+    (should-not (delete-indentation nil (1+ (point)) (pos-eol)))
     (should (equal (simple-test--buffer-substrings)
                    '(" " . "first ")))
-    (should-not (delete-indentation
-                 nil (line-beginning-position) (line-end-position)))
+    (should-not (delete-indentation nil (pos-bol) (pos-eol)))
     (should (equal (simple-test--buffer-substrings)
                    '("" . " first ")))
     ;; Multiple lines.
     (goto-char (point-max))
     (insert "\n second \n third \n fourth ")
     (goto-char (point-min))
-    (should-not (delete-indentation
-                 nil (line-end-position) (line-beginning-position 2)))
+    (should-not (delete-indentation nil (pos-eol) (pos-bol 2)))
     (should (equal (simple-test--buffer-substrings)
                    '(" first" . " second \n third \n fourth ")))
-    (should-not (delete-indentation
-                 nil (point) (1+ (line-beginning-position 2))))
+    (should-not (delete-indentation nil (point) (1+ (pos-bol 2))))
     (should (equal (simple-test--buffer-substrings)
                    '(" first second" . " third \n fourth ")))
     ;; Prefix argument overrides region.
@@ -808,7 +804,7 @@ See Bug#21722."
       (insert "a\nb\nc\nd\n")
       (goto-char (point-min))
       (forward-line (1- target-line))
-      (narrow-to-region (line-beginning-position) (line-end-position))
+      (narrow-to-region (pos-bol) (pos-eol))
       (should (equal (line-number-at-pos) 1))
       (should (equal (line-number-at-pos nil t) target-line)))))
 
@@ -817,7 +813,7 @@ See Bug#21722."
     (insert "a\nb\nc\nd\n")
     (goto-char (point-min))
     (forward-line 2)
-    (narrow-to-region (line-beginning-position) (line-end-position))
+    (narrow-to-region (pos-bol) (pos-eol))
     (should (equal (line-number-at-pos) 1))
     (line-number-at-pos nil t)
     (should (equal (line-number-at-pos) 1))))
diff --git a/test/lisp/so-long-tests/so-long-tests.el 
b/test/lisp/so-long-tests/so-long-tests.el
index d83ed34e27..bf619f453d 100644
--- a/test/lisp/so-long-tests/so-long-tests.el
+++ b/test/lisp/so-long-tests/so-long-tests.el
@@ -59,7 +59,7 @@
 (declare-function so-long-tests-assert-and-revert "so-long-tests-helpers")
 (declare-function so-long-tests-predicates "so-long-tests-helpers")
 
-;; Enable the automated behaviour for all tests.
+;; Enable the automated behavior for all tests.
 (global-so-long-mode 1)
 
 (ert-deftest so-long-tests-threshold-under ()
@@ -210,7 +210,7 @@
       ;; From Emacs 27 the `display-buffer' call is insufficient.
       ;; The various 'window change functions' are now invoked by the
       ;; redisplay, and redisplay does nothing at all in batch mode,
-      ;; so we cannot test under this revised behaviour.  Refer to:
+      ;; so we cannot test under this revised behavior.  Refer to:
       ;; https://lists.gnu.org/r/emacs-devel/2019-10/msg00971.html
       ;; For interactive (non-batch) test runs, calling `redisplay'
       ;; does do the trick; so do that first.
diff --git a/test/lisp/so-long-tests/spelling-tests.el 
b/test/lisp/so-long-tests/spelling-tests.el
index ce4b0844c9..7bd0639553 100644
--- a/test/lisp/so-long-tests/spelling-tests.el
+++ b/test/lisp/so-long-tests/spelling-tests.el
@@ -58,7 +58,7 @@
              (find-spelling-mistake
               (cl-letf (((symbol-function 'ispell-command-loop)
                          (lambda (_miss _guess word _start _end)
-                           (message "Unrecognised word: %s." word)
+                           (message "Unrecognized word: %s." word)
                            (throw 'mistake t))))
                 (catch 'mistake
                   (find-library "so-long")
diff --git a/test/lisp/subr-tests.el b/test/lisp/subr-tests.el
index a25eb363b0..3d03057f56 100644
--- a/test/lisp/subr-tests.el
+++ b/test/lisp/subr-tests.el
@@ -112,7 +112,7 @@
   (should (equal (kbd "C-x C-f") "\C-x\C-f"))
   (should (equal (kbd "C-M-<down>") [C-M-down]))
   (should (equal (kbd "<C-M-down>") [C-M-down]))
-  (should (equal (kbd "C-RET") [?\C-\C-m]))
+  (should (equal (kbd "C-RET") [?\C-\r]))
   (should (equal (kbd "C-SPC") [?\C- ]))
   (should (equal (kbd "C-TAB") [?\C-\t]))
   (should (equal (kbd "C-<down>") [C-down]))
@@ -368,6 +368,17 @@
              2)))
 
 (ert-deftest string-comparison-test ()
+  (should (string-equal-ignore-case "abc" "abc"))
+  (should (string-equal-ignore-case "abc" "ABC"))
+  (should (string-equal-ignore-case "abc" "abC"))
+  (should-not (string-equal-ignore-case "abc" "abCD"))
+  (should (string-equal-ignore-case "S" "s"))
+  (should (string-equal-ignore-case "ẞ" "ß"))
+  (should (string-equal-ignore-case "Dz" "DZ"))
+  (should (string-equal-ignore-case "Όσος" "ΌΣΟΣ"))
+  ;; not yet: (should (string-equal-ignore-case "SS" "ß"))
+  ;; not yet: (should (string-equal-ignore-case "SS" "ẞ"))
+
   (should (string-lessp "abc" "acb"))
   (should (string-lessp "aBc" "abc"))
   (should (string-lessp "abc" "abcd"))
@@ -1026,7 +1037,19 @@ final or penultimate step during initialization."))
 
 (ert-deftest test-readablep ()
   (should (readablep "foo"))
-  (should-not (readablep (list (make-marker)))))
+  (should-not (readablep (list (make-marker))))
+  (should-not (readablep (make-marker))))
+
+(ert-deftest test-print-unreadable-function ()
+  ;; Check that problem with unwinding properly is fixed (bug#56773).
+  (let* ((before nil)
+         (after nil)
+         (r (with-temp-buffer
+              (setq before (current-buffer))
+              (prog1 (readablep (make-marker))
+                (setq after (current-buffer))))))
+    (should (equal after before))
+    (should (equal r nil))))
 
 (ert-deftest test-string-lines ()
   (should (equal (string-lines "") '("")))
@@ -1081,5 +1104,31 @@ final or penultimate step during initialization."))
   (dolist (c (list ?a ?b ?α ?β))
     (should-not (char-uppercase-p c))))
 
+(ert-deftest test-plistp ()
+  (should (plistp nil))
+  (should-not (plistp 1))
+  (should (plistp '(1 2)))
+  (should-not (plistp '(1 . 2)))
+  (should (plistp '(1 2 3 4)))
+  (should-not (plistp '(1 2 3)))
+  (should-not (plistp '(1 2 3 . 4))))
+
+(defun subr-tests--butlast-ref (list &optional n)
+  "Reference implementation of `butlast'."
+  (let ((m (or n 1))
+        (len (length list)))
+    (let ((r nil))
+      (while (and list (> len m))
+        (push (car list) r)
+        (setq list (cdr list))
+        (setq len (1- len)))
+      (nreverse r))))
+
+(ert-deftest subr-butlast ()
+  (dolist (l '(nil '(a) '(a b) '(a b c) '(a b c d)))
+    (dolist (n (cons nil (number-sequence -2 6)))
+      (should (equal (butlast l n)
+                     (subr-tests--butlast-ref l n))))))
+
 (provide 'subr-tests)
 ;;; subr-tests.el ends here
diff --git a/test/lisp/textmodes/conf-mode-tests.el 
b/test/lisp/textmodes/conf-mode-tests.el
index 2b4fde40c3..097b25f114 100644
--- a/test/lisp/textmodes/conf-mode-tests.el
+++ b/test/lisp/textmodes/conf-mode-tests.el
@@ -74,8 +74,7 @@ PersistMoniker=file://Folder.htt")
 (ert-deftest conf-test-javaprop-mode ()
   (with-temp-buffer
     ;; From `conf-javaprop-mode' docstring
-    (insert "// another kind of comment
-/* yet another */
+    (insert "# comment
 
 name:value
 name=value
@@ -90,8 +89,6 @@ x.2.y.1.z.2.zz =")
     (should (equal (face-at-point) 'font-lock-comment-delimiter-face))
     (forward-char 3)
     (should (equal (face-at-point) 'font-lock-comment-face))
-    (search-forward "*")
-    (should (equal (face-at-point) 'font-lock-comment-delimiter-face))
     (while (search-forward "nam" nil t)
       (should (equal (face-at-point) 'font-lock-variable-name-face))
       (search-forward "val")
diff --git a/test/lisp/textmodes/css-mode-tests.el 
b/test/lisp/textmodes/css-mode-tests.el
index a746edf894..1d2d556992 100644
--- a/test/lisp/textmodes/css-mode-tests.el
+++ b/test/lisp/textmodes/css-mode-tests.el
@@ -435,7 +435,7 @@
                       'css-selector)
             (should-not (format "Didn't recognize %s as a selector"
                                 (buffer-substring-no-properties
-                                 (point) (line-end-position)))))))
+                                 (point) (pos-eol)))))))
       ;; Test many selectors.
       (dolist (selector selectors)
         (with-temp-buffer
@@ -451,7 +451,7 @@
                       'css-selector)
             (should-not (format "Didn't recognize %s as a selector"
                                 (buffer-substring-no-properties
-                                 (point) (line-end-position)))))))
+                                 (point) (pos-eol)))))))
       ;; Test wrong separators.
       (dolist (selector selectors)
         (with-temp-buffer
@@ -467,7 +467,7 @@
                     'css-selector)
             (should-not (format "Recognized %s as a selector"
                                 (buffer-substring-no-properties
-                                 (point) (line-end-position))))))))))
+                                 (point) (pos-eol))))))))))
 
 (ert-deftest scss-mode-test-selectors ()
   (let ((selectors
@@ -485,7 +485,7 @@
                       'css-selector)
             (should-not (format "Didn't recognize %s as a selector"
                                 (buffer-substring-no-properties
-                                 (point) (line-end-position))))))))))
+                                 (point) (pos-eol))))))))))
 
 
 (provide 'css-mode-tests)
diff --git a/test/lisp/textmodes/emacs-news-mode-resources/toggle-tag.erts 
b/test/lisp/textmodes/emacs-news-mode-resources/toggle-tag.erts
new file mode 100644
index 0000000000..63c3b1b7d8
--- /dev/null
+++ b/test/lisp/textmodes/emacs-news-mode-resources/toggle-tag.erts
@@ -0,0 +1,131 @@
+Name: tag1
+Point-Char: |
+
+=-=
++++
+*** 'dired-do-relsymlink-regexp' moved from dired-x to dired.
+The corresponding key "% Y" is now bound by default in Dired.
+
+*** 'M-G' is now bound to 'dired-goto-subdir'.
+|Before, that binding was only available with 'dired-x'.
+=-=
++++
+*** 'dired-do-relsymlink-regexp' moved from dired-x to dired.
+The corresponding key "% Y" is now bound by default in Dired.
+
+---
+*** 'M-G' is now bound to 'dired-goto-subdir'.
+|Before, that binding was only available with 'dired-x'.
+=-=-=
+
+Name: tag2
+Point-Char: |
+
+=-=
++++
+*** 'dired-do-relsymlink-regexp' moved from dired-x to dired.
+The corresponding key "% Y" is now bound by default in Dired.
+
+---
+*** 'M-G' is now bound to 'dired-goto-subdir'.
+|Before, that binding was only available if the 'dired-x' package was
+loaded.
+=-=
++++
+*** 'dired-do-relsymlink-regexp' moved from dired-x to dired.
+The corresponding key "% Y" is now bound by default in Dired.
+
++++
+*** 'M-G' is now bound to 'dired-goto-subdir'.
+|Before, that binding was only available if the 'dired-x' package was
+loaded.
+=-=-=
+
+Name: tag3
+Point-Char: |
+
+=-=
++++
+*** 'dired-do-relsymlink-regexp' moved from dired-x to dired.
+The corresponding key "% Y" is now bound by default in Dired.
+
++++
+*** 'M-G' is now bound to 'dired-goto-subdir'.
+|Before, that binding was only available if the 'dired-x' package was
+loaded.
+=-=
++++
+*** 'dired-do-relsymlink-regexp' moved from dired-x to dired.
+The corresponding key "% Y" is now bound by default in Dired.
+
+*** 'M-G' is now bound to 'dired-goto-subdir'.
+|Before, that binding was only available if the 'dired-x' package was
+loaded.
+=-=-=
+
+Name: tag4-point-at-headline
+Point-Char: |
+
+=-=
++++
+*** 'dired-do-relsymlink-regexp' moved from dired-x to dired.
+The corresponding key "% Y" is now bound by default in Dired.
+
+|*** 'M-G' is now bound to 'dired-goto-subdir'.
+Before, that binding was only available if the 'dired-x' package was
+loaded.
+=-=
++++
+*** 'dired-do-relsymlink-regexp' moved from dired-x to dired.
+The corresponding key "% Y" is now bound by default in Dired.
+
+---
+|*** 'M-G' is now bound to 'dired-goto-subdir'.
+Before, that binding was only available if the 'dired-x' package was
+loaded.
+=-=-=
+
+Name: tag5-point-at-tag
+Point-Char: |
+
+=-=
++++
+*** 'dired-do-relsymlink-regexp' moved from dired-x to dired.
+The corresponding key "% Y" is now bound by default in Dired.
+
+|---
+*** 'M-G' is now bound to 'dired-goto-subdir'.
+Before, that binding was only available if the 'dired-x' package was
+loaded.
+=-=
++++
+*** 'dired-do-relsymlink-regexp' moved from dired-x to dired.
+The corresponding key "% Y" is now bound by default in Dired.
+
+|+++
+*** 'M-G' is now bound to 'dired-goto-subdir'.
+Before, that binding was only available if the 'dired-x' package was
+loaded.
+=-=-=
+
+Name: tag6-point-at-tag
+Point-Char: |
+
+=-=
++++
+*** 'dired-do-relsymlink-regexp' moved from dired-x to dired.
+The corresponding key "% Y" is now bound by default in Dired.
+
+|+++
+*** 'M-G' is now bound to 'dired-goto-subdir'.
+Before, that binding was only available if the 'dired-x' package was
+loaded.
+=-=
++++
+*** 'dired-do-relsymlink-regexp' moved from dired-x to dired.
+The corresponding key "% Y" is now bound by default in Dired.
+
+|*** 'M-G' is now bound to 'dired-goto-subdir'.
+Before, that binding was only available if the 'dired-x' package was
+loaded.
+=-=-=
diff --git a/test/lisp/textmodes/emacs-news-mode-tests.el 
b/test/lisp/textmodes/emacs-news-mode-tests.el
new file mode 100644
index 0000000000..d2da5eda90
--- /dev/null
+++ b/test/lisp/textmodes/emacs-news-mode-tests.el
@@ -0,0 +1,32 @@
+;;; emacs-news-mode-tests.el --- Tests for emacs-news-mode.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 'ert-x)
+(require 'emacs-news-mode)
+
+(ert-deftest emacs-news-toggle-tag ()
+  (ert-test-erts-file (ert-resource-file "toggle-tag.erts")
+                      (lambda ()
+                        (emacs-news-mode)
+                        (emacs-news-toggle-tag))))
+
+;;; emacs-news-mode-tests.el ends here
diff --git a/test/lisp/textmodes/fill-tests.el 
b/test/lisp/textmodes/fill-tests.el
index b730de5a69..f2a0daf812 100644
--- a/test/lisp/textmodes/fill-tests.el
+++ b/test/lisp/textmodes/fill-tests.el
@@ -53,8 +53,8 @@
       (goto-char (point-min))
       (search-forward "b")
       (let* ((pos (point))
-             (beg (line-beginning-position))
-             (end (line-end-position))
+             (beg (pos-bol))
+             (end (pos-eol))
              (fill-prefix (make-string (- pos beg) ?\s))
              ;; `fill-column' is too small to accommodate the current line
              (fill-column (- end beg 10)))
@@ -68,8 +68,8 @@
       (goto-char (point-min))
       (search-forward "b")
       (let* ((pos (point))
-             (beg (line-beginning-position))
-             (end (line-end-position))
+             (beg (pos-bol))
+             (end (pos-eol))
              (fill-prefix (make-string (- pos beg) ?\s))
              ;; `fill-column' is too small to accommodate the current line
              (fill-column (- end beg 10)))
diff --git a/test/lisp/textmodes/reftex-tests.el 
b/test/lisp/textmodes/reftex-tests.el
index 9ef41088d1..97ff390817 100644
--- a/test/lisp/textmodes/reftex-tests.el
+++ b/test/lisp/textmodes/reftex-tests.el
@@ -190,8 +190,8 @@
 
 (ert-deftest reftex-format-citation-test ()
   "Test `reftex-format-citation'."
-  (let ((entry (reftex-parse-bibtex-entry
-"@article{Foo13,
+  (let ((entry (reftex-parse-bibtex-entry "\
+@article{Foo13,
   author =    {Jane Roe and John Doe and Jane Q. Taxpayer},
   title =        {Some Article},
   journal =    {Some Journal},
@@ -202,6 +202,137 @@
     (should (string= (reftex-format-citation entry "%l:%A:%y:%t %j %P %a")
                      "Foo13:Jane Roe:2013:Some Article Some Journal 1 Jane 
Roe, John Doe \\& Jane Taxpayer"))))
 
+(ert-deftest reftex-all-used-citation-keys ()
+  "Test `reftex-all-used-citation-keys'.
+Take the cite macros provided by biblatex package as reference."
+  (ert-with-temp-directory temp-dir
+    (let ((tex-file (expand-file-name "keys.tex" temp-dir))
+          keys)
+      (with-temp-buffer
+        (insert "\
+\\documentclass{article}
+\\usepackage{biblatex}
+\\begin{document}
+
+Standard commands:
+\\cite[pre][pos]{cite:2022}
+\\Cite[pos]{Cite:2022}
+\\parencite{parencite:2022}
+\\Parencite[pre][]{Parencite:2022}
+\\footcite[][]{footcite:2022}
+\\footcitetext[pre][pos]{footcitetext:2022}
+
+Style specific commands:
+\\textcite{textcite:2022}
+\\Textcite[pos]{Textcite:2022}
+\\smartcite[pre][pos]{smartcite:2022}
+\\Smartcite[pre][]{Smartcite:2022}
+\\cite*[pre][pos]{cite*:2022}
+\\parencite*[][]{parencite*:2022}
+
+Style independent commands:
+\\autocite[pre][pos]{autocite:2022}
+\\autocite*[pos]{autocite*:2022}
+\\Autocite[pre][]{Autocite:2022}
+\\Autocite*{Autocite*:2022}
+
+Text commands:
+\\citeauthor[pre][pos]{citeauthor:2022}
+\\citeauthor*[pre][]{citeauthor*:2022}
+\\Citeauthor[pos]{Citeauthor:2022}
+\\Citeauthor*{Citeauthor*:2022}
+\\citetitle[][]{citetitle:2022}
+\\citetitle*[pre][pos]{citetitle*:2022}
+\\citeyear[pre][pos]{citeyear:2022}
+\\citeyear*[pre][pos]{citeyear*:2022}
+\\citedate[pre][pos]{citedate:2022}
+\\citedate*[pre][pos]{citedate*:2022}
+\\citeurl[pre][pos]{citeurl:2022}
+
+Special commands:
+\\nocite{nocite:2022}
+\\fullcite[pos]{fullcite:2022}
+\\footfullcite[][]{fullfootcite:2022}
+``volcite'' macros have different number of args.
+\\volcite{2}{volcite:2022}
+\\Volcite[pre]{1}{Volcite:2022}
+\\pvolcite{1}[pg]{pvolcite:2022}
+\\Pvolcite[pre]{2}[pg]{Pvolcite:2022}
+\\fvolcite[pre]{3}[pg]{fvolcite:2022}
+\\ftvolcite[pre]{3}[pg]{ftvolcite:2022}
+\\svolcite[pre]{2}[pg]{svolcite:2022}
+\\Svolcite[pre]{4}[pg]{Svolcite:2022}
+\\tvolcite[pre]{5}[pg]{tvolcite:2022}
+\\Tvolcite[pre]{2}[pg]{Tvolcite:2022}
+\\avolcite[pre]{3}[pg]{avolcite:2022}
+\\Avolcite[pre]{1}[pg]{Avolcite:2022}
+\\Notecite[pre]{Notecite:2022}
+\\pnotecite[pre]{pnotecite:2022}
+\\Pnotecite[pre]{Pnotecite:2022}
+\\fnotecite[pre]{fnotecite:2022}
+
+Natbib compatibility commands:
+\\citet{citet:2022}
+\\citet*[pre][pos]{citet*:2022}
+\\citep[pre][pos]{citep:2022}
+\\citep*[pos]{citep*:2022}
+\\citealt[pre][]{citealt:2022}
+\\citealt*[][]{citealt*:2022}
+\\citealp[pre][pos]{citealp:2022}
+\\citealp*{citealp*:2022}
+\\Citet[pre][pos]{Citet:2022}
+\\Citet*[pre][pos]{Citet*:2022}
+\\Citep[pre][pos]{Citep:2022}
+\\Citep*[pre][pos]{Citep*:2022}
+
+Test for bug#56655:
+There was a few \\% of increase in budget \\Citep*{bug:56655}.
+
+And this should be % \\cite{ignored}.
+\\end{document}")
+        (write-region (point-min) (point-max) tex-file))
+      (find-file tex-file)
+      (setq keys (reftex-all-used-citation-keys))
+      (should (equal (sort keys #'string<)
+                     (sort '(;; Standard commands:
+                             "cite:2022"      "Cite:2022"
+                             "parencite:2022" "Parencite:2022"
+                             "footcite:2022"  "footcitetext:2022"
+                             ;; Style specific commands:
+                             "textcite:2022"  "Textcite:2022"
+                             "smartcite:2022" "Smartcite:2022"
+                             "cite*:2022" "parencite*:2022"
+                             ;; Style independent commands:
+                             "autocite:2022"  "autocite*:2022"
+                             "Autocite:2022"  "Autocite*:2022"
+                             ;; Text commands
+                             "citeauthor:2022" "citeauthor*:2022"
+                             "Citeauthor:2022" "Citeauthor*:2022"
+                             "citetitle:2022"  "citetitle*:2022"
+                             "citeyear:2022"   "citeyear*:2022"
+                             "citedate:2022"   "citedate*:2022"
+                             "citeurl:2022"
+                             ;; Special commands:
+                             "nocite:2022"     "fullcite:2022"
+                             "fullfootcite:2022"
+                             "volcite:2022"   "Volcite:2022"
+                             "pvolcite:2022"  "Pvolcite:2022"
+                             "fvolcite:2022"  "ftvolcite:2022"
+                             "svolcite:2022"  "Svolcite:2022"
+                             "tvolcite:2022"  "Tvolcite:2022"
+                             "avolcite:2022"  "Avolcite:2022"
+                             "Notecite:2022"  "pnotecite:2022"
+                             "Pnotecite:2022" "fnotecite:2022"
+                             ;; Natbib compatibility commands:
+                             "citet:2022"   "citet*:2022"
+                             "citep:2022"   "citep*:2022"
+                             "citealt:2022" "citealt*:2022"
+                             "citealp:2022" "citealp*:2022"
+                             "Citet:2022"   "Citet*:2022"
+                             "Citep:2022"   "Citep*:2022"
+                             "bug:56655")
+                           #'string<)))
+      (kill-buffer (file-name-nondirectory tex-file)))))
 
 ;;; Autoload tests
 
diff --git a/test/lisp/time-stamp-tests.el b/test/lisp/time-stamp-tests.el
index d52a19ef5d..55e37b71d8 100644
--- a/test/lisp/time-stamp-tests.el
+++ b/test/lisp/time-stamp-tests.el
@@ -147,13 +147,11 @@
                                     (string-to-number line-limit1))))
                 (goto-char (point-min))
                 (if (> limit-number 0)
-                    (should (= search-limit (line-beginning-position
-                                             (1+ limit-number))))
+                    (should (= search-limit (pos-bol (1+ limit-number))))
                   (should (= search-limit (point-max))))
                 (goto-char (point-max))
                 (if (< limit-number 0)
-                    (should (= start (line-beginning-position
-                                      (1+ limit-number))))
+                    (should (= start (pos-bol (1+ limit-number))))
                   (should (= start (point-min)))))
               (if (equal start1 "")
                   (should (equal ts-start time-stamp-start))
@@ -271,7 +269,8 @@
      (should (equal (time-stamp-string "%3a" ref-time1) Mon))
      (should (equal (time-stamp-string "%#A" ref-time1) MONDAY))
      ;; documented 1997-2019
-     (should (equal (time-stamp-string "%3A" ref-time1) MON))
+     (should (equal (time-stamp-string "%3A" ref-time1)
+                    (substring MONDAY 0 3)))
      (should (equal (time-stamp-string "%:a" ref-time1) Monday))
      ;; implemented since 2001, documented since 2019
      (should (equal (time-stamp-string "%#a" ref-time1) MON))
@@ -291,10 +290,12 @@
          (January (format-time-string "%B" ref-time1 t))
          (JANUARY (format-time-string "%^B" ref-time1 t)))
      ;; implemented and documented since 1997
-     (should (equal (time-stamp-string "%3b" ref-time1) Jan))
+     (should (equal (time-stamp-string "%3b" ref-time1)
+                    (substring January 0 3)))
      (should (equal (time-stamp-string "%#B" ref-time1) JANUARY))
      ;; documented 1997-2019
-     (should (equal (time-stamp-string "%3B" ref-time1) JAN))
+     (should (equal (time-stamp-string "%3B" ref-time1)
+                    (substring JANUARY 0 3)))
      (should (equal (time-stamp-string "%:b" ref-time1) January))
      ;; implemented since 2001, documented since 2019
      (should (equal (time-stamp-string "%#b" ref-time1) JAN))
@@ -652,15 +653,17 @@
      (should (equal (time-stamp-string "%0b" ref-time3) ""))
      (should (equal (time-stamp-string "%1b" ref-time3) (substring May 0 1)))
      (should (equal (time-stamp-string "%2b" ref-time3) (substring May 0 2)))
-     (should (equal (time-stamp-string "%3b" ref-time3) May))
+     (should (equal (time-stamp-string "%3b" ref-time3) (substring May 0 3)))
      (should (equal (time-stamp-string "%4b" ref-time3) (concat " " May)))
      (should (equal (time-stamp-string "%0%" ref-time3) ""))
      (should (equal (time-stamp-string "%1%" ref-time3) "%"))
      (should (equal (time-stamp-string "%2%" ref-time3) " %"))
      (should (equal (time-stamp-string "%9%" ref-time3) "        %"))
      (should (equal (time-stamp-string "%10%" ref-time3) "         %"))
-     (should (equal (time-stamp-string "%#3a" ref-time3) SUN))
-     (should (equal (time-stamp-string "%#3b" ref-time2) NOV)))))
+     (should (equal (time-stamp-string "%#3a" ref-time3)
+                    (substring SUN 0 3)))
+     (should (equal (time-stamp-string "%#3b" ref-time2)
+                    (substring NOV 0 3))))))
 
 ;;; Tests of helper functions
 
diff --git a/test/lisp/url/url-tramp-tests.el b/test/lisp/url/url-tramp-tests.el
index 033c17444d..369de0e245 100644
--- a/test/lisp/url/url-tramp-tests.el
+++ b/test/lisp/url/url-tramp-tests.el
@@ -55,8 +55,12 @@
     (password-cache-remove key)
     (should-not (password-in-cache-p key)))
 
-  ;; "http" does not belong to `url-tramp-protocols'.
-  (should-not (url-tramp-convert-url-to-tramp "http://www.gnu.org";)))
+  ;; "http" does not belong to `url-tramp-protocols'.  The string
+  ;; isn't changed, therefore.
+  (should
+   (string-equal
+    (url-tramp-convert-url-to-tramp "http://www.gnu.org";)
+    "http://www.gnu.org";)))
 
 (ert-deftest url-tramp-test-convert-tramp-to-url ()
   "Test that Tramp file names are converted into proper URLs."
@@ -75,8 +79,12 @@
     (url-tramp-convert-tramp-to-url "/telnet:user@remotehost#42:")
     "telnet://user@remotehost:42"))
 
-  ;; "sftp" does not belong to `url-tramp-protocols'.
-  (should-not (url-tramp-convert-tramp-to-url "/sftp:user@localhost:")))
+  ;; "sftp" does not belong to `url-tramp-protocols'.  The string
+  ;; isn't changed, therefore.
+  (should
+   (string-equal
+    (url-tramp-convert-tramp-to-url "/sftp:user@localhost:")
+    "/sftp:user@localhost:")))
 
 (provide 'url-tramp-tests)
 
diff --git a/test/lisp/url/url-util-tests.el b/test/lisp/url/url-util-tests.el
index 8c042c0135..cfc2d93c89 100644
--- a/test/lisp/url/url-util-tests.el
+++ b/test/lisp/url/url-util-tests.el
@@ -46,6 +46,26 @@
                    ("key2" "val2")
                    ("key1" "val1")))))
 
+(ert-deftest url-unhex-string-tests ()
+  (should (equal (url-unhex-string "foo%20bar")
+                 "foo bar"))
+  (should (equal (decode-coding-string (url-unhex-string "Fran%C3%A7ois") 
'utf-8)
+                 "François"))
+  (should (equal (url-unhex-string "%20%21%23%24%25%26%27%28%29%2A")
+                 " !#$%&'()*"))
+  (should (equal (url-unhex-string "%2B%2C%2F%3A%3B%3D%3F%40%5B%5D")
+                 "+,/:;=?@[]")))
+
+(ert-deftest url-hexify-string-tests ()
+  (should (equal (url-hexify-string "foo bar")
+                 "foo%20bar"))
+  (should (equal (url-hexify-string "François")
+                 "Fran%C3%A7ois"))
+  (should (equal (url-hexify-string " !#$%&'()*")
+                 "%20%21%23%24%25%26%27%28%29%2A"))
+  (should (equal (url-hexify-string "+,/:;=?@[]")
+                 "%2B%2C%2F%3A%3B%3D%3F%40%5B%5D")))
+
 (ert-deftest url-domain-tests ()
   (should (equal (url-domain (url-generic-parse-url "http://www.fsf.co.uk";))
                  "fsf.co.uk"))
diff --git a/test/lisp/whitespace-tests.el b/test/lisp/whitespace-tests.el
index 07eaad4862..2a59bfe9d8 100644
--- a/test/lisp/whitespace-tests.el
+++ b/test/lisp/whitespace-tests.el
@@ -52,9 +52,9 @@
 ;; mode.  So we call its innards instead.
 (defun whitespace-tests-whitespace-mode-on ()
   "Turn `whitespace-mode' on even in batch mode."
+  (setq whitespace-mode t)
   (whitespace-turn-on)
-  (whitespace-action-when-on)
-  (setq whitespace-mode t))
+  (whitespace-action-when-on))
 
 (ert-deftest whitespace-tests-display-tables ()
   "Test whitespace stores and restores the buffer display table - bug26892."
@@ -77,7 +77,6 @@
       ;test the stored display table is preserved
       (should (equal nil
                      (progn (whitespace-tests-whitespace-mode-on)
-                            (whitespace-tests-whitespace-mode-on)
                             (whitespace-turn-off)
                             buffer-display-table))))))
 
diff --git a/test/lisp/x-dnd-tests.el b/test/lisp/x-dnd-tests.el
index 35cda3b10a..55994e9b72 100644
--- a/test/lisp/x-dnd-tests.el
+++ b/test/lisp/x-dnd-tests.el
@@ -24,6 +24,7 @@
 ;;; Code:
 
 (require 'x-dnd)
+(require 'cl-lib)
 
 (when (display-graphic-p)
   (error "This test cannot be run under X"))
@@ -33,6 +34,9 @@
 (defconst x-dnd-tests-drag-window-xid 3948573
   "XID of the drag window returned during the test.")
 
+(defvar x-dnd-tests-xds-property-value nil
+  "The value of the `XdndDirectSave0' window property.")
+
 (defconst x-dnd-tests-targets-table
   (base64-decode-string
    
"bAArAKIBAAAGAB8AAABqAQAANgIAAJMCAAAFAwAABgMAAAEAkMJbAAEAINNbAAUAHwAAAGoBAAA2
@@ -62,7 +66,7 @@ AgAABQMAAAYDAAATGwAAGhsAAA==")
   "The expected result of parsing that targets table.")
 
 (defalias 'x-window-property
-  (lambda (prop &optional _frame type window-id _delete-p _vector-ret-p)
+  (lambda (prop &optional _frame type window-id delete-p _vector-ret-p)
     (cond
      ((and (equal prop "_MOTIF_DRAG_WINDOW")
            (zerop window-id) (equal type "WINDOW"))
@@ -70,7 +74,13 @@ AgAABQMAAAYDAAATGwAAGhsAAA==")
      ((and (equal prop "_MOTIF_DRAG_TARGETS")
            (equal type "_MOTIF_DRAG_TARGETS")
            (equal window-id x-dnd-tests-drag-window-xid))
-      x-dnd-tests-targets-table))))
+      x-dnd-tests-targets-table)
+     ((and (equal prop "XdndDirectSave0")
+           (or (equal type "text/plain")
+               (equal type "AnyPropertyType")))
+      (prog1 x-dnd-tests-xds-property-value
+        (when delete-p
+          (setq x-dnd-tests-xds-property-value nil)))))))
 
 ;; This test also serves to exercise most of the Motif value
 ;; extraction code.
@@ -78,5 +88,119 @@ AgAABQMAAAYDAAATGwAAGhsAAA==")
   (should (equal (x-dnd-xm-read-targets-table nil)
                  x-dnd-tests-lispy-targets-table)))
 
+;;; XDS tests.
+
+(defvar x-dnd-xds-testing)
+
+(defvar x-dnd-tests-xds-target-dir nil
+  "The name of the target directory where the file will be saved.")
+
+(defvar x-dnd-tests-xds-name nil
+  "The name that the dragged file should be saved under.")
+
+(defvar x-dnd-tests-xds-include-hostname nil
+  "Whether or not to include the hostname inside the XDS URI.")
+
+(defun x-dnd-tests-call-xds-converter ()
+  "Look up the XDS selection converter and call it.
+Return the result of the selection."
+  (let ((conv (cdr (assq 'XdndDirectSave0
+                         selection-converter-alist))))
+    (should (functionp conv))
+    (funcall conv 'XdndDirectSave0 'XdndDirectSave0 nil)))
+
+(defalias 'x-begin-drag
+  (lambda (_targets &optional action frame &rest _)
+    ;; Verify that frame is either nil or a valid frame.
+    (when (and frame (not (frame-live-p frame)))
+      (signal 'wrong-type-argument frame))
+    (prog1 'XdndActionDirectSave
+      ;; Verify that the action is `XdndActionDirectSave'.
+      (should (eq action 'XdndActionDirectSave))
+      ;; Set the property value to the URI of the new file.
+      (should (and (stringp x-dnd-tests-xds-property-value)
+                   (not (multibyte-string-p x-dnd-tests-xds-property-value))))
+      (let ((uri (if x-dnd-tests-xds-include-hostname
+                     (format "file://%s%s" (system-name)
+                             (expand-file-name x-dnd-tests-xds-property-value
+                                               x-dnd-tests-xds-target-dir))
+                   (concat "file://" (expand-file-name 
x-dnd-tests-xds-property-value
+                                                       
x-dnd-tests-xds-target-dir)))))
+        (setq x-dnd-tests-xds-property-value
+              (encode-coding-string (url-encode-url uri)
+                                    'raw-text)))
+      ;; Convert the selection and verify its success.
+      (should (equal (x-dnd-tests-call-xds-converter)
+                     '(STRING . "S"))))))
+
+(defalias 'x-change-window-property
+  (lambda (prop value &optional _frame type format outer-p _window-id)
+    ;; Check that the properties are the right type.
+    (should (equal prop "XdndDirectSave0"))
+    (should (equal value (encode-coding-string
+                          x-dnd-tests-xds-name
+                          (or file-name-coding-system
+                              default-file-name-coding-system))))
+    (should (equal type "text/plain"))
+    (should (equal format 8))
+    (should (not outer-p))
+    (setq x-dnd-tests-xds-property-value value)))
+
+(defalias 'x-delete-window-property
+  (lambda (&rest _args)
+    ;; This function shouldn't ever be reached during XDS.
+    (setq x-dnd-tests-xds-property-value nil)))
+
+(defun x-dnd-tests-do-direct-save-internal (include-hostname)
+  "Test the behavior of `x-dnd-do-direct-save'.
+Make it perform a direct save to a randomly generated directory,
+and check that the file exists.  If INCLUDE-HOSTNAME, include the
+hostname in the target URI."
+  (let ((x-dnd-tests-xds-include-hostname include-hostname)
+        (x-dnd-tests-xds-target-dir
+         (file-name-as-directory (expand-file-name
+                                  (make-temp-name "x-dnd-test")
+                                  temporary-file-directory)))
+        (original-file (expand-file-name
+                        (make-temp-name "x-dnd-test")
+                        temporary-file-directory))
+        (x-dnd-tests-xds-name (make-temp-name "x-dnd-test-target"))
+        (x-dnd-xds-testing t))
+    ;; The call to `gui-set-selection' is only used for providing the
+    ;; conventional `text/uri-list' target and can be ignored.
+    (cl-flet ((gui-set-selection #'ignore))
+      (unwind-protect
+          (progn
+            ;; Touch `original-file' if it doesn't exist.
+            (unless (file-exists-p original-file)
+              (write-region "" 0 original-file))
+            ;; Create `x-dnd-tests-xds-target-dir'.
+            (make-directory x-dnd-tests-xds-target-dir)
+            ;; Start the direct save and verify it returns the correct action.
+            (should (eq (x-dnd-do-direct-save original-file
+                                              x-dnd-tests-xds-name
+                                              nil nil)
+                        'XdndActionDirectSave))
+            ;; Now verify that the new file exists.
+            (should (file-exists-p
+                     (expand-file-name x-dnd-tests-xds-name
+                                       x-dnd-tests-xds-target-dir)))
+            ;; The XDS protocol makes very clear that the window
+            ;; property must be deleted after the drag-and-drop
+            ;; operation completes.
+            (should (not x-dnd-tests-xds-property-value)))
+        ;; Clean up after ourselves.
+        (ignore-errors
+          (delete-file original-file))
+        (ignore-errors
+          (delete-directory x-dnd-tests-xds-target-dir t))))))
+
+(ert-deftest x-dnd-tests-do-direct-save ()
+  ;; TODO: add tests for application/octet-stream transfer.
+  (x-dnd-tests-do-direct-save-internal nil)
+  ;; Test with both kinds of file: URIs, since different programs
+  ;; generate different kinds.
+  (x-dnd-tests-do-direct-save-internal t))
+
 (provide 'x-dnd-tests)
 ;;; x-dnd-tests.el ends here
diff --git a/test/lisp/xml-tests.el b/test/lisp/xml-tests.el
index 748f1e3944..0040e5c7ba 100644
--- a/test/lisp/xml-tests.el
+++ b/test/lisp/xml-tests.el
@@ -195,8 +195,4 @@ Parser is called with and without `symbol-qnames' 
argument.")
     (should (equal (cdr test)
                    (xml-parse-region (point-min) (point-max))))))
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; xml-tests.el ends here
diff --git a/test/lisp/xt-mouse-tests.el b/test/lisp/xt-mouse-tests.el
index 9318e8ef59..379ad7bf03 100644
--- a/test/lisp/xt-mouse-tests.el
+++ b/test/lisp/xt-mouse-tests.el
@@ -28,28 +28,34 @@
 (defmacro with-xterm-mouse-mode (&rest body)
   "Run BODY with `xterm-mouse-mode' temporarily enabled."
   (declare (indent 0))
-  ;; Make the frame huge so that the test input events below don't hit
-  ;; the menu bar.
-  `(cl-letf (((frame-width nil) 2000)
-             ((frame-height nil) 2000)
-             ;; Reset XTerm parameters so that the tests don't get
-             ;; confused.
-             ((terminal-parameter nil 'xterm-mouse-x) nil)
-             ((terminal-parameter nil 'xterm-mouse-y) nil)
-             ((terminal-parameter nil 'xterm-mouse-last-down) nil)
-             ((terminal-parameter nil 'xterm-mouse-last-click) nil))
-     (if xterm-mouse-mode
-         (progn ,@body)
-       (unwind-protect
-           (progn
-             ;; `xterm-mouse-mode' doesn't work in the initial
-             ;; terminal.  Since we can't create a second terminal in
-             ;; batch mode, fake it temporarily.
-             (cl-letf (((symbol-function 'terminal-name)
-                        (lambda (&optional _terminal) "fake-terminal")))
-               (xterm-mouse-mode))
-             ,@body)
-         (xterm-mouse-mode 0)))))
+  `(let ((width (frame-width))
+         (height (frame-height)))
+     (unwind-protect
+         (progn
+           ;; Make the frame huge so that the test input events below
+           ;; don't hit the menu bar.
+           (set-frame-width nil (max width 2000))
+           (set-frame-height nil (max height 2000))
+           (cl-letf (;; Reset XTerm parameters so that the tests don't
+                     ;; get confused.
+                     ((terminal-parameter nil 'xterm-mouse-x) nil)
+                     ((terminal-parameter nil 'xterm-mouse-y) nil)
+                     ((terminal-parameter nil 'xterm-mouse-last-down) nil)
+                     ((terminal-parameter nil 'xterm-mouse-last-click) nil))
+             (if xterm-mouse-mode
+                 ,(macroexp-progn body)
+               (unwind-protect
+                   (progn
+                     ;; `xterm-mouse-mode' doesn't work in the initial
+                     ;; terminal.  Since we can't create a second
+                     ;; terminal in batch mode, fake it temporarily.
+                     (cl-letf (((symbol-function 'terminal-name)
+                                (lambda (&optional _terminal) 
"fake-terminal")))
+                       (xterm-mouse-mode))
+                     ,@body)
+                 (xterm-mouse-mode 0)))))
+       (set-frame-width nil width)
+       (set-frame-height nil height))))
 
 (ert-deftest xt-mouse-tracking-basic ()
   (should (equal (xterm-mouse-tracking-enable-sequence)
diff --git a/test/manual/etags/ETAGS.good_1 b/test/manual/etags/ETAGS.good_1
index c3d1477d44..4baaff4c42 100644
--- a/test/manual/etags/ETAGS.good_1
+++ b/test/manual/etags/ETAGS.good_1
@@ -2941,92 +2941,92 @@ complete(328,10055
 add_active(340,10527
 parse(353,10949
 derived_analyses(364,11341
-build(378,11965
-buildact(392,12521
-mapsyn(412,13542
-add_edge(434,14278
-findcats(447,14758
-normalize_tree(465,15478
-normalize_trees(475,15856
-expandmng_tree(486,16248
-expandmng_trees(496,16614
-cat(511,17013
-subtree(644,21266
-hypothetical_mem(653,21565
-make_coor(667,22130
-start_up:-start_up688,23013
-tokenizeatom(710,23921
-tokenize(720,24348
-isoperator(752,25377
-isoptab(756,25431
-specialsymbol(765,25756
-sstab(771,25861
-parse_cgi(787,26347
-keyvalseq(792,26510
-andkeyvalseq(796,26609
-keyval(799,26688
-valseq(807,26920
-plusvalseq(810,27007
-val(816,27109
-argvals(824,27426
-commaargvals(828,27503
-atomval(833,27578
-atom(836,27640
-action(846,28004
-keyvalcgi(864,28649
-keyvalscgi(865,28670
-outsyn(868,28726
-act(876,29060
-actout(901,29906
-texttreelist(912,30089
-htmltreelist(918,30190
-fitchtreelist(924,30304
-pp_html_table_tree(938,30759
-pp_html_tree(949,31113
-pp_html_trees(988,32381
-pp_html_table_fitch_tree(999,32769
-pp_html_fitch_tree(1017,33672
-removeexp(1129,39002
-splitexp(1142,39490
-pp_exp(1155,39990
-map_word(1168,40249
-pp_exps(1180,40474
-pp_tree(1188,40777
-pp_trees(1216,41807
-pp_word_list(1225,42128
-pp_word(1231,42262
-pp_word_list_rest(1238,42569
-pp_cat(1248,42929
-pp_syn(1255,43196
-pp_syn_paren(1276,43899
-pp_paren(1293,44377
-pp_syn_back(1300,44661
-pp_bas_cat(1311,45001
-writecat(1322,45409
-writesubs(1351,46455
-writesups(1361,46757
-writelistsubs(1371,47090
-pp_lam(1380,47408
-pp_lam_bracket(1398,48022
-pp_lam_paren(1407,48338
-pp_rule(1429,49238
-member(1447,49866
-append_list(1451,49919
-append(1456,50010
-at_least_one_member(1460,50076
-numbervars(1464,50171
-reverse(1467,50209
-select(1471,50290
-select_last(1475,50357
-cat_atoms(1479,50436
-writelist(1485,50524
-write_lex_cat(1492,50676
-writebreaklex(1500,50988
-write_lex(1513,51265
-writebreak(1521,51541
-tt:-tt1531,51713
-mt:-mt1534,51784
-cmt:-cmt1537,51878
+build(378,11967
+buildact(392,12523
+mapsyn(412,13544
+add_edge(434,14280
+findcats(447,14760
+normalize_tree(465,15480
+normalize_trees(475,15858
+expandmng_tree(486,16250
+expandmng_trees(496,16616
+cat(511,17015
+subtree(644,21268
+hypothetical_mem(653,21567
+make_coor(667,22132
+start_up:-start_up688,23015
+tokenizeatom(710,23923
+tokenize(720,24350
+isoperator(752,25379
+isoptab(756,25433
+specialsymbol(765,25758
+sstab(771,25863
+parse_cgi(787,26349
+keyvalseq(792,26512
+andkeyvalseq(796,26611
+keyval(799,26690
+valseq(807,26922
+plusvalseq(810,27009
+val(816,27111
+argvals(824,27428
+commaargvals(828,27505
+atomval(833,27580
+atom(836,27642
+action(846,28006
+keyvalcgi(864,28651
+keyvalscgi(865,28672
+outsyn(868,28728
+act(876,29062
+actout(901,29908
+texttreelist(912,30091
+htmltreelist(918,30192
+fitchtreelist(924,30306
+pp_html_table_tree(938,30761
+pp_html_tree(949,31115
+pp_html_trees(988,32383
+pp_html_table_fitch_tree(999,32771
+pp_html_fitch_tree(1017,33674
+removeexp(1129,39004
+splitexp(1142,39492
+pp_exp(1155,39992
+map_word(1168,40251
+pp_exps(1180,40476
+pp_tree(1188,40779
+pp_trees(1216,41809
+pp_word_list(1225,42130
+pp_word(1231,42264
+pp_word_list_rest(1238,42571
+pp_cat(1248,42931
+pp_syn(1255,43198
+pp_syn_paren(1276,43901
+pp_paren(1293,44379
+pp_syn_back(1300,44663
+pp_bas_cat(1311,45003
+writecat(1322,45411
+writesubs(1351,46457
+writesups(1361,46759
+writelistsubs(1371,47092
+pp_lam(1380,47410
+pp_lam_bracket(1398,48024
+pp_lam_paren(1407,48340
+pp_rule(1429,49240
+member(1447,49868
+append_list(1451,49921
+append(1456,50012
+at_least_one_member(1460,50078
+numbervars(1464,50173
+reverse(1467,50211
+select(1471,50292
+select_last(1475,50359
+cat_atoms(1479,50438
+writelist(1485,50526
+write_lex_cat(1492,50678
+writebreaklex(1500,50990
+write_lex(1513,51267
+writebreak(1521,51543
+tt:-tt1531,51715
+mt:-mt1534,51786
+cmt:-cmt1537,51880
 
 pyt-src/server.py,1438
 class Controls:Controls17,358
@@ -3921,60 +3921,60 @@ merc-src/accumulator.m,3228
 :- func initialize_goal_store570,22060
 :- pred accu_store580,22421
 :- pred identify_recursive_calls601,23288
-:- pred identify_out_and_out_prime626,24396
-:- type accu_sets676,26425
-:- pred accu_stage1689,26977
-:- pred accu_stage1_2727,28347
-:- pred accu_sets_init781,30557
-:- func set_upto796,30984
-:- pred accu_before812,31498
-:- pred accu_assoc835,32477
-:- pred accu_construct862,33712
-:- pred accu_construct_assoc896,35307
-:- pred accu_update938,37069
-:- pred member_lessthan_goalid964,38219
-:- type accu_assoc975,38652
-:- pred accu_is_associative986,39138
-:- pred associativity_assertion1014,40263
-:- pred commutativity_assertion1037,41242
-:- pred accu_is_update1057,41952
-:- pred is_associative_construction1078,42802
-:- type accu_substs1095,43480
-:- type accu_base1103,43744
-:- pred accu_stage21124,44605
-:- pred accu_substs_init1179,46957
-:- pred acc_var_subst_init1194,47573
-:- pred create_new_var1207,48147
-:- pred accu_process_assoc_set1223,48862
-:- pred accu_has_heuristic1297,52081
-:- pred accu_heuristic1304,52336
-:- pred accu_process_update_set1318,52906
-:- pred accu_divide_base_case1380,55844
-:- pred accu_related1412,57146
-:- inst stored_goal_plain_call1444,58415
-:- pred lookup_call1449,58601
-:- pred accu_stage31470,59432
-:- pred acc_proc_info1508,61326
-:- pred acc_pred_info1556,63449
-:- pred accu_create_goal1600,65285
-:- func create_acc_call1621,66400
-:- pred create_orig_goal1634,66987
-:- pred create_acc_goal1662,68157
-:- func create_new_orig_recursive_goals1709,70225
-:- func create_new_recursive_goals1723,70918
-:- func create_new_base_goals1738,71717
-:- pred acc_unification1749,72156
-:- pred accu_top_level1766,72896
-:- pred update_accumulator_pred1856,76290
-:- func accu_rename1876,77253
-:- func base_case_ids1889,77784
-:- func base_case_ids_set1898,78048
-:- func accu_goal_list1905,78269
-:- pred calculate_goal_info1916,78680
-:- func chain_subst1932,79319
-:- pred chain_subst_21938,79482
-:- some [T] pred unravel_univ1956,80060
-:- pragma foreign_export1957,80116
+:- pred identify_out_and_out_prime626,24397
+:- type accu_sets676,26426
+:- pred accu_stage1689,26978
+:- pred accu_stage1_2727,28348
+:- pred accu_sets_init781,30558
+:- func set_upto796,30985
+:- pred accu_before812,31499
+:- pred accu_assoc835,32478
+:- pred accu_construct862,33713
+:- pred accu_construct_assoc896,35308
+:- pred accu_update938,37070
+:- pred member_lessthan_goalid964,38220
+:- type accu_assoc975,38653
+:- pred accu_is_associative986,39139
+:- pred associativity_assertion1014,40264
+:- pred commutativity_assertion1037,41243
+:- pred accu_is_update1057,41953
+:- pred is_associative_construction1078,42803
+:- type accu_substs1095,43481
+:- type accu_base1103,43745
+:- pred accu_stage21124,44606
+:- pred accu_substs_init1179,46958
+:- pred acc_var_subst_init1194,47574
+:- pred create_new_var1207,48148
+:- pred accu_process_assoc_set1223,48863
+:- pred accu_has_heuristic1297,52082
+:- pred accu_heuristic1304,52337
+:- pred accu_process_update_set1318,52907
+:- pred accu_divide_base_case1380,55845
+:- pred accu_related1412,57147
+:- inst stored_goal_plain_call1444,58416
+:- pred lookup_call1449,58602
+:- pred accu_stage31470,59433
+:- pred acc_proc_info1508,61327
+:- pred acc_pred_info1556,63450
+:- pred accu_create_goal1600,65286
+:- func create_acc_call1621,66401
+:- pred create_orig_goal1634,66988
+:- pred create_acc_goal1662,68158
+:- func create_new_orig_recursive_goals1709,70226
+:- func create_new_recursive_goals1723,70919
+:- func create_new_base_goals1738,71718
+:- pred acc_unification1749,72157
+:- pred accu_top_level1766,72897
+:- pred update_accumulator_pred1856,76291
+:- func accu_rename1876,77254
+:- func base_case_ids1889,77785
+:- func base_case_ids_set1898,78049
+:- func accu_goal_list1905,78270
+:- pred calculate_goal_info1916,78681
+:- func chain_subst1932,79320
+:- pred chain_subst_21938,79483
+:- some [T] pred unravel_univ1956,80061
+:- pragma foreign_export1957,80117
 
 c-src/c.c,76
 T f(1,0
diff --git a/test/manual/etags/ETAGS.good_2 b/test/manual/etags/ETAGS.good_2
index 3c611dc8ef..6e90f1e8e0 100644
--- a/test/manual/etags/ETAGS.good_2
+++ b/test/manual/etags/ETAGS.good_2
@@ -3514,92 +3514,92 @@ complete(328,10055
 add_active(340,10527
 parse(353,10949
 derived_analyses(364,11341
-build(378,11965
-buildact(392,12521
-mapsyn(412,13542
-add_edge(434,14278
-findcats(447,14758
-normalize_tree(465,15478
-normalize_trees(475,15856
-expandmng_tree(486,16248
-expandmng_trees(496,16614
-cat(511,17013
-subtree(644,21266
-hypothetical_mem(653,21565
-make_coor(667,22130
-start_up:-start_up688,23013
-tokenizeatom(710,23921
-tokenize(720,24348
-isoperator(752,25377
-isoptab(756,25431
-specialsymbol(765,25756
-sstab(771,25861
-parse_cgi(787,26347
-keyvalseq(792,26510
-andkeyvalseq(796,26609
-keyval(799,26688
-valseq(807,26920
-plusvalseq(810,27007
-val(816,27109
-argvals(824,27426
-commaargvals(828,27503
-atomval(833,27578
-atom(836,27640
-action(846,28004
-keyvalcgi(864,28649
-keyvalscgi(865,28670
-outsyn(868,28726
-act(876,29060
-actout(901,29906
-texttreelist(912,30089
-htmltreelist(918,30190
-fitchtreelist(924,30304
-pp_html_table_tree(938,30759
-pp_html_tree(949,31113
-pp_html_trees(988,32381
-pp_html_table_fitch_tree(999,32769
-pp_html_fitch_tree(1017,33672
-removeexp(1129,39002
-splitexp(1142,39490
-pp_exp(1155,39990
-map_word(1168,40249
-pp_exps(1180,40474
-pp_tree(1188,40777
-pp_trees(1216,41807
-pp_word_list(1225,42128
-pp_word(1231,42262
-pp_word_list_rest(1238,42569
-pp_cat(1248,42929
-pp_syn(1255,43196
-pp_syn_paren(1276,43899
-pp_paren(1293,44377
-pp_syn_back(1300,44661
-pp_bas_cat(1311,45001
-writecat(1322,45409
-writesubs(1351,46455
-writesups(1361,46757
-writelistsubs(1371,47090
-pp_lam(1380,47408
-pp_lam_bracket(1398,48022
-pp_lam_paren(1407,48338
-pp_rule(1429,49238
-member(1447,49866
-append_list(1451,49919
-append(1456,50010
-at_least_one_member(1460,50076
-numbervars(1464,50171
-reverse(1467,50209
-select(1471,50290
-select_last(1475,50357
-cat_atoms(1479,50436
-writelist(1485,50524
-write_lex_cat(1492,50676
-writebreaklex(1500,50988
-write_lex(1513,51265
-writebreak(1521,51541
-tt:-tt1531,51713
-mt:-mt1534,51784
-cmt:-cmt1537,51878
+build(378,11967
+buildact(392,12523
+mapsyn(412,13544
+add_edge(434,14280
+findcats(447,14760
+normalize_tree(465,15480
+normalize_trees(475,15858
+expandmng_tree(486,16250
+expandmng_trees(496,16616
+cat(511,17015
+subtree(644,21268
+hypothetical_mem(653,21567
+make_coor(667,22132
+start_up:-start_up688,23015
+tokenizeatom(710,23923
+tokenize(720,24350
+isoperator(752,25379
+isoptab(756,25433
+specialsymbol(765,25758
+sstab(771,25863
+parse_cgi(787,26349
+keyvalseq(792,26512
+andkeyvalseq(796,26611
+keyval(799,26690
+valseq(807,26922
+plusvalseq(810,27009
+val(816,27111
+argvals(824,27428
+commaargvals(828,27505
+atomval(833,27580
+atom(836,27642
+action(846,28006
+keyvalcgi(864,28651
+keyvalscgi(865,28672
+outsyn(868,28728
+act(876,29062
+actout(901,29908
+texttreelist(912,30091
+htmltreelist(918,30192
+fitchtreelist(924,30306
+pp_html_table_tree(938,30761
+pp_html_tree(949,31115
+pp_html_trees(988,32383
+pp_html_table_fitch_tree(999,32771
+pp_html_fitch_tree(1017,33674
+removeexp(1129,39004
+splitexp(1142,39492
+pp_exp(1155,39992
+map_word(1168,40251
+pp_exps(1180,40476
+pp_tree(1188,40779
+pp_trees(1216,41809
+pp_word_list(1225,42130
+pp_word(1231,42264
+pp_word_list_rest(1238,42571
+pp_cat(1248,42931
+pp_syn(1255,43198
+pp_syn_paren(1276,43901
+pp_paren(1293,44379
+pp_syn_back(1300,44663
+pp_bas_cat(1311,45003
+writecat(1322,45411
+writesubs(1351,46457
+writesups(1361,46759
+writelistsubs(1371,47092
+pp_lam(1380,47410
+pp_lam_bracket(1398,48024
+pp_lam_paren(1407,48340
+pp_rule(1429,49240
+member(1447,49868
+append_list(1451,49921
+append(1456,50012
+at_least_one_member(1460,50078
+numbervars(1464,50173
+reverse(1467,50211
+select(1471,50292
+select_last(1475,50359
+cat_atoms(1479,50438
+writelist(1485,50526
+write_lex_cat(1492,50678
+writebreaklex(1500,50990
+write_lex(1513,51267
+writebreak(1521,51543
+tt:-tt1531,51715
+mt:-mt1534,51786
+cmt:-cmt1537,51880
 
 pyt-src/server.py,1438
 class Controls:Controls17,358
@@ -4505,108 +4505,108 @@ initialize_goal_store573,22166
 accu_store584,22576
 :- pred identify_recursive_calls601,23288
 identify_recursive_calls604,23406
-:- pred identify_out_and_out_prime626,24396
-identify_out_and_out_prime631,24631
-:- type accu_sets676,26425
-:- pred accu_stage1689,26977
-accu_stage1693,27155
-:- pred accu_stage1_2727,28347
-accu_stage1_2731,28515
-:- pred accu_sets_init781,30557
-accu_sets_init783,30605
-:- func set_upto796,30984
-set_upto798,31039
-:- pred accu_before812,31498
-accu_before815,31639
-:- pred accu_assoc835,32477
-accu_assoc838,32617
-:- pred accu_construct862,33712
-accu_construct865,33856
-:- pred accu_construct_assoc896,35307
-accu_construct_assoc899,35457
-:- pred accu_update938,37069
-accu_update941,37210
-:- pred member_lessthan_goalid964,38219
-member_lessthan_goalid967,38342
-:- type accu_assoc975,38652
-:- pred accu_is_associative986,39138
-accu_is_associative989,39250
-:- pred associativity_assertion1014,40263
-associativity_assertion1017,40404
-:- pred commutativity_assertion1037,41242
-commutativity_assertion1040,41369
-:- pred accu_is_update1057,41952
-accu_is_update1060,42066
-:- pred is_associative_construction1078,42802
-is_associative_construction1081,42898
-:- type accu_substs1095,43480
-:- type accu_base1103,43744
-:- pred accu_stage21124,44605
-accu_stage21131,44946
-:- pred accu_substs_init1179,46957
-accu_substs_init1182,47097
-:- pred acc_var_subst_init1194,47573
-acc_var_subst_init1198,47718
-:- pred create_new_var1207,48147
-create_new_var1210,48288
-:- pred accu_process_assoc_set1223,48862
-accu_process_assoc_set1229,49150
-:- pred accu_has_heuristic1297,52081
-accu_has_heuristic1299,52161
-:- pred accu_heuristic1304,52336
-accu_heuristic1307,52457
-:- pred accu_process_update_set1318,52906
-accu_process_update_set1325,53221
-:- pred accu_divide_base_case1380,55844
-accu_divide_base_case1385,56059
-:- pred accu_related1412,57146
-accu_related1415,57270
-:- inst stored_goal_plain_call1444,58415
-:- pred lookup_call1449,58601
-lookup_call1452,58715
-:- pred accu_stage31470,59432
-accu_stage31477,59826
-:- pred acc_proc_info1508,61326
-acc_proc_info1512,61485
-:- pred acc_pred_info1556,63449
-acc_pred_info1559,63597
-:- pred accu_create_goal1600,65285
-accu_create_goal1607,65628
-:- func create_acc_call1621,66400
-create_acc_call1625,66569
-:- pred create_orig_goal1634,66987
-create_orig_goal1638,67176
-:- pred create_acc_goal1662,68157
-create_acc_goal1667,68380
-:- func create_new_orig_recursive_goals1709,70225
-create_new_orig_recursive_goals1712,70368
-:- func create_new_recursive_goals1723,70918
-create_new_recursive_goals1727,71108
-:- func create_new_base_goals1738,71717
-create_new_base_goals1741,71831
-:- pred acc_unification1749,72156
-acc_unification1751,72225
-:- pred accu_top_level1766,72896
-accu_top_level1770,73058
-:- pred update_accumulator_pred1856,76290
-update_accumulator_pred1859,76411
-:- func accu_rename1876,77253
-accu_rename1879,77363
-:- func base_case_ids1889,77784
-base_case_ids1891,77846
-:- func base_case_ids_set1898,78048
-base_case_ids_set1900,78113
-:- func accu_goal_list1905,78269
-accu_goal_list1907,78349
-:- pred calculate_goal_info1916,78680
-calculate_goal_info1918,78753
-:- func chain_subst1932,79319
-chain_subst1934,79378
-:- pred chain_subst_21938,79482
-chain_subst_21941,79576
-:- some [T] pred unravel_univ1956,80060
-:- pragma foreign_export1957,80116
-unravel_univ1961,80340
+:- pred identify_out_and_out_prime626,24397
+identify_out_and_out_prime631,24632
+:- type accu_sets676,26426
+:- pred accu_stage1689,26978
+accu_stage1693,27156
+:- pred accu_stage1_2727,28348
+accu_stage1_2731,28516
+:- pred accu_sets_init781,30558
+accu_sets_init783,30606
+:- func set_upto796,30985
+set_upto798,31040
+:- pred accu_before812,31499
+accu_before815,31640
+:- pred accu_assoc835,32478
+accu_assoc838,32618
+:- pred accu_construct862,33713
+accu_construct865,33857
+:- pred accu_construct_assoc896,35308
+accu_construct_assoc899,35458
+:- pred accu_update938,37070
+accu_update941,37211
+:- pred member_lessthan_goalid964,38220
+member_lessthan_goalid967,38343
+:- type accu_assoc975,38653
+:- pred accu_is_associative986,39139
+accu_is_associative989,39251
+:- pred associativity_assertion1014,40264
+associativity_assertion1017,40405
+:- pred commutativity_assertion1037,41243
+commutativity_assertion1040,41370
+:- pred accu_is_update1057,41953
+accu_is_update1060,42067
+:- pred is_associative_construction1078,42803
+is_associative_construction1081,42899
+:- type accu_substs1095,43481
+:- type accu_base1103,43745
+:- pred accu_stage21124,44606
+accu_stage21131,44947
+:- pred accu_substs_init1179,46958
+accu_substs_init1182,47098
+:- pred acc_var_subst_init1194,47574
+acc_var_subst_init1198,47719
+:- pred create_new_var1207,48148
+create_new_var1210,48289
+:- pred accu_process_assoc_set1223,48863
+accu_process_assoc_set1229,49151
+:- pred accu_has_heuristic1297,52082
+accu_has_heuristic1299,52162
+:- pred accu_heuristic1304,52337
+accu_heuristic1307,52458
+:- pred accu_process_update_set1318,52907
+accu_process_update_set1325,53222
+:- pred accu_divide_base_case1380,55845
+accu_divide_base_case1385,56060
+:- pred accu_related1412,57147
+accu_related1415,57271
+:- inst stored_goal_plain_call1444,58416
+:- pred lookup_call1449,58602
+lookup_call1452,58716
+:- pred accu_stage31470,59433
+accu_stage31477,59827
+:- pred acc_proc_info1508,61327
+acc_proc_info1512,61486
+:- pred acc_pred_info1556,63450
+acc_pred_info1559,63598
+:- pred accu_create_goal1600,65286
+accu_create_goal1607,65629
+:- func create_acc_call1621,66401
+create_acc_call1625,66570
+:- pred create_orig_goal1634,66988
+create_orig_goal1638,67177
+:- pred create_acc_goal1662,68158
+create_acc_goal1667,68381
+:- func create_new_orig_recursive_goals1709,70226
+create_new_orig_recursive_goals1712,70369
+:- func create_new_recursive_goals1723,70919
+create_new_recursive_goals1727,71109
+:- func create_new_base_goals1738,71718
+create_new_base_goals1741,71832
+:- pred acc_unification1749,72157
+acc_unification1751,72226
+:- pred accu_top_level1766,72897
+accu_top_level1770,73059
+:- pred update_accumulator_pred1856,76291
+update_accumulator_pred1859,76412
+:- func accu_rename1876,77254
+accu_rename1879,77364
+:- func base_case_ids1889,77785
+base_case_ids1891,77847
+:- func base_case_ids_set1898,78049
+base_case_ids_set1900,78114
+:- func accu_goal_list1905,78270
+accu_goal_list1907,78350
+:- pred calculate_goal_info1916,78681
+calculate_goal_info1918,78754
+:- func chain_subst1932,79320
+chain_subst1934,79379
+:- pred chain_subst_21938,79483
+chain_subst_21941,79577
+:- some [T] pred unravel_univ1956,80061
+:- pragma foreign_export1957,80117
+unravel_univ1961,80341
 
 c-src/c.c,76
 T f(1,0
diff --git a/test/manual/etags/ETAGS.good_3 b/test/manual/etags/ETAGS.good_3
index 45507706b3..15ed7855b3 100644
--- a/test/manual/etags/ETAGS.good_3
+++ b/test/manual/etags/ETAGS.good_3
@@ -3348,92 +3348,92 @@ complete(328,10055
 add_active(340,10527
 parse(353,10949
 derived_analyses(364,11341
-build(378,11965
-buildact(392,12521
-mapsyn(412,13542
-add_edge(434,14278
-findcats(447,14758
-normalize_tree(465,15478
-normalize_trees(475,15856
-expandmng_tree(486,16248
-expandmng_trees(496,16614
-cat(511,17013
-subtree(644,21266
-hypothetical_mem(653,21565
-make_coor(667,22130
-start_up:-start_up688,23013
-tokenizeatom(710,23921
-tokenize(720,24348
-isoperator(752,25377
-isoptab(756,25431
-specialsymbol(765,25756
-sstab(771,25861
-parse_cgi(787,26347
-keyvalseq(792,26510
-andkeyvalseq(796,26609
-keyval(799,26688
-valseq(807,26920
-plusvalseq(810,27007
-val(816,27109
-argvals(824,27426
-commaargvals(828,27503
-atomval(833,27578
-atom(836,27640
-action(846,28004
-keyvalcgi(864,28649
-keyvalscgi(865,28670
-outsyn(868,28726
-act(876,29060
-actout(901,29906
-texttreelist(912,30089
-htmltreelist(918,30190
-fitchtreelist(924,30304
-pp_html_table_tree(938,30759
-pp_html_tree(949,31113
-pp_html_trees(988,32381
-pp_html_table_fitch_tree(999,32769
-pp_html_fitch_tree(1017,33672
-removeexp(1129,39002
-splitexp(1142,39490
-pp_exp(1155,39990
-map_word(1168,40249
-pp_exps(1180,40474
-pp_tree(1188,40777
-pp_trees(1216,41807
-pp_word_list(1225,42128
-pp_word(1231,42262
-pp_word_list_rest(1238,42569
-pp_cat(1248,42929
-pp_syn(1255,43196
-pp_syn_paren(1276,43899
-pp_paren(1293,44377
-pp_syn_back(1300,44661
-pp_bas_cat(1311,45001
-writecat(1322,45409
-writesubs(1351,46455
-writesups(1361,46757
-writelistsubs(1371,47090
-pp_lam(1380,47408
-pp_lam_bracket(1398,48022
-pp_lam_paren(1407,48338
-pp_rule(1429,49238
-member(1447,49866
-append_list(1451,49919
-append(1456,50010
-at_least_one_member(1460,50076
-numbervars(1464,50171
-reverse(1467,50209
-select(1471,50290
-select_last(1475,50357
-cat_atoms(1479,50436
-writelist(1485,50524
-write_lex_cat(1492,50676
-writebreaklex(1500,50988
-write_lex(1513,51265
-writebreak(1521,51541
-tt:-tt1531,51713
-mt:-mt1534,51784
-cmt:-cmt1537,51878
+build(378,11967
+buildact(392,12523
+mapsyn(412,13544
+add_edge(434,14280
+findcats(447,14760
+normalize_tree(465,15480
+normalize_trees(475,15858
+expandmng_tree(486,16250
+expandmng_trees(496,16616
+cat(511,17015
+subtree(644,21268
+hypothetical_mem(653,21567
+make_coor(667,22132
+start_up:-start_up688,23015
+tokenizeatom(710,23923
+tokenize(720,24350
+isoperator(752,25379
+isoptab(756,25433
+specialsymbol(765,25758
+sstab(771,25863
+parse_cgi(787,26349
+keyvalseq(792,26512
+andkeyvalseq(796,26611
+keyval(799,26690
+valseq(807,26922
+plusvalseq(810,27009
+val(816,27111
+argvals(824,27428
+commaargvals(828,27505
+atomval(833,27580
+atom(836,27642
+action(846,28006
+keyvalcgi(864,28651
+keyvalscgi(865,28672
+outsyn(868,28728
+act(876,29062
+actout(901,29908
+texttreelist(912,30091
+htmltreelist(918,30192
+fitchtreelist(924,30306
+pp_html_table_tree(938,30761
+pp_html_tree(949,31115
+pp_html_trees(988,32383
+pp_html_table_fitch_tree(999,32771
+pp_html_fitch_tree(1017,33674
+removeexp(1129,39004
+splitexp(1142,39492
+pp_exp(1155,39992
+map_word(1168,40251
+pp_exps(1180,40476
+pp_tree(1188,40779
+pp_trees(1216,41809
+pp_word_list(1225,42130
+pp_word(1231,42264
+pp_word_list_rest(1238,42571
+pp_cat(1248,42931
+pp_syn(1255,43198
+pp_syn_paren(1276,43901
+pp_paren(1293,44379
+pp_syn_back(1300,44663
+pp_bas_cat(1311,45003
+writecat(1322,45411
+writesubs(1351,46457
+writesups(1361,46759
+writelistsubs(1371,47092
+pp_lam(1380,47410
+pp_lam_bracket(1398,48024
+pp_lam_paren(1407,48340
+pp_rule(1429,49240
+member(1447,49868
+append_list(1451,49921
+append(1456,50012
+at_least_one_member(1460,50078
+numbervars(1464,50173
+reverse(1467,50211
+select(1471,50292
+select_last(1475,50359
+cat_atoms(1479,50438
+writelist(1485,50526
+write_lex_cat(1492,50678
+writebreaklex(1500,50990
+write_lex(1513,51267
+writebreak(1521,51543
+tt:-tt1531,51715
+mt:-mt1534,51786
+cmt:-cmt1537,51880
 
 pyt-src/server.py,1438
 class Controls:Controls17,358
@@ -4328,60 +4328,60 @@ merc-src/accumulator.m,3228
 :- func initialize_goal_store570,22060
 :- pred accu_store580,22421
 :- pred identify_recursive_calls601,23288
-:- pred identify_out_and_out_prime626,24396
-:- type accu_sets676,26425
-:- pred accu_stage1689,26977
-:- pred accu_stage1_2727,28347
-:- pred accu_sets_init781,30557
-:- func set_upto796,30984
-:- pred accu_before812,31498
-:- pred accu_assoc835,32477
-:- pred accu_construct862,33712
-:- pred accu_construct_assoc896,35307
-:- pred accu_update938,37069
-:- pred member_lessthan_goalid964,38219
-:- type accu_assoc975,38652
-:- pred accu_is_associative986,39138
-:- pred associativity_assertion1014,40263
-:- pred commutativity_assertion1037,41242
-:- pred accu_is_update1057,41952
-:- pred is_associative_construction1078,42802
-:- type accu_substs1095,43480
-:- type accu_base1103,43744
-:- pred accu_stage21124,44605
-:- pred accu_substs_init1179,46957
-:- pred acc_var_subst_init1194,47573
-:- pred create_new_var1207,48147
-:- pred accu_process_assoc_set1223,48862
-:- pred accu_has_heuristic1297,52081
-:- pred accu_heuristic1304,52336
-:- pred accu_process_update_set1318,52906
-:- pred accu_divide_base_case1380,55844
-:- pred accu_related1412,57146
-:- inst stored_goal_plain_call1444,58415
-:- pred lookup_call1449,58601
-:- pred accu_stage31470,59432
-:- pred acc_proc_info1508,61326
-:- pred acc_pred_info1556,63449
-:- pred accu_create_goal1600,65285
-:- func create_acc_call1621,66400
-:- pred create_orig_goal1634,66987
-:- pred create_acc_goal1662,68157
-:- func create_new_orig_recursive_goals1709,70225
-:- func create_new_recursive_goals1723,70918
-:- func create_new_base_goals1738,71717
-:- pred acc_unification1749,72156
-:- pred accu_top_level1766,72896
-:- pred update_accumulator_pred1856,76290
-:- func accu_rename1876,77253
-:- func base_case_ids1889,77784
-:- func base_case_ids_set1898,78048
-:- func accu_goal_list1905,78269
-:- pred calculate_goal_info1916,78680
-:- func chain_subst1932,79319
-:- pred chain_subst_21938,79482
-:- some [T] pred unravel_univ1956,80060
-:- pragma foreign_export1957,80116
+:- pred identify_out_and_out_prime626,24397
+:- type accu_sets676,26426
+:- pred accu_stage1689,26978
+:- pred accu_stage1_2727,28348
+:- pred accu_sets_init781,30558
+:- func set_upto796,30985
+:- pred accu_before812,31499
+:- pred accu_assoc835,32478
+:- pred accu_construct862,33713
+:- pred accu_construct_assoc896,35308
+:- pred accu_update938,37070
+:- pred member_lessthan_goalid964,38220
+:- type accu_assoc975,38653
+:- pred accu_is_associative986,39139
+:- pred associativity_assertion1014,40264
+:- pred commutativity_assertion1037,41243
+:- pred accu_is_update1057,41953
+:- pred is_associative_construction1078,42803
+:- type accu_substs1095,43481
+:- type accu_base1103,43745
+:- pred accu_stage21124,44606
+:- pred accu_substs_init1179,46958
+:- pred acc_var_subst_init1194,47574
+:- pred create_new_var1207,48148
+:- pred accu_process_assoc_set1223,48863
+:- pred accu_has_heuristic1297,52082
+:- pred accu_heuristic1304,52337
+:- pred accu_process_update_set1318,52907
+:- pred accu_divide_base_case1380,55845
+:- pred accu_related1412,57147
+:- inst stored_goal_plain_call1444,58416
+:- pred lookup_call1449,58602
+:- pred accu_stage31470,59433
+:- pred acc_proc_info1508,61327
+:- pred acc_pred_info1556,63450
+:- pred accu_create_goal1600,65286
+:- func create_acc_call1621,66401
+:- pred create_orig_goal1634,66988
+:- pred create_acc_goal1662,68158
+:- func create_new_orig_recursive_goals1709,70226
+:- func create_new_recursive_goals1723,70919
+:- func create_new_base_goals1738,71718
+:- pred acc_unification1749,72157
+:- pred accu_top_level1766,72897
+:- pred update_accumulator_pred1856,76291
+:- func accu_rename1876,77254
+:- func base_case_ids1889,77785
+:- func base_case_ids_set1898,78049
+:- func accu_goal_list1905,78270
+:- pred calculate_goal_info1916,78681
+:- func chain_subst1932,79320
+:- pred chain_subst_21938,79483
+:- some [T] pred unravel_univ1956,80061
+:- pragma foreign_export1957,80117
 
 c-src/c.c,76
 T f(1,0
diff --git a/test/manual/etags/ETAGS.good_4 b/test/manual/etags/ETAGS.good_4
index dee534ae75..dc65a09fdc 100644
--- a/test/manual/etags/ETAGS.good_4
+++ b/test/manual/etags/ETAGS.good_4
@@ -3103,92 +3103,92 @@ complete(328,10055
 add_active(340,10527
 parse(353,10949
 derived_analyses(364,11341
-build(378,11965
-buildact(392,12521
-mapsyn(412,13542
-add_edge(434,14278
-findcats(447,14758
-normalize_tree(465,15478
-normalize_trees(475,15856
-expandmng_tree(486,16248
-expandmng_trees(496,16614
-cat(511,17013
-subtree(644,21266
-hypothetical_mem(653,21565
-make_coor(667,22130
-start_up:-start_up688,23013
-tokenizeatom(710,23921
-tokenize(720,24348
-isoperator(752,25377
-isoptab(756,25431
-specialsymbol(765,25756
-sstab(771,25861
-parse_cgi(787,26347
-keyvalseq(792,26510
-andkeyvalseq(796,26609
-keyval(799,26688
-valseq(807,26920
-plusvalseq(810,27007
-val(816,27109
-argvals(824,27426
-commaargvals(828,27503
-atomval(833,27578
-atom(836,27640
-action(846,28004
-keyvalcgi(864,28649
-keyvalscgi(865,28670
-outsyn(868,28726
-act(876,29060
-actout(901,29906
-texttreelist(912,30089
-htmltreelist(918,30190
-fitchtreelist(924,30304
-pp_html_table_tree(938,30759
-pp_html_tree(949,31113
-pp_html_trees(988,32381
-pp_html_table_fitch_tree(999,32769
-pp_html_fitch_tree(1017,33672
-removeexp(1129,39002
-splitexp(1142,39490
-pp_exp(1155,39990
-map_word(1168,40249
-pp_exps(1180,40474
-pp_tree(1188,40777
-pp_trees(1216,41807
-pp_word_list(1225,42128
-pp_word(1231,42262
-pp_word_list_rest(1238,42569
-pp_cat(1248,42929
-pp_syn(1255,43196
-pp_syn_paren(1276,43899
-pp_paren(1293,44377
-pp_syn_back(1300,44661
-pp_bas_cat(1311,45001
-writecat(1322,45409
-writesubs(1351,46455
-writesups(1361,46757
-writelistsubs(1371,47090
-pp_lam(1380,47408
-pp_lam_bracket(1398,48022
-pp_lam_paren(1407,48338
-pp_rule(1429,49238
-member(1447,49866
-append_list(1451,49919
-append(1456,50010
-at_least_one_member(1460,50076
-numbervars(1464,50171
-reverse(1467,50209
-select(1471,50290
-select_last(1475,50357
-cat_atoms(1479,50436
-writelist(1485,50524
-write_lex_cat(1492,50676
-writebreaklex(1500,50988
-write_lex(1513,51265
-writebreak(1521,51541
-tt:-tt1531,51713
-mt:-mt1534,51784
-cmt:-cmt1537,51878
+build(378,11967
+buildact(392,12523
+mapsyn(412,13544
+add_edge(434,14280
+findcats(447,14760
+normalize_tree(465,15480
+normalize_trees(475,15858
+expandmng_tree(486,16250
+expandmng_trees(496,16616
+cat(511,17015
+subtree(644,21268
+hypothetical_mem(653,21567
+make_coor(667,22132
+start_up:-start_up688,23015
+tokenizeatom(710,23923
+tokenize(720,24350
+isoperator(752,25379
+isoptab(756,25433
+specialsymbol(765,25758
+sstab(771,25863
+parse_cgi(787,26349
+keyvalseq(792,26512
+andkeyvalseq(796,26611
+keyval(799,26690
+valseq(807,26922
+plusvalseq(810,27009
+val(816,27111
+argvals(824,27428
+commaargvals(828,27505
+atomval(833,27580
+atom(836,27642
+action(846,28006
+keyvalcgi(864,28651
+keyvalscgi(865,28672
+outsyn(868,28728
+act(876,29062
+actout(901,29908
+texttreelist(912,30091
+htmltreelist(918,30192
+fitchtreelist(924,30306
+pp_html_table_tree(938,30761
+pp_html_tree(949,31115
+pp_html_trees(988,32383
+pp_html_table_fitch_tree(999,32771
+pp_html_fitch_tree(1017,33674
+removeexp(1129,39004
+splitexp(1142,39492
+pp_exp(1155,39992
+map_word(1168,40251
+pp_exps(1180,40476
+pp_tree(1188,40779
+pp_trees(1216,41809
+pp_word_list(1225,42130
+pp_word(1231,42264
+pp_word_list_rest(1238,42571
+pp_cat(1248,42931
+pp_syn(1255,43198
+pp_syn_paren(1276,43901
+pp_paren(1293,44379
+pp_syn_back(1300,44663
+pp_bas_cat(1311,45003
+writecat(1322,45411
+writesubs(1351,46457
+writesups(1361,46759
+writelistsubs(1371,47092
+pp_lam(1380,47410
+pp_lam_bracket(1398,48024
+pp_lam_paren(1407,48340
+pp_rule(1429,49240
+member(1447,49868
+append_list(1451,49921
+append(1456,50012
+at_least_one_member(1460,50078
+numbervars(1464,50173
+reverse(1467,50211
+select(1471,50292
+select_last(1475,50359
+cat_atoms(1479,50438
+writelist(1485,50526
+write_lex_cat(1492,50678
+writebreaklex(1500,50990
+write_lex(1513,51267
+writebreak(1521,51543
+tt:-tt1531,51715
+mt:-mt1534,51786
+cmt:-cmt1537,51880
 
 pyt-src/server.py,1438
 class Controls:Controls17,358
@@ -4083,60 +4083,60 @@ merc-src/accumulator.m,3228
 :- func initialize_goal_store570,22060
 :- pred accu_store580,22421
 :- pred identify_recursive_calls601,23288
-:- pred identify_out_and_out_prime626,24396
-:- type accu_sets676,26425
-:- pred accu_stage1689,26977
-:- pred accu_stage1_2727,28347
-:- pred accu_sets_init781,30557
-:- func set_upto796,30984
-:- pred accu_before812,31498
-:- pred accu_assoc835,32477
-:- pred accu_construct862,33712
-:- pred accu_construct_assoc896,35307
-:- pred accu_update938,37069
-:- pred member_lessthan_goalid964,38219
-:- type accu_assoc975,38652
-:- pred accu_is_associative986,39138
-:- pred associativity_assertion1014,40263
-:- pred commutativity_assertion1037,41242
-:- pred accu_is_update1057,41952
-:- pred is_associative_construction1078,42802
-:- type accu_substs1095,43480
-:- type accu_base1103,43744
-:- pred accu_stage21124,44605
-:- pred accu_substs_init1179,46957
-:- pred acc_var_subst_init1194,47573
-:- pred create_new_var1207,48147
-:- pred accu_process_assoc_set1223,48862
-:- pred accu_has_heuristic1297,52081
-:- pred accu_heuristic1304,52336
-:- pred accu_process_update_set1318,52906
-:- pred accu_divide_base_case1380,55844
-:- pred accu_related1412,57146
-:- inst stored_goal_plain_call1444,58415
-:- pred lookup_call1449,58601
-:- pred accu_stage31470,59432
-:- pred acc_proc_info1508,61326
-:- pred acc_pred_info1556,63449
-:- pred accu_create_goal1600,65285
-:- func create_acc_call1621,66400
-:- pred create_orig_goal1634,66987
-:- pred create_acc_goal1662,68157
-:- func create_new_orig_recursive_goals1709,70225
-:- func create_new_recursive_goals1723,70918
-:- func create_new_base_goals1738,71717
-:- pred acc_unification1749,72156
-:- pred accu_top_level1766,72896
-:- pred update_accumulator_pred1856,76290
-:- func accu_rename1876,77253
-:- func base_case_ids1889,77784
-:- func base_case_ids_set1898,78048
-:- func accu_goal_list1905,78269
-:- pred calculate_goal_info1916,78680
-:- func chain_subst1932,79319
-:- pred chain_subst_21938,79482
-:- some [T] pred unravel_univ1956,80060
-:- pragma foreign_export1957,80116
+:- pred identify_out_and_out_prime626,24397
+:- type accu_sets676,26426
+:- pred accu_stage1689,26978
+:- pred accu_stage1_2727,28348
+:- pred accu_sets_init781,30558
+:- func set_upto796,30985
+:- pred accu_before812,31499
+:- pred accu_assoc835,32478
+:- pred accu_construct862,33713
+:- pred accu_construct_assoc896,35308
+:- pred accu_update938,37070
+:- pred member_lessthan_goalid964,38220
+:- type accu_assoc975,38653
+:- pred accu_is_associative986,39139
+:- pred associativity_assertion1014,40264
+:- pred commutativity_assertion1037,41243
+:- pred accu_is_update1057,41953
+:- pred is_associative_construction1078,42803
+:- type accu_substs1095,43481
+:- type accu_base1103,43745
+:- pred accu_stage21124,44606
+:- pred accu_substs_init1179,46958
+:- pred acc_var_subst_init1194,47574
+:- pred create_new_var1207,48148
+:- pred accu_process_assoc_set1223,48863
+:- pred accu_has_heuristic1297,52082
+:- pred accu_heuristic1304,52337
+:- pred accu_process_update_set1318,52907
+:- pred accu_divide_base_case1380,55845
+:- pred accu_related1412,57147
+:- inst stored_goal_plain_call1444,58416
+:- pred lookup_call1449,58602
+:- pred accu_stage31470,59433
+:- pred acc_proc_info1508,61327
+:- pred acc_pred_info1556,63450
+:- pred accu_create_goal1600,65286
+:- func create_acc_call1621,66401
+:- pred create_orig_goal1634,66988
+:- pred create_acc_goal1662,68158
+:- func create_new_orig_recursive_goals1709,70226
+:- func create_new_recursive_goals1723,70919
+:- func create_new_base_goals1738,71718
+:- pred acc_unification1749,72157
+:- pred accu_top_level1766,72897
+:- pred update_accumulator_pred1856,76291
+:- func accu_rename1876,77254
+:- func base_case_ids1889,77785
+:- func base_case_ids_set1898,78049
+:- func accu_goal_list1905,78270
+:- pred calculate_goal_info1916,78681
+:- func chain_subst1932,79320
+:- pred chain_subst_21938,79483
+:- some [T] pred unravel_univ1956,80061
+:- pragma foreign_export1957,80117
 
 c-src/c.c,76
 T f(1,0
diff --git a/test/manual/etags/ETAGS.good_5 b/test/manual/etags/ETAGS.good_5
index 6410685cb3..3e238a50f3 100644
--- a/test/manual/etags/ETAGS.good_5
+++ b/test/manual/etags/ETAGS.good_5
@@ -4083,92 +4083,92 @@ complete(328,10055
 add_active(340,10527
 parse(353,10949
 derived_analyses(364,11341
-build(378,11965
-buildact(392,12521
-mapsyn(412,13542
-add_edge(434,14278
-findcats(447,14758
-normalize_tree(465,15478
-normalize_trees(475,15856
-expandmng_tree(486,16248
-expandmng_trees(496,16614
-cat(511,17013
-subtree(644,21266
-hypothetical_mem(653,21565
-make_coor(667,22130
-start_up:-start_up688,23013
-tokenizeatom(710,23921
-tokenize(720,24348
-isoperator(752,25377
-isoptab(756,25431
-specialsymbol(765,25756
-sstab(771,25861
-parse_cgi(787,26347
-keyvalseq(792,26510
-andkeyvalseq(796,26609
-keyval(799,26688
-valseq(807,26920
-plusvalseq(810,27007
-val(816,27109
-argvals(824,27426
-commaargvals(828,27503
-atomval(833,27578
-atom(836,27640
-action(846,28004
-keyvalcgi(864,28649
-keyvalscgi(865,28670
-outsyn(868,28726
-act(876,29060
-actout(901,29906
-texttreelist(912,30089
-htmltreelist(918,30190
-fitchtreelist(924,30304
-pp_html_table_tree(938,30759
-pp_html_tree(949,31113
-pp_html_trees(988,32381
-pp_html_table_fitch_tree(999,32769
-pp_html_fitch_tree(1017,33672
-removeexp(1129,39002
-splitexp(1142,39490
-pp_exp(1155,39990
-map_word(1168,40249
-pp_exps(1180,40474
-pp_tree(1188,40777
-pp_trees(1216,41807
-pp_word_list(1225,42128
-pp_word(1231,42262
-pp_word_list_rest(1238,42569
-pp_cat(1248,42929
-pp_syn(1255,43196
-pp_syn_paren(1276,43899
-pp_paren(1293,44377
-pp_syn_back(1300,44661
-pp_bas_cat(1311,45001
-writecat(1322,45409
-writesubs(1351,46455
-writesups(1361,46757
-writelistsubs(1371,47090
-pp_lam(1380,47408
-pp_lam_bracket(1398,48022
-pp_lam_paren(1407,48338
-pp_rule(1429,49238
-member(1447,49866
-append_list(1451,49919
-append(1456,50010
-at_least_one_member(1460,50076
-numbervars(1464,50171
-reverse(1467,50209
-select(1471,50290
-select_last(1475,50357
-cat_atoms(1479,50436
-writelist(1485,50524
-write_lex_cat(1492,50676
-writebreaklex(1500,50988
-write_lex(1513,51265
-writebreak(1521,51541
-tt:-tt1531,51713
-mt:-mt1534,51784
-cmt:-cmt1537,51878
+build(378,11967
+buildact(392,12523
+mapsyn(412,13544
+add_edge(434,14280
+findcats(447,14760
+normalize_tree(465,15480
+normalize_trees(475,15858
+expandmng_tree(486,16250
+expandmng_trees(496,16616
+cat(511,17015
+subtree(644,21268
+hypothetical_mem(653,21567
+make_coor(667,22132
+start_up:-start_up688,23015
+tokenizeatom(710,23923
+tokenize(720,24350
+isoperator(752,25379
+isoptab(756,25433
+specialsymbol(765,25758
+sstab(771,25863
+parse_cgi(787,26349
+keyvalseq(792,26512
+andkeyvalseq(796,26611
+keyval(799,26690
+valseq(807,26922
+plusvalseq(810,27009
+val(816,27111
+argvals(824,27428
+commaargvals(828,27505
+atomval(833,27580
+atom(836,27642
+action(846,28006
+keyvalcgi(864,28651
+keyvalscgi(865,28672
+outsyn(868,28728
+act(876,29062
+actout(901,29908
+texttreelist(912,30091
+htmltreelist(918,30192
+fitchtreelist(924,30306
+pp_html_table_tree(938,30761
+pp_html_tree(949,31115
+pp_html_trees(988,32383
+pp_html_table_fitch_tree(999,32771
+pp_html_fitch_tree(1017,33674
+removeexp(1129,39004
+splitexp(1142,39492
+pp_exp(1155,39992
+map_word(1168,40251
+pp_exps(1180,40476
+pp_tree(1188,40779
+pp_trees(1216,41809
+pp_word_list(1225,42130
+pp_word(1231,42264
+pp_word_list_rest(1238,42571
+pp_cat(1248,42931
+pp_syn(1255,43198
+pp_syn_paren(1276,43901
+pp_paren(1293,44379
+pp_syn_back(1300,44663
+pp_bas_cat(1311,45003
+writecat(1322,45411
+writesubs(1351,46457
+writesups(1361,46759
+writelistsubs(1371,47092
+pp_lam(1380,47410
+pp_lam_bracket(1398,48024
+pp_lam_paren(1407,48340
+pp_rule(1429,49240
+member(1447,49868
+append_list(1451,49921
+append(1456,50012
+at_least_one_member(1460,50078
+numbervars(1464,50173
+reverse(1467,50211
+select(1471,50292
+select_last(1475,50359
+cat_atoms(1479,50438
+writelist(1485,50526
+write_lex_cat(1492,50678
+writebreaklex(1500,50990
+write_lex(1513,51267
+writebreak(1521,51543
+tt:-tt1531,51715
+mt:-mt1534,51786
+cmt:-cmt1537,51880
 
 pyt-src/server.py,1438
 class Controls:Controls17,358
@@ -5074,108 +5074,108 @@ initialize_goal_store573,22166
 accu_store584,22576
 :- pred identify_recursive_calls601,23288
 identify_recursive_calls604,23406
-:- pred identify_out_and_out_prime626,24396
-identify_out_and_out_prime631,24631
-:- type accu_sets676,26425
-:- pred accu_stage1689,26977
-accu_stage1693,27155
-:- pred accu_stage1_2727,28347
-accu_stage1_2731,28515
-:- pred accu_sets_init781,30557
-accu_sets_init783,30605
-:- func set_upto796,30984
-set_upto798,31039
-:- pred accu_before812,31498
-accu_before815,31639
-:- pred accu_assoc835,32477
-accu_assoc838,32617
-:- pred accu_construct862,33712
-accu_construct865,33856
-:- pred accu_construct_assoc896,35307
-accu_construct_assoc899,35457
-:- pred accu_update938,37069
-accu_update941,37210
-:- pred member_lessthan_goalid964,38219
-member_lessthan_goalid967,38342
-:- type accu_assoc975,38652
-:- pred accu_is_associative986,39138
-accu_is_associative989,39250
-:- pred associativity_assertion1014,40263
-associativity_assertion1017,40404
-:- pred commutativity_assertion1037,41242
-commutativity_assertion1040,41369
-:- pred accu_is_update1057,41952
-accu_is_update1060,42066
-:- pred is_associative_construction1078,42802
-is_associative_construction1081,42898
-:- type accu_substs1095,43480
-:- type accu_base1103,43744
-:- pred accu_stage21124,44605
-accu_stage21131,44946
-:- pred accu_substs_init1179,46957
-accu_substs_init1182,47097
-:- pred acc_var_subst_init1194,47573
-acc_var_subst_init1198,47718
-:- pred create_new_var1207,48147
-create_new_var1210,48288
-:- pred accu_process_assoc_set1223,48862
-accu_process_assoc_set1229,49150
-:- pred accu_has_heuristic1297,52081
-accu_has_heuristic1299,52161
-:- pred accu_heuristic1304,52336
-accu_heuristic1307,52457
-:- pred accu_process_update_set1318,52906
-accu_process_update_set1325,53221
-:- pred accu_divide_base_case1380,55844
-accu_divide_base_case1385,56059
-:- pred accu_related1412,57146
-accu_related1415,57270
-:- inst stored_goal_plain_call1444,58415
-:- pred lookup_call1449,58601
-lookup_call1452,58715
-:- pred accu_stage31470,59432
-accu_stage31477,59826
-:- pred acc_proc_info1508,61326
-acc_proc_info1512,61485
-:- pred acc_pred_info1556,63449
-acc_pred_info1559,63597
-:- pred accu_create_goal1600,65285
-accu_create_goal1607,65628
-:- func create_acc_call1621,66400
-create_acc_call1625,66569
-:- pred create_orig_goal1634,66987
-create_orig_goal1638,67176
-:- pred create_acc_goal1662,68157
-create_acc_goal1667,68380
-:- func create_new_orig_recursive_goals1709,70225
-create_new_orig_recursive_goals1712,70368
-:- func create_new_recursive_goals1723,70918
-create_new_recursive_goals1727,71108
-:- func create_new_base_goals1738,71717
-create_new_base_goals1741,71831
-:- pred acc_unification1749,72156
-acc_unification1751,72225
-:- pred accu_top_level1766,72896
-accu_top_level1770,73058
-:- pred update_accumulator_pred1856,76290
-update_accumulator_pred1859,76411
-:- func accu_rename1876,77253
-accu_rename1879,77363
-:- func base_case_ids1889,77784
-base_case_ids1891,77846
-:- func base_case_ids_set1898,78048
-base_case_ids_set1900,78113
-:- func accu_goal_list1905,78269
-accu_goal_list1907,78349
-:- pred calculate_goal_info1916,78680
-calculate_goal_info1918,78753
-:- func chain_subst1932,79319
-chain_subst1934,79378
-:- pred chain_subst_21938,79482
-chain_subst_21941,79576
-:- some [T] pred unravel_univ1956,80060
-:- pragma foreign_export1957,80116
-unravel_univ1961,80340
+:- pred identify_out_and_out_prime626,24397
+identify_out_and_out_prime631,24632
+:- type accu_sets676,26426
+:- pred accu_stage1689,26978
+accu_stage1693,27156
+:- pred accu_stage1_2727,28348
+accu_stage1_2731,28516
+:- pred accu_sets_init781,30558
+accu_sets_init783,30606
+:- func set_upto796,30985
+set_upto798,31040
+:- pred accu_before812,31499
+accu_before815,31640
+:- pred accu_assoc835,32478
+accu_assoc838,32618
+:- pred accu_construct862,33713
+accu_construct865,33857
+:- pred accu_construct_assoc896,35308
+accu_construct_assoc899,35458
+:- pred accu_update938,37070
+accu_update941,37211
+:- pred member_lessthan_goalid964,38220
+member_lessthan_goalid967,38343
+:- type accu_assoc975,38653
+:- pred accu_is_associative986,39139
+accu_is_associative989,39251
+:- pred associativity_assertion1014,40264
+associativity_assertion1017,40405
+:- pred commutativity_assertion1037,41243
+commutativity_assertion1040,41370
+:- pred accu_is_update1057,41953
+accu_is_update1060,42067
+:- pred is_associative_construction1078,42803
+is_associative_construction1081,42899
+:- type accu_substs1095,43481
+:- type accu_base1103,43745
+:- pred accu_stage21124,44606
+accu_stage21131,44947
+:- pred accu_substs_init1179,46958
+accu_substs_init1182,47098
+:- pred acc_var_subst_init1194,47574
+acc_var_subst_init1198,47719
+:- pred create_new_var1207,48148
+create_new_var1210,48289
+:- pred accu_process_assoc_set1223,48863
+accu_process_assoc_set1229,49151
+:- pred accu_has_heuristic1297,52082
+accu_has_heuristic1299,52162
+:- pred accu_heuristic1304,52337
+accu_heuristic1307,52458
+:- pred accu_process_update_set1318,52907
+accu_process_update_set1325,53222
+:- pred accu_divide_base_case1380,55845
+accu_divide_base_case1385,56060
+:- pred accu_related1412,57147
+accu_related1415,57271
+:- inst stored_goal_plain_call1444,58416
+:- pred lookup_call1449,58602
+lookup_call1452,58716
+:- pred accu_stage31470,59433
+accu_stage31477,59827
+:- pred acc_proc_info1508,61327
+acc_proc_info1512,61486
+:- pred acc_pred_info1556,63450
+acc_pred_info1559,63598
+:- pred accu_create_goal1600,65286
+accu_create_goal1607,65629
+:- func create_acc_call1621,66401
+create_acc_call1625,66570
+:- pred create_orig_goal1634,66988
+create_orig_goal1638,67177
+:- pred create_acc_goal1662,68158
+create_acc_goal1667,68381
+:- func create_new_orig_recursive_goals1709,70226
+create_new_orig_recursive_goals1712,70369
+:- func create_new_recursive_goals1723,70919
+create_new_recursive_goals1727,71109
+:- func create_new_base_goals1738,71718
+create_new_base_goals1741,71832
+:- pred acc_unification1749,72157
+acc_unification1751,72226
+:- pred accu_top_level1766,72897
+accu_top_level1770,73059
+:- pred update_accumulator_pred1856,76291
+update_accumulator_pred1859,76412
+:- func accu_rename1876,77254
+accu_rename1879,77364
+:- func base_case_ids1889,77785
+base_case_ids1891,77847
+:- func base_case_ids_set1898,78049
+base_case_ids_set1900,78114
+:- func accu_goal_list1905,78270
+accu_goal_list1907,78350
+:- pred calculate_goal_info1916,78681
+calculate_goal_info1918,78754
+:- func chain_subst1932,79320
+chain_subst1934,79379
+:- pred chain_subst_21938,79483
+chain_subst_21941,79577
+:- some [T] pred unravel_univ1956,80061
+:- pragma foreign_export1957,80117
+unravel_univ1961,80341
 
 c-src/c.c,76
 T f(1,0
diff --git a/test/manual/etags/ETAGS.good_6 b/test/manual/etags/ETAGS.good_6
index 6f440a7fc9..09abde35c5 100644
--- a/test/manual/etags/ETAGS.good_6
+++ b/test/manual/etags/ETAGS.good_6
@@ -4083,92 +4083,92 @@ complete(328,10055
 add_active(340,10527
 parse(353,10949
 derived_analyses(364,11341
-build(378,11965
-buildact(392,12521
-mapsyn(412,13542
-add_edge(434,14278
-findcats(447,14758
-normalize_tree(465,15478
-normalize_trees(475,15856
-expandmng_tree(486,16248
-expandmng_trees(496,16614
-cat(511,17013
-subtree(644,21266
-hypothetical_mem(653,21565
-make_coor(667,22130
-start_up:-start_up688,23013
-tokenizeatom(710,23921
-tokenize(720,24348
-isoperator(752,25377
-isoptab(756,25431
-specialsymbol(765,25756
-sstab(771,25861
-parse_cgi(787,26347
-keyvalseq(792,26510
-andkeyvalseq(796,26609
-keyval(799,26688
-valseq(807,26920
-plusvalseq(810,27007
-val(816,27109
-argvals(824,27426
-commaargvals(828,27503
-atomval(833,27578
-atom(836,27640
-action(846,28004
-keyvalcgi(864,28649
-keyvalscgi(865,28670
-outsyn(868,28726
-act(876,29060
-actout(901,29906
-texttreelist(912,30089
-htmltreelist(918,30190
-fitchtreelist(924,30304
-pp_html_table_tree(938,30759
-pp_html_tree(949,31113
-pp_html_trees(988,32381
-pp_html_table_fitch_tree(999,32769
-pp_html_fitch_tree(1017,33672
-removeexp(1129,39002
-splitexp(1142,39490
-pp_exp(1155,39990
-map_word(1168,40249
-pp_exps(1180,40474
-pp_tree(1188,40777
-pp_trees(1216,41807
-pp_word_list(1225,42128
-pp_word(1231,42262
-pp_word_list_rest(1238,42569
-pp_cat(1248,42929
-pp_syn(1255,43196
-pp_syn_paren(1276,43899
-pp_paren(1293,44377
-pp_syn_back(1300,44661
-pp_bas_cat(1311,45001
-writecat(1322,45409
-writesubs(1351,46455
-writesups(1361,46757
-writelistsubs(1371,47090
-pp_lam(1380,47408
-pp_lam_bracket(1398,48022
-pp_lam_paren(1407,48338
-pp_rule(1429,49238
-member(1447,49866
-append_list(1451,49919
-append(1456,50010
-at_least_one_member(1460,50076
-numbervars(1464,50171
-reverse(1467,50209
-select(1471,50290
-select_last(1475,50357
-cat_atoms(1479,50436
-writelist(1485,50524
-write_lex_cat(1492,50676
-writebreaklex(1500,50988
-write_lex(1513,51265
-writebreak(1521,51541
-tt:-tt1531,51713
-mt:-mt1534,51784
-cmt:-cmt1537,51878
+build(378,11967
+buildact(392,12523
+mapsyn(412,13544
+add_edge(434,14280
+findcats(447,14760
+normalize_tree(465,15480
+normalize_trees(475,15858
+expandmng_tree(486,16250
+expandmng_trees(496,16616
+cat(511,17015
+subtree(644,21268
+hypothetical_mem(653,21567
+make_coor(667,22132
+start_up:-start_up688,23015
+tokenizeatom(710,23923
+tokenize(720,24350
+isoperator(752,25379
+isoptab(756,25433
+specialsymbol(765,25758
+sstab(771,25863
+parse_cgi(787,26349
+keyvalseq(792,26512
+andkeyvalseq(796,26611
+keyval(799,26690
+valseq(807,26922
+plusvalseq(810,27009
+val(816,27111
+argvals(824,27428
+commaargvals(828,27505
+atomval(833,27580
+atom(836,27642
+action(846,28006
+keyvalcgi(864,28651
+keyvalscgi(865,28672
+outsyn(868,28728
+act(876,29062
+actout(901,29908
+texttreelist(912,30091
+htmltreelist(918,30192
+fitchtreelist(924,30306
+pp_html_table_tree(938,30761
+pp_html_tree(949,31115
+pp_html_trees(988,32383
+pp_html_table_fitch_tree(999,32771
+pp_html_fitch_tree(1017,33674
+removeexp(1129,39004
+splitexp(1142,39492
+pp_exp(1155,39992
+map_word(1168,40251
+pp_exps(1180,40476
+pp_tree(1188,40779
+pp_trees(1216,41809
+pp_word_list(1225,42130
+pp_word(1231,42264
+pp_word_list_rest(1238,42571
+pp_cat(1248,42931
+pp_syn(1255,43198
+pp_syn_paren(1276,43901
+pp_paren(1293,44379
+pp_syn_back(1300,44663
+pp_bas_cat(1311,45003
+writecat(1322,45411
+writesubs(1351,46457
+writesups(1361,46759
+writelistsubs(1371,47092
+pp_lam(1380,47410
+pp_lam_bracket(1398,48024
+pp_lam_paren(1407,48340
+pp_rule(1429,49240
+member(1447,49868
+append_list(1451,49921
+append(1456,50012
+at_least_one_member(1460,50078
+numbervars(1464,50173
+reverse(1467,50211
+select(1471,50292
+select_last(1475,50359
+cat_atoms(1479,50438
+writelist(1485,50526
+write_lex_cat(1492,50678
+writebreaklex(1500,50990
+write_lex(1513,51267
+writebreak(1521,51543
+tt:-tt1531,51715
+mt:-mt1534,51786
+cmt:-cmt1537,51880
 
 pyt-src/server.py,1438
 class Controls:Controls17,358
@@ -5074,108 +5074,108 @@ initialize_goal_store573,22166
 accu_store584,22576
 :- pred identify_recursive_calls601,23288
 identify_recursive_calls604,23406
-:- pred identify_out_and_out_prime626,24396
-identify_out_and_out_prime631,24631
-:- type accu_sets676,26425
-:- pred accu_stage1689,26977
-accu_stage1693,27155
-:- pred accu_stage1_2727,28347
-accu_stage1_2731,28515
-:- pred accu_sets_init781,30557
-accu_sets_init783,30605
-:- func set_upto796,30984
-set_upto798,31039
-:- pred accu_before812,31498
-accu_before815,31639
-:- pred accu_assoc835,32477
-accu_assoc838,32617
-:- pred accu_construct862,33712
-accu_construct865,33856
-:- pred accu_construct_assoc896,35307
-accu_construct_assoc899,35457
-:- pred accu_update938,37069
-accu_update941,37210
-:- pred member_lessthan_goalid964,38219
-member_lessthan_goalid967,38342
-:- type accu_assoc975,38652
-:- pred accu_is_associative986,39138
-accu_is_associative989,39250
-:- pred associativity_assertion1014,40263
-associativity_assertion1017,40404
-:- pred commutativity_assertion1037,41242
-commutativity_assertion1040,41369
-:- pred accu_is_update1057,41952
-accu_is_update1060,42066
-:- pred is_associative_construction1078,42802
-is_associative_construction1081,42898
-:- type accu_substs1095,43480
-:- type accu_base1103,43744
-:- pred accu_stage21124,44605
-accu_stage21131,44946
-:- pred accu_substs_init1179,46957
-accu_substs_init1182,47097
-:- pred acc_var_subst_init1194,47573
-acc_var_subst_init1198,47718
-:- pred create_new_var1207,48147
-create_new_var1210,48288
-:- pred accu_process_assoc_set1223,48862
-accu_process_assoc_set1229,49150
-:- pred accu_has_heuristic1297,52081
-accu_has_heuristic1299,52161
-:- pred accu_heuristic1304,52336
-accu_heuristic1307,52457
-:- pred accu_process_update_set1318,52906
-accu_process_update_set1325,53221
-:- pred accu_divide_base_case1380,55844
-accu_divide_base_case1385,56059
-:- pred accu_related1412,57146
-accu_related1415,57270
-:- inst stored_goal_plain_call1444,58415
-:- pred lookup_call1449,58601
-lookup_call1452,58715
-:- pred accu_stage31470,59432
-accu_stage31477,59826
-:- pred acc_proc_info1508,61326
-acc_proc_info1512,61485
-:- pred acc_pred_info1556,63449
-acc_pred_info1559,63597
-:- pred accu_create_goal1600,65285
-accu_create_goal1607,65628
-:- func create_acc_call1621,66400
-create_acc_call1625,66569
-:- pred create_orig_goal1634,66987
-create_orig_goal1638,67176
-:- pred create_acc_goal1662,68157
-create_acc_goal1667,68380
-:- func create_new_orig_recursive_goals1709,70225
-create_new_orig_recursive_goals1712,70368
-:- func create_new_recursive_goals1723,70918
-create_new_recursive_goals1727,71108
-:- func create_new_base_goals1738,71717
-create_new_base_goals1741,71831
-:- pred acc_unification1749,72156
-acc_unification1751,72225
-:- pred accu_top_level1766,72896
-accu_top_level1770,73058
-:- pred update_accumulator_pred1856,76290
-update_accumulator_pred1859,76411
-:- func accu_rename1876,77253
-accu_rename1879,77363
-:- func base_case_ids1889,77784
-base_case_ids1891,77846
-:- func base_case_ids_set1898,78048
-base_case_ids_set1900,78113
-:- func accu_goal_list1905,78269
-accu_goal_list1907,78349
-:- pred calculate_goal_info1916,78680
-calculate_goal_info1918,78753
-:- func chain_subst1932,79319
-chain_subst1934,79378
-:- pred chain_subst_21938,79482
-chain_subst_21941,79576
-:- some [T] pred unravel_univ1956,80060
-:- pragma foreign_export1957,80116
-unravel_univ1961,80340
+:- pred identify_out_and_out_prime626,24397
+identify_out_and_out_prime631,24632
+:- type accu_sets676,26426
+:- pred accu_stage1689,26978
+accu_stage1693,27156
+:- pred accu_stage1_2727,28348
+accu_stage1_2731,28516
+:- pred accu_sets_init781,30558
+accu_sets_init783,30606
+:- func set_upto796,30985
+set_upto798,31040
+:- pred accu_before812,31499
+accu_before815,31640
+:- pred accu_assoc835,32478
+accu_assoc838,32618
+:- pred accu_construct862,33713
+accu_construct865,33857
+:- pred accu_construct_assoc896,35308
+accu_construct_assoc899,35458
+:- pred accu_update938,37070
+accu_update941,37211
+:- pred member_lessthan_goalid964,38220
+member_lessthan_goalid967,38343
+:- type accu_assoc975,38653
+:- pred accu_is_associative986,39139
+accu_is_associative989,39251
+:- pred associativity_assertion1014,40264
+associativity_assertion1017,40405
+:- pred commutativity_assertion1037,41243
+commutativity_assertion1040,41370
+:- pred accu_is_update1057,41953
+accu_is_update1060,42067
+:- pred is_associative_construction1078,42803
+is_associative_construction1081,42899
+:- type accu_substs1095,43481
+:- type accu_base1103,43745
+:- pred accu_stage21124,44606
+accu_stage21131,44947
+:- pred accu_substs_init1179,46958
+accu_substs_init1182,47098
+:- pred acc_var_subst_init1194,47574
+acc_var_subst_init1198,47719
+:- pred create_new_var1207,48148
+create_new_var1210,48289
+:- pred accu_process_assoc_set1223,48863
+accu_process_assoc_set1229,49151
+:- pred accu_has_heuristic1297,52082
+accu_has_heuristic1299,52162
+:- pred accu_heuristic1304,52337
+accu_heuristic1307,52458
+:- pred accu_process_update_set1318,52907
+accu_process_update_set1325,53222
+:- pred accu_divide_base_case1380,55845
+accu_divide_base_case1385,56060
+:- pred accu_related1412,57147
+accu_related1415,57271
+:- inst stored_goal_plain_call1444,58416
+:- pred lookup_call1449,58602
+lookup_call1452,58716
+:- pred accu_stage31470,59433
+accu_stage31477,59827
+:- pred acc_proc_info1508,61327
+acc_proc_info1512,61486
+:- pred acc_pred_info1556,63450
+acc_pred_info1559,63598
+:- pred accu_create_goal1600,65286
+accu_create_goal1607,65629
+:- func create_acc_call1621,66401
+create_acc_call1625,66570
+:- pred create_orig_goal1634,66988
+create_orig_goal1638,67177
+:- pred create_acc_goal1662,68158
+create_acc_goal1667,68381
+:- func create_new_orig_recursive_goals1709,70226
+create_new_orig_recursive_goals1712,70369
+:- func create_new_recursive_goals1723,70919
+create_new_recursive_goals1727,71109
+:- func create_new_base_goals1738,71718
+create_new_base_goals1741,71832
+:- pred acc_unification1749,72157
+acc_unification1751,72226
+:- pred accu_top_level1766,72897
+accu_top_level1770,73059
+:- pred update_accumulator_pred1856,76291
+update_accumulator_pred1859,76412
+:- func accu_rename1876,77254
+accu_rename1879,77364
+:- func base_case_ids1889,77785
+base_case_ids1891,77847
+:- func base_case_ids_set1898,78049
+base_case_ids_set1900,78114
+:- func accu_goal_list1905,78270
+accu_goal_list1907,78350
+:- pred calculate_goal_info1916,78681
+calculate_goal_info1918,78754
+:- func chain_subst1932,79320
+chain_subst1934,79379
+:- pred chain_subst_21938,79483
+chain_subst_21941,79577
+:- some [T] pred unravel_univ1956,80061
+:- pragma foreign_export1957,80117
+unravel_univ1961,80341
 
 c-src/c.c,76
 T f(1,0
diff --git a/test/manual/etags/cp-src/clheir.hpp 
b/test/manual/etags/cp-src/clheir.hpp
index 55d91228fb..831da5ca09 100644
--- a/test/manual/etags/cp-src/clheir.hpp
+++ b/test/manual/etags/cp-src/clheir.hpp
@@ -2,7 +2,7 @@
 /*                                 CLHEIR.H                                */
 /* ======================================================================= */
 
-// CLASS HEIRARCHY
+// CLASS HIERARCHY
 // Locations or Agents are both of type generic_object. Generic_objects may
 // have states, and are responsible for updating their states appropriately
 // when their step() functions are executed.
diff --git a/test/manual/etags/merc-src/accumulator.m 
b/test/manual/etags/merc-src/accumulator.m
index c82dbf58ff..0ee41216c1 100644
--- a/test/manual/etags/merc-src/accumulator.m
+++ b/test/manual/etags/merc-src/accumulator.m
@@ -616,7 +616,7 @@ identify_recursive_calls(PredId, ProcId, GoalStore, Ids) :-
     % Determine the variables which are members of the sets Out and Out',
     % and initialize the substitutions between the two sets.
     %
-    % This is done by identifing those variables whose instantiatedness change
+    % This is done by identifying those variables whose instantiatedness change
     % in the goals after the recursive call and are headvars.
     %
     % Note that we are only identifying the output variables which will need
diff --git a/test/manual/etags/prol-src/natded.prolog 
b/test/manual/etags/prol-src/natded.prolog
index f0ee6b41b1..08c81d48f6 100644
--- a/test/manual/etags/prol-src/natded.prolog
+++ b/test/manual/etags/prol-src/natded.prolog
@@ -371,7 +371,7 @@ derived_analyses([W|Ws],[W|DerWs]):-
 
 % build(Ws:+<list(<word>)>, Right:+<int>, Left:-<int>)
 % ----------------------------------------------------------------------
-% finishes building chart with Ws as remaing word, starting from
+% finishes building chart with Ws as remaining word, starting from
 % right position Right and finishing on left position Left
 %      -- counts backwards, so Left > Right
 % ----------------------------------------------------------------------
diff --git a/test/manual/image-circular-tests.el 
b/test/manual/image-circular-tests.el
index edc65eee9b..1299970f82 100644
--- a/test/manual/image-circular-tests.el
+++ b/test/manual/image-circular-tests.el
@@ -29,22 +29,25 @@
 
 (ert-deftest image-test-duplicate-keywords ()
   "Test that duplicate keywords in an image spec lead to rejection."
-  (should-error (image-size `(image :type xbm :type xbm :width 1 :height 1
+  (should-error (image-size `(image :type xbm :type xbm
+                                    :data-width 1 :data-height 1
                                     :data ,(bool-vector t))
                             t)))
 
 (ert-deftest image-test-circular-plist ()
   "Test that a circular image spec is rejected."
   (should-error
-   (let ((l `(image :type xbm :width 1 :height 1 :data ,(bool-vector t))))
+   (let ((l `(image :type xbm :data-width 1 :data-height 1
+                    :data ,(bool-vector t))))
      (setcdr (last l) '#1=(:invalid . #1#))
      (image-size l t))))
 
 (ert-deftest image-test-:type-property-value ()
   "Test that :type is allowed as a property value in an image spec."
-  (should (equal (image-size `(image :dummy :type :type xbm :width 1 :height 1
-                                        :data ,(bool-vector t))
-                                t)
+  (should (equal (image-size `(image :dummy :type :type xbm
+                                     :data-width 1 :data-height 1
+                                     :data ,(bool-vector t))
+                             t)
                  (cons 1 1))))
 
 (ert-deftest image-test-circular-specs ()
@@ -52,9 +55,9 @@
   (should
    (let* ((circ1 (cons :dummy nil))
           (circ2 (cons :dummy nil))
-          (spec1 `(image :type xbm :width 1 :height 1
+          (spec1 `(image :type xbm :data-width 1 :data-height 1
                          :data ,(bool-vector 1) :ignored ,circ1))
-          (spec2 `(image :type xbm :width 1 :height 1
+          (spec2 `(image :type xbm :data-width 1 :data-height 1
                         :data ,(bool-vector 1) :ignored ,circ2)))
      (setcdr circ1 circ1)
      (setcdr circ2 circ2)
diff --git a/test/manual/indent/perl.perl b/test/manual/indent/perl.perl
index db94552a92..b44593da02 100755
--- a/test/manual/indent/perl.perl
+++ b/test/manual/indent/perl.perl
@@ -90,7 +90,7 @@ s:abc:def:g;  # FIXME: the initial s is fontified like a 
label, and indented
 s'def'ghi'g;  # The middle ' should not end the quoting.
 s"ghi"ijk"g;  # The middle ' should not end the quoting.
 
-s#ijk#lmn#g;  # This is a regular expression sustitution.
+s#ijk#lmn#g;  # This is a regular expression substitution.
 
 s #lmn#opq#g; # FIXME: this should be a comment starting with "#lmn"
   /lmn/rst/g; # and this is the actual regular expression
diff --git a/test/manual/process-callout-tests.el 
b/test/manual/process-callout-tests.el
new file mode 100644
index 0000000000..0bb960cf90
--- /dev/null
+++ b/test/manual/process-callout-tests.el
@@ -0,0 +1,64 @@
+;;; process-callout-tests.el --- Testing the process facilities -*- 
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:
+
+;;
+
+;;; Code:
+
+(require 'cl-lib)
+(require 'ert)
+
+;;; This test is here in test/manual instead of
+;;; test/src/process-tests.el for two reasons: The test suite
+;;; shouldn't "call home" automatically, because that's against our
+;;; privacy principles, and as a practical matter, the server may have
+;;; problems, and that shouldn't trigger a test error.
+
+(ert-deftest process-async-https-with-delay ()
+  "Bug#49449: asynchronous TLS connection with delayed completion."
+  (skip-unless (and internet-is-working (gnutls-available-p)))
+  (let* ((status nil)
+         (buf (url-http
+                 #s(url "https" nil nil "elpa.gnu.org" nil
+                        "/packages/archive-contents" nil nil t silent t t)
+                 (lambda (s) (setq status s))
+                 '(nil) nil 'tls)))
+    (unwind-protect
+        (progn
+          ;; Busy-wait for 1 s to allow for the TCP connection to complete.
+          (let ((delay 1.0)
+                (t0 (float-time)))
+            (while (< (float-time) (+ t0 delay))))
+          ;; Wait for the entire operation to finish.
+          (let ((limit 4.0)
+                (t0 (float-time)))
+            (while (and (null status)
+                        (< (float-time) (+ t0 limit)))
+              (sit-for 0.1)))
+          (should status)
+          (should-not (plist-get status ':error))
+          (should buf)
+          (should (> (buffer-size buf) 0))
+          )
+      (when buf
+        (kill-buffer buf)))))
+
+;;; process-callout-tests.el ends here
diff --git a/test/src/buffer-tests.el b/test/src/buffer-tests.el
index 13d48b31a4..3c6a9208ff 100644
--- a/test/src/buffer-tests.el
+++ b/test/src/buffer-tests.el
@@ -1503,9 +1503,12 @@ with parameters from the *Messages* buffer modification."
 
 (ert-deftest test-restore-buffer-modified-p ()
   (ert-with-temp-file file
+    ;; This avoids the annoying "foo and bar are the same file" on
+    ;; MS-Windows.
+    (setq file (file-truename file))
     (with-current-buffer (find-file file)
       (auto-save-mode 1)
-      (should-not (buffer-modified-p))
+      (should-not (eq (buffer-modified-p) t))
       (insert "foo")
       (should (buffer-modified-p))
       (restore-buffer-modified-p nil)
@@ -1522,13 +1525,34 @@ with parameters from the *Messages* buffer 
modification."
         (delete-file buffer-auto-save-file-name))))
 
   (ert-with-temp-file file
+    (setq file (file-truename file))
     (with-current-buffer (find-file file)
       (auto-save-mode 1)
-      (should-not (buffer-modified-p))
+      (should-not (eq (buffer-modified-p) t))
       (insert "foo")
       (should (buffer-modified-p))
       (should-not (eq (buffer-modified-p) 'autosaved))
       (restore-buffer-modified-p 'autosaved)
       (should (eq (buffer-modified-p) 'autosaved)))))
 
+(ert-deftest test-buffer-chars-modified-ticks ()
+  "Test `buffer-chars-modified-tick'."
+  (setq temporary-file-directory (file-truename temporary-file-directory))
+  (let ((text "foobar")
+        f1 f2)
+    (unwind-protect
+        (progn
+          (setq f1 (make-temp-file "buf-modiff-tests")
+                f2 (make-temp-file "buf-modiff-tests"))
+          (with-current-buffer (find-file f1)
+            (should (= (buffer-chars-modified-tick) 1))
+            (should (= (buffer-chars-modified-tick) (buffer-modified-tick)))
+            (write-region text nil f2 nil 'silent)
+            (insert-file-contents f2)
+            (should (= (buffer-chars-modified-tick) (buffer-modified-tick)))
+            (should (> (buffer-chars-modified-tick) 1))))
+      (if f1 (delete-file f1))
+      (if f2 (delete-file f2))
+      )))
+
 ;;; buffer-tests.el ends here
diff --git a/test/src/callint-tests.el b/test/src/callint-tests.el
index d964fc3c1f..5a633fdc2b 100644
--- a/test/src/callint-tests.el
+++ b/test/src/callint-tests.el
@@ -52,4 +52,17 @@
       (call-interactively #'ignore t))
     (should (= (length command-history) history-length))))
 
+(defun callint-test-int-args (foo bar &optional zot)
+  (declare (interactive-args
+            (bar 10)
+            (zot 11)))
+  (interactive (list 1 1 1))
+  (+ foo bar zot))
+
+(ert-deftest test-interactive-args ()
+  (let ((history-length 1)
+        (command-history ()))
+    (should (= (call-interactively 'callint-test-int-args t) 3))
+    (should (equal command-history '((callint-test-int-args 1 10 11))))))
+
 ;;; callint-tests.el ends here
diff --git a/test/src/coding-tests.el b/test/src/coding-tests.el
index de4ddb546d..f65d575d0c 100644
--- a/test/src/coding-tests.el
+++ b/test/src/coding-tests.el
@@ -61,16 +61,17 @@
 ;; Return the contents (specified by CONTENT-TYPE; ascii, latin, or
 ;; binary) of a test file.
 (defun coding-tests-file-contents (content-type)
-  (let* ((ascii "ABCDEFGHIJKLMNOPQRSTUVWXYZ\n")
-        (latin (concat ascii "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ\n"))
-        (binary (string-to-multibyte
-                 (concat (string-as-unibyte latin)
-                         (unibyte-string #xC0 #xC1 ?\n)))))
-    (cond ((eq content-type 'ascii) ascii)
-         ((eq content-type 'latin) latin)
-         ((eq content-type 'binary) binary)
-         (t
-          (error "Invalid file content type: %s" content-type)))))
+  (with-suppressed-warnings ((obsolete string-as-unibyte))
+    (let* ((ascii "ABCDEFGHIJKLMNOPQRSTUVWXYZ\n")
+           (latin (concat ascii "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ\n"))
+           (binary (string-to-multibyte
+                    (concat (string-as-unibyte latin)
+                            (unibyte-string #xC0 #xC1 ?\n)))))
+      (cond ((eq content-type 'ascii) ascii)
+            ((eq content-type 'latin) latin)
+            ((eq content-type 'binary) binary)
+            (t
+             (error "Invalid file content type: %s" content-type))))))
 
 ;; Generate FILE with CONTENTS encoded by CODING-SYSTEM.
 ;; whose encoding specified by CODING-SYSTEM.
@@ -429,9 +430,5 @@
                  '((iso-latin-1 3) (us-ascii 1 3))))
   (should-error (check-coding-systems-region "å" nil '(bad-coding-system))))
 
-;; Local Variables:
-;; byte-compile-warnings: (not obsolete)
-;; End:
-
 (provide 'coding-tests)
 ;;; coding-tests.el ends here
diff --git a/test/src/comp-resources/comp-test-funcs.el 
b/test/src/comp-resources/comp-test-funcs.el
index 0a60f4d6cc..9092f040c8 100644
--- a/test/src/comp-resources/comp-test-funcs.el
+++ b/test/src/comp-resources/comp-test-funcs.el
@@ -515,6 +515,8 @@
 (defun comp-test-47868-4-f ()
   #(" " 0 1 (face font-lock-keyword-face)))
 
+(defun comp-test-48029-nonascii-žžž-f (arg)
+  (when arg t))
 
 
 ;;;;;;;;;;;;;;;;;;;;
diff --git a/test/src/comp-tests.el b/test/src/comp-tests.el
index e7b534d00e..1b239cec79 100644
--- a/test/src/comp-tests.el
+++ b/test/src/comp-tests.el
@@ -508,11 +508,6 @@ 
https://lists.gnu.org/archive/html/bug-gnu-emacs/2020-03/msg00914.html.";
   (should (string= (comp-test-45635-f :height 180 :family "PragmataPro Liga")
                    "PragmataPro Liga")))
 
-(comp-deftest 45603-1 ()
-  "<https://lists.gnu.org/archive/html/bug-gnu-emacs/2020-12/msg01994.html>"
-  (load (native-compile (ert-resource-file "comp-test-45603.el")))
-  (should (fboundp 'comp-test-45603--file-local-name)))
-
 (comp-deftest 46670-1 ()
   "<https://lists.gnu.org/archive/html/bug-gnu-emacs/2021-02/msg01413.html>"
   (should (string= (comp-test-46670-2-f "foo") "foo"))
@@ -532,6 +527,11 @@ 
https://lists.gnu.org/archive/html/bug-gnu-emacs/2020-03/msg00914.html.";
   (should (eq (comp-test-47868-1-f) (comp-test-47868-3-f)))
   (should (eq (comp-test-47868-2-f) (comp-test-47868-4-f))))
 
+(comp-deftest 48029-1 ()
+  "<https://lists.gnu.org/archive/html/bug-gnu-emacs/2022-07/msg00666.html>"
+  (should (subr-native-elisp-p
+           (symbol-function 'comp-test-48029-nonascii-žžž-f))))
+
 
 ;;;;;;;;;;;;;;;;;;;;;
 ;; Tromey's tests. ;;
diff --git a/test/src/data-tests.el b/test/src/data-tests.el
index 7d8535f5f3..0f84b2fb77 100644
--- a/test/src/data-tests.el
+++ b/test/src/data-tests.el
@@ -741,14 +741,15 @@ comparing the subr with a much slower Lisp 
implementation."
   (should (= (ash 1000 (* 2 most-negative-fixnum)) 0))
   (should (= (ash -1000 (* 2 most-negative-fixnum)) -1))
   (should (= (ash (* 2 most-negative-fixnum) (* 2 most-negative-fixnum)) -1))
-  (should (= (lsh most-negative-fixnum 1)
-             (* most-negative-fixnum 2)))
   (should (= (ash (* 2 most-negative-fixnum) -1)
             most-negative-fixnum))
-  (should (= (lsh most-positive-fixnum -1) (/ most-positive-fixnum 2)))
-  (should (= (lsh most-negative-fixnum -1) (lsh (- most-negative-fixnum) -1)))
-  (should (= (lsh -1 -1) most-positive-fixnum))
-  (should-error (lsh (1- most-negative-fixnum) -1)))
+  (with-suppressed-warnings ((suspicious lsh))
+    (should (= (lsh most-negative-fixnum 1)
+               (* most-negative-fixnum 2)))
+    (should (= (lsh most-positive-fixnum -1) (/ most-positive-fixnum 2)))
+    (should (= (lsh most-negative-fixnum -1) (lsh (- most-negative-fixnum) 
-1)))
+    (should (= (lsh -1 -1) most-positive-fixnum))
+    (should-error (lsh (1- most-negative-fixnum) -1))))
 
 (ert-deftest data-tests-make-local-forwarded-var () ;bug#34318
   ;; Boy, this bug is tricky to trigger.  You need to:
@@ -768,4 +769,8 @@ comparing the subr with a much slower Lisp implementation."
                          (default-value 'last-coding-system-used))
                    '(no-conversion bug34318)))))
 
+(ert-deftest data-tests-make_symbol_constant ()
+  "Can't set variable marked with 'make_symbol_constant'."
+  (should-error (setq most-positive-fixnum 1) :type 'setting-constant))
+
 ;;; data-tests.el ends here
diff --git a/test/src/fileio-tests.el b/test/src/fileio-tests.el
index c137ce06f1..08582c8a86 100644
--- a/test/src/fileio-tests.el
+++ b/test/src/fileio-tests.el
@@ -201,4 +201,20 @@ Also check that an encoding error can appear in a symlink."
     (insert-file-contents "/dev/urandom" nil nil 10)
     (should (= (buffer-size) 10))))
 
+(defun fileio-tests--identity-expand-handler (_ file &rest _)
+  file)
+(put 'fileio-tests--identity-expand-handler 'operations '(expand-file-name))
+
+(ert-deftest fileio--file-name-case-insensitive-p ()
+  ;; Check that we at least don't crash if given nonexisting files
+  ;; without a directory (bug#56443).
+
+  ;; Use an identity file-name handler, as if called by `ffap'.
+  (let* ((file-name-handler-alist
+          '(("^mailto:"; . fileio-tests--identity-expand-handler)))
+         (file "mailto:snowball@hell.com";))
+    ;; Check that `expand-file-name' is identity for this name.
+    (should (equal (expand-file-name file nil) file))
+    (file-name-case-insensitive-p file)))
+
 ;;; fileio-tests.el ends here
diff --git a/test/src/fns-tests.el b/test/src/fns-tests.el
index c080c48392..a84cce3ad4 100644
--- a/test/src/fns-tests.el
+++ b/test/src/fns-tests.el
@@ -852,24 +852,6 @@
     (should-not (plist-get d1 3))
     (should-not (plist-get d2 3))))
 
-(ert-deftest test-cycle-lax-plist-get ()
-  (let ((c1 (cyc1 1))
-        (c2 (cyc2 1 2))
-        (d1 (dot1 1))
-        (d2 (dot2 1 2)))
-    (should (lax-plist-get c1 1))
-    (should (lax-plist-get c2 1))
-    (should (lax-plist-get d1 1))
-    (should (lax-plist-get d2 1))
-    (should-error (lax-plist-get c1 2) :type 'circular-list)
-    (should (lax-plist-get c2 2))
-    (should-error (lax-plist-get d1 2) :type 'wrong-type-argument)
-    (should (lax-plist-get d2 2))
-    (should-error (lax-plist-get c1 3) :type 'circular-list)
-    (should-error (lax-plist-get c2 3) :type 'circular-list)
-    (should-error (lax-plist-get d1 3) :type 'wrong-type-argument)
-    (should-error (lax-plist-get d2 3) :type 'wrong-type-argument)))
-
 (ert-deftest test-cycle-plist-member ()
   (let ((c1 (cyc1 1))
         (c2 (cyc2 1 2))
@@ -906,24 +888,6 @@
     (should-error (plist-put d1 3 3) :type 'wrong-type-argument)
     (should-error (plist-put d2 3 3) :type 'wrong-type-argument)))
 
-(ert-deftest test-cycle-lax-plist-put ()
-  (let ((c1 (cyc1 1))
-        (c2 (cyc2 1 2))
-        (d1 (dot1 1))
-        (d2 (dot2 1 2)))
-    (should (lax-plist-put c1 1 1))
-    (should (lax-plist-put c2 1 1))
-    (should (lax-plist-put d1 1 1))
-    (should (lax-plist-put d2 1 1))
-    (should-error (lax-plist-put c1 2 2) :type 'circular-list)
-    (should (lax-plist-put c2 2 2))
-    (should-error (lax-plist-put d1 2 2) :type 'wrong-type-argument)
-    (should (lax-plist-put d2 2 2))
-    (should-error (lax-plist-put c1 3 3) :type 'circular-list)
-    (should-error (lax-plist-put c2 3 3) :type 'circular-list)
-    (should-error (lax-plist-put d1 3 3) :type 'wrong-type-argument)
-    (should-error (lax-plist-put d2 3 3) :type 'wrong-type-argument)))
-
 (ert-deftest test-cycle-equal ()
   (should-error (equal (cyc1 1) (cyc1 1)))
   (should-error (equal (cyc2 1 2) (cyc2 1 2))))
@@ -936,24 +900,12 @@
   "Test that `plist-get' doesn't signal an error on degenerate plists."
   (should-not (plist-get '(:foo 1 :bar) :bar)))
 
-(ert-deftest lax-plist-get/odd-number-of-elements ()
-  "Check for https://debbugs.gnu.org/cgi/bugreport.cgi?bug=27726.";
-  (should (equal (should-error (lax-plist-get '(:foo 1 :bar) :bar)
-                               :type 'wrong-type-argument)
-                 '(wrong-type-argument plistp (:foo 1 :bar)))))
-
 (ert-deftest plist-put/odd-number-of-elements ()
   "Check for https://debbugs.gnu.org/cgi/bugreport.cgi?bug=27726.";
   (should (equal (should-error (plist-put '(:foo 1 :bar) :zot 2)
                                :type 'wrong-type-argument)
                  '(wrong-type-argument plistp (:foo 1 :bar)))))
 
-(ert-deftest lax-plist-put/odd-number-of-elements ()
-  "Check for https://debbugs.gnu.org/cgi/bugreport.cgi?bug=27726.";
-  (should (equal (should-error (lax-plist-put '(:foo 1 :bar) :zot 2)
-                               :type 'wrong-type-argument)
-                 '(wrong-type-argument plistp (:foo 1 :bar)))))
-
 (ert-deftest plist-member/improper-list ()
   "Check for https://debbugs.gnu.org/cgi/bugreport.cgi?bug=27726.";
   (should (equal (should-error (plist-member '(:foo 1 . :bar) :qux)
@@ -978,7 +930,7 @@
   (should (equal 1 (string-distance "ab" "a我b")))
   (should (equal 1 (string-distance "我" "她")))
 
-  ;; correct behaviour with empty strings
+  ;; correct behavior with empty strings
   (should (equal 0 (string-distance "" "")))
   (should (equal 0 (string-distance "" "" t)))
   (should (equal 1 (string-distance "x" "")))
@@ -1375,4 +1327,91 @@
     (should-error (append loop '(end))
                   :type 'circular-list)))
 
+(ert-deftest test-plist ()
+  (let ((plist '(:a "b")))
+    (setq plist (plist-put plist :b "c"))
+    (should (equal (plist-get plist :b) "c"))
+    (should (equal (plist-member plist :b) '(:b "c"))))
+
+  (let ((plist '("1" "2" "a" "b")))
+    (setq plist (plist-put plist (copy-sequence "a") "c"))
+    (should-not (equal (plist-get plist (copy-sequence "a")) "c"))
+    (should-not (equal (plist-member plist (copy-sequence "a")) '("a" "c"))))
+
+  (let ((plist '("1" "2" "a" "b")))
+    (setq plist (plist-put plist (copy-sequence "a") "c" #'equal))
+    (should (equal (plist-get plist (copy-sequence "a") #'equal) "c"))
+    (should (equal (plist-member plist (copy-sequence "a") #'equal)
+                   '("a" "c")))))
+
+(ert-deftest fns--string-to-unibyte-multibyte ()
+  (dolist (str (list "" "a" "abc" "a\x00\x7fz" "a\xaa\xbbz" "\x80\xdd\xff"
+                     (apply #'unibyte-string (number-sequence 0 255))))
+    (ert-info ((prin1-to-string str) :prefix "str: ")
+      (should-not (multibyte-string-p str))
+      (let* ((u (string-to-unibyte str))   ; should be identity
+             (m (string-to-multibyte u))   ; lossless conversion
+             (mm (string-to-multibyte m))  ; should be identity
+             (uu (string-to-unibyte m))    ; also lossless
+             (ml (mapcar (lambda (c) (if (<= c #x7f) c (+ c #x3fff00))) u)))
+        (should-not (multibyte-string-p u))
+        (should (multibyte-string-p m))
+        (should (multibyte-string-p mm))
+        (should-not (multibyte-string-p uu))
+        (should (equal str u))
+        (should (equal m mm))
+        (should (equal str uu))
+        (should (equal (append m nil) ml)))))
+  (should-error (string-to-unibyte "å"))
+  (should-error (string-to-unibyte "ABC∀BC")))
+
+(defun fns-tests--take-ref (n list)
+  "Reference implementation of `take'."
+  (named-let loop ((m n) (tail list) (ac nil))
+    (if (and (> m 0) tail)
+        (loop (1- m) (cdr tail) (cons (car tail) ac))
+      (nreverse ac))))
+
+(ert-deftest fns--take-ntake ()
+  "Test `take' and `ntake'."
+  ;; Check errors and edge cases.
+  (should-error (take 'x '(a)))
+  (should-error (ntake 'x '(a)))
+  (should-error (take 1 'a))
+  (should-error (ntake 1 'a))
+  (should-error (take 2 '(a . b)))
+  (should-error (ntake 2 '(a . b)))
+  ;; Tolerate non-lists for a count of zero.
+  (should (equal (take 0 'a) nil))
+  (should (equal (ntake 0 'a) nil))
+  ;; But not non-numbers for empty lists.
+  (should-error (take 'x nil))
+  (should-error (ntake 'x nil))
+
+  (dolist (list '(nil (a) (a b) (a b c) (a b c d) (a . b) (a b . c)))
+    (ert-info ((prin1-to-string list) :prefix "list: ")
+      (let ((max (if (proper-list-p list)
+                     (+ 2 (length list))
+                   (safe-length list))))
+        (dolist (n (number-sequence -1 max))
+          (ert-info ((prin1-to-string n) :prefix "n: ")
+            (let* ((l (copy-tree list))
+                   (ref (fns-tests--take-ref n l)))
+              (should (equal (take n l) ref))
+              (should (equal l list))
+              (should (equal (ntake n l) ref))))))))
+
+  ;; Circular list.
+  (let ((list (list 'a 'b 'c)))
+    (setcdr (nthcdr 2 list) (cdr list)) ; list now (a b c b c b c ...)
+    (should (equal (take 0 list) nil))
+    (should (equal (take 1 list) '(a)))
+    (should (equal (take 2 list) '(a b)))
+    (should (equal (take 3 list) '(a b c)))
+    (should (equal (take 4 list) '(a b c b)))
+    (should (equal (take 5 list) '(a b c b c)))
+    (should (equal (take 10 list) '(a b c b c b c b c b)))
+
+    (should (equal (ntake 10 list) '(a b)))))
+
 ;;; fns-tests.el ends here
diff --git a/test/src/font-tests.el b/test/src/font-tests.el
index d99b0be89e..7e9669c651 100644
--- a/test/src/font-tests.el
+++ b/test/src/font-tests.el
@@ -96,8 +96,7 @@ expected font properties from parsing NAME.")
 (put 'font-parse-check 'ert-explainer 'font-parse-explain)
 
 (defun font-parse-explain (name prop expected)
-  (let ((result (font-get (font-spec :name name) prop))
-       (propname (symbol-name prop)))
+  (let ((propname (symbol-name prop)))
     (format "Parsing `%s': expected %s `%s', got `%s'."
            name (substring propname 1) expected
            (font-get (font-spec :name name) prop))))
@@ -184,9 +183,5 @@ expected font properties from parsing NAME.")
                   :family)
                  'name-with-lots-of-dashes)))
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 (provide 'font-tests)
 ;;; font-tests.el ends here.
diff --git a/test/src/image-tests.el b/test/src/image-tests.el
index f710aadea7..36278f4b9f 100644
--- a/test/src/image-tests.el
+++ b/test/src/image-tests.el
@@ -2,7 +2,7 @@
 
 ;; Copyright (C) 2021-2022 Free Software Foundation, Inc.
 
-;; Author: Stefan Kangas <stefan@marxist.se>
+;; Author: Stefan Kangas <stefankangas@gmail.com>
 
 ;; This file is part of GNU Emacs.
 
diff --git a/test/src/json-tests.el b/test/src/json-tests.el
index f3dfeea30b..3560e1abc9 100644
--- a/test/src/json-tests.el
+++ b/test/src/json-tests.el
@@ -187,8 +187,11 @@
 (ert-deftest json-parse-string/null ()
   (skip-unless (fboundp 'json-parse-string))
   (should-error (json-parse-string "\x00") :type 'wrong-type-argument)
-  ;; FIXME: Reconsider whether this is the right behavior.
-  (should-error (json-parse-string "[\"a\\u0000b\"]") :type 'json-parse-error))
+  (should (json-parse-string "[\"a\\u0000b\"]"))
+  (let* ((string "{\"foo\":\"this is a string including a literal \\u0000\"}")
+         (data (json-parse-string string)))
+    (should (hash-table-p data))
+    (should (equal string (json-serialize data)))))
 
 (ert-deftest json-parse-string/invalid-unicode ()
   "Some examples from
diff --git a/test/src/keymap-tests.el b/test/src/keymap-tests.el
index 69aa723849..ce96be6869 100644
--- a/test/src/keymap-tests.el
+++ b/test/src/keymap-tests.el
@@ -125,7 +125,7 @@
 ;;   ...)
 
 (ert-deftest keymap-lookup-key/mixed-case ()
-  "Backwards compatibility behaviour (Bug#50752)."
+  "Backwards compatibility behavior (Bug#50752)."
   (let ((map (make-keymap)))
     (define-key map [menu-bar foo bar] 'foo)
     (should (eq (lookup-key map [menu-bar foo bar]) 'foo))
@@ -135,7 +135,7 @@
     (should (eq (lookup-key map [menu-bar I-bar]) 'foo))))
 
 (ert-deftest keymap-lookup-key/mixed-case-multibyte ()
-  "Backwards compatibility behaviour (Bug#50752)."
+  "Backwards compatibility behavior (Bug#50752)."
   (let ((map (make-keymap)))
     ;; (downcase "Åäö") => "åäö"
     (define-key map [menu-bar åäö bar] 'foo)
@@ -153,19 +153,19 @@
     (should (eq (lookup-key map [menu-bar buffer 1]) 'foo))))
 
 (ert-deftest keymap-lookup-keymap/with-spaces ()
-  "Backwards compatibility behaviour (Bug#50752)."
+  "Backwards compatibility behavior (Bug#50752)."
   (let ((map (make-keymap)))
     (define-key map [menu-bar foo-bar] 'foo)
     (should (eq (lookup-key map [menu-bar Foo\ Bar]) 'foo))))
 
 (ert-deftest keymap-lookup-keymap/with-spaces-multibyte ()
-  "Backwards compatibility behaviour (Bug#50752)."
+  "Backwards compatibility behavior (Bug#50752)."
   (let ((map (make-keymap)))
     (define-key map [menu-bar åäö-bar] 'foo)
     (should (eq (lookup-key map [menu-bar Åäö\ Bar]) 'foo))))
 
 (ert-deftest keymap-lookup-keymap/with-spaces-multibyte-lang-env ()
-  "Backwards compatibility behaviour (Bug#50752)."
+  "Backwards compatibility behavior (Bug#50752)."
   (let ((lang-env current-language-environment))
     (set-language-environment "Turkish")
     (let ((map (make-keymap)))
@@ -418,6 +418,30 @@ g .. h             foo
   (should-error (text-char-description ?\M-c))
   (should-error (text-char-description ?\s-c)))
 
+(ert-deftest test-non-key-events ()
+  ;; Dummy command.
+  (declare-function keymap-tests-command nil)
+  (should (null (where-is-internal 'keymap-tests-command)))
+  (keymap-set global-map "C-c g" #'keymap-tests-command)
+  (should (equal (where-is-internal 'keymap-tests-command) '([3 103])))
+  (keymap-set global-map "<keymap-tests-event>" #'keymap-tests-command)
+  (should (equal (where-is-internal 'keymap-tests-command)
+                 '([keymap-tests-event] [3 103])))
+  (make-non-key-event 'keymap-tests-event)
+  (should (equal (where-is-internal 'keymap-tests-command) '([3 103]))))
+
+(ert-deftest keymap-test-duplicate-definitions ()
+  "Check that defvar-keymap rejects duplicate key definitions."
+  (should-error
+   (defvar-keymap
+       ert-keymap-duplicate
+       "a" #'next-line
+       "a" #'previous-line))
+  (should-error
+   (define-keymap
+       "a" #'next-line
+       "a" #'previous-line)))
+
 (provide 'keymap-tests)
 
 ;;; keymap-tests.el ends here
diff --git a/test/src/lread-resources/lazydoc.el 
b/test/src/lread-resources/lazydoc.el
new file mode 100644
index 0000000000..cb434c239b
Binary files /dev/null and b/test/src/lread-resources/lazydoc.el differ
diff --git a/test/src/lread-tests.el b/test/src/lread-tests.el
index f190f14781..57143dd81e 100644
--- a/test/src/lread-tests.el
+++ b/test/src/lread-tests.el
@@ -128,7 +128,7 @@
     (save-excursion
       (goto-char (point-max))
       (skip-chars-backward "\n")
-      (buffer-substring (line-beginning-position) (point)))))
+      (buffer-substring (pos-bol) (point)))))
 
 (ert-deftest lread-tests--unescaped-char-literals ()
   "Check that loading warns about unescaped character
@@ -322,4 +322,21 @@ literals (Bug#20852)."
   (should-error (read-from-string "?\\\n x"))
   (should (equal (read-from-string "\"a\\\nb\"") '("ab" . 6))))
 
+(ert-deftest lread-force-load-doc-strings ()
+  ;; Verify that lazy doc strings are loaded lazily by default,
+  ;; but eagerly with `force-load-doc-strings' set.
+  (let ((file (expand-file-name "lazydoc.el" (ert-resource-directory))))
+    (fmakunbound 'lazydoc-fun)
+    (load file)
+    (let ((f (symbol-function 'lazydoc-fun)))
+      (should (byte-code-function-p f))
+      (should (equal (aref f 4) (cons file 87))))
+
+    (fmakunbound 'lazydoc-fun)
+    (let ((load-force-doc-strings t))
+      (load file)
+      (let ((f (symbol-function 'lazydoc-fun)))
+        (should (byte-code-function-p f))
+        (should (equal (aref f 4) "My little\ndoc string\nhere"))))))
+
 ;;; lread-tests.el ends here
diff --git a/test/src/print-tests.el b/test/src/print-tests.el
index 6ff7e99783..5c349342eb 100644
--- a/test/src/print-tests.el
+++ b/test/src/print-tests.el
@@ -514,7 +514,7 @@ otherwise, use a different charset."
               (should (< lead (length numbers)))
               (should (<= lead loopback-index))
               (should (< loopback-index (length numbers)))
-              (let ((lead-part (butlast numbers (- (length numbers) lead)))
+              (let ((lead-part (take lead numbers))
                     (loop-part (nthcdr lead numbers)))
                 ;; The lead part must match exactly.
                 (should (equal lead-part (number-sequence 1 lead)))
@@ -529,6 +529,18 @@ otherwise, use a different charset."
                   (should (equal (% (- (length numbers) loopback-index) loop)
                                  0)))))))))))
 
+(ert-deftest test-print-unreadable-function-buffer ()
+  (let* ((buffer nil)
+         (callback-buffer nil)
+         (str (with-temp-buffer
+                (setq buffer (current-buffer))
+                (let ((print-unreadable-function
+                       (lambda (_object _escape)
+                         (setq callback-buffer (current-buffer))
+                         "tata")))
+                  (prin1-to-string (make-marker))))))
+      (should (eq callback-buffer buffer))
+      (should (equal str "tata"))))
 
 (provide 'print-tests)
 ;;; print-tests.el ends here
diff --git a/test/src/process-tests.el b/test/src/process-tests.el
index 824c6da119..6e1e148332 100644
--- a/test/src/process-tests.el
+++ b/test/src/process-tests.el
@@ -38,10 +38,11 @@
 ;; Timeout in seconds; the test fails if the timeout is reached.
 (defvar process-test-sentinel-wait-timeout 2.0)
 
-;; Start a process that exits immediately.  Call WAIT-FUNCTION,
-;; possibly multiple times, to wait for the process to complete.
-(defun process-test-sentinel-wait-function-working-p (wait-function)
-  (let ((proc (start-process "test" nil "bash" "-c" "exit 20"))
+(defun process-test-wait-for-sentinel (proc exit-status &optional 
wait-function)
+  "Set a sentinel on PROC and wait for it to be called with EXIT-STATUS.
+Call WAIT-FUNCTION, possibly multiple times, to wait for the
+process to complete."
+  (let ((wait-function (or wait-function #'accept-process-output))
        (sentinel-called nil)
        (start-time (float-time)))
     (set-process-sentinel proc (lambda (_proc _msg)
@@ -50,21 +51,22 @@
                    (> (- (float-time) start-time)
                       process-test-sentinel-wait-timeout)))
       (funcall wait-function))
-    (cl-assert (eq (process-status proc) 'exit))
-    (cl-assert (= (process-exit-status proc) 20))
-    sentinel-called))
+    (should sentinel-called)
+    (should (eq (process-status proc) 'exit))
+    (should (= (process-exit-status proc) exit-status))))
 
 (ert-deftest process-test-sentinel-accept-process-output ()
   (skip-unless (executable-find "bash"))
   (with-timeout (60 (ert-fail "Test timed out"))
-  (should (process-test-sentinel-wait-function-working-p
-           #'accept-process-output))))
+    (let ((proc (start-process "test" nil "bash" "-c" "exit 20")))
+      (should (process-test-wait-for-sentinel proc 20)))))
 
 (ert-deftest process-test-sentinel-sit-for ()
   (skip-unless (executable-find "bash"))
   (with-timeout (60 (ert-fail "Test timed out"))
-  (should
-   (process-test-sentinel-wait-function-working-p (lambda () (sit-for 0.01 
t))))))
+    (let ((proc (start-process "test" nil "bash" "-c" "exit 20")))
+      (should (process-test-wait-for-sentinel
+               proc 20 (lambda () (sit-for 0.01 t)))))))
 
 (when (eq system-type 'windows-nt)
   (ert-deftest process-test-quoted-batfile ()
@@ -97,17 +99,8 @@
                                                    "echo hello stderr! >&2; "
                                                    "exit 20"))
                             :buffer stdout-buffer
-                            :stderr stderr-buffer))
-        (sentinel-called nil)
-        (start-time (float-time)))
-    (set-process-sentinel proc (lambda (_proc _msg)
-                                (setq sentinel-called t)))
-    (while (not (or sentinel-called
-                   (> (- (float-time) start-time)
-                      process-test-sentinel-wait-timeout)))
-      (accept-process-output))
-    (cl-assert (eq (process-status proc) 'exit))
-    (cl-assert (= (process-exit-status proc) 20))
+                            :stderr stderr-buffer)))
+    (process-test-wait-for-sentinel proc 20)
     (should (with-current-buffer stdout-buffer
              (goto-char (point-min))
              (looking-at "hello stdout!")))
@@ -118,8 +111,7 @@
 (ert-deftest process-test-stderr-filter ()
   (skip-unless (executable-find "bash"))
   (with-timeout (60 (ert-fail "Test timed out"))
-  (let* ((sentinel-called nil)
-        (stderr-sentinel-called nil)
+  (let* ((stderr-sentinel-called nil)
         (stdout-output nil)
         (stderr-output nil)
         (stdout-buffer (generate-new-buffer "*stdout*"))
@@ -131,23 +123,14 @@
                                            (concat "echo hello stdout!; "
                                                    "echo hello stderr! >&2; "
                                                    "exit 20"))
-                            :stderr stderr-proc))
-        (start-time (float-time)))
+                            :stderr stderr-proc)))
     (set-process-filter proc (lambda (_proc input)
                               (push input stdout-output)))
-    (set-process-sentinel proc (lambda (_proc _msg)
-                                (setq sentinel-called t)))
     (set-process-filter stderr-proc (lambda (_proc input)
                                      (push input stderr-output)))
     (set-process-sentinel stderr-proc (lambda (_proc _input)
                                        (setq stderr-sentinel-called t)))
-    (while (not (or sentinel-called
-                   (> (- (float-time) start-time)
-                      process-test-sentinel-wait-timeout)))
-      (accept-process-output))
-    (cl-assert (eq (process-status proc) 'exit))
-    (cl-assert (= (process-exit-status proc) 20))
-    (should sentinel-called)
+    (process-test-wait-for-sentinel proc 20)
     (should (equal 1 (with-current-buffer stdout-buffer
                       (point-max))))
     (should (equal "hello stdout!\n"
@@ -177,8 +160,7 @@
                         (setq count (1+ count))))))))
       (set-process-query-on-exit-flag proc nil)
       (send-string proc "one\n")
-      (while (not (equal (buffer-substring
-                          (line-beginning-position) (point-max))
+      (while (not (equal (buffer-substring (pos-bol) (point-max))
                          "1> "))
         (accept-process-output proc))   ; Read "one".
       (should (equal (buffer-string) "0> one\n1> "))
@@ -188,8 +170,7 @@
        (accept-process-output proc 1))  ; Can't read "two" yet.
       (should (equal (buffer-string) "0> one\n1> "))
       (set-process-filter proc nil)     ; Resume reading from proc.
-      (while (not (equal (buffer-substring
-                          (line-beginning-position) (point-max))
+      (while (not (equal (buffer-substring (pos-bol) (point-max))
                          "2> "))
         (accept-process-output proc))   ; Read "Two".
       (should (equal (buffer-string) "0> one\n1> two\n2> "))))))
@@ -289,6 +270,77 @@
                   (error :got-error))))
     (should have-called-debugger))))
 
+(defun make-process/test-connection-type (ttys &rest args)
+  "Make a process and check whether its standard streams match TTYS.
+This calls `make-process', passing ARGS to adjust how the process
+is created.  TTYS should be a list of 3 boolean values,
+indicating whether the subprocess's stdin, stdout, and stderr
+should be a TTY, respectively."
+  (declare (indent 1))
+  (let* (;; MS-Windows doesn't support communicating via pty.
+         (ttys (if (eq system-type 'windows-nt) '(nil nil nil) ttys))
+         (expected-output (concat (and (nth 0 ttys) "stdin\n")
+                                  (and (nth 1 ttys) "stdout\n")
+                                  (and (nth 2 ttys) "stderr\n")))
+         (stdout-buffer (generate-new-buffer "*stdout*"))
+         (proc (apply
+                #'make-process
+                :name "test"
+                :command (list "sh" "-c"
+                               (concat "if [ -t 0 ]; then echo stdin; fi; "
+                                       "if [ -t 1 ]; then echo stdout; fi; "
+                                       "if [ -t 2 ]; then echo stderr; fi"))
+                :buffer stdout-buffer
+                args)))
+    (should (eq (and (process-tty-name proc 'stdin) t) (nth 0 ttys)))
+    (should (eq (and (process-tty-name proc 'stdout) t) (nth 1 ttys)))
+    (should (eq (and (process-tty-name proc 'stderr) t) (nth 2 ttys)))
+    (process-test-wait-for-sentinel proc 0)
+    (should (equal (with-current-buffer stdout-buffer (buffer-string))
+                   expected-output))))
+
+(ert-deftest make-process/connection-type/pty ()
+  (skip-unless (executable-find "sh"))
+  (make-process/test-connection-type '(t t t)
+    :connection-type 'pty))
+
+(ert-deftest make-process/connection-type/pty-2 ()
+  (skip-unless (executable-find "sh"))
+  (make-process/test-connection-type '(t t t)
+    :connection-type '(pty . pty)))
+
+(ert-deftest make-process/connection-type/pipe ()
+  (skip-unless (executable-find "sh"))
+  (make-process/test-connection-type '(nil nil nil)
+    :connection-type 'pipe))
+
+(ert-deftest make-process/connection-type/pipe-2 ()
+  (skip-unless (executable-find "sh"))
+  (make-process/test-connection-type '(nil nil nil)
+    :connection-type '(pipe . pipe)))
+
+(ert-deftest make-process/connection-type/in-pty ()
+  (skip-unless (executable-find "sh"))
+  (make-process/test-connection-type '(t nil nil)
+    :connection-type '(pty . pipe)))
+
+(ert-deftest make-process/connection-type/out-pty ()
+  (skip-unless (executable-find "sh"))
+  (make-process/test-connection-type '(nil t t)
+    :connection-type '(pipe . pty)))
+
+(ert-deftest make-process/connection-type/pty-with-stderr-buffer ()
+  (skip-unless (executable-find "sh"))
+  (let ((stderr-buffer (generate-new-buffer "*stderr*")))
+    (make-process/test-connection-type '(t t nil)
+      :connection-type 'pty :stderr stderr-buffer)))
+
+(ert-deftest make-process/connection-type/out-pty-with-stderr-buffer ()
+  (skip-unless (executable-find "sh"))
+  (let ((stderr-buffer (generate-new-buffer "*stderr*")))
+    (make-process/test-connection-type '(nil t nil)
+      :connection-type '(pipe . pty) :stderr stderr-buffer)))
+
 (ert-deftest make-process/file-handler/found ()
   "Check that the `:file-handler’ argument of `make-process’
 works as expected if a file name handler is found."
@@ -378,6 +430,58 @@ See Bug#30460."
   (when (ipv6-is-available)
     (should (network-lookup-address-info "localhost" 'ipv6)))))
 
+(ert-deftest lookup-hints-specification ()
+  "`network-lookup-address-info' should only accept valid hints arg."
+  (should-error (network-lookup-address-info "1.1.1.1" nil t))
+  (should-error (network-lookup-address-info "1.1.1.1" 'ipv4 t))
+  (should (network-lookup-address-info "1.1.1.1" nil 'numeric))
+  (should (network-lookup-address-info "1.1.1.1" 'ipv4 'numeric))
+  (when (ipv6-is-available)
+    (should-error (network-lookup-address-info "::1" nil t))
+    (should-error (network-lookup-address-info "::1" 'ipv6 't))
+    (should (network-lookup-address-info "::1" nil 'numeric))
+    (should (network-lookup-address-info "::1" 'ipv6 'numeric))))
+
+(ert-deftest lookup-hints-values ()
+  "`network-lookup-address-info' should succeed/fail in looking up various 
numeric IP addresses."
+  (let ((ipv4-invalid-addrs
+         '("localhost" "343.1.2.3" "1.2.3.4.5"))
+        ;; These are valid for IPv4 but invalid for IPv6
+        (ipv4-addrs
+         '("127.0.0.1" "127.0.1" "127.1" "127" "1" "0"
+           "0xe3010203" "0xe3.1.2.3" "227.0x1.2.3"
+           "034300201003" "0343.1.2.3" "227.001.2.3"))
+        (ipv6-only-invalid-addrs
+         '("fe80:1" "e301:203:1" "e301::203::1"
+           "1:2:3:4:5:6:7:8:9" "0xe301:203::1"
+           "343:10001:2::3"
+           ;; "00343:1:2::3" is invalid on GNU/Linux and FreeBSD, but
+           ;; valid on macOS.  macOS is wrong here, but such is life.
+           ))
+        ;; These are valid for IPv6 but invalid for IPv4
+        (ipv6-addrs
+         '("fe80::1" "e301::203:1" "e301:203::1"
+           "e301:0203::1" "::1" "::0"
+           "0343:1:2::3" "343:001:2::3")))
+    (dolist (a ipv4-invalid-addrs)
+      (should-not (network-lookup-address-info a nil 'numeric))
+      (should-not (network-lookup-address-info a 'ipv4 'numeric)))
+    (dolist (a ipv6-addrs)
+      (should-not (network-lookup-address-info a 'ipv4 'numeric)))
+    (dolist (a ipv4-addrs)
+      (should (network-lookup-address-info a nil 'numeric))
+      (should (network-lookup-address-info a 'ipv4 'numeric)))
+    (when (ipv6-is-available)
+      (dolist (a ipv4-addrs)
+        (should-not (network-lookup-address-info a 'ipv6 'numeric)))
+      (dolist (a ipv6-only-invalid-addrs)
+        (should-not (network-lookup-address-info a 'ipv6 'numeric)))
+      (dolist (a ipv6-addrs)
+        (should (network-lookup-address-info a nil 'numeric))
+        (should (network-lookup-address-info a 'ipv6 'numeric))
+        (should (network-lookup-address-info (upcase a) nil 'numeric))
+        (should (network-lookup-address-info (upcase a) 'ipv6 'numeric))))))
+
 (ert-deftest lookup-unicode-domains ()
   "Unicode domains should fail."
   (skip-unless internet-is-working)
@@ -909,35 +1013,6 @@ Return nil if FILENAME doesn't exist."
       ;; ...and the change description should be "interrupt".
       (should (equal '("interrupt\n") events)))))
 
-(ert-deftest process-async-https-with-delay ()
-  "Bug#49449: asynchronous TLS connection with delayed completion."
-  (skip-unless (and internet-is-working (gnutls-available-p)))
-  (let* ((status nil)
-         (buf (url-http
-                 #s(url "https" nil nil "elpa.gnu.org" nil
-                        "/packages/archive-contents" nil nil t silent t t)
-                 (lambda (s) (setq status s))
-                 '(nil) nil 'tls)))
-    (unwind-protect
-        (progn
-          ;; Busy-wait for 1 s to allow for the TCP connection to complete.
-          (let ((delay 1.0)
-                (t0 (float-time)))
-            (while (< (float-time) (+ t0 delay))))
-          ;; Wait for the entire operation to finish.
-          (let ((limit 4.0)
-                (t0 (float-time)))
-            (while (and (null status)
-                        (< (float-time) (+ t0 limit)))
-              (sit-for 0.1)))
-          (should status)
-          (should-not (plist-get status ':error))
-          (should buf)
-          (should (> (buffer-size buf) 0))
-          )
-      (when buf
-        (kill-buffer buf)))))
-
 (ert-deftest process-num-processors ()
   "Sanity checks for num-processors."
   (should (equal (num-processors) (num-processors)))
diff --git a/test/src/timefns-tests.el b/test/src/timefns-tests.el
index 08d06f27d9..24f9000ffb 100644
--- a/test/src/timefns-tests.el
+++ b/test/src/timefns-tests.el
@@ -93,7 +93,6 @@
                           most-negative-fixnum most-positive-fixnum
                           (1- most-negative-fixnum)
                           (1+ most-positive-fixnum)
-                          1e+INF -1e+INF 1e+NaN -1e+NaN
                           '(0 1 0 0) '(1 0 0 0) '(-1 0 0 0)
                           '(123456789000000 . 1000000)
                           (cons (1+ most-positive-fixnum) 1000000000000)
@@ -169,10 +168,6 @@ a fixed place on the right and are padded on the left."
 (ert-deftest time-equal-p-nil-nil ()
   (should (time-equal-p nil nil)))
 
-(ert-deftest time-equal-p-NaN-NaN ()
-  (let ((x 0.0e+NaN))
-    (should (not (time-equal-p x x)))))
-
 (ert-deftest time-arith-tests ()
   (let ((time-values (list 0 -1 1 0.0 -0.0 -1.0 1.0
                           most-negative-fixnum most-positive-fixnum
@@ -184,7 +179,6 @@ a fixed place on the right and are padded on the left."
                           1e10 -1e10 1e-10 -1e-10
                           1e16 -1e16 1e-16 -1e-16
                           1e37 -1e37 1e-37 -1e-37
-                          1e+INF -1e+INF 1e+NaN -1e+NaN
                           '(0 0 0 1) '(0 0 1 0) '(0 1 0 0) '(1 0 0 0)
                           '(-1 0 0 0) '(1 2 3 4) '(-1 2 3 4)
                           '(-123456789 . 100000) '(123456789 . 1000000)
diff --git a/test/src/undo-tests.el b/test/src/undo-tests.el
index c84ed74f0b..cb0822fb1b 100644
--- a/test/src/undo-tests.el
+++ b/test/src/undo-tests.el
@@ -460,11 +460,10 @@ Demonstrates bug 25599."
                  (delete-overlay ov))))))
       (save-excursion
         (goto-char (point-min))
-        (let ((ov (make-overlay (line-beginning-position 2)
-                                (line-end-position 2))))
+        (let ((ov (make-overlay (pos-bol 2) (pos-eol 2))))
           (overlay-put ov 'insert-in-front-hooks
                        (list overlay-modified)))))
-    (kill-region (point-min) (line-beginning-position 2))
+    (kill-region (point-min) (pos-bol 2))
     (undo-boundary)
     (undo)))
 



reply via email to

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